From: Mario Six Date: Mon, 6 Aug 2018 08:23:30 +0000 (+0200) Subject: ram: Add driver for MPC83xx X-Git-Url: http://git.dujemihanovic.xyz/?a=commitdiff_plain;h=e40615565d68465284b3c6a5fc4147f662824a88;p=u-boot.git ram: Add driver for MPC83xx Add a RAM driver for the MPC83xx architecture. Reviewed-by: Simon Glass Signed-off-by: Mario Six --- diff --git a/Documentation/devicetree/bindings/ram/fsl,mpc83xx-mem-controller.txt b/Documentation/devicetree/bindings/ram/fsl,mpc83xx-mem-controller.txt new file mode 100644 index 0000000000..da01fe908d --- /dev/null +++ b/Documentation/devicetree/bindings/ram/fsl,mpc83xx-mem-controller.txt @@ -0,0 +1,314 @@ +MPC83xx RAM controller + +This driver supplies support for the embedded RAM controller on MCP83xx-series +SoCs. + +For static configuration mode, each controller node should have child nodes +describing the actual RAM modules installed. + +Controller node +=============== + +Required properties: +- compatible: Must be "fsl,mpc83xx-mem-controller" +- reg: The address of the RAM controller's register space +- #address-cells: Must be 2 +- #size-cells: Must be 1 +- driver_software_override: DDR driver software override is enabled (1) or + disabled (0) +- p_impedance_override: DDR driver software p-impedance override; possible + values: + * DSO_P_IMPEDANCE_HIGHEST_Z + * DSO_P_IMPEDANCE_MUCH_HIGHER_Z + * DSO_P_IMPEDANCE_HIGHER_Z + * DSO_P_IMPEDANCE_NOMINAL + * DSO_P_IMPEDANCE_LOWER_Z +- n_impedance_override: DDR driver software n-impedance override; possible + values: + * DSO_N_IMPEDANCE_HIGHEST_Z + * DSO_N_IMPEDANCE_MUCH_HIGHER_Z + * DSO_N_IMPEDANCE_HIGHER_Z + * DSO_N_IMPEDANCE_NOMINAL + * DSO_N_IMPEDANCE_LOWER_Z +- odt_termination_value: ODT termination value for I/Os; possible values: + * ODT_TERMINATION_75_OHM + * ODT_TERMINATION_150_OHM +- ddr_type: Selects voltage level for DDR pads; possible + values: + * DDR_TYPE_DDR2_1_8_VOLT + * DDR_TYPE_DDR1_2_5_VOLT +- mvref_sel: Determine where MVREF_SEL signal is generated; + possible values: + * MVREF_SEL_EXTERNAL + * MVREF_SEL_INTERNAL_GVDD +- m_odr: Disable memory transaction reordering; possible + values: + * M_ODR_ENABLE + * M_ODR_DISABLE +- clock_adjust: Clock adjust; possible values: + * CLOCK_ADJUST_025 + * CLOCK_ADJUST_05 + * CLOCK_ADJUST_075 + * CLOCK_ADJUST_1 +- ext_refresh_rec: Extended refresh recovery time; possible values: + 0, 16, 32, 48, 64, 80, 96, 112 +- read_to_write: Read-to-write turnaround; possible values: + 0, 1, 2, 3 +- write_to_read: Write-to-read turnaround; possible values: + 0, 1, 2, 3 +- read_to_read: Read-to-read turnaround; possible values: + 0, 1, 2, 3 +- write_to_write: Write-to-write turnaround; possible values: + 0, 1, 2, 3 +- active_powerdown_exit: Active powerdown exit timing; possible values: + 1, 2, 3, 4, 5, 6, 7 +- precharge_powerdown_exit: Precharge powerdown exit timing; possible values: + 1, 2, 3, 4, 5, 6, 7 +- odt_powerdown_exit: ODT powerdown exit timing; possible values: + 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15 +- mode_reg_set_cycle: Mode register set cycle time; possible values: + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +- precharge_to_activate: Precharge-to-acitvate interval; possible values: + 1, 2, 3, 4, 5, 6, 7 +- activate_to_precharge: Activate to precharge interval; possible values: + 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19 +- activate_to_readwrite: Activate to read/write interval for SDRAM; + possible values: + 1, 2, 3, 4, 5, 6, 7 +- mcas_latency: MCAS latency from READ command; possible values: + * CASLAT_20 + * CASLAT_25 + * CASLAT_30 + * CASLAT_35 + * CASLAT_40 + * CASLAT_45 + * CASLAT_50 + * CASLAT_55 + * CASLAT_60 + * CASLAT_65 + * CASLAT_70 + * CASLAT_75 + * CASLAT_80 +- refresh_recovery: Refresh recovery time; possible values: + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23 +- last_data_to_precharge: Last data to precharge minimum interval; possible + values: + 1, 2, 3, 4, 5, 6, 7 +- activate_to_activate: Activate-to-activate interval; possible values: + 1, 2, 3, 4, 5, 6, 7 +- last_write_data_to_read: Last write data pair to read command issue + interval; possible values: + 1, 2, 3, 4, 5, 6, 7 +- additive_latency: Additive latency; possible values: + 0, 1, 2, 3, 4, 5 +- mcas_to_preamble_override: MCAS-to-preamble-override; possible values: + * READ_LAT + * READ_LAT_PLUS_1_4 + * READ_LAT_PLUS_1_2 + * READ_LAT_PLUS_3_4 + * READ_LAT_PLUS_1 + * READ_LAT_PLUS_5_4 + * READ_LAT_PLUS_3_2 + * READ_LAT_PLUS_7_4 + * READ_LAT_PLUS_2 + * READ_LAT_PLUS_9_4 + * READ_LAT_PLUS_5_2 + * READ_LAT_PLUS_11_4 + * READ_LAT_PLUS_3 + * READ_LAT_PLUS_13_4 + * READ_LAT_PLUS_7_2 + * READ_LAT_PLUS_15_4 + * READ_LAT_PLUS_4 + * READ_LAT_PLUS_17_4 + * READ_LAT_PLUS_9_2 + * READ_LAT_PLUS_19_4 +- write_latency: Write latency; possible values: + 1, 2, 3, 4, 5, 6, 7 +- read_to_precharge: Read to precharge; possible values: + 1, 2, 3, 4 +- write_cmd_to_write_data: Write command to write data strobe timing + adjustment; possible values: + * CLOCK_DELAY_0 + * CLOCK_DELAY_1_4 + * CLOCK_DELAY_1_2 + * CLOCK_DELAY_3_4 + * CLOCK_DELAY_1 + * CLOCK_DELAY_5_4 + * CLOCK_DELAY_3_2 +- minimum_cke_pulse_width: Minimum CKE pulse width; possible values: + 1, 2, 3, 4 +- four_activates_window: Window for four activates; possible values: + 1, 2, 3, 4 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19 +- self_refresh: Self refresh (during sleep); possible values: + * SREN_DISABLE + * SREN_ENABLE +- ecc: Support for ECC; possible values: + * ECC_DISABLE + * ECC_ENABLE +- registered_dram: Support for registered DRAM; possible values: + * RD_DISABLE + * RD_ENABLE +- sdram_type: Type of SDRAM device to be used; possible values: + * TYPE_DDR1 + * TYPE_DDR2 +- dynamic_power_management: Dynamic power management mode; possible values: + * DYN_PWR_DISABLE + * DYN_PWR_ENABLE +- databus_width: DRAM data bus width; possible values + * DATA_BUS_WIDTH_16 + * DATA_BUS_WIDTH_32 +- nc_auto_precharge: Non-concurrent auto-precharge; possible values: + * NCAP_DISABLE + * NCAP_ENABLE +- timing_2t: 2T timing; possible values: + * TIMING_1T + * TIMING_2T +- bank_interleaving_ctrl: Bank (chip select) interleaving control; possible + values: + * INTERLEAVE_NONE + * INTERLEAVE_1_AND_2 +- precharge_bit_8: Precharge bin 8; possible values + * PRECHARGE_MA_10 + * PRECHARGE_MA_8 +- half_strength: Global half-strength override; possible values: + * STRENGTH_FULL + * STRENGTH_HALF +- bypass_initialization: Bypass initialization; possible values: + * INITIALIZATION_DONT_BYPASS + * INITIALIZATION_BYPASS +- force_self_refresh: Force self refresh; possible values: + * MODE_NORMAL + * MODE_REFRESH +- dll_reset: DLL reset; possible values: + * DLL_RESET_ENABLE + * DLL_RESET_DISABLE +- dqs_config: DQS configuration; possible values: + * DQS_TRUE +- odt_config: ODT configuration; possible values: + * ODT_ASSERT_NEVER + * ODT_ASSERT_WRITES + * ODT_ASSERT_READS + * ODT_ASSERT_ALWAYS +- posted_refreshes: Number of posted refreshes + 1, 2, 3, 4, 5, 6, 7, 8 +- sdmode: Initial value loaded into the DDR SDRAM mode + register +- esdmode: Initial value loaded into the DDR SDRAM extended + mode register +- esdmode2: Initial value loaded into the DDR SDRAM extended + mode 2 register +- esdmode3: Initial value loaded into the DDR SDRAM extended + mode 3 register +- refresh_interval: Refresh interval; possible values: + 0 - 65535 +- precharge_interval: Precharge interval; possible values: + 0 - 16383 + +RAM module node: +================ + +Required properties: +- reg: A triple , which consists of: + * cs - the chipselect used to drive this RAM module + * addr - the address where this RAM module's memory is map + to in the global memory space + * size - the size of the RAM module's memory in bytes +- auto_precharge: Chip select auto-precharge; possible values: + * AUTO_PRECHARGE_ENABLE + * AUTO_PRECHARGE_DISABLE +- odt_rd_cfg: ODT for reads configuration; possible values: + * ODT_RD_NEVER + * ODT_RD_ONLY_CURRENT + * ODT_RD_ONLY_OTHER_CS + * ODT_RD_ONLY_OTHER_DIMM + * ODT_RD_ALL +- odt_wr_cfg: ODT for writes configuration; possible values: + * ODT_WR_NEVER + * ODT_WR_ONLY_CURRENT + * ODT_WR_ONLY_OTHER_CS + * ODT_WR_ONLY_OTHER_DIMM + * ODT_WR_ALL +- bank_bits: Number of bank bits for SDRAM on chip select; possible + values: + 2, 3 +- row_bits: Number of row bits for SDRAM on chip select; possible values: + 12, 13, 14 +- col_bits: Number of column bits for SDRAM on chip select; possible + values: + 8, 9, 10, 11 + +Example: + +memory@2000 { + #address-cells = <2>; + #size-cells = <1>; + compatible = "fsl,mpc83xx-mem-controller"; + reg = <0x2000 0x1000>; + device_type = "memory"; + u-boot,dm-pre-reloc; + + driver_software_override = ; + p_impedance_override = ; + n_impedance_override = ; + odt_termination_value = ; + ddr_type = ; + + clock_adjust = ; + + read_to_write = <0>; + write_to_read = <0>; + read_to_read = <0>; + write_to_write = <0>; + active_powerdown_exit = <2>; + precharge_powerdown_exit = <6>; + odt_powerdown_exit = <8>; + mode_reg_set_cycle = <2>; + + precharge_to_activate = <2>; + activate_to_precharge = <6>; + activate_to_readwrite = <2>; + mcas_latency = ; + refresh_recovery = <17>; + last_data_to_precharge = <2>; + activate_to_activate = <2>; + last_write_data_to_read = <2>; + + additive_latency = <0>; + mcas_to_preamble_override = ; + write_latency = <3>; + read_to_precharge = <2>; + write_cmd_to_write_data = ; + minimum_cke_pulse_width = <3>; + four_activates_window = <5>; + + self_refresh = ; + sdram_type = ; + databus_width = ; + + force_self_refresh = ; + dll_reset = ; + dqs_config = ; + odt_config = ; + posted_refreshes = <1>; + + refresh_interval = <2084>; + precharge_interval = <256>; + + sdmode = <0x0242>; + esdmode = <0x0440>; + + ram@0 { + reg = <0x0 0x0 0x8000000>; + compatible = "nanya,nt5tu64m16hg"; + + odt_rd_cfg = ; + odt_wr_cfg = ; + bank_bits = <3>; + row_bits = <13>; + col_bits = <10>; + }; +}; diff --git a/MAINTAINERS b/MAINTAINERS index 39d28e5d45..76b2505ade 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -519,6 +519,8 @@ POWERPC MPC83XX M: Mario Six S: Maintained T: git git://git.denx.de/u-boot-mpc83xx.git +F: drivers/ram/mpc83xx_sdram.c +F: include/dt-bindings/memory/mpc83xx-sdram.h F: arch/powerpc/cpu/mpc83xx/ F: arch/powerpc/include/asm/arch-mpc83xx/ diff --git a/arch/powerpc/cpu/mpc83xx/spd_sdram.c b/arch/powerpc/cpu/mpc83xx/spd_sdram.c index bbc8ef03c7..328a018eb6 100644 --- a/arch/powerpc/cpu/mpc83xx/spd_sdram.c +++ b/arch/powerpc/cpu/mpc83xx/spd_sdram.c @@ -10,6 +10,8 @@ * Xianghua Xiao (X.Xiao@motorola.com) */ +#ifndef CONFIG_MPC83XX_SDRAM + #include #include #include @@ -924,3 +926,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..54bb4b419f 100644 --- a/drivers/ram/Kconfig +++ b/drivers/ram/Kconfig @@ -34,4 +34,13 @@ 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 (Serial Presence Detect) 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..441baeb6f1 --- /dev/null +++ b/drivers/ram/mpc83xx_sdram.c @@ -0,0 +1,1096 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + */ + +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* Masks for the CS config register */ +static const u32 CSCONFIG_ENABLE = 0x80000000; + +static const u32 BANK_BITS_2; +static const u32 BANK_BITS_3 = 0x00004000; + +static const u32 ROW_BITS_12; +static const u32 ROW_BITS_13 = 0x00000100; +static const u32 ROW_BITS_14 = 0x00000200; + +static const u32 COL_BITS_8; +static const u32 COL_BITS_9 = 0x00000001; +static const u32 COL_BITS_10 = 0x00000002; +static const u32 COL_BITS_11 = 0x00000003; + +/* Shifts for the DDR SDRAM Timing Configuration 3 register */ +static const uint TIMING_CFG3_EXT_REFREC_SHIFT = (31 - 15); + +/* Shifts for the DDR SDRAM Timing Configuration 0 register */ +static const uint TIMING_CFG0_RWT_SHIFT = (31 - 1); +static const uint TIMING_CFG0_WRT_SHIFT = (31 - 3); +static const uint TIMING_CFG0_RRT_SHIFT = (31 - 5); +static const uint TIMING_CFG0_WWT_SHIFT = (31 - 7); +static const uint TIMING_CFG0_ACT_PD_EXIT_SHIFT = (31 - 11); +static const uint TIMING_CFG0_PRE_PD_EXIT_SHIFT = (31 - 15); +static const uint TIMING_CFG0_ODT_PD_EXIT_SHIFT = (31 - 23); +static const uint TIMING_CFG0_MRS_CYC_SHIFT = (31 - 31); + +/* Shifts for the DDR SDRAM Timing Configuration 1 register */ +static const uint TIMING_CFG1_PRETOACT_SHIFT = (31 - 3); +static const uint TIMING_CFG1_ACTTOPRE_SHIFT = (31 - 7); +static const uint TIMING_CFG1_ACTTORW_SHIFT = (31 - 11); +static const uint TIMING_CFG1_CASLAT_SHIFT = (31 - 15); +static const uint TIMING_CFG1_REFREC_SHIFT = (31 - 19); +static const uint TIMING_CFG1_WRREC_SHIFT = (31 - 23); +static const uint TIMING_CFG1_ACTTOACT_SHIFT = (31 - 27); +static const uint TIMING_CFG1_WRTORD_SHIFT = (31 - 31); + +/* Shifts for the DDR SDRAM Timing Configuration 2 register */ +static const uint TIMING_CFG2_CPO_SHIFT = (31 - 8); +static const uint TIMING_CFG2_WR_DATA_DELAY_SHIFT = (31 - 21); +static const uint TIMING_CFG2_ADD_LAT_SHIFT = (31 - 3); +static const uint TIMING_CFG2_WR_LAT_DELAY_SHIFT = (31 - 12); +static const uint TIMING_CFG2_RD_TO_PRE_SHIFT = (31 - 18); +static const uint TIMING_CFG2_CKE_PLS_SHIFT = (31 - 25); +static const uint TIMING_CFG2_FOUR_ACT_SHIFT; + +/* Shifts for the DDR SDRAM Control Configuration register */ +static const uint SDRAM_CFG_SREN_SHIFT = (31 - 1); +static const uint SDRAM_CFG_ECC_EN_SHIFT = (31 - 2); +static const uint SDRAM_CFG_RD_EN_SHIFT = (31 - 3); +static const uint SDRAM_CFG_SDRAM_TYPE_SHIFT = (31 - 7); +static const uint SDRAM_CFG_DYN_PWR_SHIFT = (31 - 10); +static const uint SDRAM_CFG_DBW_SHIFT = (31 - 12); +static const uint SDRAM_CFG_NCAP_SHIFT = (31 - 14); +static const uint SDRAM_CFG_2T_EN_SHIFT = (31 - 16); +static const uint SDRAM_CFG_BA_INTLV_CTL_SHIFT = (31 - 23); +static const uint SDRAM_CFG_PCHB8_SHIFT = (31 - 27); +static const uint SDRAM_CFG_HSE_SHIFT = (31 - 28); +static const uint SDRAM_CFG_BI_SHIFT = (31 - 31); + +/* Shifts for the DDR SDRAM Control Configuration 2 register */ +static const uint SDRAM_CFG2_FRC_SR_SHIFT = (31 - 0); +static const uint SDRAM_CFG2_DLL_RST_DIS = (31 - 2); +static const uint SDRAM_CFG2_DQS_CFG = (31 - 5); +static const uint SDRAM_CFG2_ODT_CFG = (31 - 10); +static const uint SDRAM_CFG2_NUM_PR = (31 - 19); + +/* Shifts for the DDR SDRAM Mode register */ +static const uint SDRAM_MODE_ESD_SHIFT = (31 - 15); +static const uint SDRAM_MODE_SD_SHIFT = (31 - 31); + +/* Shifts for the DDR SDRAM Mode 2 register */ +static const uint SDRAM_MODE2_ESD2_SHIFT = (31 - 15); +static const uint SDRAM_MODE2_ESD3_SHIFT = (31 - 31); + +/* Shifts for the DDR SDRAM Interval Configuration register */ +static const uint SDRAM_INTERVAL_REFINT_SHIFT = (31 - 15); +static const uint SDRAM_INTERVAL_BSTOPRE_SHIFT = (31 - 31); + +/* Mask for the DDR SDRAM Mode Control register */ +static const u32 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("%s: uclass_first_device_err failed: %d\n", + __func__, ret); + return ret; + } + + /* FIXME(mario.six@gdsys.cc): Set gd->ram_size? */ + + return 0; +} + +phys_size_t get_effective_memsize(void) +{ + if (!IS_ENABLED(CONFIG_VERY_BIG_RAM)) + return gd->ram_size; + + /* Limit stack to what we can reasonable map */ + return ((gd->ram_size > CONFIG_MAX_MEM_MAPPED) ? + CONFIG_MAX_MEM_MAPPED : gd->ram_size); +} + +/** + * struct mpc83xx_sdram_priv - Private data for MPC83xx RAM controllers + * @total_size: The total size of all RAM modules associated with this RAM + * controller in bytes + */ +struct mpc83xx_sdram_priv { + ulong total_size; +}; + +/** + * mpc83xx_sdram_static_init() - Statically initialize a RAM module. + * @node: Device tree node associated with ths module in question + * @cs: The chip select to use for this RAM module + * @mapaddr: The address where the RAM module should be mapped + * @size: The size of the RAM module to be mapped in bytes + * + * Return: 0 if OK, -ve on error + */ +static 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("%s: auto_precharge value %d invalid.\n", + ofnode_get_name(node), auto_precharge); + return -EINVAL; + } + + odt_rd_cfg = ofnode_read_u32_default(node, "odt_rd_cfg", 0); + switch (odt_rd_cfg) { + case ODT_RD_ONLY_OTHER_DIMM: + if (!IS_ENABLED(CONFIG_MPC8360) && + !IS_ENABLED(CONFIG_MPC837x)) { + debug("%s: odt_rd_cfg value %d invalid.\n", + ofnode_get_name(node), odt_rd_cfg); + return -EINVAL; + } + /* fall through */ + case ODT_RD_NEVER: + case ODT_RD_ONLY_CURRENT: + case ODT_RD_ONLY_OTHER_CS: + if (!IS_ENABLED(CONFIG_MPC830x) && + !IS_ENABLED(CONFIG_MPC831x) && + !IS_ENABLED(CONFIG_MPC8360) && + !IS_ENABLED(CONFIG_MPC837x)) { + debug("%s: odt_rd_cfg value %d invalid.\n", + ofnode_get_name(node), odt_rd_cfg); + return -EINVAL; + } + /* fall through */ + /* Only MPC832x knows this value */ + case ODT_RD_ALL: + break; + default: + debug("%s: odt_rd_cfg value %d invalid.\n", + ofnode_get_name(node), odt_rd_cfg); + return -EINVAL; + } + + odt_wr_cfg = ofnode_read_u32_default(node, "odt_wr_cfg", 0); + switch (odt_wr_cfg) { + case ODT_WR_ONLY_OTHER_DIMM: + if (!IS_ENABLED(CONFIG_MPC8360) && + !IS_ENABLED(CONFIG_MPC837x)) { + debug("%s: odt_wr_cfg value %d invalid.\n", + ofnode_get_name(node), odt_wr_cfg); + return -EINVAL; + } + /* fall through */ + case ODT_WR_NEVER: + case ODT_WR_ONLY_CURRENT: + case ODT_WR_ONLY_OTHER_CS: + if (!IS_ENABLED(CONFIG_MPC830x) && + !IS_ENABLED(CONFIG_MPC831x) && + !IS_ENABLED(CONFIG_MPC8360) && + !IS_ENABLED(CONFIG_MPC837x)) { + debug("%s: odt_wr_cfg value %d invalid.\n", + ofnode_get_name(node), odt_wr_cfg); + return -EINVAL; + } + /* fall through */ + /* MPC832x only knows this value */ + case ODT_WR_ALL: + break; + default: + debug("%s: odt_wr_cfg value %d invalid.\n", + ofnode_get_name(node), odt_wr_cfg); + 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("%s: bank_bits value %d invalid.\n", + ofnode_get_name(node), bank_bits); + 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("%s: row_bits value %d invalid.\n", + ofnode_get_name(node), row_bits); + 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("%s: col_bits value %d invalid.\n", + ofnode_get_name(node), col_bits); + 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; +} + +/** + * mpc83xx_sdram_spd_init() - Initialize a RAM module using a SPD flash. + * @node: Device tree node associated with ths module in question + * @cs: The chip select to use for this RAM module + * @mapaddr: The address where the RAM module should be mapped + * @size: The size of the RAM module to be mapped in bytes + * + * Return: 0 if OK, -ve on error + */ +static int mpc83xx_sdram_spd_init(ofnode node, u32 cs, u32 mapaddr, u32 size) +{ + /* TODO(mario.six@gdsys.cc): Implement */ + 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 ret = 0; + ofnode subnode; + /* DDR control driver register values */ + u32 dso, pz_override, nz_override, odt_term, ddr_type, mvref_sel, m_odr; + u32 ddrcdr; + /* DDR SDRAM Clock Control register values */ + u32 clock_adjust; + /* DDR SDRAM Timing Configuration 3 register values */ + u32 ext_refresh_rec, ext_refresh_rec_mask; + /* DDR SDRAM Timing Configuration 0 register values */ + 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; + /* DDR SDRAM Timing Configuration 1 register values */ + 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; + /* DDR SDRAM Timing Configuration 2 register values */ + 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; + /* DDR SDRAM Control Configuration register values */ + 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; + /* DDR SDRAM Control Configuration 2 register values */ + u32 force_self_refresh, dll_reset, dqs_config, odt_config, + posted_refreshes; + u32 sdram_cfg2; + /* DDR SDRAM Mode Configuration register values */ + u32 sdmode, esdmode; + u32 sdram_mode; + /* DDR SDRAM Mode Configuration 2 register values */ + u32 esdmode2, esdmode3; + u32 sdram_mode2; + /* DDR SDRAM Interval Configuration register values */ + u32 refresh_interval, precharge_interval; + u32 sdram_interval; + + 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("%s: driver_software_override value %d invalid.\n", + dev->name, dso); + 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("%s: p_impedance_override value %d invalid.\n", + dev->name, pz_override); + 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("%s: n_impedance_override value %d invalid.\n", + dev->name, nz_override); + return -EINVAL; + } + + odt_term = dev_read_u32_default(dev, "odt_termination_value", 0); + if (odt_term > 1) { + debug("%s: odt_termination_value value %d invalid.\n", + dev->name, odt_term); + return -EINVAL; + } + + ddr_type = dev_read_u32_default(dev, "ddr_type", 0); + if (ddr_type > 1) { + debug("%s: ddr_type value %d invalid.\n", + dev->name, ddr_type); + return -EINVAL; + } + + mvref_sel = dev_read_u32_default(dev, "mvref_sel", 0); + if (mvref_sel > 1) { + debug("%s: mvref_sel value %d invalid.\n", + dev->name, mvref_sel); + return -EINVAL; + } + + m_odr = dev_read_u32_default(dev, "m_odr", 0); + if (mvref_sel > 1) { + debug("%s: m_odr value %d invalid.\n", + dev->name, m_odr); + 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("%s: chip select value %d invalid.\n", + dev->name, cs); + return -EINVAL; + } + + /* TODO(mario.six@gdsys.cc): Sanity check for size. */ + + if (ofnode_read_bool(subnode, "read-spd")) + ret = mpc83xx_sdram_spd_init(subnode, cs, addr, size); + else + ret = mpc83xx_sdram_static_init(subnode, cs, addr, + size); + if (ret) { + debug("%s: RAM init failed.\n", dev->name); + return ret; + } + }; + + /* + * TODO(mario.six@gdsys.cc): 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("%s: clock_adjust value %d invalid.\n", + dev->name, clock_adjust); + 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("%s: ext_refresh_rec value %d invalid.\n", + dev->name, ext_refresh_rec); + 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("%s: read_to_write value %d invalid.\n", + dev->name, read_to_write); + return -EINVAL; + } + + write_to_read = dev_read_u32_default(dev, "write_to_read", 0); + if (write_to_read > 3) { + debug("%s: write_to_read value %d invalid.\n", + dev->name, write_to_read); + return -EINVAL; + } + + read_to_read = dev_read_u32_default(dev, "read_to_read", 0); + if (read_to_read > 3) { + debug("%s: read_to_read value %d invalid.\n", + dev->name, read_to_read); + return -EINVAL; + } + + write_to_write = dev_read_u32_default(dev, "write_to_write", 0); + if (write_to_write > 3) { + debug("%s: write_to_write value %d invalid.\n", + dev->name, write_to_write); + return -EINVAL; + } + + active_powerdown_exit = + dev_read_u32_default(dev, "active_powerdown_exit", 0); + if (active_powerdown_exit > 7) { + debug("%s: active_powerdown_exit value %d invalid.\n", + dev->name, active_powerdown_exit); + return -EINVAL; + } + + precharge_powerdown_exit = + dev_read_u32_default(dev, "precharge_powerdown_exit", 0); + if (precharge_powerdown_exit > 7) { + debug("%s: precharge_powerdown_exit value %d invalid.\n", + dev->name, precharge_powerdown_exit); + return -EINVAL; + } + + odt_powerdown_exit = dev_read_u32_default(dev, "odt_powerdown_exit", 0); + if (odt_powerdown_exit > 15) { + debug("%s: odt_powerdown_exit value %d invalid.\n", + dev->name, odt_powerdown_exit); + return -EINVAL; + } + + mode_reg_set_cycle = dev_read_u32_default(dev, "mode_reg_set_cycle", 0); + if (mode_reg_set_cycle > 15) { + debug("%s: mode_reg_set_cycle value %d invalid.\n", + dev->name, mode_reg_set_cycle); + 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("%s: precharge_to_activate value %d invalid.\n", + dev->name, precharge_to_activate); + return -EINVAL; + } + + activate_to_precharge = + dev_read_u32_default(dev, "activate_to_precharge", 0); + if (activate_to_precharge > 19) { + debug("%s: activate_to_precharge value %d invalid.\n", + dev->name, activate_to_precharge); + return -EINVAL; + } + + activate_to_readwrite = + dev_read_u32_default(dev, "activate_to_readwrite", 0); + if (activate_to_readwrite > 7 || activate_to_readwrite == 0) { + debug("%s: activate_to_readwrite value %d invalid.\n", + dev->name, activate_to_readwrite); + return -EINVAL; + } + + mcas_latency = dev_read_u32_default(dev, "mcas_latency", 0); + switch (mcas_latency) { + case CASLAT_20: + case CASLAT_25: + if (!IS_ENABLED(CONFIG_ARCH_MPC8308)) { + debug("%s: MCAS latency < 3.0 unsupported on MPC8308\n", + dev->name); + return -EINVAL; + } + /* fall through */ + case CASLAT_30: + case CASLAT_35: + case CASLAT_40: + case CASLAT_45: + case CASLAT_50: + case CASLAT_55: + case CASLAT_60: + case CASLAT_65: + case CASLAT_70: + case CASLAT_75: + case CASLAT_80: + break; + default: + debug("%s: mcas_latency value %d invalid.\n", + dev->name, mcas_latency); + return -EINVAL; + } + + refresh_recovery = dev_read_u32_default(dev, "refresh_recovery", 0); + if (refresh_recovery > 23 || refresh_recovery < 8) { + debug("%s: refresh_recovery value %d invalid.\n", + dev->name, refresh_recovery); + 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("%s: last_data_to_precharge value %d invalid.\n", + dev->name, last_data_to_precharge); + return -EINVAL; + } + + activate_to_activate = + dev_read_u32_default(dev, "activate_to_activate", 0); + if (activate_to_activate > 7 || activate_to_activate == 0) { + debug("%s: activate_to_activate value %d invalid.\n", + dev->name, activate_to_activate); + 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("%s: last_write_data_to_read value %d invalid.\n", + dev->name, last_write_data_to_read); + return -EINVAL; + } + + timing_cfg_1 = precharge_to_activate << TIMING_CFG1_PRETOACT_SHIFT | + (activate_to_precharge > 15 ? + activate_to_precharge - 16 : + 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("%s: additive_latency value %d invalid.\n", + dev->name, additive_latency); + 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("%s: mcas_to_preamble_override value %d invalid.\n", + dev->name, mcas_to_preamble_override); + return -EINVAL; + } + + write_latency = dev_read_u32_default(dev, "write_latency", 0); + if (write_latency > 7 || write_latency == 0) { + debug("%s: write_latency value %d invalid.\n", + dev->name, write_latency); + return -EINVAL; + } + + read_to_precharge = dev_read_u32_default(dev, "read_to_precharge", 0); + if (read_to_precharge > 4 || read_to_precharge == 0) { + debug("%s: read_to_precharge value %d invalid.\n", + dev->name, read_to_precharge); + 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("%s: write_cmd_to_write_data value %d invalid.\n", + dev->name, write_cmd_to_write_data); + 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("%s: minimum_cke_pulse_width value %d invalid.\n", + dev->name, minimum_cke_pulse_width); + return -EINVAL; + } + + four_activates_window = + dev_read_u32_default(dev, "four_activates_window", 0); + if (four_activates_window > 20 || four_activates_window == 0) { + debug("%s: four_activates_window value %d invalid.\n", + dev->name, four_activates_window); + 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("%s: self_refresh value %d invalid.\n", + dev->name, self_refresh); + return -EINVAL; + } + + ecc = dev_read_u32_default(dev, "ecc", 0); + switch (ecc) { + case ECC_DISABLE: + case ECC_ENABLE: + break; + default: + debug("%s: ecc value %d invalid.\n", dev->name, ecc); + return -EINVAL; + } + + registered_dram = dev_read_u32_default(dev, "registered_dram", 0); + switch (registered_dram) { + case RD_DISABLE: + case RD_ENABLE: + break; + default: + debug("%s: registered_dram value %d invalid.\n", + dev->name, registered_dram); + return -EINVAL; + } + + sdram_type = dev_read_u32_default(dev, "sdram_type", 0); + switch (sdram_type) { + case TYPE_DDR1: + case TYPE_DDR2: + break; + default: + debug("%s: sdram_type value %d invalid.\n", + dev->name, sdram_type); + 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("%s: dynamic_power_management value %d invalid.\n", + dev->name, dynamic_power_management); + 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("%s: databus_width value %d invalid.\n", + dev->name, databus_width); + 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("%s: nc_auto_precharge value %d invalid.\n", + dev->name, nc_auto_precharge); + return -EINVAL; + } + + timing_2t = dev_read_u32_default(dev, "timing_2t", 0); + switch (timing_2t) { + case TIMING_1T: + case TIMING_2T: + break; + default: + debug("%s: timing_2t value %d invalid.\n", + dev->name, timing_2t); + 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("%s: bank_interleaving_ctrl value %d invalid.\n", + dev->name, bank_interleaving_ctrl); + 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("%s: precharge_bit_8 value %d invalid.\n", + dev->name, precharge_bit_8); + return -EINVAL; + } + + half_strength = dev_read_u32_default(dev, "half_strength", 0); + switch (half_strength) { + case STRENGTH_FULL: + case STRENGTH_HALF: + break; + default: + debug("%s: half_strength value %d invalid.\n", + dev->name, half_strength); + 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("%s: bypass_initialization value %d invalid.\n", + dev->name, bypass_initialization); + 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("%s: force_self_refresh value %d invalid.\n", + dev->name, force_self_refresh); + 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("%s: dll_reset value %d invalid.\n", + dev->name, dll_reset); + return -EINVAL; + } + + dqs_config = dev_read_u32_default(dev, "dqs_config", 0); + switch (dqs_config) { + case DQS_TRUE: + break; + default: + debug("%s: dqs_config value %d invalid.\n", + dev->name, dqs_config); + 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("%s: odt_config value %d invalid.\n", + dev->name, odt_config); + return -EINVAL; + } + + posted_refreshes = dev_read_u32_default(dev, "posted_refreshes", 0); + if (posted_refreshes > 8 || posted_refreshes == 0) { + debug("%s: posted_refreshes value %d invalid.\n", + dev->name, posted_refreshes); + 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("%s: sdmode value %d invalid.\n", + dev->name, sdmode); + return -EINVAL; + } + + esdmode = dev_read_u32_default(dev, "esdmode", 0); + if (esdmode > 0xFFFF) { + debug("%s: esdmode value %d invalid.\n", dev->name, esdmode); + 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("%s: esdmode2 value %d invalid.\n", dev->name, esdmode2); + return -EINVAL; + } + + esdmode3 = dev_read_u32_default(dev, "esdmode3", 0); + if (esdmode3 > 0xFFFF) { + debug("%s: esdmode3 value %d invalid.\n", dev->name, esdmode3); + 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("%s: refresh_interval value %d invalid.\n", + dev->name, refresh_interval); + return -EINVAL; + } + + precharge_interval = dev_read_u32_default(dev, "precharge_interval", 0); + if (precharge_interval > 0x3FFF) { + debug("%s: precharge_interval value %d invalid.\n", + dev->name, precharge_interval); + 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) +{ + /* TODO(mario.six@gdsys.cc): Implement */ + 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..7d4ce01cc4 --- /dev/null +++ b/include/dt-bindings/memory/mpc83xx-sdram.h @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + */ + +#ifndef DT_BINDINGS_MPC83XX_SDRAM_H +#define DT_BINDINGS_MPC83XX_SDRAM_H + +/* DDR Control Driver register */ + +#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_ONLY_OTHER_DIMM 0x00300000 +#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_ONLY_OTHER_DIMM 0x00030000 +#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 CASLAT_55 0xa /* CAS latency = 5.5 */ +#define CASLAT_60 0xb /* CAS latency = 6.0 */ +#define CASLAT_65 0xc /* CAS latency = 6.5 */ +#define CASLAT_70 0xd /* CAS latency = 7.0 */ +#define CASLAT_75 0xe /* CAS latency = 7.5 */ +#define CASLAT_80 0xf /* CAS latency = 8.0 */ + +/* DDR SDRAM Timing Configuration 2 register */ + +#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_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 register */ + +#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 e1e50ab6b5..a4c5bd3837 100644 --- a/include/mpc83xx.h +++ b/include/mpc83xx.h @@ -1110,6 +1110,8 @@ #define CSBNDS_EA 0x000000FF #define CSBNDS_EA_SHIFT 24 +#ifndef CONFIG_MPC83XX_SDRAM + /* * CSn_CONFIG - Chip Select Configuration Register */ @@ -1407,6 +1409,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 */ @@ -1510,6 +1514,7 @@ */ #define PMCCR1_POWER_OFF 0x00000020 +#ifndef CONFIG_RAM /* * DDRCDR - DDR Control Driver Register */ @@ -1531,6 +1536,7 @@ #define DDRCDR_DDR_CFG 0x00040000 #define DDRCDR_M_ODR 0x00000002 #define DDRCDR_Q_DRN 0x00000001 +#endif /* !CONFIG_RAM */ /* * PCIE Bridge Register