Merge tag 'v2022.01-rc3' into next
authorTom Rini <trini@konsulko.com>
Mon, 29 Nov 2021 17:00:57 +0000 (12:00 -0500)
committerTom Rini <trini@konsulko.com>
Mon, 29 Nov 2021 17:00:57 +0000 (12:00 -0500)
Prepare v2022.01-rc3

Signed-off-by: Tom Rini <trini@konsulko.com>
136 files changed:
MAINTAINERS
Makefile
README
arch/arm/Kconfig
arch/arm/dts/ast2600-evb.dts
arch/arm/dts/ast2600.dtsi
arch/arm/dts/k3-am642-r5-sk.dts
arch/arm/dts/k3-am642-sk-u-boot.dtsi
arch/arm/dts/ls1021a-tsn.dts
arch/arm/include/asm/arch-aspeed/platform.h
arch/arm/include/asm/arch-aspeed/scu_ast2600.h
arch/arm/lib/crt0.S
arch/arm/lib/crt0_64.S
arch/arm/mach-aspeed/ast2600/spl.c
arch/arm/mach-rockchip/rk3399/rk3399.c
arch/sandbox/cpu/os.c
arch/sandbox/dts/test.dts
board/sandbox/sandbox.env [new file with mode: 0644]
boot/bootm_os.c
boot/image-fit.c
boot/pxe_utils.c
cmd/bootm.c
cmd/elf.c
cmd/mbr.c
cmd/sf.c
common/Kconfig
common/console.c
config.mk
configs/am64x_evm_a53_defconfig
configs/am64x_evm_r5_defconfig
configs/elgin-rv1108_defconfig
configs/evb-ast2600_defconfig
configs/evb-rk3128_defconfig
configs/evb-rv1108_defconfig
configs/ls1021atsn_qspi_defconfig
configs/ls1021atsn_sdcard_defconfig
configs/pine64_plus_defconfig
configs/pm9g45_defconfig
configs/qemu_arm64_defconfig
configs/qemu_arm_defconfig
configs/sandbox_flattree_defconfig
configs/snow_defconfig
configs/stm32mp15_defconfig
configs/stm32mp15_trusted_defconfig
disk/part_dos.c
doc/develop/environment.rst [new file with mode: 0644]
doc/develop/index.rst
doc/device-tree-bindings/arm/arm,scmi.txt
doc/device-tree-bindings/mmc/sandbox,mmc.txt [new file with mode: 0644]
doc/device-tree-bindings/pinctrl/apple,pinctrl.yaml [new file with mode: 0644]
doc/usage/environment.rst [new file with mode: 0644]
doc/usage/index.rst
doc/usage/sf.rst [new file with mode: 0644]
drivers/clk/aspeed/clk_ast2600.c
drivers/clk/clk_scmi.c
drivers/core/device-remove.c
drivers/core/device.c
drivers/core/of_access.c
drivers/core/of_extra.c
drivers/core/ofnode.c
drivers/core/read.c
drivers/core/uclass.c
drivers/crypto/Kconfig
drivers/crypto/Makefile
drivers/crypto/aspeed/Kconfig [new file with mode: 0644]
drivers/crypto/aspeed/Makefile [new file with mode: 0644]
drivers/crypto/aspeed/aspeed_acry.c [new file with mode: 0644]
drivers/crypto/aspeed/aspeed_hace.c [new file with mode: 0644]
drivers/crypto/hash/Kconfig
drivers/firmware/scmi/Kconfig
drivers/firmware/scmi/Makefile
drivers/firmware/scmi/mailbox_agent.c
drivers/firmware/scmi/optee_agent.c [new file with mode: 0644]
drivers/firmware/scmi/smccc_agent.c
drivers/mmc/mmc-uclass.c
drivers/mmc/mtk-sd.c
drivers/mmc/sandbox_mmc.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/aspeed_mdio.c [new file with mode: 0644]
drivers/net/fec_mxc.h
drivers/net/mscc_eswitch/felix_switch.c
drivers/net/phy/Kconfig
drivers/net/phy/mscc.c
drivers/net/phy/realtek.c
drivers/net/sja1105.c [new file with mode: 0644]
drivers/net/tsec.c
drivers/pci/pci-aardvark.c
drivers/pci/pcie_ecam_generic.c
drivers/pci/pcie_ecam_synquacer.c
drivers/pci/pcie_phytium.c
drivers/pci/pcie_rockchip.c
drivers/pci/pcie_xilinx.c
drivers/phy/cadence/phy-cadence-torrent.c
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/aspeed/Makefile
drivers/pinctrl/aspeed/pinctrl_ast2600.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-apple.c [new file with mode: 0644]
drivers/power/regulator/scmi_regulator.c
drivers/reset/reset-scmi.c
drivers/tee/optee/optee_msg.h
drivers/usb/cdns3/cdns3-ti.c
env/Kconfig
env/common.c
env/embedded.c
include/command.h
include/configs/aspeed-common.h
include/configs/evb_ast2500.h
include/configs/evb_ast2600.h
include/configs/sandbox.h
include/dm/device.h
include/dm/of_extra.h
include/dm/ofnode.h
include/dm/read.h
include/dm/uclass-internal.h
include/dm/uclass.h
include/env.h
include/env_default.h
include/linux/if_vlan.h [new file with mode: 0644]
include/net/dsa.h
include/os.h
include/pci.h
include/scmi_agent.h
include/tee.h
include/tsec.h
lib/rsa/Kconfig
net/bootp.c
net/dsa-uclass.c
scripts/env2string.awk [new file with mode: 0644]
test/dm/ofnode.c
test/py/conftest.py
test/py/multiplexed_log.py
test/py/tests/test_env.py
test/py/u_boot_utils.py
tools/binman/control.py

index e718ad2..9045e50 100644 (file)
@@ -115,6 +115,7 @@ F:  arch/arm/include/asm/arch-m1/
 F:     arch/arm/mach-apple/
 F:     configs/apple_m1_defconfig
 F:     drivers/iommu/apple_dart.c
+F:     drivers/pinctrl/pinctrl-apple.c
 F:     include/configs/apple.h
 
 ARM
@@ -761,6 +762,13 @@ F: test/env/
 F:     tools/env*
 F:     tools/mkenvimage.c
 
+ENVIRONMENT AS TEXT
+M:     Simon Glass <sjg@chromium.org>
+R:     Wolfgang Denk <wd@denx.de>
+S:     Maintained
+F:     doc/usage/environment.rst
+F:     scripts/env2string.awk
+
 FASTBOOT
 S:     Orphaned
 F:     cmd/fastboot.c
index 179d314..57c3643 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -517,6 +517,7 @@ version_h := include/generated/version_autogenerated.h
 timestamp_h := include/generated/timestamp_autogenerated.h
 defaultenv_h := include/generated/defaultenv_autogenerated.h
 dt_h := include/generated/dt.h
+env_h := include/generated/environment.h
 
 no-dot-config-targets := clean clobber mrproper distclean \
                         help %docs check% coccicheck \
@@ -1794,6 +1795,69 @@ quiet_cmd_sym ?= SYM     $@
 u-boot.sym: u-boot FORCE
        $(call if_changed,sym)
 
+# Environment processing
+# ---------------------------------------------------------------------------
+
+# Directory where we expect the .env file, if it exists
+ENV_DIR := $(srctree)/board/$(BOARDDIR)
+
+# Basename of .env file, stripping quotes
+ENV_SOURCE_FILE := $(CONFIG_ENV_SOURCE_FILE:"%"=%)
+
+# Filename of .env file
+ENV_FILE_CFG := $(ENV_DIR)/$(ENV_SOURCE_FILE).env
+
+# Default filename, if CONFIG_ENV_SOURCE_FILE is empty
+ENV_FILE_BOARD := $(ENV_DIR)/$(CONFIG_SYS_BOARD:"%"=%).env
+
+# Select between the CONFIG_ENV_SOURCE_FILE and the default one
+ENV_FILE := $(if $(ENV_SOURCE_FILE),$(ENV_FILE_CFG),$(wildcard $(ENV_FILE_BOARD)))
+
+# Run the environment text file through the preprocessor, but only if it is
+# non-empty, to save time and possible build errors if something is wonky with
+# the board
+quiet_cmd_gen_envp = ENVP    $@
+      cmd_gen_envp = \
+       if [ -s "$(ENV_FILE)" ]; then \
+               $(CPP) -P $(CFLAGS) -x assembler-with-cpp -D__ASSEMBLY__ \
+                       -D__UBOOT_CONFIG__ \
+                       -I . -I include -I $(srctree)/include \
+                       -include linux/kconfig.h -include include/config.h \
+                       -I$(srctree)/arch/$(ARCH)/include \
+                       $< -o $@; \
+       else \
+               echo -n >$@ ; \
+       fi
+include/generated/env.in: include/generated/env.txt FORCE
+       $(call cmd,gen_envp)
+
+# Regenerate the environment if it changes
+# We use 'wildcard' since the file is not required to exist (at present), in
+# which case we don't want this dependency, but instead should create an empty
+# file
+# This rule is useful since it shows the source file for the environment
+quiet_cmd_envc = ENVC    $@
+      cmd_envc = \
+       if [ -f "$<" ]; then \
+               cat $< > $@; \
+       elif [ -n "$(ENV_SOURCE_FILE)" ]; then \
+               echo "Missing file $(ENV_FILE_CFG)"; \
+       else \
+               echo -n >$@ ; \
+       fi
+
+include/generated/env.txt: $(wildcard $(ENV_FILE)) FORCE
+       $(call cmd,envc)
+
+# Write out the resulting environment, converted to a C string
+quiet_cmd_gen_envt = ENVT    $@
+      cmd_gen_envt = \
+       awk -f $(srctree)/scripts/env2string.awk $< >$@
+$(env_h): include/generated/env.in
+       $(call cmd,gen_envt)
+
+# ---------------------------------------------------------------------------
+
 # The actual objects are generated when descending,
 # make sure no implicit rule kicks in
 $(sort $(u-boot-init) $(u-boot-main)): $(u-boot-dirs) ;
@@ -1849,7 +1913,7 @@ endif
 # prepare2 creates a makefile if using a separate output directory
 prepare2: prepare3 outputmakefile cfg
 
-prepare1: prepare2 $(version_h) $(timestamp_h) $(dt_h) \
+prepare1: prepare2 $(version_h) $(timestamp_h) $(dt_h) $(env_h) \
                    include/config/auto.conf
 ifeq ($(wildcard $(LDSCRIPT)),)
        @echo >&2 "  Could not find linker script."
diff --git a/README b/README
index 9606a8b..0e37358 100644 (file)
--- a/README
+++ b/README
@@ -2966,334 +2966,6 @@ TODO.
 For now: just type "help <command>".
 
 
-Environment Variables:
-======================
-
-U-Boot supports user configuration using Environment Variables which
-can be made persistent by saving to Flash memory.
-
-Environment Variables are set using "setenv", printed using
-"printenv", and saved to Flash using "saveenv". Using "setenv"
-without a value can be used to delete a variable from the
-environment. As long as you don't save the environment you are
-working with an in-memory copy. In case the Flash area containing the
-environment is erased by accident, a default environment is provided.
-
-Some configuration options can be set using Environment Variables.
-
-List of environment variables (most likely not complete):
-
-  baudrate     - see CONFIG_BAUDRATE
-
-  bootdelay    - see CONFIG_BOOTDELAY
-
-  bootcmd      - see CONFIG_BOOTCOMMAND
-
-  bootargs     - Boot arguments when booting an RTOS image
-
-  bootfile     - Name of the image to load with TFTP
-
-  bootm_low    - Memory range available for image processing in the bootm
-                 command can be restricted. This variable is given as
-                 a hexadecimal number and defines lowest address allowed
-                 for use by the bootm command. See also "bootm_size"
-                 environment variable. Address defined by "bootm_low" is
-                 also the base of the initial memory mapping for the Linux
-                 kernel -- see the description of CONFIG_SYS_BOOTMAPSZ and
-                 bootm_mapsize.
-
-  bootm_mapsize - Size of the initial memory mapping for the Linux kernel.
-                 This variable is given as a hexadecimal number and it
-                 defines the size of the memory region starting at base
-                 address bootm_low that is accessible by the Linux kernel
-                 during early boot.  If unset, CONFIG_SYS_BOOTMAPSZ is used
-                 as the default value if it is defined, and bootm_size is
-                 used otherwise.
-
-  bootm_size   - Memory range available for image processing in the bootm
-                 command can be restricted. This variable is given as
-                 a hexadecimal number and defines the size of the region
-                 allowed for use by the bootm command. See also "bootm_low"
-                 environment variable.
-
-  bootstopkeysha256, bootdelaykey, bootstopkey - See README.autoboot
-
-  updatefile   - Location of the software update file on a TFTP server, used
-                 by the automatic software update feature. Please refer to
-                 documentation in doc/README.update for more details.
-
-  autoload     - if set to "no" (any string beginning with 'n'),
-                 "bootp" will just load perform a lookup of the
-                 configuration from the BOOTP server, but not try to
-                 load any image using TFTP
-
-  autostart    - if set to "yes", an image loaded using the "bootp",
-                 "rarpboot", "tftpboot" or "diskboot" commands will
-                 be automatically started (by internally calling
-                 "bootm")
-
-                 If set to "no", a standalone image passed to the
-                 "bootm" command will be copied to the load address
-                 (and eventually uncompressed), but NOT be started.
-                 This can be used to load and uncompress arbitrary
-                 data.
-
-  fdt_high     - if set this restricts the maximum address that the
-                 flattened device tree will be copied into upon boot.
-                 For example, if you have a system with 1 GB memory
-                 at physical address 0x10000000, while Linux kernel
-                 only recognizes the first 704 MB as low memory, you
-                 may need to set fdt_high as 0x3C000000 to have the
-                 device tree blob be copied to the maximum address
-                 of the 704 MB low memory, so that Linux kernel can
-                 access it during the boot procedure.
-
-                 If this is set to the special value 0xFFFFFFFF then
-                 the fdt will not be copied at all on boot.  For this
-                 to work it must reside in writable memory, have
-                 sufficient padding on the end of it for u-boot to
-                 add the information it needs into it, and the memory
-                 must be accessible by the kernel.
-
-  fdtcontroladdr- if set this is the address of the control flattened
-                 device tree used by U-Boot when CONFIG_OF_CONTROL is
-                 defined.
-
-  i2cfast      - (PPC405GP|PPC405EP only)
-                 if set to 'y' configures Linux I2C driver for fast
-                 mode (400kHZ). This environment variable is used in
-                 initialization code. So, for changes to be effective
-                 it must be saved and board must be reset.
-
-  initrd_high  - restrict positioning of initrd images:
-                 If this variable is not set, initrd images will be
-                 copied to the highest possible address in RAM; this
-                 is usually what you want since it allows for
-                 maximum initrd size. If for some reason you want to
-                 make sure that the initrd image is loaded below the
-                 CONFIG_SYS_BOOTMAPSZ limit, you can set this environment
-                 variable to a value of "no" or "off" or "0".
-                 Alternatively, you can set it to a maximum upper
-                 address to use (U-Boot will still check that it
-                 does not overwrite the U-Boot stack and data).
-
-                 For instance, when you have a system with 16 MB
-                 RAM, and want to reserve 4 MB from use by Linux,
-                 you can do this by adding "mem=12M" to the value of
-                 the "bootargs" variable. However, now you must make
-                 sure that the initrd image is placed in the first
-                 12 MB as well - this can be done with
-
-                 setenv initrd_high 00c00000
-
-                 If you set initrd_high to 0xFFFFFFFF, this is an
-                 indication to U-Boot that all addresses are legal
-                 for the Linux kernel, including addresses in flash
-                 memory. In this case U-Boot will NOT COPY the
-                 ramdisk at all. This may be useful to reduce the
-                 boot time on your system, but requires that this
-                 feature is supported by your Linux kernel.
-
-  ipaddr       - IP address; needed for tftpboot command
-
-  loadaddr     - Default load address for commands like "bootp",
-                 "rarpboot", "tftpboot", "loadb" or "diskboot"
-
-  loads_echo   - see CONFIG_LOADS_ECHO
-
-  serverip     - TFTP server IP address; needed for tftpboot command
-
-  bootretry    - see CONFIG_BOOT_RETRY_TIME
-
-  bootdelaykey - see CONFIG_AUTOBOOT_DELAY_STR
-
-  bootstopkey  - see CONFIG_AUTOBOOT_STOP_STR
-
-  ethprime     - controls which interface is used first.
-
-  ethact       - controls which interface is currently active.
-                 For example you can do the following
-
-                 => setenv ethact FEC
-                 => ping 192.168.0.1 # traffic sent on FEC
-                 => setenv ethact SCC
-                 => ping 10.0.0.1 # traffic sent on SCC
-
-  ethrotate    - When set to "no" U-Boot does not go through all
-                 available network interfaces.
-                 It just stays at the currently selected interface.
-
-  netretry     - When set to "no" each network operation will
-                 either succeed or fail without retrying.
-                 When set to "once" the network operation will
-                 fail when all the available network interfaces
-                 are tried once without success.
-                 Useful on scripts which control the retry operation
-                 themselves.
-
-  npe_ucode    - set load address for the NPE microcode
-
-  silent_linux  - If set then Linux will be told to boot silently, by
-                 changing the console to be empty. If "yes" it will be
-                 made silent. If "no" it will not be made silent. If
-                 unset, then it will be made silent if the U-Boot console
-                 is silent.
-
-  tftpsrcp     - If this is set, the value is used for TFTP's
-                 UDP source port.
-
-  tftpdstp     - If this is set, the value is used for TFTP's UDP
-                 destination port instead of the Well Know Port 69.
-
-  tftpblocksize - Block size to use for TFTP transfers; if not set,
-                 we use the TFTP server's default block size
-
-  tftptimeout  - Retransmission timeout for TFTP packets (in milli-
-                 seconds, minimum value is 1000 = 1 second). Defines
-                 when a packet is considered to be lost so it has to
-                 be retransmitted. The default is 5000 = 5 seconds.
-                 Lowering this value may make downloads succeed
-                 faster in networks with high packet loss rates or
-                 with unreliable TFTP servers.
-
-  tftptimeoutcountmax  - maximum count of TFTP timeouts (no
-                 unit, minimum value = 0). Defines how many timeouts
-                 can happen during a single file transfer before that
-                 transfer is aborted. The default is 10, and 0 means
-                 'no timeouts allowed'. Increasing this value may help
-                 downloads succeed with high packet loss rates, or with
-                 unreliable TFTP servers or client hardware.
-
-  tftpwindowsize       - if this is set, the value is used for TFTP's
-                 window size as described by RFC 7440.
-                 This means the count of blocks we can receive before
-                 sending ack to server.
-
-  vlan         - When set to a value < 4095 the traffic over
-                 Ethernet is encapsulated/received over 802.1q
-                 VLAN tagged frames.
-
-  bootpretryperiod     - Period during which BOOTP/DHCP sends retries.
-                 Unsigned value, in milliseconds. If not set, the period will
-                 be either the default (28000), or a value based on
-                 CONFIG_NET_RETRY_COUNT, if defined. This value has
-                 precedence over the valu based on CONFIG_NET_RETRY_COUNT.
-
-  memmatches   - Number of matches found by the last 'ms' command, in hex
-
-  memaddr      - Address of the last match found by the 'ms' command, in hex,
-                 or 0 if none
-
-  mempos       - Index position of the last match found by the 'ms' command,
-                 in units of the size (.b, .w, .l) of the search
-
-  zbootbase    - (x86 only) Base address of the bzImage 'setup' block
-
-  zbootaddr    - (x86 only) Address of the loaded bzImage, typically
-                 BZIMAGE_LOAD_ADDR which is 0x100000
-
-The following image location variables contain the location of images
-used in booting. The "Image" column gives the role of the image and is
-not an environment variable name. The other columns are environment
-variable names. "File Name" gives the name of the file on a TFTP
-server, "RAM Address" gives the location in RAM the image will be
-loaded to, and "Flash Location" gives the image's address in NOR
-flash or offset in NAND flash.
-
-*Note* - these variables don't have to be defined for all boards, some
-boards currently use other variables for these purposes, and some
-boards use these variables for other purposes.
-
-Image              File Name        RAM Address       Flash Location
------              ---------        -----------       --------------
-u-boot             u-boot           u-boot_addr_r     u-boot_addr
-Linux kernel       bootfile         kernel_addr_r     kernel_addr
-device tree blob    fdtfile         fdt_addr_r        fdt_addr
-ramdisk                    ramdiskfile      ramdisk_addr_r    ramdisk_addr
-
-The following environment variables may be used and automatically
-updated by the network boot commands ("bootp" and "rarpboot"),
-depending the information provided by your boot server:
-
-  bootfile     - see above
-  dnsip                - IP address of your Domain Name Server
-  dnsip2       - IP address of your secondary Domain Name Server
-  gatewayip    - IP address of the Gateway (Router) to use
-  hostname     - Target hostname
-  ipaddr       - see above
-  netmask      - Subnet Mask
-  rootpath     - Pathname of the root filesystem on the NFS server
-  serverip     - see above
-
-
-There are two special Environment Variables:
-
-  serial#      - contains hardware identification information such
-                 as type string and/or serial number
-  ethaddr      - Ethernet address
-
-These variables can be set only once (usually during manufacturing of
-the board). U-Boot refuses to delete or overwrite these variables
-once they have been set once.
-
-
-Further special Environment Variables:
-
-  ver          - Contains the U-Boot version string as printed
-                 with the "version" command. This variable is
-                 readonly (see CONFIG_VERSION_VARIABLE).
-
-
-Please note that changes to some configuration parameters may take
-only effect after the next boot (yes, that's just like Windoze :-).
-
-
-Callback functions for environment variables:
----------------------------------------------
-
-For some environment variables, the behavior of u-boot needs to change
-when their values are changed.  This functionality allows functions to
-be associated with arbitrary variables.  On creation, overwrite, or
-deletion, the callback will provide the opportunity for some side
-effect to happen or for the change to be rejected.
-
-The callbacks are named and associated with a function using the
-U_BOOT_ENV_CALLBACK macro in your board or driver code.
-
-These callbacks are associated with variables in one of two ways.  The
-static list can be added to by defining CONFIG_ENV_CALLBACK_LIST_STATIC
-in the board configuration to a string that defines a list of
-associations.  The list must be in the following format:
-
-       entry = variable_name[:callback_name]
-       list = entry[,list]
-
-If the callback name is not specified, then the callback is deleted.
-Spaces are also allowed anywhere in the list.
-
-Callbacks can also be associated by defining the ".callbacks" variable
-with the same list format above.  Any association in ".callbacks" will
-override any association in the static list. You can define
-CONFIG_ENV_CALLBACK_LIST_DEFAULT to a list (string) to define the
-".callbacks" environment variable in the default or embedded environment.
-
-If CONFIG_REGEX is defined, the variable_name above is evaluated as a
-regular expression. This allows multiple variables to be connected to
-the same callback without explicitly listing them all out.
-
-The signature of the callback functions is:
-
-    int callback(const char *name, const char *value, enum env_op op, int flags)
-
-* name - changed environment variable
-* value - new value of the environment variable
-* op - operation (create, overwrite, or delete)
-* flags - attributes of the environment variable change, see flags H_* in
-  include/search.h
-
-The return value is 0 if the variable change is accepted and 1 otherwise.
-
-
 Note for Redundant Ethernet Interfaces:
 =======================================
 
index f7f0383..eed27af 100644 (file)
@@ -927,6 +927,7 @@ config ARCH_APPLE
        select CLK
        select CMD_USB
        select DM
+       select DM_GPIO
        select DM_KEYBOARD
        select DM_SERIAL
        select DM_USB
@@ -935,6 +936,7 @@ config ARCH_APPLE
        select LINUX_KERNEL_IMAGE_HEADER
        select OF_CONTROL
        select OF_BOARD
+       select PINCTRL
        select POSITION_INDEPENDENT
        select USB
        imply CMD_DM
index 2abd313..05362d1 100644 (file)
                          0x08 0x04
                          0x08 0x04>;
 };
+
+&hace {
+       u-boot,dm-pre-reloc;
+       status = "okay";
+};
+
+&acry {
+       u-boot,dm-pre-reloc;
+       status = "okay";
+};
index f121f54..31905fd 100644 (file)
                        };
                };
 
+               hace: hace@1e6d0000 {
+                       compatible = "aspeed,ast2600-hace";
+                       reg = <0x1e6d0000 0x200>;
+                       interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&scu ASPEED_CLK_GATE_YCLK>;
+                       status = "disabled";
+               };
+
+               acry: acry@1e6fa000 {
+                       compatible = "aspeed,ast2600-acry";
+                       reg = <0x1e6fa000 0x1000>,
+                             <0x1e710000 0x10000>;
+                       interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&scu ASPEED_CLK_GATE_RSACLK>;
+                       status = "disabled";
+               };
+
                edac: sdram@1e6e0000 {
                        compatible = "aspeed,ast2600-sdram-edac";
                        reg = <0x1e6e0000 0x174>;
index 79eff82..71fcf61 100644 (file)
@@ -5,6 +5,8 @@
 
 /dts-v1/;
 
+#include <dt-bindings/mux/ti-serdes.h>
+#include <dt-bindings/phy/phy.h>
 #include "k3-am642.dtsi"
 #include "k3-am64-sk-lp4-1333MTs.dtsi"
 #include "k3-am64-ddr.dtsi"
                        AM64X_IOPAD(0x029c, PIN_INPUT_PULLUP, 0)        /* (C20) MMC1_SDWP */
                >;
        };
+
+       main_usb0_pins_default: main-usb0-pins-default {
+               u-boot,dm-spl;
+               pinctrl-single,pins = <
+                       AM64X_IOPAD(0x02a8, PIN_OUTPUT, 0) /* (E19) USB0_DRVVBUS */
+               >;
+       };
 };
 
 &dmsc {
        pinctrl-0 = <&main_mmc1_pins_default>;
 };
 
+&serdes_ln_ctrl {
+       idle-states = <AM64_SERDES0_LANE0_USB>;
+};
+
+&serdes_wiz0 {
+       status = "okay";
+};
+
+&serdes0 {
+       serdes0_usb_link: link@0 {
+               reg = <0>;
+               cdns,num-lanes = <1>;
+               #phy-cells = <0>;
+               cdns,phy-type = <PHY_TYPE_USB3>;
+               resets = <&serdes_wiz0 1>;
+       };
+};
+
+&usbss0 {
+       ti,vbus-divider;
+};
+
+&usb0 {
+       dr_mode = "host";
+       maximum-speed = "super-speed";
+       pinctrl-names = "default";
+       pinctrl-0 = <&main_usb0_pins_default>;
+       phys = <&serdes0_usb_link>;
+       phy-names = "cdns3,usb3-phy";
+};
+
 #include "k3-am642-sk-u-boot.dtsi"
index efbcfb3..95cf52c 100644 (file)
 &cpsw_port2 {
        status = "disabled";
 };
+
+&main_usb0_pins_default {
+       u-boot,dm-spl;
+};
+
+&serdes_ln_ctrl {
+       u-boot,mux-autoprobe;
+};
+
+&usbss0 {
+       u-boot,dm-spl;
+};
+
+&usb0 {
+       dr_mode = "host";
+       u-boot,dm-spl;
+};
+
+&serdes_wiz0 {
+       u-boot,dm-spl;
+};
+
+&serdes0_usb_link {
+       u-boot,dm-spl;
+};
+
+&serdes0 {
+       u-boot,dm-spl;
+};
+
+&serdes_refclk {
+       u-boot,dm-spl;
+};
index 8e0f4ea..68f5543 100644 (file)
                enet1-sgmii-phy = &sgmii_phy1;
                spi0 = &qspi;
                spi1 = &dspi1;
+               ethernet0 = &enet0;
+               ethernet1 = &enet1;
+               ethernet2 = &enet2;
+               ethernet3 = &swp2;
+               ethernet4 = &swp3;
+               ethernet5 = &swp4;
+               ethernet6 = &swp5;
+       };
+};
+
+&dspi0 {
+       bus-num = <0>;
+       status = "okay";
+
+       sja1105: ethernet-switch@1 {
+               reg = <0x1>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nxp,sja1105t";
+               /* 12 MHz */
+               spi-max-frequency = <12000000>;
+               /* Sample data on trailing clock edge */
+               spi-cpha;
+               /* SPI controller settings for SJA1105 timing requirements */
+               fsl,spi-cs-sck-delay = <1000>;
+               fsl,spi-sck-cs-delay = <1000>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       swp5: port@0 {
+                               /* ETH5 written on chassis */
+                               label = "swp5";
+                               phy-handle = <&rgmii_phy6>;
+                               phy-mode = "rgmii-id";
+                               reg = <0>;
+                       };
+
+                       swp2: port@1 {
+                               /* ETH2 written on chassis */
+                               label = "swp2";
+                               phy-handle = <&rgmii_phy3>;
+                               phy-mode = "rgmii-id";
+                               reg = <1>;
+                       };
+
+                       swp3: port@2 {
+                               /* ETH3 written on chassis */
+                               label = "swp3";
+                               phy-handle = <&rgmii_phy4>;
+                               phy-mode = "rgmii-id";
+                               reg = <2>;
+                       };
+
+                       swp4: port@3 {
+                               /* ETH4 written on chassis */
+                               label = "swp4";
+                               phy-handle = <&rgmii_phy5>;
+                               phy-mode = "rgmii-id";
+                               reg = <3>;
+                       };
+
+                       port@4 {
+                               /* Internal port connected to eth2 */
+                               ethernet = <&enet2>;
+                               phy-mode = "rgmii";
+                               reg = <4>;
+
+                               fixed-link {
+                                       speed = <1000>;
+                                       full-duplex;
+                               };
+                       };
+               };
        };
 };
 
        status = "okay";
 };
 
+/* RGMII delays added via PCB traces */
+&enet2 {
+       phy-mode = "rgmii";
+       status = "okay";
+
+       fixed-link {
+               speed = <1000>;
+               full-duplex;
+       };
+};
+
 &i2c0 {
        status = "okay";
 };
                reg = <0x2>;
        };
 
+       /* BCM5464 quad PHY */
+       rgmii_phy3: ethernet-phy@3 {
+               reg = <0x3>;
+       };
+
+       rgmii_phy4: ethernet-phy@4 {
+               reg = <0x4>;
+       };
+
+       rgmii_phy5: ethernet-phy@5 {
+               reg = <0x5>;
+       };
+
+       rgmii_phy6: ethernet-phy@6 {
+               reg = <0x6>;
+       };
+
        /* SGMII PCS for enet0 */
        tbi0: tbi-phy@1f {
                reg = <0x1f>;
index d50ec5f..589abd4 100644 (file)
@@ -17,7 +17,7 @@
 #define ASPEED_MAC_COUNT       4
 #define ASPEED_DRAM_BASE       0x80000000
 #define ASPEED_SRAM_BASE       0x10000000
-#define ASPEED_SRAM_SIZE       0x10000
+#define ASPEED_SRAM_SIZE       0x16000
 #else
 #err "Unrecognized Aspeed platform."
 #endif
index a205fb1..7c5aab9 100644 (file)
@@ -8,10 +8,12 @@
 #define SCU_UNLOCK_KEY                 0x1688a8a8
 
 #define SCU_CLKGATE1_EMMC                      BIT(27)
+#define SCU_CLKGATE1_ACRY                      BIT(24)
 #define SCU_CLKGATE1_MAC2                      BIT(21)
 #define SCU_CLKGATE1_MAC1                      BIT(20)
-#define SCU_CLKGATE1_USB_HUB           BIT(14)
-#define SCU_CLKGATE1_USB_HOST2         BIT(7)
+#define SCU_CLKGATE1_USB_HUB                   BIT(14)
+#define SCU_CLKGATE1_HACE                      BIT(13)
+#define SCU_CLKGATE1_USB_HOST2                 BIT(7)
 
 #define SCU_CLKGATE2_FSI                       BIT(30)
 #define SCU_CLKGATE2_MAC4                      BIT(21)
index 956d258..ba31290 100644 (file)
@@ -109,6 +109,10 @@ ENTRY(_main)
        mov     r9, r0
        bl      board_init_f_init_reserve
 
+#if defined(CONFIG_DEBUG_UART) && CONFIG_IS_ENABLED(SERIAL)
+       bl      debug_uart_init
+#endif
+
 #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_EARLY_BSS)
        CLEAR_BSS
 #endif
index 28c8356..84c04bd 100644 (file)
@@ -91,6 +91,10 @@ ENTRY(_main)
        mov     x18, x0
        bl      board_init_f_init_reserve
 
+#if defined(CONFIG_DEBUG_UART) && CONFIG_IS_ENABLED(SERIAL)
+       bl      debug_uart_init
+#endif
+
        mov     x0, #0
        bl      board_init_f
 
index 0d8cb29..6c49d6a 100644 (file)
@@ -28,14 +28,7 @@ u32 spl_boot_device(void)
 
 struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
 {
-       /*
-        * When boot from SPI, AST2600 already remap 0x00000000 ~ 0x0fffffff
-        * to BMC SPI memory space 0x20000000 ~ 0x2fffffff. The next stage BL
-        * has been located in SPI for XIP. In this case, the load buffer for
-        * SPL image loading will be set to the remapped address of the next
-        * BL instead of the DRAM space CONFIG_SYS_LOAD_ADDR
-        */
-       return (struct image_header *)(CONFIG_SYS_TEXT_BASE);
+       return (struct image_header *)(CONFIG_SYS_LOAD_ADDR);
 }
 
 #ifdef CONFIG_SPL_OS_BOOT
index 2bc8e60..d40969c 100644 (file)
@@ -118,10 +118,6 @@ void board_debug_uart_init(void)
 #define GPIO0_BASE     0xff720000
 #define PMUGRF_BASE    0xff320000
        struct rk3399_grf_regs * const grf = (void *)GRF_BASE;
-#ifdef CONFIG_TARGET_CHROMEBOOK_BOB
-       struct rk3399_pmugrf_regs * const pmugrf = (void *)PMUGRF_BASE;
-       struct rockchip_gpio_regs * const gpio = (void *)GPIO0_BASE;
-#endif
 
 #if defined(CONFIG_DEBUG_UART_BASE) && (CONFIG_DEBUG_UART_BASE == 0xff180000)
        /* Enable early UART0 on the RK3399 */
@@ -140,19 +136,25 @@ void board_debug_uart_init(void)
                     GRF_GPIO3B7_SEL_MASK,
                     GRF_UART3_SOUT << GRF_GPIO3B7_SEL_SHIFT);
 #else
-# ifdef CONFIG_TARGET_CHROMEBOOK_BOB
-       rk_setreg(&grf->io_vsel, 1 << 0);
-
-       /*
-        * Let's enable these power rails here, we are already running the SPI
-        * Flash based code.
-        */
-       spl_gpio_output(gpio, GPIO(BANK_B, 2), 1);  /* PP1500_EN */
-       spl_gpio_set_pull(&pmugrf->gpio0_p, GPIO(BANK_B, 2), GPIO_PULL_NORMAL);
+       struct rk3399_pmugrf_regs * const pmugrf = (void *)PMUGRF_BASE;
+       struct rockchip_gpio_regs * const gpio = (void *)GPIO0_BASE;
 
-       spl_gpio_output(gpio, GPIO(BANK_B, 4), 1);  /* PP3000_EN */
-       spl_gpio_set_pull(&pmugrf->gpio0_p, GPIO(BANK_B, 4), GPIO_PULL_NORMAL);
-#endif /* CONFIG_TARGET_CHROMEBOOK_BOB */
+       if (IS_ENABLED(CONFIG_SPL_BUILD) &&
+           IS_ENABLED(CONFIG_TARGET_CHROMEBOOK_BOB)) {
+               rk_setreg(&grf->io_vsel, 1 << 0);
+
+               /*
+                * Let's enable these power rails here, we are already running
+                * the SPI-Flash-based code.
+                */
+               spl_gpio_output(gpio, GPIO(BANK_B, 2), 1);  /* PP1500_EN */
+               spl_gpio_set_pull(&pmugrf->gpio0_p, GPIO(BANK_B, 2),
+                                 GPIO_PULL_NORMAL);
+
+               spl_gpio_output(gpio, GPIO(BANK_B, 4), 1);  /* PP3000_EN */
+               spl_gpio_set_pull(&pmugrf->gpio0_p, GPIO(BANK_B, 4),
+                                 GPIO_PULL_NORMAL);
+       }
 
        /* Enable early UART2 channel C on the RK3399 */
        rk_clrsetreg(&grf->gpio4c_iomux,
index b72dafc..873f85a 100644 (file)
@@ -211,6 +211,16 @@ int os_map_file(const char *pathname, int os_flags, void **bufp, int *sizep)
        return 0;
 }
 
+int os_unmap(void *buf, int size)
+{
+       if (munmap(buf, size)) {
+               printf("Can't unmap %p %x\n", buf, size);
+               return -EIO;
+       }
+
+       return 0;
+}
+
 /* Restore tty state when we exit */
 static struct termios orig_term;
 static bool term_setup;
index 8cd688e..e5261bb 100644 (file)
                test4-gpios = <&gpio_a 14>, <&gpio_b 4 1 3 2 1>;
                test5-gpios = <&gpio_a 19>;
 
+               bool-value;
                int-value = <1234>;
                uint-value = <(-1234)>;
                int64-value = /bits/ 64 <0x1111222233334444>;
diff --git a/board/sandbox/sandbox.env b/board/sandbox/sandbox.env
new file mode 100644 (file)
index 0000000..b4c0463
--- /dev/null
@@ -0,0 +1,25 @@
+stdin=serial
+#ifdef CONFIG_SANDBOX_SDL
+stdin+=,cros-ec-keyb,usbkbd
+#endif
+stdout=serial,vidconsole
+stderr=serial,vidconsole
+
+ethaddr=02:00:11:22:33:44
+eth2addr=02:00:11:22:33:48
+eth3addr=02:00:11:22:33:45
+eth4addr=02:00:11:22:33:48
+eth5addr=02:00:11:22:33:46
+eth6addr=02:00:11:22:33:47
+ipaddr=192.0.2.1
+
+/*
+ * These are used for distro boot which is not supported. But once bootmethod
+ * is provided these will be used again.
+ */
+bootm_size=0x10000000
+kernel_addr_r=0x1000000
+fdt_addr_r=0xc00000
+ramdisk_addr_r=0x2000000
+scriptaddr=0x1000
+pxefile_addr_r=0x2000
index e635c72..f31820c 100644 (file)
@@ -26,12 +26,9 @@ DECLARE_GLOBAL_DATA_PTR;
 static int do_bootm_standalone(int flag, int argc, char *const argv[],
                               bootm_headers_t *images)
 {
-       char *s;
        int (*appl)(int, char *const[]);
 
-       /* Don't start if "autostart" is set to "no" */
-       s = env_get("autostart");
-       if ((s != NULL) && !strcmp(s, "no")) {
+       if (!env_get_autostart()) {
                env_set_hex("filesize", images->os.image_len);
                return 0;
        }
index 33b4a46..b629339 100644 (file)
@@ -1202,7 +1202,7 @@ int fit_set_timestamp(void *fit, int noffset, time_t timestamp)
  * calculate_hash - calculate and return hash for provided input data
  * @data: pointer to the input data
  * @data_len: data length
- * @algo: requested hash algorithm
+ * @name: requested hash algorithm name
  * @value: pointer to the char, will hold hash value data (caller must
  * allocate enough free space)
  * value_len: length of the calculated hash
@@ -1230,7 +1230,7 @@ int calculate_hash(const void *data, int data_len, const char *name,
                return -1;
        }
 
-       hash_algo = hash_algo_lookup_by_name(algo);
+       hash_algo = hash_algo_lookup_by_name(name);
        if (hash_algo == HASH_ALGO_INVALID) {
                debug("Unsupported hash algorithm\n");
                return -1;
index a7a84f2..a32acca 100644 (file)
@@ -550,7 +550,10 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
         * Scenario 2: If there is an fdt_addr specified, pass it along to
         * bootm, and adjust argc appropriately.
         *
-        * Scenario 3: fdt blob is not available.
+        * Scenario 3: If there is an fdtcontroladdr specified, pass it along to
+        * bootm, and adjust argc appropriately.
+        *
+        * Scenario 4: fdt blob is not available.
         */
        bootm_argv[3] = env_get("fdt_addr_r");
 
@@ -652,6 +655,9 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
        if (!bootm_argv[3])
                bootm_argv[3] = env_get("fdt_addr");
 
+       if (!bootm_argv[3])
+               bootm_argv[3] = env_get("fdtcontroladdr");
+
        if (bootm_argv[3]) {
                if (!bootm_argv[2])
                        bootm_argv[2] = "-";
index 92468d0..b82a872 100644 (file)
@@ -140,9 +140,7 @@ int do_bootm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 
 int bootm_maybe_autostart(struct cmd_tbl *cmdtp, const char *cmd)
 {
-       const char *ep = env_get("autostart");
-
-       if (ep && !strcmp(ep, "yes")) {
+       if (env_get_autostart()) {
                char *local_args[2];
                local_args[0] = (char *)cmd;
                local_args[1] = NULL;
index d75b214..2b33c50 100644 (file)
--- a/cmd/elf.c
+++ b/cmd/elf.c
@@ -41,7 +41,6 @@ int do_bootelf(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
        unsigned long addr; /* Address of the ELF image */
        unsigned long rc; /* Return value from user code */
        char *sload = NULL;
-       const char *ep = env_get("autostart");
        int rcode = 0;
 
        /* Consume 'bootelf' */
@@ -69,7 +68,7 @@ int do_bootelf(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
        else
                addr = load_elf_image_shdr(addr);
 
-       if (ep && !strcmp(ep, "no"))
+       if (!env_get_autostart())
                return rcode;
 
        printf("## Starting application at 0x%08lx ...\n", addr);
index e7e2298..c269833 100644 (file)
--- a/cmd/mbr.c
+++ b/cmd/mbr.c
@@ -244,12 +244,12 @@ static int do_verify_mbr(struct blk_desc *dev, const char *str)
        for (i = 0; i < count; i++) {
                struct disk_partition p;
 
-               if (part_get_info(dev, i+1, &p))
+               if (part_get_info(dev, i + 1, &p))
                        goto fail;
 
-               if ((partitions[i].size && p.size < partitions[i].size) ||
-                   (partitions[i].start && p.start < partitions[i].start) ||
-                   (p.sys_ind != partitions[i].sys_ind))
+               if ((partitions[i].size && p.size != partitions[i].size) ||
+                   (partitions[i].start && p.start != partitions[i].start) ||
+                   p.sys_ind != partitions[i].sys_ind)
                        goto fail;
        }
        ret = 0;
index eac27ed..72246d9 100644 (file)
--- a/cmd/sf.c
+++ b/cmd/sf.c
@@ -384,7 +384,6 @@ static int do_spi_protect(int argc, char *const argv[])
        return ret == 0 ? 0 : 1;
 }
 
-#ifdef CONFIG_CMD_SF_TEST
 enum {
        STAGE_ERASE,
        STAGE_CHECK,
@@ -394,7 +393,7 @@ enum {
        STAGE_COUNT,
 };
 
-static char *stage_name[STAGE_COUNT] = {
+static const char *stage_name[STAGE_COUNT] = {
        "erase",
        "check",
        "write",
@@ -548,7 +547,6 @@ static int do_spi_flash_test(int argc, char *const argv[])
 
        return 0;
 }
-#endif /* CONFIG_CMD_SF_TEST */
 
 static int do_spi_flash(struct cmd_tbl *cmdtp, int flag, int argc,
                        char *const argv[])
@@ -582,10 +580,8 @@ static int do_spi_flash(struct cmd_tbl *cmdtp, int flag, int argc,
                ret = do_spi_flash_erase(argc, argv);
        else if (strcmp(cmd, "protect") == 0)
                ret = do_spi_protect(argc, argv);
-#ifdef CONFIG_CMD_SF_TEST
-       else if (!strcmp(cmd, "test"))
+       else if (IS_ENABLED(CONFIG_CMD_SF_TEST) && !strcmp(cmd, "test"))
                ret = do_spi_flash_test(argc, argv);
-#endif
        else
                ret = -1;
 
@@ -597,16 +593,8 @@ usage:
        return CMD_RET_USAGE;
 }
 
-#ifdef CONFIG_CMD_SF_TEST
-#define SF_TEST_HELP "\nsf test offset len             " \
-               "- run a very basic destructive test"
-#else
-#define SF_TEST_HELP
-#endif
-
-U_BOOT_CMD(
-       sf,     5,      1,      do_spi_flash,
-       "SPI flash sub-system",
+#ifdef CONFIG_SYS_LONGHELP
+static const char long_help[] =
        "probe [[bus:]cs] [hz] [mode]   - init flash device on given SPI bus\n"
        "                                 and chip select\n"
        "sf read addr offset|partition len      - read `len' bytes starting at\n"
@@ -622,6 +610,14 @@ U_BOOT_CMD(
        "                                         at `addr' to flash at `offset'\n"
        "                                         or to start of mtd `partition'\n"
        "sf protect lock/unlock sector len      - protect/unprotect 'len' bytes starting\n"
-       "                                         at address 'sector'\n"
-       SF_TEST_HELP
+       "                                         at address 'sector'"
+#ifdef CONFIG_CMD_SF_TEST
+       "\nsf test offset len           - run a very basic destructive test"
+#endif
+#endif /* CONFIG_SYS_LONGHELP */
+       ;
+
+U_BOOT_CMD(
+       sf,     5,      1,      do_spi_flash,
+       "SPI flash sub-system", long_help
 );
index fdcf453..fede7e4 100644 (file)
@@ -32,6 +32,16 @@ config CONSOLE_RECORD_OUT_SIZE
          more data will be recorded until some is removed. The buffer is
          allocated immediately after the malloc() region is ready.
 
+config CONSOLE_RECORD_OUT_SIZE_F
+       hex "Output buffer size before relocation"
+       depends on CONSOLE_RECORD
+       default 0x400 if CONSOLE_RECORD
+       help
+         Set the size of the console output buffer before relocation. When
+         this fills up, no more data will be recorded until some is removed.
+         The buffer is allocated immediately after the early malloc() region is
+         ready.
+
 config CONSOLE_RECORD_IN_SIZE
        hex "Input buffer size"
        depends on CONSOLE_RECORD
index 0013d18..0c9099c 100644 (file)
@@ -735,7 +735,9 @@ int console_record_init(void)
        int ret;
 
        ret = membuff_new((struct membuff *)&gd->console_out,
-                         CONFIG_CONSOLE_RECORD_OUT_SIZE);
+                         gd->flags & GD_FLG_RELOC ?
+                                 CONFIG_CONSOLE_RECORD_OUT_SIZE :
+                                 CONFIG_CONSOLE_RECORD_OUT_SIZE_F);
        if (ret)
                return ret;
        ret = membuff_new((struct membuff *)&gd->console_in,
index 7bb1fd4..2595aed 100644 (file)
--- a/config.mk
+++ b/config.mk
@@ -50,8 +50,10 @@ endif
 ifneq ($(BOARD),)
 ifdef  VENDOR
 BOARDDIR = $(VENDOR)/$(BOARD)
+ENVDIR=${vendor}/env
 else
 BOARDDIR = $(BOARD)
+ENVDIR=${board}/env
 endif
 endif
 ifdef  BOARD
index aafbb41..698e80a 100644 (file)
@@ -3,6 +3,7 @@ CONFIG_SKIP_LOWLEVEL_INIT=y
 CONFIG_ARCH_K3=y
 CONFIG_SYS_MALLOC_LEN=0x2000000
 CONFIG_SYS_MALLOC_F_LEN=0x8000
+CONFIG_SPL_GPIO=y
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
 CONFIG_SPL_LIBGENERIC_SUPPORT=y
 CONFIG_NR_DRAM_BANKS=2
@@ -34,6 +35,7 @@ CONFIG_SPL_SEPARATE_BSS=y
 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y
 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1400
 CONFIG_SPL_DMA=y
+CONFIG_SPL_DM_GPIO=y
 CONFIG_SPL_ENV_SUPPORT=y
 CONFIG_SPL_I2C=y
 CONFIG_SPL_DM_MAILBOX=y
@@ -70,10 +72,14 @@ CONFIG_SPL_DM=y
 CONFIG_SPL_DM_SEQ_ALIAS=y
 CONFIG_REGMAP=y
 CONFIG_SPL_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_SPL_SYSCON=y
 CONFIG_SPL_OF_TRANSLATE=y
 CONFIG_CLK=y
 CONFIG_SPL_CLK=y
 CONFIG_CLK_TI_SCI=y
+CONFIG_CLK_CCF=y
+CONFIG_SPL_CLK_CCF=y
 CONFIG_DFU_MMC=y
 CONFIG_DFU_RAM=y
 CONFIG_DFU_SF=y
@@ -84,6 +90,7 @@ CONFIG_TI_K3_NAVSS_UDMA=y
 CONFIG_TI_SCI_PROTOCOL=y
 CONFIG_DM_I2C=y
 CONFIG_SYS_I2C_OMAP24XX=y
+CONFIG_DM_GPIO=y
 CONFIG_DM_MAILBOX=y
 CONFIG_K3_SEC_PROXY=y
 CONFIG_SUPPORT_EMMC_BOOT=y
@@ -96,10 +103,18 @@ CONFIG_MMC_SDHCI_AM654=y
 CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH_SPANSION=y
 CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_MULTIPLEXER=y
+CONFIG_MUX_MMIO=y
 CONFIG_PHY_TI_DP83867=y
 CONFIG_PHY_FIXED=y
 CONFIG_DM_ETH=y
 CONFIG_TI_AM65_CPSW_NUSS=y
+CONFIG_PHY=y
+CONFIG_SPL_PHY=y
+CONFIG_PHY_CADENCE_TORRENT=y
+CONFIG_SPL_PHY_CADENCE_TORRENT=y
+CONFIG_PHY_J721E_WIZ=y
+CONFIG_SPL_PHY_J721E_WIZ=y
 CONFIG_PINCTRL=y
 CONFIG_SPL_PINCTRL=y
 CONFIG_PINCTRL_SINGLE=y
index f564fa0..f943e1f 100644 (file)
@@ -10,6 +10,7 @@ CONFIG_TARGET_AM642_R5_EVM=y
 CONFIG_ENV_SIZE=0x20000
 CONFIG_ENV_OFFSET=0x680000
 CONFIG_DM_GPIO=y
+CONFIG_SPL_DM_GPIO=y
 CONFIG_SPL_DM_SPI=y
 CONFIG_DEFAULT_DEVICE_TREE="k3-am642-r5-evm"
 CONFIG_SPL_TEXT_BASE=0x70000000
@@ -76,10 +77,14 @@ CONFIG_SPL_DM=y
 CONFIG_SPL_DM_SEQ_ALIAS=y
 CONFIG_REGMAP=y
 CONFIG_SPL_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_SPL_SYSCON=y
 CONFIG_SPL_OF_TRANSLATE=y
 CONFIG_CLK=y
 CONFIG_SPL_CLK=y
 CONFIG_CLK_TI_SCI=y
+CONFIG_CLK_CCF=y
+CONFIG_SPL_CLK_CCF=y
 CONFIG_DFU_MMC=y
 CONFIG_DFU_RAM=y
 CONFIG_DFU_SF=y
@@ -97,6 +102,14 @@ CONFIG_MMC_SDHCI_AM654=y
 CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH_SPANSION=y
 CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_PHY=y
+CONFIG_SPL_PHY=y
+CONFIG_PHY_CADENCE_SIERRA=y
+CONFIG_SPL_PHY_CADENCE_SIERRA=y
+CONFIG_PHY_CADENCE_TORRENT=y
+CONFIG_SPL_PHY_CADENCE_TORRENT=y
+CONFIG_PHY_J721E_WIZ=y
+CONFIG_SPL_PHY_J721E_WIZ=y
 CONFIG_PINCTRL=y
 # CONFIG_PINCTRL_GENERIC is not set
 CONFIG_SPL_PINCTRL=y
index ee5bfdd..ed6557a 100644 (file)
@@ -6,6 +6,7 @@ CONFIG_NR_DRAM_BANKS=1
 CONFIG_ENV_OFFSET=0x3F8000
 CONFIG_DEFAULT_DEVICE_TREE="rv1108-elgin-r1"
 CONFIG_ROCKCHIP_RV1108=y
+# CONFIG_DEBUG_UART_BOARD_INIT is not set
 CONFIG_ROCKCHIP_BOOT_MODE_REG=0
 CONFIG_TARGET_ELGIN_RV1108=y
 CONFIG_DEBUG_UART_BASE=0x10210000
index 5f00d6a..0f03a72 100644 (file)
@@ -1,9 +1,10 @@
 CONFIG_ARM=y
 CONFIG_SYS_DCACHE_OFF=y
+CONFIG_SPL_SYS_THUMB_BUILD=y
 CONFIG_ARCH_ASPEED=y
-CONFIG_SYS_TEXT_BASE=0x10000
 CONFIG_SYS_MALLOC_LEN=0x2000000
 CONFIG_SYS_MALLOC_F_LEN=0x800
+CONFIG_SYS_TEXT_BASE=0x80000000
 CONFIG_ASPEED_AST2600=y
 CONFIG_TARGET_EVB_AST2600=y
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
@@ -12,22 +13,28 @@ CONFIG_NR_DRAM_BANKS=1
 CONFIG_ENV_SIZE=0x10000
 CONFIG_DEFAULT_DEVICE_TREE="ast2600-evb"
 CONFIG_SPL_SERIAL=y
+CONFIG_SPL_STACK_R_ADDR=0x83000000
 CONFIG_SPL_SIZE_LIMIT=0x10000
 CONFIG_SPL=y
 # CONFIG_ARMV7_NONSEC is not set
 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
 CONFIG_SYS_LOAD_ADDR=0x83000000
 CONFIG_FIT=y
-# CONFIG_LEGACY_IMAGE_FORMAT is not set
+CONFIG_SPL_FIT_SIGNATURE=y
+CONFIG_SPL_LOAD_FIT=y
+CONFIG_SPL_LOAD_FIT_ADDRESS=0x10000
+# CONFIG_USE_SPL_FIT_GENERATOR is not set
 CONFIG_USE_BOOTARGS=y
 CONFIG_BOOTARGS="console=ttyS4,115200n8 root=/dev/ram rw"
 CONFIG_USE_BOOTCOMMAND=y
-CONFIG_BOOTCOMMAND="bootm 20100000"
+CONFIG_BOOTCOMMAND="run bootspi"
 # CONFIG_DISPLAY_CPUINFO is not set
 CONFIG_SPL_SIZE_LIMIT_SUBTRACT_GD=y
 CONFIG_SPL_SIZE_LIMIT_SUBTRACT_MALLOC=y
-# CONFIG_SPL_LEGACY_IMAGE_SUPPORT is not set
 CONFIG_SPL_SYS_MALLOC_SIMPLE=y
+CONFIG_SPL_STACK_R=y
+CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x2000000
+CONFIG_SPL_FIT_IMAGE_TINY=y
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_RAM_SUPPORT=y
 CONFIG_SPL_RAM_DEVICE=y
@@ -47,6 +54,9 @@ CONFIG_REGMAP=y
 CONFIG_SPL_OF_TRANSLATE=y
 CONFIG_CLK=y
 CONFIG_SPL_CLK=y
+CONFIG_DM_HASH=y
+CONFIG_HASH_ASPEED=y
+CONFIG_ASPEED_ACRY=y
 CONFIG_DM_I2C=y
 CONFIG_MISC=y
 CONFIG_SPL_MISC=y
@@ -65,5 +75,9 @@ CONFIG_SYS_NS16550=y
 CONFIG_SYSRESET=y
 CONFIG_SPL_SYSRESET=y
 CONFIG_WDT=y
+CONFIG_SHA512_ALGO=y
+CONFIG_SHA512=y
+CONFIG_SHA384=y
 CONFIG_HEXDUMP=y
 # CONFIG_EFI_LOADER is not set
+CONFIG_PHANDLE_CHECK_SEQ=y
index e446a22..544d6de 100644 (file)
@@ -6,6 +6,7 @@ CONFIG_NR_DRAM_BANKS=2
 CONFIG_ENV_OFFSET=0x0
 CONFIG_DEFAULT_DEVICE_TREE="rk3128-evb"
 CONFIG_ROCKCHIP_RK3128=y
+# CONFIG_DEBUG_UART_BOARD_INIT is not set
 CONFIG_DEBUG_UART_BASE=0x20068000
 CONFIG_DEBUG_UART_CLOCK=24000000
 CONFIG_DEBUG_UART=y
index 916a6fb..b6510b5 100644 (file)
@@ -5,6 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x60000000
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_DEFAULT_DEVICE_TREE="rv1108-evb"
 CONFIG_ROCKCHIP_RV1108=y
+# CONFIG_DEBUG_UART_BOARD_INIT is not set
 CONFIG_DEBUG_UART_BASE=0x10210000
 CONFIG_DEBUG_UART_CLOCK=24000000
 CONFIG_DEBUG_UART=y
index d92fdf4..4385df6 100644 (file)
@@ -51,8 +51,11 @@ CONFIG_SPI_FLASH_DATAFLASH=y
 CONFIG_PHY_ATHEROS=y
 CONFIG_PHY_BROADCOM=y
 CONFIG_PHY_FIXED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_DM_ETH=y
 CONFIG_DM_MDIO=y
+CONFIG_DM_DSA=y
+CONFIG_SJA1105=y
 CONFIG_PHY_GIGE=y
 CONFIG_MII=y
 CONFIG_TSEC_ENET=y
index a745857..506a337 100644 (file)
@@ -66,8 +66,11 @@ CONFIG_SPI_FLASH_DATAFLASH=y
 CONFIG_PHY_ATHEROS=y
 CONFIG_PHY_BROADCOM=y
 CONFIG_PHY_FIXED=y
+CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_DM_ETH=y
 CONFIG_DM_MDIO=y
+CONFIG_DM_DSA=y
+CONFIG_SJA1105=y
 CONFIG_PHY_GIGE=y
 CONFIG_MII=y
 CONFIG_TSEC_ENET=y
index d1c2c3c..f42f4e5 100644 (file)
@@ -8,7 +8,6 @@ CONFIG_PINE64_DT_SELECTION=y
 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
 CONFIG_OF_LIST="sun50i-a64-pine64 sun50i-a64-pine64-plus"
 CONFIG_PHY_REALTEK=y
-CONFIG_RTL8211E_PINE64_GIGABIT_FIX=y
 CONFIG_SUN8I_EMAC=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_OHCI_HCD=y
index 9382c38..96260e0 100644 (file)
@@ -8,7 +8,6 @@ CONFIG_TARGET_PM9G45=y
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_DM_GPIO=y
 CONFIG_DEFAULT_DEVICE_TREE="at91sam9m10g45ek"
-CONFIG_DEBUG_UART_BOARD_INIT=y
 CONFIG_DEBUG_UART_BASE=0xffffee00
 CONFIG_DEBUG_UART_CLOCK=132000000
 CONFIG_ENV_OFFSET_REDUND=0x100000
index 83d7ae5..02a5e94 100644 (file)
@@ -5,6 +5,9 @@ CONFIG_SYS_MALLOC_LEN=0x1000000
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_ENV_SIZE=0x40000
 CONFIG_ENV_SECT_SIZE=0x40000
+CONFIG_DEBUG_UART_BASE=0x9000000
+CONFIG_DEBUG_UART_CLOCK=0
+CONFIG_DEBUG_UART=y
 CONFIG_AHCI=y
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_SYS_LOAD_ADDR=0x40200000
@@ -47,6 +50,8 @@ CONFIG_PCI=y
 CONFIG_PCIE_ECAM_GENERIC=y
 CONFIG_SCSI=y
 CONFIG_DM_SCSI=y
+CONFIG_DEBUG_UART_PL011=y
+CONFIG_DEBUG_UART_SHIFT=2
 CONFIG_SYSRESET=y
 CONFIG_SYSRESET_PSCI=y
 CONFIG_TPM2_MMIO=y
index ab55748..d4f6d0b 100644 (file)
@@ -6,7 +6,10 @@ CONFIG_NR_DRAM_BANKS=1
 CONFIG_ENV_SIZE=0x40000
 CONFIG_ENV_SECT_SIZE=0x40000
 CONFIG_TARGET_QEMU_ARM_32BIT=y
+CONFIG_DEBUG_UART_BASE=0x9000000
+CONFIG_DEBUG_UART_CLOCK=0
 CONFIG_ARMV7_LPAE=y
+CONFIG_DEBUG_UART=y
 CONFIG_AHCI=y
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_SYS_LOAD_ADDR=0x40200000
@@ -49,6 +52,8 @@ CONFIG_PCI=y
 CONFIG_PCIE_ECAM_GENERIC=y
 CONFIG_SCSI=y
 CONFIG_DM_SCSI=y
+CONFIG_DEBUG_UART_PL011=y
+CONFIG_DEBUG_UART_SHIFT=2
 CONFIG_SYSRESET=y
 CONFIG_SYSRESET_PSCI=y
 CONFIG_TPM2_MMIO=y
index 7cc76bf..f184723 100644 (file)
@@ -203,6 +203,7 @@ CONFIG_RSA_VERIFY_WITH_PKEY=y
 CONFIG_TPM=y
 CONFIG_LZ4=y
 CONFIG_ERRNO_STR=y
+CONFIG_HEXDUMP=y
 CONFIG_UNIT_TEST=y
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
index e5bac37..0018112 100644 (file)
@@ -18,6 +18,7 @@ CONFIG_SPL_TEXT_BASE=0x02023400
 CONFIG_SPL=y
 CONFIG_DEBUG_UART_BASE=0x12c30000
 CONFIG_DEBUG_UART_CLOCK=100000000
+CONFIG_DEBUG_UART_S5P=y
 CONFIG_IDENT_STRING=" for snow"
 CONFIG_DEBUG_UART=y
 CONFIG_DISTRO_DEFAULTS=y
index 4c6a52f..7b844a3 100644 (file)
@@ -77,6 +77,7 @@ CONFIG_FASTBOOT_MMC_USER_NAME="mmc1"
 CONFIG_FASTBOOT_CMD_OEM_FORMAT=y
 CONFIG_FASTBOOT_CMD_OEM_PARTCONF=y
 CONFIG_FASTBOOT_CMD_OEM_BOOTBUS=y
+# CONFIG_SCMI_AGENT_MAILBOX is not set
 CONFIG_GPIO_HOG=y
 CONFIG_DM_HWSPINLOCK=y
 CONFIG_HWSPINLOCK_STM32=y
index feca26e..270cbaa 100644 (file)
@@ -78,6 +78,7 @@ CONFIG_FASTBOOT_MMC_USER_NAME="mmc1"
 CONFIG_FASTBOOT_CMD_OEM_FORMAT=y
 CONFIG_FASTBOOT_CMD_OEM_PARTCONF=y
 CONFIG_FASTBOOT_CMD_OEM_BOOTBUS=y
+# CONFIG_SCMI_AGENT_MAILBOX is not set
 CONFIG_GPIO_HOG=y
 CONFIG_DM_HWSPINLOCK=y
 CONFIG_HWSPINLOCK_STM32=y
index 9e29aa6..94fae71 100644 (file)
@@ -459,10 +459,12 @@ int layout_mbr_partitions(struct disk_partition *p, int count,
                        ext = &p[i];
        }
 
-       if (i >= 4 && !ext) {
-               printf("%s: extended partition is needed for more than 4 partitions\n",
-                       __func__);
-               return -1;
+       if (count < 4)
+               return 0;
+
+       if (!ext) {
+               log_err("extended partition is needed for more than 4 partitions\n");
+               return -EINVAL;
        }
 
        /* calculate extended volumes start and size if needed */
diff --git a/doc/develop/environment.rst b/doc/develop/environment.rst
new file mode 100644 (file)
index 0000000..0b86faf
--- /dev/null
@@ -0,0 +1,51 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Environment implementation
+==========================
+
+See :doc:`../usage/environment` for usage information.
+
+Callback functions for environment variables
+--------------------------------------------
+
+For some environment variables, the behavior of u-boot needs to change
+when their values are changed.  This functionality allows functions to
+be associated with arbitrary variables.  On creation, overwrite, or
+deletion, the callback will provide the opportunity for some side
+effect to happen or for the change to be rejected.
+
+The callbacks are named and associated with a function using the
+U_BOOT_ENV_CALLBACK macro in your board or driver code.
+
+These callbacks are associated with variables in one of two ways.  The
+static list can be added to by defining CONFIG_ENV_CALLBACK_LIST_STATIC
+in the board configuration to a string that defines a list of
+associations.  The list must be in the following format::
+
+    entry = variable_name[:callback_name]
+    list = entry[,list]
+
+If the callback name is not specified, then the callback is deleted.
+Spaces are also allowed anywhere in the list.
+
+Callbacks can also be associated by defining the ".callbacks" variable
+with the same list format above.  Any association in ".callbacks" will
+override any association in the static list. You can define
+CONFIG_ENV_CALLBACK_LIST_DEFAULT to a list (string) to define the
+".callbacks" environment variable in the default or embedded environment.
+
+If CONFIG_REGEX is defined, the variable_name above is evaluated as a
+regular expression. This allows multiple variables to be connected to
+the same callback without explicitly listing them all out.
+
+The signature of the callback functions is::
+
+    int callback(const char *name, const char *value, enum env_op op, int flags)
+
+* name - changed environment variable
+* value - new value of the environment variable
+* op - operation (create, overwrite, or delete)
+* flags - attributes of the environment variable change, see flags H_* in
+  include/search.h
+
+The return value is 0 if the variable change is accepted and 1 otherwise.
index b3871b1..9592d19 100644 (file)
@@ -16,6 +16,7 @@ Implementation
    devicetree/index
    distro
    driver-model/index
+   environment
    global_data
    logging
    makefiles
index a76124f..92572ea 100644 (file)
@@ -14,7 +14,8 @@ Required properties:
 
 The scmi node with the following properties shall be under the /firmware/ node.
 
-- compatible : shall be "arm,scmi" or "arm,scmi-smc" for smc/hvc transports
+- compatible : shall be "arm,scmi" or "arm,scmi-smc" for smc/hvc transports,
+         or "linaro,scmi-optee" for OP-TEE transport.
 - mboxes: List of phandle and mailbox channel specifiers. It should contain
          exactly one or two mailboxes, one for transmitting messages("tx")
          and another optional for receiving the notifications("rx") if
@@ -26,6 +27,8 @@ The scmi node with the following properties shall be under the /firmware/ node.
 - #size-cells : should be '0' as 'reg' property doesn't have any size
          associated with it.
 - arm,smc-id : SMC id required when using smc or hvc transports
+- linaro,optee-channel-id : Channel specifier required when using OP-TEE
+         transport.
 
 Optional properties:
 
@@ -33,16 +36,16 @@ Optional properties:
 
 See Documentation/devicetree/bindings/mailbox/mailbox.txt for more details
 about the generic mailbox controller and client driver bindings.
-
-The mailbox is the only permitted method of calling the SCMI firmware.
 Mailbox doorbell is used as a mechanism to alert the presence of a
 messages and/or notification.
 
 Each protocol supported shall have a sub-node with corresponding compatible
 as described in the following sections. If the platform supports dedicated
-communication channel for a particular protocol, the 3 properties namely:
-mboxes, mbox-names and shmem shall be present in the sub-node corresponding
-to that protocol.
+communication channel for a particular protocol, properties shall be present
+in the sub-node corresponding to that protocol. These properties are:
+- mboxes, mbox-names and shmem for mailbox transport
+- arm,smc-id and shmem for smc/hvc transport
+- linaro,optee-channel-id and possibly shmem for OP-TEE transport
 
 Clock/Performance bindings for the clocks/OPPs based on SCMI Message Protocol
 ------------------------------------------------------------
diff --git a/doc/device-tree-bindings/mmc/sandbox,mmc.txt b/doc/device-tree-bindings/mmc/sandbox,mmc.txt
new file mode 100644 (file)
index 0000000..1170bcd
--- /dev/null
@@ -0,0 +1,18 @@
+Sandbox MMC
+===========
+
+Required properties:
+- compatible : "sandbox,mmc"
+
+Optional properties:
+- filename : Name of backing file, if any. This is mapped into the MMC device
+    so can be used to provide a filesystem or other test data
+
+
+Example
+-------
+
+mmc2 {
+       compatible = "sandbox,mmc";
+       non-removable;
+};
diff --git a/doc/device-tree-bindings/pinctrl/apple,pinctrl.yaml b/doc/device-tree-bindings/pinctrl/apple,pinctrl.yaml
new file mode 100644 (file)
index 0000000..d50571a
--- /dev/null
@@ -0,0 +1,106 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/apple,pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Apple GPIO controller
+
+maintainers:
+  - Mark Kettenis <kettenis@openbsd.org>
+
+description: |
+  The Apple GPIO controller is a simple combined pin and GPIO
+  controller present on Apple ARM SoC platforms, including various
+  iPhone and iPad devices and the "Apple Silicon" Macs.
+
+properties:
+  compatible:
+    items:
+      - const: apple,t8103-pinctrl
+      - const: apple,pinctrl
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 2
+
+  gpio-ranges:
+    maxItems: 1
+
+  interrupts:
+    description: One interrupt for each of the (up to 7) interrupt
+      groups supported by the controller sorted by interrupt group
+      number in ascending order.
+    minItems: 1
+    maxItems: 7
+
+  interrupt-controller: true
+
+patternProperties:
+  '-pins$':
+    type: object
+    $ref: pinmux-node.yaml#
+
+    properties:
+      pinmux:
+        description:
+          Values are constructed from pin number and alternate function
+          configuration number using the APPLE_PINMUX() helper macro
+          defined in include/dt-bindings/pinctrl/apple.h.
+
+    required:
+      - pinmux
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - gpio-controller
+  - '#gpio-cells'
+  - gpio-ranges
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/apple-aic.h>
+    #include <dt-bindings/pinctrl/apple.h>
+
+    soc {
+      #address-cells = <2>;
+      #size-cells = <2>;
+
+      pinctrl: pinctrl@23c100000 {
+        compatible = "apple,t8103-pinctrl", "apple,pinctrl";
+        reg = <0x2 0x3c100000 0x0 0x100000>;
+        clocks = <&gpio_clk>;
+
+        gpio-controller;
+        #gpio-cells = <2>;
+        gpio-ranges = <&pinctrl 0 0 212>;
+
+        interrupt-controller;
+        interrupt-parent = <&aic>;
+        interrupts = <AIC_IRQ 16 IRQ_TYPE_LEVEL_HIGH>,
+                     <AIC_IRQ 17 IRQ_TYPE_LEVEL_HIGH>,
+                     <AIC_IRQ 18 IRQ_TYPE_LEVEL_HIGH>,
+                     <AIC_IRQ 19 IRQ_TYPE_LEVEL_HIGH>,
+                     <AIC_IRQ 20 IRQ_TYPE_LEVEL_HIGH>,
+                     <AIC_IRQ 21 IRQ_TYPE_LEVEL_HIGH>,
+                     <AIC_IRQ 22 IRQ_TYPE_LEVEL_HIGH>;
+
+        pcie_pins: pcie-pins {
+          pinmux = <APPLE_PINMUX(150, 1)>,
+                   <APPLE_PINMUX(151, 1)>,
+                   <APPLE_PINMUX(32, 1)>;
+        };
+      };
+    };
diff --git a/doc/usage/environment.rst b/doc/usage/environment.rst
new file mode 100644 (file)
index 0000000..d295cc8
--- /dev/null
@@ -0,0 +1,465 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Environment Variables
+=====================
+
+U-Boot supports user configuration using environment variables which
+can be made persistent by saving to persistent storage, for example flash
+memory.
+
+Environment variables are set using "env set" (alias "setenv"), printed using
+"env print" (alias "printenv"), and saved to persistent storage using
+"env save" (alias "saveenv"). Using "env set"
+without a value can be used to delete a variable from the
+environment. As long as you don't save the environment, you are
+working with an in-memory copy. In case the Flash area containing the
+environment is erased by accident, a default environment is provided.
+
+Some configuration is controlled by Environment Variables, so that setting the
+variable can adjust the behaviour of U-Boot (e.g. autoboot delay, autoloading
+from tftp).
+
+Text-based Environment
+----------------------
+
+The default environment for a board is created using a `.env` environment file
+using a simple text format. The base filename for this is defined by
+`CONFIG_ENV_SOURCE_FILE`, or `CONFIG_SYS_BOARD` if that is empty.
+
+The file must be in the board directory and have a .env extension, so
+assuming that there is a board vendor, the resulting filename is therefore::
+
+   board/<vendor>/<board>/<CONFIG_ENV_SOURCE_FILE>.env
+
+or::
+
+   board/<vendor>/<board>/<CONFIG_SYS_BOARD>.env
+
+This is a plain text file where you can type your environment variables in
+the form `var=value`. Blank lines and multi-line variables are supported.
+The conversion script looks for a line that starts in column 1 with a string
+and has an equals sign immediately afterwards. Spaces before the = are not
+permitted. It is a good idea to indent your scripts so that only the 'var='
+appears at the start of a line.
+
+To add additional text to a variable you can use `var+=value`. This text is
+merged into the variable during the make process and made available as a
+single value to U-Boot. Variables can contain `+` characters but in the unlikely
+event that you want to have a variable name ending in plus, put a backslash
+before the `+` so that the script knows you are not adding to an existing
+variable but assigning to a new one::
+
+    maximum\+=value
+
+This file can include C-style comments. Blank lines and multi-line
+variables are supported, and you can use normal C preprocessor directives
+and CONFIG defines from your board config also.
+
+For example, for snapper9260 you would create a text file called
+`board/bluewater/snapper9260.env` containing the environment text.
+
+Example::
+
+    stdout=serial
+    #ifdef CONFIG_LCD
+    stdout+=,lcd
+    #endif
+    bootcmd=
+        /* U-Boot script for booting */
+
+        if [ -z ${tftpserverip} ]; then
+            echo "Use 'setenv tftpserverip a.b.c.d' to set IP address."
+        fi
+
+        usb start; setenv autoload n; bootp;
+        tftpboot ${tftpserverip}:
+        bootm
+    failed=
+        /* Print a message when boot fails */
+        echo CONFIG_SYS_BOARD boot failed - please check your image
+        echo Load address is CONFIG_SYS_LOAD_ADDR
+
+If CONFIG_ENV_SOURCE_FILE is empty and the default filename is not present, then
+the old-style C environment is used instead. See below.
+
+Old-style C environment
+-----------------------
+
+Traditionally, the default environment is created in `include/env_default.h`,
+and can be augmented by various `CONFIG` defines. See that file for details. In
+particular you can define `CONFIG_EXTRA_ENV_SETTINGS` in your board file
+to add environment variables.
+
+Board maintainers are encouraged to migrate to the text-based environment as it
+is easier to maintain. The distro-board script still requires the old-style
+environment but work is underway to address this.
+
+
+List of environment variables
+-----------------------------
+
+Some device configuration options can be set using environment variables. In
+many cases the value in the default environment comes from a CONFIG option - see
+`include/env_default.h`) for this.
+
+This is most-likely not complete:
+
+baudrate
+    Used to set the baudrate of the UART - it defaults to CONFIG_BAUDRATE (which
+    defaults to 115200).
+
+bootdelay
+    Delay before automatically running bootcmd. During this time the user
+    can choose to enter the shell (or the boot menu if
+    CONFIG_AUTOBOOT_MENU_SHOW=y):
+
+    - 0 to autoboot with no delay, but you can stop it by key input.
+    - -1 to disable autoboot.
+    - -2 to autoboot with no delay and not check for abort
+
+    The default value is defined by CONFIG_BOOTDELAY.
+    The value of 'bootdelay' is overridden by the /config/bootdelay value in
+    the device-tree if CONFIG_OF_CONTROL=y.
+    Does it really make sense that the devicetree overrides the user setting?
+
+bootcmd
+    The command that is run if the user does not enter the shell during the
+    boot delay.
+
+bootargs
+    Command line arguments passed when booting an operating system or binary
+    image
+
+bootfile
+    Name of the image to load with TFTP
+
+bootm_low
+    Memory range available for image processing in the bootm
+    command can be restricted. This variable is given as
+    a hexadecimal number and defines lowest address allowed
+    for use by the bootm command. See also "bootm_size"
+    environment variable. Address defined by "bootm_low" is
+    also the base of the initial memory mapping for the Linux
+    kernel -- see the description of CONFIG_SYS_BOOTMAPSZ and
+    bootm_mapsize.
+
+bootm_mapsize
+    Size of the initial memory mapping for the Linux kernel.
+    This variable is given as a hexadecimal number and it
+    defines the size of the memory region starting at base
+    address bootm_low that is accessible by the Linux kernel
+    during early boot.  If unset, CONFIG_SYS_BOOTMAPSZ is used
+    as the default value if it is defined, and bootm_size is
+    used otherwise.
+
+bootm_size
+    Memory range available for image processing in the bootm
+    command can be restricted. This variable is given as
+    a hexadecimal number and defines the size of the region
+    allowed for use by the bootm command. See also "bootm_low"
+    environment variable.
+
+bootstopkeysha256, bootdelaykey, bootstopkey
+    See README.autoboot
+
+updatefile
+    Location of the software update file on a TFTP server, used
+    by the automatic software update feature. Please refer to
+    documentation in doc/README.update for more details.
+
+autoload
+    if set to "no" (any string beginning with 'n'),
+    "bootp" and "dhcp" will just load perform a lookup of the
+    configuration from the BOOTP server, but not try to
+    load any image using TFTP or DHCP.
+
+autostart
+    if set to "yes", an image loaded using the "bootp", "dhcp",
+    "rarpboot", "tftpboot" or "diskboot" commands will
+    be automatically started (by internally calling
+    "bootm")
+
+    If unset, or set to "1"/"yes"/"true" (case insensitive, just the first
+    character is enough), a standalone image
+    passed to the "bootm" command will be copied to the load address
+    (and eventually uncompressed), but NOT be started.
+    This can be used to load and uncompress arbitrary
+    data.
+
+fdt_high
+    if set this restricts the maximum address that the
+    flattened device tree will be copied into upon boot.
+    For example, if you have a system with 1 GB memory
+    at physical address 0x10000000, while Linux kernel
+    only recognizes the first 704 MB as low memory, you
+    may need to set fdt_high as 0x3C000000 to have the
+    device tree blob be copied to the maximum address
+    of the 704 MB low memory, so that Linux kernel can
+    access it during the boot procedure.
+
+    If this is set to the special value 0xffffffff (32-bit machines) or
+    0xffffffffffffffff (64-bit machines) then
+    the fdt will not be copied at all on boot.  For this
+    to work it must reside in writable memory, have
+    sufficient padding on the end of it for u-boot to
+    add the information it needs into it, and the memory
+    must be accessible by the kernel.
+
+fdtcontroladdr
+    if set this is the address of the control flattened
+    device tree used by U-Boot when CONFIG_OF_CONTROL is
+    defined.
+
+initrd_high
+    restrict positioning of initrd images:
+    If this variable is not set, initrd images will be
+    copied to the highest possible address in RAM; this
+    is usually what you want since it allows for
+    maximum initrd size. If for some reason you want to
+    make sure that the initrd image is loaded below the
+    CONFIG_SYS_BOOTMAPSZ limit, you can set this environment
+    variable to a value of "no" or "off" or "0".
+    Alternatively, you can set it to a maximum upper
+    address to use (U-Boot will still check that it
+    does not overwrite the U-Boot stack and data).
+
+    For instance, when you have a system with 16 MB
+    RAM, and want to reserve 4 MB from use by Linux,
+    you can do this by adding "mem=12M" to the value of
+    the "bootargs" variable. However, now you must make
+    sure that the initrd image is placed in the first
+    12 MB as well - this can be done with::
+
+        setenv initrd_high 00c00000
+
+    If you set initrd_high to 0xffffffff (32-bit machines) or
+    0xffffffffffffffff (64-bit machines), this is an
+    indication to U-Boot that all addresses are legal
+    for the Linux kernel, including addresses in flash
+    memory. In this case U-Boot will NOT COPY the
+    ramdisk at all. This may be useful to reduce the
+    boot time on your system, but requires that this
+    feature is supported by your Linux kernel.
+
+ipaddr
+    IP address; needed for tftpboot command
+
+loadaddr
+    Default load address for commands like "bootp",
+    "rarpboot", "tftpboot", "loadb" or "diskboot"
+
+loads_echo
+    see CONFIG_LOADS_ECHO
+
+serverip
+    TFTP server IP address; needed for tftpboot command
+
+bootretry
+    see CONFIG_BOOT_RETRY_TIME
+
+bootdelaykey
+    see CONFIG_AUTOBOOT_DELAY_STR
+
+bootstopkey
+    see CONFIG_AUTOBOOT_STOP_STR
+
+ethprime
+    controls which network interface is used first.
+
+ethact
+    controls which interface is currently active.
+    For example you can do the following::
+
+    => setenv ethact FEC
+    => ping 192.168.0.1 # traffic sent on FEC
+    => setenv ethact SCC
+    => ping 10.0.0.1 # traffic sent on SCC
+
+ethrotate
+    When set to "no" U-Boot does not go through all
+    available network interfaces.
+    It just stays at the currently selected interface. When unset or set to
+    anything other than "no", U-Boot does go through all
+    available network interfaces.
+
+netretry
+    When set to "no" each network operation will
+    either succeed or fail without retrying.
+    When set to "once" the network operation will
+    fail when all the available network interfaces
+    are tried once without success.
+    Useful on scripts which control the retry operation
+    themselves.
+
+silent_linux
+    If set then Linux will be told to boot silently, by
+    adding 'console=' to its command line. If "yes" it will be
+    made silent. If "no" it will not be made silent. If
+    unset, then it will be made silent if the U-Boot console
+    is silent.
+
+tftpsrcp
+    If this is set, the value is used for TFTP's
+    UDP source port.
+
+tftpdstp
+    If this is set, the value is used for TFTP's UDP
+    destination port instead of the default port 69.
+
+tftpblocksize
+    Block size to use for TFTP transfers; if not set,
+    we use the TFTP server's default block size
+
+tftptimeout
+    Retransmission timeout for TFTP packets (in milli-
+    seconds, minimum value is 1000 = 1 second). Defines
+    when a packet is considered to be lost so it has to
+    be retransmitted. The default is 5000 = 5 seconds.
+    Lowering this value may make downloads succeed
+    faster in networks with high packet loss rates or
+    with unreliable TFTP servers.
+
+tftptimeoutcountmax
+    maximum count of TFTP timeouts (no
+    unit, minimum value = 0). Defines how many timeouts
+    can happen during a single file transfer before that
+    transfer is aborted. The default is 10, and 0 means
+    'no timeouts allowed'. Increasing this value may help
+    downloads succeed with high packet loss rates, or with
+    unreliable TFTP servers or client hardware.
+
+tftpwindowsize
+    if this is set, the value is used for TFTP's
+    window size as described by RFC 7440.
+    This means the count of blocks we can receive before
+    sending ack to server.
+
+vlan
+    When set to a value < 4095 the traffic over
+    Ethernet is encapsulated/received over 802.1q
+    VLAN tagged frames.
+
+    Note: This appears not to be used in U-Boot. See `README.VLAN`.
+
+bootpretryperiod
+    Period during which BOOTP/DHCP sends retries.
+    Unsigned value, in milliseconds. If not set, the period will
+    be either the default (28000), or a value based on
+    CONFIG_NET_RETRY_COUNT, if defined. This value has
+    precedence over the valu based on CONFIG_NET_RETRY_COUNT.
+
+memmatches
+    Number of matches found by the last 'ms' command, in hex
+
+memaddr
+    Address of the last match found by the 'ms' command, in hex,
+    or 0 if none
+
+mempos
+    Index position of the last match found by the 'ms' command,
+    in units of the size (.b, .w, .l) of the search
+
+zbootbase
+    (x86 only) Base address of the bzImage 'setup' block
+
+zbootaddr
+    (x86 only) Address of the loaded bzImage, typically
+    BZIMAGE_LOAD_ADDR which is 0x100000
+
+
+Image locations
+---------------
+
+The following image location variables contain the location of images
+used in booting. The "Image" column gives the role of the image and is
+not an environment variable name. The other columns are environment
+variable names. "File Name" gives the name of the file on a TFTP
+server, "RAM Address" gives the location in RAM the image will be
+loaded to, and "Flash Location" gives the image's address in NOR
+flash or offset in NAND flash.
+
+*Note* - these variables don't have to be defined for all boards, some
+boards currently use other variables for these purposes, and some
+boards use these variables for other purposes.
+
+Also note that most of these variables are just a commonly used set of variable
+names, used in some other variable definitions, but are not hard-coded anywhere
+in U-Boot code.
+
+================= ============== ================ ==============
+Image             File Name      RAM Address      Flash Location
+================= ============== ================ ==============
+u-boot            u-boot         u-boot_addr_r    u-boot_addr
+Linux kernel      bootfile       kernel_addr_r    kernel_addr
+device tree blob  fdtfile        fdt_addr_r       fdt_addr
+ramdisk           ramdiskfile    ramdisk_addr_r   ramdisk_addr
+================= ============== ================ ==============
+
+
+Automatically updated variables
+-------------------------------
+
+The following environment variables may be used and automatically
+updated by the network boot commands ("bootp" and "rarpboot"),
+depending the information provided by your boot server:
+
+=========  ===================================================
+Variable   Notes
+=========  ===================================================
+bootfile   see above
+dnsip      IP address of your Domain Name Server
+dnsip2     IP address of your secondary Domain Name Server
+gatewayip  IP address of the Gateway (Router) to use
+hostname   Target hostname
+ipaddr     See above
+netmask    Subnet Mask
+rootpath   Pathname of the root filesystem on the NFS server
+serverip   see above
+=========  ===================================================
+
+
+Special environment variables
+-----------------------------
+
+There are two special Environment Variables:
+
+serial#
+    contains hardware identification information such as type string and/or
+    serial number
+ethaddr
+    Ethernet address. If CONFIG_REGEX=y, also eth*addr (where * is an integer).
+
+These variables can be set only once (usually during manufacturing of
+the board). U-Boot refuses to delete or overwrite these variables
+once they have been set, unless CONFIG_ENV_OVERWRITE is enabled in the board
+configuration.
+
+Also:
+
+ver
+    Contains the U-Boot version string as printed
+    with the "version" command. This variable is
+    readonly (see CONFIG_VERSION_VARIABLE).
+
+Please note that changes to some configuration parameters may take
+only effect after the next boot (yes, that's just like Windows).
+
+
+External environment file
+-------------------------
+
+The `CONFIG_USE_DEFAULT_ENV_FILE` option provides a way to bypass the
+environment generation in U-Boot. If enabled, then `CONFIG_DEFAULT_ENV_FILE`
+provides the name of a file which is converted into the environment,
+completely bypassing the standard environment variables in `env_default.h`.
+
+The format is the same as accepted by the mkenvimage tool, with lines containing
+key=value pairs. Blank lines and lines beginning with # are ignored.
+
+Future work may unify this feature with the text-based environment, perhaps
+moving the contents of `env_default.h` to a text file.
+
+Implementation
+--------------
+
+See :doc:`../develop/environment` for internal development details.
index 356f2a5..3905540 100644 (file)
@@ -5,11 +5,13 @@ Use U-Boot
    :maxdepth: 1
 
    dfu
+   environment
    fdt_overlays
    fit
    netconsole
    partitions
    cmdline
+   environment
 
 Shell commands
 --------------
@@ -43,6 +45,7 @@ Shell commands
    qfw
    reset
    sbi
+   sf
    scp03
    setexpr
    size
diff --git a/doc/usage/sf.rst b/doc/usage/sf.rst
new file mode 100644 (file)
index 0000000..71bd1be
--- /dev/null
@@ -0,0 +1,245 @@
+.. SPDX-License-Identifier: GPL-2.0+:
+
+sf command
+==========
+
+Synopis
+-------
+
+::
+
+    sf probe [[[<bus>:]<cs>] [<hz> [<mode>]]]
+    sf read <addr> <offset>|<partition> <len>
+    sf write <addr> <offset>|<partition> <len>
+    sf erase <offset>|<partition> <len>
+    sf update <addr> <offset>|<partition> <len>
+    sf protect lock|unlock <sector> <len>
+    sf test <offset>|<partition> <len>
+
+Description
+-----------
+
+The *sf* command is used to access SPI flash, supporting read/write/erase and
+a few other functions.
+
+Probe
+-----
+
+The flash must first be probed with *sf probe* before any of the other
+subcommands can be used. All of the parameters are optional:
+
+bus
+       SPI bus number containing the SPI-flash chip, e.g. 0. If you don't know
+       the number, you can use 'dm uclass' to see all the spi devices,
+       and check the value for 'seq' for each one (here 0 and 2)::
+
+          uclass 89: spi
+          0     spi@0 @ 05484960, seq 0
+          1     spi@1 @ 05484b40, seq 2
+
+cs
+       SPI chip-select to use for the chip. This is often 0 and can be omitted,
+       but in some cases multiple slaves are attached to a SPI controller,
+       selected by a chip-select line for each one.
+
+hz
+       Speed of the SPI bus in hertz. This normally defaults to 100000, i.e.
+       100KHz, which is very slow. Note that if the device exists in the
+       device tree, there might be a speed provided there, in which case this
+       setting is ignored.
+
+mode
+       SPI mode to use:
+
+       =====  ================
+       Mode   Meaning
+       =====  ================
+       0      CPOL=0, CPHA=0
+       1      CPOL=0, CPHA=1
+       2      CPOL=1, CPHA=0
+       3      CPOL=1, CPHA=1
+       =====  ================
+
+       Clock phase (CPHA) 0 means that data is transferred (sampled) on the
+       first clock edge; 1 means the second.
+
+       Clock polarity (CPOL) controls the idle state of the clock, 0 for low,
+       1 for high.
+       The active state is the opposite of idle.
+
+       You may find this `SPI documentation`_ useful.
+
+Parameters for other subcommands (described below) are as follows:
+
+addr
+       Memory address to start transfer
+
+offset
+       Flash offset to start transfer
+
+partition
+       If the parameter is not numeric, it is assumed to be a partition
+       description in the format <dev_type><dev_num>,<part_num> which is not
+       covered here. This requires CONFIG_CMD_MTDPARTS.
+
+len
+       Number of bytes to transfer
+
+Read
+~~~~
+
+Use *sf read* to read from SPI flash to memory. The read will fail if an
+attempt is made to read past the end of the flash.
+
+
+Write
+~~~~~
+
+Use *sf write* to write from memory to SPI flash. The SPI flash should be
+erased first, since otherwise the result is undefined.
+
+The write will fail if an attempt is made to read past the end of the flash.
+
+
+Erase
+~~~~~
+
+Use *sf erase* to erase a region of SPI flash. The erase will fail if any part
+of the region to be erased is protected or lies past the end of the flash. It
+may also fail if the start offset or length are not aligned to an erase region
+(e.g. 256 bytes).
+
+
+Update
+~~~~~~
+
+Use *sf update* to automatically erase and update a region of SPI flash from
+memory. This works a sector at a time (typical 4KB or 64KB). For each
+sector it first checks if the sector already has the right data. If so it is
+skipped. If not, the sector is erased and the new data written. Note that if
+the length is not a multiple of the erase size, the space after the data in
+the last sector will be erased. If the offset does not start at the beginning
+of an erase block, the operation will fail.
+
+Speed statistics are shown including the number of bytes that were already
+correct.
+
+
+Protect
+~~~~~~~
+
+SPI-flash chips often have a protection feature where the chip is split up into
+regions which can be locked or unlocked. With *sf protect* it is possible to
+change these settings, if supported by the driver.
+
+lock|unlock
+       Selects whether to lock or unlock the sectors
+
+<sector>
+       Start sector number to lock/unlock. This may be the byte offset or some
+       other value, depending on the chip.
+
+<len>
+       Number of bytes to lock/unlock
+
+
+Test
+~~~~
+
+A convenient and fast *sf test* subcommand provides a way to check that SPI
+flash is working as expected. This works in four stages:
+
+   * erase - erases the entire region
+   * check - checks that the region is erased
+   * write - writes a test pattern to the region, consisting of the U-Boot code
+   * read - reads back the test pattern to check that it was written correctly
+
+Memory is allocated for two buffers, each <len> bytes in size. At typical
+size is 64KB to 1MB. The offset and size must be aligned to an erase boundary.
+
+Note that this test will fail if any part of the SPI flash is write-protected.
+
+
+Examples
+--------
+
+This first example uses sandbox::
+
+   => sf probe
+   SF: Detected m25p16 with page size 256 Bytes, erase size 64 KiB, total 2 MiB
+   => sf read 1000 1100 80000
+   device 0 offset 0x1100, size 0x80000
+   SF: 524288 bytes @ 0x1100 Read: OK
+   => md 1000
+   00001000: edfe0dd0 f33a0000 78000000 84250000    ......:....x..%.
+   00001010: 28000000 11000000 10000000 00000000    ...(............
+   00001020: 6f050000 0c250000 00000000 00000000    ...o..%.........
+   00001030: 00000000 00000000 00000000 00000000    ................
+   00001040: 00000000 00000000 00000000 00000000    ................
+   00001050: 00000000 00000000 00000000 00000000    ................
+   00001060: 00000000 00000000 00000000 00000000    ................
+   00001070: 00000000 00000000 01000000 00000000    ................
+   00001080: 03000000 04000000 00000000 01000000    ................
+   00001090: 03000000 04000000 0f000000 01000000    ................
+   000010a0: 03000000 08000000 1b000000 646e6173    ............sand
+   000010b0: 00786f62 03000000 08000000 21000000    box............!
+   000010c0: 646e6173 00786f62 01000000 61696c61    sandbox.....alia
+   000010d0: 00736573 03000000 07000000 2c000000    ses............,
+   000010e0: 6332692f 00003040 03000000 07000000    /i2c@0..........
+   000010f0: 31000000 6963702f 00003040 03000000    ...1/pci@0......
+   => sf erase 0 80000
+   SF: 524288 bytes @ 0x0 Erased: OK
+   => sf read 1000 1100 80000
+   device 0 offset 0x1100, size 0x80000
+   SF: 524288 bytes @ 0x1100 Read: OK
+   => md 1000
+   00001000: ffffffff ffffffff ffffffff ffffffff    ................
+   00001010: ffffffff ffffffff ffffffff ffffffff    ................
+   00001020: ffffffff ffffffff ffffffff ffffffff    ................
+   00001030: ffffffff ffffffff ffffffff ffffffff    ................
+   00001040: ffffffff ffffffff ffffffff ffffffff    ................
+   00001050: ffffffff ffffffff ffffffff ffffffff    ................
+   00001060: ffffffff ffffffff ffffffff ffffffff    ................
+   00001070: ffffffff ffffffff ffffffff ffffffff    ................
+   00001080: ffffffff ffffffff ffffffff ffffffff    ................
+   00001090: ffffffff ffffffff ffffffff ffffffff    ................
+   000010a0: ffffffff ffffffff ffffffff ffffffff    ................
+   000010b0: ffffffff ffffffff ffffffff ffffffff    ................
+   000010c0: ffffffff ffffffff ffffffff ffffffff    ................
+   000010d0: ffffffff ffffffff ffffffff ffffffff    ................
+   000010e0: ffffffff ffffffff ffffffff ffffffff    ................
+   000010f0: ffffffff ffffffff ffffffff ffffffff    ................
+
+This second example is running on coral, an x86 Chromebook::
+
+   => sf probe
+   SF: Detected w25q128fw with page size 256 Bytes, erase size 4 KiB, total 16 MiB
+   => sf erase 300000 80000
+   SF: 524288 bytes @ 0x300000 Erased: OK
+   => sf update 1110000 300000 80000
+   device 0 offset 0x300000, size 0x80000
+   524288 bytes written, 0 bytes skipped in 0.457s, speed 1164578 B/s
+
+   # This does nothing as the flash is already updated
+   => sf update 1110000 300000 80000
+   device 0 offset 0x300000, size 0x80000
+   0 bytes written, 524288 bytes skipped in 0.196s, speed 2684354 B/s
+   => sf test 00000 80000   # try a protected region
+   SPI flash test:
+   Erase failed (err = -5)
+   Test failed
+   => sf test 800000 80000
+   SPI flash test:
+   0 erase: 18 ticks, 28444 KiB/s 227.552 Mbps
+   1 check: 192 ticks, 2666 KiB/s 21.328 Mbps
+   2 write: 227 ticks, 2255 KiB/s 18.040 Mbps
+   3 read: 189 ticks, 2708 KiB/s 21.664 Mbps
+   Test passed
+   0 erase: 18 ticks, 28444 KiB/s 227.552 Mbps
+   1 check: 192 ticks, 2666 KiB/s 21.328 Mbps
+   2 write: 227 ticks, 2255 KiB/s 18.040 Mbps
+   3 read: 189 ticks, 2708 KiB/s 21.664 Mbps
+
+
+.. _SPI documentation:
+   https://en.wikipedia.org/wiki/Serial_Peripheral_Interface
index 3a92739..42ca394 100644 (file)
@@ -1013,6 +1013,46 @@ static ulong ast2600_enable_usbbhclk(struct ast2600_scu *scu)
        return 0;
 }
 
+static ulong ast2600_enable_haceclk(struct ast2600_scu *scu)
+{
+       uint32_t reset_bit;
+       uint32_t clkgate_bit;
+
+       /* share the same reset control bit with ACRY */
+       reset_bit = BIT(ASPEED_RESET_HACE);
+       clkgate_bit = SCU_CLKGATE1_HACE;
+
+       /*
+        * we don't do reset assertion here as HACE
+        * shares the same reset control with ACRY
+        */
+       writel(clkgate_bit, &scu->clkgate_clr1);
+       mdelay(20);
+       writel(reset_bit, &scu->modrst_clr1);
+
+       return 0;
+}
+
+static ulong ast2600_enable_rsaclk(struct ast2600_scu *scu)
+{
+       uint32_t reset_bit;
+       uint32_t clkgate_bit;
+
+       /* same reset control bit with HACE */
+       reset_bit = BIT(ASPEED_RESET_HACE);
+       clkgate_bit = SCU_CLKGATE1_ACRY;
+
+       /*
+        * we don't do reset assertion here as HACE
+        * shares the same reset control with ACRY
+        */
+       writel(clkgate_bit, &scu->clkgate_clr1);
+       mdelay(20);
+       writel(reset_bit, &scu->modrst_clr1);
+
+       return 0;
+}
+
 static int ast2600_clk_enable(struct clk *clk)
 {
        struct ast2600_clk_priv *priv = dev_get_priv(clk->dev);
@@ -1051,6 +1091,12 @@ static int ast2600_clk_enable(struct clk *clk)
        case ASPEED_CLK_GATE_USBPORT2CLK:
                ast2600_enable_usbbhclk(priv->scu);
                break;
+       case ASPEED_CLK_GATE_YCLK:
+               ast2600_enable_haceclk(priv->scu);
+               break;
+       case ASPEED_CLK_GATE_RSACLK:
+               ast2600_enable_rsaclk(priv->scu);
+               break;
        default:
                pr_err("can't enable clk\n");
                return -ENOENT;
index 93a4819..9a0a6f6 100644 (file)
@@ -2,6 +2,9 @@
 /*
  * Copyright (C) 2019-2020 Linaro Limited
  */
+
+#define LOG_CATEGORY UCLASS_CLK
+
 #include <common.h>
 #include <clk-uclass.h>
 #include <dm.h>
index 11d3959..69c50da 100644 (file)
@@ -95,6 +95,9 @@ int device_unbind(struct udevice *dev)
        if (ret)
                return log_msg_ret("child unbind", ret);
 
+       ret = uclass_pre_unbind_device(dev);
+       if (ret)
+               return log_msg_ret("uc", ret);
        if (dev_get_flags(dev) & DM_FLAG_ALLOC_PDATA) {
                free(dev_get_plat(dev));
                dev_set_plat(dev, NULL);
@@ -142,10 +145,8 @@ void device_free(struct udevice *dev)
        }
        if (dev->parent) {
                size = dev->parent->driver->per_child_auto;
-               if (!size) {
-                       size = dev->parent->uclass->uc_drv->
-                                       per_child_auto;
-               }
+               if (!size)
+                       size = dev->parent->uclass->uc_drv->per_child_auto;
                if (size) {
                        free(dev_get_parent_priv(dev));
                        dev_set_parent_priv(dev, NULL);
index efd0717..aed093c 100644 (file)
@@ -902,15 +902,16 @@ int device_find_first_child_by_uclass(const struct udevice *parent,
        return -ENODEV;
 }
 
-int device_find_child_by_name(const struct udevice *parent, const char *name,
-                             struct udevice **devp)
+int device_find_child_by_namelen(const struct udevice *parent, const char *name,
+                                int len, struct udevice **devp)
 {
        struct udevice *dev;
 
        *devp = NULL;
 
        list_for_each_entry(dev, &parent->child_head, sibling_node) {
-               if (!strcmp(dev->name, name)) {
+               if (!strncmp(dev->name, name, len) &&
+                   strlen(dev->name) == len) {
                        *devp = dev;
                        return 0;
                }
@@ -919,6 +920,12 @@ int device_find_child_by_name(const struct udevice *parent, const char *name,
        return -ENODEV;
 }
 
+int device_find_child_by_name(const struct udevice *parent, const char *name,
+                             struct udevice **devp)
+{
+       return device_find_child_by_namelen(parent, name, strlen(name), devp);
+}
+
 int device_first_child_err(struct udevice *parent, struct udevice **devp)
 {
        struct udevice *dev;
index 9960e6b..3707143 100644 (file)
@@ -581,7 +581,8 @@ int of_property_match_string(const struct device_node *np, const char *propname,
  * @propname:  name of the property to be searched.
  * @out_strs:  output array of string pointers.
  * @sz:                number of array elements to read.
- * @skip:      Number of strings to skip over at beginning of list.
+ * @skip:      Number of strings to skip over at beginning of list (cannot be
+ *     negative)
  *
  * Don't call this function directly. It is a utility helper for the
  * of_property_read_string*() family of functions.
index 632a1c2..59ce917 100644 (file)
@@ -155,3 +155,15 @@ bool ofnode_phy_is_fixed_link(ofnode eth_node, ofnode *phy_node)
 
        return true;
 }
+
+bool ofnode_eth_uses_inband_aneg(ofnode eth_node)
+{
+       bool inband_aneg = false;
+       const char *managed;
+
+       managed = ofnode_read_string(eth_node, "managed");
+       if (managed && !strcmp(managed, "in-band-status"))
+               inband_aneg = true;
+
+       return inband_aneg;
+}
index 08705ef..709bea2 100644 (file)
@@ -456,6 +456,32 @@ int ofnode_read_string_count(ofnode node, const char *property)
        }
 }
 
+int ofnode_read_string_list(ofnode node, const char *property,
+                           const char ***listp)
+{
+       const char **prop;
+       int count;
+       int i;
+
+       *listp = NULL;
+       count = ofnode_read_string_count(node, property);
+       if (count < 0)
+               return count;
+       if (!count)
+               return 0;
+
+       prop = calloc(count + 1, sizeof(char *));
+       if (!prop)
+               return -ENOMEM;
+
+       for (i = 0; i < count; i++)
+               ofnode_read_string_index(node, property, i, &prop[i]);
+       prop[count] = NULL;
+       *listp = prop;
+
+       return count;
+}
+
 static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
                                            struct ofnode_phandle_args *out)
 {
index 4307ca4..31f9e78 100644 (file)
@@ -205,6 +205,12 @@ int dev_read_string_count(const struct udevice *dev, const char *propname)
        return ofnode_read_string_count(dev_ofnode(dev), propname);
 }
 
+int dev_read_string_list(const struct udevice *dev, const char *propname,
+                        const char ***listp)
+{
+       return ofnode_read_string_list(dev_ofnode(dev), propname, listp);
+}
+
 int dev_read_phandle_with_args(const struct udevice *dev, const char *list_name,
                               const char *cells_name, int cell_count,
                               int index, struct ofnode_phandle_args *out_args)
index c5a5095..2aa2143 100644 (file)
@@ -180,20 +180,25 @@ void uclass_set_priv(struct uclass *uc, void *priv)
        uc->priv_ = priv;
 }
 
-enum uclass_id uclass_get_by_name(const char *name)
+enum uclass_id uclass_get_by_name_len(const char *name, int len)
 {
        int i;
 
        for (i = 0; i < UCLASS_COUNT; i++) {
                struct uclass_driver *uc_drv = lists_uclass_lookup(i);
 
-               if (uc_drv && !strcmp(uc_drv->name, name))
+               if (uc_drv && !strncmp(uc_drv->name, name, len))
                        return i;
        }
 
        return UCLASS_INVALID;
 }
 
+enum uclass_id uclass_get_by_name(const char *name)
+{
+       return uclass_get_by_name_len(name, strlen(name));
+}
+
 int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
 {
        struct udevice *iter;
@@ -682,7 +687,7 @@ err:
 }
 
 #if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
-int uclass_unbind_device(struct udevice *dev)
+int uclass_pre_unbind_device(struct udevice *dev)
 {
        struct uclass *uc;
        int ret;
@@ -694,7 +699,13 @@ int uclass_unbind_device(struct udevice *dev)
                        return ret;
        }
 
+       return 0;
+}
+
+int uclass_unbind_device(struct udevice *dev)
+{
        list_del(&dev->uclass_node);
+
        return 0;
 }
 #endif
@@ -783,6 +794,18 @@ int uclass_probe_all(enum uclass_id id)
        return 0;
 }
 
+int uclass_id_count(enum uclass_id id)
+{
+       struct udevice *dev;
+       struct uclass *uc;
+       int count = 0;
+
+       uclass_id_foreach_dev(id, dev, uc)
+               count++;
+
+       return count;
+}
+
 UCLASS_DRIVER(nop) = {
        .id             = UCLASS_NOP,
        .name           = "nop",
index 0082177..675081e 100644 (file)
@@ -4,4 +4,6 @@ source drivers/crypto/hash/Kconfig
 
 source drivers/crypto/fsl/Kconfig
 
+source drivers/crypto/aspeed/Kconfig
+
 endmenu
index e8bae43..6b76256 100644 (file)
@@ -7,3 +7,4 @@ obj-$(CONFIG_EXYNOS_ACE_SHA)    += ace_sha.o
 obj-y += rsa_mod_exp/
 obj-y += fsl/
 obj-y += hash/
+obj-y += aspeed/
diff --git a/drivers/crypto/aspeed/Kconfig b/drivers/crypto/aspeed/Kconfig
new file mode 100644 (file)
index 0000000..9bf3171
--- /dev/null
@@ -0,0 +1,20 @@
+config ASPEED_HACE
+       bool "ASPEED Hash and Crypto Engine"
+       depends on DM_HASH
+       help
+         Select this option to enable a driver for using the SHA engine in
+         the ASPEED BMC SoCs.
+
+         Enabling this allows the use of SHA operations in hardware without
+         requiring the SHA software implementations. It also improves performance
+         and saves code size.
+
+config ASPEED_ACRY
+       bool "ASPEED RSA and ECC Engine"
+       depends on ASPEED_AST2600
+       help
+        Select this option to enable a driver for using the RSA/ECC engine in
+        the ASPEED BMC SoCs.
+
+        Enabling this allows the use of RSA/ECC operations in hardware without requiring the
+        software implementations. It also improves performance and saves code size.
diff --git a/drivers/crypto/aspeed/Makefile b/drivers/crypto/aspeed/Makefile
new file mode 100644 (file)
index 0000000..58b55fc
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ASPEED_HACE) += aspeed_hace.o
+obj-$(CONFIG_ASPEED_ACRY) += aspeed_acry.o
diff --git a/drivers/crypto/aspeed/aspeed_acry.c b/drivers/crypto/aspeed/aspeed_acry.c
new file mode 100644 (file)
index 0000000..c28cdf3
--- /dev/null
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2021 ASPEED Technology Inc.
+ */
+#include <config.h>
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include <dm/device.h>
+#include <dm/fdtaddr.h>
+#include <linux/delay.h>
+#include <u-boot/rsa-mod-exp.h>
+
+/* ACRY register offsets */
+#define ACRY_CTRL1             0x00
+#define   ACRY_CTRL1_RSA_DMA           BIT(1)
+#define   ACRY_CTRL1_RSA_START         BIT(0)
+#define ACRY_CTRL2             0x44
+#define ACRY_CTRL3             0x48
+#define   ACRY_CTRL3_SRAM_AHB_ACCESS   BIT(8)
+#define   ACRY_CTRL3_ECC_RSA_MODE_MASK GENMASK(5, 4)
+#define   ACRY_CTRL3_ECC_RSA_MODE_SHIFT        4
+#define ACRY_DMA_DRAM_SADDR    0x4c
+#define ACRY_DMA_DMEM_TADDR    0x50
+#define   ACRY_DMA_DMEM_TADDR_LEN_MASK GENMASK(15, 0)
+#define   ACRY_DMA_DMEM_TADDR_LEN_SHIFT        0
+#define ACRY_RSA_PARAM         0x58
+#define   ACRY_RSA_PARAM_EXP_MASK      GENMASK(31, 16)
+#define   ACRY_RSA_PARAM_EXP_SHIFT     16
+#define   ACRY_RSA_PARAM_MOD_MASK      GENMASK(15, 0)
+#define   ACRY_RSA_PARAM_MOD_SHIFT     0
+#define ACRY_RSA_INT_EN                0x3f8
+#define   ACRY_RSA_INT_EN_RSA_READY    BIT(2)
+#define   ACRY_RSA_INT_EN_RSA_CMPLT    BIT(1)
+#define ACRY_RSA_INT_STS       0x3fc
+#define   ACRY_RSA_INT_STS_RSA_READY   BIT(2)
+#define   ACRY_RSA_INT_STS_RSA_CMPLT   BIT(1)
+
+/* misc. constant */
+#define ACRY_ECC_MODE  2
+#define ACRY_RSA_MODE  3
+#define ACRY_CTX_BUFSZ 0x600
+
+struct aspeed_acry {
+       phys_addr_t base;
+       phys_addr_t sram_base; /* internal sram */
+       struct clk clk;
+};
+
+static int aspeed_acry_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
+                              struct key_prop *prop, uint8_t *out)
+{
+       int i, j;
+       u8 *ctx;
+       u8 *ptr;
+       u32 reg;
+       struct aspeed_acry *acry = dev_get_priv(dev);
+
+       ctx = memalign(16, ACRY_CTX_BUFSZ);
+       if (!ctx)
+               return -ENOMEM;
+
+       memset(ctx, 0, ACRY_CTX_BUFSZ);
+
+       ptr = (u8 *)prop->public_exponent;
+       for (i = prop->exp_len - 1, j = 0; i >= 0; --i) {
+               ctx[j] = ptr[i];
+               j++;
+               j = (j % 16) ? j : j + 32;
+       }
+
+       ptr = (u8 *)prop->modulus;
+       for (i = (prop->num_bits >> 3) - 1, j = 0; i >= 0; --i) {
+               ctx[j + 16] = ptr[i];
+               j++;
+               j = (j % 16) ? j : j + 32;
+       }
+
+       ptr = (u8 *)sig;
+       for (i = sig_len - 1, j = 0; i >= 0; --i) {
+               ctx[j + 32] = ptr[i];
+               j++;
+               j = (j % 16) ? j : j + 32;
+       }
+
+       writel((u32)ctx, acry->base + ACRY_DMA_DRAM_SADDR);
+
+       reg = (((prop->exp_len << 3) << ACRY_RSA_PARAM_EXP_SHIFT) & ACRY_RSA_PARAM_EXP_MASK) |
+                 ((prop->num_bits << ACRY_RSA_PARAM_MOD_SHIFT) & ACRY_RSA_PARAM_MOD_MASK);
+       writel(reg, acry->base + ACRY_RSA_PARAM);
+
+       reg = (ACRY_CTX_BUFSZ << ACRY_DMA_DMEM_TADDR_LEN_SHIFT) & ACRY_DMA_DMEM_TADDR_LEN_MASK;
+       writel(reg, acry->base + ACRY_DMA_DMEM_TADDR);
+
+       reg = (ACRY_RSA_MODE << ACRY_CTRL3_ECC_RSA_MODE_SHIFT) & ACRY_CTRL3_ECC_RSA_MODE_MASK;
+       writel(reg, acry->base + ACRY_CTRL3);
+
+       writel(ACRY_CTRL1_RSA_DMA | ACRY_CTRL1_RSA_START, acry->base + ACRY_CTRL1);
+
+       /* polling RSA status */
+       while (1) {
+               reg = readl(acry->base + ACRY_RSA_INT_STS);
+               if ((reg & ACRY_RSA_INT_STS_RSA_READY) && (reg & ACRY_RSA_INT_STS_RSA_CMPLT)) {
+                       writel(reg, ACRY_RSA_INT_STS);
+                       break;
+               }
+               udelay(20);
+       }
+
+       /* grant SRAM access permission to CPU */
+       writel(0x0, acry->base + ACRY_CTRL1);
+       writel(ACRY_CTRL3_SRAM_AHB_ACCESS, acry->base + ACRY_CTRL3);
+       udelay(20);
+
+       for (i = (prop->num_bits / 8) - 1, j = 0; i >= 0; --i) {
+               out[i] = readb(acry->sram_base + (j + 32));
+               j++;
+               j = (j % 16) ? j : j + 32;
+       }
+
+       /* return SRAM access permission to ACRY */
+       writel(0, acry->base + ACRY_CTRL3);
+
+       free(ctx);
+
+       return 0;
+}
+
+static int aspeed_acry_probe(struct udevice *dev)
+{
+       struct aspeed_acry *acry = dev_get_priv(dev);
+       int ret;
+
+       ret = clk_get_by_index(dev, 0, &acry->clk);
+       if (ret < 0) {
+               debug("Can't get clock for %s: %d\n", dev->name, ret);
+               return ret;
+       }
+
+       ret = clk_enable(&acry->clk);
+       if (ret) {
+               debug("Failed to enable acry clock (%d)\n", ret);
+               return ret;
+       }
+
+       acry->base = devfdt_get_addr_index(dev, 0);
+       if (acry->base == FDT_ADDR_T_NONE) {
+               debug("Failed to get acry base\n");
+               return acry->base;
+       }
+
+       acry->sram_base = devfdt_get_addr_index(dev, 1);
+       if (acry->sram_base == FDT_ADDR_T_NONE) {
+               debug("Failed to get acry SRAM base\n");
+               return acry->sram_base;
+       }
+
+       return ret;
+}
+
+static int aspeed_acry_remove(struct udevice *dev)
+{
+       struct aspeed_acry *acry = dev_get_priv(dev);
+
+       clk_disable(&acry->clk);
+
+       return 0;
+}
+
+static const struct mod_exp_ops aspeed_acry_ops = {
+       .mod_exp = aspeed_acry_mod_exp,
+};
+
+static const struct udevice_id aspeed_acry_ids[] = {
+       { .compatible = "aspeed,ast2600-acry" },
+       { }
+};
+
+U_BOOT_DRIVER(aspeed_acry) = {
+       .name = "aspeed_acry",
+       .id = UCLASS_MOD_EXP,
+       .of_match = aspeed_acry_ids,
+       .probe = aspeed_acry_probe,
+       .remove = aspeed_acry_remove,
+       .priv_auto = sizeof(struct aspeed_acry),
+       .ops = &aspeed_acry_ops,
+       .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/crypto/aspeed/aspeed_hace.c b/drivers/crypto/aspeed/aspeed_hace.c
new file mode 100644 (file)
index 0000000..1178cc6
--- /dev/null
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2021 ASPEED Technology Inc.
+ */
+#include <config.h>
+#include <common.h>
+#include <dm.h>
+#include <clk.h>
+#include <log.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <watchdog.h>
+#include <u-boot/hash.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/iopoll.h>
+
+/* register offsets*/
+#define HACE_STS               0x1C
+#define   HACE_HASH_DATA_OVF           BIT(23)
+#define   HACE_HASH_INT                        BIT(9)
+#define   HACE_HASH_BUSY               BIT(0)
+#define HACE_HASH_DATA         0x20
+#define HACE_HASH_DIGEST       0x24
+#define HACE_HASH_HMAC_KEY     0x28
+#define HACE_HASH_DATA_LEN     0x2C
+#define HACE_HASH_CMD          0x30
+#define   HACE_HASH_MODE_ACCUM         BIT(8)
+#define   HACE_HASH_ALGO_SHA1          BIT(5)
+#define   HACE_HASH_ALGO_SHA256                (BIT(6) | BIT(4))
+#define   HACE_HASH_ALGO_SHA384                (BIT(10) | BIT(6) | BIT(5))
+#define   HACE_HASH_ALGO_SHA512                (BIT(6) | BIT(5))
+#define   HACE_HASH_SHA_BE_EN          BIT(3)
+
+/* buffer size based on SHA-512 need*/
+#define HASH_BLOCK_BUFSZ       128
+#define HASH_DIGEST_BUFSZ      64
+
+struct aspeed_hace_ctx {
+       uint8_t digest[HASH_DIGEST_BUFSZ];
+
+       uint32_t cmd;
+       enum HASH_ALGO algo;
+
+       uint32_t blk_size;
+       uint32_t pad_size;
+       uint64_t total[2];
+
+       uint8_t buf[HASH_BLOCK_BUFSZ];
+       uint32_t buf_cnt;
+} __aligned((8));
+
+struct aspeed_hace {
+       phys_addr_t base;
+       struct clk clk;
+};
+
+static const uint32_t iv_sha1[8] = {
+       0x01234567, 0x89abcdef, 0xfedcba98, 0x76543210,
+       0xf0e1d2c3, 0, 0, 0
+};
+
+static const uint32_t iv_sha256[8] = {
+       0x67e6096a, 0x85ae67bb, 0x72f36e3c, 0x3af54fa5,
+       0x7f520e51, 0x8c68059b, 0xabd9831f, 0x19cde05bUL
+};
+
+static const uint32_t iv_sha384[16] = {
+       0x5d9dbbcb, 0xd89e05c1, 0x2a299a62, 0x07d57c36,
+       0x5a015991, 0x17dd7030, 0xd8ec2f15, 0x39590ef7,
+       0x67263367, 0x310bc0ff, 0x874ab48e, 0x11155868,
+       0x0d2e0cdb, 0xa78ff964, 0x1d48b547, 0xa44ffabeUL
+};
+
+static const uint32_t iv_sha512[16] = {
+       0x67e6096a, 0x08c9bcf3, 0x85ae67bb, 0x3ba7ca84,
+       0x72f36e3c, 0x2bf894fe, 0x3af54fa5, 0xf1361d5f,
+       0x7f520e51, 0xd182e6ad, 0x8c68059b, 0x1f6c3e2b,
+       0xabd9831f, 0x6bbd41fb, 0x19cde05b, 0x79217e13UL
+};
+
+static int aspeed_hace_wait_completion(uint32_t reg, uint32_t flag, int timeout_us)
+{
+       uint32_t val;
+
+       return readl_poll_timeout(reg, val, (val & flag) == flag, timeout_us);
+}
+
+static int aspeed_hace_process(struct udevice *dev, void *ctx, const void *ibuf, uint32_t ilen)
+{
+       struct aspeed_hace *hace = dev_get_priv(dev);
+       struct aspeed_hace_ctx *hace_ctx = (struct aspeed_hace_ctx *)ctx;
+       uint32_t sts = readl(hace->base + HACE_STS);
+
+       if (sts & HACE_HASH_BUSY) {
+               debug("HACE engine busy\n");
+               return -EBUSY;
+       }
+
+       writel(HACE_HASH_INT, hace->base + HACE_STS);
+
+       writel((uint32_t)ibuf, hace->base + HACE_HASH_DATA);
+       writel((uint32_t)hace_ctx->digest, hace->base + HACE_HASH_DIGEST);
+       writel((uint32_t)hace_ctx->digest, hace->base + HACE_HASH_HMAC_KEY);
+       writel(ilen, hace->base + HACE_HASH_DATA_LEN);
+       writel(hace_ctx->cmd, hace->base + HACE_HASH_CMD);
+
+       return aspeed_hace_wait_completion(hace->base + HACE_STS,
+                                          HACE_HASH_INT,
+                                          1000 + (ilen >> 3));
+}
+
+static int aspeed_hace_init(struct udevice *dev, enum HASH_ALGO algo, void **ctxp)
+{
+       struct aspeed_hace_ctx *hace_ctx;
+
+       hace_ctx = memalign(8, sizeof(struct aspeed_hace_ctx));
+       if (!hace_ctx)
+               return -ENOMEM;
+
+       memset(hace_ctx, 0, sizeof(struct aspeed_hace_ctx));
+
+       hace_ctx->algo = algo;
+       hace_ctx->cmd = HACE_HASH_MODE_ACCUM | HACE_HASH_SHA_BE_EN;
+
+       switch (algo) {
+       case HASH_ALGO_SHA1:
+               hace_ctx->blk_size = 64;
+               hace_ctx->pad_size = 8;
+               hace_ctx->cmd |= HACE_HASH_ALGO_SHA1;
+               memcpy(hace_ctx->digest, iv_sha1, sizeof(iv_sha1));
+               break;
+       case HASH_ALGO_SHA256:
+               hace_ctx->blk_size = 64;
+               hace_ctx->pad_size = 8;
+               hace_ctx->cmd |= HACE_HASH_ALGO_SHA256;
+               memcpy(hace_ctx->digest, iv_sha256, sizeof(iv_sha256));
+               break;
+       case HASH_ALGO_SHA384:
+               hace_ctx->blk_size = 128;
+               hace_ctx->pad_size = 16;
+               hace_ctx->cmd |= HACE_HASH_ALGO_SHA384;
+               memcpy(hace_ctx->digest, iv_sha384, sizeof(iv_sha384));
+               break;
+       case HASH_ALGO_SHA512:
+               hace_ctx->blk_size = 128;
+               hace_ctx->pad_size = 16;
+               hace_ctx->cmd |= HACE_HASH_ALGO_SHA512;
+               memcpy(hace_ctx->digest, iv_sha512, sizeof(iv_sha512));
+               break;
+       default:
+               debug("Unsupported hash algorithm '%s'\n", hash_algo_name(algo));
+               goto free_n_out;
+       };
+
+       *ctxp = hace_ctx;
+
+       return 0;
+
+free_n_out:
+       free(hace_ctx);
+
+       return -EINVAL;
+}
+
+static int aspeed_hace_update(struct udevice *dev, void *ctx, const void *ibuf, uint32_t ilen)
+{
+       int rc;
+       uint32_t left, fill;
+       struct aspeed_hace_ctx *hace_ctx = ctx;
+
+       left = hace_ctx->total[0] & (hace_ctx->blk_size - 1);
+       fill = hace_ctx->blk_size - left;
+
+       hace_ctx->total[0] += ilen;
+       if (hace_ctx->total[0] < ilen)
+               hace_ctx->total[1]++;
+
+       if (left && ilen >= fill) {
+               memcpy(hace_ctx->buf + left, ibuf, fill);
+               rc = aspeed_hace_process(dev, ctx, hace_ctx->buf, hace_ctx->blk_size);
+               if (rc) {
+                       debug("failed to process hash, rc=%d\n", rc);
+                       return rc;
+               }
+               ilen -= fill;
+               ibuf += fill;
+               left = 0;
+       }
+
+       while (ilen >= hace_ctx->blk_size) {
+               rc = aspeed_hace_process(dev, ctx, ibuf, hace_ctx->blk_size);
+               if (rc) {
+                       debug("failed to process hash, rc=%d\n", rc);
+                       return rc;
+               }
+
+               ibuf += hace_ctx->blk_size;
+               ilen -= hace_ctx->blk_size;
+       }
+
+       if (ilen)
+               memcpy(hace_ctx->buf + left, ibuf, ilen);
+
+       return 0;
+}
+
+static int aspeed_hace_finish(struct udevice *dev, void *ctx, void *obuf)
+{
+       int rc = 0;
+       uint8_t pad[HASH_BLOCK_BUFSZ * 2];
+       uint32_t last, padn;
+       uint64_t ibits_h, ibits_l;
+       uint64_t ibits_be_h, ibits_be_l;
+       struct aspeed_hace_ctx *hace_ctx = ctx;
+
+       memset(pad, 0, sizeof(pad));
+       pad[0] = 0x80;
+
+       ibits_h = (hace_ctx->total[0] >> 61) | (hace_ctx->total[1] << 3);
+       ibits_be_h = cpu_to_be64(ibits_h);
+
+       ibits_l = (hace_ctx->total[0] << 3);
+       ibits_be_l = cpu_to_be64(ibits_l);
+
+       last = hace_ctx->total[0] & (hace_ctx->blk_size - 1);
+
+       switch (hace_ctx->algo) {
+       case HASH_ALGO_SHA1:
+       case HASH_ALGO_SHA256:
+               padn = (last < 56) ? (56 - last) : (120 - last);
+
+               rc = aspeed_hace_update(dev, ctx, pad, padn);
+               if (rc) {
+                       debug("failed to append padding, rc=%d\n", rc);
+                       goto free_n_out;
+               }
+
+               rc = aspeed_hace_update(dev, ctx, &ibits_be_l, sizeof(ibits_be_l));
+               if (rc) {
+                       debug("failed to append message bits length, rc=%d\n", rc);
+                       goto free_n_out;
+               }
+
+               break;
+       case HASH_ALGO_SHA384:
+       case HASH_ALGO_SHA512:
+               padn = (last < 112) ? (112 - last) : (240 - last);
+
+               rc = aspeed_hace_update(dev, ctx, pad, padn);
+               if (rc) {
+                       debug("failed to append padding, rc=%d\n", rc);
+                       goto free_n_out;
+               }
+
+               rc = aspeed_hace_update(dev, ctx, &ibits_be_h, sizeof(ibits_be_h)) |
+                    aspeed_hace_update(dev, ctx, &ibits_be_l, sizeof(ibits_be_l));
+               if (rc) {
+                       debug("failed to append message bits length, rc=%d\n", rc);
+                       goto free_n_out;
+               }
+
+               break;
+       default:
+               rc = -EINVAL;
+               break;
+       }
+
+       memcpy(obuf, hace_ctx->digest, hash_algo_digest_size(hace_ctx->algo));
+
+free_n_out:
+       free(ctx);
+
+       return rc;
+}
+
+static int aspeed_hace_digest_wd(struct udevice *dev, enum HASH_ALGO algo,
+                             const void *ibuf, const uint32_t ilen,
+                             void *obuf, uint32_t chunk_sz)
+{
+       int rc;
+       void *ctx;
+       const void *cur, *end;
+       uint32_t chunk;
+
+       rc = aspeed_hace_init(dev, algo, &ctx);
+       if (rc)
+               return rc;
+
+       if (CONFIG_IS_ENABLED(HW_WATCHDOG) || CONFIG_IS_ENABLED(WATCHDOG)) {
+               cur = ibuf;
+               end = ibuf + ilen;
+
+               while (cur < end) {
+                       chunk = end - cur;
+                       if (chunk > chunk_sz)
+                               chunk = chunk_sz;
+
+                       rc = aspeed_hace_update(dev, ctx, cur, chunk);
+                       if (rc)
+                               return rc;
+
+                       cur += chunk;
+                       WATCHDOG_RESET();
+               }
+       } else {
+               rc = aspeed_hace_update(dev, ctx, ibuf, ilen);
+               if (rc)
+                       return rc;
+       }
+
+       rc = aspeed_hace_finish(dev, ctx, obuf);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int aspeed_hace_digest(struct udevice *dev, enum HASH_ALGO algo,
+                             const void *ibuf, const uint32_t ilen,
+                             void *obuf)
+{
+       /* re-use the watchdog version with input length as the chunk_sz */
+       return aspeed_hace_digest_wd(dev, algo, ibuf, ilen, obuf, ilen);
+}
+
+static int aspeed_hace_probe(struct udevice *dev)
+{
+       int rc;
+       struct aspeed_hace *hace = dev_get_priv(dev);
+
+       rc = clk_get_by_index(dev, 0, &hace->clk);
+       if (rc < 0) {
+               debug("cannot get clock for %s: %d\n", dev->name, rc);
+               return rc;
+       }
+
+       rc = clk_enable(&hace->clk);
+       if (rc) {
+               debug("cannot enable clock for %s: %d\n", dev->name, rc);
+               return rc;
+       }
+
+       hace->base = devfdt_get_addr(dev);
+
+       return rc;
+}
+
+static int aspeed_hace_remove(struct udevice *dev)
+{
+       struct aspeed_hace *hace = dev_get_priv(dev);
+
+       clk_disable(&hace->clk);
+
+       return 0;
+}
+
+static const struct hash_ops aspeed_hace_ops = {
+       .hash_init = aspeed_hace_init,
+       .hash_update = aspeed_hace_update,
+       .hash_finish = aspeed_hace_finish,
+       .hash_digest_wd = aspeed_hace_digest_wd,
+       .hash_digest = aspeed_hace_digest,
+};
+
+static const struct udevice_id aspeed_hace_ids[] = {
+       { .compatible = "aspeed,ast2600-hace" },
+       { }
+};
+
+U_BOOT_DRIVER(aspeed_hace) = {
+       .name = "aspeed_hace",
+       .id = UCLASS_HASH,
+       .of_match = aspeed_hace_ids,
+       .ops = &aspeed_hace_ops,
+       .probe = aspeed_hace_probe,
+       .remove = aspeed_hace_remove,
+       .priv_auto = sizeof(struct aspeed_hace),
+       .flags = DM_FLAG_PRE_RELOC,
+};
index cd29a5c..bf9540e 100644 (file)
@@ -14,3 +14,11 @@ config HASH_SOFTWARE
        help
          Enable driver for hashing operations in software. Currently
          it support multiple hash algorithm including CRC/MD5/SHA.
+
+config HASH_ASPEED
+       bool "Enable Hash with ASPEED hash accelerator"
+       depends on DM_HASH
+       select ASPEED_HACE
+       help
+         Enable this to support HW-assisted hashing operations using ASPEED Hash
+         and Crypto engine - HACE
index c3a109b..8cf85f0 100644 (file)
@@ -2,7 +2,7 @@ config SCMI_FIRMWARE
        bool "Enable SCMI support"
        select FIRMWARE
        select OF_TRANSLATE
-       depends on SANDBOX || DM_MAILBOX || ARM_SMCCC
+       depends on SANDBOX || DM_MAILBOX || ARM_SMCCC || OPTEE
        help
          System Control and Management Interface (SCMI) is a communication
          protocol that defines standard interfaces for power, performance
@@ -14,6 +14,30 @@ config SCMI_FIRMWARE
          or a companion host in the CPU system.
 
          Communications between agent (client) and the SCMI server are
-         based on message exchange. Messages can be exchange over tranport
+         based on message exchange. Messages can be exchanged over transport
          channels as a mailbox device or an Arm SMCCC service with some
          piece of identified shared memory.
+
+config SCMI_AGENT_MAILBOX
+       bool "Enable SCMI agent mailbox"
+       depends on SCMI_FIRMWARE && DM_MAILBOX
+       default y
+       help
+         Enable the SCMI communication channel based on mailbox
+         for compatible "arm,scmi".
+
+config SCMI_AGENT_SMCCC
+       bool "Enable SCMI agent SMCCC"
+       depends on SCMI_FIRMWARE && ARM_SMCCC
+       default y
+       help
+         Enable the SCMI communication channel based on Arm SMCCC service for
+         compatible "arm,scmi-smc".
+
+config SCMI_AGENT_OPTEE
+       bool "Enable SCMI agent OP-TEE"
+       depends on SCMI_FIRMWARE && OPTEE
+       default y
+       help
+         Enable the SCMI communication channel based on OP-TEE transport
+         for compatible "linaro,scmi-optee".
index 966475e..b2ff483 100644 (file)
@@ -1,5 +1,6 @@
 obj-y  += scmi_agent-uclass.o
 obj-y  += smt.o
-obj-$(CONFIG_ARM_SMCCC)                += smccc_agent.o
-obj-$(CONFIG_DM_MAILBOX)       += mailbox_agent.o
+obj-$(CONFIG_SCMI_AGENT_SMCCC)         += smccc_agent.o
+obj-$(CONFIG_SCMI_AGENT_MAILBOX)       += mailbox_agent.o
+obj-$(CONFIG_SCMI_AGENT_OPTEE) += optee_agent.o
 obj-$(CONFIG_SANDBOX)          += sandbox-scmi_agent.o sandbox-scmi_devices.o
index ea35e7e..8e4af0c 100644 (file)
@@ -33,7 +33,7 @@ struct scmi_mbox_channel {
 
 static int scmi_mbox_process_msg(struct udevice *dev, struct scmi_msg *msg)
 {
-       struct scmi_mbox_channel *chan = dev_get_priv(dev);
+       struct scmi_mbox_channel *chan = dev_get_plat(dev);
        int ret;
 
        ret = scmi_write_msg_to_smt(dev, &chan->smt, msg);
@@ -62,9 +62,9 @@ out:
        return ret;
 }
 
-int scmi_mbox_probe(struct udevice *dev)
+int scmi_mbox_of_to_plat(struct udevice *dev)
 {
-       struct scmi_mbox_channel *chan = dev_get_priv(dev);
+       struct scmi_mbox_channel *chan = dev_get_plat(dev);
        int ret;
 
        chan->timeout_us = TIMEOUT_US_10MS;
@@ -72,17 +72,13 @@ int scmi_mbox_probe(struct udevice *dev)
        ret = mbox_get_by_index(dev, 0, &chan->mbox);
        if (ret) {
                dev_err(dev, "Failed to find mailbox: %d\n", ret);
-               goto out;
+               return ret;
        }
 
        ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
        if (ret)
                dev_err(dev, "Failed to get shm resources: %d\n", ret);
 
-out:
-       if (ret)
-               devm_kfree(dev, chan);
-
        return ret;
 }
 
@@ -99,7 +95,7 @@ U_BOOT_DRIVER(scmi_mbox) = {
        .name           = "scmi-over-mailbox",
        .id             = UCLASS_SCMI_AGENT,
        .of_match       = scmi_mbox_ids,
-       .priv_auto      = sizeof(struct scmi_mbox_channel),
-       .probe          = scmi_mbox_probe,
+       .plat_auto      = sizeof(struct scmi_mbox_channel),
+       .of_to_plat     = scmi_mbox_of_to_plat,
        .ops            = &scmi_mbox_ops,
 };
diff --git a/drivers/firmware/scmi/optee_agent.c b/drivers/firmware/scmi/optee_agent.c
new file mode 100644 (file)
index 0000000..1f26592
--- /dev/null
@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020-2021 Linaro Limited.
+ */
+
+#define LOG_CATEGORY UCLASS_SCMI_AGENT
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <scmi_agent.h>
+#include <scmi_agent-uclass.h>
+#include <string.h>
+#include <tee.h>
+#include <asm/types.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <linux/arm-smccc.h>
+#include <linux/bug.h>
+#include <linux/compat.h>
+
+#include "smt.h"
+
+#define SCMI_SHM_SIZE          128
+
+/**
+ * struct scmi_optee_channel - Description of an SCMI OP-TEE transport
+ * @channel_id:                Channel identifier
+ * @smt:               Shared memory buffer with synchronisation protocol
+ * @dyn_shm:           True if using dynamically allocated shared memory
+ */
+struct scmi_optee_channel {
+       unsigned int channel_id;
+       struct scmi_smt smt;
+       bool dyn_shm;
+};
+
+/**
+ * struct channel_session - Aggreates SCMI service session context references
+ * @tee:               OP-TEE device to invoke
+ * @tee_session:       OP-TEE session identifier
+ * @tee_shm:           Dynamically allocated OP-TEE shared memory, or NULL
+ * @channel_hdl:       Channel handle provided by OP-TEE SCMI service
+ */
+struct channel_session {
+       struct udevice *tee;
+       u32 tee_session;
+       struct tee_shm *tee_shm;
+       u32 channel_hdl;
+};
+
+#define TA_SCMI_UUID { 0xa8cfe406, 0xd4f5, 0x4a2e, \
+                     { 0x9f, 0x8d, 0xa2, 0x5d, 0xc7, 0x54, 0xc0, 0x99 } }
+
+enum optee_smci_pta_cmd {
+       /*
+        * PTA_SCMI_CMD_CAPABILITIES - Get channel capabilities
+        *
+        * [out]    value[0].a: Capability bit mask (enum pta_scmi_caps)
+        * [out]    value[0].b: Extended capabilities or 0
+        */
+       PTA_SCMI_CMD_CAPABILITIES = 0,
+
+       /*
+        * PTA_SCMI_CMD_PROCESS_SMT_CHANNEL - Process SCMI message in SMT buffer
+        *
+        * [in]     value[0].a: Channel handle
+        *
+        * Shared memory used for SCMI message/response exhange is expected
+        * already identified and bound to channel handle in both SCMI agent
+        * and SCMI server (OP-TEE) parts.
+        * The memory uses SMT header to carry SCMI meta-data (protocol ID and
+        * protocol message ID).
+        */
+       PTA_SCMI_CMD_PROCESS_SMT_CHANNEL = 1,
+
+       /*
+        * PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE - Process SMT/SCMI message
+        *
+        * [in]     value[0].a: Channel handle
+        * [in/out] memref[1]: Message/response buffer (SMT and SCMI payload)
+        *
+        * Shared memory used for SCMI message/response is a SMT buffer
+        * referenced by param[1]. It shall be 128 bytes large to fit response
+        * payload whatever message playload size.
+        * The memory uses SMT header to carry SCMI meta-data (protocol ID and
+        * protocol message ID).
+        */
+       PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE = 2,
+
+       /*
+        * PTA_SCMI_CMD_GET_CHANNEL - Get channel handle
+        *
+        * SCMI shm information are 0 if agent expects to use OP-TEE regular SHM
+        *
+        * [in]     value[0].a: Channel identifier
+        * [out]    value[0].a: Returned channel handle
+        * [in]     value[0].b: Requested capabilities mask (enum pta_scmi_caps)
+        */
+       PTA_SCMI_CMD_GET_CHANNEL = 3,
+};
+
+/*
+ * OP-TEE SCMI service capabilities bit flags (32bit)
+ *
+ * PTA_SCMI_CAPS_SMT_HEADER
+ * When set, OP-TEE supports command using SMT header protocol (SCMI shmem) in
+ * shared memory buffers to carry SCMI protocol synchronisation information.
+ */
+#define PTA_SCMI_CAPS_NONE             0
+#define PTA_SCMI_CAPS_SMT_HEADER       BIT(0)
+
+static int open_channel(struct udevice *dev, struct channel_session *sess)
+{
+       const struct tee_optee_ta_uuid uuid = TA_SCMI_UUID;
+       struct scmi_optee_channel *chan = dev_get_plat(dev);
+       struct tee_open_session_arg sess_arg = { };
+       struct tee_invoke_arg cmd_arg = { };
+       struct tee_param param[1] = { };
+       int ret;
+
+       memset(sess, 0, sizeof(sess));
+
+       sess->tee = tee_find_device(NULL, NULL, NULL, NULL);
+       if (!sess->tee)
+               return -ENODEV;
+
+       sess_arg.clnt_login = TEE_LOGIN_REE_KERNEL;
+       tee_optee_ta_uuid_to_octets(sess_arg.uuid, &uuid);
+
+       ret = tee_open_session(sess->tee, &sess_arg, 0, NULL);
+       if (ret) {
+               dev_err(dev, "can't open session: %d\n", ret);
+               return ret;
+       }
+
+       cmd_arg.func = PTA_SCMI_CMD_GET_CHANNEL;
+       cmd_arg.session = sess_arg.session;
+
+       param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INOUT;
+       param[0].u.value.a = chan->channel_id;
+       param[0].u.value.b = PTA_SCMI_CAPS_SMT_HEADER;
+
+       ret = tee_invoke_func(sess->tee, &cmd_arg, ARRAY_SIZE(param), param);
+       if (ret || cmd_arg.ret) {
+               dev_err(dev, "Invoke failed: %d, 0x%x\n", ret, cmd_arg.ret);
+               if (!ret)
+                       ret = -EPROTO;
+
+               tee_close_session(sess->tee, sess_arg.session);
+               return ret;
+       }
+
+       sess->tee_session = sess_arg.session;
+       sess->channel_hdl = param[0].u.value.a;
+
+       return 0;
+}
+
+static void close_channel(struct channel_session *sess)
+{
+       tee_close_session(sess->tee, sess->tee_session);
+}
+
+static int invoke_cmd(struct udevice *dev, struct channel_session *sess,
+                     struct scmi_msg *msg)
+{
+       struct scmi_optee_channel *chan = dev_get_plat(dev);
+       struct tee_invoke_arg arg = { };
+       struct tee_param param[2] = { };
+       int ret;
+
+       scmi_write_msg_to_smt(dev, &chan->smt, msg);
+
+       arg.session = sess->tee_session;
+       param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
+       param[0].u.value.a = sess->channel_hdl;
+
+       if (chan->dyn_shm) {
+               arg.func = PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE;
+               param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT;
+               param[1].u.memref.shm = sess->tee_shm;
+               param[1].u.memref.size = SCMI_SHM_SIZE;
+       } else {
+               arg.func = PTA_SCMI_CMD_PROCESS_SMT_CHANNEL;
+       }
+
+       ret = tee_invoke_func(sess->tee, &arg, ARRAY_SIZE(param), param);
+       if (ret || arg.ret) {
+               if (!ret)
+                       ret = -EPROTO;
+       } else {
+               ret = scmi_read_resp_from_smt(dev, &chan->smt, msg);
+       }
+
+       scmi_clear_smt_channel(&chan->smt);
+
+       return ret;
+}
+
+static int prepare_shm(struct udevice *dev, struct channel_session *sess)
+{
+       struct scmi_optee_channel *chan = dev_get_plat(dev);
+       int ret;
+
+       /* Static shm is already prepared by the firmware: nothing to do */
+       if (!chan->dyn_shm)
+               return 0;
+
+       chan->smt.size = SCMI_SHM_SIZE;
+
+       ret = tee_shm_alloc(sess->tee, chan->smt.size, 0, &sess->tee_shm);
+       if (ret) {
+               dev_err(dev, "Failed to allocated shmem: %d\n", ret);
+               return ret;
+       }
+
+       chan->smt.buf = sess->tee_shm->addr;
+
+       /* Initialize shm buffer for message exchanges */
+       scmi_clear_smt_channel(&chan->smt);
+
+       return 0;
+}
+
+static void release_shm(struct udevice *dev, struct channel_session *sess)
+{
+       struct scmi_optee_channel *chan = dev_get_plat(dev);
+
+       if (chan->dyn_shm)
+               tee_shm_free(sess->tee_shm);
+}
+
+static int scmi_optee_process_msg(struct udevice *dev, struct scmi_msg *msg)
+{
+       struct channel_session sess;
+       int ret;
+
+       ret = open_channel(dev, &sess);
+       if (ret)
+               return ret;
+
+       ret = prepare_shm(dev, &sess);
+       if (ret)
+               goto out;
+
+       ret = invoke_cmd(dev, &sess, msg);
+
+       release_shm(dev, &sess);
+
+out:
+       close_channel(&sess);
+
+       return ret;
+}
+
+static int scmi_optee_of_to_plat(struct udevice *dev)
+{
+       struct scmi_optee_channel *chan = dev_get_plat(dev);
+       int ret;
+
+       if (dev_read_u32(dev, "linaro,optee-channel-id", &chan->channel_id)) {
+               dev_err(dev, "Missing property linaro,optee-channel-id\n");
+               return -EINVAL;
+       }
+
+       if (dev_read_prop(dev, "shmem", NULL)) {
+               ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
+               if (ret) {
+                       dev_err(dev, "Failed to get smt resources: %d\n", ret);
+                       return ret;
+               }
+               chan->dyn_shm = false;
+       } else {
+               chan->dyn_shm = true;
+       }
+
+       return 0;
+}
+
+static int scmi_optee_probe(struct udevice *dev)
+{
+       struct channel_session sess;
+       int ret;
+
+       /* Check OP-TEE service acknowledges the SCMI channel */
+       ret = open_channel(dev, &sess);
+       if (!ret)
+               close_channel(&sess);
+
+       return ret;
+}
+
+static const struct udevice_id scmi_optee_ids[] = {
+       { .compatible = "linaro,scmi-optee" },
+       { }
+};
+
+static const struct scmi_agent_ops scmi_optee_ops = {
+       .process_msg = scmi_optee_process_msg,
+};
+
+U_BOOT_DRIVER(scmi_optee) = {
+       .name           = "scmi-over-optee",
+       .id             = UCLASS_SCMI_AGENT,
+       .of_match       = scmi_optee_ids,
+       .plat_auto      = sizeof(struct scmi_optee_channel),
+       .of_to_plat     = scmi_optee_of_to_plat,
+       .probe          = scmi_optee_probe,
+       .flags          = DM_FLAG_OS_PREPARE,
+       .ops            = &scmi_optee_ops,
+};
index f185891..5e166ca 100644 (file)
@@ -32,7 +32,7 @@ struct scmi_smccc_channel {
 
 static int scmi_smccc_process_msg(struct udevice *dev, struct scmi_msg *msg)
 {
-       struct scmi_smccc_channel *chan = dev_get_priv(dev);
+       struct scmi_smccc_channel *chan = dev_get_plat(dev);
        struct arm_smccc_res res;
        int ret;
 
@@ -51,9 +51,9 @@ static int scmi_smccc_process_msg(struct udevice *dev, struct scmi_msg *msg)
        return ret;
 }
 
-static int scmi_smccc_probe(struct udevice *dev)
+static int scmi_smccc_of_to_plat(struct udevice *dev)
 {
-       struct scmi_smccc_channel *chan = dev_get_priv(dev);
+       struct scmi_smccc_channel *chan = dev_get_plat(dev);
        u32 func_id;
        int ret;
 
@@ -65,12 +65,10 @@ static int scmi_smccc_probe(struct udevice *dev)
        chan->func_id = func_id;
 
        ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
-       if (ret) {
+       if (ret)
                dev_err(dev, "Failed to get smt resources: %d\n", ret);
-               return ret;
-       }
 
-       return 0;
+       return ret;
 }
 
 static const struct udevice_id scmi_smccc_ids[] = {
@@ -86,7 +84,7 @@ U_BOOT_DRIVER(scmi_smccc) = {
        .name           = "scmi-over-smccc",
        .id             = UCLASS_SCMI_AGENT,
        .of_match       = scmi_smccc_ids,
-       .priv_auto      = sizeof(struct scmi_smccc_channel),
-       .probe          = scmi_smccc_probe,
+       .plat_auto      = sizeof(struct scmi_smccc_channel),
+       .of_to_plat     = scmi_smccc_of_to_plat,
        .ops            = &scmi_smccc_ops,
 };
index 3ee92d0..b80e838 100644 (file)
@@ -320,7 +320,7 @@ struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
        struct blk_desc *desc;
        struct udevice *dev;
 
-       device_find_first_child(mmc->dev, &dev);
+       device_find_first_child_by_uclass(mmc->dev, UCLASS_BLK, &dev);
        if (!dev)
                return NULL;
        desc = dev_get_uclass_plat(dev);
@@ -425,7 +425,7 @@ int mmc_unbind(struct udevice *dev)
 {
        struct udevice *bdev;
 
-       device_find_first_child(dev, &bdev);
+       device_find_first_child_by_uclass(dev, UCLASS_BLK, &bdev);
        if (bdev) {
                device_remove(bdev, DM_REMOVE_NORMAL);
                device_unbind(bdev);
index 8599f09..97182ff 100644 (file)
@@ -1724,6 +1724,20 @@ static int msdc_drv_bind(struct udevice *dev)
        return mmc_bind(dev, &plat->mmc, &plat->cfg);
 }
 
+static int msdc_ops_wait_dat0(struct udevice *dev, int state, int timeout_us)
+{
+       struct msdc_host *host = dev_get_priv(dev);
+       int ret;
+       u32 reg;
+
+       ret = readl_poll_sleep_timeout(&host->base->msdc_ps, reg,
+                                      !!(reg & MSDC_PS_DAT0) == !!state,
+                                      1000, /* 1 ms */
+                                      timeout_us);
+
+       return ret;
+}
+
 static const struct dm_mmc_ops msdc_ops = {
        .send_cmd = msdc_ops_send_cmd,
        .set_ios = msdc_ops_set_ios,
@@ -1732,6 +1746,7 @@ static const struct dm_mmc_ops msdc_ops = {
 #ifdef MMC_SUPPORTS_TUNING
        .execute_tuning = msdc_execute_tuning,
 #endif
+       .wait_dat0 = msdc_ops_wait_dat0,
 };
 
 static const struct msdc_compatible mt7620_compat = {
index 895fbff..451fe4a 100644 (file)
@@ -9,23 +9,26 @@
 #include <errno.h>
 #include <fdtdec.h>
 #include <log.h>
+#include <malloc.h>
 #include <mmc.h>
+#include <os.h>
 #include <asm/test.h>
 
 struct sandbox_mmc_plat {
        struct mmc_config cfg;
        struct mmc mmc;
+       const char *fname;
 };
 
-#define MMC_CSIZE 0
-#define MMC_CMULT 8 /* 8 because the card is high-capacity */
-#define MMC_BL_LEN_SHIFT 10
-#define MMC_BL_LEN BIT(MMC_BL_LEN_SHIFT)
-#define MMC_CAPACITY (((MMC_CSIZE + 1) << (MMC_CMULT + 2)) \
-                     * MMC_BL_LEN) /* 1 MiB */
+#define MMC_CMULT              8 /* 8 because the card is high-capacity */
+#define MMC_BL_LEN_SHIFT       10
+#define MMC_BL_LEN             BIT(MMC_BL_LEN_SHIFT)
+#define SIZE_MULTIPLE          ((1 << (MMC_CMULT + 2)) * MMC_BL_LEN)
 
 struct sandbox_mmc_priv {
-       u8 buf[MMC_CAPACITY];
+       char *buf;
+       int csize;      /* CSIZE value to report */
+       int size;
 };
 
 /**
@@ -60,8 +63,8 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
        case MMC_CMD_SEND_CSD:
                cmd->response[0] = 0;
                cmd->response[1] = (MMC_BL_LEN_SHIFT << 16) |
-                                  ((MMC_CSIZE >> 16) & 0x3f);
-               cmd->response[2] = (MMC_CSIZE & 0xffff) << 16;
+                                  ((priv->csize >> 16) & 0x3f);
+               cmd->response[2] = (priv->csize & 0xffff) << 16;
                cmd->response[3] = 0;
                break;
        case SD_CMD_SWITCH_FUNC: {
@@ -143,6 +146,8 @@ static int sandbox_mmc_of_to_plat(struct udevice *dev)
        struct blk_desc *blk;
        int ret;
 
+       plat->fname = dev_read_string(dev, "filename");
+
        ret = mmc_of_parse(dev, cfg);
        if (ret)
                return ret;
@@ -156,10 +161,46 @@ static int sandbox_mmc_of_to_plat(struct udevice *dev)
 static int sandbox_mmc_probe(struct udevice *dev)
 {
        struct sandbox_mmc_plat *plat = dev_get_plat(dev);
+       struct sandbox_mmc_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       if (plat->fname) {
+               ret = os_map_file(plat->fname, OS_O_RDWR | OS_O_CREAT,
+                                 (void **)&priv->buf, &priv->size);
+               if (ret) {
+                       log_err("%s: Unable to map file '%s'\n", dev->name,
+                               plat->fname);
+                       return ret;
+               }
+               priv->csize = priv->size / SIZE_MULTIPLE - 1;
+       } else {
+               priv->csize = 0;
+               priv->size = (priv->csize + 1) * SIZE_MULTIPLE; /* 1 MiB */
+
+               priv->buf = malloc(priv->size);
+               if (!priv->buf) {
+                       log_err("%s: Not enough memory (%x bytes)\n",
+                               dev->name, priv->size);
+                       return -ENOMEM;
+               }
+       }
 
        return mmc_init(&plat->mmc);
 }
 
+static int sandbox_mmc_remove(struct udevice *dev)
+{
+       struct sandbox_mmc_plat *plat = dev_get_plat(dev);
+       struct sandbox_mmc_priv *priv = dev_get_priv(dev);
+
+       if (plat->fname)
+               os_unmap(priv->buf, priv->size);
+       else
+               free(priv->buf);
+
+       return 0;
+}
+
 static int sandbox_mmc_bind(struct udevice *dev)
 {
        struct sandbox_mmc_plat *plat = dev_get_plat(dev);
@@ -196,6 +237,7 @@ U_BOOT_DRIVER(mmc_sandbox) = {
        .unbind         = sandbox_mmc_unbind,
        .of_to_plat     = sandbox_mmc_of_to_plat,
        .probe          = sandbox_mmc_probe,
+       .remove         = sandbox_mmc_remove,
        .priv_auto = sizeof(struct sandbox_mmc_priv),
        .plat_auto = sizeof(struct sandbox_mmc_plat),
 };
index c1a4917..e054bec 100644 (file)
@@ -554,6 +554,22 @@ config RTL8169
          This driver supports Realtek 8169 series gigabit ethernet family of
          PCI/PCIe chipsets/adapters.
 
+config SJA1105
+       bool "NXP SJA1105 Ethernet switch family driver"
+       depends on DM_DSA && DM_SPI
+       select BITREVERSE
+       help
+         This is the driver for the NXP SJA1105 automotive Ethernet switch
+         family. These are 5-port devices and are managed over an SPI
+         interface. Probing is handled based on OF bindings. The driver
+         supports the following revisions:
+           - SJA1105E (Gen. 1, No TT-Ethernet)
+           - SJA1105T (Gen. 1, TT-Ethernet)
+           - SJA1105P (Gen. 2, No SGMII, No TT-Ethernet)
+           - SJA1105Q (Gen. 2, No SGMII, TT-Ethernet)
+           - SJA1105R (Gen. 2, SGMII, No TT-Ethernet)
+           - SJA1105S (Gen. 2, SGMII, TT-Ethernet)
+
 config SMC911X
        bool "SMSC LAN911x and LAN921x controller driver"
 
@@ -835,6 +851,13 @@ config FSL_LS_MDIO
          This driver supports the MDIO bus found on the Fman 10G Ethernet MACs and
          on the mEMAC (which supports both Clauses 22 and 45).
 
+config ASPEED_MDIO
+       bool "Aspeed MDIO interface support"
+       depends on DM_MDIO
+       help
+         This driver supports the MDIO bus of Aspeed AST2600 SOC.  The driver
+         currently supports Clause 22.
+
 config MDIO_MUX_MMIOREG
        bool "MDIO MUX accessed as a MMIO register access"
        depends on DM_MDIO_MUX
index e4078d1..cf6294c 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_DM_ETH_PHY) += eth-phy-uclass.o
 obj-$(CONFIG_E1000) += e1000.o
 obj-$(CONFIG_E1000_SPI) += e1000_spi.o
 obj-$(CONFIG_EEPRO100) += eepro100.o
+obj-$(CONFIG_SJA1105) += sja1105.o
 obj-$(CONFIG_SUN4I_EMAC) += sunxi_emac.o
 obj-$(CONFIG_SUN8I_EMAC) += sun8i_emac.o
 obj-$(CONFIG_EP93XX) += ep93xx_eth.o
@@ -101,3 +102,4 @@ obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o
 obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o
 obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o
 obj-$(CONFIG_FSL_LS_MDIO) += fsl_ls_mdio.o
+obj-$(CONFIG_ASPEED_MDIO) += aspeed_mdio.o
diff --git a/drivers/net/aspeed_mdio.c b/drivers/net/aspeed_mdio.c
new file mode 100644 (file)
index 0000000..a99715a
--- /dev/null
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Aspeed MDIO driver
+ *
+ * (C) Copyright 2021 Aspeed Technology Inc.
+ *
+ * This file is inspired from the Linux kernel driver drivers/net/phy/mdio-aspeed.c
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <miiphy.h>
+#include <net.h>
+#include <reset.h>
+#include <linux/bitops.h>
+#include <linux/bitfield.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+
+#define ASPEED_MDIO_CTRL               0x0
+#define   ASPEED_MDIO_CTRL_FIRE                BIT(31)
+#define   ASPEED_MDIO_CTRL_ST          BIT(28)
+#define     ASPEED_MDIO_CTRL_ST_C45    0
+#define     ASPEED_MDIO_CTRL_ST_C22    1
+#define   ASPEED_MDIO_CTRL_OP          GENMASK(27, 26)
+#define     MDIO_C22_OP_WRITE          0b01
+#define     MDIO_C22_OP_READ           0b10
+#define   ASPEED_MDIO_CTRL_PHYAD       GENMASK(25, 21)
+#define   ASPEED_MDIO_CTRL_REGAD       GENMASK(20, 16)
+#define   ASPEED_MDIO_CTRL_MIIWDATA    GENMASK(15, 0)
+
+#define ASPEED_MDIO_DATA               0x4
+#define   ASPEED_MDIO_DATA_MDC_THRES   GENMASK(31, 24)
+#define   ASPEED_MDIO_DATA_MDIO_EDGE   BIT(23)
+#define   ASPEED_MDIO_DATA_MDIO_LATCH  GENMASK(22, 20)
+#define   ASPEED_MDIO_DATA_IDLE                BIT(16)
+#define   ASPEED_MDIO_DATA_MIIRDATA    GENMASK(15, 0)
+
+#define ASPEED_MDIO_TIMEOUT_US         1000
+
+struct aspeed_mdio_priv {
+       void *base;
+};
+
+static int aspeed_mdio_read(struct udevice *mdio_dev, int addr, int devad, int reg)
+{
+       struct aspeed_mdio_priv *priv = dev_get_priv(mdio_dev);
+       u32 ctrl;
+       u32 data;
+       int rc;
+
+       if (devad != MDIO_DEVAD_NONE)
+               return -EOPNOTSUPP;
+
+       ctrl = ASPEED_MDIO_CTRL_FIRE
+               | FIELD_PREP(ASPEED_MDIO_CTRL_ST, ASPEED_MDIO_CTRL_ST_C22)
+               | FIELD_PREP(ASPEED_MDIO_CTRL_OP, MDIO_C22_OP_READ)
+               | FIELD_PREP(ASPEED_MDIO_CTRL_PHYAD, addr)
+               | FIELD_PREP(ASPEED_MDIO_CTRL_REGAD, reg);
+
+       writel(ctrl, priv->base + ASPEED_MDIO_CTRL);
+
+       rc = readl_poll_timeout(priv->base + ASPEED_MDIO_DATA, data,
+                               data & ASPEED_MDIO_DATA_IDLE,
+                               ASPEED_MDIO_TIMEOUT_US);
+
+       if (rc < 0)
+               return rc;
+
+       return FIELD_GET(ASPEED_MDIO_DATA_MIIRDATA, data);
+}
+
+static int aspeed_mdio_write(struct udevice *mdio_dev, int addr, int devad, int reg, u16 val)
+{
+       struct aspeed_mdio_priv *priv = dev_get_priv(mdio_dev);
+       u32 ctrl;
+
+       if (devad != MDIO_DEVAD_NONE)
+               return -EOPNOTSUPP;
+
+       ctrl = ASPEED_MDIO_CTRL_FIRE
+               | FIELD_PREP(ASPEED_MDIO_CTRL_ST, ASPEED_MDIO_CTRL_ST_C22)
+               | FIELD_PREP(ASPEED_MDIO_CTRL_OP, MDIO_C22_OP_WRITE)
+               | FIELD_PREP(ASPEED_MDIO_CTRL_PHYAD, addr)
+               | FIELD_PREP(ASPEED_MDIO_CTRL_REGAD, reg)
+               | FIELD_PREP(ASPEED_MDIO_CTRL_MIIWDATA, val);
+
+       writel(ctrl, priv->base + ASPEED_MDIO_CTRL);
+
+       return readl_poll_timeout(priv->base + ASPEED_MDIO_CTRL, ctrl,
+                                 !(ctrl & ASPEED_MDIO_CTRL_FIRE),
+                                 ASPEED_MDIO_TIMEOUT_US);
+}
+
+static const struct mdio_ops aspeed_mdio_ops = {
+       .read = aspeed_mdio_read,
+       .write = aspeed_mdio_write,
+};
+
+static int aspeed_mdio_probe(struct udevice *dev)
+{
+       struct aspeed_mdio_priv *priv = dev_get_priv(dev);
+       struct reset_ctl reset_ctl;
+       int ret = 0;
+
+       priv->base = dev_read_addr_ptr(dev);
+
+       ret = reset_get_by_index(dev, 0, &reset_ctl);
+       reset_deassert(&reset_ctl);
+
+       return 0;
+}
+
+static const struct udevice_id aspeed_mdio_ids[] = {
+       { .compatible = "aspeed,ast2600-mdio" },
+       { }
+};
+
+U_BOOT_DRIVER(aspeed_mdio) = {
+       .name = "aspeed_mdio",
+       .id = UCLASS_MDIO,
+       .of_match = aspeed_mdio_ids,
+       .probe = aspeed_mdio_probe,
+       .ops = &aspeed_mdio_ops,
+       .plat_auto = sizeof(struct mdio_perdev_priv),
+       .priv_auto = sizeof(struct aspeed_mdio_priv),
+};
index 1c0d0e5..48faa33 100644 (file)
@@ -272,7 +272,7 @@ struct fec_priv {
        struct clk clk_ref;
        struct clk clk_ptp;
        u32 clk_rate;
-       char promisc;
+       bool promisc;
 };
 
 /**
index 551fc2c..2df8dde 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include <dm/device_compat.h>
+#include <dm/of_extra.h>
 #include <linux/delay.h>
 #include <net/dsa.h>
 #include <asm/io.h>
@@ -210,17 +211,14 @@ static int felix_init_sxgmii(struct mii_dev *imdio, int pidx)
 static void felix_start_pcs(struct udevice *dev, int port,
                            struct phy_device *phy, struct mii_dev *imdio)
 {
-       bool autoneg = true;
-
-       if (phy->phy_id == PHY_FIXED_ID ||
-           phy->interface == PHY_INTERFACE_MODE_2500BASEX)
-               autoneg = false;
+       ofnode node = dsa_port_get_ofnode(dev, port);
+       bool inband_an = ofnode_eth_uses_inband_aneg(node);
 
        switch (phy->interface) {
        case PHY_INTERFACE_MODE_SGMII:
        case PHY_INTERFACE_MODE_2500BASEX:
        case PHY_INTERFACE_MODE_QSGMII:
-               felix_init_sgmii(imdio, port, autoneg);
+               felix_init_sgmii(imdio, port, inband_an);
                break;
        case PHY_INTERFACE_MODE_10GBASER:
        case PHY_INTERFACE_MODE_USXGMII:
index 68ee7d7..e69cd8a 100644 (file)
@@ -214,16 +214,6 @@ config PHY_NXP_C45_TJA11XX
 config PHY_REALTEK
        bool "Realtek Ethernet PHYs support"
 
-config RTL8211E_PINE64_GIGABIT_FIX
-       bool "Fix gigabit throughput on some Pine64+ models"
-       depends on PHY_REALTEK
-       help
-         Configure the Realtek RTL8211E found on some Pine64+ models differently to
-         fix throughput on Gigabit links, turning off all internal delays in the
-         process. The settings that this touches are not documented in the CONFREG
-         section of the RTL8211E datasheet, but come from Realtek by way of the
-         Pine64 engineering team.
-
 config RTL8211X_PHY_FORCE_MASTER
        bool "Ethernet PHY RTL8211x: force 1000BASE-T master mode"
        depends on PHY_REALTEK
index d1a643c..f9482b2 100644 (file)
@@ -19,6 +19,7 @@
 /* Microsemi PHY ID's */
 #define PHY_ID_VSC8530                  0x00070560
 #define PHY_ID_VSC8531                  0x00070570
+#define PHY_ID_VSC8502                 0x00070630
 #define PHY_ID_VSC8540                  0x00070760
 #define PHY_ID_VSC8541                  0x00070770
 #define PHY_ID_VSC8574                 0x000704a0
@@ -1513,6 +1514,50 @@ static int vsc8584_config(struct phy_device *phydev)
        return vsc8584_config_init(phydev);
 }
 
+static int vsc8502_config(struct phy_device *phydev)
+{
+       bool rgmii_rx_delay = false, rgmii_tx_delay = false;
+       u16 reg = 0;
+       int ret;
+
+       /* Assume nothing needs to be done for the default GMII/MII mode */
+       if (!phy_interface_is_rgmii(phydev))
+               return 0;
+
+       /* Set Extended PHY Control 1 register to RGMII */
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_EXT_PHY_CNTL_1_REG,
+                 BIT(13) | BIT(12));
+
+       /* Soft reset required after changing PHY mode from the default
+        * of GMII/MII
+        */
+       ret = mscc_phy_soft_reset(phydev);
+       if (ret)
+               return ret;
+
+       if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
+           phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+               rgmii_rx_delay = true;
+       if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
+           phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+               rgmii_tx_delay = true;
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                 MSCC_PHY_PAGE_EXT2);
+
+       if (rgmii_rx_delay)
+               reg |= VSC_PHY_RGMII_DELAY_2000_PS << RGMII_RX_CLK_DELAY_POS;
+       if (rgmii_tx_delay)
+               reg |= VSC_PHY_RGMII_DELAY_2000_PS << RGMII_TX_CLK_DELAY_POS;
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg);
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
+                 MSCC_PHY_PAGE_STD);
+
+       return 0;
+}
+
 static struct phy_driver VSC8530_driver = {
        .name = "Microsemi VSC8530",
        .uid = PHY_ID_VSC8530,
@@ -1533,6 +1578,16 @@ static struct phy_driver VSC8531_driver = {
        .shutdown = &genphy_shutdown,
 };
 
+static struct phy_driver VSC8502_driver = {
+       .name = "Microsemi VSC8502",
+       .uid = PHY_ID_VSC8502,
+       .mask = 0x000ffff0,
+       .features = PHY_GBIT_FEATURES,
+       .config = &vsc8502_config,
+       .startup = &mscc_startup,
+       .shutdown = &genphy_shutdown,
+};
+
 static struct phy_driver VSC8540_driver = {
        .name = "Microsemi VSC8540",
        .uid = PHY_ID_VSC8540,
@@ -1577,6 +1632,7 @@ int phy_mscc_init(void)
 {
        phy_register(&VSC8530_driver);
        phy_register(&VSC8531_driver);
+       phy_register(&VSC8502_driver);
        phy_register(&VSC8540_driver);
        phy_register(&VSC8541_driver);
        phy_register(&VSC8574_driver);
index b1b1fa5..24c3ea5 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/delay.h>
 
 #define PHY_RTL8211x_FORCE_MASTER BIT(1)
-#define PHY_RTL8211E_PINE64_GIGABIT_FIX BIT(2)
 #define PHY_RTL8211F_FORCE_EEE_RXC_ON BIT(3)
 #define PHY_RTL8201F_S700_RMII_TIMINGS BIT(4)
 
 #define MIIM_RTL8211F_PHYSTAT_SPDDONE  0x0800
 #define MIIM_RTL8211F_PHYSTAT_LINK     0x0004
 
-#define MIIM_RTL8211E_CONFREG           0x1c
-#define MIIM_RTL8211E_CONFREG_TXD              0x0002
-#define MIIM_RTL8211E_CONFREG_RXD              0x0004
-#define MIIM_RTL8211E_CONFREG_MAGIC            0xb400  /* Undocumented */
+#define MIIM_RTL8211E_CONFREG          0x1c
+#define MIIM_RTL8211E_CTRL_DELAY       BIT(13)
+#define MIIM_RTL8211E_TX_DELAY         BIT(12)
+#define MIIM_RTL8211E_RX_DELAY         BIT(11)
 
 #define MIIM_RTL8211E_EXT_PAGE_SELECT  0x1e
 
@@ -108,10 +107,6 @@ static int rtl8211b_probe(struct phy_device *phydev)
 
 static int rtl8211e_probe(struct phy_device *phydev)
 {
-#ifdef CONFIG_RTL8211E_PINE64_GIGABIT_FIX
-       phydev->flags |= PHY_RTL8211E_PINE64_GIGABIT_FIX;
-#endif
-
        return 0;
 }
 
@@ -154,22 +149,6 @@ static int rtl8211x_config(struct phy_device *phydev)
                reg |= MIIM_RTL8211x_CTRL1000T_MASTER;
                phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, reg);
        }
-       if (phydev->flags & PHY_RTL8211E_PINE64_GIGABIT_FIX) {
-               unsigned int reg;
-
-               phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT,
-                         7);
-               phy_write(phydev, MDIO_DEVAD_NONE,
-                         MIIM_RTL8211E_EXT_PAGE_SELECT, 0xa4);
-               reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG);
-               /* Ensure both internal delays are turned off */
-               reg &= ~(MIIM_RTL8211E_CONFREG_TXD | MIIM_RTL8211E_CONFREG_RXD);
-               /* Flip the magic undocumented bits */
-               reg |= MIIM_RTL8211E_CONFREG_MAGIC;
-               phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG, reg);
-               phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT,
-                         0);
-       }
        /* read interrupt status just to clear it */
        phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER);
 
@@ -201,6 +180,44 @@ static int rtl8201f_config(struct phy_device *phydev)
        return 0;
 }
 
+static int rtl8211e_config(struct phy_device *phydev)
+{
+       int reg, val;
+
+       /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */
+       switch (phydev->interface) {
+       case PHY_INTERFACE_MODE_RGMII:
+               val = MIIM_RTL8211E_CTRL_DELAY;
+               break;
+       case PHY_INTERFACE_MODE_RGMII_ID:
+               val = MIIM_RTL8211E_CTRL_DELAY | MIIM_RTL8211E_TX_DELAY |
+                     MIIM_RTL8211E_RX_DELAY;
+               break;
+       case PHY_INTERFACE_MODE_RGMII_RXID:
+               val = MIIM_RTL8211E_CTRL_DELAY | MIIM_RTL8211E_RX_DELAY;
+               break;
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+               val = MIIM_RTL8211E_CTRL_DELAY | MIIM_RTL8211E_TX_DELAY;
+               break;
+       default: /* the rest of the modes imply leaving delays as is. */
+               goto default_delay;
+       }
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, 7);
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_EXT_PAGE_SELECT, 0xa4);
+
+       reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG);
+       reg &= ~(MIIM_RTL8211E_TX_DELAY | MIIM_RTL8211E_RX_DELAY);
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG, reg | val);
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, 0);
+
+default_delay:
+       genphy_config_aneg(phydev);
+
+       return 0;
+}
+
 static int rtl8211f_config(struct phy_device *phydev)
 {
        u16 reg;
@@ -410,7 +427,7 @@ static struct phy_driver RTL8211E_driver = {
        .mask = 0xffffff,
        .features = PHY_GBIT_FEATURES,
        .probe = &rtl8211e_probe,
-       .config = &rtl8211x_config,
+       .config = &rtl8211e_config,
        .startup = &rtl8211e_startup,
        .shutdown = &genphy_shutdown,
 };
diff --git a/drivers/net/sja1105.c b/drivers/net/sja1105.c
new file mode 100644 (file)
index 0000000..17bab33
--- /dev/null
@@ -0,0 +1,3376 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2016-2018 NXP
+ * Copyright 2018, Sensor-Technik Wiedemann GmbH
+ * Copyright 2018-2019, Vladimir Oltean <olteanv@gmail.com>
+ * Copyright 2020-2021 NXP
+ *
+ * Ported from Linux (drivers/net/dsa/sja1105/).
+ */
+
+#include <common.h>
+#include <dm/device_compat.h>
+#include <linux/bitops.h>
+#include <linux/bitrev.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/types.h>
+#include <net/dsa.h>
+#include <stdlib.h>
+#include <spi.h>
+#include <miiphy.h>
+#include <dm/of_extra.h>
+
+enum packing_op {
+       PACK,
+       UNPACK,
+};
+
+#define ETHER_CRC32_POLY                               0x04C11DB7
+#define ETH_P_SJA1105                                  0xdadb
+#define SJA1105_NUM_PORTS                              5
+#define SJA1110_NUM_PORTS                              11
+#define SJA1105_MAX_NUM_PORTS                          SJA1110_NUM_PORTS
+#define SJA1105_NUM_TC                                 8
+#define SJA1105ET_FDB_BIN_SIZE                         4
+#define SJA1105_SIZE_CGU_CMD                           4
+#define SJA1105_SIZE_RESET_CMD                         4
+#define SJA1105_SIZE_MDIO_CMD                          4
+#define SJA1105_SIZE_SPI_MSG_HEADER                    4
+#define SJA1105_SIZE_SPI_MSG_MAXLEN                    (64 * 4)
+#define SJA1105_SIZE_DEVICE_ID                         4
+#define SJA1105_SIZE_TABLE_HEADER                      12
+#define SJA1105_SIZE_L2_POLICING_ENTRY                 8
+#define SJA1105_SIZE_VLAN_LOOKUP_ENTRY                 8
+#define SJA1110_SIZE_VLAN_LOOKUP_ENTRY                 12
+#define SJA1105_SIZE_L2_FORWARDING_ENTRY               8
+#define SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY                12
+#define SJA1105_SIZE_XMII_PARAMS_ENTRY                 4
+#define SJA1110_SIZE_XMII_PARAMS_ENTRY                 8
+#define SJA1105ET_SIZE_MAC_CONFIG_ENTRY                        28
+#define SJA1105ET_SIZE_GENERAL_PARAMS_ENTRY            40
+#define SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY              32
+#define SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY          44
+#define SJA1110_SIZE_GENERAL_PARAMS_ENTRY              56
+
+#define SJA1105_MAX_L2_LOOKUP_COUNT                    1024
+#define SJA1105_MAX_L2_POLICING_COUNT                  45
+#define SJA1110_MAX_L2_POLICING_COUNT                  110
+#define SJA1105_MAX_VLAN_LOOKUP_COUNT                  4096
+#define SJA1105_MAX_L2_FORWARDING_COUNT                        13
+#define SJA1110_MAX_L2_FORWARDING_COUNT                        19
+#define SJA1105_MAX_MAC_CONFIG_COUNT                   5
+#define SJA1110_MAX_MAC_CONFIG_COUNT                   11
+#define SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT         1
+#define SJA1105_MAX_GENERAL_PARAMS_COUNT               1
+#define SJA1105_MAX_XMII_PARAMS_COUNT                  1
+
+#define SJA1105_MAX_FRAME_MEMORY                       929
+
+#define SJA1105E_DEVICE_ID                             0x9C00000Cull
+#define SJA1105T_DEVICE_ID                             0x9E00030Eull
+#define SJA1105PR_DEVICE_ID                            0xAF00030Eull
+#define SJA1105QS_DEVICE_ID                            0xAE00030Eull
+#define SJA1110_DEVICE_ID                              0xB700030Full
+
+#define SJA1105ET_PART_NO                              0x9A83
+#define SJA1105P_PART_NO                               0x9A84
+#define SJA1105Q_PART_NO                               0x9A85
+#define SJA1105R_PART_NO                               0x9A86
+#define SJA1105S_PART_NO                               0x9A87
+#define SJA1110A_PART_NO                               0x1110
+#define SJA1110B_PART_NO                               0x1111
+#define SJA1110C_PART_NO                               0x1112
+#define SJA1110D_PART_NO                               0x1113
+
+#define SJA1110_ACU                    0x1c4400
+#define SJA1110_RGU                    0x1c6000
+#define SJA1110_CGU                    0x1c6400
+
+#define SJA1110_SPI_ADDR(x)            ((x) / 4)
+#define SJA1110_ACU_ADDR(x)            (SJA1110_ACU + SJA1110_SPI_ADDR(x))
+#define SJA1110_CGU_ADDR(x)            (SJA1110_CGU + SJA1110_SPI_ADDR(x))
+#define SJA1110_RGU_ADDR(x)            (SJA1110_RGU + SJA1110_SPI_ADDR(x))
+
+#define SJA1105_RSV_ADDR               0xffffffffffffffffull
+
+#define SJA1110_PCS_BANK_REG           SJA1110_SPI_ADDR(0x3fc)
+
+#define DSA_8021Q_DIR_TX               BIT(11)
+#define DSA_8021Q_PORT_SHIFT           0
+#define DSA_8021Q_PORT_MASK            GENMASK(3, 0)
+#define DSA_8021Q_PORT(x)              (((x) << DSA_8021Q_PORT_SHIFT) & \
+                                                DSA_8021Q_PORT_MASK)
+
+#define SJA1105_RATE_MBPS(speed) (((speed) * 64000) / 1000)
+
+/* XPCS registers */
+
+/* VR MII MMD registers offsets */
+#define DW_VR_MII_DIG_CTRL1            0x8000
+#define DW_VR_MII_AN_CTRL              0x8001
+#define DW_VR_MII_DIG_CTRL2            0x80e1
+
+/* VR_MII_DIG_CTRL1 */
+#define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW                BIT(9)
+
+/* VR_MII_DIG_CTRL2 */
+#define DW_VR_MII_DIG_CTRL2_TX_POL_INV         BIT(4)
+
+/* VR_MII_AN_CTRL */
+#define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT      3
+#define DW_VR_MII_TX_CONFIG_MASK               BIT(3)
+#define DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII     0x0
+#define DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT       1
+#define DW_VR_MII_PCS_MODE_MASK                        GENMASK(2, 1)
+#define DW_VR_MII_PCS_MODE_C37_SGMII           0x2
+
+/* PMA registers */
+
+/* LANE_DRIVER1_0 register */
+#define SJA1110_LANE_DRIVER1_0         0x8038
+#define SJA1110_TXDRV(x)               (((x) << 12) & GENMASK(14, 12))
+
+/* LANE_DRIVER2_0 register */
+#define SJA1110_LANE_DRIVER2_0         0x803a
+#define SJA1110_TXDRVTRIM_LSB(x)       ((x) & GENMASK_ULL(15, 0))
+
+/* LANE_DRIVER2_1 register */
+#define SJA1110_LANE_DRIVER2_1         0x803b
+#define SJA1110_LANE_DRIVER2_1_RSV     BIT(9)
+#define SJA1110_TXDRVTRIM_MSB(x)       (((x) & GENMASK_ULL(23, 16)) >> 16)
+
+/* LANE_TRIM register */
+#define SJA1110_LANE_TRIM              0x8040
+#define SJA1110_TXTEN                  BIT(11)
+#define SJA1110_TXRTRIM(x)             (((x) << 8) & GENMASK(10, 8))
+#define SJA1110_TXPLL_BWSEL            BIT(7)
+#define SJA1110_RXTEN                  BIT(6)
+#define SJA1110_RXRTRIM(x)             (((x) << 3) & GENMASK(5, 3))
+#define SJA1110_CDR_GAIN               BIT(2)
+#define SJA1110_ACCOUPLE_RXVCM_EN      BIT(0)
+
+/* LANE_DATAPATH_1 register */
+#define SJA1110_LANE_DATAPATH_1                0x8037
+
+/* POWERDOWN_ENABLE register */
+#define SJA1110_POWERDOWN_ENABLE       0x8041
+#define SJA1110_TXPLL_PD               BIT(12)
+#define SJA1110_TXPD                   BIT(11)
+#define SJA1110_RXPKDETEN              BIT(10)
+#define SJA1110_RXCH_PD                        BIT(9)
+#define SJA1110_RXBIAS_PD              BIT(8)
+#define SJA1110_RESET_SER_EN           BIT(7)
+#define SJA1110_RESET_SER              BIT(6)
+#define SJA1110_RESET_DES              BIT(5)
+#define SJA1110_RCVEN                  BIT(4)
+
+/* RXPLL_CTRL0 register */
+#define SJA1110_RXPLL_CTRL0            0x8065
+#define SJA1110_RXPLL_FBDIV(x)         (((x) << 2) & GENMASK(9, 2))
+
+/* RXPLL_CTRL1 register */
+#define SJA1110_RXPLL_CTRL1            0x8066
+#define SJA1110_RXPLL_REFDIV(x)                ((x) & GENMASK(4, 0))
+
+/* TXPLL_CTRL0 register */
+#define SJA1110_TXPLL_CTRL0            0x806d
+#define SJA1110_TXPLL_FBDIV(x)         ((x) & GENMASK(11, 0))
+
+/* TXPLL_CTRL1 register */
+#define SJA1110_TXPLL_CTRL1            0x806e
+#define SJA1110_TXPLL_REFDIV(x)                ((x) & GENMASK(5, 0))
+
+/* RX_DATA_DETECT register */
+#define SJA1110_RX_DATA_DETECT         0x8045
+
+/* RX_CDR_CTLE register */
+#define SJA1110_RX_CDR_CTLE            0x8042
+
+/* UM10944.pdf Page 11, Table 2. Configuration Blocks */
+enum {
+       BLKID_L2_POLICING                               = 0x06,
+       BLKID_VLAN_LOOKUP                               = 0x07,
+       BLKID_L2_FORWARDING                             = 0x08,
+       BLKID_MAC_CONFIG                                = 0x09,
+       BLKID_L2_FORWARDING_PARAMS                      = 0x0E,
+       BLKID_GENERAL_PARAMS                            = 0x11,
+       BLKID_XMII_PARAMS                               = 0x4E,
+};
+
+enum sja1105_blk_idx {
+       BLK_IDX_L2_POLICING = 0,
+       BLK_IDX_VLAN_LOOKUP,
+       BLK_IDX_L2_FORWARDING,
+       BLK_IDX_MAC_CONFIG,
+       BLK_IDX_L2_FORWARDING_PARAMS,
+       BLK_IDX_GENERAL_PARAMS,
+       BLK_IDX_XMII_PARAMS,
+       BLK_IDX_MAX,
+};
+
+struct sja1105_general_params_entry {
+       u64 mac_fltres1;
+       u64 mac_fltres0;
+       u64 mac_flt1;
+       u64 mac_flt0;
+       u64 casc_port;
+       u64 host_port;
+       u64 mirr_port;
+       u64 tpid;
+       u64 tpid2;
+};
+
+struct sja1105_vlan_lookup_entry {
+       u64 vmemb_port;
+       u64 vlan_bc;
+       u64 tag_port;
+       u64 vlanid;
+       u64 type_entry; /* SJA1110 only */
+};
+
+struct sja1105_l2_forwarding_entry {
+       u64 bc_domain;
+       u64 reach_port;
+       u64 fl_domain;
+};
+
+struct sja1105_l2_forwarding_params_entry {
+       u64 part_spc[SJA1105_NUM_TC];
+};
+
+struct sja1105_l2_policing_entry {
+       u64 sharindx;
+       u64 smax;
+       u64 rate;
+       u64 maxlen;
+       u64 partition;
+};
+
+struct sja1105_mac_config_entry {
+       u64 top[SJA1105_NUM_TC];
+       u64 base[SJA1105_NUM_TC];
+       u64 enabled[SJA1105_NUM_TC];
+       u64 speed;
+       u64 vlanid;
+       u64 egress;
+       u64 ingress;
+};
+
+struct sja1105_xmii_params_entry {
+       u64 phy_mac[SJA1105_MAX_NUM_PORTS];
+       u64 xmii_mode[SJA1105_MAX_NUM_PORTS];
+       u64 special[SJA1105_MAX_NUM_PORTS];
+};
+
+struct sja1105_table_header {
+       u64 block_id;
+       u64 len;
+       u64 crc;
+};
+
+struct sja1105_table_ops {
+       size_t (*packing)(void *buf, void *entry_ptr, enum packing_op op);
+       size_t unpacked_entry_size;
+       size_t packed_entry_size;
+       size_t max_entry_count;
+};
+
+struct sja1105_table {
+       const struct sja1105_table_ops *ops;
+       size_t entry_count;
+       void *entries;
+};
+
+struct sja1105_static_config {
+       u64 device_id;
+       struct sja1105_table tables[BLK_IDX_MAX];
+};
+
+struct sja1105_xpcs_cfg {
+       bool inband_an;
+       int speed;
+};
+
+struct sja1105_private {
+       struct sja1105_static_config static_config;
+       bool rgmii_rx_delay[SJA1105_MAX_NUM_PORTS];
+       bool rgmii_tx_delay[SJA1105_MAX_NUM_PORTS];
+       u16 pvid[SJA1105_MAX_NUM_PORTS];
+       struct sja1105_xpcs_cfg xpcs_cfg[SJA1105_MAX_NUM_PORTS];
+       struct mii_dev *mdio_pcs;
+       const struct sja1105_info *info;
+       struct udevice *dev;
+};
+
+typedef enum {
+       SPI_READ = 0,
+       SPI_WRITE = 1,
+} sja1105_spi_rw_mode_t;
+
+typedef enum {
+       XMII_MAC = 0,
+       XMII_PHY = 1,
+} sja1105_mii_role_t;
+
+typedef enum {
+       XMII_MODE_MII           = 0,
+       XMII_MODE_RMII          = 1,
+       XMII_MODE_RGMII         = 2,
+       XMII_MODE_SGMII         = 3,
+} sja1105_phy_interface_t;
+
+enum {
+       SJA1105_SPEED_AUTO,
+       SJA1105_SPEED_10MBPS,
+       SJA1105_SPEED_100MBPS,
+       SJA1105_SPEED_1000MBPS,
+       SJA1105_SPEED_MAX,
+};
+
+enum sja1110_vlan_type {
+       SJA1110_VLAN_INVALID = 0,
+       SJA1110_VLAN_C_TAG = 1, /* Single inner VLAN tag */
+       SJA1110_VLAN_S_TAG = 2, /* Single outer VLAN tag */
+       SJA1110_VLAN_D_TAG = 3, /* Double tagged, use outer tag for lookup */
+};
+
+/* Keeps the different addresses between E/T and P/Q/R/S */
+struct sja1105_regs {
+       u64 device_id;
+       u64 prod_id;
+       u64 status;
+       u64 port_control;
+       u64 rgu;
+       u64 config;
+       u64 rmii_pll1;
+       u64 pad_mii_tx[SJA1105_MAX_NUM_PORTS];
+       u64 pad_mii_rx[SJA1105_MAX_NUM_PORTS];
+       u64 pad_mii_id[SJA1105_MAX_NUM_PORTS];
+       u64 cgu_idiv[SJA1105_MAX_NUM_PORTS];
+       u64 mii_tx_clk[SJA1105_MAX_NUM_PORTS];
+       u64 mii_rx_clk[SJA1105_MAX_NUM_PORTS];
+       u64 mii_ext_tx_clk[SJA1105_MAX_NUM_PORTS];
+       u64 mii_ext_rx_clk[SJA1105_MAX_NUM_PORTS];
+       u64 rgmii_tx_clk[SJA1105_MAX_NUM_PORTS];
+       u64 rmii_ref_clk[SJA1105_MAX_NUM_PORTS];
+       u64 rmii_ext_tx_clk[SJA1105_MAX_NUM_PORTS];
+       u64 pcs_base[SJA1105_MAX_NUM_PORTS];
+};
+
+struct sja1105_info {
+       u64 device_id;
+       u64 part_no;
+       const struct sja1105_table_ops *static_ops;
+       const struct sja1105_regs *regs;
+       int (*reset_cmd)(struct sja1105_private *priv);
+       int (*setup_rgmii_delay)(struct sja1105_private *priv, int port);
+       int (*pcs_mdio_read)(struct mii_dev *bus, int phy, int mmd, int reg);
+       int (*pcs_mdio_write)(struct mii_dev *bus, int phy, int mmd, int reg,
+                             u16 val);
+       int (*pma_config)(struct sja1105_private *priv, int port);
+       const char *name;
+       bool supports_mii[SJA1105_MAX_NUM_PORTS];
+       bool supports_rmii[SJA1105_MAX_NUM_PORTS];
+       bool supports_rgmii[SJA1105_MAX_NUM_PORTS];
+       bool supports_sgmii[SJA1105_MAX_NUM_PORTS];
+       const u64 port_speed[SJA1105_SPEED_MAX];
+};
+
+struct sja1105_chunk {
+       u8      *buf;
+       size_t  len;
+       u64     reg_addr;
+};
+
+struct sja1105_spi_message {
+       u64 access;
+       u64 read_count;
+       u64 address;
+};
+
+/* Common structure for CFG_PAD_MIIx_RX and CFG_PAD_MIIx_TX */
+struct sja1105_cfg_pad_mii {
+       u64 d32_os;
+       u64 d32_ih;
+       u64 d32_ipud;
+       u64 d10_ih;
+       u64 d10_os;
+       u64 d10_ipud;
+       u64 ctrl_os;
+       u64 ctrl_ih;
+       u64 ctrl_ipud;
+       u64 clk_os;
+       u64 clk_ih;
+       u64 clk_ipud;
+};
+
+struct sja1105_cfg_pad_mii_id {
+       u64 rxc_stable_ovr;
+       u64 rxc_delay;
+       u64 rxc_bypass;
+       u64 rxc_pd;
+       u64 txc_stable_ovr;
+       u64 txc_delay;
+       u64 txc_bypass;
+       u64 txc_pd;
+};
+
+struct sja1105_cgu_idiv {
+       u64 clksrc;
+       u64 autoblock;
+       u64 idiv;
+       u64 pd;
+};
+
+struct sja1105_cgu_pll_ctrl {
+       u64 pllclksrc;
+       u64 msel;
+       u64 autoblock;
+       u64 psel;
+       u64 direct;
+       u64 fbsel;
+       u64 bypass;
+       u64 pd;
+};
+
+enum {
+       CLKSRC_MII0_TX_CLK      = 0x00,
+       CLKSRC_MII0_RX_CLK      = 0x01,
+       CLKSRC_MII1_TX_CLK      = 0x02,
+       CLKSRC_MII1_RX_CLK      = 0x03,
+       CLKSRC_MII2_TX_CLK      = 0x04,
+       CLKSRC_MII2_RX_CLK      = 0x05,
+       CLKSRC_MII3_TX_CLK      = 0x06,
+       CLKSRC_MII3_RX_CLK      = 0x07,
+       CLKSRC_MII4_TX_CLK      = 0x08,
+       CLKSRC_MII4_RX_CLK      = 0x09,
+       CLKSRC_PLL0             = 0x0B,
+       CLKSRC_PLL1             = 0x0E,
+       CLKSRC_IDIV0            = 0x11,
+       CLKSRC_IDIV1            = 0x12,
+       CLKSRC_IDIV2            = 0x13,
+       CLKSRC_IDIV3            = 0x14,
+       CLKSRC_IDIV4            = 0x15,
+};
+
+struct sja1105_cgu_mii_ctrl {
+       u64 clksrc;
+       u64 autoblock;
+       u64 pd;
+};
+
+static int get_reverse_lsw32_offset(int offset, size_t len)
+{
+       int closest_multiple_of_4;
+       int word_index;
+
+       word_index = offset / 4;
+       closest_multiple_of_4 = word_index * 4;
+       offset -= closest_multiple_of_4;
+       word_index = (len / 4) - word_index - 1;
+       return word_index * 4 + offset;
+}
+
+/* Simplified version of the "packing" function from Linux, adapted
+ * to support only sja1105's quirk: QUIRK_LSW32_IS_FIRST
+ */
+static void sja1105_packing(void *pbuf, u64 *uval, int startbit, int endbit,
+                           size_t pbuflen, enum packing_op op)
+{
+       int plogical_first_u8, plogical_last_u8, box;
+
+       if (op == UNPACK)
+               *uval = 0;
+
+       plogical_first_u8 = startbit / 8;
+       plogical_last_u8  = endbit / 8;
+
+       for (box = plogical_first_u8; box >= plogical_last_u8; box--) {
+               int box_start_bit, box_end_bit, box_addr;
+               int proj_start_bit, proj_end_bit;
+               u64 proj_mask;
+               u8  box_mask;
+
+               if (box == plogical_first_u8)
+                       box_start_bit = startbit % 8;
+               else
+                       box_start_bit = 7;
+               if (box == plogical_last_u8)
+                       box_end_bit = endbit % 8;
+               else
+                       box_end_bit = 0;
+
+               proj_start_bit = ((box * 8) + box_start_bit) - endbit;
+               proj_end_bit   = ((box * 8) + box_end_bit) - endbit;
+               proj_mask = GENMASK_ULL(proj_start_bit, proj_end_bit);
+               box_mask  = GENMASK_ULL(box_start_bit, box_end_bit);
+
+               box_addr = pbuflen - box - 1;
+               box_addr = get_reverse_lsw32_offset(box_addr, pbuflen);
+
+               if (op == UNPACK) {
+                       u64 pval;
+
+                       /* Read from pbuf, write to uval */
+                       pval = ((u8 *)pbuf)[box_addr] & box_mask;
+
+                       pval >>= box_end_bit;
+                       pval <<= proj_end_bit;
+                       *uval &= ~proj_mask;
+                       *uval |= pval;
+               } else {
+                       u64 pval;
+
+                       /* Write to pbuf, read from uval */
+                       pval = (*uval) & proj_mask;
+                       pval >>= proj_end_bit;
+
+                       pval <<= box_end_bit;
+                       ((u8 *)pbuf)[box_addr] &= ~box_mask;
+                       ((u8 *)pbuf)[box_addr] |= pval;
+               }
+       }
+}
+
+static u32 crc32_add(u32 crc, u8 byte)
+{
+       u32 byte32 = bitrev32(byte);
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               if ((crc ^ byte32) & BIT(31)) {
+                       crc <<= 1;
+                       crc ^= ETHER_CRC32_POLY;
+               } else {
+                       crc <<= 1;
+               }
+               byte32 <<= 1;
+       }
+       return crc;
+}
+
+/* Little-endian Ethernet CRC32 of data packed as big-endian u32 words */
+static uint32_t sja1105_crc32(void *buf, size_t len)
+{
+       unsigned int i;
+       u64 chunk;
+       u32 crc;
+
+       /* seed */
+       crc = 0xFFFFFFFF;
+       for (i = 0; i < len; i += 4) {
+               sja1105_packing(buf + i, &chunk, 31, 0, 4, UNPACK);
+               crc = crc32_add(crc, chunk & 0xFF);
+               crc = crc32_add(crc, (chunk >> 8) & 0xFF);
+               crc = crc32_add(crc, (chunk >> 16) & 0xFF);
+               crc = crc32_add(crc, (chunk >> 24) & 0xFF);
+       }
+       return bitrev32(~crc);
+}
+
+static void sja1105_spi_message_pack(void *buf, struct sja1105_spi_message *msg)
+{
+       const int size = SJA1105_SIZE_SPI_MSG_HEADER;
+
+       memset(buf, 0, size);
+
+       sja1105_packing(buf, &msg->access,     31, 31, size, PACK);
+       sja1105_packing(buf, &msg->read_count, 30, 25, size, PACK);
+       sja1105_packing(buf, &msg->address,    24,  4, size, PACK);
+}
+
+static int sja1105_xfer_buf(const struct sja1105_private *priv,
+                           sja1105_spi_rw_mode_t rw, u64 reg_addr,
+                           u8 *buf, size_t len)
+{
+       struct udevice *dev = priv->dev;
+       struct sja1105_chunk chunk = {
+               .len = min_t(size_t, len, SJA1105_SIZE_SPI_MSG_MAXLEN),
+               .reg_addr = reg_addr,
+               .buf = buf,
+       };
+       int num_chunks;
+       int rc, i;
+
+       rc = dm_spi_claim_bus(dev);
+       if (rc)
+               return rc;
+
+       num_chunks = DIV_ROUND_UP(len, SJA1105_SIZE_SPI_MSG_MAXLEN);
+
+       for (i = 0; i < num_chunks; i++) {
+               u8 hdr_buf[SJA1105_SIZE_SPI_MSG_HEADER];
+               struct sja1105_spi_message msg;
+               u8 *rx_buf = NULL;
+               u8 *tx_buf = NULL;
+
+               /* Populate the transfer's header buffer */
+               msg.address = chunk.reg_addr;
+               msg.access = rw;
+               if (rw == SPI_READ)
+                       msg.read_count = chunk.len / 4;
+               else
+                       /* Ignored */
+                       msg.read_count = 0;
+               sja1105_spi_message_pack(hdr_buf, &msg);
+               rc = dm_spi_xfer(dev, SJA1105_SIZE_SPI_MSG_HEADER * 8, hdr_buf,
+                                NULL, SPI_XFER_BEGIN);
+               if (rc)
+                       goto out;
+
+               /* Populate the transfer's data buffer */
+               if (rw == SPI_READ)
+                       rx_buf = chunk.buf;
+               else
+                       tx_buf = chunk.buf;
+               rc = dm_spi_xfer(dev, chunk.len * 8, tx_buf, rx_buf,
+                                SPI_XFER_END);
+               if (rc)
+                       goto out;
+
+               /* Calculate next chunk */
+               chunk.buf += chunk.len;
+               chunk.reg_addr += chunk.len / 4;
+               chunk.len = min_t(size_t, (ptrdiff_t)(buf + len - chunk.buf),
+                                 SJA1105_SIZE_SPI_MSG_MAXLEN);
+       }
+
+out:
+       dm_spi_release_bus(dev);
+
+       return rc;
+}
+
+static int sja1105et_reset_cmd(struct sja1105_private *priv)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       u8 packed_buf[SJA1105_SIZE_RESET_CMD] = {0};
+       const int size = SJA1105_SIZE_RESET_CMD;
+       u64 cold_rst = 1;
+
+       sja1105_packing(packed_buf, &cold_rst, 3, 3, size, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgu, packed_buf,
+                               SJA1105_SIZE_RESET_CMD);
+}
+
+static int sja1105pqrs_reset_cmd(struct sja1105_private *priv)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       u8 packed_buf[SJA1105_SIZE_RESET_CMD] = {0};
+       const int size = SJA1105_SIZE_RESET_CMD;
+       u64 cold_rst = 1;
+
+       sja1105_packing(packed_buf, &cold_rst, 2, 2, size, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgu, packed_buf,
+                               SJA1105_SIZE_RESET_CMD);
+}
+
+static int sja1110_reset_cmd(struct sja1105_private *priv)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       u8 packed_buf[SJA1105_SIZE_RESET_CMD] = {0};
+       const int size = SJA1105_SIZE_RESET_CMD;
+       u64 switch_rst = 1;
+
+       /* Only reset the switch core.
+        * A full cold reset would re-enable the BASE_MCSS_CLOCK PLL which
+        * would turn on the microcontroller, potentially letting it execute
+        * code which could interfere with our configuration.
+        */
+       sja1105_packing(packed_buf, &switch_rst, 20, 20, size, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgu, packed_buf,
+                               SJA1105_SIZE_RESET_CMD);
+}
+
+static size_t sja1105et_general_params_entry_packing(void *buf, void *entry_ptr,
+                                                    enum packing_op op)
+{
+       const size_t size = SJA1105ET_SIZE_GENERAL_PARAMS_ENTRY;
+       struct sja1105_general_params_entry *entry = entry_ptr;
+
+       sja1105_packing(buf, &entry->mac_fltres1, 311, 264, size, op);
+       sja1105_packing(buf, &entry->mac_fltres0, 263, 216, size, op);
+       sja1105_packing(buf, &entry->mac_flt1,    215, 168, size, op);
+       sja1105_packing(buf, &entry->mac_flt0,    167, 120, size, op);
+       sja1105_packing(buf, &entry->casc_port,   115, 113, size, op);
+       sja1105_packing(buf, &entry->host_port,   112, 110, size, op);
+       sja1105_packing(buf, &entry->mirr_port,   109, 107, size, op);
+       sja1105_packing(buf, &entry->tpid,         42,  27, size, op);
+       sja1105_packing(buf, &entry->tpid2,        25,  10, size, op);
+       return size;
+}
+
+static size_t sja1110_general_params_entry_packing(void *buf, void *entry_ptr,
+                                                  enum packing_op op)
+{
+       struct sja1105_general_params_entry *entry = entry_ptr;
+       const size_t size = SJA1110_SIZE_GENERAL_PARAMS_ENTRY;
+
+       sja1105_packing(buf, &entry->mac_fltres1,  438, 391, size, op);
+       sja1105_packing(buf, &entry->mac_fltres0,  390, 343, size, op);
+       sja1105_packing(buf, &entry->mac_flt1,     342, 295, size, op);
+       sja1105_packing(buf, &entry->mac_flt0,     294, 247, size, op);
+       sja1105_packing(buf, &entry->casc_port,    242, 232, size, op);
+       sja1105_packing(buf, &entry->host_port,    231, 228, size, op);
+       sja1105_packing(buf, &entry->mirr_port,    227, 224, size, op);
+       sja1105_packing(buf, &entry->tpid2,        159, 144, size, op);
+       sja1105_packing(buf, &entry->tpid,         142, 127, size, op);
+       return size;
+}
+
+static size_t
+sja1105pqrs_general_params_entry_packing(void *buf, void *entry_ptr,
+                                        enum packing_op op)
+{
+       const size_t size = SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY;
+       struct sja1105_general_params_entry *entry = entry_ptr;
+
+       sja1105_packing(buf, &entry->mac_fltres1, 343, 296, size, op);
+       sja1105_packing(buf, &entry->mac_fltres0, 295, 248, size, op);
+       sja1105_packing(buf, &entry->mac_flt1,    247, 200, size, op);
+       sja1105_packing(buf, &entry->mac_flt0,    199, 152, size, op);
+       sja1105_packing(buf, &entry->casc_port,   147, 145, size, op);
+       sja1105_packing(buf, &entry->host_port,   144, 142, size, op);
+       sja1105_packing(buf, &entry->mirr_port,   141, 139, size, op);
+       sja1105_packing(buf, &entry->tpid,         74,  59, size, op);
+       sja1105_packing(buf, &entry->tpid2,        57,  42, size, op);
+       return size;
+}
+
+static size_t
+sja1105_l2_forwarding_params_entry_packing(void *buf, void *entry_ptr,
+                                          enum packing_op op)
+{
+       const size_t size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY;
+       struct sja1105_l2_forwarding_params_entry *entry = entry_ptr;
+       int offset, i;
+
+       for (i = 0, offset = 13; i < SJA1105_NUM_TC; i++, offset += 10)
+               sja1105_packing(buf, &entry->part_spc[i],
+                               offset + 9, offset + 0, size, op);
+       return size;
+}
+
+static size_t
+sja1110_l2_forwarding_params_entry_packing(void *buf, void *entry_ptr,
+                                          enum packing_op op)
+{
+       struct sja1105_l2_forwarding_params_entry *entry = entry_ptr;
+       const size_t size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY;
+       int offset, i;
+
+       for (i = 0, offset = 5; i < 8; i++, offset += 11)
+               sja1105_packing(buf, &entry->part_spc[i],
+                               offset + 10, offset + 0, size, op);
+       return size;
+}
+
+static size_t sja1105_l2_forwarding_entry_packing(void *buf, void *entry_ptr,
+                                                 enum packing_op op)
+{
+       const size_t size = SJA1105_SIZE_L2_FORWARDING_ENTRY;
+       struct sja1105_l2_forwarding_entry *entry = entry_ptr;
+
+       sja1105_packing(buf, &entry->bc_domain,  63, 59, size, op);
+       sja1105_packing(buf, &entry->reach_port, 58, 54, size, op);
+       sja1105_packing(buf, &entry->fl_domain,  53, 49, size, op);
+       return size;
+}
+
+static size_t sja1110_l2_forwarding_entry_packing(void *buf, void *entry_ptr,
+                                                 enum packing_op op)
+{
+       struct sja1105_l2_forwarding_entry *entry = entry_ptr;
+       const size_t size = SJA1105_SIZE_L2_FORWARDING_ENTRY;
+
+       sja1105_packing(buf, &entry->bc_domain,  63, 53, size, op);
+       sja1105_packing(buf, &entry->reach_port, 52, 42, size, op);
+       sja1105_packing(buf, &entry->fl_domain,  41, 31, size, op);
+       return size;
+}
+
+static size_t sja1105_l2_policing_entry_packing(void *buf, void *entry_ptr,
+                                               enum packing_op op)
+{
+       struct sja1105_l2_policing_entry *entry = entry_ptr;
+       const size_t size = SJA1105_SIZE_L2_POLICING_ENTRY;
+
+       sja1105_packing(buf, &entry->sharindx,  63, 58, size, op);
+       sja1105_packing(buf, &entry->smax,      57, 42, size, op);
+       sja1105_packing(buf, &entry->rate,      41, 26, size, op);
+       sja1105_packing(buf, &entry->maxlen,    25, 15, size, op);
+       sja1105_packing(buf, &entry->partition, 14, 12, size, op);
+       return size;
+}
+
+static size_t sja1110_l2_policing_entry_packing(void *buf, void *entry_ptr,
+                                               enum packing_op op)
+{
+       struct sja1105_l2_policing_entry *entry = entry_ptr;
+       const size_t size = SJA1105_SIZE_L2_POLICING_ENTRY;
+
+       sja1105_packing(buf, &entry->sharindx, 63, 57, size, op);
+       sja1105_packing(buf, &entry->smax,     56, 39, size, op);
+       sja1105_packing(buf, &entry->rate,     38, 21, size, op);
+       sja1105_packing(buf, &entry->maxlen,   20, 10, size, op);
+       sja1105_packing(buf, &entry->partition, 9,  7, size, op);
+       return size;
+}
+
+static size_t sja1105et_mac_config_entry_packing(void *buf, void *entry_ptr,
+                                                enum packing_op op)
+{
+       const size_t size = SJA1105ET_SIZE_MAC_CONFIG_ENTRY;
+       struct sja1105_mac_config_entry *entry = entry_ptr;
+       int offset, i;
+
+       for (i = 0, offset = 72; i < SJA1105_NUM_TC; i++, offset += 19) {
+               sja1105_packing(buf, &entry->enabled[i],
+                               offset +  0, offset +  0, size, op);
+               sja1105_packing(buf, &entry->base[i],
+                               offset +  9, offset +  1, size, op);
+               sja1105_packing(buf, &entry->top[i],
+                               offset + 18, offset + 10, size, op);
+       }
+       sja1105_packing(buf, &entry->speed,     66, 65, size, op);
+       sja1105_packing(buf, &entry->vlanid,    21, 10, size, op);
+       sja1105_packing(buf, &entry->egress,     2,  2, size, op);
+       sja1105_packing(buf, &entry->ingress,    1,  1, size, op);
+       return size;
+}
+
+static size_t sja1105pqrs_mac_config_entry_packing(void *buf, void *entry_ptr,
+                                                  enum packing_op op)
+{
+       const size_t size = SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
+       struct sja1105_mac_config_entry *entry = entry_ptr;
+       int offset, i;
+
+       for (i = 0, offset = 104; i < SJA1105_NUM_TC; i++, offset += 19) {
+               sja1105_packing(buf, &entry->enabled[i],
+                               offset +  0, offset +  0, size, op);
+               sja1105_packing(buf, &entry->base[i],
+                               offset +  9, offset +  1, size, op);
+               sja1105_packing(buf, &entry->top[i],
+                               offset + 18, offset + 10, size, op);
+       }
+       sja1105_packing(buf, &entry->speed,      98, 97, size, op);
+       sja1105_packing(buf, &entry->vlanid,     53, 42, size, op);
+       sja1105_packing(buf, &entry->egress,     32, 32, size, op);
+       sja1105_packing(buf, &entry->ingress,    31, 31, size, op);
+       return size;
+}
+
+static size_t sja1110_mac_config_entry_packing(void *buf, void *entry_ptr,
+                                              enum packing_op op)
+{
+       const size_t size = SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY;
+       struct sja1105_mac_config_entry *entry = entry_ptr;
+       int offset, i;
+
+       for (i = 0, offset = 104; i < 8; i++, offset += 19) {
+               sja1105_packing(buf, &entry->enabled[i],
+                               offset +  0, offset +  0, size, op);
+               sja1105_packing(buf, &entry->base[i],
+                               offset +  9, offset +  1, size, op);
+               sja1105_packing(buf, &entry->top[i],
+                               offset + 18, offset + 10, size, op);
+       }
+       sja1105_packing(buf, &entry->speed,      98, 96, size, op);
+       sja1105_packing(buf, &entry->vlanid,     52, 41, size, op);
+       sja1105_packing(buf, &entry->egress,     31, 31, size, op);
+       sja1105_packing(buf, &entry->ingress,    30, 30, size, op);
+       return size;
+}
+
+static size_t sja1105_vlan_lookup_entry_packing(void *buf, void *entry_ptr,
+                                               enum packing_op op)
+{
+       const size_t size = SJA1105_SIZE_VLAN_LOOKUP_ENTRY;
+       struct sja1105_vlan_lookup_entry *entry = entry_ptr;
+
+       sja1105_packing(buf, &entry->vmemb_port, 53, 49, size, op);
+       sja1105_packing(buf, &entry->vlan_bc,    48, 44, size, op);
+       sja1105_packing(buf, &entry->tag_port,   43, 39, size, op);
+       sja1105_packing(buf, &entry->vlanid,     38, 27, size, op);
+       return size;
+}
+
+static size_t sja1110_vlan_lookup_entry_packing(void *buf, void *entry_ptr,
+                                               enum packing_op op)
+{
+       struct sja1105_vlan_lookup_entry *entry = entry_ptr;
+       const size_t size = SJA1110_SIZE_VLAN_LOOKUP_ENTRY;
+
+       sja1105_packing(buf, &entry->vmemb_port, 73, 63, size, op);
+       sja1105_packing(buf, &entry->vlan_bc,    62, 52, size, op);
+       sja1105_packing(buf, &entry->tag_port,   51, 41, size, op);
+       sja1105_packing(buf, &entry->type_entry, 40, 39, size, op);
+       sja1105_packing(buf, &entry->vlanid,     38, 27, size, op);
+       return size;
+}
+
+static size_t sja1105_xmii_params_entry_packing(void *buf, void *entry_ptr,
+                                               enum packing_op op)
+{
+       const size_t size = SJA1105_SIZE_XMII_PARAMS_ENTRY;
+       struct sja1105_xmii_params_entry *entry = entry_ptr;
+       int offset, i;
+
+       for (i = 0, offset = 17; i < SJA1105_NUM_PORTS; i++, offset += 3) {
+               sja1105_packing(buf, &entry->xmii_mode[i],
+                               offset + 1, offset + 0, size, op);
+               sja1105_packing(buf, &entry->phy_mac[i],
+                               offset + 2, offset + 2, size, op);
+       }
+       return size;
+}
+
+static size_t sja1110_xmii_params_entry_packing(void *buf, void *entry_ptr,
+                                               enum packing_op op)
+{
+       const size_t size = SJA1110_SIZE_XMII_PARAMS_ENTRY;
+       struct sja1105_xmii_params_entry *entry = entry_ptr;
+       int offset, i;
+
+       for (i = 0, offset = 20; i < SJA1110_NUM_PORTS; i++, offset += 4) {
+               sja1105_packing(buf, &entry->xmii_mode[i],
+                               offset + 1, offset + 0, size, op);
+               sja1105_packing(buf, &entry->phy_mac[i],
+                               offset + 2, offset + 2, size, op);
+               sja1105_packing(buf, &entry->special[i],
+                               offset + 3, offset + 3, size, op);
+       }
+       return size;
+}
+
+static size_t sja1105_table_header_packing(void *buf, void *entry_ptr,
+                                          enum packing_op op)
+{
+       const size_t size = SJA1105_SIZE_TABLE_HEADER;
+       struct sja1105_table_header *entry = entry_ptr;
+
+       sja1105_packing(buf, &entry->block_id, 31, 24, size, op);
+       sja1105_packing(buf, &entry->len,      55, 32, size, op);
+       sja1105_packing(buf, &entry->crc,      95, 64, size, op);
+       return size;
+}
+
+static void
+sja1105_table_header_pack_with_crc(void *buf, struct sja1105_table_header *hdr)
+{
+       /* First pack the table as-is, then calculate the CRC, and
+        * finally put the proper CRC into the packed buffer
+        */
+       memset(buf, 0, SJA1105_SIZE_TABLE_HEADER);
+       sja1105_table_header_packing(buf, hdr, PACK);
+       hdr->crc = sja1105_crc32(buf, SJA1105_SIZE_TABLE_HEADER - 4);
+       sja1105_packing(buf + SJA1105_SIZE_TABLE_HEADER - 4, &hdr->crc,
+                       31, 0, 4, PACK);
+}
+
+static void sja1105_table_write_crc(u8 *table_start, u8 *crc_ptr)
+{
+       u64 computed_crc;
+       int len_bytes;
+
+       len_bytes = (uintptr_t)(crc_ptr - table_start);
+       computed_crc = sja1105_crc32(table_start, len_bytes);
+       sja1105_packing(crc_ptr, &computed_crc, 31, 0, 4, PACK);
+}
+
+/* The block IDs that the switches support are unfortunately sparse, so keep a
+ * mapping table to "block indices" and translate back and forth.
+ */
+static const u64 blk_id_map[BLK_IDX_MAX] = {
+       [BLK_IDX_L2_POLICING] = BLKID_L2_POLICING,
+       [BLK_IDX_VLAN_LOOKUP] = BLKID_VLAN_LOOKUP,
+       [BLK_IDX_L2_FORWARDING] = BLKID_L2_FORWARDING,
+       [BLK_IDX_MAC_CONFIG] = BLKID_MAC_CONFIG,
+       [BLK_IDX_L2_FORWARDING_PARAMS] = BLKID_L2_FORWARDING_PARAMS,
+       [BLK_IDX_GENERAL_PARAMS] = BLKID_GENERAL_PARAMS,
+       [BLK_IDX_XMII_PARAMS] = BLKID_XMII_PARAMS,
+};
+
+static void
+sja1105_static_config_pack(void *buf, struct sja1105_static_config *config)
+{
+       struct sja1105_table_header header = {0};
+       enum sja1105_blk_idx i;
+       u8 *p = buf;
+       int j;
+
+       sja1105_packing(p, &config->device_id, 31, 0, 4, PACK);
+       p += SJA1105_SIZE_DEVICE_ID;
+
+       for (i = 0; i < BLK_IDX_MAX; i++) {
+               const struct sja1105_table *table;
+               u8 *table_start;
+
+               table = &config->tables[i];
+               if (!table->entry_count)
+                       continue;
+
+               header.block_id = blk_id_map[i];
+               header.len = table->entry_count *
+                            table->ops->packed_entry_size / 4;
+               sja1105_table_header_pack_with_crc(p, &header);
+               p += SJA1105_SIZE_TABLE_HEADER;
+               table_start = p;
+               for (j = 0; j < table->entry_count; j++) {
+                       u8 *entry_ptr = table->entries;
+
+                       entry_ptr += j * table->ops->unpacked_entry_size;
+                       memset(p, 0, table->ops->packed_entry_size);
+                       table->ops->packing(p, entry_ptr, PACK);
+                       p += table->ops->packed_entry_size;
+               }
+               sja1105_table_write_crc(table_start, p);
+               p += 4;
+       }
+       /* Final header:
+        * Block ID does not matter
+        * Length of 0 marks that header is final
+        * CRC will be replaced on-the-fly
+        */
+       header.block_id = 0;
+       header.len = 0;
+       header.crc = 0xDEADBEEF;
+       memset(p, 0, SJA1105_SIZE_TABLE_HEADER);
+       sja1105_table_header_packing(p, &header, PACK);
+}
+
+static size_t
+sja1105_static_config_get_length(const struct sja1105_static_config *config)
+{
+       unsigned int header_count;
+       enum sja1105_blk_idx i;
+       unsigned int sum;
+
+       /* Ending header */
+       header_count = 1;
+       sum = SJA1105_SIZE_DEVICE_ID;
+
+       /* Tables (headers and entries) */
+       for (i = 0; i < BLK_IDX_MAX; i++) {
+               const struct sja1105_table *table;
+
+               table = &config->tables[i];
+               if (table->entry_count)
+                       header_count++;
+
+               sum += table->ops->packed_entry_size * table->entry_count;
+       }
+       /* Headers have an additional CRC at the end */
+       sum += header_count * (SJA1105_SIZE_TABLE_HEADER + 4);
+       /* Last header does not have an extra CRC because there is no data */
+       sum -= 4;
+
+       return sum;
+}
+
+/* Compatibility matrices */
+static const struct sja1105_table_ops sja1105et_table_ops[BLK_IDX_MAX] = {
+       [BLK_IDX_L2_POLICING] = {
+               .packing = sja1105_l2_policing_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_l2_policing_entry),
+               .packed_entry_size = SJA1105_SIZE_L2_POLICING_ENTRY,
+               .max_entry_count = SJA1105_MAX_L2_POLICING_COUNT,
+       },
+       [BLK_IDX_VLAN_LOOKUP] = {
+               .packing = sja1105_vlan_lookup_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_vlan_lookup_entry),
+               .packed_entry_size = SJA1105_SIZE_VLAN_LOOKUP_ENTRY,
+               .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
+       },
+       [BLK_IDX_L2_FORWARDING] = {
+               .packing = sja1105_l2_forwarding_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_l2_forwarding_entry),
+               .packed_entry_size = SJA1105_SIZE_L2_FORWARDING_ENTRY,
+               .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
+       },
+       [BLK_IDX_MAC_CONFIG] = {
+               .packing = sja1105et_mac_config_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_mac_config_entry),
+               .packed_entry_size = SJA1105ET_SIZE_MAC_CONFIG_ENTRY,
+               .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
+       },
+       [BLK_IDX_L2_FORWARDING_PARAMS] = {
+               .packing = sja1105_l2_forwarding_params_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_l2_forwarding_params_entry),
+               .packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
+               .max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
+       },
+       [BLK_IDX_GENERAL_PARAMS] = {
+               .packing = sja1105et_general_params_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
+               .packed_entry_size = SJA1105ET_SIZE_GENERAL_PARAMS_ENTRY,
+               .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
+       },
+       [BLK_IDX_XMII_PARAMS] = {
+               .packing = sja1105_xmii_params_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_xmii_params_entry),
+               .packed_entry_size = SJA1105_SIZE_XMII_PARAMS_ENTRY,
+               .max_entry_count = SJA1105_MAX_XMII_PARAMS_COUNT,
+       },
+};
+
+static const struct sja1105_table_ops sja1105pqrs_table_ops[BLK_IDX_MAX] = {
+       [BLK_IDX_L2_POLICING] = {
+               .packing = sja1105_l2_policing_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_l2_policing_entry),
+               .packed_entry_size = SJA1105_SIZE_L2_POLICING_ENTRY,
+               .max_entry_count = SJA1105_MAX_L2_POLICING_COUNT,
+       },
+       [BLK_IDX_VLAN_LOOKUP] = {
+               .packing = sja1105_vlan_lookup_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_vlan_lookup_entry),
+               .packed_entry_size = SJA1105_SIZE_VLAN_LOOKUP_ENTRY,
+               .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
+       },
+       [BLK_IDX_L2_FORWARDING] = {
+               .packing = sja1105_l2_forwarding_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_l2_forwarding_entry),
+               .packed_entry_size = SJA1105_SIZE_L2_FORWARDING_ENTRY,
+               .max_entry_count = SJA1105_MAX_L2_FORWARDING_COUNT,
+       },
+       [BLK_IDX_MAC_CONFIG] = {
+               .packing = sja1105pqrs_mac_config_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_mac_config_entry),
+               .packed_entry_size = SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY,
+               .max_entry_count = SJA1105_MAX_MAC_CONFIG_COUNT,
+       },
+       [BLK_IDX_L2_FORWARDING_PARAMS] = {
+               .packing = sja1105_l2_forwarding_params_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_l2_forwarding_params_entry),
+               .packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
+               .max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
+       },
+       [BLK_IDX_GENERAL_PARAMS] = {
+               .packing = sja1105pqrs_general_params_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
+               .packed_entry_size = SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY,
+               .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
+       },
+       [BLK_IDX_XMII_PARAMS] = {
+               .packing = sja1105_xmii_params_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_xmii_params_entry),
+               .packed_entry_size = SJA1105_SIZE_XMII_PARAMS_ENTRY,
+               .max_entry_count = SJA1105_MAX_XMII_PARAMS_COUNT,
+       },
+};
+
+static const struct sja1105_table_ops sja1110_table_ops[BLK_IDX_MAX] = {
+       [BLK_IDX_L2_POLICING] = {
+               .packing = sja1110_l2_policing_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_l2_policing_entry),
+               .packed_entry_size = SJA1105_SIZE_L2_POLICING_ENTRY,
+               .max_entry_count = SJA1110_MAX_L2_POLICING_COUNT,
+       },
+       [BLK_IDX_VLAN_LOOKUP] = {
+               .packing = sja1110_vlan_lookup_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_vlan_lookup_entry),
+               .packed_entry_size = SJA1110_SIZE_VLAN_LOOKUP_ENTRY,
+               .max_entry_count = SJA1105_MAX_VLAN_LOOKUP_COUNT,
+       },
+       [BLK_IDX_L2_FORWARDING] = {
+               .packing = sja1110_l2_forwarding_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_l2_forwarding_entry),
+               .packed_entry_size = SJA1105_SIZE_L2_FORWARDING_ENTRY,
+               .max_entry_count = SJA1110_MAX_L2_FORWARDING_COUNT,
+       },
+       [BLK_IDX_MAC_CONFIG] = {
+               .packing = sja1110_mac_config_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_mac_config_entry),
+               .packed_entry_size = SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY,
+               .max_entry_count = SJA1110_MAX_MAC_CONFIG_COUNT,
+       },
+       [BLK_IDX_L2_FORWARDING_PARAMS] = {
+               .packing = sja1110_l2_forwarding_params_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_l2_forwarding_params_entry),
+               .packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
+               .max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
+       },
+       [BLK_IDX_GENERAL_PARAMS] = {
+               .packing = sja1110_general_params_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
+               .packed_entry_size = SJA1110_SIZE_GENERAL_PARAMS_ENTRY,
+               .max_entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT,
+       },
+       [BLK_IDX_XMII_PARAMS] = {
+               .packing = sja1110_xmii_params_entry_packing,
+               .unpacked_entry_size = sizeof(struct sja1105_xmii_params_entry),
+               .packed_entry_size = SJA1110_SIZE_XMII_PARAMS_ENTRY,
+               .max_entry_count = SJA1105_MAX_XMII_PARAMS_COUNT,
+       },
+};
+
+static int sja1105_init_mii_settings(struct sja1105_private *priv)
+{
+       struct sja1105_table *table;
+
+       table = &priv->static_config.tables[BLK_IDX_XMII_PARAMS];
+
+       table->entries = calloc(SJA1105_MAX_XMII_PARAMS_COUNT,
+                               table->ops->unpacked_entry_size);
+       if (!table->entries)
+               return -ENOMEM;
+
+       /* Table will be populated at runtime */
+       table->entry_count = SJA1105_MAX_XMII_PARAMS_COUNT;
+
+       return 0;
+}
+
+static void sja1105_setup_tagging(struct sja1105_private *priv, int port)
+{
+       struct dsa_pdata *pdata = dev_get_uclass_plat(priv->dev);
+       struct sja1105_vlan_lookup_entry *vlan;
+       int cpu = pdata->cpu_port;
+
+       /* The CPU port is implicitly configured by
+        * configuring the front-panel ports
+        */
+       if (port == cpu)
+               return;
+
+       vlan = priv->static_config.tables[BLK_IDX_VLAN_LOOKUP].entries;
+
+       priv->pvid[port] = DSA_8021Q_DIR_TX | DSA_8021Q_PORT(port);
+
+       vlan[port].vmemb_port   = BIT(port) | BIT(cpu);
+       vlan[port].vlan_bc      = BIT(port) | BIT(cpu);
+       vlan[port].tag_port     = BIT(cpu);
+       vlan[port].vlanid       = priv->pvid[port];
+       vlan[port].type_entry   = SJA1110_VLAN_D_TAG;
+}
+
+static int sja1105_init_vlan(struct sja1105_private *priv)
+{
+       struct dsa_pdata *pdata = dev_get_uclass_plat(priv->dev);
+       struct sja1105_table *table;
+       int port;
+
+       table = &priv->static_config.tables[BLK_IDX_VLAN_LOOKUP];
+
+       table->entries = calloc(pdata->num_ports,
+                               table->ops->unpacked_entry_size);
+       if (!table->entries)
+               return -ENOMEM;
+
+       table->entry_count = pdata->num_ports;
+
+       for (port = 0; port < pdata->num_ports; port++)
+               sja1105_setup_tagging(priv, port);
+
+       return 0;
+}
+
+static void
+sja1105_port_allow_traffic(struct sja1105_l2_forwarding_entry *l2_fwd,
+                          int from, int to)
+{
+       l2_fwd[from].bc_domain  |= BIT(to);
+       l2_fwd[from].reach_port |= BIT(to);
+       l2_fwd[from].fl_domain  |= BIT(to);
+}
+
+static int sja1105_init_l2_forwarding(struct sja1105_private *priv)
+{
+       struct dsa_pdata *pdata = dev_get_uclass_plat(priv->dev);
+       struct sja1105_l2_forwarding_entry *l2fwd;
+       struct sja1105_table *table;
+       int cpu = pdata->cpu_port;
+       int i;
+
+       table = &priv->static_config.tables[BLK_IDX_L2_FORWARDING];
+
+       table->entries = calloc(SJA1105_MAX_L2_FORWARDING_COUNT,
+                               table->ops->unpacked_entry_size);
+       if (!table->entries)
+               return -ENOMEM;
+
+       table->entry_count = SJA1105_MAX_L2_FORWARDING_COUNT;
+
+       l2fwd = table->entries;
+
+       /* First 5 entries define the forwarding rules */
+       for (i = 0; i < pdata->num_ports; i++) {
+               if (i == cpu)
+                       continue;
+
+               sja1105_port_allow_traffic(l2fwd, i, cpu);
+               sja1105_port_allow_traffic(l2fwd, cpu, i);
+       }
+       /* Next 8 entries define VLAN PCP mapping from ingress to egress.
+        * Leave them unpopulated (implicitly 0) but present.
+        */
+       return 0;
+}
+
+static int sja1105_init_l2_forwarding_params(struct sja1105_private *priv)
+{
+       struct sja1105_l2_forwarding_params_entry default_l2fwd_params = {
+               /* Use a single memory partition for all ingress queues */
+               .part_spc = { SJA1105_MAX_FRAME_MEMORY, 0, 0, 0, 0, 0, 0, 0 },
+       };
+       struct sja1105_table *table;
+
+       table = &priv->static_config.tables[BLK_IDX_L2_FORWARDING_PARAMS];
+
+       table->entries = calloc(SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
+                               table->ops->unpacked_entry_size);
+       if (!table->entries)
+               return -ENOMEM;
+
+       table->entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT;
+
+       /* This table only has a single entry */
+       ((struct sja1105_l2_forwarding_params_entry *)table->entries)[0] =
+                               default_l2fwd_params;
+
+       return 0;
+}
+
+static int sja1105_init_general_params(struct sja1105_private *priv)
+{
+       struct dsa_pdata *pdata = dev_get_uclass_plat(priv->dev);
+       struct sja1105_general_params_entry default_general_params = {
+               /* No frame trapping */
+               .mac_fltres1 = 0x0,
+               .mac_flt1    = 0xffffffffffff,
+               .mac_fltres0 = 0x0,
+               .mac_flt0    = 0xffffffffffff,
+               .host_port = pdata->num_ports,
+               /* No mirroring => specify an out-of-range port value */
+               .mirr_port = pdata->num_ports,
+               /* No link-local trapping => specify an out-of-range port value
+                */
+               .casc_port = pdata->num_ports,
+               /* Force the switch to see all traffic as untagged. */
+               .tpid = ETH_P_SJA1105,
+               .tpid2 = ETH_P_SJA1105,
+       };
+       struct sja1105_table *table;
+
+       table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS];
+
+       table->entries = calloc(SJA1105_MAX_GENERAL_PARAMS_COUNT,
+                               table->ops->unpacked_entry_size);
+       if (!table->entries)
+               return -ENOMEM;
+
+       table->entry_count = SJA1105_MAX_GENERAL_PARAMS_COUNT;
+
+       /* This table only has a single entry */
+       ((struct sja1105_general_params_entry *)table->entries)[0] =
+                               default_general_params;
+
+       return 0;
+}
+
+static void sja1105_setup_policer(struct sja1105_l2_policing_entry *policing,
+                                 int index, int mtu)
+{
+       policing[index].sharindx = index;
+       policing[index].smax = 65535; /* Burst size in bytes */
+       policing[index].rate = SJA1105_RATE_MBPS(1000);
+       policing[index].maxlen = mtu;
+       policing[index].partition = 0;
+}
+
+static int sja1105_init_l2_policing(struct sja1105_private *priv)
+{
+       struct dsa_pdata *pdata = dev_get_uclass_plat(priv->dev);
+       struct sja1105_l2_policing_entry *policing;
+       struct sja1105_table *table;
+       int cpu = pdata->cpu_port;
+       int i, j, k;
+
+       table = &priv->static_config.tables[BLK_IDX_L2_POLICING];
+
+       table->entries = calloc(SJA1105_MAX_L2_POLICING_COUNT,
+                               table->ops->unpacked_entry_size);
+       if (!table->entries)
+               return -ENOMEM;
+
+       table->entry_count = SJA1105_MAX_L2_POLICING_COUNT;
+
+       policing = table->entries;
+
+       /* k sweeps through all unicast policers (0-39).
+        * bcast sweeps through policers 40-44.
+        */
+       for (i = 0, k = 0; i < pdata->num_ports; i++) {
+               int bcast = (pdata->num_ports * SJA1105_NUM_TC) + i;
+               int mtu = VLAN_ETH_FRAME_LEN + ETH_FCS_LEN;
+
+               if (i == cpu)
+                       mtu += VLAN_HLEN;
+
+               for (j = 0; j < SJA1105_NUM_TC; j++, k++)
+                       sja1105_setup_policer(policing, k, mtu);
+
+               /* Set up this port's policer for broadcast traffic */
+               sja1105_setup_policer(policing, bcast, mtu);
+       }
+       return 0;
+}
+
+static int sja1105_init_mac_settings(struct sja1105_private *priv)
+{
+       struct sja1105_mac_config_entry default_mac = {
+               /* Enable 1 priority queue on egress. */
+               .top  = {0x1FF, 0, 0, 0, 0, 0, 0},
+               .base = {0x0, 0, 0, 0, 0, 0, 0, 0},
+               .enabled = {1, 0, 0, 0, 0, 0, 0, 0},
+               /* Will be overridden in sja1105_port_enable. */
+               .speed = priv->info->port_speed[SJA1105_SPEED_AUTO],
+               .egress = true,
+               .ingress = true,
+       };
+       struct dsa_pdata *pdata = dev_get_uclass_plat(priv->dev);
+       struct sja1105_mac_config_entry *mac;
+       struct sja1105_table *table;
+       int port;
+
+       table = &priv->static_config.tables[BLK_IDX_MAC_CONFIG];
+
+       table->entries = calloc(pdata->num_ports,
+                               table->ops->unpacked_entry_size);
+       if (!table->entries)
+               return -ENOMEM;
+
+       table->entry_count = pdata->num_ports;
+
+       mac = table->entries;
+
+       for (port = 0; port < pdata->num_ports; port++) {
+               mac[port] = default_mac;
+               /* Internal VLAN (pvid) to apply to untagged ingress */
+               mac[port].vlanid = priv->pvid[port];
+       }
+
+       return 0;
+}
+
+static int sja1105_static_config_init(struct sja1105_private *priv)
+{
+       struct sja1105_static_config *config = &priv->static_config;
+       const struct sja1105_table_ops *static_ops = priv->info->static_ops;
+       u64 device_id = priv->info->device_id;
+       enum sja1105_blk_idx i;
+       int rc;
+
+       *config = (struct sja1105_static_config) {0};
+
+       /* Transfer static_ops array from priv into per-table ops
+        * for handier access
+        */
+       for (i = 0; i < BLK_IDX_MAX; i++)
+               config->tables[i].ops = &static_ops[i];
+
+       config->device_id = device_id;
+
+       /* Build initial static configuration, to be fixed up during runtime */
+       rc = sja1105_init_vlan(priv);
+       if (rc < 0)
+               return rc;
+       rc = sja1105_init_mac_settings(priv);
+       if (rc < 0)
+               return rc;
+       rc = sja1105_init_mii_settings(priv);
+       if (rc < 0)
+               return rc;
+       rc = sja1105_init_l2_forwarding(priv);
+       if (rc < 0)
+               return rc;
+       rc = sja1105_init_l2_forwarding_params(priv);
+       if (rc < 0)
+               return rc;
+       rc = sja1105_init_l2_policing(priv);
+       if (rc < 0)
+               return rc;
+       rc = sja1105_init_general_params(priv);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+static void sja1105_static_config_free(struct sja1105_static_config *config)
+{
+       enum sja1105_blk_idx i;
+
+       for (i = 0; i < BLK_IDX_MAX; i++) {
+               if (config->tables[i].entry_count) {
+                       free(config->tables[i].entries);
+                       config->tables[i].entry_count = 0;
+               }
+       }
+}
+
+static void sja1105_cgu_idiv_packing(void *buf, struct sja1105_cgu_idiv *idiv,
+                                    enum packing_op op)
+{
+       const int size = 4;
+
+       sja1105_packing(buf, &idiv->clksrc,    28, 24, size, op);
+       sja1105_packing(buf, &idiv->autoblock, 11, 11, size, op);
+       sja1105_packing(buf, &idiv->idiv,       5,  2, size, op);
+       sja1105_packing(buf, &idiv->pd,         0,  0, size, op);
+}
+
+static int sja1105_cgu_idiv_config(struct sja1105_private *priv, int port,
+                                  bool enabled, int factor)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+       struct sja1105_cgu_idiv idiv;
+
+       if (regs->cgu_idiv[port] == SJA1105_RSV_ADDR)
+               return 0;
+
+       if (enabled && factor != 1 && factor != 10)
+               return -ERANGE;
+
+       /* Payload for packed_buf */
+       idiv.clksrc    = 0x0A;            /* 25MHz */
+       idiv.autoblock = 1;               /* Block clk automatically */
+       idiv.idiv      = factor - 1;      /* Divide by 1 or 10 */
+       idiv.pd        = enabled ? 0 : 1; /* Power down? */
+       sja1105_cgu_idiv_packing(packed_buf, &idiv, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->cgu_idiv[port],
+                               packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static void
+sja1105_cgu_mii_control_packing(void *buf, struct sja1105_cgu_mii_ctrl *cmd,
+                               enum packing_op op)
+{
+       const int size = 4;
+
+       sja1105_packing(buf, &cmd->clksrc,    28, 24, size, op);
+       sja1105_packing(buf, &cmd->autoblock, 11, 11, size, op);
+       sja1105_packing(buf, &cmd->pd,         0,  0, size, op);
+}
+
+static int sja1105_cgu_mii_tx_clk_config(struct sja1105_private *priv,
+                                        int port, sja1105_mii_role_t role)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       struct sja1105_cgu_mii_ctrl mii_tx_clk;
+       const int mac_clk_sources[] = {
+               CLKSRC_MII0_TX_CLK,
+               CLKSRC_MII1_TX_CLK,
+               CLKSRC_MII2_TX_CLK,
+               CLKSRC_MII3_TX_CLK,
+               CLKSRC_MII4_TX_CLK,
+       };
+       const int phy_clk_sources[] = {
+               CLKSRC_IDIV0,
+               CLKSRC_IDIV1,
+               CLKSRC_IDIV2,
+               CLKSRC_IDIV3,
+               CLKSRC_IDIV4,
+       };
+       u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+       int clksrc;
+
+       if (regs->mii_tx_clk[port] == SJA1105_RSV_ADDR)
+               return 0;
+
+       if (role == XMII_MAC)
+               clksrc = mac_clk_sources[port];
+       else
+               clksrc = phy_clk_sources[port];
+
+       /* Payload for packed_buf */
+       mii_tx_clk.clksrc    = clksrc;
+       mii_tx_clk.autoblock = 1;  /* Autoblock clk while changing clksrc */
+       mii_tx_clk.pd        = 0;  /* Power Down off => enabled */
+       sja1105_cgu_mii_control_packing(packed_buf, &mii_tx_clk, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_tx_clk[port],
+                               packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int
+sja1105_cgu_mii_rx_clk_config(struct sja1105_private *priv, int port)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+       struct sja1105_cgu_mii_ctrl mii_rx_clk;
+       const int clk_sources[] = {
+               CLKSRC_MII0_RX_CLK,
+               CLKSRC_MII1_RX_CLK,
+               CLKSRC_MII2_RX_CLK,
+               CLKSRC_MII3_RX_CLK,
+               CLKSRC_MII4_RX_CLK,
+       };
+
+       if (regs->mii_rx_clk[port] == SJA1105_RSV_ADDR)
+               return 0;
+
+       /* Payload for packed_buf */
+       mii_rx_clk.clksrc    = clk_sources[port];
+       mii_rx_clk.autoblock = 1;  /* Autoblock clk while changing clksrc */
+       mii_rx_clk.pd        = 0;  /* Power Down off => enabled */
+       sja1105_cgu_mii_control_packing(packed_buf, &mii_rx_clk, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_rx_clk[port],
+                               packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int
+sja1105_cgu_mii_ext_tx_clk_config(struct sja1105_private *priv, int port)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       struct sja1105_cgu_mii_ctrl mii_ext_tx_clk;
+       u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+       const int clk_sources[] = {
+               CLKSRC_IDIV0,
+               CLKSRC_IDIV1,
+               CLKSRC_IDIV2,
+               CLKSRC_IDIV3,
+               CLKSRC_IDIV4,
+       };
+
+       if (regs->mii_ext_tx_clk[port] == SJA1105_RSV_ADDR)
+               return 0;
+
+       /* Payload for packed_buf */
+       mii_ext_tx_clk.clksrc    = clk_sources[port];
+       mii_ext_tx_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
+       mii_ext_tx_clk.pd        = 0; /* Power Down off => enabled */
+       sja1105_cgu_mii_control_packing(packed_buf, &mii_ext_tx_clk, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_ext_tx_clk[port],
+                               packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int
+sja1105_cgu_mii_ext_rx_clk_config(struct sja1105_private *priv, int port)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       struct sja1105_cgu_mii_ctrl mii_ext_rx_clk;
+       u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+       const int clk_sources[] = {
+               CLKSRC_IDIV0,
+               CLKSRC_IDIV1,
+               CLKSRC_IDIV2,
+               CLKSRC_IDIV3,
+               CLKSRC_IDIV4,
+       };
+
+       if (regs->mii_ext_rx_clk[port] == SJA1105_RSV_ADDR)
+               return 0;
+
+       /* Payload for packed_buf */
+       mii_ext_rx_clk.clksrc    = clk_sources[port];
+       mii_ext_rx_clk.autoblock = 1; /* Autoblock clk while changing clksrc */
+       mii_ext_rx_clk.pd        = 0; /* Power Down off => enabled */
+       sja1105_cgu_mii_control_packing(packed_buf, &mii_ext_rx_clk, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_ext_rx_clk[port],
+                               packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int sja1105_mii_clocking_setup(struct sja1105_private *priv, int port,
+                                     sja1105_mii_role_t role)
+{
+       int rc;
+
+       rc = sja1105_cgu_idiv_config(priv, port, (role == XMII_PHY), 1);
+       if (rc < 0)
+               return rc;
+
+       rc = sja1105_cgu_mii_tx_clk_config(priv, port, role);
+       if (rc < 0)
+               return rc;
+
+       rc = sja1105_cgu_mii_rx_clk_config(priv, port);
+       if (rc < 0)
+               return rc;
+
+       if (role == XMII_PHY) {
+               rc = sja1105_cgu_mii_ext_tx_clk_config(priv, port);
+               if (rc < 0)
+                       return rc;
+
+               rc = sja1105_cgu_mii_ext_rx_clk_config(priv, port);
+               if (rc < 0)
+                       return rc;
+       }
+       return 0;
+}
+
+static void
+sja1105_cgu_pll_control_packing(void *buf, struct sja1105_cgu_pll_ctrl *cmd,
+                               enum packing_op op)
+{
+       const int size = 4;
+
+       sja1105_packing(buf, &cmd->pllclksrc, 28, 24, size, op);
+       sja1105_packing(buf, &cmd->msel,      23, 16, size, op);
+       sja1105_packing(buf, &cmd->autoblock, 11, 11, size, op);
+       sja1105_packing(buf, &cmd->psel,       9,  8, size, op);
+       sja1105_packing(buf, &cmd->direct,     7,  7, size, op);
+       sja1105_packing(buf, &cmd->fbsel,      6,  6, size, op);
+       sja1105_packing(buf, &cmd->bypass,     1,  1, size, op);
+       sja1105_packing(buf, &cmd->pd,         0,  0, size, op);
+}
+
+static int sja1105_cgu_rgmii_tx_clk_config(struct sja1105_private *priv,
+                                          int port, u64 speed)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       struct sja1105_cgu_mii_ctrl txc;
+       u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+       int clksrc;
+
+       if (regs->rgmii_tx_clk[port] == SJA1105_RSV_ADDR)
+               return 0;
+
+       if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) {
+               clksrc = CLKSRC_PLL0;
+       } else {
+               int clk_sources[] = {CLKSRC_IDIV0, CLKSRC_IDIV1, CLKSRC_IDIV2,
+                                    CLKSRC_IDIV3, CLKSRC_IDIV4};
+               clksrc = clk_sources[port];
+       }
+
+       /* RGMII: 125MHz for 1000, 25MHz for 100, 2.5MHz for 10 */
+       txc.clksrc = clksrc;
+       /* Autoblock clk while changing clksrc */
+       txc.autoblock = 1;
+       /* Power Down off => enabled */
+       txc.pd = 0;
+       sja1105_cgu_mii_control_packing(packed_buf, &txc, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgmii_tx_clk[port],
+                               packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+/* AGU */
+static void
+sja1105_cfg_pad_mii_packing(void *buf, struct sja1105_cfg_pad_mii *cmd,
+                           enum packing_op op)
+{
+       const int size = 4;
+
+       sja1105_packing(buf, &cmd->d32_os,   28, 27, size, op);
+       sja1105_packing(buf, &cmd->d32_ih,   26, 26, size, op);
+       sja1105_packing(buf, &cmd->d32_ipud, 25, 24, size, op);
+       sja1105_packing(buf, &cmd->d10_os,   20, 19, size, op);
+       sja1105_packing(buf, &cmd->d10_ih,   18, 18, size, op);
+       sja1105_packing(buf, &cmd->d10_ipud, 17, 16, size, op);
+       sja1105_packing(buf, &cmd->ctrl_os,  12, 11, size, op);
+       sja1105_packing(buf, &cmd->ctrl_ih,  10, 10, size, op);
+       sja1105_packing(buf, &cmd->ctrl_ipud, 9,  8, size, op);
+       sja1105_packing(buf, &cmd->clk_os,    4,  3, size, op);
+       sja1105_packing(buf, &cmd->clk_ih,    2,  2, size, op);
+       sja1105_packing(buf, &cmd->clk_ipud,  1,  0, size, op);
+}
+
+static void
+sja1110_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
+                              enum packing_op op)
+{
+       const int size = SJA1105_SIZE_CGU_CMD;
+       u64 range = 4;
+
+       /* Fields RXC_RANGE and TXC_RANGE select the input frequency range:
+        * 0 = 2.5MHz
+        * 1 = 25MHz
+        * 2 = 50MHz
+        * 3 = 125MHz
+        * 4 = Automatically determined by port speed.
+        * There's no point in defining a structure different than the one for
+        * SJA1105, so just hardcode the frequency range to automatic, just as
+        * before.
+        */
+       sja1105_packing(buf, &cmd->rxc_stable_ovr, 26, 26, size, op);
+       sja1105_packing(buf, &cmd->rxc_delay,      25, 21, size, op);
+       sja1105_packing(buf, &range,               20, 18, size, op);
+       sja1105_packing(buf, &cmd->rxc_bypass,     17, 17, size, op);
+       sja1105_packing(buf, &cmd->rxc_pd,         16, 16, size, op);
+       sja1105_packing(buf, &cmd->txc_stable_ovr, 10, 10, size, op);
+       sja1105_packing(buf, &cmd->txc_delay,       9,  5, size, op);
+       sja1105_packing(buf, &range,                4,  2, size, op);
+       sja1105_packing(buf, &cmd->txc_bypass,      1,  1, size, op);
+       sja1105_packing(buf, &cmd->txc_pd,          0,  0, size, op);
+}
+
+static int sja1105_rgmii_cfg_pad_tx_config(struct sja1105_private *priv,
+                                          int port)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       struct sja1105_cfg_pad_mii pad_mii_tx = {0};
+       u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+
+       if (regs->pad_mii_tx[port] == SJA1105_RSV_ADDR)
+               return 0;
+
+       /* Payload */
+       pad_mii_tx.d32_os    = 3; /* TXD[3:2] output stage: */
+                                 /*          high noise/high speed */
+       pad_mii_tx.d10_os    = 3; /* TXD[1:0] output stage: */
+                                 /*          high noise/high speed */
+       pad_mii_tx.d32_ipud  = 2; /* TXD[3:2] input stage: */
+                                 /*          plain input (default) */
+       pad_mii_tx.d10_ipud  = 2; /* TXD[1:0] input stage: */
+                                 /*          plain input (default) */
+       pad_mii_tx.ctrl_os   = 3; /* TX_CTL / TX_ER output stage */
+       pad_mii_tx.ctrl_ipud = 2; /* TX_CTL / TX_ER input stage (default) */
+       pad_mii_tx.clk_os    = 3; /* TX_CLK output stage */
+       pad_mii_tx.clk_ih    = 0; /* TX_CLK input hysteresis (default) */
+       pad_mii_tx.clk_ipud  = 2; /* TX_CLK input stage (default) */
+       sja1105_cfg_pad_mii_packing(packed_buf, &pad_mii_tx, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_tx[port],
+                               packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int sja1105_cfg_pad_rx_config(struct sja1105_private *priv, int port)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       struct sja1105_cfg_pad_mii pad_mii_rx = {0};
+       u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+
+       if (regs->pad_mii_rx[port] == SJA1105_RSV_ADDR)
+               return 0;
+
+       /* Payload */
+       pad_mii_rx.d32_ih    = 0; /* RXD[3:2] input stage hysteresis: */
+                                 /*          non-Schmitt (default) */
+       pad_mii_rx.d32_ipud  = 2; /* RXD[3:2] input weak pull-up/down */
+                                 /*          plain input (default) */
+       pad_mii_rx.d10_ih    = 0; /* RXD[1:0] input stage hysteresis: */
+                                 /*          non-Schmitt (default) */
+       pad_mii_rx.d10_ipud  = 2; /* RXD[1:0] input weak pull-up/down */
+                                 /*          plain input (default) */
+       pad_mii_rx.ctrl_ih   = 0; /* RX_DV/CRS_DV/RX_CTL and RX_ER */
+                                 /* input stage hysteresis: */
+                                 /* non-Schmitt (default) */
+       pad_mii_rx.ctrl_ipud = 3; /* RX_DV/CRS_DV/RX_CTL and RX_ER */
+                                 /* input stage weak pull-up/down: */
+                                 /* pull-down */
+       pad_mii_rx.clk_os    = 2; /* RX_CLK/RXC output stage: */
+                                 /* medium noise/fast speed (default) */
+       pad_mii_rx.clk_ih    = 0; /* RX_CLK/RXC input hysteresis: */
+                                 /* non-Schmitt (default) */
+       pad_mii_rx.clk_ipud  = 2; /* RX_CLK/RXC input pull-up/down: */
+                                 /* plain input (default) */
+       sja1105_cfg_pad_mii_packing(packed_buf, &pad_mii_rx, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_rx[port],
+                               packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static void
+sja1105_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
+                              enum packing_op op)
+{
+       const int size = SJA1105_SIZE_CGU_CMD;
+
+       sja1105_packing(buf, &cmd->rxc_stable_ovr, 15, 15, size, op);
+       sja1105_packing(buf, &cmd->rxc_delay,      14, 10, size, op);
+       sja1105_packing(buf, &cmd->rxc_bypass,      9,  9, size, op);
+       sja1105_packing(buf, &cmd->rxc_pd,          8,  8, size, op);
+       sja1105_packing(buf, &cmd->txc_stable_ovr,  7,  7, size, op);
+       sja1105_packing(buf, &cmd->txc_delay,       6,  2, size, op);
+       sja1105_packing(buf, &cmd->txc_bypass,      1,  1, size, op);
+       sja1105_packing(buf, &cmd->txc_pd,          0,  0, size, op);
+}
+
+/* Valid range in degrees is an integer between 73.8 and 101.7 */
+static u64 sja1105_rgmii_delay(u64 phase)
+{
+       /* UM11040.pdf: The delay in degree phase is 73.8 + delay_tune * 0.9.
+        * To avoid floating point operations we'll multiply by 10
+        * and get 1 decimal point precision.
+        */
+       phase *= 10;
+       return (phase - 738) / 9;
+}
+
+static int sja1105pqrs_setup_rgmii_delay(struct sja1105_private *priv, int port)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
+       u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+       int rc;
+
+       if (priv->rgmii_rx_delay[port])
+               pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
+       if (priv->rgmii_tx_delay[port])
+               pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
+
+       /* Stage 1: Turn the RGMII delay lines off. */
+       pad_mii_id.rxc_bypass = 1;
+       pad_mii_id.rxc_pd = 1;
+       pad_mii_id.txc_bypass = 1;
+       pad_mii_id.txc_pd = 1;
+       sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
+
+       rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port],
+                             packed_buf, SJA1105_SIZE_CGU_CMD);
+       if (rc < 0)
+               return rc;
+
+       /* Stage 2: Turn the RGMII delay lines on. */
+       if (priv->rgmii_rx_delay[port]) {
+               pad_mii_id.rxc_bypass = 0;
+               pad_mii_id.rxc_pd = 0;
+       }
+       if (priv->rgmii_tx_delay[port]) {
+               pad_mii_id.txc_bypass = 0;
+               pad_mii_id.txc_pd = 0;
+       }
+       sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port],
+                               packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int sja1110_setup_rgmii_delay(struct sja1105_private *priv, int port)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
+       u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+
+       pad_mii_id.rxc_pd = 1;
+       pad_mii_id.txc_pd = 1;
+
+       if (priv->rgmii_rx_delay[port]) {
+               pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
+               /* The "BYPASS" bit in SJA1110 is actually a "don't bypass" */
+               pad_mii_id.rxc_bypass = 1;
+               pad_mii_id.rxc_pd = 0;
+       }
+
+       if (priv->rgmii_tx_delay[port]) {
+               pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
+               pad_mii_id.txc_bypass = 1;
+               pad_mii_id.txc_pd = 0;
+       }
+
+       sja1110_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port],
+                               packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
+                                       sja1105_mii_role_t role)
+{
+       struct sja1105_mac_config_entry *mac;
+       struct udevice *dev = priv->dev;
+       u64 speed;
+       int rc;
+
+       mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
+       speed = mac[port].speed;
+
+       if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) {
+               /* 1000Mbps, IDIV disabled (125 MHz) */
+               rc = sja1105_cgu_idiv_config(priv, port, false, 1);
+       } else if (speed == priv->info->port_speed[SJA1105_SPEED_100MBPS]) {
+               /* 100Mbps, IDIV enabled, divide by 1 (25 MHz) */
+               rc = sja1105_cgu_idiv_config(priv, port, true, 1);
+       } else if (speed == priv->info->port_speed[SJA1105_SPEED_10MBPS]) {
+               /* 10Mbps, IDIV enabled, divide by 10 (2.5 MHz) */
+               rc = sja1105_cgu_idiv_config(priv, port, true, 10);
+       } else if (speed == priv->info->port_speed[SJA1105_SPEED_AUTO]) {
+               /* Skip CGU configuration if there is no speed available
+                * (e.g. link is not established yet)
+                */
+               dev_dbg(dev, "Speed not available, skipping CGU config\n");
+               return 0;
+       } else {
+               rc = -EINVAL;
+       }
+
+       if (rc < 0) {
+               dev_err(dev, "Failed to configure idiv\n");
+               return rc;
+       }
+       rc = sja1105_cgu_rgmii_tx_clk_config(priv, port, speed);
+       if (rc < 0) {
+               dev_err(dev, "Failed to configure RGMII Tx clock\n");
+               return rc;
+       }
+       rc = sja1105_rgmii_cfg_pad_tx_config(priv, port);
+       if (rc < 0) {
+               dev_err(dev, "Failed to configure Tx pad registers\n");
+               return rc;
+       }
+
+       if (!priv->info->setup_rgmii_delay)
+               return 0;
+
+       return priv->info->setup_rgmii_delay(priv, port);
+}
+
+static int sja1105_cgu_rmii_ref_clk_config(struct sja1105_private *priv,
+                                          int port)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+       struct sja1105_cgu_mii_ctrl ref_clk;
+       const int clk_sources[] = {
+               CLKSRC_MII0_TX_CLK,
+               CLKSRC_MII1_TX_CLK,
+               CLKSRC_MII2_TX_CLK,
+               CLKSRC_MII3_TX_CLK,
+               CLKSRC_MII4_TX_CLK,
+       };
+
+       if (regs->rmii_ref_clk[port] == SJA1105_RSV_ADDR)
+               return 0;
+
+       /* Payload for packed_buf */
+       ref_clk.clksrc    = clk_sources[port];
+       ref_clk.autoblock = 1;      /* Autoblock clk while changing clksrc */
+       ref_clk.pd        = 0;      /* Power Down off => enabled */
+       sja1105_cgu_mii_control_packing(packed_buf, &ref_clk, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_ref_clk[port],
+                               packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int
+sja1105_cgu_rmii_ext_tx_clk_config(struct sja1105_private *priv, int port)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       struct sja1105_cgu_mii_ctrl ext_tx_clk;
+       u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+
+       if (regs->rmii_ext_tx_clk[port] == SJA1105_RSV_ADDR)
+               return 0;
+
+       /* Payload for packed_buf */
+       ext_tx_clk.clksrc    = CLKSRC_PLL1;
+       ext_tx_clk.autoblock = 1;   /* Autoblock clk while changing clksrc */
+       ext_tx_clk.pd        = 0;   /* Power Down off => enabled */
+       sja1105_cgu_mii_control_packing(packed_buf, &ext_tx_clk, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_ext_tx_clk[port],
+                               packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int sja1105_cgu_rmii_pll_config(struct sja1105_private *priv)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+       struct sja1105_cgu_pll_ctrl pll = {0};
+       int rc;
+
+       if (regs->rmii_pll1 == SJA1105_RSV_ADDR)
+               return 0;
+
+       /* Step 1: PLL1 setup for 50Mhz */
+       pll.pllclksrc = 0xA;
+       pll.msel      = 0x1;
+       pll.autoblock = 0x1;
+       pll.psel      = 0x1;
+       pll.direct    = 0x0;
+       pll.fbsel     = 0x1;
+       pll.bypass    = 0x0;
+       pll.pd        = 0x1;
+
+       sja1105_cgu_pll_control_packing(packed_buf, &pll, PACK);
+       rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_pll1, packed_buf,
+                             SJA1105_SIZE_CGU_CMD);
+       if (rc < 0)
+               return rc;
+
+       /* Step 2: Enable PLL1 */
+       pll.pd = 0x0;
+
+       sja1105_cgu_pll_control_packing(packed_buf, &pll, PACK);
+       rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_pll1, packed_buf,
+                             SJA1105_SIZE_CGU_CMD);
+       return rc;
+}
+
+static int sja1105_rmii_clocking_setup(struct sja1105_private *priv, int port,
+                                      sja1105_mii_role_t role)
+{
+       int rc;
+
+       /* AH1601.pdf chapter 2.5.1. Sources */
+       if (role == XMII_MAC) {
+               /* Configure and enable PLL1 for 50Mhz output */
+               rc = sja1105_cgu_rmii_pll_config(priv);
+               if (rc < 0)
+                       return rc;
+       }
+       /* Disable IDIV for this port */
+       rc = sja1105_cgu_idiv_config(priv, port, false, 1);
+       if (rc < 0)
+               return rc;
+       /* Source to sink mappings */
+       rc = sja1105_cgu_rmii_ref_clk_config(priv, port);
+       if (rc < 0)
+               return rc;
+       if (role == XMII_MAC) {
+               rc = sja1105_cgu_rmii_ext_tx_clk_config(priv, port);
+               if (rc < 0)
+                       return rc;
+       }
+       return 0;
+}
+
+static int sja1105_pcs_read(struct sja1105_private *priv, int addr,
+                           int devad, int regnum)
+{
+       return priv->mdio_pcs->read(priv->mdio_pcs, addr, devad, regnum);
+}
+
+static int sja1105_pcs_write(struct sja1105_private *priv, int addr,
+                            int devad, int regnum, u16 val)
+{
+       return priv->mdio_pcs->write(priv->mdio_pcs, addr, devad, regnum, val);
+}
+
+/* In NXP SJA1105, the PCS is integrated with a PMA that has the TX lane
+ * polarity inverted by default (PLUS is MINUS, MINUS is PLUS). To obtain
+ * normal non-inverted behavior, the TX lane polarity must be inverted in the
+ * PCS, via the DIGITAL_CONTROL_2 register.
+ */
+static int sja1105_pma_config(struct sja1105_private *priv, int port)
+{
+       return sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
+                                DW_VR_MII_DIG_CTRL2,
+                                DW_VR_MII_DIG_CTRL2_TX_POL_INV);
+}
+
+static int sja1110_pma_config(struct sja1105_private *priv, int port)
+{
+       u16 txpll_fbdiv = 0x19, txpll_refdiv = 0x1;
+       u16 rxpll_fbdiv = 0x19, rxpll_refdiv = 0x1;
+       u16 rx_cdr_ctle = 0x212a;
+       u16 val;
+       int rc;
+
+       /* Program TX PLL feedback divider and reference divider settings for
+        * correct oscillation frequency.
+        */
+       rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL0,
+                              SJA1110_TXPLL_FBDIV(txpll_fbdiv));
+       if (rc < 0)
+               return rc;
+
+       rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL1,
+                              SJA1110_TXPLL_REFDIV(txpll_refdiv));
+       if (rc < 0)
+               return rc;
+
+       /* Program transmitter amplitude and disable amplitude trimming */
+       rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
+                              SJA1110_LANE_DRIVER1_0, SJA1110_TXDRV(0x5));
+       if (rc < 0)
+               return rc;
+
+       val = SJA1110_TXDRVTRIM_LSB(0xffffffull);
+
+       rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
+                              SJA1110_LANE_DRIVER2_0, val);
+       if (rc < 0)
+               return rc;
+
+       val = SJA1110_TXDRVTRIM_MSB(0xffffffull) | SJA1110_LANE_DRIVER2_1_RSV;
+
+       rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
+                              SJA1110_LANE_DRIVER2_1, val);
+       if (rc < 0)
+               return rc;
+
+       /* Enable input and output resistor terminations for low BER. */
+       val = SJA1110_ACCOUPLE_RXVCM_EN | SJA1110_CDR_GAIN |
+             SJA1110_RXRTRIM(4) | SJA1110_RXTEN | SJA1110_TXPLL_BWSEL |
+             SJA1110_TXRTRIM(3) | SJA1110_TXTEN;
+
+       rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_LANE_TRIM,
+                              val);
+       if (rc < 0)
+               return rc;
+
+       /* Select PCS as transmitter data source. */
+       rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
+                              SJA1110_LANE_DATAPATH_1, 0);
+       if (rc < 0)
+               return rc;
+
+       /* Program RX PLL feedback divider and reference divider for correct
+        * oscillation frequency.
+        */
+       rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL0,
+                              SJA1110_RXPLL_FBDIV(rxpll_fbdiv));
+       if (rc < 0)
+               return rc;
+
+       rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL1,
+                              SJA1110_RXPLL_REFDIV(rxpll_refdiv));
+       if (rc < 0)
+               return rc;
+
+       /* Program threshold for receiver signal detector.
+        * Enable control of RXPLL by receiver signal detector to disable RXPLL
+        * when an input signal is not present.
+        */
+       rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
+                              SJA1110_RX_DATA_DETECT, 0x0005);
+       if (rc < 0)
+               return rc;
+
+       /* Enable TX and RX PLLs and circuits.
+        * Release reset of PMA to enable data flow to/from PCS.
+        */
+       rc = sja1105_pcs_read(priv, port, MDIO_MMD_VEND2,
+                             SJA1110_POWERDOWN_ENABLE);
+       if (rc < 0)
+               return rc;
+
+       val = rc & ~(SJA1110_TXPLL_PD | SJA1110_TXPD | SJA1110_RXCH_PD |
+                    SJA1110_RXBIAS_PD | SJA1110_RESET_SER_EN |
+                    SJA1110_RESET_SER | SJA1110_RESET_DES);
+       val |= SJA1110_RXPKDETEN | SJA1110_RCVEN;
+
+       rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
+                              SJA1110_POWERDOWN_ENABLE, val);
+       if (rc < 0)
+               return rc;
+
+       /* Program continuous-time linear equalizer (CTLE) settings. */
+       rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_RX_CDR_CTLE,
+                              rx_cdr_ctle);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+static int sja1105_xpcs_config_aneg_c37_sgmii(struct sja1105_private *priv,
+                                             int port)
+{
+       int rc;
+
+       rc = sja1105_pcs_read(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1);
+       if (rc < 0)
+               return rc;
+       rc &= ~MDIO_AN_CTRL1_ENABLE;
+       rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1,
+                              rc);
+       if (rc < 0)
+               return rc;
+
+       rc = sja1105_pcs_read(priv, port, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL);
+       if (rc < 0)
+               return rc;
+
+       rc &= ~(DW_VR_MII_PCS_MODE_MASK | DW_VR_MII_TX_CONFIG_MASK);
+       rc |= (DW_VR_MII_PCS_MODE_C37_SGMII <<
+              DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT &
+              DW_VR_MII_PCS_MODE_MASK);
+       rc |= (DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII <<
+              DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT &
+              DW_VR_MII_TX_CONFIG_MASK);
+       rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL,
+                              rc);
+       if (rc < 0)
+               return rc;
+
+       rc = sja1105_pcs_read(priv, port, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
+       if (rc < 0)
+               return rc;
+
+       if (priv->xpcs_cfg[port].inband_an)
+               rc |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
+       else
+               rc &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
+
+       rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1,
+                              rc);
+       if (rc < 0)
+               return rc;
+
+       rc = sja1105_pcs_read(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1);
+       if (rc < 0)
+               return rc;
+
+       if (priv->xpcs_cfg[port].inband_an)
+               rc |= MDIO_AN_CTRL1_ENABLE;
+       else
+               rc &= ~MDIO_AN_CTRL1_ENABLE;
+
+       return sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1, rc);
+}
+
+static int sja1105_xpcs_link_up_sgmii(struct sja1105_private *priv, int port)
+{
+       int val = BMCR_FULLDPLX;
+
+       if (priv->xpcs_cfg[port].inband_an)
+               return 0;
+
+       switch (priv->xpcs_cfg[port].speed) {
+       case SPEED_1000:
+               val = BMCR_SPEED1000;
+               break;
+       case SPEED_100:
+               val = BMCR_SPEED100;
+               break;
+       case SPEED_10:
+               val = BMCR_SPEED10;
+               break;
+       default:
+               dev_err(priv->dev, "Invalid PCS speed %d\n",
+                       priv->xpcs_cfg[port].speed);
+               return -EINVAL;
+       }
+
+       return sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1, val);
+}
+
+static int sja1105_sgmii_setup(struct sja1105_private *priv, int port)
+{
+       int rc;
+
+       rc = sja1105_xpcs_config_aneg_c37_sgmii(priv, port);
+       if (rc)
+               return rc;
+
+       rc = sja1105_xpcs_link_up_sgmii(priv, port);
+       if (rc)
+               return rc;
+
+       return priv->info->pma_config(priv, port);
+}
+
+static int sja1105_clocking_setup_port(struct sja1105_private *priv, int port)
+{
+       struct sja1105_xmii_params_entry *mii;
+       sja1105_phy_interface_t phy_mode;
+       sja1105_mii_role_t role;
+       int rc;
+
+       mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
+
+       /* RGMII etc */
+       phy_mode = mii->xmii_mode[port];
+       /* MAC or PHY, for applicable types (not RGMII) */
+       role = mii->phy_mac[port];
+
+       switch (phy_mode) {
+       case XMII_MODE_MII:
+               rc = sja1105_mii_clocking_setup(priv, port, role);
+               break;
+       case XMII_MODE_RMII:
+               rc = sja1105_rmii_clocking_setup(priv, port, role);
+               break;
+       case XMII_MODE_RGMII:
+               rc = sja1105_rgmii_clocking_setup(priv, port, role);
+               break;
+       case XMII_MODE_SGMII:
+               rc = sja1105_sgmii_setup(priv, port);
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (rc)
+               return rc;
+
+       /* Internally pull down the RX_DV/CRS_DV/RX_CTL and RX_ER inputs */
+       return sja1105_cfg_pad_rx_config(priv, port);
+}
+
+static int sja1105_clocking_setup(struct sja1105_private *priv)
+{
+       struct dsa_pdata *pdata = dev_get_uclass_plat(priv->dev);
+       int port, rc;
+
+       for (port = 0; port < pdata->num_ports; port++) {
+               rc = sja1105_clocking_setup_port(priv, port);
+               if (rc < 0)
+                       return rc;
+       }
+       return 0;
+}
+
+static int sja1105_pcs_mdio_read(struct mii_dev *bus, int phy, int mmd, int reg)
+{
+       u8 packed_buf[SJA1105_SIZE_MDIO_CMD] = {0};
+       struct sja1105_private *priv = bus->priv;
+       const int size = SJA1105_SIZE_MDIO_CMD;
+       u64 addr, tmp;
+       int rc;
+
+       if (mmd == MDIO_DEVAD_NONE)
+               return -ENODEV;
+
+       if (!priv->info->supports_sgmii[phy])
+               return -ENODEV;
+
+       addr = (mmd << 16) | (reg & GENMASK(15, 0));
+
+       if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2)
+               return 0xffff;
+
+       rc = sja1105_xfer_buf(priv, SPI_READ, addr, packed_buf, size);
+       if (rc < 0)
+               return rc;
+
+       sja1105_packing(packed_buf, &tmp, 31, 0, size, UNPACK);
+
+       return tmp & 0xffff;
+}
+
+static int sja1105_pcs_mdio_write(struct mii_dev *bus, int phy, int mmd,
+                                 int reg, u16 val)
+{
+       u8 packed_buf[SJA1105_SIZE_MDIO_CMD] = {0};
+       struct sja1105_private *priv = bus->priv;
+       const int size = SJA1105_SIZE_MDIO_CMD;
+       u64 addr, tmp;
+
+       if (mmd == MDIO_DEVAD_NONE)
+               return -ENODEV;
+
+       if (!priv->info->supports_sgmii[phy])
+               return -ENODEV;
+
+       addr = (mmd << 16) | (reg & GENMASK(15, 0));
+       tmp = val;
+
+       if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2)
+               return -ENODEV;
+
+       sja1105_packing(packed_buf, &tmp, 31, 0, size, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, addr, packed_buf, size);
+}
+
+static int sja1110_pcs_mdio_read(struct mii_dev *bus, int phy, int mmd, int reg)
+{
+       struct sja1105_private *priv = bus->priv;
+       const struct sja1105_regs *regs = priv->info->regs;
+       u8 packed_buf[SJA1105_SIZE_MDIO_CMD] = {0};
+       const int size = SJA1105_SIZE_MDIO_CMD;
+       int offset, bank;
+       u64 addr, tmp;
+       int rc;
+
+       if (mmd == MDIO_DEVAD_NONE)
+               return -ENODEV;
+
+       if (regs->pcs_base[phy] == SJA1105_RSV_ADDR)
+               return -ENODEV;
+
+       addr = (mmd << 16) | (reg & GENMASK(15, 0));
+
+       bank = addr >> 8;
+       offset = addr & GENMASK(7, 0);
+
+       /* This addressing scheme reserves register 0xff for the bank address
+        * register, so that can never be addressed.
+        */
+       if (offset == 0xff)
+               return -ENODEV;
+
+       tmp = bank;
+
+       sja1105_packing(packed_buf, &tmp, 31, 0, size, PACK);
+
+       rc = sja1105_xfer_buf(priv, SPI_WRITE,
+                             regs->pcs_base[phy] + SJA1110_PCS_BANK_REG,
+                             packed_buf, size);
+       if (rc < 0)
+               return rc;
+
+       rc = sja1105_xfer_buf(priv, SPI_READ, regs->pcs_base[phy] + offset,
+                             packed_buf, size);
+       if (rc < 0)
+               return rc;
+
+       sja1105_packing(packed_buf, &tmp, 31, 0, size, UNPACK);
+
+       return tmp & 0xffff;
+}
+
+static int sja1110_pcs_mdio_write(struct mii_dev *bus, int phy, int mmd,
+                                 int reg, u16 val)
+{
+       struct sja1105_private *priv = bus->priv;
+       const struct sja1105_regs *regs = priv->info->regs;
+       u8 packed_buf[SJA1105_SIZE_MDIO_CMD] = {0};
+       const int size = SJA1105_SIZE_MDIO_CMD;
+       int offset, bank;
+       u64 addr, tmp;
+       int rc;
+
+       if (mmd == MDIO_DEVAD_NONE)
+               return -ENODEV;
+
+       if (regs->pcs_base[phy] == SJA1105_RSV_ADDR)
+               return -ENODEV;
+
+       addr = (mmd << 16) | (reg & GENMASK(15, 0));
+
+       bank = addr >> 8;
+       offset = addr & GENMASK(7, 0);
+
+       /* This addressing scheme reserves register 0xff for the bank address
+        * register, so that can never be addressed.
+        */
+       if (offset == 0xff)
+               return -ENODEV;
+
+       tmp = bank;
+       sja1105_packing(packed_buf, &tmp, 31, 0, size, PACK);
+
+       rc = sja1105_xfer_buf(priv, SPI_WRITE,
+                             regs->pcs_base[phy] + SJA1110_PCS_BANK_REG,
+                             packed_buf, size);
+       if (rc < 0)
+               return rc;
+
+       tmp = val;
+       sja1105_packing(packed_buf, &tmp, 31, 0, size, PACK);
+
+       return sja1105_xfer_buf(priv, SPI_WRITE, regs->pcs_base[phy] + offset,
+                               packed_buf, size);
+}
+
+static int sja1105_mdiobus_register(struct sja1105_private *priv)
+{
+       struct udevice *dev = priv->dev;
+       struct mii_dev *bus;
+       int rc;
+
+       if (!priv->info->pcs_mdio_read || !priv->info->pcs_mdio_write)
+               return 0;
+
+       bus = mdio_alloc();
+       if (!bus)
+               return -ENOMEM;
+
+       snprintf(bus->name, MDIO_NAME_LEN, "%s-pcs", dev->name);
+       bus->read = priv->info->pcs_mdio_read;
+       bus->write = priv->info->pcs_mdio_write;
+       bus->priv = priv;
+
+       rc = mdio_register(bus);
+       if (rc) {
+               mdio_free(bus);
+               return rc;
+       }
+
+       priv->mdio_pcs = bus;
+
+       return 0;
+}
+
+static void sja1105_mdiobus_unregister(struct sja1105_private *priv)
+{
+       if (!priv->mdio_pcs)
+               return;
+
+       mdio_unregister(priv->mdio_pcs);
+       mdio_free(priv->mdio_pcs);
+}
+
+static const struct sja1105_regs sja1105et_regs = {
+       .device_id = 0x0,
+       .prod_id = 0x100BC3,
+       .status = 0x1,
+       .port_control = 0x11,
+       .config = 0x020000,
+       .rgu = 0x100440,
+       /* UM10944.pdf, Table 86, ACU Register overview */
+       .pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
+       .pad_mii_rx = {0x100801, 0x100803, 0x100805, 0x100807, 0x100809},
+       .rmii_pll1 = 0x10000A,
+       .cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
+       /* UM10944.pdf, Table 78, CGU Register overview */
+       .mii_tx_clk = {0x100013, 0x10001A, 0x100021, 0x100028, 0x10002F},
+       .mii_rx_clk = {0x100014, 0x10001B, 0x100022, 0x100029, 0x100030},
+       .mii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034},
+       .mii_ext_rx_clk = {0x100019, 0x100020, 0x100027, 0x10002E, 0x100035},
+       .rgmii_tx_clk = {0x100016, 0x10001D, 0x100024, 0x10002B, 0x100032},
+       .rmii_ref_clk = {0x100015, 0x10001C, 0x100023, 0x10002A, 0x100031},
+       .rmii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034},
+};
+
+static const struct sja1105_regs sja1105pqrs_regs = {
+       .device_id = 0x0,
+       .prod_id = 0x100BC3,
+       .status = 0x1,
+       .port_control = 0x12,
+       .config = 0x020000,
+       .rgu = 0x100440,
+       /* UM10944.pdf, Table 86, ACU Register overview */
+       .pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
+       .pad_mii_rx = {0x100801, 0x100803, 0x100805, 0x100807, 0x100809},
+       .pad_mii_id = {0x100810, 0x100811, 0x100812, 0x100813, 0x100814},
+       .rmii_pll1 = 0x10000A,
+       .cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
+       /* UM11040.pdf, Table 114 */
+       .mii_tx_clk = {0x100013, 0x100019, 0x10001F, 0x100025, 0x10002B},
+       .mii_rx_clk = {0x100014, 0x10001A, 0x100020, 0x100026, 0x10002C},
+       .mii_ext_tx_clk = {0x100017, 0x10001D, 0x100023, 0x100029, 0x10002F},
+       .mii_ext_rx_clk = {0x100018, 0x10001E, 0x100024, 0x10002A, 0x100030},
+       .rgmii_tx_clk = {0x100016, 0x10001C, 0x100022, 0x100028, 0x10002E},
+       .rmii_ref_clk = {0x100015, 0x10001B, 0x100021, 0x100027, 0x10002D},
+       .rmii_ext_tx_clk = {0x100017, 0x10001D, 0x100023, 0x100029, 0x10002F},
+};
+
+static const struct sja1105_regs sja1110_regs = {
+       .device_id = SJA1110_SPI_ADDR(0x0),
+       .prod_id = SJA1110_ACU_ADDR(0xf00),
+       .status = SJA1110_SPI_ADDR(0x4),
+       .port_control = SJA1110_SPI_ADDR(0x50), /* actually INHIB_TX */
+       .config = 0x020000,
+       .rgu = SJA1110_RGU_ADDR(0x100), /* Reset Control Register 0 */
+       /* Ports 2 and 3 are capable of xMII, but there isn't anything to
+        * configure in the CGU/ACU for them.
+        */
+       .pad_mii_tx = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR},
+       .pad_mii_rx = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR},
+       .pad_mii_id = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1110_ACU_ADDR(0x18), SJA1110_ACU_ADDR(0x28),
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR},
+       .rmii_pll1 = SJA1105_RSV_ADDR,
+       .cgu_idiv = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                    SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                    SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                    SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+       .mii_tx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+       .mii_rx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                      SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+       .mii_ext_tx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                          SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                          SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                          SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+       .mii_ext_rx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                          SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                          SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                          SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+       .rgmii_tx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                        SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                        SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                        SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+       .rmii_ref_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                        SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                        SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                        SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+       .rmii_ext_tx_clk = {SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                           SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                           SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                           SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                           SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                           SJA1105_RSV_ADDR},
+       .pcs_base = {SJA1105_RSV_ADDR, 0x1c1400, 0x1c1800, 0x1c1c00, 0x1c2000,
+                    SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
+                    SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
+};
+
+enum sja1105_switch_id {
+       SJA1105E = 0,
+       SJA1105T,
+       SJA1105P,
+       SJA1105Q,
+       SJA1105R,
+       SJA1105S,
+       SJA1110A,
+       SJA1110B,
+       SJA1110C,
+       SJA1110D,
+       SJA1105_MAX_SWITCH_ID,
+};
+
+static const struct sja1105_info sja1105_info[] = {
+       [SJA1105E] = {
+               .device_id              = SJA1105E_DEVICE_ID,
+               .part_no                = SJA1105ET_PART_NO,
+               .static_ops             = sja1105et_table_ops,
+               .reset_cmd              = sja1105et_reset_cmd,
+               .regs                   = &sja1105et_regs,
+               .port_speed             = {
+                       [SJA1105_SPEED_AUTO] = 0,
+                       [SJA1105_SPEED_10MBPS] = 3,
+                       [SJA1105_SPEED_100MBPS] = 2,
+                       [SJA1105_SPEED_1000MBPS] = 1,
+               },
+               .supports_mii           = {true, true, true, true, true},
+               .supports_rmii          = {true, true, true, true, true},
+               .supports_rgmii         = {true, true, true, true, true},
+               .name                   = "SJA1105E",
+       },
+       [SJA1105T] = {
+               .device_id              = SJA1105T_DEVICE_ID,
+               .part_no                = SJA1105ET_PART_NO,
+               .static_ops             = sja1105et_table_ops,
+               .reset_cmd              = sja1105et_reset_cmd,
+               .regs                   = &sja1105et_regs,
+               .port_speed             = {
+                       [SJA1105_SPEED_AUTO] = 0,
+                       [SJA1105_SPEED_10MBPS] = 3,
+                       [SJA1105_SPEED_100MBPS] = 2,
+                       [SJA1105_SPEED_1000MBPS] = 1,
+               },
+               .supports_mii           = {true, true, true, true, true},
+               .supports_rmii          = {true, true, true, true, true},
+               .supports_rgmii         = {true, true, true, true, true},
+               .name                   = "SJA1105T",
+       },
+       [SJA1105P] = {
+               .device_id              = SJA1105PR_DEVICE_ID,
+               .part_no                = SJA1105P_PART_NO,
+               .static_ops             = sja1105pqrs_table_ops,
+               .setup_rgmii_delay      = sja1105pqrs_setup_rgmii_delay,
+               .reset_cmd              = sja1105pqrs_reset_cmd,
+               .regs                   = &sja1105pqrs_regs,
+               .port_speed             = {
+                       [SJA1105_SPEED_AUTO] = 0,
+                       [SJA1105_SPEED_10MBPS] = 3,
+                       [SJA1105_SPEED_100MBPS] = 2,
+                       [SJA1105_SPEED_1000MBPS] = 1,
+               },
+               .supports_mii           = {true, true, true, true, true},
+               .supports_rmii          = {true, true, true, true, true},
+               .supports_rgmii         = {true, true, true, true, true},
+               .name                   = "SJA1105P",
+       },
+       [SJA1105Q] = {
+               .device_id              = SJA1105QS_DEVICE_ID,
+               .part_no                = SJA1105Q_PART_NO,
+               .static_ops             = sja1105pqrs_table_ops,
+               .setup_rgmii_delay      = sja1105pqrs_setup_rgmii_delay,
+               .reset_cmd              = sja1105pqrs_reset_cmd,
+               .regs                   = &sja1105pqrs_regs,
+               .port_speed             = {
+                       [SJA1105_SPEED_AUTO] = 0,
+                       [SJA1105_SPEED_10MBPS] = 3,
+                       [SJA1105_SPEED_100MBPS] = 2,
+                       [SJA1105_SPEED_1000MBPS] = 1,
+               },
+               .supports_mii           = {true, true, true, true, true},
+               .supports_rmii          = {true, true, true, true, true},
+               .supports_rgmii         = {true, true, true, true, true},
+               .name                   = "SJA1105Q",
+       },
+       [SJA1105R] = {
+               .device_id              = SJA1105PR_DEVICE_ID,
+               .part_no                = SJA1105R_PART_NO,
+               .static_ops             = sja1105pqrs_table_ops,
+               .setup_rgmii_delay      = sja1105pqrs_setup_rgmii_delay,
+               .reset_cmd              = sja1105pqrs_reset_cmd,
+               .regs                   = &sja1105pqrs_regs,
+               .pcs_mdio_read          = sja1105_pcs_mdio_read,
+               .pcs_mdio_write         = sja1105_pcs_mdio_write,
+               .pma_config             = sja1105_pma_config,
+               .port_speed             = {
+                       [SJA1105_SPEED_AUTO] = 0,
+                       [SJA1105_SPEED_10MBPS] = 3,
+                       [SJA1105_SPEED_100MBPS] = 2,
+                       [SJA1105_SPEED_1000MBPS] = 1,
+               },
+               .supports_mii           = {true, true, true, true, true},
+               .supports_rmii          = {true, true, true, true, true},
+               .supports_rgmii         = {true, true, true, true, true},
+               .supports_sgmii         = {false, false, false, false, true},
+               .name                   = "SJA1105R",
+       },
+       [SJA1105S] = {
+               .device_id              = SJA1105QS_DEVICE_ID,
+               .part_no                = SJA1105S_PART_NO,
+               .static_ops             = sja1105pqrs_table_ops,
+               .setup_rgmii_delay      = sja1105pqrs_setup_rgmii_delay,
+               .reset_cmd              = sja1105pqrs_reset_cmd,
+               .regs                   = &sja1105pqrs_regs,
+               .pcs_mdio_read          = sja1105_pcs_mdio_read,
+               .pcs_mdio_write         = sja1105_pcs_mdio_write,
+               .pma_config             = sja1105_pma_config,
+               .port_speed             = {
+                       [SJA1105_SPEED_AUTO] = 0,
+                       [SJA1105_SPEED_10MBPS] = 3,
+                       [SJA1105_SPEED_100MBPS] = 2,
+                       [SJA1105_SPEED_1000MBPS] = 1,
+               },
+               .supports_mii           = {true, true, true, true, true},
+               .supports_rmii          = {true, true, true, true, true},
+               .supports_rgmii         = {true, true, true, true, true},
+               .supports_sgmii         = {false, false, false, false, true},
+               .name                   = "SJA1105S",
+       },
+       [SJA1110A] = {
+               .device_id              = SJA1110_DEVICE_ID,
+               .part_no                = SJA1110A_PART_NO,
+               .static_ops             = sja1110_table_ops,
+               .setup_rgmii_delay      = sja1110_setup_rgmii_delay,
+               .reset_cmd              = sja1110_reset_cmd,
+               .regs                   = &sja1110_regs,
+               .pcs_mdio_read          = sja1110_pcs_mdio_read,
+               .pcs_mdio_write         = sja1110_pcs_mdio_write,
+               .pma_config             = sja1110_pma_config,
+               .port_speed             = {
+                       [SJA1105_SPEED_AUTO] = 0,
+                       [SJA1105_SPEED_10MBPS] = 4,
+                       [SJA1105_SPEED_100MBPS] = 3,
+                       [SJA1105_SPEED_1000MBPS] = 2,
+               },
+               .supports_mii           = {true, true, true, true, false,
+                                          true, true, true, true, true, true},
+               .supports_rmii          = {false, false, true, true, false,
+                                          false, false, false, false, false, false},
+               .supports_rgmii         = {false, false, true, true, false,
+                                          false, false, false, false, false, false},
+               .supports_sgmii         = {false, true, true, true, true,
+                                          false, false, false, false, false, false},
+               .name                   = "SJA1110A",
+       },
+       [SJA1110B] = {
+               .device_id              = SJA1110_DEVICE_ID,
+               .part_no                = SJA1110B_PART_NO,
+               .static_ops             = sja1110_table_ops,
+               .setup_rgmii_delay      = sja1110_setup_rgmii_delay,
+               .reset_cmd              = sja1110_reset_cmd,
+               .regs                   = &sja1110_regs,
+               .pcs_mdio_read          = sja1110_pcs_mdio_read,
+               .pcs_mdio_write         = sja1110_pcs_mdio_write,
+               .pma_config             = sja1110_pma_config,
+               .port_speed             = {
+                       [SJA1105_SPEED_AUTO] = 0,
+                       [SJA1105_SPEED_10MBPS] = 4,
+                       [SJA1105_SPEED_100MBPS] = 3,
+                       [SJA1105_SPEED_1000MBPS] = 2,
+               },
+               .supports_mii           = {true, true, true, true, false,
+                                          true, true, true, true, true, false},
+               .supports_rmii          = {false, false, true, true, false,
+                                          false, false, false, false, false, false},
+               .supports_rgmii         = {false, false, true, true, false,
+                                          false, false, false, false, false, false},
+               .supports_sgmii         = {false, false, false, true, true,
+                                          false, false, false, false, false, false},
+               .name                   = "SJA1110B",
+       },
+       [SJA1110C] = {
+               .device_id              = SJA1110_DEVICE_ID,
+               .part_no                = SJA1110C_PART_NO,
+               .static_ops             = sja1110_table_ops,
+               .setup_rgmii_delay      = sja1110_setup_rgmii_delay,
+               .reset_cmd              = sja1110_reset_cmd,
+               .regs                   = &sja1110_regs,
+               .pcs_mdio_read          = sja1110_pcs_mdio_read,
+               .pcs_mdio_write         = sja1110_pcs_mdio_write,
+               .pma_config             = sja1110_pma_config,
+               .port_speed             = {
+                       [SJA1105_SPEED_AUTO] = 0,
+                       [SJA1105_SPEED_10MBPS] = 4,
+                       [SJA1105_SPEED_100MBPS] = 3,
+                       [SJA1105_SPEED_1000MBPS] = 2,
+               },
+               .supports_mii           = {true, true, true, true, false,
+                                          true, true, true, false, false, false},
+               .supports_rmii          = {false, false, true, true, false,
+                                          false, false, false, false, false, false},
+               .supports_rgmii         = {false, false, true, true, false,
+                                          false, false, false, false, false, false},
+               .supports_sgmii         = {false, false, false, false, true,
+                                          false, false, false, false, false, false},
+               .name                   = "SJA1110C",
+       },
+       [SJA1110D] = {
+               .device_id              = SJA1110_DEVICE_ID,
+               .part_no                = SJA1110D_PART_NO,
+               .static_ops             = sja1110_table_ops,
+               .setup_rgmii_delay      = sja1110_setup_rgmii_delay,
+               .reset_cmd              = sja1110_reset_cmd,
+               .regs                   = &sja1110_regs,
+               .pcs_mdio_read          = sja1110_pcs_mdio_read,
+               .pcs_mdio_write         = sja1110_pcs_mdio_write,
+               .pma_config             = sja1110_pma_config,
+               .port_speed             = {
+                       [SJA1105_SPEED_AUTO] = 0,
+                       [SJA1105_SPEED_10MBPS] = 4,
+                       [SJA1105_SPEED_100MBPS] = 3,
+                       [SJA1105_SPEED_1000MBPS] = 2,
+               },
+               .supports_mii           = {true, false, true, false, false,
+                                          true, true, true, false, false, false},
+               .supports_rmii          = {false, false, true, false, false,
+                                          false, false, false, false, false, false},
+               .supports_rgmii         = {false, false, true, false, false,
+                                          false, false, false, false, false, false},
+               .supports_sgmii         = {false, true, true, true, true,
+                                          false, false, false, false, false, false},
+               .name                   = "SJA1110D",
+       },
+};
+
+struct sja1105_status {
+       u64 configs;
+       u64 crcchkl;
+       u64 ids;
+       u64 crcchkg;
+};
+
+static void sja1105_status_unpack(void *buf, struct sja1105_status *status)
+{
+       sja1105_packing(buf, &status->configs, 31, 31, 4, UNPACK);
+       sja1105_packing(buf, &status->crcchkl, 30, 30, 4, UNPACK);
+       sja1105_packing(buf, &status->ids,     29, 29, 4, UNPACK);
+       sja1105_packing(buf, &status->crcchkg, 28, 28, 4, UNPACK);
+}
+
+static int sja1105_status_get(struct sja1105_private *priv,
+                             struct sja1105_status *status)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       u8 packed_buf[4];
+       int rc;
+
+       rc = sja1105_xfer_buf(priv, SPI_READ, regs->status, packed_buf, 4);
+       if (rc < 0)
+               return rc;
+
+       sja1105_status_unpack(packed_buf, status);
+
+       return 0;
+}
+
+/* Not const because unpacking priv->static_config into buffers and preparing
+ * for upload requires the recalculation of table CRCs and updating the
+ * structures with these.
+ */
+static int
+static_config_buf_prepare_for_upload(struct sja1105_private *priv,
+                                    void *config_buf, int buf_len)
+{
+       struct sja1105_static_config *config = &priv->static_config;
+       struct sja1105_table_header final_header;
+       char *final_header_ptr;
+       int crc_len;
+
+       /* Write Device ID and config tables to config_buf */
+       sja1105_static_config_pack(config_buf, config);
+       /* Recalculate CRC of the last header (right now 0xDEADBEEF).
+        * Don't include the CRC field itself.
+        */
+       crc_len = buf_len - 4;
+       /* Read the whole table header */
+       final_header_ptr = config_buf + buf_len - SJA1105_SIZE_TABLE_HEADER;
+       sja1105_table_header_packing(final_header_ptr, &final_header, UNPACK);
+       /* Modify */
+       final_header.crc = sja1105_crc32(config_buf, crc_len);
+       /* Rewrite */
+       sja1105_table_header_packing(final_header_ptr, &final_header, PACK);
+
+       return 0;
+}
+
+static int sja1105_static_config_upload(struct sja1105_private *priv)
+{
+       struct sja1105_static_config *config = &priv->static_config;
+       const struct sja1105_regs *regs = priv->info->regs;
+       struct sja1105_status status;
+       u8 *config_buf;
+       int buf_len;
+       int rc;
+
+       buf_len = sja1105_static_config_get_length(config);
+       config_buf = calloc(buf_len, sizeof(char));
+       if (!config_buf)
+               return -ENOMEM;
+
+       rc = static_config_buf_prepare_for_upload(priv, config_buf, buf_len);
+       if (rc < 0) {
+               printf("Invalid config, cannot upload\n");
+               rc = -EINVAL;
+               goto out;
+       }
+       /* Put the SJA1105 in programming mode */
+       rc = priv->info->reset_cmd(priv);
+       if (rc < 0) {
+               printf("Failed to reset switch\n");
+               goto out;
+       }
+       /* Wait for the switch to come out of reset */
+       udelay(1000);
+       /* Upload the static config to the device */
+       rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->config,
+                             config_buf, buf_len);
+       if (rc < 0) {
+               printf("Failed to upload config\n");
+               goto out;
+       }
+       /* Check that SJA1105 responded well to the config upload */
+       rc = sja1105_status_get(priv, &status);
+       if (rc < 0)
+               goto out;
+
+       if (status.ids == 1) {
+               printf("Mismatch between hardware and static config device id. "
+                      "Wrote 0x%llx, wants 0x%llx\n",
+                      config->device_id, priv->info->device_id);
+               rc = -EIO;
+               goto out;
+       }
+       if (status.crcchkl == 1 || status.crcchkg == 1) {
+               printf("Switch reported invalid CRC on static config\n");
+               rc = -EIO;
+               goto out;
+       }
+       if (status.configs == 0) {
+               printf("Switch reported that config is invalid\n");
+               rc = -EIO;
+               goto out;
+       }
+
+out:
+       free(config_buf);
+       return rc;
+}
+
+static int sja1105_static_config_reload(struct sja1105_private *priv)
+{
+       int rc;
+
+       rc = sja1105_static_config_upload(priv);
+       if (rc < 0) {
+               printf("Failed to load static config: %d\n", rc);
+               return rc;
+       }
+
+       /* Configure the CGU (PHY link modes and speeds) */
+       rc = sja1105_clocking_setup(priv);
+       if (rc < 0) {
+               printf("Failed to configure MII clocking: %d\n", rc);
+               return rc;
+       }
+
+       return 0;
+}
+
+static int sja1105_port_probe(struct udevice *dev, int port,
+                             struct phy_device *phy)
+{
+       struct sja1105_private *priv = dev_get_priv(dev);
+       ofnode node = dsa_port_get_ofnode(dev, port);
+       phy_interface_t phy_mode = phy->interface;
+
+       priv->xpcs_cfg[port].inband_an = ofnode_eth_uses_inband_aneg(node);
+
+       if (phy_mode == PHY_INTERFACE_MODE_MII ||
+           phy_mode == PHY_INTERFACE_MODE_RMII) {
+               phy->supported &= PHY_BASIC_FEATURES;
+               phy->advertising &= PHY_BASIC_FEATURES;
+       } else {
+               phy->supported &= PHY_GBIT_FEATURES;
+               phy->advertising &= PHY_GBIT_FEATURES;
+       }
+
+       return phy_config(phy);
+}
+
+static int sja1105_port_enable(struct udevice *dev, int port,
+                              struct phy_device *phy)
+{
+       struct sja1105_private *priv = dev_get_priv(dev);
+       phy_interface_t phy_mode = phy->interface;
+       struct sja1105_xmii_params_entry *mii;
+       struct sja1105_mac_config_entry *mac;
+       int rc;
+
+       rc = phy_startup(phy);
+       if (rc)
+               return rc;
+
+       mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
+       mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
+
+       switch (phy_mode) {
+       case PHY_INTERFACE_MODE_MII:
+               if (!priv->info->supports_mii[port])
+                       goto unsupported;
+
+               mii->xmii_mode[port] = XMII_MODE_MII;
+               break;
+       case PHY_INTERFACE_MODE_RMII:
+               if (!priv->info->supports_rmii[port])
+                       goto unsupported;
+
+               mii->xmii_mode[port] = XMII_MODE_RMII;
+               break;
+       case PHY_INTERFACE_MODE_RGMII:
+       case PHY_INTERFACE_MODE_RGMII_ID:
+       case PHY_INTERFACE_MODE_RGMII_RXID:
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+               if (!priv->info->supports_rgmii[port])
+                       goto unsupported;
+
+               mii->xmii_mode[port] = XMII_MODE_RGMII;
+               break;
+       case PHY_INTERFACE_MODE_SGMII:
+               if (!priv->info->supports_sgmii[port])
+                       goto unsupported;
+
+               mii->xmii_mode[port] = XMII_MODE_SGMII;
+               mii->special[port] = true;
+               break;
+unsupported:
+       default:
+               dev_err(dev, "Unsupported PHY mode %d on port %d!\n",
+                       phy_mode, port);
+               return -EINVAL;
+       }
+
+       /* RevMII, RevRMII not supported */
+       mii->phy_mac[port] = XMII_MAC;
+
+       /* Let the PHY handle the RGMII delays, if present. */
+       if (phy->phy_id == PHY_FIXED_ID) {
+               if (phy_mode == PHY_INTERFACE_MODE_RGMII_RXID ||
+                   phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
+                       priv->rgmii_rx_delay[port] = true;
+
+               if (phy_mode == PHY_INTERFACE_MODE_RGMII_TXID ||
+                   phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
+                       priv->rgmii_tx_delay[port] = true;
+
+               if ((priv->rgmii_rx_delay[port] ||
+                    priv->rgmii_tx_delay[port]) &&
+                    !priv->info->setup_rgmii_delay) {
+                       printf("Chip does not support internal RGMII delays\n");
+                       return -EINVAL;
+               }
+       }
+
+       if (mii->xmii_mode[port] == XMII_MODE_SGMII) {
+               mac[port].speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS];
+               priv->xpcs_cfg[port].speed = phy->speed;
+       } else if (phy->speed == SPEED_1000) {
+               mac[port].speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS];
+       } else if (phy->speed == SPEED_100) {
+               mac[port].speed = priv->info->port_speed[SJA1105_SPEED_100MBPS];
+       } else if (phy->speed == SPEED_10) {
+               mac[port].speed = priv->info->port_speed[SJA1105_SPEED_10MBPS];
+       } else {
+               printf("Invalid PHY speed %d on port %d\n", phy->speed, port);
+               return -EINVAL;
+       }
+
+       return sja1105_static_config_reload(priv);
+}
+
+static void sja1105_port_disable(struct udevice *dev, int port,
+                                struct phy_device *phy)
+{
+       phy_shutdown(phy);
+}
+
+static int sja1105_xmit(struct udevice *dev, int port, void *packet, int length)
+{
+       struct sja1105_private *priv = dev_get_priv(dev);
+       u8 *from = (u8 *)packet + VLAN_HLEN;
+       struct vlan_ethhdr *hdr = packet;
+       u8 *dest = (u8 *)packet;
+
+       memmove(dest, from, 2 * ETH_ALEN);
+       hdr->h_vlan_proto = htons(ETH_P_SJA1105);
+       hdr->h_vlan_TCI = htons(priv->pvid[port]);
+
+       return 0;
+}
+
+static int sja1105_rcv(struct udevice *dev, int *port, void *packet, int length)
+{
+       struct vlan_ethhdr *hdr = packet;
+       u8 *dest = packet + VLAN_HLEN;
+       u8 *from = packet;
+
+       if (ntohs(hdr->h_vlan_proto) != ETH_P_SJA1105)
+               return -EINVAL;
+
+       *port = ntohs(hdr->h_vlan_TCI) & DSA_8021Q_PORT_MASK;
+       memmove(dest, from, 2 * ETH_ALEN);
+
+       return 0;
+}
+
+static const struct dsa_ops sja1105_dsa_ops = {
+       .port_probe     = sja1105_port_probe,
+       .port_enable    = sja1105_port_enable,
+       .port_disable   = sja1105_port_disable,
+       .xmit           = sja1105_xmit,
+       .rcv            = sja1105_rcv,
+};
+
+static int sja1105_init(struct sja1105_private *priv)
+{
+       int rc;
+
+       rc = sja1105_static_config_init(priv);
+       if (rc) {
+               printf("Failed to initialize static config: %d\n", rc);
+               return rc;
+       }
+
+       rc = sja1105_mdiobus_register(priv);
+       if (rc) {
+               printf("Failed to register MDIO bus: %d\n", rc);
+               goto err_mdiobus_register;
+       }
+
+       return 0;
+
+err_mdiobus_register:
+       sja1105_static_config_free(&priv->static_config);
+
+       return rc;
+}
+
+static int sja1105_check_device_id(struct sja1105_private *priv)
+{
+       const struct sja1105_regs *regs = priv->info->regs;
+       u8 packed_buf[SJA1105_SIZE_DEVICE_ID] = {0};
+       enum sja1105_switch_id id;
+       u64 device_id;
+       u64 part_no;
+       int rc;
+
+       rc = sja1105_xfer_buf(priv, SPI_READ, regs->device_id, packed_buf,
+                             SJA1105_SIZE_DEVICE_ID);
+       if (rc < 0)
+               return rc;
+
+       sja1105_packing(packed_buf, &device_id, 31, 0, SJA1105_SIZE_DEVICE_ID,
+                       UNPACK);
+
+       if (device_id != priv->info->device_id) {
+               printf("Expected device ID 0x%llx but read 0x%llx\n",
+                      priv->info->device_id, device_id);
+               return -ENODEV;
+       }
+
+       rc = sja1105_xfer_buf(priv, SPI_READ, regs->prod_id, packed_buf,
+                             SJA1105_SIZE_DEVICE_ID);
+       if (rc < 0)
+               return rc;
+
+       sja1105_packing(packed_buf, &part_no, 19, 4, SJA1105_SIZE_DEVICE_ID,
+                       UNPACK);
+
+       for (id = 0; id < SJA1105_MAX_SWITCH_ID; id++) {
+               const struct sja1105_info *info = &sja1105_info[id];
+
+               /* Is what's been probed in our match table at all? */
+               if (info->device_id != device_id || info->part_no != part_no)
+                       continue;
+
+               /* But is it what's in the device tree? */
+               if (priv->info->device_id != device_id ||
+                   priv->info->part_no != part_no) {
+                       printf("Device tree specifies chip %s but found %s, please fix it!\n",
+                              priv->info->name, info->name);
+                       /* It isn't. No problem, pick that up. */
+                       priv->info = info;
+               }
+
+               return 0;
+       }
+
+       printf("Unexpected {device ID, part number}: 0x%llx 0x%llx\n",
+              device_id, part_no);
+
+       return -ENODEV;
+}
+
+static int sja1105_probe(struct udevice *dev)
+{
+       enum sja1105_switch_id id = dev_get_driver_data(dev);
+       struct sja1105_private *priv = dev_get_priv(dev);
+       int rc;
+
+       if (ofnode_valid(dev_ofnode(dev)) &&
+           !ofnode_is_available(dev_ofnode(dev))) {
+               dev_dbg(dev, "switch disabled\n");
+               return -ENODEV;
+       }
+
+       priv->info = &sja1105_info[id];
+       priv->dev = dev;
+
+       rc = sja1105_check_device_id(priv);
+       if (rc < 0) {
+               dev_err(dev, "Device ID check failed: %d\n", rc);
+               return rc;
+       }
+
+       dsa_set_tagging(dev, VLAN_HLEN, 0);
+
+       return sja1105_init(priv);
+}
+
+static int sja1105_remove(struct udevice *dev)
+{
+       struct sja1105_private *priv = dev_get_priv(dev);
+
+       sja1105_mdiobus_unregister(priv);
+       sja1105_static_config_free(&priv->static_config);
+
+       return 0;
+}
+
+static const struct udevice_id sja1105_ids[] = {
+       { .compatible = "nxp,sja1105e", .data = SJA1105E },
+       { .compatible = "nxp,sja1105t", .data = SJA1105T },
+       { .compatible = "nxp,sja1105p", .data = SJA1105P },
+       { .compatible = "nxp,sja1105q", .data = SJA1105Q },
+       { .compatible = "nxp,sja1105r", .data = SJA1105R },
+       { .compatible = "nxp,sja1105s", .data = SJA1105S },
+       { .compatible = "nxp,sja1110a", .data = SJA1110A },
+       { .compatible = "nxp,sja1110b", .data = SJA1110B },
+       { .compatible = "nxp,sja1110c", .data = SJA1110C },
+       { .compatible = "nxp,sja1110d", .data = SJA1110D },
+       { }
+};
+
+U_BOOT_DRIVER(sja1105) = {
+       .name           = "sja1105",
+       .id             = UCLASS_DSA,
+       .of_match       = sja1105_ids,
+       .probe          = sja1105_probe,
+       .remove         = sja1105_remove,
+       .ops            = &sja1105_dsa_ops,
+       .priv_auto      = sizeof(struct sja1105_private),
+};
index 0ce9765..beca886 100644 (file)
@@ -156,6 +156,19 @@ static int tsec_mcast_addr(struct udevice *dev, const u8 *mcast_mac, int join)
        return 0;
 }
 
+static int __maybe_unused tsec_set_promisc(struct udevice *dev, bool enable)
+{
+       struct tsec_private *priv = dev_get_priv(dev);
+       struct tsec __iomem *regs = priv->regs;
+
+       if (enable)
+               setbits_be32(&regs->rctrl, RCTRL_PROM);
+       else
+               clrbits_be32(&regs->rctrl, RCTRL_PROM);
+
+       return 0;
+}
+
 /*
  * Initialized required registers to appropriate values, zeroing
  * those we don't care about (unless zero is bad, in which case,
@@ -186,8 +199,6 @@ static void init_registers(struct tsec __iomem *regs)
        out_be32(&regs->hash.gaddr6, 0);
        out_be32(&regs->hash.gaddr7, 0);
 
-       out_be32(&regs->rctrl, 0x00000000);
-
        /* Init RMON mib registers */
        memset((void *)&regs->rmon, 0, sizeof(regs->rmon));
 
@@ -432,7 +443,7 @@ static void tsec_halt(struct udevice *dev)
  * of the eTSEC port initialization sequence,
  * the eTSEC Rx logic may not be properly initialized.
  */
-void redundant_init(struct tsec_private *priv)
+static void redundant_init(struct tsec_private *priv)
 {
        struct tsec __iomem *regs = priv->regs;
        uint t, count = 0;
@@ -454,7 +465,7 @@ void redundant_init(struct tsec_private *priv)
                0x71, 0x72};
 
        /* Enable promiscuous mode */
-       setbits_be32(&regs->rctrl, 0x8);
+       setbits_be32(&regs->rctrl, RCTRL_PROM);
        /* Enable loopback mode */
        setbits_be32(&regs->maccfg1, MACCFG1_LOOPBACK);
        /* Enable transmit and receive */
@@ -506,7 +517,7 @@ void redundant_init(struct tsec_private *priv)
        if (fail)
                panic("eTSEC init fail!\n");
        /* Disable promiscuous mode */
-       clrbits_be32(&regs->rctrl, 0x8);
+       clrbits_be32(&regs->rctrl, RCTRL_PROM);
        /* Disable loopback mode */
        clrbits_be32(&regs->maccfg1, MACCFG1_LOOPBACK);
 }
@@ -932,6 +943,7 @@ static const struct eth_ops tsec_ops = {
        .free_pkt = tsec_free_pkt,
        .stop = tsec_halt,
        .mcast = tsec_mcast_addr,
+       .set_promisc = tsec_set_promisc,
 };
 
 static struct tsec_data etsec2_data = {
index 4e94b77..6d73aab 100644 (file)
 #define PCIE_CONFIG_WR_TYPE0                   0xa
 #define PCIE_CONFIG_WR_TYPE1                   0xb
 
-/* PCI_BDF shifts 8bit, so we need extra 4bit shift */
-#define PCIE_BDF(b, d, f)                      (PCI_BDF(b, d, f) << 4)
-#define PCIE_CONF_BUS(bus)                     (((bus) & 0xff) << 20)
-#define PCIE_CONF_DEV(dev)                     (((dev) & 0x1f) << 15)
-#define PCIE_CONF_FUNC(fun)                    (((fun) & 0x7)  << 12)
-#define PCIE_CONF_REG(reg)                     ((reg) & 0xffc)
-#define PCIE_CONF_ADDR(bus, devfn, where)      \
-       (PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn))    | \
-        PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where))
-
 /* PCIe Retries & Timeout definitions */
 #define PIO_MAX_RETRIES                                1500
 #define PIO_WAIT_TIMEOUT                       1000
@@ -468,7 +458,7 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf,
        advk_writel(pcie, reg, PIO_CTRL);
 
        /* Program the address registers */
-       reg = PCIE_BDF(busno, PCI_DEV(bdf), PCI_FUNC(bdf)) | PCIE_CONF_REG(offset);
+       reg = PCIE_ECAM_OFFSET(busno, PCI_DEV(bdf), PCI_FUNC(bdf), (offset & ~0x3));
        advk_writel(pcie, reg, PIO_ADDR_LS);
        advk_writel(pcie, 0, PIO_ADDR_MS);
 
@@ -628,7 +618,7 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf,
        advk_writel(pcie, reg, PIO_CTRL);
 
        /* Program the address registers */
-       reg = PCIE_BDF(busno, PCI_DEV(bdf), PCI_FUNC(bdf)) | PCIE_CONF_REG(offset);
+       reg = PCIE_ECAM_OFFSET(busno, PCI_DEV(bdf), PCI_FUNC(bdf), (offset & ~0x3));
        advk_writel(pcie, reg, PIO_ADDR_LS);
        advk_writel(pcie, 0, PIO_ADDR_MS);
        dev_dbg(pcie->dev, "\tPIO req. - addr = 0x%08x\n", reg);
index e83e5af..1a9f9ae 100644 (file)
@@ -14,6 +14,8 @@
 
 #include <asm/io.h>
 
+#define TYPE_PCI 0x1
+
 /**
  * struct generic_ecam_pcie - generic_ecam PCIe controller state
  * @cfg_base: The base address of memory mapped configuration space
@@ -46,10 +48,14 @@ static int pci_generic_ecam_conf_address(const struct udevice *bus,
        void *addr;
 
        addr = pcie->cfg_base;
-       addr += (PCI_BUS(bdf) - pcie->first_busno) << 20;
-       addr += PCI_DEV(bdf) << 15;
-       addr += PCI_FUNC(bdf) << 12;
-       addr += offset;
+
+       if (dev_get_driver_data(bus) == TYPE_PCI) {
+               addr += ((PCI_BUS(bdf) - pcie->first_busno) << 16) |
+                        (PCI_DEV(bdf) << 11) | (PCI_FUNC(bdf) << 8) | offset;
+       } else {
+               addr += PCIE_ECAM_OFFSET(PCI_BUS(bdf) - pcie->first_busno,
+                                        PCI_DEV(bdf), PCI_FUNC(bdf), offset);
+       }
        *paddress = addr;
 
        return 0;
@@ -158,7 +164,8 @@ static const struct dm_pci_ops pci_generic_ecam_ops = {
 };
 
 static const struct udevice_id pci_generic_ecam_ids[] = {
-       { .compatible = "pci-host-ecam-generic" },
+       { .compatible = "pci-host-ecam-generic" /* PCI-E */ },
+       { .compatible = "pci-host-cam-generic", .data = TYPE_PCI },
        { }
 };
 
index c6e7c59..e3e2289 100644 (file)
@@ -235,10 +235,8 @@ static int pci_synquacer_ecam_conf_address(const struct udevice *bus,
        void *addr;
 
        addr = pcie->cfg_base;
-       addr += (PCI_BUS(bdf) - pcie->first_busno) << 20;
-       addr += PCI_DEV(bdf) << 15;
-       addr += PCI_FUNC(bdf) << 12;
-       addr += offset;
+       addr += PCIE_ECAM_OFFSET(PCI_BUS(bdf) - pcie->first_busno,
+                                PCI_DEV(bdf), PCI_FUNC(bdf), offset);
        *paddress = addr;
 
        return 0;
index 752e170..a807276 100644 (file)
@@ -36,9 +36,7 @@ static int phytium_pci_skip_dev(pci_dev_t parent)
        unsigned short capreg;
        unsigned char port_type;
 
-       addr += PCI_BUS(parent) << 20;
-       addr += PCI_DEV(parent) << 15;
-       addr += PCI_FUNC(parent) << 12;
+       addr += PCIE_ECAM_OFFSET(PCI_BUS(parent), PCI_DEV(parent), PCI_FUNC(parent), 0);
 
        pos = 0x34;
        while (1) {
@@ -89,9 +87,7 @@ static int pci_phytium_conf_address(const struct udevice *bus, pci_dev_t bdf,
        bdf_parent = PCI_BDF((bus_no - 1), 0, 0);
 
        addr = pcie->cfg_base;
-       addr += PCI_BUS(bdf) << 20;
-       addr += PCI_DEV(bdf) << 15;
-       addr += PCI_FUNC(bdf) << 12;
+       addr += PCIE_ECAM_OFFSET(PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), 0);
 
        if (bus_no > 0 && dev_no > 0) {
                if ((readb(addr + PCI_HEADER_TYPE) & 0x7f) !=
index b0c91c0..67039d2 100644 (file)
@@ -101,15 +101,6 @@ struct rockchip_pcie {
        struct phy pcie_phy;
 };
 
-static int rockchip_pcie_off_conf(pci_dev_t bdf, uint offset)
-{
-       unsigned int bus = PCI_BUS(bdf);
-       unsigned int dev = PCI_DEV(bdf);
-       unsigned int func = PCI_FUNC(bdf);
-
-       return (bus << 20) | (dev << 15) | (func << 12) | (offset & ~0x3);
-}
-
 static int rockchip_pcie_rd_conf(const struct udevice *udev, pci_dev_t bdf,
                                 uint offset, ulong *valuep,
                                 enum pci_size_t size)
@@ -117,7 +108,7 @@ static int rockchip_pcie_rd_conf(const struct udevice *udev, pci_dev_t bdf,
        struct rockchip_pcie *priv = dev_get_priv(udev);
        unsigned int bus = PCI_BUS(bdf);
        unsigned int dev = PCI_DEV(bdf);
-       int where = rockchip_pcie_off_conf(bdf, offset);
+       int where = PCIE_ECAM_OFFSET(PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), offset & ~0x3);
        ulong value;
 
        if (bus == priv->first_busno && dev == 0) {
@@ -144,7 +135,7 @@ static int rockchip_pcie_wr_conf(struct udevice *udev, pci_dev_t bdf,
        struct rockchip_pcie *priv = dev_get_priv(udev);
        unsigned int bus = PCI_BUS(bdf);
        unsigned int dev = PCI_DEV(bdf);
-       int where = rockchip_pcie_off_conf(bdf, offset);
+       int where = PCIE_ECAM_OFFSET(PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), offset & ~0x3);
        ulong old;
 
        if (bus == priv->first_busno && dev == 0) {
index ae9a65b..eb9ec97 100644 (file)
@@ -76,10 +76,7 @@ static int pcie_xilinx_config_address(const struct udevice *udev, pci_dev_t bdf,
                return -ENODEV;
 
        addr = pcie->cfg_base;
-       addr += bus << 20;
-       addr += dev << 15;
-       addr += func << 12;
-       addr += offset;
+       addr += PCIE_ECAM_OFFSET(bus, dev, func, offset);
        *paddress = addr;
 
        return 0;
index 141ece4..ef924e7 100644 (file)
@@ -616,8 +616,8 @@ static int cdns_torrent_phy_probe(struct udevice *dev)
 
        /* Going through all the available subnodes or children*/
        ofnode_for_each_subnode(child, dev_ofnode(dev)) {
-               /* PHY subnode name must be a 'link' */
-               if (!ofnode_name_eq(child, "link"))
+               /* PHY subnode name must be a 'phy' */
+               if (!ofnode_name_eq(child, "phy"))
                        continue;
                cdns_phy->phys[node].lnk_rst =
                                devm_reset_bulk_get_by_node(dev, child);
index 30eaa37..0394624 100644 (file)
@@ -145,6 +145,17 @@ config SPL_PINCONF_RECURSIVE
 
 if PINCTRL || SPL_PINCTRL
 
+config PINCTRL_APPLE
+       bool "Apple pinctrl driver"
+       depends on DM && PINCTRL_GENERIC && ARCH_APPLE
+       default y
+       help
+         Support pin multiplexing on Apple SoCs.
+
+         The driver is controlled by a device tree node which contains
+         both the GPIO definitions and pin control functions for each
+         available multiplex function.
+
 config PINCTRL_AR933X
        bool "QCA/Athores ar933x pin control driver"
        depends on DM && SOC_AR933X
@@ -291,6 +302,15 @@ config ASPEED_AST2500_PINCTRL
          uses Generic Pinctrl framework and is compatible with the Linux
          driver, i.e. it uses the same device tree configuration.
 
+config ASPEED_AST2600_PINCTRL
+       bool "Aspeed AST2600 pin control driver"
+       depends on DM && PINCTRL_GENERIC && ASPEED_AST2600
+       default y
+       help
+         Support pin multiplexing control on Aspeed ast2600 SoC. The driver
+         uses Generic Pinctrl framework and is compatible with the Linux
+         driver, i.e. it uses the same device tree configuration.
+
 config PINCTRL_K210
        bool "Kendryte K210 Fully-Programmable Input/Output Array driver"
        depends on DM && PINCTRL_GENERIC
index 05b71f2..fd736a7 100644 (file)
@@ -3,6 +3,7 @@
 obj-y                                  += pinctrl-uclass.o
 obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC)   += pinctrl-generic.o
 
+obj-$(CONFIG_PINCTRL_APPLE)            += pinctrl-apple.o
 obj-$(CONFIG_PINCTRL_AT91)             += pinctrl-at91.o
 obj-$(CONFIG_PINCTRL_AT91PIO4)         += pinctrl-at91-pio4.o
 obj-y                                  += nxp/
index 2e6ed60..a3e01ed 100644 (file)
@@ -1 +1,2 @@
 obj-$(CONFIG_ASPEED_AST2500_PINCTRL) += pinctrl_ast2500.o
+obj-$(CONFIG_ASPEED_AST2600_PINCTRL) += pinctrl_ast2600.o
diff --git a/drivers/pinctrl/aspeed/pinctrl_ast2600.c b/drivers/pinctrl/aspeed/pinctrl_ast2600.c
new file mode 100644 (file)
index 0000000..12cba83
--- /dev/null
@@ -0,0 +1,459 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) ASPEED Technology Inc.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/arch/pinctrl.h>
+#include <asm/arch/scu_ast2600.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+
+/*
+ * This driver works with very simple configuration that has the same name
+ * for group and function. This way it is compatible with the Linux Kernel
+ * driver.
+ */
+struct aspeed_sig_desc {
+       u32 offset;
+       u32 reg_set;
+       int clr;
+};
+
+struct aspeed_group_config {
+       char *group_name;
+       int ndescs;
+       struct aspeed_sig_desc *descs;
+};
+
+struct ast2600_pinctrl_priv {
+       struct ast2600_scu *scu;
+};
+
+static int ast2600_pinctrl_probe(struct udevice *dev)
+{
+       struct ast2600_pinctrl_priv *priv = dev_get_priv(dev);
+       struct udevice *clk_dev;
+       int ret = 0;
+
+       /* find SCU base address from clock device */
+       uclass_get_device_by_driver(UCLASS_CLK, DM_DRIVER_GET(aspeed_ast2600_scu), &clk_dev);
+
+       if (ret)
+               return ret;
+
+       priv->scu = dev_read_addr_ptr(clk_dev);
+       if (IS_ERR(priv->scu))
+               return PTR_ERR(priv->scu);
+
+       return 0;
+}
+
+static struct aspeed_sig_desc i2c1_link[] = {
+       { 0x418, GENMASK(9, 8), 1 },
+       { 0x4B8, GENMASK(9, 8), 0 },
+};
+
+static struct aspeed_sig_desc i2c2_link[] = {
+       { 0x418, GENMASK(11, 10), 1 },
+       { 0x4B8, GENMASK(11, 10), 0 },
+};
+
+static struct aspeed_sig_desc i2c3_link[] = {
+       { 0x418, GENMASK(13, 12), 1 },
+       { 0x4B8, GENMASK(13, 12), 0 },
+};
+
+static struct aspeed_sig_desc i2c4_link[] = {
+       { 0x418, GENMASK(15, 14), 1 },
+       { 0x4B8, GENMASK(15, 14), 0 },
+};
+
+static struct aspeed_sig_desc i2c5_link[] = {
+       { 0x418, GENMASK(17, 16), 0 },
+};
+
+static struct aspeed_sig_desc i2c6_link[] = {
+       { 0x418, GENMASK(19, 18), 0 },
+};
+
+static struct aspeed_sig_desc i2c7_link[] = {
+       { 0x418, GENMASK(21, 20), 0 },
+};
+
+static struct aspeed_sig_desc i2c8_link[] = {
+       { 0x418, GENMASK(23, 22), 0 },
+};
+
+static struct aspeed_sig_desc i2c9_link[] = {
+       { 0x418, GENMASK(25, 24), 0 },
+};
+
+static struct aspeed_sig_desc i2c10_link[] = {
+       { 0x418, GENMASK(27, 26), 0 },
+};
+
+static struct aspeed_sig_desc i2c11_link[] = {
+       { 0x410, GENMASK(1, 0), 1 },
+       { 0x4B0, GENMASK(1, 0), 0 },
+};
+
+static struct aspeed_sig_desc i2c12_link[] = {
+       { 0x410, GENMASK(3, 2), 1 },
+       { 0x4B0, GENMASK(3, 2), 0 },
+};
+
+static struct aspeed_sig_desc i2c13_link[] = {
+       { 0x410, GENMASK(5, 4), 1 },
+       { 0x4B0, GENMASK(5, 4), 0 },
+};
+
+static struct aspeed_sig_desc i2c14_link[] = {
+       { 0x410, GENMASK(7, 6), 1 },
+       { 0x4B0, GENMASK(7, 6), 0 },
+};
+
+static struct aspeed_sig_desc i2c15_link[] = {
+       { 0x414, GENMASK(29, 28), 1 },
+       { 0x4B4, GENMASK(29, 28), 0 },
+};
+
+static struct aspeed_sig_desc i2c16_link[] = {
+       { 0x414, GENMASK(31, 30), 1 },
+       { 0x4B4, GENMASK(31, 30), 0 },
+};
+
+static struct aspeed_sig_desc mac1_link[] = {
+       { 0x410, BIT(4), 0 },
+       { 0x470, BIT(4), 1 },
+};
+
+static struct aspeed_sig_desc mac2_link[] = {
+       { 0x410, BIT(5), 0 },
+       { 0x470, BIT(5), 1 },
+};
+
+static struct aspeed_sig_desc mac3_link[] = {
+       { 0x410, BIT(6), 0 },
+       { 0x470, BIT(6), 1 },
+};
+
+static struct aspeed_sig_desc mac4_link[] = {
+       { 0x410, BIT(7), 0 },
+       { 0x470, BIT(7), 1 },
+};
+
+static struct aspeed_sig_desc rgmii1[] = {
+       { 0x500, BIT(6),         0 },
+       { 0x400, GENMASK(11, 0), 0 },
+};
+
+static struct aspeed_sig_desc rgmii2[] = {
+       { 0x500, BIT(7),          0 },
+       { 0x400, GENMASK(23, 12), 0 },
+};
+
+static struct aspeed_sig_desc rgmii3[] = {
+       { 0x510, BIT(0),          0 },
+       { 0x410, GENMASK(27, 16), 0 },
+};
+
+static struct aspeed_sig_desc rgmii4[] = {
+       { 0x510, BIT(1),          0 },
+       { 0x410, GENMASK(31, 28), 1 },
+       { 0x4b0, GENMASK(31, 28), 0 },
+       { 0x474, GENMASK(7, 0),   1 },
+       { 0x414, GENMASK(7, 0),   1 },
+       { 0x4b4, GENMASK(7, 0),   0 },
+};
+
+static struct aspeed_sig_desc rmii1[] = {
+       { 0x504, BIT(6),         0 },
+       { 0x400, GENMASK(3, 0),  0 },
+       { 0x400, GENMASK(11, 6), 0 },
+};
+
+static struct aspeed_sig_desc rmii2[] = {
+       { 0x504, BIT(7),          0 },
+       { 0x400, GENMASK(15, 12), 0 },
+       { 0x400, GENMASK(23, 18), 0 },
+};
+
+static struct aspeed_sig_desc rmii3[] = {
+       { 0x514, BIT(0),          0 },
+       { 0x410, GENMASK(27, 22), 0 },
+       { 0x410, GENMASK(19, 16), 0 },
+};
+
+static struct aspeed_sig_desc rmii4[] = {
+       { 0x514, BIT(1),          0 },
+       { 0x410, GENMASK(7, 2),   1 },
+       { 0x410, GENMASK(31, 28), 1 },
+       { 0x414, GENMASK(7, 2),   1 },
+       { 0x4B0, GENMASK(31, 28), 0 },
+       { 0x4B4, GENMASK(7, 2),   0 },
+};
+
+static struct aspeed_sig_desc rmii1_rclk_oe[] = {
+       { 0x340, BIT(29), 0 },
+};
+
+static struct aspeed_sig_desc rmii2_rclk_oe[] = {
+       { 0x340, BIT(30), 0 },
+};
+
+static struct aspeed_sig_desc rmii3_rclk_oe[] = {
+       { 0x350, BIT(29), 0 },
+};
+
+static struct aspeed_sig_desc rmii4_rclk_oe[] = {
+       { 0x350, BIT(30), 0 },
+};
+
+static struct aspeed_sig_desc mdio1_link[] = {
+       { 0x430, BIT(17) | BIT(16), 0 },
+};
+
+static struct aspeed_sig_desc mdio2_link[] = {
+       { 0x470, BIT(13) | BIT(12), 1 },
+       { 0x410, BIT(13) | BIT(12), 0 },
+};
+
+static struct aspeed_sig_desc mdio3_link[] = {
+       { 0x470, BIT(1) | BIT(0), 1 },
+       { 0x410, BIT(1) | BIT(0), 0 },
+};
+
+static struct aspeed_sig_desc mdio4_link[] = {
+       { 0x470, BIT(3) | BIT(2), 1 },
+       { 0x410, BIT(3) | BIT(2), 0 },
+};
+
+static struct aspeed_sig_desc sdio2_link[] = {
+       { 0x414, GENMASK(23, 16), 1 },
+       { 0x4B4, GENMASK(23, 16), 0 },
+       { 0x450, BIT(1),          0 },
+};
+
+static struct aspeed_sig_desc sdio1_link[] = {
+       { 0x414, GENMASK(15, 8), 0 },
+};
+
+/* when sdio1 8bits, sdio2 can't use */
+static struct aspeed_sig_desc sdio1_8bit_link[] = {
+       { 0x414, GENMASK(15, 8),  0 },
+       { 0x4b4, GENMASK(21, 18), 0 },
+       { 0x450, BIT(3),          0 },
+       { 0x450, BIT(1),          1 },
+};
+
+static struct aspeed_sig_desc emmc_link[] = {
+       { 0x400, GENMASK(31, 24), 0 },
+};
+
+static struct aspeed_sig_desc emmcg8_link[] = {
+       { 0x400, GENMASK(31, 24), 0 },
+       { 0x404, GENMASK(3, 0),   0 },
+/* set SCU504 to clear the strap bits in SCU500 */
+       { 0x504, BIT(3),          0 },
+       { 0x504, BIT(5),          0 },
+};
+
+static struct aspeed_sig_desc fmcquad_link[] = {
+       { 0x438, GENMASK(5, 4), 0 },
+};
+
+static struct aspeed_sig_desc spi1_link[] = {
+       { 0x438, GENMASK(13, 11), 0 },
+};
+
+static struct aspeed_sig_desc spi1abr_link[] = {
+       { 0x438, BIT(9), 0 },
+};
+
+static struct aspeed_sig_desc spi1cs1_link[] = {
+       { 0x438, BIT(8), 0 },
+};
+
+static struct aspeed_sig_desc spi1wp_link[] = {
+       { 0x438, BIT(10), 0 },
+};
+
+static struct aspeed_sig_desc spi1quad_link[] = {
+       { 0x438, GENMASK(15, 14), 0 },
+};
+
+static struct aspeed_sig_desc spi2_link[] = {
+       { 0x434, GENMASK(29, 27) | BIT(24), 0 },
+};
+
+static struct aspeed_sig_desc spi2cs1_link[] = {
+       { 0x434, BIT(25), 0 },
+};
+
+static struct aspeed_sig_desc spi2cs2_link[] = {
+       { 0x434, BIT(26), 0 },
+};
+
+static struct aspeed_sig_desc spi2quad_link[] = {
+       { 0x434, GENMASK(31, 30), 0 },
+};
+
+static struct aspeed_sig_desc fsi1[] = {
+       { 0xd48, GENMASK(21, 20), 0 },
+};
+
+static struct aspeed_sig_desc fsi2[] = {
+       { 0xd48, GENMASK(23, 22), 0 },
+};
+
+static struct aspeed_sig_desc usb2ad_link[] = {
+       { 0x440, BIT(24), 0 },
+       { 0x440, BIT(25), 1 },
+};
+
+static struct aspeed_sig_desc usb2ah_link[] = {
+       { 0x440, BIT(24), 1 },
+       { 0x440, BIT(25), 0 },
+};
+
+static struct aspeed_sig_desc usb2bh_link[] = {
+       { 0x440, BIT(28), 1 },
+       { 0x440, BIT(29), 0 },
+};
+
+static struct aspeed_sig_desc pcie0rc_link[] = {
+       { 0x40, BIT(21), 0 },
+};
+
+static struct aspeed_sig_desc pcie1rc_link[] = {
+       { 0x40, BIT(19), 0 },  /* SSPRST# output enable */
+       { 0x500, BIT(24), 0 }, /* dedicate rc reset */
+};
+
+static const struct aspeed_group_config ast2600_groups[] = {
+       { "MAC1LINK", ARRAY_SIZE(mac1_link), mac1_link },
+       { "MAC2LINK", ARRAY_SIZE(mac2_link), mac2_link },
+       { "MAC3LINK", ARRAY_SIZE(mac3_link), mac3_link },
+       { "MAC4LINK", ARRAY_SIZE(mac4_link), mac4_link },
+       { "RGMII1", ARRAY_SIZE(rgmii1), rgmii1 },
+       { "RGMII2", ARRAY_SIZE(rgmii2), rgmii2 },
+       { "RGMII3", ARRAY_SIZE(rgmii3), rgmii3 },
+       { "RGMII4", ARRAY_SIZE(rgmii4), rgmii4 },
+       { "RMII1", ARRAY_SIZE(rmii1), rmii1 },
+       { "RMII2", ARRAY_SIZE(rmii2), rmii2 },
+       { "RMII3", ARRAY_SIZE(rmii3), rmii3 },
+       { "RMII4", ARRAY_SIZE(rmii4), rmii4 },
+       { "RMII1RCLK", ARRAY_SIZE(rmii1_rclk_oe), rmii1_rclk_oe },
+       { "RMII2RCLK", ARRAY_SIZE(rmii2_rclk_oe), rmii2_rclk_oe },
+       { "RMII3RCLK", ARRAY_SIZE(rmii3_rclk_oe), rmii3_rclk_oe },
+       { "RMII4RCLK", ARRAY_SIZE(rmii4_rclk_oe), rmii4_rclk_oe },
+       { "MDIO1", ARRAY_SIZE(mdio1_link), mdio1_link },
+       { "MDIO2", ARRAY_SIZE(mdio2_link), mdio2_link },
+       { "MDIO3", ARRAY_SIZE(mdio3_link), mdio3_link },
+       { "MDIO4", ARRAY_SIZE(mdio4_link), mdio4_link },
+       { "SD1", ARRAY_SIZE(sdio1_link), sdio1_link },
+       { "SD1_8bits", ARRAY_SIZE(sdio1_8bit_link), sdio1_8bit_link },
+       { "SD2", ARRAY_SIZE(sdio2_link), sdio2_link },
+       { "EMMC", ARRAY_SIZE(emmc_link), emmc_link },
+       { "EMMCG8", ARRAY_SIZE(emmcg8_link), emmcg8_link },
+       { "FMCQUAD", ARRAY_SIZE(fmcquad_link), fmcquad_link },
+       { "SPI1", ARRAY_SIZE(spi1_link), spi1_link },
+       { "SPI1ABR", ARRAY_SIZE(spi1abr_link), spi1abr_link },
+       { "SPI1CS1", ARRAY_SIZE(spi1cs1_link), spi1cs1_link },
+       { "SPI1WP", ARRAY_SIZE(spi1wp_link), spi1wp_link },
+       { "SPI1QUAD", ARRAY_SIZE(spi1quad_link), spi1quad_link },
+       { "SPI2", ARRAY_SIZE(spi2_link), spi2_link },
+       { "SPI2CS1", ARRAY_SIZE(spi2cs1_link), spi2cs1_link },
+       { "SPI2CS2", ARRAY_SIZE(spi2cs2_link), spi2cs2_link },
+       { "SPI2QUAD", ARRAY_SIZE(spi2quad_link), spi2quad_link },
+       { "I2C1", ARRAY_SIZE(i2c1_link), i2c1_link },
+       { "I2C2", ARRAY_SIZE(i2c2_link), i2c2_link },
+       { "I2C3", ARRAY_SIZE(i2c3_link), i2c3_link },
+       { "I2C4", ARRAY_SIZE(i2c4_link), i2c4_link },
+       { "I2C5", ARRAY_SIZE(i2c5_link), i2c5_link },
+       { "I2C6", ARRAY_SIZE(i2c6_link), i2c6_link },
+       { "I2C7", ARRAY_SIZE(i2c7_link), i2c7_link },
+       { "I2C8", ARRAY_SIZE(i2c8_link), i2c8_link },
+       { "I2C9", ARRAY_SIZE(i2c9_link), i2c9_link },
+       { "I2C10", ARRAY_SIZE(i2c10_link), i2c10_link },
+       { "I2C11", ARRAY_SIZE(i2c11_link), i2c11_link },
+       { "I2C12", ARRAY_SIZE(i2c12_link), i2c12_link },
+       { "I2C13", ARRAY_SIZE(i2c13_link), i2c13_link },
+       { "I2C14", ARRAY_SIZE(i2c14_link), i2c14_link },
+       { "I2C15", ARRAY_SIZE(i2c15_link), i2c15_link },
+       { "I2C16", ARRAY_SIZE(i2c16_link), i2c16_link },
+       { "FSI1", ARRAY_SIZE(fsi1), fsi1 },
+       { "FSI2", ARRAY_SIZE(fsi2), fsi2 },
+       { "USB2AD", ARRAY_SIZE(usb2ad_link), usb2ad_link },
+       { "USB2AH", ARRAY_SIZE(usb2ah_link), usb2ah_link },
+       { "USB2BH", ARRAY_SIZE(usb2bh_link), usb2bh_link },
+       { "PCIE0RC", ARRAY_SIZE(pcie0rc_link), pcie0rc_link },
+       { "PCIE1RC", ARRAY_SIZE(pcie1rc_link), pcie1rc_link },
+};
+
+static int ast2600_pinctrl_get_groups_count(struct udevice *dev)
+{
+       debug("PINCTRL: get_(functions/groups)_count\n");
+
+       return ARRAY_SIZE(ast2600_groups);
+}
+
+static const char *ast2600_pinctrl_get_group_name(struct udevice *dev,
+                                                 unsigned selector)
+{
+       debug("PINCTRL: get_(function/group)_name %u\n", selector);
+
+       return ast2600_groups[selector].group_name;
+}
+
+static int ast2600_pinctrl_group_set(struct udevice *dev, unsigned selector, unsigned func_selector)
+{
+       struct ast2600_pinctrl_priv *priv = dev_get_priv(dev);
+       const struct aspeed_group_config *config;
+       const struct aspeed_sig_desc *descs;
+       u32 ctrl_reg = (u32)priv->scu;
+       u32 i;
+
+       debug("PINCTRL: group_set <%u, %u>\n", selector, func_selector);
+       if (selector >= ARRAY_SIZE(ast2600_groups))
+               return -EINVAL;
+
+       config = &ast2600_groups[selector];
+       for (i = 0; i < config->ndescs; i++) {
+               descs = &config->descs[i];
+               if (descs->clr)
+                       clrbits_le32((u32)ctrl_reg + descs->offset, descs->reg_set);
+               else
+                       setbits_le32((u32)ctrl_reg + descs->offset, descs->reg_set);
+       }
+
+       return 0;
+}
+
+static struct pinctrl_ops ast2600_pinctrl_ops = {
+       .set_state = pinctrl_generic_set_state,
+       .get_groups_count = ast2600_pinctrl_get_groups_count,
+       .get_group_name = ast2600_pinctrl_get_group_name,
+       .get_functions_count = ast2600_pinctrl_get_groups_count,
+       .get_function_name = ast2600_pinctrl_get_group_name,
+       .pinmux_group_set = ast2600_pinctrl_group_set,
+};
+
+static const struct udevice_id ast2600_pinctrl_ids[] = {
+       { .compatible = "aspeed,g6-pinctrl" },
+       { }
+};
+
+U_BOOT_DRIVER(pinctrl_aspeed) = {
+       .name = "aspeed_ast2600_pinctrl",
+       .id = UCLASS_PINCTRL,
+       .of_match = ast2600_pinctrl_ids,
+       .priv_auto = sizeof(struct ast2600_pinctrl_priv),
+       .ops = &ast2600_pinctrl_ops,
+       .probe = ast2600_pinctrl_probe,
+};
diff --git a/drivers/pinctrl/pinctrl-apple.c b/drivers/pinctrl/pinctrl-apple.c
new file mode 100644 (file)
index 0000000..6247635
--- /dev/null
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2021 Mark Kettenis <kettenis@openbsd.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/pinctrl.h>
+#include <dt-bindings/pinctrl/apple.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <linux/bitfield.h>
+
+struct apple_pinctrl_priv {
+       void *base;
+       int pin_count;
+};
+
+#define REG_GPIO(x)    (4 * (x))
+#define  REG_GPIO_DATA         BIT(0)
+#define  REG_GPIO_MODE         GENMASK(3, 1)
+#define  REG_GPIO_OUT          1
+#define  REG_GPIO_PERIPH       GENMASK(6, 5)
+#define  REG_GPIO_INPUT_ENABLE BIT(9)
+
+static void apple_pinctrl_config_pin(struct apple_pinctrl_priv *priv,
+                                    unsigned pin, u32 clr, u32 set)
+{
+       unsigned reg = REG_GPIO(pin);
+       u32 old, new;
+
+       old = readl(priv->base + REG_GPIO(pin));
+       new = (old & ~clr) | set;
+       writel(new, priv->base + reg);
+}
+
+static int apple_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+       struct apple_pinctrl_priv *priv = dev_get_priv(dev->parent);
+
+       return !!(readl(priv->base + REG_GPIO(offset)) & REG_GPIO_DATA);
+}
+
+static int apple_gpio_set_value(struct udevice *dev, unsigned offset,
+                               int value)
+{
+       struct apple_pinctrl_priv *priv = dev_get_priv(dev->parent);
+
+       apple_pinctrl_config_pin(priv, offset, REG_GPIO_DATA,
+                                value ? REG_GPIO_DATA : 0);
+       return 0;
+}
+
+static int apple_gpio_get_direction(struct udevice *dev, unsigned offset)
+{
+       struct apple_pinctrl_priv *priv = dev_get_priv(dev->parent);
+       u32 reg = readl(priv->base + REG_GPIO(offset));
+
+       if (FIELD_GET(REG_GPIO_MODE, reg) == REG_GPIO_OUT)
+               return GPIOF_OUTPUT;
+       else
+               return GPIOF_INPUT;
+}
+
+static int apple_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+       struct apple_pinctrl_priv *priv = dev_get_priv(dev->parent);
+
+       apple_pinctrl_config_pin(priv, offset,
+                                REG_GPIO_PERIPH | REG_GPIO_MODE,
+                                REG_GPIO_INPUT_ENABLE);
+       return 0;
+}
+
+static int apple_gpio_direction_output(struct udevice *dev, unsigned offset,
+                                      int value)
+{
+       struct apple_pinctrl_priv *priv = dev_get_priv(dev->parent);
+       u32 set = (value ? REG_GPIO_DATA : 0);
+
+       apple_pinctrl_config_pin(priv, offset, REG_GPIO_DATA |
+                                REG_GPIO_PERIPH | REG_GPIO_MODE,
+                                set | FIELD_PREP(REG_GPIO_MODE, REG_GPIO_OUT));
+       return 0;
+}
+
+static int apple_gpio_probe(struct udevice *dev)
+{
+       struct apple_pinctrl_priv *priv = dev_get_priv(dev->parent);
+       struct gpio_dev_priv *uc_priv;
+
+       uc_priv = dev_get_uclass_priv(dev);
+       uc_priv->bank_name = "gpio";
+       uc_priv->gpio_count = priv->pin_count;
+
+       return 0;
+}
+
+static struct dm_gpio_ops apple_gpio_ops = {
+       .get_value = apple_gpio_get_value,
+       .set_value = apple_gpio_set_value,
+       .get_function = apple_gpio_get_direction,
+       .direction_input = apple_gpio_direction_input,
+       .direction_output = apple_gpio_direction_output,
+};
+
+static struct driver apple_gpio_driver = {
+       .name = "apple_gpio",
+       .id = UCLASS_GPIO,
+       .probe = apple_gpio_probe,
+       .ops = &apple_gpio_ops,
+};
+
+static int apple_pinctrl_get_pins_count(struct udevice *dev)
+{
+       struct apple_pinctrl_priv *priv = dev_get_priv(dev);
+
+       return priv->pin_count;
+}
+
+static const char *apple_pinctrl_get_pin_name(struct udevice *dev,
+                                             unsigned selector)
+{
+       static char pin_name[PINNAME_SIZE];
+
+       snprintf(pin_name, PINNAME_SIZE, "pin%d", selector);
+       return pin_name;
+}
+
+static int apple_pinctrl_get_pin_muxing(struct udevice *dev, unsigned selector,
+                                       char *buf, int size)
+{
+       struct apple_pinctrl_priv *priv = dev_get_priv(dev);
+
+       if (readl(priv->base + REG_GPIO(selector)) & REG_GPIO_PERIPH)
+               strncpy(buf, "periph", size);
+       else
+               strncpy(buf, "gpio", size);
+       return 0;
+}
+
+static int apple_pinctrl_pinmux_set(struct udevice *dev, unsigned pin_selector,
+                                   unsigned func_selector)
+{
+       struct apple_pinctrl_priv *priv = dev_get_priv(dev);
+
+       apple_pinctrl_config_pin(priv, pin_selector,
+                                REG_GPIO_DATA | REG_GPIO_MODE,
+                                FIELD_PREP(REG_GPIO_PERIPH, func_selector) |
+                                REG_GPIO_INPUT_ENABLE);
+       return 0;
+}
+
+static int apple_pinctrl_pinmux_property_set(struct udevice *dev,
+                                            u32 pinmux_group)
+{
+       unsigned pin_selector = APPLE_PIN(pinmux_group);
+       unsigned func_selector = APPLE_FUNC(pinmux_group);
+       int ret;
+
+       ret = apple_pinctrl_pinmux_set(dev, pin_selector, func_selector);
+       return ret ? ret : pin_selector;
+}
+
+static int apple_pinctrl_probe(struct udevice *dev)
+{
+       struct apple_pinctrl_priv *priv = dev_get_priv(dev);
+       struct ofnode_phandle_args args;
+       struct udevice *child;
+
+       priv->base = dev_read_addr_ptr(dev);
+       if (!priv->base)
+               return -EINVAL;
+
+       if (!dev_read_phandle_with_args(dev, "gpio-ranges",
+                                       NULL, 3, 0, &args))
+               priv->pin_count = args.args[2];
+
+       device_bind(dev, &apple_gpio_driver, "apple_gpio", NULL,
+                   dev_ofnode(dev), &child);
+
+       return 0;
+}
+
+static struct pinctrl_ops apple_pinctrl_ops = {
+       .set_state = pinctrl_generic_set_state,
+       .get_pins_count = apple_pinctrl_get_pins_count,
+       .get_pin_name = apple_pinctrl_get_pin_name,
+       .pinmux_set = apple_pinctrl_pinmux_set,
+       .pinmux_property_set = apple_pinctrl_pinmux_property_set,
+       .get_pin_muxing = apple_pinctrl_get_pin_muxing,
+};
+
+static const struct udevice_id apple_pinctrl_ids[] = {
+       { .compatible = "apple,pinctrl" },
+       { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(pinctrl_apple) = {
+       .name = "apple_pinctrl",
+       .id = UCLASS_PINCTRL,
+       .of_match = apple_pinctrl_ids,
+       .priv_auto = sizeof(struct apple_pinctrl_priv),
+       .ops = &apple_pinctrl_ops,
+       .probe = apple_pinctrl_probe,
+};
index b3142bf..3ddeaf4 100644 (file)
@@ -2,6 +2,9 @@
 /*
  * Copyright (C) 2020-2021 Linaro Limited
  */
+
+#define LOG_CATEGORY UCLASS_REGULATOR
+
 #include <common.h>
 #include <dm.h>
 #include <errno.h>
index 1bff807..ca0135a 100644 (file)
@@ -2,6 +2,9 @@
 /*
  * Copyright (C) 2019-2020 Linaro Limited
  */
+
+#define LOG_CATEGORY UCLASS_RESET
+
 #include <common.h>
 #include <dm.h>
 #include <errno.h>
index 8d40ce6..a8ef926 100644 (file)
 #define OPTEE_MSG_ATTR_CACHE_PREDEFINED                0
 
 /*
- * Same values as TEE_LOGIN_* from TEE Internal API
- */
-#define OPTEE_MSG_LOGIN_PUBLIC                 0x00000000
-#define OPTEE_MSG_LOGIN_USER                   0x00000001
-#define OPTEE_MSG_LOGIN_GROUP                  0x00000002
-#define OPTEE_MSG_LOGIN_APPLICATION            0x00000004
-#define OPTEE_MSG_LOGIN_APPLICATION_USER       0x00000005
-#define OPTEE_MSG_LOGIN_APPLICATION_GROUP      0x00000006
-
-/*
  * Page size used in non-contiguous buffer entries
  */
 #define OPTEE_MSG_NONCONTIG_PAGE_SIZE          4096
@@ -279,7 +269,7 @@ struct optee_msg_arg {
  * parameters to pass the following information:
  * param[0].u.value.a-b uuid of Trusted Application
  * param[1].u.value.a-b uuid of Client
- * param[1].u.value.c Login class of client OPTEE_MSG_LOGIN_*
+ * param[1].u.value.c Login class of client TEE_LOGIN_*
  *
  * OPTEE_MSG_CMD_INVOKE_COMMAND invokes a command a previously opened
  * session to a Trusted Application.  struct optee_msg_arg::func is Trusted
index 4317167..8958f01 100644 (file)
@@ -180,6 +180,7 @@ static int cdns_ti_remove(struct udevice *dev)
 
 static const struct udevice_id cdns_ti_of_match[] = {
        { .compatible = "ti,j721e-usb", },
+       { .compatible = "ti,am64-usb", },
        {},
 };
 
index 06d72ba..24966f8 100644 (file)
@@ -3,6 +3,24 @@ menu "Environment"
 config ENV_SUPPORT
        def_bool y
 
+config ENV_SOURCE_FILE
+       string "Environment file to use"
+       default ""
+       help
+         This sets the basename to use to generate the default environment.
+         This a text file as described in doc/usage/environment.rst
+
+         The file must be in the board directory and have a .env extension, so
+         the resulting filename is typically
+         board/<vendor>/<board>/<CONFIG_ENV_SOURCE_FILE>.env
+
+         If the file is not present, an error is produced.
+
+         If this CONFIG is empty, U-Boot uses CONFIG SYS_BOARD as a default, if
+         the file board/<vendor>/<board>/<SYS_BOARD>.env exists. Otherwise the
+         environment is assumed to come from the ad-hoc
+         CONFIG_EXTRA_ENV_SETTINGS #define
+
 config SAVEENV
        def_bool y if CMD_SAVEENV
 
index 208e2ad..ee957c0 100644 (file)
@@ -235,6 +235,11 @@ int env_get_yesno(const char *var)
                1 : 0;
 }
 
+bool env_get_autostart(void)
+{
+       return env_get_yesno("autostart") == 1;
+}
+
 /*
  * Look up the variable from the default environment
  */
index 208553e..9f26e6c 100644 (file)
@@ -66,6 +66,7 @@
 #endif
 
 #define DEFAULT_ENV_INSTANCE_EMBEDDED
+#include <config.h>
 #include <env_default.h>
 
 #ifdef CONFIG_ENV_ADDR_REDUND
index 137cfbc..f8e07a5 100644 (file)
@@ -45,7 +45,7 @@ struct cmd_tbl {
                               char *const argv[]);
        char            *usage;         /* Usage message        (short) */
 #ifdef CONFIG_SYS_LONGHELP
-       char            *help;          /* Help  message        (long)  */
+       const char      *help;          /* Help  message        (long)  */
 #endif
 #ifdef CONFIG_AUTO_COMPLETE
        /* do auto completion on the arguments */
index 5177bf2..96526e1 100644 (file)
  */
 #define CONFIG_BOOTP_BOOTFILESIZE
 
-/*
- * Miscellaneous configurable options
- */
-
-#define CONFIG_EXTRA_ENV_SETTINGS \
-       "verify=yes\0"  \
-       "spi_dma=yes\0" \
-       ""
-
 #endif /* __AST_COMMON_CONFIG_H */
index dc032c1..558d6f9 100644 (file)
 
 #define CONFIG_SYS_UBOOT_BASE          CONFIG_SYS_TEXT_BASE
 
+/* Memory Info */
+#define CONFIG_SYS_LOAD_ADDR           0x83000000
+
+/* Misc */
+#define CONFIG_EXTRA_ENV_SETTINGS \
+       ""
+
 #endif /* __CONFIG_H */
index 177a52e..9049a9f 100644 (file)
 
 #define CONFIG_SYS_UBOOT_BASE          CONFIG_SYS_TEXT_BASE
 
+/* Memory Info */
+#define CONFIG_SYS_LOAD_ADDR           0x83000000
+
+/* Misc */
+#define STR_HELPER(s)  #s
+#define STR(s)         STR_HELPER(s)
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+       "loadaddr=" STR(CONFIG_SYS_LOAD_ADDR) "\0" \
+       "bootspi=fdt addr 20100000 && fdt header get fitsize totalsize && " \
+       "cp.b 20100000 ${loadaddr} ${fitsize} && bootm; " \
+       "echo Error loading kernel FIT image\0" \
+       ""
+
 #endif /* __CONFIG_H */
index d614b70..cc3a7ff 100644 (file)
 #define CONFIG_SYS_BAUDRATE_TABLE      {4800, 9600, 19200, 38400, 57600,\
                                        115200}
 
-#define BOOT_TARGET_DEVICES(func) \
-       func(HOST, host, 1) \
-       func(HOST, host, 0)
-
-#ifdef __ASSEMBLY__
-#define BOOTENV
-#else
-#include <config_distro_bootcmd.h>
-#endif
-
 #define CONFIG_KEEP_SERVERADDR
 #define CONFIG_UDP_CHECKSUM
 #define CONFIG_TIMESTAMP
 #define CONFIG_LCD_BMP_RLE8
 
 #define CONFIG_KEYBOARD
-
-#define SANDBOX_SERIAL_SETTINGS                "stdin=serial,cros-ec-keyb,usbkbd\0" \
-                                       "stdout=serial,vidconsole\0" \
-                                       "stderr=serial,vidconsole\0"
-#else
-#define SANDBOX_SERIAL_SETTINGS                "stdin=serial\0" \
-                                       "stdout=serial,vidconsole\0" \
-                                       "stderr=serial,vidconsole\0"
 #endif
 
-#define SANDBOX_ETH_SETTINGS           "ethaddr=00:00:11:22:33:44\0" \
-                                       "eth2addr=00:00:11:22:33:48\0" \
-                                       "eth3addr=00:00:11:22:33:45\0" \
-                                       "eth4addr=00:00:11:22:33:48\0" \
-                                       "eth5addr=00:00:11:22:33:46\0" \
-                                       "eth6addr=00:00:11:22:33:47\0" \
-                                       "ipaddr=1.2.3.4\0"
-
-#define MEM_LAYOUT_ENV_SETTINGS \
-       "bootm_size=0x10000000\0" \
-       "kernel_addr_r=0x1000000\0" \
-       "fdt_addr_r=0xc00000\0" \
-       "ramdisk_addr_r=0x2000000\0" \
-       "scriptaddr=0x1000\0" \
-       "pxefile_addr_r=0x2000\0"
-
-#define CONFIG_EXTRA_ENV_SETTINGS \
-       SANDBOX_SERIAL_SETTINGS \
-       SANDBOX_ETH_SETTINGS \
-       BOOTENV \
-       MEM_LAYOUT_ENV_SETTINGS
-
 #ifndef CONFIG_SPL_BUILD
 #define CONFIG_SYS_IDE_MAXBUS          1
 #define CONFIG_SYS_ATA_IDE0_OFFSET     0
index 3028d00..daf28a0 100644 (file)
@@ -763,6 +763,18 @@ int device_find_first_child_by_uclass(const struct udevice *parent,
  *
  * @parent:    Parent device to search
  * @name:      Name to look for
+ * @len:       Length of the name
+ * @devp:      Returns device found, if any
+ * @return 0 if found, else -ENODEV
+ */
+int device_find_child_by_namelen(const struct udevice *parent, const char *name,
+                                int len, struct udevice **devp);
+
+/**
+ * device_find_child_by_name() - Find a child by device name
+ *
+ * @parent:    Parent device to search
+ * @name:      Name to look for
  * @devp:      Returns device found, if any
  * @return 0 if found, else -ENODEV
  */
index f0d2054..c2498aa 100644 (file)
@@ -114,4 +114,18 @@ int ofnode_decode_memory_region(ofnode config_node, const char *mem_type,
  */
 bool ofnode_phy_is_fixed_link(ofnode eth_node, ofnode *phy_node);
 
+/**
+ * ofnode_eth_uses_inband_aneg() - Detect whether MAC should use in-band autoneg
+ *
+ * This function detects whether the Ethernet controller should use IEEE 802.3
+ * clause 37 in-band autonegotiation for serial protocols such as 1000base-x,
+ * SGMII, USXGMII, etc. The property is relevant when the Ethernet controller
+ * is connected to an on-board PHY or an SFP cage, and is not relevant when it
+ * has a fixed link (in that case, in-band autoneg should not be used).
+ *
+ * @param eth_node     ofnode belonging to the Ethernet controller
+ * @return true if in-band autoneg should be used, false otherwise
+ */
+bool ofnode_eth_uses_inband_aneg(ofnode eth_node);
+
 #endif
index 0f680e5..6601bd8 100644 (file)
@@ -590,11 +590,11 @@ int ofnode_stringlist_search(ofnode node, const char *propname,
  *
  * @node: node to check
  * @propname: name of the property containing the string list
- * @index: index of the string to return
+ * @index: index of the string to return (cannot be negative)
  * @lenp: return location for the string length or an error code on failure
  *
  * @return:
- *   length of string, if found or -ve error value if not found
+ *   0 if found or -ve error value if not found
  */
 int ofnode_read_string_index(ofnode node, const char *propname, int index,
                             const char **outp);
@@ -610,6 +610,26 @@ int ofnode_read_string_index(ofnode node, const char *propname, int index,
 int ofnode_read_string_count(ofnode node, const char *property);
 
 /**
+ * ofnode_read_string_list() - read a list of strings
+ *
+ * This produces a list of string pointers with each one pointing to a string
+ * in the string list. If the property does not exist, it returns {NULL}.
+ *
+ * The data is allocated and the caller is reponsible for freeing the return
+ * value (the list of string pointers). The strings themselves may not be
+ * changed as they point directly into the devicetree property.
+ *
+ * @node: node to check
+ * @listp: returns an allocated, NULL-terminated list of strings if the return
+ *     value is > 0, else is set to NULL
+ * @return number of strings in list, 0 if none, -ENOMEM if out of memory,
+ *     -EINVAL if no such property, -EENODATA if property is empty
+ * @return: NULL-terminated list of strings (NULL if no property or empty)
+ */
+int ofnode_read_string_list(ofnode node, const char *property,
+                           const char ***listp);
+
+/**
  * ofnode_parse_phandle_with_args() - Find a node pointed by phandle in a list
  *
  * This function is useful to parse lists of phandles and their arguments.
index 890bf3d..75c6ad6 100644 (file)
@@ -371,6 +371,27 @@ int dev_read_string_index(const struct udevice *dev, const char *propname,
  *   number of strings in the list, or -ve error value if not found
  */
 int dev_read_string_count(const struct udevice *dev, const char *propname);
+
+/**
+ * dev_read_string_list() - read a list of strings
+ *
+ * This produces a list of string pointers with each one pointing to a string
+ * in the string list. If the property does not exist, it returns {NULL}.
+ *
+ * The data is allocated and the caller is reponsible for freeing the return
+ * value (the list of string pointers). The strings themselves may not be
+ * changed as they point directly into the devicetree property.
+ *
+ * @dev: device to examine
+ * @propname: name of the property containing the string list
+ * @listp: returns an allocated, NULL-terminated list of strings if the return
+ *     value is > 0, else is set to NULL
+ * @return number of strings in list, 0 if none, -ENOMEM if out of memory,
+ *     -ENOENT if no such property
+ */
+int dev_read_string_list(const struct udevice *dev, const char *propname,
+                        const char ***listp);
+
 /**
  * dev_read_phandle_with_args() - Find a node pointed by phandle in a list
  *
@@ -906,6 +927,13 @@ static inline int dev_read_string_count(const struct udevice *dev,
        return ofnode_read_string_count(dev_ofnode(dev), propname);
 }
 
+static inline int dev_read_string_list(const struct udevice *dev,
+                                      const char *propname,
+                                      const char ***listp)
+{
+       return ofnode_read_string_list(dev_ofnode(dev), propname, listp);
+}
+
 static inline int dev_read_phandle_with_args(const struct udevice *dev,
                const char *list_name, const char *cells_name, int cell_count,
                int index, struct ofnode_phandle_args *out_args)
index 57c664c..49808c5 100644 (file)
@@ -243,6 +243,17 @@ int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent,
  */
 int uclass_bind_device(struct udevice *dev);
 
+#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
+/**
+ * uclass_pre_unbind_device() - Prepare to deassociate device with a uclass
+ *
+ * Call any handled needed before uclass_unbind_device() is called
+ *
+ * @dev:       Pointer to the device
+ * #return 0 on success, -ve on error
+ */
+int uclass_pre_unbind_device(struct udevice *dev);
+
 /**
  * uclass_unbind_device() - Deassociate device with a uclass
  *
@@ -251,9 +262,10 @@ int uclass_bind_device(struct udevice *dev);
  * @dev:       Pointer to the device
  * #return 0 on success, -ve on error
  */
-#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
 int uclass_unbind_device(struct udevice *dev);
+
 #else
+static inline int uclass_pre_unbind_device(struct udevice *dev) { return 0; }
 static inline int uclass_unbind_device(struct udevice *dev) { return 0; }
 #endif
 
index 15e5f9e..f1fd2ba 100644 (file)
@@ -176,6 +176,15 @@ const char *uclass_get_name(enum uclass_id id);
  * uclass_get_by_name() - Look up a uclass by its driver name
  *
  * @name: Name to look up
+ * @len: Length of name
+ * @returns the associated uclass ID, or UCLASS_INVALID if not found
+ */
+enum uclass_id uclass_get_by_name_len(const char *name, int len);
+
+/**
+ * uclass_get_by_name() - Look up a uclass by its driver name
+ *
+ * @name: Name to look up
  * @returns the associated uclass ID, or UCLASS_INVALID if not found
  */
 enum uclass_id uclass_get_by_name(const char *name);
@@ -417,6 +426,14 @@ int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data,
 int uclass_probe_all(enum uclass_id id);
 
 /**
+ * uclass_id_count() - Count the number of devices in a uclass
+ *
+ * @id: uclass ID to look up
+ * @return number of devices in that uclass (0 if none)
+ */
+int uclass_id_count(enum uclass_id id);
+
+/**
  * uclass_id_foreach_dev() - Helper function to iteration through devices
  *
  * This creates a for() loop which works through the available devices in
index ee5e30d..ff8943e 100644 (file)
@@ -134,6 +134,13 @@ int env_get_f(const char *name, char *buf, unsigned int len);
 int env_get_yesno(const char *var);
 
 /**
+ * env_get_autostart() - Check if autostart is enabled
+ *
+ * @return true if the "autostart" env var exists and is set to "yes"
+ */
+bool env_get_autostart(void);
+
+/**
  * env_set() - set an environment variable
  *
  * This sets or deletes the value of an environment variable. For setting the
index 23430dc..401e84e 100644 (file)
 #include <env_callback.h>
 #include <linux/stringify.h>
 
+#ifndef USE_HOSTCC
+#include <generated/environment.h>
+#endif
+
 #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
 env_t embedded_environment __UBOOT_ENV_SECTION__(environment) = {
        ENV_CRC,        /* CRC Sum */
@@ -110,6 +114,13 @@ const char default_environment[] = {
 #if defined(CONFIG_BOOTCOUNT_BOOTLIMIT) && (CONFIG_BOOTCOUNT_BOOTLIMIT > 0)
        "bootlimit="    __stringify(CONFIG_BOOTCOUNT_BOOTLIMIT)"\0"
 #endif
+#ifdef CONFIG_EXTRA_ENV_TEXT
+# ifdef CONFIG_EXTRA_ENV_SETTINGS
+# error "Your board uses a text-file environment, so must not define CONFIG_EXTRA_ENV_SETTINGS"
+# endif
+       /* This is created in the Makefile */
+       CONFIG_EXTRA_ENV_TEXT
+#endif
 #ifdef CONFIG_EXTRA_ENV_SETTINGS
        CONFIG_EXTRA_ENV_SETTINGS
 #endif
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
new file mode 100644 (file)
index 0000000..cbc82f4
--- /dev/null
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * VLAN                An implementation of 802.1Q VLAN tagging.
+ *
+ * Authors:    Ben Greear <greearb@candelatech.com>
+ */
+#ifndef _LINUX_IF_VLAN_H_
+#define _LINUX_IF_VLAN_H_
+
+/**
+ *     struct vlan_ethhdr - vlan ethernet header (ethhdr + vlan_hdr)
+ *     @h_dest: destination ethernet address
+ *     @h_source: source ethernet address
+ *     @h_vlan_proto: ethernet protocol
+ *     @h_vlan_TCI: priority and VLAN ID
+ *     @h_vlan_encapsulated_proto: packet type ID or len
+ */
+struct vlan_ethhdr {
+       unsigned char   h_dest[ETH_ALEN];
+       unsigned char   h_source[ETH_ALEN];
+       __be16          h_vlan_proto;
+       __be16          h_vlan_TCI;
+       __be16          h_vlan_encapsulated_proto;
+};
+
+#endif /* !(_LINUX_IF_VLAN_H_) */
index a339a49..1b1068c 100644 (file)
@@ -6,6 +6,7 @@
 #ifndef __DSA_H__
 #define __DSA_H__
 
+#include <dm/ofnode.h>
 #include <phy.h>
 #include <net.h>
 
@@ -146,6 +147,17 @@ int dsa_set_tagging(struct udevice *dev, ushort headroom, ushort tailroom);
 struct udevice *dsa_get_master(struct udevice *dev);
 
 /**
+ * dsa_port_get_ofnode() - Return a reference to the given port's OF node
+ *
+ * Can be called at driver probe time or later.
+ *
+ * @dev:       DSA switch udevice pointer
+ * @port:      Port index
+ * @return OF node reference if OK, NULL on error
+ */
+ofnode dsa_port_get_ofnode(struct udevice *dev, int port);
+
+/**
  * dsa_port_get_pdata() - Helper that returns the platdata of an active
  *                     (non-CPU) DSA port device.
  *
index 770d76e..4cbcbd9 100644 (file)
@@ -419,6 +419,15 @@ int os_read_file(const char *name, void **bufp, int *sizep);
  */
 int os_map_file(const char *pathname, int os_flags, void **bufp, int *sizep);
 
+/**
+ * os_unmap() - Unmap a file previously mapped
+ *
+ * @buf: Mapped address
+ * @size: Size in bytes
+ * Return:     0 if OK, -ve on error
+ */
+int os_unmap(void *buf, int size);
+
 /*
  * os_find_text_base() - Find the text section in this running process
  *
index 797f224..6c1094d 100644 (file)
 
 #include <pci_ids.h>
 
+/*
+ * Enhanced Configuration Access Mechanism (ECAM)
+ *
+ * See PCI Express Base Specification, Revision 5.0, Version 1.0,
+ * Section 7.2.2, Table 7-1, p. 677.
+ */
+#define PCIE_ECAM_BUS_SHIFT    20 /* Bus number */
+#define PCIE_ECAM_DEV_SHIFT    15 /* Device number */
+#define PCIE_ECAM_FUNC_SHIFT   12 /* Function number */
+
+#define PCIE_ECAM_BUS_MASK     0xff
+#define PCIE_ECAM_DEV_MASK     0x1f
+#define PCIE_ECAM_FUNC_MASK    0x7
+#define PCIE_ECAM_REG_MASK     0xfff /* Limit offset to a maximum of 4K */
+
+#define PCIE_ECAM_BUS(x)       (((x) & PCIE_ECAM_BUS_MASK) << PCIE_ECAM_BUS_SHIFT)
+#define PCIE_ECAM_DEV(x)       (((x) & PCIE_ECAM_DEV_MASK) << PCIE_ECAM_DEV_SHIFT)
+#define PCIE_ECAM_FUNC(x)      (((x) & PCIE_ECAM_FUNC_MASK) << PCIE_ECAM_FUNC_SHIFT)
+#define PCIE_ECAM_REG(x)       ((x) & PCIE_ECAM_REG_MASK)
+
+#define PCIE_ECAM_OFFSET(bus, dev, func, where) \
+       (PCIE_ECAM_BUS(bus) | \
+        PCIE_ECAM_DEV(dev) | \
+        PCIE_ECAM_FUNC(func) | \
+        PCIE_ECAM_REG(where))
+
 #ifndef __ASSEMBLY__
 
 #include <dm/pci.h>
index f1be9ff..ed40c73 100644 (file)
@@ -45,9 +45,9 @@ struct scmi_msg {
        }
 
 /**
- * scmi_send_and_process_msg() - send and process a SCMI message
+ * devm_scmi_process_msg() - Send and process an SCMI message
  *
- * Send a message to a SCMI server through a target SCMI agent device.
+ * Send a message to an SCMI server through a target SCMI agent device.
  * Caller sets scmi_msg::out_msg_sz to the output message buffer size.
  * On return, scmi_msg::out_msg_sz stores the response payload size.
  *
index 44e9cd4..5005149 100644 (file)
                                                 TEE_PARAM_ATTR_META)
 
 /*
+ * Global Platform login identifiers for tee_open_session_arg::clnt_login
+ */
+#define TEE_LOGIN_PUBLIC                  0x00000000
+#define TEE_LOGIN_USER                    0x00000001
+#define TEE_LOGIN_GROUP                   0x00000002
+#define TEE_LOGIN_APPLICATION             0x00000004
+#define TEE_LOGIN_APPLICATION_USER        0x00000005
+#define TEE_LOGIN_APPLICATION_GROUP       0x00000006
+/*
+ * Reserve use of GP implementation specific login method range
+ * (0x80000000 - 0xBFFFFFFF). This range is rather being used
+ * for REE kernel clients or TEE implementation.
+ */
+#define TEE_LOGIN_REE_KERNEL_MIN          0x80000000
+#define TEE_LOGIN_REE_KERNEL_MAX          0xBFFFFFFF
+/* Private login method for REE kernel/privileged clients */
+#define TEE_LOGIN_REE_KERNEL              0x80000000
+
+/*
  * Some Global Platform error codes which has a meaning if the
  * TEE_GEN_CAP_GP bit is returned by the driver in
  * struct tee_version_data::gen_caps
@@ -45,6 +64,7 @@
 #define TEE_ERROR_NOT_SUPPORTED                0xffff000a
 #define TEE_ERROR_COMMUNICATION                0xffff000e
 #define TEE_ERROR_SECURITY             0xffff000f
+#define TEE_ERROR_SHORT_BUFFER         0xffff0010
 #define TEE_ERROR_OUT_OF_MEMORY                0xffff000c
 #define TEE_ERROR_OVERFLOW              0xffff300f
 #define TEE_ERROR_TARGET_DEAD          0xffff3024
@@ -135,8 +155,8 @@ struct tee_param {
 /**
  * struct tee_open_session_arg - extra arguments for tee_open_session()
  * @uuid:      [in] UUID of the Trusted Application
- * @clnt_uuid: [in] Normally zeroes
- * @clnt_login:        [in] Normally 0
+ * @clnt_uuid: [in] UUID of client, zeroes for PUBLIC/REE_KERNEL
+ * @clnt_login:        [in] Class of client TEE_LOGIN_*
  * @session:   [out] Session id
  * @ret:       [out] return value
  * @ret_origin:        [out] origin of the return value
index c301c28..72f3485 100644 (file)
 #define ECNTRL_REDUCED_MII_MODE        0x00000004
 #define ECNTRL_SGMII_MODE      0x00000002
 
+#define RCTRL_PROM             0x00000008
+
 #ifndef CONFIG_SYS_TBIPA_VALUE
 # define CONFIG_SYS_TBIPA_VALUE        0x1f
 #endif
index 469596a..be9775b 100644 (file)
@@ -1,7 +1,8 @@
 config RSA
        bool "Use RSA Library"
        select RSA_FREESCALE_EXP if FSL_CAAM && !ARCH_MX7 && !ARCH_MX7ULP && !ARCH_MX6 && !ARCH_MX5
-       select RSA_SOFTWARE_EXP if !RSA_FREESCALE_EXP
+       select RSA_ASPEED_EXP if ASPEED_ACRY
+       select RSA_SOFTWARE_EXP if !RSA_FREESCALE_EXP && !RSA_ASPEED_EXP
        help
          RSA support. This enables the RSA algorithm used for FIT image
          verification in U-Boot.
@@ -62,4 +63,11 @@ config RSA_FREESCALE_EXP
        Enables driver for RSA modular exponentiation using Freescale cryptographic
        accelerator - CAAM.
 
+config RSA_ASPEED_EXP
+       bool "Enable RSA Modular Exponentiation with ASPEED crypto accelerator"
+       depends on DM && ASPEED_ACRY
+       help
+       Enables driver for RSA modular exponentiation using ASPEED cryptographic
+       accelerator - ACRY
+
 endif
index 655b9cc..58e30cd 100644 (file)
@@ -647,7 +647,7 @@ static int bootp_extended(u8 *e)
        *e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
 #endif
 
-       add_vci(e);
+       e = add_vci(e);
 
 #if defined(CONFIG_BOOTP_SUBNETMASK)
        *e++ = 1;               /* Subnet mask request */
index bf762cd..606b153 100644 (file)
@@ -44,6 +44,26 @@ int dsa_set_tagging(struct udevice *dev, ushort headroom, ushort tailroom)
        return 0;
 }
 
+ofnode dsa_port_get_ofnode(struct udevice *dev, int port)
+{
+       struct dsa_pdata *pdata = dev_get_uclass_plat(dev);
+       struct dsa_port_pdata *port_pdata;
+       struct udevice *pdev;
+
+       if (port == pdata->cpu_port)
+               return pdata->cpu_port_node;
+
+       for (device_find_first_child(dev, &pdev);
+            pdev;
+            device_find_next_child(&pdev)) {
+               port_pdata = dev_get_parent_plat(pdev);
+               if (port_pdata->index == port)
+                       return dev_ofnode(pdev);
+       }
+
+       return ofnode_null();
+}
+
 /* returns the DSA master Ethernet device */
 struct udevice *dsa_get_master(struct udevice *dev)
 {
@@ -250,7 +270,7 @@ static void dsa_port_set_hwaddr(struct udevice *pdev, struct udevice *master)
                struct eth_ops *eth_ops = eth_get_ops(master);
 
                if (eth_ops->set_promisc)
-                       eth_ops->set_promisc(master, 1);
+                       eth_ops->set_promisc(master, true);
 
                return;
        }
diff --git a/scripts/env2string.awk b/scripts/env2string.awk
new file mode 100644 (file)
index 0000000..1bfe9ed
--- /dev/null
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2021 Google, Inc
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+# Awk script to parse a text file containing an environment and convert it
+# to a C string which can be compiled into U-Boot.
+
+# The resulting output is:
+#
+#   #define CONFIG_EXTRA_ENV_TEXT "<environment here>"
+#
+# If the input is empty, this script outputs a comment instead.
+
+BEGIN {
+       # env holds the env variable we are currently processing
+       env = "";
+       ORS = ""
+}
+
+# Skip empty lines, as these are generated by the clang preprocessor
+NF {
+       do_output = 0
+
+       # Quote quotes
+       gsub("\"", "\\\"")
+
+       # Avoid using the non-POSIX third parameter to match(), by splitting
+       # the work into several steps.
+       has_var = match($0, "^([^ \t=][^ =]*)=(.*)$")
+
+       # Is this the start of a new environment variable?
+       if (has_var) {
+               if (length(env) != 0) {
+                       # Record the value of the variable now completed
+                       vars[var] = env
+                       do_output = 1
+               }
+
+               # Collect the variable name. The value follows the '='
+               match($0, "^([^ \t=][^ =]*)=")
+               var = substr($0, 1, RLENGTH - 1)
+               env = substr($0, RLENGTH + 1)
+
+               # Deal with += which concatenates the new string to the existing
+               # variable. Again we are careful to use POSIX match()
+               if (length(env) != 0 && match(var, "^(.*)[+]$")) {
+                       plusname = substr(var, RSTART, RLENGTH - 1)
+                       # Allow var\+=val to indicate that the variable name is
+                       # var+ and this is not actually a concatenation
+                       if (substr(plusname, length(plusname)) == "\\") {
+                               # Drop the backslash
+                               sub(/\\[+]$/, "+", var)
+                       } else {
+                               var = plusname
+                               env = vars[var] env
+                       }
+               }
+       } else {
+               # Change newline to space
+               gsub(/^[ \t]+/, "")
+
+               # Don't keep leading spaces generated by the previous blank line
+               if (length(env) == 0) {
+                       env = $0
+               } else {
+                       env = env " " $0
+               }
+       }
+}
+
+END {
+       # Record the value of the variable now completed. If the variable is
+       # empty it is not set.
+       if (length(env) != 0) {
+               vars[var] = env
+               do_output = 1
+       }
+
+       if (do_output) {
+               printf("%s", "#define CONFIG_EXTRA_ENV_TEXT \"")
+
+               # Print out all the variables
+               for (var in vars) {
+                       env = vars[var]
+                       print var "=" vars[var] "\\0"
+               }
+               print "\"\n"
+       }
+}
index cea0746..5e7c968 100644 (file)
@@ -351,3 +351,99 @@ static int dm_test_ofnode_for_each_compatible_node(struct unit_test_state *uts)
        return 0;
 }
 DM_TEST(dm_test_ofnode_for_each_compatible_node, UT_TESTF_SCAN_FDT);
+
+static int dm_test_ofnode_string(struct unit_test_state *uts)
+{
+       const char **val;
+       const char *out;
+       ofnode node;
+
+       node = ofnode_path("/a-test");
+       ut_assert(ofnode_valid(node));
+
+       /* single string */
+       ut_asserteq(1, ofnode_read_string_count(node, "str-value"));
+       ut_assertok(ofnode_read_string_index(node, "str-value", 0, &out));
+       ut_asserteq_str("test string", out);
+       ut_asserteq(0, ofnode_stringlist_search(node, "str-value",
+                                               "test string"));
+       ut_asserteq(1, ofnode_read_string_list(node, "str-value", &val));
+       ut_asserteq_str("test string", val[0]);
+       ut_assertnull(val[1]);
+       free(val);
+
+       /* list of strings */
+       ut_asserteq(5, ofnode_read_string_count(node, "mux-control-names"));
+       ut_assertok(ofnode_read_string_index(node, "mux-control-names", 0,
+                                            &out));
+       ut_asserteq_str("mux0", out);
+       ut_asserteq(0, ofnode_stringlist_search(node, "mux-control-names",
+                                               "mux0"));
+       ut_asserteq(5, ofnode_read_string_list(node, "mux-control-names",
+                                              &val));
+       ut_asserteq_str("mux0", val[0]);
+       ut_asserteq_str("mux1", val[1]);
+       ut_asserteq_str("mux2", val[2]);
+       ut_asserteq_str("mux3", val[3]);
+       ut_asserteq_str("mux4", val[4]);
+       ut_assertnull(val[5]);
+       free(val);
+
+       ut_assertok(ofnode_read_string_index(node, "mux-control-names", 4,
+                                            &out));
+       ut_asserteq_str("mux4", out);
+       ut_asserteq(4, ofnode_stringlist_search(node, "mux-control-names",
+                                               "mux4"));
+
+       return 0;
+}
+DM_TEST(dm_test_ofnode_string, 0);
+
+static int dm_test_ofnode_string_err(struct unit_test_state *uts)
+{
+       const char **val;
+       const char *out;
+       ofnode node;
+
+       /*
+        * Test error codes only on livetree, as they are different with
+        * flattree
+        */
+       node = ofnode_path("/a-test");
+       ut_assert(ofnode_valid(node));
+
+       /* non-existent property */
+       ut_asserteq(-EINVAL, ofnode_read_string_count(node, "missing"));
+       ut_asserteq(-EINVAL, ofnode_read_string_index(node, "missing", 0,
+                                                     &out));
+       ut_asserteq(-EINVAL, ofnode_read_string_list(node, "missing", &val));
+
+       /* empty property */
+       ut_asserteq(-ENODATA, ofnode_read_string_count(node, "bool-value"));
+       ut_asserteq(-ENODATA, ofnode_read_string_index(node, "bool-value", 0,
+                                                      &out));
+       ut_asserteq(-ENODATA, ofnode_read_string_list(node, "bool-value",
+                                                    &val));
+
+       /* badly formatted string list */
+       ut_asserteq(-EILSEQ, ofnode_read_string_count(node, "int64-value"));
+       ut_asserteq(-EILSEQ, ofnode_read_string_index(node, "int64-value", 0,
+                                                      &out));
+       ut_asserteq(-EILSEQ, ofnode_read_string_list(node, "int64-value",
+                                                    &val));
+
+       /* out of range / not found */
+       ut_asserteq(-ENODATA, ofnode_read_string_index(node, "str-value", 1,
+                                                      &out));
+       ut_asserteq(-ENODATA, ofnode_stringlist_search(node, "str-value",
+                                                      "other"));
+
+       /* negative value for index is not allowed, so don't test for that */
+
+       ut_asserteq(-ENODATA, ofnode_read_string_index(node,
+                                                      "mux-control-names", 5,
+                                                      &out));
+
+       return 0;
+}
+DM_TEST(dm_test_ofnode_string_err, UT_TESTF_LIVE_TREE);
index 11a3f30..16e445c 100644 (file)
@@ -226,7 +226,7 @@ def pytest_configure(config):
         import u_boot_console_exec_attach
         console = u_boot_console_exec_attach.ConsoleExecAttach(log, ubconfig)
 
-re_ut_test_list = re.compile(r'[^a-zA-Z0-9_]_u_boot_list_2_ut_(.*)_test_2_\1_test_(.*)\s*$')
+re_ut_test_list = re.compile(r'[^a-zA-Z0-9_]_u_boot_list_2_ut_(.*)_test_2_(.*)\s*$')
 def generate_ut_subtest(metafunc, fixture_name, sym_path):
     """Provide parametrization for a ut_subtest fixture.
 
index 442edad..5e79075 100644 (file)
@@ -111,7 +111,7 @@ class RunAndLog(object):
         """Clean up any resources managed by this object."""
         pass
 
-    def run(self, cmd, cwd=None, ignore_errors=False):
+    def run(self, cmd, cwd=None, ignore_errors=False, stdin=None):
         """Run a command as a sub-process, and log the results.
 
         The output is available at self.output which can be useful if there is
@@ -125,6 +125,7 @@ class RunAndLog(object):
                 function will simply return if the command cannot be executed
                 or exits with an error code, otherwise an exception will be
                 raised if such problems occur.
+            stdin: Input string to pass to the command as stdin (or None)
 
         Returns:
             The output as a string.
@@ -137,8 +138,9 @@ class RunAndLog(object):
 
         try:
             p = subprocess.Popen(cmd, cwd=cwd,
-                stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-            (stdout, stderr) = p.communicate()
+                stdin=subprocess.PIPE if stdin else None,
+                stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+            (stdout, stderr) = p.communicate(input=stdin)
             if stdout is not None:
                 stdout = stdout.decode('utf-8')
             if stderr is not None:
@@ -165,7 +167,7 @@ class RunAndLog(object):
         if output and not output.endswith('\n'):
             output += '\n'
         if exit_status and not exception and not ignore_errors:
-            exception = Exception('Exit code: ' + str(exit_status))
+            exception = ValueError('Exit code: ' + str(exit_status))
         if exception:
             output += str(exception) + '\n'
         self.logfile.write(self, output)
index 9bed2f4..f85cb03 100644 (file)
@@ -7,6 +7,7 @@
 import os
 import os.path
 from subprocess import call, check_call, CalledProcessError
+import tempfile
 
 import pytest
 import u_boot_utils
@@ -515,3 +516,109 @@ def test_env_ext4(state_test_env):
     finally:
         if fs_img:
             call('rm -f %s' % fs_img, shell=True)
+
+def test_env_text(u_boot_console):
+    """Test the script that converts the environment to a text file"""
+
+    def check_script(intext, expect_val):
+        """Check a test case
+
+        Args:
+            intext: Text to pass to the script
+            expect_val: Expected value of the CONFIG_EXTRA_ENV_TEXT string, or
+                None if we expect it not to be defined
+        """
+        with tempfile.TemporaryDirectory() as path:
+            fname = os.path.join(path, 'infile')
+            with open(fname, 'w') as inf:
+                print(intext, file=inf)
+            result = u_boot_utils.run_and_log(cons, ['awk', '-f', script, fname])
+            if expect_val is not None:
+                expect = '#define CONFIG_EXTRA_ENV_TEXT "%s"\n' % expect_val
+                assert result == expect
+            else:
+                assert result == ''
+
+    cons = u_boot_console
+    script = os.path.join(cons.config.source_dir, 'scripts', 'env2string.awk')
+
+    # simple script with a single var
+    check_script('fred=123', 'fred=123\\0')
+
+    # no vars
+    check_script('', None)
+
+    # two vars
+    check_script('''fred=123
+ernie=456''', 'fred=123\\0ernie=456\\0')
+
+    # blank lines
+    check_script('''fred=123
+
+
+ernie=456
+
+''', 'fred=123\\0ernie=456\\0')
+
+    # append
+    check_script('''fred=123
+ernie=456
+fred+= 456''', 'fred=123 456\\0ernie=456\\0')
+
+    # append from empty
+    check_script('''fred=
+ernie=456
+fred+= 456''', 'fred= 456\\0ernie=456\\0')
+
+    # variable with + in it
+    check_script('fred+ernie=123', 'fred+ernie=123\\0')
+
+    # ignores variables that are empty
+    check_script('''fred=
+fred+=
+ernie=456''', 'ernie=456\\0')
+
+    # single-character env name
+    check_script('''f=123
+e=456
+f+= 456''', 'e=456\\0f=123 456\\0')
+
+    # contains quotes
+    check_script('''fred="my var"
+ernie=another"''', 'fred=\\"my var\\"\\0ernie=another\\"\\0')
+
+    # variable name ending in +
+    check_script('''fred\\+=my var
+fred++= again''', 'fred+=my var again\\0')
+
+    # variable name containing +
+    check_script('''fred+jane=both
+fred+jane+=again
+ernie=456''', 'fred+jane=bothagain\\0ernie=456\\0')
+
+    # multi-line vars - new vars always start at column 1
+    check_script('''fred=first
+ second
+\tthird with tab
+
+   after blank
+ confusing=oops
+ernie=another"''', 'fred=first second third with tab after blank confusing=oops\\0ernie=another\\"\\0')
+
+    # real-world example
+    check_script('''ubifs_boot=
+       env exists bootubipart ||
+               env set bootubipart UBI;
+       env exists bootubivol ||
+               env set bootubivol boot;
+       if ubi part ${bootubipart} &&
+               ubifsmount ubi${devnum}:${bootubivol};
+       then
+               devtype=ubi;
+               run scan_dev_for_boot;
+       fi
+''',
+        'ubifs_boot=env exists bootubipart || env set bootubipart UBI; '
+        'env exists bootubivol || env set bootubivol boot; '
+        'if ubi part ${bootubipart} && ubifsmount ubi${devnum}:${bootubivol}; '
+        'then devtype=ubi; run scan_dev_for_boot; fi\\0')
index 089eda5..c4fc23a 100644 (file)
@@ -157,7 +157,7 @@ def wait_until_file_open_fails(fn, ignore_errors):
         return
     raise Exception('File can still be opened')
 
-def run_and_log(u_boot_console, cmd, ignore_errors=False):
+def run_and_log(u_boot_console, cmd, ignore_errors=False, stdin=None):
     """Run a command and log its output.
 
     Args:
@@ -169,6 +169,7 @@ def run_and_log(u_boot_console, cmd, ignore_errors=False):
             will simply return if the command cannot be executed or exits with
             an error code, otherwise an exception will be raised if such
             problems occur.
+        stdin: Input string to pass to the command as stdin (or None)
 
     Returns:
         The output as a string.
@@ -176,7 +177,7 @@ def run_and_log(u_boot_console, cmd, ignore_errors=False):
     if isinstance(cmd, str):
         cmd = cmd.split()
     runner = u_boot_console.log.get_runner(cmd[0], sys.stdout)
-    output = runner.run(cmd, ignore_errors=ignore_errors)
+    output = runner.run(cmd, ignore_errors=ignore_errors, stdin=stdin)
     runner.close()
     return output
 
index 304fc70..7da69ba 100644 (file)
@@ -355,6 +355,7 @@ def ReplaceEntries(image_fname, input_fname, indir, entry_paths,
     Returns:
         List of EntryInfo records that were written
     """
+    image_fname = os.path.abspath(image_fname)
     image = Image.FromFile(image_fname)
 
     # Replace an entry from a single file, as a special case