Patchwork [U-Boot,09/10] Adding interactive ddr

login
register
mail settings
Submitter York Sun
Date Dec. 9, 2010, 2:55 a.m.
Message ID <1291863340-4354-9-git-send-email-yorksun@freescale.com>
Download mbox | patch
Permalink /patch/74840/
State Changes Requested
Delegated to: Kumar Gala
Headers show

Comments

York Sun - Dec. 9, 2010, 2:55 a.m.
Use environment variable to active the interactive debugging.

Signed-off-by: York Sun <yorksun@freescale.com>
---
 arch/powerpc/cpu/mpc8xxx/ddr/Makefile      |    6 +-
 arch/powerpc/cpu/mpc8xxx/ddr/interactive.c | 1882 ++++++++++++++++++++++++++++
 arch/powerpc/cpu/mpc8xxx/ddr/main.c        |    8 +-
 doc/README.fsl-ddr                         |   20 +
 4 files changed, 1910 insertions(+), 6 deletions(-)
 create mode 100644 arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
Kumar Gala - Dec. 14, 2010, 5:15 a.m.
On Dec 8, 2010, at 8:55 PM, York Sun wrote:

> Use environment variable to active the interactive debugging.
> 
> Signed-off-by: York Sun <yorksun@freescale.com>
> ---
> arch/powerpc/cpu/mpc8xxx/ddr/Makefile      |    6 +-
> arch/powerpc/cpu/mpc8xxx/ddr/interactive.c | 1882 ++++++++++++++++++++++++++++
> arch/powerpc/cpu/mpc8xxx/ddr/main.c        |    8 +-
> doc/README.fsl-ddr                         |   20 +
> 4 files changed, 1910 insertions(+), 6 deletions(-)
> create mode 100644 arch/powerpc/cpu/mpc8xxx/ddr/interactive.c

Can you make this the last patch.

- k
Wolfgang Denk - Dec. 14, 2010, 7:47 a.m.
Dear York Sun,

In message <1291863340-4354-9-git-send-email-yorksun@freescale.com> you wrote:
> Use environment variable to active the interactive debugging.
...

s/active/activate/

> diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/Makefile b/arch/powerpc/cpu/mpc8xxx/ddr/Makefile
> index cb7f856..4bd416a 100644
> --- a/arch/powerpc/cpu/mpc8xxx/ddr/Makefile
> +++ b/arch/powerpc/cpu/mpc8xxx/ddr/Makefile
> @@ -11,15 +11,15 @@ include $(TOPDIR)/config.mk
>  LIB	= $(obj)libddr.a
>  
>  COBJS-$(CONFIG_FSL_DDR1)	+= main.o util.o ctrl_regs.o options.o \
> -				   lc_common_dimm_params.o
> +				   lc_common_dimm_params.o interactive.o
>  COBJS-$(CONFIG_FSL_DDR1)	+= ddr1_dimm_params.o
>  
>  COBJS-$(CONFIG_FSL_DDR2)	+= main.o util.o ctrl_regs.o options.o \
> -				   lc_common_dimm_params.o
> +				   lc_common_dimm_params.o interactive.o
>  COBJS-$(CONFIG_FSL_DDR2)	+= ddr2_dimm_params.o
>  
>  COBJS-$(CONFIG_FSL_DDR3)	+= main.o util.o ctrl_regs.o options.o \
> -				   lc_common_dimm_params.o
> +				   lc_common_dimm_params.o interactive.o
>  COBJS-$(CONFIG_FSL_DDR3)	+= ddr3_dimm_params.o

Building interactive.o should depend on CONFIG_FSL_DDR_INTERACTIVE
being set.

>  SRCS	:= $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
> diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
> new file mode 100644
> index 0000000..7d492a9
> --- /dev/null
> +++ b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
> @@ -0,0 +1,1882 @@
> +/*
> + * Copyright 2010 Freescale Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * Version 2 as published by the Free Software Foundation.
> + */

NAK.   V2 or later is mandatory.


