From: Tom Rini Date: Mon, 14 Mar 2022 21:40:36 +0000 (-0400) Subject: Merge tag 'v2022.04-rc4' into next X-Git-Tag: v2022.07~124^2~17 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2abf048ab7b835787d6627423559832f2b18f253;hp=7b958ede8c795501717b972b67473ea4cdc09b45;p=platform%2Fkernel%2Fu-boot.git Merge tag 'v2022.04-rc4' into next Prepare v2022.04-rc4 --- diff --git a/.mailmap b/.mailmap index b36ae66..1f88ea9 100644 --- a/.mailmap +++ b/.mailmap @@ -22,11 +22,13 @@ Andreas Bießmann Aneesh V Anup Patel Atish Patra +Bin Meng Boris Brezillon Boris Brezillon Dirk Behme Fabio Estevam Heinrich Schuchardt +Heinrich Schuchardt xypron.glpk@gmx.de Jagan Teki <402jagan@gmail.com> Jagan Teki Jagan Teki @@ -35,7 +37,15 @@ Jagan Teki Jernej Skrabec Igor Opaniuk Igor Opaniuk +Marek Vasut +Marek Vasut +Marek Vasut Markus Klotzbuecher +Masahiro Yamada +Masahiro Yamada +Michal Simek +Michal Simek +Michal Simek Nicolas Saenz Julienne Patrice Chotard Patrick Delaunay @@ -47,10 +57,19 @@ Ricardo Ribalda Ruchika Gupta Sandeep Paulraj Shaohui Xie -Stefan Roese +Stefan Roese Stefano Babic +Tom Rini TsiChung Liew -Wolfgang Denk +Wolfgang Denk +Wolfgang Denk +Wolfgang Denk +Wolfgang Denk +Wolfgang Denk +Wolfgang Denk +Wolfgang Denk +Wolfgang Denk +Wolfgang Denk York Sun York Sun Łukasz Majewski diff --git a/MAINTAINERS b/MAINTAINERS index 7012cc2..5011a54 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1171,6 +1171,13 @@ S: Maintained T: git https://source.denx.de/u-boot/custodians/u-boot-sh.git F: arch/sh/ +SL28CLPD +M: Michael Walle +S: Maintained +F: drivers/gpio/sl28cpld-gpio.c +F: drivers/misc/sl28cpld.c +F: drivers/watchdog/sl28cpld-wdt.c + SPI M: Jagan Teki S: Maintained @@ -1329,6 +1336,14 @@ F: include/virtio*.h F: test/dm/virtio.c F: doc/develop/driver-model/virtio.rst +WATCHDOG +M: Stefan Roese +S: Maintained +T: git https://source.denx.de/u-boot/custodians/u-boot-watchdog.git +F: cmd/wdt.c +F: drivers/watchdog/ +F: include/watchdog*.h + X86 M: Simon Glass M: Bin Meng diff --git a/Makefile b/Makefile index 9ef34ca..06572ac 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2022 PATCHLEVEL = 04 SUBLEVEL = -EXTRAVERSION = -rc3 +EXTRAVERSION = -rc4 NAME = # *DOCUMENTATION* @@ -1412,7 +1412,7 @@ MKIMAGEFLAGS_u-boot-spl.kwb = -n $(KWD_CONFIG_FILE) \ $(if $(KEYDIR),-k $(KEYDIR)) MKIMAGEFLAGS_u-boot.pbl = -n $(srctree)/$(CONFIG_SYS_FSL_PBL_RCW:"%"=%) \ - -R $(srctree)/$(CONFIG_SYS_FSL_PBL_PBI:"%"=%) -T pblimage + -R $(srctree)/$(CONFIG_SYS_FSL_PBL_PBI:"%"=%) -A $(ARCH) -T pblimage ifeq ($(CONFIG_MPC85xx)$(CONFIG_OF_SEPARATE),yy) UBOOT_BIN := u-boot-with-dtb.bin diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 403156b..474ce4a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1075,6 +1075,8 @@ config ARCH_SUNXI select DM_ETH select DM_GPIO select DM_I2C if I2C + select DM_SPI if SPI + select DM_SPI_FLASH if SPI select DM_KEYBOARD select DM_MMC if MMC select DM_SCSI if SCSI diff --git a/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S b/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S index 08be7ed..2592403 100644 --- a/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S +++ b/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S @@ -25,9 +25,9 @@ ENTRY(return_to_fel) mov sp, r0 mov lr, r1 ldr r0, =fel_stash - ldr r1, [r0, #16] - mcr p15, 0, r1, c1, c0, 0 @ Write CP15 Control Register ldr r1, [r0, #12] + mcr p15, 0, r1, c1, c0, 0 @ Write CP15 SCTLR register + ldr r1, [r0, #8] msr cpsr, r1 @ Write CPSR bx lr ENDPROC(return_to_fel) diff --git a/arch/arm/dts/armada-3720-turris-mox.dts b/arch/arm/dts/armada-3720-turris-mox.dts index 1fc4a30..595b4b5 100644 --- a/arch/arm/dts/armada-3720-turris-mox.dts +++ b/arch/arm/dts/armada-3720-turris-mox.dts @@ -139,7 +139,9 @@ /* * U-Boot port for Turris Mox has a bug which always expects that "ranges" DT property * contains exactly 2 ranges with 3 (child) address cells, 2 (parent) address cells and - * 2 size cells and also expects that the second range starts at 16 MB offset. If these + * 2 size cells and also expects that the second range starts at 16 MB offset. Also it + * expects that first range uses same address for PCI (child) and CPU (parent) cells (so + * no remapping) and that this address is the lowest from all specified ranges. If these * conditions are not met then U-Boot crashes during loading kernel DTB file. PCIe address * space is 128 MB long, so the best split between MEM and IO is to use fixed 16 MB window * for IO and the rest 112 MB (64+32+16) for MEM. Controller supports 32-bit IO mapping. @@ -148,6 +150,9 @@ * https://source.denx.de/u-boot/u-boot/-/commit/cb2ddb291ee6fcbddd6d8f4ff49089dfe580f5d7 * https://source.denx.de/u-boot/u-boot/-/commit/c64ac3b3185aeb3846297ad7391fc6df8ecd73bf * https://source.denx.de/u-boot/u-boot/-/commit/4a82fca8e330157081fc132a591ebd99ba02ee33 + * Bug related to requirement of same child and parent addresses for first range is fixed + * in U-Boot version 2022.04 by following commit: + * https://source.denx.de/u-boot/u-boot/-/commit/1fd54253bca7d43d046bba4853fe5fafd034bc17 */ #address-cells = <3>; #size-cells = <2>; diff --git a/arch/arm/dts/armada-37xx.dtsi b/arch/arm/dts/armada-37xx.dtsi index 9fa6457..0bb4f60 100644 --- a/arch/arm/dts/armada-37xx.dtsi +++ b/arch/arm/dts/armada-37xx.dtsi @@ -499,7 +499,7 @@ * (totaling 127 MiB) for MEM. */ ranges = <0x82000000 0 0xe8000000 0 0xe8000000 0 0x07f00000 /* Port 0 MEM */ - 0x81000000 0 0xeff00000 0 0xeff00000 0 0x00100000>; /* Port 0 IO*/ + 0x81000000 0 0x00000000 0 0xeff00000 0 0x00100000>; /* Port 0 IO */ interrupt-map-mask = <0 0 0 7>; interrupt-map = <0 0 0 1 &pcie_intc 0>, <0 0 0 2 &pcie_intc 1>, diff --git a/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi b/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi index d4b8332..2dcb3c2 100644 --- a/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi +++ b/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi @@ -27,6 +27,7 @@ fit { offset = ; description = "FIT image with multiple configurations"; + fit,fdt-list = "of-list"; images { uboot { @@ -41,95 +42,20 @@ }; }; - fdt-1 { - description = "fsl-ls1028a-kontron-sl28"; + @fdt-SEQ { + description = "NAME"; type = "flat_dt"; - arch = "arm"; - compression = "none"; - - blob { - filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28.dtb"; - }; - }; - - fdt-2 { - description = "fsl-ls1028a-kontron-sl28-var1"; - type = "flat_dt"; - arch = "arm"; - compression = "none"; - - blob { - filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var1.dtb"; - }; - }; - - fdt-3 { - description = "fsl-ls1028a-kontron-sl28-var2"; - type = "flat_dt"; - arch = "arm"; - compression = "none"; - - blob { - filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var2.dtb"; - }; - }; - - fdt-4 { - description = "fsl-ls1028a-kontron-sl28-var3"; - type = "flat_dt"; - arch = "arm"; compression = "none"; - - blob { - filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var3.dtb"; - }; - }; - - fdt-5 { - description = "fsl-ls1028a-kontron-sl28-var4"; - type = "flat_dt"; - arch = "arm"; - compression = "none"; - - blob { - filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var4.dtb"; - }; }; }; configurations { - default = "conf-1"; - - conf-1 { - description = "fsl-ls1028a-kontron-sl28"; - firmware = "uboot"; - fdt = "fdt-1"; - }; - - conf-2 { - description = "fsl-ls1028a-kontron-sl28-var1"; - firmware = "uboot"; - fdt = "fdt-2"; - }; - - conf-3 { - description = "fsl-ls1028a-kontron-sl28-var2"; - firmware = "uboot"; - fdt = "fdt-3"; - }; - - conf-4 { - description = "fsl-ls1028a-kontron-sl28-var3"; - firmware = "uboot"; - loadables = "uboot"; - fdt = "fdt-4"; - }; + default = "@config-DEFAULT-SEQ"; - conf-5 { - description = "fsl-ls1028a-kontron-sl28-var4"; + @config-SEQ { + description = "NAME"; firmware = "uboot"; - loadables = "uboot"; - fdt = "fdt-5"; + fdt = "fdt-SEQ"; }; }; }; @@ -189,27 +115,7 @@ }; configurations { - conf-1 { - firmware = "bl31"; - loadables = "uboot"; - }; - - conf-2 { - firmware = "bl31"; - loadables = "uboot"; - }; - - conf-3 { - firmware = "bl31"; - loadables = "uboot"; - }; - - conf-4 { - firmware = "bl31"; - loadables = "uboot"; - }; - - conf-5 { + @config-SEQ { firmware = "bl31"; loadables = "uboot"; }; @@ -238,23 +144,7 @@ }; configurations { - conf-1 { - loadables = "uboot", "bl32"; - }; - - conf-2 { - loadables = "uboot", "bl32"; - }; - - conf-3 { - loadables = "uboot", "bl32"; - }; - - conf-4 { - loadables = "uboot", "bl32"; - }; - - conf-5 { + @config-SEQ { loadables = "uboot", "bl32"; }; }; diff --git a/arch/arm/dts/k3-am65-iot2050-common-u-boot.dtsi b/arch/arm/dts/k3-am65-iot2050-common-u-boot.dtsi index 286e25f..d80c550 100644 --- a/arch/arm/dts/k3-am65-iot2050-common-u-boot.dtsi +++ b/arch/arm/dts/k3-am65-iot2050-common-u-boot.dtsi @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) Siemens AG, 2018-2021 + * Copyright (c) Siemens AG, 2018-2022 * * Authors: * Le Jin @@ -27,6 +27,29 @@ &cbass_mcu { u-boot,dm-spl; + + mcu_navss: bus@28380000 { + ringacc@2b800000 { + reg = <0x0 0x2b800000 0x0 0x400000>, + <0x0 0x2b000000 0x0 0x400000>, + <0x0 0x28590000 0x0 0x100>, + <0x0 0x2a500000 0x0 0x40000>, + <0x0 0x28440000 0x0 0x40000>; + reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target", "cfg"; + ti,dma-ring-reset-quirk; + }; + + dma-controller@285c0000 { + reg = <0x0 0x285c0000 0x0 0x100>, + <0x0 0x284c0000 0x0 0x4000>, + <0x0 0x2a800000 0x0 0x40000>, + <0x0 0x284a0000 0x0 0x4000>, + <0x0 0x2aa00000 0x0 0x40000>, + <0x0 0x28400000 0x0 0x2000>; + reg-names = "gcfg", "rchan", "rchanrt", "tchan", + "tchanrt", "rflow"; + }; + }; }; &cbass_wakeup { diff --git a/arch/arm/dts/sama7g5ek.dts b/arch/arm/dts/sama7g5ek.dts index 6adb044..ac6f23f 100644 --- a/arch/arm/dts/sama7g5ek.dts +++ b/arch/arm/dts/sama7g5ek.dts @@ -125,7 +125,9 @@ #address-cells = <1>; #size-cells = <0>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_gmac0_default &pinctrl_gmac0_txc_default>; + pinctrl-0 = <&pinctrl_gmac0_default + &pinctrl_gmac0_mdio_default + &pinctrl_gmac0_txc_default>; phy-mode = "rgmii-id"; status = "okay"; @@ -138,7 +140,7 @@ #address-cells = <1>; #size-cells = <0>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_gmac1_default>; + pinctrl-0 = <&pinctrl_gmac1_default &pinctrl_gmac1_mdio_default>; phy-mode = "rmii"; status = "okay"; @@ -235,14 +237,20 @@ , , , - , - , ; + slew-rate = <0>; + bias-disable; + }; + + pinctrl_gmac0_mdio_default: gmac0_mdio_default { + pinmux = , + ; bias-disable; }; pinctrl_gmac0_txc_default: gmac0_txc_default { pinmux = ; + slew-rate = <0>; bias-pull-up; }; @@ -254,8 +262,13 @@ , , , - , - , + ; + slew-rate = <0>; + bias-disable; + }; + + pinctrl_gmac1_mdio_default: gmac1_mdio_default { + pinmux = , ; bias-disable; }; diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h index 7f7eb05..edd0fbf 100644 --- a/arch/arm/include/asm/arch-sunxi/gpio.h +++ b/arch/arm/include/asm/arch-sunxi/gpio.h @@ -160,6 +160,7 @@ enum sunxi_gpio_number { #define SUNXI_GPC_SDC2 3 #define SUN6I_GPC_SDC3 4 #define SUN50I_GPC_SPI0 4 +#define SUNIV_GPC_SPI0 2 #define SUNXI_GPD_LCD0 2 #define SUNXI_GPD_LVDS0 3 diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h index 58cdf80..b543d24 100644 --- a/arch/arm/include/asm/arch-sunxi/spl.h +++ b/arch/arm/include/asm/arch-sunxi/spl.h @@ -19,6 +19,15 @@ #define SUNXI_BOOTED_FROM_MMC0_HIGH 0x10 #define SUNXI_BOOTED_FROM_MMC2_HIGH 0x12 +/* + * Values taken from the F1C200s BootROM stack + * to determine where we booted from. + */ +#define SUNIV_BOOTED_FROM_MMC0 0xffff40f8 +#define SUNIV_BOOTED_FROM_NAND 0xffff4114 +#define SUNIV_BOOTED_FROM_SPI 0xffff4130 +#define SUNIV_BOOTED_FROM_MMC1 0xffff4150 + #define is_boot0_magic(addr) (memcmp((void *)(addr), BOOT0_MAGIC, 8) == 0) uint32_t sunxi_get_boot_device(void); diff --git a/arch/arm/mach-k3/am6_init.c b/arch/arm/mach-k3/am6_init.c index ffb7aad..8a6b1de 100644 --- a/arch/arm/mach-k3/am6_init.c +++ b/arch/arm/mach-k3/am6_init.c @@ -251,7 +251,8 @@ void board_init_f(ulong dummy) k3_sysfw_print_ver(); /* Perform EEPROM-based board detection */ - do_board_detect(); + if (IS_ENABLED(CONFIG_TI_I2C_BOARD_DETECT)) + do_board_detect(); #if defined(CONFIG_CPU_V7R) && defined(CONFIG_K3_AVS0) ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(k3_avs), diff --git a/arch/arm/mach-mvebu/armada3700/cpu.c b/arch/arm/mach-mvebu/armada3700/cpu.c index 23492f4..52b5109 100644 --- a/arch/arm/mach-mvebu/armada3700/cpu.c +++ b/arch/arm/mach-mvebu/armada3700/cpu.c @@ -316,8 +316,8 @@ static int fdt_setprop_inplace_u32_partial(void *blob, int node, int a3700_fdt_fix_pcie_regions(void *blob) { - int acells, pacells, scells; - u32 base, fix_offset; + u32 base, lowest_cpu_addr, fix_offset; + int pci_cells, cpu_cells, size_cells; const u32 *ranges; int node, pnode; int ret, i, len; @@ -331,51 +331,80 @@ int a3700_fdt_fix_pcie_regions(void *blob) return node; ranges = fdt_getprop(blob, node, "ranges", &len); - if (!ranges || len % sizeof(u32)) - return -ENOENT; + if (!ranges || !len || len % sizeof(u32)) + return -EINVAL; /* * The "ranges" property is an array of - * { } + * { } + * where number of PCI address cells and size cells is stored in the + * "#address-cells" and "#size-cells" properties of the same node + * containing the "ranges" property and number of CPU address cells + * is stored in the parent's "#address-cells" property. * - * All 3 elements can span a diffent number of cells. Fetch their sizes. + * All 3 elements can span a diffent number of cells. Fetch them. */ pnode = fdt_parent_offset(blob, node); - acells = fdt_address_cells(blob, node); - pacells = fdt_address_cells(blob, pnode); - scells = fdt_size_cells(blob, node); + pci_cells = fdt_address_cells(blob, node); + cpu_cells = fdt_address_cells(blob, pnode); + size_cells = fdt_size_cells(blob, node); - /* Child PCI addresses always use 3 cells */ - if (acells != 3) - return -ENOENT; + /* PCI addresses always use 3 cells */ + if (pci_cells != 3) + return -EINVAL; + + /* CPU addresses on Armada 37xx always use 2 cells */ + if (cpu_cells != 2) + return -EINVAL; + + for (i = 0; i < len / sizeof(u32); + i += pci_cells + cpu_cells + size_cells) { + /* + * Parent CPU addresses on Armada 37xx are always 32-bit, so + * check that the high word is zero. + */ + if (fdt32_to_cpu(ranges[i + pci_cells])) + return -EINVAL; + + if (i == 0 || + fdt32_to_cpu(ranges[i + pci_cells + 1]) < lowest_cpu_addr) + lowest_cpu_addr = fdt32_to_cpu(ranges[i + pci_cells + 1]); + } - /* Calculate fixup offset from first child address (in last cell) */ - fix_offset = base - fdt32_to_cpu(ranges[2]); + /* Calculate fixup offset from the lowest (first) CPU address */ + fix_offset = base - lowest_cpu_addr; - /* If fixup offset is zero then there is nothing to fix */ + /* If fixup offset is zero there is nothing to fix */ if (!fix_offset) return 0; /* - * Fix address (last cell) of each child address and each parent - * address + * Fix each CPU address and corresponding PCI address if PCI address + * is not already remapped (has the same value) */ - for (i = 0; i < len / sizeof(u32); i += acells + pacells + scells) { + for (i = 0; i < len / sizeof(u32); + i += pci_cells + cpu_cells + size_cells) { + u32 cpu_addr; + u64 pci_addr; int idx; - /* fix child address */ - idx = i + acells - 1; + /* Fix CPU address */ + idx = i + pci_cells + cpu_cells - 1; + cpu_addr = fdt32_to_cpu(ranges[idx]); ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx, - fdt32_to_cpu(ranges[idx]) + - fix_offset); + cpu_addr + fix_offset); if (ret) return ret; - /* fix parent address */ - idx = i + acells + pacells - 1; + /* Fix PCI address only if it isn't remapped (is same as CPU) */ + idx = i + pci_cells - 1; + pci_addr = ((u64)fdt32_to_cpu(ranges[idx - 1]) << 32) | + fdt32_to_cpu(ranges[idx]); + if (cpu_addr != pci_addr) + continue; + ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx, - fdt32_to_cpu(ranges[idx]) + - fix_offset); + cpu_addr + fix_offset); if (ret) return ret; } diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 205fe3c..73da6b8 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -332,9 +332,6 @@ config MACH_SUN9I config MACH_SUN50I bool "sun50i (Allwinner A64)" select ARM64 - select SPI - select DM_SPI if SPI - select DM_SPI_FLASH select PHY_SUN4I_USB select SUN6I_PRCM select SUNXI_DE2 @@ -1038,7 +1035,7 @@ config SPL_STACK_R_ADDR config SPL_SPI_SUNXI bool "Support for SPI Flash on Allwinner SoCs in SPL" - depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40 || MACH_SUN50I_H6 + depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40 || MACH_SUN50I_H6 || MACH_SUNIV help Enable support for SPI Flash. This option allows SPL to read from sunxi SPI Flash. It uses the same method as the boot ROM, so does diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index 57078f7..0071de1 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -191,12 +191,48 @@ SPL_LOAD_IMAGE_METHOD("FEL", 0, BOOT_DEVICE_BOARD, spl_board_load_image); #define SUNXI_INVALID_BOOT_SOURCE -1 +static int suniv_get_boot_source(void) +{ + /* Get the last function call from BootROM's stack. */ + u32 brom_call = *(u32 *)(uintptr_t)(fel_stash.sp - 4); + + /* translate SUNIV BootROM stack to standard SUNXI boot sources */ + switch (brom_call) { + case SUNIV_BOOTED_FROM_MMC0: + return SUNXI_BOOTED_FROM_MMC0; + case SUNIV_BOOTED_FROM_SPI: + return SUNXI_BOOTED_FROM_SPI; + case SUNIV_BOOTED_FROM_MMC1: + return SUNXI_BOOTED_FROM_MMC2; + /* SPI NAND is not supported yet. */ + case SUNIV_BOOTED_FROM_NAND: + return SUNXI_INVALID_BOOT_SOURCE; + } + /* If we get here something went wrong try to boot from FEL.*/ + printf("Unknown boot source from BROM: 0x%x\n", brom_call); + return SUNXI_INVALID_BOOT_SOURCE; +} + static int sunxi_get_boot_source(void) { + /* + * On the ARMv5 SoCs, the SPL header in SRAM is overwritten by the + * exception vectors in U-Boot proper, so we won't find any + * information there. Also the FEL stash is only valid in the SPL, + * so we can't use that either. So if this is called from U-Boot + * proper, just return MMC0 as a placeholder, for now. + */ + if (IS_ENABLED(CONFIG_MACH_SUNIV) && + !IS_ENABLED(CONFIG_SPL_BUILD)) + return SUNXI_BOOTED_FROM_MMC0; + if (!is_boot0_magic(SPL_ADDR + 4)) /* eGON.BT0 */ return SUNXI_INVALID_BOOT_SOURCE; - return readb(SPL_ADDR + 0x28); + if (IS_ENABLED(CONFIG_MACH_SUNIV)) + return suniv_get_boot_source(); + else + return readb(SPL_ADDR + 0x28); } /* The sunxi internal brom will try to loader external bootloader @@ -276,36 +312,10 @@ unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc, return sector; } -#ifdef CONFIG_MACH_SUNIV -/* - * The suniv BROM does not pass the boot media type to SPL, so we try with the - * boot sequence in BROM: mmc0->spinor->fail. - * TODO: This has the slight chance of being wrong (invalid SPL signature, - * but valid U-Boot legacy image on the SD card), but this should be rare. - * It looks like we can deduce from some BROM state upon entering the SPL - * (registers, SP, or stack itself) where the BROM was coming from and use - * that here. - */ -void board_boot_order(u32 *spl_boot_list) -{ - /* - * See the comments above in sunxi_get_boot_device() for information - * about FEL boot. - */ - if (!is_boot0_magic(SPL_ADDR + 4)) { - spl_boot_list[0] = BOOT_DEVICE_BOARD; - return; - } - - spl_boot_list[0] = BOOT_DEVICE_MMC1; - spl_boot_list[1] = BOOT_DEVICE_SPI; -} -#else u32 spl_boot_device(void) { return sunxi_get_boot_device(); } -#endif __weak void sunxi_sram_init(void) { diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c index 910e805..734c165 100644 --- a/arch/arm/mach-sunxi/spl_spi_sunxi.c +++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c @@ -90,6 +90,7 @@ #define SPI0_CLK_DIV_BY_2 0x1000 #define SPI0_CLK_DIV_BY_4 0x1001 +#define SPI0_CLK_DIV_BY_32 0x100f /*****************************************************************************/ @@ -132,7 +133,8 @@ static uintptr_t spi0_base_address(void) if (IS_ENABLED(CONFIG_MACH_SUN50I_H6)) return 0x05010000; - if (!is_sun6i_gen_spi()) + if (!is_sun6i_gen_spi() || + IS_ENABLED(CONFIG_MACH_SUNIV)) return 0x01C05000; return 0x01C68000; @@ -156,11 +158,16 @@ static void spi0_enable_clock(void) if (!IS_ENABLED(CONFIG_MACH_SUN50I_H6)) setbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0)); - /* Divide by 4 */ - writel(SPI0_CLK_DIV_BY_4, base + (is_sun6i_gen_spi() ? - SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL)); - /* 24MHz from OSC24M */ - writel((1 << 31), CCM_SPI0_CLK); + if (IS_ENABLED(CONFIG_MACH_SUNIV)) { + /* Divide by 32, clock source is AHB clock 200MHz */ + writel(SPI0_CLK_DIV_BY_32, base + SUN6I_SPI0_CCTL); + } else { + /* Divide by 4 */ + writel(SPI0_CLK_DIV_BY_4, base + (is_sun6i_gen_spi() ? + SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL)); + /* 24MHz from OSC24M */ + writel((1 << 31), CCM_SPI0_CLK); + } if (is_sun6i_gen_spi()) { /* Enable SPI in the master mode and do a soft reset */ @@ -191,7 +198,8 @@ static void spi0_disable_clock(void) SUN4I_CTL_ENABLE); /* Disable the SPI0 clock */ - writel(0, CCM_SPI0_CLK); + if (!IS_ENABLED(CONFIG_MACH_SUNIV)) + writel(0, CCM_SPI0_CLK); /* Close the SPI0 gate */ if (!IS_ENABLED(CONFIG_MACH_SUN50I_H6)) @@ -212,6 +220,8 @@ static void spi0_init(void) if (IS_ENABLED(CONFIG_MACH_SUN50I) || IS_ENABLED(CONFIG_MACH_SUN50I_H6)) pin_function = SUN50I_GPC_SPI0; + else if (IS_ENABLED(CONFIG_MACH_SUNIV)) + pin_function = SUNIV_GPC_SPI0; spi0_pinmux_setup(pin_function); spi0_enable_clock(); diff --git a/arch/x86/include/asm/intel_gnvs.h b/arch/x86/include/asm/intel_gnvs.h index fc743dc..0b69530 100644 --- a/arch/x86/include/asm/intel_gnvs.h +++ b/arch/x86/include/asm/intel_gnvs.h @@ -47,7 +47,13 @@ enum { BINF_RW_B = 2 }; -enum { +/** + * enum cros_fw_type_t - Used to indicate Chromium OS firmware type + * + * Chromium OS uses a region of the GNVS starting at offset 0x100 to store + * various bits of information, including the type of firmware being booted + */ +enum cros_fw_type_t { FIRMWARE_TYPE_AUTO_DETECT = -1, FIRMWARE_TYPE_RECOVERY = 0, FIRMWARE_TYPE_NORMAL = 1, diff --git a/board/advantech/som-db5800-som-6867/.gitignore b/board/advantech/som-db5800-som-6867/.gitignore index 6eb8a54..39e46ba 100644 --- a/board/advantech/som-db5800-som-6867/.gitignore +++ b/board/advantech/som-db5800-som-6867/.gitignore @@ -1,3 +1,3 @@ -dsdt.aml -dsdt.asl.tmp -dsdt.c +dsdt_generated.aml +dsdt_generated.asl.tmp +dsdt_generated.c diff --git a/board/alliedtelesis/x530/x530.c b/board/alliedtelesis/x530/x530.c index 8b31045..c0ec2af 100644 --- a/board/alliedtelesis/x530/x530.c +++ b/board/alliedtelesis/x530/x530.c @@ -73,6 +73,7 @@ static struct mv_ddr_topology_map board_topology_map = { {0}, /* timing parameters */ { {0} }, /* electrical configuration */ {0}, /* electrical parameters */ + 0, /* ODT configuration */ 0, /* Clock enable mask */ 160 /* Clock delay */ }; diff --git a/board/congatec/conga-qeval20-qa3-e3845/.gitignore b/board/congatec/conga-qeval20-qa3-e3845/.gitignore index 6eb8a54..39e46ba 100644 --- a/board/congatec/conga-qeval20-qa3-e3845/.gitignore +++ b/board/congatec/conga-qeval20-qa3-e3845/.gitignore @@ -1,3 +1,3 @@ -dsdt.aml -dsdt.asl.tmp -dsdt.c +dsdt_generated.aml +dsdt_generated.asl.tmp +dsdt_generated.c diff --git a/board/coreboot/coreboot/MAINTAINERS b/board/coreboot/coreboot/MAINTAINERS index a05673b..ee12d32 100644 --- a/board/coreboot/coreboot/MAINTAINERS +++ b/board/coreboot/coreboot/MAINTAINERS @@ -2,12 +2,12 @@ COREBOOT BOARD M: Simon Glass S: Maintained F: board/coreboot/coreboot/ -F: include/configs/chromebook_link.h +F: include/configs/coreboot.h F: configs/coreboot_defconfig COREBOOT64 BOARD M: Simon Glass S: Maintained F: board/coreboot/coreboot/ -F: include/configs/chromebook_link.h +F: include/configs/coreboot.h F: configs/coreboot64_defconfig diff --git a/board/intel/bayleybay/.gitignore b/board/intel/bayleybay/.gitignore index 6eb8a54..39e46ba 100644 --- a/board/intel/bayleybay/.gitignore +++ b/board/intel/bayleybay/.gitignore @@ -1,3 +1,3 @@ -dsdt.aml -dsdt.asl.tmp -dsdt.c +dsdt_generated.aml +dsdt_generated.asl.tmp +dsdt_generated.c diff --git a/board/intel/edison/.gitignore b/board/intel/edison/.gitignore index 6eb8a54..39e46ba 100644 --- a/board/intel/edison/.gitignore +++ b/board/intel/edison/.gitignore @@ -1,3 +1,3 @@ -dsdt.aml -dsdt.asl.tmp -dsdt.c +dsdt_generated.aml +dsdt_generated.asl.tmp +dsdt_generated.c diff --git a/board/intel/galileo/.gitignore b/board/intel/galileo/.gitignore index 6eb8a54..39e46ba 100644 --- a/board/intel/galileo/.gitignore +++ b/board/intel/galileo/.gitignore @@ -1,3 +1,3 @@ -dsdt.aml -dsdt.asl.tmp -dsdt.c +dsdt_generated.aml +dsdt_generated.asl.tmp +dsdt_generated.c diff --git a/board/intel/minnowmax/.gitignore b/board/intel/minnowmax/.gitignore index 6eb8a54..39e46ba 100644 --- a/board/intel/minnowmax/.gitignore +++ b/board/intel/minnowmax/.gitignore @@ -1,3 +1,3 @@ -dsdt.aml -dsdt.asl.tmp -dsdt.c +dsdt_generated.aml +dsdt_generated.asl.tmp +dsdt_generated.c diff --git a/board/kontron/sl28/sl28.c b/board/kontron/sl28/sl28.c index e84b356..3c48a91 100644 --- a/board/kontron/sl28/sl28.c +++ b/board/kontron/sl28/sl28.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ #include +#include #include #include #include @@ -14,7 +15,9 @@ #include #include #include +#include +#include #include #include @@ -39,16 +42,68 @@ int board_eth_init(struct bd_info *bis) return pci_eth_init(bis); } +static int __sl28cpld_read(uint reg) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_NOP, + DM_DRIVER_GET(sl28cpld), &dev); + if (ret) + return ret; + + return sl28cpld_read(dev, reg); +} + +static void print_cpld_version(void) +{ + int version = __sl28cpld_read(SL28CPLD_VERSION); + + if (version < 0) + printf("CPLD: error reading version (%d)\n", version); + else + printf("CPLD: v%d\n", version); +} + int checkboard(void) { printf("EL: %d\n", current_el()); + if (CONFIG_IS_ENABLED(SL28CPLD)) + print_cpld_version(); + + return 0; +} + +static void stop_recovery_watchdog(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_WDT, + DM_DRIVER_GET(sl28cpld_wdt), &dev); + if (!ret) + wdt_stop(dev); +} + +int fsl_board_late_init(void) +{ + /* + * Usually, the after a board reset, the watchdog is enabled by + * default. This is to supervise the bootloader boot-up. Therefore, + * to prevent a watchdog reset if we don't actively kick it, we have + * to disable it. + * + * If the watchdog isn't enabled at reset (which is a configuration + * option) disabling it doesn't hurt either. + */ + if (!CONFIG_IS_ENABLED(WATCHDOG_AUTOSTART)) + stop_recovery_watchdog(); + return 0; } void detail_board_ddr_info(void) { - puts("\nDDR "); - print_size(gd->bd->bi_dram[0].size + gd->bd->bi_dram[1].size, ""); print_ddr_info(0); } diff --git a/board/solidrun/clearfog/clearfog.c b/board/solidrun/clearfog/clearfog.c index c920cf8..03adb59 100644 --- a/board/solidrun/clearfog/clearfog.c +++ b/board/solidrun/clearfog/clearfog.c @@ -147,6 +147,7 @@ static struct mv_ddr_topology_map board_topology_map = { {0}, /* timing parameters */ { {0} }, /* electrical configuration */ {0,}, /* electrical parameters */ + 0, /* ODT configuration */ 0x3, /* clock enable mask */ }; diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 82c52b2..a096159 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -171,21 +171,56 @@ void i2c_init_board(void) #endif } -#if defined(CONFIG_ENV_IS_IN_MMC) && defined(CONFIG_ENV_IS_IN_FAT) +/* + * Try to use the environment from the boot source first. + * For MMC, this means a FAT partition on the boot device (SD or eMMC). + * If the raw MMC environment is also enabled, this is tried next. + * SPI flash falls back to FAT (on SD card). + */ enum env_location env_get_location(enum env_operation op, int prio) { - switch (prio) { - case 0: - return ENVL_FAT; + enum env_location boot_loc = ENVL_FAT; - case 1: - return ENVL_MMC; + gd->env_load_prio = prio; + switch (sunxi_get_boot_device()) { + case BOOT_DEVICE_MMC1: + case BOOT_DEVICE_MMC2: + boot_loc = ENVL_FAT; + break; + case BOOT_DEVICE_NAND: + if (IS_ENABLED(CONFIG_ENV_IS_IN_NAND)) + boot_loc = ENVL_NAND; + break; + case BOOT_DEVICE_SPI: + if (IS_ENABLED(CONFIG_ENV_IS_IN_SPI_FLASH)) + boot_loc = ENVL_SPI_FLASH; + break; + case BOOT_DEVICE_BOARD: + break; default: - return ENVL_UNKNOWN; + break; + } + + /* Always try to access the environment on the boot device first. */ + if (prio == 0) + return boot_loc; + + if (prio == 1) { + switch (boot_loc) { + case ENVL_SPI_FLASH: + return ENVL_FAT; + case ENVL_FAT: + if (IS_ENABLED(CONFIG_ENV_IS_IN_MMC)) + return ENVL_MMC; + break; + default: + break; + } } + + return ENVL_UNKNOWN; } -#endif #ifdef CONFIG_DM_MMC static void mmc_pinmux_setup(int sdc); diff --git a/board/ti/am65x/evm.c b/board/ti/am65x/evm.c index fbe33cb..7182a8c 100644 --- a/board/ti/am65x/evm.c +++ b/board/ti/am65x/evm.c @@ -129,6 +129,7 @@ int ft_board_setup(void *blob, struct bd_info *bd) } #endif +#ifdef CONFIG_TI_I2C_BOARD_DETECT int do_board_detect(void) { int ret; @@ -353,23 +354,26 @@ static int probe_daughtercards(void) return 0; } +#endif int board_late_init(void) { - struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA; + if (IS_ENABLED(CONFIG_TI_I2C_BOARD_DETECT)) { + struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA; - setup_board_eeprom_env(); + setup_board_eeprom_env(); - /* - * The first MAC address for ethernet a.k.a. ethernet0 comes from - * efuse populated via the am654 gigabit eth switch subsystem driver. - * All the other ones are populated via EEPROM, hence continue with - * an index of 1. - */ - board_ti_am6_set_ethaddr(1, ep->mac_addr_cnt); + /* + * The first MAC address for ethernet a.k.a. ethernet0 comes from + * efuse populated via the am654 gigabit eth switch subsystem driver. + * All the other ones are populated via EEPROM, hence continue with + * an index of 1. + */ + board_ti_am6_set_ethaddr(1, ep->mac_addr_cnt); - /* Check for and probe any plugged-in daughtercards */ - probe_daughtercards(); + /* Check for and probe any plugged-in daughtercards */ + probe_daughtercards(); + } return 0; } diff --git a/board/ti/j721e/evm.c b/board/ti/j721e/evm.c index f479197..e6ff54c 100644 --- a/board/ti/j721e/evm.c +++ b/board/ti/j721e/evm.c @@ -397,36 +397,34 @@ void configure_serdes_torrent(void) void configure_serdes_sierra(void) { - struct udevice *dev, *lnk_dev; - struct phy serdes; + struct udevice *dev, *link_dev; + struct phy link; int ret, count, i; + int link_count = 0; if (!IS_ENABLED(CONFIG_PHY_CADENCE_SIERRA)) return; - ret = uclass_get_device_by_driver(UCLASS_PHY, + ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(sierra_phy_provider), &dev); if (ret) printf("Sierra init failed:%d\n", ret); - serdes.dev = dev; - serdes.id = 0; - count = device_get_child_count(dev); for (i = 0; i < count; i++) { - ret = device_get_child(dev, i, &lnk_dev); + ret = device_get_child(dev, i, &link_dev); if (ret) printf("probe of sierra child node %d failed\n", i); - } + if (link_dev->driver->id == UCLASS_PHY) { + link.dev = link_dev; + link.id = link_count++; - ret = generic_phy_init(&serdes); - if (ret) - printf("phy_init failed!!\n"); - - ret = generic_phy_power_on(&serdes); - if (ret) - printf("phy_power_on failed !!\n"); + ret = generic_phy_power_on(&link); + if (ret) + printf("phy_power_on failed !!\n"); + } + } } #ifdef CONFIG_BOARD_LATE_INIT diff --git a/cmd/cls.c b/cmd/cls.c index eab4e69..bdeb497 100644 --- a/cmd/cls.c +++ b/cmd/cls.c @@ -11,17 +11,23 @@ #include #include +#define CSI "\x1b[" + static int do_video_clear(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { -#if defined(CONFIG_DM_VIDEO) - struct udevice *dev; + __maybe_unused struct udevice *dev; + /* Send clear screen and home */ + printf(CSI "2J" CSI "1;1H"); +#if defined(CONFIG_DM_VIDEO) +#if !defined(CONFIG_VIDEO_ANSI) if (uclass_first_device_err(UCLASS_VIDEO, &dev)) return CMD_RET_FAILURE; if (video_clear(dev)) return CMD_RET_FAILURE; +#endif #elif defined(CONFIG_CFB_CONSOLE) video_clear(); #elif defined(CONFIG_LCD) diff --git a/cmd/pwm.c b/cmd/pwm.c index 7947e61..7e82955 100644 --- a/cmd/pwm.c +++ b/cmd/pwm.c @@ -111,5 +111,5 @@ U_BOOT_CMD(pwm, 6, 0, do_pwm, "invert - invert polarity\n" "pwm config - config PWM\n" "pwm enable - enable PWM output\n" - "pwm disable - eisable PWM output\n" + "pwm disable - disable PWM output\n" "Note: All input values are in decimal"); diff --git a/configs/j721e_evm_a72_defconfig b/configs/j721e_evm_a72_defconfig index 7929e22..d518195 100644 --- a/configs/j721e_evm_a72_defconfig +++ b/configs/j721e_evm_a72_defconfig @@ -193,3 +193,4 @@ CONFIG_UFS=y CONFIG_CADENCE_UFS=y CONFIG_TI_J721E_UFS=y CONFIG_OF_LIBFDT_OVERLAY=y +CONFIG_MMC_SPEED_MODE_SET=y diff --git a/configs/j721e_hs_evm_a72_defconfig b/configs/j721e_hs_evm_a72_defconfig index c37c20a..6850b99 100644 --- a/configs/j721e_hs_evm_a72_defconfig +++ b/configs/j721e_hs_evm_a72_defconfig @@ -162,3 +162,4 @@ CONFIG_UFS=y CONFIG_CADENCE_UFS=y CONFIG_TI_J721E_UFS=y CONFIG_OF_LIBFDT_OVERLAY=y +CONFIG_MMC_SPEED_MODE_SET=y diff --git a/configs/kontron_sl28_defconfig b/configs/kontron_sl28_defconfig index b61276c..cf8aedf 100644 --- a/configs/kontron_sl28_defconfig +++ b/configs/kontron_sl28_defconfig @@ -42,23 +42,23 @@ CONFIG_CMD_GREPENV=y CONFIG_CMD_NVEDIT_EFI=y CONFIG_CMD_DFU=y CONFIG_CMD_DM=y +CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_PCI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y +CONFIG_CMD_WDT=y CONFIG_CMD_CACHE=y CONFIG_CMD_EFIDEBUG=y CONFIG_CMD_RNG=y CONFIG_OF_CONTROL=y CONFIG_SPL_OF_CONTROL=y -CONFIG_OF_LIST="" +CONFIG_OF_LIST="fsl-ls1028a-kontron-sl28 fsl-ls1028a-kontron-sl28-var1 fsl-ls1028a-kontron-sl28-var2 fsl-ls1028a-kontron-sl28-var3 fsl-ls1028a-kontron-sl28-var4" CONFIG_ENV_OVERWRITE=y CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_SYS_REDUNDAND_ENVIRONMENT=y -CONFIG_NET_RANDOM_ETHADDR=y -CONFIG_NETCONSOLE=y CONFIG_SPL_DM_SEQ_ALIAS=y CONFIG_SATA=y CONFIG_SCSI_AHCI=y @@ -69,8 +69,10 @@ CONFIG_DDR_ECC=y CONFIG_ECC_INIT_VIA_DDRCONTROLLER=y CONFIG_DFU_MMC=y CONFIG_DFU_SF=y +CONFIG_SL28CPLD_GPIO=y CONFIG_I2C_SET_DEFAULT_BUS_NUM=y CONFIG_I2C_MUX=y +CONFIG_SL28CPLD=y CONFIG_MMC_HS400_SUPPORT=y CONFIG_FSL_ESDHC=y CONFIG_FSL_ESDHC_SUPPORT_ADMA2=y @@ -102,6 +104,11 @@ CONFIG_USB_DWC3=y CONFIG_USB_DWC3_LAYERSCAPE=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DOWNLOAD=y +# CONFIG_WATCHDOG is not set +# CONFIG_WATCHDOG_AUTOSTART is not set +CONFIG_WDT=y +CONFIG_WDT_SL28CPLD=y +CONFIG_WDT_SP805=y CONFIG_OF_LIBFDT_ASSUME_MASK=0x0 CONFIG_OF_LIBFDT_OVERLAY=y CONFIG_EFI_SET_TIME=y diff --git a/configs/libretech_all_h3_it_h5_defconfig b/configs/libretech_all_h3_it_h5_defconfig index 7f0e0be..cb7ffb4 100644 --- a/configs/libretech_all_h3_it_h5_defconfig +++ b/configs/libretech_all_h3_it_h5_defconfig @@ -7,9 +7,7 @@ CONFIG_DRAM_CLK=672 CONFIG_MMC_SUNXI_SLOT_EXTRA=2 CONFIG_SPL_SPI_SUNXI=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set -CONFIG_DM_SPI_FLASH=y CONFIG_SPI_FLASH_XMC=y CONFIG_SPI=y -CONFIG_DM_SPI=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y diff --git a/configs/libretech_all_h5_cc_h5_defconfig b/configs/libretech_all_h5_cc_h5_defconfig index 25bfe52..c3aa4b1 100644 --- a/configs/libretech_all_h5_cc_h5_defconfig +++ b/configs/libretech_all_h5_cc_h5_defconfig @@ -7,10 +7,8 @@ CONFIG_DRAM_CLK=672 CONFIG_MMC_SUNXI_SLOT_EXTRA=2 CONFIG_SPL_SPI_SUNXI=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set -CONFIG_DM_SPI_FLASH=y CONFIG_SPI_FLASH_XMC=y CONFIG_SUN8I_EMAC=y CONFIG_SPI=y -CONFIG_DM_SPI=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y diff --git a/configs/licheepi_nano_defconfig b/configs/licheepi_nano_defconfig index 2ac0ef4..67b7b85 100644 --- a/configs/licheepi_nano_defconfig +++ b/configs/licheepi_nano_defconfig @@ -9,3 +9,5 @@ CONFIG_MACH_SUNIV=y CONFIG_DRAM_CLK=156 CONFIG_DRAM_ZQ=0 # CONFIG_VIDEO_SUNXI is not set +CONFIG_SPL_SPI_SUNXI=y +# CONFIG_SYSRESET is not set diff --git a/configs/oceanic_5205_5inmfd_defconfig b/configs/oceanic_5205_5inmfd_defconfig index 9ba115c..7ce63ba 100644 --- a/configs/oceanic_5205_5inmfd_defconfig +++ b/configs/oceanic_5205_5inmfd_defconfig @@ -11,5 +11,6 @@ CONFIG_MMC0_CD_PIN="" CONFIG_SPL_SPI_SUNXI=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set CONFIG_SUN8I_EMAC=y +CONFIG_SPI=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y diff --git a/configs/orangepi_pc2_defconfig b/configs/orangepi_pc2_defconfig index 2eaddcf..777af8c 100644 --- a/configs/orangepi_pc2_defconfig +++ b/configs/orangepi_pc2_defconfig @@ -11,9 +11,11 @@ CONFIG_SPL_SPI_SUNXI=y CONFIG_SPL_I2C=y CONFIG_SPL_SYS_I2C_LEGACY=y CONFIG_SYS_I2C_MVTWSI=y +CONFIG_SPI_FLASH_MACRONIX=y CONFIG_SUN8I_EMAC=y CONFIG_SY8106A_POWER=y CONFIG_SY8106A_VOUT1_VOLT=1100 +CONFIG_SPI=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_MUSB_GADGET=y diff --git a/configs/orangepi_r1_defconfig b/configs/orangepi_r1_defconfig index 745451c..4496aa4 100644 --- a/configs/orangepi_r1_defconfig +++ b/configs/orangepi_r1_defconfig @@ -8,6 +8,8 @@ CONFIG_DRAM_CLK=624 CONFIG_SPL_SPI_SUNXI=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set CONFIG_CONSOLE_MUX=y +CONFIG_SPI_FLASH_WINBOND=y CONFIG_SUN8I_EMAC=y +CONFIG_SPI=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y diff --git a/configs/orangepi_win_defconfig b/configs/orangepi_win_defconfig index 8c2179b..3b78ad7 100644 --- a/configs/orangepi_win_defconfig +++ b/configs/orangepi_win_defconfig @@ -7,7 +7,9 @@ CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y CONFIG_MACPWR="PD14" CONFIG_SPL_SPI_SUNXI=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_SPI_FLASH_WINBOND=y CONFIG_PHY_REALTEK=y CONFIG_SUN8I_EMAC=y +CONFIG_SPI=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y diff --git a/configs/orangepi_zero2_defconfig b/configs/orangepi_zero2_defconfig index 22563c8..54faf6a 100644 --- a/configs/orangepi_zero2_defconfig +++ b/configs/orangepi_zero2_defconfig @@ -15,5 +15,7 @@ CONFIG_SPL_SYS_I2C_LEGACY=y CONFIG_SYS_I2C_MVTWSI=y CONFIG_SYS_I2C_SLAVE=0x7f CONFIG_SYS_I2C_SPEED=400000 +CONFIG_SPI_FLASH_MACRONIX=y CONFIG_PHY_REALTEK=y CONFIG_SUN8I_EMAC=y +CONFIG_SPI=y diff --git a/configs/orangepi_zero_defconfig b/configs/orangepi_zero_defconfig index 332cd47..2dc69d2 100644 --- a/configs/orangepi_zero_defconfig +++ b/configs/orangepi_zero_defconfig @@ -8,6 +8,8 @@ CONFIG_DRAM_CLK=624 CONFIG_SPL_SPI_SUNXI=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set CONFIG_CONSOLE_MUX=y +CONFIG_SPI_FLASH_WINBOND=y CONFIG_SUN8I_EMAC=y +CONFIG_SPI=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y diff --git a/configs/pine64-lts_defconfig b/configs/pine64-lts_defconfig index 6209e68..45a9e77 100644 --- a/configs/pine64-lts_defconfig +++ b/configs/pine64-lts_defconfig @@ -10,6 +10,8 @@ CONFIG_MMC0_CD_PIN="" CONFIG_MMC_SUNXI_SLOT_EXTRA=2 CONFIG_SPL_SPI_SUNXI=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_SPI_FLASH_WINBOND=y CONFIG_SUN8I_EMAC=y +CONFIG_SPI=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y diff --git a/configs/pine_h64_defconfig b/configs/pine_h64_defconfig index 1928509..1e730dd 100644 --- a/configs/pine_h64_defconfig +++ b/configs/pine_h64_defconfig @@ -11,8 +11,10 @@ CONFIG_USB3_VBUS_PIN="PL5" CONFIG_SPL_SPI_SUNXI=y # CONFIG_PSCI_RESET is not set # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +CONFIG_SPI_FLASH_WINBOND=y CONFIG_SUN8I_EMAC=y CONFIG_PHY_SUN50I_USB3=y +CONFIG_SPI=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y CONFIG_USB_EHCI_HCD=y diff --git a/configs/pinecube_defconfig b/configs/pinecube_defconfig index 0c71d59..e779663 100644 --- a/configs/pinecube_defconfig +++ b/configs/pinecube_defconfig @@ -12,8 +12,10 @@ CONFIG_SPL_SYS_I2C_LEGACY=y CONFIG_SYS_I2C_MVTWSI=y CONFIG_SYS_I2C_SLAVE=0x7f CONFIG_SYS_I2C_SPEED=400000 +CONFIG_SPI_FLASH_WINBOND=y # CONFIG_NETDEVICES is not set CONFIG_AXP209_POWER=y CONFIG_AXP_DCDC2_VOLT=1250 CONFIG_AXP_DCDC3_VOLT=3300 CONFIG_CONS_INDEX=3 +CONFIG_SPI=y diff --git a/configs/sopine_baseboard_defconfig b/configs/sopine_baseboard_defconfig index 0093076..982f7b0 100644 --- a/configs/sopine_baseboard_defconfig +++ b/configs/sopine_baseboard_defconfig @@ -13,5 +13,6 @@ CONFIG_SPL_SPI_SUNXI=y # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set CONFIG_SPI_FLASH_WINBOND=y CONFIG_SUN8I_EMAC=y +CONFIG_SPI=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_OHCI_HCD=y diff --git a/configs/tbs2910_defconfig b/configs/tbs2910_defconfig index e1278f2..8a33160 100644 --- a/configs/tbs2910_defconfig +++ b/configs/tbs2910_defconfig @@ -14,6 +14,7 @@ CONFIG_DEFAULT_DEVICE_TREE="imx6q-tbs2910" CONFIG_PRE_CON_BUF_ADDR=0x7c000000 CONFIG_CMD_HDMIDETECT=y CONFIG_AHCI=y +CONFIG_LTO=y CONFIG_SUPPORT_RAW_INITRD=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTCOMMAND=y diff --git a/configs/turris_omnia_defconfig b/configs/turris_omnia_defconfig index 280dd55..5b1fdbf 100644 --- a/configs/turris_omnia_defconfig +++ b/configs/turris_omnia_defconfig @@ -93,3 +93,4 @@ CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y CONFIG_WDT=y CONFIG_WDT_ORION=y +CONFIG_EXT4_WRITE=y diff --git a/configs/vexpress_aemv8a_semi_defconfig b/configs/vexpress_aemv8a_semi_defconfig index d55e560..50715e2 100644 --- a/configs/vexpress_aemv8a_semi_defconfig +++ b/configs/vexpress_aemv8a_semi_defconfig @@ -17,7 +17,7 @@ CONFIG_ANDROID_BOOT_IMAGE=y CONFIG_BOOTDELAY=1 CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyAMA0 earlycon=pl011,0x1c090000 debug user_debug=31 loglevel=9" -CONFIG_BOOTCOMMAND="if smhload ${boot_name} ${boot_addr_r}; then set bootargs; abootimg addr ${boot_addr_r}; abootimg get dtb --index=0 fdt_addr_r; bootm ${boot_addr_r} ${boot_addr_r} ${fdt_addr_r}; else; set fdt_high 0xffffffffffffffff; set initrd_high 0xffffffffffffffff; smhload ${kernel_name} ${kernel_addr}; smhload ${fdtfile} ${fdt_addr_r}; smhload ${ramdisk_name} ${ramdisk_addr_r} ramdisk_end; fdt addr ${fdt_addr_r}; fdt resize; fdt chosen ${ramdisk_addr_r} ${ramdisk_end}; booti $kernel_addr - $fdt_addr_r; fi" +CONFIG_BOOTCOMMAND="if smhload ${boot_name} ${boot_addr_r}; then setenv bootargs; abootimg addr ${boot_addr_r}; abootimg get dtb --index=0 fdt_addr_r; bootm ${boot_addr_r} ${boot_addr_r} ${fdt_addr_r}; else; setenv fdt_high 0xffffffffffffffff; setenv initrd_high 0xffffffffffffffff; smhload ${kernel_name} ${kernel_addr_r}; smhload ${fdtfile} ${fdt_addr_r}; smhload ${ramdisk_name} ${ramdisk_addr_r} ramdisk_end; fdt addr ${fdt_addr_r}; fdt resize; fdt chosen ${ramdisk_addr_r} ${ramdisk_end}; booti $kernel_addr_r - $fdt_addr_r; fi" # CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SYS_PROMPT="VExpress64# " diff --git a/doc/board/kontron/sl28.rst b/doc/board/kontron/sl28.rst index c7b18be..44435d9 100644 --- a/doc/board/kontron/sl28.rst +++ b/doc/board/kontron/sl28.rst @@ -23,34 +23,17 @@ Copy u-boot.rom to a TFTP server. Install the bootloader on the board ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Please note, this bootloader doesn't support the builtin watchdog (yet), -therefore you have to disable it, see below. Otherwise you'll end up in -the failsafe bootloader on every reset:: +To install the bootloader binary use the following command:: > tftp path/to/u-boot.rom > sf probe 0 > sf update $fileaddr 0x210000 $filesize -The board is fully failsafe, you can't break anything. But because you've -disabled the builtin watchdog you might have to manually enter failsafe -mode by asserting the ``FORCE_RECOV#`` line during board reset. - -Disable the builtin watchdog -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -- boot into the failsafe bootloader, either by asserting the - ``FORCE_RECOV#`` line or if you still have the original bootloader - installed you can use the command:: - - > wdt dev cpld_watchdog@4a; wdt expire 1 - -- in the failsafe bootloader use the "sl28 nvm" command to disable - the automatic start of the builtin watchdog:: - - > sl28 nvm 0008 - -- power-cycle the board - +The board is fully failsafe, you can't break anything. If builtin watchdog +is enabled, you'll automatically end up in the failsafe bootloader if +something goes wrong. If the watchdog is disabled, you have to manually +enter failsafe mode by asserting the ``FORCE_RECOV#`` line during board +reset. Update image ------------ @@ -67,20 +50,41 @@ Afterward you can copy this file to your ESP into the /EFI/UpdateCapsule/ folder. On the next EFI boot this will automatically update your bootloader. -Useful I2C tricks ------------------ +Builtin watchdog +---------------- + +The builtin watchdog will supervise the bootloader startup. If anything +goes wrong it will reset the board and boot into the failsafe bootloader. + +Once the bootloader is started successfully, it will disable the watchdog +timer. -The board has a board management controller which is not supported in -u-boot (yet). But you can use the i2c command to access it. +wdt command flags +^^^^^^^^^^^^^^^^^ -- reset into failsafe bootloader:: +The `wdt start` as well as the `wdt expire` command take a flags argument. +The supported bitmask is as follows. - > i2c mw 4a 5.1 0; i2c mw 4a 6.1 6b; i2c mw 4a 4.1 42 +| Bit | Description | +| --- | ----------------------------- | +| 0 | Enable failsafe mode | +| 1 | Lock the control register | +| 2 | Disable board reset | +| 3 | Enable WDT_TIME_OUT# line | -- read board management controller version:: +For example, you can use `wdt expire 1` to issue a reset and boot into the +failsafe bootloader. + +Disable the builtin watchdog +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - > i2c md 4a 3.1 1 +If for some reason, this isn't a desired behavior, the watchdog can also +be configured to not be enabled on board reset. It's configuration is saved +in the non-volatile board configuration bits. To change these you can use +the `sl28 nvm` command. +For more information on the non-volatile board configuration bits, see the +following section. Non-volatile Board Configuration Bits ------------------------------------- diff --git a/doc/board/sifive/unmatched.rst b/doc/board/sifive/unmatched.rst index 24a8899..a994422 100644 --- a/doc/board/sifive/unmatched.rst +++ b/doc/board/sifive/unmatched.rst @@ -560,7 +560,7 @@ Write U-boot SPL and U-boot to their partitions. .. code-block:: none - dd if=u-boot-spl.bin of=/dev/mtdblock0 bs=4096 seek=5 conv=sync + dd if=spl/u-boot-spl.bin of=/dev/mtdblock0 bs=4096 seek=5 conv=sync dd if=u-boot.itb of=/dev/mtdblock0 bs=4096 seek=261 conv=sync Power off the board. diff --git a/doc/build/gcc.rst b/doc/build/gcc.rst index b883cf7..470a7aa 100644 --- a/doc/build/gcc.rst +++ b/doc/build/gcc.rst @@ -25,11 +25,12 @@ Depending on the build targets further packages maybe needed sudo apt-get install bc bison build-essential coccinelle \ device-tree-compiler dfu-util efitools flex gdisk graphviz imagemagick \ - liblz4-tool libguestfs-tools libncurses-dev libpython3-dev libsdl2-dev \ - libssl-dev lz4 lzma lzma-alone openssl pkg-config python3 \ - python3-coverage python3-pkg-resources python3-pycryptodome \ - python3-pyelftools python3-pytest python3-sphinxcontrib.apidoc \ - python3-sphinx-rtd-theme python3-virtualenv swig + liblz4-tool libgnutls28-dev libguestfs-tools libncurses-dev \ + libpython3-dev libsdl2-dev libssl-dev lz4 lzma lzma-alone openssl \ + pkg-config python3 python3-coverage python3-pkg-resources \ + python3-pycryptodome python3-pyelftools python3-pytest \ + python3-sphinxcontrib.apidoc python3-sphinx-rtd-theme python3-virtualenv \ + swig SUSE based ~~~~~~~~~~ diff --git a/doc/kwboot.1 b/doc/kwboot.1 index acdea89..f555ff2 100644 --- a/doc/kwboot.1 +++ b/doc/kwboot.1 @@ -1,4 +1,4 @@ -.TH KWBOOT 1 "2021-08-25" +.TH KWBOOT 1 "2022-03-02" .SH NAME kwboot \- Boot Marvell Kirkwood (and others 32-bit) SoCs over a serial link. @@ -11,7 +11,7 @@ kwboot \- Boot Marvell Kirkwood (and others 32-bit) SoCs over a serial link. .SH "DESCRIPTION" The \fBkwboot\fP program boots boards based on Marvell's 32-bit -platforms including Kirkwood, Dove, A370, AXP, A375, A38x +platforms including Kirkwood, Dove, Avanta, A370, AXP, A375, A38x and A39x over their integrated UART. Boot image files will typically contain a second stage boot loader, such as U-Boot. The image file must conform to Marvell's BootROM firmware image format @@ -48,6 +48,48 @@ example U-Boot SPL does this). In such a case, this output is also written to stdout after the header is sent. .TP +.B "\-b" +Do only handshake on \fITTY\fP without uploading any file. File upload +could be done later via option \fB\-D\fP or via any other Xmodem +application, like \fBsx\fP(1). + +.TP +.B "\-d" +Do special handshake on \fITTY\fP for console debug mode. + +This will instruct BootROM to enter builtin simple console debug mode. +Should be combined with option \fB\-t\fP. + +To get a BootROM help, type this command followed by ENTER key: + +.RS 1.2i +.TP +.B ? +.RE +.IP + +Armada 38x BootROM has a bug which cause that BootROM's standard output +is turned off on UART when SPI-NOR contains valid boot image. Nevertheless +BootROM's standard input and BootROM's terminal echo are active and working +fine. To workaround this BootROM bug with standard output, it is possible +to manually overwrite BootROM variables stored in SRAM which BootROM use +for checking if standard output is enabled or not. To enable BootROM +standard output on UART, type this command folled by ENTER key: + +.RS 1.2i +.TP +.B w 0x40034100 1 +.RE + +.TP +.BI "\-D" " image" +Upload file \fIimage\fP over \fITTY\fP without initial handshake. + +This method is used primary on Dove platforms, where BootROM does +not support initial handshake for entering UART upload mode and +strapping pins (exported via e.g. buttons) are used instead. + +.TP .BI "\-p" Obsolete. Does nothing. @@ -56,12 +98,32 @@ in the image prior upload, to "UART boot" type. This is now done by default. .TP +.B "\-q" +Obsolete. Does nothing. + +It is unknown whether it did something in the past. + +.TP +.BI "\-s" " response-timeout" +Specify custom response timeout when doing handshake. Default value is 50 ms. +It is the timeout between sending two consecutive handshake patterns, meaning +how long to wait for response from BootROM. Affects only option \fB\-b\fP with +image file and option \fB\-d\fP. + +Option \fB-a\fP specify response timeout suitable for Armada XP BootROM and +currently it is 1000 ms. + +Some testing showed that specifying 24 ms as response timeout make handshake +with Armada 385 BootROM more stable. + +.TP .BI "\-t" Run a terminal program, connecting standard input and output to .RB \fITTY\fP. -If used in combination with \fB-b\fP, terminal mode is entered -immediately following a successful image upload. +If used in combination with \fB\-b\fP, \fB\-D\fP or \fB\-d\fP option, +terminal mode is entered immediately following a successful image upload +or successful handshake (if not doing image upload). If standard I/O streams connect to a console, this mode will terminate after receiving \fBctrl-\e\fP followed by \fBc\fP from console input. @@ -85,9 +147,42 @@ Tested values for \fIbaudrate\fP for Armada 38x include: 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, 3125000, 4000000 and 5200000. +.SH "EXAMPLES" + +Instruct BootROM to enter boot Xmodem boot mode, send \fIu-boot-spl.kwb\fP +kwbimage file via Xmodem on \fI/dev/ttyUSB0\fP at 115200 Bd and run terminal +program: +.IP +.B kwboot -b u-boot-spl.kwb -t /dev/ttyUSB0 + +.PP +Instruct BootROM to enter boot Xmodem boot mode, send header of +\fIu-boot-spl.kwb\fP kwbimage file via Xmodem at 115200 Bd, then instruct +BootROM to change baudrate to 5200000 Bd, send data part of the kwbimage +file via Xmodem at high speed and finally run terminal program: +.IP +.B kwboot -b u-boot-spl.kwb -B 5200000 -t /dev/ttyUSB0 + +.PP +Only send \fIu-boot-spl.kwb\fP kwbimage file via Xmodem on \fI/dev/ttyUSB0\fP +at 115200 Bd: +.IP +.B kwboot -D u-boot-spl.kwb /dev/ttyUSB0 + +.PP +Instruct BootROM to enter console debug mode and run terminal program on +\fI/dev/ttyUSB0\fP at 115200 Bd: +.IP +.B kwboot -d -t /dev/ttyUSB0 + +.PP +Only run terminal program on \fI/dev/ttyUSB0\fP at 115200 Bd: +.IP +.B kwboot -t /dev/ttyUSB0 + .SH "SEE ALSO" .PP -\fBmkimage\fP(1) +\fBmkimage\fP(1), \fBsx\fP(1) .SH "AUTHORS" diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index be64303..12972cd 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -552,4 +552,10 @@ config ZYNQMP_GPIO_MODEPIN are accessed using xilinx firmware. In modepin register, [3:0] bits set direction, [7:4] bits read IO, [11:8] bits set/clear IO. +config SL28CPLD_GPIO + bool "Kontron sl28cpld GPIO driver" + depends on DM_GPIO && SL28CPLD + help + Support GPIO access on Kontron sl28cpld board management controllers. + endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 7202979..44f0153 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -71,4 +71,5 @@ obj-$(CONFIG_NX_GPIO) += nx_gpio.o obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o obj-$(CONFIG_NOMADIK_GPIO) += nmk_gpio.o obj-$(CONFIG_MAX7320_GPIO) += max7320_gpio.o +obj-$(CONFIG_SL28CPLD_GPIO) += sl28cpld-gpio.o obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN) += zynqmp_gpio_modepin.o diff --git a/drivers/gpio/sl28cpld-gpio.c b/drivers/gpio/sl28cpld-gpio.c new file mode 100644 index 0000000..700fc3d --- /dev/null +++ b/drivers/gpio/sl28cpld-gpio.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * GPIO driver for the sl28cpld + * + * Copyright (c) 2021 Michael Walle + */ + +#include +#include +#include +#include + +/* GPIO flavor */ +#define SL28CPLD_GPIO_DIR 0x00 +#define SL28CPLD_GPIO_OUT 0x01 +#define SL28CPLD_GPIO_IN 0x02 + +/* input-only flavor */ +#define SL28CPLD_GPI_IN 0x00 + +/* output-only flavor */ +#define SL28CPLD_GPO_OUT 0x00 + +enum { + SL28CPLD_GPIO, + SL28CPLD_GPI, + SL28CPLD_GPO, +}; + +static int sl28cpld_gpio_get_value(struct udevice *dev, unsigned int gpio) +{ + ulong type = dev_get_driver_data(dev); + int val, reg; + + switch (type) { + case SL28CPLD_GPIO: + reg = SL28CPLD_GPIO_IN; + break; + case SL28CPLD_GPI: + reg = SL28CPLD_GPI_IN; + break; + case SL28CPLD_GPO: + /* we are output only, thus just return the output value */ + reg = SL28CPLD_GPO_OUT; + break; + default: + return -EINVAL; + } + + val = sl28cpld_read(dev, reg); + + return val < 0 ? val : !!(val & BIT(gpio)); +} + +static int sl28cpld_gpio_set_value(struct udevice *dev, unsigned int gpio, + int value) +{ + ulong type = dev_get_driver_data(dev); + uint reg; + + switch (type) { + case SL28CPLD_GPIO: + reg = SL28CPLD_GPIO_OUT; + break; + case SL28CPLD_GPO: + reg = SL28CPLD_GPO_OUT; + break; + case SL28CPLD_GPI: + default: + return -EINVAL; + } + + if (value) + return sl28cpld_update(dev, reg, 0, BIT(gpio)); + else + return sl28cpld_update(dev, reg, BIT(gpio), 0); +} + +static int sl28cpld_gpio_direction_input(struct udevice *dev, unsigned int gpio) +{ + ulong type = dev_get_driver_data(dev); + + switch (type) { + case SL28CPLD_GPI: + return 0; + case SL28CPLD_GPIO: + return sl28cpld_update(dev, SL28CPLD_GPIO_DIR, BIT(gpio), 0); + case SL28CPLD_GPO: + default: + return -EINVAL; + } +} + +static int sl28cpld_gpio_direction_output(struct udevice *dev, + unsigned int gpio, int value) +{ + ulong type = dev_get_driver_data(dev); + int ret; + + /* set_value() will report an error if we are input-only */ + ret = sl28cpld_gpio_set_value(dev, gpio, value); + if (ret) + return ret; + + if (type == SL28CPLD_GPIO) + return sl28cpld_update(dev, SL28CPLD_GPIO_DIR, 0, BIT(gpio)); + + return 0; +} + +static int sl28cpld_gpio_get_function(struct udevice *dev, unsigned int gpio) +{ + ulong type = dev_get_driver_data(dev); + int val; + + switch (type) { + case SL28CPLD_GPIO: + val = sl28cpld_read(dev, SL28CPLD_GPIO_DIR); + if (val < 0) + return val; + if (val & BIT(gpio)) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; + case SL28CPLD_GPI: + return GPIOF_INPUT; + case SL28CPLD_GPO: + return GPIOF_OUTPUT; + default: + return -EINVAL; + } +} + +static const struct dm_gpio_ops sl28cpld_gpio_ops = { + .direction_input = sl28cpld_gpio_direction_input, + .direction_output = sl28cpld_gpio_direction_output, + .get_value = sl28cpld_gpio_get_value, + .set_value = sl28cpld_gpio_set_value, + .get_function = sl28cpld_gpio_get_function, +}; + +static int sl28cpld_gpio_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + uc_priv->gpio_count = 8; + uc_priv->bank_name = dev_read_name(dev); + + return 0; +} + +static const struct udevice_id sl28cpld_gpio_ids[] = { + { .compatible = "kontron,sl28cpld-gpio", .data = SL28CPLD_GPIO}, + { .compatible = "kontron,sl28cpld-gpo", .data = SL28CPLD_GPO}, + { .compatible = "kontron,sl28cpld-gpi", .data = SL28CPLD_GPI}, + { } +}; + +U_BOOT_DRIVER(sl28cpld_gpio) = { + .name = "sl28cpld_gpio", + .id = UCLASS_GPIO, + .of_match = sl28cpld_gpio_ids, + .probe = sl28cpld_gpio_probe, + .ops = &sl28cpld_gpio_ops, +}; diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 0ade3e3..7029bb7 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -512,4 +512,12 @@ config ESM_PMIC config FSL_IFC bool +config SL28CPLD + bool "Enable Kontron sl28cpld multi-function driver" + depends on DM_I2C + help + Support for the Kontron sl28cpld management controller. This is + the base driver which provides common access methods for the + sub-drivers. + endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index bca7b24..f22eff6 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -82,3 +82,4 @@ obj-$(CONFIG_MICROCHIP_FLEXCOM) += microchip_flexcom.o obj-$(CONFIG_K3_AVS0) += k3_avs.o obj-$(CONFIG_ESM_K3) += k3_esm.o obj-$(CONFIG_ESM_PMIC) += esm_pmic.o +obj-$(CONFIG_SL28CPLD) += sl28cpld.o diff --git a/drivers/misc/sl28cpld.c b/drivers/misc/sl28cpld.c new file mode 100644 index 0000000..01ef1c6 --- /dev/null +++ b/drivers/misc/sl28cpld.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021 Michael Walle + */ + +#include +#include +#include + +struct sl28cpld_child_plat { + uint offset; +}; + +/* + * The access methods works either with the first argument being a child + * device or with the MFD device itself. + */ +static int sl28cpld_read_child(struct udevice *dev, uint offset) +{ + struct sl28cpld_child_plat *plat = dev_get_parent_plat(dev); + struct udevice *mfd = dev_get_parent(dev); + + return dm_i2c_reg_read(mfd, offset + plat->offset); +} + +int sl28cpld_read(struct udevice *dev, uint offset) +{ + if (dev->driver == DM_DRIVER_GET(sl28cpld)) + return dm_i2c_reg_read(dev, offset); + else + return sl28cpld_read_child(dev, offset); +} + +static int sl28cpld_write_child(struct udevice *dev, uint offset, + uint8_t value) +{ + struct sl28cpld_child_plat *plat = dev_get_parent_plat(dev); + struct udevice *mfd = dev_get_parent(dev); + + return dm_i2c_reg_write(mfd, offset + plat->offset, value); +} + +int sl28cpld_write(struct udevice *dev, uint offset, uint8_t value) +{ + if (dev->driver == DM_DRIVER_GET(sl28cpld)) + return dm_i2c_reg_write(dev, offset, value); + else + return sl28cpld_write_child(dev, offset, value); +} + +int sl28cpld_update(struct udevice *dev, uint offset, uint8_t clear, + uint8_t set) +{ + int val; + + val = sl28cpld_read(dev, offset); + if (val < 0) + return val; + + val &= ~clear; + val |= set; + + return sl28cpld_write(dev, offset, val); +} + +static int sl28cpld_probe(struct udevice *dev) +{ + i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS | + DM_I2C_CHIP_WR_ADDRESS); + + return 0; +} + +static int sl28cpld_child_post_bind(struct udevice *dev) +{ + struct sl28cpld_child_plat *plat = dev_get_parent_plat(dev); + int offset; + + if (!dev_has_ofnode(dev)) + return 0; + + offset = dev_read_u32_default(dev, "reg", -1); + if (offset == -1) + return -EINVAL; + + plat->offset = offset; + + return 0; +} + +static const struct udevice_id sl28cpld_ids[] = { + { .compatible = "kontron,sl28cpld" }, + {} +}; + +U_BOOT_DRIVER(sl28cpld) = { + .name = "sl28cpld", + .id = UCLASS_NOP, + .of_match = sl28cpld_ids, + .probe = sl28cpld_probe, + .bind = dm_scan_fdt_dev, + .flags = DM_FLAG_PRE_RELOC, + .per_child_plat_auto = sizeof(struct sl28cpld_child_plat), + .child_post_bind = sl28cpld_child_post_bind, +}; diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c index 2784738..b91df05 100644 --- a/drivers/mmc/rockchip_sdhci.c +++ b/drivers/mmc/rockchip_sdhci.c @@ -90,9 +90,33 @@ struct rockchip_sdhc { }; struct sdhci_data { - int (*emmc_set_clock)(struct sdhci_host *host, unsigned int clock); int (*emmc_phy_init)(struct udevice *dev); int (*get_phy)(struct udevice *dev); + + /** + * set_control_reg() - Set SDHCI control registers + * + * This is the set_control_reg() SDHCI operation that should be + * used for the hardware this driver data is associated with. + * Normally, this is used to set up control registers for + * voltage level and UHS speed mode. + * + * @host: SDHCI host structure + */ + void (*set_control_reg)(struct sdhci_host *host); + + /** + * set_ios_post() - Host specific hook after set_ios() calls + * + * This is the set_ios_post() SDHCI operation that should be + * used for the hardware this driver data is associated with. + * Normally, this is a hook that is called after sdhci_set_ios() + * that does any necessary host-specific configuration. + * + * @host: SDHCI host structure + * Return: 0 if successful, -ve on error + */ + int (*set_ios_post)(struct sdhci_host *host); }; static int rk3399_emmc_phy_init(struct udevice *dev) @@ -182,15 +206,28 @@ static int rk3399_emmc_get_phy(struct udevice *dev) return 0; } -static int rk3399_sdhci_emmc_set_clock(struct sdhci_host *host, unsigned int clock) +static void rk3399_sdhci_set_control_reg(struct sdhci_host *host) { struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host); + struct mmc *mmc = host->mmc; + uint clock = mmc->tran_speed; int cycle_phy = host->clock != clock && clock > EMMC_MIN_FREQ; if (cycle_phy) rk3399_emmc_phy_power_off(priv->phy); - sdhci_set_clock(host->mmc, clock); + sdhci_set_control_reg(host); +}; + +static int rk3399_sdhci_set_ios_post(struct sdhci_host *host) +{ + struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host); + struct mmc *mmc = host->mmc; + uint clock = mmc->tran_speed; + int cycle_phy = host->clock != clock && clock > EMMC_MIN_FREQ; + + if (!clock) + clock = mmc->clock; if (cycle_phy) rk3399_emmc_phy_power_on(priv->phy, clock); @@ -269,10 +306,8 @@ static int rk3568_emmc_get_phy(struct udevice *dev) return 0; } -static int rockchip_sdhci_set_ios_post(struct sdhci_host *host) +static int rk3568_sdhci_set_ios_post(struct sdhci_host *host) { - struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host); - struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev); struct mmc *mmc = host->mmc; uint clock = mmc->tran_speed; u32 reg; @@ -280,8 +315,7 @@ static int rockchip_sdhci_set_ios_post(struct sdhci_host *host) if (!clock) clock = mmc->clock; - if (data->emmc_set_clock) - data->emmc_set_clock(host, clock); + rk3568_sdhci_emmc_set_clock(host, clock); if (mmc->selected_mode == MMC_HS_400 || mmc->selected_mode == MMC_HS_400_ES) { reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); @@ -295,6 +329,26 @@ static int rockchip_sdhci_set_ios_post(struct sdhci_host *host) return 0; } +static void rockchip_sdhci_set_control_reg(struct sdhci_host *host) +{ + struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host); + struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev); + + if (data->set_control_reg) + data->set_control_reg(host); +} + +static int rockchip_sdhci_set_ios_post(struct sdhci_host *host) +{ + struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host); + struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev); + + if (data->set_ios_post) + return data->set_ios_post(host); + + return 0; +} + static int rockchip_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) { struct sdhci_host *host = dev_get_priv(mmc->dev); @@ -358,6 +412,7 @@ static int rockchip_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) static struct sdhci_ops rockchip_sdhci_ops = { .set_ios_post = rockchip_sdhci_set_ios_post, .platform_execute_tuning = &rockchip_sdhci_execute_tuning, + .set_control_reg = rockchip_sdhci_set_control_reg, }; static int rockchip_sdhci_probe(struct udevice *dev) @@ -436,15 +491,16 @@ static int rockchip_sdhci_bind(struct udevice *dev) } static const struct sdhci_data rk3399_data = { - .emmc_set_clock = rk3399_sdhci_emmc_set_clock, .get_phy = rk3399_emmc_get_phy, .emmc_phy_init = rk3399_emmc_phy_init, + .set_control_reg = rk3399_sdhci_set_control_reg, + .set_ios_post = rk3399_sdhci_set_ios_post, }; static const struct sdhci_data rk3568_data = { - .emmc_set_clock = rk3568_sdhci_emmc_set_clock, .get_phy = rk3568_emmc_get_phy, .emmc_phy_init = rk3568_emmc_phy_init, + .set_ios_post = rk3568_sdhci_set_ios_post, }; static const struct udevice_id sdhci_ids[] = { diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index b551ebd..763bab0 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -119,7 +119,7 @@ const struct flash_info spi_nor_ids[] = { }, { INFO("gd25lq128", 0xc86018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, { diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index 5a0a59a..f076693 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -30,37 +30,25 @@ #include /* PCIe unit register offsets */ -#define SELECT(x, n) ((x >> n) & 1UL) - -#define PCIE_DEV_ID_OFF 0x0000 -#define PCIE_CMD_OFF 0x0004 -#define PCIE_DEV_REV_OFF 0x0008 -#define PCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3)) -#define PCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3)) -#define PCIE_EXP_ROM_BAR_OFF 0x0030 -#define PCIE_CAPAB_OFF 0x0060 -#define PCIE_CTRL_STAT_OFF 0x0068 -#define PCIE_HEADER_LOG_4_OFF 0x0128 -#define PCIE_BAR_CTRL_OFF(n) (0x1804 + (((n) - 1) * 4)) -#define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4)) -#define PCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4)) -#define PCIE_WIN04_REMAP_OFF(n) (0x182c + ((n) << 4)) -#define PCIE_WIN5_CTRL_OFF 0x1880 -#define PCIE_WIN5_BASE_OFF 0x1884 -#define PCIE_WIN5_REMAP_OFF 0x188c -#define PCIE_CONF_ADDR_OFF 0x18f8 -#define PCIE_CONF_DATA_OFF 0x18fc -#define PCIE_MASK_OFF 0x1910 -#define PCIE_MASK_ENABLE_INTS (0xf << 24) -#define PCIE_CTRL_OFF 0x1a00 -#define PCIE_CTRL_X1_MODE BIT(0) -#define PCIE_CTRL_RC_MODE BIT(1) -#define PCIE_STAT_OFF 0x1a04 -#define PCIE_STAT_BUS (0xff << 8) -#define PCIE_STAT_DEV (0x1f << 16) -#define PCIE_STAT_LINK_DOWN BIT(0) -#define PCIE_DEBUG_CTRL 0x1a60 -#define PCIE_DEBUG_SOFT_RESET BIT(20) +#define MVPCIE_ROOT_PORT_PCI_CFG_OFF 0x0000 +#define MVPCIE_ROOT_PORT_PCI_EXP_OFF 0x0060 +#define MVPCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3)) +#define MVPCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3)) +#define MVPCIE_BAR_CTRL_OFF(n) (0x1804 + (((n) - 1) * 4)) +#define MVPCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4)) +#define MVPCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4)) +#define MVPCIE_WIN04_REMAP_OFF(n) (0x182c + ((n) << 4)) +#define MVPCIE_WIN5_CTRL_OFF 0x1880 +#define MVPCIE_WIN5_BASE_OFF 0x1884 +#define MVPCIE_WIN5_REMAP_OFF 0x188c +#define MVPCIE_CONF_ADDR_OFF 0x18f8 +#define MVPCIE_CONF_DATA_OFF 0x18fc +#define MVPCIE_CTRL_OFF 0x1a00 +#define MVPCIE_CTRL_RC_MODE BIT(1) +#define MVPCIE_STAT_OFF 0x1a04 +#define MVPCIE_STAT_BUS (0xff << 8) +#define MVPCIE_STAT_DEV (0x1f << 16) +#define MVPCIE_STAT_LINK_DOWN BIT(0) #define LINK_WAIT_RETRIES 100 #define LINK_WAIT_TIMEOUT 1000 @@ -77,7 +65,6 @@ struct mvebu_pcie { u32 lane; bool is_x4; int devfn; - u32 lane_mask; int sec_busno; char name[16]; unsigned int mem_target; @@ -90,8 +77,8 @@ struct mvebu_pcie { static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie) { u32 val; - val = readl(pcie->base + PCIE_STAT_OFF); - return !(val & PCIE_STAT_LINK_DOWN); + val = readl(pcie->base + MVPCIE_STAT_OFF); + return !(val & MVPCIE_STAT_LINK_DOWN); } static void mvebu_pcie_wait_for_link(struct mvebu_pcie *pcie) @@ -115,20 +102,20 @@ static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie *pcie, int busno) { u32 stat; - stat = readl(pcie->base + PCIE_STAT_OFF); - stat &= ~PCIE_STAT_BUS; + stat = readl(pcie->base + MVPCIE_STAT_OFF); + stat &= ~MVPCIE_STAT_BUS; stat |= busno << 8; - writel(stat, pcie->base + PCIE_STAT_OFF); + writel(stat, pcie->base + MVPCIE_STAT_OFF); } static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie *pcie, int devno) { u32 stat; - stat = readl(pcie->base + PCIE_STAT_OFF); - stat &= ~PCIE_STAT_DEV; + stat = readl(pcie->base + MVPCIE_STAT_OFF); + stat &= ~MVPCIE_STAT_DEV; stat |= devno << 16; - writel(stat, pcie->base + PCIE_STAT_OFF); + writel(stat, pcie->base + MVPCIE_STAT_OFF); } static inline struct mvebu_pcie *hose_to_pcie(struct pci_controller *hose) @@ -198,18 +185,18 @@ static int mvebu_pcie_read_config(const struct udevice *bus, pci_dev_t bdf, addr = PCI_CONF1_EXT_ADDRESS(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset); /* write address */ - writel(addr, pcie->base + PCIE_CONF_ADDR_OFF); + writel(addr, pcie->base + MVPCIE_CONF_ADDR_OFF); /* read data */ switch (size) { case PCI_SIZE_8: - data = readb(pcie->base + PCIE_CONF_DATA_OFF + (offset & 3)); + data = readb(pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 3)); break; case PCI_SIZE_16: - data = readw(pcie->base + PCIE_CONF_DATA_OFF + (offset & 2)); + data = readw(pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 2)); break; case PCI_SIZE_32: - data = readl(pcie->base + PCIE_CONF_DATA_OFF); + data = readl(pcie->base + MVPCIE_CONF_DATA_OFF); break; default: return -EINVAL; @@ -289,18 +276,18 @@ static int mvebu_pcie_write_config(struct udevice *bus, pci_dev_t bdf, addr = PCI_CONF1_EXT_ADDRESS(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset); /* write address */ - writel(addr, pcie->base + PCIE_CONF_ADDR_OFF); + writel(addr, pcie->base + MVPCIE_CONF_ADDR_OFF); /* write data */ switch (size) { case PCI_SIZE_8: - writeb(value, pcie->base + PCIE_CONF_DATA_OFF + (offset & 3)); + writeb(value, pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 3)); break; case PCI_SIZE_16: - writew(value, pcie->base + PCIE_CONF_DATA_OFF + (offset & 2)); + writew(value, pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 2)); break; case PCI_SIZE_32: - writel(value, pcie->base + PCIE_CONF_DATA_OFF); + writel(value, pcie->base + MVPCIE_CONF_DATA_OFF); break; default: return -EINVAL; @@ -324,20 +311,20 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie) /* First, disable and clear BARs and windows. */ for (i = 1; i < 3; i++) { - writel(0, pcie->base + PCIE_BAR_CTRL_OFF(i)); - writel(0, pcie->base + PCIE_BAR_LO_OFF(i)); - writel(0, pcie->base + PCIE_BAR_HI_OFF(i)); + writel(0, pcie->base + MVPCIE_BAR_CTRL_OFF(i)); + writel(0, pcie->base + MVPCIE_BAR_LO_OFF(i)); + writel(0, pcie->base + MVPCIE_BAR_HI_OFF(i)); } for (i = 0; i < 5; i++) { - writel(0, pcie->base + PCIE_WIN04_CTRL_OFF(i)); - writel(0, pcie->base + PCIE_WIN04_BASE_OFF(i)); - writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i)); + writel(0, pcie->base + MVPCIE_WIN04_CTRL_OFF(i)); + writel(0, pcie->base + MVPCIE_WIN04_BASE_OFF(i)); + writel(0, pcie->base + MVPCIE_WIN04_REMAP_OFF(i)); } - writel(0, pcie->base + PCIE_WIN5_CTRL_OFF); - writel(0, pcie->base + PCIE_WIN5_BASE_OFF); - writel(0, pcie->base + PCIE_WIN5_REMAP_OFF); + writel(0, pcie->base + MVPCIE_WIN5_CTRL_OFF); + writel(0, pcie->base + MVPCIE_WIN5_BASE_OFF); + writel(0, pcie->base + MVPCIE_WIN5_REMAP_OFF); /* Setup windows for DDR banks. Count total DDR size on the fly. */ size = 0; @@ -345,12 +332,12 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie) const struct mbus_dram_window *cs = dram->cs + i; writel(cs->base & 0xffff0000, - pcie->base + PCIE_WIN04_BASE_OFF(i)); - writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i)); + pcie->base + MVPCIE_WIN04_BASE_OFF(i)); + writel(0, pcie->base + MVPCIE_WIN04_REMAP_OFF(i)); writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | (dram->mbus_dram_target_id << 4) | 1, - pcie->base + PCIE_WIN04_CTRL_OFF(i)); + pcie->base + MVPCIE_WIN04_CTRL_OFF(i)); size += cs->size; } @@ -360,14 +347,14 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie) size = 1 << fls(size); /* Setup BAR[1] to all DRAM banks. */ - writel(dram->cs[0].base | 0xc, pcie->base + PCIE_BAR_LO_OFF(1)); - writel(0, pcie->base + PCIE_BAR_HI_OFF(1)); + writel(dram->cs[0].base | 0xc, pcie->base + MVPCIE_BAR_LO_OFF(1)); + writel(0, pcie->base + MVPCIE_BAR_HI_OFF(1)); writel(((size - 1) & 0xffff0000) | 0x1, - pcie->base + PCIE_BAR_CTRL_OFF(1)); + pcie->base + MVPCIE_BAR_CTRL_OFF(1)); /* Setup BAR[0] to internal registers. */ - writel(pcie->intregs, pcie->base + PCIE_BAR_LO_OFF(0)); - writel(0, pcie->base + PCIE_BAR_HI_OFF(0)); + writel(pcie->intregs, pcie->base + MVPCIE_BAR_LO_OFF(0)); + writel(0, pcie->base + MVPCIE_BAR_HI_OFF(0)); } /* Only enable PCIe link, do not setup it */ @@ -406,9 +393,9 @@ static void mvebu_pcie_setup_link(struct mvebu_pcie *pcie) 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); + reg = readl(pcie->base + MVPCIE_CTRL_OFF); + reg |= MVPCIE_CTRL_RC_MODE; + writel(reg, pcie->base + MVPCIE_CTRL_OFF); /* * Set Maximum Link Width to X1 or X4 in Root Port's PCIe Link @@ -417,10 +404,10 @@ static void mvebu_pcie_setup_link(struct mvebu_pcie *pcie) * 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 = readl(pcie->base + MVPCIE_ROOT_PORT_PCI_EXP_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); + writel(reg, pcie->base + MVPCIE_ROOT_PORT_PCI_EXP_OFF + PCI_EXP_LNKCAP); } static int mvebu_pcie_probe(struct udevice *dev) @@ -443,7 +430,7 @@ static int mvebu_pcie_probe(struct udevice *dev) * have the same format in Marvell's specification as in PCIe * specification, but their meaning is totally different and they do * different things: they are aliased into internal mvebu registers - * (e.g. PCIE_BAR_LO_OFF) and these should not be changed or + * (e.g. MVPCIE_BAR_LO_OFF) and these should not be changed or * reconfigured by pci device drivers. * * So our driver converts Type 0 config space to Type 1 and reports @@ -451,10 +438,10 @@ static int mvebu_pcie_probe(struct udevice *dev) * Type 1 registers is redirected to the virtual cfgcache[] buffer, * which avoids changing unrelated registers. */ - reg = readl(pcie->base + PCIE_DEV_REV_OFF); + reg = readl(pcie->base + MVPCIE_ROOT_PORT_PCI_CFG_OFF + PCI_CLASS_REVISION); reg &= ~0xffffff00; reg |= (PCI_CLASS_BRIDGE_PCI << 8) << 8; - writel(reg, pcie->base + PCIE_DEV_REV_OFF); + writel(reg, pcie->base + MVPCIE_ROOT_PORT_PCI_CFG_OFF + PCI_CLASS_REVISION); /* * mvebu uses local bus number and local device number to determinate diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index d95d4b4..fc5044f 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -358,26 +358,10 @@ static inline int cdns_reset_deassert(struct reset_control *rst) return 0; } -static inline struct cdns_sierra_inst *phy_get_drvdata(struct phy *phy) +static int cdns_sierra_link_init(struct phy *gphy) { - struct cdns_sierra_phy *sp = dev_get_priv(phy->dev); - int index; - - if (phy->id >= SIERRA_MAX_LANES) - return NULL; - - for (index = 0; index < sp->nsubnodes; index++) { - if (phy->id == sp->phys[index]->mlane) - return sp->phys[index]; - } - - return NULL; -} - -static int cdns_sierra_phy_init(struct phy *gphy) -{ - struct cdns_sierra_inst *ins = phy_get_drvdata(gphy); - struct cdns_sierra_phy *phy = dev_get_priv(gphy->dev); + struct cdns_sierra_inst *ins = dev_get_priv(gphy->dev); + struct cdns_sierra_phy *phy = dev_get_priv(gphy->dev->parent); struct cdns_sierra_data *init_data = phy->init_data; struct cdns_sierra_vals *pma_cmn_vals, *pma_ln_vals; enum cdns_sierra_phy_type phy_type = ins->phy_type; @@ -443,10 +427,11 @@ static int cdns_sierra_phy_init(struct phy *gphy) return 0; } -static int cdns_sierra_phy_on(struct phy *gphy) +static int cdns_sierra_link_on(struct phy *gphy) { - struct cdns_sierra_inst *ins = phy_get_drvdata(gphy); - struct cdns_sierra_phy *sp = dev_get_priv(gphy->dev); + struct cdns_sierra_inst *ins = dev_get_priv(gphy->dev); + struct cdns_sierra_phy *sp = dev_get_priv(gphy->dev->parent); + struct udevice *dev = gphy->dev; u32 val; int ret; @@ -503,16 +488,16 @@ static int cdns_sierra_phy_on(struct phy *gphy) return ret; } -static int cdns_sierra_phy_off(struct phy *gphy) +static int cdns_sierra_link_off(struct phy *gphy) { - struct cdns_sierra_inst *ins = phy_get_drvdata(gphy); + struct cdns_sierra_inst *ins = dev_get_priv(gphy->dev); return reset_assert_bulk(ins->lnk_rst); } -static int cdns_sierra_phy_reset(struct phy *gphy) +static int cdns_sierra_link_reset(struct phy *gphy) { - struct cdns_sierra_phy *sp = dev_get_priv(gphy->dev); + struct cdns_sierra_phy *sp = dev_get_priv(gphy->dev->parent); reset_control_assert(sp->phy_rst); reset_control_deassert(sp->phy_rst); @@ -520,10 +505,10 @@ static int cdns_sierra_phy_reset(struct phy *gphy) }; static const struct phy_ops ops = { - .init = cdns_sierra_phy_init, - .power_on = cdns_sierra_phy_on, - .power_off = cdns_sierra_phy_off, - .reset = cdns_sierra_phy_reset, + .init = cdns_sierra_link_init, + .power_on = cdns_sierra_link_on, + .power_off = cdns_sierra_link_off, + .reset = cdns_sierra_link_reset, }; struct cdns_sierra_pll_mux_sel { @@ -580,7 +565,7 @@ static const struct clk_ops cdns_sierra_pll_mux_ops = { .set_parent = cdns_sierra_pll_mux_set_parent, }; -int cdns_sierra_pll_mux_probe(struct udevice *dev) +static int cdns_sierra_pll_mux_probe(struct udevice *dev) { struct cdns_sierra_pll_mux *priv = dev_get_priv(dev); struct cdns_sierra_phy *sp = dev_get_priv(dev->parent); @@ -1012,9 +997,8 @@ static int cdns_sierra_phy_get_resets(struct cdns_sierra_phy *sp, return 0; } -static int cdns_sierra_bind_link_nodes(struct cdns_sierra_phy *sp) +static int cdns_sierra_phy_bind(struct udevice *dev) { - struct udevice *dev = sp->dev; struct driver *link_drv; ofnode child; int rc; @@ -1079,6 +1063,7 @@ U_BOOT_DRIVER(sierra_phy_link) = { .name = "sierra_phy_link", .id = UCLASS_PHY, .probe = cdns_sierra_link_probe, + .ops = &ops, .priv_auto = sizeof(struct cdns_sierra_inst), }; @@ -1141,10 +1126,6 @@ static int cdns_sierra_phy_probe(struct udevice *dev) } sp->autoconf = dev_read_bool(dev, "cdns,autoconf"); - /* Binding link nodes as children to serdes */ - ret = cdns_sierra_bind_link_nodes(sp); - if (ret) - goto clk_disable; dev_info(dev, "sierra probed\n"); return 0; @@ -1971,10 +1952,10 @@ static const struct udevice_id cdns_sierra_id_table[] = { U_BOOT_DRIVER(sierra_phy_provider) = { .name = "cdns,sierra", - .id = UCLASS_PHY, + .id = UCLASS_MISC, .of_match = cdns_sierra_id_table, .probe = cdns_sierra_phy_probe, .remove = cdns_sierra_phy_remove, - .ops = &ops, + .bind = cdns_sierra_phy_bind, .priv_auto = sizeof(struct cdns_sierra_phy), }; diff --git a/drivers/phy/nop-phy.c b/drivers/phy/nop-phy.c index e2ee6e9..d0904f4 100644 --- a/drivers/phy/nop-phy.c +++ b/drivers/phy/nop-phy.c @@ -45,11 +45,13 @@ static int nop_phy_init(struct phy *phy) #if CONFIG_IS_ENABLED(DM_GPIO) /* Take phy out of reset */ - ret = dm_gpio_set_value(&priv->reset_gpio, false); - if (ret) { - if (CONFIG_IS_ENABLED(CLK)) - clk_disable_bulk(&priv->bulk); - return ret; + if (dm_gpio_is_valid(&priv->reset_gpio)) { + ret = dm_gpio_set_value(&priv->reset_gpio, false); + if (ret) { + if (CONFIG_IS_ENABLED(CLK)) + clk_disable_bulk(&priv->bulk); + return ret; + } } #endif return 0; diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c index 1cf1f06..e76ef15 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c @@ -162,11 +162,11 @@ static struct armada_37xx_pin_group armada_37xx_nb_groups[] = { PIN_GRP_GPIO("emmc_nb", 27, 9, BIT(2), "emmc"), PIN_GRP_GPIO_3("pwm0", 11, 1, BIT(3) | BIT(20), 0, BIT(20), BIT(3), "pwm", "led"), - PIN_GRP_GPIO_3("pwm1", 11, 1, BIT(4) | BIT(21), 0, BIT(21), BIT(4), + PIN_GRP_GPIO_3("pwm1", 12, 1, BIT(4) | BIT(21), 0, BIT(21), BIT(4), "pwm", "led"), - PIN_GRP_GPIO_3("pwm2", 11, 1, BIT(5) | BIT(22), 0, BIT(22), BIT(5), + PIN_GRP_GPIO_3("pwm2", 13, 1, BIT(5) | BIT(22), 0, BIT(22), BIT(5), "pwm", "led"), - PIN_GRP_GPIO_3("pwm3", 11, 1, BIT(6) | BIT(23), 0, BIT(23), BIT(6), + PIN_GRP_GPIO_3("pwm3", 14, 1, BIT(6) | BIT(23), 0, BIT(23), BIT(6), "pwm", "led"), PIN_GRP_GPIO("pmic1", 7, 1, BIT(7), "pmic"), PIN_GRP_GPIO("pmic0", 6, 1, BIT(8), "pmic"), diff --git a/drivers/rtc/armada38x.c b/drivers/rtc/armada38x.c index 2d264ac..2af64e3 100644 --- a/drivers/rtc/armada38x.c +++ b/drivers/rtc/armada38x.c @@ -121,7 +121,7 @@ static int armada38x_rtc_reset(struct udevice *dev) armada38x_rtc_write(0, rtc, RTC_CONF_TEST); mdelay(500); armada38x_rtc_write(0, rtc, RTC_TIME); - armada38x_rtc_write(BIT(0) | BIT(1), 0, RTC_STATUS); + armada38x_rtc_write(BIT(0) | BIT(1), rtc, RTC_STATUS); } return 0; diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 362cedd..f30f352 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -66,7 +66,8 @@ static int serial_check_stdout(const void *blob, struct udevice **devp) */ if (node > 0 && !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node), devp, NULL, false)) { - if (!device_probe(*devp)) + if (device_get_uclass_id(*devp) == UCLASS_SERIAL && + !device_probe(*devp)) return 0; } diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 0a6a85f..423a757 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -185,6 +185,12 @@ config ICH_SPI access the SPI NOR flash on platforms embedding this Intel ICH IP core. +config IPROC_QSPI + bool "Broadcom iProc QSPI Flash Controller driver" + help + Enable Broadcom iProc QSPI Flash Controller driver. + This driver can be used to access the SPI NOR flash. + config KIRKWOOD_SPI bool "Marvell Kirkwood SPI Driver" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index bea746f..7f43f84 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_FSL_DSPI) += fsl_dspi.o obj-$(CONFIG_FSL_ESPI) += fsl_espi.o obj-$(CONFIG_SYNQUACER_SPI) += spi-synquacer.o obj-$(CONFIG_ICH_SPI) += ich.o +obj-$(CONFIG_IPROC_QSPI) += iproc_qspi.o obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index d1b3808..db68061 100644 --- a/drivers/spi/cadence_qspi.c +++ b/drivers/spi/cadence_qspi.c @@ -201,11 +201,9 @@ static int cadence_spi_probe(struct udevice *bus) } } - ret = reset_get_bulk(bus, &priv->resets); - if (ret) - dev_warn(bus, "Can't get reset: %d\n", ret); - else - reset_deassert_bulk(&priv->resets); + priv->resets = devm_reset_bulk_get_optional(bus); + if (priv->resets) + reset_deassert_bulk(priv->resets); if (!priv->qspi_is_init) { cadence_qspi_apb_controller_init(plat); @@ -220,8 +218,12 @@ static int cadence_spi_probe(struct udevice *bus) static int cadence_spi_remove(struct udevice *dev) { struct cadence_spi_priv *priv = dev_get_priv(dev); + int ret = 0; + + if (priv->resets) + ret = reset_release_bulk(priv->resets); - return reset_release_bulk(&priv->resets); + return ret; } static int cadence_spi_set_mode(struct udevice *bus, uint mode) diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h index 49b4011..19345ca 100644 --- a/drivers/spi/cadence_qspi.h +++ b/drivers/spi/cadence_qspi.h @@ -56,7 +56,7 @@ struct cadence_spi_priv { unsigned int qspi_calibrated_cs; unsigned int previous_hz; - struct reset_ctl_bulk resets; + struct reset_ctl_bulk *resets; }; /* Functions call declaration */ diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c index 7421211..fc22f54 100644 --- a/drivers/spi/designware_spi.c +++ b/drivers/spi/designware_spi.c @@ -572,7 +572,7 @@ static int dw_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) int pos, i, ret = 0; struct udevice *bus = slave->dev->parent; struct dw_spi_priv *priv = dev_get_priv(bus); - u8 op_len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; + u8 op_len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes; u8 op_buf[op_len]; u32 cr0; diff --git a/drivers/spi/iproc_qspi.c b/drivers/spi/iproc_qspi.c new file mode 100644 index 0000000..b5c2743 --- /dev/null +++ b/drivers/spi/iproc_qspi.c @@ -0,0 +1,576 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020-2021 Broadcom + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Delay required to change the mode of operation */ +#define BUSY_DELAY_US 1 +#define BUSY_TIMEOUT_US 200000 +#define DWORD_ALIGNED(a) (!(((ulong)(a)) & 3)) + +/* Chip attributes */ +#define QSPI_AXI_CLK 175000000 +#define SPBR_MIN 8U +#define SPBR_MAX 255U +#define NUM_CDRAM 16U + +#define CDRAM_PCS0 2 +#define CDRAM_CONT BIT(7) +#define CDRAM_BITS_EN BIT(6) +#define CDRAM_QUAD_MODE BIT(8) +#define CDRAM_RBIT_INPUT BIT(10) +#define MSPI_SPE BIT(6) +#define MSPI_CONT_AFTER_CMD BIT(7) +#define MSPI_MSTR BIT(7) + +/* Register fields */ +#define MSPI_SPCR0_MSB_BITS_8 0x00000020 +#define BSPI_RAF_CONTROL_START_MASK 0x00000001 +#define BSPI_RAF_STATUS_SESSION_BUSY_MASK 0x00000001 +#define BSPI_RAF_STATUS_FIFO_EMPTY_MASK 0x00000002 +#define BSPI_STRAP_OVERRIDE_DATA_QUAD_SHIFT 3 +#define BSPI_STRAP_OVERRIDE_4BYTE_SHIFT 2 +#define BSPI_STRAP_OVERRIDE_DATA_DUAL_SHIFT 1 +#define BSPI_STRAP_OVERRIDE_SHIFT 0 +#define BSPI_BPC_DATA_SHIFT 0 +#define BSPI_BPC_MODE_SHIFT 8 +#define BSPI_BPC_ADDR_SHIFT 16 +#define BSPI_BPC_CMD_SHIFT 24 +#define BSPI_BPP_ADDR_SHIFT 16 + +/* MSPI registers */ +#define MSPI_SPCR0_LSB_REG 0x000 +#define MSPI_SPCR0_MSB_REG 0x004 +#define MSPI_SPCR1_LSB_REG 0x008 +#define MSPI_SPCR1_MSB_REG 0x00c +#define MSPI_NEWQP_REG 0x010 +#define MSPI_ENDQP_REG 0x014 +#define MSPI_SPCR2_REG 0x018 +#define MSPI_STATUS_REG 0x020 +#define MSPI_CPTQP_REG 0x024 +#define MSPI_TX_REG 0x040 +#define MSPI_RX_REG 0x0c0 +#define MSPI_CDRAM_REG 0x140 +#define MSPI_WRITE_LOCK_REG 0x180 +#define MSPI_DISABLE_FLUSH_GEN_REG 0x184 + +/* BSPI registers */ +#define BSPI_REVISION_ID_REG 0x000 +#define BSPI_SCRATCH_REG 0x004 +#define BSPI_MAST_N_BOOT_CTRL_REG 0x008 +#define BSPI_BUSY_STATUS_REG 0x00c +#define BSPI_INTR_STATUS_REG 0x010 +#define BSPI_B0_STATUS_REG 0x014 +#define BSPI_B0_CTRL_REG 0x018 +#define BSPI_B1_STATUS_REG 0x01c +#define BSPI_B1_CTRL_REG 0x020 +#define BSPI_STRAP_OVERRIDE_CTRL_REG 0x024 +#define BSPI_FLEX_MODE_ENABLE_REG 0x028 +#define BSPI_BITS_PER_CYCLE_REG 0x02C +#define BSPI_BITS_PER_PHASE_REG 0x030 +#define BSPI_CMD_AND_MODE_BYTE_REG 0x034 +#define BSPI_FLASH_UPPER_ADDR_BYTE_REG 0x038 +#define BSPI_XOR_VALUE_REG 0x03C +#define BSPI_XOR_ENABLE_REG 0x040 +#define BSPI_PIO_MODE_ENABLE_REG 0x044 +#define BSPI_PIO_IODIR_REG 0x048 +#define BSPI_PIO_DATA_REG 0x04C + +/* RAF registers */ +#define BSPI_RAF_START_ADDRESS_REG 0x00 +#define BSPI_RAF_NUM_WORDS_REG 0x04 +#define BSPI_RAF_CTRL_REG 0x08 +#define BSPI_RAF_FULLNESS_REG 0x0C +#define BSPI_RAF_WATERMARK_REG 0x10 +#define BSPI_RAF_STATUS_REG 0x14 +#define BSPI_RAF_READ_DATA_REG 0x18 +#define BSPI_RAF_WORD_CNT_REG 0x1C +#define BSPI_RAF_CURR_ADDR_REG 0x20 + +#define XFER_DUAL BIT(30) +#define XFER_QUAD BIT(31) + +#define FLUSH_BIT BIT(0) +#define MAST_N_BOOT_BIT BIT(0) +#define WRITE_LOCK_BIT BIT(0) + +#define CEIL(m, n) (((m) + (n) - 1) / (n)) +#define UPPER_BYTE_MASK 0xFF000000 +#define SIZE_16MB 0x001000000 + +/* + * struct bcmspi_priv - qspi private structure + * + * @bspi_addr: bspi read address + * @bspi_4byte_addr: bspi 4 byte address mode + * @mspi: mspi registers block address + * @bspi: bspi registers block address + * @bspi_raf: bspi raf registers block address + */ +struct bcmspi_priv { + u32 bspi_addr; + bool bspi_4byte_addr; + fdt_addr_t mspi; + fdt_addr_t bspi; + fdt_addr_t bspi_raf; +}; + +/* BSPI mode */ + +static void bspi_flush_prefetch_buffers(struct bcmspi_priv *priv) +{ + writel(0, priv->bspi + BSPI_B0_CTRL_REG); + writel(0, priv->bspi + BSPI_B1_CTRL_REG); + writel(FLUSH_BIT, priv->bspi + BSPI_B0_CTRL_REG); + writel(FLUSH_BIT, priv->bspi + BSPI_B1_CTRL_REG); +} + +static int bspi_enable(struct bcmspi_priv *priv) +{ + /* Disable write lock */ + writel(0, priv->mspi + MSPI_WRITE_LOCK_REG); + /* Flush prefetch buffers */ + bspi_flush_prefetch_buffers(priv); + /* Switch to BSPI */ + writel(0, priv->bspi + BSPI_MAST_N_BOOT_CTRL_REG); + + return 0; +} + +static int bspi_disable(struct bcmspi_priv *priv) +{ + int ret; + uint val; + + if ((readl(priv->bspi + BSPI_MAST_N_BOOT_CTRL_REG) & 1) == 0) { + ret = readl_poll_timeout(priv->bspi + BSPI_BUSY_STATUS_REG, val, !(val & 1), + BUSY_TIMEOUT_US); + if (ret) { + printf("%s: Failed to disable bspi, device busy\n", __func__); + return ret; + } + + /* Switch to MSPI */ + writel(MAST_N_BOOT_BIT, priv->bspi + BSPI_MAST_N_BOOT_CTRL_REG); + udelay(BUSY_DELAY_US); + + val = readl(priv->bspi + BSPI_MAST_N_BOOT_CTRL_REG); + if (!(val & 1)) { + printf("%s: Failed to enable mspi\n", __func__); + return -EBUSY; + } + } + + /* Enable write lock */ + writel(WRITE_LOCK_BIT, priv->mspi + MSPI_WRITE_LOCK_REG); + + return 0; +} + +static int bspi_read_via_raf(struct bcmspi_priv *priv, u8 *rx, uint bytes) +{ + u32 status; + uint words; + int aligned; + int ret; + + /* + * Flush data from the previous session (unlikely) + * Read outstanding bits in the poll condition to empty FIFO + */ + ret = readl_poll_timeout(priv->bspi_raf + BSPI_RAF_STATUS_REG, + status, + (!readl(priv->bspi_raf + BSPI_RAF_READ_DATA_REG) && + status & BSPI_RAF_STATUS_FIFO_EMPTY_MASK) && + !(status & BSPI_RAF_STATUS_SESSION_BUSY_MASK), + BUSY_TIMEOUT_US); + if (ret) { + printf("%s: Failed to flush fifo\n", __func__); + return ret; + } + + /* Transfer is in words */ + words = CEIL(bytes, 4); + + /* Setup hardware */ + if (priv->bspi_4byte_addr) { + u32 val = priv->bspi_addr & UPPER_BYTE_MASK; + + if (val != readl(priv->bspi + BSPI_FLASH_UPPER_ADDR_BYTE_REG)) { + writel(val, priv->bspi + BSPI_FLASH_UPPER_ADDR_BYTE_REG); + bspi_flush_prefetch_buffers(priv); + } + } + + writel(priv->bspi_addr & ~UPPER_BYTE_MASK, priv->bspi_raf + BSPI_RAF_START_ADDRESS_REG); + writel(words, priv->bspi_raf + BSPI_RAF_NUM_WORDS_REG); + writel(0, priv->bspi_raf + BSPI_RAF_WATERMARK_REG); + + /* Start reading */ + writel(BSPI_RAF_CONTROL_START_MASK, priv->bspi_raf + BSPI_RAF_CTRL_REG); + aligned = DWORD_ALIGNED(rx); + while (bytes) { + status = readl(priv->bspi_raf + BSPI_RAF_STATUS_REG); + if (!(status & BSPI_RAF_STATUS_FIFO_EMPTY_MASK)) { + /* RAF is LE only, convert data to host endianness */ + u32 data = le32_to_cpu(readl(priv->bspi_raf + BSPI_RAF_READ_DATA_REG)); + + /* Check if we can use the whole word */ + if (aligned && bytes >= 4) { + *(u32 *)rx = data; + rx += 4; + bytes -= 4; + } else { + uint chunk = min(bytes, 4U); + + /* Read out bytes one by one */ + while (chunk) { + *rx++ = (u8)data; + data >>= 8; + chunk--; + bytes--; + } + } + + continue; + } + if (!(status & BSPI_RAF_STATUS_SESSION_BUSY_MASK)) { + /* FIFO is empty and the session is done */ + break; + } + } + + return 0; +} + +static int bspi_read(struct bcmspi_priv *priv, u8 *rx, uint bytes) +{ + int ret; + + /* Transfer data */ + while (bytes > 0) { + /* Special handing since RAF cannot go across 16MB boundary */ + uint trans = bytes; + /* Divide into multiple transfers if it goes across the 16MB boundary */ + if (priv->bspi_4byte_addr && (priv->bspi_addr >> 24) != + ((priv->bspi_addr + bytes) >> 24)) + trans = SIZE_16MB - (priv->bspi_addr & ~UPPER_BYTE_MASK); + + ret = bspi_read_via_raf(priv, rx, trans); + if (ret) + return ret; + + priv->bspi_addr += trans; + rx += trans; + bytes -= trans; + } + + bspi_flush_prefetch_buffers(priv); + return 0; +} + +static void bspi_set_flex_mode(struct bcmspi_priv *priv, const struct spi_mem_op *op) +{ + int bpp = (op->dummy.nbytes * 8) / op->dummy.buswidth; + int cmd = op->cmd.opcode; + int bpc = ilog2(op->data.buswidth) << BSPI_BPC_DATA_SHIFT | + ilog2(op->addr.buswidth) << BSPI_BPC_ADDR_SHIFT | + ilog2(op->cmd.buswidth) << BSPI_BPC_CMD_SHIFT; + int so = BIT(BSPI_STRAP_OVERRIDE_SHIFT) | + (op->data.buswidth > 1) << BSPI_STRAP_OVERRIDE_DATA_DUAL_SHIFT | + (op->addr.nbytes > 3) << BSPI_STRAP_OVERRIDE_4BYTE_SHIFT | + (op->data.buswidth > 3) << BSPI_STRAP_OVERRIDE_DATA_QUAD_SHIFT; + + /* Disable flex mode first */ + writel(0, priv->bspi + BSPI_FLEX_MODE_ENABLE_REG); + + /* Configure single, dual or quad mode */ + writel(bpc, priv->bspi + BSPI_BITS_PER_CYCLE_REG); + + /* Opcode */ + writel(cmd, priv->bspi + BSPI_CMD_AND_MODE_BYTE_REG); + + /* Count of dummy cycles */ + writel(bpp, priv->bspi + BSPI_BITS_PER_PHASE_REG); + + /* Enable 4-byte address */ + if (priv->bspi_4byte_addr) { + setbits_le32(priv->bspi + BSPI_BITS_PER_PHASE_REG, BIT(BSPI_BPP_ADDR_SHIFT)); + } else { + clrbits_le32(priv->bspi + BSPI_BITS_PER_PHASE_REG, BIT(BSPI_BPP_ADDR_SHIFT)); + writel(0, priv->bspi + BSPI_FLASH_UPPER_ADDR_BYTE_REG); + } + + /* Enable flex mode to take effect */ + writel(1, priv->bspi + BSPI_FLEX_MODE_ENABLE_REG); + + /* Flush prefetch buffers since 32MB window BSPI could be used */ + bspi_flush_prefetch_buffers(priv); + + /* Override the strap settings */ + writel(so, priv->bspi + BSPI_STRAP_OVERRIDE_CTRL_REG); +} + +static int bspi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) +{ + struct udevice *bus = dev_get_parent(slave->dev); + struct bcmspi_priv *priv = dev_get_priv(bus); + int ret = -ENOTSUPP; + + /* BSPI read */ + if (op->data.dir == SPI_MEM_DATA_IN && + op->data.nbytes && op->addr.nbytes) { + priv->bspi_4byte_addr = (op->addr.nbytes > 3); + priv->bspi_addr = op->addr.val; + bspi_set_flex_mode(priv, op); + ret = bspi_read(priv, op->data.buf.in, op->data.nbytes); + } + + return ret; +} + +static const struct spi_controller_mem_ops bspi_mem_ops = { + .exec_op = bspi_exec_op, +}; + +/* MSPI mode */ + +static int mspi_exec(struct bcmspi_priv *priv, uint bytes, const u8 *tx, u8 *rx, ulong flags) +{ + u32 cdr = CDRAM_PCS0 | CDRAM_CONT; + bool use_16bits = !(bytes & 1); + + if (flags & XFER_QUAD) { + cdr |= CDRAM_QUAD_MODE; + + if (!tx) + cdr |= CDRAM_RBIT_INPUT; + } + + while (bytes) { + uint chunk; + uint queues; + uint i; + uint val; + int ret; + + if (use_16bits) { + chunk = min(bytes, NUM_CDRAM * 2); + queues = (chunk + 1) / 2; + bytes -= chunk; + + /* Fill CDRAMs */ + for (i = 0; i < queues; i++) + writel(cdr | CDRAM_BITS_EN, priv->mspi + MSPI_CDRAM_REG + 4 * i); + + /* Fill TXRAMs */ + for (i = 0; i < chunk; i++) + writel(tx ? tx[i] : 0xff, priv->mspi + MSPI_TX_REG + 4 * i); + } else { + /* Determine how many bytes to process this time */ + chunk = min(bytes, NUM_CDRAM); + queues = chunk; + bytes -= chunk; + + /* Fill CDRAMs and TXRAMS */ + for (i = 0; i < chunk; i++) { + writel(cdr, priv->mspi + MSPI_CDRAM_REG + 4 * i); + writel(tx ? tx[i] : 0xff, priv->mspi + MSPI_TX_REG + 8 * i); + } + } + + /* Setup queue pointers */ + writel(0, priv->mspi + MSPI_NEWQP_REG); + writel(queues - 1, priv->mspi + MSPI_ENDQP_REG); + + /* Deassert CS if requested and it's the last transfer */ + if (bytes == 0 && (flags & SPI_XFER_END)) + clrbits_le32(priv->mspi + MSPI_CDRAM_REG + ((queues - 1) << 2), CDRAM_CONT); + + /* Kick off */ + writel(0, priv->mspi + MSPI_STATUS_REG); + if (bytes == 0 && (flags & SPI_XFER_END)) + writel(MSPI_SPE, priv->mspi + MSPI_SPCR2_REG); + else + writel(MSPI_SPE | MSPI_CONT_AFTER_CMD, + priv->mspi + MSPI_SPCR2_REG); + + ret = readl_poll_timeout(priv->mspi + MSPI_STATUS_REG, val, (val & 1), + BUSY_TIMEOUT_US); + if (ret) { + printf("%s: Failed to disable bspi, device busy\n", __func__); + return ret; + } + + /* Read data out */ + if (rx) { + if (use_16bits) { + for (i = 0; i < chunk; i++) + rx[i] = readl(priv->mspi + MSPI_RX_REG + 4 * i) & 0xff; + } else { + for (i = 0; i < chunk; i++) + rx[i] = readl(priv->mspi + MSPI_RX_REG + 8 * i + 4) & 0xff; + } + } + + /* Advance pointers */ + if (tx) + tx += chunk; + if (rx) + rx += chunk; + } + + return 0; +} + +static int mspi_xfer(struct udevice *dev, uint bitlen, const void *dout, void *din, ulong flags) +{ + struct udevice *bus = dev_get_parent(dev); + struct bcmspi_priv *priv = dev_get_priv(bus); + uint bytes; + int ret = 0; + + /* we can only transfer multiples of 8 bits */ + if (bitlen % 8) + return -EPROTONOSUPPORT; + + bytes = bitlen / 8; + + if (flags & SPI_XFER_BEGIN) { + /* Switch to MSPI */ + ret = bspi_disable(priv); + if (ret) + return ret; + } + + /* MSPI: Transfer */ + if (bytes) + ret = mspi_exec(priv, bytes, dout, din, flags); + + if (flags & SPI_XFER_END) { + /* Switch back to BSPI */ + ret = bspi_enable(priv); + if (ret) + return ret; + } + + return ret; +} + +/* iProc interface */ + +static int iproc_qspi_set_speed(struct udevice *bus, uint speed) +{ + struct bcmspi_priv *priv = dev_get_priv(bus); + uint spbr; + + /* MSPI: SCK configuration */ + spbr = (QSPI_AXI_CLK - 1) / (2 * speed) + 1; + writel(max(min(spbr, SPBR_MAX), SPBR_MIN), priv->mspi + MSPI_SPCR0_LSB_REG); + + return 0; +} + +static int iproc_qspi_set_mode(struct udevice *bus, uint mode) +{ + struct bcmspi_priv *priv = dev_get_priv(bus); + + /* MSPI: set master bit and mode */ + writel(MSPI_MSTR /* Master */ | (mode & 3), priv->mspi + MSPI_SPCR0_MSB_REG); + + return 0; +} + +static int iproc_qspi_claim_bus(struct udevice *dev) +{ + /* Nothing to do */ + return 0; +} + +static int iproc_qspi_release_bus(struct udevice *dev) +{ + struct udevice *bus = dev_get_parent(dev); + struct bcmspi_priv *priv = dev_get_priv(bus); + + /* Make sure no operation is in progress */ + writel(0, priv->mspi + MSPI_SPCR2_REG); + udelay(BUSY_DELAY_US); + + return 0; +} + +static int iproc_qspi_of_to_plat(struct udevice *bus) +{ + struct bcmspi_priv *priv = dev_get_priv(bus); + + priv->bspi = dev_read_addr_name(bus, "bspi"); + if (IS_ERR((void *)priv->bspi)) { + printf("%s: Failed to get bspi base address\n", __func__); + return PTR_ERR((void *)priv->bspi); + } + + priv->bspi_raf = dev_read_addr_name(bus, "bspi_raf"); + if (IS_ERR((void *)priv->bspi_raf)) { + printf("%s: Failed to get bspi_raf base address\n", __func__); + return PTR_ERR((void *)priv->bspi_raf); + } + + priv->mspi = dev_read_addr_name(bus, "mspi"); + if (IS_ERR((void *)priv->mspi)) { + printf("%s: Failed to get mspi base address\n", __func__); + return PTR_ERR((void *)priv->mspi); + } + + return 0; +} + +static int iproc_qspi_probe(struct udevice *bus) +{ + struct bcmspi_priv *priv = dev_get_priv(bus); + + /* configure mspi */ + writel(0, priv->mspi + MSPI_SPCR1_LSB_REG); + writel(0, priv->mspi + MSPI_SPCR1_MSB_REG); + writel(0, priv->mspi + MSPI_NEWQP_REG); + writel(0, priv->mspi + MSPI_ENDQP_REG); + writel(0, priv->mspi + MSPI_SPCR2_REG); + + /* configure bspi */ + bspi_enable(priv); + + return 0; +} + +static const struct dm_spi_ops iproc_qspi_ops = { + .claim_bus = iproc_qspi_claim_bus, + .release_bus = iproc_qspi_release_bus, + .xfer = mspi_xfer, + .set_speed = iproc_qspi_set_speed, + .set_mode = iproc_qspi_set_mode, + .mem_ops = &bspi_mem_ops, +}; + +static const struct udevice_id iproc_qspi_ids[] = { + { .compatible = "brcm,iproc-qspi" }, + { } +}; + +U_BOOT_DRIVER(iproc_qspi) = { + .name = "iproc_qspi", + .id = UCLASS_SPI, + .of_match = iproc_qspi_ids, + .ops = &iproc_qspi_ops, + .of_to_plat = iproc_qspi_of_to_plat, + .priv_auto = sizeof(struct bcmspi_priv), + .probe = iproc_qspi_probe, +}; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 1f3ca99..5b614cf 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -267,6 +267,13 @@ config WDT_SBSA In the single stage mode, when the timeout is reached, your system will be reset by WS1. The first signal (WS0) is ignored. +config WDT_SL28CPLD + bool "sl28cpld watchdog timer support" + depends on WDT && SL28CPLD + help + Enable support for the watchdog timer in the Kontron sl28cpld + management controller. + config WDT_SP805 bool "SP805 watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 6d2b382..a35bd55 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_WDT_OCTEONTX) += octeontx_wdt.o obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o obj-$(CONFIG_WDT_K3_RTI) += rti_wdt.o +obj-$(CONFIG_WDT_SL28CPLD) += sl28cpld-wdt.o obj-$(CONFIG_WDT_SP805) += sp805_wdt.o obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o diff --git a/drivers/watchdog/armada-37xx-wdt.c b/drivers/watchdog/armada-37xx-wdt.c index 2e119b9..bacebbc 100644 --- a/drivers/watchdog/armada-37xx-wdt.c +++ b/drivers/watchdog/armada-37xx-wdt.c @@ -58,13 +58,11 @@ static void counter_disable(struct a37xx_wdt *priv, int id) clrbits_le32(priv->reg + CNTR_CTRL(id), CNTR_CTRL_ENABLE); } -static int init_counter(struct a37xx_wdt *priv, int id, u32 mode, u32 trig_src) +static void init_counter(struct a37xx_wdt *priv, int id, u32 mode, u32 trig_src) { u32 reg; reg = readl(priv->reg + CNTR_CTRL(id)); - if (reg & CNTR_CTRL_ACTIVE) - return -EBUSY; reg &= ~(CNTR_CTRL_MODE_MASK | CNTR_CTRL_PRESCALE_MASK | CNTR_CTRL_TRIG_SRC_MASK); @@ -79,8 +77,6 @@ static int init_counter(struct a37xx_wdt *priv, int id, u32 mode, u32 trig_src) reg |= trig_src; writel(reg, priv->reg + CNTR_CTRL(id)); - - return 0; } static int a37xx_wdt_reset(struct udevice *dev) @@ -116,16 +112,9 @@ static int a37xx_wdt_expire_now(struct udevice *dev, ulong flags) static int a37xx_wdt_start(struct udevice *dev, u64 ms, ulong flags) { struct a37xx_wdt *priv = dev_get_priv(dev); - int err; - - err = init_counter(priv, 0, CNTR_CTRL_MODE_ONESHOT, 0); - if (err < 0) - return err; - err = init_counter(priv, 1, CNTR_CTRL_MODE_HWSIG, - CNTR_CTRL_TRIG_SRC_PREV_CNTR); - if (err < 0) - return err; + init_counter(priv, 0, CNTR_CTRL_MODE_ONESHOT, 0); + init_counter(priv, 1, CNTR_CTRL_MODE_HWSIG, CNTR_CTRL_TRIG_SRC_PREV_CNTR); priv->timeout = ms * priv->clk_rate / 1000 / CNTR_CTRL_PRESCALE_MIN; diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c index 253286d..8d93f19 100644 --- a/drivers/watchdog/rti_wdt.c +++ b/drivers/watchdog/rti_wdt.c @@ -41,7 +41,7 @@ struct rti_wdt_priv { phys_addr_t regs; - unsigned int clk_khz; + unsigned int clk_hz; }; #ifdef CONFIG_WDT_K3_RTI_LOAD_FW @@ -139,7 +139,7 @@ static int rti_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) if (ret < 0) return ret; - timer_margin = timeout_ms * priv->clk_khz / 1000; + timer_margin = timeout_ms * priv->clk_hz / 1000; timer_margin >>= WDT_PRELOAD_SHIFT; if (timer_margin > WDT_PRELOAD_MAX) timer_margin = WDT_PRELOAD_MAX; @@ -185,7 +185,15 @@ static int rti_wdt_probe(struct udevice *dev) if (ret) return ret; - priv->clk_khz = clk_get_rate(&clk); + priv->clk_hz = clk_get_rate(&clk); + + /* + * If watchdog is running at 32k clock, it is not accurate. + * Adjust frequency down in this case so that it does not expire + * earlier than expected. + */ + if (priv->clk_hz < 32768) + priv->clk_hz = priv->clk_hz * 9 / 10; return 0; } diff --git a/drivers/watchdog/sl28cpld-wdt.c b/drivers/watchdog/sl28cpld-wdt.c new file mode 100644 index 0000000..af5a6b1 --- /dev/null +++ b/drivers/watchdog/sl28cpld-wdt.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Watchdog driver for the sl28cpld + * + * Copyright (c) 2021 Michael Walle + */ + +#include +#include +#include +#include +#include + +#define SL28CPLD_WDT_CTRL 0x00 +#define WDT_CTRL_EN0 BIT(0) +#define WDT_CTRL_EN1 BIT(1) +#define WDT_CTRL_EN_MASK GENMASK(1, 0) +#define WDT_CTRL_LOCK BIT(2) +#define WDT_CTRL_ASSERT_SYS_RESET BIT(6) +#define WDT_CTRL_ASSERT_WDT_TIMEOUT BIT(7) +#define SL28CPLD_WDT_TIMEOUT 0x01 +#define SL28CPLD_WDT_KICK 0x02 +#define WDT_KICK_VALUE 0x6b + +static int sl28cpld_wdt_reset(struct udevice *dev) +{ + return sl28cpld_write(dev, SL28CPLD_WDT_KICK, WDT_KICK_VALUE); +} + +static int sl28cpld_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + int ret, val; + + val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL); + if (val < 0) + return val; + + /* (1) disable watchdog */ + val &= ~WDT_CTRL_EN_MASK; + ret = sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val); + if (ret) + return ret; + + /* (2) set timeout */ + ret = sl28cpld_write(dev, SL28CPLD_WDT_TIMEOUT, lldiv(timeout, 1000)); + if (ret) + return ret; + + /* (3) kick it, will reset timer to the timeout value */ + ret = sl28cpld_wdt_reset(dev); + if (ret) + return ret; + + /* (4) enable either recovery or normal one */ + if (flags & BIT(0)) + val |= WDT_CTRL_EN1; + else + val |= WDT_CTRL_EN0; + + if (flags & BIT(1)) + val |= WDT_CTRL_LOCK; + + if (flags & BIT(2)) + val &= ~WDT_CTRL_ASSERT_SYS_RESET; + else + val |= WDT_CTRL_ASSERT_SYS_RESET; + + if (flags & BIT(3)) + val |= WDT_CTRL_ASSERT_WDT_TIMEOUT; + else + val &= ~WDT_CTRL_ASSERT_WDT_TIMEOUT; + + return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val); +} + +static int sl28cpld_wdt_stop(struct udevice *dev) +{ + int val; + + val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL); + if (val < 0) + return val; + + return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val & ~WDT_CTRL_EN_MASK); +} + +static int sl28cpld_wdt_expire_now(struct udevice *dev, ulong flags) +{ + return sl28cpld_wdt_start(dev, 0, flags); +} + +static const struct wdt_ops sl28cpld_wdt_ops = { + .start = sl28cpld_wdt_start, + .reset = sl28cpld_wdt_reset, + .stop = sl28cpld_wdt_stop, + .expire_now = sl28cpld_wdt_expire_now, +}; + +static const struct udevice_id sl28cpld_wdt_ids[] = { + { .compatible = "kontron,sl28cpld-wdt", }, + {} +}; + +U_BOOT_DRIVER(sl28cpld_wdt) = { + .name = "sl28cpld-wdt", + .id = UCLASS_WDT, + .of_match = sl28cpld_wdt_ids, + .ops = &sl28cpld_wdt_ops, +}; diff --git a/drivers/watchdog/wdt-uclass.c b/drivers/watchdog/wdt-uclass.c index 6d0f473..dbf5564 100644 --- a/drivers/watchdog/wdt-uclass.c +++ b/drivers/watchdog/wdt-uclass.c @@ -36,6 +36,8 @@ struct wdt_priv { ulong next_reset; /* Whether watchdog_start() has been called on the device. */ bool running; + /* No autostart */ + bool noautostart; }; static void init_watchdog_dev(struct udevice *dev) @@ -52,7 +54,7 @@ static void init_watchdog_dev(struct udevice *dev) dev->name); } - if (!IS_ENABLED(CONFIG_WATCHDOG_AUTOSTART)) { + if (!IS_ENABLED(CONFIG_WATCHDOG_AUTOSTART) || priv->noautostart) { printf("WDT: Not starting %s\n", dev->name); return; } @@ -256,16 +258,19 @@ static int wdt_pre_probe(struct udevice *dev) * indicated by a hw_margin_ms property. */ ulong reset_period = 1000; + bool noautostart = false; struct wdt_priv *priv; if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { timeout = dev_read_u32_default(dev, "timeout-sec", timeout); reset_period = dev_read_u32_default(dev, "hw_margin_ms", 4 * reset_period) / 4; + noautostart = dev_read_bool(dev, "u-boot,noautostart"); } priv = dev_get_uclass_priv(dev); priv->timeout = timeout; priv->reset_period = reset_period; + priv->noautostart = noautostart; /* * Pretend this device was last reset "long" ago so the first * watchdog_reset will actually call its ->reset method. diff --git a/env/Kconfig b/env/Kconfig index 20f395f..443f2f7 100644 --- a/env/Kconfig +++ b/env/Kconfig @@ -320,6 +320,7 @@ config ENV_IS_IN_SPI_FLASH default y if NORTHBRIDGE_INTEL_IVYBRIDGE default y if INTEL_QUARK default y if INTEL_QUEENSBAY + default y if ARCH_SUNXI help Define this if you have a SPI Flash memory device which you want to use for the environment. @@ -536,7 +537,7 @@ config ENV_OFFSET ENV_IS_IN_SPI_FLASH default 0x3f8000 if ARCH_ROCKCHIP && ENV_IS_IN_MMC default 0x140000 if ARCH_ROCKCHIP && ENV_IS_IN_SPI_FLASH - default 0x88000 if ARCH_SUNXI + default 0xF0000 if ARCH_SUNXI default 0xE0000 if ARCH_ZYNQ default 0x1E00000 if ARCH_ZYNQMP default 0x7F40000 if ARCH_VERSAL @@ -559,7 +560,8 @@ config ENV_OFFSET_REDUND config ENV_SIZE hex "Environment Size" default 0x40000 if ENV_IS_IN_SPI_FLASH && ARCH_ZYNQMP - default 0x20000 if ARCH_SUNXI || ARCH_ZYNQ || ARCH_OMAP2PLUS || ARCH_AT91 + default 0x20000 if ARCH_ZYNQ || ARCH_OMAP2PLUS || ARCH_AT91 + default 0x10000 if ARCH_SUNXI default 0x8000 if ARCH_ROCKCHIP && ENV_IS_IN_MMC default 0x2000 if ARCH_ROCKCHIP && ENV_IS_IN_SPI_FLASH default 0x8000 if ARCH_ZYNQMP || ARCH_VERSAL @@ -575,6 +577,7 @@ config ENV_SECT_SIZE default 0x40000 if ARCH_ZYNQMP || ARCH_VERSAL default 0x20000 if ARCH_ZYNQ || ARCH_OMAP2PLUS || ARCH_AT91 default 0x20000 if MICROBLAZE && ENV_IS_IN_SPI_FLASH + default 0x10000 if ARCH_SUNXI && ENV_IS_IN_SPI_FLASH help Size of the sector containing the environment. diff --git a/include/configs/lx2160a_common.h b/include/configs/lx2160a_common.h index c407fa8..469989a 100644 --- a/include/configs/lx2160a_common.h +++ b/include/configs/lx2160a_common.h @@ -243,12 +243,36 @@ "run distro_bootcmd;run sd2_bootcmd;" \ "env exists secureboot && esbc_halt;" +#ifdef CONFIG_CMD_USB +#define BOOT_TARGET_DEVICES_USB(func) func(USB, usb, 0) +#else +#define BOOT_TARGET_DEVICES_USB(func) +#endif + +#ifdef CONFIG_MMC +#define BOOT_TARGET_DEVICES_MMC(func, instance) func(MMC, mmc, instance) +#else +#define BOOT_TARGET_DEVICES_MMC(func) +#endif + +#ifdef CONFIG_SCSI +#define BOOT_TARGET_DEVICES_SCSI(func) func(SCSI, scsi, 0) +#else +#define BOOT_TARGET_DEVICES_SCSI(func) +#endif + +#ifdef CONFIG_CMD_DHCP +#define BOOT_TARGET_DEVICES_DHCP(func) func(DHCP, dhcp, na) +#else +#define BOOT_TARGET_DEVICES_DHCP(func) +#endif + #define BOOT_TARGET_DEVICES(func) \ - func(USB, usb, 0) \ - func(MMC, mmc, 0) \ - func(MMC, mmc, 1) \ - func(SCSI, scsi, 0) \ - func(DHCP, dhcp, na) + BOOT_TARGET_DEVICES_USB(func) \ + BOOT_TARGET_DEVICES_MMC(func, 0) \ + BOOT_TARGET_DEVICES_MMC(func, 1) \ + BOOT_TARGET_DEVICES_SCSI(func) \ + BOOT_TARGET_DEVICES_DHCP(func) #include #endif /* __LX2_COMMON_H */ diff --git a/include/configs/ti_armv7_common.h b/include/configs/ti_armv7_common.h index 9733707..7483bc8 100644 --- a/include/configs/ti_armv7_common.h +++ b/include/configs/ti_armv7_common.h @@ -55,7 +55,7 @@ "do;" \ "setenv overlaystring ${overlaystring}'#'${overlay};" \ "done;\0" \ - "run_fit=bootm ${addr_fit}#${fdtfile}${overlaystring}\0" \ + "run_fit=bootm ${addr_fit}#conf-${fdtfile}${overlaystring}\0" \ /* * DDR information. If the CONFIG_NR_DRAM_BANKS is not defined, diff --git a/include/efi_loader.h b/include/efi_loader.h index e390d32..110d8ae 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -342,7 +342,7 @@ struct efi_open_protocol_info_item { */ struct efi_handler { struct list_head link; - const efi_guid_t *guid; + const efi_guid_t guid; void *protocol_interface; struct list_head open_infos; }; diff --git a/include/sl28cpld.h b/include/sl28cpld.h new file mode 100644 index 0000000..9a7c6de --- /dev/null +++ b/include/sl28cpld.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2021 Michael Walle + */ + +#ifndef __SL28CPLD_H +#define __SL28CPLD_H + +#define SL28CPLD_VERSION 0x03 + +int sl28cpld_read(struct udevice *dev, uint offset); +int sl28cpld_write(struct udevice *dev, uint offset, uint8_t value); +int sl28cpld_update(struct udevice *dev, uint offset, uint8_t clear, + uint8_t set); + +#endif diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 82128ac..d0f3e05 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -552,7 +552,7 @@ efi_status_t efi_search_protocol(const efi_handle_t handle, struct efi_handler *protocol; protocol = list_entry(lhandle, struct efi_handler, link); - if (!guidcmp(protocol->guid, protocol_guid)) { + if (!guidcmp(&protocol->guid, protocol_guid)) { if (handler) *handler = protocol; return EFI_SUCCESS; @@ -604,7 +604,7 @@ efi_status_t efi_remove_all_protocols(const efi_handle_t handle) list_for_each_entry_safe(protocol, pos, &efiobj->protocols, link) { efi_status_t ret; - ret = efi_remove_protocol(handle, protocol->guid, + ret = efi_remove_protocol(handle, &protocol->guid, protocol->protocol_interface); if (ret != EFI_SUCCESS) return ret; @@ -1131,7 +1131,7 @@ efi_status_t efi_add_protocol(const efi_handle_t handle, handler = calloc(1, sizeof(struct efi_handler)); if (!handler) return EFI_OUT_OF_RESOURCES; - handler->guid = protocol; + memcpy((void *)&handler->guid, protocol, sizeof(efi_guid_t)); handler->protocol_interface = protocol_interface; INIT_LIST_HEAD(&handler->open_infos); list_add_tail(&handler->link, &efiobj->protocols); @@ -1227,7 +1227,7 @@ static efi_status_t efi_get_drivers(efi_handle_t handle, /* Count all driver associations */ list_for_each_entry(handler, &handle->protocols, link) { - if (protocol && guidcmp(handler->guid, protocol)) + if (protocol && guidcmp(&handler->guid, protocol)) continue; list_for_each_entry(item, &handler->open_infos, link) { if (item->info.attributes & @@ -1249,7 +1249,7 @@ static efi_status_t efi_get_drivers(efi_handle_t handle, return EFI_OUT_OF_RESOURCES; /* Collect unique driver handles */ list_for_each_entry(handler, &handle->protocols, link) { - if (protocol && guidcmp(handler->guid, protocol)) + if (protocol && guidcmp(&handler->guid, protocol)) continue; list_for_each_entry(item, &handler->open_infos, link) { if (item->info.attributes & @@ -2446,7 +2446,7 @@ static efi_status_t EFIAPI efi_protocols_per_handle( protocol = list_entry(protocol_handle, struct efi_handler, link); - (*protocol_buffer)[j] = (void *)protocol->guid; + (*protocol_buffer)[j] = (void *)&protocol->guid; ++j; } } @@ -3094,7 +3094,7 @@ close_next: (efi_handle_t)image_obj) continue; r = EFI_CALL(efi_close_protocol - (efiobj, protocol->guid, + (efiobj, &protocol->guid, info->info.agent_handle, info->info.controller_handle )); diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index 5df3593..9611398 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -91,7 +91,7 @@ void efi_print_image_infos(void *pc) list_for_each_entry(efiobj, &efi_obj_list, link) { list_for_each_entry(handler, &efiobj->protocols, link) { - if (!guidcmp(handler->guid, &efi_guid_loaded_image)) { + if (!guidcmp(&handler->guid, &efi_guid_loaded_image)) { efi_print_image_info( (struct efi_loaded_image_obj *)efiobj, handler->protocol_interface, pc); diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c index 3e7b798..b2a2119 100644 --- a/lib/rsa/rsa-sign.c +++ b/lib/rsa/rsa-sign.c @@ -383,12 +383,11 @@ static int rsa_sign_with_key(EVP_PKEY *pkey, struct padding_algo *padding_algo, goto err_alloc; } - context = EVP_MD_CTX_create(); + context = EVP_MD_CTX_new(); if (!context) { ret = rsa_err("EVP context creation failed"); goto err_create; } - EVP_MD_CTX_init(context); ckey = EVP_PKEY_CTX_new(pkey, NULL); if (!ckey) { @@ -425,8 +424,7 @@ static int rsa_sign_with_key(EVP_PKEY *pkey, struct padding_algo *padding_algo, goto err_sign; } - EVP_MD_CTX_reset(context); - EVP_MD_CTX_destroy(context); + EVP_MD_CTX_free(context); debug("Got signature: %zu bytes, expected %d\n", size, EVP_PKEY_size(pkey)); *sigp = sig; @@ -435,7 +433,7 @@ static int rsa_sign_with_key(EVP_PKEY *pkey, struct padding_algo *padding_algo, return 0; err_sign: - EVP_MD_CTX_destroy(context); + EVP_MD_CTX_free(context); err_create: free(sig); err_alloc: diff --git a/tools/Makefile b/tools/Makefile index 5409ff2..60231c7 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -196,6 +196,9 @@ hostprogs-$(CONFIG_EXYNOS5250) += mkexynosspl hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl HOSTCFLAGS_mkexynosspl.o := -pedantic +HOSTCFLAGS_kwboot.o += -pthread +HOSTLDLIBS_kwboot += -pthread -ltinfo + ifdtool-objs := $(LIBFDT_OBJS) ifdtool.o hostprogs-$(CONFIG_X86) += ifdtool diff --git a/tools/kwboot.c b/tools/kwboot.c index 68c0ef1..9f2dd2d 100644 --- a/tools/kwboot.c +++ b/tools/kwboot.c @@ -1,15 +1,40 @@ /* * Boot a Marvell SoC, with Xmodem over UART0. - * supports Kirkwood, Dove, Armada 370, Armada XP, Armada 375, Armada 38x and - * Armada 39x + * supports Kirkwood, Dove, Avanta, Armada 370, Armada XP, Armada 375, + * Armada 38x and Armada 39x. * * (c) 2012 Daniel Stodden * (c) 2021 Pali Rohár * (c) 2021 Marek Behún * - * References: marvell.com, "88F6180, 88F6190, 88F6192, and 88F6281 - * Integrated Controller: Functional Specifications" December 2, - * 2008. Chapter 24.2 "BootROM Firmware". + * References: + * - "88F6180, 88F6190, 88F6192, and 88F6281: Integrated Controller: Functional + * Specifications" December 2, 2008. Chapter 24.2 "BootROM Firmware". + * https://web.archive.org/web/20130730091033/https://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf + * - "88AP510: High-Performance SoC with Integrated CPU, 2D/3D Graphics + * Processor, and High-Definition Video Decoder: Functional Specifications" + * August 3, 2011. Chapter 5 "BootROM Firmware" + * https://web.archive.org/web/20120130172443/https://www.marvell.com/application-processors/armada-500/assets/Armada-510-Functional-Spec.pdf + * - "88F6710, 88F6707, and 88F6W11: ARMADA(R) 370 SoC: Functional Specifications" + * May 26, 2014. Chapter 6 "BootROM Firmware". + * https://web.archive.org/web/20140617183701/https://www.marvell.com/embedded-processors/armada-300/assets/ARMADA370-FunctionalSpec-datasheet.pdf + * - "MV78230, MV78260, and MV78460: ARMADA(R) XP Family of Highly Integrated + * Multi-Core ARMv7 Based SoC Processors: Functional Specifications" + * May 29, 2014. Chapter 6 "BootROM Firmware". + * https://web.archive.org/web/20180829171131/https://www.marvell.com/embedded-processors/armada-xp/assets/ARMADA-XP-Functional-SpecDatasheet.pdf + * - "ARMADA(R) 375 Value-Performance Dual Core CPU System on Chip: Functional + * Specifications" Doc. No. MV-S109377-00, Rev. A. September 18, 2013. + * Chapter 7 "Boot Sequence" + * CONFIDENTIAL, no public documentation available + * - "88F6810, 88F6811, 88F6821, 88F6W21, 88F6820, and 88F6828: ARMADA(R) 38x + * Family High-Performance Single/Dual CPU System on Chip: Functional + * Specifications" Doc. No. MV-S109094-00, Rev. C. August 2, 2015. + * Chapter 7 "Boot Flow" + * CONFIDENTIAL, no public documentation available + * - "88F6920, 88F6925 and 88F6928: ARMADA(R) 39x High-Performance Dual Core CPU + * System on Chip Functional Specifications" Doc. No. MV-S109896-00, Rev. B. + * December 22, 2015. Chapter 7 "Boot Flow" + * CONFIDENTIAL, no public documentation available */ #include "kwbimage.h" @@ -28,6 +53,7 @@ #include #include #include +#include #ifdef __linux__ #include "termios_linux.h" @@ -36,6 +62,13 @@ #endif /* + * These functions are in header file, but this header file conflicts + * with "termios_linux.h" header file. So declare these functions manually. + */ +extern int setupterm(const char *, int, int *); +extern char *tigetstr(const char *); + +/* * Marvell BootROM UART Sensing */ @@ -48,11 +81,9 @@ static unsigned char kwboot_msg_debug[] = { }; /* Defines known to work on Kirkwood */ -#define KWBOOT_MSG_REQ_DELAY 10 /* ms */ #define KWBOOT_MSG_RSP_TIMEO 50 /* ms */ /* Defines known to work on Armada XP */ -#define KWBOOT_MSG_REQ_DELAY_AXP 1000 /* ms */ #define KWBOOT_MSG_RSP_TIMEO_AXP 1000 /* ms */ /* @@ -285,7 +316,6 @@ static const char kwb_baud_magic[16] = "$baudratechange"; static int kwboot_verbose; -static int msg_req_delay = KWBOOT_MSG_REQ_DELAY; static int msg_rsp_timeo = KWBOOT_MSG_RSP_TIMEO; static int blk_rsp_timeo = KWBOOT_BLK_RSP_TIMEO; @@ -720,42 +750,120 @@ out: return rc; } +static void * +kwboot_msg_write_handler(void *arg) +{ + int tty = *(int *)((void **)arg)[0]; + const void *msg = ((void **)arg)[1]; + int rsp_timeo = msg_rsp_timeo; + int i, dummy_oldtype; + + /* allow to cancel this thread at any time */ + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &dummy_oldtype); + + while (1) { + /* write 128 samples of message pattern into the output queue without waiting */ + for (i = 0; i < 128; i++) { + if (kwboot_tty_send(tty, msg, 8, 1) < 0) { + perror("\nFailed to send message pattern"); + exit(1); + } + } + /* wait until output queue is transmitted and then make pause */ + if (tcdrain(tty) < 0) { + perror("\nFailed to send message pattern"); + exit(1); + } + /* BootROM requires pause on UART after it detects message pattern */ + usleep(rsp_timeo * 1000); + } +} + static int -kwboot_bootmsg(int tty, void *msg) +kwboot_msg_start_thread(pthread_t *thread, int *tty, void *msg) { - struct kwboot_block block; + void *arg[2]; int rc; - char c; - int count; - if (msg == NULL) - kwboot_printv("Please reboot the target into UART boot mode..."); - else - kwboot_printv("Sending boot message. Please reboot the target..."); + arg[0] = tty; + arg[1] = msg; + rc = pthread_create(thread, NULL, kwboot_msg_write_handler, arg); + if (rc) { + errno = rc; + return -1; + } - do { - rc = tcflush(tty, TCIOFLUSH); - if (rc) - break; + return 0; +} - for (count = 0; count < 128; count++) { - rc = kwboot_tty_send(tty, msg, 8, 0); - if (rc) { - usleep(msg_req_delay * 1000); - continue; - } - } +static int +kwboot_msg_stop_thread(pthread_t thread) +{ + int rc; - rc = kwboot_tty_recv(tty, &c, 1, msg_rsp_timeo); + rc = pthread_cancel(thread); + if (rc) { + errno = rc; + return -1; + } + + rc = pthread_join(thread, NULL); + if (rc) { + errno = rc; + return -1; + } + + return 0; +} +static int +kwboot_bootmsg(int tty) +{ + struct kwboot_block block; + pthread_t write_thread; + int rc, err; + char c; + + /* flush input and output queue */ + tcflush(tty, TCIOFLUSH); + + rc = kwboot_msg_start_thread(&write_thread, &tty, kwboot_msg_boot); + if (rc) { + perror("Failed to start write thread"); + return rc; + } + + kwboot_printv("Sending boot message. Please reboot the target..."); + + err = 0; + while (1) { kwboot_spinner(); - } while (rc || c != NAK); + rc = kwboot_tty_recv(tty, &c, 1, msg_rsp_timeo); + if (rc && errno == ETIMEDOUT) { + continue; + } else if (rc) { + err = errno; + break; + } + + if (c == NAK) + break; + } kwboot_printv("\n"); - if (rc) + rc = kwboot_msg_stop_thread(write_thread); + if (rc) { + perror("Failed to stop write thread"); return rc; + } + + if (err) { + errno = err; + perror("Failed to read response for boot message pattern"); + return -1; + } /* * At this stage we have sent more boot message patterns and BootROM @@ -772,11 +880,19 @@ kwboot_bootmsg(int tty, void *msg) */ /* flush output queue with remaining boot message patterns */ - tcflush(tty, TCOFLUSH); + rc = tcflush(tty, TCOFLUSH); + if (rc) { + perror("Failed to flush output queue"); + return rc; + } /* send one xmodem packet with 0xff bytes to force BootROM to re-sync */ memset(&block, 0xff, sizeof(block)); - kwboot_tty_send(tty, &block, sizeof(block), 0); + rc = kwboot_tty_send(tty, &block, sizeof(block), 0); + if (rc) { + perror("Failed to send sync sequence"); + return rc; + } /* * Sending 132 bytes via 115200B/8-N-1 takes 11.45 ms, reading 132 bytes @@ -785,40 +901,151 @@ kwboot_bootmsg(int tty, void *msg) usleep(30 * 1000); /* flush remaining NAK replies from input queue */ - tcflush(tty, TCIFLUSH); + rc = tcflush(tty, TCIFLUSH); + if (rc) { + perror("Failed to flush input queue"); + return rc; + } return 0; } static int -kwboot_debugmsg(int tty, void *msg) +kwboot_debugmsg(int tty) { - int rc; + unsigned char buf[8192]; + pthread_t write_thread; + int rc, err, i, pos; + size_t off; - kwboot_printv("Sending debug message. Please reboot the target..."); + /* flush input and output queue */ + tcflush(tty, TCIOFLUSH); - do { - char buf[16]; + rc = kwboot_msg_start_thread(&write_thread, &tty, kwboot_msg_debug); + if (rc) { + perror("Failed to start write thread"); + return rc; + } - rc = tcflush(tty, TCIOFLUSH); - if (rc) - break; + kwboot_printv("Sending debug message. Please reboot the target..."); + kwboot_spinner(); - rc = kwboot_tty_send(tty, msg, 8, 0); - if (rc) { - usleep(msg_req_delay * 1000); + err = 0; + off = 0; + while (1) { + /* Read immediately all bytes in queue without waiting */ + rc = read(tty, buf + off, sizeof(buf) - off); + if ((rc < 0 && errno == EINTR) || rc == 0) { continue; + } else if (rc < 0) { + err = errno; + break; } - - rc = kwboot_tty_recv(tty, buf, 16, msg_rsp_timeo); + off += rc - 1; kwboot_spinner(); - } while (rc); + /* + * Check if we received at least 4 debug message patterns + * (console echo from BootROM) in cyclic buffer + */ + + for (pos = 0; pos < sizeof(kwboot_msg_debug); pos++) + if (buf[off] == kwboot_msg_debug[(pos + off) % sizeof(kwboot_msg_debug)]) + break; + + for (i = off; i >= 0; i--) + if (buf[i] != kwboot_msg_debug[(pos + i) % sizeof(kwboot_msg_debug)]) + break; + + off -= i; + + if (off >= 4 * sizeof(kwboot_msg_debug)) + break; + + /* If not move valid suffix from end of the buffer to the beginning of buffer */ + memmove(buf, buf + i + 1, off); + } kwboot_printv("\n"); - return rc; + rc = kwboot_msg_stop_thread(write_thread); + if (rc) { + perror("Failed to stop write thread"); + return rc; + } + + if (err) { + errno = err; + perror("Failed to read response for debug message pattern"); + return -1; + } + + /* flush output queue with remaining debug message patterns */ + rc = tcflush(tty, TCOFLUSH); + if (rc) { + perror("Failed to flush output queue"); + return rc; + } + + kwboot_printv("Clearing input buffer...\n"); + + /* + * Wait until BootROM transmit all remaining echo characters. + * Experimentally it was measured that for Armada 385 BootROM + * it is required to wait at least 0.415s. So wait 0.5s. + */ + usleep(500 * 1000); + + /* + * In off variable is stored number of characters received after the + * successful detection of echo reply. So these characters are console + * echo for other following debug message patterns. BootROM may have in + * its output queue other echo characters which were being transmitting + * before above sleep call. So read remaining number of echo characters + * sent by the BootROM now. + */ + while ((rc = kwboot_tty_recv(tty, &buf[0], 1, 0)) == 0) + off++; + if (errno != ETIMEDOUT) { + perror("Failed to read response"); + return rc; + } + + /* + * Clear every echo character set by the BootROM by backspace byte. + * This is required prior writing any command to the BootROM debug + * because BootROM command line buffer has limited size. If length + * of the command is larger than buffer size then it looks like + * that Armada 385 BootROM crashes after sending ENTER. So erase it. + * Experimentally it was measured that for Armada 385 BootROM it is + * required to send at least 3 backspace bytes for one echo character. + * This is unknown why. But lets do it. + */ + off *= 3; + memset(buf, '\x08', sizeof(buf)); + while (off > sizeof(buf)) { + rc = kwboot_tty_send(tty, buf, sizeof(buf), 1); + if (rc) { + perror("Failed to send clear sequence"); + return rc; + } + off -= sizeof(buf); + } + rc = kwboot_tty_send(tty, buf, off, 0); + if (rc) { + perror("Failed to send clear sequence"); + return rc; + } + + usleep(msg_rsp_timeo * 1000); + rc = tcflush(tty, TCIFLUSH); + if (rc) { + perror("Failed to flush input queue"); + return rc; + } + + return 0; } static size_t @@ -1181,37 +1408,84 @@ kwboot_xmodem(int tty, const void *_img, size_t size, int baudrate) } static int -kwboot_term_pipe(int in, int out, const char *quit, int *s) +kwboot_term_pipe(int in, int out, const char *quit, int *s, const char *kbs, int *k) { char buf[128]; - ssize_t nin; + ssize_t nin, noff; nin = read(in, buf, sizeof(buf)); if (nin <= 0) return -1; - if (quit) { + noff = 0; + + if (quit || kbs) { int i; for (i = 0; i < nin; i++) { - if (buf[i] == quit[*s]) { + if ((quit || kbs) && + (!quit || buf[i] != quit[*s]) && + (!kbs || buf[i] != kbs[*k])) { + const char *prefix; + int plen; + + if (quit && kbs) { + prefix = (*s >= *k) ? quit : kbs; + plen = (*s >= *k) ? *s : *k; + } else if (quit) { + prefix = quit; + plen = *s; + } else { + prefix = kbs; + plen = *k; + } + + if (plen > i && kwboot_write(out, prefix, plen - i) < 0) + return -1; + } + + if (quit && buf[i] == quit[*s]) { (*s)++; if (!quit[*s]) { - nin = i - *s; + nin = (i > *s) ? (i - *s) : 0; break; } - } else { - if (*s > i && kwboot_write(out, quit, *s - i) < 0) - return -1; + } else if (quit) { *s = 0; } + + if (kbs && buf[i] == kbs[*k]) { + (*k)++; + if (!kbs[*k]) { + if (i > *k + noff && + kwboot_write(out, buf + noff, i - *k - noff) < 0) + return -1; + /* + * Replace backspace key by '\b' (0x08) + * byte which is the only recognized + * backspace byte by Marvell BootROM. + */ + if (write(out, "\x08", 1) < 0) + return -1; + noff = i + 1; + *k = 0; + } + } else if (kbs) { + *k = 0; + } } - if (i == nin) - nin -= *s; + if (i == nin) { + i = 0; + if (quit && i < *s) + i = *s; + if (kbs && i < *k) + i = *k; + nin -= (nin > i) ? i : nin; + } } - if (kwboot_write(out, buf, nin) < 0) + if (nin > noff && kwboot_write(out, buf + noff, nin - noff) < 0) return -1; return 0; @@ -1220,7 +1494,8 @@ kwboot_term_pipe(int in, int out, const char *quit, int *s) static int kwboot_terminal(int tty) { - int rc, in, s; + int rc, in, s, k; + const char *kbs = NULL; const char *quit = "\34c"; struct termios otio, tio; @@ -1239,6 +1514,33 @@ kwboot_terminal(int tty) goto out; } + /* + * Get sequence for backspace key used by the current + * terminal. Every occurrence of this sequence will be + * replaced by '\b' byte which is the only recognized + * backspace byte by Marvell BootROM. + * + * Note that we cannot read this sequence from termios + * c_cc[VERASE] as VERASE is valid only when ICANON is + * set in termios c_lflag, which is not case for us. + * + * Also most terminals do not set termios c_cc[VERASE] + * as c_cc[VERASE] can specify only one-byte sequence + * and instead let applications to read (possible + * multi-byte) sequence for backspace key from "kbs" + * terminfo database based on $TERM env variable. + * + * So read "kbs" from terminfo database via tigetstr() + * call after successful setupterm(). Most terminals + * use byte 0x7F for backspace key, so replacement with + * '\b' is required. + */ + if (setupterm(NULL, STDOUT_FILENO, &rc) == 0) { + kbs = tigetstr("kbs"); + if (kbs == (char *)-1) + kbs = NULL; + } + kwboot_printv("[Type Ctrl-%c + %c to quit]\r\n", quit[0] | 0100, quit[1]); } else @@ -1246,6 +1548,7 @@ kwboot_terminal(int tty) rc = 0; s = 0; + k = 0; do { fd_set rfds; @@ -1265,13 +1568,13 @@ kwboot_terminal(int tty) break; if (FD_ISSET(tty, &rfds)) { - rc = kwboot_term_pipe(tty, STDOUT_FILENO, NULL, NULL); + rc = kwboot_term_pipe(tty, STDOUT_FILENO, NULL, NULL, NULL, NULL); if (rc) break; } if (in >= 0 && FD_ISSET(in, &rfds)) { - rc = kwboot_term_pipe(in, tty, quit, &s); + rc = kwboot_term_pipe(in, tty, quit, &s, kbs, &k); if (rc) break; } @@ -1708,16 +2011,16 @@ static void kwboot_usage(FILE *stream, char *progname) { fprintf(stream, - "Usage: %s [OPTIONS] [-b | -D ] [-B ] \n", + "Usage: %s [OPTIONS] [-b | -D | -b | -d ] [-B ] [-t] \n", progname); fprintf(stream, "\n"); fprintf(stream, - " -b : boot with preamble (Kirkwood, Armada 370/XP)\n"); + " -b : boot with preamble (Kirkwood, Avanta, Armada 370/XP/375/38x/39x)\n"); fprintf(stream, " -D : boot without preamble (Dove)\n"); - fprintf(stream, " -d: enter debug mode\n"); + fprintf(stream, " -b: enter xmodem boot mode\n"); + fprintf(stream, " -d: enter console debug mode\n"); fprintf(stream, " -a: use timings for Armada XP\n"); - fprintf(stream, " -q : use specific request-delay\n"); fprintf(stream, " -s : use specific response-timeout\n"); fprintf(stream, " -o : use specific xmodem block timeout\n"); @@ -1733,8 +2036,8 @@ main(int argc, char **argv) { const char *ttypath, *imgpath; int rv, rc, tty, term; - void *bootmsg; - void *debugmsg; + int bootmsg; + int debugmsg; void *img; size_t size; size_t after_img_rsv; @@ -1744,8 +2047,8 @@ main(int argc, char **argv) rv = 1; tty = -1; - bootmsg = NULL; - debugmsg = NULL; + bootmsg = 0; + debugmsg = 0; imgpath = NULL; img = NULL; term = 0; @@ -1767,24 +2070,25 @@ main(int argc, char **argv) case 'b': if (imgpath || bootmsg || debugmsg) goto usage; - bootmsg = kwboot_msg_boot; + bootmsg = 1; if (prev_optind == optind) goto usage; - if (optind < argc - 1 && argv[optind] && argv[optind][0] != '-') + /* Option -b could have optional argument which specify image path */ + if (optind < argc && argv[optind] && argv[optind][0] != '-') imgpath = argv[optind++]; break; case 'D': if (imgpath || bootmsg || debugmsg) goto usage; - bootmsg = NULL; + bootmsg = 0; imgpath = optarg; break; case 'd': if (imgpath || bootmsg || debugmsg) goto usage; - debugmsg = kwboot_msg_debug; + debugmsg = 1; break; case 'p': @@ -1796,12 +2100,11 @@ main(int argc, char **argv) break; case 'a': - msg_req_delay = KWBOOT_MSG_REQ_DELAY_AXP; msg_rsp_timeo = KWBOOT_MSG_RSP_TIMEO_AXP; break; case 'q': - msg_req_delay = atoi(optarg); + /* nop, for backward compatibility */ break; case 's': @@ -1826,17 +2129,44 @@ main(int argc, char **argv) if (!bootmsg && !term && !debugmsg && !imgpath) goto usage; - ttypath = argv[optind++]; + /* + * If there is no remaining argument but optional imgpath was parsed + * then it means that optional imgpath was eaten by getopt parser. + * Reassing imgpath to required ttypath argument. + */ + if (optind == argc && imgpath) { + ttypath = imgpath; + imgpath = NULL; + } else if (optind + 1 == argc) { + ttypath = argv[optind]; + } else { + goto usage; + } - if (optind != argc) + /* boot and debug message use baudrate 115200 */ + if (((bootmsg && !imgpath) || debugmsg) && baudrate != 115200) { + fprintf(stderr, "Baudrate other than 115200 cannot be used for this operation.\n"); goto usage; + } - tty = kwboot_open_tty(ttypath, imgpath ? 115200 : baudrate); + tty = kwboot_open_tty(ttypath, baudrate); if (tty < 0) { perror(ttypath); goto out; } + /* + * initial baudrate for image transfer is always 115200, + * the change to different baudrate is done only after the header is sent + */ + if (imgpath && baudrate != 115200) { + rc = kwboot_tty_change_baudrate(tty, 115200); + if (rc) { + perror(ttypath); + goto out; + } + } + if (baudrate == 115200) /* do not change baudrate during Xmodem to the same value */ baudrate = 0; @@ -1866,17 +2196,13 @@ main(int argc, char **argv) } if (debugmsg) { - rc = kwboot_debugmsg(tty, debugmsg); - if (rc) { - perror("debugmsg"); + rc = kwboot_debugmsg(tty); + if (rc) goto out; - } } else if (bootmsg) { - rc = kwboot_bootmsg(tty, bootmsg); - if (rc) { - perror("bootmsg"); + rc = kwboot_bootmsg(tty); + if (rc) goto out; - } } if (img) { diff --git a/tools/mkimage.c b/tools/mkimage.c index 7601451..74bd072 100644 --- a/tools/mkimage.c +++ b/tools/mkimage.c @@ -381,6 +381,11 @@ int main(int argc, char **argv) } if (params.fflag){ + if (!tparams) { + fprintf(stderr, "%s: Missing FIT support\n", + params.cmdname); + exit (EXIT_FAILURE); + } if (tparams->fflag_handle) /* * in some cases, some additional processing needs @@ -391,7 +396,7 @@ int main(int argc, char **argv) retval = tparams->fflag_handle(¶ms); if (retval != EXIT_SUCCESS) - exit (retval); + usage("Bad parameters for FIT image type"); } if (params.lflag || params.fflag) { diff --git a/tools/pblimage.c b/tools/pblimage.c index 3c823e9..bd639c2 100644 --- a/tools/pblimage.c +++ b/tools/pblimage.c @@ -230,19 +230,25 @@ static int pblimage_verify_header(unsigned char *ptr, int image_size, struct image_tool_params *params) { struct pbl_header *pbl_hdr = (struct pbl_header *) ptr; + uint32_t rcwheader; + + if (params->arch == IH_ARCH_ARM) + rcwheader = RCW_ARM_HEADER; + else + rcwheader = RCW_PPC_HEADER; /* Only a few checks can be done: search for magic numbers */ if (ENDIANNESS == 'l') { if (pbl_hdr->preamble != reverse_byte(RCW_PREAMBLE)) return -FDT_ERR_BADSTRUCTURE; - if (pbl_hdr->rcwheader != reverse_byte(RCW_HEADER)) + if (pbl_hdr->rcwheader != reverse_byte(rcwheader)) return -FDT_ERR_BADSTRUCTURE; } else { if (pbl_hdr->preamble != RCW_PREAMBLE) return -FDT_ERR_BADSTRUCTURE; - if (pbl_hdr->rcwheader != RCW_HEADER) + if (pbl_hdr->rcwheader != rcwheader) return -FDT_ERR_BADSTRUCTURE; } return 0; diff --git a/tools/pblimage.h b/tools/pblimage.h index 81c5492..0222e80 100644 --- a/tools/pblimage.h +++ b/tools/pblimage.h @@ -8,7 +8,8 @@ #define RCW_BYTES 64 #define RCW_PREAMBLE 0xaa55aa55 -#define RCW_HEADER 0x010e0100 +#define RCW_ARM_HEADER 0x01ee0100 +#define RCW_PPC_HEADER 0x010e0100 struct pbl_header { uint32_t preamble;