diff options
52 files changed, 1316 insertions, 528 deletions
diff --git a/arch/arm/dts/armada-cp110-master.dtsi b/arch/arm/dts/armada-cp110-master.dtsi index e4c17e9f4b..cd5c974482 100644 --- a/arch/arm/dts/armada-cp110-master.dtsi +++ b/arch/arm/dts/armada-cp110-master.dtsi @@ -99,6 +99,15 @@ device-name = "cpm-mdio"; }; + cpm_xmdio: mdio@12a600 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "marvell,xmdio"; + reg = <0x12a600 0x16>; + status = "disabled"; + device-name = "cpm-xmdio"; + }; + cpm_syscon0: system-controller@440000 { compatible = "marvell,cp110-system-controller0", "syscon"; diff --git a/arch/arm/dts/armada-cp110-slave.dtsi b/arch/arm/dts/armada-cp110-slave.dtsi index 2fbd7b5514..b426a4eb69 100644 --- a/arch/arm/dts/armada-cp110-slave.dtsi +++ b/arch/arm/dts/armada-cp110-slave.dtsi @@ -99,6 +99,15 @@ device-name = "cps-mdio"; }; + cps_xmdio: mdio@12a600 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "marvell,xmdio"; + reg = <0x12a600 0x16>; + status = "disabled"; + device-name = "cps-xmdio"; + }; + cps_syscon0: system-controller@440000 { compatible = "marvell,cp110-system-controller0", "syscon"; diff --git a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi index 8589f76d23..bea80c5d00 100644 --- a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi +++ b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi @@ -336,13 +336,12 @@ reg = <0>; /* TODO: phy reset: TCA9555RTWR(i2c:0x21)[p04].GPIO_MCU_RGMII_RSTN */ ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>; - ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>; ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>; }; }; &cpsw_port1 { - phy-mode = "rgmii-id"; + phy-mode = "rgmii-rxid"; phy-handle = <&phy0>; }; diff --git a/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi b/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi index 541da22c48..9291e57e25 100644 --- a/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi +++ b/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi @@ -3,11 +3,18 @@ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ */ +#include <dt-bindings/dma/k3-udma.h> +#include <dt-bindings/net/ti-dp83867.h> + / { chosen { stdout-path = "serial2:115200n8"; tick-timer = &timer1; }; + + aliases { + ethernet0 = &cpsw_port1; + }; }; &cbass_main{ @@ -24,6 +31,184 @@ clock-frequency = <25000000>; u-boot,dm-spl; }; + + mcu_conf: scm_conf@40f00000 { + compatible = "syscon", "simple-mfd"; + reg = <0x0 0x40f00000 0x0 0x20000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x40f00000 0x20000>; + + phy_sel: cpsw-phy-sel@4040 { + compatible = "ti,am654-cpsw-phy-sel"; + reg = <0x4040 0x4>; + reg-names = "gmii-sel"; + }; + }; + + cbass_mcu_navss: mcu_navss { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + dma-coherent; + dma-ranges; + ranges; + + ti,sci-dev-id = <232>; + u-boot,dm-spl; + + mcu_ringacc: ringacc@2b800000 { + compatible = "ti,am654-navss-ringacc"; + reg = <0x0 0x2b800000 0x0 0x400000>, + <0x0 0x2b000000 0x0 0x400000>, + <0x0 0x28590000 0x0 0x100>, + <0x0 0x2a500000 0x0 0x40000>; + reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target"; + ti,num-rings = <286>; + ti,sci-rm-range-gp-rings = <0x1>; /* GP ring range */ + ti,sci = <&dmsc>; + ti,sci-dev-id = <235>; + u-boot,dm-spl; + }; + + mcu_udmap: udmap@31150000 { + compatible = "ti,j721e-navss-mcu-udmap"; + reg = <0x0 0x285c0000 0x0 0x100>, + <0x0 0x2a800000 0x0 0x40000>, + <0x0 0x2aa00000 0x0 0x40000>; + reg-names = "gcfg", "rchanrt", "tchanrt"; + #dma-cells = <3>; + + ti,ringacc = <&mcu_ringacc>; + ti,psil-base = <0x6000>; + + ti,sci = <&dmsc>; + ti,sci-dev-id = <236>; + + ti,sci-rm-range-tchan = <0x0d>, /* TX_CHAN */ + <0x0f>; /* TX_HCHAN */ + ti,sci-rm-range-rchan = <0x0a>, /* RX_CHAN */ + <0x0b>; /* RX_HCHAN */ + ti,sci-rm-range-rflow = <0x00>; /* GP RFLOW */ + u-boot,dm-spl; + }; + }; + + mcu_cpsw: ethernet@046000000 { + compatible = "ti,j721e-cpsw-nuss"; + #address-cells = <2>; + #size-cells = <2>; + reg = <0x0 0x46000000 0x0 0x200000>; + reg-names = "cpsw_nuss"; + ranges; + dma-coherent; + clocks = <&k3_clks 18 22>; + clock-names = "fck"; + power-domains = <&k3_pds 18 TI_SCI_PD_EXCLUSIVE>; + ti,psil-base = <0x7000>; + cpsw-phy-sel = <&phy_sel>; + + dmas = <&mcu_udmap &mcu_cpsw 0 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 1 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 2 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 3 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 4 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 5 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 6 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 7 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 0 UDMA_DIR_RX>; + dma-names = "tx0", "tx1", "tx2", "tx3", + "tx4", "tx5", "tx6", "tx7", + "rx"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + host: host@0 { + reg = <0>; + ti,label = "host"; + }; + + cpsw_port1: port@1 { + reg = <1>; + ti,mac-only; + ti,label = "port1"; + ti,syscon-efuse = <&mcu_conf 0x200>; + }; + }; + + davinci_mdio: mdio { + #address-cells = <1>; + #size-cells = <0>; + bus_freq = <1000000>; + }; + + cpts { + clocks = <&k3_clks 18 2>; + clock-names = "cpts"; + interrupts-extended = <&gic500 GIC_SPI 858 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cpts"; + ti,cpts-ext-ts-inputs = <4>; + ti,cpts-periodic-outputs = <2>; + }; + + ti,psil-config0 { + linux,udma-mode = <UDMA_PKT_MODE>; + statictr-type = <PSIL_STATIC_TR_NONE>; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config1 { + linux,udma-mode = <UDMA_PKT_MODE>; + statictr-type = <PSIL_STATIC_TR_NONE>; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config2 { + linux,udma-mode = <UDMA_PKT_MODE>; + statictr-type = <PSIL_STATIC_TR_NONE>; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config3 { + linux,udma-mode = <UDMA_PKT_MODE>; + statictr-type = <PSIL_STATIC_TR_NONE>; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config4 { + linux,udma-mode = <UDMA_PKT_MODE>; + statictr-type = <PSIL_STATIC_TR_NONE>; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config5 { + linux,udma-mode = <UDMA_PKT_MODE>; + statictr-type = <PSIL_STATIC_TR_NONE>; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config6 { + linux,udma-mode = <UDMA_PKT_MODE>; + statictr-type = <PSIL_STATIC_TR_NONE>; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config7 { + linux,udma-mode = <UDMA_PKT_MODE>; + statictr-type = <PSIL_STATIC_TR_NONE>; + ti,needs-epib; + ti,psd-size = <16>; + }; + }; }; &secure_proxy_main { @@ -52,6 +237,29 @@ &wkup_pmx0 { u-boot,dm-spl; + mcu_cpsw_pins_default: mcu_cpsw_pins_default { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x0058, PIN_OUTPUT, 0) /* (N4) MCU_RGMII1_TX_CTL */ + J721E_WKUP_IOPAD(0x005c, PIN_INPUT, 0) /* (N5) MCU_RGMII1_RX_CTL */ + J721E_WKUP_IOPAD(0x0060, PIN_OUTPUT, 0) /* (M2) MCU_RGMII1_TD3 */ + J721E_WKUP_IOPAD(0x0064, PIN_OUTPUT, 0) /* (M3) MCU_RGMII1_TD2 */ + J721E_WKUP_IOPAD(0x0068, PIN_OUTPUT, 0) /* (M4) MCU_RGMII1_TD1 */ + J721E_WKUP_IOPAD(0x006c, PIN_OUTPUT, 0) /* (M5) MCU_RGMII1_TD0 */ + J721E_WKUP_IOPAD(0x0078, PIN_INPUT, 0) /* (L2) MCU_RGMII1_RD3 */ + J721E_WKUP_IOPAD(0x007c, PIN_INPUT, 0) /* (L5) MCU_RGMII1_RD2 */ + J721E_WKUP_IOPAD(0x0080, PIN_INPUT, 0) /* (M6) MCU_RGMII1_RD1 */ + J721E_WKUP_IOPAD(0x0084, PIN_INPUT, 0) /* (L6) MCU_RGMII1_RD0 */ + J721E_WKUP_IOPAD(0x0070, PIN_INPUT, 0) /* (N1) MCU_RGMII1_TXC */ + J721E_WKUP_IOPAD(0x0074, PIN_INPUT, 0) /* (M1) MCU_RGMII1_RXC */ + >; + }; + + mcu_mdio_pins_default: mcu_mdio1_pins_default { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x008c, PIN_OUTPUT, 0) /* (L1) MCU_MDIO0_MDC */ + J721E_WKUP_IOPAD(0x0088, PIN_INPUT, 0) /* (L4) MCU_MDIO0_MDIO */ + >; + }; }; &main_pmx0 { @@ -73,3 +281,33 @@ &main_sdhci1 { u-boot,dm-spl; }; + +&mcu_cpsw { + pinctrl-names = "default"; + pinctrl-0 = <&mcu_cpsw_pins_default &mcu_mdio_pins_default>; +}; + +&davinci_mdio { + phy0: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>; + ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>; + }; +}; + +&cpsw_port1 { + phy-mode = "rgmii-rxid"; + phy-handle = <&phy0>; +}; + +&mcu_cpsw { + reg = <0x0 0x46000000 0x0 0x200000>, + <0x0 0x40f00200 0x0 0x2>; + reg-names = "cpsw_nuss", "mac_efuse"; + + cpsw-phy-sel@40f04040 { + compatible = "ti,am654-cpsw-phy-sel"; + reg= <0x0 0x40f04040 0x0 0x4>; + reg-names = "gmii-sel"; + }; +}; diff --git a/arch/arm/mach-tegra/cboot.c b/arch/arm/mach-tegra/cboot.c index 0433081c6c..0762144ecf 100644 --- a/arch/arm/mach-tegra/cboot.c +++ b/arch/arm/mach-tegra/cboot.c @@ -495,7 +495,7 @@ static int cboot_get_ethaddr_legacy(const void *fdt, uint8_t mac[ETH_ALEN]) return -ENOENT; } - eth_parse_enetaddr(prop, mac); + string_to_enetaddr(prop, mac); if (!is_valid_ethaddr(mac)) { printf("Invalid MAC address: %s\n", prop); diff --git a/board/renesas/sh7752evb/sh7752evb.c b/board/renesas/sh7752evb/sh7752evb.c index d675f65c12..203eecf3d6 100644 --- a/board/renesas/sh7752evb/sh7752evb.c +++ b/board/renesas/sh7752evb/sh7752evb.c @@ -94,7 +94,7 @@ static void set_mac_to_sh_giga_eth_register(int channel, char *mac_string) unsigned char mac[6]; unsigned long val; - eth_parse_enetaddr(mac_string, mac); + string_to_enetaddr(mac_string, mac); if (!channel) ether = GETHER0_MAC_BASE; diff --git a/board/renesas/sh7753evb/sh7753evb.c b/board/renesas/sh7753evb/sh7753evb.c index 43e13829f3..0b118b2f65 100644 --- a/board/renesas/sh7753evb/sh7753evb.c +++ b/board/renesas/sh7753evb/sh7753evb.c @@ -101,7 +101,7 @@ static void set_mac_to_sh_giga_eth_register(int channel, char *mac_string) unsigned char mac[6]; unsigned long val; - eth_parse_enetaddr(mac_string, mac); + string_to_enetaddr(mac_string, mac); if (!channel) ether = GETHER0_MAC_BASE; diff --git a/board/renesas/sh7757lcr/sh7757lcr.c b/board/renesas/sh7757lcr/sh7757lcr.c index 1d7ed9977e..e8d1fdd03f 100644 --- a/board/renesas/sh7757lcr/sh7757lcr.c +++ b/board/renesas/sh7757lcr/sh7757lcr.c @@ -141,7 +141,7 @@ static void set_mac_to_sh_eth_register(int channel, char *mac_string) unsigned char mac[6]; unsigned long val; - eth_parse_enetaddr(mac_string, mac); + string_to_enetaddr(mac_string, mac); if (!channel) ether = ETHER0_MAC_BASE; @@ -160,7 +160,7 @@ static void set_mac_to_sh_giga_eth_register(int channel, char *mac_string) unsigned char mac[6]; unsigned long val; - eth_parse_enetaddr(mac_string, mac); + string_to_enetaddr(mac_string, mac); if (!channel) ether = GETHER0_MAC_BASE; diff --git a/cmd/Kconfig b/cmd/Kconfig index bc8318d7fa..1e4cf146c5 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1473,8 +1473,22 @@ config CMD_NFS config CMD_MII bool "mii" - help - Enable MII utility commands. + imply CMD_MDIO + help + If set, allows 802.3(clause 22) MII Management functions interface access + The management interface specified in Clause 22 provides + a simple, two signal, serial interface to connect a + Station Management entity and a managed PHY for providing access + to management parameters and services. + The interface is referred to as the MII management interface. + +config CMD_MDIO + bool "mdio" + depends on PHYLIB + help + If set, allows Enable 802.3(clause 45) MDIO interface registers access + The MDIO interface is orthogonal to the MII interface and extends + it by adding access to more registers through indirect addressing. config CMD_PING bool "ping" diff --git a/cmd/Makefile b/cmd/Makefile index e87c2f1625..3ac7104546 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -89,9 +89,7 @@ obj-$(CONFIG_CMD_MEMORY) += mem.o obj-$(CONFIG_CMD_IO) += io.o obj-$(CONFIG_CMD_MFSL) += mfsl.o obj-$(CONFIG_CMD_MII) += mii.o -ifdef CONFIG_PHYLIB -obj-$(CONFIG_CMD_MII) += mdio.o -endif +obj-$(CONFIG_CMD_MDIO) += mdio.o obj-$(CONFIG_CMD_MISC) += misc.o obj-$(CONFIG_CMD_MMC) += mmc.o obj-$(CONFIG_MP) += mp.o diff --git a/cmd/ethsw.c b/cmd/ethsw.c index 8846805799..8d271ce1f3 100644 --- a/cmd/ethsw.c +++ b/cmd/ethsw.c @@ -864,7 +864,7 @@ static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc, return 0; } - eth_parse_enetaddr(argv[*argc_nr + 1], parsed_cmd->ethaddr); + string_to_enetaddr(argv[*argc_nr + 1], parsed_cmd->ethaddr); if (is_broadcast_ethaddr(parsed_cmd->ethaddr)) { memset(parsed_cmd->ethaddr, 0xFF, sizeof(parsed_cmd->ethaddr)); diff --git a/cmd/nvedit.c b/cmd/nvedit.c index 3420e0b985..81d94cd193 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -361,7 +361,7 @@ ulong env_get_hex(const char *varname, ulong default_val) int eth_env_get_enetaddr(const char *name, uint8_t *enetaddr) { - eth_parse_enetaddr(env_get(name), enetaddr); + string_to_enetaddr(env_get(name), enetaddr); return is_valid_ethaddr(enetaddr); } diff --git a/cmd/pxe_utils.c b/cmd/pxe_utils.c index 42b584ead3..a636346bb5 100644 --- a/cmd/pxe_utils.c +++ b/cmd/pxe_utils.c @@ -22,7 +22,7 @@ #include "pxe_utils.h" -#define MAX_TFTP_PATH_LEN 127 +#define MAX_TFTP_PATH_LEN 512 bool is_pxe; diff --git a/configs/j721e_evm_a72_defconfig b/configs/j721e_evm_a72_defconfig index 61d28db803..daa661384d 100644 --- a/configs/j721e_evm_a72_defconfig +++ b/configs/j721e_evm_a72_defconfig @@ -51,6 +51,7 @@ CONFIG_DEFAULT_DEVICE_TREE="k3-j721e-common-proc-board" CONFIG_SPL_MULTI_DTB_FIT=y CONFIG_SPL_MULTI_DTB_FIT_NO_COMPRESSION=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_NET_RANDOM_ETHADDR=y CONFIG_DM=y CONFIG_SPL_DM=y CONFIG_SPL_DM_SEQ_ALIAS=y @@ -61,6 +62,8 @@ CONFIG_SPL_OF_TRANSLATE=y CONFIG_CLK=y CONFIG_SPL_CLK=y CONFIG_CLK_TI_SCI=y +CONFIG_DMA_CHANNELS=y +CONFIG_TI_K3_NAVSS_UDMA=y CONFIG_TI_SCI_PROTOCOL=y CONFIG_DM_MAILBOX=y CONFIG_K3_SEC_PROXY=y @@ -79,6 +82,10 @@ CONFIG_SYS_FLASH_CFI=y CONFIG_HBMC_AM654=y CONFIG_DM_SPI_FLASH=y CONFIG_SPI_FLASH_STMICRO=y +CONFIG_PHY_TI=y +CONFIG_PHY_FIXED=y +CONFIG_DM_ETH=y +CONFIG_TI_AM65_CPSW_NUSS=y CONFIG_PINCTRL=y # CONFIG_PINCTRL_GENERIC is not set CONFIG_SPL_PINCTRL=y @@ -93,6 +100,7 @@ CONFIG_RESET_TI_SCI=y CONFIG_SCSI=y CONFIG_DM_SCSI=y CONFIG_DM_SERIAL=y +CONFIG_SOC_TI=y CONFIG_SPI=y CONFIG_DM_SPI=y CONFIG_CADENCE_QSPI=y diff --git a/doc/README.enetaddr b/doc/README.enetaddr index f926485986..5baa9f2179 100644 --- a/doc/README.enetaddr +++ b/doc/README.enetaddr @@ -76,12 +76,12 @@ To assist in the management of these layers, a few helper functions exist. You should use these rather than attempt to do any kind of parsing/manipulation yourself as many common errors have arisen in the past. - * void eth_parse_enetaddr(const char *addr, uchar *enetaddr); + * void string_to_enetaddr(const char *addr, uchar *enetaddr); Convert a string representation of a MAC address to the binary version. char *addr = "00:11:22:33:44:55"; uchar enetaddr[6]; -eth_parse_enetaddr(addr, enetaddr); +string_to_enetaddr(addr, enetaddr); /* enetaddr now equals { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 } */ * int eth_env_get_enetaddr(char *name, uchar *enetaddr); diff --git a/doc/device-tree-bindings/net/aquantia-phy.txt b/doc/device-tree-bindings/net/aquantia-phy.txt new file mode 100644 index 0000000000..89ce61e05b --- /dev/null +++ b/doc/device-tree-bindings/net/aquantia-phy.txt @@ -0,0 +1,25 @@ +PHY nodes for Aquantia devices. + +This text describes properties that are applicable to Aquantia PHY nodes in +addition to the bindings in phy.txt. + +Aquantia PHYs allow some flexibility in the way they are wired in a system, +they allow MDI pins to be reversed, LEDs linked up in different weays, have an +I2C slave interface that can be used for debug. Normally the configuration +corresponding to these is driven by the PHY firmware with the downside that +a custom firmware is needed for each integration of a PHY. +Several optional bindings are defined that allow these configuration points to +be driven by the PHY driver and reduce dependency on specific FW versions. + +Optional properties: +mdi-reversal: 0 or 1 indicating that reversal must be disabled/enabled. + Firmware default is used if the property is missing. +smb-addr: I2C/SMBus address to use, firmware default is used if the property + is missing. + +Example node: +phy@00 { + reg = <0x00>; + mdi-reversal = <1>; + smb-addr = <0x25>; +}; diff --git a/doc/device-tree-bindings/net/phy.txt b/doc/device-tree-bindings/net/phy.txt new file mode 100644 index 0000000000..6599c667b5 --- /dev/null +++ b/doc/device-tree-bindings/net/phy.txt @@ -0,0 +1,24 @@ +PHY nodes + +If the device tree is used to describe networking interfaces, U-Boot expects a +node for each PHY. Parent node for such a PHY node is expected to correspond to +a MDIO bus and the bus is used to access the PHY. + +Required properties: + + - reg : The ID number for the phy, usually a small integer + +Example: + +ethernet-phy@0 { + compatible = "ethernet-phy-id0141.0e90", "ethernet-phy-ieee802.3-c22"; + interrupt-parent = <&PIC>; + interrupts = <35 IRQ_TYPE_EDGE_RISING>; + reg = <0>; + + resets = <&rst 8>; + reset-names = "phy"; + reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; + reset-assert-us = <1000>; + reset-deassert-us = <2000>; +}; diff --git a/doc/device-tree-bindings/net/ti,dp83867.txt b/doc/device-tree-bindings/net/ti,dp83867.txt index 034146f5f8..268220964a 100644 --- a/doc/device-tree-bindings/net/ti,dp83867.txt +++ b/doc/device-tree-bindings/net/ti,dp83867.txt @@ -12,8 +12,10 @@ Required properties: compensate for the board being designed with the lanes swapped. - enet-phy-no-lane-swap - Indicates that PHY will disable swap of the TX/RX lanes. - - ti,clk-output-sel - Clock output select - see dt-bindings/net/ti-dp83867.h - for applicable values + - ti,clk-output-sel - Muxing option for CLK_OUT pin. See dt-bindings/net/ti-dp83867.h + for applicable values. The CLK_OUT pin can also + be disabled by this property. When omitted, the + PHY's default will be left as is. Default child nodes are standard Ethernet PHY device nodes as described in doc/devicetree/bindings/net/ethernet.txt diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c index 0ff56f7e88..5598bca21c 100644 --- a/drivers/dma/dma-uclass.c +++ b/drivers/dma/dma-uclass.c @@ -187,6 +187,18 @@ int dma_send(struct dma *dma, void *src, size_t len, void *metadata) return ops->send(dma, src, len, metadata); } + +int dma_get_cfg(struct dma *dma, u32 cfg_id, void **cfg_data) +{ + struct dma_ops *ops = dma_dev_ops(dma->dev); + + debug("%s(dma=%p)\n", __func__, dma); + + if (!ops->get_cfg) + return -ENOSYS; + + return ops->get_cfg(dma, cfg_id, cfg_data); +} #endif /* CONFIG_DMA_CHANNELS */ int dma_get_device(u32 transfer_type, struct udevice **devp) diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index 2e64d338ca..f7128610c5 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -104,6 +104,8 @@ struct udma_chan { struct udma_rchan *rchan; struct udma_rflow *rflow; + struct ti_udma_drv_chan_cfg_data cfg_data; + u32 bcnt; /* number of bytes completed since the start of the channel */ bool pkt_mode; /* TR or packet */ @@ -1407,6 +1409,11 @@ static int udma_request(struct dma *dma) uc->desc_rx_cur = 0; uc->num_rx_bufs = 0; + if (uc->dir == DMA_DEV_TO_MEM) { + uc->cfg_data.flow_id_base = uc->rflow->id; + uc->cfg_data.flow_id_cnt = 1; + } + return 0; } @@ -1689,6 +1696,26 @@ int udma_prepare_rcv_buf(struct dma *dma, void *dst, size_t size) return 0; } +static int udma_get_cfg(struct dma *dma, u32 id, void **data) +{ + struct udma_dev *ud = dev_get_priv(dma->dev); + struct udma_chan *uc; + + if (dma->id >= (ud->rchan_cnt + ud->tchan_cnt)) { + dev_err(dma->dev, "invalid dma ch_id %lu\n", dma->id); + return -EINVAL; + } + + switch (id) { + case TI_UDMA_CHAN_PRIV_INFO: + uc = &ud->channels[dma->id]; + *data = &uc->cfg_data; + return 0; + } + + return -EINVAL; +} + static const struct dma_ops udma_ops = { .transfer = udma_transfer, .of_xlate = udma_of_xlate, @@ -1699,10 +1726,12 @@ static const struct dma_ops udma_ops = { .send = udma_send, .receive = udma_receive, .prepare_rcv_buf = udma_prepare_rcv_buf, + .get_cfg = udma_get_cfg, }; static const struct udevice_id udma_ids[] = { { .compatible = "ti,k3-navss-udmap" }, + { .compatible = "ti,j721e-navss-mcu-udmap" }, { } }; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 4182897d89..142a2c6953 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -298,6 +298,8 @@ config MVPP2 bool "Marvell Armada 375/7K/8K network interface support" depends on ARMADA_375 || ARMADA_8K select PHYLIB + select MVMDIO + select DM_MDIO help This driver supports the network interface units in the Marvell ARMADA 375, 7K and 8K SoCs. diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c index 0ca7e838a8..02c1ee70d9 100644 --- a/drivers/net/fsl_enetc.c +++ b/drivers/net/fsl_enetc.c @@ -156,19 +156,14 @@ static void enetc_start_pcs(struct udevice *dev) priv->if_type = PHY_INTERFACE_MODE_NONE; - /* check internal mdio capability, not all ports need it */ + /* register internal MDIO for debug purposes */ if (enetc_read_port(priv, ENETC_PCAPR0) & ENETC_PCAPRO_MDIO) { - /* - * set up internal MDIO, this is part of ETH PCI function and is - * used to access serdes / internal SoC PHYs. - * We don't currently register it as a MDIO bus as it goes away - * when the interface is removed, so it can't practically be - * used in the console. - */ priv->imdio.read = enetc_mdio_read; priv->imdio.write = enetc_mdio_write; priv->imdio.priv = priv->port_regs + ENETC_PM_IMDIO_BASE; strncpy(priv->imdio.name, dev->name, MDIO_NAME_LEN); + if (!miiphy_get_dev_by_name(priv->imdio.name)) + mdio_register(&priv->imdio); } if (!ofnode_valid(dev->node)) { @@ -190,70 +185,30 @@ static void enetc_start_pcs(struct udevice *dev) case PHY_INTERFACE_MODE_SGMII_2500: enetc_init_sgmii(dev); break; - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_TXID: - enetc_init_rgmii(dev); - break; case PHY_INTERFACE_MODE_XGMII: + case PHY_INTERFACE_MODE_USXGMII: + case PHY_INTERFACE_MODE_XFI: enetc_init_sxgmii(dev); break; }; } /* Configure the actual/external ethernet PHY, if one is found */ -static void enetc_start_phy(struct udevice *dev) +static void enetc_config_phy(struct udevice *dev) { struct enetc_priv *priv = dev_get_priv(dev); - struct udevice *miidev; - struct phy_device *phy; - u32 phandle, phy_id; - ofnode phy_node; int supported; - if (!ofnode_valid(dev->node)) { - enetc_dbg(dev, "no enetc ofnode found, skipping PHY set-up\n"); - return; - } + priv->phy = dm_eth_phy_connect(dev); - if (ofnode_read_u32(dev->node, "phy-handle", &phandle)) { - enetc_dbg(dev, "phy-handle not found, skipping PHY set-up\n"); + if (!priv->phy) return; - } - phy_node = ofnode_get_by_phandle(phandle); - if (!ofnode_valid(phy_node)) { - enetc_dbg(dev, "invalid phy node, skipping PHY set-up\n"); - return; - } - enetc_dbg(dev, "phy node: %s\n", ofnode_get_name(phy_node)); - - if (ofnode_read_u32(phy_node, "reg", &phy_id)) { - enetc_dbg(dev, - "missing reg in PHY node, skipping PHY set-up\n"); - return; - } + supported = PHY_GBIT_FEATURES | SUPPORTED_2500baseX_Full; + priv->phy->supported &= supported; + priv->phy->advertising &= supported; - if (uclass_get_device_by_ofnode(UCLASS_MDIO, - ofnode_get_parent(phy_node), - &miidev)) { - enetc_dbg(dev, "can't find MDIO bus for node %s\n", - ofnode_get_name(ofnode_get_parent(phy_node))); - return; - } - - phy = dm_mdio_phy_connect(miidev, phy_id, dev, priv->if_type); - if (!phy) { - enetc_dbg(dev, "dm_mdio_phy_connect returned null\n"); - return; - } - - supported = GENMASK(6, 0); /* speeds up to 1G & AN */ - phy->advertising = phy->supported & supported; - phy->node = phy_node; - phy_config(phy); - phy_startup(phy); + phy_config(priv->phy); } /* @@ -292,6 +247,9 @@ static int enetc_probe(struct udevice *dev) dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY); + enetc_start_pcs(dev); + enetc_config_phy(dev); + return 0; } @@ -467,8 +425,14 @@ static int enetc_start(struct udevice *dev) enetc_setup_tx_bdr(dev); enetc_setup_rx_bdr(dev); - enetc_start_pcs(dev); - enetc_start_phy(dev); + if (priv->if_type == PHY_INTERFACE_MODE_RGMII || + priv->if_type == PHY_INTERFACE_MODE_RGMII_ID || + priv->if_type == PHY_INTERFACE_MODE_RGMII_RXID || + priv->if_type == PHY_INTERFACE_MODE_RGMII_TXID) + enetc_init_rgmii(dev); + + if (priv->phy) + phy_startup(priv->phy); return 0; } @@ -482,6 +446,10 @@ static void enetc_stop(struct udevice *dev) { /* FLR is sufficient to quiesce the device */ dm_pci_flr(dev); + /* leave the BARs accessible after we stop, this is needed to use + * internal MDIO in command line. + */ + dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY); } /* diff --git a/drivers/net/fsl_enetc.h b/drivers/net/fsl_enetc.h index 0bb4cdff47..9a36cdad80 100644 --- a/drivers/net/fsl_enetc.h +++ b/drivers/net/fsl_enetc.h @@ -154,6 +154,7 @@ struct enetc_priv { int if_type; struct mii_dev imdio; + struct phy_device *phy; }; /* register accessors */ diff --git a/drivers/net/fsl_enetc_mdio.c b/drivers/net/fsl_enetc_mdio.c index b4463a58a5..47257a6cf6 100644 --- a/drivers/net/fsl_enetc_mdio.c +++ b/drivers/net/fsl_enetc_mdio.c @@ -17,8 +17,13 @@ static void enetc_mdio_wait_bsy(struct enetc_mdio_priv *priv) { - while (enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_BSY) + int to = 10000; + + while ((enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_BSY) && + --to) cpu_relax(); + if (!to) + printf("T"); } int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr, int devad, diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c index b6b8a93bb5..ebb74339b2 100644 --- a/drivers/net/ftgmac100.c +++ b/drivers/net/ftgmac100.c @@ -72,8 +72,8 @@ enum ftgmac100_model { struct ftgmac100_data { struct ftgmac100 *iobase; - struct ftgmac100_txdes txdes[PKTBUFSTX]; - struct ftgmac100_rxdes rxdes[PKTBUFSRX]; + struct ftgmac100_txdes txdes[PKTBUFSTX] __aligned(ARCH_DMA_MINALIGN); + struct ftgmac100_rxdes rxdes[PKTBUFSRX] __aligned(ARCH_DMA_MINALIGN); int tx_index; int rx_index; @@ -310,7 +310,7 @@ static int ftgmac100_start(struct udevice *dev) } priv->txdes[PKTBUFSTX - 1].txdes0 = priv->txdes0_edotr_mask; - start = (ulong)&priv->txdes[0]; + start = ((ulong)&priv->txdes[0]) & ~(ARCH_DMA_MINALIGN - 1); end = start + roundup(sizeof(priv->txdes), ARCH_DMA_MINALIGN); flush_dcache_range(start, end); @@ -320,7 +320,7 @@ static int ftgmac100_start(struct udevice *dev) } priv->rxdes[PKTBUFSRX - 1].rxdes0 = priv->rxdes0_edorr_mask; - start = (ulong)&priv->rxdes[0]; + start = ((ulong)&priv->rxdes[0]) & ~(ARCH_DMA_MINALIGN - 1); end = start + roundup(sizeof(priv->rxdes), ARCH_DMA_MINALIGN); flush_dcache_range(start, end); @@ -370,7 +370,7 @@ static int ftgmac100_free_pkt(struct udevice *dev, uchar *packet, int length) { struct ftgmac100_data *priv = dev_get_priv(dev); struct ftgmac100_rxdes *curr_des = &priv->rxdes[priv->rx_index]; - ulong des_start = (ulong)curr_des; + ulong des_start = ((ulong)curr_des) & ~(ARCH_DMA_MINALIGN - 1); ulong des_end = des_start + roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN); @@ -392,7 +392,7 @@ static int ftgmac100_recv(struct udevice *dev, int flags, uchar **packetp) struct ftgmac100_data *priv = dev_get_priv(dev); struct ftgmac100_rxdes *curr_des = &priv->rxdes[priv->rx_index]; unsigned short rxlen; - ulong des_start = (ulong)curr_des; + ulong des_start = ((ulong)curr_des) & ~(ARCH_DMA_MINALIGN - 1); ulong des_end = des_start + roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN); ulong data_start = curr_des->rxdes3; @@ -427,7 +427,7 @@ static int ftgmac100_recv(struct udevice *dev, int flags, uchar **packetp) static u32 ftgmac100_read_txdesc(const void *desc) { const struct ftgmac100_txdes *txdes = desc; - ulong des_start = (ulong)txdes; + ulong des_start = ((ulong)txdes) & ~(ARCH_DMA_MINALIGN - 1); ulong des_end = des_start + roundup(sizeof(*txdes), ARCH_DMA_MINALIGN); invalidate_dcache_range(des_start, des_end); @@ -445,7 +445,7 @@ static int ftgmac100_send(struct udevice *dev, void *packet, int length) struct ftgmac100_data *priv = dev_get_priv(dev); struct ftgmac100 *ftgmac100 = priv->iobase; struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index]; - ulong des_start = (ulong)curr_des; + ulong des_start = ((ulong)curr_des) & ~(ARCH_DMA_MINALIGN - 1); ulong des_end = des_start + roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN); ulong data_start; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index f809f3eb07..8359425378 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -165,7 +165,8 @@ static int gem_is_gigabit_capable(struct macb_device *macb) return macb_is_gem(macb) && !cpu_is_sama5d2() && !cpu_is_sama5d4(); } -static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value) +static void macb_mdio_write(struct macb_device *macb, u8 phy_adr, u8 reg, + u16 value) { unsigned long netctl; unsigned long netstat; @@ -177,7 +178,7 @@ static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value) frame = (MACB_BF(SOF, 1) | MACB_BF(RW, 1) - | MACB_BF(PHYA, macb->phy_addr) + | MACB_BF(PHYA, phy_adr) | MACB_BF(REGA, reg) | MACB_BF(CODE, 2) | MACB_BF(DATA, value)); @@ -192,7 +193,7 @@ static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value) macb_writel(macb, NCR, netctl); } -static u16 macb_mdio_read(struct macb_device *macb, u8 reg) +static u16 macb_mdio_read(struct macb_device *macb, u8 phy_adr, u8 reg) { unsigned long netctl; unsigned long netstat; @@ -204,7 +205,7 @@ static u16 macb_mdio_read(struct macb_device *macb, u8 reg) frame = (MACB_BF(SOF, 1) | MACB_BF(RW, 2) - | MACB_BF(PHYA, macb->phy_addr) + | MACB_BF(PHYA, phy_adr) | MACB_BF(REGA, reg) | MACB_BF(CODE, 2)); macb_writel(macb, MAN, frame); @@ -240,11 +241,8 @@ int macb_miiphy_read(struct mii_dev *bus, int phy_adr, int devad, int reg) struct macb_device *macb = to_macb(dev); #endif - if (macb->phy_addr != phy_adr) - return -1; - arch_get_mdio_control(bus->name); - value = macb_mdio_read(macb, reg); + value = macb_mdio_read(macb, phy_adr, reg); return value; } @@ -260,11 +258,8 @@ int macb_miiphy_write(struct mii_dev *bus, int phy_adr, int devad, int reg, struct macb_device *macb = to_macb(dev); #endif - if (macb->phy_addr != phy_adr) - return -1; - arch_get_mdio_control(bus->name); - macb_mdio_write(macb, reg, value); + macb_mdio_write(macb, phy_adr, reg, value); return 0; } @@ -451,13 +446,13 @@ static void macb_phy_reset(struct macb_device *macb, const char *name) u16 status, adv; adv = ADVERTISE_CSMA | ADVERTISE_ALL; - macb_mdio_write(macb, MII_ADVERTISE, adv); + macb_mdio_write(macb, macb->phy_addr, MII_ADVERTISE, adv); printf("%s: Starting autonegotiation...\n", name); - macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE + macb_mdio_write(macb, macb->phy_addr, MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART)); for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { - status = macb_mdio_read(macb, MII_BMSR); + status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR); if (status & BMSR_ANEGCOMPLETE) break; udelay(100); @@ -478,7 +473,7 @@ static int macb_phy_find(struct macb_device *macb, const char *name) /* Search for PHY... */ for (i = 0; i < 32; i++) { macb->phy_addr = i; - phy_id = macb_mdio_read(macb, MII_PHYSID1); + phy_id = macb_mdio_read(macb, macb->phy_addr, MII_PHYSID1); if (phy_id != 0xffff) { printf("%s: PHY present at %d\n", name, i); return 0; @@ -596,7 +591,7 @@ static int macb_phy_init(struct macb_device *macb, const char *name) return ret; /* Check if the PHY is up to snuff... */ - phy_id = macb_mdio_read(macb, MII_PHYSID1); + phy_id = macb_mdio_read(macb, macb->phy_addr, MII_PHYSID1); if (phy_id == 0xffff) { printf("%s: No PHY present\n", name); return -ENODEV; @@ -619,13 +614,13 @@ static int macb_phy_init(struct macb_device *macb, const char *name) phy_config(macb->phydev); #endif - status = macb_mdio_read(macb, MII_BMSR); + status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR); if (!(status & BMSR_LSTATUS)) { /* Try to re-negotiate if we don't have link already. */ macb_phy_reset(macb, name); for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { - status = macb_mdio_read(macb, MII_BMSR); + status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR); if (status & BMSR_LSTATUS) { /* * Delay a bit after the link is established, @@ -646,7 +641,7 @@ static int macb_phy_init(struct macb_device *macb, const char *name) /* First check for GMAC and that it is GiB capable */ if (gem_is_gigabit_capable(macb)) { - lpa = macb_mdio_read(macb, MII_STAT1000); + lpa = macb_mdio_read(macb, macb->phy_addr, MII_STAT1000); if (lpa & (LPA_1000FULL | LPA_1000HALF | LPA_1000XFULL | LPA_1000XHALF)) { @@ -680,8 +675,8 @@ static int macb_phy_init(struct macb_device *macb, const char *name) } /* fall back for EMAC checking */ - adv = macb_mdio_read(macb, MII_ADVERTISE); - lpa = macb_mdio_read(macb, MII_LPA); + adv = macb_mdio_read(macb, macb->phy_addr, MII_ADVERTISE); + lpa = macb_mdio_read(macb, macb->phy_addr, MII_LPA); media = mii_nway_result(lpa & adv); speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? 1 : 0); diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c index 8148c03d22..c5d1f9cf9f 100644 --- a/drivers/net/mvpp2.c +++ b/drivers/net/mvpp2.c @@ -33,6 +33,7 @@ #include <linux/mbus.h> #include <asm-generic/gpio.h> #include <fdt_support.h> +#include <linux/mdio.h> DECLARE_GLOBAL_DATA_PTR; @@ -63,8 +64,6 @@ do { \ #define MTU 1500 #define RX_BUFFER_SIZE (ALIGN(MTU + WRAP, ARCH_DMA_MINALIGN)) -#define MVPP2_SMI_TIMEOUT 10000 - /* RX Fifo Registers */ #define MVPP2_RX_DATA_FIFO_SIZE_REG(port) (0x00 + 4 * (port)) #define MVPP2_RX_ATTR_FIFO_SIZE_REG(port) (0x20 + 4 * (port)) @@ -491,23 +490,8 @@ do { \ #define MVPP2_QUEUE_NEXT_DESC(q, index) \ (((index) < (q)->last_desc) ? ((index) + 1) : 0) -/* SMI: 0xc0054 -> offset 0x54 to lms_base */ -#define MVPP21_SMI 0x0054 /* PP2.2: SMI: 0x12a200 -> offset 0x1200 to iface_base */ #define MVPP22_SMI 0x1200 -#define MVPP2_PHY_REG_MASK 0x1f -/* SMI register fields */ -#define MVPP2_SMI_DATA_OFFS 0 /* Data */ -#define MVPP2_SMI_DATA_MASK (0xffff << MVPP2_SMI_DATA_OFFS) -#define MVPP2_SMI_DEV_ADDR_OFFS 16 /* PHY device address */ -#define MVPP2_SMI_REG_ADDR_OFFS 21 /* PHY device reg addr*/ -#define MVPP2_SMI_OPCODE_OFFS 26 /* Write/Read opcode */ -#define MVPP2_SMI_OPCODE_READ (1 << MVPP2_SMI_OPCODE_OFFS) -#define MVPP2_SMI_READ_VALID (1 << 27) /* Read Valid */ -#define MVPP2_SMI_BUSY (1 << 28) /* Busy */ - -#define MVPP2_PHY_ADDR_MASK 0x1f -#define MVPP2_PHY_REG_MASK 0x1f /* Additional PPv2.2 offsets */ #define MVPP22_MPCS 0x007000 @@ -953,7 +937,6 @@ struct mvpp2_port { /* Per-port registers' base address */ void __iomem *base; - void __iomem *mdio_base; struct mvpp2_rx_queue **rxqs; struct mvpp2_tx_queue **txqs; @@ -974,9 +957,8 @@ struct mvpp2_port { struct phy_device *phy_dev; phy_interface_t phy_interface; - int phy_node; int phyaddr; - struct mii_dev *bus; + struct udevice *mdio_dev; #ifdef CONFIG_DM_GPIO struct gpio_desc phy_reset_gpio; struct gpio_desc phy_tx_disable_gpio; @@ -4495,17 +4477,40 @@ static void mvpp2_stop_dev(struct mvpp2_port *port) gop_port_enable(port, 0); } -static int mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) +static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) { struct phy_device *phy_dev; if (!port->init || port->link == 0) { - phy_dev = phy_connect(port->bus, port->phyaddr, dev, - port->phy_interface); + phy_dev = dm_mdio_phy_connect(port->mdio_dev, port->phyaddr, + dev, port->phy_interface); + + /* + * If the phy doesn't match with any existing u-boot drivers the + * phy framework will connect it to generic one which + * uid == 0xffffffff. In this case act as if the phy wouldn't be + * declared in dts. Otherwise in case of 3310 (for which the + * driver doesn't exist) the link will not be correctly + * detected. Removing phy entry from dts in case of 3310 is not + * an option because it is required for the phy_fw_down + * procedure. + */ + if (phy_dev && + phy_dev->drv->uid == 0xffffffff) {/* Generic phy */ + netdev_warn(port->dev, + "Marking phy as invalid, link will not be checked\n"); + /* set phy_addr to invalid value */ + port->phyaddr = PHY_MAX_ADDR; + mvpp2_egress_enable(port); + mvpp2_ingress_enable(port); + + return; + } + port->phy_dev = phy_dev; if (!phy_dev) { netdev_err(port->dev, "cannot connect to phy\n"); - return -ENODEV; + return; } phy_dev->supported &= PHY_GBIT_FEATURES; phy_dev->advertising = phy_dev->supported; @@ -4517,18 +4522,14 @@ static int mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) phy_config(phy_dev); phy_startup(phy_dev); - if (!phy_dev->link) { + if (!phy_dev->link) printf("%s: No link\n", phy_dev->dev->name); - return -1; - } - - port->init = 1; + else + port->init = 1; } else { mvpp2_egress_enable(port); mvpp2_ingress_enable(port); } - - return 0; } static int mvpp2_open(struct udevice *dev, struct mvpp2_port *port) @@ -4567,11 +4568,8 @@ static int mvpp2_open(struct udevice *dev, struct mvpp2_port *port) return err; } - if (port->phy_node) { - err = mvpp2_phy_connect(dev, port); - if (err < 0) - return err; - + if (port->phyaddr < PHY_MAX_ADDR) { + mvpp2_phy_connect(dev, port); mvpp2_link_event(port); } else { mvpp2_egress_enable(port); @@ -4709,35 +4707,25 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port) u32 id; u32 phyaddr = 0; int phy_mode = -1; - - /* Default mdio_base from the same eth base */ - if (port->priv->hw_version == MVPP21) - port->mdio_base = port->priv->lms_base + MVPP21_SMI; - else - port->mdio_base = port->priv->iface_base + MVPP22_SMI; + int ret; phy_node = fdtdec_lookup_phandle(gd->fdt_blob, port_node, "phy"); if (phy_node > 0) { - ofnode phy_ofnode; - fdt_addr_t phy_base; - + int parent; phyaddr = fdtdec_get_int(gd->fdt_blob, phy_node, "reg", 0); if (phyaddr < 0) { dev_err(&pdev->dev, "could not find phy address\n"); return -1; } - - phy_ofnode = ofnode_get_parent(offset_to_ofnode(phy_node)); - phy_base = ofnode_get_addr(phy_ofnode); - port->mdio_base = (void *)phy_base; - - if (port->mdio_base < 0) { - dev_err(&pdev->dev, "could not find mdio base address\n"); - return -1; - } + parent = fdt_parent_offset(gd->fdt_blob, phy_node); + ret = uclass_get_device_by_of_offset(UCLASS_MDIO, parent, + &port->mdio_dev); + if (ret) + return ret; } else { - phy_node = 0; + /* phy_addr is set to invalid value */ + phyaddr = PHY_MAX_ADDR; } phy_mode_str = fdt_getprop(gd->fdt_blob, port_node, "phy-mode", NULL); @@ -4775,7 +4763,6 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port) port->first_rxq = port->id * rxq_number; else port->first_rxq = port->id * port->priv->max_port_rxqs; - port->phy_node = phy_node; port->phy_interface = phy_mode; port->phyaddr = phyaddr; @@ -5052,118 +5039,6 @@ static int mvpp2_init(struct udevice *dev, struct mvpp2 *priv) return 0; } -/* SMI / MDIO functions */ - -static int smi_wait_ready(struct mvpp2_port *priv) -{ - u32 timeout = MVPP2_SMI_TIMEOUT; - u32 smi_reg; - - /* wait till the SMI is not busy */ - do { - /* read smi register */ - smi_reg = readl(priv->mdio_base); - if (timeout-- == 0) { - printf("Error: SMI busy timeout\n"); - return -EFAULT; - } - } while (smi_reg & MVPP2_SMI_BUSY); - - return 0; -} - -/* - * mpp2_mdio_read - miiphy_read callback function. - * - * Returns 16bit phy register value, or 0xffff on error - */ -static int mpp2_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) -{ - struct mvpp2_port *priv = bus->priv; - u32 smi_reg; - u32 timeout; - - /* check parameters */ - if (addr > MVPP2_PHY_ADDR_MASK) { - printf("Error: Invalid PHY address %d\n", addr); - return -EFAULT; - } - - if (reg > MVPP2_PHY_REG_MASK) { - printf("Err: Invalid register offset %d\n", reg); - return -EFAULT; - } - - /* wait till the SMI is not busy */ - if (smi_wait_ready(priv) < 0) - return -EFAULT; - - /* fill the phy address and regiser offset and read opcode */ - smi_reg = (addr << MVPP2_SMI_DEV_ADDR_OFFS) - | (reg << MVPP2_SMI_REG_ADDR_OFFS) - | MVPP2_SMI_OPCODE_READ; - - /* write the smi register */ - writel(smi_reg, priv->mdio_base); - - /* wait till read value is ready */ - timeout = MVPP2_SMI_TIMEOUT; - - do { - /* read smi register */ - smi_reg = readl(priv->mdio_base); - if (timeout-- == 0) { - printf("Err: SMI read ready timeout\n"); - return -EFAULT; - } - } while (!(smi_reg & MVPP2_SMI_READ_VALID)); - - /* Wait for the data to update in the SMI register */ - for (timeout = 0; timeout < MVPP2_SMI_TIMEOUT; timeout++) - ; - - return readl(priv->mdio_base) & MVPP2_SMI_DATA_MASK; -} - -/* - * mpp2_mdio_write - miiphy_write callback function. - * - * Returns 0 if write succeed, -EINVAL on bad parameters - * -ETIME on timeout - */ -static int mpp2_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, - u16 value) -{ - struct mvpp2_port *priv = bus->priv; - u32 smi_reg; - - /* check parameters */ - if (addr > MVPP2_PHY_ADDR_MASK) { - printf("Error: Invalid PHY address %d\n", addr); - return -EFAULT; - } - - if (reg > MVPP2_PHY_REG_MASK) { - printf("Err: Invalid register offset %d\n", reg); - return -EFAULT; - } - - /* wait till the SMI is not busy */ - if (smi_wait_ready(priv) < 0) - return -EFAULT; - - /* fill the phy addr and reg offset and write opcode and data */ - smi_reg = value << MVPP2_SMI_DATA_OFFS; - smi_reg |= (addr << MVPP2_SMI_DEV_ADDR_OFFS) - | (reg << MVPP2_SMI_REG_ADDR_OFFS); - smi_reg &= ~MVPP2_SMI_OPCODE_READ; - - /* write the smi register */ - writel(smi_reg, priv->mdio_base); - - return 0; -} - static int mvpp2_recv(struct udevice *dev, int flags, uchar **packetp) { struct mvpp2_port *port = dev_get_priv(dev); @@ -5176,6 +5051,10 @@ static int mvpp2_recv(struct udevice *dev, int flags, uchar **packetp) struct mvpp2_rx_queue *rxq; u8 *data; + if (port->phyaddr < PHY_MAX_ADDR) + if (!port->phy_dev->link) + return 0; + /* Process RX packets */ rxq = port->rxqs[0]; @@ -5241,6 +5120,10 @@ static int mvpp2_send(struct udevice *dev, void *packet, int length) int tx_done; int timeout; + if (port->phyaddr < PHY_MAX_ADDR) + if (!port->phy_dev->link) + return 0; + txq = port->txqs[0]; aggr_txq = &port->priv->aggr_txqs[smp_processor_id()]; @@ -5421,31 +5304,13 @@ static int mvpp2_probe(struct udevice *dev) { struct mvpp2_port *port = dev_get_priv(dev); struct mvpp2 *priv = dev_get_priv(dev->parent); - struct mii_dev *bus; int err; /* Only call the probe function for the parent once */ if (!priv->probe_done) err = mvpp2_base_probe(dev->parent); - port->priv = dev_get_priv(dev->parent); - - /* Create and register the MDIO bus driver */ - bus = mdio_alloc(); - if (!bus) { - printf("Failed to allocate MDIO bus\n"); - return -ENOMEM; - } - - bus->read = mpp2_mdio_read; - bus->write = mpp2_mdio_write; - snprintf(bus->name, sizeof(bus->name), dev->name); - bus->priv = (void *)port; - port->bus = bus; - - err = mdio_register(bus); - if (err) - return err; + port->priv = priv; err = phy_info_parse(dev, port); if (err) @@ -5474,7 +5339,7 @@ static int mvpp2_probe(struct udevice *dev) port->gop_id * MVPP22_PORT_OFFSET; /* Set phy address of the port */ - if(port->phy_node) + if (port->phyaddr < PHY_MAX_ADDR) mvpp22_smi_phy_addr_cfg(port); /* GoP Init */ diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index bcea8a0c3e..dceea1516f 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -46,7 +46,7 @@ config B53_PHY_PORTS endif # B53_SWITCH config MV88E61XX_SWITCH - bool "Marvel MV88E61xx Ethernet switch PHY support." + bool "Marvell MV88E61xx Ethernet switch PHY support." if MV88E61XX_SWITCH diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 76b6197009..78955c57a8 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -25,7 +25,7 @@ obj-$(CONFIG_PHY_NATSEMI) += natsemi.o obj-$(CONFIG_PHY_REALTEK) += realtek.o obj-$(CONFIG_PHY_SMSC) += smsc.o obj-$(CONFIG_PHY_TERANETICS) += teranetics.o -obj-$(CONFIG_PHY_TI) += ti.o +obj-$(CONFIG_PHY_TI) += dp83867.o obj-$(CONFIG_PHY_XILINX) += xilinx_phy.o obj-$(CONFIG_PHY_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o obj-$(CONFIG_PHY_VITESSE) += vitesse.o diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 465ec2d342..c4bd443001 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -21,6 +21,7 @@ #define AQUNTIA_SPEED_MSB_MASK 0x40 #define AQUANTIA_SYSTEM_INTERFACE_SR 0xe812 +#define AQUANTIA_SYSTEM_INTERFACE_SR_READY BIT(0) #define AQUANTIA_VENDOR_PROVISIONING_REG 0xC441 #define AQUANTIA_FIRMWARE_ID 0x20 #define AQUANTIA_RESERVED_STATUS 0xc885 @@ -33,10 +34,16 @@ #define AQUANTIA_SI_USXGMII 0x0018 /* registers in MDIO_MMD_VEND1 region */ +#define AQUANTIA_VND1_GLOBAL_SC 0x000 +#define AQUANTIA_VND1_GLOBAL_SC_LP BIT(0xb) + #define GLOBAL_FIRMWARE_ID 0x20 #define GLOBAL_FAULT 0xc850 #define GLOBAL_RSTATUS_1 0xc885 +#define GLOBAL_ALARM_1 0xcc00 +#define SYSTEM_READY_BIT 0x40 + #define GLOBAL_STANDARD_CONTROL 0x0 #define SOFT_RESET BIT(15) #define LOW_POWER BIT(11) @@ -60,6 +67,36 @@ #define UP_RUN_STALL_OVERRIDE BIT(6) #define UP_RUN_STALL BIT(0) +#define AQUANTIA_PMA_RX_VENDOR_P1 0xe400 +#define AQUANTIA_PMA_RX_VENDOR_P1_MDI_MSK GENMASK(1, 0) +/* MDI reversal configured through registers */ +#define AQUANTIA_PMA_RX_VENDOR_P1_MDI_CFG BIT(1) +/* MDI reversal enabled */ +#define AQUANTIA_PMA_RX_VENDOR_P1_MDI_REV BIT(0) + +/* + * global start rate, the protocol associated with this speed is used by default + * on SI. + */ +#define AQUANTIA_VND1_GSTART_RATE 0x31a +#define AQUANTIA_VND1_GSTART_RATE_OFF 0 +#define AQUANTIA_VND1_GSTART_RATE_100M 1 +#define AQUANTIA_VND1_GSTART_RATE_1G 2 +#define AQUANTIA_VND1_GSTART_RATE_10G 3 +#define AQUANTIA_VND1_GSTART_RATE_2_5G 4 +#define AQUANTIA_VND1_GSTART_RATE_5G 5 + +/* SYSCFG registers for 100M, 1G, 2.5G, 5G, 10G */ +#define AQUANTIA_VND1_GSYSCFG_BASE 0x31b +#define AQUANTIA_VND1_GSYSCFG_100M 0 +#define AQUANTIA_VND1_GSYSCFG_1G 1 +#define AQUANTIA_VND1_GSYSCFG_2_5G 2 +#define AQUANTIA_VND1_GSYSCFG_5G 3 +#define AQUANTIA_VND1_GSYSCFG_10G 4 + +#define AQUANTIA_VND1_SMBUS0 0xc485 +#define AQUANTIA_VND1_SMBUS1 0xc495 + /* addresses of memory segments in the phy */ #define DRAM_BASE_ADDR 0x3FFE0000 #define IRAM_BASE_ADDR 0x40000000 @@ -69,6 +106,12 @@ #define VERSION_STRING_OFFSET 0x0200 #define HEADER_OFFSET 0x300 +/* driver private data */ +#define AQUANTIA_NA 0 +#define AQUANTIA_GEN1 1 +#define AQUANTIA_GEN2 2 +#define AQUANTIA_GEN3 3 + #pragma pack(1) struct fw_header { u8 padding[4]; @@ -254,10 +297,128 @@ static int aquantia_upload_firmware(struct phy_device *phydev) } #endif +struct { + u16 syscfg; + int cnt; + u16 start_rate; +} aquantia_syscfg[PHY_INTERFACE_MODE_COUNT] = { + [PHY_INTERFACE_MODE_SGMII] = {0x04b, AQUANTIA_VND1_GSYSCFG_1G, + AQUANTIA_VND1_GSTART_RATE_1G}, + [PHY_INTERFACE_MODE_SGMII_2500] = {0x144, AQUANTIA_VND1_GSYSCFG_2_5G, + AQUANTIA_VND1_GSTART_RATE_2_5G}, + [PHY_INTERFACE_MODE_XGMII] = {0x100, AQUANTIA_VND1_GSYSCFG_10G, + AQUANTIA_VND1_GSTART_RATE_10G}, + [PHY_INTERFACE_MODE_XFI] = {0x100, AQUANTIA_VND1_GSYSCFG_10G, + AQUANTIA_VND1_GSTART_RATE_10G}, + [PHY_INTERFACE_MODE_USXGMII] = {0x080, AQUANTIA_VND1_GSYSCFG_10G, + AQUANTIA_VND1_GSTART_RATE_10G}, +}; + +static int aquantia_set_proto(struct phy_device *phydev) +{ + int i; + + if (!aquantia_syscfg[phydev->interface].cnt) + return 0; + + /* set the default rate to enable the SI link */ + phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE, + aquantia_syscfg[phydev->interface].start_rate); + + /* set selected protocol for all relevant line side link speeds */ + for (i = 0; i <= aquantia_syscfg[phydev->interface].cnt; i++) + phy_write(phydev, MDIO_MMD_VEND1, + AQUANTIA_VND1_GSYSCFG_BASE + i, + aquantia_syscfg[phydev->interface].syscfg); + return 0; +} + +static int aquantia_dts_config(struct phy_device *phydev) +{ +#ifdef CONFIG_DM_ETH + ofnode node = phydev->node; + u32 prop; + u16 reg; + + /* this code only works on gen2 and gen3 PHYs */ + if (phydev->drv->data != AQUANTIA_GEN2 && + phydev->drv->data != AQUANTIA_GEN3) + return -ENOTSUPP; + + if (!ofnode_valid(node)) + return 0; + + if (!ofnode_read_u32(node, "mdi-reversal", &prop)) { + debug("mdi-reversal = %d\n", (int)prop); + reg = phy_read(phydev, MDIO_MMD_PMAPMD, + AQUANTIA_PMA_RX_VENDOR_P1); + reg &= ~AQUANTIA_PMA_RX_VENDOR_P1_MDI_MSK; + reg |= AQUANTIA_PMA_RX_VENDOR_P1_MDI_CFG; + reg |= prop ? AQUANTIA_PMA_RX_VENDOR_P1_MDI_REV : 0; + phy_write(phydev, MDIO_MMD_PMAPMD, AQUANTIA_PMA_RX_VENDOR_P1, + reg); + } + if (!ofnode_read_u32(node, "smb-addr", &prop)) { + debug("smb-addr = %x\n", (int)prop); + /* + * there are two addresses here, normally just one bus would + * be in use so we're setting both regs using the same DT + * property. + */ + phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_SMBUS0, + (u16)(prop << 1)); + phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_SMBUS1, + (u16)(prop << 1)); + } + +#endif + return 0; +} + +static bool aquantia_link_is_up(struct phy_device *phydev) +{ + u16 reg, regmask; + int devad, regnum; + + /* + * On Gen 2 and 3 we have a bit that indicates that both system and + * line side are ready for data, use that if possible. + */ + if (phydev->drv->data == AQUANTIA_GEN2 || + phydev->drv->data == AQUANTIA_GEN3) { + devad = MDIO_MMD_PHYXS; + regnum = AQUANTIA_SYSTEM_INTERFACE_SR; + regmask = AQUANTIA_SYSTEM_INTERFACE_SR_READY; + } else { + devad = MDIO_MMD_AN; + regnum = MDIO_STAT1; + regmask = MDIO_AN_STAT1_COMPLETE; + } + /* the register should be latched, do a double read */ + phy_read(phydev, devad, regnum); + reg = phy_read(phydev, devad, regnum); + + return !!(reg & regmask); +} + int aquantia_config(struct phy_device *phydev) { + int interface = phydev->interface; u32 val, id, rstatus, fault; u32 reg_val1 = 0; + int num_retries = 5; + int usx_an = 0; + + /* + * check if the system is out of reset and init sequence completed. + * chip-wide reset for gen1 quad phys takes longer + */ + while (--num_retries) { + rstatus = phy_read(phydev, MDIO_MMD_VEND1, GLOBAL_ALARM_1); + if (rstatus & SYSTEM_READY_BIT) + break; + mdelay(10); + } id = phy_read(phydev, MDIO_MMD_VEND1, GLOBAL_FIRMWARE_ID); rstatus = phy_read(phydev, MDIO_MMD_VEND1, GLOBAL_RSTATUS_1); @@ -278,17 +439,57 @@ int aquantia_config(struct phy_device *phydev) if (ret != 0) return ret; } + /* + * for backward compatibility convert XGMII into either XFI or USX based + * on FW config + */ + if (interface == PHY_INTERFACE_MODE_XGMII) { + reg_val1 = phy_read(phydev, MDIO_MMD_PHYXS, + AQUANTIA_SYSTEM_INTERFACE_SR); + if ((reg_val1 & AQUANTIA_SI_IN_USE_MASK) == AQUANTIA_SI_USXGMII) + interface = PHY_INTERFACE_MODE_USXGMII; + else + interface = PHY_INTERFACE_MODE_XFI; + } + + /* + * if link is up already we can just use it, otherwise configure + * the protocols in the PHY. If link is down set the system + * interface protocol to use based on phydev->interface + */ + if (!aquantia_link_is_up(phydev) && + (phydev->drv->data == AQUANTIA_GEN2 || + phydev->drv->data == AQUANTIA_GEN3)) { + /* set PHY in low power mode so we can configure protocols */ + phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, + AQUANTIA_VND1_GLOBAL_SC_LP); + mdelay(10); + + /* configure protocol based on phydev->interface */ + aquantia_set_proto(phydev); + /* apply custom configuration based on DT */ + aquantia_dts_config(phydev); + + /* wake PHY back up */ + phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0); + mdelay(10); + } val = phy_read(phydev, MDIO_MMD_PMAPMD, MII_BMCR); - if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { + switch (interface) { + case PHY_INTERFACE_MODE_SGMII: /* 1000BASE-T mode */ phydev->advertising = SUPPORTED_1000baseT_Full; phydev->supported = phydev->advertising; val = (val & ~AQUNTIA_SPEED_LSB_MASK) | AQUNTIA_SPEED_MSB_MASK; phy_write(phydev, MDIO_MMD_PMAPMD, MII_BMCR, val); - } else if (phydev->interface == PHY_INTERFACE_MODE_XGMII) { + break; + case PHY_INTERFACE_MODE_USXGMII: + usx_an = 1; + /* FALLTHROUGH */ + case PHY_INTERFACE_MODE_XFI: /* 10GBASE-T mode */ phydev->advertising = SUPPORTED_10000baseT_Full; phydev->supported = phydev->advertising; @@ -299,40 +500,40 @@ int aquantia_config(struct phy_device *phydev) AQUNTIA_SPEED_LSB_MASK | AQUNTIA_SPEED_MSB_MASK); - val = phy_read(phydev, MDIO_MMD_PHYXS, - AQUANTIA_SYSTEM_INTERFACE_SR); /* If SI is USXGMII then start USXGMII autoneg */ - if ((val & AQUANTIA_SI_IN_USE_MASK) == AQUANTIA_SI_USXGMII) { - reg_val1 = phy_read(phydev, MDIO_MMD_PHYXS, - AQUANTIA_VENDOR_PROVISIONING_REG); + reg_val1 = phy_read(phydev, MDIO_MMD_PHYXS, + AQUANTIA_VENDOR_PROVISIONING_REG); + if (usx_an) { reg_val1 |= AQUANTIA_USX_AUTONEG_CONTROL_ENA; - - phy_write(phydev, MDIO_MMD_PHYXS, - AQUANTIA_VENDOR_PROVISIONING_REG, - reg_val1); printf("%s: system interface USXGMII\n", phydev->dev->name); } else { + reg_val1 &= ~AQUANTIA_USX_AUTONEG_CONTROL_ENA; printf("%s: system interface XFI\n", phydev->dev->name); } - } else if (phydev->interface == PHY_INTERFACE_MODE_SGMII_2500) { + phy_write(phydev, MDIO_MMD_PHYXS, + AQUANTIA_VENDOR_PROVISIONING_REG, reg_val1); + break; + case PHY_INTERFACE_MODE_SGMII_2500: /* 2.5GBASE-T mode */ phydev->advertising = SUPPORTED_1000baseT_Full; phydev->supported = phydev->advertising; phy_write(phydev, MDIO_MMD_AN, AQUNTIA_10G_CTL, 1); phy_write(phydev, MDIO_MMD_AN, AQUNTIA_VENDOR_P1, 0x9440); - } else if (phydev->interface == PHY_INTERFACE_MODE_MII) { + break; + case PHY_INTERFACE_MODE_MII: /* 100BASE-TX mode */ phydev->advertising = SUPPORTED_100baseT_Full; phydev->supported = phydev->advertising; val = (val & ~AQUNTIA_SPEED_MSB_MASK) | AQUNTIA_SPEED_LSB_MASK; phy_write(phydev, MDIO_MMD_PMAPMD, MII_BMCR, val); - } + break; + }; val = phy_read(phydev, MDIO_MMD_VEND1, AQUANTIA_RESERVED_STATUS); reg_val1 = phy_read(phydev, MDIO_MMD_VEND1, AQUANTIA_FIRMWARE_ID); @@ -354,17 +555,14 @@ int aquantia_startup(struct phy_device *phydev) phydev->duplex = DUPLEX_FULL; /* if the AN is still in progress, wait till timeout. */ - phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1); - reg = phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1); - if (!(reg & MDIO_AN_STAT1_COMPLETE)) { + if (!aquantia_link_is_up(phydev)) { printf("%s Waiting for PHY auto negotiation to complete", phydev->dev->name); do { udelay(1000); - reg = phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1); if ((i++ % 500) == 0) printf("."); - } while (!(reg & MDIO_AN_STAT1_COMPLETE) && + } while (!aquantia_link_is_up(phydev) && i < (4 * PHY_ANEG_TIMEOUT)); if (i > PHY_ANEG_TIMEOUT) @@ -433,6 +631,7 @@ struct phy_driver aqr105_driver = { .config = &aquantia_config, .startup = &aquantia_startup, .shutdown = &gen10g_shutdown, + .data = AQUANTIA_GEN1, }; struct phy_driver aqr106_driver = { @@ -459,6 +658,7 @@ struct phy_driver aqr107_driver = { .config = &aquantia_config, .startup = &aquantia_startup, .shutdown = &gen10g_shutdown, + .data = AQUANTIA_GEN2, }; struct phy_driver aqr112_driver = { @@ -472,6 +672,7 @@ struct phy_driver aqr112_driver = { .config = &aquantia_config, .startup = &aquantia_startup, .shutdown = &gen10g_shutdown, + .data = AQUANTIA_GEN3, }; struct phy_driver aqr405_driver = { @@ -485,6 +686,7 @@ struct phy_driver aqr405_driver = { .config = &aquantia_config, .startup = &aquantia_startup, .shutdown = &gen10g_shutdown, + .data = AQUANTIA_GEN1, }; struct phy_driver aqr412_driver = { @@ -498,6 +700,7 @@ struct phy_driver aqr412_driver = { .config = &aquantia_config, .startup = &aquantia_startup, .shutdown = &gen10g_shutdown, + .data = AQUANTIA_GEN3, }; int phy_aquantia_init(void) diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/dp83867.c index 7509936465..a43793cd42 100644 --- a/drivers/net/phy/ti.c +++ b/drivers/net/phy/dp83867.c @@ -25,6 +25,7 @@ #define DP83867_CFG4 0x0031 #define DP83867_RGMIICTL 0x0032 #define DP83867_STRAP_STS1 0x006E +#define DP83867_STRAP_STS2 0x006f #define DP83867_RGMIIDCTL 0x0086 #define DP83867_IO_MUX_CFG 0x0170 @@ -52,18 +53,27 @@ /* STRAP_STS1 bits */ #define DP83867_STRAP_STS1_RESERVED BIT(11) +/* STRAP_STS2 bits */ +#define DP83867_STRAP_STS2_CLK_SKEW_TX_MASK GENMASK(6, 4) +#define DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT 4 +#define DP83867_STRAP_STS2_CLK_SKEW_RX_MASK GENMASK(2, 0) +#define DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT 0 +#define DP83867_STRAP_STS2_CLK_SKEW_NONE BIT(2) + /* PHY CTRL bits */ #define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14 +#define DP83867_PHYCR_FIFO_DEPTH_MASK GENMASK(15, 14) #define DP83867_PHYCR_RESERVED_MASK BIT(11) #define DP83867_MDI_CROSSOVER 5 -#define DP83867_MDI_CROSSOVER_AUTO 2 #define DP83867_MDI_CROSSOVER_MDIX 2 #define DP83867_PHYCTRL_SGMIIEN 0x0800 #define DP83867_PHYCTRL_RXFIFO_SHIFT 12 #define DP83867_PHYCTRL_TXFIFO_SHIFT 14 /* RGMIIDCTL bits */ +#define DP83867_RGMII_TX_CLK_DELAY_MAX 0xf #define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4 +#define DP83867_RGMII_RX_CLK_DELAY_MAX 0xf /* CFG2 bits */ #define MII_DP83867_CFG2_SPEEDOPT_10EN 0x0040 @@ -74,8 +84,6 @@ #define MII_DP83867_CFG2_MASK 0x003F /* User setting - can be taken from DTS */ -#define DEFAULT_RX_ID_DELAY DP83867_RGMIIDCTL_2_25_NS -#define DEFAULT_TX_ID_DELAY DP83867_RGMIIDCTL_2_75_NS #define DEFAULT_FIFO_DEPTH DP83867_PHYCR_FIFO_DEPTH_4_B_NIB /* IO_MUX_CFG bits */ @@ -83,6 +91,7 @@ #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX 0x0 #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN 0x1f +#define DP83867_IO_MUX_CFG_CLK_O_DISABLE BIT(6) #define DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT 8 #define DP83867_IO_MUX_CFG_CLK_O_SEL_MASK \ GENMASK(0x1f, DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT) @@ -97,12 +106,13 @@ enum { }; struct dp83867_private { - int rx_id_delay; - int tx_id_delay; + u32 rx_id_delay; + u32 tx_id_delay; int fifo_depth; int io_impedance; bool rxctrl_strap_quirk; int port_mirroring; + bool set_clk_output; unsigned int clk_output_sel; }; @@ -134,16 +144,28 @@ static int dp83867_of_init(struct phy_device *phydev) { struct dp83867_private *dp83867 = phydev->priv; ofnode node; - u16 val; + int ret; node = phy_get_ofnode(phydev); if (!ofnode_valid(node)) return -EINVAL; - /* Keep the default value if ti,clk-output-sel is not set */ - dp83867->clk_output_sel = - ofnode_read_u32_default(node, "ti,clk-output-sel", - DP83867_CLK_O_SEL_REF_CLK); + /* Optional configuration */ + ret = ofnode_read_u32(node, "ti,clk-output-sel", + &dp83867->clk_output_sel); + /* If not set, keep default */ + if (!ret) { + dp83867->set_clk_output = true; + /* Valid values are 0 to DP83867_CLK_O_SEL_REF_CLK or + * DP83867_CLK_O_SEL_OFF. + */ + if (dp83867->clk_output_sel > DP83867_CLK_O_SEL_REF_CLK && + dp83867->clk_output_sel != DP83867_CLK_O_SEL_OFF) { + pr_debug("ti,clk-output-sel value %u out of range\n", + dp83867->clk_output_sel); + return -EINVAL; + } + } if (ofnode_read_bool(node, "ti,max-output-impedance")) dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX; @@ -154,13 +176,55 @@ static int dp83867_of_init(struct phy_device *phydev) if (ofnode_read_bool(node, "ti,dp83867-rxctrl-strap-quirk")) dp83867->rxctrl_strap_quirk = true; - dp83867->rx_id_delay = ofnode_read_u32_default(node, - "ti,rx-internal-delay", - DEFAULT_RX_ID_DELAY); - dp83867->tx_id_delay = ofnode_read_u32_default(node, - "ti,tx-internal-delay", - DEFAULT_TX_ID_DELAY); + /* Existing behavior was to use default pin strapping delay in rgmii + * mode, but rgmii should have meant no delay. Warn existing users. + */ + if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { + u16 val = phy_read_mmd(phydev, DP83867_DEVADDR, + DP83867_STRAP_STS2); + u16 txskew = (val & DP83867_STRAP_STS2_CLK_SKEW_TX_MASK) >> + DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT; + u16 rxskew = (val & DP83867_STRAP_STS2_CLK_SKEW_RX_MASK) >> + DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT; + + if (txskew != DP83867_STRAP_STS2_CLK_SKEW_NONE || + rxskew != DP83867_STRAP_STS2_CLK_SKEW_NONE) + pr_warn("PHY has delays via pin strapping, but phy-mode = 'rgmii'\n" + "Should be 'rgmii-id' to use internal delays\n"); + } + + /* RX delay *must* be specified if internal delay of RX is used. */ + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { + ret = ofnode_read_u32(node, "ti,rx-internal-delay", + &dp83867->rx_id_delay); + if (ret) { + pr_debug("ti,rx-internal-delay must be specified\n"); + return ret; + } + if (dp83867->rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX) { + pr_debug("ti,rx-internal-delay value of %u out of range\n", + dp83867->rx_id_delay); + return -EINVAL; + } + } + + /* TX delay *must* be specified if internal delay of RX is used. */ + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { + ret = ofnode_read_u32(node, "ti,tx-internal-delay", + &dp83867->tx_id_delay); + if (ret) { + debug("ti,tx-internal-delay must be specified\n"); + return ret; + } + if (dp83867->tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX) { + pr_debug("ti,tx-internal-delay value of %u out of range\n", + dp83867->tx_id_delay); + return -EINVAL; + } + } dp83867->fifo_depth = ofnode_read_u32_default(node, "ti,fifo-depth", DEFAULT_FIFO_DEPTH); @@ -170,18 +234,6 @@ static int dp83867_of_init(struct phy_device *phydev) if (ofnode_read_bool(node, "enet-phy-lane-no-swap")) dp83867->port_mirroring = DP83867_PORT_MIRRORING_DIS; - - /* Clock output selection if muxing property is set */ - if (dp83867->clk_output_sel != DP83867_CLK_O_SEL_REF_CLK) { - val = phy_read_mmd(phydev, DP83867_DEVADDR, - DP83867_IO_MUX_CFG); - val &= ~DP83867_IO_MUX_CFG_CLK_O_SEL_MASK; - val |= (dp83867->clk_output_sel << - DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT); - phy_write_mmd(phydev, DP83867_DEVADDR, - DP83867_IO_MUX_CFG, val); - } - return 0; } #else @@ -189,8 +241,8 @@ static int dp83867_of_init(struct phy_device *phydev) { struct dp83867_private *dp83867 = phydev->priv; - dp83867->rx_id_delay = DEFAULT_RX_ID_DELAY; - dp83867->tx_id_delay = DEFAULT_TX_ID_DELAY; + dp83867->rx_id_delay = DP83867_RGMIIDCTL_2_25_NS; + dp83867->tx_id_delay = DP83867_RGMIIDCTL_2_75_NS; dp83867->fifo_depth = DEFAULT_FIFO_DEPTH; dp83867->io_impedance = -EINVAL; @@ -204,18 +256,11 @@ static int dp83867_config(struct phy_device *phydev) unsigned int val, delay, cfg2; int ret, bs; - if (!phydev->priv) { - dp83867 = kzalloc(sizeof(*dp83867), GFP_KERNEL); - if (!dp83867) - return -ENOMEM; + dp83867 = (struct dp83867_private *)phydev->priv; - phydev->priv = dp83867; - ret = dp83867_of_init(phydev); - if (ret) - goto err_out; - } else { - dp83867 = (struct dp83867_private *)phydev->priv; - } + ret = dp83867_of_init(phydev); + if (ret) + return ret; /* Restart the PHY. */ val = phy_read(phydev, MDIO_DEVAD_NONE, DP83867_CTRL); @@ -232,11 +277,11 @@ static int dp83867_config(struct phy_device *phydev) } if (phy_interface_is_rgmii(phydev)) { - ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL, - (DP83867_MDI_CROSSOVER_AUTO << DP83867_MDI_CROSSOVER) | - (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT)); - if (ret) + val = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL); + if (val < 0) goto err_out; + val &= ~DP83867_PHYCR_FIFO_DEPTH_MASK; + val |= (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT); /* The code below checks if "port mirroring" N/A MODE4 has been * enabled during power on bootstrap. @@ -248,16 +293,39 @@ static int dp83867_config(struct phy_device *phydev) * register's bit 11 (marked as RESERVED). */ - bs = phy_read_mmd(phydev, DP83867_DEVADDR, - DP83867_STRAP_STS1); - val = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL); - if (bs & DP83867_STRAP_STS1_RESERVED) { + bs = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_STRAP_STS1); + if (bs & DP83867_STRAP_STS1_RESERVED) val &= ~DP83867_PHYCR_RESERVED_MASK; - phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL, - val); - } - } else if (phy_interface_is_sgmii(phydev)) { + ret = phy_write(phydev, MDIO_DEVAD_NONE, + MII_DP83867_PHYCTRL, val); + + val = phy_read_mmd(phydev, DP83867_DEVADDR, + DP83867_RGMIICTL); + + val &= ~(DP83867_RGMII_TX_CLK_DELAY_EN | + DP83867_RGMII_RX_CLK_DELAY_EN); + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + val |= (DP83867_RGMII_TX_CLK_DELAY_EN | + DP83867_RGMII_RX_CLK_DELAY_EN); + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) + val |= DP83867_RGMII_TX_CLK_DELAY_EN; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) + val |= DP83867_RGMII_RX_CLK_DELAY_EN; + + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIICTL, val); + + delay = (dp83867->rx_id_delay | + (dp83867->tx_id_delay << + DP83867_RGMII_TX_CLK_DELAY_SHIFT)); + + phy_write_mmd(phydev, DP83867_DEVADDR, + DP83867_RGMIIDCTL, delay); + } + + if (phy_interface_is_sgmii(phydev)) { phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, (BMCR_ANENABLE | BMCR_FULLDPLX | BMCR_SPEED1000)); @@ -282,57 +350,62 @@ static int dp83867_config(struct phy_device *phydev) phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_BISCR, 0x0); } - if (phy_interface_is_rgmii(phydev)) { - val = phy_read_mmd(phydev, DP83867_DEVADDR, - DP83867_RGMIICTL); - - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) - val |= (DP83867_RGMII_TX_CLK_DELAY_EN | - DP83867_RGMII_RX_CLK_DELAY_EN); - - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) - val |= DP83867_RGMII_TX_CLK_DELAY_EN; - - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) - val |= DP83867_RGMII_RX_CLK_DELAY_EN; - + if (dp83867->io_impedance >= 0) { + val = phy_read_mmd(phydev, + DP83867_DEVADDR, + DP83867_IO_MUX_CFG); + val &= ~DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL; + val |= dp83867->io_impedance & + DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL; phy_write_mmd(phydev, DP83867_DEVADDR, - DP83867_RGMIICTL, val); + DP83867_IO_MUX_CFG, val); + } - delay = (dp83867->rx_id_delay | - (dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT)); + if (dp83867->port_mirroring != DP83867_PORT_MIRRORING_KEEP) + dp83867_config_port_mirroring(phydev); - phy_write_mmd(phydev, DP83867_DEVADDR, - DP83867_RGMIIDCTL, delay); + /* Clock output selection if muxing property is set */ + if (dp83867->set_clk_output) { + val = phy_read_mmd(phydev, DP83867_DEVADDR, + DP83867_IO_MUX_CFG); - if (dp83867->io_impedance >= 0) { - val = phy_read_mmd(phydev, - DP83867_DEVADDR, - DP83867_IO_MUX_CFG); - val &= ~DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL; - val |= dp83867->io_impedance & - DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL; - phy_write_mmd(phydev, DP83867_DEVADDR, - DP83867_IO_MUX_CFG, val); + if (dp83867->clk_output_sel == DP83867_CLK_O_SEL_OFF) { + val |= DP83867_IO_MUX_CFG_CLK_O_DISABLE; + } else { + val &= ~(DP83867_IO_MUX_CFG_CLK_O_SEL_MASK | + DP83867_IO_MUX_CFG_CLK_O_DISABLE); + val |= dp83867->clk_output_sel << + DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT; } + phy_write_mmd(phydev, DP83867_DEVADDR, + DP83867_IO_MUX_CFG, val); } - if (dp83867->port_mirroring != DP83867_PORT_MIRRORING_KEEP) - dp83867_config_port_mirroring(phydev); - genphy_config_aneg(phydev); return 0; err_out: - kfree(dp83867); return ret; } +static int dp83867_probe(struct phy_device *phydev) +{ + struct dp83867_private *dp83867; + + dp83867 = kzalloc(sizeof(*dp83867), GFP_KERNEL); + if (!dp83867) + return -ENOMEM; + + phydev->priv = dp83867; + return 0; +} + static struct phy_driver DP83867_driver = { .name = "TI DP83867", .uid = 0x2000a231, .mask = 0xfffffff0, .features = PHY_GBIT_FEATURES, + .probe = dp83867_probe, .config = &dp83867_config, .startup = &genphy_startup, .shutdown = &genphy_shutdown, diff --git a/drivers/net/phy/micrel_ksz8xxx.c b/drivers/net/phy/micrel_ksz8xxx.c index daa57ce33c..e27fc45a28 100644 --- a/drivers/net/phy/micrel_ksz8xxx.c +++ b/drivers/net/phy/micrel_ksz8xxx.c @@ -24,6 +24,7 @@ static struct phy_driver KSZ804_driver = { }; #define MII_KSZPHY_OMSO 0x16 +#define KSZPHY_OMSO_FACTORY_TEST BIT(15) #define KSZPHY_OMSO_B_CAST_OFF (1 << 9) static int ksz_genconfig_bcastoff(struct phy_device *phydev) @@ -80,12 +81,30 @@ static struct phy_driver KSZ8051_driver = { .shutdown = &genphy_shutdown, }; +static int ksz8081_config(struct phy_device *phydev) +{ + int ret; + + ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO); + if (ret < 0) + return ret; + + ret &= ~KSZPHY_OMSO_FACTORY_TEST; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO, + ret | KSZPHY_OMSO_B_CAST_OFF); + if (ret < 0) + return ret; + + return genphy_config(phydev); +} + static struct phy_driver KSZ8081_driver = { .name = "Micrel KSZ8081", .uid = 0x221560, .mask = 0xfffff0, .features = PHY_BASIC_FEATURES, - .config = &ksz_genconfig_bcastoff, + .config = &ksz8081_config, .startup = &genphy_startup, .shutdown = &genphy_shutdown, }; diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c index c1e2860329..5aff7ed397 100644 --- a/drivers/net/phy/mv88e61xx.c +++ b/drivers/net/phy/mv88e61xx.c @@ -39,15 +39,11 @@ #define PHY_AUTONEGOTIATE_TIMEOUT 5000 -#define PORT_COUNT 11 -#define PORT_MASK ((1 << PORT_COUNT) - 1) +#define PORT_MASK(port_count) ((1 << (port_count)) - 1) /* Device addresses */ #define DEVADDR_PHY(p) (p) -#define DEVADDR_PORT(p) (0x10 + (p)) #define DEVADDR_SERDES 0x0F -#define DEVADDR_GLOBAL_1 0x1B -#define DEVADDR_GLOBAL_2 0x1C /* SMI indirection registers for multichip addressing mode */ #define SMI_CMD_REG 0x00 @@ -88,11 +84,7 @@ #define GLOBAL1_MON_CTRL_CPUDEST_SHIFT 4 #define GLOBAL1_MON_CTRL_CPUDEST_WIDTH 4 -#define PORT_REG_STATUS_LINK BIT(11) -#define PORT_REG_STATUS_DUPLEX BIT(10) - #define PORT_REG_STATUS_SPEED_SHIFT 8 -#define PORT_REG_STATUS_SPEED_WIDTH 2 #define PORT_REG_STATUS_SPEED_10 0 #define PORT_REG_STATUS_SPEED_100 1 #define PORT_REG_STATUS_SPEED_1000 2 @@ -111,6 +103,7 @@ #define PORT_REG_PHYS_CTRL_DUPLEX_VALUE BIT(3) #define PORT_REG_PHYS_CTRL_DUPLEX_FORCE BIT(2) #define PORT_REG_PHYS_CTRL_SPD1000 BIT(1) +#define PORT_REG_PHYS_CTRL_SPD100 BIT(0) #define PORT_REG_PHYS_CTRL_SPD_MASK (BIT(1) | BIT(0)) #define PORT_REG_CTRL_PSTATE_SHIFT 0 @@ -124,14 +117,12 @@ #define SERDES_REG_CTRL_1_FORCE_LINK BIT(10) -#define PHY_REG_CTRL1_ENERGY_DET_SHIFT 8 -#define PHY_REG_CTRL1_ENERGY_DET_WIDTH 2 - /* Field values */ #define PORT_REG_CTRL_PSTATE_DISABLED 0 #define PORT_REG_CTRL_PSTATE_FORWARD 3 #define PHY_REG_CTRL1_ENERGY_DET_OFF 0 +#define PHY_REG_CTRL1_ENERGY_DET_SENSE_PULSE 1 #define PHY_REG_CTRL1_ENERGY_DET_SENSE_ONLY 2 #define PHY_REG_CTRL1_ENERGY_DET_SENSE_XMIT 3 @@ -182,17 +173,32 @@ #endif /* ID register values for different switch models */ +#define PORT_SWITCH_ID_6020 0x0200 +#define PORT_SWITCH_ID_6070 0x0700 +#define PORT_SWITCH_ID_6071 0x0710 #define PORT_SWITCH_ID_6096 0x0980 #define PORT_SWITCH_ID_6097 0x0990 #define PORT_SWITCH_ID_6172 0x1720 #define PORT_SWITCH_ID_6176 0x1760 +#define PORT_SWITCH_ID_6220 0x2200 #define PORT_SWITCH_ID_6240 0x2400 +#define PORT_SWITCH_ID_6250 0x2500 #define PORT_SWITCH_ID_6352 0x3520 struct mv88e61xx_phy_priv { struct mii_dev *mdio_bus; int smi_addr; int id; + int port_count; /* Number of switch ports */ + int port_reg_base; /* Base of the switch port registers */ + u16 port_stat_link_mask;/* Bitmask for port link status bits */ + u16 port_stat_dup_mask; /* Bitmask for port duplex status bits */ + u8 port_stat_speed_width;/* Width of speed status bitfield */ + u8 global1; /* Offset of Switch Global 1 registers */ + u8 global2; /* Offset of Switch Global 2 registers */ + u8 phy_ctrl1_en_det_shift; /* 'EDet' bit field offset */ + u8 phy_ctrl1_en_det_width; /* Width of 'EDet' bit field */ + u8 phy_ctrl1_en_det_ctrl; /* 'EDet' control value */ }; static inline int smi_cmd(int cmd, int addr, int reg) @@ -329,11 +335,12 @@ static int mv88e61xx_reg_write(struct phy_device *phydev, int dev, int reg, static int mv88e61xx_phy_wait(struct phy_device *phydev) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int val; u32 timeout = 100; do { - val = mv88e61xx_reg_read(phydev, DEVADDR_GLOBAL_2, + val = mv88e61xx_reg_read(phydev, priv->global2, GLOBAL2_REG_PHY_CMD); if (val >= 0 && (val & SMI_BUSY) == 0) return 0; @@ -347,13 +354,15 @@ static int mv88e61xx_phy_wait(struct phy_device *phydev) static int mv88e61xx_phy_read_indirect(struct mii_dev *smi_wrapper, int dev, int devad, int reg) { + struct mv88e61xx_phy_priv *priv; struct phy_device *phydev; int res; phydev = (struct phy_device *)smi_wrapper->priv; + priv = phydev->priv; /* Issue command to read */ - res = mv88e61xx_reg_write(phydev, DEVADDR_GLOBAL_2, + res = mv88e61xx_reg_write(phydev, priv->global2, GLOBAL2_REG_PHY_CMD, smi_cmd_read(dev, reg)); @@ -363,25 +372,27 @@ static int mv88e61xx_phy_read_indirect(struct mii_dev *smi_wrapper, int dev, return res; /* Read retrieved data */ - return mv88e61xx_reg_read(phydev, DEVADDR_GLOBAL_2, + return mv88e61xx_reg_read(phydev, priv->global2, GLOBAL2_REG_PHY_DATA); } static int mv88e61xx_phy_write_indirect(struct mii_dev *smi_wrapper, int dev, int devad, int reg, u16 data) { + struct mv88e61xx_phy_priv *priv; struct phy_device *phydev; int res; phydev = (struct phy_device *)smi_wrapper->priv; + priv = phydev->priv; /* Set the data to write */ - res = mv88e61xx_reg_write(phydev, DEVADDR_GLOBAL_2, + res = mv88e61xx_reg_write(phydev, priv->global2, GLOBAL2_REG_PHY_DATA, data); if (res < 0) return res; /* Issue the write command */ - res = mv88e61xx_reg_write(phydev, DEVADDR_GLOBAL_2, + res = mv88e61xx_reg_write(phydev, priv->global2, GLOBAL2_REG_PHY_CMD, smi_cmd_write(dev, reg)); if (res < 0) @@ -408,13 +419,18 @@ static int mv88e61xx_phy_write(struct phy_device *phydev, int phy, static int mv88e61xx_port_read(struct phy_device *phydev, u8 port, u8 reg) { - return mv88e61xx_reg_read(phydev, DEVADDR_PORT(port), reg); + struct mv88e61xx_phy_priv *priv = phydev->priv; + + return mv88e61xx_reg_read(phydev, priv->port_reg_base + port, reg); } static int mv88e61xx_port_write(struct phy_device *phydev, u8 port, u8 reg, u16 val) { - return mv88e61xx_reg_write(phydev, DEVADDR_PORT(port), reg, val); + struct mv88e61xx_phy_priv *priv = phydev->priv; + + return mv88e61xx_reg_write(phydev, priv->port_reg_base + port, + reg, val); } static int mv88e61xx_set_page(struct phy_device *phydev, u8 phy, u8 page) @@ -515,12 +531,13 @@ static int mv88e61xx_parse_status(struct phy_device *phydev) static int mv88e61xx_switch_reset(struct phy_device *phydev) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int time; int val; u8 port; /* Disable all ports */ - for (port = 0; port < PORT_COUNT; port++) { + for (port = 0; port < priv->port_count; port++) { val = mv88e61xx_port_read(phydev, port, PORT_REG_CTRL); if (val < 0) return val; @@ -536,19 +553,19 @@ static int mv88e61xx_switch_reset(struct phy_device *phydev) udelay(2000); /* Reset switch */ - val = mv88e61xx_reg_read(phydev, DEVADDR_GLOBAL_1, GLOBAL1_CTRL); + val = mv88e61xx_reg_read(phydev, priv->global1, GLOBAL1_CTRL); if (val < 0) return val; val |= GLOBAL1_CTRL_SWRESET; - val = mv88e61xx_reg_write(phydev, DEVADDR_GLOBAL_1, - GLOBAL1_CTRL, val); + val = mv88e61xx_reg_write(phydev, priv->global1, + GLOBAL1_CTRL, val); if (val < 0) return val; /* Wait up to 1 second for switch reset complete */ for (time = 1000; time; time--) { - val = mv88e61xx_reg_read(phydev, DEVADDR_GLOBAL_1, - GLOBAL1_CTRL); + val = mv88e61xx_reg_read(phydev, priv->global1, + GLOBAL1_CTRL); if (val >= 0 && ((val & GLOBAL1_CTRL_SWRESET) == 0)) break; udelay(1000); @@ -628,6 +645,7 @@ static int mv88e61xx_port_set_vlan(struct phy_device *phydev, u8 port, static int mv88e61xx_read_port_config(struct phy_device *phydev, u8 port) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int res; int val; bool forced = false; @@ -635,7 +653,7 @@ static int mv88e61xx_read_port_config(struct phy_device *phydev, u8 port) val = mv88e61xx_port_read(phydev, port, PORT_REG_STATUS); if (val < 0) return val; - if (!(val & PORT_REG_STATUS_LINK)) { + if (!(val & priv->port_stat_link_mask)) { /* Temporarily force link to read port configuration */ u32 timeout = 100; forced = true; @@ -658,7 +676,7 @@ static int mv88e61xx_read_port_config(struct phy_device *phydev, u8 port) res = -EIO; goto unforce; } - if (val & PORT_REG_STATUS_LINK) + if (val & priv->port_stat_link_mask) break; } while (--timeout); @@ -668,13 +686,13 @@ static int mv88e61xx_read_port_config(struct phy_device *phydev, u8 port) } } - if (val & PORT_REG_STATUS_DUPLEX) + if (val & priv->port_stat_dup_mask) phydev->duplex = DUPLEX_FULL; else phydev->duplex = DUPLEX_HALF; val = bitfield_extract(val, PORT_REG_STATUS_SPEED_SHIFT, - PORT_REG_STATUS_SPEED_WIDTH); + priv->port_stat_speed_width); switch (val) { case PORT_REG_STATUS_SPEED_1000: phydev->speed = SPEED_1000; @@ -707,6 +725,7 @@ unforce: static int mv88e61xx_fixed_port_setup(struct phy_device *phydev, u8 port) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int val; val = mv88e61xx_port_read(phydev, port, PORT_REG_PHYS_CTRL); @@ -714,13 +733,19 @@ static int mv88e61xx_fixed_port_setup(struct phy_device *phydev, u8 port) return val; val &= ~(PORT_REG_PHYS_CTRL_SPD_MASK | - PORT_REG_PHYS_CTRL_FC_VALUE); - val |= PORT_REG_PHYS_CTRL_PCS_AN_EN | - PORT_REG_PHYS_CTRL_PCS_AN_RST | - PORT_REG_PHYS_CTRL_FC_FORCE | + PORT_REG_PHYS_CTRL_FC_VALUE | + PORT_REG_PHYS_CTRL_FC_FORCE); + val |= PORT_REG_PHYS_CTRL_FC_FORCE | PORT_REG_PHYS_CTRL_DUPLEX_VALUE | - PORT_REG_PHYS_CTRL_DUPLEX_FORCE | - PORT_REG_PHYS_CTRL_SPD1000; + PORT_REG_PHYS_CTRL_DUPLEX_FORCE; + + if (priv->id == PORT_SWITCH_ID_6071) { + val |= PORT_REG_PHYS_CTRL_SPD100; + } else { + val |= PORT_REG_PHYS_CTRL_PCS_AN_EN | + PORT_REG_PHYS_CTRL_PCS_AN_RST | + PORT_REG_PHYS_CTRL_SPD1000; + } if (port == CONFIG_MV88E61XX_CPU_PORT) val |= PORT_REG_PHYS_CTRL_LINK_VALUE | @@ -732,22 +757,23 @@ static int mv88e61xx_fixed_port_setup(struct phy_device *phydev, u8 port) static int mv88e61xx_set_cpu_port(struct phy_device *phydev) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int val; /* Set CPUDest */ - val = mv88e61xx_reg_read(phydev, DEVADDR_GLOBAL_1, GLOBAL1_MON_CTRL); + val = mv88e61xx_reg_read(phydev, priv->global1, GLOBAL1_MON_CTRL); if (val < 0) return val; val = bitfield_replace(val, GLOBAL1_MON_CTRL_CPUDEST_SHIFT, GLOBAL1_MON_CTRL_CPUDEST_WIDTH, CONFIG_MV88E61XX_CPU_PORT); - val = mv88e61xx_reg_write(phydev, DEVADDR_GLOBAL_1, - GLOBAL1_MON_CTRL, val); + val = mv88e61xx_reg_write(phydev, priv->global1, + GLOBAL1_MON_CTRL, val); if (val < 0) return val; /* Allow CPU to route to any port */ - val = PORT_MASK & ~(1 << CONFIG_MV88E61XX_CPU_PORT); + val = PORT_MASK(priv->port_count) & ~(1 << CONFIG_MV88E61XX_CPU_PORT); val = mv88e61xx_port_set_vlan(phydev, CONFIG_MV88E61XX_CPU_PORT, val); if (val < 0) return val; @@ -821,6 +847,7 @@ static int mv88e61xx_phy_enable(struct phy_device *phydev, u8 phy) static int mv88e61xx_phy_setup(struct phy_device *phydev, u8 phy) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int val; /* @@ -830,9 +857,9 @@ static int mv88e61xx_phy_setup(struct phy_device *phydev, u8 phy) val = mv88e61xx_phy_read(phydev, phy, PHY_REG_CTRL1); if (val < 0) return val; - val = bitfield_replace(val, PHY_REG_CTRL1_ENERGY_DET_SHIFT, - PHY_REG_CTRL1_ENERGY_DET_WIDTH, - PHY_REG_CTRL1_ENERGY_DET_SENSE_XMIT); + val = bitfield_replace(val, priv->phy_ctrl1_en_det_shift, + priv->phy_ctrl1_en_det_width, + priv->phy_ctrl1_en_det_ctrl); val = mv88e61xx_phy_write(phydev, phy, PHY_REG_CTRL1, val); if (val < 0) return val; @@ -856,6 +883,48 @@ static int mv88e61xx_phy_config_port(struct phy_device *phydev, u8 phy) return 0; } +/* + * This function is used to pre-configure the required register + * offsets, so that the indirect register access to the PHY registers + * is possible. This is necessary to be able to read the PHY ID + * while driver probing or in get_phy_id(). The globalN register + * offsets must be initialized correctly for a detected switch, + * otherwise detection of the PHY ID won't work! + */ +static int mv88e61xx_priv_reg_offs_pre_init(struct phy_device *phydev) +{ + struct mv88e61xx_phy_priv *priv = phydev->priv; + + /* + * Initial 'port_reg_base' value must be an offset of existing + * port register, then reading the ID should succeed. First, try + * to read via port registers with device address 0x10 (88E6096 + * and compatible switches). + */ + priv->port_reg_base = 0x10; + priv->id = mv88e61xx_get_switch_id(phydev); + if (priv->id != 0xfff0) { + priv->global1 = 0x1B; + priv->global2 = 0x1C; + return 0; + } + + /* + * Now try via port registers with device address 0x08 + * (88E6020 and compatible switches). + */ + priv->port_reg_base = 0x08; + priv->id = mv88e61xx_get_switch_id(phydev); + if (priv->id != 0xfff0) { + priv->global1 = 0x0F; + priv->global2 = 0x07; + return 0; + } + + debug("%s Unknown ID 0x%x\n", __func__, priv->id); + return -ENODEV; +} + static int mv88e61xx_probe(struct phy_device *phydev) { struct mii_dev *smi_wrapper; @@ -910,13 +979,57 @@ static int mv88e61xx_probe(struct phy_device *phydev) phydev->priv = priv; - priv->id = mv88e61xx_get_switch_id(phydev); + res = mv88e61xx_priv_reg_offs_pre_init(phydev); + if (res < 0) + return res; + + debug("%s ID 0x%x\n", __func__, priv->id); + + switch (priv->id) { + case PORT_SWITCH_ID_6096: + case PORT_SWITCH_ID_6097: + case PORT_SWITCH_ID_6172: + case PORT_SWITCH_ID_6176: + case PORT_SWITCH_ID_6240: + case PORT_SWITCH_ID_6352: + priv->port_count = 11; + priv->port_stat_link_mask = BIT(11); + priv->port_stat_dup_mask = BIT(10); + priv->port_stat_speed_width = 2; + priv->phy_ctrl1_en_det_shift = 8; + priv->phy_ctrl1_en_det_width = 2; + priv->phy_ctrl1_en_det_ctrl = + PHY_REG_CTRL1_ENERGY_DET_SENSE_XMIT; + break; + case PORT_SWITCH_ID_6020: + case PORT_SWITCH_ID_6070: + case PORT_SWITCH_ID_6071: + case PORT_SWITCH_ID_6220: + case PORT_SWITCH_ID_6250: + priv->port_count = 7; + priv->port_stat_link_mask = BIT(12); + priv->port_stat_dup_mask = BIT(9); + priv->port_stat_speed_width = 1; + priv->phy_ctrl1_en_det_shift = 14; + priv->phy_ctrl1_en_det_width = 1; + priv->phy_ctrl1_en_det_ctrl = + PHY_REG_CTRL1_ENERGY_DET_SENSE_PULSE; + break; + default: + free(priv); + return -ENODEV; + } + + res = mdio_register(smi_wrapper); + if (res) + printf("Failed to register SMI bus\n"); return 0; } static int mv88e61xx_phy_config(struct phy_device *phydev) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int res; int i; int ret = -1; @@ -925,7 +1038,7 @@ static int mv88e61xx_phy_config(struct phy_device *phydev) if (res < 0) return res; - for (i = 0; i < PORT_COUNT; i++) { + for (i = 0; i < priv->port_count; i++) { if ((1 << i) & CONFIG_MV88E61XX_PHY_PORTS) { phydev->addr = i; @@ -988,13 +1101,14 @@ static int mv88e61xx_phy_is_connected(struct phy_device *phydev) static int mv88e61xx_phy_startup(struct phy_device *phydev) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int i; int link = 0; int res; int speed = phydev->speed; int duplex = phydev->duplex; - for (i = 0; i < PORT_COUNT; i++) { + for (i = 0; i < priv->port_count; i++) { if ((1 << i) & CONFIG_MV88E61XX_PHY_PORTS) { phydev->addr = i; if (!mv88e61xx_phy_is_connected(phydev)) @@ -1040,10 +1154,22 @@ static struct phy_driver mv88e609x_driver = { .shutdown = &genphy_shutdown, }; +static struct phy_driver mv88e6071_driver = { + .name = "Marvell MV88E6071", + .uid = 0x1410db0, + .mask = 0xfffffff0, + .features = PHY_BASIC_FEATURES | SUPPORTED_MII, + .probe = mv88e61xx_probe, + .config = mv88e61xx_phy_config, + .startup = mv88e61xx_phy_startup, + .shutdown = &genphy_shutdown, +}; + int phy_mv88e61xx_init(void) { phy_register(&mv88e61xx_driver); phy_register(&mv88e609x_driver); + phy_register(&mv88e6071_driver); return 0; } @@ -1068,6 +1194,16 @@ int get_phy_id(struct mii_dev *bus, int smi_addr, int devad, u32 *phy_id) temp_phy.priv = &temp_priv; temp_mii.priv = &temp_phy; + /* + * get_phy_id() can be called by framework before mv88e61xx driver + * probing, in this case the global register offsets are not + * initialized yet. Do this initialization here before indirect + * PHY register access. + */ + val = mv88e61xx_priv_reg_offs_pre_init(&temp_phy); + if (val < 0) + return val; + val = mv88e61xx_phy_read_indirect(&temp_mii, 0, devad, MII_PHYSID1); if (val < 0) return -EIO; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index f2d17aa91a..80a7664e49 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -256,11 +256,11 @@ int genphy_update_link(struct phy_device *phydev) return -EINTR; } - if ((i++ % 500) == 0) + if ((i++ % 10) == 0) printf("."); - udelay(1000); /* 1 ms */ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); + mdelay(50); /* 50 ms */ } printf(" done\n"); phydev->link = 1; @@ -997,7 +997,7 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr, #endif { struct phy_device *phydev = NULL; - uint mask = (addr > 0) ? (1 << addr) : 0xffffffff; + uint mask = (addr >= 0) ? (1 << addr) : 0xffffffff; #ifdef CONFIG_PHY_FIXED phydev = phy_connect_fixed(bus, dev, interface); diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 53454f2f21..5ccdfdd683 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -253,6 +253,7 @@ static struct { {"RTL-8169sc/8110sc", 0x18, 0xff7e1880,}, {"RTL-8168b/8111sb", 0x30, 0xff7e1880,}, {"RTL-8168b/8111sb", 0x38, 0xff7e1880,}, + {"RTL-8168c/8111c", 0x3c, 0xff7e1880,}, {"RTL-8168d/8111d", 0x28, 0xff7e1880,}, {"RTL-8168evl/8111evl", 0x2e, 0xff7e1880,}, {"RTL-8168/8111g", 0x4c, 0xff7e1880,}, diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c index 06b0663950..2590486810 100644 --- a/drivers/net/ti/am65-cpsw-nuss.c +++ b/drivers/net/ti/am65-cpsw-nuss.c @@ -99,7 +99,6 @@ struct am65_cpsw_common { u32 port_num; struct am65_cpsw_port ports[AM65_CPSW_CPSWNU_MAX_PORTS]; - u32 rflow_id_base; struct mii_dev *bus; u32 bus_freq; @@ -276,6 +275,7 @@ static int am65_cpsw_start(struct udevice *dev) struct am65_cpsw_common *common = priv->cpsw_common; struct am65_cpsw_port *port = &common->ports[priv->port_id]; struct am65_cpsw_port *port0 = &common->ports[0]; + struct ti_udma_drv_chan_cfg_data *dma_rx_cfg_data; int ret, i; ret = power_domain_on(&common->pwrdmn); @@ -341,8 +341,11 @@ static int am65_cpsw_start(struct udevice *dev) writel(PKTSIZE_ALIGN, port0->port_base + AM65_CPSW_PN_RX_MAXLEN_REG); /* set base flow_id */ - writel(common->rflow_id_base, + dma_get_cfg(&common->dma_rx, 0, (void **)&dma_rx_cfg_data); + writel(dma_rx_cfg_data->flow_id_base, port0->port_base + AM65_CPSW_P0_FLOW_ID_REG); + dev_info(dev, "K3 CPSW: rflow_id_base: %u\n", + dma_rx_cfg_data->flow_id_base); /* Reset and enable the ALE */ writel(AM65_CPSW_ALE_CTL_REG_ENABLE | AM65_CPSW_ALE_CTL_REG_RESET_TBL | @@ -669,11 +672,6 @@ static int am65_cpsw_probe_cpsw(struct udevice *dev) AM65_CPSW_CPSW_NU_ALE_BASE; cpsw_common->mdio_base = cpsw_common->ss_base + AM65_CPSW_MDIO_BASE; - cpsw_common->rflow_id_base = 0; - cpsw_common->rflow_id_base = - dev_read_u32_default(dev, "ti,rx-flow-id-base", - cpsw_common->rflow_id_base); - ports_np = dev_read_subnode(dev, "ports"); if (!ofnode_valid(ports_np)) { ret = -ENOENT; @@ -761,12 +759,11 @@ static int am65_cpsw_probe_cpsw(struct udevice *dev) if (ret) goto out; - dev_info(dev, "K3 CPSW: nuss_ver: 0x%08X cpsw_ver: 0x%08X ale_ver: 0x%08X Ports:%u rflow_id_base:%u mdio_freq:%u\n", + dev_info(dev, "K3 CPSW: nuss_ver: 0x%08X cpsw_ver: 0x%08X ale_ver: 0x%08X Ports:%u mdio_freq:%u\n", readl(cpsw_common->ss_base), readl(cpsw_common->cpsw_base), readl(cpsw_common->ale_base), cpsw_common->port_num, - cpsw_common->rflow_id_base, cpsw_common->bus_freq); out: @@ -777,6 +774,7 @@ out: static const struct udevice_id am65_cpsw_nuss_ids[] = { { .compatible = "ti,am654-cpsw-nuss" }, + { .compatible = "ti,j721e-cpsw-nuss" }, { } }; diff --git a/include/dma-uclass.h b/include/dma-uclass.h index 31b43fb4b9..a1d9d26ac5 100644 --- a/include/dma-uclass.h +++ b/include/dma-uclass.h @@ -108,6 +108,17 @@ struct dma_ops { * @return zero on success, or -ve error code. */ int (*send)(struct dma *dma, void *src, size_t len, void *metadata); + /** + * get_cfg() - Get DMA channel configuration for client's use + * + * @dma: The DMA Channel to manipulate + * @cfg_id: DMA provider specific ID to identify what + * configuration data client needs + * @data: Pointer to store pointer to DMA driver specific + * configuration data for the given cfg_id (output param) + * @return zero on success, or -ve error code. + */ + int (*get_cfg)(struct dma *dma, u32 cfg_id, void **data); #endif /* CONFIG_DMA_CHANNELS */ /** * transfer() - Issue a DMA transfer. The implementation must diff --git a/include/dma.h b/include/dma.h index d1c3d0df7d..6c55aa3a00 100644 --- a/include/dma.h +++ b/include/dma.h @@ -290,6 +290,18 @@ int dma_receive(struct dma *dma, void **dst, void *metadata); * @return zero on success, or -ve error code. */ int dma_send(struct dma *dma, void *src, size_t len, void *metadata); + +/** + * dma_get_cfg() - Get DMA channel configuration for client's use + * + * @dma: The DMA Channel to manipulate + * @cfg_id: DMA provider specific ID to identify what + * configuration data client needs + * @cfg_data: Pointer to store pointer to DMA driver specific + * configuration data for the given cfg_id (output param) + * @return zero on success, or -ve error code. + */ +int dma_get_cfg(struct dma *dma, u32 cfg_id, void **cfg_data); #endif /* CONFIG_DMA_CHANNELS */ /* diff --git a/include/dt-bindings/net/ti-dp83867.h b/include/dt-bindings/net/ti-dp83867.h index 85d08f6974..cde5aa7e27 100644 --- a/include/dt-bindings/net/ti-dp83867.h +++ b/include/dt-bindings/net/ti-dp83867.h @@ -45,5 +45,6 @@ #define DP83867_CLK_O_SEL_CHN_C_TCLK 0xA #define DP83867_CLK_O_SEL_CHN_D_TCLK 0xB #define DP83867_CLK_O_SEL_REF_CLK 0xC - +/* Special flag to indicate clock should be off */ +#define DP83867_CLK_O_SEL_OFF 0xFFFFFFFF #endif diff --git a/include/linux/soc/ti/ti-udma.h b/include/linux/soc/ti/ti-udma.h index e9d4226c48..04e354fb2d 100644 --- a/include/linux/soc/ti/ti-udma.h +++ b/include/linux/soc/ti/ti-udma.h @@ -21,4 +21,23 @@ struct ti_udma_drv_packet_data { u32 dest_tag; }; +/** + * struct ti_udma_drv_chan_cfg_data - TI UDMA per channel specific + * configuration data + * + * @flow_id_base: Start index of flow ID allocated to this channel + * @flow_id_cnt: Number of flows allocated for this channel starting at + * flow_id_base + * + * TI UDMA channel specific data returned as part of dma_get_cfg() call + * from the DMA client driver. + */ +struct ti_udma_drv_chan_cfg_data { + u32 flow_id_base; + u32 flow_id_cnt; +}; + +/* TI UDMA specific flag IDs for dma_get_cfg() call */ +#define TI_UDMA_CHAN_PRIV_INFO 0 + #endif /* __TI_UDMA_H */ diff --git a/include/miiphy.h b/include/miiphy.h index 9b97d09f18..61c136b114 100644 --- a/include/miiphy.h +++ b/include/miiphy.h @@ -154,17 +154,29 @@ void dm_mdio_probe_devices(void); /** * dm_mdio_phy_connect - Wrapper over phy_connect for DM MDIO * - * @dev: mdio dev - * @addr: PHY address on MDIO bus + * @mdiodev: mdio device the PHY is accesible on + * @phyaddr: PHY address on MDIO bus * @ethdev: ethernet device to connect to the PHY * @interface: MAC-PHY protocol * * @return pointer to phy_device, or 0 on error */ -struct phy_device *dm_mdio_phy_connect(struct udevice *dev, int addr, +struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr, struct udevice *ethdev, phy_interface_t interface); +/** + * dm_eth_phy_connect - Connect an Eth device to a PHY based on device tree + * + * Picks up the DT phy-handle and phy-mode from ethernet device node and + * connects the ethernet device to the linked PHY. + * + * @ethdev: ethernet device + * + * @return pointer to phy_device, or 0 on error + */ +struct phy_device *dm_eth_phy_connect(struct udevice *ethdev); + #endif #ifdef CONFIG_DM_MDIO_MUX diff --git a/include/net.h b/include/net.h index 11eca1bc6c..834f244982 100644 --- a/include/net.h +++ b/include/net.h @@ -826,15 +826,29 @@ static inline void net_random_ethaddr(uchar *addr) addr[0] |= 0x02; /* set local assignment bit (IEEE802) */ } +/** + * string_to_enetaddr() - Parse a MAC address + * + * Convert a string MAC address + * + * Implemented in lib/net_utils.c (built unconditionally) + * + * @addr: MAC address in aa:bb:cc:dd:ee:ff format, where each part is a 2-digit + * hex value + * @enetaddr: Place to put MAC address (6 bytes) + */ +void string_to_enetaddr(const char *addr, uint8_t *enetaddr); + /* Convert an IP address to a string */ void ip_to_string(struct in_addr x, char *s); /** * string_to_ip() - Convert a string to ip address * - * @s: String to conver, in the format format a.b.c.d, where each value is a - * decimal number from 0 to 255 - * @return IP address, or 0 if invalid + * Implemented in lib/net_utils.c (built unconditionally) + * + * @s: Input string to parse + * @return: in_addr struct containing the parsed IP address */ struct in_addr string_to_ip(const char *s); @@ -880,19 +894,6 @@ unsigned int random_port(void); */ int update_tftp(ulong addr, char *interface, char *devstring); -/**********************************************************************/ - -/** - * eth_parse_enetaddr() - Parse a MAC address - * - * Convert a string MAC address - * - * @addr: MAC address in aa:bb:cc:dd:ee:ff format, where each part is a 2-digit - * hex value - * @enetaddr: Place to put MAC address (6 bytes) - */ -void eth_parse_enetaddr(const char *addr, uint8_t *enetaddr); - /** * env_get_ip() - Convert an environment value to to an ip address * @@ -905,5 +906,4 @@ static inline struct in_addr env_get_ip(char *var) { return string_to_ip(env_get(var)); } - #endif /* __NET_H__ */ diff --git a/include/phy.h b/include/phy.h index e50f56b6eb..6ace9b3a0c 100644 --- a/include/phy.h +++ b/include/phy.h @@ -115,6 +115,9 @@ struct phy_driver { u16 val); struct list_head list; + + /* driver private data */ + ulong data; }; struct phy_device { diff --git a/include/phy_interface.h b/include/phy_interface.h index c6823189f8..73f3a3679c 100644 --- a/include/phy_interface.h +++ b/include/phy_interface.h @@ -31,6 +31,8 @@ typedef enum { PHY_INTERFACE_MODE_XLAUI, PHY_INTERFACE_MODE_CAUI2, PHY_INTERFACE_MODE_CAUI4, + PHY_INTERFACE_MODE_XFI, + PHY_INTERFACE_MODE_USXGMII, PHY_INTERFACE_MODE_NONE, /* Must be last */ PHY_INTERFACE_MODE_COUNT, @@ -58,6 +60,8 @@ static const char * const phy_interface_strings[] = { [PHY_INTERFACE_MODE_XLAUI] = "xlaui4", [PHY_INTERFACE_MODE_CAUI2] = "caui2", [PHY_INTERFACE_MODE_CAUI4] = "caui4", + [PHY_INTERFACE_MODE_XFI] = "xfi", + [PHY_INTERFACE_MODE_USXGMII] = "usxgmii", [PHY_INTERFACE_MODE_NONE] = "", }; diff --git a/lib/net_utils.c b/lib/net_utils.c index 9fb9d4a4b0..ed5044c3de 100644 --- a/lib/net_utils.c +++ b/lib/net_utils.c @@ -41,3 +41,18 @@ struct in_addr string_to_ip(const char *s) addr.s_addr = htonl(addr.s_addr); return addr; } + +void string_to_enetaddr(const char *addr, uint8_t *enetaddr) +{ + char *end; + int i; + + if (!enetaddr) + return; + + for (i = 0; i < 6; ++i) { + enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0; + if (addr) + addr = (*end) ? end + 1 : end; + } +} diff --git a/lib/vsprintf.c b/lib/vsprintf.c index c6467ecd5f..b4edee29b0 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -320,7 +320,6 @@ static char *device_path_string(char *buf, char *end, void *dp, int field_width, #endif #endif -#ifdef CONFIG_CMD_NET static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width, int precision, int flags) { @@ -382,7 +381,6 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width, return string(buf, end, ip4_addr, field_width, precision, flags & ~SPECIAL); } -#endif #ifdef CONFIG_LIB_UUID /* @@ -474,7 +472,6 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, break; } break; -#ifdef CONFIG_CMD_NET case 'm': flags |= SPECIAL; /* Fallthrough */ @@ -493,7 +490,6 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, precision, flags); flags &= ~SPECIAL; break; -#endif #ifdef CONFIG_LIB_UUID case 'U': return uuid_string(buf, end, ptr, field_width, precision, diff --git a/net/Kconfig b/net/Kconfig index 68cecf75a2..a07f6746c5 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -31,7 +31,7 @@ config IP_DEFRAG config TFTP_BLOCKSIZE int "TFTP block size" - default 512 + default 1468 help Default TFTP block size. diff --git a/net/eth-uclass.c b/net/eth-uclass.c index 3bd98b01ad..ed81cbd537 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -227,7 +227,7 @@ static int on_ethaddr(const char *name, const char *value, enum env_op op, switch (op) { case env_op_create: case env_op_overwrite: - eth_parse_enetaddr(value, pdata->enetaddr); + string_to_enetaddr(value, pdata->enetaddr); eth_write_hwaddr(dev); break; case env_op_delete: @@ -420,20 +420,25 @@ int eth_initialize(void) bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); do { - if (num_devices) - printf(", "); + if (dev->seq != -1) { + if (num_devices) + printf(", "); - printf("eth%d: %s", dev->seq, dev->name); + printf("eth%d: %s", dev->seq, dev->name); - if (ethprime && dev == prime_dev) - printf(" [PRIME]"); + if (ethprime && dev == prime_dev) + printf(" [PRIME]"); + } eth_write_hwaddr(dev); + if (dev->seq != -1) + num_devices++; uclass_next_device_check(&dev); - num_devices++; } while (dev); + if (!num_devices) + printf("No ethernet found.\n"); putc('\n'); } diff --git a/net/eth_legacy.c b/net/eth_legacy.c index 41f5263526..5d6b0d7d7f 100644 --- a/net/eth_legacy.c +++ b/net/eth_legacy.c @@ -117,7 +117,7 @@ static int on_ethaddr(const char *name, const char *value, enum env_op op, switch (op) { case env_op_create: case env_op_overwrite: - eth_parse_enetaddr(value, dev->enetaddr); + string_to_enetaddr(value, dev->enetaddr); eth_write_hwaddr(dev, "eth", dev->index); break; case env_op_delete: diff --git a/net/mdio-uclass.c b/net/mdio-uclass.c index 6f922e80b6..f75e4df626 100644 --- a/net/mdio-uclass.c +++ b/net/mdio-uclass.c @@ -10,6 +10,16 @@ #include <dm/device-internal.h> #include <dm/uclass-internal.h> +/* DT node properties for MAC-PHY interface */ +#define PHY_MODE_STR_CNT 2 +static const char *phy_mode_str[PHY_MODE_STR_CNT] = { "phy-mode", + "phy-connection-type" }; +/* DT node properties that reference a PHY node */ +#define PHY_HANDLE_STR_CNT 3 +const char *phy_handle_str[PHY_HANDLE_STR_CNT] = { "phy-handle", + "phy", + "phy-device" }; + void dm_mdio_probe_devices(void) { struct udevice *it; @@ -104,16 +114,96 @@ static int dm_mdio_pre_remove(struct udevice *dev) return 0; } -struct phy_device *dm_mdio_phy_connect(struct udevice *dev, int addr, +struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr, struct udevice *ethdev, phy_interface_t interface) { - struct mdio_perdev_priv *pdata = dev_get_uclass_priv(dev); + struct mdio_perdev_priv *pdata = dev_get_uclass_priv(mdiodev); - if (device_probe(dev)) - return 0; + if (device_probe(mdiodev)) + return NULL; + + return phy_connect(pdata->mii_bus, phyaddr, ethdev, interface); +} + +static struct phy_device *dm_eth_connect_phy_handle(struct udevice *ethdev, + phy_interface_t interface) +{ + u32 phy_addr; + struct udevice *mdiodev; + struct phy_device *phy; + struct ofnode_phandle_args phandle = {.node = ofnode_null()}; + int i; + + for (i = 0; i < PHY_HANDLE_STR_CNT; i++) + if (!dev_read_phandle_with_args(ethdev, phy_handle_str[i], NULL, + 0, 0, &phandle)) + break; + + if (!ofnode_valid(phandle.node)) { + dev_dbg(dev, "can't find PHY node\n"); + return NULL; + } + + /* + * reading 'reg' directly should be fine. This is a PHY node, the + * address is always size 1 and requires no translation + */ + if (ofnode_read_u32(phandle.node, "reg", &phy_addr)) { + dev_dbg(ethdev, "missing reg property in phy node\n"); + return NULL; + } + + if (uclass_get_device_by_ofnode(UCLASS_MDIO, + ofnode_get_parent(phandle.node), + &mdiodev)) { + dev_dbg(dev, "can't find MDIO bus for node %s\n", + ofnode_get_name(ofnode_get_parent(phandle.node))); + return NULL; + } + + phy = dm_mdio_phy_connect(mdiodev, phy_addr, ethdev, interface); + + if (phy) + phy->node = phandle.node; + + return phy; +} + +/* Connect to a PHY linked in eth DT node */ +struct phy_device *dm_eth_phy_connect(struct udevice *ethdev) +{ + const char *if_str; + phy_interface_t interface; + struct phy_device *phy; + int i; + + if (!ofnode_valid(ethdev->node)) { + debug("%s: supplied eth dev has no DT node!\n", ethdev->name); + return NULL; + } + + interface = PHY_INTERFACE_MODE_NONE; + for (i = 0; i < PHY_MODE_STR_CNT; i++) { + if_str = ofnode_read_string(ethdev->node, phy_mode_str[i]); + if (if_str) { + interface = phy_get_interface_by_name(if_str); + break; + } + } + if (interface < 0) + interface = PHY_INTERFACE_MODE_NONE; + if (interface == PHY_INTERFACE_MODE_NONE) + dev_dbg(ethdev, "can't find interface mode, default to NONE\n"); + + phy = dm_eth_connect_phy_handle(ethdev, interface); + + if (!phy) + return NULL; + + phy->interface = interface; - return phy_connect(pdata->mii_bus, addr, ethdev, interface); + return phy; } UCLASS_DRIVER(mdio) = { @@ -308,7 +308,7 @@ U_BOOT_ENV_CALLBACK(dnsip, on_dnsip); */ void net_auto_load(void) { -#if defined(CONFIG_CMD_NFS) +#if defined(CONFIG_CMD_NFS) && !defined(CONFIG_SPL_BUILD) const char *s = env_get("autoload"); if (s != NULL && strcmp(s, "NFS") == 0) { @@ -496,7 +496,7 @@ restart: ping_start(); break; #endif -#if defined(CONFIG_CMD_NFS) +#if defined(CONFIG_CMD_NFS) && !defined(CONFIG_SPL_BUILD) case NFS: nfs_start(); break; @@ -1271,7 +1271,7 @@ void net_process_received_packet(uchar *in_packet, int len) #ifdef CONFIG_UDP_CHECKSUM if (ip->udp_xsum != 0) { ulong xsum; - ushort *sumptr; + u8 *sumptr; ushort sumlen; xsum = ip->ip_p; @@ -1282,22 +1282,16 @@ void net_process_received_packet(uchar *in_packet, int len) xsum += (ntohl(ip->ip_dst.s_addr) >> 0) & 0x0000ffff; sumlen = ntohs(ip->udp_len); - sumptr = (ushort *)&(ip->udp_src); + sumptr = (u8 *)&ip->udp_src; while (sumlen > 1) { - ushort sumdata; - - sumdata = *sumptr++; - xsum += ntohs(sumdata); + /* inlined ntohs() to avoid alignment errors */ + xsum += (sumptr[0] << 8) + sumptr[1]; + sumptr += 2; sumlen -= 2; } - if (sumlen > 0) { - ushort sumdata; - - sumdata = *(unsigned char *)sumptr; - sumdata = (sumdata << 8) & 0xff00; - xsum += sumdata; - } + if (sumlen > 0) + xsum += (sumptr[0] << 8) + sumptr[0]; while ((xsum >> 16) != 0) { xsum = (xsum & 0x0000ffff) + ((xsum >> 16) & 0x0000ffff); @@ -1625,15 +1619,3 @@ ushort env_get_vlan(char *var) { return string_to_vlan(env_get(var)); } - -void eth_parse_enetaddr(const char *addr, uint8_t *enetaddr) -{ - char *end; - int i; - - for (i = 0; i < 6; ++i) { - enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0; - if (addr) - addr = (*end) ? end + 1 : end; - } -} diff --git a/net/tftp.c b/net/tftp.c index 5a69bca641..1e3c18ae69 100644 --- a/net/tftp.c +++ b/net/tftp.c @@ -171,8 +171,13 @@ static inline int store_block(int block, uchar *src, unsigned int len) void *ptr; #ifdef CONFIG_LMB + ulong end_addr = tftp_load_addr + tftp_load_size; + + if (!end_addr) + end_addr = ULONG_MAX; + if (store_addr < tftp_load_addr || - store_addr + len > tftp_load_addr + tftp_load_size) { + store_addr + len > end_addr) { puts("\nTFTP error: "); puts("trying to overwrite reserved memory...\n"); return -1; |