From 8f9e0f4d207e7bb65173c7cd00d91946cfb838a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 21 Dec 2021 12:20:11 +0100 Subject: [PATCH 01/38] arm: mvebu: Convert board_pex_config() to CONFIG_SPL_BOARD_INIT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only user of board_pex_config() weak function is A385 controlcenterdc board. It looks like that code in its board_pex_config() function needs to be executed after PCIe link is up. Therefore put this code into spl_board_init() function which is called after a38x serdes initialization, and therefore it is after the serdes hws_pex_config() function finishes (which is the state before this change). With this change completely remove board_pex_config() function as it is not used anymore. Signed-off-by: Pali Rohár --- arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c | 7 ------- arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h | 1 - board/gdsys/a38x/controlcenterdc.c | 2 +- configs/controlcenterdc_defconfig | 1 + 4 files changed, 2 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c index 55c3f9ca39..b3cbddf6a2 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c +++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c @@ -14,11 +14,6 @@ #include "ctrl_pex.h" #include "sys_env_lib.h" -__weak void board_pex_config(void) -{ - /* nothing in this weak default implementation */ -} - int hws_pex_config(const struct serdes_map *serdes_map, u8 count) { enum serdes_type serdes_type; @@ -58,7 +53,5 @@ int hws_pex_config(const struct serdes_map *serdes_map, u8 count) reg_write(SOC_CONTROL_REG1, tmp); - board_pex_config(); - return MV_OK; } diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h index 64193d5288..abdbe3c660 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h +++ b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h @@ -23,6 +23,5 @@ #define PCIE4_ENABLE_MASK (0x1 << PCIE3_ENABLE_OFFS) int hws_pex_config(const struct serdes_map *serdes_map, u8 count); -void board_pex_config(void); #endif diff --git a/board/gdsys/a38x/controlcenterdc.c b/board/gdsys/a38x/controlcenterdc.c index dc424f271c..243d022326 100644 --- a/board/gdsys/a38x/controlcenterdc.c +++ b/board/gdsys/a38x/controlcenterdc.c @@ -94,7 +94,7 @@ int hws_board_topology_load(struct serdes_map **serdes_map_array, u8 *count) return 0; } -void board_pex_config(void) +void spl_board_init(void) { #ifdef CONFIG_SPL_BUILD uint k; diff --git a/configs/controlcenterdc_defconfig b/configs/controlcenterdc_defconfig index d6844a48ac..b6eb955086 100644 --- a/configs/controlcenterdc_defconfig +++ b/configs/controlcenterdc_defconfig @@ -33,6 +33,7 @@ CONFIG_SYS_CONSOLE_INFO_QUIET=y CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_BOARD_LATE_INIT=y CONFIG_LAST_STAGE_INIT=y +CONFIG_SPL_BOARD_INIT=y CONFIG_SPL_SYS_MALLOC_SIMPLE=y CONFIG_SPL_I2C=y CONFIG_HUSH_PARSER=y From 2ac06f3e66c13b793f9b0859888b7062f24910e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 21 Dec 2021 12:20:12 +0100 Subject: [PATCH 02/38] board: gdsys: a38x: Enable PCIe link 2 in spl_board_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A385 controlcenterdc board does not use PCI DM properly and touches some PCIe devices directly in its board code. This controlcenterdc spl_board_init() function expects that PCIe link is already initialized. Link itself is initialized in a38x serdes code but this will change in future and link initialization will be postponed from U-Boot SPL to proper U-Boot. So explicitly enable PCIe link 2 in spl_board_init() function via SoC Control Register 1 to not break this code by future changes. This board has PCIe link 2 just x1, so no additional initialization (except enabling PCIe port) is needed. Signed-off-by: Pali Rohár --- board/gdsys/a38x/controlcenterdc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/board/gdsys/a38x/controlcenterdc.c b/board/gdsys/a38x/controlcenterdc.c index 243d022326..7d65400ccb 100644 --- a/board/gdsys/a38x/controlcenterdc.c +++ b/board/gdsys/a38x/controlcenterdc.c @@ -100,6 +100,10 @@ void spl_board_init(void) uint k; struct gpio_desc gpio = {}; + /* Enable PCIe link 2 */ + setbits_32(MVEBU_REGISTER(0x18204), BIT(2)); + mdelay(10); + if (!request_gpio_by_name(&gpio, "pca9698@22", 31, "fpga-program-gpio")) { /* prepare FPGA reconfiguration */ dm_gpio_set_dir_flags(&gpio, GPIOD_IS_OUT); From 537b0142b04de845a13cc9e2237037c53e53c016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 21 Dec 2021 12:20:13 +0100 Subject: [PATCH 03/38] pci: pci_mvebu: Fix PCIe MEM and IO resources assignment and mbus mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not call pci_set_region() for resources which were not properly mapped. This prevents U-Boot to access unmapped memory space. Update MBUS_PCI_MEM_SIZE and MBUS_PCI_IO_SIZE macros to cover all PCIe MEM and IO ranges. Previously these macros covered only address ranges for the first PCIe port. Between MBUS_PCI_IO_BASE and MBUS_PCI_MEM_BASE there is space for six 128 MB long address ranges. So set MBUS_PCI_MEM_SIZE to value of 6*128 MB. Similarly set MBUS_PCI_IO_SIZE to 6*64 KB. Function resource_size() returns zero when start address is 0 and end address is -1. So set invalid resources to these values to indicate that resource has no mapping. Split global PCIe MEM and IO resources (defined by MBUS_PCI_*_* macros) into PCIe ports in mvebu_pcie_bind() function which allocates per-port based struct mvebu_pcie, instead of using global state variables mvebu_pcie_membase and mvebu_pcie_iobase. This makes pci_mvebu.c driver independent of global static variables (which store the state of allocation) and allows to bind and unbind the driver more times. Signed-off-by: Pali Rohár Signed-off-by: Marek Behún --- arch/arm/mach-mvebu/include/mach/cpu.h | 5 +- drivers/pci/pci_mvebu.c | 84 ++++++++++++++++++-------- 2 files changed, 62 insertions(+), 27 deletions(-) diff --git a/arch/arm/mach-mvebu/include/mach/cpu.h b/arch/arm/mach-mvebu/include/mach/cpu.h index a7a62c7e7d..b99d86a87a 100644 --- a/arch/arm/mach-mvebu/include/mach/cpu.h +++ b/arch/arm/mach-mvebu/include/mach/cpu.h @@ -74,10 +74,11 @@ enum { /* * Default Device Address MAP BAR values */ +#define MBUS_PCI_MAX_PORTS 6 #define MBUS_PCI_MEM_BASE MVEBU_SDRAM_SIZE_MAX -#define MBUS_PCI_MEM_SIZE (128 << 20) +#define MBUS_PCI_MEM_SIZE ((MBUS_PCI_MAX_PORTS * 128) << 20) #define MBUS_PCI_IO_BASE 0xF1100000 -#define MBUS_PCI_IO_SIZE (64 << 10) +#define MBUS_PCI_IO_SIZE ((MBUS_PCI_MAX_PORTS * 64) << 10) #define MBUS_SPI_BASE 0xF4000000 #define MBUS_SPI_SIZE (8 << 20) #define MBUS_DFX_BASE 0xF6000000 diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index 18f79d249c..0ce602b435 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -25,6 +25,7 @@ #include #include #include +#include /* PCIe unit register offsets */ #define SELECT(x, n) ((x >> n) & 1UL) @@ -80,14 +81,6 @@ struct mvebu_pcie { u32 cfgcache[(0x3c - 0x10) / 4]; }; -/* - * MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped - * into SoCs address space. Each controller will map 128M of MEM - * and 64K of I/O space when registered. - */ -static void __iomem *mvebu_pcie_membase = (void __iomem *)MBUS_PCI_MEM_BASE; -static void __iomem *mvebu_pcie_iobase = (void __iomem *)MBUS_PCI_IO_BASE; - static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie) { u32 val; @@ -433,26 +426,24 @@ static int mvebu_pcie_probe(struct udevice *dev) mvebu_pcie_set_local_bus_nr(pcie, 0); mvebu_pcie_set_local_dev_nr(pcie, 1); - pcie->mem.start = (u32)mvebu_pcie_membase; - pcie->mem.end = pcie->mem.start + MBUS_PCI_MEM_SIZE - 1; - mvebu_pcie_membase += MBUS_PCI_MEM_SIZE; - - if (mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr, + if (resource_size(&pcie->mem) && + mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr, (phys_addr_t)pcie->mem.start, resource_size(&pcie->mem))) { printf("PCIe unable to add mbus window for mem at %08x+%08x\n", (u32)pcie->mem.start, (unsigned)resource_size(&pcie->mem)); + pcie->mem.start = 0; + pcie->mem.end = -1; } - pcie->io.start = (u32)mvebu_pcie_iobase; - pcie->io.end = pcie->io.start + MBUS_PCI_IO_SIZE - 1; - mvebu_pcie_iobase += MBUS_PCI_IO_SIZE; - - if (mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr, + if (resource_size(&pcie->io) && + mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr, (phys_addr_t)pcie->io.start, resource_size(&pcie->io))) { printf("PCIe unable to add mbus window for IO at %08x+%08x\n", (u32)pcie->io.start, (unsigned)resource_size(&pcie->io)); + pcie->io.start = 0; + pcie->io.end = -1; } /* Setup windows and configure host bridge */ @@ -461,13 +452,23 @@ static int mvebu_pcie_probe(struct udevice *dev) /* PCI memory space */ pci_set_region(hose->regions + 0, pcie->mem.start, pcie->mem.start, resource_size(&pcie->mem), PCI_REGION_MEM); - pci_set_region(hose->regions + 1, - 0, 0, - gd->ram_size, - PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); - pci_set_region(hose->regions + 2, pcie->io.start, - pcie->io.start, resource_size(&pcie->io), PCI_REGION_IO); - hose->region_count = 3; + hose->region_count = 1; + + if (resource_size(&pcie->mem)) { + pci_set_region(hose->regions + hose->region_count, + pcie->mem.start, pcie->mem.start, + resource_size(&pcie->mem), + PCI_REGION_MEM); + hose->region_count++; + } + + if (resource_size(&pcie->io)) { + pci_set_region(hose->regions + hose->region_count, + pcie->io.start, pcie->io.start, + resource_size(&pcie->io), + PCI_REGION_IO); + hose->region_count++; + } /* PCI Bridge support 32-bit I/O and 64-bit prefetch mem addressing */ pcie->cfgcache[(PCI_IO_BASE - 0x10) / 4] = @@ -628,6 +629,8 @@ static int mvebu_pcie_bind(struct udevice *parent) struct mvebu_pcie *pcie; struct uclass_driver *drv; struct udevice *dev; + struct resource mem; + struct resource io; ofnode subnode; /* Lookup pci driver */ @@ -637,6 +640,11 @@ static int mvebu_pcie_bind(struct udevice *parent) return -ENOENT; } + mem.start = MBUS_PCI_MEM_BASE; + mem.end = MBUS_PCI_MEM_BASE + MBUS_PCI_MEM_SIZE - 1; + io.start = MBUS_PCI_IO_BASE; + io.end = MBUS_PCI_IO_BASE + MBUS_PCI_IO_SIZE - 1; + ofnode_for_each_subnode(subnode, dev_ofnode(parent)) { if (!ofnode_is_available(subnode)) continue; @@ -645,6 +653,32 @@ static int mvebu_pcie_bind(struct udevice *parent) if (!pcie) return -ENOMEM; + /* + * MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped + * into SoCs address space. Each controller will map 128M of MEM + * and 64K of I/O space when registered. + */ + + if (resource_size(&mem) >= SZ_128M) { + pcie->mem.start = mem.start; + pcie->mem.end = mem.start + SZ_128M - 1; + mem.start += SZ_128M; + } else { + printf("PCIe unable to assign mbus window for mem\n"); + pcie->mem.start = 0; + pcie->mem.end = -1; + } + + if (resource_size(&io) >= SZ_64K) { + pcie->io.start = io.start; + pcie->io.end = io.start + SZ_64K - 1; + io.start += SZ_64K; + } else { + printf("PCIe unable to assign mbus window for io\n"); + pcie->io.start = 0; + pcie->io.end = -1; + } + /* Create child device UCLASS_PCI and bind it */ device_bind(parent, &pcie_mvebu_drv, pcie->name, pcie, subnode, &dev); From 6f4988f90c93758f3d4987986394dae90bb8ce24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 21 Dec 2021 12:20:14 +0100 Subject: [PATCH 04/38] pci: pci_mvebu: Inline mvebu_pcie_port_parse_dt() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function mvebu_pcie_port_parse_dt() is called only from mvebu_pcie_of_to_plat() function. Both these function parse DT properties required to setup mvebu pcie. So inline mvebu_pcie_port_parse_dt() function into mvebu_pcie_of_to_plat() to have all code related to parsing DT properties at one place. Signed-off-by: Pali Rohár --- drivers/pci/pci_mvebu.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index 0ce602b435..2e2fa31877 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -479,22 +479,6 @@ static int mvebu_pcie_probe(struct udevice *dev) return 0; } -static int mvebu_pcie_port_parse_dt(ofnode node, struct mvebu_pcie *pcie) -{ - const u32 *addr; - int len; - - addr = ofnode_get_property(node, "assigned-addresses", &len); - if (!addr) { - pr_err("property \"assigned-addresses\" not found"); - return -FDT_ERR_NOTFOUND; - } - - pcie->base = (void *)(fdt32_to_cpu(addr[2]) + SOC_REGS_PHY_BASE); - - return 0; -} - #define DT_FLAGS_TO_TYPE(flags) (((flags) >> 24) & 0x03) #define DT_TYPE_IO 0x1 #define DT_TYPE_MEM32 0x2 @@ -558,7 +542,9 @@ static int mvebu_get_tgt_attr(ofnode node, int devfn, static int mvebu_pcie_of_to_plat(struct udevice *dev) { struct mvebu_pcie *pcie = dev_get_plat(dev); + const u32 *addr; int ret = 0; + int len; /* Get port number, lane number and memory target / attr */ if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-port", @@ -596,9 +582,14 @@ static int mvebu_pcie_of_to_plat(struct udevice *dev) } /* Parse PCIe controller register base from DT */ - ret = mvebu_pcie_port_parse_dt(dev_ofnode(dev), pcie); - if (ret < 0) + addr = ofnode_get_property(dev_ofnode(dev), "assigned-addresses", &len); + if (!addr) { + printf("%s: property \"assigned-addresses\" not found\n", pcie->name); + ret = -FDT_ERR_NOTFOUND; goto err; + } + + pcie->base = (void *)(fdt32_to_cpu(addr[2]) + SOC_REGS_PHY_BASE); return 0; From 137db2af147979dc27d912e0567e7953a9380df3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 21 Dec 2021 12:20:15 +0100 Subject: [PATCH 05/38] pci: pci_mvebu: Remove dependency on SOC_REGS_PHY_BASE macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SoC specific macro SOC_REGS_PHY_BASE is used for two things: * calculation of base PCIe port address * filling PCIe register with address of internal registers For calculating base PCIe port address use function ofnode_translate_address() which translates DT "assigned-addresses" to final PCIe port address. And for calculating address of internal registers use untranslated and translated DT "assigned-addresses". Basically this change reads SOC_REGS_PHY_BASE address indirectly from DT. Signed-off-by: Pali Rohár --- drivers/pci/pci_mvebu.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index 2e2fa31877..f8a2272a8f 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -67,6 +67,7 @@ struct mvebu_pcie { struct resource mem; void __iomem *iobase; struct resource io; + u32 intregs; u32 port; u32 lane; int devfn; @@ -350,7 +351,7 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie) pcie->base + PCIE_BAR_CTRL_OFF(1)); /* Setup BAR[0] to internal registers. */ - writel(SOC_REGS_PHY_BASE, pcie->base + PCIE_BAR_LO_OFF(0)); + writel(pcie->intregs, pcie->base + PCIE_BAR_LO_OFF(0)); writel(0, pcie->base + PCIE_BAR_HI_OFF(0)); } @@ -589,7 +590,8 @@ static int mvebu_pcie_of_to_plat(struct udevice *dev) goto err; } - pcie->base = (void *)(fdt32_to_cpu(addr[2]) + SOC_REGS_PHY_BASE); + pcie->base = (void *)(u32)ofnode_translate_address(dev_ofnode(dev), addr); + pcie->intregs = (u32)pcie->base - fdt32_to_cpu(addr[2]); return 0; From afef9f4215c9e2ce968734d6b9993ce8c4cffa5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 21 Dec 2021 12:20:16 +0100 Subject: [PATCH 06/38] pci: pci_mvebu: Split initialization of PCIe ports into 3 phases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In first phase just parse DT properties and fill struct mvebu_pcie. In second phase setup all PCIe links (without enabling them). And in the last third phase enable all PCIe links and create UCLASS_PCI device for each one. Because parsing of DT is done before UCLASS_PCI is created, we cannot use DM for this action anymore. So remove .of_to_plat callback and replace it by ad-hoc function for parsing DT properties and filling struct mvebu_pcie. Signed-off-by: Pali Rohár --- drivers/pci/pci_mvebu.c | 106 +++++++++++++++++++++++++++++++--------- 1 file changed, 84 insertions(+), 22 deletions(-) diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index f8a2272a8f..b9944e4585 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -355,17 +355,30 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie) writel(0, pcie->base + PCIE_BAR_HI_OFF(0)); } -static int mvebu_pcie_probe(struct udevice *dev) +/* Only enable PCIe link, do not setup it */ +static int mvebu_pcie_enable_link(struct mvebu_pcie *pcie, ofnode node) +{ + /* PCIe link is currently automatically enabled in SerDes code */ + return 0; +} + +/* Setup PCIe link but do not enable it */ +static void mvebu_pcie_setup_link(struct mvebu_pcie *pcie) { - struct mvebu_pcie *pcie = dev_get_plat(dev); - struct udevice *ctlr = pci_get_controller(dev); - struct pci_controller *hose = dev_get_uclass_priv(ctlr); u32 reg; /* Setup PCIe controller to Root Complex mode */ reg = readl(pcie->base + PCIE_CTRL_OFF); reg |= PCIE_CTRL_RC_MODE; writel(reg, pcie->base + PCIE_CTRL_OFF); +} + +static int mvebu_pcie_probe(struct udevice *dev) +{ + struct mvebu_pcie *pcie = dev_get_plat(dev); + struct udevice *ctlr = pci_get_controller(dev); + struct pci_controller *hose = dev_get_uclass_priv(ctlr); + u32 reg; /* * Change Class Code of PCI Bridge device to PCI Bridge (0x600400) @@ -431,7 +444,8 @@ static int mvebu_pcie_probe(struct udevice *dev) mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr, (phys_addr_t)pcie->mem.start, resource_size(&pcie->mem))) { - printf("PCIe unable to add mbus window for mem at %08x+%08x\n", + printf("%s: unable to add mbus window for mem at %08x+%08x\n", + pcie->name, (u32)pcie->mem.start, (unsigned)resource_size(&pcie->mem)); pcie->mem.start = 0; pcie->mem.end = -1; @@ -441,7 +455,8 @@ static int mvebu_pcie_probe(struct udevice *dev) mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr, (phys_addr_t)pcie->io.start, resource_size(&pcie->io))) { - printf("PCIe unable to add mbus window for IO at %08x+%08x\n", + printf("%s: unable to add mbus window for IO at %08x+%08x\n", + pcie->name, (u32)pcie->io.start, (unsigned)resource_size(&pcie->io)); pcie->io.start = 0; pcie->io.end = -1; @@ -540,33 +555,34 @@ static int mvebu_get_tgt_attr(ofnode node, int devfn, return -ENOENT; } -static int mvebu_pcie_of_to_plat(struct udevice *dev) +static int mvebu_pcie_port_parse_dt(ofnode node, ofnode parent, struct mvebu_pcie *pcie) { - struct mvebu_pcie *pcie = dev_get_plat(dev); + struct fdt_pci_addr pci_addr; const u32 *addr; int ret = 0; int len; /* Get port number, lane number and memory target / attr */ - if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-port", + if (ofnode_read_u32(node, "marvell,pcie-port", &pcie->port)) { ret = -ENODEV; goto err; } - if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-lane", &pcie->lane)) + if (ofnode_read_u32(node, "marvell,pcie-lane", &pcie->lane)) pcie->lane = 0; sprintf(pcie->name, "pcie%d.%d", pcie->port, pcie->lane); - /* pci_get_devfn() returns devfn in bits 15..8, see PCI_DEV usage */ - pcie->devfn = pci_get_devfn(dev); - if (pcie->devfn < 0) { - ret = -ENODEV; + /* devfn is in bits [15:8], see PCI_DEV usage */ + ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", &pci_addr); + if (ret < 0) { + printf("%s: property \"reg\" is invalid\n", pcie->name); goto err; } + pcie->devfn = pci_addr.phys_hi & 0xff00; - ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn, + ret = mvebu_get_tgt_attr(parent, pcie->devfn, IORESOURCE_MEM, &pcie->mem_target, &pcie->mem_attr); if (ret < 0) { @@ -574,7 +590,7 @@ static int mvebu_pcie_of_to_plat(struct udevice *dev) goto err; } - ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn, + ret = mvebu_get_tgt_attr(parent, pcie->devfn, IORESOURCE_IO, &pcie->io_target, &pcie->io_attr); if (ret < 0) { @@ -583,14 +599,14 @@ static int mvebu_pcie_of_to_plat(struct udevice *dev) } /* Parse PCIe controller register base from DT */ - addr = ofnode_get_property(dev_ofnode(dev), "assigned-addresses", &len); + addr = ofnode_get_property(node, "assigned-addresses", &len); if (!addr) { printf("%s: property \"assigned-addresses\" not found\n", pcie->name); ret = -FDT_ERR_NOTFOUND; goto err; } - pcie->base = (void *)(u32)ofnode_translate_address(dev_ofnode(dev), addr); + pcie->base = (void *)(u32)ofnode_translate_address(node, addr); pcie->intregs = (u32)pcie->base - fdt32_to_cpu(addr[2]); return 0; @@ -609,7 +625,6 @@ static struct driver pcie_mvebu_drv = { .id = UCLASS_PCI, .ops = &mvebu_pcie_ops, .probe = mvebu_pcie_probe, - .of_to_plat = mvebu_pcie_of_to_plat, .plat_auto = sizeof(struct mvebu_pcie), }; @@ -619,11 +634,14 @@ static struct driver pcie_mvebu_drv = { */ static int mvebu_pcie_bind(struct udevice *parent) { + struct mvebu_pcie **ports_pcie; struct mvebu_pcie *pcie; struct uclass_driver *drv; struct udevice *dev; struct resource mem; struct resource io; + int ports_count, i; + ofnode *ports_nodes; ofnode subnode; /* Lookup pci driver */ @@ -633,18 +651,34 @@ static int mvebu_pcie_bind(struct udevice *parent) return -ENOENT; } + ports_count = ofnode_get_child_count(dev_ofnode(parent)); + ports_pcie = calloc(ports_count, sizeof(*ports_pcie)); + ports_nodes = calloc(ports_count, sizeof(*ports_nodes)); + if (!ports_pcie || !ports_nodes) { + free(ports_pcie); + free(ports_nodes); + return -ENOMEM; + } + ports_count = 0; + mem.start = MBUS_PCI_MEM_BASE; mem.end = MBUS_PCI_MEM_BASE + MBUS_PCI_MEM_SIZE - 1; io.start = MBUS_PCI_IO_BASE; io.end = MBUS_PCI_IO_BASE + MBUS_PCI_IO_SIZE - 1; + /* First phase: Fill mvebu_pcie struct for each port */ ofnode_for_each_subnode(subnode, dev_ofnode(parent)) { if (!ofnode_is_available(subnode)) continue; pcie = calloc(1, sizeof(*pcie)); if (!pcie) - return -ENOMEM; + continue; + + if (mvebu_pcie_port_parse_dt(subnode, dev_ofnode(parent), pcie) < 0) { + free(pcie); + continue; + } /* * MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped @@ -657,7 +691,7 @@ static int mvebu_pcie_bind(struct udevice *parent) pcie->mem.end = mem.start + SZ_128M - 1; mem.start += SZ_128M; } else { - printf("PCIe unable to assign mbus window for mem\n"); + printf("%s: unable to assign mbus window for mem\n", pcie->name); pcie->mem.start = 0; pcie->mem.end = -1; } @@ -667,16 +701,44 @@ static int mvebu_pcie_bind(struct udevice *parent) pcie->io.end = io.start + SZ_64K - 1; io.start += SZ_64K; } else { - printf("PCIe unable to assign mbus window for io\n"); + printf("%s: unable to assign mbus window for io\n", pcie->name); pcie->io.start = 0; pcie->io.end = -1; } + ports_pcie[ports_count] = pcie; + ports_nodes[ports_count] = subnode; + ports_count++; + } + + /* Second phase: Setup all PCIe links (do not enable them yet) */ + for (i = 0; i < ports_count; i++) + mvebu_pcie_setup_link(ports_pcie[i]); + + /* Third phase: Enable all PCIe links and create for each UCLASS_PCI device */ + for (i = 0; i < ports_count; i++) { + pcie = ports_pcie[i]; + subnode = ports_nodes[i]; + + /* + * PCIe link can be enabled only after all PCIe links were + * properly configured. This is because more PCIe links shares + * one enable bit and some PCIe links cannot be enabled + * individually. + */ + if (mvebu_pcie_enable_link(pcie, subnode) < 0) { + free(pcie); + continue; + } + /* Create child device UCLASS_PCI and bind it */ device_bind(parent, &pcie_mvebu_drv, pcie->name, pcie, subnode, &dev); } + free(ports_pcie); + free(ports_nodes); + return 0; } From e7ff4271ab431cc725a95a87fe6b175bb6cede3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 21 Dec 2021 12:20:17 +0100 Subject: [PATCH 07/38] pci: pci_mvebu: Wait 100ms for Link Up in mvebu_pcie_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After function mvebu_pcie_probe() returns U-Boot DM expects that PCIe link is already up. In followup patches link initialization will be moved from SPL to proper and therefore explicitly link up delay is required. Delay mvebu_pcie_probe() for 100ms to ensure that PCIe link is up after function finish. In the case when no card is connected to the PCIe slot, this will delay probe time by 100ms, which should not be problematic. This change fixes detection and initialization of some QCA98xx cards on the first serdes when configured in x1 mode. Default configuration of the first serdes on A385 is x4 mode, so it looks as if some delay is required when x4 is changed to x1 and card correctly links with A385. Other PCIe serdes ports on A385 are x1-only, and so they don't have this problem. Signed-off-by: Pali Rohár --- drivers/pci/pci_mvebu.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index b9944e4585..55cde2dd83 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,9 @@ #define PCIE_DEBUG_CTRL 0x1a60 #define PCIE_DEBUG_SOFT_RESET BIT(20) +#define LINK_WAIT_RETRIES 100 +#define LINK_WAIT_TIMEOUT 1000 + struct mvebu_pcie { struct pci_controller hose; void __iomem *base; @@ -89,6 +93,23 @@ static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie) return !(val & PCIE_STAT_LINK_DOWN); } +static void mvebu_pcie_wait_for_link(struct mvebu_pcie *pcie) +{ + int retries; + + /* check if the link is up or not */ + for (retries = 0; retries < LINK_WAIT_RETRIES; retries++) { + if (mvebu_pcie_link_up(pcie)) { + printf("%s: Link up\n", pcie->name); + return; + } + + udelay(LINK_WAIT_TIMEOUT); + } + + printf("%s: Link down\n", pcie->name); +} + static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie *pcie, int busno) { u32 stat; @@ -492,6 +513,8 @@ static int mvebu_pcie_probe(struct udevice *dev) pcie->cfgcache[(PCI_PREF_MEMORY_BASE - 0x10) / 4] = PCI_PREF_RANGE_TYPE_64 | (PCI_PREF_RANGE_TYPE_64 << 16); + mvebu_pcie_wait_for_link(pcie); + return 0; } From 35e29e89a38662407d773e01ad6344de6ad268f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 21 Dec 2021 12:20:18 +0100 Subject: [PATCH 08/38] arm: mvebu: Implement simple mvebu-reset driver for enabling/disabling PCIe ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabling and disabling PCIe ports is done via address space of system controller. All 32-bit Armada SoCs use low 4 bits in SoC Control 1 Register for enabling and disabling some or more PCIe ports. Correct mapping needs to be set in particular DTS files. DT API for mvebu-reset is prepared for implementing resets also for other HW blocks, but currently only PCIe is implemented via index 0. Currently this driver is not used as PCIe ports are automatically enabled by SerDes code executed by U-Boot SPL. But this will change in followup patches. Signed-off-by: Pali Rohár --- arch/arm/dts/armada-375.dtsi | 3 +- arch/arm/dts/armada-38x.dtsi | 1 + arch/arm/dts/armada-xp-98dx3236.dtsi | 1 + arch/arm/dts/armada-xp.dtsi | 1 + arch/arm/mach-mvebu/Makefile | 1 + arch/arm/mach-mvebu/system-controller.c | 105 ++++++++++++++++++++++++ 6 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-mvebu/system-controller.c diff --git a/arch/arm/dts/armada-375.dtsi b/arch/arm/dts/armada-375.dtsi index 62a548a55f..fdf2d6dbdc 100644 --- a/arch/arm/dts/armada-375.dtsi +++ b/arch/arm/dts/armada-375.dtsi @@ -384,9 +384,10 @@ interrupts = ; }; - system-controller@18200 { + systemc: system-controller@18200 { compatible = "marvell,armada-375-system-controller"; reg = <0x18200 0x100>; + #reset-cells = <2>; }; gateclk: clock-gating-control@18220 { diff --git a/arch/arm/dts/armada-38x.dtsi b/arch/arm/dts/armada-38x.dtsi index 72c49beb71..061bd78520 100644 --- a/arch/arm/dts/armada-38x.dtsi +++ b/arch/arm/dts/armada-38x.dtsi @@ -328,6 +328,7 @@ compatible = "marvell,armada-380-system-controller", "marvell,armada-370-xp-system-controller"; reg = <0x18200 0x100>; + #reset-cells = <2>; }; gateclk: clock-gating-control@18220 { diff --git a/arch/arm/dts/armada-xp-98dx3236.dtsi b/arch/arm/dts/armada-xp-98dx3236.dtsi index 5df1d1848d..8369de79af 100644 --- a/arch/arm/dts/armada-xp-98dx3236.dtsi +++ b/arch/arm/dts/armada-xp-98dx3236.dtsi @@ -136,6 +136,7 @@ systemc: system-controller@18200 { compatible = "marvell,armada-370-xp-system-controller"; reg = <0x18200 0x500>; + #reset-cells = <2>; }; gateclk: clock-gating-control@18220 { diff --git a/arch/arm/dts/armada-xp.dtsi b/arch/arm/dts/armada-xp.dtsi index d856d96022..fb5640bbd9 100644 --- a/arch/arm/dts/armada-xp.dtsi +++ b/arch/arm/dts/armada-xp.dtsi @@ -78,6 +78,7 @@ systemc: system-controller@18200 { compatible = "marvell,armada-370-xp-system-controller"; reg = <0x18200 0x500>; + #reset-cells = <2>; }; gateclk: clock-gating-control@18220 { diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 7e9c206ed6..0b2c57e573 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -21,6 +21,7 @@ else # CONFIG_ARCH_KIRKWOOD obj-y = cpu.o obj-y += dram.o +obj-$(CONFIG_DM_RESET) += system-controller.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_ARMADA_375) += ../../../drivers/ddr/marvell/axp/xor.o obj-$(CONFIG_ARMADA_38X) += ../../../drivers/ddr/marvell/a38x/xor.o diff --git a/arch/arm/mach-mvebu/system-controller.c b/arch/arm/mach-mvebu/system-controller.c new file mode 100644 index 0000000000..ea858b269e --- /dev/null +++ b/arch/arm/mach-mvebu/system-controller.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0+ +// (C) 2021 Pali Rohár + +#include +#include +#include +#include + +#define MVEBU_SOC_CONTROL_1_REG 0x4 + +#define MVEBU_PCIE_ID 0 + +struct mvebu_reset_data { + void *base; +}; + +static int mvebu_reset_of_xlate(struct reset_ctl *rst, + struct ofnode_phandle_args *args) +{ + if (args->args_count < 2) + return -EINVAL; + + rst->id = args->args[0]; + rst->data = args->args[1]; + + /* Currently only PCIe is implemented */ + if (rst->id != MVEBU_PCIE_ID) + return -EINVAL; + + /* Four PCIe enable bits are shared across more PCIe links */ + if (!(rst->data >= 0 && rst->data <= 3)) + return -EINVAL; + + return 0; +} + +static int mvebu_reset_request(struct reset_ctl *rst) +{ + return 0; +} + +static int mvebu_reset_free(struct reset_ctl *rst) +{ + return 0; +} + +static int mvebu_reset_assert(struct reset_ctl *rst) +{ + struct mvebu_reset_data *data = dev_get_priv(rst->dev); + + clrbits_32(data->base + MVEBU_SOC_CONTROL_1_REG, BIT(rst->data)); + return 0; +} + +static int mvebu_reset_deassert(struct reset_ctl *rst) +{ + struct mvebu_reset_data *data = dev_get_priv(rst->dev); + + setbits_32(data->base + MVEBU_SOC_CONTROL_1_REG, BIT(rst->data)); + return 0; +} + +static int mvebu_reset_status(struct reset_ctl *rst) +{ + struct mvebu_reset_data *data = dev_get_priv(rst->dev); + + return !(readl(data->base + MVEBU_SOC_CONTROL_1_REG) & BIT(rst->data)); +} + +static int mvebu_reset_of_to_plat(struct udevice *dev) +{ + struct mvebu_reset_data *data = dev_get_priv(dev); + + data->base = (void *)dev_read_addr(dev); + if ((fdt_addr_t)data->base == FDT_ADDR_T_NONE) + return -EINVAL; + + return 0; +} + +static const struct udevice_id mvebu_reset_of_match[] = { + { .compatible = "marvell,armada-370-xp-system-controller" }, + { .compatible = "marvell,armada-375-system-controller" }, + { .compatible = "marvell,armada-380-system-controller" }, + { .compatible = "marvell,armada-390-system-controller" }, + { }, +}; + +static struct reset_ops mvebu_reset_ops = { + .of_xlate = mvebu_reset_of_xlate, + .request = mvebu_reset_request, + .rfree = mvebu_reset_free, + .rst_assert = mvebu_reset_assert, + .rst_deassert = mvebu_reset_deassert, + .rst_status = mvebu_reset_status, +}; + +U_BOOT_DRIVER(mvebu_reset) = { + .name = "mvebu-reset", + .id = UCLASS_RESET, + .of_match = mvebu_reset_of_match, + .of_to_plat = mvebu_reset_of_to_plat, + .priv_auto = sizeof(struct mvebu_reset_data), + .ops = &mvebu_reset_ops, +}; From 94c30f9c8f3cf3032349167be21b837b2d568ea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 21 Dec 2021 12:20:19 +0100 Subject: [PATCH 09/38] arm: mvebu: a38x: serdes: Move non-serdes PCIe code to pci_mvebu.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As explained in commit 3bedbcc3aa18 ("arm: mvebu: a38x: serdes: Don't overwrite read-only SAR PCIe registers") it is required to set Maximum Link Width bits of PCIe Root Port Link Capabilities Register depending of number of used serdes lanes. As this register is part of PCIe address space and not serdes address space, move it into pci_mvebu.c driver. Read number of PCIe lanes from DT property "num-lanes" which is used also by other PCIe controller drivers in Linux kernel. If this property is absent then it defaults to 1. This property needs to be set to 4 for every mvebu board which use PEX_ROOT_COMPLEX_X4 or PEX_BUS_MODE_X4. Enabling of PCIe port needs to be done afer all registers in PCIe address space are properly configure. For this purpose use new mvebu-reset driver (part of system-controller) and remove this code from serdes code. Because some PCIe ports cannot be enabled individually, it is required to first setup all PCIe ports and then enable them. This change contains also all required "num-lanes" and "resets" DTS properties, to make pci_mvebu.c driver work correctly. Signed-off-by: Pali Rohár --- arch/arm/dts/armada-375.dtsi | 2 + arch/arm/dts/armada-380.dtsi | 3 + arch/arm/dts/armada-385.dtsi | 4 ++ arch/arm/dts/armada-xp-98dx3236.dtsi | 1 + arch/arm/dts/armada-xp-mv78230.dtsi | 5 ++ arch/arm/dts/armada-xp-mv78260.dtsi | 9 +++ arch/arm/dts/armada-xp-mv78460.dtsi | 10 ++++ arch/arm/dts/armada-xp-synology-ds414.dts | 1 + arch/arm/dts/armada-xp-theadorable.dts | 1 + arch/arm/mach-mvebu/serdes/a38x/Makefile | 1 - arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c | 57 ------------------- arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h | 27 --------- .../serdes/a38x/high_speed_env_spec.c | 19 ------- drivers/pci/Kconfig | 1 + drivers/pci/pci_mvebu.c | 43 +++++++++++++- 15 files changed, 79 insertions(+), 105 deletions(-) delete mode 100644 arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c delete mode 100644 arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h diff --git a/arch/arm/dts/armada-375.dtsi b/arch/arm/dts/armada-375.dtsi index fdf2d6dbdc..ff0ad7a9c7 100644 --- a/arch/arm/dts/armada-375.dtsi +++ b/arch/arm/dts/armada-375.dtsi @@ -617,6 +617,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <0>; clocks = <&gateclk 5>; + resets = <&systemc 0 0>; status = "disabled"; }; @@ -635,6 +636,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <1>; clocks = <&gateclk 6>; + resets = <&systemc 0 1>; status = "disabled"; }; diff --git a/arch/arm/dts/armada-380.dtsi b/arch/arm/dts/armada-380.dtsi index cff1269f3f..f3d7f4b27d 100644 --- a/arch/arm/dts/armada-380.dtsi +++ b/arch/arm/dts/armada-380.dtsi @@ -73,6 +73,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <0>; clocks = <&gateclk 8>; + resets = <&systemc 0 0>; status = "disabled"; }; @@ -92,6 +93,7 @@ marvell,pcie-port = <1>; marvell,pcie-lane = <0>; clocks = <&gateclk 5>; + resets = <&systemc 0 1>; status = "disabled"; }; @@ -111,6 +113,7 @@ marvell,pcie-port = <2>; marvell,pcie-lane = <0>; clocks = <&gateclk 6>; + resets = <&systemc 0 2>; status = "disabled"; }; }; diff --git a/arch/arm/dts/armada-385.dtsi b/arch/arm/dts/armada-385.dtsi index f0022d10c7..581a7d9bea 100644 --- a/arch/arm/dts/armada-385.dtsi +++ b/arch/arm/dts/armada-385.dtsi @@ -78,6 +78,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <0>; clocks = <&gateclk 8>; + resets = <&systemc 0 0>; status = "disabled"; }; @@ -97,6 +98,7 @@ marvell,pcie-port = <1>; marvell,pcie-lane = <0>; clocks = <&gateclk 5>; + resets = <&systemc 0 1>; status = "disabled"; }; @@ -116,6 +118,7 @@ marvell,pcie-port = <2>; marvell,pcie-lane = <0>; clocks = <&gateclk 6>; + resets = <&systemc 0 2>; status = "disabled"; }; @@ -138,6 +141,7 @@ marvell,pcie-port = <3>; marvell,pcie-lane = <0>; clocks = <&gateclk 7>; + resets = <&systemc 0 3>; status = "disabled"; }; }; diff --git a/arch/arm/dts/armada-xp-98dx3236.dtsi b/arch/arm/dts/armada-xp-98dx3236.dtsi index 8369de79af..1a48ff3c61 100644 --- a/arch/arm/dts/armada-xp-98dx3236.dtsi +++ b/arch/arm/dts/armada-xp-98dx3236.dtsi @@ -85,6 +85,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <0>; clocks = <&gateclk 5>; + resets = <&systemc 0 0>; status = "disabled"; }; }; diff --git a/arch/arm/dts/armada-xp-mv78230.dtsi b/arch/arm/dts/armada-xp-mv78230.dtsi index 8558bf6bb5..63d7f48cf4 100644 --- a/arch/arm/dts/armada-xp-mv78230.dtsi +++ b/arch/arm/dts/armada-xp-mv78230.dtsi @@ -92,6 +92,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <0>; clocks = <&gateclk 5>; + resets = <&systemc 0 0>; status = "disabled"; }; @@ -110,6 +111,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <1>; clocks = <&gateclk 6>; + resets = <&systemc 0 0>; status = "disabled"; }; @@ -128,6 +130,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <2>; clocks = <&gateclk 7>; + resets = <&systemc 0 0>; status = "disabled"; }; @@ -146,6 +149,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <3>; clocks = <&gateclk 8>; + resets = <&systemc 0 0>; status = "disabled"; }; @@ -164,6 +168,7 @@ marvell,pcie-port = <1>; marvell,pcie-lane = <0>; clocks = <&gateclk 9>; + resets = <&systemc 0 1>; status = "disabled"; }; }; diff --git a/arch/arm/dts/armada-xp-mv78260.dtsi b/arch/arm/dts/armada-xp-mv78260.dtsi index 2d85fe8ac3..5dc413dd14 100644 --- a/arch/arm/dts/armada-xp-mv78260.dtsi +++ b/arch/arm/dts/armada-xp-mv78260.dtsi @@ -107,6 +107,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <0>; clocks = <&gateclk 5>; + resets = <&systemc 0 0>; status = "disabled"; }; @@ -125,6 +126,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <1>; clocks = <&gateclk 6>; + resets = <&systemc 0 0>; status = "disabled"; }; @@ -143,6 +145,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <2>; clocks = <&gateclk 7>; + resets = <&systemc 0 0>; status = "disabled"; }; @@ -161,6 +164,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <3>; clocks = <&gateclk 8>; + resets = <&systemc 0 0>; status = "disabled"; }; @@ -179,6 +183,7 @@ marvell,pcie-port = <1>; marvell,pcie-lane = <0>; clocks = <&gateclk 9>; + resets = <&systemc 0 1>; status = "disabled"; }; @@ -197,6 +202,7 @@ marvell,pcie-port = <1>; marvell,pcie-lane = <1>; clocks = <&gateclk 10>; + resets = <&systemc 0 1>; status = "disabled"; }; @@ -215,6 +221,7 @@ marvell,pcie-port = <1>; marvell,pcie-lane = <2>; clocks = <&gateclk 11>; + resets = <&systemc 0 1>; status = "disabled"; }; @@ -233,6 +240,7 @@ marvell,pcie-port = <1>; marvell,pcie-lane = <3>; clocks = <&gateclk 12>; + resets = <&systemc 0 1>; status = "disabled"; }; @@ -251,6 +259,7 @@ marvell,pcie-port = <2>; marvell,pcie-lane = <0>; clocks = <&gateclk 26>; + resets = <&systemc 0 2>; status = "disabled"; }; }; diff --git a/arch/arm/dts/armada-xp-mv78460.dtsi b/arch/arm/dts/armada-xp-mv78460.dtsi index 230a3fd36b..6fbd0ce215 100644 --- a/arch/arm/dts/armada-xp-mv78460.dtsi +++ b/arch/arm/dts/armada-xp-mv78460.dtsi @@ -128,6 +128,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <0>; clocks = <&gateclk 5>; + resets = <&systemc 0 0>; status = "disabled"; }; @@ -146,6 +147,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <1>; clocks = <&gateclk 6>; + resets = <&systemc 0 0>; status = "disabled"; }; @@ -164,6 +166,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <2>; clocks = <&gateclk 7>; + resets = <&systemc 0 0>; status = "disabled"; }; @@ -182,6 +185,7 @@ marvell,pcie-port = <0>; marvell,pcie-lane = <3>; clocks = <&gateclk 8>; + resets = <&systemc 0 0>; status = "disabled"; }; @@ -200,6 +204,7 @@ marvell,pcie-port = <1>; marvell,pcie-lane = <0>; clocks = <&gateclk 9>; + resets = <&systemc 0 1>; status = "disabled"; }; @@ -218,6 +223,7 @@ marvell,pcie-port = <1>; marvell,pcie-lane = <1>; clocks = <&gateclk 10>; + resets = <&systemc 0 1>; status = "disabled"; }; @@ -236,6 +242,7 @@ marvell,pcie-port = <1>; marvell,pcie-lane = <2>; clocks = <&gateclk 11>; + resets = <&systemc 0 1>; status = "disabled"; }; @@ -254,6 +261,7 @@ marvell,pcie-port = <1>; marvell,pcie-lane = <3>; clocks = <&gateclk 12>; + resets = <&systemc 0 1>; status = "disabled"; }; @@ -272,6 +280,7 @@ marvell,pcie-port = <2>; marvell,pcie-lane = <0>; clocks = <&gateclk 26>; + resets = <&systemc 0 2>; status = "disabled"; }; @@ -290,6 +299,7 @@ marvell,pcie-port = <3>; marvell,pcie-lane = <0>; clocks = <&gateclk 27>; + resets = <&systemc 0 3>; status = "disabled"; }; }; diff --git a/arch/arm/dts/armada-xp-synology-ds414.dts b/arch/arm/dts/armada-xp-synology-ds414.dts index 861967cd7e..35909e3c69 100644 --- a/arch/arm/dts/armada-xp-synology-ds414.dts +++ b/arch/arm/dts/armada-xp-synology-ds414.dts @@ -187,6 +187,7 @@ pcie@1,0 { /* Port 0, Lane 0 */ status = "okay"; + num-lanes = <4>; }; /* diff --git a/arch/arm/dts/armada-xp-theadorable.dts b/arch/arm/dts/armada-xp-theadorable.dts index 24cc1cc527..a06a65af15 100644 --- a/arch/arm/dts/armada-xp-theadorable.dts +++ b/arch/arm/dts/armada-xp-theadorable.dts @@ -214,5 +214,6 @@ pcie@9,0 { /* Port 2, Lane 0 */ status = "okay"; + num-lanes = <4>; }; }; diff --git a/arch/arm/mach-mvebu/serdes/a38x/Makefile b/arch/arm/mach-mvebu/serdes/a38x/Makefile index 917fc1350c..5a70b37596 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/Makefile +++ b/arch/arm/mach-mvebu/serdes/a38x/Makefile @@ -1,6 +1,5 @@ # SPDX-License-Identifier: GPL-2.0+ -obj-$(CONFIG_SPL_BUILD) = ctrl_pex.o obj-$(CONFIG_SPL_BUILD) += high_speed_env_spec.o obj-$(CONFIG_SPL_BUILD) += high_speed_env_spec-38x.o obj-$(CONFIG_SPL_BUILD) += seq_exec.o diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c deleted file mode 100644 index b3cbddf6a2..0000000000 --- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) Marvell International Ltd. and its affiliates - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "ctrl_pex.h" -#include "sys_env_lib.h" - -int hws_pex_config(const struct serdes_map *serdes_map, u8 count) -{ - enum serdes_type serdes_type; - u32 idx, tmp; - - DEBUG_INIT_FULL_S("\n### hws_pex_config ###\n"); - - tmp = reg_read(SOC_CONTROL_REG1); - tmp &= ~0x03; - - for (idx = 0; idx < count; idx++) { - serdes_type = serdes_map[idx].serdes_type; - if ((serdes_type != PEX0) && - ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) || - (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) { - /* for PEX by4 - relevant for the first port only */ - continue; - } - - switch (serdes_type) { - case PEX0: - tmp |= 0x1 << PCIE0_ENABLE_OFFS; - break; - case PEX1: - tmp |= 0x1 << PCIE1_ENABLE_OFFS; - break; - case PEX2: - tmp |= 0x1 << PCIE2_ENABLE_OFFS; - break; - case PEX3: - tmp |= 0x1 << PCIE3_ENABLE_OFFS; - break; - default: - break; - } - } - - reg_write(SOC_CONTROL_REG1, tmp); - - return MV_OK; -} diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h deleted file mode 100644 index abdbe3c660..0000000000 --- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) Marvell International Ltd. and its affiliates - */ - -#ifndef _CTRL_PEX_H -#define _CTRL_PEX_H - -#include -#include "high_speed_env_spec.h" - -/* Direct access to PEX0 Root Port's PCIe Capability structure */ -#define PEX0_RP_PCIE_CFG_OFFSET (0x00080000 + 0x60) - -/* SOC_CONTROL_REG1 fields */ -#define PCIE0_ENABLE_OFFS 0 -#define PCIE0_ENABLE_MASK (0x1 << PCIE0_ENABLE_OFFS) -#define PCIE1_ENABLE_OFFS 1 -#define PCIE1_ENABLE_MASK (0x1 << PCIE1_ENABLE_OFFS) -#define PCIE2_ENABLE_OFFS 2 -#define PCIE2_ENABLE_MASK (0x1 << PCIE2_ENABLE_OFFS) -#define PCIE3_ENABLE_OFFS 3 -#define PCIE4_ENABLE_MASK (0x1 << PCIE3_ENABLE_OFFS) - -int hws_pex_config(const struct serdes_map *serdes_map, u8 count); - -#endif diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c index 9ba60b57aa..2e467b546d 100644 --- a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c +++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c @@ -12,7 +12,6 @@ #include "high_speed_env_spec.h" #include "sys_env_lib.h" -#include "ctrl_pex.h" /* * serdes_seq_db - holds all serdes sequences, their size and the @@ -1555,9 +1554,6 @@ int hws_power_up_serdes_lanes(struct serdes_map *serdes_map, u8 count) After finish the Power_up sequence for all lanes, the lanes should be released from reset state. */ CHECK_STATUS(hws_pex_tx_config_seq(serdes_map, count)); - - /* PEX configuration */ - CHECK_STATUS(hws_pex_config(serdes_map, count)); } /* USB2 configuration */ @@ -1743,21 +1739,6 @@ int serdes_power_up_ctrl(u32 serdes_num, int serdes_power_up, else reg_data &= ~0x4000; reg_write(SOC_CONTROL_REG1, reg_data); - - /* - * Set Maximum Link Width to X1 or X4 in Root - * Port's PCIe Link Capability register. - * This register is read-only but if is not set - * correctly then access to PCI config space of - * endpoint card behind this Root Port does not - * work. - */ - reg_data = reg_read(PEX0_RP_PCIE_CFG_OFFSET + - PCI_EXP_LNKCAP); - reg_data &= ~PCI_EXP_LNKCAP_MLW; - reg_data |= (is_pex_by1 ? 1 : 4) << 4; - reg_write(PEX0_RP_PCIE_CFG_OFFSET + - PCI_EXP_LNKCAP, reg_data); } CHECK_STATUS(mv_seq_exec(serdes_num, PEX_POWER_UP_SEQ)); diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 42f8cb6be0..630d6e6cc5 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -265,6 +265,7 @@ config PCI_MVEBU bool "Enable Armada XP/38x PCIe driver" depends on ARCH_MVEBU select MISC + select DM_RESET help Say Y here if you want to enable PCIe controller support on Armada XP/38x SoCs. diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index 55cde2dd83..b3ea034a28 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -74,6 +75,7 @@ struct mvebu_pcie { u32 intregs; u32 port; u32 lane; + bool is_x4; int devfn; u32 lane_mask; int first_busno; @@ -379,7 +381,30 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie) /* Only enable PCIe link, do not setup it */ static int mvebu_pcie_enable_link(struct mvebu_pcie *pcie, ofnode node) { - /* PCIe link is currently automatically enabled in SerDes code */ + struct reset_ctl rst; + int ret; + + ret = reset_get_by_index_nodev(node, 0, &rst); + if (ret == -ENOENT) { + return 0; + } else if (ret < 0) { + printf("%s: cannot get reset controller: %d\n", pcie->name, ret); + return ret; + } + + ret = reset_request(&rst); + if (ret) { + printf("%s: cannot request reset controller: %d\n", pcie->name, ret); + return ret; + } + + ret = reset_deassert(&rst); + reset_free(&rst); + if (ret) { + printf("%s: cannot enable PCIe port: %d\n", pcie->name, ret); + return ret; + } + return 0; } @@ -392,6 +417,18 @@ static void mvebu_pcie_setup_link(struct mvebu_pcie *pcie) reg = readl(pcie->base + PCIE_CTRL_OFF); reg |= PCIE_CTRL_RC_MODE; writel(reg, pcie->base + PCIE_CTRL_OFF); + + /* + * Set Maximum Link Width to X1 or X4 in Root Port's PCIe Link + * Capability register. This register is defined by PCIe specification + * as read-only but this mvebu controller has it as read-write and must + * be set to number of SerDes PCIe lanes (1 or 4). If this register is + * not set correctly then link with endpoint card is not established. + */ + reg = readl(pcie->base + PCIE_CAPAB_OFF + PCI_EXP_LNKCAP); + reg &= ~PCI_EXP_LNKCAP_MLW; + reg |= (pcie->is_x4 ? 4 : 1) << 4; + writel(reg, pcie->base + PCIE_CAPAB_OFF + PCI_EXP_LNKCAP); } static int mvebu_pcie_probe(struct udevice *dev) @@ -582,6 +619,7 @@ static int mvebu_pcie_port_parse_dt(ofnode node, ofnode parent, struct mvebu_pci { struct fdt_pci_addr pci_addr; const u32 *addr; + u32 num_lanes; int ret = 0; int len; @@ -597,6 +635,9 @@ static int mvebu_pcie_port_parse_dt(ofnode node, ofnode parent, struct mvebu_pci sprintf(pcie->name, "pcie%d.%d", pcie->port, pcie->lane); + if (!ofnode_read_u32(node, "num-lanes", &num_lanes) && num_lanes == 4) + pcie->is_x4 = true; + /* devfn is in bits [15:8], see PCI_DEV usage */ ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", &pci_addr); if (ret < 0) { From c03f4da187afa94589f04534c7227298d423dd9c Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sat, 25 Dec 2021 05:46:29 +0100 Subject: [PATCH 10/38] mtd: nand: pxa3xx: use marvell, prefix for custom DT properties The DT properties for the "enable-arbiter" and "keep-config" config knobs were previously named inconsistently: - The u-boot driver used "nand-enable-arbiter" and "nand-keep-config" names, without Marvell prefixes. - The Linux driver uses "marvell,nand-keep-config" ("enable-arbiter" does not exist anymore in recent kernels, but it also used to be "marvell,nand-enable-arbiter"). - The device trees almost all use "marvell," prefixed names, except for one single instance of "nand-enable-arbiter" without vendor prefix. This commit standardizes on the vendor prefixed version, making the u-boot driver read from DT props "marvell,nand-enable-arbiter" and "marvell,nand-keep-config". The one device tree using the unprefixed version is also changed to use the new naming. This has the side effect of making the previously no-op "marvell," config knobs already present in some DTs actually do something. This was likely the original intention of the DT authors, but note that this commit was not tested on every single impacted board. Signed-off-by: Pierre Bourdon --- arch/arm/dts/armada-cp110.dtsi | 2 +- drivers/mtd/nand/raw/pxa3xx_nand.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/dts/armada-cp110.dtsi b/arch/arm/dts/armada-cp110.dtsi index abf1e4ea08..ddc10d2374 100644 --- a/arch/arm/dts/armada-cp110.dtsi +++ b/arch/arm/dts/armada-cp110.dtsi @@ -231,7 +231,7 @@ #address-cells = <1>; #size-cells = <0>; clocks = <&CP110_LABEL(syscon0) 1 2>; - nand-enable-arbiter; + marvell,nand-enable-arbiter; num-cs = <1>; nand-ecc-strength = <8>; nand-ecc-step-size = <512>; diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c index 8ff58a7038..3a9c9ca508 100644 --- a/drivers/mtd/nand/raw/pxa3xx_nand.c +++ b/drivers/mtd/nand/raw/pxa3xx_nand.c @@ -1862,10 +1862,10 @@ static int pxa3xx_nand_probe_dt(struct udevice *dev, struct pxa3xx_nand_info *in return -EINVAL; } - if (dev_read_bool(dev, "nand-enable-arbiter")) + if (dev_read_bool(dev, "marvell,nand-enable-arbiter")) pdata->enable_arbiter = 1; - if (dev_read_bool(dev, "nand-keep-config")) + if (dev_read_bool(dev, "marvell,nand-keep-config")) pdata->keep_config = 1; /* From 531d4bb04e49d279530be3a4c88595656eb6ef35 Mon Sep 17 00:00:00 2001 From: Tony Dinh Date: Sat, 1 Jan 2022 20:57:37 -0800 Subject: [PATCH 11/38] arm: kirkwood: iConnect : Add PCIe related configs - Add MVEBU PCIe configs - Also add SYS_THUMB_BUILD to keep u-boot image size within 512K Signed-off-by: Tony Dinh Reviewed-by: Stefan Roese --- configs/iconnect_defconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configs/iconnect_defconfig b/configs/iconnect_defconfig index 605b98b164..1c9c77a292 100644 --- a/configs/iconnect_defconfig +++ b/configs/iconnect_defconfig @@ -2,6 +2,7 @@ CONFIG_ARM=y CONFIG_SKIP_LOWLEVEL_INIT=y CONFIG_SYS_DCACHE_OFF=y CONFIG_ARCH_CPU_INIT=y +CONFIG_SYS_THUMB_BUILD=y CONFIG_ARCH_KIRKWOOD=y CONFIG_SYS_KWD_CONFIG="board/iomega/iconnect/kwbimage.cfg" CONFIG_SYS_TEXT_BASE=0x600000 @@ -18,9 +19,11 @@ CONFIG_USE_BOOTCOMMAND=y CONFIG_BOOTCOMMAND="setenv bootargs ${console} ${mtdparts} ${bootargs_root}; ubi part rootfs; ubifsmount ubi:rootfs; ubifsload 0x800000 ${kernel}; bootm 0x800000" CONFIG_USE_PREBOOT=y # CONFIG_DISPLAY_BOARDINFO is not set +CONFIG_BOARD_LATE_INIT=y CONFIG_SYS_PROMPT="iconnect => " # CONFIG_CMD_FLASH is not set CONFIG_CMD_NAND=y +CONFIG_CMD_PCI=y CONFIG_CMD_USB=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_MII=y @@ -43,6 +46,8 @@ CONFIG_MTD=y CONFIG_MTD_RAW_NAND=y CONFIG_MVGBE=y CONFIG_MII=y +CONFIG_PCI=y +CONFIG_PCI_MVEBU=y CONFIG_SYS_NS16550=y CONFIG_USB=y CONFIG_USB_EHCI_HCD=y From bbebd5b0a55686bc81855cdb5bc55b100fda2c0a Mon Sep 17 00:00:00 2001 From: Tony Dinh Date: Sat, 1 Jan 2022 20:57:38 -0800 Subject: [PATCH 12/38] arm: kirkwood: iConnect : Add PCIe late init - Add board_late_init function to enable pci_init Signed-off-by: Tony Dinh Reviewed-by: Stefan Roese --- board/iomega/iconnect/iconnect.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/board/iomega/iconnect/iconnect.c b/board/iomega/iconnect/iconnect.c index fe4be28b13..9e123aab00 100644 --- a/board/iomega/iconnect/iconnect.c +++ b/board/iomega/iconnect/iconnect.c @@ -92,3 +92,10 @@ int board_init(void) return 0; } + +int board_late_init(void) +{ + /* Do late init to ensure successful enumeration of PCIe devices */ + pci_init(); + return 0; +} From 1b24de6e9fadd4538873161c520c5c568145ab70 Mon Sep 17 00:00:00 2001 From: Tony Dinh Date: Sat, 1 Jan 2022 20:57:39 -0800 Subject: [PATCH 13/38] arm: kirkwood: iConnect : Update board maintainer Add myself as maintainer. Signed-off-by: Tony Dinh Reviewed-by: Stefan Roese --- board/iomega/iconnect/MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/board/iomega/iconnect/MAINTAINERS b/board/iomega/iconnect/MAINTAINERS index 167cf074b9..a1b018e816 100644 --- a/board/iomega/iconnect/MAINTAINERS +++ b/board/iomega/iconnect/MAINTAINERS @@ -1,4 +1,5 @@ ICONNECT BOARD +M: Tony Dinh M: Luka Perkov S: Maintained F: board/iomega/iconnect/ From eadc4f512fb43bba2fa4e842c982da919da664be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Tue, 4 Jan 2022 15:57:49 +0100 Subject: [PATCH 14/38] ddr: marvell: a38x: Fix Synchronous vs Asynchronous mode determination MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before commit 4c289425752f ("mv_ddr: a38x: add support for ddr async mode"), Asynchornous Mode was only used when the CPU Subsystem Clock Options[4:0] field in the SAR1 register was set to value 0x13: CPU at 2 GHz and DDR at 933 MHz. Then commit 4c289425752f ("mv_ddr: a38x: add support for ddr async mode") added support for Asynchornous Modes with frequencies other than 933 MHz (but at least 467 MHz), but the code it added to check for whether Asynchornous Mode should be used is wrong: it checks whether the frequency setting in board DDR topology map is set to value other than MV_DDR_FREQ_SAR. Thus boards which define a specific value, greater than 400 MHz, for DDR frequency in their board topology (e.g. Turris Omnia defines MV_DDR_FREQ_800), are incorrectly put into Asynchornous Mode after that commit. The A38x Functional Specification, section 10.12 DRAM Clocking, says: In Synchornous mode, the DRAM and CPU clocks are edge aligned and run in 1:2 or 1:3 CPU to DRAM frequency ratios. Change the check for whether Asynchornous Mode should be used according to this explanation in Functional Specification. Signed-off-by: Marek Behún Tested-by: Chris Packham Reviewed-by: Stefan Roese --- drivers/ddr/marvell/a38x/mv_ddr_plat.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/ddr/marvell/a38x/mv_ddr_plat.c b/drivers/ddr/marvell/a38x/mv_ddr_plat.c index faafc86ea2..7c7bce73a3 100644 --- a/drivers/ddr/marvell/a38x/mv_ddr_plat.c +++ b/drivers/ddr/marvell/a38x/mv_ddr_plat.c @@ -167,8 +167,6 @@ static u16 a38x_vco_freq_per_sar_ref_clk_40_mhz[] = { }; -static u32 async_mode_at_tf; - static u32 dq_bit_map_2_phy_pin[] = { 1, 0, 2, 6, 9, 8, 3, 7, /* 0 */ 8, 9, 1, 7, 2, 6, 3, 0, /* 1 */ @@ -734,7 +732,8 @@ static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id, u32 divider = 0; u32 sar_val, ref_clk_satr; u32 async_val; - u32 freq = mv_ddr_freq_get(frequency); + u32 cpu_freq; + u32 ddr_freq = mv_ddr_freq_get(frequency); if (if_id != 0) { DEBUG_TRAINING_ACCESS(DEBUG_LEVEL_ERROR, @@ -751,11 +750,14 @@ static int ddr3_tip_a38x_set_divider(u8 dev_num, u32 if_id, ref_clk_satr = reg_read(DEVICE_SAMPLE_AT_RESET2_REG); if (((ref_clk_satr >> DEVICE_SAMPLE_AT_RESET2_REG_REFCLK_OFFSET) & 0x1) == DEVICE_SAMPLE_AT_RESET2_REG_REFCLK_25MHZ) - divider = a38x_vco_freq_per_sar_ref_clk_25_mhz[sar_val] / freq; + cpu_freq = a38x_vco_freq_per_sar_ref_clk_25_mhz[sar_val]; else - divider = a38x_vco_freq_per_sar_ref_clk_40_mhz[sar_val] / freq; + cpu_freq = a38x_vco_freq_per_sar_ref_clk_40_mhz[sar_val]; - if ((async_mode_at_tf == 1) && (freq > 400)) { + divider = cpu_freq / ddr_freq; + + if (((cpu_freq % ddr_freq != 0) || (divider != 2 && divider != 3)) && + (ddr_freq > 400)) { /* Set async mode */ dunit_write(0x20220, 0x1000, 0x1000); dunit_write(0xe42f4, 0x200, 0x200); @@ -869,8 +871,6 @@ int ddr3_tip_ext_write(u32 dev_num, u32 if_id, u32 reg_addr, int mv_ddr_early_init(void) { - struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); - /* FIXME: change this configuration per ddr type * configure a380 and a390 to work with receiver odt timing * the odt_config is defined: @@ -882,9 +882,6 @@ int mv_ddr_early_init(void) mv_ddr_sw_db_init(0, 0); - if (tm->interface_params[0].memory_freq != MV_DDR_FREQ_SAR) - async_mode_at_tf = 1; - return MV_OK; } From 28c1922675715c38abeef8627bdf26a48de8be02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Tue, 4 Jan 2022 16:14:54 +0100 Subject: [PATCH 15/38] board: gdsys: Drop Dirk Eibach from MAINTAINERS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I got an : host mxlb.ispgateway.de[80.67.18.126] said: 554 Sorry, no mailbox here by that name. (in reply to RCPT TO command) when sending e-mail to dirk.eibach@gdsys.cc. Drop Dirk Eibach from MAINTAINERS of board/gdsys/a38x and board/gdsys/mpc8308. The latter would be left maintainerless, add Mario Six (he is also maintainer of the former board). Signed-off-by: Marek Behún Reviewed-by: Stefan Roese --- board/gdsys/a38x/MAINTAINERS | 1 - board/gdsys/mpc8308/MAINTAINERS | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/board/gdsys/a38x/MAINTAINERS b/board/gdsys/a38x/MAINTAINERS index d31e675ddc..6492e79541 100644 --- a/board/gdsys/a38x/MAINTAINERS +++ b/board/gdsys/a38x/MAINTAINERS @@ -1,5 +1,4 @@ A38X BOARD -M: Dirk Eibach M: Mario Six S: Maintained F: board/gdsys/a38x/ diff --git a/board/gdsys/mpc8308/MAINTAINERS b/board/gdsys/mpc8308/MAINTAINERS index dc0b389f73..57faba4695 100644 --- a/board/gdsys/mpc8308/MAINTAINERS +++ b/board/gdsys/mpc8308/MAINTAINERS @@ -1,5 +1,5 @@ MPC8308 BOARD -M: Dirk Eibach +M: Mario Six S: Maintained F: board/gdsys/mpc8308/ F: include/configs/gazerbeam.h From 3fc92a215b69ad448c151489228eb340df9a8703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Wed, 12 Jan 2022 17:06:59 +0100 Subject: [PATCH 16/38] ddr: marvell: a38x: fix SPLIT_OUT_MIX state decision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a cleaned up and fixed version of a patch mv_ddr: a380: fix SPLIT_OUT_MIX state decision in each pattern cycle the bus state can be changed in order to avoide it, need to back to the same bus state on each pattern cycle by Moti Boskula The original patch is not in Marvell's mv-ddr-marvell repository. It was gives to us by Marvell to fix an issues with DDR training on some boards, but it cannot be applied as is to mv-ddr-marvell, because it is a very dirty draft patch that would certainly break other things, mainly DDR4 training code in mv-ddr-marvell, since it changes common functions. I have cleaned up the patch and removed stuff that seemed unnecessary (when removed, it still fixed things). Note that I don't understand completely what the code does exactly, since I haven't studied the DDR training code extensively (and I suspect that no one besides some few people in Marvell understand the code completely). Anyway after the cleanup the patch still fixes isssues with DDR training on the failing boards. There was also a problem with the original patch on some of the Allied Telesis' x530 boards, reported by Chris Packham. I have asked Chris to send me some logs, and managed to fix it: - if you look at the change, you'll notice that it introduces subtraction of cur_start_win[] and cur_end_win[] members, depending on a bit set in the current_byte_status variable - the original patch subtracted cur_start_win[] if either BYTE_SPLIT_OUT_MIX or BYTE_HOMOGENEOUS_SPLIT_OUT bits were set, but subtracted cur_end_win[] only if the first one (BYTE_SPLIT_OUT_MIX) was set - from Chris Packham logs I discovered that the x530 board where the original patch introduced DDR training failure, only the BYTE_HOMOGENEOUS_SPLIT_OUT bit was set, and on our boards where the patch is needed only the BYTE_SPLIT_OUT_MIX is set in the current_byte_status variable - this led me to the hypothesis that both cur_start_win[] and cur_end_win[] should be subtracted only if BYTE_SPLIT_OUT_MIX bit is set, the BYTE_HOMOGENEOUS_SPLIT_OUT bit shouldn't be considered at all - this hypothesis also gains credibility when considering the commit title ("fix SPLIT_OUT_MIX state decision") Hopefully this will fix things without breaking anything else. Signed-off-by: Marek Behún Reviewed-by: Stefan Roese Tested-by: Chris Packham --- .../a38x/ddr3_training_centralization.c | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/ddr/marvell/a38x/ddr3_training_centralization.c b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c index 648b37ef6f..42308b6965 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_centralization.c +++ b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c @@ -55,6 +55,7 @@ static int ddr3_tip_centralization(u32 dev_num, u32 mode) enum hws_training_ip_stat training_result[MAX_INTERFACE_NUM]; u32 if_id, pattern_id, bit_id; u8 bus_id; + u8 current_byte_status; u8 cur_start_win[BUS_WIDTH_IN_BITS]; u8 centralization_result[MAX_INTERFACE_NUM][BUS_WIDTH_IN_BITS]; u8 cur_end_win[BUS_WIDTH_IN_BITS]; @@ -166,6 +167,10 @@ static int ddr3_tip_centralization(u32 dev_num, u32 mode) result[search_dir_id][7])); } + current_byte_status = + mv_ddr_tip_sub_phy_byte_status_get(if_id, + bus_id); + for (bit_id = 0; bit_id < BUS_WIDTH_IN_BITS; bit_id++) { /* check if this code is valid for 2 edge, probably not :( */ @@ -174,11 +179,32 @@ static int ddr3_tip_centralization(u32 dev_num, u32 mode) [HWS_LOW2HIGH] [bit_id], EDGE_1); + if (current_byte_status & + BYTE_SPLIT_OUT_MIX) { + if (cur_start_win[bit_id] >= 64) + cur_start_win[bit_id] -= 64; + else + cur_start_win[bit_id] = 0; + DEBUG_CENTRALIZATION_ENGINE + (DEBUG_LEVEL_INFO, + ("pattern %d IF %d pup %d bit %d subtract 64 adll from start\n", + pattern_id, if_id, bus_id, bit_id)); + } cur_end_win[bit_id] = GET_TAP_RESULT(result [HWS_HIGH2LOW] [bit_id], EDGE_1); + if (cur_end_win[bit_id] >= 64 && + (current_byte_status & + BYTE_SPLIT_OUT_MIX)) { + cur_end_win[bit_id] -= 64; + DEBUG_CENTRALIZATION_ENGINE + (DEBUG_LEVEL_INFO, + ("pattern %d IF %d pup %d bit %d subtract 64 adll from end\n", + pattern_id, if_id, bus_id, bit_id)); + } + /* window length */ current_window[bit_id] = cur_end_win[bit_id] - From 6eb20bbff38581c0bef00027937d510fe540c8c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:35 +0100 Subject: [PATCH 17/38] tools: kwbimage: Mark all local functions as static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark all local functions as static. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwbimage.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 224d8156be..b0598cab4b 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -199,7 +199,7 @@ static const char *image_boot_mode_name(unsigned int id) return NULL; } -int image_boot_mode_id(const char *boot_mode_name) +static int image_boot_mode_id(const char *boot_mode_name) { int i; @@ -210,7 +210,7 @@ int image_boot_mode_id(const char *boot_mode_name) return -1; } -int image_nand_ecc_mode_id(const char *nand_ecc_mode_name) +static int image_nand_ecc_mode_id(const char *nand_ecc_mode_name) { int i; @@ -602,7 +602,8 @@ static int kwb_export_pubkey(RSA *key, struct pubkey_der_v1 *dst, FILE *hashf, return 0; } -int kwb_sign(RSA *key, void *data, int datasz, struct sig_v1 *sig, char *signame) +static int kwb_sign(RSA *key, void *data, int datasz, struct sig_v1 *sig, + char *signame) { EVP_PKEY *evp_key; EVP_MD_CTX *ctx; @@ -662,8 +663,8 @@ err_key: return ret; } -int kwb_verify(RSA *key, void *data, int datasz, struct sig_v1 *sig, - char *signame) +static int kwb_verify(RSA *key, void *data, int datasz, struct sig_v1 *sig, + char *signame) { EVP_PKEY *evp_key; EVP_MD_CTX *ctx; @@ -722,8 +723,8 @@ err_key: return ret; } -int kwb_sign_and_verify(RSA *key, void *data, int datasz, struct sig_v1 *sig, - char *signame) +static int kwb_sign_and_verify(RSA *key, void *data, int datasz, + struct sig_v1 *sig, char *signame) { if (kwb_sign(key, data, datasz, sig, signame) < 0) return -1; @@ -735,7 +736,7 @@ int kwb_sign_and_verify(RSA *key, void *data, int datasz, struct sig_v1 *sig, } -int kwb_dump_fuse_cmds_38x(FILE *out, struct secure_hdr_v1 *sec_hdr) +static int kwb_dump_fuse_cmds_38x(FILE *out, struct secure_hdr_v1 *sec_hdr) { struct hash_v1 kak_pub_hash; struct image_cfg_element *e; @@ -1051,9 +1052,9 @@ static size_t image_headersz_v1(int *hasext) return image_headersz_align(headersz, image_get_bootfrom()); } -int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext, - struct image_cfg_element *binarye, - struct main_hdr_v1 *main_hdr) +static int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext, + struct image_cfg_element *binarye, + struct main_hdr_v1 *main_hdr) { struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)*cur; uint32_t add_args; @@ -1135,7 +1136,7 @@ err_close: return -1; } -int export_pub_kak_hash(RSA *kak, struct secure_hdr_v1 *secure_hdr) +static int export_pub_kak_hash(RSA *kak, struct secure_hdr_v1 *secure_hdr) { FILE *hashf; int res; @@ -1154,8 +1155,8 @@ int export_pub_kak_hash(RSA *kak, struct secure_hdr_v1 *secure_hdr) return res < 0 ? 1 : 0; } -int kwb_sign_csk_with_kak(struct image_tool_params *params, - struct secure_hdr_v1 *secure_hdr, RSA *csk) +static int kwb_sign_csk_with_kak(struct image_tool_params *params, + struct secure_hdr_v1 *secure_hdr, RSA *csk) { RSA *kak = NULL; RSA *kak_pub = NULL; @@ -1196,9 +1197,9 @@ int kwb_sign_csk_with_kak(struct image_tool_params *params, return 0; } -int add_secure_header_v1(struct image_tool_params *params, uint8_t *ptr, - int payloadsz, size_t headersz, uint8_t *image, - struct secure_hdr_v1 *secure_hdr) +static int add_secure_header_v1(struct image_tool_params *params, uint8_t *ptr, + int payloadsz, size_t headersz, uint8_t *image, + struct secure_hdr_v1 *secure_hdr) { struct image_cfg_element *e_jtagdelay; struct image_cfg_element *e_boxid; @@ -1415,7 +1416,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, return image; } -int recognize_keyword(char *keyword) +static int recognize_keyword(char *keyword) { int kw_id; From 9ac1def0207c0b3e01eee203b138fba4ca299ef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:36 +0100 Subject: [PATCH 18/38] tools: kwbimage: Deduplicate v1 regtype header finishing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deduplicate code that finishes OPT_HDR_V1_REGISTER_TYPE header by extracing it into separate function. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwbimage.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index b0598cab4b..552fef9e9a 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -1249,6 +1249,22 @@ static int add_secure_header_v1(struct image_tool_params *params, uint8_t *ptr, return 0; } +static void finish_register_set_header_v1(uint8_t **cur, uint8_t **next_ext, + struct register_set_hdr_v1 *register_set_hdr, + int *datai, uint8_t delay) +{ + int size = sizeof(struct register_set_hdr_v1) + 8 * (*datai) + 4; + + register_set_hdr->headertype = OPT_HDR_V1_REGISTER_TYPE; + register_set_hdr->headersz_lsb = cpu_to_le16(size & 0xFFFF); + register_set_hdr->headersz_msb = size >> 16; + register_set_hdr->data[*datai].last_entry.delay = delay; + *cur += size; + **next_ext = 1; + *next_ext = ®ister_set_hdr->data[*datai].last_entry.next; + *datai = 0; +} + static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, uint8_t *ptr, int payloadsz) { @@ -1261,7 +1277,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, uint8_t *image, *cur; int hasext = 0; uint8_t *next_ext = NULL; - int cfgi, datai, size; + int cfgi, datai; /* * Calculate the size of the header and the size of the @@ -1359,15 +1375,8 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, e->type != IMAGE_CFG_DATA_DELAY) continue; if (e->type == IMAGE_CFG_DATA_DELAY) { - size = sizeof(struct register_set_hdr_v1) + 8 * datai + 4; - register_set_hdr->headertype = OPT_HDR_V1_REGISTER_TYPE; - register_set_hdr->headersz_lsb = cpu_to_le16(size & 0xFFFF); - register_set_hdr->headersz_msb = size >> 16; - register_set_hdr->data[datai].last_entry.delay = e->regdata_delay; - cur += size; - *next_ext = 1; - next_ext = ®ister_set_hdr->data[datai].last_entry.next; - datai = 0; + finish_register_set_header_v1(&cur, &next_ext, register_set_hdr, + &datai, e->regdata_delay); continue; } register_set_hdr->data[datai].entry.address = @@ -1377,15 +1386,9 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, datai++; } if (datai != 0) { - size = sizeof(struct register_set_hdr_v1) + 8 * datai + 4; - register_set_hdr->headertype = OPT_HDR_V1_REGISTER_TYPE; - register_set_hdr->headersz_lsb = cpu_to_le16(size & 0xFFFF); - register_set_hdr->headersz_msb = size >> 16; - /* Set delay to the smallest possible value 1ms. */ - register_set_hdr->data[datai].last_entry.delay = 1; - cur += size; - *next_ext = 1; - next_ext = ®ister_set_hdr->data[datai].last_entry.next; + /* Set delay to the smallest possible value. */ + finish_register_set_header_v1(&cur, &next_ext, register_set_hdr, + &datai, REGISTER_SET_HDR_OPT_DELAY_MS(0)); } for (cfgi = 0; cfgi < cfgn; cfgi++) { From d737d5d2c1e9aaea830c1cc469091ed9c13b2b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:37 +0100 Subject: [PATCH 19/38] tools: kwbimage: Fix generating image with multiple DATA_DELAY commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Register set header consists of sequence of DATA commands followed by exactly one DATA_DELAY command. Thus if we are generating image with multiple DATA_DELAY commands, we need to create more register set headers. Fix calculation of image size with multiple DATA_DELAY commands and correctly set pointer to struct register_set_hdr_v1 when initializing new register set header. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwbimage.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 552fef9e9a..6ee3d0aaa8 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -993,7 +993,7 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params, static size_t image_headersz_v1(int *hasext) { - struct image_cfg_element *binarye; + struct image_cfg_element *binarye, *e; unsigned int count; size_t headersz; int cfgi; @@ -1010,7 +1010,18 @@ static size_t image_headersz_v1(int *hasext) *hasext = 1; } - count = image_count_options(IMAGE_CFG_DATA); + count = 0; + for (cfgi = 0; cfgi < cfgn; cfgi++) { + e = &image_cfg[cfgi]; + + if (e->type == IMAGE_CFG_DATA) + count++; + + if (e->type == IMAGE_CFG_DATA_DELAY) { + headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4; + count = 0; + } + } if (count > 0) headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4; @@ -1368,12 +1379,13 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, } datai = 0; - register_set_hdr = (struct register_set_hdr_v1 *)cur; for (cfgi = 0; cfgi < cfgn; cfgi++) { e = &image_cfg[cfgi]; if (e->type != IMAGE_CFG_DATA && e->type != IMAGE_CFG_DATA_DELAY) continue; + if (datai == 0) + register_set_hdr = (struct register_set_hdr_v1 *)cur; if (e->type == IMAGE_CFG_DATA_DELAY) { finish_register_set_header_v1(&cur, &next_ext, register_set_hdr, &datai, e->regdata_delay); From 3db9c417688f0f6f2239c52ca6f847f3db5ec23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:38 +0100 Subject: [PATCH 20/38] tools: kwbimage: Preserve order of BINARY, DATA and DATA_DELAY commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preserve the order of BINARY, DATA and DATA_DELAY commands as they appear in the input file. They may depend on each other. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwbimage.c | 58 +++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 6ee3d0aaa8..17d3c3cf22 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -1017,7 +1017,8 @@ static size_t image_headersz_v1(int *hasext) if (e->type == IMAGE_CFG_DATA) count++; - if (e->type == IMAGE_CFG_DATA_DELAY) { + if (e->type == IMAGE_CFG_DATA_DELAY || + (e->type == IMAGE_CFG_BINARY && count > 0)) { headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4; count = 0; } @@ -1289,6 +1290,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, int hasext = 0; uint8_t *next_ext = NULL; int cfgi, datai; + uint8_t delay; /* * Calculate the size of the header and the size of the @@ -1382,34 +1384,50 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, for (cfgi = 0; cfgi < cfgn; cfgi++) { e = &image_cfg[cfgi]; if (e->type != IMAGE_CFG_DATA && - e->type != IMAGE_CFG_DATA_DELAY) + e->type != IMAGE_CFG_DATA_DELAY && + e->type != IMAGE_CFG_BINARY) continue; + if (datai == 0) register_set_hdr = (struct register_set_hdr_v1 *)cur; - if (e->type == IMAGE_CFG_DATA_DELAY) { + + /* If delay is not specified, use the smallest possible value. */ + if (e->type == IMAGE_CFG_DATA_DELAY) + delay = e->regdata_delay; + else + delay = REGISTER_SET_HDR_OPT_DELAY_MS(0); + + /* + * DATA_DELAY command is the last entry in the register set + * header and BINARY command inserts new binary header. + * Therefore BINARY command requires to finish register set + * header if some DATA command was specified. And DATA_DELAY + * command automatically finish register set header even when + * there was no DATA command. + */ + if (e->type == IMAGE_CFG_DATA_DELAY || + (e->type == IMAGE_CFG_BINARY && datai != 0)) finish_register_set_header_v1(&cur, &next_ext, register_set_hdr, - &datai, e->regdata_delay); - continue; + &datai, delay); + + if (e->type == IMAGE_CFG_DATA) { + register_set_hdr->data[datai].entry.address = + cpu_to_le32(e->regdata.raddr); + register_set_hdr->data[datai].entry.value = + cpu_to_le32(e->regdata.rdata); + datai++; + } + + if (e->type == IMAGE_CFG_BINARY) { + if (add_binary_header_v1(&cur, &next_ext, e, main_hdr)) + return NULL; } - register_set_hdr->data[datai].entry.address = - cpu_to_le32(e->regdata.raddr); - register_set_hdr->data[datai].entry.value = - cpu_to_le32(e->regdata.rdata); - datai++; } if (datai != 0) { /* Set delay to the smallest possible value. */ + delay = REGISTER_SET_HDR_OPT_DELAY_MS(0); finish_register_set_header_v1(&cur, &next_ext, register_set_hdr, - &datai, REGISTER_SET_HDR_OPT_DELAY_MS(0)); - } - - for (cfgi = 0; cfgi < cfgn; cfgi++) { - e = &image_cfg[cfgi]; - if (e->type != IMAGE_CFG_BINARY) - continue; - - if (add_binary_header_v1(&cur, &next_ext, e, main_hdr)) - return NULL; + &datai, delay); } if (secure_hdr && add_secure_header_v1(params, ptr, payloadsz + headersz, From 6329d4402e06529f9c2aaa6d76a4869a20ed7afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:39 +0100 Subject: [PATCH 21/38] arm: mvebu: Generate kwbimage.cfg with $(call cmd, ...) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Usage of $(call cmd,...) is standard way to call other commands which generate things. It also has the advantage of printing build information in the form KWBCFG arch/arm/mach-mvebu/kwbimage.cfg if verbosity is disabled, and printing the build command otherwise. Note that the '#' character needs to be escaped in Makefile when used as value for make variable assignment. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 0b2c57e573..8066d827b0 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -59,10 +59,13 @@ KWB_REPLACE += SEC_FUSE_DUMP KWB_CFG_SEC_FUSE_DUMP = a38x endif +quiet_cmd_kwbcfg = KWBCFG $@ +cmd_kwbcfg = sed -ne '$(foreach V,$(KWB_REPLACE),s/^\#@$(V)/$(V) $(KWB_CFG_$(V))/;)p' \ + <$< >$(dir $@)$(@F) + $(obj)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \ include/config/auto.conf - $(Q)sed -ne '$(foreach V,$(KWB_REPLACE),s/^#@$(V)/$(V) $(KWB_CFG_$(V))/;)p' \ - <$< >$(dir $@)$(@F) + $(call cmd,kwbcfg) endif # CONFIG_SPL_BUILD obj-y += gpio.o From af49605b955f32b027221ef106c04b44a43ad298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:40 +0100 Subject: [PATCH 22/38] tools: kwbimage: Add support for specifying CPU core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For other changes it is required to know if CPU core is Sheeva or not. Therefore add a new command CPU for specifying CPU. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- tools/kwbimage.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 17d3c3cf22..44843be2c1 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -99,6 +99,7 @@ enum image_cfg_type { IMAGE_CFG_NAND_BADBLK_LOCATION, IMAGE_CFG_NAND_ECC_MODE, IMAGE_CFG_NAND_PAGESZ, + IMAGE_CFG_CPU, IMAGE_CFG_BINARY, IMAGE_CFG_DATA, IMAGE_CFG_DATA_DELAY, @@ -129,6 +130,7 @@ static const char * const id_strs[] = { [IMAGE_CFG_NAND_BADBLK_LOCATION] = "NAND_BADBLK_LOCATION", [IMAGE_CFG_NAND_ECC_MODE] = "NAND_ECC_MODE", [IMAGE_CFG_NAND_PAGESZ] = "NAND_PAGE_SIZE", + [IMAGE_CFG_CPU] = "CPU", [IMAGE_CFG_BINARY] = "BINARY", [IMAGE_CFG_DATA] = "DATA", [IMAGE_CFG_DATA_DELAY] = "DATA_DELAY", @@ -152,6 +154,7 @@ struct image_cfg_element { enum image_cfg_type type; union { unsigned int version; + unsigned int cpu_sheeva; unsigned int bootfrom; struct { const char *file; @@ -280,6 +283,17 @@ static int image_get_bootfrom(void) return e->bootfrom; } +static int image_is_cpu_sheeva(void) +{ + struct image_cfg_element *e; + + e = image_find_option(IMAGE_CFG_CPU); + if (!e) + return 0; + + return e->cpu_sheeva; +} + /* * Compute a 8-bit checksum of a memory area. This algorithm follows * the requirements of the Marvell SoC BootROM specifications. @@ -1489,6 +1503,18 @@ static int image_create_config_parse_oneline(char *line, case IMAGE_CFG_VERSION: el->version = atoi(value1); break; + case IMAGE_CFG_CPU: + if (strcmp(value1, "FEROCEON") == 0) + el->cpu_sheeva = 0; + else if (strcmp(value1, "SHEEVA") == 0) + el->cpu_sheeva = 1; + else if (strcmp(value1, "A9") == 0) + el->cpu_sheeva = 0; + else { + fprintf(stderr, "Invalid CPU %s\n", value1); + return -1; + } + break; case IMAGE_CFG_BOOT_FROM: ret = image_boot_mode_id(value1); From 0aca27ea185188a50292dd5bcec07fef020d10e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:41 +0100 Subject: [PATCH 23/38] tools: kwbimage: Add support for specifying LOAD_ADDRESS for BINARY command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ARM executable code included in kwbimage binary header, which is not position independent, needs to be loaded and executed by BootROM at the correct fixed address. Armada BootROMs load kwbimage header (in which the executable code is also stored) at fixed address 0x40004000 or 0x40000000 which is mapped to L2-SRAM (L2 Cache as SRAM). Address 0x40004000 is used on Armada platforms with Sheeva CPU core (A370 and AXP) where BootROM uses MMU with 0x4000 bytes for MMU translation table. Address 0x40000000 is used on all other platforms. Thus the only way to specify load and execute address of this executable code in binary kwbimage header is by filling dummy arguments into the binary header, using the same mechanism we already have for achieving 128-bit boundary alignment on A370 and AXP SoCs. Extend kwbimage config file parser to allow to specify load address as part of BINARY command with syntax: BINARY path_to_binary arg1 arg2 ... argN LOAD_ADDRESS address If the specified load address is invalid or cannot be used, mkimage will throw fatal error and exit. This will prevent generating kwbimage with invalid load address for non-position independent binary code. If no load address is specified, kwbimage will not fill any the dummy arguments, thus it will behave the same as before this change. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwbimage.c | 109 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 93 insertions(+), 16 deletions(-) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 44843be2c1..c0f1bdac02 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -158,6 +158,7 @@ struct image_cfg_element { unsigned int bootfrom; struct { const char *file; + unsigned int loadaddr; unsigned int args[BINARY_MAX_ARGS]; unsigned int nargs; } binary; @@ -1007,10 +1008,13 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params, static size_t image_headersz_v1(int *hasext) { - struct image_cfg_element *binarye, *e; + struct image_cfg_element *e; unsigned int count; size_t headersz; + int cpu_sheeva; + struct stat s; int cfgi; + int ret; /* * Calculate the size of the header and the size of the @@ -1024,6 +1028,8 @@ static size_t image_headersz_v1(int *hasext) *hasext = 1; } + cpu_sheeva = image_is_cpu_sheeva(); + count = 0; for (cfgi = 0; cfgi < cfgn; cfgi++) { e = &image_cfg[cfgi]; @@ -1036,19 +1042,11 @@ static size_t image_headersz_v1(int *hasext) headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4; count = 0; } - } - if (count > 0) - headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4; - for (cfgi = 0; cfgi < cfgn; cfgi++) { - int ret; - struct stat s; - - binarye = &image_cfg[cfgi]; - if (binarye->type != IMAGE_CFG_BINARY) + if (e->type != IMAGE_CFG_BINARY) continue; - ret = stat(binarye->binary.file, &s); + ret = stat(e->binary.file, &s); if (ret < 0) { char cwd[PATH_MAX]; char *dir = cwd; @@ -1063,18 +1061,58 @@ static size_t image_headersz_v1(int *hasext) "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n" "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n" "image for your board. Use 'dumpimage -T kwbimage -p 0' to extract it from an existing image.\n", - binarye->binary.file, dir); + e->binary.file, dir); return 0; } headersz += sizeof(struct opt_hdr_v1) + sizeof(uint32_t) + - (binarye->binary.nargs) * sizeof(uint32_t); - headersz = ALIGN(headersz, 16); + (e->binary.nargs) * sizeof(uint32_t); + + if (e->binary.loadaddr) { + /* + * BootROM loads kwbimage header (in which the + * executable code is also stored) to address + * 0x40004000 or 0x40000000. Thus there is + * restriction for the load address of the N-th + * BINARY image. + */ + unsigned int base_addr, low_addr, high_addr; + + base_addr = cpu_sheeva ? 0x40004000 : 0x40000000; + low_addr = base_addr + headersz; + high_addr = low_addr + + (BINARY_MAX_ARGS - e->binary.nargs) * sizeof(uint32_t); + + if (cpu_sheeva && e->binary.loadaddr % 16) { + fprintf(stderr, + "Invalid LOAD_ADDRESS 0x%08x for BINARY %s with %d args.\n" + "Address for CPU SHEEVA must be 16-byte aligned.\n", + e->binary.loadaddr, e->binary.file, e->binary.nargs); + return 0; + } + + if (e->binary.loadaddr % 4 || e->binary.loadaddr < low_addr || + e->binary.loadaddr > high_addr) { + fprintf(stderr, + "Invalid LOAD_ADDRESS 0x%08x for BINARY %s with %d args.\n" + "Address must be 4-byte aligned and in range 0x%08x-0x%08x.\n", + e->binary.loadaddr, e->binary.file, + e->binary.nargs, low_addr, high_addr); + return 0; + } + headersz = e->binary.loadaddr - base_addr; + } else { + headersz = ALIGN(headersz, 16); + } + headersz += ALIGN(s.st_size, 4) + sizeof(uint32_t); if (hasext) *hasext = 1; } + if (count > 0) + headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4; + return image_headersz_align(headersz, image_get_bootfrom()); } @@ -1083,10 +1121,12 @@ static int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext, struct main_hdr_v1 *main_hdr) { struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)*cur; + uint32_t base_addr; uint32_t add_args; uint32_t offset; uint32_t *args; size_t binhdrsz; + int cpu_sheeva; struct stat s; int argi; FILE *bin; @@ -1120,11 +1160,18 @@ static int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext, /* * ARM executable code inside the BIN header on some mvebu platforms * (e.g. A370, AXP) must always be aligned with the 128-bit boundary. + * In the case when this code is not position independent (e.g. ARM + * SPL), it must be placed at fixed load and execute address. * This requirement can be met by inserting dummy arguments into * BIN header, if needed. */ + cpu_sheeva = image_is_cpu_sheeva(); + base_addr = cpu_sheeva ? 0x40004000 : 0x40000000; offset = *cur - (uint8_t *)main_hdr; - add_args = ((16 - offset % 16) % 16) / sizeof(uint32_t); + if (binarye->binary.loadaddr) + add_args = (binarye->binary.loadaddr - base_addr - offset) / sizeof(uint32_t); + else + add_args = ((16 - offset % 16) % 16) / sizeof(uint32_t); if (add_args) { *(args - 1) = cpu_to_le32(binarye->binary.nargs + add_args); *cur += add_args * sizeof(uint32_t); @@ -1548,10 +1595,40 @@ static int image_create_config_parse_oneline(char *line, el->binary.file = strdup(value1); while (1) { char *value = strtok_r(NULL, delimiters, &saveptr); + char *endptr; if (!value) break; - el->binary.args[argi] = strtoul(value, NULL, 16); + + if (!strcmp(value, "LOAD_ADDRESS")) { + value = strtok_r(NULL, delimiters, &saveptr); + if (!value) { + fprintf(stderr, + "Missing address argument for BINARY LOAD_ADDRESS\n"); + return -1; + } + el->binary.loadaddr = strtoul(value, &endptr, 16); + if (*endptr) { + fprintf(stderr, + "Invalid argument '%s' for BINARY LOAD_ADDRESS\n", + value); + return -1; + } + value = strtok_r(NULL, delimiters, &saveptr); + if (value) { + fprintf(stderr, + "Unexpected argument '%s' after BINARY LOAD_ADDRESS\n", + value); + return -1; + } + break; + } + + el->binary.args[argi] = strtoul(value, &endptr, 16); + if (*endptr) { + fprintf(stderr, "Invalid argument '%s' for BINARY\n", value); + return -1; + } argi++; if (argi >= BINARY_MAX_ARGS) { fprintf(stderr, From 252e7c3a24fefdf88dfa3fff87e8dc4d0c7aa9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:42 +0100 Subject: [PATCH 24/38] tools: kwbimage: Check the return value of image_headersz_v1() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function image_headersz_v1() may return zero on fatal errors. In this case the function already printed an error message. Check the return value of image_headersz_v1() in kwbimage_generate(), and exit on zero value with EXIT_FAILURE. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwbimage.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index c0f1bdac02..a5b518f60b 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -2029,6 +2029,10 @@ static int kwbimage_generate(struct image_tool_params *params, case 1: alloc_len = image_headersz_v1(NULL); + if (!alloc_len) { + free(image_cfg); + exit(EXIT_FAILURE); + } break; default: From 78d997f98bc049bf62c8f4c3e39a30fdbdef2fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:43 +0100 Subject: [PATCH 25/38] tools: kwbimage: Check for maximal kwbimage header size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BootROM loads kwbimage header to L2-SRAM and BootROM reserve only 192 kB for it. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- tools/kwbimage.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index a5b518f60b..ce053a4a5a 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -2033,6 +2033,11 @@ static int kwbimage_generate(struct image_tool_params *params, free(image_cfg); exit(EXIT_FAILURE); } + if (alloc_len > 192*1024) { + fprintf(stderr, "Header is too big (%u bytes), maximal kwbimage header size is %u bytes\n", alloc_len, 192*1024); + free(image_cfg); + exit(EXIT_FAILURE); + } break; default: From 29c6a9c7638c776a291976c1d9d4a91f3e92d363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:44 +0100 Subject: [PATCH 26/38] arm: mvebu: Set CPU for U-Boot SPL binary in kwbimage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kwbimage needs to know CPU type, so set it in kwbimage config file. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/Makefile | 8 ++++++++ arch/arm/mach-mvebu/kwbimage.cfg.in | 3 +++ 2 files changed, 11 insertions(+) diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 8066d827b0..82a366ad0f 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -31,6 +31,14 @@ obj-$(CONFIG_MVEBU_EFUSE) += efuse.o extra-y += kwbimage.cfg +ifneq ($(CONFIG_ARMADA_370)$(CONFIG_ARMADA_XP),) + KWB_REPLACE += CPU + KWB_CFG_CPU = SHEEVA +else ifneq ($(CONFIG_ARMADA_375)$(CONFIG_ARMADA_38X)$(CONFIG_ARMADA_39X),) + KWB_REPLACE += CPU + KWB_CFG_CPU = A9 +endif + KWB_REPLACE += BOOT_FROM ifneq ($(CONFIG_MVEBU_SPL_BOOT_DEVICE_SPI),) KWB_CFG_BOOT_FROM=spi diff --git a/arch/arm/mach-mvebu/kwbimage.cfg.in b/arch/arm/mach-mvebu/kwbimage.cfg.in index 049d23c6ef..8e720daf48 100644 --- a/arch/arm/mach-mvebu/kwbimage.cfg.in +++ b/arch/arm/mach-mvebu/kwbimage.cfg.in @@ -5,6 +5,9 @@ # Armada 38x uses version 1 image format VERSION 1 +# Type of the CPU core +#@CPU + # Boot Media configurations #@BOOT_FROM From a2b1db41cf0d21e8fca56d403f0d7834afe3a3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:45 +0100 Subject: [PATCH 27/38] arm: mvebu: Correctly set LOAD_ADDRESS for U-Boot SPL binary in kwbimage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit U-Boot SPL for mvebu platform is not compiled as position independent. Therefore it is required to instruct BootROM to load U-Boot SPL at the correct address. Loading of kwbimage binary code at specific address can be now achieved by the new LOAD_ADDRESS token as part of BINARY command in kwbimage config file. Update mvebu Makefile to put value of $(CONFIG_SPL_TEXT_BASE) into LOAD_ADDRESS token when generating kwbimage.cfg from kwbimage.cfg.in. It is required to update regex for sed to find replacement tokens at any position on a line in kwbimage config file and not only at the beginning of the line. This is because LOAD_ADDRESS is specified at the end of line containing the BINARY command. It looks like all Armada boards set CONFIG_SPL_TEXT_BASE to value 0x40004030 or 0x40000030. Why this value? It is because main kwbimage header is at address 0x40004030 or 0x40000000 and it is 32 bytes long. After the main header there is the binary header, which consist of 1 byte for type, 3 bytes for size, 1 byte for number of arguments, 3 reserved bytes and then 4 bytes for each argument. After these arguments comes the executable code. So arguments start at address 0x40004028 or 0x40000028. Before commit e6571f38c943 ("arm: mvebu: Remove dummy BIN header arguments for SPL binary") there were two (dummy) arguments, which resulted in load address of 0x40004030 or 0x40000030, always. After that commit (which removed dummy arguments), load address stayed same due to the 128-bit alignment done by mkimage. This patch now reflects the dependency between $(CONFIG_SPL_TEXT_BASE), load address and dummy kwbimage arguments, and allows the user to adjust $(CONFIG_SPL_TEXT_BASE) config option to some other value. For unsupported values, when mkimage/kwbimage cannot set chosen load address as specified by $(CONFIG_SPL_TEXT_BASE), the build process now fails, instead of silently generating non-working kwbimage. Removal of this alignment between $(CONFIG_SPL_TEXT_BASE) and LOAD_ADDRESS can only be done by compiling U-Boot SPL as position independent. But this currently is not possible for 32-bit ARM version of U-Boot SPL. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/Makefile | 5 ++++- arch/arm/mach-mvebu/kwbimage.cfg.in | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 82a366ad0f..799935ce0b 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -39,6 +39,9 @@ else ifneq ($(CONFIG_ARMADA_375)$(CONFIG_ARMADA_38X)$(CONFIG_ARMADA_39X),) KWB_CFG_CPU = A9 endif +KWB_REPLACE += LOAD_ADDRESS +KWB_CFG_LOAD_ADDRESS = $(CONFIG_SPL_TEXT_BASE) + KWB_REPLACE += BOOT_FROM ifneq ($(CONFIG_MVEBU_SPL_BOOT_DEVICE_SPI),) KWB_CFG_BOOT_FROM=spi @@ -68,7 +71,7 @@ KWB_CFG_SEC_FUSE_DUMP = a38x endif quiet_cmd_kwbcfg = KWBCFG $@ -cmd_kwbcfg = sed -ne '$(foreach V,$(KWB_REPLACE),s/^\#@$(V)/$(V) $(KWB_CFG_$(V))/;)p' \ +cmd_kwbcfg = sed -ne '$(foreach V,$(KWB_REPLACE),s/\#@$(V)/$(V) $(KWB_CFG_$(V))/;)p' \ <$< >$(dir $@)$(@F) $(obj)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \ diff --git a/arch/arm/mach-mvebu/kwbimage.cfg.in b/arch/arm/mach-mvebu/kwbimage.cfg.in index 8e720daf48..603e886345 100644 --- a/arch/arm/mach-mvebu/kwbimage.cfg.in +++ b/arch/arm/mach-mvebu/kwbimage.cfg.in @@ -11,5 +11,5 @@ VERSION 1 # Boot Media configurations #@BOOT_FROM -# Binary Header (bin_hdr) with DDR3 training code -BINARY spl/u-boot-spl.bin +# Include U-Boot SPL with DDR3 training code into Binary Header +BINARY spl/u-boot-spl.bin #@LOAD_ADDRESS From bdf8c9f219af279cbf9e037318ba44ef3bef1d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:46 +0100 Subject: [PATCH 28/38] tools: kwbimage: Enforce 128-bit boundary alignment only for Sheeva CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This alignment is required only for platforms based on Sheeva CPU core which are A370 and AXP. Now when U-Boot build system correctly propagates LOAD_ADDRESS there is no need to have enabled 128-bit boundary alignment on platforms which do not need it. Previously it was required because load address was implicitly rounded to 128-bit boundary and U-Boot build system expected it and misused it. Now with explicit setting of LOAD_ADDRESS there is no guessing for load address anymore. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- tools/kwbimage.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index ce053a4a5a..7c2106006a 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -1101,8 +1101,10 @@ static size_t image_headersz_v1(int *hasext) return 0; } headersz = e->binary.loadaddr - base_addr; - } else { + } else if (cpu_sheeva) { headersz = ALIGN(headersz, 16); + } else { + headersz = ALIGN(headersz, 4); } headersz += ALIGN(s.st_size, 4) + sizeof(uint32_t); @@ -1158,8 +1160,8 @@ static int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext, *cur += (binarye->binary.nargs + 1) * sizeof(uint32_t); /* - * ARM executable code inside the BIN header on some mvebu platforms - * (e.g. A370, AXP) must always be aligned with the 128-bit boundary. + * ARM executable code inside the BIN header on platforms with Sheeva + * CPU (A370 and AXP) must always be aligned with the 128-bit boundary. * In the case when this code is not position independent (e.g. ARM * SPL), it must be placed at fixed load and execute address. * This requirement can be met by inserting dummy arguments into @@ -1170,8 +1172,10 @@ static int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext, offset = *cur - (uint8_t *)main_hdr; if (binarye->binary.loadaddr) add_args = (binarye->binary.loadaddr - base_addr - offset) / sizeof(uint32_t); - else + else if (cpu_sheeva) add_args = ((16 - offset % 16) % 16) / sizeof(uint32_t); + else + add_args = 0; if (add_args) { *(args - 1) = cpu_to_le32(binarye->binary.nargs + add_args); *cur += add_args * sizeof(uint32_t); From 18d85d6e8ad766de9dd35c4d5c0d984233fb9b21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:47 +0100 Subject: [PATCH 29/38] arm: mvebu: Enable BootROM output on A38x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BootROMs on pre-A38x SoCs enabled its output on UART by default, but A38x' BootROM has its output on UART disabled by default. To enable BootROM output on A38x SoC, it is required to set DEBUG flag (which only enables BootROM output and nothing more) in kwbimage. For UART images this DEBUG flag is ignored by BootROM. Enable kwbimage DEBUG flag for all A38x boards. With this change BootROM prints the following (success) information on UART before booting U-Boot kwbimage: BootROM - 1.73 Booting from SPI flash Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/Makefile | 7 +++++++ arch/arm/mach-mvebu/kwbimage.cfg.in | 3 +++ 2 files changed, 10 insertions(+) diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 799935ce0b..a5a20877dd 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -70,6 +70,13 @@ KWB_REPLACE += SEC_FUSE_DUMP KWB_CFG_SEC_FUSE_DUMP = a38x endif +ifdef CONFIG_ARMADA_38X +# BootROM output is by default enabled on pre-A38x and disabled on A38x +# DEBUG flag on A38x for non-UART boot source only enable BootROM output and nothing more +KWB_REPLACE += DEBUG +KWB_CFG_DEBUG = 1 +endif + quiet_cmd_kwbcfg = KWBCFG $@ cmd_kwbcfg = sed -ne '$(foreach V,$(KWB_REPLACE),s/\#@$(V)/$(V) $(KWB_CFG_$(V))/;)p' \ <$< >$(dir $@)$(@F) diff --git a/arch/arm/mach-mvebu/kwbimage.cfg.in b/arch/arm/mach-mvebu/kwbimage.cfg.in index 603e886345..ccb0997581 100644 --- a/arch/arm/mach-mvebu/kwbimage.cfg.in +++ b/arch/arm/mach-mvebu/kwbimage.cfg.in @@ -11,5 +11,8 @@ VERSION 1 # Boot Media configurations #@BOOT_FROM +# Enable BootROM output via DEBUG flag on SoCs which require it +#@DEBUG + # Include U-Boot SPL with DDR3 training code into Binary Header BINARY spl/u-boot-spl.bin #@LOAD_ADDRESS From fdcae2615639454f6c2b7c787de49e74e8746d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:48 +0100 Subject: [PATCH 30/38] tools: kwbimage: Add missing check for maximal value for DATA_DELAY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Data delay is stored as 8-bit number in kwbimage structure. Ensure the given value is at most 255. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwbimage.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 7c2106006a..2de8c371c1 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -1659,6 +1659,10 @@ static int image_create_config_parse_oneline(char *line, el->regdata_delay = REGISTER_SET_HDR_OPT_DELAY_SDRAM_SETUP; else el->regdata_delay = REGISTER_SET_HDR_OPT_DELAY_MS(strtoul(value1, NULL, 10)); + if (el->regdata_delay > 255) { + fprintf(stderr, "Maximal DATA_DELAY is 255\n"); + return -1; + } break; case IMAGE_CFG_BAUDRATE: el->baudrate = strtoul(value1, NULL, 10); From c934c9a66622c5a9054dc38765190c5c182caefb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:49 +0100 Subject: [PATCH 31/38] tools: kwbimage: Show binary image offset in mkimage -l, in addition to size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For debugging purposes it is good to know where the binary image would be loaded and also it is needed to know if printed size is image size or the size of header together with image. Make it unambiguous by showing that printed size is not the size of the whole header, but only the size of executable code, and print also the executable offset of this binary image. Load/execute address is the offset relative to the base address (either 0x40004000 or 0x40000000). Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- tools/kwbimage.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 2de8c371c1..d1fb67d3db 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -1872,9 +1872,12 @@ static void kwbimage_print_header(const void *ptr) for_each_opt_hdr_v1 (ohdr, mhdr) { if (ohdr->headertype == OPT_HDR_V1_BINARY_TYPE) { - printf("BIN Hdr Size: "); + printf("BIN Img Size: "); genimg_print_size(opt_hdr_v1_size(ohdr) - 12 - 4 * ohdr->data[0]); + printf("BIN Img Offs: %08x\n", + (unsigned)((uint8_t *)ohdr - (uint8_t *)mhdr) + + 8 + 4 * ohdr->data[0]); } } From 1a8e6b63e24f65b03a3997823bc4f55ecd8940ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:50 +0100 Subject: [PATCH 32/38] tools: kwbimage: Dump kwbimage config file on '-p -1' option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To regenerate kwbimage from existing image, it is needed to have kwbimage config file. Add a new option to generate kwbimage config file from existing kwbimage when '-p 1' option is given. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwbimage.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index d1fb67d3db..de7e9acf7f 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -214,6 +214,17 @@ static int image_boot_mode_id(const char *boot_mode_name) return -1; } +static const char *image_nand_ecc_mode_name(unsigned int id) +{ + int i; + + for (i = 0; nand_ecc_modes[i].name; i++) + if (nand_ecc_modes[i].id == id) + return nand_ecc_modes[i].name; + + return NULL; +} + static int image_nand_ecc_mode_id(const char *nand_ecc_mode_name) { int i; @@ -359,6 +370,29 @@ static uint32_t image_checksum32(void *start, uint32_t len) return csum; } +static unsigned int options_to_baudrate(uint8_t options) +{ + switch (options & 0x7) { + case MAIN_HDR_V1_OPT_BAUD_2400: + return 2400; + case MAIN_HDR_V1_OPT_BAUD_4800: + return 4800; + case MAIN_HDR_V1_OPT_BAUD_9600: + return 9600; + case MAIN_HDR_V1_OPT_BAUD_19200: + return 19200; + case MAIN_HDR_V1_OPT_BAUD_38400: + return 38400; + case MAIN_HDR_V1_OPT_BAUD_57600: + return 57600; + case MAIN_HDR_V1_OPT_BAUD_115200: + return 115200; + case MAIN_HDR_V1_OPT_BAUD_DEFAULT: + default: + return 0; + } +} + static uint8_t baudrate_to_option(unsigned int baudrate) { switch (baudrate) { @@ -2088,6 +2122,144 @@ static int kwbimage_generate(struct image_tool_params *params, return 4 + (4 - s.st_size % 4) % 4; } +static int kwbimage_generate_config(void *ptr, struct image_tool_params *params) +{ + struct main_hdr_v0 *mhdr0 = (struct main_hdr_v0 *)ptr; + struct main_hdr_v1 *mhdr = (struct main_hdr_v1 *)ptr; + size_t header_size = kwbheader_size(ptr); + struct register_set_hdr_v1 *regset_hdr; + struct ext_hdr_v0_reg *regdata; + struct ext_hdr_v0 *ehdr0; + struct opt_hdr_v1 *ohdr; + unsigned offset; + int cur_idx; + int version; + FILE *f; + int i; + + f = fopen(params->outfile, "w"); + if (!f) { + fprintf(stderr, "Can't open \"%s\": %s\n", params->outfile, strerror(errno)); + return -1; + } + + version = kwbimage_version(ptr); + + if (version != 0) + fprintf(f, "VERSION %d\n", version); + + fprintf(f, "BOOT_FROM %s\n", image_boot_mode_name(mhdr->blockid) ?: ""); + + if (version == 0 && mhdr->blockid == IBR_HDR_NAND_ID) + fprintf(f, "NAND_ECC_MODE %s\n", image_nand_ecc_mode_name(mhdr0->nandeccmode)); + + if (mhdr->blockid == IBR_HDR_NAND_ID) + fprintf(f, "NAND_PAGE_SIZE 0x%x\n", (unsigned)mhdr->nandpagesize); + + if (version != 0 && mhdr->blockid == IBR_HDR_NAND_ID) { + fprintf(f, "NAND_BLKSZ 0x%x\n", (unsigned)mhdr->nandblocksize); + fprintf(f, "NAND_BADBLK_LOCATION 0x%x\n", (unsigned)mhdr->nandbadblklocation); + } + + if (version == 0 && mhdr->blockid == IBR_HDR_SATA_ID) + fprintf(f, "SATA_PIO_MODE %u\n", (unsigned)mhdr0->satapiomode); + + /* + * Addresses and sizes which are specified by mkimage command line + * arguments and not in kwbimage config file + */ + + if (version != 0) + fprintf(f, "#HEADER_SIZE 0x%x\n", + ((unsigned)mhdr->headersz_msb << 8) | le16_to_cpu(mhdr->headersz_lsb)); + + fprintf(f, "#SRC_ADDRESS 0x%x\n", le32_to_cpu(mhdr->srcaddr)); + fprintf(f, "#BLOCK_SIZE 0x%x\n", le32_to_cpu(mhdr->blocksize)); + fprintf(f, "#DEST_ADDRESS 0x%08x\n", le32_to_cpu(mhdr->destaddr)); + fprintf(f, "#EXEC_ADDRESS 0x%08x\n", le32_to_cpu(mhdr->execaddr)); + + if (version != 0) { + if (options_to_baudrate(mhdr->options)) + fprintf(f, "BAUDRATE %u\n", options_to_baudrate(mhdr->options)); + if (options_to_baudrate(mhdr->options) || + ((mhdr->options >> 3) & 0x3) || ((mhdr->options >> 5) & 0x7)) { + fprintf(f, "UART_PORT %u\n", (unsigned)((mhdr->options >> 3) & 0x3)); + fprintf(f, "UART_MPP 0x%x\n", (unsigned)((mhdr->options >> 5) & 0x7)); + } + if (mhdr->flags & 0x1) + fprintf(f, "DEBUG 1\n"); + } + + cur_idx = 1; + for_each_opt_hdr_v1(ohdr, ptr) { + if (ohdr->headertype == OPT_HDR_V1_SECURE_TYPE) { + fprintf(f, "#SECURE_HEADER\n"); + } else if (ohdr->headertype == OPT_HDR_V1_BINARY_TYPE) { + fprintf(f, "BINARY binary%d.bin", cur_idx); + for (i = 0; i < ohdr->data[0]; i++) + fprintf(f, " 0x%x", le32_to_cpu(((uint32_t *)ohdr->data)[i + 1])); + offset = (unsigned)((uint8_t *)ohdr - (uint8_t *)mhdr) + 8 + 4 * ohdr->data[0]; + fprintf(f, " LOAD_ADDRESS 0x%08x\n", 0x40000000 + offset); + fprintf(f, " # for CPU SHEEVA: LOAD_ADDRESS 0x%08x\n", 0x40004000 + offset); + cur_idx++; + } else if (ohdr->headertype == OPT_HDR_V1_REGISTER_TYPE) { + regset_hdr = (struct register_set_hdr_v1 *)ohdr; + for (i = 0; + i < opt_hdr_v1_size(ohdr) - sizeof(struct opt_hdr_v1) - + sizeof(regset_hdr->data[0].last_entry); + i++) + fprintf(f, "DATA 0x%08x 0x%08x\n", + le32_to_cpu(regset_hdr->data[i].entry.address), + le32_to_cpu(regset_hdr->data[i].entry.value)); + if (opt_hdr_v1_size(ohdr) - sizeof(struct opt_hdr_v1) >= + sizeof(regset_hdr->data[0].last_entry)) { + if (regset_hdr->data[0].last_entry.delay) + fprintf(f, "DATA_DELAY %u\n", + (unsigned)regset_hdr->data[0].last_entry.delay); + else + fprintf(f, "DATA_DELAY SDRAM_SETUP\n"); + } + } + } + + if (version == 0 && mhdr0->ext) { + ehdr0 = (struct ext_hdr_v0 *)(mhdr0 + 1); + if (ehdr0->offset) { + for (regdata = (struct ext_hdr_v0_reg *)((uint8_t *)ptr + ehdr0->offset); + (uint8_t *)regdata < (uint8_t *)ptr + header_size && regdata->raddr && + regdata->rdata; + regdata++) + fprintf(f, "DATA 0x%08x 0x%08x\n", le32_to_cpu(regdata->raddr), + le32_to_cpu(regdata->rdata)); + } + } + + if (version == 0 && le16_to_cpu(mhdr0->ddrinitdelay)) + fprintf(f, "DDR_INIT_DELAY %u\n", (unsigned)le16_to_cpu(mhdr0->ddrinitdelay)); + + /* Undocumented reserved fields */ + + if (version == 0 && (mhdr0->rsvd1[0] || mhdr0->rsvd1[1] || mhdr0->rsvd1[2])) + fprintf(f, "#RSVD1 0x%x 0x%x 0x%x\n", (unsigned)mhdr0->rsvd1[0], + (unsigned)mhdr0->rsvd1[1], (unsigned)mhdr0->rsvd1[2]); + + if (version == 0 && mhdr0->rsvd3) + fprintf(f, "#RSVD3 0x%x\n", (unsigned)mhdr0->rsvd3); + + if (version == 0 && le16_to_cpu(mhdr0->rsvd2)) + fprintf(f, "#RSVD2 0x%x\n", (unsigned)le16_to_cpu(mhdr0->rsvd2)); + + if (version != 0 && mhdr->reserved4) + fprintf(f, "#RESERVED4 0x%x\n", (unsigned)mhdr->reserved4); + + if (version != 0 && mhdr->reserved5) + fprintf(f, "#RESERVED5 0x%x\n", (unsigned)le16_to_cpu(mhdr->reserved5)); + + fclose(f); + + return 0; +} + static int kwbimage_extract_subimage(void *ptr, struct image_tool_params *params) { struct main_hdr_v1 *mhdr = (struct main_hdr_v1 *)ptr; @@ -2099,6 +2271,10 @@ static int kwbimage_extract_subimage(void *ptr, struct image_tool_params *params ulong image; ulong size; + /* Generate kwbimage config file when '-p -1' is specified */ + if (idx == -1) + return kwbimage_generate_config(ptr, params); + for_each_opt_hdr_v1 (ohdr, ptr) { if (ohdr->headertype != OPT_HDR_V1_BINARY_TYPE) continue; From 1a0e52f50a2085c46bf3bc5116f820a3cb655a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:51 +0100 Subject: [PATCH 33/38] tools: kwbimage: Do not cast const pointers to non-const pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid casting const to non-const. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwbimage.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/kwbimage.h b/tools/kwbimage.h index 8d37357e5a..c000cba4b8 100644 --- a/tools/kwbimage.h +++ b/tools/kwbimage.h @@ -235,11 +235,11 @@ static inline int opt_hdr_v1_valid_size(const struct opt_hdr_v1 *ohdr, { uint32_t ohdr_size; - if ((void *)(ohdr + 1) > mhdr_end) + if ((const void *)(ohdr + 1) > mhdr_end) return 0; ohdr_size = opt_hdr_v1_size(ohdr); - if (ohdr_size < 8 || (void *)((uint8_t *)ohdr + ohdr_size) > mhdr_end) + if (ohdr_size < 8 || (const void *)((const uint8_t *)ohdr + ohdr_size) > mhdr_end) return 0; return 1; From 44691034e18d3b242f911abeb20566d418995710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:52 +0100 Subject: [PATCH 34/38] tools: kwbimage/kwboot: Check ext field for non-zero value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Despite the official specification, BootROM does not look at the lowest bit of ext field but rather checks if ext field is non-zero. Moreover original Marvell doimage tool puts into the mhdr->ext field the number of extended headers, so basically it sets ext filed to non-zero value if some extended header is present. Fix U-Boot dumpimage and kwboot tools to parse correctly also kwbimage files created by Marvell doimage tool, in the same way as the BootROM is doing it when booting these images. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwbimage.c | 2 +- tools/kwbimage.h | 6 +++--- tools/kwboot.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index de7e9acf7f..92d163b605 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -1948,7 +1948,7 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size, if (kwbimage_version(ptr) == 0) { struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr; - if (mhdr->ext & 0x1) { + if (mhdr->ext) { struct ext_hdr_v0 *ext_hdr = (void *)(mhdr + 1); csum = image_checksum8(ext_hdr, sizeof(*ext_hdr) - 1); diff --git a/tools/kwbimage.h b/tools/kwbimage.h index c000cba4b8..9ebc7d72d3 100644 --- a/tools/kwbimage.h +++ b/tools/kwbimage.h @@ -208,7 +208,7 @@ static inline size_t kwbheader_size(const void *header) const struct main_hdr_v0 *hdr = header; return sizeof(*hdr) + - (hdr->ext & 0x1) ? sizeof(struct ext_hdr_v0) : 0; + hdr->ext ? sizeof(struct ext_hdr_v0) : 0; } else { const struct main_hdr_v1 *hdr = header; @@ -252,7 +252,7 @@ static inline struct opt_hdr_v1 *opt_hdr_v1_first(void *img) { return NULL; mhdr = img; - if (mhdr->ext & 0x1) + if (mhdr->ext) return (struct opt_hdr_v1 *)(mhdr + 1); else return NULL; @@ -272,7 +272,7 @@ static inline struct opt_hdr_v1 *_opt_hdr_v1_next(struct opt_hdr_v1 *cur) static inline struct opt_hdr_v1 *opt_hdr_v1_next(struct opt_hdr_v1 *cur) { - if (*opt_hdr_v1_ext(cur) & 0x1) + if (*opt_hdr_v1_ext(cur)) return _opt_hdr_v1_next(cur); else return NULL; diff --git a/tools/kwboot.c b/tools/kwboot.c index d22e6ea96a..c3d8ab6544 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -1398,7 +1398,7 @@ kwboot_add_bin_ohdr_v1(void *img, size_t *size, uint32_t binsz) uint32_t ohdrsz; uint8_t *prev_ext; - if (hdr->ext & 0x1) { + if (hdr->ext) { for_each_opt_hdr_v1 (ohdr, img) if (opt_hdr_v1_next(ohdr) == NULL) break; @@ -1422,7 +1422,7 @@ kwboot_add_bin_ohdr_v1(void *img, size_t *size, uint32_t binsz) ohdrsz = sizeof(*ohdr) + 4 + 4 * num_args + binsz + 4; kwboot_img_grow_hdr(hdr, size, ohdrsz); - *prev_ext |= 1; + *prev_ext = 1; ohdr->headertype = OPT_HDR_V1_BINARY_TYPE; ohdr->headersz_msb = ohdrsz >> 16; From 1972c7e30859b48326e41e56a7fddfac1a6f5739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:53 +0100 Subject: [PATCH 35/38] tools: kwbimage: Extract main data image without -p arg for dumpimage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When there is no -p argument for dumpimage tool specified, extract the main data image from kwbimage file. This makes dumpimage consistent with other image formats. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwbimage.c | 75 ++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 92d163b605..d159087d9d 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -2266,7 +2266,7 @@ static int kwbimage_extract_subimage(void *ptr, struct image_tool_params *params size_t header_size = kwbheader_size(ptr); struct opt_hdr_v1 *ohdr; int idx = params->pflag; - int cur_idx = 0; + int cur_idx; uint32_t offset; ulong image; ulong size; @@ -2275,41 +2275,54 @@ static int kwbimage_extract_subimage(void *ptr, struct image_tool_params *params if (idx == -1) return kwbimage_generate_config(ptr, params); - for_each_opt_hdr_v1 (ohdr, ptr) { - if (ohdr->headertype != OPT_HDR_V1_BINARY_TYPE) - continue; + image = 0; + size = 0; - if (idx == cur_idx) { - image = (ulong)&ohdr->data[4 + 4 * ohdr->data[0]]; - size = opt_hdr_v1_size(ohdr) - 12 - 4 * ohdr->data[0]; - goto extract; + if (idx == 0) { + /* Extract data image when -p is not specified or when '-p 0' is specified */ + offset = le32_to_cpu(mhdr->srcaddr); + + if (mhdr->blockid == IBR_HDR_SATA_ID) { + offset -= 1; + offset *= 512; } - ++cur_idx; + if (mhdr->blockid == IBR_HDR_SDIO_ID) + offset *= 512; + + if (mhdr->blockid == IBR_HDR_PEX_ID && offset == 0xFFFFFFFF) + offset = header_size; + + image = (ulong)((uint8_t *)ptr + offset); + size = le32_to_cpu(mhdr->blocksize) - 4; + } else { + /* Extract N-th binary header executabe image when other '-p N' is specified */ + cur_idx = 1; + for_each_opt_hdr_v1(ohdr, ptr) { + if (ohdr->headertype != OPT_HDR_V1_BINARY_TYPE) + continue; + + if (idx == cur_idx) { + image = (ulong)&ohdr->data[4 + 4 * ohdr->data[0]]; + size = opt_hdr_v1_size(ohdr) - 12 - 4 * ohdr->data[0]; + break; + } + + ++cur_idx; + } + + if (!image) { + fprintf(stderr, "Argument -p %d is invalid\n", idx); + fprintf(stderr, "Available subimages:\n"); + fprintf(stderr, " -p -1 - kwbimage config file\n"); + fprintf(stderr, " -p 0 - data image\n"); + if (cur_idx - 1 > 0) + fprintf(stderr, " -p N - Nth binary header image (totally: %d)\n", + cur_idx - 1); + return -1; + } } - if (idx != cur_idx) { - printf("Image %d is not present\n", idx); - return -1; - } - - offset = le32_to_cpu(mhdr->srcaddr); - - if (mhdr->blockid == IBR_HDR_SATA_ID) { - offset -= 1; - offset *= 512; - } - - if (mhdr->blockid == IBR_HDR_SDIO_ID) - offset *= 512; - - if (mhdr->blockid == IBR_HDR_PEX_ID && offset == 0xFFFFFFFF) - offset = header_size; - - image = (ulong)((uint8_t *)ptr + offset); - size = le32_to_cpu(mhdr->blocksize) - 4; - -extract: return imagetool_save_subimage(params->outfile, image, size); } From 32860b00bf2cb441c5b9b396d41c84aac340d7ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:20:54 +0100 Subject: [PATCH 36/38] tools: kwbimage: Fix mkimage/dumpimage -l argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not check for kwbimage configuration file when just showing information about existing kwbimage file. The check for kwbimage configuration file is required only when creating kwbimage, not when showing information about image or when extracting data from image. With this change, it is possible to call mkimage -l and dumpimage -l also for existing kwbimage file. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- tools/kwbimage.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/kwbimage.c b/tools/kwbimage.c index d159087d9d..9b63ce80ff 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -2331,7 +2331,8 @@ static int kwbimage_extract_subimage(void *ptr, struct image_tool_params *params */ static int kwbimage_check_params(struct image_tool_params *params) { - if (!params->iflag && (!params->imagename || !strlen(params->imagename))) { + if (!params->lflag && !params->iflag && + (!params->imagename || !strlen(params->imagename))) { char *msg = "Configuration file for kwbimage creation omitted"; fprintf(stderr, "Error:%s - %s\n", params->cmdname, msg); From 5435f6e3fd6c16263debdf9048c8357c7e2e4d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:30:09 +0100 Subject: [PATCH 37/38] arm: mvebu: db-88f6720: Fix CONFIG_SPL_TEXT_BASE and remove wrong memory layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Memory layout in the comment is from Armada XP platform which uses load address 0x40004030. DB-88f6720 is Armada 375 platform which uses same load address as Armada 38x which is 0x40000030. Currently SPL support for Armada 375 is unfinished and does not work. There is missing Serdes initialization and DDR3 training code. So nobody noticed that CONFIG_SPL_* options are not correct. Fix at least CONFIG_SPL_TEXT_BASE constant and remove incorrect comments about memory layout. So it is not misleading. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- configs/db-88f6720_defconfig | 2 +- include/configs/db-88f6720.h | 15 +-------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/configs/db-88f6720_defconfig b/configs/db-88f6720_defconfig index 32a7349993..2e8f4c00de 100644 --- a/configs/db-88f6720_defconfig +++ b/configs/db-88f6720_defconfig @@ -11,7 +11,7 @@ CONFIG_ENV_SIZE=0x10000 CONFIG_ENV_OFFSET=0x100000 CONFIG_ENV_SECT_SIZE=0x10000 CONFIG_DEFAULT_DEVICE_TREE="armada-375-db" -CONFIG_SPL_TEXT_BASE=0x40004030 +CONFIG_SPL_TEXT_BASE=0x40000030 CONFIG_SPL_SERIAL=y CONFIG_SPL=y CONFIG_DEBUG_UART_BASE=0xf1012000 diff --git a/include/configs/db-88f6720.h b/include/configs/db-88f6720.h index 19fc669f89..cf9e44d17c 100644 --- a/include/configs/db-88f6720.h +++ b/include/configs/db-88f6720.h @@ -32,22 +32,9 @@ */ #include "mv-common.h" -/* - * Memory layout while starting into the bin_hdr via the - * BootROM: - * - * 0x4000.4000 - 0x4003.4000 headers space (192KiB) - * 0x4000.4030 bin_hdr start address - * 0x4003.4000 - 0x4004.7c00 BootROM memory allocations (15KiB) - * 0x4007.fffc BootROM stack top - * - * The address space between 0x4007.fffc and 0x400f.fff is not locked in - * L2 cache thus cannot be used. - */ - /* SPL */ /* Defines for SPL */ -#define CONFIG_SPL_MAX_SIZE ((128 << 10) - 0x4030) +#define CONFIG_SPL_MAX_SIZE ((128 << 10) - 0x0030) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10)) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) From 1dcbcc715e87da6d30b8ae22f1ef04c881cfea5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 12 Jan 2022 18:32:08 +0100 Subject: [PATCH 38/38] arm: mvebu: Replace hardcoded values 0x0030/0x4030 by proper calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These hardcoded values were calculated from CONFIG_SPL_TEXT_BASE macro. Now this macro is configurable via Kconfig, so calculate values 0x0030/0x4030 at compile time via CONFIG_SPL_TEXT_BASE option. Values 0x0030/0x4030 represents offset of CONFIG_SPL_TEXT_BASE from address 0x40000000. Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- include/configs/clearfog.h | 2 +- include/configs/db-88f6720.h | 2 +- include/configs/db-88f6820-amc.h | 2 +- include/configs/db-88f6820-gp.h | 2 +- include/configs/db-mv784mp-gp.h | 2 +- include/configs/ds414.h | 2 +- include/configs/helios4.h | 2 +- include/configs/maxbcm.h | 2 +- include/configs/theadorable.h | 2 +- include/configs/turris_omnia.h | 2 +- include/configs/x530.h | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/configs/clearfog.h b/include/configs/clearfog.h index a30bca5147..c9af5a40ce 100644 --- a/include/configs/clearfog.h +++ b/include/configs/clearfog.h @@ -53,7 +53,7 @@ /* Defines for SPL */ #define CONFIG_SPL_SIZE (140 << 10) -#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x0030) +#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) diff --git a/include/configs/db-88f6720.h b/include/configs/db-88f6720.h index cf9e44d17c..16c83a88da 100644 --- a/include/configs/db-88f6720.h +++ b/include/configs/db-88f6720.h @@ -34,7 +34,7 @@ /* SPL */ /* Defines for SPL */ -#define CONFIG_SPL_MAX_SIZE ((128 << 10) - 0x0030) +#define CONFIG_SPL_MAX_SIZE ((128 << 10) - (CONFIG_SPL_TEXT_BASE - 0x40000000)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10)) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) diff --git a/include/configs/db-88f6820-amc.h b/include/configs/db-88f6820-amc.h index 1f70c609d2..6538e66052 100644 --- a/include/configs/db-88f6820-amc.h +++ b/include/configs/db-88f6820-amc.h @@ -41,7 +41,7 @@ /* Defines for SPL */ #define CONFIG_SPL_SIZE (140 << 10) -#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x0030) +#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) diff --git a/include/configs/db-88f6820-gp.h b/include/configs/db-88f6820-gp.h index 41dadfebb9..5f2611995d 100644 --- a/include/configs/db-88f6820-gp.h +++ b/include/configs/db-88f6820-gp.h @@ -50,7 +50,7 @@ /* Defines for SPL */ #define CONFIG_SPL_SIZE (140 << 10) -#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x0030) +#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) diff --git a/include/configs/db-mv784mp-gp.h b/include/configs/db-mv784mp-gp.h index dbbc33ebf9..449a56753b 100644 --- a/include/configs/db-mv784mp-gp.h +++ b/include/configs/db-mv784mp-gp.h @@ -59,7 +59,7 @@ /* SPL */ /* Defines for SPL */ -#define CONFIG_SPL_MAX_SIZE ((128 << 10) - 0x4030) +#define CONFIG_SPL_MAX_SIZE ((128 << 10) - (CONFIG_SPL_TEXT_BASE - 0x40000000)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10)) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) diff --git a/include/configs/ds414.h b/include/configs/ds414.h index 7fba2b4cc4..dbccd46bbd 100644 --- a/include/configs/ds414.h +++ b/include/configs/ds414.h @@ -45,7 +45,7 @@ /* SPL */ /* Defines for SPL */ -#define CONFIG_SPL_MAX_SIZE ((128 << 10) - 0x4030) +#define CONFIG_SPL_MAX_SIZE ((128 << 10) - (CONFIG_SPL_TEXT_BASE - 0x40000000)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10)) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) diff --git a/include/configs/helios4.h b/include/configs/helios4.h index 56d35d6fdb..de1ebbf375 100644 --- a/include/configs/helios4.h +++ b/include/configs/helios4.h @@ -53,7 +53,7 @@ /* Defines for SPL */ #define CONFIG_SPL_SIZE (140 << 10) -#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x0030) +#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) diff --git a/include/configs/maxbcm.h b/include/configs/maxbcm.h index 53ba64909e..073c5a57b2 100644 --- a/include/configs/maxbcm.h +++ b/include/configs/maxbcm.h @@ -48,7 +48,7 @@ /* SPL */ /* Defines for SPL */ -#define CONFIG_SPL_MAX_SIZE ((128 << 10) - 0x4030) +#define CONFIG_SPL_MAX_SIZE ((128 << 10) - (CONFIG_SPL_TEXT_BASE - 0x40000000)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10)) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) diff --git a/include/configs/theadorable.h b/include/configs/theadorable.h index b43c03d3e8..3c942cc6fa 100644 --- a/include/configs/theadorable.h +++ b/include/configs/theadorable.h @@ -77,7 +77,7 @@ /* SPL */ /* Defines for SPL */ -#define CONFIG_SPL_MAX_SIZE ((128 << 10) - 0x4030) +#define CONFIG_SPL_MAX_SIZE ((128 << 10) - (CONFIG_SPL_TEXT_BASE - 0x40000000)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + (128 << 10)) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) diff --git a/include/configs/turris_omnia.h b/include/configs/turris_omnia.h index 9436a623d6..b35299b2fb 100644 --- a/include/configs/turris_omnia.h +++ b/include/configs/turris_omnia.h @@ -28,7 +28,7 @@ /* Defines for SPL */ #define CONFIG_SPL_SIZE (140 << 10) -#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x0030) +#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10) diff --git a/include/configs/x530.h b/include/configs/x530.h index e78e249e41..67ff01db90 100644 --- a/include/configs/x530.h +++ b/include/configs/x530.h @@ -68,7 +68,7 @@ /* Defines for SPL */ #define CONFIG_SPL_SIZE (140 << 10) -#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - 0x0030) +#define CONFIG_SPL_MAX_SIZE (CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000)) #define CONFIG_SPL_BSS_START_ADDR (0x40000000 + CONFIG_SPL_SIZE) #define CONFIG_SPL_BSS_MAX_SIZE (16 << 10)