Merge tag 'v2022.04-rc4' into next
authorTom Rini <trini@konsulko.com>
Mon, 14 Mar 2022 21:40:36 +0000 (17:40 -0400)
committerTom Rini <trini@konsulko.com>
Mon, 14 Mar 2022 21:40:36 +0000 (17:40 -0400)
Prepare v2022.04-rc4

95 files changed:
.mailmap
MAINTAINERS
Makefile
arch/arm/Kconfig
arch/arm/cpu/arm926ejs/sunxi/fel_utils.S
arch/arm/dts/armada-3720-turris-mox.dts
arch/arm/dts/armada-37xx.dtsi
arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi
arch/arm/dts/k3-am65-iot2050-common-u-boot.dtsi
arch/arm/dts/sama7g5ek.dts
arch/arm/include/asm/arch-sunxi/gpio.h
arch/arm/include/asm/arch-sunxi/spl.h
arch/arm/mach-k3/am6_init.c
arch/arm/mach-mvebu/armada3700/cpu.c
arch/arm/mach-sunxi/Kconfig
arch/arm/mach-sunxi/board.c
arch/arm/mach-sunxi/spl_spi_sunxi.c
arch/x86/include/asm/intel_gnvs.h
board/advantech/som-db5800-som-6867/.gitignore
board/alliedtelesis/x530/x530.c
board/congatec/conga-qeval20-qa3-e3845/.gitignore
board/coreboot/coreboot/MAINTAINERS
board/intel/bayleybay/.gitignore
board/intel/edison/.gitignore
board/intel/galileo/.gitignore
board/intel/minnowmax/.gitignore
board/kontron/sl28/sl28.c
board/solidrun/clearfog/clearfog.c
board/sunxi/board.c
board/ti/am65x/evm.c
board/ti/j721e/evm.c
cmd/cls.c
cmd/pwm.c
configs/j721e_evm_a72_defconfig
configs/j721e_hs_evm_a72_defconfig
configs/kontron_sl28_defconfig
configs/libretech_all_h3_it_h5_defconfig
configs/libretech_all_h5_cc_h5_defconfig
configs/licheepi_nano_defconfig
configs/oceanic_5205_5inmfd_defconfig
configs/orangepi_pc2_defconfig
configs/orangepi_r1_defconfig
configs/orangepi_win_defconfig
configs/orangepi_zero2_defconfig
configs/orangepi_zero_defconfig
configs/pine64-lts_defconfig
configs/pine_h64_defconfig
configs/pinecube_defconfig
configs/sopine_baseboard_defconfig
configs/tbs2910_defconfig
configs/turris_omnia_defconfig
configs/vexpress_aemv8a_semi_defconfig
doc/board/kontron/sl28.rst
doc/board/sifive/unmatched.rst
doc/build/gcc.rst
doc/kwboot.1
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/sl28cpld-gpio.c [new file with mode: 0644]
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/sl28cpld.c [new file with mode: 0644]
drivers/mmc/rockchip_sdhci.c
drivers/mtd/spi/spi-nor-ids.c
drivers/pci/pci_mvebu.c
drivers/phy/cadence/phy-cadence-sierra.c
drivers/phy/nop-phy.c
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
drivers/rtc/armada38x.c
drivers/serial/serial-uclass.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/cadence_qspi.c
drivers/spi/cadence_qspi.h
drivers/spi/designware_spi.c
drivers/spi/iproc_qspi.c [new file with mode: 0644]
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/armada-37xx-wdt.c
drivers/watchdog/rti_wdt.c
drivers/watchdog/sl28cpld-wdt.c [new file with mode: 0644]
drivers/watchdog/wdt-uclass.c
env/Kconfig
include/configs/lx2160a_common.h
include/configs/ti_armv7_common.h
include/efi_loader.h
include/sl28cpld.h [new file with mode: 0644]
lib/efi_loader/efi_boottime.c
lib/efi_loader/efi_image_loader.c
lib/rsa/rsa-sign.c
tools/Makefile
tools/kwboot.c
tools/mkimage.c
tools/pblimage.c
tools/pblimage.h

index b36ae66..1f88ea9 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -22,11 +22,13 @@ Andreas Bießmann <andreas@biessmann.org>
 Aneesh V <aneesh@ti.com>
 Anup Patel <anup@brainfault.org> <anup.patel@wdc.com>
 Atish Patra <atishp@atishpatra.org> <atish.patra@wdc.com>
