summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/ppc/boards/freescale-p2020rdb/p2020rdb.c13
-rw-r--r--arch/ppc/configs/p2020rdb_defconfig4
-rw-r--r--arch/ppc/ddr-8xxx/common_timing_params.h44
-rw-r--r--arch/ppc/ddr-8xxx/ctrl_regs.c425
-rw-r--r--arch/ppc/ddr-8xxx/ddr.h105
-rw-r--r--arch/ppc/ddr-8xxx/ddr2_dimm_params.c303
-rw-r--r--arch/ppc/ddr-8xxx/ddr2_setctrl.c58
-rw-r--r--arch/ppc/ddr-8xxx/lc_common_dimm_params.c214
-rw-r--r--arch/ppc/ddr-8xxx/main.c238
-rw-r--r--arch/ppc/ddr-8xxx/options.c111
-rw-r--r--arch/ppc/ddr-8xxx/util.c100
-rw-r--r--arch/ppc/include/asm/fsl_ddr_dimm_params.h60
-rw-r--r--arch/ppc/include/asm/fsl_ddr_sdram.h131
-rw-r--r--arch/ppc/mach-mpc85xx/eth-devices.c44
-rw-r--r--arch/ppc/mach-mpc85xx/fsl_i2c.c253
-rw-r--r--arch/ppc/mach-mpc85xx/include/mach/fsl_i2c.h17
-rw-r--r--arch/ppc/mach-mpc85xx/include/mach/gianfar.h4
-rw-r--r--common/Makefile1
-rw-r--r--common/ddr_spd.c39
-rw-r--r--drivers/net/gianfar.c146
-rw-r--r--drivers/net/gianfar.h13
-rw-r--r--include/ddr_spd.h135
22 files changed, 2395 insertions, 63 deletions
diff --git a/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c b/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
index edb9bcd273..6426bd3c7e 100644
--- a/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
+++ b/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
@@ -59,12 +59,19 @@
#define SYSCLK_50 50000000
#define SYSCLK_100 100000000
-/* Ethernet. Use eTSEC3 */
+/* Define attributes for eTSEC2 and eTSEC3 */
static struct gfar_info_struct gfar_info[] = {
{
+ .phyaddr = 0,
+ .tbiana = 0x1a0,
+ .tbicr = 0x9140,
+ .mdiobus_tbi = 1,
+ },
+ {
.phyaddr = 1,
.tbiana = 0,
.tbicr = 0,
+ .mdiobus_tbi = 2,
},
};
@@ -82,8 +89,8 @@ static int devices_init(void)
add_generic_device("i2c-fsl", 1, NULL, I2C2_BASE_ADDR,
0x100, IORESOURCE_MEM, &i2cplat);
- /* eTSEC3 */
- fsl_eth_init(3, &gfar_info[0]);
+ fsl_eth_init(2, &gfar_info[0]);
+ fsl_eth_init(3, &gfar_info[1]);
devfs_add_partition("nor0", 0xf80000, 0x80000, DEVFS_PARTITION_FIXED,
"self0");
diff --git a/arch/ppc/configs/p2020rdb_defconfig b/arch/ppc/configs/p2020rdb_defconfig
index 7690327424..0f77903286 100644
--- a/arch/ppc/configs/p2020rdb_defconfig
+++ b/arch/ppc/configs/p2020rdb_defconfig
@@ -24,9 +24,11 @@ CONFIG_RELOCATABLE=y
CONFIG_DRIVER_NET_GIANFAR=y
CONFIG_NET=y
CONFIG_NET_PING=y
+CONFIG_FS_TFTP=y
CONFIG_NET_TFTP=y
+CONFIG_CMD_TFTP=y
CONFIG_PING=y
-CONFIG_TFTP=y
CONFIG_I2C=y
CONFIG_I2C_IMX=y
CONFIG_CMD_I2C=y
+CONFIG_CMD_MIITOOL=y
diff --git a/arch/ppc/ddr-8xxx/common_timing_params.h b/arch/ppc/ddr-8xxx/common_timing_params.h
new file mode 100644
index 0000000000..b2621937ea
--- /dev/null
+++ b/arch/ppc/ddr-8xxx/common_timing_params.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#ifndef COMMON_TIMING_PARAMS_H
+#define COMMON_TIMING_PARAMS_H
+
+struct common_timing_params_s {
+ uint32_t tCKmin_X_ps;
+ uint32_t tCKmax_ps;
+ uint32_t tCKmax_max_ps;
+ uint32_t tRCD_ps;
+ uint32_t tRP_ps;
+ uint32_t tRAS_ps;
+ uint32_t tWR_ps; /* maximum = 63750 ps */
+ uint32_t tWTR_ps; /* maximum = 63750 ps */
+ uint32_t tRFC_ps; /* maximum = 255 ns + 256 ns + .75 ns
+ = 511750 ps */
+ uint32_t tRRD_ps; /* maximum = 63750 ps */
+ uint32_t tRC_ps; /* maximum = 254 ns + .75 ns = 254750 ps */
+ uint32_t refresh_rate_ps;
+ uint32_t tIS_ps; /* byte 32, spd->ca_setup */
+ uint32_t tIH_ps; /* byte 33, spd->ca_hold */
+ uint32_t tDS_ps; /* byte 34, spd->data_setup */
+ uint32_t tDH_ps; /* byte 35, spd->data_hold */
+ uint32_t tRTP_ps; /* byte 38, spd->trtp */
+ uint32_t tDQSQ_max_ps; /* byte 44, spd->tdqsq */
+ uint32_t tQHS_ps; /* byte 45, spd->tqhs */
+ uint32_t ndimms_present;
+ uint32_t lowest_common_SPD_caslat;
+ uint32_t highest_common_derated_caslat;
+ uint32_t additive_latency;
+ uint32_t all_DIMMs_burst_lengths_bitmask;
+ uint32_t all_DIMMs_registered;
+ uint32_t all_DIMMs_ECC_capable;
+ uint64_t total_mem;
+ uint64_t base_address;
+};
+
+#endif
diff --git a/arch/ppc/ddr-8xxx/ctrl_regs.c b/arch/ppc/ddr-8xxx/ctrl_regs.c
new file mode 100644
index 0000000000..3f8ecf7c28
--- /dev/null
+++ b/arch/ppc/ddr-8xxx/ctrl_regs.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright 2008-2012 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
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+/*
+ * Generic driver for Freescale DDR2 memory controller.
+ * Based on code from spd_sdram.c
+ * Author: James Yang [at freescale.com]
+ */
+
+#include <common.h>
+#include <asm/fsl_ddr_sdram.h>
+#include "ddr.h"
+
+static void set_csn_config(int dimm_number, int i,
+ struct fsl_ddr_cfg_regs_s *ddr,
+ const struct memctl_options_s *popts,
+ const struct dimm_params_s *dimm)
+{
+ uint32_t cs_n_en = 0, ap_n_en = 0, odt_rd_cfg = 0, odt_wr_cfg = 0,
+ ba_bits_cs_n = 0, row_bits_cs_n = 0, col_bits_cs_n = 0,
+ n_banks_per_sdram_device;
+ int go_config = 0;
+
+ switch (i) {
+ case 0:
+ if (dimm[dimm_number].n_ranks > 0)
+ go_config = 1;
+ break;
+ case 1:
+ if ((dimm_number == 0 && dimm[0].n_ranks > 1) ||
+ (dimm_number == 1 && dimm[1].n_ranks > 0))
+ go_config = 1;
+ break;
+ case 2:
+ if ((dimm_number == 0 && dimm[0].n_ranks > 2) ||
+ (dimm_number >= 1 && dimm[dimm_number].n_ranks > 0))
+ go_config = 1;
+ break;
+ case 3:
+ if ((dimm_number == 0 && dimm[0].n_ranks > 3) ||
+ (dimm_number == 1 && dimm[1].n_ranks > 1) ||
+ (dimm_number == 3 && dimm[3].n_ranks > 0))
+ go_config = 1;
+ break;
+ default:
+ break;
+ }
+
+ if (go_config) {
+ /* Chip Select enable */
+ cs_n_en = 1;
+ /* CSn auto-precharge enable */
+ ap_n_en = popts->cs_local_opts[i].auto_precharge;
+ /* ODT for reads configuration */
+ odt_rd_cfg = popts->cs_local_opts[i].odt_rd_cfg;
+ /* ODT for writes configuration */
+ odt_wr_cfg = popts->cs_local_opts[i].odt_wr_cfg;
+ /* Num of bank bits for SDRAM on CSn */
+ n_banks_per_sdram_device =
+ dimm[dimm_number].n_banks_per_sdram_device;
+ ba_bits_cs_n = __ilog2(n_banks_per_sdram_device) - 2;
+ /* Num of row bits for SDRAM on CSn */
+ row_bits_cs_n = dimm[dimm_number].n_row_addr - 12;
+ /* Num of ocl bits for SDRAM on CSn */
+ col_bits_cs_n = dimm[dimm_number].n_col_addr - 8;
+ }
+
+ ddr->cs[i].config = (((cs_n_en & 0x1) << 31)
+ | ((ap_n_en & 0x1) << 23)
+ | ((odt_rd_cfg & 0x7) << 20)
+ | ((odt_wr_cfg & 0x7) << 16)
+ | ((ba_bits_cs_n & 0x3) << 14)
+ | ((row_bits_cs_n & 0x7) << 8)
+ | ((col_bits_cs_n & 0x7) << 0));
+}
+
+static void set_timing_cfg_0(struct fsl_ddr_cfg_regs_s *ddr,
+ const struct memctl_options_s *popts)
+{
+ uint32_t trwt_mclk = 0;
+
+ if (popts->trwt_override)
+ trwt_mclk = popts->trwt;
+
+ ddr->timing_cfg_0 = (((trwt_mclk & 0x3) << 30)
+ | ((popts->txard & 0x7) << 20)
+ | ((popts->txp & 0xF) << 16)
+ | ((popts->taxpd & 0xf) << 8)
+ | ((popts->tmrd & 0xf) << 0));
+}
+
+static void set_timing_cfg_3(struct fsl_ddr_cfg_regs_s *ddr,
+ const struct common_timing_params_s *dimm,
+ uint32_t cas_latency)
+{
+ uint32_t ext_pretoact, ext_acttopre, ext_acttorw, ext_refrec;
+
+ ext_pretoact = picos_to_mclk(dimm->tRP_ps) >> 4;
+ ext_acttopre = picos_to_mclk(dimm->tRAS_ps) >> 4;
+ ext_acttorw = picos_to_mclk(dimm->tRCD_ps) >> 4;
+ cas_latency = ((cas_latency << 1) - 1) >> 4;
+ ext_refrec = (picos_to_mclk(dimm->tRFC_ps) - 8) >> 4;
+
+ ddr->timing_cfg_3 = (((ext_pretoact & 0x1) << 28)
+ | ((ext_acttopre & 0x2) << 24)
+ | ((ext_acttorw & 0x1) << 22)
+ | ((ext_refrec & 0x1F) << 16)
+ | ((cas_latency & 0x3) << 12));
+}
+
+static void set_timing_cfg_1(struct fsl_ddr_cfg_regs_s *ddr,
+ const struct common_timing_params_s *dimm,
+ uint32_t cas_latency)
+{
+ uint32_t pretoact_mclk, acttopre_mclk, acttorw_mclk, refrec_ctrl,
+ wrrec_mclk, acttoact_mclk, wrtord_mclk;
+ /* DDR_SDRAM_MODE doesn't support 9,11,13,15 */
+ static const u8 wrrec_table[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 10, 10, 12, 12, 14, 14, 0, 0
+ };
+
+ pretoact_mclk = picos_to_mclk(dimm->tRP_ps);
+ acttopre_mclk = picos_to_mclk(dimm->tRAS_ps);
+ acttorw_mclk = picos_to_mclk(dimm->tRCD_ps);
+
+ /*
+ * Translate CAS Latency to a DDR controller field value:
+ *
+ * CAS Lat DDR II Ctrl
+ * Clocks SPD Bit Value
+ * ------- ------- ------
+ * 1.0 0001
+ * 1.5 0010
+ * 2.0 2 0011
+ * 2.5 0100
+ * 3.0 3 0101
+ * 3.5 0110
+ * 4.0 4 0111
+ * 4.5 1000
+ * 5.0 5 1001
+ */
+ cas_latency = (cas_latency << 1) - 1;
+ refrec_ctrl = picos_to_mclk(dimm->tRFC_ps) - 8;
+ acttoact_mclk = picos_to_mclk(dimm->tRRD_ps);
+
+ wrrec_mclk = picos_to_mclk(dimm->tWR_ps);
+ if (wrrec_mclk <= 16)
+ wrrec_mclk = wrrec_table[wrrec_mclk - 1];
+
+ wrtord_mclk = picos_to_mclk(dimm->tWTR_ps);
+ if (wrtord_mclk < 2)
+ wrtord_mclk = 2;
+
+ ddr->timing_cfg_1 = (((pretoact_mclk & 0x0F) << 28)
+ | ((acttopre_mclk & 0x0F) << 24)
+ | ((acttorw_mclk & 0xF) << 20)
+ | ((cas_latency & 0xF) << 16)
+ | ((refrec_ctrl & 0xF) << 12)
+ | ((wrrec_mclk & 0x0F) << 8)
+ | ((acttoact_mclk & 0x0F) << 4)
+ | ((wrtord_mclk & 0x0F) << 0));
+}
+
+static void set_timing_cfg_2(struct fsl_ddr_cfg_regs_s *ddr,
+ const struct memctl_options_s *popts,
+ const struct common_timing_params_s *dimm,
+ uint32_t cas_latency, uint32_t additive_latency)
+{
+ uint32_t cpo, rd_to_pre, wr_data_delay, cke_pls, four_act;
+
+ cpo = popts->cpo_override;
+ rd_to_pre = picos_to_mclk(dimm->tRTP_ps);
+ if (rd_to_pre < 2)
+ rd_to_pre = 2;
+
+ if (additive_latency)
+ rd_to_pre += additive_latency;
+
+ wr_data_delay = popts->write_data_delay;
+ cke_pls = picos_to_mclk(popts->tCKE_clock_pulse_width_ps);
+ four_act = picos_to_mclk(popts->tFAW_window_four_activates_ps);
+
+ ddr->timing_cfg_2 = (((additive_latency & 0xf) << 28)
+ | ((cpo & 0x1f) << 23)
+ | (((cas_latency - 1) & 0xf) << 19)
+ | ((rd_to_pre & 7) << 13)
+ | ((wr_data_delay & 7) << 10)
+ | ((cke_pls & 0x7) << 6)
+ | ((four_act & 0x3f) << 0));
+}
+
+static void set_ddr_sdram_cfg(struct fsl_ddr_cfg_regs_s *ddr,
+ const struct memctl_options_s *popts,
+ const struct common_timing_params_s *dimm)
+{
+ uint32_t mem_en, sren, ecc_en, sdram_type, dyn_pwr, dbw, twoT_en, hse;
+
+ mem_en = 1;
+ sren = popts->self_refresh_in_sleep;
+ if (dimm->all_DIMMs_ECC_capable)
+ ecc_en = popts->ECC_mode;
+ else
+ ecc_en = 0;
+
+ if (popts->sdram_type)
+ sdram_type = popts->sdram_type;
+ else
+ sdram_type = FSL_SDRAM_TYPE;
+
+ twoT_en = popts->twoT_en;
+ dyn_pwr = popts->dynamic_power;
+ dbw = popts->data_bus_width;
+ hse = popts->half_strength_driver_enable;
+
+ ddr->ddr_sdram_cfg = (((mem_en & 0x1) << 31)
+ | ((sren & 0x1) << 30)
+ | ((ecc_en & 0x1) << 29)
+ | ((sdram_type & 0x7) << 24)
+ | ((dyn_pwr & 0x1) << 21)
+ | ((dbw & 0x3) << 19)
+ | ((twoT_en & 0x1) << 15)
+ | ((hse & 0x1) << 3));
+}
+
+static void set_ddr_sdram_cfg_2(struct fsl_ddr_cfg_regs_s *ddr,
+ const struct memctl_options_s *popts)
+{
+ struct ddr_board_info_s *bi = popts->board_info;
+ uint32_t i, dll_rst_dis, dqs_cfg, odt_cfg = 0, num_pr, d_init = 0;
+
+ dll_rst_dis = popts->dll_rst_dis;
+ dqs_cfg = popts->DQS_config;
+
+ /*
+ * Check for On-Die Termination options and
+ * assert ODT only during reads to DRAM.
+ */
+ for (i = 0; i < bi->cs_per_ctrl; i++)
+ if (popts->cs_local_opts[i].odt_rd_cfg ||
+ popts->cs_local_opts[i].odt_wr_cfg) {
+ odt_cfg = SDRAM_CFG2_ODT_ONLY_READ;
+ break;
+ }
+
+ /* Default number of posted refresh */
+ num_pr = 1;
+
+ if (popts->ECC_init_using_memctl) {
+ d_init = 1;
+ ddr->ddr_data_init = popts->data_init;
+ }
+
+ ddr->ddr_sdram_cfg_2 = (((dll_rst_dis & 0x1) << 29)
+ | ((dqs_cfg & 0x3) << 26)
+ | ((odt_cfg & 0x3) << 21)
+ | ((num_pr & 0xf) << 12)
+ | ((d_init & 0x1) << 4));
+}
+
+static void
+set_ddr_sdram_interval(struct fsl_ddr_cfg_regs_s *ddr,
+ const struct memctl_options_s *popts,
+ const struct common_timing_params_s *dimm)
+{
+ uint32_t refint, bstopre;
+
+ refint = picos_to_mclk(dimm->refresh_rate_ps);
+ /* Precharge interval */
+ bstopre = popts->bstopre;
+
+ ddr->ddr_sdram_interval = (((refint & 0xFFFF) << 16)
+ | ((bstopre & 0x3FFF) << 0));
+}
+
+static void set_ddr_sdram_mode(struct fsl_ddr_cfg_regs_s *ddr,
+ const struct memctl_options_s *popts,
+ const struct common_timing_params_s *dimm,
+ uint32_t cas_latency,
+ uint32_t additive_latency)
+{
+ uint16_t esdmode, sdmode;
+ uint32_t dqs_en, rtt, al, wr, bl;
+ const uint32_t mclk_ps = get_memory_clk_period_ps();
+
+ /* DQS# Enable: 0=enable, 1=disable */
+ dqs_en = !popts->DQS_config;
+ /* Posted CAS# additive latency (AL) */
+ al = additive_latency;
+ /* Internal Termination Resistor */
+ if (popts->rtt_override)
+ rtt = popts->rtt_override_value;
+ else
+ rtt = popts->cs_local_opts[0].odt_rtt_norm;
+
+ /*
+ * Extended SDRAM mode.
+ * The variable also selects:
+ * - OCD set to exit mode
+ * - all outputs bit i.e DQ, DQS, RDQS output enabled
+ * - RDQS ball disabled
+ * - DQS ball enabled
+ * - DLL enabled
+ * - Output drive strength: full strength.
+ */
+ esdmode = (((dqs_en & 0x1) << 10)
+ | ((rtt & 0x2) << 5)
+ | ((al & 0x7) << 3)
+ | ((rtt & 0x1) << 2));
+
+ /* Write recovery */
+ wr = (dimm->tWR_ps + mclk_ps - 1) / (mclk_ps - 1);
+
+ switch (popts->burst_length) {
+ case DDR_BL4:
+ bl = 2;
+ break;
+ case DDR_BL8:
+ bl = 3;
+ break;
+ default:
+ bl = 2;
+ break;
+ }
+
+ /* SDRAM mode
+ * The variable also selects:
+ * - power down mode: fast exit (normal)
+ * - DLL reset disabled.
+ * - burst type: sequential
+ */
+ sdmode = (((wr & 0x7) << 9)
+ | ((cas_latency & 0x7) << 4)
+ | ((bl & 0x7) << 0));
+
+ ddr->ddr_sdram_mode = (((esdmode & 0xFFFF) << 16)
+ | ((sdmode & 0xFFFF) << 0));
+}
+
+uint32_t check_fsl_memctl_config_regs(const struct fsl_ddr_cfg_regs_s *ddr)
+{
+ /*
+ * DDR_SDRAM_CFG[RD_EN] and DDR_SDRAM_CFG[2T_EN should not
+ * be set at the same time.
+ */
+ if ((ddr->ddr_sdram_cfg & 0x10000000) &&
+ (ddr->ddr_sdram_cfg & 0x00008000))
+ return 1;
+
+ return 0;
+}
+
+uint32_t
+compute_fsl_memctl_config_regs(const struct memctl_options_s *popts,
+ struct fsl_ddr_cfg_regs_s *ddr,
+ const struct common_timing_params_s *dimm,
+ const struct dimm_params_s *dimmp,
+ uint32_t dbw_cap_adj)
+{
+ struct ddr_board_info_s *binfo = popts->board_info;
+ uint32_t cas_latency, additive_latency, i, cs_per_dimm,
+ dimm_number;
+ uint64_t ea, sa, rank_density;
+
+ if (dimm == NULL)
+ return 1;
+
+ memset(ddr, 0, sizeof(struct fsl_ddr_cfg_regs_s));
+
+ /* Process overrides first. */
+ if (popts->cas_latency_override)
+ cas_latency = popts->cas_latency_override_value;
+ else
+ cas_latency = dimm->lowest_common_SPD_caslat;
+
+ if (popts->additive_latency_override)
+ additive_latency = popts->additive_latency_override_value;
+ else
+ additive_latency = dimm->additive_latency;
+
+ /* Chip Select Memory Bounds (CSn_BNDS) */
+ for (i = 0; i < binfo->cs_per_ctrl; i++) {
+ cs_per_dimm = binfo->cs_per_ctrl / binfo->dimm_slots_per_ctrl;
+ dimm_number = i / cs_per_dimm;
+ rank_density =
+ dimmp[dimm_number].rank_density >> dbw_cap_adj;
+
+ if (dimmp[dimm_number].n_ranks == 0)
+ continue;
+
+ sa = dimmp[dimm_number].base_address;
+ ea = sa + rank_density - 1;
+ if (dimmp[dimm_number].n_ranks > (i % cs_per_dimm)) {
+ sa += (i % cs_per_dimm) * rank_density;
+ ea += (i % cs_per_dimm) * rank_density;
+ } else {
+ sa = 0;
+ ea = 0;
+ }
+ sa >>= 24;
+ ea >>= 24;
+
+ ddr->cs[i].bnds = (((sa & 0xFFF) << 16) | ((ea & 0xFFF) << 0));
+ set_csn_config(dimm_number, i, ddr, popts, dimmp);
+ }
+
+ set_timing_cfg_0(ddr, popts);
+ set_timing_cfg_3(ddr, dimm, cas_latency);
+ set_timing_cfg_1(ddr, dimm, cas_latency);
+ set_timing_cfg_2(ddr, popts, dimm, cas_latency, additive_latency);
+ set_ddr_sdram_cfg(ddr, popts, dimm);
+ set_ddr_sdram_cfg_2(ddr, popts);
+ set_ddr_sdram_mode(ddr, popts, dimm, cas_latency, additive_latency);
+ set_ddr_sdram_interval(ddr, popts, dimm);
+
+ ddr->ddr_data_init = popts->data_init;
+ ddr->ddr_sdram_clk_cntl = (popts->clk_adjust & 0xF) << 23;
+
+ return check_fsl_memctl_config_regs(ddr);
+}
diff --git a/arch/ppc/ddr-8xxx/ddr.h b/arch/ppc/ddr-8xxx/ddr.h
new file mode 100644
index 0000000000..6574500acc
--- /dev/null
+++ b/arch/ppc/ddr-8xxx/ddr.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2013 GE Intelligent Platforms, Inc
+ * Copyright 2008-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
+ * Version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef FSL_DDR_MAIN_H
+#define FSL_DDR_MAIN_H
+
+#include <asm/fsl_ddr_sdram.h>
+#include <asm/fsl_ddr_dimm_params.h>
+#include <mach/fsl_i2c.h>
+#include <mach/clock.h>
+#include "common_timing_params.h"
+
+#ifdef CONFIG_MPC85xx
+#include <mach/immap_85xx.h>
+#endif
+
+/* Record of computed register values. */
+struct fsl_ddr_cfg_regs_s {
+ struct {
+ uint32_t bnds;
+ uint32_t config;
+ uint32_t config_2;
+ } cs[MAX_CHIP_SELECTS_PER_CTRL];
+ uint32_t timing_cfg_3;
+ uint32_t timing_cfg_0;
+ uint32_t timing_cfg_1;
+ uint32_t timing_cfg_2;
+ uint32_t ddr_sdram_cfg;
+ uint32_t ddr_sdram_cfg_2;
+ uint32_t ddr_sdram_mode;
+ uint32_t ddr_sdram_mode_2;
+ uint32_t ddr_sdram_mode_3;
+ uint32_t ddr_sdram_mode_4;
+ uint32_t ddr_sdram_mode_5;
+ uint32_t ddr_sdram_mode_6;
+ uint32_t ddr_sdram_mode_7;
+ uint32_t ddr_sdram_mode_8;
+ uint32_t ddr_sdram_md_cntl;
+ uint32_t ddr_sdram_interval;
+ uint32_t ddr_data_init;
+ uint32_t ddr_sdram_clk_cntl;
+ uint32_t ddr_init_addr;
+ uint32_t ddr_init_ext_addr;
+ uint32_t err_disable;
+ uint32_t err_int_en;
+ uint32_t debug[32];
+};
+
+/*
+ * Data Structures
+ *
+ * All data structures have to be on the stack
+ */
+struct fsl_ddr_info_s {
+ generic_spd_eeprom_t
+ spd_installed_dimms[MAX_DIMM_SLOTS_PER_CTLR];
+ struct dimm_params_s
+ dimm_params[MAX_DIMM_SLOTS_PER_CTLR];
+ struct memctl_options_s memctl_opts;
+ struct common_timing_params_s common_timing_params;
+ struct fsl_ddr_cfg_regs_s fsl_ddr_config_reg;
+ struct ddr_board_info_s board_info;
+};
+
+uint32_t mclk_to_picos(uint32_t mclk);
+uint32_t get_memory_clk_period_ps(void);
+uint32_t picos_to_mclk(uint32_t picos);
+uint32_t check_fsl_memctl_config_regs(const struct fsl_ddr_cfg_regs_s *ddr);
+uint64_t fsl_ddr_compute(struct fsl_ddr_info_s *pinfo);
+uint32_t compute_fsl_memctl_config_regs(
+ const struct memctl_options_s *popts,
+ struct fsl_ddr_cfg_regs_s *ddr,
+ const struct common_timing_params_s *common_dimm,
+ const struct dimm_params_s *dimm_parameters,
+ uint32_t dbw_capacity_adjust);
+uint32_t compute_dimm_parameters(
+ const generic_spd_eeprom_t *spdin,
+ struct dimm_params_s *pdimm);
+uint32_t compute_lowest_common_dimm_parameters(
+ const struct dimm_params_s *dimm_params,
+ struct common_timing_params_s *outpdimm,
+ uint32_t number_of_dimms);
+uint32_t populate_memctl_options(
+ int all_DIMMs_registered,
+ struct memctl_options_s *popts,
+ struct dimm_params_s *pdimm);
+int fsl_ddr_set_lawbar(
+ const struct common_timing_params_s *memctl_common_params,
+ uint32_t memctl_interleaved);
+int fsl_ddr_get_spd(
+ generic_spd_eeprom_t *ctrl_dimms_spd,
+ struct ddr_board_info_s *binfo);
+int fsl_ddr_set_memctl_regs(
+ const struct fsl_ddr_info_s *info);
+void fsl_ddr_board_options(
+ struct memctl_options_s *popts,
+ struct dimm_params_s *pdimm);
+void fsl_ddr_board_info(struct ddr_board_info_s *info);
+#endif
diff --git a/arch/ppc/ddr-8xxx/ddr2_dimm_params.c b/arch/ppc/ddr-8xxx/ddr2_dimm_params.c
new file mode 100644
index 0000000000..b36a8887da
--- /dev/null
+++ b/arch/ppc/ddr-8xxx/ddr2_dimm_params.c
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ */
+
+#include <common.h>
+#include <asm/fsl_ddr_sdram.h>
+#include "ddr.h"
+/*
+ * Calculate the Density of each Physical Rank.
+ * Returned size is in bytes.
+ *
+ * Table comes from Byte 31 of JEDEC SPD Spec.
+ *
+ * DDR II
+ * Bit Size Size
+ * --- -----
+ * 7 high 512MB
+ * 6 256MB
+ * 5 128MB
+ * 4 16GB
+ * 3 8GB
+ * 2 4GB
+ * 1 2GB
+ * 0 low 1GB
+ *
+ * Reorder Table to be linear by stripping the bottom
+ * 2 or 5 bits off and shifting them up to the top.
+ *
+ */
+static uint64_t compute_ranksize(uint32_t mem_type, unsigned char row_dens)
+{
+ uint64_t bsize;
+
+ bsize = ((row_dens >> 5) | ((row_dens & 31) << 3));
+ bsize <<= 27ULL;
+
+ return bsize;
+}
+
+/*
+ * Convert a two-nibble BCD value into a cycle time.
+ * While the spec calls for nano-seconds, picos are returned.
+ */
+static uint32_t convert_bcd_tenths_to_cycle_time_ps(uint32_t spd_val)
+{
+ uint32_t tenths_ps[16] = {
+ 0,
+ 100,
+ 200,
+ 300,
+ 400,
+ 500,
+ 600,
+ 700,
+ 800,
+ 900,
+ 250,
+ 330,
+ 660,
+ 750,
+ 0,
+ 0
+ };
+ uint32_t whole_ns = (spd_val & 0xF0) >> 4;
+ uint32_t tenth_ns = spd_val & 0x0F;
+ uint32_t ps = (whole_ns * 1000) + tenths_ps[tenth_ns];
+
+ return ps;
+}
+
+static uint32_t convert_bcd_hundredths_to_cycle_time_ps(uint32_t spd_val)
+{
+ uint32_t tenth_ns = (spd_val & 0xF0) >> 4;
+ uint32_t hundredth_ns = spd_val & 0x0F;
+ uint32_t ps = (tenth_ns * 100) + (hundredth_ns * 10);
+
+ return ps;
+}
+
+static uint32_t byte40_table_ps[8] = {
+ 0,
+ 250,
+ 330,
+ 500,
+ 660,
+ 750,
+ 0,
+ 0
+};
+
+static uint32_t
+compute_trfc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trfc)
+{
+ uint32_t trfc_ps;
+
+ trfc_ps = (((trctrfc_ext & 0x1) * 256) + trfc) * 1000;
+ trfc_ps += byte40_table_ps[(trctrfc_ext >> 1) & 0x7];
+
+ return trfc_ps;
+}
+
+static uint32_t
+compute_trc_ps_from_spd(unsigned char trctrfc_ext, unsigned char trc)
+{
+ uint32_t trc_ps;
+
+ trc_ps = (trc * 1000);
+ trc_ps += byte40_table_ps[(trctrfc_ext >> 4) & 0x7];
+
+ return trc_ps;
+}
+
+/*
+ * Determine Refresh Rate.
+ * Table from SPD Spec, Byte 12, converted to picoseconds and
+ * filled in with "default" normal values.
+ */
+static uint32_t determine_refresh_rate_ps(const uint32_t spd_refresh)
+{
+ uint32_t refresh_time_ps[8] = {
+ 15625000, /* 0 Normal 1.00x */
+ 3900000, /* 1 Reduced .25x */
+ 7800000, /* 2 Extended .50x */
+ 31300000, /* 3 Extended 2.00x */
+ 62500000, /* 4 Extended 4.00x */
+ 125000000, /* 5 Extended 8.00x */
+ 15625000, /* 6 Normal 1.00x filler */
+ 15625000, /* 7 Normal 1.00x filler */
+ };
+
+ return refresh_time_ps[spd_refresh & 0x7];
+}
+
+/*
+ * The purpose of this function is to compute a suitable
+ * CAS latency given the DRAM clock period. The SPD only
+ * defines at most 3 CAS latencies. Typically the slower in
+ * frequency the DIMM runs at, the shorter its CAS latency can.
+ * be. If the DIMM is operating at a sufficiently low frequency,
+ * it may be able to run at a CAS latency shorter than the
+ * shortest SPD-defined CAS latency.
+ *
+ * If a CAS latency is not found, 0 is returned.
+ *
+ * Do this by finding in the standard speed table the longest
+ * tCKmin that doesn't exceed the value of mclk_ps (tCK).
+ *
+ * An assumption made is that the SDRAM device allows the
+ * CL to be programmed for a value that is lower than those
+ * advertised by the SPD. This is not always the case,
+ * as those modes not defined in the SPD are optional.
+ *
+ * CAS latency de-rating based upon values JEDEC Standard No. 79-2C
+ * Table 40, "DDR2 SDRAM standard speed bins and tCK, tRCD, tRP, tRAS,
+ * and tRC for corresponding bin"
+ *
+ * ordinal 2, ddr2_speed_bins[1] contains tCK for CL=3
+ * Not certain if any good value exists for CL=2
+ */
+ /* CL2 CL3 CL4 CL5 CL6 CL7 */
+uint16_t ddr2_speed_bins[] = { 0, 5000, 3750, 3000, 2500, 1875 };
+
+uint32_t compute_derated_DDR2_CAS_latency(uint32_t mclk_ps)
+{
+ const uint32_t num_speed_bins = ARRAY_SIZE(ddr2_speed_bins);
+ uint32_t lowest_tCKmin_found = 0, lowest_tCKmin_CL = 0, i, x;
+
+ for (i = 0; i < num_speed_bins; i++) {
+ x = ddr2_speed_bins[i];
+ if (x && (x <= mclk_ps) && (x >= lowest_tCKmin_found)) {
+ lowest_tCKmin_found = x;
+ lowest_tCKmin_CL = i + 2;
+ }
+ }
+
+ return lowest_tCKmin_CL;
+}
+
+/*
+ * compute_dimm_parameters for DDR2 SPD
+ *
+ * Compute DIMM parameters based upon the SPD information in SPD.
+ * Writes the results to the dimm_params_s structure pointed by pdimm.
+ */
+uint32_t
+compute_dimm_parameters(const generic_spd_eeprom_t *spdin,
+ struct dimm_params_s *pdimm)
+{
+ const struct ddr2_spd_eeprom_s *spd = spdin;
+ uint32_t retval;
+
+ if (!spd->mem_type) {
+ memset(pdimm, 0, sizeof(struct dimm_params_s));
+ goto error;
+ }
+
+ if (spd->mem_type != SPD_MEMTYPE_DDR2)
+ goto error;
+
+ retval = ddr2_spd_checksum_pass(spd);
+ if (retval)
+ goto spd_err;
+
+ /*
+ * The part name in ASCII in the SPD EEPROM is not null terminated.
+ * Guarantee null termination here by presetting all bytes to 0
+ * and copying the part name in ASCII from the SPD onto it
+ */
+ memset(pdimm->mpart, 0, sizeof(pdimm->mpart));
+ memcpy(pdimm->mpart, spd->mpart, sizeof(pdimm->mpart) - 1);
+
+ /* DIMM organization parameters */
+ pdimm->n_ranks = (spd->mod_ranks & 0x7) + 1;
+ pdimm->rank_density = compute_ranksize(spd->mem_type, spd->rank_dens);
+ pdimm->capacity = pdimm->n_ranks * pdimm->rank_density;
+ pdimm->data_width = spd->dataw;
+ pdimm->primary_sdram_width = spd->primw;
+ pdimm->ec_sdram_width = spd->ecw;
+
+ /* These are all the types defined by the JEDEC DDR2 SPD 1.3 spec */
+ switch (spd->dimm_type) {
+ case DDR2_SPD_DIMMTYPE_RDIMM:
+ case DDR2_SPD_DIMMTYPE_72B_SO_RDIMM:
+ case DDR2_SPD_DIMMTYPE_MINI_RDIMM:
+ /* Registered/buffered DIMMs */
+ pdimm->registered_dimm = 1;
+ break;
+
+ case DDR2_SPD_DIMMTYPE_UDIMM:
+ case DDR2_SPD_DIMMTYPE_SO_DIMM:
+ case DDR2_SPD_DIMMTYPE_MICRO_DIMM:
+ case DDR2_SPD_DIMMTYPE_MINI_UDIMM:
+ /* Unbuffered DIMMs */
+ pdimm->registered_dimm = 0;
+ break;
+
+ case DDR2_SPD_DIMMTYPE_72B_SO_CDIMM:
+ default:
+ goto error;
+ }
+
+ pdimm->n_row_addr = spd->nrow_addr;
+ pdimm->n_col_addr = spd->ncol_addr;
+ pdimm->n_banks_per_sdram_device = spd->nbanks;
+ pdimm->edc_config = spd->config;
+ pdimm->burst_lengths_bitmask = spd->burstl;
+ pdimm->row_density = spd->rank_dens;
+
+ /*
+ * Calculate the Maximum Data Rate based on the Minimum Cycle time.
+ * The SPD clk_cycle field (tCKmin) is measured in tenths of
+ * nanoseconds and represented as BCD.
+ */
+ pdimm->tCKmin_X_ps
+ = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle);
+ pdimm->tCKmin_X_minus_1_ps
+ = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle2);
+ pdimm->tCKmin_X_minus_2_ps
+ = convert_bcd_tenths_to_cycle_time_ps(spd->clk_cycle3);
+ pdimm->tCKmax_ps = convert_bcd_tenths_to_cycle_time_ps(spd->tckmax);
+
+ /*
+ * Compute CAS latencies defined by SPD
+ * The SPD caslat_X should have at least 1 and at most 3 bits set.
+ *
+ * If cas_lat after masking is 0, the __ilog2 function returns
+ * 255 into the variable. This behavior is abused once.
+ */
+ pdimm->caslat_X = __ilog2(spd->cas_lat);
+ pdimm->caslat_X_minus_1 = __ilog2(spd->cas_lat
+ & ~(1 << pdimm->caslat_X));
+ pdimm->caslat_X_minus_2 = __ilog2(spd->cas_lat & ~(1 << pdimm->caslat_X)
+ & ~(1 << pdimm->caslat_X_minus_1));
+ pdimm->caslat_lowest_derated
+ = compute_derated_DDR2_CAS_latency(get_memory_clk_period_ps());
+ pdimm->tRCD_ps = spd->trcd * 250;
+ pdimm->tRP_ps = spd->trp * 250;
+ pdimm->tRAS_ps = spd->tras * 1000;
+ pdimm->tWR_ps = spd->twr * 250;
+ pdimm->tWTR_ps = spd->twtr * 250;
+ pdimm->tRFC_ps = compute_trfc_ps_from_spd(spd->trctrfc_ext, spd->trfc);
+ pdimm->tRRD_ps = spd->trrd * 250;
+ pdimm->tRC_ps = compute_trc_ps_from_spd(spd->trctrfc_ext, spd->trc);
+ pdimm->refresh_rate_ps = determine_refresh_rate_ps(spd->refresh);
+ pdimm->tIS_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_setup);
+ pdimm->tIH_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->ca_hold);
+ pdimm->tDS_ps
+ = convert_bcd_hundredths_to_cycle_time_ps(spd->data_setup);
+ pdimm->tDH_ps = convert_bcd_hundredths_to_cycle_time_ps(spd->data_hold);
+ pdimm->tRTP_ps = spd->trtp * 250;
+ pdimm->tDQSQ_max_ps = spd->tdqsq * 10;
+ pdimm->tQHS_ps = spd->tqhs * 10;
+
+ return 0;
+error:
+ return 1;
+spd_err:
+ return 2;
+}
diff --git a/arch/ppc/ddr-8xxx/ddr2_setctrl.c b/arch/ppc/ddr-8xxx/ddr2_setctrl.c
new file mode 100644
index 0000000000..14571b0489
--- /dev/null
+++ b/arch/ppc/ddr-8xxx/ddr2_setctrl.c
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#include <common.h>
+#include <config.h>
+#include <asm/io.h>
+#include <asm/fsl_ddr_sdram.h>
+#include <mach/early_udelay.h>
+#include "ddr.h"
+
+int fsl_ddr_set_memctl_regs(const struct fsl_ddr_info_s *info)
+{
+ uint32_t i;
+ void __iomem *ddr;
+ const struct fsl_ddr_cfg_regs_s *regs;
+
+ regs = &info->fsl_ddr_config_reg;
+ ddr = info->board_info.ddr_base;
+
+ if (in_be32(ddr + DDR_OFF(SDRAM_CFG)) & SDRAM_CFG_MEM_EN)
+ return 0;
+
+ for (i = 0; i < info->board_info.cs_per_ctrl; i++) {
+ out_be32(ddr + DDR_OFF(CS0_BNDS) + (i << 3), regs->cs[i].bnds);
+ out_be32(ddr + DDR_OFF(CS0_CONFIG) + (i << 2),
+ regs->cs[i].config);
+ }
+
+ out_be32(ddr + DDR_OFF(TIMING_CFG_3), regs->timing_cfg_3);
+ out_be32(ddr + DDR_OFF(TIMING_CFG_0), regs->timing_cfg_0);
+ out_be32(ddr + DDR_OFF(TIMING_CFG_1), regs->timing_cfg_1);
+ out_be32(ddr + DDR_OFF(TIMING_CFG_2), regs->timing_cfg_2);
+ out_be32(ddr + DDR_OFF(SDRAM_CFG_2), regs->ddr_sdram_cfg_2);
+ out_be32(ddr + DDR_OFF(SDRAM_MODE), regs->ddr_sdram_mode);
+ out_be32(ddr + DDR_OFF(SDRAM_MODE_2), regs->ddr_sdram_mode_2);
+ out_be32(ddr + DDR_OFF(SDRAM_MD_CNTL), regs->ddr_sdram_md_cntl);
+ out_be32(ddr + DDR_OFF(SDRAM_INTERVAL), regs->ddr_sdram_interval);
+ out_be32(ddr + DDR_OFF(SDRAM_DATA_INIT), regs->ddr_data_init);
+ out_be32(ddr + DDR_OFF(SDRAM_CLK_CNTL), regs->ddr_sdram_clk_cntl);
+ out_be32(ddr + DDR_OFF(SDRAM_INIT_ADDR), regs->ddr_init_addr);
+ out_be32(ddr + DDR_OFF(SDRAM_INIT_ADDR_EXT), regs->ddr_init_ext_addr);
+
+ early_udelay(200);
+ asm volatile("sync;isync");
+
+ out_be32(ddr + DDR_OFF(SDRAM_CFG), regs->ddr_sdram_cfg);
+
+ /* Poll DDR_SDRAM_CFG_2[D_INIT] bit until auto-data init is done. */
+ while (in_be32(ddr + DDR_OFF(SDRAM_CFG_2)) & SDRAM_CFG2_D_INIT)
+ early_udelay(10000);
+
+ return 0;
+}
diff --git a/arch/ppc/ddr-8xxx/lc_common_dimm_params.c b/arch/ppc/ddr-8xxx/lc_common_dimm_params.c
new file mode 100644
index 0000000000..a1addb0696
--- /dev/null
+++ b/arch/ppc/ddr-8xxx/lc_common_dimm_params.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2008-2012 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.
+ */
+
+#include <common.h>
+#include <config.h>
+#include <asm/fsl_ddr_sdram.h>
+
+#include "ddr.h"
+
+static unsigned int common_burst_length(
+ const struct dimm_params_s *dimm_params,
+ const unsigned int number_of_dimms)
+{
+ unsigned int i, temp;
+
+ temp = 0xff;
+ for (i = 0; i < number_of_dimms; i++)
+ if (dimm_params[i].n_ranks)
+ temp &= dimm_params[i].burst_lengths_bitmask;
+
+ return temp;
+}
+
+/* Compute a CAS latency suitable for all DIMMs */
+static unsigned int compute_lowest_caslat(
+ const struct dimm_params_s *dimm_params,
+ const unsigned int number_of_dimms)
+{
+ uint32_t temp1, temp2, i, not_ok, lowest_good_caslat,
+ tCKmin_X_minus_1_ps, tCKmin_X_minus_2_ps;
+ const unsigned int mclk_ps = get_memory_clk_period_ps();
+
+ /*
+ * Step 1: find CAS latency common to all DIMMs using bitwise
+ * operation.
+ */
+ temp1 = 0xFF;
+ for (i = 0; i < number_of_dimms; i++)
+ if (dimm_params[i].n_ranks) {
+ temp2 = 0;
+ temp2 |= 1 << dimm_params[i].caslat_X;
+ temp2 |= 1 << dimm_params[i].caslat_X_minus_1;
+ temp2 |= 1 << dimm_params[i].caslat_X_minus_2;
+ /*
+ * FIXME: If there was no entry for X-2 (X-1) in
+ * the SPD, then caslat_X_minus_2
+ * (caslat_X_minus_1) contains either 255 or
+ * 0xFFFFFFFF because that's what the __ilog2
+ * function returns for an input of 0.
+ * On 32-bit PowerPC, left shift counts with bit
+ * 26 set (that the value of 255 or 0xFFFFFFFF
+ * will have), cause the destination register to
+ * be 0. That is why this works.
+ */
+ temp1 &= temp2;
+ }
+
+ /*
+ * Step 2: check each common CAS latency against tCK of each
+ * DIMM's SPD.
+ */
+ lowest_good_caslat = 0;
+ temp2 = 0;
+ while (temp1) {
+ not_ok = 0;
+ temp2 = __ilog2(temp1);
+
+ for (i = 0; i < number_of_dimms; i++) {
+ if (!dimm_params[i].n_ranks)
+ continue;
+
+ if (dimm_params[i].caslat_X == temp2) {
+ if (mclk_ps >= dimm_params[i].tCKmin_X_ps)
+ continue;
+ else
+ not_ok++;
+ }
+
+ if (dimm_params[i].caslat_X_minus_1 == temp2) {
+ tCKmin_X_minus_1_ps =
+ dimm_params[i].tCKmin_X_minus_1_ps;
+ if (mclk_ps >= tCKmin_X_minus_1_ps)
+ continue;
+ else
+ not_ok++;
+ }
+
+ if (dimm_params[i].caslat_X_minus_2 == temp2) {
+ tCKmin_X_minus_2_ps
+ = dimm_params[i].tCKmin_X_minus_2_ps;
+ if (mclk_ps >= tCKmin_X_minus_2_ps)
+ continue;
+ else
+ not_ok++;
+ }
+ }
+
+ if (!not_ok)
+ lowest_good_caslat = temp2;
+
+ temp1 &= ~(1 << temp2);
+ }
+ return lowest_good_caslat;
+}
+
+/*
+ * compute_lowest_common_dimm_parameters()
+ *
+ * Determine the worst-case DIMM timing parameters from the set of DIMMs
+ * whose parameters have been computed into the array pointed to
+ * by dimm_params.
+ */
+unsigned int
+compute_lowest_common_dimm_parameters(const struct dimm_params_s *dimm,
+ struct common_timing_params_s *out,
+ const unsigned int number_of_dimms)
+{
+ const uint32_t mclk_ps = get_memory_clk_period_ps();
+ uint32_t temp1, i;
+ struct common_timing_params_s tmp = {0};
+
+ tmp.tCKmax_ps = 0xFFFFFFFF;
+ temp1 = 0;
+ for (i = 0; i < number_of_dimms; i++) {
+ if (dimm[i].n_ranks == 0) {
+ temp1++;
+ continue;
+ }
+
+ /*
+ * Find minimum tCKmax_ps to find fastest slow speed,
+ * i.e., this is the slowest the whole system can go.
+ */
+ tmp.tCKmax_ps = min(tmp.tCKmax_ps, dimm[i].tCKmax_ps);
+
+ /* Find maximum value to determine slowest speed, delay, etc */
+ tmp.tCKmin_X_ps = max(tmp.tCKmin_X_ps, dimm[i].tCKmin_X_ps);
+ tmp.tCKmax_max_ps = max(tmp.tCKmax_max_ps, dimm[i].tCKmax_ps);
+ tmp.tRCD_ps = max(tmp.tRCD_ps, dimm[i].tRCD_ps);
+ tmp.tRP_ps = max(tmp.tRP_ps, dimm[i].tRP_ps);
+ tmp.tRAS_ps = max(tmp.tRAS_ps, dimm[i].tRAS_ps);
+ tmp.tWR_ps = max(tmp.tWR_ps, dimm[i].tWR_ps);
+ tmp.tWTR_ps = max(tmp.tWTR_ps, dimm[i].tWTR_ps);
+ tmp.tRFC_ps = max(tmp.tRFC_ps, dimm[i].tRFC_ps);
+ tmp.tRRD_ps = max(tmp.tRRD_ps, dimm[i].tRRD_ps);
+ tmp.tRC_ps = max(tmp.tRC_ps, dimm[i].tRC_ps);
+ tmp.tIS_ps = max(tmp.tIS_ps, dimm[i].tIS_ps);
+ tmp.tIH_ps = max(tmp.tIH_ps, dimm[i].tIH_ps);
+ tmp.tDS_ps = max(tmp.tDS_ps, dimm[i].tDS_ps);
+ tmp.tDH_ps = max(tmp.tDH_ps, dimm[i].tDH_ps);
+ tmp.tRTP_ps = max(tmp.tRTP_ps, dimm[i].tRTP_ps);
+ tmp.tQHS_ps = max(tmp.tQHS_ps, dimm[i].tQHS_ps);
+ tmp.refresh_rate_ps = max(tmp.refresh_rate_ps,
+ dimm[i].refresh_rate_ps);
+ /* Find maximum tDQSQ_max_ps to find slowest timing. */
+ tmp.tDQSQ_max_ps = max(tmp.tDQSQ_max_ps, dimm[i].tDQSQ_max_ps);
+ }
+ tmp.ndimms_present = number_of_dimms - temp1;
+
+ if (temp1 == number_of_dimms)
+ return 0;
+
+ temp1 = common_burst_length(dimm, number_of_dimms);
+ tmp.all_DIMMs_burst_lengths_bitmask = temp1;
+ tmp.all_DIMMs_registered = 0;
+
+ tmp.lowest_common_SPD_caslat = compute_lowest_caslat(dimm,
+ number_of_dimms);
+ /*
+ * Compute a common 'de-rated' CAS latency.
+ *
+ * The strategy here is to find the *highest* de-rated cas latency
+ * with the assumption that all of the DIMMs will support a de-rated
+ * CAS latency higher than or equal to their lowest de-rated value.
+ */
+ temp1 = 0;
+ for (i = 0; i < number_of_dimms; i++)
+ temp1 = max(temp1, dimm[i].caslat_lowest_derated);
+ tmp.highest_common_derated_caslat = temp1;
+
+ temp1 = 1;
+ for (i = 0; i < number_of_dimms; i++)
+ if (dimm[i].n_ranks &&
+ !(dimm[i].edc_config & EDC_ECC)) {
+ temp1 = 0;
+ break;
+ }
+ tmp.all_DIMMs_ECC_capable = temp1;
+
+ if (mclk_ps > tmp.tCKmax_max_ps)
+ return 1;
+
+ /*
+ * AL must be less or equal to tRCD. Typically, AL would
+ * be AL = tRCD - 1;
+ *
+ * When ODT read or write is enabled the sum of CAS latency +
+ * additive latency must be at least 3 cycles.
+ *
+ */
+ if ((tmp.lowest_common_SPD_caslat < 4) && (picos_to_mclk(tmp.tRCD_ps) >
+ tmp.lowest_common_SPD_caslat))
+ tmp.additive_latency = picos_to_mclk(tmp.tRCD_ps) -
+ tmp.lowest_common_SPD_caslat;
+
+ memcpy(out, &tmp, sizeof(struct common_timing_params_s));
+
+ return 0;
+}
diff --git a/arch/ppc/ddr-8xxx/main.c b/arch/ppc/ddr-8xxx/main.c
new file mode 100644
index 0000000000..6e4a02d568
--- /dev/null
+++ b/arch/ppc/ddr-8xxx/main.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2008-2012 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 DDR2 memory controller.
+ * Based on code from spd_sdram.c
+ * Author: James Yang [at freescale.com]
+ */
+
+#include <common.h>
+#include <config.h>
+#include <asm/fsl_law.h>
+#include "ddr.h"
+
+static int get_spd(generic_spd_eeprom_t *spd,
+ struct ddr_board_info_s *bi, u8 i2c_address)
+{
+ int ret;
+
+ fsl_i2c_init(bi->i2c_base, bi->i2c_speed, bi->i2c_slave);
+ ret = fsl_i2c_read(bi->i2c_base, i2c_address, 0, 1, (uchar *) spd,
+ sizeof(generic_spd_eeprom_t));
+ fsl_i2c_stop(bi->i2c_base);
+
+ return ret;
+}
+
+int fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
+ struct ddr_board_info_s *binfo)
+{
+ uint32_t i;
+ uint8_t i2c_address;
+
+ for (i = 0; i < binfo->dimm_slots_per_ctrl; i++) {
+ if (binfo->spd_i2c_addr == NULL)
+ goto error;
+ i2c_address = binfo->spd_i2c_addr[i];
+ if (get_spd(&(ctrl_dimms_spd[i]), binfo, i2c_address))
+ goto error;
+ }
+
+ return 0;
+error:
+ return 1;
+}
+
+static uint64_t step_assign_addresses(struct fsl_ddr_info_s *pinfo,
+ uint32_t dbw_cap_adj)
+{
+ uint64_t total_mem, current_mem_base, total_ctlr_mem, cap;
+ uint32_t ndimm, dw, j, found = 0;
+
+ ndimm = pinfo->board_info.dimm_slots_per_ctrl;
+ /*
+ * If a reduced data width is requested, but the SPD
+ * specifies a physically wider device, adjust the
+ * computed dimm capacities accordingly before
+ * assigning addresses.
+ */
+ switch (pinfo->memctl_opts.data_bus_width) {
+ case 2:
+ /* 16-bit */
+ for (j = 0; j < ndimm; j++) {
+ if (!pinfo->dimm_params[j].n_ranks)
+ continue;
+ dw = pinfo->dimm_params[j].primary_sdram_width;
+ if ((dw == 72 || dw == 64)) {
+ dbw_cap_adj = 2;
+ break;
+ } else if ((dw == 40 || dw == 32)) {
+ dbw_cap_adj = 1;
+ break;
+ }
+ }
+ break;
+ case 1:
+ /* 32-bit */
+ for (j = 0; j < ndimm; j++) {
+ dw = pinfo->dimm_params[j].data_width;
+ if (pinfo->dimm_params[j].n_ranks
+ && (dw == 72 || dw == 64)) {
+ /*
+ * FIXME: can't really do it
+ * like this because this just
+ * further reduces the memory
+ */
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ dbw_cap_adj = 1;
+ break;
+ case 0:
+ /* 64-bit */
+ break;
+ default:
+ return 1;
+ }
+
+ current_mem_base = 0ull;
+ total_mem = 0;
+ total_ctlr_mem = 0;
+ pinfo->common_timing_params.base_address = current_mem_base;
+
+ for (j = 0; j < ndimm; j++) {
+ cap = pinfo->dimm_params[j].capacity >> dbw_cap_adj;
+ pinfo->dimm_params[j].base_address = current_mem_base;
+ current_mem_base += cap;
+ total_ctlr_mem += cap;
+
+ }
+
+ pinfo->common_timing_params.total_mem = total_ctlr_mem;
+ total_mem += total_ctlr_mem;
+
+ return total_mem;
+}
+
+static uint32_t retrieve_max_size(struct fsl_ddr_cfg_regs_s *ddr_reg,
+ uint32_t ncs)
+{
+ uint32_t max_end = 0, end, i;
+
+ for (i = 0; i < ncs; i++)
+ if (ddr_reg->cs[i].config & 0x80000000) {
+ end = ddr_reg->cs[i].bnds & 0xFFF;
+ if (end > max_end)
+ max_end = end;
+ }
+
+ return max_end;
+}
+
+static uint32_t compute_dimm_param(struct fsl_ddr_info_s *pinfo, uint32_t ndimm)
+{
+ struct dimm_params_s *pdimm;
+ generic_spd_eeprom_t *spd;
+ uint32_t i, retval;
+
+ for (i = 0; i < ndimm; i++) {
+ spd = &(pinfo->spd_installed_dimms[i]);
+ pdimm = &(pinfo->dimm_params[i]);
+
+ retval = compute_dimm_parameters(spd, pdimm);
+
+ if (retval == 2) /* Fatal error */
+ return 1;
+ }
+
+ return 0;
+}
+
+uint64_t fsl_ddr_compute(struct fsl_ddr_info_s *pinfo)
+{
+ uint64_t total_mem = 0;
+ uint32_t ncs, ndimm, max_end = 0;
+ struct fsl_ddr_cfg_regs_s *ddr_reg;
+ struct common_timing_params_s *timing_params;
+ /* data bus width capacity adjust shift amount */
+ uint32_t dbw_capacity_adjust;
+
+ ddr_reg = &pinfo->fsl_ddr_config_reg;
+ timing_params = &pinfo->common_timing_params;
+ ncs = pinfo->board_info.cs_per_ctrl;
+ ndimm = pinfo->board_info.dimm_slots_per_ctrl;
+ dbw_capacity_adjust = 0;
+ pinfo->memctl_opts.board_info = &pinfo->board_info;
+
+ /* STEP 1: Gather all DIMM SPD data */
+ if (fsl_ddr_get_spd(pinfo->spd_installed_dimms,
+ pinfo->memctl_opts.board_info))
+ return 0;
+
+ /* STEP 2: Compute DIMM parameters from SPD data */
+ if (compute_dimm_param(pinfo, ndimm))
+ return 0;
+
+ /*
+ * STEP 3: Compute a common set of timing parameters
+ * suitable for all of the DIMMs on each memory controller
+ */
+ compute_lowest_common_dimm_parameters(pinfo->dimm_params,
+ timing_params, ndimm);
+
+ /* STEP 4: Gather configuration requirements from user */
+ populate_memctl_options(timing_params->all_DIMMs_registered,
+ &pinfo->memctl_opts,
+ pinfo->dimm_params);
+
+ /* STEP 5: Assign addresses to chip selects */
+ total_mem = step_assign_addresses(pinfo, dbw_capacity_adjust);
+
+ /* STEP 6: compute controller register values */
+ if (timing_params->ndimms_present == 0)
+ memset(ddr_reg, 0, sizeof(struct fsl_ddr_cfg_regs_s));
+
+ compute_fsl_memctl_config_regs(&pinfo->memctl_opts,
+ ddr_reg, timing_params,
+ pinfo->dimm_params,
+ dbw_capacity_adjust);
+
+ max_end = retrieve_max_size(ddr_reg, ncs);
+ total_mem = 1 + (((uint64_t)max_end << 24ULL) | 0xFFFFFFULL);
+
+ return total_mem;
+}
+
+/*
+ * fsl_ddr_sdram():
+ * This is the main function to initialize the memory.
+ *
+ * It returns amount of memory configured in bytes.
+ */
+phys_size_t fsl_ddr_sdram(void)
+{
+ uint64_t total_memory;
+ struct fsl_ddr_info_s info;
+
+ memset(&info, 0, sizeof(struct fsl_ddr_info_s));
+ /* Gather board information on the memory controller and I2C bus. */
+ fsl_ddr_board_info(&info.board_info);
+
+ total_memory = fsl_ddr_compute(&info);
+
+ if (info.common_timing_params.ndimms_present == 0)
+ return 0;
+
+ fsl_ddr_set_memctl_regs(&info);
+ fsl_ddr_set_lawbar(&info.common_timing_params, LAW_TRGT_IF_DDR_1);
+
+ return total_memory;
+}
diff --git a/arch/ppc/ddr-8xxx/options.c b/arch/ppc/ddr-8xxx/options.c
new file mode 100644
index 0000000000..22b621f52b
--- /dev/null
+++ b/arch/ppc/ddr-8xxx/options.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2008, 2010-2012 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
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <common.h>
+#include <asm/fsl_ddr_sdram.h>
+#include "ddr.h"
+
+uint32_t populate_memctl_options(int all_DIMMs_registered,
+ struct memctl_options_s *popts,
+ struct dimm_params_s *pdimm)
+{
+ const struct ddr_board_info_s *binfo = popts->board_info;
+ uint32_t i;
+
+ for (i = 0; i < binfo->cs_per_ctrl; i++) {
+ popts->cs_local_opts[i].odt_rd_cfg = FSL_DDR_ODT_NEVER;
+ popts->cs_local_opts[i].odt_wr_cfg = FSL_DDR_ODT_ALL;
+ popts->cs_local_opts[i].odt_rtt_norm = DDR2_RTT_50_OHM;
+ popts->cs_local_opts[i].odt_rtt_wr = DDR2_RTT_OFF;
+ popts->cs_local_opts[i].auto_precharge = 0;
+ }
+
+ /* Memory Organization Parameters */
+ popts->registered_dimm_en = all_DIMMs_registered;
+ popts->ECC_mode = 0; /* 0 = disabled, 1 = enabled */
+ popts->ECC_init_using_memctl = 1; /* 0 = use DMA, 1 = use memctl */
+
+ /* Choose DQS config - 1 for DDR2 */
+ popts->DQS_config = 1;
+
+ /* Choose self-refresh during sleep. */
+ popts->self_refresh_in_sleep = 1;
+
+ /* Choose dynamic power management mode. */
+ popts->dynamic_power = 0;
+
+ /*
+ * check first dimm for primary sdram width
+ * assuming all dimms are similar
+ * 0 = 64-bit, 1 = 32-bit, 2 = 16-bit
+ */
+ if (pdimm->n_ranks != 0) {
+ if ((pdimm->data_width >= 64) && (pdimm->data_width <= 72))
+ popts->data_bus_width = 0;
+ else if ((pdimm->data_width >= 32) ||
+ (pdimm->data_width <= 40))
+ popts->data_bus_width = 1;
+ else
+ panic("data width %u is invalid!\n",
+ pdimm->data_width);
+ }
+
+ /* Must be a burst length of 4 for DD2 */
+ popts->burst_length = DDR_BL4;
+ /* Decide whether to use the computed de-rated latency */
+ popts->use_derated_caslat = 0;
+
+ /*
+ * 2T_EN setting
+ *
+ * Factors to consider for 2T_EN:
+ * - number of DIMMs installed
+ * - number of components, number of active ranks
+ * - how much time you want to spend playing around
+ */
+ popts->twoT_en = 0;
+
+ /*
+ * Default BSTTOPRE precharge interval
+ *
+ * Set the parameter to 0 for global auto precharge in
+ * the board options function.
+ */
+ popts->bstopre = 0x100;
+
+ /* Minimum CKE pulse width -- tCKE(MIN) */
+ popts->tCKE_clock_pulse_width_ps
+ = mclk_to_picos(FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR);
+
+ /*
+ * Window for four activates -- tFAW
+ *
+ * Set according to specification for the memory used.
+ * The default value below would work for x4/x8 wide memory.
+ *
+ */
+ popts->tFAW_window_four_activates_ps = 37500;
+
+ /*
+ * Default powerdown exit timings.
+ * Set according to specifications for the memory used in
+ * the board options function.
+ */
+ popts->txard = 3;
+ popts->txp = 3;
+ popts->taxpd = 11;
+
+ /* Default value for load mode cycle time */
+ popts->tmrd = 2;
+
+ /* Specific board override parameters. */
+ fsl_ddr_board_options(popts, pdimm);
+
+ return 0;
+}
diff --git a/arch/ppc/ddr-8xxx/util.c b/arch/ppc/ddr-8xxx/util.c
new file mode 100644
index 0000000000..626b5f3f9b
--- /dev/null
+++ b/arch/ppc/ddr-8xxx/util.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2008-2012 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.
+ */
+
+#include <common.h>
+#include <asm/fsl_law.h>
+#include <asm-generic/div64.h>
+#include <mach/clock.h>
+#include "ddr.h"
+
+#define ULL_2E12 2000000000000ULL
+#define UL_5POW12 244140625UL
+#define UL_2POW13 (1UL << 13)
+#define ULL_8FS 0xFFFFFFFFULL
+
+/*
+ * Round up mclk_ps to nearest 1 ps in memory controller code
+ * if the error is 0.5ps or more.
+ *
+ * If an imprecise data rate is too high due to rounding error
+ * propagation, compute a suitably rounded mclk_ps to compute
+ * a working memory controller configuration.
+ */
+uint32_t get_memory_clk_period_ps(void)
+{
+ uint32_t result, data_rate = fsl_get_ddr_freq(0);
+ /* Round to nearest 10ps, being careful about 64-bit multiply/divide */
+ uint64_t rem, mclk_ps = ULL_2E12;
+
+ /* Now perform the big divide, the result fits in 32-bits */
+ rem = do_div(mclk_ps, data_rate);
+ if (rem >= (data_rate >> 1))
+ result = mclk_ps + 1;
+ else
+ result = mclk_ps;
+
+ return result;
+}
+
+/* Convert picoseconds into DRAM clock cycles (rounding up if needed). */
+uint32_t picos_to_mclk(uint32_t picos)
+{
+ uint64_t clks, clks_rem;
+ uint32_t data_rate = fsl_get_ddr_freq(0);
+
+ if (!picos)
+ return 0;
+
+ /* First multiply the time by the data rate (32x32 => 64) */
+ clks = picos * (uint64_t)data_rate;
+ /*
+ * Now divide by 5^12 and track the 32-bit remainder, then divide
+ * by 2*(2^12) using shifts (and updating the remainder).
+ */
+ clks_rem = do_div(clks, UL_5POW12);
+ clks_rem += (clks & (UL_2POW13 - 1)) * UL_5POW12;
+ clks >>= 13;
+
+ /* If we had a remainder greater than the 1ps error, then round up */
+ if (clks_rem > data_rate)
+ clks++;
+
+ if (clks > ULL_8FS)
+ clks = ULL_8FS;
+
+ return (uint32_t)clks;
+}
+
+uint32_t mclk_to_picos(unsigned int mclk)
+{
+ return get_memory_clk_period_ps() * mclk;
+}
+
+int fsl_ddr_set_lawbar(
+ const struct common_timing_params_s *params,
+ uint32_t law_memctl)
+{
+ uint64_t base = params->base_address;
+ uint64_t size = params->total_mem;
+
+ if (!params->ndimms_present)
+ goto out;
+
+ if (base >= MAX_MEM_MAPPED)
+ goto error;
+
+ if ((base + size) >= MAX_MEM_MAPPED)
+ size = MAX_MEM_MAPPED - base;
+
+ if (fsl_set_ddr_laws(base, size, law_memctl) < 0)
+ goto error;
+out:
+ return 0;
+error:
+ return 1;
+}
diff --git a/arch/ppc/include/asm/fsl_ddr_dimm_params.h b/arch/ppc/include/asm/fsl_ddr_dimm_params.h
new file mode 100644
index 0000000000..73c239be85
--- /dev/null
+++ b/arch/ppc/include/asm/fsl_ddr_dimm_params.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#ifndef DDR2_DIMM_PARAMS_H
+#define DDR2_DIMM_PARAMS_H
+
+#define EDC_ECC 2
+
+/* Parameters for a DDR2 dimm computed from the SPD */
+struct dimm_params_s {
+ char mpart[19];
+ uint32_t n_ranks;
+ uint64_t rank_density;
+ uint64_t capacity;
+ uint32_t data_width;
+ uint32_t primary_sdram_width;
+ uint32_t ec_sdram_width;
+ uint32_t registered_dimm;
+ uint32_t n_row_addr;
+ uint32_t n_col_addr;
+ uint32_t edc_config; /* 0 = none, 1 = parity, 2 = ECC */
+ uint32_t n_banks_per_sdram_device;
+ uint32_t burst_lengths_bitmask; /* BL=4 bit 2, BL=8 = bit 3 */
+ uint32_t row_density;
+ uint64_t base_address;
+ /* SDRAM clock periods */
+ uint32_t tCKmin_X_ps;
+ uint32_t tCKmin_X_minus_1_ps;
+ uint32_t tCKmin_X_minus_2_ps;
+ uint32_t tCKmax_ps;
+ /* SPD-defined CAS latencies */
+ uint32_t caslat_X;
+ uint32_t caslat_X_minus_1;
+ uint32_t caslat_X_minus_2;
+ uint32_t caslat_lowest_derated;
+ /* basic timing parameters */
+ uint32_t tRCD_ps;
+ uint32_t tRP_ps;
+ uint32_t tRAS_ps;
+ uint32_t tWR_ps; /* maximum = 63750 ps */
+ uint32_t tWTR_ps; /* maximum = 63750 ps */
+ uint32_t tRFC_ps; /* max = 255 ns + 256 ns + .75 ns = 511750 ps */
+ uint32_t tRRD_ps; /* maximum = 63750 ps */
+ uint32_t tRC_ps; /* maximum = 254 ns + .75 ns = 254750 ps */
+ uint32_t refresh_rate_ps;
+ uint32_t tIS_ps; /* byte 32, spd->ca_setup */
+ uint32_t tIH_ps; /* byte 33, spd->ca_hold */
+ uint32_t tDS_ps; /* byte 34, spd->data_setup */
+ uint32_t tDH_ps; /* byte 35, spd->data_hold */
+ uint32_t tRTP_ps; /* byte 38, spd->trtp */
+ uint32_t tDQSQ_max_ps; /* byte 44, spd->tdqsq */
+ uint32_t tQHS_ps; /* byte 45, spd->tqhs */
+};
+
+#endif
diff --git a/arch/ppc/include/asm/fsl_ddr_sdram.h b/arch/ppc/include/asm/fsl_ddr_sdram.h
index ef793c9d65..444bcbc497 100644
--- a/arch/ppc/include/asm/fsl_ddr_sdram.h
+++ b/arch/ppc/include/asm/fsl_ddr_sdram.h
@@ -10,9 +10,40 @@
#ifndef FSL_DDR_MEMCTL_H
#define FSL_DDR_MEMCTL_H
-/*
- * DDR_SDRAM_CFG - DDR SDRAM Control Configuration
- */
+#include <ddr_spd.h>
+
+/* Basic DDR Technology. */
+#define SDRAM_TYPE_DDR1 2
+#define SDRAM_TYPE_DDR2 3
+#define SDRAM_TYPE_LPDDR1 6
+#define SDRAM_TYPE_DDR3 7
+
+#define DDR_BL4 4
+#define DDR_BL8 8
+
+#define DDR2_RTT_OFF 0
+#define DDR2_RTT_75_OHM 1
+#define DDR2_RTT_150_OHM 2
+#define DDR2_RTT_50_OHM 3
+
+#if defined(CONFIG_FSL_DDR2)
+#define FSL_DDR_MIN_TCKE_PULSE_WIDTH_DDR (3)
+typedef struct ddr2_spd_eeprom_s generic_spd_eeprom_t;
+#define FSL_SDRAM_TYPE SDRAM_TYPE_DDR2
+#endif
+
+#define FSL_DDR_ODT_NEVER 0x0
+#define FSL_DDR_ODT_CS 0x1
+#define FSL_DDR_ODT_ALL_OTHER_CS 0x2
+#define FSL_DDR_ODT_OTHER_DIMM 0x3
+#define FSL_DDR_ODT_ALL 0x4
+#define FSL_DDR_ODT_SAME_DIMM 0x5
+#define FSL_DDR_ODT_CS_AND_OTHER_DIMM 0x6
+#define FSL_DDR_ODT_OTHER_CS_ONSAMEDIMM 0x7
+
+#define SDRAM_CS_CONFIG_EN 0x80000000
+
+/* DDR_SDRAM_CFG - DDR SDRAM Control Configuration */
#define SDRAM_CFG_MEM_EN 0x80000000
#define SDRAM_CFG_SREN 0x40000000
#define SDRAM_CFG_ECC_EN 0x20000000
@@ -23,11 +54,103 @@
#define SDRAM_CFG_SDRAM_TYPE_SHIFT 24
#define SDRAM_CFG_DYN_PWR 0x00200000
#define SDRAM_CFG_32_BE 0x00080000
+#define SDRAM_CFG_16_BE 0x00100000
#define SDRAM_CFG_8_BE 0x00040000
#define SDRAM_CFG_NCAP 0x00020000
#define SDRAM_CFG_2T_EN 0x00008000
#define SDRAM_CFG_BI 0x00000001
-extern phys_size_t fixed_sdram(void);
+#define SDRAM_CFG2_D_INIT 0x00000010
+#define SDRAM_CFG2_ODT_CFG_MASK 0x00600000
+#define SDRAM_CFG2_ODT_NEVER 0
+#define SDRAM_CFG2_ODT_ONLY_WRITE 1
+#define SDRAM_CFG2_ODT_ONLY_READ 2
+#define SDRAM_CFG2_ODT_ALWAYS 3
+
+#define MAX_CHIP_SELECTS_PER_CTRL 4
+#define MAX_DIMM_SLOTS_PER_CTLR 4
+
+/*
+ * Memory controller characteristics and I2C parameters to
+ * read the SPD data.
+ */
+struct ddr_board_info_s {
+ uint32_t fsl_ddr_ver;
+ void __iomem *ddr_base;
+ uint32_t cs_per_ctrl;
+ uint32_t dimm_slots_per_ctrl;
+ uint32_t i2c_bus;
+ uint32_t i2c_slave;
+ uint32_t i2c_speed;
+ void __iomem *i2c_base;
+ uint8_t *spd_i2c_addr;
+};
+/*
+ * Generalized parameters for memory controller configuration,
+ * might be a little specific to the FSL memory controller
+ */
+struct memctl_options_s {
+ struct ddr_board_info_s *board_info;
+ uint32_t sdram_type;
+ /*
+ * Memory organization parameters
+ *
+ * if DIMM is present in the system
+ * where DIMMs are with respect to chip select
+ * where chip selects are with respect to memory boundaries
+ */
+ uint32_t registered_dimm_en;
+ /* Options local to a Chip Select */
+ struct cs_local_opts_s {
+ uint32_t auto_precharge;
+ uint32_t odt_rd_cfg;
+ uint32_t odt_wr_cfg;
+ uint32_t odt_rtt_norm;
+ uint32_t odt_rtt_wr;
+ } cs_local_opts[MAX_CHIP_SELECTS_PER_CTRL];
+ /* DLL reset disable */
+ uint32_t dll_rst_dis;
+ /* Operational mode parameters */
+ uint32_t ECC_mode;
+ uint32_t ECC_init_using_memctl;
+ uint32_t data_init;
+ /* Use DQS? maybe only with DDR2? */
+ uint32_t DQS_config;
+ uint32_t self_refresh_in_sleep;
+ uint32_t dynamic_power;
+ uint32_t data_bus_width;
+ uint32_t burst_length;
+ /* Global Timing Parameters */
+ uint32_t cas_latency_override;
+ uint32_t cas_latency_override_value;
+ uint32_t use_derated_caslat;
+ uint32_t additive_latency_override;
+ uint32_t additive_latency_override_value;
+ uint32_t clk_adjust;
+ uint32_t cpo_override;
+ uint32_t write_data_delay;
+ uint32_t half_strength_driver_enable;
+ uint32_t twoT_en;
+ uint32_t bstopre;
+ uint32_t tCKE_clock_pulse_width_ps;
+ uint32_t tFAW_window_four_activates_ps;
+ /* Rtt impedance */
+ uint32_t rtt_override;
+ uint32_t rtt_override_value;
+ /* Automatic self refresh */
+ uint32_t auto_self_refresh_en;
+ /* read-to-write turnaround */
+ uint32_t trwt_override;
+ uint32_t trwt;
+ /* Powerdon timings. */
+ uint32_t txp;
+ uint32_t taxpd;
+ uint32_t txard;
+ /* Load mode cycle time */
+ uint32_t tmrd;
+};
+
+extern phys_size_t fsl_ddr_sdram(void);
+extern phys_size_t fixed_sdram(void);
#endif
diff --git a/arch/ppc/mach-mpc85xx/eth-devices.c b/arch/ppc/mach-mpc85xx/eth-devices.c
index c6e8f3660d..611a5787f8 100644
--- a/arch/ppc/mach-mpc85xx/eth-devices.c
+++ b/arch/ppc/mach-mpc85xx/eth-devices.c
@@ -22,28 +22,40 @@
#include <common.h>
#include <driver.h>
+#include <init.h>
#include <mach/immap_85xx.h>
#include <mach/gianfar.h>
-int fsl_eth_init(int num, struct gfar_info_struct *gf)
+static int fsl_phy_init(void)
{
- struct resource *res;
+ int i;
+ void __iomem *base = IOMEM(GFAR_BASE_ADDR + GFAR_TBIPA_OFFSET);
+
+ /*
+ * The TBI address must be initialised to enable the PHY to
+ * link up after the MDIO reset.
+ */
+ out_be32(base, GFAR_TBIPA_END);
+ /* All ports access external PHYs via the "gfar-mdio" device */
+ add_generic_device("gfar-mdio", 0, NULL, MDIO_BASE_ADDR,
+ 0x1000, IORESOURCE_MEM, NULL);
- res = xzalloc(3 * sizeof(struct resource));
- /* TSEC interface registers */
- res[0].start = GFAR_BASE_ADDR + ((num - 1) * 0x1000);
- res[0].end = res[0].start + 0x1000 - 1;
- res[0].flags = IORESOURCE_MEM;
- /* External PHY access always through eTSEC1 */
- res[1].start = MDIO_BASE_ADDR;
- res[1].end = res[1].start + 0x1000 - 1;
- res[1].flags = IORESOURCE_MEM;
- /* Access to TBI/RTBI interface. */
- res[2].start = MDIO_BASE_ADDR + ((num - 1) * 0x1000);
- res[2].end = res[2].start + 0x1000 - 1;
- res[2].flags = IORESOURCE_MEM;
+ for (i = 1; i < 3; i++) {
+ out_be32(base + (i * 0x1000), GFAR_TBIPA_END - i);
+ /* Use "gfar-tbiphy" devices to access internal PHY. */
+ add_generic_device("gfar-tbiphy", i, NULL,
+ MDIO_BASE_ADDR + (i * 0x1000),
+ 0x1000, IORESOURCE_MEM, NULL);
+ }
+ return 0;
+}
- add_generic_device_res("gfar", DEVICE_ID_DYNAMIC, res, 3, gf);
+coredevice_initcall(fsl_phy_init);
+int fsl_eth_init(int num, struct gfar_info_struct *gf)
+{
+ add_generic_device("gfar", DEVICE_ID_DYNAMIC, NULL,
+ GFAR_BASE_ADDR + ((num - 1) * 0x1000), 0x1000,
+ IORESOURCE_MEM, gf);
return 0;
}
diff --git a/arch/ppc/mach-mpc85xx/fsl_i2c.c b/arch/ppc/mach-mpc85xx/fsl_i2c.c
new file mode 100644
index 0000000000..51fcc64c26
--- /dev/null
+++ b/arch/ppc/mach-mpc85xx/fsl_i2c.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2013 GE Intelligent Platforms, Inc
+ * Copyright 2006,2009 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 Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Early I2C support functions to read SPD data or board
+ * information.
+ * Based on U-Boot drivers/i2c/fsl_i2c.c
+ */
+#include <common.h>
+#include <i2c/i2c.h>
+#include <mach/clock.h>
+#include <mach/immap_85xx.h>
+#include <mach/early_udelay.h>
+
+/* FSL I2C registers */
+#define FSL_I2C_ADR 0x00
+#define FSL_I2C_FDR 0x04
+#define FSL_I2C_CR 0x08
+#define FSL_I2C_SR 0x0C
+#define FSL_I2C_DR 0x10
+#define FSL_I2C_DFSRR 0x14
+
+/* Bits of FSL I2C registers */
+#define I2C_SR_RXAK 0x01
+#define I2C_SR_MIF 0x02
+#define I2C_SR_MAL 0x10
+#define I2C_SR_MBB 0x20
+#define I2C_SR_MCF 0x80
+#define I2C_CR_RSTA 0x04
+#define I2C_CR_TXAK 0x08
+#define I2C_CR_MTX 0x10
+#define I2C_CR_MSTA 0x20
+#define I2C_CR_MEN 0x80
+
+/*
+ * Set the I2C bus speed for a given I2C device
+ *
+ * parameters:
+ * - i2c: the I2C base address.
+ * - i2c_clk: I2C bus clock frequency.
+ * - speed: the desired speed of the bus.
+ *
+ * The I2C device must be stopped before calling this function.
+ *
+ * The return value is the actual bus speed that is set.
+ */
+static uint32_t fsl_set_i2c_bus_speed(const void __iomem *i2c,
+ uint32_t i2c_clk, uint32_t speed)
+{
+ uint8_t dfsr, fdr = 0x31; /* Default if no FDR found */
+ uint16_t a, b, ga, gb, bin_gb, bin_ga, divider;
+ uint32_t c_div, est_div;
+
+ divider = min((uint16_t)(i2c_clk / speed), (uint16_t) -1);
+ /* Condition 1: dfsr <= 50/T */
+ dfsr = (5 * (i2c_clk / 1000)) / 100000;
+ if (!dfsr)
+ dfsr = 1;
+ est_div = ~0;
+
+ /*
+ * Bus speed is calculated as per Freescale AN2919.
+ * a, b and dfsr matches identifiers A,B and C as in the
+ * application note.
+ */
+ for (ga = 0x4, a = 10; a <= 30; ga++, a += 2) {
+ for (gb = 0; gb < 8; gb++) {
+ b = 16 << gb;
+ c_div = b * (a + (((3 * dfsr) / b) * 2));
+
+ if ((c_div > divider) && (c_div < est_div)) {
+ est_div = c_div;
+ bin_gb = gb << 2;
+ bin_ga = (ga & 0x3) | ((ga & 0x4) << 3);
+ fdr = bin_gb | bin_ga;
+ speed = i2c_clk / est_div;
+ }
+ }
+ if (a == 20)
+ a += 2;
+ if (a == 24)
+ a += 4;
+ }
+ writeb(dfsr, i2c + FSL_I2C_DFSRR); /* set default filter */
+ writeb(fdr, i2c + FSL_I2C_FDR); /* set bus speed */
+
+ return speed;
+}
+
+void fsl_i2c_init(void __iomem *i2c, int speed, int slaveadd)
+{
+ uint32_t i2c_clk;
+
+ i2c_clk = fsl_get_i2c_freq();
+ writeb(0, i2c + FSL_I2C_CR);
+ early_udelay(5);
+
+ fsl_set_i2c_bus_speed(i2c, i2c_clk, speed);
+ writeb(slaveadd << 1, i2c + FSL_I2C_ADR);
+ writeb(0x0, i2c + FSL_I2C_SR);
+ writeb(I2C_CR_MEN, i2c + FSL_I2C_CR);
+}
+
+static uint32_t fsl_usec2ticks(uint32_t usec)
+{
+ ulong ticks;
+
+ if (usec < 1000) {
+ ticks = (usec * (fsl_get_timebase_clock() / 1000));
+ ticks = (ticks + 500) / 1000;
+ } else {
+ ticks = (usec / 10);
+ ticks *= (fsl_get_timebase_clock() / 100000);
+ }
+
+ return ticks;
+}
+
+static int fsl_i2c_wait4bus(void __iomem *i2c)
+{
+ uint64_t timeval = get_ticks();
+ const uint64_t timeout = fsl_usec2ticks(20000);
+
+ while (readb(i2c + FSL_I2C_SR) & I2C_SR_MBB)
+ if ((get_ticks() - timeval) > timeout)
+ return -1;
+
+ return 0;
+}
+
+void fsl_i2c_stop(void __iomem *i2c)
+{
+ writeb(I2C_CR_MEN, i2c + FSL_I2C_CR);
+}
+
+static int fsl_i2c_wait(void __iomem *i2c, int write)
+{
+ const uint64_t timeout = fsl_usec2ticks(100000);
+ uint64_t timeval = get_ticks();
+ int csr;
+
+ do {
+ csr = readb(i2c + FSL_I2C_SR);
+ if (csr & I2C_SR_MIF)
+ break;
+ } while ((get_ticks() - timeval) < timeout);
+
+ if ((get_ticks() - timeval) > timeout)
+ goto error;
+
+ csr = readb(i2c + FSL_I2C_SR);
+ writeb(0x0, i2c + FSL_I2C_SR);
+
+ if (csr & I2C_SR_MAL)
+ goto error;
+
+ if (!(csr & I2C_SR_MCF))
+ goto error;
+
+ if (write == 0 && (csr & I2C_SR_RXAK))
+ goto error;
+
+ return 0;
+error:
+ return -1;
+}
+
+static int __i2c_write(void __iomem *i2c, uint8_t *data, int length)
+{
+ int i;
+
+ for (i = 0; i < length; i++) {
+ writeb(data[i], i2c + FSL_I2C_DR);
+ if (fsl_i2c_wait(i2c, 0) < 0)
+ break;
+ }
+
+ return i;
+}
+
+static int __i2c_read(void __iomem *i2c, uint8_t *data, int length)
+{
+ int i;
+ uint8_t val = I2C_CR_MEN | I2C_CR_MSTA;
+
+ if (length == 1)
+ writeb(val | I2C_CR_TXAK, i2c + FSL_I2C_CR);
+ else
+ writeb(val, i2c + FSL_I2C_CR);
+
+ readb(i2c + FSL_I2C_DR);
+ for (i = 0; i < length; i++) {
+ if (fsl_i2c_wait(i2c, 1) < 0)
+ break;
+
+ /* Generate ack on last next to last byte */
+ if (i == length - 2)
+ writeb(val | I2C_CR_TXAK, i2c + FSL_I2C_CR);
+ /* Do not generate stop on last byte */
+ if (i == length - 1)
+ writeb(val | I2C_CR_MTX, i2c + FSL_I2C_CR);
+
+ data[i] = readb(i2c + FSL_I2C_DR);
+ }
+
+ return i;
+}
+
+static int
+fsl_i2c_write_addr(void __iomem *i2c, uint8_t dev, uint8_t dir, int rsta)
+{
+ uint8_t val = I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX;
+
+ if (rsta)
+ val |= I2C_CR_RSTA;
+ writeb(val, i2c + FSL_I2C_CR);
+ writeb((dev << 1) | dir, i2c + FSL_I2C_DR);
+
+ if (fsl_i2c_wait(i2c, 0) < 0)
+ return 0;
+
+ return 1;
+}
+
+int fsl_i2c_read(void __iomem *i2c, uint8_t dev, uint addr, int alen,
+ uint8_t *data, int length)
+{
+ int i = -1;
+ uint8_t *a = (uint8_t *)&addr;
+
+ if (alen && (fsl_i2c_wait4bus(i2c) >= 0) &&
+ (fsl_i2c_write_addr(i2c, dev, 0, 0) != 0) &&
+ (__i2c_write(i2c, &a[4 - alen], alen) == alen))
+ i = 0;
+
+ if (length && fsl_i2c_write_addr(i2c, dev, 1, 1) != 0)
+ i = __i2c_read(i2c, data, length);
+
+ if (i == length)
+ return 0;
+
+ return -1;
+}
diff --git a/arch/ppc/mach-mpc85xx/include/mach/fsl_i2c.h b/arch/ppc/mach-mpc85xx/include/mach/fsl_i2c.h
new file mode 100644
index 0000000000..d187c6cf49
--- /dev/null
+++ b/arch/ppc/mach-mpc85xx/include/mach/fsl_i2c.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2013 GE Intelligent Platforms, 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 Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+void fsl_i2c_init(void __iomem *i2c, int speed, int slaveadd);
+int fsl_i2c_read(void __iomem *i2c, uint8_t dev, uint addr, int alen,
+ uint8_t *data, int length);
+void fsl_i2c_stop(void __iomem *i2c);
diff --git a/arch/ppc/mach-mpc85xx/include/mach/gianfar.h b/arch/ppc/mach-mpc85xx/include/mach/gianfar.h
index ae3163865c..6a7b9e945d 100644
--- a/arch/ppc/mach-mpc85xx/include/mach/gianfar.h
+++ b/arch/ppc/mach-mpc85xx/include/mach/gianfar.h
@@ -22,10 +22,14 @@
* Platform data for the Motorola Triple Speed Ethernet Controller
*/
+#define GFAR_TBIPA_OFFSET 0x030 /* TBI PHY address */
+#define GFAR_TBIPA_END 0x1f /* Last valid PHY address */
+
struct gfar_info_struct {
unsigned int phyaddr;
unsigned int tbiana;
unsigned int tbicr;
+ unsigned int mdiobus_tbi;
};
int fsl_eth_init(int num, struct gfar_info_struct *gf);
diff --git a/common/Makefile b/common/Makefile
index 4f430b6ed1..64eacc3047 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_CMD_LOADS) += s_record.o
obj-$(CONFIG_OFTREE) += oftree.o
obj-y += memory.o
+obj-$(CONFIG_DDR_SPD) += ddr_spd.o
obj-y += memory_display.o
obj-$(CONFIG_MALLOC_DLMALLOC) += dlmalloc.o
obj-$(CONFIG_MALLOC_TLSF) += tlsf_malloc.o
diff --git a/common/ddr_spd.c b/common/ddr_spd.c
new file mode 100644
index 0000000000..c8b73ff56c
--- /dev/null
+++ b/common/ddr_spd.c
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#include <common.h>
+#include <ddr_spd.h>
+
+uint32_t ddr2_spd_checksum_pass(const struct ddr2_spd_eeprom_s *spd)
+{
+ uint32_t i, cksum = 0;
+ const uint8_t *buf = (const uint8_t *)spd;
+ uint8_t rev, spd_cksum;
+
+ rev = spd->spd_rev;
+ spd_cksum = spd->cksum;
+
+ /* Rev 1.X or less supported by this code */
+ if (rev >= 0x20)
+ goto error;
+
+ /*
+ * The checksum is calculated on the first 64 bytes
+ * of the SPD as per JEDEC specification.
+ */
+ for (i = 0; i < 63; i++)
+ cksum += *buf++;
+ cksum &= 0xFF;
+
+ if (cksum != spd_cksum)
+ goto error;
+
+ return 0;
+error:
+ return 1;
+}
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 96055bd39c..f944c6c060 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -184,10 +184,11 @@ static int gfar_open(struct eth_device *edev)
{
int ix;
struct gfar_private *priv = edev->priv;
+ struct gfar_phy *phy = priv->gfar_mdio;
void __iomem *regs = priv->regs;
int ret;
- ret = phy_device_connect(edev, &priv->miibus, priv->phyaddr,
+ ret = phy_device_connect(edev, &phy->miibus, priv->phyaddr,
gfar_adjust_link, 0, PHY_INTERFACE_MODE_NA);
if (ret)
return ret;
@@ -305,44 +306,51 @@ static uint gfar_local_mdio_read(void __iomem *phyregs, uint phyid, uint regnum)
static void gfar_configure_serdes(struct gfar_private *priv)
{
- gfar_local_mdio_write(priv->phyregs_sgmii,
+ struct gfar_phy *phy = priv->gfar_tbi;
+
+ gfar_local_mdio_write(phy->regs,
in_be32(priv->regs + GFAR_TBIPA_OFFSET), GFAR_TBI_ANA,
priv->tbiana);
- gfar_local_mdio_write(priv->phyregs_sgmii,
+ gfar_local_mdio_write(phy->regs,
in_be32(priv->regs + GFAR_TBIPA_OFFSET),
GFAR_TBI_TBICON, GFAR_TBICON_CLK_SELECT);
- gfar_local_mdio_write(priv->phyregs_sgmii,
+ gfar_local_mdio_write(phy->regs,
in_be32(priv->regs + GFAR_TBIPA_OFFSET), GFAR_TBI_CR,
priv->tbicr);
}
-/* Reset the internal and external PHYs. */
-static void gfar_init_phy(struct eth_device *dev)
+static int gfar_bus_reset(struct mii_bus *bus)
{
- struct gfar_private *priv = dev->priv;
- void __iomem *regs = priv->regs;
+ struct gfar_phy *phy = bus->priv;
uint64_t start;
- /* Assign a Physical address to the TBI */
- out_be32(regs + GFAR_TBIPA_OFFSET, GFAR_TBIPA_VALUE);
-
/* Reset MII (due to new addresses) */
- out_be32(priv->phyregs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_RESET);
- out_be32(priv->phyregs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_INIT_VALUE);
+ out_be32(phy->regs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_RESET);
+ out_be32(phy->regs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_INIT_VALUE);
start = get_time_ns();
while (!is_timeout(start, 10 * MSECOND)) {
- if (!(in_be32(priv->phyregs + GFAR_MIIMMIND_OFFSET) &
+ if (!(in_be32(phy->regs + GFAR_MIIMMIND_OFFSET) &
GFAR_MIIMIND_BUSY))
break;
}
+ return 0;
+}
- gfar_local_mdio_write(priv->phyregs, priv->phyaddr, GFAR_MIIM_CR,
+/* Reset the external PHYs. */
+static void gfar_init_phy(struct eth_device *dev)
+{
+ struct gfar_private *priv = dev->priv;
+ struct gfar_phy *phy = priv->gfar_mdio;
+ void __iomem *regs = priv->regs;
+ uint64_t start;
+
+ gfar_local_mdio_write(phy->regs, priv->phyaddr, GFAR_MIIM_CR,
GFAR_MIIM_CR_RST);
start = get_time_ns();
while (!is_timeout(start, 10 * MSECOND)) {
- if (!(gfar_local_mdio_read(priv->phyregs, priv->phyaddr,
+ if (!(gfar_local_mdio_read(phy->regs, priv->phyaddr,
GFAR_MIIM_CR) & GFAR_MIIM_CR_RST))
break;
}
@@ -433,13 +441,12 @@ static int gfar_recv(struct eth_device *edev)
/* Read a MII PHY register. */
static int gfar_miiphy_read(struct mii_bus *bus, int addr, int reg)
{
- struct device_d *dev = bus->parent;
- struct gfar_private *priv = bus->priv;
+ struct gfar_phy *phy = bus->priv;
int ret;
- ret = gfar_local_mdio_read(priv->phyregs, addr, reg);
+ ret = gfar_local_mdio_read(phy->regs, addr, reg);
if (ret == -EIO)
- dev_err(dev, "Can't read PHY at address %d\n", addr);
+ dev_err(phy->dev, "Can't read PHY at address %d\n", addr);
return ret;
}
@@ -448,15 +455,14 @@ static int gfar_miiphy_read(struct mii_bus *bus, int addr, int reg)
static int gfar_miiphy_write(struct mii_bus *bus, int addr, int reg,
u16 value)
{
- struct device_d *dev = bus->parent;
- struct gfar_private *priv = bus->priv;
+ struct gfar_phy *phy = bus->priv;
unsigned short val = value;
int ret;
- ret = gfar_local_mdio_write(priv->phyregs, addr, reg, val);
+ ret = gfar_local_mdio_write(phy->regs, addr, reg, val);
if (ret)
- dev_err(dev, "Can't write PHY at address %d\n", addr);
+ dev_err(phy->dev, "Can't write PHY at address %d\n", addr);
return 0;
}
@@ -470,7 +476,9 @@ static int gfar_probe(struct device_d *dev)
struct gfar_info_struct *gfar_info = dev->platform_data;
struct eth_device *edev;
struct gfar_private *priv;
+ struct device_d *mdev;
size_t size;
+ char devname[16];
char *p;
priv = xzalloc(sizeof(struct gfar_private));
@@ -480,14 +488,28 @@ static int gfar_probe(struct device_d *dev)
edev = &priv->edev;
- priv->regs = dev_request_mem_region(dev, 0);
- priv->phyregs = dev_request_mem_region(dev, 1);
- priv->phyregs_sgmii = dev_request_mem_region(dev, 2);
-
+ priv->mdiobus_tbi = gfar_info->mdiobus_tbi;
+ priv->regs = dev_get_mem_region(dev, 0);
priv->phyaddr = gfar_info->phyaddr;
priv->tbicr = gfar_info->tbicr;
priv->tbiana = gfar_info->tbiana;
+ mdev = get_device_by_name("gfar-mdio0");
+ if (mdev == NULL) {
+ pr_err("gfar-mdio0 was not found\n");
+ return -ENODEV;
+ }
+ priv->gfar_mdio = mdev->priv;
+
+ if (priv->mdiobus_tbi != 0) {
+ sprintf(devname, "%s%d", "gfar-tbiphy", priv->mdiobus_tbi);
+ mdev = get_device_by_name(devname);
+ if (mdev == NULL) {
+ pr_err("%s was not found\n", devname);
+ return -ENODEV;
+ }
+ }
+ priv->gfar_tbi = mdev->priv;
/*
* Allocate descriptors 64-bit aligned. Descriptors
* are 8 bytes in size.
@@ -512,15 +534,8 @@ static int gfar_probe(struct device_d *dev)
udelay(2);
clrbits_be32(priv->regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_SOFT_RESET);
- priv->miibus.read = gfar_miiphy_read;
- priv->miibus.write = gfar_miiphy_write;
- priv->miibus.priv = priv;
- priv->miibus.parent = dev;
-
gfar_init_phy(edev);
- mdiobus_register(&priv->miibus);
-
return eth_register(edev);
}
@@ -529,3 +544,64 @@ static struct driver_d gfar_eth_driver = {
.probe = gfar_probe,
};
device_platform_driver(gfar_eth_driver);
+
+static int gfar_phy_probe(struct device_d *dev)
+{
+ struct gfar_phy *phy;
+ int ret;
+
+ phy = xzalloc(sizeof(*phy));
+ phy->dev = dev;
+ phy->regs = dev_get_mem_region(dev, 0);
+ if (!phy->regs)
+ return -ENOMEM;
+
+ phy->miibus.read = gfar_miiphy_read;
+ phy->miibus.write = gfar_miiphy_write;
+ phy->miibus.priv = phy;
+ phy->miibus.reset = gfar_bus_reset;
+ phy->miibus.parent = dev;
+ dev->priv = phy;
+
+ ret = mdiobus_register(&phy->miibus);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct driver_d gfar_phy_driver = {
+ .name = "gfar-mdio",
+ .probe = gfar_phy_probe,
+};
+register_driver_macro(coredevice, platform, gfar_phy_driver);
+
+static int gfar_tbiphy_probe(struct device_d *dev)
+{
+ struct gfar_phy *phy;
+ int ret;
+
+ phy = xzalloc(sizeof(*phy));
+ phy->dev = dev;
+ phy->regs = dev_get_mem_region(dev, 0);
+ if (!phy->regs)
+ return -ENOMEM;
+
+ phy->miibus.read = gfar_miiphy_read;
+ phy->miibus.write = gfar_miiphy_write;
+ phy->miibus.priv = phy;
+ phy->miibus.parent = dev;
+ dev->priv = phy;
+
+ ret = mdiobus_register(&phy->miibus);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct driver_d gfar_tbiphy_driver = {
+ .name = "gfar-tbiphy",
+ .probe = gfar_tbiphy_probe,
+};
+register_driver_macro(coredevice, platform, gfar_tbiphy_driver);
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index b52cc5ab3b..1aac47907a 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -205,7 +205,6 @@ struct rxbd8 {
#define GFAR_ECNTRL_OFFSET 0x020 /* Ethernet Control */
#define GFAR_MINFLR_OFFSET 0x024 /* Minimum Frame Length */
#define GFAR_DMACTRL_OFFSET 0x02c /* DMA Control */
-#define GFAR_TBIPA_OFFSET 0x030 /* TBI PHY address */
/* eTSEC transmit control and status register */
#define GFAR_TSTAT_OFFSET 0x104 /* transmit status register */
@@ -263,13 +262,19 @@ struct rxbd8 {
#define GFAR_ATTR_OFFSET 0xbf8 /* Default Attribute Register */
#define GFAR_ATTRELI_OFFSET 0xbfc /* Default Attribute Extract Len/Idx */
+struct gfar_phy {
+ void __iomem *regs;
+ struct device_d *dev;
+ struct mii_bus miibus;
+};
+
struct gfar_private {
struct eth_device edev;
void __iomem *regs;
- void __iomem *phyregs;
- void __iomem *phyregs_sgmii;
+ int mdiobus_tbi;
+ struct gfar_phy *gfar_mdio;
+ struct gfar_phy *gfar_tbi;
struct phy_info *phyinfo;
- struct mii_bus miibus;
volatile struct txbd8 *txbd;
volatile struct rxbd8 *rxbd;
uint txidx;
diff --git a/include/ddr_spd.h b/include/ddr_spd.h
new file mode 100644
index 0000000000..c8762a28df
--- /dev/null
+++ b/include/ddr_spd.h
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#ifndef _DDR_SPD_H_
+#define _DDR_SPD_H_
+
+/*
+ * Format from "JEDEC Appendix X: Serial Presence Detects for DDR2 SDRAM",
+ * SPD Revision 1.2
+ */
+struct ddr2_spd_eeprom_s {
+ uint8_t info_size; /* 0 # bytes written into serial memory */
+ uint8_t chip_size; /* 1 Total # bytes of SPD memory device */
+ uint8_t mem_type; /* 2 Fundamental memory type */
+ uint8_t nrow_addr; /* 3 # of Row Addresses on this assembly */
+ uint8_t ncol_addr; /* 4 # of Column Addrs on this assembly */
+ uint8_t mod_ranks; /* 5 Number of DIMM Ranks */
+ uint8_t dataw; /* 6 Module Data Width */
+ uint8_t res_7; /* 7 Reserved */
+ uint8_t voltage; /* 8 Voltage intf std of this assembly */
+ uint8_t clk_cycle; /* 9 SDRAM Cycle time @ CL=X */
+ uint8_t clk_access; /* 10 SDRAM Access from Clk @ CL=X (tAC) */
+ uint8_t config; /* 11 DIMM Configuration type */
+ uint8_t refresh; /* 12 Refresh Rate/Type */
+ uint8_t primw; /* 13 Primary SDRAM Width */
+ uint8_t ecw; /* 14 Error Checking SDRAM width */
+ uint8_t res_15; /* 15 Reserved */
+ uint8_t burstl; /* 16 Burst Lengths Supported */
+ uint8_t nbanks; /* 17 # of Banks on Each SDRAM Device */
+ uint8_t cas_lat; /* 18 CAS# Latencies Supported */
+ uint8_t mech_char; /* 19 DIMM Mechanical Characteristics */
+ uint8_t dimm_type; /* 20 DIMM type information */
+ uint8_t mod_attr; /* 21 SDRAM Module Attributes */
+ uint8_t dev_attr; /* 22 SDRAM Device Attributes */
+ uint8_t clk_cycle2; /* 23 Min SDRAM Cycle time @ CL=X-1 */
+ uint8_t clk_access2; /* 24 SDRAM Access from Clk @ CL=X-1 (tAC) */
+ uint8_t clk_cycle3; /* 25 Min SDRAM Cycle time @ CL=X-2 */
+ uint8_t clk_access3; /* 26 Max Access from Clk @ CL=X-2 (tAC) */
+ uint8_t trp; /* 27 Min Row Precharge Time (tRP)*/
+ uint8_t trrd; /* 28 Min Row Active to Row Active (tRRD) */
+ uint8_t trcd; /* 29 Min RAS to CAS Delay (tRCD) */
+ uint8_t tras; /* 30 Minimum RAS Pulse Width (tRAS) */
+ uint8_t rank_dens; /* 31 Density of each rank on module */
+ uint8_t ca_setup; /* 32 Addr+Cmd Setup Time Before Clk (tIS) */
+ uint8_t ca_hold; /* 33 Addr+Cmd Hold Time After Clk (tIH) */
+ uint8_t data_setup; /* 34 Data Input Setup Time Before Strobe
+ (tDS) */
+ uint8_t data_hold; /* 35 Data Input Hold Time
+ After Strobe (tDH) */
+ uint8_t twr; /* 36 Write Recovery time tWR */
+ uint8_t twtr; /* 37 Int write to read delay tWTR */
+ uint8_t trtp; /* 38 Int read to precharge delay tRTP */
+ uint8_t mem_probe; /* 39 Mem analysis probe characteristics */
+ uint8_t trctrfc_ext; /* 40 Extensions to trc and trfc */
+ uint8_t trc; /* 41 Min Active to Auto refresh time tRC */
+ uint8_t trfc; /* 42 Min Auto to Active period tRFC */
+ uint8_t tckmax; /* 43 Max device cycle time tCKmax */
+ uint8_t tdqsq; /* 44 Max DQS to DQ skew (tDQSQ max) */
+ uint8_t tqhs; /* 45 Max Read DataHold skew (tQHS) */
+ uint8_t pll_relock; /* 46 PLL Relock time */
+ uint8_t Tcasemax; /* 47 Tcasemax */
+ uint8_t psiTAdram; /* 48 Thermal Resistance of DRAM Package
+ from Top (Case) to Ambient
+ (Psi T-A DRAM) */
+ uint8_t dt0_mode; /* 49 DRAM Case Temperature Rise from
+ Ambient due to Activate-Precharge/Mode
+ Bits (DT0/Mode Bits) */
+ uint8_t dt2n_dt2q; /* 50 DRAM Case Temperature Rise from
+ Ambient due to Precharge/Quiet Standby
+ (DT2N/DT2Q) */
+ uint8_t dt2p; /* 51 DRAM Case Temperature Rise from
+ Ambient due to Precharge Power-Down
+ (DT2P) */
+ uint8_t dt3n; /* 52 DRAM Case Temperature Rise from
+ Ambient due to Active Standby (DT3N) */
+ uint8_t dt3pfast; /* 53 DRAM Case Temperature Rise from
+ Ambient due to Active Power-Down with
+ Fast PDN Exit (DT3Pfast) */
+ uint8_t dt3pslow; /* 54 DRAM Case Temperature Rise from
+ Ambient due to Active Power-Down with
+ Slow PDN Exit (DT3Pslow) */
+ uint8_t dt4r_dt4r4w; /* 55 DRAM Case Temperature Rise from
+ Ambient due to Page Open Burst
+ Read/DT4R4W Mode Bit
+ (DT4R/DT4R4W Mode Bit) */
+ uint8_t dt5b; /* 56 DRAM Case Temperature Rise from
+ Ambient due to Burst Refresh (DT5B) */
+ uint8_t dt7; /* 57 DRAM Case Temperature Rise from
+ Ambient due to Bank Interleave Reads
+ with Auto-Precharge (DT7) */
+ uint8_t psiTApll; /* 58 Thermal Resistance of PLL Package
+ form Top (Case) to Ambient
+ (Psi T-A PLL) */
+ uint8_t psiTAreg; /* 59 Thermal Reisitance of Register
+ Package from Top (Case) to Ambient
+ (Psi T-A Register) */
+ uint8_t dtpllactive; /* 60 PLL Case Temperature Rise from
+ Ambient due to PLL Active
+ (DT PLL Active) */
+ uint8_t dtregact; /* 61 Register Case Temperature Rise from
+ Ambient due to Register Active/Mode
+ Bit (DT Register Active/Mode Bit) */
+ uint8_t spd_rev; /* 62 SPD Data Revision Code */
+ uint8_t cksum; /* 63 Checksum for bytes 0-62 */
+ uint8_t mid[8]; /* 64 Mfr's JEDEC ID code per JEP-106 */
+ uint8_t mloc; /* 72 Manufacturing Location */
+ uint8_t mpart[18]; /* 73 Manufacturer's Part Number */
+ uint8_t rev[2]; /* 91 Revision Code */
+ uint8_t mdate[2]; /* 93 Manufacturing Date */
+ uint8_t sernum[4]; /* 95 Assembly Serial Number */
+ uint8_t mspec[27]; /* 99-127 Manufacturer Specific Data */
+
+};
+
+extern uint32_t ddr2_spd_checksum_pass(const struct ddr2_spd_eeprom_s *spd);
+
+/* * Byte 2 Fundamental Memory Types. */
+#define SPD_MEMTYPE_DDR2 (0x08)
+
+/* DIMM Type for DDR2 SPD (according to v1.3) */
+#define DDR2_SPD_DIMMTYPE_RDIMM (0x01)
+#define DDR2_SPD_DIMMTYPE_UDIMM (0x02)
+#define DDR2_SPD_DIMMTYPE_SO_DIMM (0x04)
+#define DDR2_SPD_DIMMTYPE_72B_SO_CDIMM (0x06)
+#define DDR2_SPD_DIMMTYPE_72B_SO_RDIMM (0x07)
+#define DDR2_SPD_DIMMTYPE_MICRO_DIMM (0x08)
+#define DDR2_SPD_DIMMTYPE_MINI_RDIMM (0x10)
+#define DDR2_SPD_DIMMTYPE_MINI_UDIMM (0x20)
+
+#endif /* _DDR_SPD_H_ */