> +static void fsl_ddr_generic_edit(void *pdata,
> +			   void *pend,
> +			   unsigned int element_size,
> +			   unsigned int element_num,
> +			   unsigned int value)
> +{
> +	char *pcdata = (char *)pdata;		/* BIG ENDIAN ONLY */
> +
> +	pcdata += element_num * element_size;
> +	if ((pcdata + element_size) > (char *) pend) {
> +		debug("trying to write past end of data\n");
> +		return;

Should that not be an error message that is always enabled?

> +	default:
> +		debug("unexpected element size %u\n", element_size);
> +		break;

Ditto?


> +	static const options_strings_t options[] = {
> +		{"cs0_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[0].odt_rd_cfg)},
> +		{"cs0_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[0].odt_wr_cfg)},
> +		{"cs0_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[0].odt_rtt_norm)},
> +		{"cs0_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[0].odt_rtt_wr)},
> +		{"cs1_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[1].odt_rd_cfg)},
> +		{"cs1_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[1].odt_wr_cfg)},
> +		{"cs1_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[1].odt_rtt_norm)},
> +		{"cs1_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[1].odt_rtt_wr)},
> +		{"cs2_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[2].odt_rd_cfg)},
> +		{"cs2_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[2].odt_wr_cfg)},
> +		{"cs2_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[2].odt_rtt_norm)},
> +		{"cs2_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[2].odt_rtt_wr)},
> +		{"cs3_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[3].odt_rd_cfg)},
> +		{"cs3_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[3].odt_wr_cfg)},
> +		{"cs3_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[3].odt_rtt_norm)},
> +		{"cs3_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[3].odt_rtt_wr)},

Lines too long.


> +	if (handle_uint_option_table(options, nopts, (u32) p,
> +					optname_str, value_str))
> +		return;

Please use braces for multiline statements.

> +	printf("couldn't find option string %s\n", optname_str);
> +}
> +
> +static void print_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
> +		printf("cs%u_bnds           = %08X\n", i, ddr->cs[i].bnds);
> +		printf("cs%u_config         = %08X\n", i, ddr->cs[i].config);
> +		printf("cs%u_config_2       = %08X\n", i, ddr->cs[i].config_2);
> +	}
> +
> +	printf("timing_cfg_3       = %08X\n", ddr->timing_cfg_3);
> +	printf("timing_cfg_0       = %08X\n", ddr->timing_cfg_0);
> +	printf("timing_cfg_1       = %08X\n", ddr->timing_cfg_1);
> +	printf("timing_cfg_2       = %08X\n", ddr->timing_cfg_2);
> +	printf("ddr_sdram_cfg      = %08X\n", ddr->ddr_sdram_cfg);
> +	printf("ddr_sdram_cfg_2    = %08X\n", ddr->ddr_sdram_cfg_2);
> +	printf("ddr_sdram_mode     = %08X\n", ddr->ddr_sdram_mode);
> +	printf("ddr_sdram_mode_2   = %08X\n", ddr->ddr_sdram_mode_2);
> +	printf("ddr_sdram_mode_3   = %08X\n", ddr->ddr_sdram_mode_3);
> +	printf("ddr_sdram_mode_4   = %08X\n", ddr->ddr_sdram_mode_4);
> +	printf("ddr_sdram_mode_5   = %08X\n", ddr->ddr_sdram_mode_5);
> +	printf("ddr_sdram_mode_6   = %08X\n", ddr->ddr_sdram_mode_6);
> +	printf("ddr_sdram_mode_7   = %08X\n", ddr->ddr_sdram_mode_7);
> +	printf("ddr_sdram_mode_8   = %08X\n", ddr->ddr_sdram_mode_8);
> +	printf("ddr_sdram_interval = %08X\n", ddr->ddr_sdram_interval);
> +	printf("ddr_data_init      = %08X\n", ddr->ddr_data_init);
> +	printf("ddr_sdram_clk_cntl = %08X\n", ddr->ddr_sdram_clk_cntl);
> +	printf("ddr_init_addr      = %08X\n", ddr->ddr_init_addr);
> +	printf("ddr_init_ext_addr  = %08X\n", ddr->ddr_init_ext_addr);
> +	printf("timing_cfg_4       = %08X\n", ddr->timing_cfg_4);
> +	printf("timing_cfg_5       = %08X\n", ddr->timing_cfg_5);
> +	printf("ddr_zq_cntl        = %08X\n", ddr->ddr_zq_cntl);
> +	printf("ddr_wrlvl_cntl     = %08X\n", ddr->ddr_wrlvl_cntl);
> +	printf("ddr_sr_cntr        = %08X\n", ddr->ddr_sr_cntr);
> +	printf("ddr_sdram_rcw_1    = %08X\n", ddr->ddr_sdram_rcw_1);
> +	printf("ddr_sdram_rcw_2    = %08X\n", ddr->ddr_sdram_rcw_2);
> +	printf("ddr_cdr1           = %08X\n", ddr->ddr_cdr1);
> +	printf("ddr_cdr2           = %08X\n", ddr->ddr_cdr2);
> +	printf("err_disable        = %08X\n", ddr->err_disable);
> +	printf("err_int_en         = %08X\n", ddr->err_int_en);
> +	for (i = 0; i < 18; i++)
> +		printf("debug_%02d	= %08X\n", i+1, ddr->debug[i]);
> +}
> +
> +static void fsl_ddr_regs_edit(fsl_ddr_info_t *pinfo,
> +			unsigned int ctrl_num,
> +			const char *regname,
> +			unsigned int value)
> +{
> +	unsigned int i;
> +	fsl_ddr_cfg_regs_t *ddr;
> +	char buf[20];
> +
> +	debug("fsl_ddr_regs_edit: ctrl_num = %u, "
> +		"regname = %s, value = 0x%08X\n",
> +		ctrl_num, regname, value);
> +	if (ctrl_num > CONFIG_NUM_DDR_CONTROLLERS)
> +		return;
> +
> +	/* FIXME: Change this into struct like the other editing functions */
> +	ddr = &(pinfo->fsl_ddr_config_reg[ctrl_num]);
> +
> +	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
> +		sprintf(buf, "cs%u_bnds", i);
> +		if (strcmp(buf, regname) == 0) {
> +			ddr->cs[i].bnds = value;
> +			return;
> +		}
> +
> +		sprintf(buf, "cs%u_config", i);
> +		if (strcmp(buf, regname) == 0) {
> +			ddr->cs[i].config = value;
> +			return;
> +		}
> +
> +		sprintf(buf, "cs%u_config_2", i);
> +		if (strcmp(buf, regname) == 0) {
> +			ddr->cs[i].config_2 = value;
> +			return;
> +		}
> +	}

Use format string / pointer table and a loop.

> +	if (strcmp("timing_cfg_3", regname) == 0) {
> +		ddr->timing_cfg_3 = value;
> +		return;
> +	}
> +
> +	if (strcmp("timing_cfg_0", regname) == 0) {
> +		ddr->timing_cfg_0 = value;
> +		return;
> +	}
> +
> +	if (strcmp("timing_cfg_1", regname) == 0) {
> +		ddr->timing_cfg_1 = value;
> +		return;
> +	}
> +
> +	if (strcmp("timing_cfg_2", regname) == 0) {
> +		ddr->timing_cfg_2 = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_sdram_cfg", regname) == 0) {
> +		ddr->ddr_sdram_cfg = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_sdram_cfg_2", regname) == 0) {
> +		ddr->ddr_sdram_cfg_2 = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_sdram_mode", regname) == 0) {
> +		ddr->ddr_sdram_mode = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_sdram_mode_2", regname) == 0) {
> +		ddr->ddr_sdram_mode_2 = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_sdram_mode_3", regname) == 0) {
> +		ddr->ddr_sdram_mode_3 = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_sdram_mode_4", regname) == 0) {
> +		ddr->ddr_sdram_mode_4 = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_sdram_mode_5", regname) == 0) {
> +		ddr->ddr_sdram_mode_5 = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_sdram_mode_6", regname) == 0) {
> +		ddr->ddr_sdram_mode_6 = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_sdram_mode_7", regname) == 0) {
> +		ddr->ddr_sdram_mode_7 = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_sdram_mode_8", regname) == 0) {
> +		ddr->ddr_sdram_mode_8 = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_sdram_interval", regname) == 0) {
> +		ddr->ddr_sdram_interval = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_data_init", regname) == 0) {
> +		ddr->ddr_data_init = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_sdram_clk_cntl", regname) == 0) {
> +		ddr->ddr_sdram_clk_cntl = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_init_addr", regname) == 0) {
> +		ddr->ddr_init_addr = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_init_ext_addr", regname) == 0) {
> +		ddr->ddr_init_ext_addr = value;
> +		return;
> +	}
> +
> +	if (strcmp("timing_cfg_4", regname) == 0) {
> +		ddr->timing_cfg_4 = value;
> +		return;
> +	}
> +
> +	if (strcmp("timing_cfg_5", regname) == 0) {
> +		ddr->timing_cfg_5 = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_zq_cntl", regname) == 0) {
> +		ddr->ddr_zq_cntl = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_wrlvl_cntl", regname) == 0) {
> +		ddr->ddr_wrlvl_cntl = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_sr_cntr", regname) == 0) {
> +		ddr->ddr_sr_cntr = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_sdram_rcw_1", regname) == 0) {
> +		ddr->ddr_sdram_rcw_1 = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_sdram_rcw_2", regname) == 0) {
> +		ddr->ddr_sdram_rcw_2 = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_cdr1", regname) == 0) {
> +		ddr->ddr_cdr1 = value;
> +		return;
> +	}
> +
> +	if (strcmp("ddr_cdr2", regname) == 0) {
> +		ddr->ddr_cdr2 = value;
> +		return;
> +	}
> +
> +	if (strcmp("err_disable", regname) == 0) {
> +		ddr->err_disable = value;
> +		return;
> +	}
> +
> +	if (strcmp("err_int_en", regname) == 0) {
> +		ddr->err_int_en = value;
> +		return;
> +	}

Use string / pointer table and a loop.

...
> +#define PRINT_NXS(x, y, z) printf("%-3d    : %02x %s\n", x, y, z);
> +#define PRINT_NNXXS(n0, n1, x0, x1, s) printf("%-3d-%3d: %02x %02x %s\n", n0, n1, x0, x1, s);
> +#define PRINT_SNNlots(x, y, z, arr) do {printf(x); printf("%-3d-%3d: ", y, z); for (i = y; i <= z; i++) printf("%02x", arr[i - y]); } while (0)

Lines way too long; please fix globally.

...
> +				if (strcmp(argv[i], "dimmparms") == 0) {
> +					step_mask |= STEP_COMPUTE_DIMM_PARMS;
> +					continue;
> +				}
> +
> +				if (strcmp(argv[i], "commonparms") == 0) {
> +					step_mask |= STEP_COMPUTE_COMMON_PARMS;
> +					continue;
> +				}
> +
> +				if (strcmp(argv[i], "opts") == 0) {
> +					step_mask |= STEP_GATHER_OPTS;
> +					continue;
> +				}
> +
> +				if (strcmp(argv[i], "addresses") == 0) {
> +					step_mask |= STEP_ASSIGN_ADDRESSES;
> +					continue;
> +				}
> +
> +				if (strcmp(argv[i], "regs") == 0) {
> +					step_mask |= STEP_COMPUTE_REGS;
> +					continue;
> +				}

Here again the code could be made much smaller and easier to read by
using a data (table) driven approach and a loop through the table.
Please consider using this technique globally.


Best regards,

Wolfgang Denk
Kumar Gala - Dec. 14, 2010, 3:07 p.m.
On Dec 14, 2010, at 1:47 AM, Wolfgang Denk wrote:

> Dear York Sun,
> 
> In message <1291863340-4354-9-git-send-email-yorksun@freescale.com> you wrote:
>> Use environment variable to active the interactive debugging.
> ...
> 
> s/active/activate/
> 
>> diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/Makefile b/arch/powerpc/cpu/mpc8xxx/ddr/Makefile
>> index cb7f856..4bd416a 100644
>> --- a/arch/powerpc/cpu/mpc8xxx/ddr/Makefile
>> +++ b/arch/powerpc/cpu/mpc8xxx/ddr/Makefile
>> @@ -11,15 +11,15 @@ include $(TOPDIR)/config.mk
>> LIB	= $(obj)libddr.a
>> 
>> COBJS-$(CONFIG_FSL_DDR1)	+= main.o util.o ctrl_regs.o options.o \
>> -				   lc_common_dimm_params.o
>> +				   lc_common_dimm_params.o interactive.o
>> COBJS-$(CONFIG_FSL_DDR1)	+= ddr1_dimm_params.o
>> 
>> COBJS-$(CONFIG_FSL_DDR2)	+= main.o util.o ctrl_regs.o options.o \
>> -				   lc_common_dimm_params.o
>> +				   lc_common_dimm_params.o interactive.o
>> COBJS-$(CONFIG_FSL_DDR2)	+= ddr2_dimm_params.o
>> 
>> COBJS-$(CONFIG_FSL_DDR3)	+= main.o util.o ctrl_regs.o options.o \
>> -				   lc_common_dimm_params.o
>> +				   lc_common_dimm_params.o interactive.o
>> COBJS-$(CONFIG_FSL_DDR3)	+= ddr3_dimm_params.o
> 
> Building interactive.o should depend on CONFIG_FSL_DDR_INTERACTIVE
> being set.

Agreed

> 
>> SRCS	:= $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
>> diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
>> new file mode 100644
>> index 0000000..7d492a9
>> --- /dev/null
>> +++ b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
>> @@ -0,0 +1,1882 @@
>> +/*
>> + * Copyright 2010 Freescale Semiconductor, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * Version 2 as published by the Free Software Foundation.
>> + */
> 
> NAK.   V2 or later is mandatory.

Yes, we will fix.

- k

Patch

diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/Makefile b/arch/powerpc/cpu/mpc8xxx/ddr/Makefile
index cb7f856..4bd416a 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/Makefile
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/Makefile
@@ -11,15 +11,15 @@  include $(TOPDIR)/config.mk
 LIB	= $(obj)libddr.a
 
 COBJS-$(CONFIG_FSL_DDR1)	+= main.o util.o ctrl_regs.o options.o \
-				   lc_common_dimm_params.o
+				   lc_common_dimm_params.o interactive.o
 COBJS-$(CONFIG_FSL_DDR1)	+= ddr1_dimm_params.o
 
 COBJS-$(CONFIG_FSL_DDR2)	+= main.o util.o ctrl_regs.o options.o \
-				   lc_common_dimm_params.o
+				   lc_common_dimm_params.o interactive.o
 COBJS-$(CONFIG_FSL_DDR2)	+= ddr2_dimm_params.o
 
 COBJS-$(CONFIG_FSL_DDR3)	+= main.o util.o ctrl_regs.o options.o \
-				   lc_common_dimm_params.o
+				   lc_common_dimm_params.o interactive.o
 COBJS-$(CONFIG_FSL_DDR3)	+= ddr3_dimm_params.o
 
 SRCS	:= $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
new file mode 100644
index 0000000..7d492a9
--- /dev/null
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/interactive.c
@@ -0,0 +1,1882 @@ 
+/*
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+/*
+ * Generic driver for Freescale DDR/DDR2/DDR3 memory controller.
+ * Based on code from spd_sdram.c
+ * Author: James Yang [at freescale.com]
+ * Maintainer: York Sun <yorksun@freescale.com>
+ */
+
+#include <common.h>
+#include <linux/ctype.h>
+#include <asm/types.h>
+
+#include <asm/fsl_ddr_sdram.h>
+#include "ddr.h"
+
+/* Option parameter Structures */
+typedef struct {
+	const char *option_name;
+	size_t offset;
+} options_strings_t;
+
+int do_reset(void *cmdtp, int flag, int argc, char *argv[]);
+unsigned int check_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr);
+const char *step_to_string(unsigned int step);
+
+static unsigned int picos_to_mhz(unsigned int picos)
+{
+	return 1000000 / picos;
+}
+
+static int handle_uint_option_table(const options_strings_t *table,
+			 int table_size,
+			 u32 base,
+			 const char *opt,
+			 const char *val)
+{
+	unsigned int i;
+	unsigned int value, *ptr;
+
+	for (i = 0; i < table_size; i++) {
+		if (strcmp(table[i].option_name, opt) == 0) {
+			value = simple_strtoul(val, NULL, 0);
+			ptr = (unsigned int *)(base + table[i].offset);
+			*ptr = value;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int handle_ull_option_table(const options_strings_t *table,
+			int table_size,
+			u32 base,
+			const char *opt,
+			const char *val)
+{
+	unsigned int i;
+	unsigned long long value, *ptr;
+
+	for (i = 0; i < table_size; i++) {
+		if (strcmp(table[i].option_name, opt) == 0) {
+			value = simple_strtoull(val, NULL, 0);
+			ptr = (unsigned long long *)(base + table[i].offset);
+			*ptr = value;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static void fsl_ddr_generic_edit(void *pdata,
+			   void *pend,
+			   unsigned int element_size,
+			   unsigned int element_num,
+			   unsigned int value)
+{
+	char *pcdata = (char *)pdata;		/* BIG ENDIAN ONLY */
+
+	pcdata += element_num * element_size;
+	if ((pcdata + element_size) > (char *) pend) {
+		debug("trying to write past end of data\n");
+		return;
+	}
+
+	switch (element_size) {
+	case 1:
+		__raw_writeb(value, pcdata);
+		break;
+	case 2:
+		__raw_writew(value, pcdata);
+		break;
+	case 4:
+		__raw_writel(value, pcdata);
+		break;
+	default:
+		debug("unexpected element size %u\n", element_size);
+		break;
+	}
+}
+
+static void fsl_ddr_spd_edit(fsl_ddr_info_t *pinfo,
+		       unsigned int ctrl_num,
+		       unsigned int dimm_num,
+		       unsigned int element_num,
+		       unsigned int value)
+{
+	generic_spd_eeprom_t *pspd;
+
+	pspd = &(pinfo->spd_installed_dimms[ctrl_num][dimm_num]);
+	fsl_ddr_generic_edit(pspd, pspd + 1,
+				   sizeof(char), element_num, value);
+}
+#define OPTIONS_UNIT(x) {#x, offsetof(common_timing_params_t, x)}
+static void lowest_common_dimm_parameters_edit(fsl_ddr_info_t *pinfo,
+					unsigned int ctrl_num,
+					const char *optname_str,
+					const char *value_str)
+{
+	common_timing_params_t *p = &pinfo->common_timing_params[ctrl_num];
+
+	static const options_strings_t options_uint[] = {
+		OPTIONS_UNIT(tCKmin_X_ps),
+		OPTIONS_UNIT(tCKmax_ps),
+		OPTIONS_UNIT(tCKmax_max_ps),
+		OPTIONS_UNIT(tRCD_ps),
+		OPTIONS_UNIT(tRP_ps),
+		OPTIONS_UNIT(tRAS_ps),
+		OPTIONS_UNIT(tWR_ps),
+		OPTIONS_UNIT(tWTR_ps),
+		OPTIONS_UNIT(tRFC_ps),
+		OPTIONS_UNIT(tRRD_ps),
+		OPTIONS_UNIT(tRC_ps),
+		OPTIONS_UNIT(refresh_rate_ps),
+		OPTIONS_UNIT(tIS_ps),
+		OPTIONS_UNIT(tIH_ps),
+		OPTIONS_UNIT(tDS_ps),
+		OPTIONS_UNIT(tDH_ps),
+		OPTIONS_UNIT(tRTP_ps),
+		OPTIONS_UNIT(tDQSQ_max_ps),
+		OPTIONS_UNIT(tQHS_ps),
+		OPTIONS_UNIT(ndimms_present),
+		OPTIONS_UNIT(lowest_common_SPD_caslat),
+		OPTIONS_UNIT(highest_common_derated_caslat),
+		OPTIONS_UNIT(additive_latency),
+		OPTIONS_UNIT(all_DIMMs_burst_lengths_bitmask),
+		OPTIONS_UNIT(all_DIMMs_registered),
+		OPTIONS_UNIT(all_DIMMs_unbuffered),
+		OPTIONS_UNIT(all_DIMMs_ECC_capable),
+	};
+
+	static const unsigned int n_uint_opts = ARRAY_SIZE(options_uint);
+
+	static const options_strings_t options_ull[] = {
+		OPTIONS_UNIT(total_mem),
+		OPTIONS_UNIT(base_address),
+	};
+
+	static const unsigned int n_ull_opts = ARRAY_SIZE(options_ull);
+
+	if (handle_uint_option_table(options_uint, n_uint_opts, (u32) p,
+				     optname_str, value_str))
+		return;
+
+	if (handle_ull_option_table(options_ull, n_ull_opts, (u32) p,
+				    optname_str, value_str))
+		return;
+
+	printf("Error: couldn't find option string %s\n", optname_str);
+}
+
+#undef OPTIONS_UNIT
+#define OPTIONS_UNIT(x) {#x, offsetof(dimm_params_t, x)}
+
+static void fsl_ddr_dimm_parameters_edit(fsl_ddr_info_t *pinfo,
+				   unsigned int ctrl_num,
+				   unsigned int dimm_num,
+				   const char *optname_str,
+				   const char *value_str)
+{
+	dimm_params_t *p = &(pinfo->dimm_params[ctrl_num][dimm_num]);
+
+	static const options_strings_t options_uint[] = {
+		OPTIONS_UNIT(n_ranks),
+		OPTIONS_UNIT(data_width),
+		OPTIONS_UNIT(primary_sdram_width),
+		OPTIONS_UNIT(ec_sdram_width),
+		OPTIONS_UNIT(registered_dimm),
+
+		OPTIONS_UNIT(n_row_addr),
+		OPTIONS_UNIT(n_col_addr),
+		OPTIONS_UNIT(edc_config),
+		OPTIONS_UNIT(n_banks_per_sdram_device),
+		OPTIONS_UNIT(burst_lengths_bitmask),
+		OPTIONS_UNIT(row_density),
+
+		OPTIONS_UNIT(tCKmin_X_ps),
+		OPTIONS_UNIT(tCKmin_X_minus_1_ps),
+		OPTIONS_UNIT(tCKmin_X_minus_2_ps),
+		OPTIONS_UNIT(tCKmax_ps),
+
+		OPTIONS_UNIT(caslat_X),
+		OPTIONS_UNIT(caslat_X_minus_1),
+		OPTIONS_UNIT(caslat_X_minus_2),
+
+		OPTIONS_UNIT(caslat_lowest_derated),
+
+		OPTIONS_UNIT(tRCD_ps),
+		OPTIONS_UNIT(tRP_ps),
+		OPTIONS_UNIT(tRAS_ps),
+		OPTIONS_UNIT(tWR_ps),
+		OPTIONS_UNIT(tWTR_ps),
+		OPTIONS_UNIT(tRFC_ps),
+		OPTIONS_UNIT(tRRD_ps),
+		OPTIONS_UNIT(tRC_ps),
+		OPTIONS_UNIT(refresh_rate_ps),
+
+		OPTIONS_UNIT(tIS_ps),
+		OPTIONS_UNIT(tIH_ps),
+		OPTIONS_UNIT(tDS_ps),
+		OPTIONS_UNIT(tDH_ps),
+		OPTIONS_UNIT(tRTP_ps),
+		OPTIONS_UNIT(tDQSQ_max_ps),
+		OPTIONS_UNIT(tQHS_ps),
+	};
+
+	static const unsigned int n_uint_opts = ARRAY_SIZE(options_uint);
+
+	static const options_strings_t options_ull[] = {
+		OPTIONS_UNIT(rank_density),
+		OPTIONS_UNIT(capacity),
+		OPTIONS_UNIT(base_address),
+	};
+
+	static const unsigned int n_ull_opts = ARRAY_SIZE(options_ull);
+
+	if (handle_uint_option_table(options_uint, n_uint_opts, (u32) p,
+				     optname_str, value_str))
+		return;
+
+	if (handle_ull_option_table(options_ull, n_ull_opts, (u32) p,
+				    optname_str, value_str))
+		return;
+
+	printf("couldn't find option string %s\n", optname_str);
+}
+
+static void print_dimm_parameters(const dimm_params_t *pdimm)
+{
+	if (pdimm->n_ranks == 0) {
+		printf("DIMM not present\n");
+		return;
+	}
+
+	printf("DIMM organization parameters:\n");
+
+	printf("module part name = %s\n", pdimm->mpart);
+	printf("n_ranks = %u\n", pdimm->n_ranks);
+	printf("rank_density = %llu bytes (%llu megabytes)\n",
+	       pdimm->rank_density, pdimm->rank_density / 0x100000);
+	printf("capacity = %llu bytes (%llu megabytes)\n",
+	       pdimm->capacity, pdimm->capacity / 0x100000);
+	printf("data_width = %u\n", pdimm->data_width);
+	printf("primary_sdram_width = %u\n", pdimm->primary_sdram_width);
+	printf("ec_sdram_width = %u\n", pdimm->ec_sdram_width);
+	printf("registered_dimm = %u\n", pdimm->registered_dimm);
+
+	printf("SDRAM device parameters:\n");
+	printf("n_row_addr = %u\n", pdimm->n_row_addr);
+	printf("n_col_addr = %u\n", pdimm->n_col_addr);
+	printf("edc_config = %u\n", pdimm->edc_config);
+	printf("n_banks_per_sdram_device = %u\n",
+	       pdimm->n_banks_per_sdram_device);
+	printf("burst_lengths_bitmask = %02X\n",
+	       pdimm->burst_lengths_bitmask);
+
+	printf("base_addresss = %llu (%08llX %08llX)\n",
+	       pdimm->base_address,
+	       (pdimm->base_address >> 32),
+	       pdimm->base_address & 0xFFFFFFFF);
+
+	printf("SDRAM clock periods:\n");
+	printf("tCKmin_X_ps = %u ps\n", pdimm->tCKmin_X_ps);
+	printf("tCKmin_X_minus_1_ps = %u ps\n", pdimm->tCKmin_X_minus_1_ps);
+	printf("tCKmin_X_minus_2_ps = %u ps\n", pdimm->tCKmin_X_minus_2_ps);
+	printf("tCKmax_ps = %u ps\n", pdimm->tCKmax_ps);
+
+	printf("SDRAM CAS latencies:\n");
+	printf("caslat_X = %u\n", pdimm->caslat_X);
+	printf("caslat_X_minus_1 = %u\n", pdimm->caslat_X_minus_1);
+	printf("caslat_X_minus_2 = %u\n", pdimm->caslat_X_minus_2);
+	printf("caslat_lowest_derated = %u\n", pdimm->caslat_lowest_derated);
+
+	printf("SDRAM timing parameters:\n");
+	printf("tRCD_ps = %u\n", pdimm->tRCD_ps);
+	printf("tRP_ps = %u\n",  pdimm->tRP_ps);
+	printf("tRAS_ps = %u\n", pdimm->tRAS_ps);
+	printf("tWR_ps = %u\n",  pdimm->tWR_ps);
+	printf("tWTR_ps = %u\n", pdimm->tWTR_ps);
+	printf("tRFC_ps = %u\n", pdimm->tRFC_ps);
+	printf("tRC_ps = %u\n",  pdimm->tRC_ps);
+	printf("tRRD_ps = %u\n", pdimm->tRRD_ps);
+	printf("refresh_rate_ps = %u\n", pdimm->refresh_rate_ps);
+
+	printf("SDRAM even more timing parameters:\n");
+	printf("tIS_ps = %u\n", pdimm->tIS_ps);
+	printf("tIH_ps = %u\n", pdimm->tIH_ps);
+	printf("tDS_ps = %u\n", pdimm->tDS_ps);
+	printf("tDH_ps = %u\n", pdimm->tDH_ps);
+	printf("tRTP_ps = %u\n", pdimm->tRTP_ps);
+	printf("tDQSQ_max_ps = %u\n", pdimm->tDQSQ_max_ps);
+	printf("tQHS_ps = %u\n", pdimm->tQHS_ps);
+}
+
+static void print_lowest_common_dimm_parameters(
+		const common_timing_params_t *plcd_dimm_params)
+{
+
+	/* Clock frequencies */
+	printf("tCKmin_X_ps = %u (%u MHz)\n",
+	       plcd_dimm_params->tCKmin_X_ps,
+	       picos_to_mhz(plcd_dimm_params->tCKmin_X_ps));
+	printf("tCKmax_ps = %u (%u MHz)\n",
+	       plcd_dimm_params->tCKmax_ps,
+	       picos_to_mhz(plcd_dimm_params->tCKmax_ps));
+	printf("tCKmax_max_ps = %u\n", plcd_dimm_params->tCKmax_max_ps);
+
+	/* Basic timing parameters */
+	printf("tRCD_ps = %u\n", plcd_dimm_params->tRCD_ps);
+	printf("tRP_ps = %u\n", plcd_dimm_params->tRP_ps);
+	printf("tRAS_ps = %u\n", plcd_dimm_params->tRAS_ps);
+
+	/* maximum = 63750 ps */
+	printf("tWR_ps = %u\n", plcd_dimm_params->tWR_ps);
+
+	/* maximum = 63750 ps */
+	printf("tWTR_ps = %u\n", plcd_dimm_params->tWTR_ps);
+
+	/* maximum = 255 ns + 256 ns + .75 ns = 511750 ps */
+	printf("tRFC_ps = %u\n", plcd_dimm_params->tRFC_ps);
+
+	/* maximum = 63750 ps */
+	printf("tRRD_ps = %u\n", plcd_dimm_params->tRRD_ps);
+
+	/* maximum = 254 ns + .75 ns = 254750 ps */
+	printf("tRC_ps = %u\n", plcd_dimm_params->tRC_ps);
+
+	printf("refresh_rate_ps = %u\n", plcd_dimm_params->refresh_rate_ps);
+
+	/* byte 32, spd->ca_setup */
+	printf("tIS_ps = %u\n", plcd_dimm_params->tIS_ps);
+	/* byte 33, spd->ca_hold */
+	printf("tIH_ps = %u\n", plcd_dimm_params->tIH_ps);
+	/* byte 34, spd->data_setup */
+	printf("tDS_ps = %u\n", plcd_dimm_params->tDS_ps);
+	/* byte 35, spd->data_hold */
+	printf("tDH_ps = %u\n", plcd_dimm_params->tDH_ps);
+	/* byte 38, spd->trtp */
+	printf("tRTP_ps = %u\n", plcd_dimm_params->tRTP_ps);
+	/* byte 44, spd->tdqsq */
+	printf("tDQSQ_max_ps = %u\n", plcd_dimm_params->tDQSQ_max_ps);
+	/* byte 45, spd->tqhs */
+	printf("tQHS_ps = %u\n", plcd_dimm_params->tQHS_ps);
+
+	printf("lowest_common_SPD_caslat = %u\n",
+	       plcd_dimm_params->lowest_common_SPD_caslat);
+	printf("highest_common_derated_caslat = %u\n",
+	       plcd_dimm_params->highest_common_derated_caslat);
+	printf("additive_latency = %u\n", plcd_dimm_params->additive_latency);
+
+	printf("ndimms_present = %u\n", plcd_dimm_params->ndimms_present);
+	printf("all_DIMMs_burst_lengths_bitmask = %02X\n",
+	       plcd_dimm_params->all_DIMMs_burst_lengths_bitmask);
+	printf("all_DIMMs_registered = %u\n",
+	       plcd_dimm_params->all_DIMMs_registered);
+	printf("all_DIMMs_unbuffered = %u\n",
+	       plcd_dimm_params->all_DIMMs_unbuffered);
+	printf("all_DIMMs_ECC_capable = %u\n",
+	       plcd_dimm_params->all_DIMMs_ECC_capable);
+
+	printf("total_mem = %llu (%llu megabytes)\n",
+	       plcd_dimm_params->total_mem,
+	       plcd_dimm_params->total_mem / 0x100000);
+	printf("base_address = %llu (%llu megabytes)\n",
+	       plcd_dimm_params->base_address,
+	       plcd_dimm_params->base_address / 0x100000);
+}
+
+#undef OPTIONS_UNIT
+#define OPTIONS_UNIT(x) {#x, offsetof(memctl_options_t, x)}
+
+static void fsl_ddr_options_edit(fsl_ddr_info_t *pinfo,
+			   unsigned int ctl_num,
+			   const char *optname_str,
+			   const char *value_str)
+{
+	memctl_options_t *p = &(pinfo->memctl_opts[ctl_num]);
+	/*
+	 * This array all on the stack and *computed* each time this
+	 * function is rung.
+	 */
+	static const options_strings_t options[] = {
+		{"cs0_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[0].odt_rd_cfg)},
+		{"cs0_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[0].odt_wr_cfg)},
+		{"cs0_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[0].odt_rtt_norm)},
+		{"cs0_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[0].odt_rtt_wr)},
+		{"cs1_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[1].odt_rd_cfg)},
+		{"cs1_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[1].odt_wr_cfg)},
+		{"cs1_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[1].odt_rtt_norm)},
+		{"cs1_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[1].odt_rtt_wr)},
+		{"cs2_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[2].odt_rd_cfg)},
+		{"cs2_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[2].odt_wr_cfg)},
+		{"cs2_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[2].odt_rtt_norm)},
+		{"cs2_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[2].odt_rtt_wr)},
+		{"cs3_odt_rd_cfg", offsetof(memctl_options_t, cs_local_opts[3].odt_rd_cfg)},
+		{"cs3_odt_wr_cfg", offsetof(memctl_options_t, cs_local_opts[3].odt_wr_cfg)},
+		{"cs3_odt_rtt_norm", offsetof(memctl_options_t, cs_local_opts[3].odt_rtt_norm)},
+		{"cs3_odt_rtt_wr", offsetof(memctl_options_t, cs_local_opts[3].odt_rtt_wr)},
+		OPTIONS_UNIT(memctl_interleaving),
+		OPTIONS_UNIT(memctl_interleaving_mode),
+		OPTIONS_UNIT(ba_intlv_ctl),
+		OPTIONS_UNIT(ECC_mode),
+		OPTIONS_UNIT(ECC_init_using_memctl),
+		OPTIONS_UNIT(DQS_config),
+		OPTIONS_UNIT(self_refresh_in_sleep),
+		OPTIONS_UNIT(dynamic_power),
+		OPTIONS_UNIT(data_bus_width),
+		OPTIONS_UNIT(burst_length),
+		OPTIONS_UNIT(cas_latency_override),
+		OPTIONS_UNIT(cas_latency_override_value),
+		OPTIONS_UNIT(use_derated_caslat),
+		OPTIONS_UNIT(additive_latency_override),
+		OPTIONS_UNIT(additive_latency_override_value),
+		OPTIONS_UNIT(clk_adjust),
+		OPTIONS_UNIT(cpo_override),
+		OPTIONS_UNIT(write_data_delay),
+		OPTIONS_UNIT(half_strength_driver_enable),
+
+		/*
+		 * These can probably be changed to 2T_EN and 3T_EN
+		 * (using a leading numerical character) without problem
+		 */
+		OPTIONS_UNIT(twoT_en),
+		OPTIONS_UNIT(threeT_en),
+		OPTIONS_UNIT(ap_en),
+		OPTIONS_UNIT(bstopre),
+		OPTIONS_UNIT(wrlvl_override),
+		OPTIONS_UNIT(wrlvl_sample),
+		OPTIONS_UNIT(wrlvl_start),
+		OPTIONS_UNIT(rcw_override),
+		OPTIONS_UNIT(rcw_1),
+		OPTIONS_UNIT(rcw_2),
+		OPTIONS_UNIT(tCKE_clock_pulse_width_ps),
+		OPTIONS_UNIT(tFAW_window_four_activates_ps),
+	};
+
+	static const unsigned int nopts = ARRAY_SIZE(options);
+
+	if (handle_uint_option_table(options, nopts, (u32) p,
+					optname_str, value_str))
+		return;
+
+	printf("couldn't find option string %s\n", optname_str);
+}
+
+static void print_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr)
+{
+	unsigned int i;
+
+	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+		printf("cs%u_bnds           = %08X\n", i, ddr->cs[i].bnds);
+		printf("cs%u_config         = %08X\n", i, ddr->cs[i].config);
+		printf("cs%u_config_2       = %08X\n", i, ddr->cs[i].config_2);
+	}
+
+	printf("timing_cfg_3       = %08X\n", ddr->timing_cfg_3);
+	printf("timing_cfg_0       = %08X\n", ddr->timing_cfg_0);
+	printf("timing_cfg_1       = %08X\n", ddr->timing_cfg_1);
+	printf("timing_cfg_2       = %08X\n", ddr->timing_cfg_2);
+	printf("ddr_sdram_cfg      = %08X\n", ddr->ddr_sdram_cfg);
+	printf("ddr_sdram_cfg_2    = %08X\n", ddr->ddr_sdram_cfg_2);
+	printf("ddr_sdram_mode     = %08X\n", ddr->ddr_sdram_mode);
+	printf("ddr_sdram_mode_2   = %08X\n", ddr->ddr_sdram_mode_2);
+	printf("ddr_sdram_mode_3   = %08X\n", ddr->ddr_sdram_mode_3);
+	printf("ddr_sdram_mode_4   = %08X\n", ddr->ddr_sdram_mode_4);
+	printf("ddr_sdram_mode_5   = %08X\n", ddr->ddr_sdram_mode_5);
+	printf("ddr_sdram_mode_6   = %08X\n", ddr->ddr_sdram_mode_6);
+	printf("ddr_sdram_mode_7   = %08X\n", ddr->ddr_sdram_mode_7);
+	printf("ddr_sdram_mode_8   = %08X\n", ddr->ddr_sdram_mode_8);
+	printf("ddr_sdram_interval = %08X\n", ddr->ddr_sdram_interval);
+	printf("ddr_data_init      = %08X\n", ddr->ddr_data_init);
+	printf("ddr_sdram_clk_cntl = %08X\n", ddr->ddr_sdram_clk_cntl);
+	printf("ddr_init_addr      = %08X\n", ddr->ddr_init_addr);
+	printf("ddr_init_ext_addr  = %08X\n", ddr->ddr_init_ext_addr);
+	printf("timing_cfg_4       = %08X\n", ddr->timing_cfg_4);
+	printf("timing_cfg_5       = %08X\n", ddr->timing_cfg_5);
+	printf("ddr_zq_cntl        = %08X\n", ddr->ddr_zq_cntl);
+	printf("ddr_wrlvl_cntl     = %08X\n", ddr->ddr_wrlvl_cntl);
+	printf("ddr_sr_cntr        = %08X\n", ddr->ddr_sr_cntr);
+	printf("ddr_sdram_rcw_1    = %08X\n", ddr->ddr_sdram_rcw_1);
+	printf("ddr_sdram_rcw_2    = %08X\n", ddr->ddr_sdram_rcw_2);
+	printf("ddr_cdr1           = %08X\n", ddr->ddr_cdr1);
+	printf("ddr_cdr2           = %08X\n", ddr->ddr_cdr2);
+	printf("err_disable        = %08X\n", ddr->err_disable);
+	printf("err_int_en         = %08X\n", ddr->err_int_en);
+	for (i = 0; i < 18; i++)
+		printf("debug_%02d	= %08X\n", i+1, ddr->debug[i]);
+}
+
+static void fsl_ddr_regs_edit(fsl_ddr_info_t *pinfo,
+			unsigned int ctrl_num,
+			const char *regname,
+			unsigned int value)
+{
+	unsigned int i;
+	fsl_ddr_cfg_regs_t *ddr;
+	char buf[20];
+
+	debug("fsl_ddr_regs_edit: ctrl_num = %u, "
+		"regname = %s, value = 0x%08X\n",
+		ctrl_num, regname, value);
+	if (ctrl_num > CONFIG_NUM_DDR_CONTROLLERS)
+		return;
+
+	/* FIXME: Change this into struct like the other editing functions */
+	ddr = &(pinfo->fsl_ddr_config_reg[ctrl_num]);
+
+	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+		sprintf(buf, "cs%u_bnds", i);
+		if (strcmp(buf, regname) == 0) {
+			ddr->cs[i].bnds = value;
+			return;
+		}
+
+		sprintf(buf, "cs%u_config", i);
+		if (strcmp(buf, regname) == 0) {
+			ddr->cs[i].config = value;
+			return;
+		}
+
+		sprintf(buf, "cs%u_config_2", i);
+		if (strcmp(buf, regname) == 0) {
+			ddr->cs[i].config_2 = value;
+			return;
+		}
+	}
+
+	if (strcmp("timing_cfg_3", regname) == 0) {
+		ddr->timing_cfg_3 = value;
+		return;
+	}
+
+	if (strcmp("timing_cfg_0", regname) == 0) {
+		ddr->timing_cfg_0 = value;
+		return;
+	}
+
+	if (strcmp("timing_cfg_1", regname) == 0) {
+		ddr->timing_cfg_1 = value;
+		return;
+	}
+
+	if (strcmp("timing_cfg_2", regname) == 0) {
+		ddr->timing_cfg_2 = value;
+		return;
+	}
+
+	if (strcmp("ddr_sdram_cfg", regname) == 0) {
+		ddr->ddr_sdram_cfg = value;
+		return;
+	}
+
+	if (strcmp("ddr_sdram_cfg_2", regname) == 0) {
+		ddr->ddr_sdram_cfg_2 = value;
+		return;
+	}
+
+	if (strcmp("ddr_sdram_mode", regname) == 0) {
+		ddr->ddr_sdram_mode = value;
+		return;
+	}
+
+	if (strcmp("ddr_sdram_mode_2", regname) == 0) {
+		ddr->ddr_sdram_mode_2 = value;
+		return;
+	}
+
+	if (strcmp("ddr_sdram_mode_3", regname) == 0) {
+		ddr->ddr_sdram_mode_3 = value;
+		return;
+	}
+
+	if (strcmp("ddr_sdram_mode_4", regname) == 0) {
+		ddr->ddr_sdram_mode_4 = value;
+		return;
+	}
+
+	if (strcmp("ddr_sdram_mode_5", regname) == 0) {
+		ddr->ddr_sdram_mode_5 = value;
+		return;
+	}
+
+	if (strcmp("ddr_sdram_mode_6", regname) == 0) {
+		ddr->ddr_sdram_mode_6 = value;
+		return;
+	}
+
+	if (strcmp("ddr_sdram_mode_7", regname) == 0) {
+		ddr->ddr_sdram_mode_7 = value;
+		return;
+	}
+
+	if (strcmp("ddr_sdram_mode_8", regname) == 0) {
+		ddr->ddr_sdram_mode_8 = value;
+		return;
+	}
+
+	if (strcmp("ddr_sdram_interval", regname) == 0) {
+		ddr->ddr_sdram_interval = value;
+		return;
+	}
+
+	if (strcmp("ddr_data_init", regname) == 0) {
+		ddr->ddr_data_init = value;
+		return;
+	}
+
+	if (strcmp("ddr_sdram_clk_cntl", regname) == 0) {
+		ddr->ddr_sdram_clk_cntl = value;
+		return;
+	}
+
+	if (strcmp("ddr_init_addr", regname) == 0) {
+		ddr->ddr_init_addr = value;
+		return;
+	}
+
+	if (strcmp("ddr_init_ext_addr", regname) == 0) {
+		ddr->ddr_init_ext_addr = value;
+		return;
+	}
+
+	if (strcmp("timing_cfg_4", regname) == 0) {
+		ddr->timing_cfg_4 = value;
+		return;
+	}
+
+	if (strcmp("timing_cfg_5", regname) == 0) {
+		ddr->timing_cfg_5 = value;
+		return;
+	}
+
+	if (strcmp("ddr_zq_cntl", regname) == 0) {
+		ddr->ddr_zq_cntl = value;
+		return;
+	}
+
+	if (strcmp("ddr_wrlvl_cntl", regname) == 0) {
+		ddr->ddr_wrlvl_cntl = value;
+		return;
+	}
+
+	if (strcmp("ddr_sr_cntr", regname) == 0) {
+		ddr->ddr_sr_cntr = value;
+		return;
+	}
+
+	if (strcmp("ddr_sdram_rcw_1", regname) == 0) {
+		ddr->ddr_sdram_rcw_1 = value;
+		return;
+	}
+
+	if (strcmp("ddr_sdram_rcw_2", regname) == 0) {
+		ddr->ddr_sdram_rcw_2 = value;
+		return;
+	}
+
+	if (strcmp("ddr_cdr1", regname) == 0) {
+		ddr->ddr_cdr1 = value;
+		return;
+	}
+
+	if (strcmp("ddr_cdr2", regname) == 0) {
+		ddr->ddr_cdr2 = value;
+		return;
+	}
+
+	if (strcmp("err_disable", regname) == 0) {
+		ddr->err_disable = value;
+		return;
+	}
+
+	if (strcmp("err_int_en", regname) == 0) {
+		ddr->err_int_en = value;
+		return;
+	}
+
+	for (i = 0; i < 18; i++) {
+		sprintf(buf, "debug_%u", i + 1);
+		if (strcmp(buf, regname) == 0) {
+			ddr->debug[i] = value;
+			return;
+		}
+	}
+}
+
+static void print_memctl_options(const memctl_options_t *popts)
+{
+	int i;
+	for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
+		printf("cs%d_odt_rd_cfg = %u\n", i, popts->cs_local_opts[i].odt_rd_cfg);
+		printf("cs%d_odt_wr_cfg = %u\n", i, popts->cs_local_opts[i].odt_wr_cfg);
+#if defined(CONFIG_FSL_DDR3)
+		printf("cs%d_odt_rtt_norm = %u\n", i, popts->cs_local_opts[i].odt_rtt_norm);
+		printf("cs%d_odt_rtt_wr = %u\n", i, popts->cs_local_opts[i].odt_rtt_wr);
+#endif
+	}
+	/* Special configurations for chip select */
+	printf("memctl_interleaving = %u\n", popts->memctl_interleaving);
+	printf("memctl_interleaving_mode = %u\n",
+	       popts->memctl_interleaving_mode);
+	printf("ba_intlv_ctl = 0x%02X\n", popts->ba_intlv_ctl);
+
+	printf("ECC_mode = %u\n", popts->ECC_mode);	 /* Use ECC? */
+
+	/* Initialize ECC using memory controller? */
+	printf("ECC_init_using_memctl = %u\n", popts->ECC_init_using_memctl);
+
+	/* Use DQS? maybe only with DDR2? */
+	printf("DQS_config = %u\n", popts->DQS_config);
+
+	/* SREN - self-refresh during sleep */
+	printf("self_refresh_in_sleep = %u\n", popts->self_refresh_in_sleep);
+
+	/* DYN_PWR */
+	printf("dynamic_power = %u\n", popts->dynamic_power);
+
+	/* memory data width to use (16-bit, 32-bit, 64-bit) */
+	printf("data_bus_width = %u\n", popts->data_bus_width);
+
+	/* 4, 8 */
+	printf("burst_length = %u\n", popts->burst_length);
+
+	/* Global Timing Parameters */
+	printf("cas_latency_override = %u\n", popts->cas_latency_override);
+	printf("cas_latency_override_value = %u\n",
+	       popts->cas_latency_override_value);
+	printf("use_derated_caslat = %u\n", popts->use_derated_caslat);
+	printf("additive_latency_override = %u\n",
+	       popts->additive_latency_override);
+	printf("additive_latency_override_value = %u\n",
+	       popts->additive_latency_override_value);
+	printf("clk_adjust = %u\n", popts->clk_adjust);
+	printf("cpo_override = %u\n", popts->cpo_override);
+	/* DQS adjust */
+	printf("write_data_delay = %u\n", popts->write_data_delay);
+	printf("half_strength_driver_enable = %u\n",
+	       popts->half_strength_driver_enable);
+	printf("twoT_en = %u\n", popts->twoT_en);
+	printf("threeT_en = %u\n", popts->threeT_en);
+	printf("ap_en = %u\n", popts->ap_en);
+	printf("bstopre = %u\n", popts->bstopre);
+	/* wrlvl */
+	printf("wrlvl_override = %u\n", popts->wrlvl_override);
+	printf("wrlvl_sample = %u\n", popts->wrlvl_sample);
+	printf("wrlvl_start = %u\n", popts->wrlvl_start);
+	/* rcw */
+	printf("rcw_override = %u\n", popts->rcw_override);
+	printf("rcw_1 = 0x%08x\n", popts->rcw_1);
+	printf("rcw_2 = 0x%08x\n", popts->rcw_2);
+	/* tCKE */
+	printf("tCKE_clock_pulse_width_ps = %u\n",
+	       popts->tCKE_clock_pulse_width_ps);
+	/* tFAW --  FOUR_ACT */
+	printf("tFAW_window_four_activates_ps = %u\n",
+	       popts->tFAW_window_four_activates_ps);
+}
+
+#ifdef CONFIG_FSL_DDR1
+void ddr1_spd_dump(const ddr1_spd_eeprom_t *spd)
+{
+	unsigned int i;
+
+	printf("%-3d    : %02x %s\n",
+	       0, spd->info_size,
+	       " spd->info_size,   *  0 # bytes written into serial memory *");
+	printf("%-3d    : %02x %s\n",
+	       1, spd->chip_size,
+	       " spd->chip_size,   *  1 Total # bytes of SPD memory device *");
+	printf("%-3d    : %02x %s\n",
+	       2, spd->mem_type,
+	       " spd->mem_type,    *  2 Fundamental memory type *");
+	printf("%-3d    : %02x %s\n",
+	       3, spd->nrow_addr,
+	       " spd->nrow_addr,   *  3 # of Row Addresses on this assembly *");
+	printf("%-3d    : %02x %s\n",
+	       4, spd->ncol_addr,
+	       " spd->ncol_addr,   *  4 # of Column Addrs on this assembly *");
+	printf("%-3d    : %02x %s\n",
+	       5, spd->nrows,
+	       " spd->nrows        *  5 # of DIMM Banks *");
+	printf("%-3d    : %02x %s\n",
+	       6, spd->dataw_lsb,
+	       " spd->dataw_lsb,   *  6 Data Width lsb of this assembly *");
+	printf("%-3d    : %02x %s\n",
+	       7, spd->dataw_msb,
+	       " spd->dataw_msb,   *  7 Data Width msb of this assembly *");
+	printf("%-3d    : %02x %s\n",
+	       8, spd->voltage,
+	       " spd->voltage,     *  8 Voltage intf std of this assembly *");
+	printf("%-3d    : %02x %s\n",
+	       9, spd->clk_cycle,
+	       " spd->clk_cycle,   *  9 SDRAM Cycle time at CL=X *");
+	printf("%-3d    : %02x %s\n",
+	       10, spd->clk_access,
+	       " spd->clk_access,  * 10 SDRAM Access from Clock at CL=X *");
+	printf("%-3d    : %02x %s\n",
+	       11, spd->config,
+	       " spd->config,      * 11 DIMM Configuration type *");
+	printf("%-3d    : %02x %s\n",
+	       12, spd->refresh,
+	       " spd->refresh,     * 12 Refresh Rate/Type *");
+	printf("%-3d    : %02x %s\n",
+	       13, spd->primw,
+	       " spd->primw,       * 13 Primary SDRAM Width *");
+	printf("%-3d    : %02x %s\n",
+	       14, spd->ecw,
+	       " spd->ecw,         * 14 Error Checking SDRAM width *");
+	printf("%-3d    : %02x %s\n",
+	       15, spd->min_delay,
+	       " spd->min_delay,   * 15 Back to Back Random Access *");
+	printf("%-3d    : %02x %s\n",
+	       16, spd->burstl,
+	       " spd->burstl,      * 16 Burst Lengths Supported *");
+	printf("%-3d    : %02x %s\n",
+	       17, spd->nbanks,
+	       " spd->nbanks,      * 17 # of Banks on Each SDRAM Device *");
+	printf("%-3d    : %02x %s\n",
+	       18, spd->cas_lat,
+	       " spd->cas_lat,     * 18 CAS# Latencies Supported *");
+	printf("%-3d    : %02x %s\n",
+	       19, spd->cs_lat,
+	       " spd->cs_lat,      * 19 Chip Select Latency *");
+	printf("%-3d    : %02x %s\n",
+	       20, spd->write_lat,
+	       " spd->write_lat,   * 20 Write Latency/Recovery *");
+	printf("%-3d    : %02x %s\n",
+	       21, spd->mod_attr,
+	       " spd->mod_attr,    * 21 SDRAM Module Attributes *");
+	printf("%-3d    : %02x %s\n",
+	       22, spd->dev_attr,
+	       " spd->dev_attr,    * 22 SDRAM Device Attributes *");
+	printf("%-3d    : %02x %s\n",
+	       23, spd->clk_cycle2,
+	       " spd->clk_cycle2,  * 23 Min SDRAM Cycle time at CL=X-1 *");
+	printf("%-3d    : %02x %s\n",
+	       24, spd->clk_access2,
+	       " spd->clk_access2, * 24 SDRAM Access from Clock at CL=X-1 *");
+	printf("%-3d    : %02x %s\n",
+	       25, spd->clk_cycle3,
+	       " spd->clk_cycle3,  * 25 Min SDRAM Cycle time at CL=X-2 *");
+	printf("%-3d    : %02x %s\n",
+	       26, spd->clk_access3,
+	       " spd->clk_access3, * 26 Max Access from Clock at CL=X-2 *");
+	printf("%-3d    : %02x %s\n",
+	       27, spd->trp,
+	       " spd->trp,         * 27 Min Row Precharge Time (tRP)*");
+	printf("%-3d    : %02x %s\n",
+	       28, spd->trrd,
+	       " spd->trrd,        * 28 Min Row Active to Row Active (tRRD) *");
+	printf("%-3d    : %02x %s\n",
+	       29, spd->trcd,
+	       " spd->trcd,        * 29 Min RAS to CAS Delay (tRCD) *");
+	printf("%-3d    : %02x %s\n",
+	       30, spd->tras,
+	       " spd->tras,        * 30 Minimum RAS Pulse Width (tRAS) *");
+	printf("%-3d    : %02x %s\n",
+	       31, spd->bank_dens,
+	       " spd->bank_dens,   * 31 Density of each bank on module *");
+	printf("%-3d    : %02x %s\n",
+	       32, spd->ca_setup,
+	       " spd->ca_setup,    * 32 Cmd + Addr signal input setup time *");
+	printf("%-3d    : %02x %s\n",
+	       33, spd->ca_hold,
+	       " spd->ca_hold,     * 33 Cmd and Addr signal input hold time *");
+	printf("%-3d    : %02x %s\n",
+	       34, spd->data_setup,
+	       " spd->data_setup,  * 34 Data signal input setup time *");
+	printf("%-3d    : %02x %s\n",
+	       35, spd->data_hold,
+	       " spd->data_hold,   * 35 Data signal input hold time *");
+	printf("%-3d    : %02x %s\n",
+	       36, spd->res_36_40[0],
+	       " spd->res_36_40[0], * 36 Reserved / tWR *");
+	printf("%-3d    : %02x %s\n",
+	       37, spd->res_36_40[1],
+	       " spd->res_36_40[1], * 37 Reserved / tWTR *");
+	printf("%-3d    : %02x %s\n",
+	       38, spd->res_36_40[2],
+	       " spd->res_36_40[2], * 38 Reserved / tRTP *");
+	printf("%-3d    : %02x %s\n",
+	       39, spd->res_36_40[3],
+	       " spd->res_36_40[3], * 39 Reserved / mem_probe *");
+	printf("%-3d    : %02x %s\n",
+	       40, spd->res_36_40[4],
+	       " spd->res_36_40[4], * 40 Reserved / trc,trfc extensions *");
+	printf("%-3d    : %02x %s\n",
+	       41, spd->trc,
+	       " spd->trc,         * 41 Min Active to Auto refresh time tRC *");
+	printf("%-3d    : %02x %s\n",
+	       42, spd->trfc,
+	       " spd->trfc,        * 42 Min Auto to Active period tRFC *");
+	printf("%-3d    : %02x %s\n",
+	       43, spd->tckmax,
+	       " spd->tckmax,      * 43 Max device cycle time tCKmax *");
+	printf("%-3d    : %02x %s\n",
+	       44, spd->tdqsq,
+	       " spd->tdqsq,       * 44 Max DQS to DQ skew *");
+	printf("%-3d    : %02x %s\n",
+	       45, spd->tqhs,
+	       " spd->tqhs,        * 45 Max Read DataHold skew tQHS *");
+	printf("%-3d    : %02x %s\n",
+	       46, spd->res_46,
+	       " spd->res_46,  * 46 Reserved/ PLL Relock time *");
+	printf("%-3d    : %02x %s\n",
+	       47, spd->dimm_height,
+	       " spd->dimm_height  * 47 SDRAM DIMM Height *");
+
+	printf("%-3d-%3d: ",  48, 61);
+
+	for (i = 0; i < 14; i++)
+		printf("%02x", spd->res_48_61[i]);
+
+	printf(" * 48-61 IDD in SPD and Reserved space *\n");
+
+	printf("%-3d    : %02x %s\n",
+	       62, spd->spd_rev,
+	       " spd->spd_rev,     * 62 SPD Data Revision Code *");
+	printf("%-3d    : %02x %s\n",
+	       63, spd->cksum,
+	       " spd->cksum,       * 63 Checksum for bytes 0-62 *");
+	printf("%-3d-%3d: ",  64, 71);
+
+	for (i = 0; i < 8; i++)
+		printf("%02x", spd->mid[i]);
+
+	printf("* 64 Mfr's JEDEC ID code per JEP-108E *\n");
+	printf("%-3d    : %02x %s\n",
+	       72, spd->mloc,
+	       " spd->mloc,        * 72 Manufacturing Location *");
+
+	printf("%-3d-%3d: >>",  73, 90);
+
+	for (i = 0; i < 18; i++)
+		printf("%c", spd->mpart[i]);
+
+	printf("<<* 73 Manufacturer's Part Number *\n");
+
+	printf("%-3d-%3d: %02x %02x %s\n",
+	       91, 92, spd->rev[0], spd->rev[1],
+	       "* 91 Revision Code *");
+	printf("%-3d-%3d: %02x %02x %s\n",
+	       93, 94, spd->mdate[0], spd->mdate[1],
+	       "* 93 Manufacturing Date *");
+	printf("%-3d-%3d: ", 95, 98);
+
+	for (i = 0; i < 4; i++)
+		printf("%02x", spd->sernum[i]);
+
+	printf("* 95 Assembly Serial Number *\n");
+
+	printf("%-3d-%3d: ", 99, 127);
+
+	for (i = 0; i < 27; i++)
+		printf("%02x", spd->mspec[i]);
+
+	printf("* 99 Manufacturer Specific Data *\n");
+}
+#endif
+
+#ifdef CONFIG_FSL_DDR2
+void ddr2_spd_dump(const ddr2_spd_eeprom_t *spd)
+{
+	unsigned int i;
+
+	printf("%-3d    : %02x %s\n",
+	       0, spd->info_size,
+	       " spd->info_size,   *  0 # bytes written into serial memory *");
+	printf("%-3d    : %02x %s\n",
+	       1, spd->chip_size,
+	       " spd->chip_size,   *  1 Total # bytes of SPD memory device *");
+	printf("%-3d    : %02x %s\n",
+	       2, spd->mem_type,
+	       " spd->mem_type,    *  2 Fundamental memory type *");
+	printf("%-3d    : %02x %s\n",
+	       3, spd->nrow_addr,
+	       " spd->nrow_addr,   *  3 # of Row Addresses on this assembly *");
+	printf("%-3d    : %02x %s\n",
+	       4, spd->ncol_addr,
+	       " spd->ncol_addr,   *  4 # of Column Addrs on this assembly *");
+	printf("%-3d    : %02x %s\n",
+	       5, spd->mod_ranks,
+	       " spd->mod_ranks    *  5 # of Module Rows on this assembly *");
+	printf("%-3d    : %02x %s\n",
+	       6, spd->dataw,
+	       " spd->dataw,       *  6 Data Width of this assembly *");
+	printf("%-3d    : %02x %s\n",
+	       7, spd->res_7,
+	       " spd->res_7,       *  7 Reserved *");
+	printf("%-3d    : %02x %s\n",
+	       8, spd->voltage,
+	       " spd->voltage,     *  8 Voltage intf std of this assembly *");
+	printf("%-3d    : %02x %s\n",
+	       9, spd->clk_cycle,
+	       " spd->clk_cycle,   *  9 SDRAM Cycle time at CL=X *");
+	printf("%-3d    : %02x %s\n",
+	       10, spd->clk_access,
+	       " spd->clk_access,  * 10 SDRAM Access from Clock at CL=X *");
+	printf("%-3d    : %02x %s\n",
+	       11, spd->config,
+	       " spd->config,      * 11 DIMM Configuration type *");
+	printf("%-3d    : %02x %s\n",
+	       12, spd->refresh,
+	       " spd->refresh,     * 12 Refresh Rate/Type *");
+	printf("%-3d    : %02x %s\n",
+	       13, spd->primw,
+	       " spd->primw,       * 13 Primary SDRAM Width *");
+	printf("%-3d    : %02x %s\n",
+	       14, spd->ecw,
+	       " spd->ecw,         * 14 Error Checking SDRAM width *");
+	printf("%-3d    : %02x %s\n",
+	       15, spd->res_15,
+	       " spd->res_15,      * 15 Reserved *");
+	printf("%-3d    : %02x %s\n",
+	       16, spd->burstl,
+	       " spd->burstl,      * 16 Burst Lengths Supported *");
+	printf("%-3d    : %02x %s\n",
+	       17, spd->nbanks,
+	       " spd->nbanks,      * 17 # of Banks on Each SDRAM Device *");
+	printf("%-3d    : %02x %s\n",
+	       18, spd->cas_lat,
+	       " spd->cas_lat,     * 18 CAS# Latencies Supported *");
+	printf("%-3d    : %02x %s\n",
+	       19, spd->mech_char,
+	       " spd->mech_char,   * 19 Mechanical Characteristics *");
+	printf("%-3d    : %02x %s\n",
+	       20, spd->dimm_type,
+	       " spd->dimm_type,   * 20 DIMM type *");
+	printf("%-3d    : %02x %s\n",
+	       21, spd->mod_attr,
+	       " spd->mod_attr,    * 21 SDRAM Module Attributes *");
+	printf("%-3d    : %02x %s\n",
+	       22, spd->dev_attr,
+	       " spd->dev_attr,    * 22 SDRAM Device Attributes *");
+	printf("%-3d    : %02x %s\n",
+	       23, spd->clk_cycle2,
+	       " spd->clk_cycle2,  * 23 Min SDRAM Cycle time at CL=X-1 *");
+	printf("%-3d    : %02x %s\n",
+	       24, spd->clk_access2,
+	       " spd->clk_access2, * 24 SDRAM Access from Clock at CL=X-1 *");
+	printf("%-3d    : %02x %s\n",
+	       25, spd->clk_cycle3,
+	       " spd->clk_cycle3,  * 25 Min SDRAM Cycle time at CL=X-2 *");
+	printf("%-3d    : %02x %s\n",
+	       26, spd->clk_access3,
+	       " spd->clk_access3, * 26 Max Access from Clock at CL=X-2 *");
+	printf("%-3d    : %02x %s\n",
+	       27, spd->trp,
+	       " spd->trp,         * 27 Min Row Precharge Time (tRP)*");
+	printf("%-3d    : %02x %s\n",
+	       28, spd->trrd,
+	       " spd->trrd,        * 28 Min Row Active to Row Active (tRRD) *");
+	printf("%-3d    : %02x %s\n",
+	       29, spd->trcd,
+	       " spd->trcd,        * 29 Min RAS to CAS Delay (tRCD) *");
+	printf("%-3d    : %02x %s\n",
+	       30, spd->tras,
+	       " spd->tras,        * 30 Minimum RAS Pulse Width (tRAS) *");
+	printf("%-3d    : %02x %s\n",
+	       31, spd->rank_dens,
+	       " spd->rank_dens,   * 31 Density of each rank on module *");
+	printf("%-3d    : %02x %s\n",
+	       32, spd->ca_setup,
+	       " spd->ca_setup,    * 32 Cmd + Addr signal input setup time *");
+	printf("%-3d    : %02x %s\n",
+	       33, spd->ca_hold,
+	       " spd->ca_hold,     * 33 Cmd and Addr signal input hold time *");
+	printf("%-3d    : %02x %s\n",
+	       34, spd->data_setup,
+	       " spd->data_setup,  * 34 Data signal input setup time *");
+	printf("%-3d    : %02x %s\n",
+	       35, spd->data_hold,
+	       " spd->data_hold,   * 35 Data signal input hold time *");
+	printf("%-3d    : %02x %s\n",
+	       36, spd->twr,
+	       " spd->twr,         * 36 Write Recovery time tWR *");
+	printf("%-3d    : %02x %s\n",
+	       37, spd->twtr,
+	       " spd->twtr,        * 37 Int write to read delay tWTR *");
+	printf("%-3d    : %02x %s\n",
+	       38, spd->trtp,
+	       " spd->trtp,        * 38 Int read to precharge delay tRTP *");
+	printf("%-3d    : %02x %s\n",
+	       39, spd->mem_probe,
+	       " spd->mem_probe,   * 39 Mem analysis probe characteristics *");
+	printf("%-3d    : %02x %s\n",
+	       40, spd->trctrfc_ext,
+	       " spd->trctrfc_ext, * 40 Extensions to trc and trfc *");
+	printf("%-3d    : %02x %s\n",
+	       41, spd->trc,
+	       " spd->trc,         * 41 Min Active to Auto refresh time tRC *");
+	printf("%-3d    : %02x %s\n",
+	       42, spd->trfc,
+	       " spd->trfc,        * 42 Min Auto to Active period tRFC *");
+	printf("%-3d    : %02x %s\n",
+	       43, spd->tckmax,
+	       " spd->tckmax,      * 43 Max device cycle time tCKmax *");
+	printf("%-3d    : %02x %s\n",
+	       44, spd->tdqsq,
+	       " spd->tdqsq,       * 44 Max DQS to DQ skew *");
+	printf("%-3d    : %02x %s\n",
+	       45, spd->tqhs,
+	       " spd->tqhs,        * 45 Max Read DataHold skew tQHS *");
+	printf("%-3d    : %02x %s\n",
+	       46, spd->pll_relock,
+	       " spd->pll_relock,  * 46 PLL Relock time *");
+	printf("%-3d    : %02x %s\n",
+	       47, spd->Tcasemax,
+	       " spd->Tcasemax,    * 47 Tcasemax *");
+	printf("%-3d    : %02x %s\n",
+	       48, spd->psiTAdram,
+	       " spd->psiTAdram,   * 48 Thermal Resistance of DRAM Package "
+	       "from Top (Case) to Ambient (Psi T-A DRAM) *");
+	printf("%-3d    : %02x %s\n",
+	       49, spd->dt0_mode,
+	       " spd->dt0_mode,    * 49 DRAM Case Temperature Rise from "
+	       "Ambient due to Activate-Precharge/Mode Bits "
+	       "(DT0/Mode Bits) *)");
+	printf("%-3d    : %02x %s\n",
+	       50, spd->dt2n_dt2q,
+	       " spd->dt2n_dt2q,   * 50 DRAM Case Temperature Rise from "
+	       "Ambient due to Precharge/Quiet Standby "
+	       "(DT2N/DT2Q) *");
+	printf("%-3d    : %02x %s\n",
+	       51, spd->dt2p,
+	       " spd->dt2p,        * 51 DRAM Case Temperature Rise from "
+	       "Ambient due to Precharge Power-Down (DT2P) *");
+	printf("%-3d    : %02x %s\n",
+	       52, spd->dt3n,
+	       " spd->dt3n,        * 52 DRAM Case Temperature Rise from "
+	       "Ambient due to Active Standby (DT3N) *");
+	printf("%-3d    : %02x %s\n",
+	       53, spd->dt3pfast,
+	       " spd->dt3pfast,    * 53 DRAM Case Temperature Rise from "
+	       "Ambient due to Active Power-Down with Fast PDN Exit "
+	       "(DT3Pfast) *");
+	printf("%-3d    : %02x %s\n",
+	       54, spd->dt3pslow,
+	       " spd->dt3pslow,    * 54 DRAM Case Temperature Rise from "
+	       "Ambient due to Active Power-Down with Slow PDN Exit "
+	       "(DT3Pslow) *");
+	printf("%-3d    : %02x %s\n",
+	       55, spd->dt4r_dt4r4w,
+	       " spd->dt4r_dt4r4w, * 55 DRAM Case Temperature Rise from "
+	       "Ambient due to Page Open Burst Read/DT4R4W Mode Bit "
+	       "(DT4R/DT4R4W Mode Bit) *");
+	printf("%-3d    : %02x %s\n",
+	       56, spd->dt5b,
+	       " spd->dt5b,        * 56 DRAM Case Temperature Rise from "
+	       "Ambient due to Burst Refresh (DT5B) *");
+	printf("%-3d    : %02x %s\n",
+	       57, spd->dt7,
+	       " spd->dt7,         * 57 DRAM Case Temperature Rise from "
+	       "Ambient due to Bank Interleave Reads with "
+	       "Auto-Precharge (DT7) *");
+	printf("%-3d    : %02x %s\n",
+	       58, spd->psiTApll,
+	       " spd->psiTApll,    * 58 Thermal Resistance of PLL Package form"
+	       " Top (Case) to Ambient (Psi T-A PLL) *");
+	printf("%-3d    : %02x %s\n",
+	       59, spd->psiTAreg,
+	       " spd->psiTAreg,    * 59 Thermal Reisitance of Register Package"
+	       " from Top (Case) to Ambient (Psi T-A Register) *");
+	printf("%-3d    : %02x %s\n",
+	       60, spd->dtpllactive,
+	       " spd->dtpllactive, * 60 PLL Case Temperature Rise from "
+	       "Ambient due to PLL Active (DT PLL Active) *");
+	printf("%-3d    : %02x %s\n",
+	       61, spd->dtregact,
+	       " spd->dtregact,    "
+	       "* 61 Register Case Temperature Rise from Ambient due to "
+	       "Register Active/Mode Bit (DT Register Active/Mode Bit) *");
+	printf("%-3d    : %02x %s\n",
+	       62, spd->spd_rev,
+	       " spd->spd_rev,     * 62 SPD Data Revision Code *");
+	printf("%-3d    : %02x %s\n",
+	       63, spd->cksum,
+	       " spd->cksum,       * 63 Checksum for bytes 0-62 *");
+
+	printf("%-3d-%3d: ",  64, 71);
+
+	for (i = 0; i < 8; i++)
+		printf("%02x", spd->mid[i]);
+
+	printf("* 64 Mfr's JEDEC ID code per JEP-108E *\n");
+
+	printf("%-3d    : %02x %s\n",
+	       72, spd->mloc,
+	       " spd->mloc,        * 72 Manufacturing Location *");
+
+	printf("%-3d-%3d: >>",  73, 90);
+	for (i = 0; i < 18; i++)
+		printf("%c", spd->mpart[i]);
+
+
+	printf("<<* 73 Manufacturer's Part Number *\n");
+
+	printf("%-3d-%3d: %02x %02x %s\n",
+	       91, 92, spd->rev[0], spd->rev[1],
+	       "* 91 Revision Code *");
+	printf("%-3d-%3d: %02x %02x %s\n",
+	       93, 94, spd->mdate[0], spd->mdate[1],
+	       "* 93 Manufacturing Date *");
+	printf("%-3d-%3d: ", 95, 98);
+
+	for (i = 0; i < 4; i++)
+		printf("%02x", spd->sernum[i]);
+
+	printf("* 95 Assembly Serial Number *\n");
+
+	printf("%-3d-%3d: ", 99, 127);
+	for (i = 0; i < 27; i++)
+		printf("%02x", spd->mspec[i]);
+
+
+	printf("* 99 Manufacturer Specific Data *\n");
+}
+#endif
+
+#ifdef CONFIG_FSL_DDR3
+void ddr3_spd_dump(const ddr3_spd_eeprom_t *spd)
+{
+	unsigned int i;
+
+	/* General Section: Bytes 0-59 */
+
+#define PRINT_NXS(x, y, z) printf("%-3d    : %02x %s\n", x, y, z);
+#define PRINT_NNXXS(n0, n1, x0, x1, s) printf("%-3d-%3d: %02x %02x %s\n", n0, n1, x0, x1, s);
+#define PRINT_SNNlots(x, y, z, arr) do {printf(x); printf("%-3d-%3d: ", y, z); for (i = y; i <= z; i++) printf("%02x", arr[i - y]); } while (0)
+
+	PRINT_NXS(0, spd->info_size_crc, "info_size_crc  bytes written into serial memory, CRC coverage");
+	PRINT_NXS(1, spd->spd_rev,       "spd_rev        SPD Revision");
+	PRINT_NXS(2, spd->mem_type,      "mem_type       Key Byte / DRAM Device Type");
+	PRINT_NXS(3, spd->module_type,   "module_type    Key Byte / Module Type");
+	PRINT_NXS(4, spd->density_banks, "density_banks  SDRAM Density and Banks");
+	PRINT_NXS(5, spd->addressing,    "addressing     SDRAM Addressing");
+	PRINT_NXS(6, spd->module_vdd,    "module_vdd     Module Nominal Voltage, VDD");
+	PRINT_NXS(7, spd->organization,  "organization   Module Organization");
+	PRINT_NXS(8, spd->bus_width,     "bus_width      Module Memory Bus Width");
+	PRINT_NXS(9, spd->ftb_div,       "ftb_div        Fine Timebase (FTB) Dividend / Divisor");
+	PRINT_NXS(10, spd->mtb_dividend,  "mtb_dividend   Medium Timebase (MTB) Dividend");
+	PRINT_NXS(11, spd->mtb_divisor,   "mtb_divisor    Medium Timebase (MTB) Divisor");
+	PRINT_NXS(12, spd->tCK_min,       "tCK_min        SDRAM Minimum Cycle Time");
+	PRINT_NXS(13, spd->res_13,        "res_13         Reserved");
+	PRINT_NXS(14, spd->caslat_lsb,    "caslat_lsb     CAS Latencies Supported, LSB");
+	PRINT_NXS(15, spd->caslat_msb,    "caslat_msb     CAS Latencies Supported, MSB");
+	PRINT_NXS(16, spd->tAA_min,       "tAA_min        Min CAS Latency Time");
+	PRINT_NXS(17, spd->tWR_min,       "tWR_min        Min Write REcovery Time");
+	PRINT_NXS(18, spd->tRCD_min,      "tRCD_min       Min RAS# to CAS# Delay Time");
+	PRINT_NXS(19, spd->tRRD_min,      "tRRD_min       Min Row Active to Row Active Delay Time");
+	PRINT_NXS(20, spd->tRP_min,       "tRP_min        Min Row Precharge Delay Time");
+	PRINT_NXS(21, spd->tRAS_tRC_ext,  "tRAS_tRC_ext   Upper Nibbles for tRAS and tRC");
+	PRINT_NXS(22, spd->tRAS_min_lsb,  "tRAS_min_lsb   Min Active to Precharge Delay Time, LSB");
+	PRINT_NXS(23, spd->tRC_min_lsb,   "tRC_min_lsb    Min Active to Active/Refresh Delay Time, LSB");
+	PRINT_NXS(24, spd->tRFC_min_lsb,  "tRFC_min_lsb   Min Refresh Recovery Delay Time LSB");
+	PRINT_NXS(25, spd->tRFC_min_msb,  "tRFC_min_msb   Min Refresh Recovery Delay Time MSB");
+	PRINT_NXS(26, spd->tWTR_min,      "tWTR_min       Min Internal Write to Read Command Delay Time");
+	PRINT_NXS(27, spd->tRTP_min,      "tRTP_min       Min Internal Read to Precharge Command Delay Time");
+	PRINT_NXS(28, spd->tFAW_msb,      "tFAW_msb       Upper Nibble for tFAW");
+	PRINT_NXS(29, spd->tFAW_min,      "tFAW_min       Min Four Activate Window Delay Time");
+	PRINT_NXS(30, spd->opt_features,  "opt_features   SDRAM Optional Features");
+	PRINT_NXS(31, spd->therm_ref_opt, "therm_ref_opt  SDRAM Thermal and Refresh Opts");
+	PRINT_NXS(32, spd->therm_sensor, "therm_sensor  SDRAM Thermal Sensor");
+	PRINT_NXS(33, spd->device_type, "device_type  SDRAM Device Type");
+
+	printf("%-3d-%3d: ",  34, 59);  /* Reserved, General Section */
+
+	for (i = 34; i <= 59; i++)
+		printf("%02x", spd->res_34_59[i - 34]);
+
+	puts("\n");
+
+	switch (spd->module_type) {
+	case 0x02:  /* UDIMM */
+	case 0x03:  /* SO-DIMM */
+	case 0x04:  /* Micro-DIMM */
+	case 0x06:  /* Mini-UDIMM */
+		PRINT_NXS(60, spd->mod_section.unbuffered.mod_height,    "mod_height  	 (Unbuffered) Module Nominal Height");
+		PRINT_NXS(61, spd->mod_section.unbuffered.mod_thickness, "mod_thickness (Unbuffered) Module Maximum Thickness");
+		PRINT_NXS(62, spd->mod_section.unbuffered.ref_raw_card,  "ref_raw_card	 (Unbuffered) Reference Raw Card Used");
+		PRINT_NXS(63, spd->mod_section.unbuffered.addr_mapping,  "addr_mapping	 (Unbuffered) Address mapping from Edge Connector to DRAM");
+		break;
+	case 0x01:  /* RDIMM */
+	case 0x05:  /* Mini-RDIMM */
+		PRINT_NXS(60, spd->mod_section.registered.mod_height,    "mod_height  	 (Registered) Module Nominal Height");
+		PRINT_NXS(61, spd->mod_section.registered.mod_thickness, "mod_thickness (Registered) Module Maximum Thickness");
+		PRINT_NXS(62, spd->mod_section.registered.ref_raw_card,  "ref_raw_card	 (Registered) Reference Raw Card Used");
+		PRINT_NXS(63, spd->mod_section.registered.modu_attr,  "modu_attr	 (Registered) DIMM Module Attributes");
+		PRINT_NXS(64, spd->mod_section.registered.thermal,  "thermal	 (Registered) Thermal Heat Spreader Solution");
+		PRINT_NXS(65, spd->mod_section.registered.reg_id_lo,  "reg_id_lo	 (Registered) Register Manufacturer ID Code, LSB");
+		PRINT_NXS(66, spd->mod_section.registered.reg_id_hi,  "reg_id_hi	 (Registered) Register Manufacturer ID Code, MSB");
+		PRINT_NXS(67, spd->mod_section.registered.reg_rev,  "reg_rev	 (Registered) Register Revision Number");
+		PRINT_NXS(68, spd->mod_section.registered.reg_type,  "reg_type	 (Registered) Register Type");
+		for (i = 69; i <= 76; i++)
+			printf("%-3d    : %02x rcw[%d]\n", i, spd->mod_section.registered.rcw[i-69], i-69);
+		break;
+	default:
+		printf("%-3d-%3d: ", 60, 116);  /* Module-specific Section, Unsupported Module Type */
+
+		for (i = 60; i <= 116; i++)
+			printf("%02x", spd->mod_section.uc[i - 60]);
+
+		break;
+	}
+
+	/* Unique Module ID: Bytes 117-125 */
+	PRINT_NXS(117, spd->mmid_lsb, "Module MfgID Code LSB - JEP-106");
+	PRINT_NXS(118, spd->mmid_msb, "Module MfgID Code MSB - JEP-106");
+	PRINT_NXS(119, spd->mloc,     "Mfg Location");
+	PRINT_NNXXS(120, 121, spd->mdate[0], spd->mdate[1], "Mfg Date");
+
+	printf("122-125 Module Serial Number\n");
+	printf("%-3d-%3d: ", 122, 125);
+
+	for (i = 122; i <= 125; i++)
+		printf("%02x", spd->sernum[i - 122]);
+
+
+	/* CRC: Bytes 126-127 */
+	PRINT_NNXXS(126, 127, spd->crc[0], spd->crc[1], "SPD CRC");
+
+	/* Other Manufacturer Fields and User Space: Bytes 128-255 */
+
+	printf("128-145 Mfg's Module Part Number\n");
+	printf("%-3d-%3d: ", 128, 145);
+
+	for (i = 128; i <= 145; i++)
+		printf("%02x", spd->mpart[i - 128]);
+
+	puts("\n");
+	PRINT_NNXXS(146, 147, spd->mrev[0], spd->mrev[1], "Module Revision code");
+
+	PRINT_NXS(148, spd->dmid_lsb, "DRAM MfgID Code LSB - JEP-106");
+	PRINT_NXS(149, spd->dmid_msb, "DRAM MfgID Code MSB - JEP-106");
+
+	printf("150-175 Mfg's Specific Data\n");
+	printf("%-3d-%3d: ", 150, 175);
+
+	for (i = 150; i <= 175; i++)
+		printf("%02x", spd->msd[i - 150]);
+
+	puts("\n");
+	printf("176-255 Mfg's Specific Data\n");
+	printf("%-3d-%3d: ", 176, 255);
+	for (i = 176; i <= 255; i++)
+		printf("%02x", spd->cust[i - 176]);
+
+}
+#endif
+
+static __inline__ void generic_spd_dump(const generic_spd_eeprom_t *spd)
+{
+#if defined(CONFIG_FSL_DDR1)
+	ddr1_spd_dump(spd);
+#elif defined(CONFIG_FSL_DDR2)
+	ddr2_spd_dump(spd);
+#elif defined(CONFIG_FSL_DDR3)
+	ddr3_spd_dump(spd);
+#endif
+}
+
+static void fsl_ddr_printinfo(const fsl_ddr_info_t *pinfo,
+			unsigned int ctrl_mask,
+			unsigned int dimm_mask,
+			unsigned int do_mask)
+{
+	unsigned int i, j, retval;
+
+	/* STEP 1:  DIMM SPD data */
+	if (do_mask & STEP_GET_SPD) {
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			if (!(ctrl_mask & (1 << i)))
+				continue;
+
+			/*
+			 * FIXME: find a way to make this generate more
+			 * optimal powerpc code (i.e. rlwimi.)
+			 */
+			for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+				if (!(dimm_mask & (1 << j)))
+					continue;
+
+				printf("SPD info:  Controller=%u "
+						"DIMM=%u\n", i, j);
+				generic_spd_dump(
+					&(pinfo->spd_installed_dimms[i][j]));
+				printf("\n");
+			}
+			printf("\n");
+		}
+		printf("\n");
+	}
+
+	/* STEP 2:  DIMM Parameters */
+	if (do_mask & STEP_COMPUTE_DIMM_PARMS) {
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			if (!(ctrl_mask & (1 << i)))
+				continue;
+			for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+				if (!(dimm_mask & (1 << j)))
+					continue;
+				printf("DIMM parameters:  Controller=%u "
+						"DIMM=%u\n", i, j);
+				print_dimm_parameters(
+					&(pinfo->dimm_params[i][j]));
+				printf("\n");
+			}
+			printf("\n");
+		}
+		printf("\n");
+	}
+
+	/* STEP 3:  Common Parameters */
+	if (do_mask & STEP_COMPUTE_COMMON_PARMS) {
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			if (!(ctrl_mask & (1 << i)))
+				continue;
+			printf("\"lowest common\" DIMM parameters:  "
+					"Controller=%u\n", i);
+			print_lowest_common_dimm_parameters(
+				&pinfo->common_timing_params[i]);
+			printf("\n");
+		}
+		printf("\n");
+	}
+
+	/* STEP 4:  User Configuration Options */
+	if (do_mask & STEP_GATHER_OPTS) {
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			if (!(ctrl_mask & (1 << i)))
+				continue;
+			printf("User Config Options: Controller=%u\n", i);
+			print_memctl_options(&pinfo->memctl_opts[i]);
+			printf("\n");
+		}
+		printf("\n");
+	}
+
+	/* STEP 5:  Address assignment */
+	if (do_mask & STEP_ASSIGN_ADDRESSES) {
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			if (!(ctrl_mask & (1 << i)))
+				continue;
+			for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+				printf("Address Assignment: Controller=%u "
+						"DIMM=%u\n", i, j);
+				printf("Don't have this functionality yet\n");
+			}
+			printf("\n");
+		}
+		printf("\n");
+	}
+
+	/* STEP 6:  computed controller register values */
+	if (do_mask & STEP_COMPUTE_REGS) {
+		for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+			if (!(ctrl_mask & (1 << i)))
+				continue;
+			printf("Computed Register Values: Controller=%u\n", i);
+			print_fsl_memctl_config_regs(
+				&pinfo->fsl_ddr_config_reg[i]);
+			retval = check_fsl_memctl_config_regs(
+				&pinfo->fsl_ddr_config_reg[i]);
+			if (retval) {
+				printf("check_fsl_memctl_config_regs "
+					"result = %u\n", retval);
+			}
+			printf("\n");
+		}
+		printf("\n");
+	}
+}
+
+phys_size_t fsl_ddr_interactive(fsl_ddr_info_t *pinfo)
+{
+	phys_size_t ddrsize;
+	const char *prompt = "FSL DDR>";
+	unsigned int len;
+	char buffer[CONFIG_SYS_CBSIZE];
+	char *argv[CONFIG_SYS_MAXARGS + 1];	/* NULL terminated */
+	int argc;
+	unsigned int next_step = STEP_GET_SPD;
+
+	/*
+	 * The strategy for next_step is that it points to the next
+	 * step in the computation process that needs to be done.
+	 */
+	while (1) {
+		/*
+		 * No need to worry for buffer overflow here in
+		 * this function;  readline() maxes out at CFG_CBSIZE
+		 */
+		len = readline_into_buffer(prompt,  buffer);
+		argc = parse_line(buffer, argv);
+		if (argc == 0)
+			continue;
+
+
+		if (strcmp(argv[0], "help") == 0) {
+
+			/*
+			 * FIXME: For some reason printing this whole
+			 * thing causes the machine to freeze.
+			 * Splitting it into two printfs seems to make
+			 * it work. Does printf() have limits on the
+			 * length of the string?
+			 */
+			printf(
+	"commands:\n"
+	"print      print SPD and intermediate computed data\n"
+	"reset      reboot machine\n"
+	"recompute  reload SPD and options to default and recompute regs\n");
+			printf(
+	"edit       modify spd, parameter, or option\n");
+			printf(
+	"compute    recompute registers from current next_step to end\n"
+	"next_step  shows current next_step\n"
+	"help       this message\n"
+	"go         program the memory controller and continue with u-boot\n");
+			continue;
+		}
+
+		if (strcmp(argv[0], "next_step") == 0) {
+			printf("next_step = 0x%02X (%s)\n",
+			       next_step,
+			       step_to_string(next_step));
+			continue;
+		}
+
+		if (strcmp(argv[0], "edit") == 0) {
+			unsigned int i;
+			unsigned int error = 0;
+			unsigned int step_mask = 0;
+			unsigned int ctlr_mask = 0;
+			unsigned int dimm_mask = 0;
+			char *p_element = NULL;
+			char *p_value = NULL;
+			unsigned int dimm_number_required = 0;
+			unsigned int ctrl_num;
+			unsigned int dimm_num;
+
+			if (argc == 1) {
+				/* Only the element and value must be last */
+				printf("edit <c#> <d#> "
+					"<spd|dimmparms|commonparms|opts|"
+					"addresses|regs> <element> <value>\n");
+				printf("for spd, specify byte number for element\n");
+				continue;
+			}
+
+			for (i = 1; i < argc - 2; i++) {
+				if (strcmp(argv[i], "spd") == 0) {
+					step_mask |= STEP_GET_SPD;
+					dimm_number_required = 1;
+					continue;
+				}
+
+				if (strcmp(argv[i], "dimmparms") == 0) {
+					step_mask |= STEP_COMPUTE_DIMM_PARMS;
+					dimm_number_required = 1;
+					continue;
+				}
+
+				if (strcmp(argv[i], "commonparms") == 0) {
+					step_mask |= STEP_COMPUTE_COMMON_PARMS;
+					continue;
+				}
+
+				if (strcmp(argv[i], "opts") == 0) {
+					step_mask |= STEP_GATHER_OPTS;
+					continue;
+				}
+
+				if (strcmp(argv[i], "addresses") == 0) {
+					step_mask |= STEP_ASSIGN_ADDRESSES;
+					/*  FIXME: not done yet */
+					continue;
+				}
+
+				if (strcmp(argv[i], "regs") == 0) {
+					step_mask |= STEP_COMPUTE_REGS;
+					continue;
+				}
+
+				if (argv[i][0] == 'c') {
+					char c = argv[i][1];
+					if (isdigit(c))
+						ctlr_mask |= 1 << (c - '0');
+					continue;
+				}
+
+				if (argv[i][0] == 'd') {
+					char c = argv[i][1];
+					if (isdigit(c))
+						dimm_mask |= 1 << (c - '0');
+					continue;
+				}
+
+				printf("unknown arg %s\n", argv[i]);
+				step_mask = 0;
+				error = 1;
+				break;
+			}
+
+
+			if (error)
+				continue;
+
+
+			/* Check arguments */
+
+			/* ERROR: If no steps were found */
+			if (step_mask == 0) {
+				printf("Error: No valid steps were specified "
+						"in argument.\n");
+				continue;
+			}
+
+			/* ERROR: If multiple steps were found */
+			if (step_mask & (step_mask - 1)) {
+				printf("Error: Multiple steps specified in "
+						"argument.\n");
+				continue;
+			}
+
+			/* ERROR: Controller not specified */
+			if (ctlr_mask == 0) {
+				printf("Error: controller number not "
+					"specified or no element and "
+					"value specified\n");
+				continue;
+			}
+
+			if (ctlr_mask & (ctlr_mask - 1)) {
+				printf("Error: multiple controllers "
+						"specified, %X\n", ctlr_mask);
+				continue;
+			}
+
+			/* ERROR: DIMM number not specified */
+			if (dimm_number_required && dimm_mask == 0) {
+				printf("Error: DIMM number number not "
+					"specified or no element and "
+					"value specified\n");
+				continue;
+			}
+
+			if (dimm_mask & (dimm_mask - 1)) {
+				printf("Error: multipled DIMMs specified\n");
+				continue;
+			}
+
+			p_element = argv[argc - 2];
+			p_value = argv[argc - 1];
+
+			ctrl_num = __ilog2(ctlr_mask);
+			dimm_num = __ilog2(dimm_mask);
+
+			switch (step_mask) {
+			case STEP_GET_SPD:
+				{
+					unsigned int element_num;
+					unsigned int value;
+
+					element_num = simple_strtoul(p_element,
+								     NULL, 0);
+					value = simple_strtoul(p_value,
+							       NULL, 0);
+					fsl_ddr_spd_edit(pinfo,
+							       ctrl_num,
+							       dimm_num,
+							       element_num,
+							       value);
+					next_step = STEP_COMPUTE_DIMM_PARMS;
+				}
+				break;
+
+			case STEP_COMPUTE_DIMM_PARMS:
+				fsl_ddr_dimm_parameters_edit(
+						 pinfo, ctrl_num, dimm_num,
+						 p_element, p_value);
+				next_step = STEP_COMPUTE_COMMON_PARMS;
+				break;
+
+			case STEP_COMPUTE_COMMON_PARMS:
+				lowest_common_dimm_parameters_edit(pinfo,
+						ctrl_num, p_element, p_value);
+				next_step = STEP_GATHER_OPTS;
+				break;
+
+			case STEP_GATHER_OPTS:
+				fsl_ddr_options_edit(pinfo, ctrl_num,
+							   p_element, p_value);
+				next_step = STEP_ASSIGN_ADDRESSES;
+				break;
+
+			case STEP_ASSIGN_ADDRESSES:
+				printf("editing of address assignment "
+						"not yet implemented\n");
+				break;
+
+			case STEP_COMPUTE_REGS:
+				{
+					unsigned int value;
+
+					value = simple_strtoul(p_value,
+							       NULL, 0);
+					fsl_ddr_regs_edit(pinfo,
+								ctrl_num,
+								p_element,
+								value);
+					next_step = STEP_PROGRAM_REGS;
+				}
+				break;
+
+			default:
+				printf("programming error\n");
+				while (1);
+				break;
+			}
+			continue;
+		}
+
+		if (strcmp(argv[0], "reset") == 0) {
+			/*
+			 * Reboot machine.
+			 * Args don't seem to matter because this
+			 * doesn't return
+			 */
+			do_reset(NULL, 0, 0, NULL);
+		}
+
+		if (strcmp(argv[0], "recompute") == 0) {
+			/*
+			 * Recalculate everything, starting with
+			 * loading SPD EEPROM from DIMMs
+			 */
+			next_step = STEP_GET_SPD;
+			ddrsize = fsl_ddr_compute(pinfo, next_step);
+			/*
+			 * FIXME: There some problems with this.
+			 * For exmaple, what happens if there is
+			 * an error inside fsl_ddr_compute?
+			 */
+			continue;
+		}
+
+		if (strcmp(argv[0], "compute") == 0) {
+			/*
+			 * Compute rest of steps starting at
+			 * the current next_step/
+			 */
+			ddrsize = fsl_ddr_compute(pinfo, next_step);
+			continue;
+		}
+
+		if (strcmp(argv[0], "print") == 0) {
+			unsigned int i;
+			unsigned int error = 0;
+			unsigned int step_mask = 0;
+			unsigned int ctlr_mask = 0;
+			unsigned int dimm_mask = 0;
+
+			if (argc == 1) {
+				printf("print [c<n>] [d<n>] [spd] [dimmparms] "
+				  "[commonparms] [opts] [addresses] [regs]\n");
+				continue;
+			}
+
+			for (i = 1; i < argc; i++) {
+				if (strcmp(argv[i], "spd") == 0) {
+					step_mask |= STEP_GET_SPD;
+					continue;
+				}
+
+				if (strcmp(argv[i], "dimmparms") == 0) {
+					step_mask |= STEP_COMPUTE_DIMM_PARMS;
+					continue;
+				}
+
+				if (strcmp(argv[i], "commonparms") == 0) {
+					step_mask |= STEP_COMPUTE_COMMON_PARMS;
+					continue;
+				}
+
+				if (strcmp(argv[i], "opts") == 0) {
+					step_mask |= STEP_GATHER_OPTS;
+					continue;
+				}
+
+				if (strcmp(argv[i], "addresses") == 0) {
+					step_mask |= STEP_ASSIGN_ADDRESSES;
+					continue;
+				}
+
+				if (strcmp(argv[i], "regs") == 0) {
+					step_mask |= STEP_COMPUTE_REGS;
+					continue;
+				}
+
+				if (argv[i][0] == 'c') {
+					char c = argv[i][1];
+					if (isdigit(c))
+						ctlr_mask |= 1 << (c - '0');
+					continue;
+				}
+
+				if (argv[i][0] == 'd') {
+					char c = argv[i][1];
+					if (isdigit(c))
+						dimm_mask |= 1 << (c - '0');
+					continue;
+				}
+
+				printf("unknown arg %s\n", argv[i]);
+				step_mask = 0;
+				error = 1;
+				break;
+			}
+
+			if (error)
+				continue;
+
+			/* If no particular controller was found, print all */
+			if (ctlr_mask == 0)
+				ctlr_mask = 0xFF;
+
+			/* If no particular dimm was found, print all dimms. */
+			if (dimm_mask == 0)
+				dimm_mask = 0xFF;
+
+			/* If no steps were found, print all steps. */
+			if (step_mask == 0)
+				step_mask = STEP_ALL;
+
+			fsl_ddr_printinfo(pinfo, ctlr_mask,
+						dimm_mask, step_mask);
+			continue;
+		}
+
+		if (strcmp(argv[0], "go") == 0) {
+			if (next_step) {
+				ddrsize = fsl_ddr_compute(pinfo, next_step);
+			}
+			break;
+		}
+
+		printf("unknown command %s\n", argv[0]);
+	}
+
+	debug("end of memory = %llu\n", (u64)ddrsize);
+
+	return ddrsize;
+}
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/main.c b/arch/powerpc/cpu/mpc8xxx/ddr/main.c
index 6d582e9..83a6dd4 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/main.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/main.c
@@ -21,6 +21,7 @@  extern void fsl_ddr_set_lawbar(
 		const common_timing_params_t *memctl_common_params,
 		unsigned int memctl_interleaved,
 		unsigned int ctrl_num);
+extern phys_size_t fsl_ddr_interactive(fsl_ddr_info_t *pinfo);
 
 /* processor specific function */
 extern void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
@@ -75,7 +76,6 @@  extern void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
  *				|  interleaving
  */
 
-#ifdef DEBUG
 const char *step_string_tbl[] = {
 	"STEP_GET_SPD",
 	"STEP_COMPUTE_DIMM_PARMS",
@@ -96,7 +96,6 @@  const char * step_to_string(unsigned int step) {
 
 	return step_string_tbl[s];
 }
-#endif
 
 int step_assign_addresses(fsl_ddr_info_t *pinfo,
 			  unsigned int dbw_cap_adj[],
@@ -405,7 +404,10 @@  phys_size_t fsl_ddr_sdram(void)
 	memset(&info, 0, sizeof(fsl_ddr_info_t));
 
 	/* Compute it once normally. */
-	total_memory = fsl_ddr_compute(&info, STEP_GET_SPD);
+	if (getenv("ddr_interactive"))
+		total_memory = fsl_ddr_interactive(&info);
+	else
+		total_memory = fsl_ddr_compute(&info, STEP_GET_SPD);
 
 	/* Check for memory controller interleaving. */
 	memctl_interleaved = 0;
diff --git a/doc/README.fsl-ddr b/doc/README.fsl-ddr
index a7ba193..13c9013 100644
--- a/doc/README.fsl-ddr
+++ b/doc/README.fsl-ddr
@@ -170,3 +170,23 @@  Single slot system
 
 Reference http://www.xrosstalkmag.com/mag_issues/xrosstalk_oct08_final.pdf
           http://download.micron.com/pdf/technotes/ddr3/tn4108_ddr3_design_guide.pdf
+
+
+Interactive DDR debugging
+===========================
+
+For DDR parameter tuning up and debugging, the interactive DDR debugging can
+be activated by saving an environment variable "ddr_interactive". The value
+doesn't matter. Once activated, U-boot prompts "FSL DDR>" before enabling DDR
+controller. The available commands can be seen by typing "help".
+
+The example flow of using interactive debugging is
+type command "compute" to calculate the parameters from the default
+type command "print" with arguments to show SPD, options, registers
+type command "edit" with arguments to change any if desired
+type command "go" to continue calculation and enable DDR controller
+
+Note, check "next_step" to show the flow. For example, after editing registers,
+DDR controller will be enabled with current setting without further
+calculation.
+