+Bin Meng <bmeng.cn@gmail.com> <bin.meng@windriver.com>
 Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@bootlin.com>
 Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@free-electrons.com>
 Dirk Behme <dirk.behme@googlemail.com>
 Fabio Estevam <fabio.estevam@nxp.com>
 Heinrich Schuchardt <xypron.glpk@gmx.de> <heinrich.schuchardt@canonical.com>
+Heinrich Schuchardt <xypron.glpk@gmx.de> xypron.glpk@gmx.de <xypron.glpk@gmx.de>
 Jagan Teki <402jagan@gmail.com>
 Jagan Teki <jaganna@gmail.com>
 Jagan Teki <jaganna@xilinx.com>
@@ -35,7 +37,15 @@ Jagan Teki <jagannadha.sutradharudu-teki@xilinx.com>
 Jernej Skrabec <jernej.skrabec@gmail.com> <jernej.skrabec@siol.net>
 Igor Opaniuk <igor.opaniuk@gmail.com> <igor.opaniuk@linaro.org>
 Igor Opaniuk <igor.opaniuk@gmail.com> <igor.opaniuk@toradex.com>
+Marek Vasut <marex@denx.de> <marek.vasut+renesas@gmail.com>
+Marek Vasut <marex@denx.de> <marek.vasut@gmail.com>
+Marek Vasut <marex@denx.de> <marex at denx.de>
 Markus Klotzbuecher <mk@denx.de>
+Masahiro Yamada <yamada.masahiro@socionext.com> <yamada.m@jp.panasonic.com>
+Masahiro Yamada <yamada.masahiro@socionext.com> <masahiroy@kernel.org>
+Michal Simek <michal.simek@xilinx.com> <monstr@monstr.eu>
+Michal Simek <michal.simek@xilinx.com> <Monstr@seznam.cz>
+Michal Simek <michal.simek@xilinx.com> <root@monstr.eu>
 Nicolas Saenz Julienne <nsaenz@kernel.org> <nsaenzjulienne@suse.de>
 Patrice Chotard <patrice.chotard@foss.st.com> <patrice.chotard@st.com>
 Patrick Delaunay <patrick.delaunay@foss.st.com> <patrick.delaunay@st.com>
@@ -47,10 +57,19 @@ Ricardo Ribalda <ricardo@ribalda.com> <ricardo.ribalda@gmail.com>
 Ruchika Gupta <ruchika.gupta@nxp.com> <ruchika.gupta@freescale.com>
 Sandeep Paulraj <s-paulraj@ti.com>
 Shaohui Xie <Shaohui.Xie@freescale.com>
-Stefan Roese <stroese>
+Stefan Roese <sr@denx.de> <stroese>
 Stefano Babic <sbabic@denx.de>
+Tom Rini <trini@konsulko.com> <trini@ti.com>
 TsiChung Liew <Tsi-Chung.Liew@freescale.com>
-Wolfgang Denk <wdenk>
+Wolfgang Denk <wd@denx.de> <wdenk>
+Wolfgang Denk <wd@denx.de> <wd@pollux.denx.de>
+Wolfgang Denk <wd@denx.de> <wd@pollux.(none)>
+Wolfgang Denk <wd@denx.de> <wd@fifi.denx.de>
+Wolfgang Denk <wd@denx.de> <wd@nyx.denx.de>
+Wolfgang Denk <wd@denx.de> <wd@atlas.denx.de>
+Wolfgang Denk <wd@denx.de> <wd@castor.denx.de>
+Wolfgang Denk <wd@denx.de> <wd@xpert.denx.de>
+Wolfgang Denk <wd@denx.de> <wd@nyx.(none)>
 York Sun <yorksun@freescale.com>
 York Sun <york.sun@nxp.com>
 Łukasz Majewski <l.majewski@samsung.com>
index 7012cc2..5011a54 100644 (file)
@@ -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 <michael@walle.cc>
+S:     Maintained
+F:     drivers/gpio/sl28cpld-gpio.c
+F:     drivers/misc/sl28cpld.c
+F:     drivers/watchdog/sl28cpld-wdt.c
+
 SPI
 M:     Jagan Teki <jagan@amarulasolutions.com>
 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 <sr@denx.de>
+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 <sjg@chromium.org>
 M:     Bin Meng <bmeng.cn@gmail.com>
