[U-Boot] [PATCH 03/14] FSL DDR: Add interactive DDR config support
Kumar Gala
galak at kernel.crashing.org
Tue Aug 12 18:06:11 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 | 1280 +++++++++++++++++++++++++++++++++++++
cpu/mpc8xxx/fsl_ddr_sdram.c | 10 +
cpu/mpc8xxx/fsl_ddr_sdram.h | 3 +
4 files changed, 1294 insertions(+), 0 deletions(-)
create mode 100644 cpu/mpc8xxx/fsl_ddr_interactive.c
diff --git a/cpu/mpc8xxx/Makefile b/cpu/mpc8xxx/Makefile
index 30f81ff..0ceac5b 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
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..ee2ae6b
--- /dev/null
+++ b/cpu/mpc8xxx/fsl_ddr_interactive.c
@@ -0,0 +1,1280 @@
+/*
+ * 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
+fsl_ddr_sdram_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 ctrl_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_options[ctrl_num].memctl_interleaving},
+ {"memctl_interleaving_mode",
+ &pinfo->memctl_options[ctrl_num].memctl_interleaving_mode},
+ {"ba_intlv_ctl",
+ &pinfo->memctl_options[ctrl_num].ba_intlv_ctl},
+ {"ecc_mode", &pinfo->memctl_options[ctrl_num].ECC_mode},
+ {"ECC_mode", &pinfo->memctl_options[ctrl_num].ECC_mode},
+ {"self_refresh_in_sleep",
+ &pinfo->memctl_options[ctrl_num].self_refresh_in_sleep},
+ {"dynamic_power",
+ &pinfo->memctl_options[ctrl_num].dynamic_power},
+ {"data_bus_width",
+ &pinfo->memctl_options[ctrl_num].data_bus_width},
+ {"burst_length",
+ &pinfo->memctl_options[ctrl_num].burst_length},
+ {"cas_latency_override",
+ &pinfo->memctl_options[ctrl_num].cas_latency_override},
+ {"cas_latency_override_value",
+ &pinfo->memctl_options[ctrl_num].cas_latency_override_value},
+ {"use_derated_caslat",
+ &pinfo->memctl_options[ctrl_num].use_derated_caslat},
+ {"additive_latency_override",
+ &pinfo->memctl_options[ctrl_num].additive_latency_override},
+ {"additive_latency_override_value",
+ &pinfo->memctl_options[ctrl_num].additive_latency_override_value},
+ {"clk_adjust", &pinfo->memctl_options[ctrl_num].clk_adjust},
+ {"cpo_override",
+ &pinfo->memctl_options[ctrl_num].cpo_override},
+ {"write_data_delay",
+ &pinfo->memctl_options[ctrl_num].write_data_delay},
+ {"half_strength_driver_enable",
+ &pinfo->memctl_options[ctrl_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_options[ctrl_num].twoT_en},
+ {"threeT_en", &pinfo->memctl_options[ctrl_num].threeT_en},
+ {"bstopre", &pinfo->memctl_options[ctrl_num].bstopre},
+ {"tCKE_clock_pulse_width_ps",
+ &pinfo->memctl_options[ctrl_num].tCKE_clock_pulse_width_ps},
+ {"tFAW_window_four_activates_ps",
+ &pinfo->memctl_options[ctrl_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;
+ unsigned int j;
+ unsigned int retval;
+
+ /*
+ * INFO 1: DIMM SPD data
+ */
+ if (do_mask & STEP_GET_SPD) {
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ if (ctrl_mask & (1 << i)) {
+ /*
+ * 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)) {
+ 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");
+ }
+
+ /*
+ * INFO 2: DIMM Parameters
+ */
+ if (do_mask & STEP_COMPUTE_DIMM_PARMS) {
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ if (ctrl_mask & (1 << i)) {
+ for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+ if (dimm_mask & (1 << j)) {
+ printf("DIMM parameters: Controller=%u DIMM=%u\n", i, j);
+ print_dimm_parameters(&(pinfo->dimm_params[i][j]));
+ printf("\n");
+ }
+ }
+ printf("\n");
+ }
+ }
+ printf("\n");
+ }
+
+ /*
+ * INFO 3: Common Parameters
+ */
+ if (do_mask & STEP_COMPUTE_COMMON_PARMS) {
+ for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+ if (ctrl_mask & (1 << i)) {
+ 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)) {
+ printf("User Config Options: Controller=%u\n", i);
+ print_memctl_options(&pinfo->memctl_options[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)) {
+ 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)) {
+ 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 registers\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:
+ fsl_ddr_sdram_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 0c558a5..a6fca88 100644
--- a/cpu/mpc8xxx/fsl_ddr_sdram.c
+++ b/cpu/mpc8xxx/fsl_ddr_sdram.c
@@ -2471,6 +2471,16 @@ phys_size_t fsl_ddr_sdram(void)
*/
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.
*/
diff --git a/cpu/mpc8xxx/fsl_ddr_sdram.h b/cpu/mpc8xxx/fsl_ddr_sdram.h
index 57398c6..c0c4d6b 100644
--- a/cpu/mpc8xxx/fsl_ddr_sdram.h
+++ b/cpu/mpc8xxx/fsl_ddr_sdram.h
@@ -54,6 +54,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