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
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
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 \
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) ;
# 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."
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:
=======================================
select CLK
select CMD_USB
select DM
+ select DM_GPIO
select DM_KEYBOARD
select DM_SERIAL
select DM_USB
select LINUX_KERNEL_IMAGE_HEADER
select OF_CONTROL
select OF_BOARD
+ select PINCTRL
select POSITION_INDEPENDENT
select USB
imply CMD_DM
0x08 0x04
0x08 0x04>;
};
+
+&hace {
+ u-boot,dm-pre-reloc;
+ status = "okay";
+};
+
+&acry {
+ u-boot,dm-pre-reloc;
+ status = "okay";
+};
};
};
+ 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>;
/dts-v1/;
+#include <dt-bindings/mux/ti-serdes.h>
+#include <dt-bindings/phy/phy.h>
#include "k3-am642.dtsi"
#include "k3-am64-sk-lp4-1333MTs.dtsi"
#include "k3-am64-ddr.dtsi"
AM64X_IOPAD(0x029c, PIN_INPUT_PULLUP, 0) /* (C20) MMC1_SDWP */
>;
};
+
+ main_usb0_pins_default: main-usb0-pins-default {
+ u-boot,dm-spl;
+ pinctrl-single,pins = <
+ AM64X_IOPAD(0x02a8, PIN_OUTPUT, 0) /* (E19) USB0_DRVVBUS */
+ >;
+ };
};
&dmsc {
pinctrl-0 = <&main_mmc1_pins_default>;
};
+&serdes_ln_ctrl {
+ idle-states = <AM64_SERDES0_LANE0_USB>;
+};
+
+&serdes_wiz0 {
+ status = "okay";
+};
+
+&serdes0 {
+ serdes0_usb_link: link@0 {
+ reg = <0>;
+ cdns,num-lanes = <1>;
+ #phy-cells = <0>;
+ cdns,phy-type = <PHY_TYPE_USB3>;
+ resets = <&serdes_wiz0 1>;
+ };
+};
+
+&usbss0 {
+ ti,vbus-divider;
+};
+
+&usb0 {
+ dr_mode = "host";
+ maximum-speed = "super-speed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_usb0_pins_default>;
+ phys = <&serdes0_usb_link>;
+ phy-names = "cdns3,usb3-phy";
+};
+
#include "k3-am642-sk-u-boot.dtsi"
&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;
+};
enet1-sgmii-phy = &sgmii_phy1;
spi0 = &qspi;
spi1 = &dspi1;
+ ethernet0 = &enet0;
+ ethernet1 = &enet1;
+ ethernet2 = &enet2;
+ ethernet3 = &swp2;
+ ethernet4 = &swp3;
+ ethernet5 = &swp4;
+ ethernet6 = &swp5;
+ };
+};
+
+&dspi0 {
+ bus-num = <0>;
+ status = "okay";
+
+ sja1105: ethernet-switch@1 {
+ reg = <0x1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "nxp,sja1105t";
+ /* 12 MHz */
+ spi-max-frequency = <12000000>;
+ /* Sample data on trailing clock edge */
+ spi-cpha;
+ /* SPI controller settings for SJA1105 timing requirements */
+ fsl,spi-cs-sck-delay = <1000>;
+ fsl,spi-sck-cs-delay = <1000>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ swp5: port@0 {
+ /* ETH5 written on chassis */
+ label = "swp5";
+ phy-handle = <&rgmii_phy6>;
+ phy-mode = "rgmii-id";
+ reg = <0>;
+ };
+
+ swp2: port@1 {
+ /* ETH2 written on chassis */
+ label = "swp2";
+ phy-handle = <&rgmii_phy3>;
+ phy-mode = "rgmii-id";
+ reg = <1>;
+ };
+
+ swp3: port@2 {
+ /* ETH3 written on chassis */
+ label = "swp3";
+ phy-handle = <&rgmii_phy4>;
+ phy-mode = "rgmii-id";
+ reg = <2>;
+ };
+
+ swp4: port@3 {
+ /* ETH4 written on chassis */
+ label = "swp4";
+ phy-handle = <&rgmii_phy5>;
+ phy-mode = "rgmii-id";
+ reg = <3>;
+ };
+
+ port@4 {
+ /* Internal port connected to eth2 */
+ ethernet = <&enet2>;
+ phy-mode = "rgmii";
+ reg = <4>;
+
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+ };
};
};
status = "okay";
};
+/* RGMII delays added via PCB traces */
+&enet2 {
+ phy-mode = "rgmii";
+ status = "okay";
+
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+};
+
&i2c0 {
status = "okay";
};
reg = <0x2>;
};
+ /* BCM5464 quad PHY */
+ rgmii_phy3: ethernet-phy@3 {
+ reg = <0x3>;
+ };
+
+ rgmii_phy4: ethernet-phy@4 {
+ reg = <0x4>;
+ };
+
+ rgmii_phy5: ethernet-phy@5 {
+ reg = <0x5>;
+ };
+
+ rgmii_phy6: ethernet-phy@6 {
+ reg = <0x6>;
+ };
+
/* SGMII PCS for enet0 */
tbi0: tbi-phy@1f {
reg = <0x1f>;
#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
#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)
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
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
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
#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 */
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,
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;
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>;
--- /dev/null
+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
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;
}
* 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
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;
* 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");
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] = "-";
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;
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' */
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);
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;
return ret == 0 ? 0 : 1;
}
-#ifdef CONFIG_CMD_SF_TEST
enum {
STAGE_ERASE,
STAGE_CHECK,
STAGE_COUNT,
};
-static char *stage_name[STAGE_COUNT] = {
+static const char *stage_name[STAGE_COUNT] = {
"erase",
"check",
"write",
return 0;
}
-#endif /* CONFIG_CMD_SF_TEST */
static int do_spi_flash(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
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;
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"
" 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
);
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
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,
ifneq ($(BOARD),)
ifdef VENDOR
BOARDDIR = $(VENDOR)/$(BOARD)
+ENVDIR=${vendor}/env
else
BOARDDIR = $(BOARD)
+ENVDIR=${board}/env
endif
endif
ifdef BOARD
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
# 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
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
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
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
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
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
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
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
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
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
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 */
--- /dev/null
+.. 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.
devicetree/index
distro
driver-model/index
+ environment
global_data
logging
makefiles
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
- #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:
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
------------------------------------------------------------
--- /dev/null
+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;
+};
--- /dev/null
+# 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)>;
+ };
+ };
+ };
--- /dev/null
+.. 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.
:maxdepth: 1
dfu
+ environment
fdt_overlays
fit
netconsole
partitions
cmdline
+ environment
Shell commands
--------------
qfw
reset
sbi
+ sf
scp03
setexpr
size
--- /dev/null
+.. 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
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);
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;
/*
* Copyright (C) 2019-2020 Linaro Limited
*/
+
+#define LOG_CATEGORY UCLASS_CLK
+
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
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);
}
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);
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;
}
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;
* @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.
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;
+}
}
}
+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)
{
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)
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;
}
#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;
return ret;
}
+ return 0;
+}
+
+int uclass_unbind_device(struct udevice *dev)
+{
list_del(&dev->uclass_node);
+
return 0;
}
#endif
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",
source drivers/crypto/fsl/Kconfig
+source drivers/crypto/aspeed/Kconfig
+
endmenu
obj-y += rsa_mod_exp/
obj-y += fsl/
obj-y += hash/
+obj-y += aspeed/
--- /dev/null
+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.
--- /dev/null
+obj-$(CONFIG_ASPEED_HACE) += aspeed_hace.o
+obj-$(CONFIG_ASPEED_ACRY) += aspeed_acry.o
--- /dev/null
+// 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,
+};
--- /dev/null
+// 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,
+};
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
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
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".
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
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);
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;
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;
}
.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,
};
--- /dev/null
+// 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,
+};
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;
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;
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[] = {
.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,
};
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);
{
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);
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,
#ifdef MMC_SUPPORTS_TUNING
.execute_tuning = msdc_execute_tuning,
#endif
+ .wait_dat0 = msdc_ops_wait_dat0,
};
static const struct msdc_compatible mt7620_compat = {
#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;
};
/**
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: {
struct blk_desc *blk;
int ret;
+ plat->fname = dev_read_string(dev, "filename");
+
ret = mmc_of_parse(dev, cfg);
if (ret)
return ret;
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);
.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),
};
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"
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
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
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
--- /dev/null
+// 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),
+};
struct clk clk_ref;
struct clk clk_ptp;
u32 clk_rate;
- char promisc;
+ bool promisc;
};
/**
*/
#include <dm/device_compat.h>
+#include <dm/of_extra.h>
#include <linux/delay.h>
#include <net/dsa.h>
#include <asm/io.h>
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:
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
/* 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
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,
.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,
{
phy_register(&VSC8530_driver);
phy_register(&VSC8531_driver);
+ phy_register(&VSC8502_driver);
phy_register(&VSC8540_driver);
phy_register(&VSC8541_driver);
phy_register(&VSC8574_driver);
#include <linux/delay.h>
#define PHY_RTL8211x_FORCE_MASTER BIT(1)
-#define PHY_RTL8211E_PINE64_GIGABIT_FIX BIT(2)
#define PHY_RTL8211F_FORCE_EEE_RXC_ON BIT(3)
#define PHY_RTL8201F_S700_RMII_TIMINGS BIT(4)
#define MIIM_RTL8211F_PHYSTAT_SPDDONE 0x0800
#define MIIM_RTL8211F_PHYSTAT_LINK 0x0004
-#define MIIM_RTL8211E_CONFREG 0x1c
-#define MIIM_RTL8211E_CONFREG_TXD 0x0002
-#define MIIM_RTL8211E_CONFREG_RXD 0x0004
-#define MIIM_RTL8211E_CONFREG_MAGIC 0xb400 /* Undocumented */
+#define MIIM_RTL8211E_CONFREG 0x1c
+#define MIIM_RTL8211E_CTRL_DELAY BIT(13)
+#define MIIM_RTL8211E_TX_DELAY BIT(12)
+#define MIIM_RTL8211E_RX_DELAY BIT(11)
#define MIIM_RTL8211E_EXT_PAGE_SELECT 0x1e
static int rtl8211e_probe(struct phy_device *phydev)
{
-#ifdef CONFIG_RTL8211E_PINE64_GIGABIT_FIX
- phydev->flags |= PHY_RTL8211E_PINE64_GIGABIT_FIX;
-#endif
-
return 0;
}
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);
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;
.mask = 0xffffff,
.features = PHY_GBIT_FEATURES,
.probe = &rtl8211e_probe,
- .config = &rtl8211x_config,
+ .config = &rtl8211e_config,
.startup = &rtl8211e_startup,
.shutdown = &genphy_shutdown,
};
--- /dev/null
+// 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),
+};
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(®s->rctrl, RCTRL_PROM);
+ else
+ clrbits_be32(®s->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,
out_be32(®s->hash.gaddr6, 0);
out_be32(®s->hash.gaddr7, 0);
- out_be32(®s->rctrl, 0x00000000);
-
/* Init RMON mib registers */
memset((void *)®s->rmon, 0, sizeof(regs->rmon));
* 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;
0x71, 0x72};
/* Enable promiscuous mode */
- setbits_be32(®s->rctrl, 0x8);
+ setbits_be32(®s->rctrl, RCTRL_PROM);
/* Enable loopback mode */
setbits_be32(®s->maccfg1, MACCFG1_LOOPBACK);
/* Enable transmit and receive */
if (fail)
panic("eTSEC init fail!\n");
/* Disable promiscuous mode */
- clrbits_be32(®s->rctrl, 0x8);
+ clrbits_be32(®s->rctrl, RCTRL_PROM);
/* Disable loopback mode */
clrbits_be32(®s->maccfg1, MACCFG1_LOOPBACK);
}
.free_pkt = tsec_free_pkt,
.stop = tsec_halt,
.mcast = tsec_mcast_addr,
+ .set_promisc = tsec_set_promisc,
};
static struct tsec_data etsec2_data = {
#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
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);
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);
#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
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;
};
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 },
{ }
};
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;
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) {
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) !=
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)
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) {
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) {
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;
/* 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);
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
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
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/
obj-$(CONFIG_ASPEED_AST2500_PINCTRL) += pinctrl_ast2500.o
+obj-$(CONFIG_ASPEED_AST2600_PINCTRL) += pinctrl_ast2600.o
--- /dev/null
+// 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,
+};
--- /dev/null
+// 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,
+};
/*
* Copyright (C) 2020-2021 Linaro Limited
*/
+
+#define LOG_CATEGORY UCLASS_REGULATOR
+
#include <common.h>
#include <dm.h>
#include <errno.h>
/*
* Copyright (C) 2019-2020 Linaro Limited
*/
+
+#define LOG_CATEGORY UCLASS_RESET
+
#include <common.h>
#include <dm.h>
#include <errno.h>
#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
* 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
static const struct udevice_id cdns_ti_of_match[] = {
{ .compatible = "ti,j721e-usb", },
+ { .compatible = "ti,am64-usb", },
{},
};
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
1 : 0;
}
+bool env_get_autostart(void)
+{
+ return env_get_yesno("autostart") == 1;
+}
+
/*
* Look up the variable from the default environment
*/
#endif
#define DEFAULT_ENV_INSTANCE_EMBEDDED
+#include <config.h>
#include <env_default.h>
#ifdef CONFIG_ENV_ADDR_REDUND
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 */
*/
#define CONFIG_BOOTP_BOOTFILESIZE
-/*
- * Miscellaneous configurable options
- */
-
-#define CONFIG_EXTRA_ENV_SETTINGS \
- "verify=yes\0" \
- "spi_dma=yes\0" \
- ""
-
#endif /* __AST_COMMON_CONFIG_H */
#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 */
#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 */
#define CONFIG_SYS_BAUDRATE_TABLE {4800, 9600, 19200, 38400, 57600,\
115200}
-#define BOOT_TARGET_DEVICES(func) \
- func(HOST, host, 1) \
- func(HOST, host, 0)
-
-#ifdef __ASSEMBLY__
-#define BOOTENV
-#else
-#include <config_distro_bootcmd.h>
-#endif
-
#define CONFIG_KEEP_SERVERADDR
#define CONFIG_UDP_CHECKSUM
#define CONFIG_TIMESTAMP
#define CONFIG_LCD_BMP_RLE8
#define CONFIG_KEYBOARD
-
-#define SANDBOX_SERIAL_SETTINGS "stdin=serial,cros-ec-keyb,usbkbd\0" \
- "stdout=serial,vidconsole\0" \
- "stderr=serial,vidconsole\0"
-#else
-#define SANDBOX_SERIAL_SETTINGS "stdin=serial\0" \
- "stdout=serial,vidconsole\0" \
- "stderr=serial,vidconsole\0"
#endif
-#define SANDBOX_ETH_SETTINGS "ethaddr=00:00:11:22:33:44\0" \
- "eth2addr=00:00:11:22:33:48\0" \
- "eth3addr=00:00:11:22:33:45\0" \
- "eth4addr=00:00:11:22:33:48\0" \
- "eth5addr=00:00:11:22:33:46\0" \
- "eth6addr=00:00:11:22:33:47\0" \
- "ipaddr=1.2.3.4\0"
-
-#define MEM_LAYOUT_ENV_SETTINGS \
- "bootm_size=0x10000000\0" \
- "kernel_addr_r=0x1000000\0" \
- "fdt_addr_r=0xc00000\0" \
- "ramdisk_addr_r=0x2000000\0" \
- "scriptaddr=0x1000\0" \
- "pxefile_addr_r=0x2000\0"
-
-#define CONFIG_EXTRA_ENV_SETTINGS \
- SANDBOX_SERIAL_SETTINGS \
- SANDBOX_ETH_SETTINGS \
- BOOTENV \
- MEM_LAYOUT_ENV_SETTINGS
-
#ifndef CONFIG_SPL_BUILD
#define CONFIG_SYS_IDE_MAXBUS 1
#define CONFIG_SYS_ATA_IDE0_OFFSET 0
*
* @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
*/
*/
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
*
* @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);
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.
* 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
*
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)
*/
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
*
* @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
* 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);
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
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
#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 */
#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
--- /dev/null
+/* 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_) */
#ifndef __DSA_H__
#define __DSA_H__
+#include <dm/ofnode.h>
#include <phy.h>
#include <net.h>
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.
*
*/
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
*
#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>
}
/**
- * 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.
*
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
#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
/**
* 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
#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
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.
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
*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 */
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)
{
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;
}
--- /dev/null
+# 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"
+ }
+}
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);
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.
"""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
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.
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:
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)
import os
import os.path
from subprocess import call, check_call, CalledProcessError
+import tempfile
import pytest
import u_boot_utils
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')
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:
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.
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
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