index 9ef34ca..06572ac 100644 (file)
--- 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
index 403156b..474ce4a 100644 (file)
@@ -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
index 08be7ed..2592403 100644 (file)
@@ -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)
index 1fc4a30..595b4b5 100644 (file)
        /*
         * 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.
         * 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>;
index 9fa6457..0bb4f60 100644 (file)
                         * (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>,
index d4b8332..2dcb3c2 100644 (file)
@@ -27,6 +27,7 @@
                fit {
                        offset = <CONFIG_SPL_PAD_TO>;
                        description = "FIT image with multiple configurations";
+                       fit,fdt-list = "of-list";
 
                        images {
                                uboot {
                                        };
                                };
 
-                               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";
                                };
                        };
                };
                };
 
                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";
                        };
                };
 
                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";
                        };
                };
index 286e25f..d80c550 100644 (file)
@@ -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 <le.jin@siemens.com>
 
 &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 {
index 6adb044..ac6f23f 100644 (file)
        #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";
 
        #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";
 
                         <PIN_PA15__G0_TXEN>,
                         <PIN_PA30__G0_RXCK>,
                         <PIN_PA18__G0_RXDV>,
-                        <PIN_PA22__G0_MDC>,
-                        <PIN_PA23__G0_MDIO>,
                         <PIN_PA25__G0_125CK>;
+               slew-rate = <0>;
+               bias-disable;
+       };
+
+       pinctrl_gmac0_mdio_default: gmac0_mdio_default {
+               pinmux = <PIN_PA22__G0_MDC>,
+                        <PIN_PA23__G0_MDIO>;
                bias-disable;
        };
 
        pinctrl_gmac0_txc_default: gmac0_txc_default {
                pinmux = <PIN_PA24__G0_TXCK>;
+               slew-rate = <0>;
                bias-pull-up;
        };
 
                         <PIN_PD25__G1_RX0>,
                         <PIN_PD26__G1_RX1>,
                         <PIN_PD27__G1_RXER>,
-                        <PIN_PD24__G1_RXDV>,
-                        <PIN_PD28__G1_MDC>,
+                        <PIN_PD24__G1_RXDV>;
+               slew-rate = <0>;
+               bias-disable;
+       };
+
+       pinctrl_gmac1_mdio_default: gmac1_mdio_default {
+               pinmux = <PIN_PD28__G1_MDC>,
                         <PIN_PD29__G1_MDIO>;
                bias-disable;
        };
index 7f7eb05..edd0fbf 100644 (file)
@@ -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
index 58cdf80..b543d24 100644 (file)
 #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);
index ffb7aad..8a6b1de 100644 (file)
@@ -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),
index 23492f4..52b5109 100644 (file)
@@ -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
-        * { <child address> <parent address> <size in child address space> }
+        *   { <PCI address> <CPU address> <size in PCI address space> }
+        * 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;
        }
index 205fe3c..73da6b8 100644 (file)
@@ -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
index 57078f7..0071de1 100644 (file)
@@ -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)
 {
index 910e805..734c165 100644 (file)
@@ -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();
index fc743dc..0b69530 100644 (file)
@@ -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,
index 6eb8a54..39e46ba 100644 (file)
@@ -1,3 +1,3 @@
-dsdt.aml
-dsdt.asl.tmp
-dsdt.c
+dsdt_generated.aml
+dsdt_generated.asl.tmp
+dsdt_generated.c
index 8b31045..c0ec2af 100644 (file)
@@ -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 */
 };
index 6eb8a54..39e46ba 100644 (file)
@@ -1,3 +1,3 @@
-dsdt.aml
-dsdt.asl.tmp
-dsdt.c
+dsdt_generated.aml
+dsdt_generated.asl.tmp
+dsdt_generated.c
index a05673b..ee12d32 100644 (file)
@@ -2,12 +2,12 @@ COREBOOT BOARD
 M:     Simon Glass <sjg@chromium.org>
 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 <sjg@chromium.org>
 S:     Maintained
 F:     board/coreboot/coreboot/
-F:     include/configs/chromebook_link.h
+F:     include/configs/coreboot.h
 F:     configs/coreboot64_defconfig
