From 6622c30f2e033eb4268720c1927a52062406f870 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 23 Aug 2022 11:30:14 +0200 Subject: [PATCH 01/12] armv8: layerscape: spl: mark OCRAM as non-secure By default the OCRAM is marked as secure. While the SPL runs in EL3 and thus can access it, DMA devices cannot. Mark the whole OCRAM as non-secure. This will fix MMC and SD card boot on LS1028A when using SPL instead of TF-A. Signed-off-by: Michael Walle Signed-off-by: Peng Fan --- arch/arm/cpu/armv8/fsl-layerscape/spl.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm/cpu/armv8/fsl-layerscape/spl.c b/arch/arm/cpu/armv8/fsl-layerscape/spl.c index 5f09ef0a4a..3a4b665f24 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/spl.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/spl.c @@ -67,11 +67,24 @@ void spl_board_init(void) #endif } +void tzpc_init(void) +{ + /* + * Mark the whole OCRAM as non-secure, otherwise DMA devices cannot + * access it. This is for example necessary for MMC boot. + */ +#ifdef TZPCR0SIZE_BASE + out_le32(TZPCR0SIZE_BASE, 0); +#endif +} + void board_init_f(ulong dummy) { int ret; icache_enable(); + tzpc_init(); + /* Clear global data */ memset((void *)gd, 0, sizeof(gd_t)); if (IS_ENABLED(CONFIG_DEBUG_UART)) From 67b5dab2637196cac82329ccc2ebf2bd95ca26e2 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 23 Aug 2022 11:30:15 +0200 Subject: [PATCH 02/12] board: sl28: implement additional bootsources The board is able to boot from the following source: - user-updateble SPI flash - write-protected part of the same SPI flash - eMMC - SD card Implement the needed function hooks to support all of these boot sources. Signed-off-by: Michael Walle Signed-off-by: Peng Fan --- board/kontron/sl28/common.c | 22 ++++++++++++++++++++ board/kontron/sl28/sl28.c | 23 ++++++++++++++++++++ board/kontron/sl28/sl28.h | 16 ++++++++++++++ board/kontron/sl28/spl.c | 38 +++++++++++++++++++++++++++++++++- configs/kontron_sl28_defconfig | 5 ++++- 5 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 board/kontron/sl28/sl28.h diff --git a/board/kontron/sl28/common.c b/board/kontron/sl28/common.c index 33c6843c3f..331de29bae 100644 --- a/board/kontron/sl28/common.c +++ b/board/kontron/sl28/common.c @@ -2,6 +2,9 @@ #include #include +#include + +#include "sl28.h" DECLARE_GLOBAL_DATA_PTR; @@ -9,3 +12,22 @@ u32 get_lpuart_clk(void) { return gd->bus_clk / CONFIG_SYS_FSL_LPUART_CLK_DIV; } + +enum boot_source sl28_boot_source(void) +{ + u32 rcw_src = in_le32(DCFG_BASE + DCFG_PORSR1) & DCFG_PORSR1_RCW_SRC; + + switch (rcw_src) { + case DCFG_PORSR1_RCW_SRC_SDHC1: + return BOOT_SOURCE_SDHC; + case DCFG_PORSR1_RCW_SRC_SDHC2: + return BOOT_SOURCE_MMC; + case DCFG_PORSR1_RCW_SRC_I2C: + return BOOT_SOURCE_I2C; + case DCFG_PORSR1_RCW_SRC_FSPI_NOR: + return BOOT_SOURCE_SPI; + default: + debug("unknown bootsource (%08x)\n", rcw_src); + return BOOT_SOURCE_UNKNOWN; + } +} diff --git a/board/kontron/sl28/sl28.c b/board/kontron/sl28/sl28.c index 32e9694b77..54719cc01c 100644 --- a/board/kontron/sl28/sl28.c +++ b/board/kontron/sl28/sl28.c @@ -24,6 +24,8 @@ #include #include +#include "sl28.h" + DECLARE_GLOBAL_DATA_PTR; #if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT) @@ -60,6 +62,27 @@ int board_eth_init(struct bd_info *bis) return pci_eth_init(bis); } +enum env_location env_get_location(enum env_operation op, int prio) +{ + enum boot_source src = sl28_boot_source(); + + if (prio) + return ENVL_UNKNOWN; + + if (!CONFIG_IS_ENABLED(ENV_IS_IN_SPI_FLASH)) + return ENVL_NOWHERE; + + /* write and erase always operate on the environment */ + if (op == ENVOP_SAVE || op == ENVOP_ERASE) + return ENVL_SPI_FLASH; + + /* failsafe boot will always use the compiled-in default environment */ + if (src == BOOT_SOURCE_SPI) + return ENVL_NOWHERE; + + return ENVL_SPI_FLASH; +} + static int __sl28cpld_read(uint reg) { struct udevice *dev; diff --git a/board/kontron/sl28/sl28.h b/board/kontron/sl28/sl28.h new file mode 100644 index 0000000000..7f0105049c --- /dev/null +++ b/board/kontron/sl28/sl28.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef __SL28_H +#define __SL28_H + +enum boot_source { + BOOT_SOURCE_UNKNOWN, + BOOT_SOURCE_SDHC, + BOOT_SOURCE_MMC, + BOOT_SOURCE_I2C, + BOOT_SOURCE_SPI, +}; + +enum boot_source sl28_boot_source(void); + +#endif diff --git a/board/kontron/sl28/spl.c b/board/kontron/sl28/spl.c index 0e6ad5f37e..b1fefc22b2 100644 --- a/board/kontron/sl28/spl.c +++ b/board/kontron/sl28/spl.c @@ -5,6 +5,9 @@ #include #include #include +#include + +#include "sl28.h" #define DCFG_RCWSR25 0x160 #define GPINFO_HW_VARIANT_MASK 0xff @@ -58,7 +61,40 @@ int board_fit_config_name_match(const char *name) void board_boot_order(u32 *spl_boot_list) { - spl_boot_list[0] = BOOT_DEVICE_SPI; + enum boot_source src = sl28_boot_source(); + + switch (src) { + case BOOT_SOURCE_SDHC: + spl_boot_list[0] = BOOT_DEVICE_MMC2; + break; + case BOOT_SOURCE_SPI: + case BOOT_SOURCE_I2C: + spl_boot_list[0] = BOOT_DEVICE_SPI; + break; + case BOOT_SOURCE_MMC: + spl_boot_list[0] = BOOT_DEVICE_MMC1; + break; + default: + panic("unexpected bootsource (%d)\n", src); + break; + } +} + +unsigned int spl_spi_get_uboot_offs(struct spi_flash *flash) +{ + enum boot_source src = sl28_boot_source(); + + switch (src) { + case BOOT_SOURCE_SPI: + return 0x000000; + case BOOT_SOURCE_I2C: + return 0x230000; + default: + panic("unexpected bootsource (%d)\n", src); + break; + } +} + } int board_early_init_f(void) diff --git a/configs/kontron_sl28_defconfig b/configs/kontron_sl28_defconfig index b0b5fb11ca..4d50c681f9 100644 --- a/configs/kontron_sl28_defconfig +++ b/configs/kontron_sl28_defconfig @@ -12,6 +12,7 @@ CONFIG_ENV_SECT_SIZE=0x10000 CONFIG_DEFAULT_DEVICE_TREE="fsl-ls1028a-kontron-sl28" CONFIG_SPL_TEXT_BASE=0x18010000 CONFIG_SYS_FSL_SDHC_CLK_DIV=1 +CONFIG_SPL_MMC=y CONFIG_SPL_SERIAL=y CONFIG_SPL_SIZE_LIMIT=0x20000 CONFIG_SPL_SIZE_LIMIT_PROVIDE_STACK=0x0 @@ -46,9 +47,11 @@ CONFIG_SPL_BOARD_INIT=y # CONFIG_SPL_SHARES_INIT_SP_ADDR is not set CONFIG_SPL_STACK=0x18009ff0 CONFIG_SYS_SPL_MALLOC=y +CONFIG_SPL_SEPARATE_BSS=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y +CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x900 CONFIG_SPL_MPC8XXX_INIT_DDR=y CONFIG_SPL_SPI_LOAD=y -CONFIG_SYS_SPI_U_BOOT_OFFS=0x230000 CONFIG_SYS_CBSIZE=256 CONFIG_SYS_PBSIZE=276 CONFIG_SYS_BOOTM_LEN=0x800000 From 9f461171238e1c32ae99e7485f4dd81247470505 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 23 Aug 2022 11:30:16 +0200 Subject: [PATCH 03/12] board: sl28: add user friendly names for the boot sources During startup the SPL will print where the u-boot proper is read from. Instead of using the default names, provide more user friendly names. Signed-off-by: Michael Walle Signed-off-by: Peng Fan --- board/kontron/sl28/spl.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/board/kontron/sl28/spl.c b/board/kontron/sl28/spl.c index b1fefc22b2..ffaf517a8b 100644 --- a/board/kontron/sl28/spl.c +++ b/board/kontron/sl28/spl.c @@ -95,6 +95,22 @@ unsigned int spl_spi_get_uboot_offs(struct spi_flash *flash) } } +const char *spl_board_loader_name(u32 boot_device) +{ + enum boot_source src = sl28_boot_source(); + + switch (src) { + case BOOT_SOURCE_SDHC: + return "SD card (Test mode)"; + case BOOT_SOURCE_SPI: + return "Failsafe SPI flash"; + case BOOT_SOURCE_I2C: + return "SPI flash"; + case BOOT_SOURCE_MMC: + return "eMMC"; + default: + return "(unknown)"; + } } int board_early_init_f(void) From 865176417afdbe96153b71080900b86f776c3a6b Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 23 Aug 2022 11:30:17 +0200 Subject: [PATCH 04/12] board: sl28: support dynamic prompts Depending on the boot source, set different CLI prompts. This will help the user to figure out in which mode the bootloader was started. There are two special modes: failsafe and SDHC boot. Signed-off-by: Michael Walle Signed-off-by: Peng Fan --- board/kontron/sl28/sl28.c | 20 ++++++++++++++++++++ configs/kontron_sl28_defconfig | 1 + 2 files changed, 21 insertions(+) diff --git a/board/kontron/sl28/sl28.c b/board/kontron/sl28/sl28.c index 54719cc01c..0576b3eae4 100644 --- a/board/kontron/sl28/sl28.c +++ b/board/kontron/sl28/sl28.c @@ -126,8 +126,28 @@ static void stop_recovery_watchdog(void) wdt_stop(dev); } +static void sl28_set_prompt(void) +{ + enum boot_source src = sl28_boot_source(); + + switch (src) { + case BOOT_SOURCE_SPI: + env_set("PS1", "[FAILSAFE] => "); + break; + case BOOT_SOURCE_SDHC: + env_set("PS1", "[SDHC] => "); + break; + default: + env_set("PS1", NULL); + break; + } +} + int fsl_board_late_init(void) { + if (IS_ENABLED(CONFIG_CMDLINE_PS_SUPPORT)) + sl28_set_prompt(); + /* * Usually, the after a board reset, the watchdog is enabled by * default. This is to supervise the bootloader boot-up. Therefore, diff --git a/configs/kontron_sl28_defconfig b/configs/kontron_sl28_defconfig index 4d50c681f9..fc1c607927 100644 --- a/configs/kontron_sl28_defconfig +++ b/configs/kontron_sl28_defconfig @@ -55,6 +55,7 @@ CONFIG_SPL_SPI_LOAD=y CONFIG_SYS_CBSIZE=256 CONFIG_SYS_PBSIZE=276 CONFIG_SYS_BOOTM_LEN=0x800000 +CONFIG_CMDLINE_PS_SUPPORT=y CONFIG_CMD_ASKENV=y CONFIG_CMD_GREPENV=y CONFIG_CMD_NVEDIT_EFI=y From a8713c29b5037ab64837a4d122e02d6d8ff88062 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 23 Aug 2022 11:30:18 +0200 Subject: [PATCH 05/12] board: sl28: remove COUNTER_FREQUENCY_REAL The frequency of the system counter is static which is given by the COUNTER_FREQUENCY option. Remove COUNTER_FREQUENCY_REAL. Signed-off-by: Michael Walle Signed-off-by: Peng Fan --- include/configs/kontron_sl28.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/configs/kontron_sl28.h b/include/configs/kontron_sl28.h index 38063ba484..df46e586f3 100644 --- a/include/configs/kontron_sl28.h +++ b/include/configs/kontron_sl28.h @@ -37,8 +37,6 @@ /* serial port */ #define CONFIG_SYS_NS16550_CLK (get_bus_freq(0) / 2) -#define COUNTER_FREQUENCY_REAL (get_board_sys_clk() / 4) - /* SPL */ #define CONFIG_SYS_MONITOR_LEN (1024 * 1024) From 96624d7b47530bb3e0009c01aa64d8e5279f95bd Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 30 Aug 2022 16:54:39 -0400 Subject: [PATCH 06/12] ddr: fsl: Reduce the size of interactive options The interactive mode uses large several tables of options which can be configured. However, much of the contents of these tables are repetetive. For example, no struct is larger than half a kilobyte, so the offset only takes up 9 bits. Similarly, the size is only ever 4 or 8, and printhex is a boolean. Reduce the size of these fields. This reduces the size of the options tables by around 10 KiB. However, the largest contributor to the size of the options tables is the use of a pointer for the strings. A better approach would be to use a separate array of strings, and store an integer index in the options tables. However, this would require a large re-architecting of this file. Signed-off-by: Sean Anderson Signed-off-by: Peng Fan --- drivers/ddr/fsl/interactive.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ddr/fsl/interactive.c b/drivers/ddr/fsl/interactive.c index 2f76beb2db..eb2f06e830 100644 --- a/drivers/ddr/fsl/interactive.c +++ b/drivers/ddr/fsl/interactive.c @@ -27,9 +27,9 @@ /* Option parameter Structures */ struct options_string { const char *option_name; - size_t offset; - unsigned int size; - const char printhex; + u32 offset : 9; + u32 size : 4; + u32 printhex : 1; }; static unsigned int picos_to_mhz(unsigned int picos) From 6f6fbb334cc72cd5183cfe9a5b9fd31bc5d404d7 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 30 Aug 2022 17:01:07 -0400 Subject: [PATCH 07/12] ddr: fsl: Make bank_addr_bits reflect actual bits In both the Freescale DDR controller and the SPD spec, bank address bits are stored as the number of bank address bits minus 2. For example, if a chip had 8 banks (3 total bank address bits), the value of bank_addr_bits would be 1. This is rather surprising for users configuring their memory manually, since they can't set bank_addr_bits to the actual number of bank address bits. Rectify this. There is at least one example of this kind of mistake already, in board/freescale/t102xrdb/ddr.c. The documented MT40A512M8HX has two bank address bits, but bank_addr_bits was set to 2, implying 4 bank address bits. Such a value is reserved in BA_BITS_CS, but I suspect the controller simply ignores the top bit, making this kind of mistake harmless, if misleading. Fixes: e8a7f1c32b5 ("powerpc/t1023rdb: Add T1023 RDB board support") Signed-off-by: Sean Anderson Signed-off-by: Peng Fan --- board/freescale/ls1043ardb/ddr.c | 2 +- drivers/ddr/fsl/ctrl_regs.c | 2 +- drivers/ddr/fsl/ddr4_dimm_params.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/board/freescale/ls1043ardb/ddr.c b/board/freescale/ls1043ardb/ddr.c index 08b43ff5e4..4d2fce3841 100644 --- a/board/freescale/ls1043ardb/ddr.c +++ b/board/freescale/ls1043ardb/ddr.c @@ -114,7 +114,7 @@ dimm_params_t ddr_raw_timing = { .mirrored_dimm = 0, .n_row_addr = 15, .n_col_addr = 10, - .bank_addr_bits = 0, + .bank_addr_bits = 2, .bank_group_bits = 2, .edc_config = 0, .burst_lengths_bitmask = 0x0c, diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c index b5122d1a1c..0b0b4e5cb7 100644 --- a/drivers/ddr/fsl/ctrl_regs.c +++ b/drivers/ddr/fsl/ctrl_regs.c @@ -214,7 +214,7 @@ static void set_csn_config(int dimm_number, int i, fsl_ddr_cfg_regs_t *ddr, odt_rd_cfg = popts->cs_local_opts[i].odt_rd_cfg; odt_wr_cfg = popts->cs_local_opts[i].odt_wr_cfg; #ifdef CONFIG_SYS_FSL_DDR4 - ba_bits_cs_n = dimm_params[dimm_number].bank_addr_bits; + ba_bits_cs_n = dimm_params[dimm_number].bank_addr_bits - 2; bg_bits_cs_n = dimm_params[dimm_number].bank_group_bits; #else n_banks_per_sdram_device diff --git a/drivers/ddr/fsl/ddr4_dimm_params.c b/drivers/ddr/fsl/ddr4_dimm_params.c index e2bdc12ef2..ea79162262 100644 --- a/drivers/ddr/fsl/ddr4_dimm_params.c +++ b/drivers/ddr/fsl/ddr4_dimm_params.c @@ -246,7 +246,7 @@ unsigned int ddr_compute_dimm_parameters(const unsigned int ctrl_num, /* SDRAM device parameters */ pdimm->n_row_addr = ((spd->addressing >> 3) & 0x7) + 12; pdimm->n_col_addr = (spd->addressing & 0x7) + 9; - pdimm->bank_addr_bits = (spd->density_banks >> 4) & 0x3; + pdimm->bank_addr_bits = ((spd->density_banks >> 4) & 0x3) + 2; pdimm->bank_group_bits = (spd->density_banks >> 6) & 0x3; /* From 5025224fadc01ec2e8c50e41b765c597dfd40dba Mon Sep 17 00:00:00 2001 From: Siarhei Yasinski Date: Wed, 31 Aug 2022 10:57:37 +0000 Subject: [PATCH 08/12] net: enetc: Fix use after free issue in fsl_enetc.c If ethernet connected to SFP, like this: &enetc_port0 { phy-connection-type = "sgmii"; sfp = <&sfp0>; managed = "in-band-status"; status = "okay"; }; Then enetc_config_phy returns -ENODEV and the memory containing the mdio interface is freed. It's better to unregister and free mdio resources. Signed-off-by: Siarhei Yasinski Reviewed-by: Simon Glass Reviewed-by: Ramon Fried Signed-off-by: Peng Fan --- drivers/net/fsl_enetc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c index cd4c2c29a6..835e5bd8bd 100644 --- a/drivers/net/fsl_enetc.c +++ b/drivers/net/fsl_enetc.c @@ -22,6 +22,8 @@ #define ENETC_DRIVER_NAME "enetc_eth" +static int enetc_remove(struct udevice *dev); + /* * sets the MAC address in IERB registers, this setting is persistent and * carried over to Linux. @@ -319,6 +321,7 @@ static int enetc_config_phy(struct udevice *dev) static int enetc_probe(struct udevice *dev) { struct enetc_priv *priv = dev_get_priv(dev); + int res; if (ofnode_valid(dev_ofnode(dev)) && !ofnode_is_available(dev_ofnode(dev))) { enetc_dbg(dev, "interface disabled\n"); @@ -350,7 +353,10 @@ static int enetc_probe(struct udevice *dev) enetc_start_pcs(dev); - return enetc_config_phy(dev); + res = enetc_config_phy(dev); + if(res) + enetc_remove(dev); + return res; } /* From 1f90be6f3445f72c526f7396f4f4a53bb7a097aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 1 Aug 2022 15:31:43 +0200 Subject: [PATCH 09/12] board: freescale: p1_p2_rdb_pc: Add workaround for board reset reboot loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPLD's system reset register on P1/P2 RDB boards is not autocleared after flipping it. If this register is set to one in 100ms after reset starts then CPLD triggers another CPU reset. This means that trying to reset board via CPLD system reset register cause reboot loop. To prevent this reboot loop, the only workaround is to try to clear CPLD's system reset register as early as possible. U-Boot is already doing it in its board_early_init_f() function, which seems to be enough as register is cleared prior CPLD triggers another reset. But board_early_init_f() is not called from SPL and therefore usage of SPL can cause reboot loop. To prevent reboot loop when using SPL, call board_early_init_f() function in SPL too. For accessing CPLD memory space it is needed to have CPLD entry in TLB. With this change it is possible to trigger board reset via CPLD's system reset register on P2020 RDB board. Signed-off-by: Pali Rohár Signed-off-by: Peng Fan --- board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c | 13 +++++++++++++ board/freescale/p1_p2_rdb_pc/spl.c | 6 ++++++ board/freescale/p1_p2_rdb_pc/tlb.c | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c b/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c index a71952dcf3..b7c3956432 100644 --- a/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c +++ b/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c @@ -97,6 +97,19 @@ void board_cpld_init(void) out_8(&cpld_data->status_led, CPLD_STATUS_LED); out_8(&cpld_data->fxo_led, CPLD_FXO_LED); out_8(&cpld_data->fxs_led, CPLD_FXS_LED); + + /* + * CPLD's system reset register on P1/P2 RDB boards is not autocleared + * after flipping it. If this register is set to one then CPLD triggers + * reset of CPU in few ms. + * + * CPLD does not trigger reset of CPU for 100ms after the last reset. + * + * This means that trying to reset board via CPLD system reset register + * cause reboot loop. To prevent this reboot loop, the only workaround + * is to try to clear CPLD's system reset register as early as possible + * and it has to be done in 100ms since the last start of reset. + */ out_8(&cpld_data->system_rst, CPLD_SYS_RST); } diff --git a/board/freescale/p1_p2_rdb_pc/spl.c b/board/freescale/p1_p2_rdb_pc/spl.c index b60027ebd9..eda84bf2b1 100644 --- a/board/freescale/p1_p2_rdb_pc/spl.c +++ b/board/freescale/p1_p2_rdb_pc/spl.c @@ -31,6 +31,12 @@ void board_init_f(ulong bootflag) u32 plat_ratio, bus_clk; ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; + /* + * Call board_early_init_f() as early as possible as it workarounds + * reboot loop due to broken CPLD state machine for reset line. + */ + board_early_init_f(); + console_init_f(); /* Set pmuxcr to allow both i2c1 and i2c2 */ diff --git a/board/freescale/p1_p2_rdb_pc/tlb.c b/board/freescale/p1_p2_rdb_pc/tlb.c index 105d9e38aa..65cedd42a0 100644 --- a/board/freescale/p1_p2_rdb_pc/tlb.c +++ b/board/freescale/p1_p2_rdb_pc/tlb.c @@ -61,11 +61,11 @@ struct fsl_e_tlb_entry tlb_table[] = { MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, 0, 5, BOOKE_PAGESZ_1M, 1), #endif +#endif /* not SPL */ SET_TLB_ENTRY(1, CONFIG_SYS_CPLD_BASE, CONFIG_SYS_CPLD_BASE_PHYS, MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, 0, 6, BOOKE_PAGESZ_1M, 1), -#endif /* not SPL */ #ifdef CONFIG_SYS_NAND_BASE /* *I*G - NAND */ From 27b2bff6eb18dfb5ba58f68b79fdc57d72c6d2a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 1 Aug 2022 15:31:44 +0200 Subject: [PATCH 10/12] board: freescale: p1_p2_rdb_pc: Add workaround for non-working watchdog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If watchdog timer was already set to non-disabled value then it means that watchdog timer was already activated, has already expired and caused CPU reset. If this happened then due to CPLD firmware bug, writing to wd_cfg register has no effect and therefore it is not possible to reactivate watchdog timer again. Watchdog starts working again after CPU reset via non-watchdog method. Implement this workaround (reset CPU when it was reset by watchdog) to make watchdog usable again. Watchdog timer logic on these P1/P2 RDB boards is connected to CPLD, not to SoC itself. Note that reset does not occur immediately after calling do_reset(), but after few ms later as real reset is done by CPLD. So it is normal that function do_reset() returns. Therefore hangs after calling do_reset() to prevent CPU execution of the rest U-Boot code. Signed-off-by: Pali Rohár Signed-off-by: Peng Fan --- board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c b/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c index b7c3956432..4c0e41f987 100644 --- a/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c +++ b/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c @@ -92,6 +92,7 @@ void board_reset(void) void board_cpld_init(void) { struct cpld_data *cpld_data = (void *)(CONFIG_SYS_CPLD_BASE); + u8 prev_wd_cfg = in_8(&cpld_data->wd_cfg); out_8(&cpld_data->wd_cfg, CPLD_WD_CFG); out_8(&cpld_data->status_led, CPLD_STATUS_LED); @@ -111,6 +112,26 @@ void board_cpld_init(void) * and it has to be done in 100ms since the last start of reset. */ out_8(&cpld_data->system_rst, CPLD_SYS_RST); + + /* + * If watchdog timer was already set to non-disabled value then it means + * that watchdog timer was already activated, has already expired and + * caused CPU reset. If this happened then due to CPLD firmware bug, + * writing to wd_cfg register has no effect and therefore it is not + * possible to reactivate watchdog timer again. Also if CPU was reset + * via watchdog then some peripherals like i2c do not work. Watchdog and + * i2c start working again after CPU reset via non-watchdog method. + * + * So in case watchdog timer register in CPLD was already enabled then + * disable it in CPLD and reset CPU which cause new boot. Watchdog timer + * is disabled few lines above, after reading CPLD previous value. + * This logic (disabling timer before reset) prevents reboot loop. + */ + if (prev_wd_cfg != CPLD_WD_CFG) { + eieio(); + do_reset(NULL, 0, 0, NULL); + while (1); /* do_reset() does not occur immediately */ + } } void board_gpio_init(void) From 7e962cb132d6056b0a6f75eee2d800c9422da961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 1 Aug 2022 15:31:45 +0200 Subject: [PATCH 11/12] board: freescale: p1_p2_rdb_pc: Avoid usage of CPLD's system reset register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPLD's system reset register is buggy and requires workaround in U-Boot. So use this kind of board reset only when there is no other reset option. Introduce a new board_reset_last() callback which is last-stage board-specific reset and implement CPLD's system reset in this new board_reset_last() callback instead of board_reset() callback. Fixes: 20fb58fc5a1c ("board: freescale: p1_p2_rdb_pc: Implement board_reset()") Signed-off-by: Pali Rohár Signed-off-by: Peng Fan --- arch/powerpc/cpu/mpc85xx/cpu.c | 4 ++++ board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/cpu/mpc85xx/cpu.c b/arch/powerpc/cpu/mpc85xx/cpu.c index 1b6cdc4df0..3a503b9b4f 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu.c +++ b/arch/powerpc/cpu/mpc85xx/cpu.c @@ -45,6 +45,7 @@ __board_reset(void) /* Do nothing */ } void board_reset(void) __attribute__((weak, alias("__board_reset"))); +void board_reset_last(void) __attribute__((weak, alias("__board_reset"))); int checkcpu (void) { @@ -325,6 +326,9 @@ int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) /* Next try asserting HRESET_REQ */ out_be32(&gur->rstcr, 0x2); udelay(100); + + /* Attempt last-stage board-specific reset */ + board_reset_last(); #endif return 1; diff --git a/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c b/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c index 4c0e41f987..e690fb4fbc 100644 --- a/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c +++ b/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c @@ -83,7 +83,7 @@ struct cpld_data { #define CPLD_FXS_LED 0x0F #define CPLD_SYS_RST 0x00 -void board_reset(void) +void board_reset_last(void) { struct cpld_data *cpld_data = (void *)(CONFIG_SYS_CPLD_BASE); out_8(&cpld_data->system_rst, 1); From 44366be10a9386a8887124a77a7d06169c3aa1f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 1 Aug 2022 15:31:46 +0200 Subject: [PATCH 12/12] board: freescale: p1_p2_rdb_pc: Turn off watchdog before reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit P1/P2 RDB boards have external max6370 watchdog connected to CPLD and this watchdog is not deactivated on board reset. So if it is active during board reset, it can trigger another reset when CPU is booting U-Boot. To prevent possible infinite reset loop caused by external watchdog, turn it off before reset. Do it via a new board_reset_prepare() callback which is called from do_reset() function before any reset sequence. Signed-off-by: Pali Rohár Signed-off-by: Peng Fan --- arch/powerpc/cpu/mpc85xx/cpu.c | 4 ++++ board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/arch/powerpc/cpu/mpc85xx/cpu.c b/arch/powerpc/cpu/mpc85xx/cpu.c index 3a503b9b4f..14d5c560bf 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu.c +++ b/arch/powerpc/cpu/mpc85xx/cpu.c @@ -44,6 +44,7 @@ __board_reset(void) { /* Do nothing */ } +void board_reset_prepare(void) __attribute__((weak, alias("__board_reset"))); void board_reset(void) __attribute__((weak, alias("__board_reset"))); void board_reset_last(void) __attribute__((weak, alias("__board_reset"))); @@ -320,6 +321,9 @@ int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) #else volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); + /* Call board-specific preparation for reset */ + board_reset_prepare(); + /* Attempt board-specific reset */ board_reset(); diff --git a/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c b/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c index e690fb4fbc..25906d3fc0 100644 --- a/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c +++ b/board/freescale/p1_p2_rdb_pc/p1_p2_rdb_pc.c @@ -83,6 +83,18 @@ struct cpld_data { #define CPLD_FXS_LED 0x0F #define CPLD_SYS_RST 0x00 +void board_reset_prepare(void) +{ + /* + * During reset preparation, turn off external watchdog. + * This ensures that external watchdog does not trigger + * another reset or possible infinite reset loop. + */ + struct cpld_data *cpld_data = (void *)(CONFIG_SYS_CPLD_BASE); + out_8(&cpld_data->wd_cfg, CPLD_WD_CFG); + in_8(&cpld_data->wd_cfg); /* Read back to sync write */ +} + void board_reset_last(void) { struct cpld_data *cpld_data = (void *)(CONFIG_SYS_CPLD_BASE);