
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@freescale.com Signed-off-by: Jon Loeliger jdl@freescale.com Signed-off-by: Kumar Gala galak@kernel.crashing.org --- cpu/mpc8xxx/Makefile | 2 + cpu/mpc8xxx/fsl_ddr_interactive.c | 1238 +++++++++++++++++++++++++++++++++++++ cpu/mpc8xxx/fsl_ddr_sdram.c | 12 +- cpu/mpc8xxx/fsl_ddr_sdram.h | 3 + 4 files changed, 1254 insertions(+), 1 deletions(-) create mode 100644 cpu/mpc8xxx/fsl_ddr_interactive.c
diff --git a/cpu/mpc8xxx/Makefile b/cpu/mpc8xxx/Makefile index 888ebfe..660ab54 100644 --- a/cpu/mpc8xxx/Makefile +++ b/cpu/mpc8xxx/Makefile @@ -10,6 +10,8 @@ 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_util.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..4e12756 --- /dev/null +++ b/cpu/mpc8xxx/fsl_ddr_interactive.c @@ -0,0 +1,1238 @@ +/* + * 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 <linux/ctype.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[]); + +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_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_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); +} + +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]; + + 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_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]); + + 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}, + {"capacity", &p->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("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); +} + +static void +fsl_ddr_options_edit(fsl_ddr_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_regs_edit(fsl_ddr_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_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_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[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 (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/cpu/mpc8xxx/fsl_ddr_sdram.c b/cpu/mpc8xxx/fsl_ddr_sdram.c index 0663609..c0b5dfd 100644 --- a/cpu/mpc8xxx/fsl_ddr_sdram.c +++ b/cpu/mpc8xxx/fsl_ddr_sdram.c @@ -84,7 +84,7 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, * | interleaving */
-#ifdef DEBUG +#if defined(DEBUG) || defined (CONFIG_FSL_DDR_INTERACTIVE) const char *step_string_tbl[] = { "STEP_GET_SPD", "STEP_COMPUTE_DIMM_PARMS", @@ -1072,6 +1072,16 @@ phys_size_t fsl_ddr_sdram(void) /* Compute it once normally. */ total_memory = fsl_ddr_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 58cac09..8823114 100644 --- a/cpu/mpc8xxx/fsl_ddr_sdram.h +++ b/cpu/mpc8xxx/fsl_ddr_sdram.h @@ -61,6 +61,9 @@ typedef struct { extern phys_size_t fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step);
+extern phys_size_t +fsl_ddr_interactive(fsl_ddr_info_t *pinfo); + extern const char * step_to_string(unsigned int step); /* * Compute steps