index 6eb8a54..39e46ba 100644 (file)
@@ -1,3 +1,3 @@
-dsdt.aml
-dsdt.asl.tmp
-dsdt.c
+dsdt_generated.aml
+dsdt_generated.asl.tmp
+dsdt_generated.c
index 6eb8a54..39e46ba 100644 (file)
@@ -1,3 +1,3 @@
-dsdt.aml
-dsdt.asl.tmp
-dsdt.c
+dsdt_generated.aml
+dsdt_generated.asl.tmp
+dsdt_generated.c
index 6eb8a54..39e46ba 100644 (file)
@@ -1,3 +1,3 @@
-dsdt.aml
-dsdt.asl.tmp
-dsdt.c
+dsdt_generated.aml
+dsdt_generated.asl.tmp
+dsdt_generated.c
index 6eb8a54..39e46ba 100644 (file)
@@ -1,3 +1,3 @@
-dsdt.aml
-dsdt.asl.tmp
-dsdt.c
+dsdt_generated.aml
+dsdt_generated.asl.tmp
+dsdt_generated.c
index e84b356..3c48a91 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 
 #include <common.h>
+#include <dm.h>
 #include <malloc.h>
 #include <errno.h>
 #include <fsl_ddr.h>
@@ -14,7 +15,9 @@
 #include <asm/arch/soc.h>
 #include <fsl_immap.h>
 #include <netdev.h>
+#include <wdt.h>
 
+#include <sl28cpld.h>
 #include <fdtdec.h>
 #include <miiphy.h>
 
@@ -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);
 }
 
index c920cf8..03adb59 100644 (file)
@@ -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 */
 };
 
index 82c52b2..a096159 100644 (file)
@@ -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);
index fbe33cb..7182a8c 100644 (file)
@@ -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;
 }
index f479197..e6ff54c 100644 (file)
@@ -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
index eab4e69..bdeb497 100644 (file)
--- a/cmd/cls.c
+++ b/cmd/cls.c
 #include <lcd.h>
 #include <video.h>
 
+#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)
index 7947e61..7e82955 100644 (file)
--- a/cmd/pwm.c
+++ b/cmd/pwm.c
@@ -111,5 +111,5 @@ U_BOOT_CMD(pwm, 6, 0, do_pwm,
           "invert <pwm_dev_num> <channel> <polarity> - invert polarity\n"
           "pwm config <pwm_dev_num> <channel> <period_ns> <duty_ns> - config PWM\n"
           "pwm enable <pwm_dev_num> <channel> - enable PWM output\n"
-          "pwm disable <pwm_dev_num> <channel> - eisable PWM output\n"
+          "pwm disable <pwm_dev_num> <channel> - disable PWM output\n"
           "Note: All input values are in decimal");
index 7929e22..d518195 100644 (file)
@@ -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
index c37c20a..6850b99 100644 (file)
@@ -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
index b61276c..cf8aedf 100644 (file)
@@ -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
index 7f0e0be..cb7ffb4 100644 (file)
@@ -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
index 25bfe52..c3aa4b1 100644 (file)
@@ -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
index 2ac0ef4..67b7b85 100644 (file)
@@ -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
index 9ba115c..7ce63ba 100644 (file)
@@ -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
index 2eaddcf..777af8c 100644 (file)
@@ -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
index 745451c..4496aa4 100644 (file)
@@ -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
index 8c2179b..3b78ad7 100644 (file)
@@ -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
index 22563c8..54faf6a 100644 (file)
@@ -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
index 332cd47..2dc69d2 100644 (file)
@@ -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
index 6209e68..45a9e77 100644 (file)
@@ -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
index 1928509..1e730dd 100644 (file)
@@ -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
index 0c71d59..e779663 100644 (file)
@@ -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
index 0093076..982f7b0 100644 (file)
@@ -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
index e1278f2..8a33160 100644 (file)
@@ -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
index 280dd55..5b1fdbf 100644 (file)
@@ -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
index d55e560..50715e2 100644 (file)
@@ -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# "
index c7b18be..44435d9 100644 (file)
@@ -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
 -------------------------------------
index 24a8899..a994422 100644 (file)
@@ -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.
index b883cf7..470a7aa 100644 (file)
@@ -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
 ~~~~~~~~~~
index acdea89..f555ff2 100644 (file)
@@ -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"
 
