[U-Boot] [PATCH 3/3] FSL DDR: Add interactive DDR config support

Kumar Gala galak at kernel.crashing.org
Wed Aug 13 07:00:38 CEST 2008


Provide a mechanism to allow interactive configuration of DDR params.  This
is useful when trying to test various DDR settings to determine optimal
configuration values for a given board.

Signed-off-by: James Yang <James.Yang at freescale.com>
Signed-off-by: Jon Loeliger <jdl at freescale.com>
Signed-off-by: Kumar Gala <galak at kernel.crashing.org>
---
 cpu/mpc8xxx/Makefile              |    1 +
 cpu/mpc8xxx/fsl_ddr_interactive.c | 1272 +++++++++++++++++++++++++++++++++++++
 cpu/mpc8xxx/fsl_ddr_sdram.c       |   10 +
 cpu/mpc8xxx/fsl_ddr_sdram.h       |    3 +
 4 files changed, 1286 insertions(+), 0 deletions(-)
 create mode 100644 cpu/mpc8xxx/fsl_ddr_interactive.c

diff --git a/cpu/mpc8xxx/Makefile b/cpu/mpc8xxx/Makefile
index 258668c..9edb1ec 100644
--- a/cpu/mpc8xxx/Makefile
+++ b/cpu/mpc8xxx/Makefile
@@ -10,6 +10,7 @@ include $(TOPDIR)/config.mk
 
 LIB	= $(obj)libmpc8xxx.a
 
+COBJS-$(CONFIG_FSL_DDR_INTERACTIVE)	+= fsl_ddr_interactive.o
 COBJS-$(CONFIG_FSL_DDR1)	+= fsl_ddr_sdram.o fsl_ddr_ctrl.o
 COBJS-$(CONFIG_FSL_DDR1)	+= fsl_ddr1.o
 
