summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS8
-rw-r--r--Makefile66
-rw-r--r--README328
-rw-r--r--arch/arm/Kconfig2
-rw-r--r--arch/arm/dts/ast2600-evb.dts10
-rw-r--r--arch/arm/dts/ast2600.dtsi17
-rw-r--r--arch/arm/dts/k3-am642-r5-sk.dts40
-rw-r--r--arch/arm/dts/k3-am642-sk-u-boot.dtsi33
-rw-r--r--arch/arm/dts/ls1021a-tsn.dts103
-rw-r--r--arch/arm/include/asm/arch-aspeed/platform.h2
-rw-r--r--arch/arm/include/asm/arch-aspeed/scu_ast2600.h6
-rw-r--r--arch/arm/lib/crt0.S4
-rw-r--r--arch/arm/lib/crt0_64.S4
-rw-r--r--arch/arm/mach-aspeed/ast2600/spl.c9
-rw-r--r--arch/arm/mach-rockchip/rk3399/rk3399.c34
-rw-r--r--arch/sandbox/cpu/os.c10
-rw-r--r--arch/sandbox/dts/test.dts1
-rw-r--r--board/sandbox/sandbox.env25
-rw-r--r--boot/bootm_os.c5
-rw-r--r--boot/image-fit.c4
-rw-r--r--boot/pxe_utils.c8
-rw-r--r--cmd/bootm.c4
-rw-r--r--cmd/elf.c3
-rw-r--r--cmd/mbr.c8
-rw-r--r--cmd/sf.c32
-rw-r--r--common/Kconfig10
-rw-r--r--common/console.c4
-rw-r--r--config.mk2
-rw-r--r--configs/am64x_evm_a53_defconfig15
-rw-r--r--configs/am64x_evm_r5_defconfig13
-rw-r--r--configs/elgin-rv1108_defconfig1
-rw-r--r--configs/evb-ast2600_defconfig22
-rw-r--r--configs/evb-rk3128_defconfig1
-rw-r--r--configs/evb-rv1108_defconfig1
-rw-r--r--configs/ls1021atsn_qspi_defconfig3
-rw-r--r--configs/ls1021atsn_sdcard_defconfig3
-rw-r--r--configs/pine64_plus_defconfig1
-rw-r--r--configs/pm9g45_defconfig1
-rw-r--r--configs/qemu_arm64_defconfig5
-rw-r--r--configs/qemu_arm_defconfig5
-rw-r--r--configs/sandbox_flattree_defconfig1
-rw-r--r--configs/snow_defconfig1
-rw-r--r--configs/stm32mp15_defconfig1
-rw-r--r--configs/stm32mp15_trusted_defconfig1
-rw-r--r--disk/part_dos.c10
-rw-r--r--doc/develop/environment.rst51
-rw-r--r--doc/develop/index.rst1
-rw-r--r--doc/device-tree-bindings/arm/arm,scmi.txt15
-rw-r--r--doc/device-tree-bindings/mmc/sandbox,mmc.txt18
-rw-r--r--doc/device-tree-bindings/pinctrl/apple,pinctrl.yaml106
-rw-r--r--doc/usage/environment.rst465
-rw-r--r--doc/usage/index.rst3
-rw-r--r--doc/usage/sf.rst245
-rw-r--r--drivers/clk/aspeed/clk_ast2600.c46
-rw-r--r--drivers/clk/clk_scmi.c3
-rw-r--r--drivers/core/device-remove.c9
-rw-r--r--drivers/core/device.c13
-rw-r--r--drivers/core/of_access.c3
-rw-r--r--drivers/core/of_extra.c12
-rw-r--r--drivers/core/ofnode.c26
-rw-r--r--drivers/core/read.c6
-rw-r--r--drivers/core/uclass.c29
-rw-r--r--drivers/crypto/Kconfig2
-rw-r--r--drivers/crypto/Makefile1
-rw-r--r--drivers/crypto/aspeed/Kconfig20
-rw-r--r--drivers/crypto/aspeed/Makefile2
-rw-r--r--drivers/crypto/aspeed/aspeed_acry.c190
-rw-r--r--drivers/crypto/aspeed/aspeed_hace.c381
-rw-r--r--drivers/crypto/hash/Kconfig8
-rw-r--r--drivers/firmware/scmi/Kconfig28
-rw-r--r--drivers/firmware/scmi/Makefile5
-rw-r--r--drivers/firmware/scmi/mailbox_agent.c16
-rw-r--r--drivers/firmware/scmi/optee_agent.c312
-rw-r--r--drivers/firmware/scmi/smccc_agent.c16
-rw-r--r--drivers/mmc/mmc-uclass.c4
-rw-r--r--drivers/mmc/mtk-sd.c15
-rw-r--r--drivers/mmc/sandbox_mmc.c60
-rw-r--r--drivers/net/Kconfig23
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/aspeed_mdio.c128
-rw-r--r--drivers/net/fec_mxc.h2
-rw-r--r--drivers/net/mscc_eswitch/felix_switch.c10
-rw-r--r--drivers/net/phy/Kconfig10
-rw-r--r--drivers/net/phy/mscc.c56
-rw-r--r--drivers/net/phy/realtek.c69
-rw-r--r--drivers/net/sja1105.c3376
-rw-r--r--drivers/net/tsec.c22
-rw-r--r--drivers/pci/pci-aardvark.c14
-rw-r--r--drivers/pci/pcie_ecam_generic.c17
-rw-r--r--drivers/pci/pcie_ecam_synquacer.c6
-rw-r--r--drivers/pci/pcie_phytium.c8
-rw-r--r--drivers/pci/pcie_rockchip.c13
-rw-r--r--drivers/pci/pcie_xilinx.c5
-rw-r--r--drivers/phy/cadence/phy-cadence-torrent.c4
-rw-r--r--drivers/pinctrl/Kconfig20
-rw-r--r--drivers/pinctrl/Makefile1
-rw-r--r--drivers/pinctrl/aspeed/Makefile1
-rw-r--r--drivers/pinctrl/aspeed/pinctrl_ast2600.c459
-rw-r--r--drivers/pinctrl/pinctrl-apple.c207
-rw-r--r--drivers/power/regulator/scmi_regulator.c3
-rw-r--r--drivers/reset/reset-scmi.c3
-rw-r--r--drivers/tee/optee/optee_msg.h12
-rw-r--r--drivers/usb/cdns3/cdns3-ti.c1
-rw-r--r--env/Kconfig18
-rw-r--r--env/common.c5
-rw-r--r--env/embedded.c1
-rw-r--r--include/command.h2
-rw-r--r--include/configs/aspeed-common.h9
-rw-r--r--include/configs/evb_ast2500.h7
-rw-r--r--include/configs/evb_ast2600.h14
-rw-r--r--include/configs/sandbox.h40
-rw-r--r--include/dm/device.h12
-rw-r--r--include/dm/of_extra.h14
-rw-r--r--include/dm/ofnode.h24
-rw-r--r--include/dm/read.h28
-rw-r--r--include/dm/uclass-internal.h14
-rw-r--r--include/dm/uclass.h17
-rw-r--r--include/env.h7
-rw-r--r--include/env_default.h11
-rw-r--r--include/linux/if_vlan.h26
-rw-r--r--include/net/dsa.h12
-rw-r--r--include/os.h9
-rw-r--r--include/pci.h26
-rw-r--r--include/scmi_agent.h4
-rw-r--r--include/tee.h24
-rw-r--r--include/tsec.h2
-rw-r--r--lib/rsa/Kconfig10
-rw-r--r--net/bootp.c2
-rw-r--r--net/dsa-uclass.c22
-rw-r--r--scripts/env2string.awk91
-rw-r--r--test/dm/ofnode.c96
-rw-r--r--test/py/conftest.py2
-rw-r--r--test/py/multiplexed_log.py10
-rw-r--r--test/py/tests/test_env.py107
-rw-r--r--test/py/u_boot_utils.py5
-rw-r--r--tools/binman/control.py1
136 files changed, 7500 insertions, 622 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index e718ad21355..9045e509d73 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -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
diff --git a/Makefile b/Makefile
index 179d31483ee..57c3643d9a8 100644
--- 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 9606a8b3acf..0e37358af1c 100644
--- 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:
=======================================
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index f7f03837feb..eed27af74e8 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -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
diff --git a/arch/arm/dts/ast2600-evb.dts b/arch/arm/dts/ast2600-evb.dts
index 2abd31341c1..05362d19bdc 100644
--- a/arch/arm/dts/ast2600-evb.dts
+++ b/arch/arm/dts/ast2600-evb.dts
@@ -177,3 +177,13 @@
0x08 0x04
0x08 0x04>;
};
+
+&hace {
+ u-boot,dm-pre-reloc;
+ status = "okay";
+};
+
+&acry {
+ u-boot,dm-pre-reloc;
+ status = "okay";
+};
diff --git a/arch/arm/dts/ast2600.dtsi b/arch/arm/dts/ast2600.dtsi
index f121f547e6d..31905fd2085 100644
--- a/arch/arm/dts/ast2600.dtsi
+++ b/arch/arm/dts/ast2600.dtsi
@@ -187,6 +187,23 @@
};
};
+ 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>;
diff --git a/arch/arm/dts/k3-am642-r5-sk.dts b/arch/arm/dts/k3-am642-r5-sk.dts
index 79eff8259f9..71fcf61ff9f 100644
--- a/arch/arm/dts/k3-am642-r5-sk.dts
+++ b/arch/arm/dts/k3-am642-r5-sk.dts
@@ -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"
@@ -107,6 +109,13 @@
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 {
@@ -142,4 +151,35 @@
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"
diff --git a/arch/arm/dts/k3-am642-sk-u-boot.dtsi b/arch/arm/dts/k3-am642-sk-u-boot.dtsi
index efbcfb36e92..95cf52c37fa 100644
--- a/arch/arm/dts/k3-am642-sk-u-boot.dtsi
+++ b/arch/arm/dts/k3-am642-sk-u-boot.dtsi
@@ -110,3 +110,36 @@
&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;
+};
diff --git a/arch/arm/dts/ls1021a-tsn.dts b/arch/arm/dts/ls1021a-tsn.dts
index 8e0f4eaf684..68f5543644e 100644
--- a/arch/arm/dts/ls1021a-tsn.dts
+++ b/arch/arm/dts/ls1021a-tsn.dts
@@ -14,6 +14,81 @@
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;
+ };
+ };
+ };
};
};
@@ -31,6 +106,17 @@
status = "okay";
};
+/* RGMII delays added via PCB traces */
+&enet2 {
+ phy-mode = "rgmii";
+ status = "okay";
+
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+};
+
&i2c0 {
status = "okay";
};
@@ -46,6 +132,23 @@
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>;
diff --git a/arch/arm/include/asm/arch-aspeed/platform.h b/arch/arm/include/asm/arch-aspeed/platform.h
index d50ec5f8a9f..589abd4a3f6 100644
--- a/arch/arm/include/asm/arch-aspeed/platform.h
+++ b/arch/arm/include/asm/arch-aspeed/platform.h
@@ -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
diff --git a/arch/arm/include/asm/arch-aspeed/scu_ast2600.h b/arch/arm/include/asm/arch-aspeed/scu_ast2600.h
index a205fb1f762..7c5aab98b63 100644
--- a/arch/arm/include/asm/arch-aspeed/scu_ast2600.h
+++ b/arch/arm/include/asm/arch-aspeed/scu_ast2600.h
@@ -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)
diff --git a/arch/arm/lib/crt0.S b/arch/arm/lib/crt0.S
index 956d258c9da..ba312901f33 100644
--- a/arch/arm/lib/crt0.S
+++ b/arch/arm/lib/crt0.S
@@ -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
diff --git a/arch/arm/lib/crt0_64.S b/arch/arm/lib/crt0_64.S
index 28c8356aeea..84c04bd43a2 100644
--- a/arch/arm/lib/crt0_64.S
+++ b/arch/arm/lib/crt0_64.S
@@ -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
diff --git a/arch/arm/mach-aspeed/ast2600/spl.c b/arch/arm/mach-aspeed/ast2600/spl.c
index 0d8cb29678b..6c49d6aede8 100644
--- a/arch/arm/mach-aspeed/ast2600/spl.c
+++ b/arch/arm/mach-aspeed/ast2600/spl.c
@@ -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
diff --git a/arch/arm/mach-rockchip/rk3399/rk3399.c b/arch/arm/mach-rockchip/rk3399/rk3399.c
index 2bc8e60b99b..d40969c8889 100644
--- a/arch/arm/mach-rockchip/rk3399/rk3399.c
+++ b/arch/arm/mach-rockchip/rk3399/rk3399.c
@@ -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,
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index b72dafca2ba..873f85ac3be 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -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;
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 8cd688e8d26..e5261bb9fa2 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -207,6 +207,7 @@
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
index 00000000000..b4c04635a48
--- /dev/null
+++ b/board/sandbox/sandbox.env
@@ -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
diff --git a/boot/bootm_os.c b/boot/bootm_os.c
index e635c72709c..f31820cd07e 100644
--- a/boot/bootm_os.c
+++ b/boot/bootm_os.c
@@ -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;
}
diff --git a/boot/image-fit.c b/boot/image-fit.c
index 33b4a46028b..b629339f4e0 100644
--- a/boot/image-fit.c
+++ b/boot/image-fit.c
@@ -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;
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c
index a7a84f26c1d..a32acca8ee8 100644
--- a/boot/pxe_utils.c
+++ b/boot/pxe_utils.c
@@ -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] = "-";
diff --git a/cmd/bootm.c b/cmd/bootm.c
index 92468d09a1f..b82a872a86c 100644
--- a/cmd/bootm.c
+++ b/cmd/bootm.c
@@ -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;
diff --git a/cmd/elf.c b/cmd/elf.c
index d75b21461c2..2b33c50bd02 100644
--- 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);
diff --git a/cmd/mbr.c b/cmd/mbr.c
index e7e22980969..c269833eb82 100644
--- 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;
diff --git a/cmd/sf.c b/cmd/sf.c
index eac27ed2d77..72246d912fe 100644
--- 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
);
diff --git a/common/Kconfig b/common/Kconfig
index fdcf4536d0f..fede7e40215 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -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
diff --git a/common/console.c b/common/console.c
index 0013d183aeb..0c9099ca52a 100644
--- a/common/console.c
+++ b/common/console.c
@@ -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,
diff --git a/config.mk b/config.mk
index 7bb1fd4ed1b..2595aed218b 100644
--- 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
diff --git a/configs/am64x_evm_a53_defconfig b/configs/am64x_evm_a53_defconfig
index aafbb410b6c..698e80a331a 100644
--- a/configs/am64x_evm_a53_defconfig
+++ b/configs/am64x_evm_a53_defconfig
@@ -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
diff --git a/configs/am64x_evm_r5_defconfig b/configs/am64x_evm_r5_defconfig
index f564fa064e8..f943e1fe688 100644
--- a/configs/am64x_evm_r5_defconfig
+++ b/configs/am64x_evm_r5_defconfig
@@ -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
diff --git a/configs/elgin-rv1108_defconfig b/configs/elgin-rv1108_defconfig
index ee5bfddc438..ed6557a6a35 100644
--- a/configs/elgin-rv1108_defconfig
+++ b/configs/elgin-rv1108_defconfig
@@ -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
diff --git a/configs/evb-ast2600_defconfig b/configs/evb-ast2600_defconfig
index 5f00d6a944a..0f03a72e525 100644
--- a/configs/evb-ast2600_defconfig
+++ b/configs/evb-ast2600_defconfig
@@ -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
diff --git a/configs/evb-rk3128_defconfig b/configs/evb-rk3128_defconfig
index e446a226415..544d6debd02 100644
--- a/configs/evb-rk3128_defconfig
+++ b/configs/evb-rk3128_defconfig
@@ -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
diff --git a/configs/evb-rv1108_defconfig b/configs/evb-rv1108_defconfig
index 916a6fb8510..b6510b5fca6 100644
--- a/configs/evb-rv1108_defconfig
+++ b/configs/evb-rv1108_defconfig
@@ -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
diff --git a/configs/ls1021atsn_qspi_defconfig b/configs/ls1021atsn_qspi_defconfig
index d92fdf4a153..4385df6248d 100644
--- a/configs/ls1021atsn_qspi_defconfig
+++ b/configs/ls1021atsn_qspi_defconfig
@@ -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
diff --git a/configs/ls1021atsn_sdcard_defconfig b/configs/ls1021atsn_sdcard_defconfig
index a745857b929..506a33789cd 100644
--- a/configs/ls1021atsn_sdcard_defconfig
+++ b/configs/ls1021atsn_sdcard_defconfig
@@ -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
diff --git a/configs/pine64_plus_defconfig b/configs/pine64_plus_defconfig
index d1c2c3c3cc1..f42f4e5923a 100644
--- a/configs/pine64_plus_defconfig
+++ b/configs/pine64_plus_defconfig
@@ -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
diff --git a/configs/pm9g45_defconfig b/configs/pm9g45_defconfig
index 9382c389678..96260e05908 100644
--- a/configs/pm9g45_defconfig
+++ b/configs/pm9g45_defconfig
@@ -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
diff --git a/configs/qemu_arm64_defconfig b/configs/qemu_arm64_defconfig
index 83d7ae54de4..02a5e940c41 100644
--- a/configs/qemu_arm64_defconfig
+++ b/configs/qemu_arm64_defconfig
@@ -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
diff --git a/configs/qemu_arm_defconfig b/configs/qemu_arm_defconfig
index ab5574847e8..d4f6d0b4373 100644
--- a/configs/qemu_arm_defconfig
+++ b/configs/qemu_arm_defconfig
@@ -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
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index 7cc76bf2713..f184723a899 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -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
diff --git a/configs/snow_defconfig b/configs/snow_defconfig
index e5bac37808e..00181124eca 100644
--- a/configs/snow_defconfig
+++ b/configs/snow_defconfig
@@ -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
diff --git a/configs/stm32mp15_defconfig b/configs/stm32mp15_defconfig
index 4c6a52fc543..7b844a3e46e 100644
--- a/configs/stm32mp15_defconfig
+++ b/configs/stm32mp15_defconfig
@@ -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
diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig
index feca26e9736..270cbaa7335 100644
--- a/configs/stm32mp15_trusted_defconfig
+++ b/configs/stm32mp15_trusted_defconfig
@@ -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
diff --git a/disk/part_dos.c b/disk/part_dos.c
index 9e29aa6583a..94fae7166d7 100644
--- a/disk/part_dos.c
+++ b/disk/part_dos.c
@@ -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
index 00000000000..0b86fafbff7
--- /dev/null
+++ b/doc/develop/environment.rst
@@ -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.
diff --git a/doc/develop/index.rst b/doc/develop/index.rst
index b3871b16f35..9592d193fca 100644
--- a/doc/develop/index.rst
+++ b/doc/develop/index.rst
@@ -16,6 +16,7 @@ Implementation
devicetree/index
distro
driver-model/index
+ environment
global_data
logging
makefiles
diff --git a/doc/device-tree-bindings/arm/arm,scmi.txt b/doc/device-tree-bindings/arm/arm,scmi.txt
index a76124f4a30..92572eabb58 100644
--- a/doc/device-tree-bindings/arm/arm,scmi.txt
+++ b/doc/device-tree-bindings/arm/arm,scmi.txt
@@ -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
index 00000000000..1170bcd6a00
--- /dev/null
+++ b/doc/device-tree-bindings/mmc/sandbox,mmc.txt
@@ -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
index 00000000000..d50571affd1
--- /dev/null
+++ b/doc/device-tree-bindings/pinctrl/apple,pinctrl.yaml
@@ -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
index 00000000000..d295cc89878
--- /dev/null
+++ b/doc/usage/environment.rst
@@ -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.
diff --git a/doc/usage/index.rst b/doc/usage/index.rst
index 356f2a56181..3905540735c 100644
--- a/doc/usage/index.rst
+++ b/doc/usage/index.rst
@@ -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
index 00000000000..71bd1be5175
--- /dev/null
+++ b/doc/usage/sf.rst
@@ -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
diff --git a/drivers/clk/aspeed/clk_ast2600.c b/drivers/clk/aspeed/clk_ast2600.c
index 3a92739f5cf..42ca39421cf 100644
--- a/drivers/clk/aspeed/clk_ast2600.c
+++ b/drivers/clk/aspeed/clk_ast2600.c
@@ -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;
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c
index 93a4819501c..9a0a6f66434 100644
--- a/drivers/clk/clk_scmi.c
+++ b/drivers/clk/clk_scmi.c
@@ -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>
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 11d3959d20f..69c50da44a9 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -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);
diff --git a/drivers/core/device.c b/drivers/core/device.c
index efd07176e37..aed093c2af1 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -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;
diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c
index 9960e6b310b..3707143ae66 100644
--- a/drivers/core/of_access.c
+++ b/drivers/core/of_access.c
@@ -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.
diff --git a/drivers/core/of_extra.c b/drivers/core/of_extra.c
index 632a1c2210e..59ce9174ad0 100644
--- a/drivers/core/of_extra.c
+++ b/drivers/core/of_extra.c
@@ -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;
+}
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 08705ef8d99..709bea272a6 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -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)
{
diff --git a/drivers/core/read.c b/drivers/core/read.c
index 4307ca45799..31f9e78a062 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -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)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index c5a50952fd0..2aa21430775 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -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",
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 0082177c21f..675081ecd37 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -4,4 +4,6 @@ source drivers/crypto/hash/Kconfig
source drivers/crypto/fsl/Kconfig
+source drivers/crypto/aspeed/Kconfig
+
endmenu
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index e8bae43e3f0..6b762565a1f 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -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
index 00000000000..9bf317177aa
--- /dev/null
+++ b/drivers/crypto/aspeed/Kconfig
@@ -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
index 00000000000..58b55fc46e4
--- /dev/null
+++ b/drivers/crypto/aspeed/Makefile
@@ -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
index 00000000000..c28cdf374b6
--- /dev/null
+++ b/drivers/crypto/aspeed/aspeed_acry.c
@@ -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
index 00000000000..1178cc6a769
--- /dev/null
+++ b/drivers/crypto/aspeed/aspeed_hace.c
@@ -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,
+};
diff --git a/drivers/crypto/hash/Kconfig b/drivers/crypto/hash/Kconfig
index cd29a5c6a4f..bf9540eca67 100644
--- a/drivers/crypto/hash/Kconfig
+++ b/drivers/crypto/hash/Kconfig
@@ -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
diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig
index c3a109beac7..8cf85f0d7a1 100644
--- a/drivers/firmware/scmi/Kconfig
+++ b/drivers/firmware/scmi/Kconfig
@@ -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".
diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile
index 966475ec10a..b2ff483c75a 100644
--- a/drivers/firmware/scmi/Makefile
+++ b/drivers/firmware/scmi/Makefile
@@ -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
diff --git a/drivers/firmware/scmi/mailbox_agent.c b/drivers/firmware/scmi/mailbox_agent.c
index ea35e7e09ed..8e4af0c8faf 100644
--- a/drivers/firmware/scmi/mailbox_agent.c
+++ b/drivers/firmware/scmi/mailbox_agent.c
@@ -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
index 00000000000..1f265922343
--- /dev/null
+++ b/drivers/firmware/scmi/optee_agent.c
@@ -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,
+};
diff --git a/drivers/firmware/scmi/smccc_agent.c b/drivers/firmware/scmi/smccc_agent.c
index f185891e8fd..5e166ca93ee 100644
--- a/drivers/firmware/scmi/smccc_agent.c
+++ b/drivers/firmware/scmi/smccc_agent.c
@@ -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,
};
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index 3ee92d03ca2..b80e838066c 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -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);
diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c
index 8599f095bcd..97182ffd7f5 100644
--- a/drivers/mmc/mtk-sd.c
+++ b/drivers/mmc/mtk-sd.c
@@ -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 = {
diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c
index 895fbffecfc..451fe4a4e5a 100644
--- a/drivers/mmc/sandbox_mmc.c
+++ b/drivers/mmc/sandbox_mmc.c
@@ -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),
};
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index c1a49173c28..e054bec46ed 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -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
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e4078d15a99..cf6294c3361 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -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
index 00000000000..a99715a7282
--- /dev/null
+++ b/drivers/net/aspeed_mdio.c
@@ -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),
+};
diff --git a/drivers/net/fec_mxc.h b/drivers/net/fec_mxc.h
index 1c0d0e5b8f8..48faa33d66e 100644
--- a/drivers/net/fec_mxc.h
+++ b/drivers/net/fec_mxc.h
@@ -272,7 +272,7 @@ struct fec_priv {
struct clk clk_ref;
struct clk clk_ptp;
u32 clk_rate;
- char promisc;
+ bool promisc;
};
/**
diff --git a/drivers/net/mscc_eswitch/felix_switch.c b/drivers/net/mscc_eswitch/felix_switch.c
index 551fc2c9f96..2df8dde55fb 100644
--- a/drivers/net/mscc_eswitch/felix_switch.c
+++ b/drivers/net/mscc_eswitch/felix_switch.c
@@ -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:
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 68ee7d7a2dd..e69cd8a4b31 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -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
diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
index d1a643cf5a0..f9482b21a01 100644
--- a/drivers/net/phy/mscc.c
+++ b/drivers/net/phy/mscc.c
@@ -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);
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index b1b1fa50809..24c3ea59bbb 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -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)
@@ -49,10 +48,10 @@
#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
index 00000000000..17bab33eddb
--- /dev/null
+++ b/drivers/net/sja1105.c
@@ -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),
+};
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index 0ce97656715..beca886b256 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -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 = {
diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c
index 4e94b776c5b..6d73aab03f9 100644
--- a/drivers/pci/pci-aardvark.c
+++ b/drivers/pci/pci-aardvark.c
@@ -165,16 +165,6 @@
#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);
diff --git a/drivers/pci/pcie_ecam_generic.c b/drivers/pci/pcie_ecam_generic.c
index e83e5aff206..1a9f9aec2ee 100644
--- a/drivers/pci/pcie_ecam_generic.c
+++ b/drivers/pci/pcie_ecam_generic.c
@@ -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 },
{ }
};
diff --git a/drivers/pci/pcie_ecam_synquacer.c b/drivers/pci/pcie_ecam_synquacer.c
index c6e7c59f8a6..e3e22891088 100644
--- a/drivers/pci/pcie_ecam_synquacer.c
+++ b/drivers/pci/pcie_ecam_synquacer.c
@@ -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;
diff --git a/drivers/pci/pcie_phytium.c b/drivers/pci/pcie_phytium.c
index 752e1703215..a8072762542 100644
--- a/drivers/pci/pcie_phytium.c
+++ b/drivers/pci/pcie_phytium.c
@@ -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) !=
diff --git a/drivers/pci/pcie_rockchip.c b/drivers/pci/pcie_rockchip.c
index b0c91c0f430..67039d2a29f 100644
--- a/drivers/pci/pcie_rockchip.c
+++ b/drivers/pci/pcie_rockchip.c
@@ -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) {
diff --git a/drivers/pci/pcie_xilinx.c b/drivers/pci/pcie_xilinx.c
index ae9a65b0a9e..eb9ec97b74f 100644
--- a/drivers/pci/pcie_xilinx.c
+++ b/drivers/pci/pcie_xilinx.c
@@ -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;
diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c
index 141ece479fe..ef924e7af50 100644
--- a/drivers/phy/cadence/phy-cadence-torrent.c
+++ b/drivers/phy/cadence/phy-cadence-torrent.c
@@ -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);
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 30eaa376c8e..03946245c7d 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -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
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 05b71f2f134..fd736a7f640 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -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/
diff --git a/drivers/pinctrl/aspeed/Makefile b/drivers/pinctrl/aspeed/Makefile
index 2e6ed604c8f..a3e01ed1ca9 100644
--- a/drivers/pinctrl/aspeed/Makefile
+++ b/drivers/pinctrl/aspeed/Makefile
@@ -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
index 00000000000..12cba83f6c0
--- /dev/null
+++ b/drivers/pinctrl/aspeed/pinctrl_ast2600.c
@@ -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
index 00000000000..62476358c34
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-apple.c
@@ -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,
+};
diff --git a/drivers/power/regulator/scmi_regulator.c b/drivers/power/regulator/scmi_regulator.c
index b3142bf4e1f..3ddeaf4adcb 100644
--- a/drivers/power/regulator/scmi_regulator.c
+++ b/drivers/power/regulator/scmi_regulator.c
@@ -2,6 +2,9 @@
/*
* Copyright (C) 2020-2021 Linaro Limited
*/
+
+#define LOG_CATEGORY UCLASS_REGULATOR
+
#include <common.h>
#include <dm.h>
#include <errno.h>
diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c
index 1bff8075ee3..ca0135a4203 100644
--- a/drivers/reset/reset-scmi.c
+++ b/drivers/reset/reset-scmi.c
@@ -2,6 +2,9 @@
/*
* Copyright (C) 2019-2020 Linaro Limited
*/
+
+#define LOG_CATEGORY UCLASS_RESET
+
#include <common.h>
#include <dm.h>
#include <errno.h>
diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h
index 8d40ce60c2b..a8ef926a480 100644
--- a/drivers/tee/optee/optee_msg.h
+++ b/drivers/tee/optee/optee_msg.h
@@ -87,16 +87,6 @@
#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
diff --git a/drivers/usb/cdns3/cdns3-ti.c b/drivers/usb/cdns3/cdns3-ti.c
index 43171678ee1..8958f0166bd 100644
--- a/drivers/usb/cdns3/cdns3-ti.c
+++ b/drivers/usb/cdns3/cdns3-ti.c
@@ -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", },
{},
};
diff --git a/env/Kconfig b/env/Kconfig
index 06d72bad1dc..24966f8c373 100644
--- a/env/Kconfig
+++ b/env/Kconfig
@@ -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
diff --git a/env/common.c b/env/common.c
index 208e2adaa01..ee957c0a8c0 100644
--- a/env/common.c
+++ b/env/common.c
@@ -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
*/
diff --git a/env/embedded.c b/env/embedded.c
index 208553e6af1..9f26e6cad9c 100644
--- a/env/embedded.c
+++ b/env/embedded.c
@@ -66,6 +66,7 @@
#endif
#define DEFAULT_ENV_INSTANCE_EMBEDDED
+#include <config.h>
#include <env_default.h>
#ifdef CONFIG_ENV_ADDR_REDUND
diff --git a/include/command.h b/include/command.h
index 137cfbc3231..f8e07a591c6 100644
--- a/include/command.h
+++ b/include/command.h
@@ -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 */
diff --git a/include/configs/aspeed-common.h b/include/configs/aspeed-common.h
index 5177bf20fad..96526e1a75c 100644
--- a/include/configs/aspeed-common.h
+++ b/include/configs/aspeed-common.h
@@ -38,13 +38,4 @@
*/
#define CONFIG_BOOTP_BOOTFILESIZE
-/*
- * Miscellaneous configurable options
- */
-
-#define CONFIG_EXTRA_ENV_SETTINGS \
- "verify=yes\0" \
- "spi_dma=yes\0" \
- ""
-
#endif /* __AST_COMMON_CONFIG_H */
diff --git a/include/configs/evb_ast2500.h b/include/configs/evb_ast2500.h
index dc032c1a419..558d6f9452c 100644
--- a/include/configs/evb_ast2500.h
+++ b/include/configs/evb_ast2500.h
@@ -13,4 +13,11 @@
#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 */
diff --git a/include/configs/evb_ast2600.h b/include/configs/evb_ast2600.h
index 177a52eb916..9049a9fc105 100644
--- a/include/configs/evb_ast2600.h
+++ b/include/configs/evb_ast2600.h
@@ -10,4 +10,18 @@
#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 */
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index d614b704715..cc3a7ff05e4 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -39,16 +39,6 @@
#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
@@ -64,38 +54,8 @@
#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
diff --git a/include/dm/device.h b/include/dm/device.h
index 3028d002ab0..daf28a0a457 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -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
*/
diff --git a/include/dm/of_extra.h b/include/dm/of_extra.h
index f0d205491c1..c2498aa5859 100644
--- a/include/dm/of_extra.h
+++ b/include/dm/of_extra.h
@@ -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
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index 0f680e5aa62..6601bd83189 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -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.
diff --git a/include/dm/read.h b/include/dm/read.h
index 890bf3d8472..75c6ad6ee49 100644
--- a/include/dm/read.h
+++ b/include/dm/read.h
@@ -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)
diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h
index 57c664c6daa..49808c5c856 100644
--- a/include/dm/uclass-internal.h
+++ b/include/dm/uclass-internal.h
@@ -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
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 15e5f9ef5bc..f1fd2ba2463 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -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
diff --git a/include/env.h b/include/env.h
index ee5e30d036d..ff8943ed96c 100644
--- a/include/env.h
+++ b/include/env.h
@@ -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
diff --git a/include/env_default.h b/include/env_default.h
index 23430dc70d7..401e84e3d51 100644
--- a/include/env_default.h
+++ b/include/env_default.h
@@ -10,6 +10,10 @@
#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
index 00000000000..cbc82f4cc21
--- /dev/null
+++ b/include/linux/if_vlan.h
@@ -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_) */
diff --git a/include/net/dsa.h b/include/net/dsa.h
index a339a497303..1b1068cd88c 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -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.
*
diff --git a/include/os.h b/include/os.h
index 770d76e02f7..4cbcbd93a71 100644
--- a/include/os.h
+++ b/include/os.h
@@ -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
*
diff --git a/include/pci.h b/include/pci.h
index 797f224e2fc..6c1094d7299 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -522,6 +522,32 @@
#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>
diff --git a/include/scmi_agent.h b/include/scmi_agent.h
index f1be9ff2091..ed40c7360a9 100644
--- a/include/scmi_agent.h
+++ b/include/scmi_agent.h
@@ -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.
*
diff --git a/include/tee.h b/include/tee.h
index 44e9cd4321b..50051496ae5 100644
--- a/include/tee.h
+++ b/include/tee.h
@@ -32,6 +32,25 @@
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
diff --git a/include/tsec.h b/include/tsec.h
index c301c28d3d5..72f34851ad1 100644
--- a/include/tsec.h
+++ b/include/tsec.h
@@ -122,6 +122,8 @@
#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
diff --git a/lib/rsa/Kconfig b/lib/rsa/Kconfig
index 469596abe7a..be9775bcceb 100644
--- a/lib/rsa/Kconfig
+++ b/lib/rsa/Kconfig
@@ -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
diff --git a/net/bootp.c b/net/bootp.c
index 655b9cceb66..58e30cd6b0c 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -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 */
diff --git a/net/dsa-uclass.c b/net/dsa-uclass.c
index bf762cd2a8c..606b1539a77 100644
--- a/net/dsa-uclass.c
+++ b/net/dsa-uclass.c
@@ -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
index 00000000000..1bfe9ed07a4
--- /dev/null
+++ b/scripts/env2string.awk
@@ -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"
+ }
+}
diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c
index cea0746bb3b..5e7c9681c79 100644
--- a/test/dm/ofnode.c
+++ b/test/dm/ofnode.c
@@ -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);
diff --git a/test/py/conftest.py b/test/py/conftest.py
index 11a3f307ea8..16e445cd8ee 100644
--- a/test/py/conftest.py
+++ b/test/py/conftest.py
@@ -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.
diff --git a/test/py/multiplexed_log.py b/test/py/multiplexed_log.py
index 442edada125..5e79075f2e6 100644
--- a/test/py/multiplexed_log.py
+++ b/test/py/multiplexed_log.py
@@ -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)
diff --git a/test/py/tests/test_env.py b/test/py/tests/test_env.py
index 9bed2f48d77..f85cb031382 100644
--- a/test/py/tests/test_env.py
+++ b/test/py/tests/test_env.py
@@ -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')
diff --git a/test/py/u_boot_utils.py b/test/py/u_boot_utils.py
index 089eda5434c..c4fc23aeda3 100644
--- a/test/py/u_boot_utils.py
+++ b/test/py/u_boot_utils.py
@@ -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
diff --git a/tools/binman/control.py b/tools/binman/control.py
index 304fc70f56f..7da69ba38de 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -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