Add a RAM driver for the MPC83xx architecture. Signed-off-by: Mario Six <mario....@gdsys.cc>
--- v1 -> v2: No changes --- arch/powerpc/cpu/mpc83xx/spd_sdram.c | 4 + drivers/ram/Kconfig | 8 + drivers/ram/Makefile | 1 + drivers/ram/mpc83xx_sdram.c | 948 +++++++++++++++++++++++++++++ include/dt-bindings/memory/mpc83xx-sdram.h | 143 +++++ include/mpc83xx.h | 6 + 6 files changed, 1110 insertions(+) create mode 100644 drivers/ram/mpc83xx_sdram.c create mode 100644 include/dt-bindings/memory/mpc83xx-sdram.h diff --git a/arch/powerpc/cpu/mpc83xx/spd_sdram.c b/arch/powerpc/cpu/mpc83xx/spd_sdram.c index 21ab0153fc..f1e2dbf7c4 100644 --- a/arch/powerpc/cpu/mpc83xx/spd_sdram.c +++ b/arch/powerpc/cpu/mpc83xx/spd_sdram.c @@ -11,6 +11,8 @@ * SPDX-License-Identifier: GPL-2.0+ */ +#ifndef CONFIG_MPC83XX_SDRAM + #include <common.h> #include <asm/processor.h> #include <asm/io.h> @@ -925,3 +927,5 @@ void ddr_enable_ecc(unsigned int dram_size) __asm__ __volatile__ ("isync"); } #endif /* CONFIG_DDR_ECC */ + +#endif /* !CONFIG_MPC83XX_SDRAM */ diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig index 496e2b793b..18532e71be 100644 --- a/drivers/ram/Kconfig +++ b/drivers/ram/Kconfig @@ -34,4 +34,12 @@ config STM32_SDRAM support external memories like sdram, psram & nand. This driver is for the sdram memory interface with the FMC. +config MPC83XX_SDRAM + bool "Enable MPC83XX SDRAM support" + depends on RAM + help + Enable support for the internal DDR Memory Controller of the MPC83xx + family of SoCs. Both static configurations, as well as configuring + the RAM through the use of SPD is supported via device tree settings. + source "drivers/ram/stm32mp1/Kconfig" diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile index 3820d03aa4..4ad3604d16 100644 --- a/drivers/ram/Makefile +++ b/drivers/ram/Makefile @@ -5,6 +5,7 @@ # SPDX-License-Identifier: GPL-2.0+ # obj-$(CONFIG_RAM) += ram-uclass.o +obj-$(CONFIG_MPC83XX_SDRAM) += mpc83xx_sdram.o obj-$(CONFIG_SANDBOX) += sandbox_ram.o obj-$(CONFIG_STM32MP1_DDR) += stm32mp1/ obj-$(CONFIG_STM32_SDRAM) += stm32_sdram.o diff --git a/drivers/ram/mpc83xx_sdram.c b/drivers/ram/mpc83xx_sdram.c new file mode 100644 index 0000000000..1a73f7b3da --- /dev/null +++ b/drivers/ram/mpc83xx_sdram.c @@ -0,0 +1,948 @@ +#define DEBUG + +#include <common.h> +#include <dm.h> +#include <ram.h> +#include <asm/io.h> +#include <dt-bindings/memory/mpc83xx-sdram.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define CSCONFIG_ENABLE 0x80000000 + +#define BANK_BITS_2 0x00000000 +#define BANK_BITS_3 0x00004000 + +#define ROW_BITS_12 0x00000000 +#define ROW_BITS_13 0x00000100 +#define ROW_BITS_14 0x00000200 + +#define COL_BITS_8 0x00000000 +#define COL_BITS_9 0x00000001 +#define COL_BITS_10 0x00000002 +#define COL_BITS_11 0x00000003 + +#define TIMING_CFG3_EXT_REFREC_SHIFT 16 + +#define TIMING_CFG0_RWT_SHIFT 30 +#define TIMING_CFG0_WRT_SHIFT 28 +#define TIMING_CFG0_RRT_SHIFT 26 +#define TIMING_CFG0_WWT_SHIFT 24 +#define TIMING_CFG0_ACT_PD_EXIT_SHIFT 20 +#define TIMING_CFG0_PRE_PD_EXIT_SHIFT 16 +#define TIMING_CFG0_ODT_PD_EXIT_SHIFT 8 +#define TIMING_CFG0_MRS_CYC_SHIFT 0 + +#define TIMING_CFG1_PRETOACT_SHIFT 28 +#define TIMING_CFG1_ACTTOPRE_SHIFT 24 +#define TIMING_CFG1_ACTTORW_SHIFT 20 +#define TIMING_CFG1_CASLAT_SHIFT 16 +#define TIMING_CFG1_REFREC_SHIFT 12 +#define TIMING_CFG1_WRREC_SHIFT 8 +#define TIMING_CFG1_ACTTOACT_SHIFT 4 +#define TIMING_CFG1_WRTORD_SHIFT 0 + +#define TIMING_CFG2_CPO_SHIFT 23 +#define TIMING_CFG2_WR_DATA_DELAY_SHIFT 10 +#define TIMING_CFG2_ADD_LAT_SHIFT 28 +#define TIMING_CFG2_WR_LAT_DELAY_SHIFT 19 +#define TIMING_CFG2_RD_TO_PRE_SHIFT 13 +#define TIMING_CFG2_CKE_PLS_SHIFT 6 +#define TIMING_CFG2_FOUR_ACT_SHIFT 0 + +#define SDRAM_CFG_SREN_SHIFT (31 - 1) +#define SDRAM_CFG_ECC_EN_SHIFT (31 - 2) +#define SDRAM_CFG_RD_EN_SHIFT (31 - 3) +#define SDRAM_CFG_SDRAM_TYPE_SHIFT (31 - 7) +#define SDRAM_CFG_DYN_PWR_SHIFT (31 - 10) +#define SDRAM_CFG_DBW_SHIFT (31 - 12) +#define SDRAM_CFG_NCAP_SHIFT (31 - 14) +#define SDRAM_CFG_2T_EN_SHIFT (31 - 16) +#define SDRAM_CFG_BA_INTLV_CTL_SHIFT (31 - 23) +#define SDRAM_CFG_PCHB8_SHIFT (31 - 27) +#define SDRAM_CFG_HSE_SHIFT (31 - 28) +#define SDRAM_CFG_BI_SHIFT (31 - 31) + +#define SDRAM_CFG2_FRC_SR_SHIFT (31 - 0) +#define SDRAM_CFG2_DLL_RST_DIS (31 - 2) +#define SDRAM_CFG2_DQS_CFG (31 - 5) +#define SDRAM_CFG2_ODT_CFG (31 - 10) +#define SDRAM_CFG2_NUM_PR (31 - 19) + +#define SDRAM_MODE_ESD_SHIFT 16 +#define SDRAM_MODE_SD_SHIFT 0 + +#define SDRAM_MODE2_ESD2_SHIFT (31 - 15) +#define SDRAM_MODE2_ESD3_SHIFT (31 - 31) + +#define SDRAM_INTERVAL_REFINT_SHIFT 16 +#define SDRAM_INTERVAL_BSTOPRE_SHIFT 0 + +#define SDRAM_CFG_MEM_EN 0x80000000 + +int dram_init(void) +{ + struct udevice *ram_ctrl; + int ret; + + /* Current assumption: There is only one RAM controller */ + ret = uclass_first_device_err(UCLASS_RAM, &ram_ctrl); + + if (ret) { + debug("uclass_first_device_err failed: %d\n", ret); + return ret; + } + + /* Set gd->ram_size? */ + + return 0; +} + +phys_size_t get_effective_memsize(void) +{ +#ifndef CONFIG_VERY_BIG_RAM + return gd->ram_size; +#else + /* limit stack to what we can reasonable map */ + return ((gd->ram_size > CONFIG_MAX_MEM_MAPPED) ? + CONFIG_MAX_MEM_MAPPED : gd->ram_size); +#endif +} + +struct mpc83xx_sdram_priv { + ulong total_size; +}; + +int mpc83xx_sdram_static_init(ofnode node, u32 cs, u32 mapaddr, u32 size) +{ + immap_t *im = (immap_t *)CONFIG_SYS_IMMR; + u32 msize = size; + u32 msize_log2 = __ilog2(msize); + u32 auto_precharge, odt_rd_cfg, odt_wr_cfg, bank_bits, row_bits, + col_bits; + u32 bank_bits_mask, row_bits_mask, col_bits_mask; + + /* Configure the DDR local access window */ + out_be32(&im->sysconf.ddrlaw[cs].bar, mapaddr & 0xfffff000); + out_be32(&im->sysconf.ddrlaw[cs].ar, LBLAWAR_EN | (msize_log2 - 1)); + + out_be32(&im->ddr.csbnds[cs].csbnds, (msize - 1) >> 24); + + auto_precharge = ofnode_read_u32_default(node, "auto_precharge", 0); + switch (auto_precharge) { + case AUTO_PRECHARGE_ENABLE: + case AUTO_PRECHARGE_DISABLE: + break; + default: + debug("auto_precharge value invalid.\n"); + return -EINVAL; + } + + odt_rd_cfg = ofnode_read_u32_default(node, "odt_rd_cfg", 0); + switch (odt_rd_cfg) { +#if defined(CONFIG_MPC830x) || defined(CONFIG_MPC831x) || \ + defined(CONFIG_MPC8360) || defined(CONFIG_MPC837x) + case ODT_RD_NEVER: + case ODT_RD_ONLY_CURRENT: + case ODT_RD_ONLY_OTHER_CS: +#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC837x) + case ODT_RD_ONLY_OTHER_DIMM: +#endif +#endif + /* MPC832x only knows this value */ + case ODT_RD_ALL: + break; + default: + debug("odt_rd_cfg value invalid.\n"); + return -EINVAL; + } + + odt_wr_cfg = ofnode_read_u32_default(node, "odt_wr_cfg", 0); + switch (odt_wr_cfg) { +#if defined(CONFIG_MPC830x) || defined(CONFIG_MPC831x) || \ + defined(CONFIG_MPC8360) || defined(CONFIG_MPC837x) + case ODT_WR_NEVER: + case ODT_WR_ONLY_CURRENT: + case ODT_WR_ONLY_OTHER_CS: +#if defined(CONFIG_MPC8360) || defined(CONFIG_MPC837x) + case ODT_WR_ONLY_OTHER_DIMM: +#endif +#endif + /* MPC832x only knows this value */ + case ODT_WR_ALL: + break; + default: + debug("odt_wr_cfg value invalid.\n"); + return -EINVAL; + } + + bank_bits = ofnode_read_u32_default(node, "bank_bits", 0); + switch (bank_bits) { + case 2: + bank_bits_mask = BANK_BITS_2; + break; + case 3: + bank_bits_mask = BANK_BITS_3; + break; + default: + debug("bank_bits value invalid.\n"); + return -EINVAL; + } + + row_bits = ofnode_read_u32_default(node, "row_bits", 0); + switch (row_bits) { + case 12: + row_bits_mask = ROW_BITS_12; + break; + case 13: + row_bits_mask = ROW_BITS_13; + break; + case 14: + row_bits_mask = ROW_BITS_14; + break; + default: + debug("row_bits value invalid.\n"); + return -EINVAL; + } + + col_bits = ofnode_read_u32_default(node, "col_bits", 0); + switch (col_bits) { + case 8: + col_bits_mask = COL_BITS_8; + break; + case 9: + col_bits_mask = COL_BITS_9; + break; + case 10: + col_bits_mask = COL_BITS_10; + break; + case 11: + col_bits_mask = COL_BITS_11; + break; + default: + debug("col_bits value invalid.\n"); + return -EINVAL; + } + + /* Write CS config value */ + out_be32(&im->ddr.cs_config[cs], CSCONFIG_ENABLE | auto_precharge | + odt_rd_cfg | odt_wr_cfg | + bank_bits_mask | row_bits_mask | + col_bits_mask); + return 0; +} + +int mpc83xx_sdram_spd_init(ofnode node, u32 cs, u32 mapaddr, u32 size) +{ + return 0; +} + +static int mpc83xx_sdram_ofdata_to_platdata(struct udevice *dev) +{ + return 0; +} + +static int mpc83xx_sdram_probe(struct udevice *dev) +{ + struct mpc83xx_sdram_priv *priv = dev_get_priv(dev); + immap_t *im = (immap_t *)CONFIG_SYS_IMMR; + int res = 0; + ofnode subnode; + u32 dso, pz_override, nz_override, odt_term, ddr_type, mvref_sel, m_odr; + u32 ddrcdr; + u32 clock_adjust; + u32 ext_refresh_rec, ext_refresh_rec_mask; + u32 read_to_write, write_to_read, read_to_read, write_to_write, + active_powerdown_exit, precharge_powerdown_exit, + odt_powerdown_exit, mode_reg_set_cycle; + u32 timing_cfg_0; + u32 precharge_to_activate, activate_to_precharge, + activate_to_readwrite, mcas_latency, refresh_recovery, + last_data_to_precharge, activate_to_activate, + last_write_data_to_read; + u32 timing_cfg_1; + u32 additive_latency, mcas_to_preamble_override, write_latency, + read_to_precharge, write_cmd_to_write_data, + minimum_cke_pulse_width, four_activates_window; + u32 timing_cfg_2; + u32 self_refresh, ecc, registered_dram, sdram_type, + dynamic_power_management, databus_width, nc_auto_precharge, + timing_2t, bank_interleaving_ctrl, precharge_bit_8, half_strength, + bypass_initialization; + u32 sdram_cfg; + u32 force_self_refresh, dll_reset, dqs_config, odt_config, + posted_refreshes; + u32 sdram_cfg2; + u32 refresh_interval, precharge_interval, sdmode, esdmode, esdmode2, + esdmode3; + u32 sdram_interval; + u32 sdram_mode; + u32 sdram_mode2; + + priv->total_size = 0; + + /* Disable both banks initially (might be re-enabled in loop below) */ + out_be32(&im->ddr.cs_config[0], 0); + out_be32(&im->ddr.cs_config[1], 0); + + dso = dev_read_u32_default(dev, "driver_software_override", 0); + if (dso > 1) { + debug("driver_software_override value invalid.\n"); + return -EINVAL; + } + + pz_override = dev_read_u32_default(dev, "p_impedance_override", 0); + + switch (pz_override) { + case DSO_P_IMPEDANCE_HIGHEST_Z: + case DSO_P_IMPEDANCE_MUCH_HIGHER_Z: + case DSO_P_IMPEDANCE_HIGHER_Z: + case DSO_P_IMPEDANCE_NOMINAL: + case DSO_P_IMPEDANCE_LOWER_Z: + break; + default: + debug("p_impedance_override value invalid.\n"); + return -EINVAL; + } + + nz_override = dev_read_u32_default(dev, "n_impedance_override", 0); + + switch (nz_override) { + case DSO_N_IMPEDANCE_HIGHEST_Z: + case DSO_N_IMPEDANCE_MUCH_HIGHER_Z: + case DSO_N_IMPEDANCE_HIGHER_Z: + case DSO_N_IMPEDANCE_NOMINAL: + case DSO_N_IMPEDANCE_LOWER_Z: + break; + default: + debug("n_impedance_override value invalid.\n"); + return -EINVAL; + } + + odt_term = dev_read_u32_default(dev, "odt_termination_value", 0); + if (odt_term > 1) { + debug("odt_termination_value value invalid.\n"); + return -EINVAL; + } + + ddr_type = dev_read_u32_default(dev, "ddr_type", 0); + if (ddr_type > 1) { + debug("ddr_type value invalid.\n"); + return -EINVAL; + } + + mvref_sel = dev_read_u32_default(dev, "mvref_sel", 0); + if (mvref_sel > 1) { + debug("mvref_sel value invalid.\n"); + return -EINVAL; + } + + m_odr = dev_read_u32_default(dev, "m_odr", 0); + if (mvref_sel > 1) { + debug("m_odr value invalid.\n"); + return -EINVAL; + } + + ddrcdr = dso << (31 - 1) | + pz_override << (31 - 5) | + nz_override << (31 - 9) | + odt_term << (31 - 12) | + ddr_type << (31 - 13) | + mvref_sel << (31 - 29) | + m_odr << (31 - 30) | 1; + + /* Configure the DDR control driver register */ + out_be32(&im->sysconf.ddrcdr, ddrcdr); + + dev_for_each_subnode(subnode, dev) { + u32 val[3]; + u32 cs, addr, size; + + /* CS, map address, size -> three values */ + ofnode_read_u32_array(subnode, "reg", val, 3); + + cs = val[0]; + addr = val[1]; + size = val[2]; + + if (cs > 1) { + debug("chip select value invalid.\n"); + return -EINVAL; + } + + /* TODO: Sanity check for size. */ + + if (ofnode_read_bool(subnode, "read-spd")) + res = mpc83xx_sdram_spd_init(subnode, cs, addr, size); + else + res = mpc83xx_sdram_static_init(subnode, cs, addr, + size); + if (res) + return res; + }; + + /* TODO: This should only occur for static configuration */ + + clock_adjust = dev_read_u32_default(dev, "clock_adjust", 0); + switch (clock_adjust) { + case CLOCK_ADJUST_025: + case CLOCK_ADJUST_05: + case CLOCK_ADJUST_075: + case CLOCK_ADJUST_1: + break; + default: + debug("clock_adjust value invalid.\n"); + return -EINVAL; + } + + /* Configure the DDR SDRAM Clock Control register */ + out_be32(&im->ddr.sdram_clk_cntl, clock_adjust); + + ext_refresh_rec = dev_read_u32_default(dev, "ext_refresh_rec", 0); + switch (ext_refresh_rec) { + case 0: + ext_refresh_rec_mask = 0 << TIMING_CFG3_EXT_REFREC_SHIFT; + break; + case 16: + ext_refresh_rec_mask = 1 << TIMING_CFG3_EXT_REFREC_SHIFT; + break; + case 32: + ext_refresh_rec_mask = 2 << TIMING_CFG3_EXT_REFREC_SHIFT; + break; + case 48: + ext_refresh_rec_mask = 3 << TIMING_CFG3_EXT_REFREC_SHIFT; + break; + case 64: + ext_refresh_rec_mask = 4 << TIMING_CFG3_EXT_REFREC_SHIFT; + break; + case 80: + ext_refresh_rec_mask = 5 << TIMING_CFG3_EXT_REFREC_SHIFT; + break; + case 96: + ext_refresh_rec_mask = 6 << TIMING_CFG3_EXT_REFREC_SHIFT; + break; + case 112: + ext_refresh_rec_mask = 7 << TIMING_CFG3_EXT_REFREC_SHIFT; + break; + default: + debug("ext_refresh_rec value invalid.\n"); + return -EINVAL; + } + + /* Configure the DDR SDRAM Timing Configuration 3 register */ + out_be32(&im->ddr.timing_cfg_3, ext_refresh_rec_mask); + + read_to_write = dev_read_u32_default(dev, "read_to_write", 0); + if (read_to_write > 3) { + debug("read_to_write value invalid.\n"); + return -EINVAL; + } + + write_to_read = dev_read_u32_default(dev, "write_to_read", 0); + if (write_to_read > 3) { + debug("write_to_read value invalid.\n"); + return -EINVAL; + } + + read_to_read = dev_read_u32_default(dev, "read_to_read", 0); + if (read_to_read > 3) { + debug("read_to_read value invalid.\n"); + return -EINVAL; + } + + write_to_write = dev_read_u32_default(dev, "write_to_write", 0); + if (write_to_write > 3) { + debug("write_to_write value invalid.\n"); + return -EINVAL; + } + + active_powerdown_exit = + dev_read_u32_default(dev, "active_powerdown_exit", 0); + if (active_powerdown_exit > 7) { + debug("active_powerdown_exit value invalid.\n"); + return -EINVAL; + } + + precharge_powerdown_exit = + dev_read_u32_default(dev, "precharge_powerdown_exit", 0); + if (precharge_powerdown_exit > 7) { + debug("precharge_powerdown_exit value invalid.\n"); + return -EINVAL; + } + + odt_powerdown_exit = dev_read_u32_default(dev, "odt_powerdown_exit", 0); + if (odt_powerdown_exit > 15) { + debug("odt_powerdown_exit value invalid.\n"); + return -EINVAL; + } + + mode_reg_set_cycle = dev_read_u32_default(dev, "mode_reg_set_cycle", 0); + if (mode_reg_set_cycle > 15) { + debug("mode_reg_set_cycle value invalid.\n"); + return -EINVAL; + } + + timing_cfg_0 = read_to_write << TIMING_CFG0_RWT_SHIFT | + write_to_read << TIMING_CFG0_WRT_SHIFT | + read_to_read << TIMING_CFG0_RRT_SHIFT | + write_to_write << TIMING_CFG0_WWT_SHIFT | + active_powerdown_exit << TIMING_CFG0_ACT_PD_EXIT_SHIFT | + precharge_powerdown_exit << TIMING_CFG0_PRE_PD_EXIT_SHIFT | + odt_powerdown_exit << TIMING_CFG0_ODT_PD_EXIT_SHIFT | + mode_reg_set_cycle << TIMING_CFG0_MRS_CYC_SHIFT; + + out_be32(&im->ddr.timing_cfg_0, timing_cfg_0); + + precharge_to_activate = + dev_read_u32_default(dev, "precharge_to_activate", 0); + if (precharge_to_activate > 7 || precharge_to_activate == 0) { + debug("precharge_to_activate value invalid.\n"); + return -EINVAL; + } + + activate_to_precharge = + dev_read_u32_default(dev, "activate_to_precharge", 0); + if (activate_to_precharge > 15 || activate_to_precharge == 0) { + debug("activate_to_precharge value invalid.\n"); + return -EINVAL; + } + + activate_to_readwrite = + dev_read_u32_default(dev, "activate_to_readwrite", 0); + if (activate_to_readwrite > 7 || activate_to_readwrite == 0) { + debug("activate_to_readwrite value invalid.\n"); + return -EINVAL; + } + + /* TODO: MPC8308 only supports caslat >= 3 clocks */ + mcas_latency = dev_read_u32_default(dev, "mcas_latency", 0); + switch (mcas_latency) { + case CASLAT_20: + case CASLAT_25: + case CASLAT_30: + case CASLAT_35: + case CASLAT_40: + case CASLAT_45: + case CASLAT_50: + break; + default: + debug("ext_refresh_rec value invalid.\n"); + return -EINVAL; + } + + refresh_recovery = dev_read_u32_default(dev, "refresh_recovery", 0); + if (refresh_recovery > 23 || refresh_recovery < 8) { + debug("refresh_recovery value invalid.\n"); + return -EINVAL; + } + + last_data_to_precharge = + dev_read_u32_default(dev, "last_data_to_precharge", 0); + if (last_data_to_precharge > 7 || last_data_to_precharge == 0) { + debug("last_data_to_precharge value invalid.\n"); + return -EINVAL; + } + + activate_to_activate = + dev_read_u32_default(dev, "activate_to_activate", 0); + if (activate_to_activate > 7 || activate_to_activate == 0) { + debug("activate_to_activate value invalid.\n"); + return -EINVAL; + } + + last_write_data_to_read = + dev_read_u32_default(dev, "last_write_data_to_read", 0); + if (last_write_data_to_read > 7 || last_write_data_to_read == 0) { + debug("last_write_data_to_read value invalid.\n"); + return -EINVAL; + } + + timing_cfg_1 = precharge_to_activate << TIMING_CFG1_PRETOACT_SHIFT | + activate_to_precharge << TIMING_CFG1_ACTTOPRE_SHIFT | + activate_to_readwrite << TIMING_CFG1_ACTTORW_SHIFT | + mcas_latency << TIMING_CFG1_CASLAT_SHIFT | + (refresh_recovery - 8) << TIMING_CFG1_REFREC_SHIFT | + last_data_to_precharge << TIMING_CFG1_WRREC_SHIFT | + activate_to_activate << TIMING_CFG1_ACTTOACT_SHIFT | + last_write_data_to_read << TIMING_CFG1_WRTORD_SHIFT; + + /* Configure the DDR SDRAM Timing Configuration 1 register */ + out_be32(&im->ddr.timing_cfg_1, timing_cfg_1); + + additive_latency = dev_read_u32_default(dev, "additive_latency", 0); + if (additive_latency > 5) { + debug("additive_latency value invalid.\n"); + return -EINVAL; + } + + mcas_to_preamble_override = + dev_read_u32_default(dev, "mcas_to_preamble_override", 0); + switch (mcas_to_preamble_override) { + case READ_LAT_PLUS_1: + case READ_LAT: + case READ_LAT_PLUS_1_4: + case READ_LAT_PLUS_1_2: + case READ_LAT_PLUS_3_4: + case READ_LAT_PLUS_5_4: + case READ_LAT_PLUS_3_2: + case READ_LAT_PLUS_7_4: + case READ_LAT_PLUS_2: + case READ_LAT_PLUS_9_4: + case READ_LAT_PLUS_5_2: + case READ_LAT_PLUS_11_4: + case READ_LAT_PLUS_3: + case READ_LAT_PLUS_13_4: + case READ_LAT_PLUS_7_2: + case READ_LAT_PLUS_15_4: + case READ_LAT_PLUS_4: + case READ_LAT_PLUS_17_4: + case READ_LAT_PLUS_9_2: + case READ_LAT_PLUS_19_4: + break; + default: + debug("mcas_to_preamble_override value invalid.\n"); + return -EINVAL; + } + + write_latency = dev_read_u32_default(dev, "write_latency", 0); + if (write_latency > 7 || write_latency == 0) { + debug("write_latency value invalid.\n"); + return -EINVAL; + } + + read_to_precharge = dev_read_u32_default(dev, "read_to_precharge", 0); + if (read_to_precharge > 4 || read_to_precharge == 0) { + debug("read_to_precharge value invalid.\n"); + return -EINVAL; + } + + write_cmd_to_write_data = + dev_read_u32_default(dev, "write_cmd_to_write_data", 0); + switch (write_cmd_to_write_data) { + case CLOCK_DELAY_0: + case CLOCK_DELAY_1_4: + case CLOCK_DELAY_1_2: + case CLOCK_DELAY_3_4: + case CLOCK_DELAY_1: + case CLOCK_DELAY_5_4: + case CLOCK_DELAY_3_2: + break; + default: + debug("write_cmd_to_write_data value invalid.\n"); + return -EINVAL; + } + + minimum_cke_pulse_width = + dev_read_u32_default(dev, "minimum_cke_pulse_width", 0); + if (minimum_cke_pulse_width > 4 || minimum_cke_pulse_width == 0) { + debug("minimum_cke_pulse_width value invalid.\n"); + return -EINVAL; + } + + four_activates_window = + dev_read_u32_default(dev, "four_activates_window", 0); + if (four_activates_window > 20 || four_activates_window == 0) { + debug("four_activates_window value invalid.\n"); + return -EINVAL; + } + + timing_cfg_2 = additive_latency << TIMING_CFG2_ADD_LAT_SHIFT | + mcas_to_preamble_override << TIMING_CFG2_CPO_SHIFT | + write_latency << TIMING_CFG2_WR_LAT_DELAY_SHIFT | + read_to_precharge << TIMING_CFG2_RD_TO_PRE_SHIFT | + write_cmd_to_write_data << TIMING_CFG2_WR_DATA_DELAY_SHIFT | + minimum_cke_pulse_width << TIMING_CFG2_CKE_PLS_SHIFT | + four_activates_window << TIMING_CFG2_FOUR_ACT_SHIFT; + + out_be32(&im->ddr.timing_cfg_2, timing_cfg_2); + + self_refresh = dev_read_u32_default(dev, "self_refresh", 0); + switch (self_refresh) { + case SREN_DISABLE: + case SREN_ENABLE: + break; + default: + debug("self_refresh value invalid.\n"); + return -EINVAL; + } + + ecc = dev_read_u32_default(dev, "ecc", 0); + switch (ecc) { + case ECC_DISABLE: + case ECC_ENABLE: + break; + default: + debug("ecc value invalid.\n"); + return -EINVAL; + } + + registered_dram = dev_read_u32_default(dev, "registered_dram", 0); + switch (registered_dram) { + case RD_DISABLE: + case RD_ENABLE: + break; + default: + debug("registered_dram value invalid.\n"); + return -EINVAL; + } + + sdram_type = dev_read_u32_default(dev, "sdram_type", 0); + switch (sdram_type) { + case TYPE_DDR1: + case TYPE_DDR2: + break; + default: + debug("sdram_type value invalid.\n"); + return -EINVAL; + } + + dynamic_power_management = + dev_read_u32_default(dev, "dynamic_power_management", 0); + switch (dynamic_power_management) { + case DYN_PWR_DISABLE: + case DYN_PWR_ENABLE: + break; + default: + debug("dynamic_power_management value invalid.\n"); + return -EINVAL; + } + + databus_width = dev_read_u32_default(dev, "databus_width", 0); + switch (databus_width) { + case DATA_BUS_WIDTH_16: + case DATA_BUS_WIDTH_32: + break; + default: + debug("databus_width value invalid.\n"); + return -EINVAL; + } + + nc_auto_precharge = dev_read_u32_default(dev, "nc_auto_precharge", 0); + switch (nc_auto_precharge) { + case NCAP_DISABLE: + case NCAP_ENABLE: + break; + default: + debug("nc_auto_precharge value invalid.\n"); + return -EINVAL; + } + + timing_2t = dev_read_u32_default(dev, "timing_2t", 0); + switch (timing_2t) { + case TIMING_1T: + case TIMING_2T: + break; + default: + debug("timing_2t value invalid.\n"); + return -EINVAL; + } + + bank_interleaving_ctrl = + dev_read_u32_default(dev, "bank_interleaving_ctrl", 0); + switch (bank_interleaving_ctrl) { + case INTERLEAVE_NONE: + case INTERLEAVE_1_AND_2: + break; + default: + debug("bank_interleaving_ctrl value invalid.\n"); + return -EINVAL; + } + + precharge_bit_8 = dev_read_u32_default(dev, "precharge_bit_8", 0); + switch (precharge_bit_8) { + case PRECHARGE_MA_10: + case PRECHARGE_MA_8: + break; + default: + debug("precharge_bit_8 value invalid.\n"); + return -EINVAL; + } + + half_strength = dev_read_u32_default(dev, "half_strength", 0); + switch (half_strength) { + case STRENGTH_FULL: + case STRENGTH_HALF: + break; + default: + debug("half_strength value invalid.\n"); + return -EINVAL; + } + + bypass_initialization = + dev_read_u32_default(dev, "bypass_initialization", 0); + switch (bypass_initialization) { + case INITIALIZATION_DONT_BYPASS: + case INITIALIZATION_BYPASS: + break; + default: + debug("bypass_initialization value invalid.\n"); + return -EINVAL; + } + + sdram_cfg = self_refresh << SDRAM_CFG_SREN_SHIFT | + ecc << SDRAM_CFG_ECC_EN_SHIFT | + registered_dram << SDRAM_CFG_RD_EN_SHIFT | + sdram_type << SDRAM_CFG_SDRAM_TYPE_SHIFT | + dynamic_power_management << SDRAM_CFG_DYN_PWR_SHIFT | + databus_width << SDRAM_CFG_DBW_SHIFT | + nc_auto_precharge << SDRAM_CFG_NCAP_SHIFT | + timing_2t << SDRAM_CFG_2T_EN_SHIFT | + bank_interleaving_ctrl << SDRAM_CFG_BA_INTLV_CTL_SHIFT | + precharge_bit_8 << SDRAM_CFG_PCHB8_SHIFT | + half_strength << SDRAM_CFG_HSE_SHIFT | + bypass_initialization << SDRAM_CFG_BI_SHIFT; + + out_be32(&im->ddr.sdram_cfg, sdram_cfg); + + force_self_refresh = dev_read_u32_default(dev, "force_self_refresh", 0); + switch (force_self_refresh) { + case MODE_NORMAL: + case MODE_REFRESH: + break; + default: + debug("force_self_refresh value invalid.\n"); + return -EINVAL; + } + + dll_reset = dev_read_u32_default(dev, "dll_reset", 0); + switch (dll_reset) { + case DLL_RESET_ENABLE: + case DLL_RESET_DISABLE: + break; + default: + debug("dll_reset value invalid.\n"); + return -EINVAL; + } + + dqs_config = dev_read_u32_default(dev, "dqs_config", 0); + switch (dqs_config) { + case DQS_TRUE: + break; + default: + debug("dqs_config value invalid.\n"); + return -EINVAL; + } + + odt_config = dev_read_u32_default(dev, "odt_config", 0); + switch (odt_config) { + case ODT_ASSERT_NEVER: + case ODT_ASSERT_WRITES: + case ODT_ASSERT_READS: + case ODT_ASSERT_ALWAYS: + break; + default: + debug("odt_config value invalid.\n"); + return -EINVAL; + } + + posted_refreshes = dev_read_u32_default(dev, "posted_refreshes", 0); + if (posted_refreshes > 8 || posted_refreshes == 0) { + debug("posted_refreshes value invalid.\n"); + return -EINVAL; + } + + sdram_cfg2 = force_self_refresh << SDRAM_CFG2_FRC_SR_SHIFT | + dll_reset << SDRAM_CFG2_DLL_RST_DIS | + dqs_config << SDRAM_CFG2_DQS_CFG | + odt_config << SDRAM_CFG2_ODT_CFG | + posted_refreshes << SDRAM_CFG2_NUM_PR; + + out_be32(&im->ddr.sdram_cfg2, sdram_cfg2); + + sdmode = dev_read_u32_default(dev, "sdmode", 0); + if (sdmode > 0xFFFF) { + debug("sdmode value invalid.\n"); + return -EINVAL; + } + + esdmode = dev_read_u32_default(dev, "esdmode", 0); + if (esdmode > 0xFFFF) { + debug("esdmode value invalid.\n"); + return -EINVAL; + } + + sdram_mode = sdmode << SDRAM_MODE_SD_SHIFT | + esdmode << SDRAM_MODE_ESD_SHIFT; + + out_be32(&im->ddr.sdram_mode, sdram_mode); + + esdmode2 = dev_read_u32_default(dev, "esdmode2", 0); + if (esdmode2 > 0xFFFF) { + debug("esdmode2 value invalid.\n"); + return -EINVAL; + } + + esdmode3 = dev_read_u32_default(dev, "esdmode3", 0); + if (esdmode3 > 0xFFFF) { + debug("esdmode3 value invalid.\n"); + return -EINVAL; + } + + sdram_mode2 = esdmode2 << SDRAM_MODE2_ESD2_SHIFT | + esdmode3 << SDRAM_MODE2_ESD3_SHIFT; + + out_be32(&im->ddr.sdram_mode2, sdram_mode2); + + refresh_interval = dev_read_u32_default(dev, "refresh_interval", 0); + if (refresh_interval > 0xFFFF) { + debug("refresh_interval value invalid.\n"); + return -EINVAL; + } + + precharge_interval = dev_read_u32_default(dev, "precharge_interval", 0); + if (precharge_interval > 0x3FFF) { + debug("precharge_interval value invalid.\n"); + return -EINVAL; + } + + sdram_interval = refresh_interval << SDRAM_INTERVAL_REFINT_SHIFT | + precharge_interval << SDRAM_INTERVAL_BSTOPRE_SHIFT; + + out_be32(&im->ddr.sdram_interval, sdram_interval); + sync(); + + /* Enable DDR controller */ + setbits_be32(&im->ddr.sdram_cfg, SDRAM_CFG_MEM_EN); + sync(); + + dev_for_each_subnode(subnode, dev) { + u32 val[3]; + u32 addr, size; + + /* CS, map address, size -> three values */ + ofnode_read_u32_array(subnode, "reg", val, 3); + + addr = val[1]; + size = val[2]; + + priv->total_size += get_ram_size((long int *)addr, size); + }; + + gd->ram_size = priv->total_size; + + return 0; +} + +static int mpc83xx_sdram_get_info(struct udevice *dev, struct ram_info *info) +{ + return 0; +} + +static struct ram_ops mpc83xx_sdram_ops = { + .get_info = mpc83xx_sdram_get_info, +}; + +static const struct udevice_id mpc83xx_sdram_ids[] = { + { .compatible = "fsl,mpc83xx-mem-controller" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(mpc83xx_sdram) = { + .name = "mpc83xx_sdram", + .id = UCLASS_RAM, + .of_match = mpc83xx_sdram_ids, + .ops = &mpc83xx_sdram_ops, + .ofdata_to_platdata = mpc83xx_sdram_ofdata_to_platdata, + .probe = mpc83xx_sdram_probe, + .priv_auto_alloc_size = sizeof(struct mpc83xx_sdram_priv), +}; diff --git a/include/dt-bindings/memory/mpc83xx-sdram.h b/include/dt-bindings/memory/mpc83xx-sdram.h new file mode 100644 index 0000000000..0f970008b6 --- /dev/null +++ b/include/dt-bindings/memory/mpc83xx-sdram.h @@ -0,0 +1,143 @@ +#ifndef DT_BINDINGS_MPC83XX_SDRAM_H +#define DT_BINDINGS_MPC83XX_SDRAM_H + +#define DSO_DISABLE 0 +#define DSO_ENABLE 1 + +#define DSO_P_IMPEDANCE_HIGHEST_Z 0x0 +#define DSO_P_IMPEDANCE_MUCH_HIGHER_Z 0x8 +#define DSO_P_IMPEDANCE_HIGHER_Z 0xC +#define DSO_P_IMPEDANCE_NOMINAL 0xE +#define DSO_P_IMPEDANCE_LOWER_Z 0xF + +#define DSO_N_IMPEDANCE_HIGHEST_Z 0x0 +#define DSO_N_IMPEDANCE_MUCH_HIGHER_Z 0x8 +#define DSO_N_IMPEDANCE_HIGHER_Z 0xC +#define DSO_N_IMPEDANCE_NOMINAL 0xE +#define DSO_N_IMPEDANCE_LOWER_Z 0xF + +#define ODT_TERMINATION_75_OHM 0 +#define ODT_TERMINATION_150_OHM 1 + +#define DDR_TYPE_DDR2_1_8_VOLT 0 +#define DDR_TYPE_DDR1_2_5_VOLT 1 + +#define MVREF_SEL_EXTERNAL 0 +#define MVREF_SEL_INTERNAL_GVDD 1 + +#define M_ODR_ENABLE 0 +#define M_ODR_DISABLE 1 + +/* CS config register */ + +#define AUTO_PRECHARGE_ENABLE 0x00800000 +#define AUTO_PRECHARGE_DISABLE 0x00000000 + +#define ODT_RD_NEVER 0x00000000 +#define ODT_RD_ONLY_CURRENT 0x00100000 +#define ODT_RD_ONLY_OTHER_CS 0x00200000 +#define ODT_RD_ALL 0x00400000 +#define ODT_WR_NEVER 0x00000000 +#define ODT_WR_ONLY_CURRENT 0x00010000 +#define ODT_WR_ONLY_OTHER_CS 0x00020000 +#define ODT_WR_ALL 0x00040000 + +/* DDR SDRAM Clock Control register */ + +#define CLOCK_ADJUST_025 0x01000000 +#define CLOCK_ADJUST_05 0x02000000 +#define CLOCK_ADJUST_075 0x03000000 +#define CLOCK_ADJUST_1 0x04000000 + +#define CASLAT_20 0x3 /* CAS latency = 2.0 */ +#define CASLAT_25 0x4 /* CAS latency = 2.5 */ +#define CASLAT_30 0x5 /* CAS latency = 3.0 */ +#define CASLAT_35 0x6 /* CAS latency = 3.5 */ +#define CASLAT_40 0x7 /* CAS latency = 4.0 */ +#define CASLAT_45 0x8 /* CAS latency = 4.5 */ +#define CASLAT_50 0x9 /* CAS latency = 5.0 */ + +#define READ_LAT_PLUS_1 0x0 +#define READ_LAT 0x2 +#define READ_LAT_PLUS_1_4 0x3 +#define READ_LAT_PLUS_1_2 0x4 +#define READ_LAT_PLUS_3_4 0x5 +/* #define READ_LAT_PLUS_1 0x6 */ +#define READ_LAT_PLUS_5_4 0x7 +#define READ_LAT_PLUS_3_2 0x8 +#define READ_LAT_PLUS_7_4 0x9 +#define READ_LAT_PLUS_2 0xA +#define READ_LAT_PLUS_9_4 0xB +#define READ_LAT_PLUS_5_2 0xC +#define READ_LAT_PLUS_11_4 0xD +#define READ_LAT_PLUS_3 0xE +#define READ_LAT_PLUS_13_4 0xF +#define READ_LAT_PLUS_7_2 0x10 +#define READ_LAT_PLUS_15_4 0x11 +#define READ_LAT_PLUS_4 0x12 +#define READ_LAT_PLUS_17_4 0x13 +#define READ_LAT_PLUS_9_2 0x14 +#define READ_LAT_PLUS_19_4 0x15 + +#define CLOCK_DELAY_0 0x0 +#define CLOCK_DELAY_1_4 0x1 +#define CLOCK_DELAY_1_2 0x2 +#define CLOCK_DELAY_3_4 0x3 +#define CLOCK_DELAY_1 0x4 +#define CLOCK_DELAY_5_4 0x5 +#define CLOCK_DELAY_3_2 0x6 + +/* DDR SDRAM Control Configuration */ + +#define SREN_DISABLE 0x0 +#define SREN_ENABLE 0x1 + +#define ECC_DISABLE 0x0 +#define ECC_ENABLE 0x1 + +#define RD_DISABLE 0x0 +#define RD_ENABLE 0x1 + +#define TYPE_DDR1 0x2 +#define TYPE_DDR2 0x3 + +#define DYN_PWR_DISABLE 0x0 +#define DYN_PWR_ENABLE 0x1 + +#define DATA_BUS_WIDTH_16 0x1 +#define DATA_BUS_WIDTH_32 0x2 + +#define NCAP_DISABLE 0x0 +#define NCAP_ENABLE 0x1 + +#define TIMING_1T 0x0 +#define TIMING_2T 0x1 + +#define INTERLEAVE_NONE 0x0 +#define INTERLEAVE_1_AND_2 0x1 + +#define PRECHARGE_MA_10 0x0 +#define PRECHARGE_MA_8 0x1 + +#define STRENGTH_FULL 0x0 +#define STRENGTH_HALF 0x1 + +#define INITIALIZATION_DONT_BYPASS 0x0 +#define INITIALIZATION_BYPASS 0x1 + +/* DDR SDRAM Control Configuration 2 */ + +#define MODE_NORMAL 0x0 +#define MODE_REFRESH 0x1 + +#define DLL_RESET_ENABLE 0x0 +#define DLL_RESET_DISABLE 0x1 + +#define DQS_TRUE 0x0 + +#define ODT_ASSERT_NEVER 0x0 +#define ODT_ASSERT_WRITES 0x1 +#define ODT_ASSERT_READS 0x2 +#define ODT_ASSERT_ALWAYS 0x3 + +#endif diff --git a/include/mpc83xx.h b/include/mpc83xx.h index b5a0bbf847..26258126d6 100644 --- a/include/mpc83xx.h +++ b/include/mpc83xx.h @@ -1111,6 +1111,8 @@ #define CSBNDS_EA 0x000000FF #define CSBNDS_EA_SHIFT 24 +#ifndef CONFIG_MPC83XX_SDRAM + /* * CSn_CONFIG - Chip Select Configuration Register */ @@ -1408,6 +1410,8 @@ #define ECC_ERROR_MAN_SBEC (0xff000000 >> 24) #define ECC_ERROR_MAN_SBEC_SHIFT 0 +#endif /* !CONFIG_MPC83XX_SDRAM */ + /* * CONFIG_ADDRESS - PCI Config Address Register */ @@ -1511,6 +1515,7 @@ */ #define PMCCR1_POWER_OFF 0x00000020 +#ifndef CONFIG_RAM /* * DDRCDR - DDR Control Driver Register */ @@ -1532,6 +1537,7 @@ #define DDRCDR_DDR_CFG 0x00040000 #define DDRCDR_M_ODR 0x00000002 #define DDRCDR_Q_DRN 0x00000001 +#endif /* !CONFIG_RAM */ /* * PCIE Bridge Register -- 2.16.1 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot