[U-Boot] [PATCH v2 01/10] ram: Add driver for MPC83xx

Add a RAM driver for the MPC83xx architecture.
Signed-off-by: Mario Six mario.six@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

It's useful to have the reset status of the SoC printed out during reset (e.g. to learn whether the reset was caused by software or a watchdog).
As a first step to implement this, add a get_status method to the sysreset class, which enables the caller to get printable information about the reset status (akin to get_desc in the CPU uclass).
Signed-off-by: Mario Six mario.six@gdsys.cc
---
v1 -> v2: New in v2
--- drivers/sysreset/sysreset-uclass.c | 10 ++++++++++ include/sysreset.h | 17 +++++++++++++++++ 2 files changed, 27 insertions(+)
diff --git a/drivers/sysreset/sysreset-uclass.c b/drivers/sysreset/sysreset-uclass.c index 0747c52b60..771a325b46 100644 --- a/drivers/sysreset/sysreset-uclass.c +++ b/drivers/sysreset/sysreset-uclass.c @@ -25,6 +25,16 @@ int sysreset_request(struct udevice *dev, enum sysreset_t type) return ops->request(dev, type); }
+int sysreset_get_status(struct udevice *dev, char *buf, int size) +{ + struct sysreset_ops *ops = sysreset_get_ops(dev); + + if (!ops->get_status) + return -ENOSYS; + + return ops->get_status(dev, buf, size); +} + int sysreset_walk(enum sysreset_t type) { struct udevice *dev; diff --git a/include/sysreset.h b/include/sysreset.h index 393c7be3d8..9e326fefeb 100644 --- a/include/sysreset.h +++ b/include/sysreset.h @@ -29,6 +29,14 @@ struct sysreset_ops { * (in which case this method will not actually return) */ int (*request)(struct udevice *dev, enum sysreset_t type); + /** + * get_status() - get printable reset status information + * + * @buf: Buffer to receive the textual reset information + * @size: Size of the passed buffer + * @return 0 if OK, -ve on error + */ + int (*get_status)(struct udevice *dev, char *buf, int size); };
#define sysreset_get_ops(dev) ((struct sysreset_ops *)(dev)->driver->ops) @@ -41,6 +49,15 @@ struct sysreset_ops { */ int sysreset_request(struct udevice *dev, enum sysreset_t type);
+/** + * get_status() - get printable reset status information + * + * @buf: Buffer to receive the textual reset information + * @size: Size of the passed buffer + * @return 0 if OK, -ve on error + */ +int sysreset_get_status(struct udevice *dev, char *buf, int size); + /** * sysreset_walk() - cause a system reset * -- 2.16.1

On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
It's useful to have the reset status of the SoC printed out during reset (e.g. to learn whether the reset was caused by software or a watchdog).
As a first step to implement this, add a get_status method to the sysreset class, which enables the caller to get printable information about the reset status (akin to get_desc in the CPU uclass).
Signed-off-by: Mario Six mario.six@gdsys.cc
v1 -> v2: New in v2
drivers/sysreset/sysreset-uclass.c | 10 ++++++++++ include/sysreset.h | 17 +++++++++++++++++ 2 files changed, 27 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org
Can you add a test for sandbox?

Hi Simon,
On Thu, May 3, 2018 at 9:01 PM, Simon Glass sjg@chromium.org wrote:
On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
It's useful to have the reset status of the SoC printed out during reset (e.g. to learn whether the reset was caused by software or a watchdog).
As a first step to implement this, add a get_status method to the sysreset class, which enables the caller to get printable information about the reset status (akin to get_desc in the CPU uclass).
Signed-off-by: Mario Six mario.six@gdsys.cc
v1 -> v2: New in v2
drivers/sysreset/sysreset-uclass.c | 10 ++++++++++ include/sysreset.h | 17 +++++++++++++++++ 2 files changed, 27 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org
Can you add a test for sandbox?
OK, will add a test in v3.
Best regards, Mario

To print the reset status during boot, add a method print_resetinfo to board_f, which is called in init_sequence_f[], that gets the reset information from the sysreset driver (assuming there is only one seems reasonable), and prints it.
Signed-off-by: Mario Six mario.six@gdsys.cc
---
v1 -> v2: New in v2
--- common/board_f.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/common/board_f.c b/common/board_f.c index ae8bdb7c5c..2df30cd250 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -25,6 +25,7 @@ #include <relocate.h> #include <spi.h> #include <status_led.h> +#include <sysreset.h> #include <timer.h> #include <trace.h> #include <video.h> @@ -141,6 +142,21 @@ static int display_text_info(void) return 0; }
+#ifdef CONFIG_SYSRESET +static int print_resetinfo(void) +{ + struct udevice *dev; + char status[256]; + + uclass_first_device_err(UCLASS_SYSRESET, &dev); + + if (!sysreset_get_status(dev, status, sizeof(status))) + printf("%s", status); + + return 0; +} +#endif + static int announce_dram_init(void) { puts("DRAM: "); @@ -789,6 +805,9 @@ static const init_fnc_t init_sequence_f[] = { #if defined(CONFIG_PPC) || defined(CONFIG_SH) || defined(CONFIG_X86) checkcpu, #endif +#if defined(CONFIG_SYSRESET) + print_resetinfo, +#endif #if defined(CONFIG_DISPLAY_CPUINFO) print_cpuinfo, /* display cpu info (and speed) */ #endif -- 2.16.1

Hi Mario,
On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
To print the reset status during boot, add a method print_resetinfo to board_f, which is called in init_sequence_f[], that gets the reset information from the sysreset driver (assuming there is only one seems reasonable), and prints it.
Signed-off-by: Mario Six mario.six@gdsys.cc
v1 -> v2: New in v2
common/board_f.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org
nit below
diff --git a/common/board_f.c b/common/board_f.c index ae8bdb7c5c..2df30cd250 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -25,6 +25,7 @@ #include <relocate.h> #include <spi.h> #include <status_led.h> +#include <sysreset.h> #include <timer.h> #include <trace.h> #include <video.h> @@ -141,6 +142,21 @@ static int display_text_info(void) return 0; }
+#ifdef CONFIG_SYSRESET +static int print_resetinfo(void) +{
struct udevice *dev;
char status[256];
uclass_first_device_err(UCLASS_SYSRESET, &dev);
Should check the result and only call the function below if it is 0.
if (!sysreset_get_status(dev, status, sizeof(status)))
printf("%s", status);
return 0;
+} +#endif
Regards, Simon

Hi Simon,
On Thu, May 3, 2018 at 9:01 PM, Simon Glass sjg@chromium.org wrote:
Hi Mario,
On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
To print the reset status during boot, add a method print_resetinfo to board_f, which is called in init_sequence_f[], that gets the reset information from the sysreset driver (assuming there is only one seems reasonable), and prints it.
Signed-off-by: Mario Six mario.six@gdsys.cc
v1 -> v2: New in v2
common/board_f.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org
nit below
diff --git a/common/board_f.c b/common/board_f.c index ae8bdb7c5c..2df30cd250 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -25,6 +25,7 @@ #include <relocate.h> #include <spi.h> #include <status_led.h> +#include <sysreset.h> #include <timer.h> #include <trace.h> #include <video.h> @@ -141,6 +142,21 @@ static int display_text_info(void) return 0; }
+#ifdef CONFIG_SYSRESET +static int print_resetinfo(void) +{
struct udevice *dev;
char status[256];
uclass_first_device_err(UCLASS_SYSRESET, &dev);
Should check the result and only call the function below if it is 0.
Yes, I found that one myself when I tried to run the sandbox tests again.
Will be fixed in v3.
if (!sysreset_get_status(dev, status, sizeof(status)))
printf("%s", status);
return 0;
+} +#endif
Regards, Simon
Best regards, Mario

