summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/cpu/mpc8xxx/ddr/options.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/cpu/mpc8xxx/ddr/options.c')
-rw-r--r--arch/powerpc/cpu/mpc8xxx/ddr/options.c411
1 files changed, 385 insertions, 26 deletions
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c
index 774c0e4..6ccc3b0 100644
--- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c
+++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008, 2010 Freescale Semiconductor, Inc.
+ * Copyright 2008, 2010-2011 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 as published by the Free
@@ -13,28 +13,338 @@
#include "ddr.h"
+/*
+ * Use our own stack based buffer before relocation to allow accessing longer
+ * hwconfig strings that might be in the environment before we've relocated.
+ * This is pretty fragile on both the use of stack and if the buffer is big
+ * enough. However we will get a warning from getenv_f for the later.
+ */
+#define HWCONFIG_BUFFER_SIZE 128
+
/* Board-specific functions defined in each board's ddr.c */
extern void fsl_ddr_board_options(memctl_options_t *popts,
dimm_params_t *pdimm,
unsigned int ctrl_num);
+typedef struct {
+ unsigned int odt_rd_cfg;
+ unsigned int odt_wr_cfg;
+ unsigned int odt_rtt_norm;
+ unsigned int odt_rtt_wr;
+} dynamic_odt_t;
+
+static const dynamic_odt_t single_Q[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS_AND_OTHER_DIMM,
+ DDR3_RTT_20_OHM,
+ DDR3_RTT_120_OHM
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER, /* tied high */
+ DDR3_RTT_OFF,
+ DDR3_RTT_120_OHM
+ },
+ { /* cs2 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS_AND_OTHER_DIMM,
+ DDR3_RTT_20_OHM,
+ DDR3_RTT_120_OHM
+ },
+ { /* cs3 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER, /* tied high */
+ DDR3_RTT_OFF,
+ DDR3_RTT_120_OHM
+ }
+};
+
+static const dynamic_odt_t single_D[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_ALL,
+ DDR3_RTT_40_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER,
+ DDR3_RTT_OFF,
+ DDR3_RTT_OFF
+ },
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}
+};
+
+static const dynamic_odt_t single_S[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_ALL,
+ DDR3_RTT_40_OHM,
+ DDR3_RTT_OFF
+ },
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+};
+
+static const dynamic_odt_t dual_DD[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_SAME_DIMM,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR3_RTT_30_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs2 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_SAME_DIMM,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs3 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR3_RTT_30_OHM,
+ DDR3_RTT_OFF
+ }
+};
+
+static const dynamic_odt_t dual_DS[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_SAME_DIMM,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR3_RTT_30_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs2 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_ALL,
+ DDR3_RTT_20_OHM,
+ DDR3_RTT_120_OHM
+ },
+ {0, 0, 0, 0}
+};
+static const dynamic_odt_t dual_SD[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_ALL,
+ DDR3_RTT_20_OHM,
+ DDR3_RTT_120_OHM
+ },
+ {0, 0, 0, 0},
+ { /* cs2 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_SAME_DIMM,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs3 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_OTHER_DIMM,
+ DDR3_RTT_20_OHM,
+ DDR3_RTT_OFF
+ }
+};
+
+static const dynamic_odt_t dual_SS[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_ALL,
+ DDR3_RTT_30_OHM,
+ DDR3_RTT_120_OHM
+ },
+ {0, 0, 0, 0},
+ { /* cs2 */
+ FSL_DDR_ODT_OTHER_DIMM,
+ FSL_DDR_ODT_ALL,
+ DDR3_RTT_30_OHM,
+ DDR3_RTT_120_OHM
+ },
+ {0, 0, 0, 0}
+};
+
+static const dynamic_odt_t dual_D0[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_SAME_DIMM,
+ DDR3_RTT_40_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER,
+ DDR3_RTT_OFF,
+ DDR3_RTT_OFF
+ },
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}
+};
+
+static const dynamic_odt_t dual_0D[4] = {
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ { /* cs2 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_SAME_DIMM,
+ DDR3_RTT_40_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs3 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_NEVER,
+ DDR3_RTT_OFF,
+ DDR3_RTT_OFF
+ }
+};
+
+static const dynamic_odt_t dual_S0[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR3_RTT_40_OHM,
+ DDR3_RTT_OFF
+ },
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}
+
+};
+
+static const dynamic_odt_t dual_0S[4] = {
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ { /* cs2 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR3_RTT_40_OHM,
+ DDR3_RTT_OFF
+ },
+ {0, 0, 0, 0}
+
+};
+
+static const dynamic_odt_t odt_unknown[4] = {
+ { /* cs0 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs1 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs2 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ },
+ { /* cs3 */
+ FSL_DDR_ODT_NEVER,
+ FSL_DDR_ODT_CS,
+ DDR3_RTT_120_OHM,
+ DDR3_RTT_OFF
+ }
+};
+
unsigned int populate_memctl_options(int all_DIMMs_registered,
memctl_options_t *popts,
dimm_params_t *pdimm,
unsigned int ctrl_num)
{
unsigned int i;
+ char buffer[HWCONFIG_BUFFER_SIZE];
+ char *buf = NULL;
+ const dynamic_odt_t *pdodt = odt_unknown;
+
+ /*
+ * Extract hwconfig from environment since we have not properly setup
+ * the environment but need it for ddr config params
+ */
+ if (getenv_f("hwconfig", buffer, sizeof(buffer)) > 0)
+ buf = buffer;
/* Chip select options. */
+ if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) {
+ switch (pdimm[0].n_ranks) {
+ case 1:
+ pdodt = single_S;
+ break;
+ case 2:
+ pdodt = single_D;
+ break;
+ case 4:
+ pdodt = single_Q;
+ break;
+ }
+ } else if (CONFIG_DIMM_SLOTS_PER_CTLR == 2) {
+ switch (pdimm[0].n_ranks) {
+ case 2:
+ switch (pdimm[1].n_ranks) {
+ case 2:
+ pdodt = dual_DD;
+ break;
+ case 1:
+ pdodt = dual_DS;
+ break;
+ case 0:
+ pdodt = dual_D0;
+ break;
+ }
+ break;
+ case 1:
+ switch (pdimm[1].n_ranks) {
+ case 2:
+ pdodt = dual_SD;
+ break;
+ case 1:
+ pdodt = dual_SS;
+ break;
+ case 0:
+ pdodt = dual_S0;
+ break;
+ }
+ break;
+ case 0:
+ switch (pdimm[1].n_ranks) {
+ case 2:
+ pdodt = dual_0D;
+ break;
+ case 1:
+ pdodt = dual_0S;
+ break;
+ }
+ break;
+ }
+ }
/* Pick chip-select local options. */
for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) {
- /* If not DDR2, odt_rd_cfg and odt_wr_cfg need to be 0. */
-
- /* only for single CS? */
- popts->cs_local_opts[i].odt_rd_cfg = 0;
-
- popts->cs_local_opts[i].odt_wr_cfg = 1;
+#if defined(CONFIG_FSL_DDR3)
+ popts->cs_local_opts[i].odt_rd_cfg = pdodt[i].odt_rd_cfg;
+ popts->cs_local_opts[i].odt_wr_cfg = pdodt[i].odt_wr_cfg;
+ popts->cs_local_opts[i].odt_rtt_norm = pdodt[i].odt_rtt_norm;
+ popts->cs_local_opts[i].odt_rtt_wr = pdodt[i].odt_rtt_wr;
+#else
+ popts->cs_local_opts[i].odt_rd_cfg = FSL_DDR_ODT_NEVER;
+ popts->cs_local_opts[i].odt_wr_cfg = FSL_DDR_ODT_CS;
+#endif
popts->cs_local_opts[i].auto_precharge = 0;
}
@@ -81,10 +391,13 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
/* Operational Mode Paramters */
/* Pick ECC modes */
-#ifdef CONFIG_DDR_ECC
- popts->ECC_mode = 1; /* 0 = disabled, 1 = enabled */
-#else
popts->ECC_mode = 0; /* 0 = disabled, 1 = enabled */
+#ifdef CONFIG_DDR_ECC
+ if (hwconfig_sub_f("fsl_ddr", "ecc", buf)) {
+ if (hwconfig_subarg_cmp_f("fsl_ddr", "ecc", "on", buf))
+ popts->ECC_mode = 1;
+ } else
+ popts->ECC_mode = 1;
#endif
popts->ECC_init_using_memctl = 1; /* 0 = use DMA, 1 = use memctl */
@@ -159,6 +472,9 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
popts->twoT_en = 0;
popts->threeT_en = 0;
+ /* for RDIMM, address parity enable */
+ popts->ap_en = 1;
+
/*
* BSTTOPRE precharge interval
*
@@ -221,7 +537,7 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
* should be a subset of the requested configuration.
*/
#if (CONFIG_NUM_DDR_CONTROLLERS > 1)
- if (hwconfig_sub("fsl_ddr", "ctlr_intlv")) {
+ if (hwconfig_sub_f("fsl_ddr", "ctlr_intlv", buf)) {
if (pdimm[0].n_ranks == 0) {
printf("There is no rank on CS0 for controller %d. Because only"
" rank on CS0 and ranks chip-select interleaved with CS0"
@@ -234,19 +550,25 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
* test null first. if CONFIG_HWCONFIG is not defined
* hwconfig_arg_cmp returns non-zero
*/
- if (hwconfig_subarg_cmp("fsl_ddr", "ctlr_intlv", "null")) {
+ if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv",
+ "null", buf)) {
popts->memctl_interleaving = 0;
debug("memory controller interleaving disabled.\n");
- } else if (hwconfig_subarg_cmp("fsl_ddr", "ctlr_intlv", "cacheline"))
+ } else if (hwconfig_subarg_cmp_f("fsl_ddr",
+ "ctlr_intlv",
+ "cacheline", buf))
popts->memctl_interleaving_mode =
FSL_DDR_CACHE_LINE_INTERLEAVING;
- else if (hwconfig_subarg_cmp("fsl_ddr", "ctlr_intlv", "page"))
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv",
+ "page", buf))
popts->memctl_interleaving_mode =
FSL_DDR_PAGE_INTERLEAVING;
- else if (hwconfig_subarg_cmp("fsl_ddr", "ctlr_intlv", "bank"))
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv",
+ "bank", buf))
popts->memctl_interleaving_mode =
FSL_DDR_BANK_INTERLEAVING;
- else if (hwconfig_subarg_cmp("fsl_ddr", "ctlr_intlv", "superbank"))
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "ctlr_intlv",
+ "superbank", buf))
popts->memctl_interleaving_mode =
FSL_DDR_SUPERBANK_INTERLEAVING;
else {
@@ -256,19 +578,24 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
}
}
#endif
- if ((hwconfig_sub("fsl_ddr", "bank_intlv")) &&
+ if ((hwconfig_sub_f("fsl_ddr", "bank_intlv", buf)) &&
(CONFIG_CHIP_SELECTS_PER_CTRL > 1)) {
/* test null first. if CONFIG_HWCONFIG is not defined,
- * hwconfig_arg_cmp returns non-zero */
- if (hwconfig_subarg_cmp("fsl_ddr", "bank_intlv", "null"))
+ * hwconfig_subarg_cmp_f returns non-zero */
+ if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
+ "null", buf))
debug("bank interleaving disabled.\n");
- else if (hwconfig_subarg_cmp("fsl_ddr", "bank_intlv", "cs0_cs1"))
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
+ "cs0_cs1", buf))
popts->ba_intlv_ctl = FSL_DDR_CS0_CS1;
- else if (hwconfig_subarg_cmp("fsl_ddr", "bank_intlv", "cs2_cs3"))
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
+ "cs2_cs3", buf))
popts->ba_intlv_ctl = FSL_DDR_CS2_CS3;
- else if (hwconfig_subarg_cmp("fsl_ddr", "bank_intlv", "cs0_cs1_and_cs2_cs3"))
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
+ "cs0_cs1_and_cs2_cs3", buf))
popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_AND_CS2_CS3;
- else if (hwconfig_subarg_cmp("fsl_ddr", "bank_intlv", "cs0_cs1_cs2_cs3"))
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "bank_intlv",
+ "cs0_cs1_cs2_cs3", buf))
popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_CS2_CS3;
else
printf("hwconfig has unrecognized parameter for bank_intlv.\n");
@@ -342,10 +669,11 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
}
}
- if (hwconfig_sub("fsl_ddr", "addr_hash")) {
- if (hwconfig_subarg_cmp("fsl_ddr", "addr_hash", "null"))
+ if (hwconfig_sub_f("fsl_ddr", "addr_hash", buf)) {
+ if (hwconfig_subarg_cmp_f("fsl_ddr", "addr_hash", "null", buf))
popts->addr_hash = 0;
- else if (hwconfig_subarg_cmp("fsl_ddr", "addr_hash", "true"))
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "addr_hash",
+ "true", buf))
popts->addr_hash = 1;
}
@@ -387,3 +715,34 @@ void check_interleaving_options(fsl_ddr_info_t *pinfo)
"Memory controller interleaving disabled.\n");
}
}
+
+int fsl_use_spd(void)
+{
+ int use_spd = 0;
+
+#ifdef CONFIG_DDR_SPD
+ char buffer[HWCONFIG_BUFFER_SIZE];
+ char *buf = NULL;
+
+ /*
+ * Extract hwconfig from environment since we have not properly setup
+ * the environment but need it for ddr config params
+ */
+ if (getenv_f("hwconfig", buffer, sizeof(buffer)) > 0)
+ buf = buffer;
+
+ /* if hwconfig is not enabled, or "sdram" is not defined, use spd */
+ if (hwconfig_sub_f("fsl_ddr", "sdram", buf)) {
+ if (hwconfig_subarg_cmp_f("fsl_ddr", "sdram", "spd", buf))
+ use_spd = 1;
+ else if (hwconfig_subarg_cmp_f("fsl_ddr", "sdram",
+ "fixed", buf))
+ use_spd = 0;
+ else
+ use_spd = 1;
+ } else
+ use_spd = 1;
+#endif
+
+ return use_spd;
+}