diff --git a/cpu/mpc8xxx/fsl_ddr_interactive.c b/cpu/mpc8xxx/fsl_ddr_interactive.c
new file mode 100644
index 0000000..2c914cc
--- /dev/null
+++ b/cpu/mpc8xxx/fsl_ddr_interactive.c
@@ -0,0 +1,1272 @@
+/*
+ * Copyright 2008 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]
+ */
+
+#include <common.h>
+#include <asm/types.h>
+
+#include "fsl_ddr_sdram.h"
+/*
+ * Option parameter Structures
+ */
+typedef struct {
+	const char *option_name;
+	unsigned long long *pointer;
+} options_strings_ulonglong_t;
+
+typedef struct {
+	const char *option_name;
+	unsigned int *pointer;
+} options_strings_uint_t;
+
+
+extern int do_reset(void *cmdtp, int flag, int argc, char *argv[]);
+
+/*
+ * interactive prompt
+ */
+
+static int is_a_num_char(const char c)
+{
+	return c >= '0' && c <= '9';
+}
+
+static unsigned int picos_to_mhz(unsigned int picos)
+{
+	return 1000000 / picos;
+}
+
+static int
+handle_uint_option_table(options_strings_uint_t *table,
+			 int table_size,
+			 const char *opt,
+			 const char *val)
+{
+	unsigned int i;
+	unsigned int value;
+
+	for (i = 0; i < table_size; i++) {
+		if (strcmp(table[i].option_name, opt) == 0) {
+			value = simple_strtoul(val, NULL, 0);
+			*table[i].pointer = value;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int
+handle_ull_option_table(options_strings_ulonglong_t *table,
+			int table_size,
+			const char *opt,
+			const char *val)
+{
+	unsigned int i;
+	unsigned long long value;
+
+	for (i = 0; i < table_size; i++) {
+		if (strcmp(table[i].option_name, opt) == 0) {
+			value = simple_strtoull(val, NULL, 0);
+			*table[i].pointer = value;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static void
+fsl_ddr_sdram_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:
+		asm volatile ("stb %0,0(%1)" : : "r" (value) , "b" (pcdata));
+		break;
+	case 2:
+		asm volatile ("sth %0,0(%1)" : : "r" (value) , "b" (pcdata));
+		break;
+	case 4:
+		asm volatile ("stw %0,0(%1)" : : "r" (value) , "b" (pcdata));
+		break;
+	default:
+		debug("unexpected element size %u\n", element_size);
+		break;
+	}
+}
+
+static void
+fsl_ddr_sdram_spd_edit(fsl_ddr_sdram_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_sdram_generic_edit(pspd, pspd + 1,
+				   sizeof(char), element_num, value);
+}
+
+static void
+lowest_common_dimm_parameters_edit(fsl_ddr_sdram_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];
+
+	options_strings_uint_t options_uint[] = {
+		{"tCKmin_X_ps",                     &p->tCKmin_X_ps},
+		{"tCKmax_ps",                       &p->tCKmax_ps},
+		{"tCKmax_max_ps",                   &p->tCKmax_max_ps},
+		{"tRCD_ps",                         &p->tRCD_ps},
+		{"tRP_ps",                          &p->tRP_ps},
+		{"tRAS_ps",                         &p->tRAS_ps},
+		{"tWR_ps",                          &p->tWR_ps},
+		{"tWTR_ps",                         &p->tWTR_ps},
+		{"tRFC_ps",                         &p->tRFC_ps},
+		{"tRRD_ps",                         &p->tRRD_ps},
+		{"tRC_ps",                          &p->tRC_ps},
+		{"refresh_rate_ps",                 &p->refresh_rate_ps},
+		{"tIS_ps",                          &p->tIS_ps},
+		{"tIH_ps",                          &p->tIH_ps},
+		{"tDS_ps",                          &p->tDS_ps},
+		{"tDH_ps",                          &p->tDH_ps},
+		{"tRTP_ps",                         &p->tRTP_ps},
+		{"tDQSQ_max_ps",                    &p->tDQSQ_max_ps},
+		{"tQHS_ps",                         &p->tQHS_ps},
+		{"ndimms_present",                  &p->ndimms_present},
+		{"lowest_common_SPD_caslat",
+			&p->lowest_common_SPD_caslat},
+		{"highest_common_derated_caslat",
+			&p->highest_common_derated_caslat},
+		{"additive_latency",                &p->additive_latency},
+		{"all_DIMMs_burst_lengths_bitmask",
+			&p->all_DIMMs_burst_lengths_bitmask},
+		{"all_DIMMs_registered",            &p->all_DIMMs_registered},
+		{"all_DIMMs_unbuffered",            &p->all_DIMMs_unbuffered},
+		{"all_DIMMs_ECC_capable",           &p->all_DIMMs_ECC_capable}
+	};
+
+	const unsigned int n_uint_opts = ARRAY_SIZE(options_uint);
+
+	options_strings_ulonglong_t options_ull[] = {
+		{"total_mem",    &p->total_mem},
+		{"base_address", &p->base_address}
+	};
+
+	const unsigned int n_ull_opts = ARRAY_SIZE(options_ull);
+
+	if (handle_uint_option_table(options_uint, n_uint_opts,
+				     optname_str, value_str))
+		return;
+
+	if (handle_ull_option_table(options_ull, n_ull_opts,
+				    optname_str, value_str))
+		return;
+
+	printf("Error: couldn't find option string %s\n", optname_str);
+}
+
+static void
+fsl_ddr_sdram_dimm_parameters_edit(fsl_ddr_sdram_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]);
+
+	options_strings_uint_t options_uint[] = {
+		{"n_ranks",                  &p->n_ranks},
+		{"data_width",               &p->data_width},
+		{"primary_sdram_width",      &p->primary_sdram_width},
+		{"ec_sdram_width",           &p->ec_sdram_width},
+		{"registered_dimm",          &p->registered_dimm},
+
+		{"n_row_addr",               &p->n_row_addr},
+		{"n_col_addr",               &p->n_col_addr},
+		{"edc_config",               &p->edc_config},
+		{"n_banks_per_sdram_device", &p->n_banks_per_sdram_device},
+		{"burst_lengths_bitmask",    &p->burst_lengths_bitmask},
+		{"row_density",              &p->row_density},
+
+		{"tCKmin_X_ps",              &p->tCKmin_X_ps},
+		{"tCKmin_X_minus_1_ps",      &p->tCKmin_X_minus_1_ps},
+		{"tCKmin_X_minus_2_ps",      &p->tCKmin_X_minus_2_ps},
+		{"tCKmax_ps",                &p->tCKmax_ps},
+
+		{"caslat_X",                 &p->caslat_X},
+		{"caslat_X_minus_1",         &p->caslat_X_minus_1},
+		{"caslat_X_minus_2",         &p->caslat_X_minus_2},
+
+		{"caslat_lowest_derated",    &p->caslat_lowest_derated},
+
+		{"tRCD_ps",                  &p->tRCD_ps},
+		{"tRP_ps",                   &p->tRP_ps},
+		{"tRAS_ps",                  &p->tRAS_ps},
+		{"tWR_ps",                   &p->tWR_ps},
+		{"tWTR_ps",                  &p->tWTR_ps},
+		{"tRFC_ps",                  &p->tRFC_ps},
+		{"tRRD_ps",                  &p->tRRD_ps},
+		{"tRC_ps",                   &p->tRC_ps},
+		{"refresh_rate_ps",          &p->refresh_rate_ps},
+
+		{"tIS_ps",                   &p->tIS_ps},
+		{"tIH_ps",                   &p->tIH_ps},
+		{"tDS_ps",                   &p->tDS_ps},
+		{"tDH_ps",                   &p->tDH_ps},
+		{"tRTP_ps",                  &p->tRTP_ps},
+		{"tDQSQ_max_ps",             &p->tDQSQ_max_ps},
+		{"tQHS_ps",                  &p->tQHS_ps},
+	};
+
+	const unsigned int n_uint_opts = ARRAY_SIZE(options_uint);
+
+	options_strings_ulonglong_t options_ull[] = {
+		{"rank_density",  &p->rank_density},
+		{"dimm_capacity", &p->dimm_capacity},
+		{"base_address",  &p->base_address},
+	};
+
+	const unsigned int n_ull_opts = ARRAY_SIZE(options_ull);
+
+	if (handle_uint_option_table(options_uint, n_uint_opts,
+				     optname_str, value_str))
+		return;
+
+	if (handle_ull_option_table(options_ull, n_ull_opts,
+				    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("dimm_capacity = %llu bytes (%llu megabytes)\n",
+	       pdimm->dimm_capacity, pdimm->dimm_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);
+}
+
+static void
+fsl_ddr_sdram_options_edit(fsl_ddr_sdram_info_t *pinfo,
+			   unsigned int ctl_num,
+			   const char *optname_str,
+			   const char *value_str)
+{
+	/*
+	 * This array all on the stack and *computed* each time this
+	 * function is rung.
+	 */
+	options_strings_uint_t options[] = {
+		{"memctl_interleaving",
+		 &pinfo->memctl_opts[ctl_num].memctl_interleaving},
+		{"memctl_interleaving_mode",
+		 &pinfo->memctl_opts[ctl_num].memctl_interleaving_mode},
+		{"ba_intlv_ctl",
+		 &pinfo->memctl_opts[ctl_num].ba_intlv_ctl},
+		{"ecc_mode", &pinfo->memctl_opts[ctl_num].ECC_mode},
+		{"ECC_mode", &pinfo->memctl_opts[ctl_num].ECC_mode},
+		{"self_refresh_in_sleep",
+		 &pinfo->memctl_opts[ctl_num].self_refresh_in_sleep},
+		{"dynamic_power",
+		 &pinfo->memctl_opts[ctl_num].dynamic_power},
+		{"data_bus_width",
+		 &pinfo->memctl_opts[ctl_num].data_bus_width},
+		{"burst_length",
+		 &pinfo->memctl_opts[ctl_num].burst_length},
+		{"cas_latency_override",
+		 &pinfo->memctl_opts[ctl_num].cas_latency_override},
+		{"cas_latency_override_value",
+		 &pinfo->memctl_opts[ctl_num].cas_latency_override_value},
+		{"use_derated_caslat",
+		 &pinfo->memctl_opts[ctl_num].use_derated_caslat},
+		{"additive_latency_override",
+		 &pinfo->memctl_opts[ctl_num].additive_latency_override},
+		{"additive_latency_override_value",
+		 &pinfo->memctl_opts[ctl_num].additive_latency_override_value},
+		{"clk_adjust", &pinfo->memctl_opts[ctl_num].clk_adjust},
+		{"cpo_override",
+		 &pinfo->memctl_opts[ctl_num].cpo_override},
+		{"write_data_delay",
+		 &pinfo->memctl_opts[ctl_num].write_data_delay},
+		{"half_strength_driver_enable",
+		 &pinfo->memctl_opts[ctl_num].half_strength_driver_enable},
+
+		/*
+		 * These can probably be changed to 2T_EN and 3T_EN
+		 * (using a leading numerical character) without problem
+		 */
+		{"twoT_en", &pinfo->memctl_opts[ctl_num].twoT_en},
+		{"threeT_en", &pinfo->memctl_opts[ctl_num].threeT_en},
+		{"bstopre", &pinfo->memctl_opts[ctl_num].bstopre},
+		{"tCKE_clock_pulse_width_ps",
+		 &pinfo->memctl_opts[ctl_num].tCKE_clock_pulse_width_ps},
+		{"tFAW_window_four_activates_ps",
+		 &pinfo->memctl_opts[ctl_num].tFAW_window_four_activates_ps}
+	};
+
+	const unsigned int nopts = ARRAY_SIZE(options);
+
+	if (handle_uint_option_table(options, nopts, optname_str, value_str))
+		return;
+
+	printf("couldn't find option string %s\n", optname_str);
+}
+
+static void
+print_fsl_memctl_config_regs(const fsl_memctl_config_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_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_pd_cntl        = %08X\n", ddr->ddr_pd_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);
+}
+
+static void
+fsl_ddr_sdram_regs_edit(fsl_ddr_sdram_info_t *pinfo,
+			unsigned int ctrl_num,
+			const char *regname,
+			unsigned int value)
+{
+	unsigned int i;
+	fsl_memctl_config_regs_t *ddr;
+	char buf[20];
+
+	debug("fsl_ddr_sdram_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_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_pd_cntl", regname) == 0) {
+		ddr->ddr_pd_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;
+	}
+}
+
+static const char *
+get_sdram_type(unsigned int sdram_type)
+{
+	switch (sdram_type) {
+	case 2:
+		return "DDR1";
+	case 3:
+		return "DDR2";
+	case 6:
+		return "LPDDR1";
+	case 7:
+		return "DDR3";
+	}
+
+	return "unknown SDRAM type";
+}
+
+static void
+print_memctl_options(const memctl_options_t *popts)
+{
+	/* 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);
+
+	/* Operational mode parameters */
+	/* 2 = DDR1, 3 = DDR2, 6 = LPDDR1, 7 = DDR3 */
+	printf("sdram_type = %u (%s)\n",
+	       popts->sdram_type, get_sdram_type(popts->sdram_type));
+
+	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("bstopre = %u\n", popts->bstopre);
+	/* 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);
+}
+
+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)
+#error "Implement generic_spd_dump() for DDR3"
+#endif
+}
+
+static void
+fsl_ddr_sdram_printinfo(const fsl_ddr_sdram_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_sdram_info_t *pinfo)
+{
+	phys_size_t ddrsize;
+	const char *prompt = "FSL DDR>";
+	unsigned int len;
+	char buffer[CFG_CBSIZE];
+	char *argv[CFG_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(
+       "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(__ilog2(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");
+				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 (is_a_num_char(c)) {
+						ctlr_mask |= 1 << (c - '0');
+					}
+					continue;
+				}
+
+				if (argv[i][0] == 'd') {
+					char c = argv[i][1];
+					if (is_a_num_char(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_sdram_spd_edit(pinfo,
+							       ctrl_num,
+							       dimm_num,
+							       element_num,
+							       value);
+					next_step = STEP_COMPUTE_DIMM_PARMS;
+				}
+				break;
+
+			case STEP_COMPUTE_DIMM_PARMS:
+				fsl_ddr_sdram_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_sdram_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_sdram_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_sdram_compute(pinfo, next_step);
+			/*
+			 * FIXME: There some problems with this.
+			 * For exmaple, what happens if there is
+			 * an error inside fsl_ddr_sdram_compute?
+			 */
+			continue;
+		}
+
+		if (strcmp(argv[0], "compute") == 0) {
+			/*
+			 * Compute rest of steps starting at
+			 * the current next_step/
+			 */
+			ddrsize = fsl_ddr_sdram_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 (c >= '0' && c <= '9') {
+						ctlr_mask |= 1 << (c - '0');
+					}
+					continue;
+				}
+
+				if (argv[i][0] == 'd') {
+					char c = argv[i][1];
+					if (c >= '0' && c <= '9') {
+						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 controllers.
+			 */
+			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_sdram_printinfo(pinfo, ctlr_mask,
+						dimm_mask, step_mask);
+			continue;
+		}
+
+		if (strcmp(argv[0], "go") == 0) {
+			if (next_step) {
+				ddrsize = fsl_ddr_sdram_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/cpu/mpc8xxx/fsl_ddr_sdram.c b/cpu/mpc8xxx/fsl_ddr_sdram.c
index e659180..1d13363 100644
--- a/cpu/mpc8xxx/fsl_ddr_sdram.c
+++ b/cpu/mpc8xxx/fsl_ddr_sdram.c
@@ -1218,6 +1218,16 @@ phys_size_t fsl_ddr_sdram(void)
 	/* Compute it once normally. */
 	total_memory = fsl_ddr_sdram_compute(&info, STEP_GET_SPD);
 
+#ifdef CONFIG_FSL_DDR_INTERACTIVE
+	/*
+	 * The presence of the environment variable "ddrsetup"
+	 * causes the interactive DDR setup prompt to appear.
+	 */
+	if (getenv("ddrsetup")) {
+		total_memory = fsl_ddr_interactive(&info);
+	}
+#endif
+
 	/* Check for memory controller interleaving. */
 	memctl_interleaved = 0;
 	for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
diff --git a/cpu/mpc8xxx/fsl_ddr_sdram.h b/cpu/mpc8xxx/fsl_ddr_sdram.h
index cad2d7f..310ccc1 100644
--- a/cpu/mpc8xxx/fsl_ddr_sdram.h
+++ b/cpu/mpc8xxx/fsl_ddr_sdram.h
@@ -58,6 +58,9 @@ typedef struct {
 
 
 extern phys_size_t
+fsl_ddr_interactive(fsl_ddr_sdram_info_t *pinfo);
+
+extern phys_size_t
 fsl_ddr_sdram_compute(fsl_ddr_sdram_info_t *pinfo,
 				  unsigned int start_step);
 
-- 
1.5.5.1




More information about the U-Boot mailing list