Add a sysreset driver for the MPC83xx platform.
Signed-off-by: Mario Six mario.six@gdsys.cc
---
v1 -> v2: New in v2
--- arch/powerpc/cpu/mpc83xx/cpu.c | 3 +- drivers/sysreset/Kconfig | 5 ++ drivers/sysreset/Makefile | 9 +- drivers/sysreset/sysreset_mpc83xx.c | 160 ++++++++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 5 deletions(-) create mode 100644 drivers/sysreset/sysreset_mpc83xx.c
diff --git a/arch/powerpc/cpu/mpc83xx/cpu.c b/arch/powerpc/cpu/mpc83xx/cpu.c index 3bdebd845c..9a5c1b7d55 100644 --- a/arch/powerpc/cpu/mpc83xx/cpu.c +++ b/arch/powerpc/cpu/mpc83xx/cpu.c @@ -116,6 +116,7 @@ int checkcpu(void) return 0; }
+#ifndef CONFIG_SYSRESET int do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { @@ -170,7 +171,7 @@ do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
return 1; } - +#endif
/* * Get timebase clock frequency (like cpu_clk in Hz) diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index a6d48e8a66..fd89e5f474 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -37,4 +37,9 @@ config SYSRESET_WATCHDOG help Reboot support for generic watchdog reset.
+config SYSRESET_MCP83XX + bool "Enable support MPC83xx SoC family reboot driver" + help + Reboot support for NXP MPC83xx SoCs. + endmenu diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index 000c288eeb..faeb4b679f 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -5,11 +5,12 @@ #
obj-$(CONFIG_SYSRESET) += sysreset-uclass.o +obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o +obj-$(CONFIG_ARCH_ROCKCHIP) += sysreset_rockchip.o +obj-$(CONFIG_ARCH_STI) += sysreset_sti.o +obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o +obj-$(CONFIG_SYSRESET_MCP83XX) += sysreset_mpc83xx.o obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o obj-$(CONFIG_SYSRESET_SYSCON) += sysreset_syscon.o obj-$(CONFIG_SYSRESET_WATCHDOG) += sysreset_watchdog.o -obj-$(CONFIG_ARCH_ROCKCHIP) += sysreset_rockchip.o -obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o -obj-$(CONFIG_ARCH_STI) += sysreset_sti.o obj-$(CONFIG_TARGET_XTFPGA) += sysreset_xtfpga.o -obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o diff --git a/drivers/sysreset/sysreset_mpc83xx.c b/drivers/sysreset/sysreset_mpc83xx.c new file mode 100644 index 0000000000..110192065e --- /dev/null +++ b/drivers/sysreset/sysreset_mpc83xx.c @@ -0,0 +1,160 @@ +/* + * (C) Copyright 2018 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <sysreset.h> + +static void __do_reset(void) +{ + ulong msr; + + immap_t *immap = (immap_t *)CONFIG_SYS_IMMR; + + puts("Resetting the board.\n"); + + /* Interrupts and MMU off */ + msr = mfmsr(); + msr &= ~(MSR_EE | MSR_IR | MSR_DR); + mtmsr(msr); + + /* enable Reset Control Reg */ + out_be32(&immap->reset.rpr, 0x52535445); + sync(); + isync(); + + /* confirm Reset Control Reg is enabled */ + + while (!(in_be32(&immap->reset.rcer) & RCER_CRE)) + ; + + udelay(200); + + /* perform reset, only one bit */ + out_be32(&immap->reset.rcr, RCR_SWHR); +} + +int mpc83xx_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + switch (type) { + case SYSRESET_WARM: + case SYSRESET_COLD: + __do_reset(); + break; + default: + return -EPROTONOSUPPORT; + } + + return -EINPROGRESS; +} + +#if defined(CONFIG_DISPLAY_AER_FULL) +static int print_83xx_arb_event(int force) +{ + int etype = (gd->arch.arbiter_event_attributes & AEATR_EVENT) + >> AEATR_EVENT_SHIFT; + int mstr_id = (gd->arch.arbiter_event_attributes & AEATR_MSTR_ID) + >> AEATR_MSTR_ID_SHIFT; + int tbst = (gd->arch.arbiter_event_attributes & AEATR_TBST) + >> AEATR_TBST_SHIFT; + int tsize = (gd->arch.arbiter_event_attributes & AEATR_TSIZE) + >> AEATR_TSIZE_SHIFT; + int ttype = (gd->arch.arbiter_event_attributes & AEATR_TTYPE) + >> AEATR_TTYPE_SHIFT; + + if (!force && !gd->arch.arbiter_event_address) + return 0; + + puts("Arbiter Event Status:\n"); + printf(" Event Address: 0x%08lX\n", + gd->arch.arbiter_event_address); + printf(" Event Type: 0x%1x = %s\n", etype, event[etype]); + printf(" Master ID: 0x%02x = %s\n", mstr_id, master[mstr_id]); + printf(" Transfer Size: 0x%1x = %d bytes\n", (tbst << 3) | tsize, + tbst ? (tsize ? tsize : 8) : 16 + 8 * tsize); + printf(" Transfer Type: 0x%02x = %s\n", ttype, transfer[ttype]); + + return gd->arch.arbiter_event_address; +} + +#elif defined(CONFIG_DISPLAY_AER_BRIEF) + +static int print_83xx_arb_event(int force, char *buf, int size) +{ + int res; + + if (!force && !gd->arch.arbiter_event_address) + return 0; + + res = snprintf(buf, size, + "Arbiter Event Status: AEATR=0x%08lX, AEADR=0x%08lX\n", + gd->arch.arbiter_event_attributes, + gd->arch.arbiter_event_address); + + return res; +} +#endif /* CONFIG_DISPLAY_AER_xxxx */ + +int mpc83xx_sysreset_get_status(struct udevice *dev, char *buf, int size) +{ + int res; + static const struct { + ulong mask; + char *desc; + } bits[] = { + { + RSR_SWSR, "Software Soft"}, { + RSR_SWHR, "Software Hard"}, { + RSR_JSRS, "JTAG Soft"}, { + RSR_CSHR, "Check Stop"}, { + RSR_SWRS, "Software Watchdog"}, { + RSR_BMRS, "Bus Monitor"}, { + RSR_SRS, "External/Internal Soft"}, { + RSR_HRS, "External/Internal Hard"} + }; + static int n = ARRAY_SIZE(bits); + ulong rsr = gd->arch.reset_status; + int i; + char *sep; + + res = snprintf(buf, size, "Reset Status:"); + if (!res) + return -EIO; + + buf += res; + size -= res; + + sep = " "; + for (i = 0; i < n; i++) + if (rsr & bits[i].mask) { + res = snprintf(buf, size, "%s%s%s", sep, bits[i].desc, (i == n - 1) ? "\n" : ""); + buf += res; + size -= res; + sep = ", "; + } + +/* TODO(mario.six@gdsys.cc): Move this into a dedicated arbiter driver */ +#if defined(CONFIG_DISPLAY_AER_FULL) || defined(CONFIG_DISPLAY_AER_BRIEF) + res = print_83xx_arb_event(rsr & RSR_BMRS, buf, size); + buf += res; + size -= res; +#endif + snprintf(buf, size, "\n"); + + return 0; +} + +static struct sysreset_ops mpc83xx_sysreset = { + .request = mpc83xx_sysreset_request, + .get_status = mpc83xx_sysreset_get_status, +}; + +U_BOOT_DRIVER(sysreset_mpc83xx) = { + .name = "mpc83xx_sysreset", + .id = UCLASS_SYSRESET, + .ops = &mpc83xx_sysreset, +}; -- 2.16.1

On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
Add a sysreset driver for the MPC83xx platform.
Signed-off-by: Mario Six mario.six@gdsys.cc
v1 -> v2: New in v2
arch/powerpc/cpu/mpc83xx/cpu.c | 3 +- drivers/sysreset/Kconfig | 5 ++ drivers/sysreset/Makefile | 9 +- drivers/sysreset/sysreset_mpc83xx.c | 160 ++++++++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 5 deletions(-) create mode 100644 drivers/sysreset/sysreset_mpc83xx.c
Reviewed-by: Simon Glass sjg@chromium.org