index be64303..12972cd 100644 (file)
@@ -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
index 7202979..44f0153 100644 (file)
@@ -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 (file)
index 0000000..700fc3d
--- /dev/null
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * GPIO driver for the sl28cpld
+ *
+ * Copyright (c) 2021 Michael Walle <michael@walle.cc>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/gpio.h>
+#include <sl28cpld.h>
+
+/* 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,
+};
index 0ade3e3..7029bb7 100644 (file)
@@ -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
index bca7b24..f22eff6 100644 (file)
@@ -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 (file)
index 0000000..01ef1c6
--- /dev/null
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Michael Walle <michael@walle.cc>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+
+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,
+};
index 2784738..b91df05 100644 (file)
@@ -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[] = {
index b551ebd..763bab0 100644 (file)
@@ -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)
        },
        {
index 5a0a59a..f076693 100644 (file)
 #include <linux/sizes.h>
 
 /* 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
index d95d4b4..fc5044f 100644 (file)
@@ -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),
 };
index e2ee6e9..d0904f4 100644 (file)
@@ -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;
index 1cf1f06..e76ef15 100644 (file)
@@ -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"),
index 2d264ac..2af64e3 100644 (file)
@@ -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;
index 362cedd..f30f352 100644 (file)
@@ -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;
        }
 
index 0a6a85f..423a757 100644 (file)
@@ -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
index bea746f..7f43f84 100644 (file)
@@ -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
index d1b3808..db68061 100644 (file)
@@ -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)
index 49b4011..19345ca 100644 (file)
@@ -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 */
index 7421211..fc22f54 100644 (file)
@@ -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 (file)
index 0000000..b5c2743
--- /dev/null
@@ -0,0 +1,576 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020-2021 Broadcom
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <spi.h>
+#include <spi-mem.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/log2.h>
+
+/* 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,
+};
index 1f3ca99..5b614cf 100644 (file)
@@ -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
index 6d2b382..a35bd55 100644 (file)
@@ -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
index 2e119b9..bacebbc 100644 (file)
@@ -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;
 
index 253286d..8d93f19 100644 (file)
@@ -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 (file)
index 0000000..af5a6b1
--- /dev/null
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Watchdog driver for the sl28cpld
+ *
+ * Copyright (c) 2021 Michael Walle <michael@walle.cc>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <wdt.h>
+#include <sl28cpld.h>
+#include <div64.h>
+
+#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,
+};
index 6d0f473..dbf5564 100644 (file)
@@ -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.
index 20f395f..443f2f7 100644 (file)
@@ -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.
 
index c407fa8..469989a 100644 (file)
                "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 <config_distro_bootcmd.h>
 
 #endif /* __LX2_COMMON_H */
index 9733707..7483bc8 100644 (file)
@@ -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,
index e390d32..110d8ae 100644 (file)
@@ -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 (file)
index 0000000..9a7c6de
--- /dev/null
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2021 Michael Walle <michael@walle.cc>
+ */
+
+#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
index 82128ac..d0f3e05 100644 (file)
@@ -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
                                                ));
index 5df3593..9611398 100644 (file)
@@ -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);
index 3e7b798..b2a2119 100644 (file)
@@ -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:
index 5409ff2..60231c7 100644 (file)
@@ -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
 
index 68c0ef1..9f2dd2d 100644 (file)
@@ -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 <daniel.stodden@gmail.com>
  * (c) 2021 Pali Rohár <pali@kernel.org>
  * (c) 2021 Marek Behún <marek.behun@nic.cz>
  *
- * 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 <stdint.h>
 #include <time.h>
 #include <sys/stat.h>
+#include <pthread.h>
 
 #ifdef __linux__
 #include "termios_linux.h"
 #endif
 
 /*
+ * These functions are in <term.h> 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 <image> | -D <image> ] [-B <baud> ] <TTY>\n",
+               "Usage: %s [OPTIONS] [-b <image> | -D <image> | -b | -d ] [-B <baud> ] [-t] <TTY>\n",
                progname);
        fprintf(stream, "\n");
        fprintf(stream,
-               "  -b <image>: boot <image> with preamble (Kirkwood, Armada 370/XP)\n");
+               "  -b <image>: boot <image> with preamble (Kirkwood, Avanta, Armada 370/XP/375/38x/39x)\n");
        fprintf(stream,
                "  -D <image>: boot <image> 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 <req-delay>:  use specific request-delay\n");
        fprintf(stream, "  -s <resp-timeo>: use specific response-timeout\n");
        fprintf(stream,
                "  -o <block-timeo>: 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) {
index 7601451..74bd072 100644 (file)
@@ -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(&params);
 
                if (retval != EXIT_SUCCESS)
-                       exit (retval);
+                       usage("Bad parameters for FIT image type");
        }
 
        if (params.lflag || params.fflag) {
index 3c823e9..bd639c2 100644 (file)
@@ -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;
index 81c5492..0222e80 100644 (file)
@@ -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;