Add a clock driver for the MPC83xx architecture.
Signed-off-by: Mario Six mario.six@gdsys.cc
---
v1 -> v2: * Added binding of sysreset driver
--- arch/powerpc/cpu/mpc83xx/speed.c | 4 + arch/powerpc/include/asm/config.h | 2 +- drivers/clk/Kconfig | 6 + drivers/clk/Makefile | 1 + drivers/clk/mpc83xx_clk.c | 430 ++++++++++++++++++++++++++++++++++ drivers/clk/mpc83xx_clk.h | 115 +++++++++ include/dt-bindings/clk/mpc83xx-clk.h | 27 +++ 7 files changed, 584 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/mpc83xx_clk.c create mode 100644 drivers/clk/mpc83xx_clk.h create mode 100644 include/dt-bindings/clk/mpc83xx-clk.h
diff --git a/arch/powerpc/cpu/mpc83xx/speed.c b/arch/powerpc/cpu/mpc83xx/speed.c index 5498c19e25..c9bdec0bc0 100644 --- a/arch/powerpc/cpu/mpc83xx/speed.c +++ b/arch/powerpc/cpu/mpc83xx/speed.c @@ -7,6 +7,8 @@ * SPDX-License-Identifier: GPL-2.0+ */
+#ifndef CONFIG_CLK_MPC83XX + #include <common.h> #include <mpc83xx.h> #include <command.h> @@ -591,3 +593,5 @@ U_BOOT_CMD(clocks, 1, 0, do_clocks, "print clock configuration", " clocks" ); + +#endif diff --git a/arch/powerpc/include/asm/config.h b/arch/powerpc/include/asm/config.h index 39eeb39901..d9dfb670af 100644 --- a/arch/powerpc/include/asm/config.h +++ b/arch/powerpc/include/asm/config.h @@ -79,7 +79,7 @@ /* All PPC boards must swap IDE bytes */ #define CONFIG_IDE_SWAP_IO
-#if defined(CONFIG_DM_SERIAL) +#if defined(CONFIG_DM_SERIAL) && !defined(CONFIG_CLK_MPC83XX) /* * TODO: Convert this to a clock driver exists that can give us the UART * clock here. diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c382e8865f..787c061e44 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -89,4 +89,10 @@ source "drivers/clk/exynos/Kconfig" source "drivers/clk/at91/Kconfig" source "drivers/clk/renesas/Kconfig"
+config CLK_MPC83XX + bool "Enable MPC83xx clock driver" + depends on CLK + help + Support for the clock driver of the MPC83xx series of SoCs. + endmenu diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index e05c607223..67da125669 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o obj-$(CONFIG_CLK_BOSTON) += clk_boston.o obj-$(CONFIG_CLK_EXYNOS) += exynos/ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o +obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o obj-$(CONFIG_CLK_RENESAS) += renesas/ obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o obj-$(CONFIG_CLK_STM32MP1) += clk_stm32mp1.o diff --git a/drivers/clk/mpc83xx_clk.c b/drivers/clk/mpc83xx_clk.c new file mode 100644 index 0000000000..96f762bfe1 --- /dev/null +++ b/drivers/clk/mpc83xx_clk.c @@ -0,0 +1,430 @@ +/* + * (C) Copyright 2017 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dm/lists.h> +#include <dt-bindings/clk/mpc83xx-clk.h> + +#include "mpc83xx_clk.h" + +DECLARE_GLOBAL_DATA_PTR; + +static u32 *speed; + +struct mpc83xx_clk_priv { + u32 *speed; +}; + +static const char * const names[] = { + [MPC83XX_CLK_CORE] = "Core", + [MPC83XX_CLK_CSB] = "Coherent System Bus", + [MPC83XX_CLK_QE] = "QE", + [MPC83XX_CLK_BRG] = "BRG", + [MPC83XX_CLK_LBIU] = "Local Bus Controller", + [MPC83XX_CLK_LCLK] = "Local Bus", + [MPC83XX_CLK_MEM] = "DDR", + [MPC83XX_CLK_MEM_SEC] = "DDR Secondary", + [MPC83XX_CLK_ENC] = "SEC", + [MPC83XX_CLK_I2C1] = "I2C1", + [MPC83XX_CLK_I2C2] = "I2C2", + [MPC83XX_CLK_TDM] = "TDM", + [MPC83XX_CLK_SDHC] = "SDHC", + [MPC83XX_CLK_TSEC1] = "TSEC1", + [MPC83XX_CLK_TSEC2] = "TSEC2", + [MPC83XX_CLK_USBDR] = "USB DR", + [MPC83XX_CLK_USBMPH] = "USB MPH", + [MPC83XX_CLK_PCIEXP1] = "PCIEXP1", + [MPC83XX_CLK_PCIEXP2] = "PCIEXP2", + [MPC83XX_CLK_SATA] = "SATA", + [MPC83XX_CLK_DMAC] = "DMAC", + [MPC83XX_CLK_PCI] = "PCI", +}; + +struct clk_mode { + u8 low; + u8 high; + int type; +}; + +const struct clk_mode modes[] = { + + [MPC83XX_CLK_CORE] = {0, 0, TYPE_SPECIAL}, + [MPC83XX_CLK_CSB] = {0, 0, TYPE_SPECIAL}, + [MPC83XX_CLK_QE] = {0, 0, TYPE_SPECIAL}, + [MPC83XX_CLK_BRG] = {0, 0, TYPE_SPECIAL}, + [MPC83XX_CLK_MEM] = {1, 1, TYPE_SPMR_DIRECT_MULTIPLY }, + [MPC83XX_CLK_LBIU] = {0, 0, TYPE_SPMR_DIRECT_MULTIPLY }, + [MPC83XX_CLK_LCLK] = {0, 0, TYPE_SPECIAL}, + [MPC83XX_CLK_MEM_SEC] = {0, 0, TYPE_SPMR_DIRECT_MULTIPLY }, /* The same as LBIU */ +#ifndef CONFIG_MPC8313 + [MPC83XX_CLK_TSEC1] = {0, 1, TYPE_SCCR_STANDARD }, + [MPC83XX_CLK_TSEC2] = {2, 3, TYPE_SCCR_STANDARD }, +#else + [MPC83XX_CLK_TSEC1] = {0, 1, TYPE_SCCR_STANDARD }, /* FIXME: This has separate enable/disable bit! */ + [MPC83XX_CLK_TSEC2] = {0, 1, TYPE_SCCR_STANDARD }, /* FIXME: This has separate enable/disable bit! */ +#endif + [MPC83XX_CLK_SDHC] = {4, 5, TYPE_SCCR_STANDARD }, +#ifdef CONFIG_MPC834x + [MPC83XX_CLK_ENC] = {6, 7, TYPE_SCCR_STANDARD }, + [MPC83XX_CLK_I2C1] = {2, 3, TYPE_SCCR_STANDARD }, /* I2C and TSEC2 are the same register */ +#else + [MPC83XX_CLK_ENC] = {6, 7, TYPE_SCCR_STANDARD }, + [MPC83XX_CLK_I2C1] = {6, 7, TYPE_SCCR_STANDARD }, /* I2C and ENC are the same register */ +#endif + [MPC83XX_CLK_I2C2] = {0, 0, TYPE_SPECIAL }, + [MPC83XX_CLK_PCIEXP1] = {10, 11, TYPE_SCCR_STANDARD }, + [MPC83XX_CLK_PCIEXP2] = {12, 13, TYPE_SCCR_STANDARD }, +#if defined(CONFIG_MPC8313) || defined(CONFIG_MPC834x) + [MPC83XX_CLK_USBDR] = {10, 11, TYPE_SCCR_STANDARD }, +#else + [MPC83XX_CLK_USBDR] = {8, 9, TYPE_SCCR_STANDARD }, +#endif + [MPC83XX_CLK_USBMPH] = {8, 9, TYPE_SCCR_STANDARD }, + [MPC83XX_CLK_PCI] = {15, 15, TYPE_SCCR_ONOFF }, +#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC8309) + [MPC83XX_CLK_DMAC] = {26, 27, TYPE_SCCR_STANDARD }, +#endif +#if 0 +/* FIXME: All SATA controllers must have the same clock ratio */ +#ifdef CONFIG_MPC83XX_SATA_SUPPORT +#ifdef CONFIG_MPC8379 + [MPC83XX_CLK_SATA] = {24, 25, TYPE_SCCR_STANDARD }, + [MPC83XX_CLK_SATA] = {26, 27, TYPE_SCCR_STANDARD }, + [MPC83XX_CLK_SATA] = {28, 29, TYPE_SCCR_STANDARD }, + [MPC83XX_CLK_SATA] = {30, 31, TYPE_SCCR_STANDARD }, +#else + [MPC83XX_CLK_SATA] = {18, 19, TYPE_SCCR_STANDARD }, + [MPC83XX_CLK_SATA] = {20, 21, TYPE_SCCR_STANDARD }, +#endif +#endif +#endif + [MPC83XX_CLK_TDM] = {26, 27, TYPE_SCCR_STANDARD }, +}; + +int get_clocks(void) +{ + return 0; +} + +inline bool is_clk_valid(int id) +{ + switch (id) { + case MPC83XX_CLK_MEM: +#if defined(CONFIG_MPC8360) + case MPC83XX_CLK_MEM_SEC: +#endif +#ifndef CONFIG_MPC830x + case MPC83XX_CLK_ENC: +#endif + case MPC83XX_CLK_I2C1: +#ifdef CONFIG_MPC8315 + case MPC83XX_CLK_TDM: +#endif +#ifdef CONFIG_MPC83XX_SDHC_SUPPORT + case MPC83XX_CLK_SDHC: +#endif +#ifdef CONFIG_MPC83XX_TSEC1_SUPPORT + case MPC83XX_CLK_TSEC1: +#endif +#ifdef CONFIG_MPC83XX_TSEC2_SUPPORT + case MPC83XX_CLK_TSEC2: +#endif +#if !defined(CONFIG_MPC8360) + case MPC83XX_CLK_USBDR: +#endif +#ifdef CONFIG_MPC834x + case MPC83XX_CLK_USBMPH: +#endif +#ifdef CONFIG_MPC83XX_PCIE1_SUPPORT + case MPC83XX_CLK_PCIEXP1: +#endif +#ifdef CONFIG_MPC83XX_PCIE2_SUPPORT + case MPC83XX_CLK_PCIEXP2: +#endif +#ifdef CONFIG_MPC83XX_SATA_SUPPORT + case MPC83XX_CLK_SATA: +#endif +#ifdef CONFIG_MPC830x + case MPC83XX_CLK_DMAC: +#endif +#ifdef CONFIG_MPC83XX_PCI_SUPPORT + case MPC83XX_CLK_PCI: +#endif + case MPC83XX_CLK_CSB: +#ifdef CONFIG_MPC83XX_SECOND_I2C_SUPPORT + case MPC83XX_CLK_I2C2: +#endif +#if defined(CONFIG_MPC83XX_QUICC_ENGINE) && !defined(CONFIG_MPC8309) + case MPC83XX_CLK_QE: + case MPC83XX_CLK_BRG: +#endif + case MPC83XX_CLK_LCLK: + case MPC83XX_CLK_LBIU: + case MPC83XX_CLK_CORE: + return true; + } + + return false; +} + +static int mpc83xx_clk_request(struct clk *clock) +{ + /* Reject requests of clocks that are not available */ + if (is_clk_valid(clock->id)) + return 0; + else + return -ENODEV; +} + +static inline void init_clks(u32 *speed) +{ + int i; + immap_t *im = (immap_t *)CONFIG_SYS_IMMR; + u32 csb_clk = get_csb_clk(im); + + for (i = 0; i < MPC83XX_CLK_COUNT; i++) { + struct clk_mode mode = modes[i]; + ulong mask; + + if (mode.type == TYPE_INVALID) + continue; + + if (mode.type == TYPE_SCCR_STANDARD) { + mask = GENMASK(31 - mode.low, 31 - mode.high); + + switch (sccr_field(im, mask, 31 - mode.high)) { + case 0: + speed[i] = 0; + break; + case 1: + speed[i] = csb_clk; + break; + case 2: + speed[i] = csb_clk / 2; + break; + case 3: + speed[i] = csb_clk / 3; + break; + default: + speed[i] = 0; + } + + continue; + } + + if (mode.type == TYPE_SPMR_DIRECT_MULTIPLY) { + mask = GENMASK(31 - mode.low, 31 - mode.high); + + speed[i] = csb_clk * (1 + sccr_field(im, mask, 31 - mode.high)); + continue; + } + + if (i == MPC83XX_CLK_CSB || i == MPC83XX_CLK_I2C2) { + speed[i] = csb_clk; /* i2c-2 clk is equal to csb clk */ + continue; + } + + if (i == MPC83XX_CLK_QE || i == MPC83XX_CLK_BRG) { + u32 pci_sync_in = get_pci_sync_in(im); + u32 qepmf = spmr_field(im, SPMR_CEPMF, SPMR_CEPMF_SHIFT); + u32 qepdf = spmr_field(im, SPMR_CEPDF, SPMR_CEPDF_SHIFT); + u32 qe_clk = (pci_sync_in * qepmf) / (1 + qepdf); + + if (i == MPC83XX_CLK_QE) + speed[i] = qe_clk; + else + speed[i] = qe_clk / 2; + + continue; + } + + if (i == MPC83XX_CLK_LCLK || i == MPC83XX_CLK_LBIU) { + u32 lbiu_clk = csb_clk * + (1 + spmr_field(im, SPMR_LBIUCM, SPMR_LBIUCM_SHIFT)); + u32 clkdiv = lcrr_field(im, LCRR_CLKDIV, LCRR_CLKDIV_SHIFT); + + if (i == MPC83XX_CLK_LBIU) + speed[i] = lbiu_clk; + + switch (clkdiv) { + case 2: + case 4: + case 8: + speed[i] = lbiu_clk / clkdiv; + break; + default: + /* unknown lcrr */ + speed[i] = 0; + } + + continue; + } + + if (i == MPC83XX_CLK_CORE) { + u8 corepll = spmr_field(im, SPMR_COREPLL, SPMR_COREPLL_SHIFT); + u32 corecnf_tab_index = ((corepll & 0x1F) << 2) | + ((corepll & 0x60) >> 5); + + if (corecnf_tab_index > (ARRAY_SIZE(corecnf_tab))) { + /* corecnf_tab_index is too high, possibly wrong value */ + speed[i] = 0; + } + + switch (corecnf_tab[corecnf_tab_index].core_csb_ratio) { + case _byp: + case _x1: + case _1x: + speed[i] = csb_clk; + break; + case _1_5x: + speed[i] = (3 * csb_clk) / 2; + break; + case _2x: + speed[i] = 2 * csb_clk; + break; + case _2_5x: + speed[i] = (5 * csb_clk) / 2; + break; + case _3x: + speed[i] = 3 * csb_clk; + break; + default: + /* unknown core to csb ratio */ + speed[i] = 0; + } + + continue; + } + } +} + +static ulong mpc83xx_clk_get_rate(struct clk *clk) +{ + struct mpc83xx_clk_priv *priv = dev_get_priv(clk->dev); + + return priv->speed[clk->id]; +} + +int get_serial_clock(void) +{ + return speed[MPC83XX_CLK_CSB]; +} + +const struct clk_ops mpc83xx_clk_ops = { + .request = mpc83xx_clk_request, + .get_rate = mpc83xx_clk_get_rate, +}; + +static const struct udevice_id mpc83xx_clk_match[] = { + { .compatible = "fsl,mpc83xx-clk", }, + { /* sentinel */ } +}; + +static int mpc83xx_clk_probe(struct udevice *dev) +{ + struct mpc83xx_clk_priv *priv = dev_get_priv(dev); + + speed = malloc((MPC83XX_CLK_COUNT + 1) * sizeof(u32)); + priv->speed = speed; + init_clks(priv->speed); + + gd->arch.csb_clk = speed[MPC83XX_CLK_CSB]; +#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC831x) || \ + defined(CONFIG_MPC834x) || defined(CONFIG_MPC837x) + gd->arch.tsec1_clk = speed[MPC83XX_CLK_TSEC1]; + gd->arch.tsec2_clk = speed[MPC83XX_CLK_TSEC2]; + gd->arch.usbdr_clk = speed[MPC83XX_CLK_USBDR]; +#elif defined(CONFIG_MPC8309) + gd->arch.usbdr_clk = speed[MPC83XX_CLK_USBDR]; +#endif +#if defined(CONFIG_MPC834x) + gd->arch.usbmph_clk = speed[MPC83XX_CLK_USBMPH]; +#endif +#if defined(CONFIG_MPC8315) + gd->arch.tdm_clk = speed[MPC83XX_CLK_TDM]; +#endif +#if defined(CONFIG_FSL_ESDHC) + gd->arch.sdhc_clk = speed[MPC83XX_CLK_SDHC]; +#endif + gd->arch.core_clk = speed[MPC83XX_CLK_CORE]; + gd->arch.i2c1_clk = speed[MPC83XX_CLK_I2C1]; +#if !defined(CONFIG_MPC832x) + gd->arch.i2c2_clk = speed[MPC83XX_CLK_I2C2]; +#endif +#if !defined(CONFIG_MPC8309) + gd->arch.enc_clk = speed[MPC83XX_CLK_ENC]; +#endif + gd->arch.lbiu_clk = speed[MPC83XX_CLK_LBIU]; + gd->arch.lclk_clk = speed[MPC83XX_CLK_LCLK]; + gd->mem_clk = speed[MPC83XX_CLK_MEM]; +#if defined(CONFIG_MPC8360) + gd->arch.mem_sec_clk = speed[MPC83XX_CLK_MEM_SEC]; +#endif +#if defined(CONFIG_QE) + gd->arch.qe_clk = speed[MPC83XX_CLK_QE]; + gd->arch.brg_clk = speed[MPC83XX_CLK_BRG]; +#endif +#if defined(CONFIG_MPC8308) || defined(CONFIG_MPC831x) || \ + defined(CONFIG_MPC837x) + gd->arch.pciexp1_clk = speed[MPC83XX_CLK_PCIEXP1]; + gd->arch.pciexp2_clk = speed[MPC83XX_CLK_PCIEXP2]; +#endif +#if defined(CONFIG_MPC837x) || defined(CONFIG_MPC8315) + gd->arch.sata_clk = speed[MPC83XX_CLK_SATA]; +#endif + gd->pci_clk = speed[MPC83XX_CLK_PCI]; + gd->cpu_clk = speed[MPC83XX_CLK_CORE]; + gd->bus_clk = speed[MPC83XX_CLK_CSB]; + + return 0; +} + +static int mpc83xx_clk_bind(struct udevice *dev) +{ + int ret; + struct udevice *sys_child; + + ret = device_bind_driver(dev, "mpc83xx_sysreset", "sysreset", + &sys_child); + if (ret) + debug("Warning: No sysreset driver: ret=%d\n", ret); + + return 0; +} + +U_BOOT_DRIVER(mpc83xx_clk) = { + .name = "mpc83xx_clk", + .id = UCLASS_CLK, + .of_match = mpc83xx_clk_match, + .ops = &mpc83xx_clk_ops, + .probe = mpc83xx_clk_probe, + .priv_auto_alloc_size = sizeof(struct mpc83xx_clk_priv), + .bind = mpc83xx_clk_bind, +}; + +static int do_clocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int i; + char buf[32]; + + for (i = 0; i < MPC83XX_CLK_COUNT; i++) { + if (!is_clk_valid(i)) + continue; + + printf("%s = %s MHz\n", names[i], strmhz(buf, speed[i])); + } + + return 0; +} + +U_BOOT_CMD( + clocks, 1, 1, do_clocks, + "display values of SoC's clocks", + "" +); diff --git a/drivers/clk/mpc83xx_clk.h b/drivers/clk/mpc83xx_clk.h new file mode 100644 index 0000000000..75db2f3699 --- /dev/null +++ b/drivers/clk/mpc83xx_clk.h @@ -0,0 +1,115 @@ +enum { + _unk, + _off, + _byp, + _x8, + _x4, + _x2, + _x1, + _1x, + _1_5x, + _2x, + _2_5x, + _3x +}; + +struct corecnf { + int core_csb_ratio; + int vco_divider; +}; + +static struct corecnf corecnf_tab[] = { + {_byp, _byp}, /* 0x00 */ + {_byp, _byp}, /* 0x01 */ + {_byp, _byp}, /* 0x02 */ + {_byp, _byp}, /* 0x03 */ + {_byp, _byp}, /* 0x04 */ + {_byp, _byp}, /* 0x05 */ + {_byp, _byp}, /* 0x06 */ + {_byp, _byp}, /* 0x07 */ + {_1x, _x2}, /* 0x08 */ + {_1x, _x4}, /* 0x09 */ + {_1x, _x8}, /* 0x0A */ + {_1x, _x8}, /* 0x0B */ + {_1_5x, _x2}, /* 0x0C */ + {_1_5x, _x4}, /* 0x0D */ + {_1_5x, _x8}, /* 0x0E */ + {_1_5x, _x8}, /* 0x0F */ + {_2x, _x2}, /* 0x10 */ + {_2x, _x4}, /* 0x11 */ + {_2x, _x8}, /* 0x12 */ + {_2x, _x8}, /* 0x13 */ + {_2_5x, _x2}, /* 0x14 */ + {_2_5x, _x4}, /* 0x15 */ + {_2_5x, _x8}, /* 0x16 */ + {_2_5x, _x8}, /* 0x17 */ + {_3x, _x2}, /* 0x18 */ + {_3x, _x4}, /* 0x19 */ + {_3x, _x8}, /* 0x1A */ + {_3x, _x8}, /* 0x1B */ +}; + +enum reg_type { + REG_SCCR, + REG_SPMR, +}; + +enum mode_type { + TYPE_INVALID = 0, + TYPE_SCCR_STANDARD, + TYPE_SCCR_ONOFF, + TYPE_SPMR_DIRECT_MULTIPLY, + TYPE_SPECIAL, +}; + +static inline u32 get_spmr(immap_t *im) +{ + u32 res = in_be32(&im->clk.spmr); + + return res; +} + +static inline u32 get_sccr(immap_t *im) +{ + u32 res = in_be32(&im->clk.sccr); + + return res; +} + +static inline u32 get_lcrr(immap_t *im) +{ + u32 res = in_be32(&im->im_lbc.lcrr); + + return res; +} + +static inline u32 get_pci_sync_in(immap_t *im) +{ + u8 clkin_div; + + clkin_div = (get_spmr(im) & SPMR_CKID) >> SPMR_CKID_SHIFT; + return CONFIG_SYS_CLK_FREQ / (1 + clkin_div); +} + +static inline u32 get_csb_clk(immap_t *im) +{ + u8 spmf; + + spmf = (get_spmr(im) & SPMR_SPMF) >> SPMR_SPMF_SHIFT; + return CONFIG_SYS_CLK_FREQ * spmf; +} + +static inline uint spmr_field(immap_t *im, u32 mask, uint shift) +{ + return (get_spmr(im) & mask) >> shift; +} + +static inline uint sccr_field(immap_t *im, u32 mask, uint shift) +{ + return (get_sccr(im) & mask) >> shift; +} + +static inline uint lcrr_field(immap_t *im, u32 mask, uint shift) +{ + return (get_lcrr(im) & mask) >> shift; +} diff --git a/include/dt-bindings/clk/mpc83xx-clk.h b/include/dt-bindings/clk/mpc83xx-clk.h new file mode 100644 index 0000000000..3e5b2858c0 --- /dev/null +++ b/include/dt-bindings/clk/mpc83xx-clk.h @@ -0,0 +1,27 @@ +#ifndef DT_BINDINGS_MPC83XX_CLK_H +#define DT_BINDINGS_MPC83XX_CLK_H +#define MPC83XX_CLK_CORE 0 +#define MPC83XX_CLK_CSB 1 +#define MPC83XX_CLK_QE 2 +#define MPC83XX_CLK_BRG 3 +#define MPC83XX_CLK_LBIU 4 +#define MPC83XX_CLK_LCLK 5 +#define MPC83XX_CLK_MEM 6 +#define MPC83XX_CLK_MEM_SEC 7 +#define MPC83XX_CLK_ENC 8 +#define MPC83XX_CLK_I2C1 9 +#define MPC83XX_CLK_I2C2 10 +#define MPC83XX_CLK_TDM 11 +#define MPC83XX_CLK_SDHC 12 +#define MPC83XX_CLK_TSEC1 13 +#define MPC83XX_CLK_TSEC2 14 +#define MPC83XX_CLK_USBDR 15 +#define MPC83XX_CLK_USBMPH 16 +#define MPC83XX_CLK_PCIEXP1 17 +#define MPC83XX_CLK_PCIEXP2 18 +#define MPC83XX_CLK_SATA 19 +#define MPC83XX_CLK_DMAC 20 +#define MPC83XX_CLK_PCI 21 +/* Count */ +#define MPC83XX_CLK_COUNT 22 +#endif /* DT_BINDINGS_MPC83XX_CLK_H */ -- 2.16.1

Add a timer driver for the MPC83xx architecture.
Signed-off-by: Mario Six mario.six@gdsys.cc
---
v1 -> v2: * Removed now-superfluous comments * Removed usage of uclass_{first,next}_device_compat * Switched to usage of new board uclass (instead of devinfo)
--- arch/powerpc/cpu/mpc83xx/cpu.c | 4 +- arch/powerpc/lib/Makefile | 4 ++ arch/powerpc/lib/interrupts.c | 5 +- drivers/timer/Kconfig | 7 ++ drivers/timer/Makefile | 1 + drivers/timer/mpc83xx_timer.c | 160 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 drivers/timer/mpc83xx_timer.c
diff --git a/arch/powerpc/cpu/mpc83xx/cpu.c b/arch/powerpc/cpu/mpc83xx/cpu.c index 9a5c1b7d55..376483eda7 100644 --- a/arch/powerpc/cpu/mpc83xx/cpu.c +++ b/arch/powerpc/cpu/mpc83xx/cpu.c @@ -176,12 +176,12 @@ do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) /* * Get timebase clock frequency (like cpu_clk in Hz) */ - +#ifndef CONFIG_TIMER unsigned long get_tbclk(void) { return (gd->bus_clk + 3L) / 4L; } - +#endif
#if defined(CONFIG_WATCHDOG) void watchdog_reset (void) diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 9a3043abf8..537693e3bc 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -19,13 +19,17 @@ endif
ifdef MINIMAL obj-y += cache.o time.o +ifndef CONFIG_TIMER obj-y += ticks.o +endif else
obj-y += ppcstring.o
obj-y += ppccache.o +ifndef CONFIG_TIMER obj-y += ticks.o +endif obj-y += reloc.o
obj-$(CONFIG_BAT_RW) += bat_rw.o diff --git a/arch/powerpc/lib/interrupts.c b/arch/powerpc/lib/interrupts.c index e8784aa16e..56a697d28c 100644 --- a/arch/powerpc/lib/interrupts.c +++ b/arch/powerpc/lib/interrupts.c @@ -15,6 +15,7 @@ #include <status_led.h> #endif
+#ifndef CONFIG_MPC83XX_TIMER #ifdef CONFIG_SHOW_ACTIVITY void board_show_activity (ulong) __attribute__((weak, alias("__board_show_activity")));
@@ -45,7 +46,7 @@ static __inline__ void set_dec (unsigned long val) if (val) asm volatile ("mtdec %0"::"r" (val)); } - +#endif /* !CONFIG_MPC83XX_TIMER */
void enable_interrupts (void) { @@ -61,6 +62,7 @@ int disable_interrupts (void) return ((msr & MSR_EE) != 0); }
+#ifndef CONFIG_MPC83XX_TIMER int interrupt_init (void) { /* call cpu specific function from $(CPU)/interrupts.c */ @@ -103,3 +105,4 @@ ulong get_timer (ulong base) { return (timestamp - base); } +#endif /* !CONFIG_MPC83XX_TIMER */ diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 2c96896726..1b78ce784a 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -126,4 +126,11 @@ config STM32_TIMER Select this to enable support for the timer found on STM32 devices.
+config MPC83XX_TIMER + bool "MPC83xx timer support" + depends on TIMER + help + Select this to enable support for the timer found on + devices based on the MPC83xx family of SoCs. + endmenu diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index a6e7832154..d35d235195 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o obj-$(CONFIG_ATMEL_PIT_TIMER) += atmel_pit_timer.o obj-$(CONFIG_STM32_TIMER) += stm32_timer.o +obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o diff --git a/drivers/timer/mpc83xx_timer.c b/drivers/timer/mpc83xx_timer.c new file mode 100644 index 0000000000..c3dd306c5b --- /dev/null +++ b/drivers/timer/mpc83xx_timer.c @@ -0,0 +1,160 @@ +/* + * (C) Copyright 2018 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <clk.h> +#include <timer.h> +#include <watchdog.h> +#include <board.h> + +struct mpc83xx_timer_priv { +}; + +static uint decrementer_count; /* count value for 1e6/HZ microseconds */ + +static inline unsigned long get_dec(void) +{ + unsigned long val; + + asm volatile ("mfdec %0":"=r" (val):); + + return val; +} + +static inline void set_dec(unsigned long val) +{ + if (val) + asm volatile ("mtdec %0"::"r" (val)); +} + +/* TODO(mario.six@gdsys.cc): This should really be done by timer_init, and the + * interrupt init should go into a interrupt driver. + */ +int interrupt_init(void) +{ + immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; + struct udevice *csb; + struct udevice *board; + struct clk clock; + + if (get_board(&board)) + return -ENOENT; + + uclass_get_device_by_phandle(UCLASS_SIMPLE_BUS, board, "csb", &csb); + clk_get_by_index(csb, 0, &clock); + + decrementer_count = (clk_get_rate(&clock) / 4) / CONFIG_SYS_HZ; + + /* Enable e300 time base */ + + setbits_be32(&immr->sysconf.spcr, 0x00400000); + + set_dec(decrementer_count); + + set_msr(get_msr() | MSR_EE); + + return 0; +} + +static volatile ulong timestamp = 0; + +void timer_interrupt(struct pt_regs *regs) +{ + /* Restore Decrementer Count */ + set_dec(decrementer_count); + + timestamp++; + +#if defined(CONFIG_WATCHDOG) || defined(CONFIG_HW_WATCHDOG) + if ((timestamp % (CONFIG_SYS_WATCHDOG_FREQ)) == 0) + WATCHDOG_RESET(); +#endif /* CONFIG_WATCHDOG || CONFIG_HW_WATCHDOG */ + +#ifdef CONFIG_LED_STATUS + status_led_tick(timestamp); +#endif /* CONFIG_LED_STATUS */ + +#ifdef CONFIG_SHOW_ACTIVITY + board_show_activity(timestamp); +#endif /* CONFIG_SHOW_ACTIVITY */ +} + +ulong get_timer(ulong base) +{ + return (timestamp - base); +} + +static inline u32 mftbu(void) +{ + u32 rval; + + asm volatile("mftbu %0" : "=r" (rval)); + return rval; +} + +static inline u32 mftb(void) +{ + u32 rval; + + asm volatile("mftb %0" : "=r" (rval)); + return rval; +} + +void wait_ticks(ulong ticks) +{ + ulong end = get_ticks() + ticks; + + while (end > get_ticks()) + WATCHDOG_RESET(); +} + +static int mpc83xx_timer_get_count(struct udevice *dev, u64 *count) +{ + u32 tbu, tbl; + + do { + tbu = mftbu(); + tbl = mftb(); + } while (tbu != mftbu()); + + *count = (tbu * 0x10000ULL) + tbl; + + return 0; +} + +static int mpc83xx_timer_probe(struct udevice *dev) +{ + struct timer_dev_priv *uc_priv = dev->uclass_priv; + struct clk clock; + + interrupt_init(); + + clk_get_by_index(dev, 0, &clock); + + uc_priv->clock_rate = (clk_get_rate(&clock) + 3L) / 4L; + + return 0; +} + +static const struct timer_ops mpc83xx_timer_ops = { + .get_count = mpc83xx_timer_get_count, +}; + +static const struct udevice_id mpc83xx_timer_ids[] = { + { .compatible = "fsl,mpc83xx-timer" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(mpc83xx_timer) = { + .name = "mpc83xx_timer", + .id = UCLASS_TIMER, + .of_match = mpc83xx_timer_ids, + .probe = mpc83xx_timer_probe, + .ops = &mpc83xx_timer_ops, + .flags = DM_FLAG_PRE_RELOC, +}; -- 2.16.1

Hi Mario,
On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
Add a timer driver for the MPC83xx architecture.
Signed-off-by: Mario Six mario.six@gdsys.cc
v1 -> v2:
- Removed now-superfluous comments
- Removed usage of uclass_{first,next}_device_compat
- Switched to usage of new board uclass (instead of devinfo)
arch/powerpc/cpu/mpc83xx/cpu.c | 4 +- arch/powerpc/lib/Makefile | 4 ++ arch/powerpc/lib/interrupts.c | 5 +- drivers/timer/Kconfig | 7 ++ drivers/timer/Makefile | 1 + drivers/timer/mpc83xx_timer.c | 160 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 drivers/timer/mpc83xx_timer.c
Reviewed-by: Simon Glass sjg@chromium.org
Please see below.
diff --git a/arch/powerpc/cpu/mpc83xx/cpu.c b/arch/powerpc/cpu/mpc83xx/cpu.c index 9a5c1b7d55..376483eda7 100644 --- a/arch/powerpc/cpu/mpc83xx/cpu.c +++ b/arch/powerpc/cpu/mpc83xx/cpu.c @@ -176,12 +176,12 @@ do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) /*
- Get timebase clock frequency (like cpu_clk in Hz)
*/
+#ifndef CONFIG_TIMER unsigned long get_tbclk(void) { return (gd->bus_clk + 3L) / 4L; }
+#endif
#if defined(CONFIG_WATCHDOG) void watchdog_reset (void) diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 9a3043abf8..537693e3bc 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -19,13 +19,17 @@ endif
ifdef MINIMAL obj-y += cache.o time.o +ifndef CONFIG_TIMER obj-y += ticks.o +endif else
obj-y += ppcstring.o
obj-y += ppccache.o +ifndef CONFIG_TIMER obj-y += ticks.o +endif obj-y += reloc.o
obj-$(CONFIG_BAT_RW) += bat_rw.o diff --git a/arch/powerpc/lib/interrupts.c b/arch/powerpc/lib/interrupts.c index e8784aa16e..56a697d28c 100644 --- a/arch/powerpc/lib/interrupts.c +++ b/arch/powerpc/lib/interrupts.c @@ -15,6 +15,7 @@ #include <status_led.h> #endif
+#ifndef CONFIG_MPC83XX_TIMER #ifdef CONFIG_SHOW_ACTIVITY void board_show_activity (ulong) __attribute__((weak, alias("__board_show_activity")));
@@ -45,7 +46,7 @@ static __inline__ void set_dec (unsigned long val) if (val) asm volatile ("mtdec %0"::"r" (val)); }
+#endif /* !CONFIG_MPC83XX_TIMER */
void enable_interrupts (void) { @@ -61,6 +62,7 @@ int disable_interrupts (void) return ((msr & MSR_EE) != 0); }
+#ifndef CONFIG_MPC83XX_TIMER int interrupt_init (void) { /* call cpu specific function from $(CPU)/interrupts.c */ @@ -103,3 +105,4 @@ ulong get_timer (ulong base) { return (timestamp - base); } +#endif /* !CONFIG_MPC83XX_TIMER */ diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 2c96896726..1b78ce784a 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -126,4 +126,11 @@ config STM32_TIMER Select this to enable support for the timer found on STM32 devices.
+config MPC83XX_TIMER
bool "MPC83xx timer support"
depends on TIMER
help
Select this to enable support for the timer found on
devices based on the MPC83xx family of SoCs.
endmenu diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index a6e7832154..d35d235195 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o obj-$(CONFIG_ATMEL_PIT_TIMER) += atmel_pit_timer.o obj-$(CONFIG_STM32_TIMER) += stm32_timer.o +obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o diff --git a/drivers/timer/mpc83xx_timer.c b/drivers/timer/mpc83xx_timer.c new file mode 100644 index 0000000000..c3dd306c5b --- /dev/null +++ b/drivers/timer/mpc83xx_timer.c @@ -0,0 +1,160 @@ +/*
- (C) Copyright 2018
- Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <clk.h> +#include <timer.h> +#include <watchdog.h> +#include <board.h>
+struct mpc83xx_timer_priv { +};
+static uint decrementer_count; /* count value for 1e6/HZ microseconds */
Have a static var in BSS means it cannot be used before relocation, or in SPL, right?
+static inline unsigned long get_dec(void) +{
unsigned long val;
asm volatile ("mfdec %0":"=r" (val):);
return val;
+}
+static inline void set_dec(unsigned long val) +{
if (val)
asm volatile ("mtdec %0"::"r" (val));
+}
+/* TODO(mario.six@gdsys.cc): This should really be done by timer_init, and the
- interrupt init should go into a interrupt driver.
- */
+int interrupt_init(void) +{
immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
struct udevice *csb;
struct udevice *board;
struct clk clock;
if (get_board(&board))
debug() ?
return -ENOENT;
uclass_get_device_by_phandle(UCLASS_SIMPLE_BUS, board, "csb", &csb);
clk_get_by_index(csb, 0, &clock);
error checking
decrementer_count = (clk_get_rate(&clock) / 4) / CONFIG_SYS_HZ;
/* Enable e300 time base */
Drop blank line
setbits_be32(&immr->sysconf.spcr, 0x00400000);
set_dec(decrementer_count);
set_msr(get_msr() | MSR_EE);
return 0;
+}
+static volatile ulong timestamp = 0;
+void timer_interrupt(struct pt_regs *regs) +{
/* Restore Decrementer Count */
set_dec(decrementer_count);
timestamp++;
+#if defined(CONFIG_WATCHDOG) || defined(CONFIG_HW_WATCHDOG)
if ((timestamp % (CONFIG_SYS_WATCHDOG_FREQ)) == 0)
WATCHDOG_RESET();
+#endif /* CONFIG_WATCHDOG || CONFIG_HW_WATCHDOG */
+#ifdef CONFIG_LED_STATUS
status_led_tick(timestamp);
+#endif /* CONFIG_LED_STATUS */
+#ifdef CONFIG_SHOW_ACTIVITY
board_show_activity(timestamp);
+#endif /* CONFIG_SHOW_ACTIVITY */ +}
+ulong get_timer(ulong base) +{
return (timestamp - base);
+}
+static inline u32 mftbu(void) +{
u32 rval;
asm volatile("mftbu %0" : "=r" (rval));
return rval;
+}
+static inline u32 mftb(void) +{
u32 rval;
asm volatile("mftb %0" : "=r" (rval));
return rval;
+}
+void wait_ticks(ulong ticks) +{
ulong end = get_ticks() + ticks;
while (end > get_ticks())
WATCHDOG_RESET();
+}
+static int mpc83xx_timer_get_count(struct udevice *dev, u64 *count) +{
u32 tbu, tbl;
do {
tbu = mftbu();
tbl = mftb();
} while (tbu != mftbu());
*count = (tbu * 0x10000ULL) + tbl;
return 0;
+}
+static int mpc83xx_timer_probe(struct udevice *dev) +{
struct timer_dev_priv *uc_priv = dev->uclass_priv;
struct clk clock;
interrupt_init();
clk_get_by_index(dev, 0, &clock);
uc_priv->clock_rate = (clk_get_rate(&clock) + 3L) / 4L;
return 0;
+}
+static const struct timer_ops mpc83xx_timer_ops = {
.get_count = mpc83xx_timer_get_count,
+};
+static const struct udevice_id mpc83xx_timer_ids[] = {
{ .compatible = "fsl,mpc83xx-timer" },
{ /* sentinel */ }
+};
+U_BOOT_DRIVER(mpc83xx_timer) = {
.name = "mpc83xx_timer",
.id = UCLASS_TIMER,
.of_match = mpc83xx_timer_ids,
.probe = mpc83xx_timer_probe,
.ops = &mpc83xx_timer_ops,
.flags = DM_FLAG_PRE_RELOC,
+};
2.16.1
Regards, Simon

Hi Simon,
On Tue, May 1, 2018 at 1:13 AM, Simon Glass sjg@chromium.org wrote:
Hi Mario,
On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
Add a timer driver for the MPC83xx architecture.
Signed-off-by: Mario Six mario.six@gdsys.cc
v1 -> v2:
- Removed now-superfluous comments
- Removed usage of uclass_{first,next}_device_compat
- Switched to usage of new board uclass (instead of devinfo)
arch/powerpc/cpu/mpc83xx/cpu.c | 4 +- arch/powerpc/lib/Makefile | 4 ++ arch/powerpc/lib/interrupts.c | 5 +- drivers/timer/Kconfig | 7 ++ drivers/timer/Makefile | 1 + drivers/timer/mpc83xx_timer.c | 160 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 drivers/timer/mpc83xx_timer.c
Reviewed-by: Simon Glass sjg@chromium.org
Please see below.
diff --git a/arch/powerpc/cpu/mpc83xx/cpu.c b/arch/powerpc/cpu/mpc83xx/cpu.c index 9a5c1b7d55..376483eda7 100644 --- a/arch/powerpc/cpu/mpc83xx/cpu.c +++ b/arch/powerpc/cpu/mpc83xx/cpu.c @@ -176,12 +176,12 @@ do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) /*
- Get timebase clock frequency (like cpu_clk in Hz)
*/
+#ifndef CONFIG_TIMER unsigned long get_tbclk(void) { return (gd->bus_clk + 3L) / 4L; }
+#endif
#if defined(CONFIG_WATCHDOG) void watchdog_reset (void) diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 9a3043abf8..537693e3bc 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -19,13 +19,17 @@ endif
ifdef MINIMAL obj-y += cache.o time.o +ifndef CONFIG_TIMER obj-y += ticks.o +endif else
obj-y += ppcstring.o
obj-y += ppccache.o +ifndef CONFIG_TIMER obj-y += ticks.o +endif obj-y += reloc.o
obj-$(CONFIG_BAT_RW) += bat_rw.o diff --git a/arch/powerpc/lib/interrupts.c b/arch/powerpc/lib/interrupts.c index e8784aa16e..56a697d28c 100644 --- a/arch/powerpc/lib/interrupts.c +++ b/arch/powerpc/lib/interrupts.c @@ -15,6 +15,7 @@ #include <status_led.h> #endif
+#ifndef CONFIG_MPC83XX_TIMER #ifdef CONFIG_SHOW_ACTIVITY void board_show_activity (ulong) __attribute__((weak, alias("__board_show_activity")));
@@ -45,7 +46,7 @@ static __inline__ void set_dec (unsigned long val) if (val) asm volatile ("mtdec %0"::"r" (val)); }
+#endif /* !CONFIG_MPC83XX_TIMER */
void enable_interrupts (void) { @@ -61,6 +62,7 @@ int disable_interrupts (void) return ((msr & MSR_EE) != 0); }
+#ifndef CONFIG_MPC83XX_TIMER int interrupt_init (void) { /* call cpu specific function from $(CPU)/interrupts.c */ @@ -103,3 +105,4 @@ ulong get_timer (ulong base) { return (timestamp - base); } +#endif /* !CONFIG_MPC83XX_TIMER */ diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 2c96896726..1b78ce784a 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -126,4 +126,11 @@ config STM32_TIMER Select this to enable support for the timer found on STM32 devices.
+config MPC83XX_TIMER
bool "MPC83xx timer support"
depends on TIMER
help
Select this to enable support for the timer found on
devices based on the MPC83xx family of SoCs.
endmenu diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index a6e7832154..d35d235195 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o obj-$(CONFIG_ATMEL_PIT_TIMER) += atmel_pit_timer.o obj-$(CONFIG_STM32_TIMER) += stm32_timer.o +obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o diff --git a/drivers/timer/mpc83xx_timer.c b/drivers/timer/mpc83xx_timer.c new file mode 100644 index 0000000000..c3dd306c5b --- /dev/null +++ b/drivers/timer/mpc83xx_timer.c @@ -0,0 +1,160 @@ +/*
- (C) Copyright 2018
- Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <dm.h> +#include <clk.h> +#include <timer.h> +#include <watchdog.h> +#include <board.h>
+struct mpc83xx_timer_priv { +};
+static uint decrementer_count; /* count value for 1e6/HZ microseconds */
Have a static var in BSS means it cannot be used before relocation, or in SPL, right?
True; same with the timestamp variable a bit below. I copied that part verbatim from arch/powerpc/lib/interrupts.c, so that's a general problem with the powerpc arch. I see that x86 keeps, e.g. the clock rate in the global data. I think this might be a way around this (two ulongs will hopefully still fit in the GD).
+static inline unsigned long get_dec(void) +{
unsigned long val;
asm volatile ("mfdec %0":"=r" (val):);
return val;
+}
+static inline void set_dec(unsigned long val) +{
if (val)
asm volatile ("mtdec %0"::"r" (val));
+}
+/* TODO(mario.six@gdsys.cc): This should really be done by timer_init, and the
- interrupt init should go into a interrupt driver.
- */
+int interrupt_init(void) +{
immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
struct udevice *csb;
struct udevice *board;
struct clk clock;
if (get_board(&board))
debug() ?
Indeed; will be fixed in v3.
return -ENOENT;
uclass_get_device_by_phandle(UCLASS_SIMPLE_BUS, board, "csb", &csb);
clk_get_by_index(csb, 0, &clock);
error checking
Will be fixed in v3.
decrementer_count = (clk_get_rate(&clock) / 4) / CONFIG_SYS_HZ;
/* Enable e300 time base */
Drop blank line
Will be fixed in v3.
setbits_be32(&immr->sysconf.spcr, 0x00400000);
set_dec(decrementer_count);
set_msr(get_msr() | MSR_EE);
return 0;
+}
+static volatile ulong timestamp = 0;
+void timer_interrupt(struct pt_regs *regs) +{
/* Restore Decrementer Count */
set_dec(decrementer_count);
timestamp++;
+#if defined(CONFIG_WATCHDOG) || defined(CONFIG_HW_WATCHDOG)
if ((timestamp % (CONFIG_SYS_WATCHDOG_FREQ)) == 0)
WATCHDOG_RESET();
+#endif /* CONFIG_WATCHDOG || CONFIG_HW_WATCHDOG */
+#ifdef CONFIG_LED_STATUS
status_led_tick(timestamp);
+#endif /* CONFIG_LED_STATUS */
+#ifdef CONFIG_SHOW_ACTIVITY
board_show_activity(timestamp);
+#endif /* CONFIG_SHOW_ACTIVITY */ +}
+ulong get_timer(ulong base) +{
return (timestamp - base);
+}
+static inline u32 mftbu(void) +{
u32 rval;
asm volatile("mftbu %0" : "=r" (rval));
return rval;
+}
+static inline u32 mftb(void) +{
u32 rval;
asm volatile("mftb %0" : "=r" (rval));
return rval;
+}
+void wait_ticks(ulong ticks) +{
ulong end = get_ticks() + ticks;
while (end > get_ticks())
WATCHDOG_RESET();
+}
+static int mpc83xx_timer_get_count(struct udevice *dev, u64 *count) +{
u32 tbu, tbl;
do {
tbu = mftbu();
tbl = mftb();
} while (tbu != mftbu());
*count = (tbu * 0x10000ULL) + tbl;
return 0;
+}
+static int mpc83xx_timer_probe(struct udevice *dev) +{
struct timer_dev_priv *uc_priv = dev->uclass_priv;
struct clk clock;
interrupt_init();
clk_get_by_index(dev, 0, &clock);
uc_priv->clock_rate = (clk_get_rate(&clock) + 3L) / 4L;
return 0;
+}
+static const struct timer_ops mpc83xx_timer_ops = {
.get_count = mpc83xx_timer_get_count,
+};
+static const struct udevice_id mpc83xx_timer_ids[] = {
{ .compatible = "fsl,mpc83xx-timer" },
{ /* sentinel */ }
+};
+U_BOOT_DRIVER(mpc83xx_timer) = {
.name = "mpc83xx_timer",
.id = UCLASS_TIMER,
.of_match = mpc83xx_timer_ids,
.probe = mpc83xx_timer_probe,
.ops = &mpc83xx_timer_ops,
.flags = DM_FLAG_PRE_RELOC,
+};
2.16.1
Regards, Simon
Best regards, Mario

Includes should be sorted.
Signed-off-by: Mario Six mario.six@gdsys.cc
---
v1 -> v2: New in v2
--- common/board_f.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/board_f.c b/common/board_f.c index 2df30cd250..ff7a52705e 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -12,8 +12,8 @@
#include <common.h> #include <console.h> -#include <environment.h> #include <dm.h> +#include <environment.h> #include <fdtdec.h> #include <fs.h> #include <i2c.h> -- 2.16.1

On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
Includes should be sorted.
Signed-off-by: Mario Six mario.six@gdsys.cc
v1 -> v2: New in v2
common/board_f.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org

Hi Mario,
On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
Add a RAM driver for the MPC83xx architecture.
Signed-off-by: Mario Six mario.six@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
Reviewed-by: Simon Glass sjg@chromium.org
Question below
[..]
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
Can this (and the #ifdefs below in this file) be converted to
if (IS_ENABLED(CONFIG_...))
instead, to increase build coverage?
Regards, Simon

Hi Simon,
On Thu, May 3, 2018 at 9:01 PM, Simon Glass sjg@chromium.org wrote:
Hi Mario,
On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
Add a RAM driver for the MPC83xx architecture.
Signed-off-by: Mario Six mario.six@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
Reviewed-by: Simon Glass sjg@chromium.org
Question below
[..]
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
Can this (and the #ifdefs below in this file) be converted to
if (IS_ENABLED(CONFIG_...))
instead, to increase build coverage?
Yes, no problem, will convert for v3.
By the way, is this a practice that's generally encouraged, or is it just useful in special cases such as this one?
Regards, Simon
Best regards, Mario

+Tom for question below
Hi Mario,
On 4 May 2018 at 02:04, Mario Six mario.six@gdsys.cc wrote:
Hi Simon,
On Thu, May 3, 2018 at 9:01 PM, Simon Glass sjg@chromium.org wrote:
Hi Mario,
On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
Add a RAM driver for the MPC83xx architecture.
Signed-off-by: Mario Six mario.six@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
Reviewed-by: Simon Glass sjg@chromium.org
Question below
[..]
+phys_size_t get_effective_memsize(void) +{ +#ifndef CONFIG_VERY_BIG_RAM
Can this (and the #ifdefs below in this file) be converted to
if (IS_ENABLED(CONFIG_...))
instead, to increase build coverage?
Yes, no problem, will convert for v3.
By the way, is this a practice that's generally encouraged, or is it just useful in special cases such as this one?
I think it is better in most cases as I don't really like #ifdefs in the code when they are easy to remove: - visually confusing particularly where there is more than one term in the #if - creates multiple builds of the code, reducing build coverage for sandbox - can sometimes be replaced with empty static inline functions, or even build up logic (e.g. of_live_active() and its callers)
Tom, do you have any thoughts on this one?
Regards, Simon

On Fri, May 04, 2018 at 09:37:54PM +0000, Simon Glass wrote:
+Tom for question below
Hi Mario,
On 4 May 2018 at 02:04, Mario Six mario.six@gdsys.cc wrote:
Hi Simon,
On Thu, May 3, 2018 at 9:01 PM, Simon Glass sjg@chromium.org wrote:
Hi Mario,
On 27 April 2018 at 06:52, Mario Six mario.six@gdsys.cc wrote:
Add a RAM driver for the MPC83xx architecture.
Signed-off-by: Mario Six mario.six@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
Reviewed-by: Simon Glass sjg@chromium.org
Question below
[..]
+phys_size_t get_effective_memsize(void) +{ +#ifndef CONFIG_VERY_BIG_RAM
Can this (and the #ifdefs below in this file) be converted to
if (IS_ENABLED(CONFIG_...))
instead, to increase build coverage?
Yes, no problem, will convert for v3.
By the way, is this a practice that's generally encouraged, or is it just useful in special cases such as this one?
I think it is better in most cases as I don't really like #ifdefs in the code when they are easy to remove:
- visually confusing particularly where there is more than one term in the
#if
- creates multiple builds of the code, reducing build coverage for sandbox
- can sometimes be replaced with empty static inline functions, or even
build up logic (e.g. of_live_active() and its callers)
Tom, do you have any thoughts on this one?
Can this even be built for sandbox? If yes, we should do what we can to increase build coverage (and coverity coverage). Otherwise I don't think that if (CONFIG_IS_ENABLED(FOO)) is always better. If we're talking about: #ifdef FOO if (bar) { ... } #endif
Then yes, testing for CONFIG_IS_ENABLED(FOO) && bar is great. Or: #ifdef FOO ... a few lines ... #endif
It's also good. But if we're talking about a lot of lines, I think the added indent doesn't help and can start making it a bit harder with additional wrap.
participants (3)
-
Mario Six
-
Simon Glass
-
Tom Rini