From ffad5fa0cdc55c47bc023e9e0fe55e27b7317ea4 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 31 Oct 2018 16:21:39 -0500 Subject: driver: net: consolidate ti's code in separate folder Add drivers/net/ti/ folder and move all TI's code in this folder for better maintenance. Reviewed-by: Tom Rini Acked-by: Joe Hershberger Signed-off-by: Grygorii Strashko --- arch/arm/mach-davinci/dp83848.c | 2 +- arch/arm/mach-davinci/et1011c.c | 2 +- arch/arm/mach-davinci/ksz8873.c | 2 +- arch/arm/mach-davinci/lxt972.c | 2 +- drivers/net/Kconfig | 12 +- drivers/net/Makefile | 4 +- drivers/net/cpsw-common.c | 121 ---- drivers/net/cpsw.c | 1508 --------------------------------------- drivers/net/davinci_emac.c | 901 ----------------------- drivers/net/davinci_emac.h | 304 -------- drivers/net/keystone_net.c | 1170 ------------------------------ drivers/net/ti/Kconfig | 15 + drivers/net/ti/Makefile | 7 + drivers/net/ti/cpsw-common.c | 121 ++++ drivers/net/ti/cpsw.c | 1508 +++++++++++++++++++++++++++++++++++++++ drivers/net/ti/davinci_emac.c | 901 +++++++++++++++++++++++ drivers/net/ti/davinci_emac.h | 304 ++++++++ drivers/net/ti/keystone_net.c | 1170 ++++++++++++++++++++++++++++++ 18 files changed, 4032 insertions(+), 4022 deletions(-) delete mode 100644 drivers/net/cpsw-common.c delete mode 100644 drivers/net/cpsw.c delete mode 100644 drivers/net/davinci_emac.c delete mode 100644 drivers/net/davinci_emac.h delete mode 100644 drivers/net/keystone_net.c create mode 100644 drivers/net/ti/Kconfig create mode 100644 drivers/net/ti/Makefile create mode 100644 drivers/net/ti/cpsw-common.c create mode 100644 drivers/net/ti/cpsw.c create mode 100644 drivers/net/ti/davinci_emac.c create mode 100644 drivers/net/ti/davinci_emac.h create mode 100644 drivers/net/ti/keystone_net.c diff --git a/arch/arm/mach-davinci/dp83848.c b/arch/arm/mach-davinci/dp83848.c index 595e3ca149b..7115d7bad24 100644 --- a/arch/arm/mach-davinci/dp83848.c +++ b/arch/arm/mach-davinci/dp83848.c @@ -12,7 +12,7 @@ #include #include #include -#include "../../../drivers/net/davinci_emac.h" +#include "../../../drivers/net/ti/davinci_emac.h" #ifdef CONFIG_DRIVER_TI_EMAC diff --git a/arch/arm/mach-davinci/et1011c.c b/arch/arm/mach-davinci/et1011c.c index 3d022748107..bfb7ff26894 100644 --- a/arch/arm/mach-davinci/et1011c.c +++ b/arch/arm/mach-davinci/et1011c.c @@ -9,7 +9,7 @@ #include #include #include -#include "../../../drivers/net/davinci_emac.h" +#include "../../../drivers/net/ti/davinci_emac.h" #ifdef CONFIG_DRIVER_TI_EMAC diff --git a/arch/arm/mach-davinci/ksz8873.c b/arch/arm/mach-davinci/ksz8873.c index 899cff0169a..85b0c2620c9 100644 --- a/arch/arm/mach-davinci/ksz8873.c +++ b/arch/arm/mach-davinci/ksz8873.c @@ -19,7 +19,7 @@ #include #include #include -#include "../../../drivers/net/davinci_emac.h" +#include "../../../drivers/net/ti/davinci_emac.h" int ksz8873_is_phy_connected(int phy_addr) { diff --git a/arch/arm/mach-davinci/lxt972.c b/arch/arm/mach-davinci/lxt972.c index 170e4a57830..b54f67dbfed 100644 --- a/arch/arm/mach-davinci/lxt972.c +++ b/arch/arm/mach-davinci/lxt972.c @@ -13,7 +13,7 @@ #include #include #include -#include "../../../drivers/net/davinci_emac.h" +#include "../../../drivers/net/ti/davinci_emac.h" #ifdef CONFIG_DRIVER_TI_EMAC diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index fd1c48049a9..8fb365fc5d2 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -11,13 +11,6 @@ config DM_ETH This is currently implemented in net/eth-uclass.c Look in include/net.h for details. -config DRIVER_TI_CPSW - bool "TI Common Platform Ethernet Switch" - select PHYLIB - help - This driver supports the TI three port switch gigabit ethernet - subsystem found in the TI SoCs. - menuconfig NETDEVICES bool "Network device support" depends on NET @@ -355,10 +348,7 @@ config SH_ETHER help This driver supports the Ethernet for Renesas SH and ARM SoCs. -config DRIVER_TI_EMAC - bool "TI Davinci EMAC" - help - Support for davinci emac +source "drivers/net/ti/Kconfig" config XILINX_AXIEMAC depends on DM_ETH && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP) diff --git a/drivers/net/Makefile b/drivers/net/Makefile index cc0971c614f..99056aa041d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -30,7 +30,6 @@ obj-$(CONFIG_FTGMAC100) += ftgmac100.o obj-$(CONFIG_FTMAC110) += ftmac110.o obj-$(CONFIG_FTMAC100) += ftmac100.o obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o -obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o obj-$(CONFIG_LAN91C96) += lan91c96.o obj-$(CONFIG_LPC32XX_ETH) += lpc32xx_eth.o @@ -57,9 +56,7 @@ obj-$(CONFIG_SH_ETHER) += sh_eth.o obj-$(CONFIG_RENESAS_RAVB) += ravb.o obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_SMC911X) += smc911x.o -obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o obj-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o -obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o cpsw-common.o obj-$(CONFIG_FMAN_ENET) += fsl_mdio.o obj-$(CONFIG_ULI526X) += uli526x.o obj-$(CONFIG_VSC7385_ENET) += vsc7385.o @@ -74,3 +71,4 @@ obj-$(CONFIG_PIC32_ETH) += pic32_mdio.o pic32_eth.o obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o obj-$(CONFIG_FSL_PFE) += pfe_eth/ obj-$(CONFIG_SNI_AVE) += sni_ave.o +obj-y += ti/ diff --git a/drivers/net/cpsw-common.c b/drivers/net/cpsw-common.c deleted file mode 100644 index 6c8ddbd9361..00000000000 --- a/drivers/net/cpsw-common.c +++ /dev/null @@ -1,121 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * CPSW common - libs used across TI ethernet devices. - * - * Copyright (C) 2016, Texas Instruments, Incorporated - */ - -#include -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -#define CTRL_MAC_REG(offset, id) ((offset) + 0x8 * (id)) - -static int davinci_emac_3517_get_macid(struct udevice *dev, u16 offset, - int slave, u8 *mac_addr) -{ - void *fdt = (void *)gd->fdt_blob; - int node = dev_of_offset(dev); - u32 macid_lsb; - u32 macid_msb; - fdt32_t gmii = 0; - int syscon; - u32 addr; - - syscon = fdtdec_lookup_phandle(fdt, node, "syscon"); - if (syscon < 0) { - pr_err("Syscon offset not found\n"); - return -ENOENT; - } - - addr = (u32)map_physmem(fdt_translate_address(fdt, syscon, &gmii), - sizeof(u32), MAP_NOCACHE); - if (addr == FDT_ADDR_T_NONE) { - pr_err("Not able to get syscon address to get mac efuse address\n"); - return -ENOENT; - } - - addr += CTRL_MAC_REG(offset, slave); - - /* try reading mac address from efuse */ - macid_lsb = readl(addr); - macid_msb = readl(addr + 4); - - mac_addr[0] = (macid_msb >> 16) & 0xff; - mac_addr[1] = (macid_msb >> 8) & 0xff; - mac_addr[2] = macid_msb & 0xff; - mac_addr[3] = (macid_lsb >> 16) & 0xff; - mac_addr[4] = (macid_lsb >> 8) & 0xff; - mac_addr[5] = macid_lsb & 0xff; - - return 0; -} - -static int cpsw_am33xx_cm_get_macid(struct udevice *dev, u16 offset, int slave, - u8 *mac_addr) -{ - void *fdt = (void *)gd->fdt_blob; - int node = dev_of_offset(dev); - u32 macid_lo; - u32 macid_hi; - fdt32_t gmii = 0; - int syscon; - u32 addr; - - syscon = fdtdec_lookup_phandle(fdt, node, "syscon"); - if (syscon < 0) { - pr_err("Syscon offset not found\n"); - return -ENOENT; - } - - addr = (u32)map_physmem(fdt_translate_address(fdt, syscon, &gmii), - sizeof(u32), MAP_NOCACHE); - if (addr == FDT_ADDR_T_NONE) { - pr_err("Not able to get syscon address to get mac efuse address\n"); - return -ENOENT; - } - - addr += CTRL_MAC_REG(offset, slave); - - /* try reading mac address from efuse */ - macid_lo = readl(addr); - macid_hi = readl(addr + 4); - - mac_addr[5] = (macid_lo >> 8) & 0xff; - mac_addr[4] = macid_lo & 0xff; - mac_addr[3] = (macid_hi >> 24) & 0xff; - mac_addr[2] = (macid_hi >> 16) & 0xff; - mac_addr[1] = (macid_hi >> 8) & 0xff; - mac_addr[0] = macid_hi & 0xff; - - return 0; -} - -int ti_cm_get_macid(struct udevice *dev, int slave, u8 *mac_addr) -{ - if (of_machine_is_compatible("ti,dm8148")) - return cpsw_am33xx_cm_get_macid(dev, 0x630, slave, mac_addr); - - if (of_machine_is_compatible("ti,am33xx")) - return cpsw_am33xx_cm_get_macid(dev, 0x630, slave, mac_addr); - - if (device_is_compatible(dev, "ti,am3517-emac")) - return davinci_emac_3517_get_macid(dev, 0x110, slave, mac_addr); - - if (device_is_compatible(dev, "ti,dm816-emac")) - return cpsw_am33xx_cm_get_macid(dev, 0x30, slave, mac_addr); - - if (of_machine_is_compatible("ti,am43")) - return cpsw_am33xx_cm_get_macid(dev, 0x630, slave, mac_addr); - - if (of_machine_is_compatible("ti,dra7")) - return davinci_emac_3517_get_macid(dev, 0x514, slave, mac_addr); - - dev_err(dev, "incompatible machine/device type for reading mac address\n"); - return -ENOENT; -} diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c deleted file mode 100644 index 8e2a48cfd67..00000000000 --- a/drivers/net/cpsw.c +++ /dev/null @@ -1,1508 +0,0 @@ -/* - * CPSW Ethernet Switch Driver - * - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -#define BITMASK(bits) (BIT(bits) - 1) -#define PHY_REG_MASK 0x1f -#define PHY_ID_MASK 0x1f -#define NUM_DESCS (PKTBUFSRX * 2) -#define PKT_MIN 60 -#define PKT_MAX (1500 + 14 + 4 + 4) -#define CLEAR_BIT 1 -#define GIGABITEN BIT(7) -#define FULLDUPLEXEN BIT(0) -#define MIIEN BIT(15) - -/* reg offset */ -#define CPSW_HOST_PORT_OFFSET 0x108 -#define CPSW_SLAVE0_OFFSET 0x208 -#define CPSW_SLAVE1_OFFSET 0x308 -#define CPSW_SLAVE_SIZE 0x100 -#define CPSW_CPDMA_OFFSET 0x800 -#define CPSW_HW_STATS 0x900 -#define CPSW_STATERAM_OFFSET 0xa00 -#define CPSW_CPTS_OFFSET 0xc00 -#define CPSW_ALE_OFFSET 0xd00 -#define CPSW_SLIVER0_OFFSET 0xd80 -#define CPSW_SLIVER1_OFFSET 0xdc0 -#define CPSW_BD_OFFSET 0x2000 -#define CPSW_MDIO_DIV 0xff - -#define AM335X_GMII_SEL_OFFSET 0x630 - -/* DMA Registers */ -#define CPDMA_TXCONTROL 0x004 -#define CPDMA_RXCONTROL 0x014 -#define CPDMA_SOFTRESET 0x01c -#define CPDMA_RXFREE 0x0e0 -#define CPDMA_TXHDP_VER1 0x100 -#define CPDMA_TXHDP_VER2 0x200 -#define CPDMA_RXHDP_VER1 0x120 -#define CPDMA_RXHDP_VER2 0x220 -#define CPDMA_TXCP_VER1 0x140 -#define CPDMA_TXCP_VER2 0x240 -#define CPDMA_RXCP_VER1 0x160 -#define CPDMA_RXCP_VER2 0x260 - -/* Descriptor mode bits */ -#define CPDMA_DESC_SOP BIT(31) -#define CPDMA_DESC_EOP BIT(30) -#define CPDMA_DESC_OWNER BIT(29) -#define CPDMA_DESC_EOQ BIT(28) - -/* - * This timeout definition is a worst-case ultra defensive measure against - * unexpected controller lock ups. Ideally, we should never ever hit this - * scenario in practice. - */ -#define MDIO_TIMEOUT 100 /* msecs */ -#define CPDMA_TIMEOUT 100 /* msecs */ - -struct cpsw_mdio_regs { - u32 version; - u32 control; -#define CONTROL_IDLE BIT(31) -#define CONTROL_ENABLE BIT(30) - - u32 alive; - u32 link; - u32 linkintraw; - u32 linkintmasked; - u32 __reserved_0[2]; - u32 userintraw; - u32 userintmasked; - u32 userintmaskset; - u32 userintmaskclr; - u32 __reserved_1[20]; - - struct { - u32 access; - u32 physel; -#define USERACCESS_GO BIT(31) -#define USERACCESS_WRITE BIT(30) -#define USERACCESS_ACK BIT(29) -#define USERACCESS_READ (0) -#define USERACCESS_DATA (0xffff) - } user[0]; -}; - -struct cpsw_regs { - u32 id_ver; - u32 control; - u32 soft_reset; - u32 stat_port_en; - u32 ptype; -}; - -struct cpsw_slave_regs { - u32 max_blks; - u32 blk_cnt; - u32 flow_thresh; - u32 port_vlan; - u32 tx_pri_map; -#ifdef CONFIG_AM33XX - u32 gap_thresh; -#elif defined(CONFIG_TI814X) - u32 ts_ctl; - u32 ts_seq_ltype; - u32 ts_vlan; -#endif - u32 sa_lo; - u32 sa_hi; -}; - -struct cpsw_host_regs { - u32 max_blks; - u32 blk_cnt; - u32 flow_thresh; - u32 port_vlan; - u32 tx_pri_map; - u32 cpdma_tx_pri_map; - u32 cpdma_rx_chan_map; -}; - -struct cpsw_sliver_regs { - u32 id_ver; - u32 mac_control; - u32 mac_status; - u32 soft_reset; - u32 rx_maxlen; - u32 __reserved_0; - u32 rx_pause; - u32 tx_pause; - u32 __reserved_1; - u32 rx_pri_map; -}; - -#define ALE_ENTRY_BITS 68 -#define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) - -/* ALE Registers */ -#define ALE_CONTROL 0x08 -#define ALE_UNKNOWNVLAN 0x18 -#define ALE_TABLE_CONTROL 0x20 -#define ALE_TABLE 0x34 -#define ALE_PORTCTL 0x40 - -#define ALE_TABLE_WRITE BIT(31) - -#define ALE_TYPE_FREE 0 -#define ALE_TYPE_ADDR 1 -#define ALE_TYPE_VLAN 2 -#define ALE_TYPE_VLAN_ADDR 3 - -#define ALE_UCAST_PERSISTANT 0 -#define ALE_UCAST_UNTOUCHED 1 -#define ALE_UCAST_OUI 2 -#define ALE_UCAST_TOUCHED 3 - -#define ALE_MCAST_FWD 0 -#define ALE_MCAST_BLOCK_LEARN_FWD 1 -#define ALE_MCAST_FWD_LEARN 2 -#define ALE_MCAST_FWD_2 3 - -enum cpsw_ale_port_state { - ALE_PORT_STATE_DISABLE = 0x00, - ALE_PORT_STATE_BLOCK = 0x01, - ALE_PORT_STATE_LEARN = 0x02, - ALE_PORT_STATE_FORWARD = 0x03, -}; - -/* ALE unicast entry flags - passed into cpsw_ale_add_ucast() */ -#define ALE_SECURE 1 -#define ALE_BLOCKED 2 - -struct cpsw_slave { - struct cpsw_slave_regs *regs; - struct cpsw_sliver_regs *sliver; - int slave_num; - u32 mac_control; - struct cpsw_slave_data *data; -}; - -struct cpdma_desc { - /* hardware fields */ - u32 hw_next; - u32 hw_buffer; - u32 hw_len; - u32 hw_mode; - /* software fields */ - u32 sw_buffer; - u32 sw_len; -}; - -struct cpdma_chan { - struct cpdma_desc *head, *tail; - void *hdp, *cp, *rxfree; -}; - -/* AM33xx SoC specific definitions for the CONTROL port */ -#define AM33XX_GMII_SEL_MODE_MII 0 -#define AM33XX_GMII_SEL_MODE_RMII 1 -#define AM33XX_GMII_SEL_MODE_RGMII 2 - -#define AM33XX_GMII_SEL_RGMII1_IDMODE BIT(4) -#define AM33XX_GMII_SEL_RGMII2_IDMODE BIT(5) -#define AM33XX_GMII_SEL_RMII1_IO_CLK_EN BIT(6) -#define AM33XX_GMII_SEL_RMII2_IO_CLK_EN BIT(7) - -#define GMII_SEL_MODE_MASK 0x3 - -#define desc_write(desc, fld, val) __raw_writel((u32)(val), &(desc)->fld) -#define desc_read(desc, fld) __raw_readl(&(desc)->fld) -#define desc_read_ptr(desc, fld) ((void *)__raw_readl(&(desc)->fld)) - -#define chan_write(chan, fld, val) __raw_writel((u32)(val), (chan)->fld) -#define chan_read(chan, fld) __raw_readl((chan)->fld) -#define chan_read_ptr(chan, fld) ((void *)__raw_readl((chan)->fld)) - -#define for_active_slave(slave, priv) \ - slave = (priv)->slaves + (priv)->data.active_slave; if (slave) -#define for_each_slave(slave, priv) \ - for (slave = (priv)->slaves; slave != (priv)->slaves + \ - (priv)->data.slaves; slave++) - -struct cpsw_priv { -#ifdef CONFIG_DM_ETH - struct udevice *dev; -#else - struct eth_device *dev; -#endif - struct cpsw_platform_data data; - int host_port; - - struct cpsw_regs *regs; - void *dma_regs; - struct cpsw_host_regs *host_port_regs; - void *ale_regs; - - struct cpdma_desc *descs; - struct cpdma_desc *desc_free; - struct cpdma_chan rx_chan, tx_chan; - - struct cpsw_slave *slaves; - struct phy_device *phydev; - struct mii_dev *bus; - - u32 phy_mask; -}; - -static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) -{ - int idx; - - idx = start / 32; - start -= idx * 32; - idx = 2 - idx; /* flip */ - return (ale_entry[idx] >> start) & BITMASK(bits); -} - -static inline void cpsw_ale_set_field(u32 *ale_entry, u32 start, u32 bits, - u32 value) -{ - int idx; - - value &= BITMASK(bits); - idx = start / 32; - start -= idx * 32; - idx = 2 - idx; /* flip */ - ale_entry[idx] &= ~(BITMASK(bits) << start); - ale_entry[idx] |= (value << start); -} - -#define DEFINE_ALE_FIELD(name, start, bits) \ -static inline int cpsw_ale_get_##name(u32 *ale_entry) \ -{ \ - return cpsw_ale_get_field(ale_entry, start, bits); \ -} \ -static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value) \ -{ \ - cpsw_ale_set_field(ale_entry, start, bits, value); \ -} - -DEFINE_ALE_FIELD(entry_type, 60, 2) -DEFINE_ALE_FIELD(mcast_state, 62, 2) -DEFINE_ALE_FIELD(port_mask, 66, 3) -DEFINE_ALE_FIELD(ucast_type, 62, 2) -DEFINE_ALE_FIELD(port_num, 66, 2) -DEFINE_ALE_FIELD(blocked, 65, 1) -DEFINE_ALE_FIELD(secure, 64, 1) -DEFINE_ALE_FIELD(mcast, 40, 1) - -/* The MAC address field in the ALE entry cannot be macroized as above */ -static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr) -{ - int i; - - for (i = 0; i < 6; i++) - addr[i] = cpsw_ale_get_field(ale_entry, 40 - 8*i, 8); -} - -static inline void cpsw_ale_set_addr(u32 *ale_entry, const u8 *addr) -{ - int i; - - for (i = 0; i < 6; i++) - cpsw_ale_set_field(ale_entry, 40 - 8*i, 8, addr[i]); -} - -static int cpsw_ale_read(struct cpsw_priv *priv, int idx, u32 *ale_entry) -{ - int i; - - __raw_writel(idx, priv->ale_regs + ALE_TABLE_CONTROL); - - for (i = 0; i < ALE_ENTRY_WORDS; i++) - ale_entry[i] = __raw_readl(priv->ale_regs + ALE_TABLE + 4 * i); - - return idx; -} - -static int cpsw_ale_write(struct cpsw_priv *priv, int idx, u32 *ale_entry) -{ - int i; - - for (i = 0; i < ALE_ENTRY_WORDS; i++) - __raw_writel(ale_entry[i], priv->ale_regs + ALE_TABLE + 4 * i); - - __raw_writel(idx | ALE_TABLE_WRITE, priv->ale_regs + ALE_TABLE_CONTROL); - - return idx; -} - -static int cpsw_ale_match_addr(struct cpsw_priv *priv, const u8 *addr) -{ - u32 ale_entry[ALE_ENTRY_WORDS]; - int type, idx; - - for (idx = 0; idx < priv->data.ale_entries; idx++) { - u8 entry_addr[6]; - - cpsw_ale_read(priv, idx, ale_entry); - type = cpsw_ale_get_entry_type(ale_entry); - if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR) - continue; - cpsw_ale_get_addr(ale_entry, entry_addr); - if (memcmp(entry_addr, addr, 6) == 0) - return idx; - } - return -ENOENT; -} - -static int cpsw_ale_match_free(struct cpsw_priv *priv) -{ - u32 ale_entry[ALE_ENTRY_WORDS]; - int type, idx; - - for (idx = 0; idx < priv->data.ale_entries; idx++) { - cpsw_ale_read(priv, idx, ale_entry); - type = cpsw_ale_get_entry_type(ale_entry); - if (type == ALE_TYPE_FREE) - return idx; - } - return -ENOENT; -} - -static int cpsw_ale_find_ageable(struct cpsw_priv *priv) -{ - u32 ale_entry[ALE_ENTRY_WORDS]; - int type, idx; - - for (idx = 0; idx < priv->data.ale_entries; idx++) { - cpsw_ale_read(priv, idx, ale_entry); - type = cpsw_ale_get_entry_type(ale_entry); - if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR) - continue; - if (cpsw_ale_get_mcast(ale_entry)) - continue; - type = cpsw_ale_get_ucast_type(ale_entry); - if (type != ALE_UCAST_PERSISTANT && - type != ALE_UCAST_OUI) - return idx; - } - return -ENOENT; -} - -static int cpsw_ale_add_ucast(struct cpsw_priv *priv, const u8 *addr, - int port, int flags) -{ - u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; - int idx; - - cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR); - cpsw_ale_set_addr(ale_entry, addr); - cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT); - cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0); - cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); - cpsw_ale_set_port_num(ale_entry, port); - - idx = cpsw_ale_match_addr(priv, addr); - if (idx < 0) - idx = cpsw_ale_match_free(priv); - if (idx < 0) - idx = cpsw_ale_find_ageable(priv); - if (idx < 0) - return -ENOMEM; - - cpsw_ale_write(priv, idx, ale_entry); - return 0; -} - -static int cpsw_ale_add_mcast(struct cpsw_priv *priv, const u8 *addr, - int port_mask) -{ - u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; - int idx, mask; - - idx = cpsw_ale_match_addr(priv, addr); - if (idx >= 0) - cpsw_ale_read(priv, idx, ale_entry); - - cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR); - cpsw_ale_set_addr(ale_entry, addr); - cpsw_ale_set_mcast_state(ale_entry, ALE_MCAST_FWD_2); - - mask = cpsw_ale_get_port_mask(ale_entry); - port_mask |= mask; - cpsw_ale_set_port_mask(ale_entry, port_mask); - - if (idx < 0) - idx = cpsw_ale_match_free(priv); - if (idx < 0) - idx = cpsw_ale_find_ageable(priv); - if (idx < 0) - return -ENOMEM; - - cpsw_ale_write(priv, idx, ale_entry); - return 0; -} - -static inline void cpsw_ale_control(struct cpsw_priv *priv, int bit, int val) -{ - u32 tmp, mask = BIT(bit); - - tmp = __raw_readl(priv->ale_regs + ALE_CONTROL); - tmp &= ~mask; - tmp |= val ? mask : 0; - __raw_writel(tmp, priv->ale_regs + ALE_CONTROL); -} - -#define cpsw_ale_enable(priv, val) cpsw_ale_control(priv, 31, val) -#define cpsw_ale_clear(priv, val) cpsw_ale_control(priv, 30, val) -#define cpsw_ale_vlan_aware(priv, val) cpsw_ale_control(priv, 2, val) - -static inline void cpsw_ale_port_state(struct cpsw_priv *priv, int port, - int val) -{ - int offset = ALE_PORTCTL + 4 * port; - u32 tmp, mask = 0x3; - - tmp = __raw_readl(priv->ale_regs + offset); - tmp &= ~mask; - tmp |= val & mask; - __raw_writel(tmp, priv->ale_regs + offset); -} - -static struct cpsw_mdio_regs *mdio_regs; - -/* wait until hardware is ready for another user access */ -static inline u32 wait_for_user_access(void) -{ - u32 reg = 0; - int timeout = MDIO_TIMEOUT; - - while (timeout-- && - ((reg = __raw_readl(&mdio_regs->user[0].access)) & USERACCESS_GO)) - udelay(10); - - if (timeout == -1) { - printf("wait_for_user_access Timeout\n"); - return -ETIMEDOUT; - } - return reg; -} - -/* wait until hardware state machine is idle */ -static inline void wait_for_idle(void) -{ - int timeout = MDIO_TIMEOUT; - - while (timeout-- && - ((__raw_readl(&mdio_regs->control) & CONTROL_IDLE) == 0)) - udelay(10); - - if (timeout == -1) - printf("wait_for_idle Timeout\n"); -} - -static int cpsw_mdio_read(struct mii_dev *bus, int phy_id, - int dev_addr, int phy_reg) -{ - int data; - u32 reg; - - if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK) - return -EINVAL; - - wait_for_user_access(); - reg = (USERACCESS_GO | USERACCESS_READ | (phy_reg << 21) | - (phy_id << 16)); - __raw_writel(reg, &mdio_regs->user[0].access); - reg = wait_for_user_access(); - - data = (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -1; - return data; -} - -static int cpsw_mdio_write(struct mii_dev *bus, int phy_id, int dev_addr, - int phy_reg, u16 data) -{ - u32 reg; - - if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK) - return -EINVAL; - - wait_for_user_access(); - reg = (USERACCESS_GO | USERACCESS_WRITE | (phy_reg << 21) | - (phy_id << 16) | (data & USERACCESS_DATA)); - __raw_writel(reg, &mdio_regs->user[0].access); - wait_for_user_access(); - - return 0; -} - -static void cpsw_mdio_init(const char *name, u32 mdio_base, u32 div) -{ - struct mii_dev *bus = mdio_alloc(); - - mdio_regs = (struct cpsw_mdio_regs *)mdio_base; - - /* set enable and clock divider */ - __raw_writel(div | CONTROL_ENABLE, &mdio_regs->control); - - /* - * wait for scan logic to settle: - * the scan time consists of (a) a large fixed component, and (b) a - * small component that varies with the mii bus frequency. These - * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x - * silicon. Since the effect of (b) was found to be largely - * negligible, we keep things simple here. - */ - udelay(1000); - - bus->read = cpsw_mdio_read; - bus->write = cpsw_mdio_write; - strcpy(bus->name, name); - - mdio_register(bus); -} - -/* Set a self-clearing bit in a register, and wait for it to clear */ -static inline void setbit_and_wait_for_clear32(void *addr) -{ - __raw_writel(CLEAR_BIT, addr); - while (__raw_readl(addr) & CLEAR_BIT) - ; -} - -#define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \ - ((mac)[2] << 16) | ((mac)[3] << 24)) -#define mac_lo(mac) (((mac)[4] << 0) | ((mac)[5] << 8)) - -static void cpsw_set_slave_mac(struct cpsw_slave *slave, - struct cpsw_priv *priv) -{ -#ifdef CONFIG_DM_ETH - struct eth_pdata *pdata = dev_get_platdata(priv->dev); - - writel(mac_hi(pdata->enetaddr), &slave->regs->sa_hi); - writel(mac_lo(pdata->enetaddr), &slave->regs->sa_lo); -#else - __raw_writel(mac_hi(priv->dev->enetaddr), &slave->regs->sa_hi); - __raw_writel(mac_lo(priv->dev->enetaddr), &slave->regs->sa_lo); -#endif -} - -static int cpsw_slave_update_link(struct cpsw_slave *slave, - struct cpsw_priv *priv, int *link) -{ - struct phy_device *phy; - u32 mac_control = 0; - int ret = -ENODEV; - - phy = priv->phydev; - if (!phy) - goto out; - - ret = phy_startup(phy); - if (ret) - goto out; - - if (link) - *link = phy->link; - - if (phy->link) { /* link up */ - mac_control = priv->data.mac_control; - if (phy->speed == 1000) - mac_control |= GIGABITEN; - if (phy->duplex == DUPLEX_FULL) - mac_control |= FULLDUPLEXEN; - if (phy->speed == 100) - mac_control |= MIIEN; - } - - if (mac_control == slave->mac_control) - goto out; - - if (mac_control) { - printf("link up on port %d, speed %d, %s duplex\n", - slave->slave_num, phy->speed, - (phy->duplex == DUPLEX_FULL) ? "full" : "half"); - } else { - printf("link down on port %d\n", slave->slave_num); - } - - __raw_writel(mac_control, &slave->sliver->mac_control); - slave->mac_control = mac_control; - -out: - return ret; -} - -static int cpsw_update_link(struct cpsw_priv *priv) -{ - int ret = -ENODEV; - struct cpsw_slave *slave; - - for_active_slave(slave, priv) - ret = cpsw_slave_update_link(slave, priv, NULL); - - return ret; -} - -static inline u32 cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num) -{ - if (priv->host_port == 0) - return slave_num + 1; - else - return slave_num; -} - -static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv) -{ - u32 slave_port; - - setbit_and_wait_for_clear32(&slave->sliver->soft_reset); - - /* setup priority mapping */ - __raw_writel(0x76543210, &slave->sliver->rx_pri_map); - __raw_writel(0x33221100, &slave->regs->tx_pri_map); - - /* setup max packet size, and mac address */ - __raw_writel(PKT_MAX, &slave->sliver->rx_maxlen); - cpsw_set_slave_mac(slave, priv); - - slave->mac_control = 0; /* no link yet */ - - /* enable forwarding */ - slave_port = cpsw_get_slave_port(priv, slave->slave_num); - cpsw_ale_port_state(priv, slave_port, ALE_PORT_STATE_FORWARD); - - cpsw_ale_add_mcast(priv, net_bcast_ethaddr, 1 << slave_port); - - priv->phy_mask |= 1 << slave->data->phy_addr; -} - -static struct cpdma_desc *cpdma_desc_alloc(struct cpsw_priv *priv) -{ - struct cpdma_desc *desc = priv->desc_free; - - if (desc) - priv->desc_free = desc_read_ptr(desc, hw_next); - return desc; -} - -static void cpdma_desc_free(struct cpsw_priv *priv, struct cpdma_desc *desc) -{ - if (desc) { - desc_write(desc, hw_next, priv->desc_free); - priv->desc_free = desc; - } -} - -static int cpdma_submit(struct cpsw_priv *priv, struct cpdma_chan *chan, - void *buffer, int len) -{ - struct cpdma_desc *desc, *prev; - u32 mode; - - desc = cpdma_desc_alloc(priv); - if (!desc) - return -ENOMEM; - - if (len < PKT_MIN) - len = PKT_MIN; - - mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP; - - desc_write(desc, hw_next, 0); - desc_write(desc, hw_buffer, buffer); - desc_write(desc, hw_len, len); - desc_write(desc, hw_mode, mode | len); - desc_write(desc, sw_buffer, buffer); - desc_write(desc, sw_len, len); - - if (!chan->head) { - /* simple case - first packet enqueued */ - chan->head = desc; - chan->tail = desc; - chan_write(chan, hdp, desc); - goto done; - } - - /* not the first packet - enqueue at the tail */ - prev = chan->tail; - desc_write(prev, hw_next, desc); - chan->tail = desc; - - /* next check if EOQ has been triggered already */ - if (desc_read(prev, hw_mode) & CPDMA_DESC_EOQ) - chan_write(chan, hdp, desc); - -done: - if (chan->rxfree) - chan_write(chan, rxfree, 1); - return 0; -} - -static int cpdma_process(struct cpsw_priv *priv, struct cpdma_chan *chan, - void **buffer, int *len) -{ - struct cpdma_desc *desc = chan->head; - u32 status; - - if (!desc) - return -ENOENT; - - status = desc_read(desc, hw_mode); - - if (len) - *len = status & 0x7ff; - - if (buffer) - *buffer = desc_read_ptr(desc, sw_buffer); - - if (status & CPDMA_DESC_OWNER) { - if (chan_read(chan, hdp) == 0) { - if (desc_read(desc, hw_mode) & CPDMA_DESC_OWNER) - chan_write(chan, hdp, desc); - } - - return -EBUSY; - } - - chan->head = desc_read_ptr(desc, hw_next); - chan_write(chan, cp, desc); - - cpdma_desc_free(priv, desc); - return 0; -} - -static int _cpsw_init(struct cpsw_priv *priv, u8 *enetaddr) -{ - struct cpsw_slave *slave; - int i, ret; - - /* soft reset the controller and initialize priv */ - setbit_and_wait_for_clear32(&priv->regs->soft_reset); - - /* initialize and reset the address lookup engine */ - cpsw_ale_enable(priv, 1); - cpsw_ale_clear(priv, 1); - cpsw_ale_vlan_aware(priv, 0); /* vlan unaware mode */ - - /* setup host port priority mapping */ - __raw_writel(0x76543210, &priv->host_port_regs->cpdma_tx_pri_map); - __raw_writel(0, &priv->host_port_regs->cpdma_rx_chan_map); - - /* disable priority elevation and enable statistics on all ports */ - __raw_writel(0, &priv->regs->ptype); - - /* enable statistics collection only on the host port */ - __raw_writel(BIT(priv->host_port), &priv->regs->stat_port_en); - __raw_writel(0x7, &priv->regs->stat_port_en); - - cpsw_ale_port_state(priv, priv->host_port, ALE_PORT_STATE_FORWARD); - - cpsw_ale_add_ucast(priv, enetaddr, priv->host_port, ALE_SECURE); - cpsw_ale_add_mcast(priv, net_bcast_ethaddr, 1 << priv->host_port); - - for_active_slave(slave, priv) - cpsw_slave_init(slave, priv); - - ret = cpsw_update_link(priv); - if (ret) - goto out; - - /* init descriptor pool */ - for (i = 0; i < NUM_DESCS; i++) { - desc_write(&priv->descs[i], hw_next, - (i == (NUM_DESCS - 1)) ? 0 : &priv->descs[i+1]); - } - priv->desc_free = &priv->descs[0]; - - /* initialize channels */ - if (priv->data.version == CPSW_CTRL_VERSION_2) { - memset(&priv->rx_chan, 0, sizeof(struct cpdma_chan)); - priv->rx_chan.hdp = priv->dma_regs + CPDMA_RXHDP_VER2; - priv->rx_chan.cp = priv->dma_regs + CPDMA_RXCP_VER2; - priv->rx_chan.rxfree = priv->dma_regs + CPDMA_RXFREE; - - memset(&priv->tx_chan, 0, sizeof(struct cpdma_chan)); - priv->tx_chan.hdp = priv->dma_regs + CPDMA_TXHDP_VER2; - priv->tx_chan.cp = priv->dma_regs + CPDMA_TXCP_VER2; - } else { - memset(&priv->rx_chan, 0, sizeof(struct cpdma_chan)); - priv->rx_chan.hdp = priv->dma_regs + CPDMA_RXHDP_VER1; - priv->rx_chan.cp = priv->dma_regs + CPDMA_RXCP_VER1; - priv->rx_chan.rxfree = priv->dma_regs + CPDMA_RXFREE; - - memset(&priv->tx_chan, 0, sizeof(struct cpdma_chan)); - priv->tx_chan.hdp = priv->dma_regs + CPDMA_TXHDP_VER1; - priv->tx_chan.cp = priv->dma_regs + CPDMA_TXCP_VER1; - } - - /* clear dma state */ - setbit_and_wait_for_clear32(priv->dma_regs + CPDMA_SOFTRESET); - - if (priv->data.version == CPSW_CTRL_VERSION_2) { - for (i = 0; i < priv->data.channels; i++) { - __raw_writel(0, priv->dma_regs + CPDMA_RXHDP_VER2 + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_RXFREE + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_RXCP_VER2 + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_TXHDP_VER2 + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_TXCP_VER2 + 4 - * i); - } - } else { - for (i = 0; i < priv->data.channels; i++) { - __raw_writel(0, priv->dma_regs + CPDMA_RXHDP_VER1 + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_RXFREE + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_RXCP_VER1 + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_TXHDP_VER1 + 4 - * i); - __raw_writel(0, priv->dma_regs + CPDMA_TXCP_VER1 + 4 - * i); - - } - } - - __raw_writel(1, priv->dma_regs + CPDMA_TXCONTROL); - __raw_writel(1, priv->dma_regs + CPDMA_RXCONTROL); - - /* submit rx descs */ - for (i = 0; i < PKTBUFSRX; i++) { - ret = cpdma_submit(priv, &priv->rx_chan, net_rx_packets[i], - PKTSIZE); - if (ret < 0) { - printf("error %d submitting rx desc\n", ret); - break; - } - } - -out: - return ret; -} - -static int cpsw_reap_completed_packets(struct cpsw_priv *priv) -{ - int timeout = CPDMA_TIMEOUT; - - /* reap completed packets */ - while (timeout-- && - (cpdma_process(priv, &priv->tx_chan, NULL, NULL) >= 0)) - ; - - return timeout; -} - -static void _cpsw_halt(struct cpsw_priv *priv) -{ - cpsw_reap_completed_packets(priv); - - writel(0, priv->dma_regs + CPDMA_TXCONTROL); - writel(0, priv->dma_regs + CPDMA_RXCONTROL); - - /* soft reset the controller and initialize priv */ - setbit_and_wait_for_clear32(&priv->regs->soft_reset); - - /* clear dma state */ - setbit_and_wait_for_clear32(priv->dma_regs + CPDMA_SOFTRESET); - -} - -static int _cpsw_send(struct cpsw_priv *priv, void *packet, int length) -{ - int timeout; - - flush_dcache_range((unsigned long)packet, - (unsigned long)packet + ALIGN(length, PKTALIGN)); - - timeout = cpsw_reap_completed_packets(priv); - if (timeout == -1) { - printf("cpdma_process timeout\n"); - return -ETIMEDOUT; - } - - return cpdma_submit(priv, &priv->tx_chan, packet, length); -} - -static int _cpsw_recv(struct cpsw_priv *priv, uchar **pkt) -{ - void *buffer; - int len; - int ret; - - ret = cpdma_process(priv, &priv->rx_chan, &buffer, &len); - if (ret < 0) - return ret; - - invalidate_dcache_range((unsigned long)buffer, - (unsigned long)buffer + PKTSIZE_ALIGN); - *pkt = buffer; - - return len; -} - -static void cpsw_slave_setup(struct cpsw_slave *slave, int slave_num, - struct cpsw_priv *priv) -{ - void *regs = priv->regs; - struct cpsw_slave_data *data = priv->data.slave_data + slave_num; - slave->slave_num = slave_num; - slave->data = data; - slave->regs = regs + data->slave_reg_ofs; - slave->sliver = regs + data->sliver_reg_ofs; -} - -static int cpsw_phy_init(struct cpsw_priv *priv, struct cpsw_slave *slave) -{ - struct phy_device *phydev; - u32 supported = PHY_GBIT_FEATURES; - - phydev = phy_connect(priv->bus, - slave->data->phy_addr, - priv->dev, - slave->data->phy_if); - - if (!phydev) - return -1; - - phydev->supported &= supported; - phydev->advertising = phydev->supported; - -#ifdef CONFIG_DM_ETH - if (slave->data->phy_of_handle) - phydev->node = offset_to_ofnode(slave->data->phy_of_handle); -#endif - - priv->phydev = phydev; - phy_config(phydev); - - return 1; -} - -static void cpsw_phy_addr_update(struct cpsw_priv *priv) -{ - struct cpsw_platform_data *data = &priv->data; - u16 alive = mdio_regs->alive & GENMASK(15, 0); - int active = data->active_slave; - int new_addr = ffs(alive) - 1; - - /* - * If there is only one phy alive and its address does not match - * that of active slave, then phy address can safely be updated. - */ - if (hweight16(alive) == 1 && - data->slave_data[active].phy_addr != new_addr) { - printf("Updated phy address for CPSW#%d, old: %d, new: %d\n", - active, data->slave_data[active].phy_addr, new_addr); - data->slave_data[active].phy_addr = new_addr; - } -} - -int _cpsw_register(struct cpsw_priv *priv) -{ - struct cpsw_slave *slave; - struct cpsw_platform_data *data = &priv->data; - void *regs = (void *)data->cpsw_base; - - priv->slaves = malloc(sizeof(struct cpsw_slave) * data->slaves); - if (!priv->slaves) { - return -ENOMEM; - } - - priv->host_port = data->host_port_num; - priv->regs = regs; - priv->host_port_regs = regs + data->host_port_reg_ofs; - priv->dma_regs = regs + data->cpdma_reg_ofs; - priv->ale_regs = regs + data->ale_reg_ofs; - priv->descs = (void *)regs + data->bd_ram_ofs; - - int idx = 0; - - for_each_slave(slave, priv) { - cpsw_slave_setup(slave, idx, priv); - idx = idx + 1; - } - - cpsw_mdio_init(priv->dev->name, data->mdio_base, data->mdio_div); - - cpsw_phy_addr_update(priv); - - priv->bus = miiphy_get_dev_by_name(priv->dev->name); - for_active_slave(slave, priv) - cpsw_phy_init(priv, slave); - - return 0; -} - -#ifndef CONFIG_DM_ETH -static int cpsw_init(struct eth_device *dev, bd_t *bis) -{ - struct cpsw_priv *priv = dev->priv; - - return _cpsw_init(priv, dev->enetaddr); -} - -static void cpsw_halt(struct eth_device *dev) -{ - struct cpsw_priv *priv = dev->priv; - - return _cpsw_halt(priv); -} - -static int cpsw_send(struct eth_device *dev, void *packet, int length) -{ - struct cpsw_priv *priv = dev->priv; - - return _cpsw_send(priv, packet, length); -} - -static int cpsw_recv(struct eth_device *dev) -{ - struct cpsw_priv *priv = dev->priv; - uchar *pkt = NULL; - int len; - - len = _cpsw_recv(priv, &pkt); - - if (len > 0) { - net_process_received_packet(pkt, len); - cpdma_submit(priv, &priv->rx_chan, pkt, PKTSIZE); - } - - return len; -} - -int cpsw_register(struct cpsw_platform_data *data) -{ - struct cpsw_priv *priv; - struct eth_device *dev; - int ret; - - dev = calloc(sizeof(*dev), 1); - if (!dev) - return -ENOMEM; - - priv = calloc(sizeof(*priv), 1); - if (!priv) { - free(dev); - return -ENOMEM; - } - - priv->dev = dev; - priv->data = *data; - - strcpy(dev->name, "cpsw"); - dev->iobase = 0; - dev->init = cpsw_init; - dev->halt = cpsw_halt; - dev->send = cpsw_send; - dev->recv = cpsw_recv; - dev->priv = priv; - - eth_register(dev); - - ret = _cpsw_register(priv); - if (ret < 0) { - eth_unregister(dev); - free(dev); - free(priv); - return ret; - } - - return 1; -} -#else -static int cpsw_eth_start(struct udevice *dev) -{ - struct eth_pdata *pdata = dev_get_platdata(dev); - struct cpsw_priv *priv = dev_get_priv(dev); - - return _cpsw_init(priv, pdata->enetaddr); -} - -static int cpsw_eth_send(struct udevice *dev, void *packet, int length) -{ - struct cpsw_priv *priv = dev_get_priv(dev); - - return _cpsw_send(priv, packet, length); -} - -static int cpsw_eth_recv(struct udevice *dev, int flags, uchar **packetp) -{ - struct cpsw_priv *priv = dev_get_priv(dev); - - return _cpsw_recv(priv, packetp); -} - -static int cpsw_eth_free_pkt(struct udevice *dev, uchar *packet, - int length) -{ - struct cpsw_priv *priv = dev_get_priv(dev); - - return cpdma_submit(priv, &priv->rx_chan, packet, PKTSIZE); -} - -static void cpsw_eth_stop(struct udevice *dev) -{ - struct cpsw_priv *priv = dev_get_priv(dev); - - return _cpsw_halt(priv); -} - - -static int cpsw_eth_probe(struct udevice *dev) -{ - struct cpsw_priv *priv = dev_get_priv(dev); - - priv->dev = dev; - - return _cpsw_register(priv); -} - -static const struct eth_ops cpsw_eth_ops = { - .start = cpsw_eth_start, - .send = cpsw_eth_send, - .recv = cpsw_eth_recv, - .free_pkt = cpsw_eth_free_pkt, - .stop = cpsw_eth_stop, -}; - -static inline fdt_addr_t cpsw_get_addr_by_node(const void *fdt, int node) -{ - return fdtdec_get_addr_size_auto_noparent(fdt, node, "reg", 0, NULL, - false); -} - -static void cpsw_gmii_sel_am3352(struct cpsw_priv *priv, - phy_interface_t phy_mode) -{ - u32 reg; - u32 mask; - u32 mode = 0; - bool rgmii_id = false; - int slave = priv->data.active_slave; - - reg = readl(priv->data.gmii_sel); - - switch (phy_mode) { - case PHY_INTERFACE_MODE_RMII: - mode = AM33XX_GMII_SEL_MODE_RMII; - break; - - case PHY_INTERFACE_MODE_RGMII: - mode = AM33XX_GMII_SEL_MODE_RGMII; - break; - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_TXID: - mode = AM33XX_GMII_SEL_MODE_RGMII; - rgmii_id = true; - break; - - case PHY_INTERFACE_MODE_MII: - default: - mode = AM33XX_GMII_SEL_MODE_MII; - break; - }; - - mask = GMII_SEL_MODE_MASK << (slave * 2) | BIT(slave + 6); - mode <<= slave * 2; - - if (priv->data.rmii_clock_external) { - if (slave == 0) - mode |= AM33XX_GMII_SEL_RMII1_IO_CLK_EN; - else - mode |= AM33XX_GMII_SEL_RMII2_IO_CLK_EN; - } - - if (rgmii_id) { - if (slave == 0) - mode |= AM33XX_GMII_SEL_RGMII1_IDMODE; - else - mode |= AM33XX_GMII_SEL_RGMII2_IDMODE; - } - - reg &= ~mask; - reg |= mode; - - writel(reg, priv->data.gmii_sel); -} - -static void cpsw_gmii_sel_dra7xx(struct cpsw_priv *priv, - phy_interface_t phy_mode) -{ - u32 reg; - u32 mask; - u32 mode = 0; - int slave = priv->data.active_slave; - - reg = readl(priv->data.gmii_sel); - - switch (phy_mode) { - case PHY_INTERFACE_MODE_RMII: - mode = AM33XX_GMII_SEL_MODE_RMII; - break; - - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_TXID: - mode = AM33XX_GMII_SEL_MODE_RGMII; - break; - - case PHY_INTERFACE_MODE_MII: - default: - mode = AM33XX_GMII_SEL_MODE_MII; - break; - }; - - switch (slave) { - case 0: - mask = GMII_SEL_MODE_MASK; - break; - case 1: - mask = GMII_SEL_MODE_MASK << 4; - mode <<= 4; - break; - default: - dev_err(priv->dev, "invalid slave number...\n"); - return; - } - - if (priv->data.rmii_clock_external) - dev_err(priv->dev, "RMII External clock is not supported\n"); - - reg &= ~mask; - reg |= mode; - - writel(reg, priv->data.gmii_sel); -} - -static void cpsw_phy_sel(struct cpsw_priv *priv, const char *compat, - phy_interface_t phy_mode) -{ - if (!strcmp(compat, "ti,am3352-cpsw-phy-sel")) - cpsw_gmii_sel_am3352(priv, phy_mode); - if (!strcmp(compat, "ti,am43xx-cpsw-phy-sel")) - cpsw_gmii_sel_am3352(priv, phy_mode); - else if (!strcmp(compat, "ti,dra7xx-cpsw-phy-sel")) - cpsw_gmii_sel_dra7xx(priv, phy_mode); -} - -static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) -{ - struct eth_pdata *pdata = dev_get_platdata(dev); - struct cpsw_priv *priv = dev_get_priv(dev); - struct gpio_desc *mode_gpios; - const char *phy_mode; - const char *phy_sel_compat = NULL; - const void *fdt = gd->fdt_blob; - int node = dev_of_offset(dev); - int subnode; - int slave_index = 0; - int active_slave; - int num_mode_gpios; - int ret; - - pdata->iobase = devfdt_get_addr(dev); - priv->data.version = CPSW_CTRL_VERSION_2; - priv->data.bd_ram_ofs = CPSW_BD_OFFSET; - priv->data.ale_reg_ofs = CPSW_ALE_OFFSET; - priv->data.cpdma_reg_ofs = CPSW_CPDMA_OFFSET; - priv->data.mdio_div = CPSW_MDIO_DIV; - priv->data.host_port_reg_ofs = CPSW_HOST_PORT_OFFSET, - - pdata->phy_interface = -1; - - priv->data.cpsw_base = pdata->iobase; - priv->data.channels = fdtdec_get_int(fdt, node, "cpdma_channels", -1); - if (priv->data.channels <= 0) { - printf("error: cpdma_channels not found in dt\n"); - return -ENOENT; - } - - priv->data.slaves = fdtdec_get_int(fdt, node, "slaves", -1); - if (priv->data.slaves <= 0) { - printf("error: slaves not found in dt\n"); - return -ENOENT; - } - priv->data.slave_data = malloc(sizeof(struct cpsw_slave_data) * - priv->data.slaves); - - priv->data.ale_entries = fdtdec_get_int(fdt, node, "ale_entries", -1); - if (priv->data.ale_entries <= 0) { - printf("error: ale_entries not found in dt\n"); - return -ENOENT; - } - - priv->data.bd_ram_ofs = fdtdec_get_int(fdt, node, "bd_ram_size", -1); - if (priv->data.bd_ram_ofs <= 0) { - printf("error: bd_ram_size not found in dt\n"); - return -ENOENT; - } - - priv->data.mac_control = fdtdec_get_int(fdt, node, "mac_control", -1); - if (priv->data.mac_control <= 0) { - printf("error: ale_entries not found in dt\n"); - return -ENOENT; - } - - num_mode_gpios = gpio_get_list_count(dev, "mode-gpios"); - if (num_mode_gpios > 0) { - mode_gpios = malloc(sizeof(struct gpio_desc) * - num_mode_gpios); - gpio_request_list_by_name(dev, "mode-gpios", mode_gpios, - num_mode_gpios, GPIOD_IS_OUT); - free(mode_gpios); - } - - active_slave = fdtdec_get_int(fdt, node, "active_slave", 0); - priv->data.active_slave = active_slave; - - fdt_for_each_subnode(subnode, fdt, node) { - int len; - const char *name; - - name = fdt_get_name(fdt, subnode, &len); - if (!strncmp(name, "mdio", 4)) { - u32 mdio_base; - - mdio_base = cpsw_get_addr_by_node(fdt, subnode); - if (mdio_base == FDT_ADDR_T_NONE) { - pr_err("Not able to get MDIO address space\n"); - return -ENOENT; - } - priv->data.mdio_base = mdio_base; - } - - if (!strncmp(name, "slave", 5)) { - u32 phy_id[2]; - - if (slave_index >= priv->data.slaves) - continue; - phy_mode = fdt_getprop(fdt, subnode, "phy-mode", NULL); - if (phy_mode) - priv->data.slave_data[slave_index].phy_if = - phy_get_interface_by_name(phy_mode); - - priv->data.slave_data[slave_index].phy_of_handle = - fdtdec_lookup_phandle(fdt, subnode, - "phy-handle"); - - if (priv->data.slave_data[slave_index].phy_of_handle >= 0) { - priv->data.slave_data[slave_index].phy_addr = - fdtdec_get_int(gd->fdt_blob, - priv->data.slave_data[slave_index].phy_of_handle, - "reg", -1); - } else { - fdtdec_get_int_array(fdt, subnode, "phy_id", - phy_id, 2); - priv->data.slave_data[slave_index].phy_addr = - phy_id[1]; - } - slave_index++; - } - - if (!strncmp(name, "cpsw-phy-sel", 12)) { - priv->data.gmii_sel = cpsw_get_addr_by_node(fdt, - subnode); - - if (priv->data.gmii_sel == FDT_ADDR_T_NONE) { - pr_err("Not able to get gmii_sel reg address\n"); - return -ENOENT; - } - - if (fdt_get_property(fdt, subnode, "rmii-clock-ext", - NULL)) - priv->data.rmii_clock_external = true; - - phy_sel_compat = fdt_getprop(fdt, subnode, "compatible", - NULL); - if (!phy_sel_compat) { - pr_err("Not able to get gmii_sel compatible\n"); - return -ENOENT; - } - } - } - - priv->data.slave_data[0].slave_reg_ofs = CPSW_SLAVE0_OFFSET; - priv->data.slave_data[0].sliver_reg_ofs = CPSW_SLIVER0_OFFSET; - - if (priv->data.slaves == 2) { - priv->data.slave_data[1].slave_reg_ofs = CPSW_SLAVE1_OFFSET; - priv->data.slave_data[1].sliver_reg_ofs = CPSW_SLIVER1_OFFSET; - } - - ret = ti_cm_get_macid(dev, active_slave, pdata->enetaddr); - if (ret < 0) { - pr_err("cpsw read efuse mac failed\n"); - return ret; - } - - pdata->phy_interface = priv->data.slave_data[active_slave].phy_if; - if (pdata->phy_interface == -1) { - debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); - return -EINVAL; - } - - /* Select phy interface in control module */ - cpsw_phy_sel(priv, phy_sel_compat, pdata->phy_interface); - - return 0; -} - -int cpsw_get_slave_phy_addr(struct udevice *dev, int slave) -{ - struct cpsw_priv *priv = dev_get_priv(dev); - struct cpsw_platform_data *data = &priv->data; - - return data->slave_data[slave].phy_addr; -} - -static const struct udevice_id cpsw_eth_ids[] = { - { .compatible = "ti,cpsw" }, - { .compatible = "ti,am335x-cpsw" }, - { } -}; - -U_BOOT_DRIVER(eth_cpsw) = { - .name = "eth_cpsw", - .id = UCLASS_ETH, - .of_match = cpsw_eth_ids, - .ofdata_to_platdata = cpsw_eth_ofdata_to_platdata, - .probe = cpsw_eth_probe, - .ops = &cpsw_eth_ops, - .priv_auto_alloc_size = sizeof(struct cpsw_priv), - .platdata_auto_alloc_size = sizeof(struct eth_pdata), - .flags = DM_FLAG_ALLOC_PRIV_DMA, -}; -#endif /* CONFIG_DM_ETH */ diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c deleted file mode 100644 index bb879d8d4fe..00000000000 --- a/drivers/net/davinci_emac.c +++ /dev/null @@ -1,901 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Ethernet driver for TI TMS320DM644x (DaVinci) chips. - * - * Copyright (C) 2007 Sergey Kubushyn - * - * Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright - * follows: - * - * ---------------------------------------------------------------------------- - * - * dm644x_emac.c - * - * TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM - * - * Copyright (C) 2005 Texas Instruments. - * - * ---------------------------------------------------------------------------- - * - * Modifications: - * ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot. - * ver 1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "davinci_emac.h" - -unsigned int emac_dbg = 0; -#define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args) - -#ifdef EMAC_HW_RAM_ADDR -static inline unsigned long BD_TO_HW(unsigned long x) -{ - if (x == 0) - return 0; - - return x - EMAC_WRAPPER_RAM_ADDR + EMAC_HW_RAM_ADDR; -} - -static inline unsigned long HW_TO_BD(unsigned long x) -{ - if (x == 0) - return 0; - - return x - EMAC_HW_RAM_ADDR + EMAC_WRAPPER_RAM_ADDR; -} -#else -#define BD_TO_HW(x) (x) -#define HW_TO_BD(x) (x) -#endif - -#ifdef DAVINCI_EMAC_GIG_ENABLE -#define emac_gigabit_enable(phy_addr) davinci_eth_gigabit_enable(phy_addr) -#else -#define emac_gigabit_enable(phy_addr) /* no gigabit to enable */ -#endif - -#if !defined(CONFIG_SYS_EMAC_TI_CLKDIV) -#define CONFIG_SYS_EMAC_TI_CLKDIV ((EMAC_MDIO_BUS_FREQ / \ - EMAC_MDIO_CLOCK_FREQ) - 1) -#endif - -static void davinci_eth_mdio_enable(void); - -static int gen_init_phy(int phy_addr); -static int gen_is_phy_connected(int phy_addr); -static int gen_get_link_speed(int phy_addr); -static int gen_auto_negotiate(int phy_addr); - -void eth_mdio_enable(void) -{ - davinci_eth_mdio_enable(); -} - -/* EMAC Addresses */ -static volatile emac_regs *adap_emac = (emac_regs *)EMAC_BASE_ADDR; -static volatile ewrap_regs *adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR; -static volatile mdio_regs *adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR; - -/* EMAC descriptors */ -static volatile emac_desc *emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE); -static volatile emac_desc *emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE); -static volatile emac_desc *emac_rx_active_head = 0; -static volatile emac_desc *emac_rx_active_tail = 0; -static int emac_rx_queue_active = 0; - -/* Receive packet buffers */ -static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * EMAC_RXBUF_SIZE] - __aligned(ARCH_DMA_MINALIGN); - -#ifndef CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT -#define CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT 3 -#endif - -/* PHY address for a discovered PHY (0xff - not found) */ -static u_int8_t active_phy_addr[CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT]; - -/* number of PHY found active */ -static u_int8_t num_phy; - -phy_t phy[CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT]; - -static int davinci_eth_set_mac_addr(struct eth_device *dev) -{ - unsigned long mac_hi; - unsigned long mac_lo; - - /* - * Set MAC Addresses & Init multicast Hash to 0 (disable any multicast - * receive) - * Using channel 0 only - other channels are disabled - * */ - writel(0, &adap_emac->MACINDEX); - mac_hi = (dev->enetaddr[3] << 24) | - (dev->enetaddr[2] << 16) | - (dev->enetaddr[1] << 8) | - (dev->enetaddr[0]); - mac_lo = (dev->enetaddr[5] << 8) | - (dev->enetaddr[4]); - - writel(mac_hi, &adap_emac->MACADDRHI); -#if defined(DAVINCI_EMAC_VERSION2) - writel(mac_lo | EMAC_MAC_ADDR_IS_VALID | EMAC_MAC_ADDR_MATCH, - &adap_emac->MACADDRLO); -#else - writel(mac_lo, &adap_emac->MACADDRLO); -#endif - - writel(0, &adap_emac->MACHASH1); - writel(0, &adap_emac->MACHASH2); - - /* Set source MAC address - REQUIRED */ - writel(mac_hi, &adap_emac->MACSRCADDRHI); - writel(mac_lo, &adap_emac->MACSRCADDRLO); - - - return 0; -} - -static void davinci_eth_mdio_enable(void) -{ - u_int32_t clkdiv; - - clkdiv = CONFIG_SYS_EMAC_TI_CLKDIV; - - writel((clkdiv & 0xff) | - MDIO_CONTROL_ENABLE | - MDIO_CONTROL_FAULT | - MDIO_CONTROL_FAULT_ENABLE, - &adap_mdio->CONTROL); - - while (readl(&adap_mdio->CONTROL) & MDIO_CONTROL_IDLE) - ; -} - -/* - * Tries to find an active connected PHY. Returns 1 if address if found. - * If no active PHY (or more than one PHY) found returns 0. - * Sets active_phy_addr variable. - */ -static int davinci_eth_phy_detect(void) -{ - u_int32_t phy_act_state; - int i; - int j; - unsigned int count = 0; - - for (i = 0; i < CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT; i++) - active_phy_addr[i] = 0xff; - - udelay(1000); - phy_act_state = readl(&adap_mdio->ALIVE); - - if (phy_act_state == 0) - return 0; /* No active PHYs */ - - debug_emac("davinci_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state); - - for (i = 0, j = 0; i < 32; i++) - if (phy_act_state & (1 << i)) { - count++; - if (count <= CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT) { - active_phy_addr[j++] = i; - } else { - printf("%s: to many PHYs detected.\n", - __func__); - count = 0; - break; - } - } - - num_phy = count; - - return count; -} - - -/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */ -int davinci_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data) -{ - int tmp; - - while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) - ; - - writel(MDIO_USERACCESS0_GO | - MDIO_USERACCESS0_WRITE_READ | - ((reg_num & 0x1f) << 21) | - ((phy_addr & 0x1f) << 16), - &adap_mdio->USERACCESS0); - - /* Wait for command to complete */ - while ((tmp = readl(&adap_mdio->USERACCESS0)) & MDIO_USERACCESS0_GO) - ; - - if (tmp & MDIO_USERACCESS0_ACK) { - *data = tmp & 0xffff; - return 1; - } - - return 0; -} - -/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */ -int davinci_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data) -{ - - while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) - ; - - writel(MDIO_USERACCESS0_GO | - MDIO_USERACCESS0_WRITE_WRITE | - ((reg_num & 0x1f) << 21) | - ((phy_addr & 0x1f) << 16) | - (data & 0xffff), - &adap_mdio->USERACCESS0); - - /* Wait for command to complete */ - while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) - ; - - return 1; -} - -/* PHY functions for a generic PHY */ -static int gen_init_phy(int phy_addr) -{ - int ret = 1; - - if (gen_get_link_speed(phy_addr)) { - /* Try another time */ - ret = gen_get_link_speed(phy_addr); - } - - return(ret); -} - -static int gen_is_phy_connected(int phy_addr) -{ - u_int16_t dummy; - - return davinci_eth_phy_read(phy_addr, MII_PHYSID1, &dummy); -} - -static int get_active_phy(void) -{ - int i; - - for (i = 0; i < num_phy; i++) - if (phy[i].get_link_speed(active_phy_addr[i])) - return i; - - return -1; /* Return error if no link */ -} - -static int gen_get_link_speed(int phy_addr) -{ - u_int16_t tmp; - - if (davinci_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp) && - (tmp & 0x04)) { -#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \ - defined(CONFIG_MACH_DAVINCI_DA850_EVM) - davinci_eth_phy_read(phy_addr, MII_LPA, &tmp); - - /* Speed doesn't matter, there is no setting for it in EMAC. */ - if (tmp & (LPA_100FULL | LPA_10FULL)) { - /* set EMAC for Full Duplex */ - writel(EMAC_MACCONTROL_MIIEN_ENABLE | - EMAC_MACCONTROL_FULLDUPLEX_ENABLE, - &adap_emac->MACCONTROL); - } else { - /*set EMAC for Half Duplex */ - writel(EMAC_MACCONTROL_MIIEN_ENABLE, - &adap_emac->MACCONTROL); - } - - if (tmp & (LPA_100FULL | LPA_100HALF)) - writel(readl(&adap_emac->MACCONTROL) | - EMAC_MACCONTROL_RMIISPEED_100, - &adap_emac->MACCONTROL); - else - writel(readl(&adap_emac->MACCONTROL) & - ~EMAC_MACCONTROL_RMIISPEED_100, - &adap_emac->MACCONTROL); -#endif - return(1); - } - - return(0); -} - -static int gen_auto_negotiate(int phy_addr) -{ - u_int16_t tmp; - u_int16_t val; - unsigned long cntr = 0; - - if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &tmp)) - return 0; - - val = tmp | BMCR_FULLDPLX | BMCR_ANENABLE | - BMCR_SPEED100; - davinci_eth_phy_write(phy_addr, MII_BMCR, val); - - if (!davinci_eth_phy_read(phy_addr, MII_ADVERTISE, &val)) - return 0; - - val |= (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10FULL | - ADVERTISE_10HALF); - davinci_eth_phy_write(phy_addr, MII_ADVERTISE, val); - - if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &tmp)) - return(0); - -#ifdef DAVINCI_EMAC_GIG_ENABLE - davinci_eth_phy_read(phy_addr, MII_CTRL1000, &val); - val |= PHY_1000BTCR_1000FD; - val &= ~PHY_1000BTCR_1000HD; - davinci_eth_phy_write(phy_addr, MII_CTRL1000, val); - davinci_eth_phy_read(phy_addr, MII_CTRL1000, &val); -#endif - - /* Restart Auto_negotiation */ - tmp |= BMCR_ANRESTART; - davinci_eth_phy_write(phy_addr, MII_BMCR, tmp); - - /*check AutoNegotiate complete */ - do { - udelay(40000); - if (!davinci_eth_phy_read(phy_addr, MII_BMSR, &tmp)) - return 0; - - if (tmp & BMSR_ANEGCOMPLETE) - break; - - cntr++; - } while (cntr < 200); - - if (!davinci_eth_phy_read(phy_addr, MII_BMSR, &tmp)) - return(0); - - if (!(tmp & BMSR_ANEGCOMPLETE)) - return(0); - - return(gen_get_link_speed(phy_addr)); -} -/* End of generic PHY functions */ - - -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) -static int davinci_mii_phy_read(struct mii_dev *bus, int addr, int devad, - int reg) -{ - unsigned short value = 0; - int retval = davinci_eth_phy_read(addr, reg, &value); - - return retval ? value : -EIO; -} - -static int davinci_mii_phy_write(struct mii_dev *bus, int addr, int devad, - int reg, u16 value) -{ - return davinci_eth_phy_write(addr, reg, value) ? 0 : 1; -} -#endif - -static void __attribute__((unused)) davinci_eth_gigabit_enable(int phy_addr) -{ - u_int16_t data; - - if (davinci_eth_phy_read(phy_addr, 0, &data)) { - if (data & (1 << 6)) { /* speed selection MSB */ - /* - * Check if link detected is giga-bit - * If Gigabit mode detected, enable gigbit in MAC - */ - writel(readl(&adap_emac->MACCONTROL) | - EMAC_MACCONTROL_GIGFORCE | - EMAC_MACCONTROL_GIGABIT_ENABLE, - &adap_emac->MACCONTROL); - } - } -} - -/* Eth device open */ -static int davinci_eth_open(struct eth_device *dev, bd_t *bis) -{ - dv_reg_p addr; - u_int32_t clkdiv, cnt, mac_control; - uint16_t __maybe_unused lpa_val; - volatile emac_desc *rx_desc; - int index; - - debug_emac("+ emac_open\n"); - - /* Reset EMAC module and disable interrupts in wrapper */ - writel(1, &adap_emac->SOFTRESET); - while (readl(&adap_emac->SOFTRESET) != 0) - ; -#if defined(DAVINCI_EMAC_VERSION2) - writel(1, &adap_ewrap->softrst); - while (readl(&adap_ewrap->softrst) != 0) - ; -#else - writel(0, &adap_ewrap->EWCTL); - for (cnt = 0; cnt < 5; cnt++) { - clkdiv = readl(&adap_ewrap->EWCTL); - } -#endif - -#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \ - defined(CONFIG_MACH_DAVINCI_DA850_EVM) - adap_ewrap->c0rxen = adap_ewrap->c1rxen = adap_ewrap->c2rxen = 0; - adap_ewrap->c0txen = adap_ewrap->c1txen = adap_ewrap->c2txen = 0; - adap_ewrap->c0miscen = adap_ewrap->c1miscen = adap_ewrap->c2miscen = 0; -#endif - rx_desc = emac_rx_desc; - - writel(1, &adap_emac->TXCONTROL); - writel(1, &adap_emac->RXCONTROL); - - davinci_eth_set_mac_addr(dev); - - /* Set DMA 8 TX / 8 RX Head pointers to 0 */ - addr = &adap_emac->TX0HDP; - for (cnt = 0; cnt < 8; cnt++) - writel(0, addr++); - - addr = &adap_emac->RX0HDP; - for (cnt = 0; cnt < 8; cnt++) - writel(0, addr++); - - /* Clear Statistics (do this before setting MacControl register) */ - addr = &adap_emac->RXGOODFRAMES; - for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++) - writel(0, addr++); - - /* No multicast addressing */ - writel(0, &adap_emac->MACHASH1); - writel(0, &adap_emac->MACHASH2); - - /* Create RX queue and set receive process in place */ - emac_rx_active_head = emac_rx_desc; - for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) { - rx_desc->next = BD_TO_HW((u_int32_t)(rx_desc + 1)); - rx_desc->buffer = &emac_rx_buffers[cnt * EMAC_RXBUF_SIZE]; - rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; - rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; - rx_desc++; - } - - /* Finalize the rx desc list */ - rx_desc--; - rx_desc->next = 0; - emac_rx_active_tail = rx_desc; - emac_rx_queue_active = 1; - - /* Enable TX/RX */ - writel(EMAC_MAX_ETHERNET_PKT_SIZE, &adap_emac->RXMAXLEN); - writel(0, &adap_emac->RXBUFFEROFFSET); - - /* - * No fancy configs - Use this for promiscous debug - * - EMAC_RXMBPENABLE_RXCAFEN_ENABLE - */ - writel(EMAC_RXMBPENABLE_RXBROADEN, &adap_emac->RXMBPENABLE); - - /* Enable ch 0 only */ - writel(1, &adap_emac->RXUNICASTSET); - - /* Init MDIO & get link state */ - clkdiv = CONFIG_SYS_EMAC_TI_CLKDIV; - writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT, - &adap_mdio->CONTROL); - - /* We need to wait for MDIO to start */ - udelay(1000); - - index = get_active_phy(); - if (index == -1) - return(0); - - /* Enable MII interface */ - mac_control = EMAC_MACCONTROL_MIIEN_ENABLE; -#ifdef DAVINCI_EMAC_GIG_ENABLE - davinci_eth_phy_read(active_phy_addr[index], MII_STAT1000, &lpa_val); - if (lpa_val & PHY_1000BTSR_1000FD) { - debug_emac("eth_open : gigabit negotiated\n"); - mac_control |= EMAC_MACCONTROL_FULLDUPLEX_ENABLE; - mac_control |= EMAC_MACCONTROL_GIGABIT_ENABLE; - } -#endif - - davinci_eth_phy_read(active_phy_addr[index], MII_LPA, &lpa_val); - if (lpa_val & (LPA_100FULL | LPA_10FULL)) - /* set EMAC for Full Duplex */ - mac_control |= EMAC_MACCONTROL_FULLDUPLEX_ENABLE; -#if defined(CONFIG_SOC_DA8XX) || \ - (defined(CONFIG_OMAP34XX) && defined(CONFIG_DRIVER_TI_EMAC_USE_RMII)) - mac_control |= EMAC_MACCONTROL_RMIISPEED_100; -#endif - writel(mac_control, &adap_emac->MACCONTROL); - /* Start receive process */ - writel(BD_TO_HW((u_int32_t)emac_rx_desc), &adap_emac->RX0HDP); - - debug_emac("- emac_open\n"); - - return(1); -} - -/* EMAC Channel Teardown */ -static void davinci_eth_ch_teardown(int ch) -{ - dv_reg dly = 0xff; - dv_reg cnt; - - debug_emac("+ emac_ch_teardown\n"); - - if (ch == EMAC_CH_TX) { - /* Init TX channel teardown */ - writel(0, &adap_emac->TXTEARDOWN); - do { - /* - * Wait here for Tx teardown completion interrupt to - * occur. Note: A task delay can be called here to pend - * rather than occupying CPU cycles - anyway it has - * been found that teardown takes very few cpu cycles - * and does not affect functionality - */ - dly--; - udelay(1); - if (dly == 0) - break; - cnt = readl(&adap_emac->TX0CP); - } while (cnt != 0xfffffffc); - writel(cnt, &adap_emac->TX0CP); - writel(0, &adap_emac->TX0HDP); - } else { - /* Init RX channel teardown */ - writel(0, &adap_emac->RXTEARDOWN); - do { - /* - * Wait here for Rx teardown completion interrupt to - * occur. Note: A task delay can be called here to pend - * rather than occupying CPU cycles - anyway it has - * been found that teardown takes very few cpu cycles - * and does not affect functionality - */ - dly--; - udelay(1); - if (dly == 0) - break; - cnt = readl(&adap_emac->RX0CP); - } while (cnt != 0xfffffffc); - writel(cnt, &adap_emac->RX0CP); - writel(0, &adap_emac->RX0HDP); - } - - debug_emac("- emac_ch_teardown\n"); -} - -/* Eth device close */ -static void davinci_eth_close(struct eth_device *dev) -{ - debug_emac("+ emac_close\n"); - - davinci_eth_ch_teardown(EMAC_CH_TX); /* TX Channel teardown */ - if (readl(&adap_emac->RXCONTROL) & 1) - davinci_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */ - - /* Reset EMAC module and disable interrupts in wrapper */ - writel(1, &adap_emac->SOFTRESET); -#if defined(DAVINCI_EMAC_VERSION2) - writel(1, &adap_ewrap->softrst); -#else - writel(0, &adap_ewrap->EWCTL); -#endif - -#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \ - defined(CONFIG_MACH_DAVINCI_DA850_EVM) - adap_ewrap->c0rxen = adap_ewrap->c1rxen = adap_ewrap->c2rxen = 0; - adap_ewrap->c0txen = adap_ewrap->c1txen = adap_ewrap->c2txen = 0; - adap_ewrap->c0miscen = adap_ewrap->c1miscen = adap_ewrap->c2miscen = 0; -#endif - debug_emac("- emac_close\n"); -} - -static int tx_send_loop = 0; - -/* - * This function sends a single packet on the network and returns - * positive number (number of bytes transmitted) or negative for error - */ -static int davinci_eth_send_packet (struct eth_device *dev, - void *packet, int length) -{ - int ret_status = -1; - int index; - tx_send_loop = 0; - - index = get_active_phy(); - if (index == -1) { - printf(" WARN: emac_send_packet: No link\n"); - return (ret_status); - } - - /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */ - if (length < EMAC_MIN_ETHERNET_PKT_SIZE) { - length = EMAC_MIN_ETHERNET_PKT_SIZE; - } - - /* Populate the TX descriptor */ - emac_tx_desc->next = 0; - emac_tx_desc->buffer = (u_int8_t *) packet; - emac_tx_desc->buff_off_len = (length & 0xffff); - emac_tx_desc->pkt_flag_len = ((length & 0xffff) | - EMAC_CPPI_SOP_BIT | - EMAC_CPPI_OWNERSHIP_BIT | - EMAC_CPPI_EOP_BIT); - - flush_dcache_range((unsigned long)packet, - (unsigned long)packet + ALIGN(length, PKTALIGN)); - - /* Send the packet */ - writel(BD_TO_HW((unsigned long)emac_tx_desc), &adap_emac->TX0HDP); - - /* Wait for packet to complete or link down */ - while (1) { - if (!phy[index].get_link_speed(active_phy_addr[index])) { - davinci_eth_ch_teardown (EMAC_CH_TX); - return (ret_status); - } - - if (readl(&adap_emac->TXINTSTATRAW) & 0x01) { - ret_status = length; - break; - } - tx_send_loop++; - } - - return (ret_status); -} - -/* - * This function handles receipt of a packet from the network - */ -static int davinci_eth_rcv_packet (struct eth_device *dev) -{ - volatile emac_desc *rx_curr_desc; - volatile emac_desc *curr_desc; - volatile emac_desc *tail_desc; - int status, ret = -1; - - rx_curr_desc = emac_rx_active_head; - if (!rx_curr_desc) - return 0; - status = rx_curr_desc->pkt_flag_len; - if ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0) { - if (status & EMAC_CPPI_RX_ERROR_FRAME) { - /* Error in packet - discard it and requeue desc */ - printf ("WARN: emac_rcv_pkt: Error in packet\n"); - } else { - unsigned long tmp = (unsigned long)rx_curr_desc->buffer; - unsigned short len = - rx_curr_desc->buff_off_len & 0xffff; - - invalidate_dcache_range(tmp, tmp + ALIGN(len, PKTALIGN)); - net_process_received_packet(rx_curr_desc->buffer, len); - ret = len; - } - - /* Ack received packet descriptor */ - writel(BD_TO_HW((ulong)rx_curr_desc), &adap_emac->RX0CP); - curr_desc = rx_curr_desc; - emac_rx_active_head = - (volatile emac_desc *) (HW_TO_BD(rx_curr_desc->next)); - - if (status & EMAC_CPPI_EOQ_BIT) { - if (emac_rx_active_head) { - writel(BD_TO_HW((ulong)emac_rx_active_head), - &adap_emac->RX0HDP); - } else { - emac_rx_queue_active = 0; - printf ("INFO:emac_rcv_packet: RX Queue not active\n"); - } - } - - /* Recycle RX descriptor */ - rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; - rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; - rx_curr_desc->next = 0; - - if (emac_rx_active_head == 0) { - printf ("INFO: emac_rcv_pkt: active queue head = 0\n"); - emac_rx_active_head = curr_desc; - emac_rx_active_tail = curr_desc; - if (emac_rx_queue_active != 0) { - writel(BD_TO_HW((ulong)emac_rx_active_head), - &adap_emac->RX0HDP); - printf ("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n"); - emac_rx_queue_active = 1; - } - } else { - tail_desc = emac_rx_active_tail; - emac_rx_active_tail = curr_desc; - tail_desc->next = BD_TO_HW((ulong) curr_desc); - status = tail_desc->pkt_flag_len; - if (status & EMAC_CPPI_EOQ_BIT) { - writel(BD_TO_HW((ulong)curr_desc), - &adap_emac->RX0HDP); - status &= ~EMAC_CPPI_EOQ_BIT; - tail_desc->pkt_flag_len = status; - } - } - return (ret); - } - return (0); -} - -/* - * This function initializes the emac hardware. It does NOT initialize - * EMAC modules power or pin multiplexors, that is done by board_init() - * much earlier in bootup process. Returns 1 on success, 0 otherwise. - */ -int davinci_emac_initialize(void) -{ - u_int32_t phy_id; - u_int16_t tmp; - int i; - int ret; - struct eth_device *dev; - - dev = malloc(sizeof *dev); - - if (dev == NULL) - return -1; - - memset(dev, 0, sizeof *dev); - strcpy(dev->name, "DaVinci-EMAC"); - - dev->iobase = 0; - dev->init = davinci_eth_open; - dev->halt = davinci_eth_close; - dev->send = davinci_eth_send_packet; - dev->recv = davinci_eth_rcv_packet; - dev->write_hwaddr = davinci_eth_set_mac_addr; - - eth_register(dev); - - davinci_eth_mdio_enable(); - - /* let the EMAC detect the PHYs */ - udelay(5000); - - for (i = 0; i < 256; i++) { - if (readl(&adap_mdio->ALIVE)) - break; - udelay(1000); - } - - if (i >= 256) { - printf("No ETH PHY detected!!!\n"); - return(0); - } - - /* Find if PHY(s) is/are connected */ - ret = davinci_eth_phy_detect(); - if (!ret) - return(0); - else - debug_emac(" %d ETH PHY detected\n", ret); - - /* Get PHY ID and initialize phy_ops for a detected PHY */ - for (i = 0; i < num_phy; i++) { - if (!davinci_eth_phy_read(active_phy_addr[i], MII_PHYSID1, - &tmp)) { - active_phy_addr[i] = 0xff; - continue; - } - - phy_id = (tmp << 16) & 0xffff0000; - - if (!davinci_eth_phy_read(active_phy_addr[i], MII_PHYSID2, - &tmp)) { - active_phy_addr[i] = 0xff; - continue; - } - - phy_id |= tmp & 0x0000ffff; - - switch (phy_id) { -#ifdef PHY_KSZ8873 - case PHY_KSZ8873: - sprintf(phy[i].name, "KSZ8873 @ 0x%02x", - active_phy_addr[i]); - phy[i].init = ksz8873_init_phy; - phy[i].is_phy_connected = ksz8873_is_phy_connected; - phy[i].get_link_speed = ksz8873_get_link_speed; - phy[i].auto_negotiate = ksz8873_auto_negotiate; - break; -#endif -#ifdef PHY_LXT972 - case PHY_LXT972: - sprintf(phy[i].name, "LXT972 @ 0x%02x", - active_phy_addr[i]); - phy[i].init = lxt972_init_phy; - phy[i].is_phy_connected = lxt972_is_phy_connected; - phy[i].get_link_speed = lxt972_get_link_speed; - phy[i].auto_negotiate = lxt972_auto_negotiate; - break; -#endif -#ifdef PHY_DP83848 - case PHY_DP83848: - sprintf(phy[i].name, "DP83848 @ 0x%02x", - active_phy_addr[i]); - phy[i].init = dp83848_init_phy; - phy[i].is_phy_connected = dp83848_is_phy_connected; - phy[i].get_link_speed = dp83848_get_link_speed; - phy[i].auto_negotiate = dp83848_auto_negotiate; - break; -#endif -#ifdef PHY_ET1011C - case PHY_ET1011C: - sprintf(phy[i].name, "ET1011C @ 0x%02x", - active_phy_addr[i]); - phy[i].init = gen_init_phy; - phy[i].is_phy_connected = gen_is_phy_connected; - phy[i].get_link_speed = et1011c_get_link_speed; - phy[i].auto_negotiate = gen_auto_negotiate; - break; -#endif - default: - sprintf(phy[i].name, "GENERIC @ 0x%02x", - active_phy_addr[i]); - phy[i].init = gen_init_phy; - phy[i].is_phy_connected = gen_is_phy_connected; - phy[i].get_link_speed = gen_get_link_speed; - phy[i].auto_negotiate = gen_auto_negotiate; - } - - debug("Ethernet PHY: %s\n", phy[i].name); - - int retval; - struct mii_dev *mdiodev = mdio_alloc(); - if (!mdiodev) - return -ENOMEM; - strncpy(mdiodev->name, phy[i].name, MDIO_NAME_LEN); - mdiodev->read = davinci_mii_phy_read; - mdiodev->write = davinci_mii_phy_write; - - retval = mdio_register(mdiodev); - if (retval < 0) - return retval; -#ifdef DAVINCI_EMAC_GIG_ENABLE -#define PHY_CONF_REG 22 - /* Enable PHY to clock out TX_CLK */ - davinci_eth_phy_read(active_phy_addr[i], PHY_CONF_REG, &tmp); - tmp |= PHY_CONF_TXCLKEN; - davinci_eth_phy_write(active_phy_addr[i], PHY_CONF_REG, tmp); - davinci_eth_phy_read(active_phy_addr[i], PHY_CONF_REG, &tmp); -#endif - } - -#if defined(CONFIG_TI816X) || (defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \ - defined(CONFIG_MACH_DAVINCI_DA850_EVM) && \ - !defined(CONFIG_DRIVER_TI_EMAC_RMII_NO_NEGOTIATE)) - for (i = 0; i < num_phy; i++) { - if (phy[i].is_phy_connected(i)) - phy[i].auto_negotiate(i); - } -#endif - return(1); -} diff --git a/drivers/net/davinci_emac.h b/drivers/net/davinci_emac.h deleted file mode 100644 index 695855b4d54..00000000000 --- a/drivers/net/davinci_emac.h +++ /dev/null @@ -1,304 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2011 Ilya Yanok, Emcraft Systems - * - * Based on: mach-davinci/emac_defs.h - * Copyright (C) 2007 Sergey Kubushyn - */ - -#ifndef _DAVINCI_EMAC_H_ -#define _DAVINCI_EMAC_H_ -/* Ethernet Min/Max packet size */ -#define EMAC_MIN_ETHERNET_PKT_SIZE 60 -#define EMAC_MAX_ETHERNET_PKT_SIZE 1518 -/* Buffer size (should be aligned on 32 byte and cache line) */ -#define EMAC_RXBUF_SIZE ALIGN(ALIGN(EMAC_MAX_ETHERNET_PKT_SIZE, 32),\ - ARCH_DMA_MINALIGN) - -/* Number of RX packet buffers - * NOTE: Only 1 buffer supported as of now - */ -#define EMAC_MAX_RX_BUFFERS 10 - - -/*********************************************** - ******** Internally used macros *************** - ***********************************************/ - -#define EMAC_CH_TX 1 -#define EMAC_CH_RX 0 - -/* Each descriptor occupies 4 words, lets start RX desc's at 0 and - * reserve space for 64 descriptors max - */ -#define EMAC_RX_DESC_BASE 0x0 -#define EMAC_TX_DESC_BASE 0x1000 - -/* EMAC Teardown value */ -#define EMAC_TEARDOWN_VALUE 0xfffffffc - -/* MII Status Register */ -#define MII_STATUS_REG 1 -/* PHY Configuration register */ -#define PHY_CONF_TXCLKEN (1 << 5) - -/* Number of statistics registers */ -#define EMAC_NUM_STATS 36 - - -/* EMAC Descriptor */ -typedef volatile struct _emac_desc -{ - u_int32_t next; /* Pointer to next descriptor - in chain */ - u_int8_t *buffer; /* Pointer to data buffer */ - u_int32_t buff_off_len; /* Buffer Offset(MSW) and Length(LSW) */ - u_int32_t pkt_flag_len; /* Packet Flags(MSW) and Length(LSW) */ -} emac_desc; - -/* CPPI bit positions */ -#define EMAC_CPPI_SOP_BIT (0x80000000) -#define EMAC_CPPI_EOP_BIT (0x40000000) -#define EMAC_CPPI_OWNERSHIP_BIT (0x20000000) -#define EMAC_CPPI_EOQ_BIT (0x10000000) -#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT (0x08000000) -#define EMAC_CPPI_PASS_CRC_BIT (0x04000000) - -#define EMAC_CPPI_RX_ERROR_FRAME (0x03fc0000) - -#define EMAC_MACCONTROL_MIIEN_ENABLE (0x20) -#define EMAC_MACCONTROL_FULLDUPLEX_ENABLE (0x1) -#define EMAC_MACCONTROL_GIGABIT_ENABLE (1 << 7) -#define EMAC_MACCONTROL_GIGFORCE (1 << 17) -#define EMAC_MACCONTROL_RMIISPEED_100 (1 << 15) - -#define EMAC_MAC_ADDR_MATCH (1 << 19) -#define EMAC_MAC_ADDR_IS_VALID (1 << 20) - -#define EMAC_RXMBPENABLE_RXCAFEN_ENABLE (0x200000) -#define EMAC_RXMBPENABLE_RXBROADEN (0x2000) - - -#define MDIO_CONTROL_IDLE (0x80000000) -#define MDIO_CONTROL_ENABLE (0x40000000) -#define MDIO_CONTROL_FAULT_ENABLE (0x40000) -#define MDIO_CONTROL_FAULT (0x80000) -#define MDIO_USERACCESS0_GO (0x80000000) -#define MDIO_USERACCESS0_WRITE_READ (0x0) -#define MDIO_USERACCESS0_WRITE_WRITE (0x40000000) -#define MDIO_USERACCESS0_ACK (0x20000000) - -/* Ethernet MAC Registers Structure */ -typedef struct { - dv_reg TXIDVER; - dv_reg TXCONTROL; - dv_reg TXTEARDOWN; - u_int8_t RSVD0[4]; - dv_reg RXIDVER; - dv_reg RXCONTROL; - dv_reg RXTEARDOWN; - u_int8_t RSVD1[100]; - dv_reg TXINTSTATRAW; - dv_reg TXINTSTATMASKED; - dv_reg TXINTMASKSET; - dv_reg TXINTMASKCLEAR; - dv_reg MACINVECTOR; - u_int8_t RSVD2[12]; - dv_reg RXINTSTATRAW; - dv_reg RXINTSTATMASKED; - dv_reg RXINTMASKSET; - dv_reg RXINTMASKCLEAR; - dv_reg MACINTSTATRAW; - dv_reg MACINTSTATMASKED; - dv_reg MACINTMASKSET; - dv_reg MACINTMASKCLEAR; - u_int8_t RSVD3[64]; - dv_reg RXMBPENABLE; - dv_reg RXUNICASTSET; - dv_reg RXUNICASTCLEAR; - dv_reg RXMAXLEN; - dv_reg RXBUFFEROFFSET; - dv_reg RXFILTERLOWTHRESH; - u_int8_t RSVD4[8]; - dv_reg RX0FLOWTHRESH; - dv_reg RX1FLOWTHRESH; - dv_reg RX2FLOWTHRESH; - dv_reg RX3FLOWTHRESH; - dv_reg RX4FLOWTHRESH; - dv_reg RX5FLOWTHRESH; - dv_reg RX6FLOWTHRESH; - dv_reg RX7FLOWTHRESH; - dv_reg RX0FREEBUFFER; - dv_reg RX1FREEBUFFER; - dv_reg RX2FREEBUFFER; - dv_reg RX3FREEBUFFER; - dv_reg RX4FREEBUFFER; - dv_reg RX5FREEBUFFER; - dv_reg RX6FREEBUFFER; - dv_reg RX7FREEBUFFER; - dv_reg MACCONTROL; - dv_reg MACSTATUS; - dv_reg EMCONTROL; - dv_reg FIFOCONTROL; - dv_reg MACCONFIG; - dv_reg SOFTRESET; - u_int8_t RSVD5[88]; - dv_reg MACSRCADDRLO; - dv_reg MACSRCADDRHI; - dv_reg MACHASH1; - dv_reg MACHASH2; - dv_reg BOFFTEST; - dv_reg TPACETEST; - dv_reg RXPAUSE; - dv_reg TXPAUSE; - u_int8_t RSVD6[16]; - dv_reg RXGOODFRAMES; - dv_reg RXBCASTFRAMES; - dv_reg RXMCASTFRAMES; - dv_reg RXPAUSEFRAMES; - dv_reg RXCRCERRORS; - dv_reg RXALIGNCODEERRORS; - dv_reg RXOVERSIZED; - dv_reg RXJABBER; - dv_reg RXUNDERSIZED; - dv_reg RXFRAGMENTS; - dv_reg RXFILTERED; - dv_reg RXQOSFILTERED; - dv_reg RXOCTETS; - dv_reg TXGOODFRAMES; - dv_reg TXBCASTFRAMES; - dv_reg TXMCASTFRAMES; - dv_reg TXPAUSEFRAMES; - dv_reg TXDEFERRED; - dv_reg TXCOLLISION; - dv_reg TXSINGLECOLL; - dv_reg TXMULTICOLL; - dv_reg TXEXCESSIVECOLL; - dv_reg TXLATECOLL; - dv_reg TXUNDERRUN; - dv_reg TXCARRIERSENSE; - dv_reg TXOCTETS; - dv_reg FRAME64; - dv_reg FRAME65T127; - dv_reg FRAME128T255; - dv_reg FRAME256T511; - dv_reg FRAME512T1023; - dv_reg FRAME1024TUP; - dv_reg NETOCTETS; - dv_reg RXSOFOVERRUNS; - dv_reg RXMOFOVERRUNS; - dv_reg RXDMAOVERRUNS; - u_int8_t RSVD7[624]; - dv_reg MACADDRLO; - dv_reg MACADDRHI; - dv_reg MACINDEX; - u_int8_t RSVD8[244]; - dv_reg TX0HDP; - dv_reg TX1HDP; - dv_reg TX2HDP; - dv_reg TX3HDP; - dv_reg TX4HDP; - dv_reg TX5HDP; - dv_reg TX6HDP; - dv_reg TX7HDP; - dv_reg RX0HDP; - dv_reg RX1HDP; - dv_reg RX2HDP; - dv_reg RX3HDP; - dv_reg RX4HDP; - dv_reg RX5HDP; - dv_reg RX6HDP; - dv_reg RX7HDP; - dv_reg TX0CP; - dv_reg TX1CP; - dv_reg TX2CP; - dv_reg TX3CP; - dv_reg TX4CP; - dv_reg TX5CP; - dv_reg TX6CP; - dv_reg TX7CP; - dv_reg RX0CP; - dv_reg RX1CP; - dv_reg RX2CP; - dv_reg RX3CP; - dv_reg RX4CP; - dv_reg RX5CP; - dv_reg RX6CP; - dv_reg RX7CP; -} emac_regs; - -/* EMAC Wrapper Registers Structure */ -typedef struct { -#ifdef DAVINCI_EMAC_VERSION2 - dv_reg idver; - dv_reg softrst; - dv_reg emctrl; - dv_reg c0rxthreshen; - dv_reg c0rxen; - dv_reg c0txen; - dv_reg c0miscen; - dv_reg c1rxthreshen; - dv_reg c1rxen; - dv_reg c1txen; - dv_reg c1miscen; - dv_reg c2rxthreshen; - dv_reg c2rxen; - dv_reg c2txen; - dv_reg c2miscen; - dv_reg c0rxthreshstat; - dv_reg c0rxstat; - dv_reg c0txstat; - dv_reg c0miscstat; - dv_reg c1rxthreshstat; - dv_reg c1rxstat; - dv_reg c1txstat; - dv_reg c1miscstat; - dv_reg c2rxthreshstat; - dv_reg c2rxstat; - dv_reg c2txstat; - dv_reg c2miscstat; - dv_reg c0rximax; - dv_reg c0tximax; - dv_reg c1rximax; - dv_reg c1tximax; - dv_reg c2rximax; - dv_reg c2tximax; -#else - u_int8_t RSVD0[4100]; - dv_reg EWCTL; - dv_reg EWINTTCNT; -#endif -} ewrap_regs; - -/* EMAC MDIO Registers Structure */ -typedef struct { - dv_reg VERSION; - dv_reg CONTROL; - dv_reg ALIVE; - dv_reg LINK; - dv_reg LINKINTRAW; - dv_reg LINKINTMASKED; - u_int8_t RSVD0[8]; - dv_reg USERINTRAW; - dv_reg USERINTMASKED; - dv_reg USERINTMASKSET; - dv_reg USERINTMASKCLEAR; - u_int8_t RSVD1[80]; - dv_reg USERACCESS0; - dv_reg USERPHYSEL0; - dv_reg USERACCESS1; - dv_reg USERPHYSEL1; -} mdio_regs; - -int davinci_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data); -int davinci_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data); - -typedef struct { - char name[64]; - int (*init)(int phy_addr); - int (*is_phy_connected)(int phy_addr); - int (*get_link_speed)(int phy_addr); - int (*auto_negotiate)(int phy_addr); -} phy_t; - -#endif /* _DAVINCI_EMAC_H_ */ diff --git a/drivers/net/keystone_net.c b/drivers/net/keystone_net.c deleted file mode 100644 index d4d909b983f..00000000000 --- a/drivers/net/keystone_net.c +++ /dev/null @@ -1,1170 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Ethernet driver for TI K2HK EVM. - * - * (C) Copyright 2012-2014 - * Texas Instruments Incorporated, - */ -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -#ifndef CONFIG_DM_ETH -unsigned int emac_open; -static struct mii_dev *mdio_bus; -static unsigned int sys_has_mdio = 1; -#endif - -#ifdef KEYSTONE2_EMAC_GIG_ENABLE -#define emac_gigabit_enable(x) keystone2_eth_gigabit_enable(x) -#else -#define emac_gigabit_enable(x) /* no gigabit to enable */ -#endif - -#define RX_BUFF_NUMS 24 -#define RX_BUFF_LEN 1520 -#define MAX_SIZE_STREAM_BUFFER RX_BUFF_LEN -#define SGMII_ANEG_TIMEOUT 4000 - -static u8 rx_buffs[RX_BUFF_NUMS * RX_BUFF_LEN] __aligned(16); - -#ifndef CONFIG_DM_ETH -struct rx_buff_desc net_rx_buffs = { - .buff_ptr = rx_buffs, - .num_buffs = RX_BUFF_NUMS, - .buff_len = RX_BUFF_LEN, - .rx_flow = 22, -}; -#endif - -#ifdef CONFIG_DM_ETH - -enum link_type { - LINK_TYPE_SGMII_MAC_TO_MAC_AUTO = 0, - LINK_TYPE_SGMII_MAC_TO_PHY_MODE = 1, - LINK_TYPE_SGMII_MAC_TO_MAC_FORCED_MODE = 2, - LINK_TYPE_SGMII_MAC_TO_FIBRE_MODE = 3, - LINK_TYPE_SGMII_MAC_TO_PHY_NO_MDIO_MODE = 4, - LINK_TYPE_RGMII_LINK_MAC_PHY = 5, - LINK_TYPE_RGMII_LINK_MAC_MAC_FORCED = 6, - LINK_TYPE_RGMII_LINK_MAC_PHY_NO_MDIO = 7, - LINK_TYPE_10G_MAC_TO_PHY_MODE = 10, - LINK_TYPE_10G_MAC_TO_MAC_FORCED_MODE = 11, -}; - -#define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \ - ((mac)[2] << 16) | ((mac)[3] << 24)) -#define mac_lo(mac) (((mac)[4] << 0) | ((mac)[5] << 8)) - -#ifdef CONFIG_KSNET_NETCP_V1_0 - -#define EMAC_EMACSW_BASE_OFS 0x90800 -#define EMAC_EMACSW_PORT_BASE_OFS (EMAC_EMACSW_BASE_OFS + 0x60) - -/* CPSW Switch slave registers */ -#define CPGMACSL_REG_SA_LO 0x10 -#define CPGMACSL_REG_SA_HI 0x14 - -#define DEVICE_EMACSW_BASE(base, x) ((base) + EMAC_EMACSW_PORT_BASE_OFS + \ - (x) * 0x30) - -#elif defined CONFIG_KSNET_NETCP_V1_5 - -#define EMAC_EMACSW_PORT_BASE_OFS 0x222000 - -/* CPSW Switch slave registers */ -#define CPGMACSL_REG_SA_LO 0x308 -#define CPGMACSL_REG_SA_HI 0x30c - -#define DEVICE_EMACSW_BASE(base, x) ((base) + EMAC_EMACSW_PORT_BASE_OFS + \ - (x) * 0x1000) - -#endif - - -struct ks2_eth_priv { - struct udevice *dev; - struct phy_device *phydev; - struct mii_dev *mdio_bus; - int phy_addr; - phy_interface_t phy_if; - int sgmii_link_type; - void *mdio_base; - struct rx_buff_desc net_rx_buffs; - struct pktdma_cfg *netcp_pktdma; - void *hd; - int slave_port; - enum link_type link_type; - bool emac_open; - bool has_mdio; -}; -#endif - -/* MDIO */ - -static int keystone2_mdio_reset(struct mii_dev *bus) -{ - u_int32_t clkdiv; - struct mdio_regs *adap_mdio = bus->priv; - - clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; - - writel((clkdiv & 0xffff) | MDIO_CONTROL_ENABLE | - MDIO_CONTROL_FAULT | MDIO_CONTROL_FAULT_ENABLE, - &adap_mdio->control); - - while (readl(&adap_mdio->control) & MDIO_CONTROL_IDLE) - ; - - return 0; -} - -/** - * keystone2_mdio_read - read a PHY register via MDIO interface. - * Blocks until operation is complete. - */ -static int keystone2_mdio_read(struct mii_dev *bus, - int addr, int devad, int reg) -{ - int tmp; - struct mdio_regs *adap_mdio = bus->priv; - - while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO) - ; - - writel(MDIO_USERACCESS0_GO | MDIO_USERACCESS0_WRITE_READ | - ((reg & 0x1f) << 21) | ((addr & 0x1f) << 16), - &adap_mdio->useraccess0); - - /* Wait for command to complete */ - while ((tmp = readl(&adap_mdio->useraccess0)) & MDIO_USERACCESS0_GO) - ; - - if (tmp & MDIO_USERACCESS0_ACK) - return tmp & 0xffff; - - return -1; -} - -/** - * keystone2_mdio_write - write to a PHY register via MDIO interface. - * Blocks until operation is complete. - */ -static int keystone2_mdio_write(struct mii_dev *bus, - int addr, int devad, int reg, u16 val) -{ - struct mdio_regs *adap_mdio = bus->priv; - - while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO) - ; - - writel(MDIO_USERACCESS0_GO | MDIO_USERACCESS0_WRITE_WRITE | - ((reg & 0x1f) << 21) | ((addr & 0x1f) << 16) | - (val & 0xffff), &adap_mdio->useraccess0); - - /* Wait for command to complete */ - while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO) - ; - - return 0; -} - -#ifndef CONFIG_DM_ETH -static void __attribute__((unused)) - keystone2_eth_gigabit_enable(struct eth_device *dev) -{ - u_int16_t data; - struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv; - - if (sys_has_mdio) { - data = keystone2_mdio_read(mdio_bus, eth_priv->phy_addr, - MDIO_DEVAD_NONE, 0); - /* speed selection MSB */ - if (!(data & (1 << 6))) - return; - } - - /* - * Check if link detected is giga-bit - * If Gigabit mode detected, enable gigbit in MAC - */ - writel(readl(DEVICE_EMACSL_BASE(eth_priv->slave_port - 1) + - CPGMACSL_REG_CTL) | - EMAC_MACCONTROL_GIGFORCE | EMAC_MACCONTROL_GIGABIT_ENABLE, - DEVICE_EMACSL_BASE(eth_priv->slave_port - 1) + CPGMACSL_REG_CTL); -} -#else -static void __attribute__((unused)) - keystone2_eth_gigabit_enable(struct udevice *dev) -{ - struct ks2_eth_priv *priv = dev_get_priv(dev); - u_int16_t data; - - if (priv->has_mdio) { - data = keystone2_mdio_read(priv->mdio_bus, priv->phy_addr, - MDIO_DEVAD_NONE, 0); - /* speed selection MSB */ - if (!(data & (1 << 6))) - return; - } - - /* - * Check if link detected is giga-bit - * If Gigabit mode detected, enable gigbit in MAC - */ - writel(readl(DEVICE_EMACSL_BASE(priv->slave_port - 1) + - CPGMACSL_REG_CTL) | - EMAC_MACCONTROL_GIGFORCE | EMAC_MACCONTROL_GIGABIT_ENABLE, - DEVICE_EMACSL_BASE(priv->slave_port - 1) + CPGMACSL_REG_CTL); -} -#endif - -#ifdef CONFIG_SOC_K2G -int keystone_rgmii_config(struct phy_device *phy_dev) -{ - unsigned int i, status; - - i = 0; - do { - if (i > SGMII_ANEG_TIMEOUT) { - puts(" TIMEOUT !\n"); - phy_dev->link = 0; - return 0; - } - - if (ctrlc()) { - puts("user interrupt!\n"); - phy_dev->link = 0; - return -EINTR; - } - - if ((i++ % 500) == 0) - printf("."); - - udelay(1000); /* 1 ms */ - status = readl(RGMII_STATUS_REG); - } while (!(status & RGMII_REG_STATUS_LINK)); - - puts(" done\n"); - - return 0; -} -#else -int keystone_sgmii_config(struct phy_device *phy_dev, int port, int interface) -{ - unsigned int i, status, mask; - unsigned int mr_adv_ability, control; - - switch (interface) { - case SGMII_LINK_MAC_MAC_AUTONEG: - mr_adv_ability = (SGMII_REG_MR_ADV_ENABLE | - SGMII_REG_MR_ADV_LINK | - SGMII_REG_MR_ADV_FULL_DUPLEX | - SGMII_REG_MR_ADV_GIG_MODE); - control = (SGMII_REG_CONTROL_MASTER | - SGMII_REG_CONTROL_AUTONEG); - - break; - case SGMII_LINK_MAC_PHY: - case SGMII_LINK_MAC_PHY_FORCED: - mr_adv_ability = SGMII_REG_MR_ADV_ENABLE; - control = SGMII_REG_CONTROL_AUTONEG; - - break; - case SGMII_LINK_MAC_MAC_FORCED: - mr_adv_ability = (SGMII_REG_MR_ADV_ENABLE | - SGMII_REG_MR_ADV_LINK | - SGMII_REG_MR_ADV_FULL_DUPLEX | - SGMII_REG_MR_ADV_GIG_MODE); - control = SGMII_REG_CONTROL_MASTER; - - break; - case SGMII_LINK_MAC_FIBER: - mr_adv_ability = 0x20; - control = SGMII_REG_CONTROL_AUTONEG; - - break; - default: - mr_adv_ability = SGMII_REG_MR_ADV_ENABLE; - control = SGMII_REG_CONTROL_AUTONEG; - } - - __raw_writel(0, SGMII_CTL_REG(port)); - - /* - * Wait for the SerDes pll to lock, - * but don't trap if lock is never read - */ - for (i = 0; i < 1000; i++) { - udelay(2000); - status = __raw_readl(SGMII_STATUS_REG(port)); - if ((status & SGMII_REG_STATUS_LOCK) != 0) - break; - } - - __raw_writel(mr_adv_ability, SGMII_MRADV_REG(port)); - __raw_writel(control, SGMII_CTL_REG(port)); - - - mask = SGMII_REG_STATUS_LINK; - - if (control & SGMII_REG_CONTROL_AUTONEG) - mask |= SGMII_REG_STATUS_AUTONEG; - - status = __raw_readl(SGMII_STATUS_REG(port)); - if ((status & mask) == mask) - return 0; - - printf("\n%s Waiting for SGMII auto negotiation to complete", - phy_dev->dev->name); - while ((status & mask) != mask) { - /* - * Timeout reached ? - */ - if (i > SGMII_ANEG_TIMEOUT) { - puts(" TIMEOUT !\n"); - phy_dev->link = 0; - return 0; - } - - if (ctrlc()) { - puts("user interrupt!\n"); - phy_dev->link = 0; - return -EINTR; - } - - if ((i++ % 500) == 0) - printf("."); - - udelay(1000); /* 1 ms */ - status = __raw_readl(SGMII_STATUS_REG(port)); - } - puts(" done\n"); - - return 0; -} -#endif - -int mac_sl_reset(u32 port) -{ - u32 i, v; - - if (port >= DEVICE_N_GMACSL_PORTS) - return GMACSL_RET_INVALID_PORT; - - /* Set the soft reset bit */ - writel(CPGMAC_REG_RESET_VAL_RESET, - DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RESET); - - /* Wait for the bit to clear */ - for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) { - v = readl(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RESET); - if ((v & CPGMAC_REG_RESET_VAL_RESET_MASK) != - CPGMAC_REG_RESET_VAL_RESET) - return GMACSL_RET_OK; - } - - /* Timeout on the reset */ - return GMACSL_RET_WARN_RESET_INCOMPLETE; -} - -int mac_sl_config(u_int16_t port, struct mac_sl_cfg *cfg) -{ - u32 v, i; - int ret = GMACSL_RET_OK; - - if (port >= DEVICE_N_GMACSL_PORTS) - return GMACSL_RET_INVALID_PORT; - - if (cfg->max_rx_len > CPGMAC_REG_MAXLEN_LEN) { - cfg->max_rx_len = CPGMAC_REG_MAXLEN_LEN; - ret = GMACSL_RET_WARN_MAXLEN_TOO_BIG; - } - - /* Must wait if the device is undergoing reset */ - for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) { - v = readl(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RESET); - if ((v & CPGMAC_REG_RESET_VAL_RESET_MASK) != - CPGMAC_REG_RESET_VAL_RESET) - break; - } - - if (i == DEVICE_EMACSL_RESET_POLL_COUNT) - return GMACSL_RET_CONFIG_FAIL_RESET_ACTIVE; - - writel(cfg->max_rx_len, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_MAXLEN); - writel(cfg->ctl, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_CTL); - -#ifndef CONFIG_SOC_K2HK - /* Map RX packet flow priority to 0 */ - writel(0, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RX_PRI_MAP); -#endif - - return ret; -} - -int ethss_config(u32 ctl, u32 max_pkt_size) -{ - u32 i; - - /* Max length register */ - writel(max_pkt_size, DEVICE_CPSW_BASE + CPSW_REG_MAXLEN); - - /* Control register */ - writel(ctl, DEVICE_CPSW_BASE + CPSW_REG_CTL); - - /* All statistics enabled by default */ - writel(CPSW_REG_VAL_STAT_ENABLE_ALL, - DEVICE_CPSW_BASE + CPSW_REG_STAT_PORT_EN); - - /* Reset and enable the ALE */ - writel(CPSW_REG_VAL_ALE_CTL_RESET_AND_ENABLE | - CPSW_REG_VAL_ALE_CTL_BYPASS, - DEVICE_CPSW_BASE + CPSW_REG_ALE_CONTROL); - - /* All ports put into forward mode */ - for (i = 0; i < DEVICE_CPSW_NUM_PORTS; i++) - writel(CPSW_REG_VAL_PORTCTL_FORWARD_MODE, - DEVICE_CPSW_BASE + CPSW_REG_ALE_PORTCTL(i)); - - return 0; -} - -int ethss_start(void) -{ - int i; - struct mac_sl_cfg cfg; - - cfg.max_rx_len = MAX_SIZE_STREAM_BUFFER; - cfg.ctl = GMACSL_ENABLE | GMACSL_RX_ENABLE_EXT_CTL; - - for (i = 0; i < DEVICE_N_GMACSL_PORTS; i++) { - mac_sl_reset(i); - mac_sl_config(i, &cfg); - } - - return 0; -} - -int ethss_stop(void) -{ - int i; - - for (i = 0; i < DEVICE_N_GMACSL_PORTS; i++) - mac_sl_reset(i); - - return 0; -} - -struct ks2_serdes ks2_serdes_sgmii_156p25mhz = { - .clk = SERDES_CLOCK_156P25M, - .rate = SERDES_RATE_5G, - .rate_mode = SERDES_QUARTER_RATE, - .intf = SERDES_PHY_SGMII, - .loopback = 0, -}; - -#ifndef CONFIG_SOC_K2G -static void keystone2_net_serdes_setup(void) -{ - ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII_BASE, - &ks2_serdes_sgmii_156p25mhz, - CONFIG_KSNET_SERDES_LANES_PER_SGMII); - -#if defined(CONFIG_SOC_K2E) || defined(CONFIG_SOC_K2L) - ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII2_BASE, - &ks2_serdes_sgmii_156p25mhz, - CONFIG_KSNET_SERDES_LANES_PER_SGMII); -#endif - - /* wait till setup */ - udelay(5000); -} -#endif - -#ifndef CONFIG_DM_ETH - -int keystone2_eth_read_mac_addr(struct eth_device *dev) -{ - struct eth_priv_t *eth_priv; - u32 maca = 0; - u32 macb = 0; - - eth_priv = (struct eth_priv_t *)dev->priv; - - /* Read the e-fuse mac address */ - if (eth_priv->slave_port == 1) { - maca = __raw_readl(MAC_ID_BASE_ADDR); - macb = __raw_readl(MAC_ID_BASE_ADDR + 4); - } - - dev->enetaddr[0] = (macb >> 8) & 0xff; - dev->enetaddr[1] = (macb >> 0) & 0xff; - dev->enetaddr[2] = (maca >> 24) & 0xff; - dev->enetaddr[3] = (maca >> 16) & 0xff; - dev->enetaddr[4] = (maca >> 8) & 0xff; - dev->enetaddr[5] = (maca >> 0) & 0xff; - - return 0; -} - -int32_t cpmac_drv_send(u32 *buffer, int num_bytes, int slave_port_num) -{ - if (num_bytes < EMAC_MIN_ETHERNET_PKT_SIZE) - num_bytes = EMAC_MIN_ETHERNET_PKT_SIZE; - - return ksnav_send(&netcp_pktdma, buffer, - num_bytes, (slave_port_num) << 16); -} - -/* Eth device open */ -static int keystone2_eth_open(struct eth_device *dev, bd_t *bis) -{ - struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv; - struct phy_device *phy_dev = eth_priv->phy_dev; - - debug("+ emac_open\n"); - - net_rx_buffs.rx_flow = eth_priv->rx_flow; - - sys_has_mdio = - (eth_priv->sgmii_link_type == SGMII_LINK_MAC_PHY) ? 1 : 0; - - if (sys_has_mdio) - keystone2_mdio_reset(mdio_bus); - -#ifdef CONFIG_SOC_K2G - keystone_rgmii_config(phy_dev); -#else - keystone_sgmii_config(phy_dev, eth_priv->slave_port - 1, - eth_priv->sgmii_link_type); -#endif - - udelay(10000); - - /* On chip switch configuration */ - ethss_config(target_get_switch_ctl(), SWITCH_MAX_PKT_SIZE); - - /* TODO: add error handling code */ - if (qm_init()) { - printf("ERROR: qm_init()\n"); - return -1; - } - if (ksnav_init(&netcp_pktdma, &net_rx_buffs)) { - qm_close(); - printf("ERROR: netcp_init()\n"); - return -1; - } - - /* - * Streaming switch configuration. If not present this - * statement is defined to void in target.h. - * If present this is usually defined to a series of register writes - */ - hw_config_streaming_switch(); - - if (sys_has_mdio) { - keystone2_mdio_reset(mdio_bus); - - phy_startup(phy_dev); - if (phy_dev->link == 0) { - ksnav_close(&netcp_pktdma); - qm_close(); - return -1; - } - } - - emac_gigabit_enable(dev); - - ethss_start(); - - debug("- emac_open\n"); - - emac_open = 1; - - return 0; -} - -/* Eth device close */ -void keystone2_eth_close(struct eth_device *dev) -{ - struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv; - struct phy_device *phy_dev = eth_priv->phy_dev; - - debug("+ emac_close\n"); - - if (!emac_open) - return; - - ethss_stop(); - - ksnav_close(&netcp_pktdma); - qm_close(); - phy_shutdown(phy_dev); - - emac_open = 0; - - debug("- emac_close\n"); -} - -/* - * This function sends a single packet on the network and returns - * positive number (number of bytes transmitted) or negative for error - */ -static int keystone2_eth_send_packet(struct eth_device *dev, - void *packet, int length) -{ - int ret_status = -1; - struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv; - struct phy_device *phy_dev = eth_priv->phy_dev; - - genphy_update_link(phy_dev); - if (phy_dev->link == 0) - return -1; - - if (cpmac_drv_send((u32 *)packet, length, eth_priv->slave_port) != 0) - return ret_status; - - return length; -} - -/* - * This function handles receipt of a packet from the network - */ -static int keystone2_eth_rcv_packet(struct eth_device *dev) -{ - void *hd; - int pkt_size; - u32 *pkt; - - hd = ksnav_recv(&netcp_pktdma, &pkt, &pkt_size); - if (hd == NULL) - return 0; - - net_process_received_packet((uchar *)pkt, pkt_size); - - ksnav_release_rxhd(&netcp_pktdma, hd); - - return pkt_size; -} - -#ifdef CONFIG_MCAST_TFTP -static int keystone2_eth_bcast_addr(struct eth_device *dev, u32 ip, u8 set) -{ - return 0; -} -#endif - -/* - * This function initializes the EMAC hardware. - */ -int keystone2_emac_initialize(struct eth_priv_t *eth_priv) -{ - int res; - struct eth_device *dev; - struct phy_device *phy_dev; - struct mdio_regs *adap_mdio = (struct mdio_regs *)EMAC_MDIO_BASE_ADDR; - - dev = malloc(sizeof(struct eth_device)); - if (dev == NULL) - return -1; - - memset(dev, 0, sizeof(struct eth_device)); - - strcpy(dev->name, eth_priv->int_name); - dev->priv = eth_priv; - - keystone2_eth_read_mac_addr(dev); - - dev->iobase = 0; - dev->init = keystone2_eth_open; - dev->halt = keystone2_eth_close; - dev->send = keystone2_eth_send_packet; - dev->recv = keystone2_eth_rcv_packet; -#ifdef CONFIG_MCAST_TFTP - dev->mcast = keystone2_eth_bcast_addr; -#endif - - eth_register(dev); - - /* Register MDIO bus if it's not registered yet */ - if (!mdio_bus) { - mdio_bus = mdio_alloc(); - mdio_bus->read = keystone2_mdio_read; - mdio_bus->write = keystone2_mdio_write; - mdio_bus->reset = keystone2_mdio_reset; - mdio_bus->priv = (void *)EMAC_MDIO_BASE_ADDR; - strcpy(mdio_bus->name, "ethernet-mdio"); - - res = mdio_register(mdio_bus); - if (res) - return res; - } - -#ifndef CONFIG_SOC_K2G - keystone2_net_serdes_setup(); -#endif - - /* Create phy device and bind it with driver */ -#ifdef CONFIG_KSNET_MDIO_PHY_CONFIG_ENABLE - phy_dev = phy_connect(mdio_bus, eth_priv->phy_addr, - dev, eth_priv->phy_if); - phy_config(phy_dev); -#else - phy_dev = phy_find_by_mask(mdio_bus, 1 << eth_priv->phy_addr, - eth_priv->phy_if); - phy_dev->dev = dev; -#endif - eth_priv->phy_dev = phy_dev; - - return 0; -} - -#else - -static int ks2_eth_start(struct udevice *dev) -{ - struct ks2_eth_priv *priv = dev_get_priv(dev); - -#ifdef CONFIG_SOC_K2G - keystone_rgmii_config(priv->phydev); -#else - keystone_sgmii_config(priv->phydev, priv->slave_port - 1, - priv->sgmii_link_type); -#endif - - udelay(10000); - - /* On chip switch configuration */ - ethss_config(target_get_switch_ctl(), SWITCH_MAX_PKT_SIZE); - - qm_init(); - - if (ksnav_init(priv->netcp_pktdma, &priv->net_rx_buffs)) { - pr_err("ksnav_init failed\n"); - goto err_knav_init; - } - - /* - * Streaming switch configuration. If not present this - * statement is defined to void in target.h. - * If present this is usually defined to a series of register writes - */ - hw_config_streaming_switch(); - - if (priv->has_mdio) { - keystone2_mdio_reset(priv->mdio_bus); - - phy_startup(priv->phydev); - if (priv->phydev->link == 0) { - pr_err("phy startup failed\n"); - goto err_phy_start; - } - } - - emac_gigabit_enable(dev); - - ethss_start(); - - priv->emac_open = true; - - return 0; - -err_phy_start: - ksnav_close(priv->netcp_pktdma); -err_knav_init: - qm_close(); - - return -EFAULT; -} - -static int ks2_eth_send(struct udevice *dev, void *packet, int length) -{ - struct ks2_eth_priv *priv = dev_get_priv(dev); - - genphy_update_link(priv->phydev); - if (priv->phydev->link == 0) - return -1; - - if (length < EMAC_MIN_ETHERNET_PKT_SIZE) - length = EMAC_MIN_ETHERNET_PKT_SIZE; - - return ksnav_send(priv->netcp_pktdma, (u32 *)packet, - length, (priv->slave_port) << 16); -} - -static int ks2_eth_recv(struct udevice *dev, int flags, uchar **packetp) -{ - struct ks2_eth_priv *priv = dev_get_priv(dev); - int pkt_size; - u32 *pkt = NULL; - - priv->hd = ksnav_recv(priv->netcp_pktdma, &pkt, &pkt_size); - if (priv->hd == NULL) - return -EAGAIN; - - *packetp = (uchar *)pkt; - - return pkt_size; -} - -static int ks2_eth_free_pkt(struct udevice *dev, uchar *packet, - int length) -{ - struct ks2_eth_priv *priv = dev_get_priv(dev); - - ksnav_release_rxhd(priv->netcp_pktdma, priv->hd); - - return 0; -} - -static void ks2_eth_stop(struct udevice *dev) -{ - struct ks2_eth_priv *priv = dev_get_priv(dev); - - if (!priv->emac_open) - return; - ethss_stop(); - - ksnav_close(priv->netcp_pktdma); - qm_close(); - phy_shutdown(priv->phydev); - priv->emac_open = false; -} - -int ks2_eth_read_rom_hwaddr(struct udevice *dev) -{ - struct ks2_eth_priv *priv = dev_get_priv(dev); - struct eth_pdata *pdata = dev_get_platdata(dev); - u32 maca = 0; - u32 macb = 0; - - /* Read the e-fuse mac address */ - if (priv->slave_port == 1) { - maca = __raw_readl(MAC_ID_BASE_ADDR); - macb = __raw_readl(MAC_ID_BASE_ADDR + 4); - } - - pdata->enetaddr[0] = (macb >> 8) & 0xff; - pdata->enetaddr[1] = (macb >> 0) & 0xff; - pdata->enetaddr[2] = (maca >> 24) & 0xff; - pdata->enetaddr[3] = (maca >> 16) & 0xff; - pdata->enetaddr[4] = (maca >> 8) & 0xff; - pdata->enetaddr[5] = (maca >> 0) & 0xff; - - return 0; -} - -int ks2_eth_write_hwaddr(struct udevice *dev) -{ - struct ks2_eth_priv *priv = dev_get_priv(dev); - struct eth_pdata *pdata = dev_get_platdata(dev); - - writel(mac_hi(pdata->enetaddr), - DEVICE_EMACSW_BASE(pdata->iobase, priv->slave_port - 1) + - CPGMACSL_REG_SA_HI); - writel(mac_lo(pdata->enetaddr), - DEVICE_EMACSW_BASE(pdata->iobase, priv->slave_port - 1) + - CPGMACSL_REG_SA_LO); - - return 0; -} - -static int ks2_eth_probe(struct udevice *dev) -{ - struct ks2_eth_priv *priv = dev_get_priv(dev); - struct mii_dev *mdio_bus; - int ret; - - priv->dev = dev; - - /* These clock enables has to be moved to common location */ - if (cpu_is_k2g()) - writel(KS2_ETHERNET_RGMII, KS2_ETHERNET_CFG); - - /* By default, select PA PLL clock as PA clock source */ -#ifndef CONFIG_SOC_K2G - if (psc_enable_module(KS2_LPSC_PA)) - return -EACCES; -#endif - if (psc_enable_module(KS2_LPSC_CPGMAC)) - return -EACCES; - if (psc_enable_module(KS2_LPSC_CRYPTO)) - return -EACCES; - - if (cpu_is_k2e() || cpu_is_k2l()) - pll_pa_clk_sel(); - - - priv->net_rx_buffs.buff_ptr = rx_buffs; - priv->net_rx_buffs.num_buffs = RX_BUFF_NUMS; - priv->net_rx_buffs.buff_len = RX_BUFF_LEN; - - if (priv->slave_port == 1) { - /* - * Register MDIO bus for slave 0 only, other slave have - * to re-use the same - */ - mdio_bus = mdio_alloc(); - if (!mdio_bus) { - pr_err("MDIO alloc failed\n"); - return -ENOMEM; - } - priv->mdio_bus = mdio_bus; - mdio_bus->read = keystone2_mdio_read; - mdio_bus->write = keystone2_mdio_write; - mdio_bus->reset = keystone2_mdio_reset; - mdio_bus->priv = priv->mdio_base; - sprintf(mdio_bus->name, "ethernet-mdio"); - - ret = mdio_register(mdio_bus); - if (ret) { - pr_err("MDIO bus register failed\n"); - return ret; - } - } else { - /* Get the MDIO bus from slave 0 device */ - struct ks2_eth_priv *parent_priv; - - parent_priv = dev_get_priv(dev->parent); - priv->mdio_bus = parent_priv->mdio_bus; - } - -#ifndef CONFIG_SOC_K2G - keystone2_net_serdes_setup(); -#endif - - priv->netcp_pktdma = &netcp_pktdma; - - if (priv->has_mdio) { - priv->phydev = phy_connect(priv->mdio_bus, priv->phy_addr, - dev, priv->phy_if); - phy_config(priv->phydev); - } - - return 0; -} - -int ks2_eth_remove(struct udevice *dev) -{ - struct ks2_eth_priv *priv = dev_get_priv(dev); - - free(priv->phydev); - mdio_unregister(priv->mdio_bus); - mdio_free(priv->mdio_bus); - - return 0; -} - -static const struct eth_ops ks2_eth_ops = { - .start = ks2_eth_start, - .send = ks2_eth_send, - .recv = ks2_eth_recv, - .free_pkt = ks2_eth_free_pkt, - .stop = ks2_eth_stop, - .read_rom_hwaddr = ks2_eth_read_rom_hwaddr, - .write_hwaddr = ks2_eth_write_hwaddr, -}; - -static int ks2_eth_bind_slaves(struct udevice *dev, int gbe, int *gbe_0) -{ - const void *fdt = gd->fdt_blob; - struct udevice *sl_dev; - int interfaces; - int sec_slave; - int slave; - int ret; - char *slave_name; - - interfaces = fdt_subnode_offset(fdt, gbe, "interfaces"); - fdt_for_each_subnode(slave, fdt, interfaces) { - int slave_no; - - slave_no = fdtdec_get_int(fdt, slave, "slave-port", -ENOENT); - if (slave_no == -ENOENT) - continue; - - if (slave_no == 0) { - /* This is the current eth device */ - *gbe_0 = slave; - } else { - /* Slave devices to be registered */ - slave_name = malloc(20); - snprintf(slave_name, 20, "netcp@slave-%d", slave_no); - ret = device_bind_driver_to_node(dev, "eth_ks2_sl", - slave_name, offset_to_ofnode(slave), - &sl_dev); - if (ret) { - pr_err("ks2_net - not able to bind slave interfaces\n"); - return ret; - } - } - } - - sec_slave = fdt_subnode_offset(fdt, gbe, "secondary-slave-ports"); - fdt_for_each_subnode(slave, fdt, sec_slave) { - int slave_no; - - slave_no = fdtdec_get_int(fdt, slave, "slave-port", -ENOENT); - if (slave_no == -ENOENT) - continue; - - /* Slave devices to be registered */ - slave_name = malloc(20); - snprintf(slave_name, 20, "netcp@slave-%d", slave_no); - ret = device_bind_driver_to_node(dev, "eth_ks2_sl", slave_name, - offset_to_ofnode(slave), &sl_dev); - if (ret) { - pr_err("ks2_net - not able to bind slave interfaces\n"); - return ret; - } - } - - return 0; -} - -static int ks2_eth_parse_slave_interface(int netcp, int slave, - struct ks2_eth_priv *priv, - struct eth_pdata *pdata) -{ - const void *fdt = gd->fdt_blob; - int mdio; - int phy; - int dma_count; - u32 dma_channel[8]; - - priv->slave_port = fdtdec_get_int(fdt, slave, "slave-port", -1); - priv->net_rx_buffs.rx_flow = priv->slave_port * 8; - - /* U-Boot slave port number starts with 1 instead of 0 */ - priv->slave_port += 1; - - dma_count = fdtdec_get_int_array_count(fdt, netcp, - "ti,navigator-dmas", - dma_channel, 8); - - if (dma_count > (2 * priv->slave_port)) { - int dma_idx; - - dma_idx = priv->slave_port * 2 - 1; - priv->net_rx_buffs.rx_flow = dma_channel[dma_idx]; - } - - priv->link_type = fdtdec_get_int(fdt, slave, "link-interface", -1); - - phy = fdtdec_lookup_phandle(fdt, slave, "phy-handle"); - if (phy >= 0) { - priv->phy_addr = fdtdec_get_int(fdt, phy, "reg", -1); - - mdio = fdt_parent_offset(fdt, phy); - if (mdio < 0) { - pr_err("mdio dt not found\n"); - return -ENODEV; - } - priv->mdio_base = (void *)fdtdec_get_addr(fdt, mdio, "reg"); - } - - if (priv->link_type == LINK_TYPE_SGMII_MAC_TO_PHY_MODE) { - priv->phy_if = PHY_INTERFACE_MODE_SGMII; - pdata->phy_interface = priv->phy_if; - priv->sgmii_link_type = SGMII_LINK_MAC_PHY; - priv->has_mdio = true; - } else if (priv->link_type == LINK_TYPE_RGMII_LINK_MAC_PHY) { - priv->phy_if = PHY_INTERFACE_MODE_RGMII; - pdata->phy_interface = priv->phy_if; - priv->has_mdio = true; - } - - return 0; -} - -static int ks2_sl_eth_ofdata_to_platdata(struct udevice *dev) -{ - struct ks2_eth_priv *priv = dev_get_priv(dev); - struct eth_pdata *pdata = dev_get_platdata(dev); - const void *fdt = gd->fdt_blob; - int slave = dev_of_offset(dev); - int interfaces; - int gbe; - int netcp_devices; - int netcp; - - interfaces = fdt_parent_offset(fdt, slave); - gbe = fdt_parent_offset(fdt, interfaces); - netcp_devices = fdt_parent_offset(fdt, gbe); - netcp = fdt_parent_offset(fdt, netcp_devices); - - ks2_eth_parse_slave_interface(netcp, slave, priv, pdata); - - pdata->iobase = fdtdec_get_addr(fdt, netcp, "reg"); - - return 0; -} - -static int ks2_eth_ofdata_to_platdata(struct udevice *dev) -{ - struct ks2_eth_priv *priv = dev_get_priv(dev); - struct eth_pdata *pdata = dev_get_platdata(dev); - const void *fdt = gd->fdt_blob; - int gbe_0 = -ENODEV; - int netcp_devices; - int gbe; - - netcp_devices = fdt_subnode_offset(fdt, dev_of_offset(dev), - "netcp-devices"); - gbe = fdt_subnode_offset(fdt, netcp_devices, "gbe"); - - ks2_eth_bind_slaves(dev, gbe, &gbe_0); - - ks2_eth_parse_slave_interface(dev_of_offset(dev), gbe_0, priv, pdata); - - pdata->iobase = devfdt_get_addr(dev); - - return 0; -} - -static const struct udevice_id ks2_eth_ids[] = { - { .compatible = "ti,netcp-1.0" }, - { } -}; - -U_BOOT_DRIVER(eth_ks2_slave) = { - .name = "eth_ks2_sl", - .id = UCLASS_ETH, - .ofdata_to_platdata = ks2_sl_eth_ofdata_to_platdata, - .probe = ks2_eth_probe, - .remove = ks2_eth_remove, - .ops = &ks2_eth_ops, - .priv_auto_alloc_size = sizeof(struct ks2_eth_priv), - .platdata_auto_alloc_size = sizeof(struct eth_pdata), - .flags = DM_FLAG_ALLOC_PRIV_DMA, -}; - -U_BOOT_DRIVER(eth_ks2) = { - .name = "eth_ks2", - .id = UCLASS_ETH, - .of_match = ks2_eth_ids, - .ofdata_to_platdata = ks2_eth_ofdata_to_platdata, - .probe = ks2_eth_probe, - .remove = ks2_eth_remove, - .ops = &ks2_eth_ops, - .priv_auto_alloc_size = sizeof(struct ks2_eth_priv), - .platdata_auto_alloc_size = sizeof(struct eth_pdata), - .flags = DM_FLAG_ALLOC_PRIV_DMA, -}; -#endif diff --git a/drivers/net/ti/Kconfig b/drivers/net/ti/Kconfig new file mode 100644 index 00000000000..35a6b5d499d --- /dev/null +++ b/drivers/net/ti/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + +config DRIVER_TI_CPSW + bool "TI Common Platform Ethernet Switch" + select PHYLIB + help + This driver supports the TI three port switch gigabit ethernet + subsystem found in the TI SoCs. + +config DRIVER_TI_EMAC + bool "TI Davinci EMAC" + help + Support for davinci emac diff --git a/drivers/net/ti/Makefile b/drivers/net/ti/Makefile new file mode 100644 index 00000000000..4ab4a27498e --- /dev/null +++ b/drivers/net/ti/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + +obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o cpsw-common.o +obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o +obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o diff --git a/drivers/net/ti/cpsw-common.c b/drivers/net/ti/cpsw-common.c new file mode 100644 index 00000000000..6c8ddbd9361 --- /dev/null +++ b/drivers/net/ti/cpsw-common.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * CPSW common - libs used across TI ethernet devices. + * + * Copyright (C) 2016, Texas Instruments, Incorporated + */ + +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define CTRL_MAC_REG(offset, id) ((offset) + 0x8 * (id)) + +static int davinci_emac_3517_get_macid(struct udevice *dev, u16 offset, + int slave, u8 *mac_addr) +{ + void *fdt = (void *)gd->fdt_blob; + int node = dev_of_offset(dev); + u32 macid_lsb; + u32 macid_msb; + fdt32_t gmii = 0; + int syscon; + u32 addr; + + syscon = fdtdec_lookup_phandle(fdt, node, "syscon"); + if (syscon < 0) { + pr_err("Syscon offset not found\n"); + return -ENOENT; + } + + addr = (u32)map_physmem(fdt_translate_address(fdt, syscon, &gmii), + sizeof(u32), MAP_NOCACHE); + if (addr == FDT_ADDR_T_NONE) { + pr_err("Not able to get syscon address to get mac efuse address\n"); + return -ENOENT; + } + + addr += CTRL_MAC_REG(offset, slave); + + /* try reading mac address from efuse */ + macid_lsb = readl(addr); + macid_msb = readl(addr + 4); + + mac_addr[0] = (macid_msb >> 16) & 0xff; + mac_addr[1] = (macid_msb >> 8) & 0xff; + mac_addr[2] = macid_msb & 0xff; + mac_addr[3] = (macid_lsb >> 16) & 0xff; + mac_addr[4] = (macid_lsb >> 8) & 0xff; + mac_addr[5] = macid_lsb & 0xff; + + return 0; +} + +static int cpsw_am33xx_cm_get_macid(struct udevice *dev, u16 offset, int slave, + u8 *mac_addr) +{ + void *fdt = (void *)gd->fdt_blob; + int node = dev_of_offset(dev); + u32 macid_lo; + u32 macid_hi; + fdt32_t gmii = 0; + int syscon; + u32 addr; + + syscon = fdtdec_lookup_phandle(fdt, node, "syscon"); + if (syscon < 0) { + pr_err("Syscon offset not found\n"); + return -ENOENT; + } + + addr = (u32)map_physmem(fdt_translate_address(fdt, syscon, &gmii), + sizeof(u32), MAP_NOCACHE); + if (addr == FDT_ADDR_T_NONE) { + pr_err("Not able to get syscon address to get mac efuse address\n"); + return -ENOENT; + } + + addr += CTRL_MAC_REG(offset, slave); + + /* try reading mac address from efuse */ + macid_lo = readl(addr); + macid_hi = readl(addr + 4); + + mac_addr[5] = (macid_lo >> 8) & 0xff; + mac_addr[4] = macid_lo & 0xff; + mac_addr[3] = (macid_hi >> 24) & 0xff; + mac_addr[2] = (macid_hi >> 16) & 0xff; + mac_addr[1] = (macid_hi >> 8) & 0xff; + mac_addr[0] = macid_hi & 0xff; + + return 0; +} + +int ti_cm_get_macid(struct udevice *dev, int slave, u8 *mac_addr) +{ + if (of_machine_is_compatible("ti,dm8148")) + return cpsw_am33xx_cm_get_macid(dev, 0x630, slave, mac_addr); + + if (of_machine_is_compatible("ti,am33xx")) + return cpsw_am33xx_cm_get_macid(dev, 0x630, slave, mac_addr); + + if (device_is_compatible(dev, "ti,am3517-emac")) + return davinci_emac_3517_get_macid(dev, 0x110, slave, mac_addr); + + if (device_is_compatible(dev, "ti,dm816-emac")) + return cpsw_am33xx_cm_get_macid(dev, 0x30, slave, mac_addr); + + if (of_machine_is_compatible("ti,am43")) + return cpsw_am33xx_cm_get_macid(dev, 0x630, slave, mac_addr); + + if (of_machine_is_compatible("ti,dra7")) + return davinci_emac_3517_get_macid(dev, 0x514, slave, mac_addr); + + dev_err(dev, "incompatible machine/device type for reading mac address\n"); + return -ENOENT; +} diff --git a/drivers/net/ti/cpsw.c b/drivers/net/ti/cpsw.c new file mode 100644 index 00000000000..8e2a48cfd67 --- /dev/null +++ b/drivers/net/ti/cpsw.c @@ -0,0 +1,1508 @@ +/* + * CPSW Ethernet Switch Driver + * + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define BITMASK(bits) (BIT(bits) - 1) +#define PHY_REG_MASK 0x1f +#define PHY_ID_MASK 0x1f +#define NUM_DESCS (PKTBUFSRX * 2) +#define PKT_MIN 60 +#define PKT_MAX (1500 + 14 + 4 + 4) +#define CLEAR_BIT 1 +#define GIGABITEN BIT(7) +#define FULLDUPLEXEN BIT(0) +#define MIIEN BIT(15) + +/* reg offset */ +#define CPSW_HOST_PORT_OFFSET 0x108 +#define CPSW_SLAVE0_OFFSET 0x208 +#define CPSW_SLAVE1_OFFSET 0x308 +#define CPSW_SLAVE_SIZE 0x100 +#define CPSW_CPDMA_OFFSET 0x800 +#define CPSW_HW_STATS 0x900 +#define CPSW_STATERAM_OFFSET 0xa00 +#define CPSW_CPTS_OFFSET 0xc00 +#define CPSW_ALE_OFFSET 0xd00 +#define CPSW_SLIVER0_OFFSET 0xd80 +#define CPSW_SLIVER1_OFFSET 0xdc0 +#define CPSW_BD_OFFSET 0x2000 +#define CPSW_MDIO_DIV 0xff + +#define AM335X_GMII_SEL_OFFSET 0x630 + +/* DMA Registers */ +#define CPDMA_TXCONTROL 0x004 +#define CPDMA_RXCONTROL 0x014 +#define CPDMA_SOFTRESET 0x01c +#define CPDMA_RXFREE 0x0e0 +#define CPDMA_TXHDP_VER1 0x100 +#define CPDMA_TXHDP_VER2 0x200 +#define CPDMA_RXHDP_VER1 0x120 +#define CPDMA_RXHDP_VER2 0x220 +#define CPDMA_TXCP_VER1 0x140 +#define CPDMA_TXCP_VER2 0x240 +#define CPDMA_RXCP_VER1 0x160 +#define CPDMA_RXCP_VER2 0x260 + +/* Descriptor mode bits */ +#define CPDMA_DESC_SOP BIT(31) +#define CPDMA_DESC_EOP BIT(30) +#define CPDMA_DESC_OWNER BIT(29) +#define CPDMA_DESC_EOQ BIT(28) + +/* + * This timeout definition is a worst-case ultra defensive measure against + * unexpected controller lock ups. Ideally, we should never ever hit this + * scenario in practice. + */ +#define MDIO_TIMEOUT 100 /* msecs */ +#define CPDMA_TIMEOUT 100 /* msecs */ + +struct cpsw_mdio_regs { + u32 version; + u32 control; +#define CONTROL_IDLE BIT(31) +#define CONTROL_ENABLE BIT(30) + + u32 alive; + u32 link; + u32 linkintraw; + u32 linkintmasked; + u32 __reserved_0[2]; + u32 userintraw; + u32 userintmasked; + u32 userintmaskset; + u32 userintmaskclr; + u32 __reserved_1[20]; + + struct { + u32 access; + u32 physel; +#define USERACCESS_GO BIT(31) +#define USERACCESS_WRITE BIT(30) +#define USERACCESS_ACK BIT(29) +#define USERACCESS_READ (0) +#define USERACCESS_DATA (0xffff) + } user[0]; +}; + +struct cpsw_regs { + u32 id_ver; + u32 control; + u32 soft_reset; + u32 stat_port_en; + u32 ptype; +}; + +struct cpsw_slave_regs { + u32 max_blks; + u32 blk_cnt; + u32 flow_thresh; + u32 port_vlan; + u32 tx_pri_map; +#ifdef CONFIG_AM33XX + u32 gap_thresh; +#elif defined(CONFIG_TI814X) + u32 ts_ctl; + u32 ts_seq_ltype; + u32 ts_vlan; +#endif + u32 sa_lo; + u32 sa_hi; +}; + +struct cpsw_host_regs { + u32 max_blks; + u32 blk_cnt; + u32 flow_thresh; + u32 port_vlan; + u32 tx_pri_map; + u32 cpdma_tx_pri_map; + u32 cpdma_rx_chan_map; +}; + +struct cpsw_sliver_regs { + u32 id_ver; + u32 mac_control; + u32 mac_status; + u32 soft_reset; + u32 rx_maxlen; + u32 __reserved_0; + u32 rx_pause; + u32 tx_pause; + u32 __reserved_1; + u32 rx_pri_map; +}; + +#define ALE_ENTRY_BITS 68 +#define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) + +/* ALE Registers */ +#define ALE_CONTROL 0x08 +#define ALE_UNKNOWNVLAN 0x18 +#define ALE_TABLE_CONTROL 0x20 +#define ALE_TABLE 0x34 +#define ALE_PORTCTL 0x40 + +#define ALE_TABLE_WRITE BIT(31) + +#define ALE_TYPE_FREE 0 +#define ALE_TYPE_ADDR 1 +#define ALE_TYPE_VLAN 2 +#define ALE_TYPE_VLAN_ADDR 3 + +#define ALE_UCAST_PERSISTANT 0 +#define ALE_UCAST_UNTOUCHED 1 +#define ALE_UCAST_OUI 2 +#define ALE_UCAST_TOUCHED 3 + +#define ALE_MCAST_FWD 0 +#define ALE_MCAST_BLOCK_LEARN_FWD 1 +#define ALE_MCAST_FWD_LEARN 2 +#define ALE_MCAST_FWD_2 3 + +enum cpsw_ale_port_state { + ALE_PORT_STATE_DISABLE = 0x00, + ALE_PORT_STATE_BLOCK = 0x01, + ALE_PORT_STATE_LEARN = 0x02, + ALE_PORT_STATE_FORWARD = 0x03, +}; + +/* ALE unicast entry flags - passed into cpsw_ale_add_ucast() */ +#define ALE_SECURE 1 +#define ALE_BLOCKED 2 + +struct cpsw_slave { + struct cpsw_slave_regs *regs; + struct cpsw_sliver_regs *sliver; + int slave_num; + u32 mac_control; + struct cpsw_slave_data *data; +}; + +struct cpdma_desc { + /* hardware fields */ + u32 hw_next; + u32 hw_buffer; + u32 hw_len; + u32 hw_mode; + /* software fields */ + u32 sw_buffer; + u32 sw_len; +}; + +struct cpdma_chan { + struct cpdma_desc *head, *tail; + void *hdp, *cp, *rxfree; +}; + +/* AM33xx SoC specific definitions for the CONTROL port */ +#define AM33XX_GMII_SEL_MODE_MII 0 +#define AM33XX_GMII_SEL_MODE_RMII 1 +#define AM33XX_GMII_SEL_MODE_RGMII 2 + +#define AM33XX_GMII_SEL_RGMII1_IDMODE BIT(4) +#define AM33XX_GMII_SEL_RGMII2_IDMODE BIT(5) +#define AM33XX_GMII_SEL_RMII1_IO_CLK_EN BIT(6) +#define AM33XX_GMII_SEL_RMII2_IO_CLK_EN BIT(7) + +#define GMII_SEL_MODE_MASK 0x3 + +#define desc_write(desc, fld, val) __raw_writel((u32)(val), &(desc)->fld) +#define desc_read(desc, fld) __raw_readl(&(desc)->fld) +#define desc_read_ptr(desc, fld) ((void *)__raw_readl(&(desc)->fld)) + +#define chan_write(chan, fld, val) __raw_writel((u32)(val), (chan)->fld) +#define chan_read(chan, fld) __raw_readl((chan)->fld) +#define chan_read_ptr(chan, fld) ((void *)__raw_readl((chan)->fld)) + +#define for_active_slave(slave, priv) \ + slave = (priv)->slaves + (priv)->data.active_slave; if (slave) +#define for_each_slave(slave, priv) \ + for (slave = (priv)->slaves; slave != (priv)->slaves + \ + (priv)->data.slaves; slave++) + +struct cpsw_priv { +#ifdef CONFIG_DM_ETH + struct udevice *dev; +#else + struct eth_device *dev; +#endif + struct cpsw_platform_data data; + int host_port; + + struct cpsw_regs *regs; + void *dma_regs; + struct cpsw_host_regs *host_port_regs; + void *ale_regs; + + struct cpdma_desc *descs; + struct cpdma_desc *desc_free; + struct cpdma_chan rx_chan, tx_chan; + + struct cpsw_slave *slaves; + struct phy_device *phydev; + struct mii_dev *bus; + + u32 phy_mask; +}; + +static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) +{ + int idx; + + idx = start / 32; + start -= idx * 32; + idx = 2 - idx; /* flip */ + return (ale_entry[idx] >> start) & BITMASK(bits); +} + +static inline void cpsw_ale_set_field(u32 *ale_entry, u32 start, u32 bits, + u32 value) +{ + int idx; + + value &= BITMASK(bits); + idx = start / 32; + start -= idx * 32; + idx = 2 - idx; /* flip */ + ale_entry[idx] &= ~(BITMASK(bits) << start); + ale_entry[idx] |= (value << start); +} + +#define DEFINE_ALE_FIELD(name, start, bits) \ +static inline int cpsw_ale_get_##name(u32 *ale_entry) \ +{ \ + return cpsw_ale_get_field(ale_entry, start, bits); \ +} \ +static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value) \ +{ \ + cpsw_ale_set_field(ale_entry, start, bits, value); \ +} + +DEFINE_ALE_FIELD(entry_type, 60, 2) +DEFINE_ALE_FIELD(mcast_state, 62, 2) +DEFINE_ALE_FIELD(port_mask, 66, 3) +DEFINE_ALE_FIELD(ucast_type, 62, 2) +DEFINE_ALE_FIELD(port_num, 66, 2) +DEFINE_ALE_FIELD(blocked, 65, 1) +DEFINE_ALE_FIELD(secure, 64, 1) +DEFINE_ALE_FIELD(mcast, 40, 1) + +/* The MAC address field in the ALE entry cannot be macroized as above */ +static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr) +{ + int i; + + for (i = 0; i < 6; i++) + addr[i] = cpsw_ale_get_field(ale_entry, 40 - 8*i, 8); +} + +static inline void cpsw_ale_set_addr(u32 *ale_entry, const u8 *addr) +{ + int i; + + for (i = 0; i < 6; i++) + cpsw_ale_set_field(ale_entry, 40 - 8*i, 8, addr[i]); +} + +static int cpsw_ale_read(struct cpsw_priv *priv, int idx, u32 *ale_entry) +{ + int i; + + __raw_writel(idx, priv->ale_regs + ALE_TABLE_CONTROL); + + for (i = 0; i < ALE_ENTRY_WORDS; i++) + ale_entry[i] = __raw_readl(priv->ale_regs + ALE_TABLE + 4 * i); + + return idx; +} + +static int cpsw_ale_write(struct cpsw_priv *priv, int idx, u32 *ale_entry) +{ + int i; + + for (i = 0; i < ALE_ENTRY_WORDS; i++) + __raw_writel(ale_entry[i], priv->ale_regs + ALE_TABLE + 4 * i); + + __raw_writel(idx | ALE_TABLE_WRITE, priv->ale_regs + ALE_TABLE_CONTROL); + + return idx; +} + +static int cpsw_ale_match_addr(struct cpsw_priv *priv, const u8 *addr) +{ + u32 ale_entry[ALE_ENTRY_WORDS]; + int type, idx; + + for (idx = 0; idx < priv->data.ale_entries; idx++) { + u8 entry_addr[6]; + + cpsw_ale_read(priv, idx, ale_entry); + type = cpsw_ale_get_entry_type(ale_entry); + if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR) + continue; + cpsw_ale_get_addr(ale_entry, entry_addr); + if (memcmp(entry_addr, addr, 6) == 0) + return idx; + } + return -ENOENT; +} + +static int cpsw_ale_match_free(struct cpsw_priv *priv) +{ + u32 ale_entry[ALE_ENTRY_WORDS]; + int type, idx; + + for (idx = 0; idx < priv->data.ale_entries; idx++) { + cpsw_ale_read(priv, idx, ale_entry); + type = cpsw_ale_get_entry_type(ale_entry); + if (type == ALE_TYPE_FREE) + return idx; + } + return -ENOENT; +} + +static int cpsw_ale_find_ageable(struct cpsw_priv *priv) +{ + u32 ale_entry[ALE_ENTRY_WORDS]; + int type, idx; + + for (idx = 0; idx < priv->data.ale_entries; idx++) { + cpsw_ale_read(priv, idx, ale_entry); + type = cpsw_ale_get_entry_type(ale_entry); + if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR) + continue; + if (cpsw_ale_get_mcast(ale_entry)) + continue; + type = cpsw_ale_get_ucast_type(ale_entry); + if (type != ALE_UCAST_PERSISTANT && + type != ALE_UCAST_OUI) + return idx; + } + return -ENOENT; +} + +static int cpsw_ale_add_ucast(struct cpsw_priv *priv, const u8 *addr, + int port, int flags) +{ + u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; + int idx; + + cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR); + cpsw_ale_set_addr(ale_entry, addr); + cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT); + cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0); + cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); + cpsw_ale_set_port_num(ale_entry, port); + + idx = cpsw_ale_match_addr(priv, addr); + if (idx < 0) + idx = cpsw_ale_match_free(priv); + if (idx < 0) + idx = cpsw_ale_find_ageable(priv); + if (idx < 0) + return -ENOMEM; + + cpsw_ale_write(priv, idx, ale_entry); + return 0; +} + +static int cpsw_ale_add_mcast(struct cpsw_priv *priv, const u8 *addr, + int port_mask) +{ + u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; + int idx, mask; + + idx = cpsw_ale_match_addr(priv, addr); + if (idx >= 0) + cpsw_ale_read(priv, idx, ale_entry); + + cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR); + cpsw_ale_set_addr(ale_entry, addr); + cpsw_ale_set_mcast_state(ale_entry, ALE_MCAST_FWD_2); + + mask = cpsw_ale_get_port_mask(ale_entry); + port_mask |= mask; + cpsw_ale_set_port_mask(ale_entry, port_mask); + + if (idx < 0) + idx = cpsw_ale_match_free(priv); + if (idx < 0) + idx = cpsw_ale_find_ageable(priv); + if (idx < 0) + return -ENOMEM; + + cpsw_ale_write(priv, idx, ale_entry); + return 0; +} + +static inline void cpsw_ale_control(struct cpsw_priv *priv, int bit, int val) +{ + u32 tmp, mask = BIT(bit); + + tmp = __raw_readl(priv->ale_regs + ALE_CONTROL); + tmp &= ~mask; + tmp |= val ? mask : 0; + __raw_writel(tmp, priv->ale_regs + ALE_CONTROL); +} + +#define cpsw_ale_enable(priv, val) cpsw_ale_control(priv, 31, val) +#define cpsw_ale_clear(priv, val) cpsw_ale_control(priv, 30, val) +#define cpsw_ale_vlan_aware(priv, val) cpsw_ale_control(priv, 2, val) + +static inline void cpsw_ale_port_state(struct cpsw_priv *priv, int port, + int val) +{ + int offset = ALE_PORTCTL + 4 * port; + u32 tmp, mask = 0x3; + + tmp = __raw_readl(priv->ale_regs + offset); + tmp &= ~mask; + tmp |= val & mask; + __raw_writel(tmp, priv->ale_regs + offset); +} + +static struct cpsw_mdio_regs *mdio_regs; + +/* wait until hardware is ready for another user access */ +static inline u32 wait_for_user_access(void) +{ + u32 reg = 0; + int timeout = MDIO_TIMEOUT; + + while (timeout-- && + ((reg = __raw_readl(&mdio_regs->user[0].access)) & USERACCESS_GO)) + udelay(10); + + if (timeout == -1) { + printf("wait_for_user_access Timeout\n"); + return -ETIMEDOUT; + } + return reg; +} + +/* wait until hardware state machine is idle */ +static inline void wait_for_idle(void) +{ + int timeout = MDIO_TIMEOUT; + + while (timeout-- && + ((__raw_readl(&mdio_regs->control) & CONTROL_IDLE) == 0)) + udelay(10); + + if (timeout == -1) + printf("wait_for_idle Timeout\n"); +} + +static int cpsw_mdio_read(struct mii_dev *bus, int phy_id, + int dev_addr, int phy_reg) +{ + int data; + u32 reg; + + if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK) + return -EINVAL; + + wait_for_user_access(); + reg = (USERACCESS_GO | USERACCESS_READ | (phy_reg << 21) | + (phy_id << 16)); + __raw_writel(reg, &mdio_regs->user[0].access); + reg = wait_for_user_access(); + + data = (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -1; + return data; +} + +static int cpsw_mdio_write(struct mii_dev *bus, int phy_id, int dev_addr, + int phy_reg, u16 data) +{ + u32 reg; + + if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK) + return -EINVAL; + + wait_for_user_access(); + reg = (USERACCESS_GO | USERACCESS_WRITE | (phy_reg << 21) | + (phy_id << 16) | (data & USERACCESS_DATA)); + __raw_writel(reg, &mdio_regs->user[0].access); + wait_for_user_access(); + + return 0; +} + +static void cpsw_mdio_init(const char *name, u32 mdio_base, u32 div) +{ + struct mii_dev *bus = mdio_alloc(); + + mdio_regs = (struct cpsw_mdio_regs *)mdio_base; + + /* set enable and clock divider */ + __raw_writel(div | CONTROL_ENABLE, &mdio_regs->control); + + /* + * wait for scan logic to settle: + * the scan time consists of (a) a large fixed component, and (b) a + * small component that varies with the mii bus frequency. These + * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x + * silicon. Since the effect of (b) was found to be largely + * negligible, we keep things simple here. + */ + udelay(1000); + + bus->read = cpsw_mdio_read; + bus->write = cpsw_mdio_write; + strcpy(bus->name, name); + + mdio_register(bus); +} + +/* Set a self-clearing bit in a register, and wait for it to clear */ +static inline void setbit_and_wait_for_clear32(void *addr) +{ + __raw_writel(CLEAR_BIT, addr); + while (__raw_readl(addr) & CLEAR_BIT) + ; +} + +#define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \ + ((mac)[2] << 16) | ((mac)[3] << 24)) +#define mac_lo(mac) (((mac)[4] << 0) | ((mac)[5] << 8)) + +static void cpsw_set_slave_mac(struct cpsw_slave *slave, + struct cpsw_priv *priv) +{ +#ifdef CONFIG_DM_ETH + struct eth_pdata *pdata = dev_get_platdata(priv->dev); + + writel(mac_hi(pdata->enetaddr), &slave->regs->sa_hi); + writel(mac_lo(pdata->enetaddr), &slave->regs->sa_lo); +#else + __raw_writel(mac_hi(priv->dev->enetaddr), &slave->regs->sa_hi); + __raw_writel(mac_lo(priv->dev->enetaddr), &slave->regs->sa_lo); +#endif +} + +static int cpsw_slave_update_link(struct cpsw_slave *slave, + struct cpsw_priv *priv, int *link) +{ + struct phy_device *phy; + u32 mac_control = 0; + int ret = -ENODEV; + + phy = priv->phydev; + if (!phy) + goto out; + + ret = phy_startup(phy); + if (ret) + goto out; + + if (link) + *link = phy->link; + + if (phy->link) { /* link up */ + mac_control = priv->data.mac_control; + if (phy->speed == 1000) + mac_control |= GIGABITEN; + if (phy->duplex == DUPLEX_FULL) + mac_control |= FULLDUPLEXEN; + if (phy->speed == 100) + mac_control |= MIIEN; + } + + if (mac_control == slave->mac_control) + goto out; + + if (mac_control) { + printf("link up on port %d, speed %d, %s duplex\n", + slave->slave_num, phy->speed, + (phy->duplex == DUPLEX_FULL) ? "full" : "half"); + } else { + printf("link down on port %d\n", slave->slave_num); + } + + __raw_writel(mac_control, &slave->sliver->mac_control); + slave->mac_control = mac_control; + +out: + return ret; +} + +static int cpsw_update_link(struct cpsw_priv *priv) +{ + int ret = -ENODEV; + struct cpsw_slave *slave; + + for_active_slave(slave, priv) + ret = cpsw_slave_update_link(slave, priv, NULL); + + return ret; +} + +static inline u32 cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num) +{ + if (priv->host_port == 0) + return slave_num + 1; + else + return slave_num; +} + +static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv) +{ + u32 slave_port; + + setbit_and_wait_for_clear32(&slave->sliver->soft_reset); + + /* setup priority mapping */ + __raw_writel(0x76543210, &slave->sliver->rx_pri_map); + __raw_writel(0x33221100, &slave->regs->tx_pri_map); + + /* setup max packet size, and mac address */ + __raw_writel(PKT_MAX, &slave->sliver->rx_maxlen); + cpsw_set_slave_mac(slave, priv); + + slave->mac_control = 0; /* no link yet */ + + /* enable forwarding */ + slave_port = cpsw_get_slave_port(priv, slave->slave_num); + cpsw_ale_port_state(priv, slave_port, ALE_PORT_STATE_FORWARD); + + cpsw_ale_add_mcast(priv, net_bcast_ethaddr, 1 << slave_port); + + priv->phy_mask |= 1 << slave->data->phy_addr; +} + +static struct cpdma_desc *cpdma_desc_alloc(struct cpsw_priv *priv) +{ + struct cpdma_desc *desc = priv->desc_free; + + if (desc) + priv->desc_free = desc_read_ptr(desc, hw_next); + return desc; +} + +static void cpdma_desc_free(struct cpsw_priv *priv, struct cpdma_desc *desc) +{ + if (desc) { + desc_write(desc, hw_next, priv->desc_free); + priv->desc_free = desc; + } +} + +static int cpdma_submit(struct cpsw_priv *priv, struct cpdma_chan *chan, + void *buffer, int len) +{ + struct cpdma_desc *desc, *prev; + u32 mode; + + desc = cpdma_desc_alloc(priv); + if (!desc) + return -ENOMEM; + + if (len < PKT_MIN) + len = PKT_MIN; + + mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP; + + desc_write(desc, hw_next, 0); + desc_write(desc, hw_buffer, buffer); + desc_write(desc, hw_len, len); + desc_write(desc, hw_mode, mode | len); + desc_write(desc, sw_buffer, buffer); + desc_write(desc, sw_len, len); + + if (!chan->head) { + /* simple case - first packet enqueued */ + chan->head = desc; + chan->tail = desc; + chan_write(chan, hdp, desc); + goto done; + } + + /* not the first packet - enqueue at the tail */ + prev = chan->tail; + desc_write(prev, hw_next, desc); + chan->tail = desc; + + /* next check if EOQ has been triggered already */ + if (desc_read(prev, hw_mode) & CPDMA_DESC_EOQ) + chan_write(chan, hdp, desc); + +done: + if (chan->rxfree) + chan_write(chan, rxfree, 1); + return 0; +} + +static int cpdma_process(struct cpsw_priv *priv, struct cpdma_chan *chan, + void **buffer, int *len) +{ + struct cpdma_desc *desc = chan->head; + u32 status; + + if (!desc) + return -ENOENT; + + status = desc_read(desc, hw_mode); + + if (len) + *len = status & 0x7ff; + + if (buffer) + *buffer = desc_read_ptr(desc, sw_buffer); + + if (status & CPDMA_DESC_OWNER) { + if (chan_read(chan, hdp) == 0) { + if (desc_read(desc, hw_mode) & CPDMA_DESC_OWNER) + chan_write(chan, hdp, desc); + } + + return -EBUSY; + } + + chan->head = desc_read_ptr(desc, hw_next); + chan_write(chan, cp, desc); + + cpdma_desc_free(priv, desc); + return 0; +} + +static int _cpsw_init(struct cpsw_priv *priv, u8 *enetaddr) +{ + struct cpsw_slave *slave; + int i, ret; + + /* soft reset the controller and initialize priv */ + setbit_and_wait_for_clear32(&priv->regs->soft_reset); + + /* initialize and reset the address lookup engine */ + cpsw_ale_enable(priv, 1); + cpsw_ale_clear(priv, 1); + cpsw_ale_vlan_aware(priv, 0); /* vlan unaware mode */ + + /* setup host port priority mapping */ + __raw_writel(0x76543210, &priv->host_port_regs->cpdma_tx_pri_map); + __raw_writel(0, &priv->host_port_regs->cpdma_rx_chan_map); + + /* disable priority elevation and enable statistics on all ports */ + __raw_writel(0, &priv->regs->ptype); + + /* enable statistics collection only on the host port */ + __raw_writel(BIT(priv->host_port), &priv->regs->stat_port_en); + __raw_writel(0x7, &priv->regs->stat_port_en); + + cpsw_ale_port_state(priv, priv->host_port, ALE_PORT_STATE_FORWARD); + + cpsw_ale_add_ucast(priv, enetaddr, priv->host_port, ALE_SECURE); + cpsw_ale_add_mcast(priv, net_bcast_ethaddr, 1 << priv->host_port); + + for_active_slave(slave, priv) + cpsw_slave_init(slave, priv); + + ret = cpsw_update_link(priv); + if (ret) + goto out; + + /* init descriptor pool */ + for (i = 0; i < NUM_DESCS; i++) { + desc_write(&priv->descs[i], hw_next, + (i == (NUM_DESCS - 1)) ? 0 : &priv->descs[i+1]); + } + priv->desc_free = &priv->descs[0]; + + /* initialize channels */ + if (priv->data.version == CPSW_CTRL_VERSION_2) { + memset(&priv->rx_chan, 0, sizeof(struct cpdma_chan)); + priv->rx_chan.hdp = priv->dma_regs + CPDMA_RXHDP_VER2; + priv->rx_chan.cp = priv->dma_regs + CPDMA_RXCP_VER2; + priv->rx_chan.rxfree = priv->dma_regs + CPDMA_RXFREE; + + memset(&priv->tx_chan, 0, sizeof(struct cpdma_chan)); + priv->tx_chan.hdp = priv->dma_regs + CPDMA_TXHDP_VER2; + priv->tx_chan.cp = priv->dma_regs + CPDMA_TXCP_VER2; + } else { + memset(&priv->rx_chan, 0, sizeof(struct cpdma_chan)); + priv->rx_chan.hdp = priv->dma_regs + CPDMA_RXHDP_VER1; + priv->rx_chan.cp = priv->dma_regs + CPDMA_RXCP_VER1; + priv->rx_chan.rxfree = priv->dma_regs + CPDMA_RXFREE; + + memset(&priv->tx_chan, 0, sizeof(struct cpdma_chan)); + priv->tx_chan.hdp = priv->dma_regs + CPDMA_TXHDP_VER1; + priv->tx_chan.cp = priv->dma_regs + CPDMA_TXCP_VER1; + } + + /* clear dma state */ + setbit_and_wait_for_clear32(priv->dma_regs + CPDMA_SOFTRESET); + + if (priv->data.version == CPSW_CTRL_VERSION_2) { + for (i = 0; i < priv->data.channels; i++) { + __raw_writel(0, priv->dma_regs + CPDMA_RXHDP_VER2 + 4 + * i); + __raw_writel(0, priv->dma_regs + CPDMA_RXFREE + 4 + * i); + __raw_writel(0, priv->dma_regs + CPDMA_RXCP_VER2 + 4 + * i); + __raw_writel(0, priv->dma_regs + CPDMA_TXHDP_VER2 + 4 + * i); + __raw_writel(0, priv->dma_regs + CPDMA_TXCP_VER2 + 4 + * i); + } + } else { + for (i = 0; i < priv->data.channels; i++) { + __raw_writel(0, priv->dma_regs + CPDMA_RXHDP_VER1 + 4 + * i); + __raw_writel(0, priv->dma_regs + CPDMA_RXFREE + 4 + * i); + __raw_writel(0, priv->dma_regs + CPDMA_RXCP_VER1 + 4 + * i); + __raw_writel(0, priv->dma_regs + CPDMA_TXHDP_VER1 + 4 + * i); + __raw_writel(0, priv->dma_regs + CPDMA_TXCP_VER1 + 4 + * i); + + } + } + + __raw_writel(1, priv->dma_regs + CPDMA_TXCONTROL); + __raw_writel(1, priv->dma_regs + CPDMA_RXCONTROL); + + /* submit rx descs */ + for (i = 0; i < PKTBUFSRX; i++) { + ret = cpdma_submit(priv, &priv->rx_chan, net_rx_packets[i], + PKTSIZE); + if (ret < 0) { + printf("error %d submitting rx desc\n", ret); + break; + } + } + +out: + return ret; +} + +static int cpsw_reap_completed_packets(struct cpsw_priv *priv) +{ + int timeout = CPDMA_TIMEOUT; + + /* reap completed packets */ + while (timeout-- && + (cpdma_process(priv, &priv->tx_chan, NULL, NULL) >= 0)) + ; + + return timeout; +} + +static void _cpsw_halt(struct cpsw_priv *priv) +{ + cpsw_reap_completed_packets(priv); + + writel(0, priv->dma_regs + CPDMA_TXCONTROL); + writel(0, priv->dma_regs + CPDMA_RXCONTROL); + + /* soft reset the controller and initialize priv */ + setbit_and_wait_for_clear32(&priv->regs->soft_reset); + + /* clear dma state */ + setbit_and_wait_for_clear32(priv->dma_regs + CPDMA_SOFTRESET); + +} + +static int _cpsw_send(struct cpsw_priv *priv, void *packet, int length) +{ + int timeout; + + flush_dcache_range((unsigned long)packet, + (unsigned long)packet + ALIGN(length, PKTALIGN)); + + timeout = cpsw_reap_completed_packets(priv); + if (timeout == -1) { + printf("cpdma_process timeout\n"); + return -ETIMEDOUT; + } + + return cpdma_submit(priv, &priv->tx_chan, packet, length); +} + +static int _cpsw_recv(struct cpsw_priv *priv, uchar **pkt) +{ + void *buffer; + int len; + int ret; + + ret = cpdma_process(priv, &priv->rx_chan, &buffer, &len); + if (ret < 0) + return ret; + + invalidate_dcache_range((unsigned long)buffer, + (unsigned long)buffer + PKTSIZE_ALIGN); + *pkt = buffer; + + return len; +} + +static void cpsw_slave_setup(struct cpsw_slave *slave, int slave_num, + struct cpsw_priv *priv) +{ + void *regs = priv->regs; + struct cpsw_slave_data *data = priv->data.slave_data + slave_num; + slave->slave_num = slave_num; + slave->data = data; + slave->regs = regs + data->slave_reg_ofs; + slave->sliver = regs + data->sliver_reg_ofs; +} + +static int cpsw_phy_init(struct cpsw_priv *priv, struct cpsw_slave *slave) +{ + struct phy_device *phydev; + u32 supported = PHY_GBIT_FEATURES; + + phydev = phy_connect(priv->bus, + slave->data->phy_addr, + priv->dev, + slave->data->phy_if); + + if (!phydev) + return -1; + + phydev->supported &= supported; + phydev->advertising = phydev->supported; + +#ifdef CONFIG_DM_ETH + if (slave->data->phy_of_handle) + phydev->node = offset_to_ofnode(slave->data->phy_of_handle); +#endif + + priv->phydev = phydev; + phy_config(phydev); + + return 1; +} + +static void cpsw_phy_addr_update(struct cpsw_priv *priv) +{ + struct cpsw_platform_data *data = &priv->data; + u16 alive = mdio_regs->alive & GENMASK(15, 0); + int active = data->active_slave; + int new_addr = ffs(alive) - 1; + + /* + * If there is only one phy alive and its address does not match + * that of active slave, then phy address can safely be updated. + */ + if (hweight16(alive) == 1 && + data->slave_data[active].phy_addr != new_addr) { + printf("Updated phy address for CPSW#%d, old: %d, new: %d\n", + active, data->slave_data[active].phy_addr, new_addr); + data->slave_data[active].phy_addr = new_addr; + } +} + +int _cpsw_register(struct cpsw_priv *priv) +{ + struct cpsw_slave *slave; + struct cpsw_platform_data *data = &priv->data; + void *regs = (void *)data->cpsw_base; + + priv->slaves = malloc(sizeof(struct cpsw_slave) * data->slaves); + if (!priv->slaves) { + return -ENOMEM; + } + + priv->host_port = data->host_port_num; + priv->regs = regs; + priv->host_port_regs = regs + data->host_port_reg_ofs; + priv->dma_regs = regs + data->cpdma_reg_ofs; + priv->ale_regs = regs + data->ale_reg_ofs; + priv->descs = (void *)regs + data->bd_ram_ofs; + + int idx = 0; + + for_each_slave(slave, priv) { + cpsw_slave_setup(slave, idx, priv); + idx = idx + 1; + } + + cpsw_mdio_init(priv->dev->name, data->mdio_base, data->mdio_div); + + cpsw_phy_addr_update(priv); + + priv->bus = miiphy_get_dev_by_name(priv->dev->name); + for_active_slave(slave, priv) + cpsw_phy_init(priv, slave); + + return 0; +} + +#ifndef CONFIG_DM_ETH +static int cpsw_init(struct eth_device *dev, bd_t *bis) +{ + struct cpsw_priv *priv = dev->priv; + + return _cpsw_init(priv, dev->enetaddr); +} + +static void cpsw_halt(struct eth_device *dev) +{ + struct cpsw_priv *priv = dev->priv; + + return _cpsw_halt(priv); +} + +static int cpsw_send(struct eth_device *dev, void *packet, int length) +{ + struct cpsw_priv *priv = dev->priv; + + return _cpsw_send(priv, packet, length); +} + +static int cpsw_recv(struct eth_device *dev) +{ + struct cpsw_priv *priv = dev->priv; + uchar *pkt = NULL; + int len; + + len = _cpsw_recv(priv, &pkt); + + if (len > 0) { + net_process_received_packet(pkt, len); + cpdma_submit(priv, &priv->rx_chan, pkt, PKTSIZE); + } + + return len; +} + +int cpsw_register(struct cpsw_platform_data *data) +{ + struct cpsw_priv *priv; + struct eth_device *dev; + int ret; + + dev = calloc(sizeof(*dev), 1); + if (!dev) + return -ENOMEM; + + priv = calloc(sizeof(*priv), 1); + if (!priv) { + free(dev); + return -ENOMEM; + } + + priv->dev = dev; + priv->data = *data; + + strcpy(dev->name, "cpsw"); + dev->iobase = 0; + dev->init = cpsw_init; + dev->halt = cpsw_halt; + dev->send = cpsw_send; + dev->recv = cpsw_recv; + dev->priv = priv; + + eth_register(dev); + + ret = _cpsw_register(priv); + if (ret < 0) { + eth_unregister(dev); + free(dev); + free(priv); + return ret; + } + + return 1; +} +#else +static int cpsw_eth_start(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct cpsw_priv *priv = dev_get_priv(dev); + + return _cpsw_init(priv, pdata->enetaddr); +} + +static int cpsw_eth_send(struct udevice *dev, void *packet, int length) +{ + struct cpsw_priv *priv = dev_get_priv(dev); + + return _cpsw_send(priv, packet, length); +} + +static int cpsw_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct cpsw_priv *priv = dev_get_priv(dev); + + return _cpsw_recv(priv, packetp); +} + +static int cpsw_eth_free_pkt(struct udevice *dev, uchar *packet, + int length) +{ + struct cpsw_priv *priv = dev_get_priv(dev); + + return cpdma_submit(priv, &priv->rx_chan, packet, PKTSIZE); +} + +static void cpsw_eth_stop(struct udevice *dev) +{ + struct cpsw_priv *priv = dev_get_priv(dev); + + return _cpsw_halt(priv); +} + + +static int cpsw_eth_probe(struct udevice *dev) +{ + struct cpsw_priv *priv = dev_get_priv(dev); + + priv->dev = dev; + + return _cpsw_register(priv); +} + +static const struct eth_ops cpsw_eth_ops = { + .start = cpsw_eth_start, + .send = cpsw_eth_send, + .recv = cpsw_eth_recv, + .free_pkt = cpsw_eth_free_pkt, + .stop = cpsw_eth_stop, +}; + +static inline fdt_addr_t cpsw_get_addr_by_node(const void *fdt, int node) +{ + return fdtdec_get_addr_size_auto_noparent(fdt, node, "reg", 0, NULL, + false); +} + +static void cpsw_gmii_sel_am3352(struct cpsw_priv *priv, + phy_interface_t phy_mode) +{ + u32 reg; + u32 mask; + u32 mode = 0; + bool rgmii_id = false; + int slave = priv->data.active_slave; + + reg = readl(priv->data.gmii_sel); + + switch (phy_mode) { + case PHY_INTERFACE_MODE_RMII: + mode = AM33XX_GMII_SEL_MODE_RMII; + break; + + case PHY_INTERFACE_MODE_RGMII: + mode = AM33XX_GMII_SEL_MODE_RGMII; + break; + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + mode = AM33XX_GMII_SEL_MODE_RGMII; + rgmii_id = true; + break; + + case PHY_INTERFACE_MODE_MII: + default: + mode = AM33XX_GMII_SEL_MODE_MII; + break; + }; + + mask = GMII_SEL_MODE_MASK << (slave * 2) | BIT(slave + 6); + mode <<= slave * 2; + + if (priv->data.rmii_clock_external) { + if (slave == 0) + mode |= AM33XX_GMII_SEL_RMII1_IO_CLK_EN; + else + mode |= AM33XX_GMII_SEL_RMII2_IO_CLK_EN; + } + + if (rgmii_id) { + if (slave == 0) + mode |= AM33XX_GMII_SEL_RGMII1_IDMODE; + else + mode |= AM33XX_GMII_SEL_RGMII2_IDMODE; + } + + reg &= ~mask; + reg |= mode; + + writel(reg, priv->data.gmii_sel); +} + +static void cpsw_gmii_sel_dra7xx(struct cpsw_priv *priv, + phy_interface_t phy_mode) +{ + u32 reg; + u32 mask; + u32 mode = 0; + int slave = priv->data.active_slave; + + reg = readl(priv->data.gmii_sel); + + switch (phy_mode) { + case PHY_INTERFACE_MODE_RMII: + mode = AM33XX_GMII_SEL_MODE_RMII; + break; + + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + mode = AM33XX_GMII_SEL_MODE_RGMII; + break; + + case PHY_INTERFACE_MODE_MII: + default: + mode = AM33XX_GMII_SEL_MODE_MII; + break; + }; + + switch (slave) { + case 0: + mask = GMII_SEL_MODE_MASK; + break; + case 1: + mask = GMII_SEL_MODE_MASK << 4; + mode <<= 4; + break; + default: + dev_err(priv->dev, "invalid slave number...\n"); + return; + } + + if (priv->data.rmii_clock_external) + dev_err(priv->dev, "RMII External clock is not supported\n"); + + reg &= ~mask; + reg |= mode; + + writel(reg, priv->data.gmii_sel); +} + +static void cpsw_phy_sel(struct cpsw_priv *priv, const char *compat, + phy_interface_t phy_mode) +{ + if (!strcmp(compat, "ti,am3352-cpsw-phy-sel")) + cpsw_gmii_sel_am3352(priv, phy_mode); + if (!strcmp(compat, "ti,am43xx-cpsw-phy-sel")) + cpsw_gmii_sel_am3352(priv, phy_mode); + else if (!strcmp(compat, "ti,dra7xx-cpsw-phy-sel")) + cpsw_gmii_sel_dra7xx(priv, phy_mode); +} + +static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct cpsw_priv *priv = dev_get_priv(dev); + struct gpio_desc *mode_gpios; + const char *phy_mode; + const char *phy_sel_compat = NULL; + const void *fdt = gd->fdt_blob; + int node = dev_of_offset(dev); + int subnode; + int slave_index = 0; + int active_slave; + int num_mode_gpios; + int ret; + + pdata->iobase = devfdt_get_addr(dev); + priv->data.version = CPSW_CTRL_VERSION_2; + priv->data.bd_ram_ofs = CPSW_BD_OFFSET; + priv->data.ale_reg_ofs = CPSW_ALE_OFFSET; + priv->data.cpdma_reg_ofs = CPSW_CPDMA_OFFSET; + priv->data.mdio_div = CPSW_MDIO_DIV; + priv->data.host_port_reg_ofs = CPSW_HOST_PORT_OFFSET, + + pdata->phy_interface = -1; + + priv->data.cpsw_base = pdata->iobase; + priv->data.channels = fdtdec_get_int(fdt, node, "cpdma_channels", -1); + if (priv->data.channels <= 0) { + printf("error: cpdma_channels not found in dt\n"); + return -ENOENT; + } + + priv->data.slaves = fdtdec_get_int(fdt, node, "slaves", -1); + if (priv->data.slaves <= 0) { + printf("error: slaves not found in dt\n"); + return -ENOENT; + } + priv->data.slave_data = malloc(sizeof(struct cpsw_slave_data) * + priv->data.slaves); + + priv->data.ale_entries = fdtdec_get_int(fdt, node, "ale_entries", -1); + if (priv->data.ale_entries <= 0) { + printf("error: ale_entries not found in dt\n"); + return -ENOENT; + } + + priv->data.bd_ram_ofs = fdtdec_get_int(fdt, node, "bd_ram_size", -1); + if (priv->data.bd_ram_ofs <= 0) { + printf("error: bd_ram_size not found in dt\n"); + return -ENOENT; + } + + priv->data.mac_control = fdtdec_get_int(fdt, node, "mac_control", -1); + if (priv->data.mac_control <= 0) { + printf("error: ale_entries not found in dt\n"); + return -ENOENT; + } + + num_mode_gpios = gpio_get_list_count(dev, "mode-gpios"); + if (num_mode_gpios > 0) { + mode_gpios = malloc(sizeof(struct gpio_desc) * + num_mode_gpios); + gpio_request_list_by_name(dev, "mode-gpios", mode_gpios, + num_mode_gpios, GPIOD_IS_OUT); + free(mode_gpios); + } + + active_slave = fdtdec_get_int(fdt, node, "active_slave", 0); + priv->data.active_slave = active_slave; + + fdt_for_each_subnode(subnode, fdt, node) { + int len; + const char *name; + + name = fdt_get_name(fdt, subnode, &len); + if (!strncmp(name, "mdio", 4)) { + u32 mdio_base; + + mdio_base = cpsw_get_addr_by_node(fdt, subnode); + if (mdio_base == FDT_ADDR_T_NONE) { + pr_err("Not able to get MDIO address space\n"); + return -ENOENT; + } + priv->data.mdio_base = mdio_base; + } + + if (!strncmp(name, "slave", 5)) { + u32 phy_id[2]; + + if (slave_index >= priv->data.slaves) + continue; + phy_mode = fdt_getprop(fdt, subnode, "phy-mode", NULL); + if (phy_mode) + priv->data.slave_data[slave_index].phy_if = + phy_get_interface_by_name(phy_mode); + + priv->data.slave_data[slave_index].phy_of_handle = + fdtdec_lookup_phandle(fdt, subnode, + "phy-handle"); + + if (priv->data.slave_data[slave_index].phy_of_handle >= 0) { + priv->data.slave_data[slave_index].phy_addr = + fdtdec_get_int(gd->fdt_blob, + priv->data.slave_data[slave_index].phy_of_handle, + "reg", -1); + } else { + fdtdec_get_int_array(fdt, subnode, "phy_id", + phy_id, 2); + priv->data.slave_data[slave_index].phy_addr = + phy_id[1]; + } + slave_index++; + } + + if (!strncmp(name, "cpsw-phy-sel", 12)) { + priv->data.gmii_sel = cpsw_get_addr_by_node(fdt, + subnode); + + if (priv->data.gmii_sel == FDT_ADDR_T_NONE) { + pr_err("Not able to get gmii_sel reg address\n"); + return -ENOENT; + } + + if (fdt_get_property(fdt, subnode, "rmii-clock-ext", + NULL)) + priv->data.rmii_clock_external = true; + + phy_sel_compat = fdt_getprop(fdt, subnode, "compatible", + NULL); + if (!phy_sel_compat) { + pr_err("Not able to get gmii_sel compatible\n"); + return -ENOENT; + } + } + } + + priv->data.slave_data[0].slave_reg_ofs = CPSW_SLAVE0_OFFSET; + priv->data.slave_data[0].sliver_reg_ofs = CPSW_SLIVER0_OFFSET; + + if (priv->data.slaves == 2) { + priv->data.slave_data[1].slave_reg_ofs = CPSW_SLAVE1_OFFSET; + priv->data.slave_data[1].sliver_reg_ofs = CPSW_SLIVER1_OFFSET; + } + + ret = ti_cm_get_macid(dev, active_slave, pdata->enetaddr); + if (ret < 0) { + pr_err("cpsw read efuse mac failed\n"); + return ret; + } + + pdata->phy_interface = priv->data.slave_data[active_slave].phy_if; + if (pdata->phy_interface == -1) { + debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); + return -EINVAL; + } + + /* Select phy interface in control module */ + cpsw_phy_sel(priv, phy_sel_compat, pdata->phy_interface); + + return 0; +} + +int cpsw_get_slave_phy_addr(struct udevice *dev, int slave) +{ + struct cpsw_priv *priv = dev_get_priv(dev); + struct cpsw_platform_data *data = &priv->data; + + return data->slave_data[slave].phy_addr; +} + +static const struct udevice_id cpsw_eth_ids[] = { + { .compatible = "ti,cpsw" }, + { .compatible = "ti,am335x-cpsw" }, + { } +}; + +U_BOOT_DRIVER(eth_cpsw) = { + .name = "eth_cpsw", + .id = UCLASS_ETH, + .of_match = cpsw_eth_ids, + .ofdata_to_platdata = cpsw_eth_ofdata_to_platdata, + .probe = cpsw_eth_probe, + .ops = &cpsw_eth_ops, + .priv_auto_alloc_size = sizeof(struct cpsw_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; +#endif /* CONFIG_DM_ETH */ diff --git a/drivers/net/ti/davinci_emac.c b/drivers/net/ti/davinci_emac.c new file mode 100644 index 00000000000..bb879d8d4fe --- /dev/null +++ b/drivers/net/ti/davinci_emac.c @@ -0,0 +1,901 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Ethernet driver for TI TMS320DM644x (DaVinci) chips. + * + * Copyright (C) 2007 Sergey Kubushyn + * + * Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright + * follows: + * + * ---------------------------------------------------------------------------- + * + * dm644x_emac.c + * + * TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM + * + * Copyright (C) 2005 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * + * Modifications: + * ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot. + * ver 1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "davinci_emac.h" + +unsigned int emac_dbg = 0; +#define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args) + +#ifdef EMAC_HW_RAM_ADDR +static inline unsigned long BD_TO_HW(unsigned long x) +{ + if (x == 0) + return 0; + + return x - EMAC_WRAPPER_RAM_ADDR + EMAC_HW_RAM_ADDR; +} + +static inline unsigned long HW_TO_BD(unsigned long x) +{ + if (x == 0) + return 0; + + return x - EMAC_HW_RAM_ADDR + EMAC_WRAPPER_RAM_ADDR; +} +#else +#define BD_TO_HW(x) (x) +#define HW_TO_BD(x) (x) +#endif + +#ifdef DAVINCI_EMAC_GIG_ENABLE +#define emac_gigabit_enable(phy_addr) davinci_eth_gigabit_enable(phy_addr) +#else +#define emac_gigabit_enable(phy_addr) /* no gigabit to enable */ +#endif + +#if !defined(CONFIG_SYS_EMAC_TI_CLKDIV) +#define CONFIG_SYS_EMAC_TI_CLKDIV ((EMAC_MDIO_BUS_FREQ / \ + EMAC_MDIO_CLOCK_FREQ) - 1) +#endif + +static void davinci_eth_mdio_enable(void); + +static int gen_init_phy(int phy_addr); +static int gen_is_phy_connected(int phy_addr); +static int gen_get_link_speed(int phy_addr); +static int gen_auto_negotiate(int phy_addr); + +void eth_mdio_enable(void) +{ + davinci_eth_mdio_enable(); +} + +/* EMAC Addresses */ +static volatile emac_regs *adap_emac = (emac_regs *)EMAC_BASE_ADDR; +static volatile ewrap_regs *adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR; +static volatile mdio_regs *adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR; + +/* EMAC descriptors */ +static volatile emac_desc *emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE); +static volatile emac_desc *emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE); +static volatile emac_desc *emac_rx_active_head = 0; +static volatile emac_desc *emac_rx_active_tail = 0; +static int emac_rx_queue_active = 0; + +/* Receive packet buffers */ +static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * EMAC_RXBUF_SIZE] + __aligned(ARCH_DMA_MINALIGN); + +#ifndef CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT +#define CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT 3 +#endif + +/* PHY address for a discovered PHY (0xff - not found) */ +static u_int8_t active_phy_addr[CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT]; + +/* number of PHY found active */ +static u_int8_t num_phy; + +phy_t phy[CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT]; + +static int davinci_eth_set_mac_addr(struct eth_device *dev) +{ + unsigned long mac_hi; + unsigned long mac_lo; + + /* + * Set MAC Addresses & Init multicast Hash to 0 (disable any multicast + * receive) + * Using channel 0 only - other channels are disabled + * */ + writel(0, &adap_emac->MACINDEX); + mac_hi = (dev->enetaddr[3] << 24) | + (dev->enetaddr[2] << 16) | + (dev->enetaddr[1] << 8) | + (dev->enetaddr[0]); + mac_lo = (dev->enetaddr[5] << 8) | + (dev->enetaddr[4]); + + writel(mac_hi, &adap_emac->MACADDRHI); +#if defined(DAVINCI_EMAC_VERSION2) + writel(mac_lo | EMAC_MAC_ADDR_IS_VALID | EMAC_MAC_ADDR_MATCH, + &adap_emac->MACADDRLO); +#else + writel(mac_lo, &adap_emac->MACADDRLO); +#endif + + writel(0, &adap_emac->MACHASH1); + writel(0, &adap_emac->MACHASH2); + + /* Set source MAC address - REQUIRED */ + writel(mac_hi, &adap_emac->MACSRCADDRHI); + writel(mac_lo, &adap_emac->MACSRCADDRLO); + + + return 0; +} + +static void davinci_eth_mdio_enable(void) +{ + u_int32_t clkdiv; + + clkdiv = CONFIG_SYS_EMAC_TI_CLKDIV; + + writel((clkdiv & 0xff) | + MDIO_CONTROL_ENABLE | + MDIO_CONTROL_FAULT | + MDIO_CONTROL_FAULT_ENABLE, + &adap_mdio->CONTROL); + + while (readl(&adap_mdio->CONTROL) & MDIO_CONTROL_IDLE) + ; +} + +/* + * Tries to find an active connected PHY. Returns 1 if address if found. + * If no active PHY (or more than one PHY) found returns 0. + * Sets active_phy_addr variable. + */ +static int davinci_eth_phy_detect(void) +{ + u_int32_t phy_act_state; + int i; + int j; + unsigned int count = 0; + + for (i = 0; i < CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT; i++) + active_phy_addr[i] = 0xff; + + udelay(1000); + phy_act_state = readl(&adap_mdio->ALIVE); + + if (phy_act_state == 0) + return 0; /* No active PHYs */ + + debug_emac("davinci_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state); + + for (i = 0, j = 0; i < 32; i++) + if (phy_act_state & (1 << i)) { + count++; + if (count <= CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT) { + active_phy_addr[j++] = i; + } else { + printf("%s: to many PHYs detected.\n", + __func__); + count = 0; + break; + } + } + + num_phy = count; + + return count; +} + + +/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */ +int davinci_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data) +{ + int tmp; + + while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) + ; + + writel(MDIO_USERACCESS0_GO | + MDIO_USERACCESS0_WRITE_READ | + ((reg_num & 0x1f) << 21) | + ((phy_addr & 0x1f) << 16), + &adap_mdio->USERACCESS0); + + /* Wait for command to complete */ + while ((tmp = readl(&adap_mdio->USERACCESS0)) & MDIO_USERACCESS0_GO) + ; + + if (tmp & MDIO_USERACCESS0_ACK) { + *data = tmp & 0xffff; + return 1; + } + + return 0; +} + +/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */ +int davinci_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data) +{ + + while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) + ; + + writel(MDIO_USERACCESS0_GO | + MDIO_USERACCESS0_WRITE_WRITE | + ((reg_num & 0x1f) << 21) | + ((phy_addr & 0x1f) << 16) | + (data & 0xffff), + &adap_mdio->USERACCESS0); + + /* Wait for command to complete */ + while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) + ; + + return 1; +} + +/* PHY functions for a generic PHY */ +static int gen_init_phy(int phy_addr) +{ + int ret = 1; + + if (gen_get_link_speed(phy_addr)) { + /* Try another time */ + ret = gen_get_link_speed(phy_addr); + } + + return(ret); +} + +static int gen_is_phy_connected(int phy_addr) +{ + u_int16_t dummy; + + return davinci_eth_phy_read(phy_addr, MII_PHYSID1, &dummy); +} + +static int get_active_phy(void) +{ + int i; + + for (i = 0; i < num_phy; i++) + if (phy[i].get_link_speed(active_phy_addr[i])) + return i; + + return -1; /* Return error if no link */ +} + +static int gen_get_link_speed(int phy_addr) +{ + u_int16_t tmp; + + if (davinci_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp) && + (tmp & 0x04)) { +#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \ + defined(CONFIG_MACH_DAVINCI_DA850_EVM) + davinci_eth_phy_read(phy_addr, MII_LPA, &tmp); + + /* Speed doesn't matter, there is no setting for it in EMAC. */ + if (tmp & (LPA_100FULL | LPA_10FULL)) { + /* set EMAC for Full Duplex */ + writel(EMAC_MACCONTROL_MIIEN_ENABLE | + EMAC_MACCONTROL_FULLDUPLEX_ENABLE, + &adap_emac->MACCONTROL); + } else { + /*set EMAC for Half Duplex */ + writel(EMAC_MACCONTROL_MIIEN_ENABLE, + &adap_emac->MACCONTROL); + } + + if (tmp & (LPA_100FULL | LPA_100HALF)) + writel(readl(&adap_emac->MACCONTROL) | + EMAC_MACCONTROL_RMIISPEED_100, + &adap_emac->MACCONTROL); + else + writel(readl(&adap_emac->MACCONTROL) & + ~EMAC_MACCONTROL_RMIISPEED_100, + &adap_emac->MACCONTROL); +#endif + return(1); + } + + return(0); +} + +static int gen_auto_negotiate(int phy_addr) +{ + u_int16_t tmp; + u_int16_t val; + unsigned long cntr = 0; + + if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &tmp)) + return 0; + + val = tmp | BMCR_FULLDPLX | BMCR_ANENABLE | + BMCR_SPEED100; + davinci_eth_phy_write(phy_addr, MII_BMCR, val); + + if (!davinci_eth_phy_read(phy_addr, MII_ADVERTISE, &val)) + return 0; + + val |= (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10FULL | + ADVERTISE_10HALF); + davinci_eth_phy_write(phy_addr, MII_ADVERTISE, val); + + if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &tmp)) + return(0); + +#ifdef DAVINCI_EMAC_GIG_ENABLE + davinci_eth_phy_read(phy_addr, MII_CTRL1000, &val); + val |= PHY_1000BTCR_1000FD; + val &= ~PHY_1000BTCR_1000HD; + davinci_eth_phy_write(phy_addr, MII_CTRL1000, val); + davinci_eth_phy_read(phy_addr, MII_CTRL1000, &val); +#endif + + /* Restart Auto_negotiation */ + tmp |= BMCR_ANRESTART; + davinci_eth_phy_write(phy_addr, MII_BMCR, tmp); + + /*check AutoNegotiate complete */ + do { + udelay(40000); + if (!davinci_eth_phy_read(phy_addr, MII_BMSR, &tmp)) + return 0; + + if (tmp & BMSR_ANEGCOMPLETE) + break; + + cntr++; + } while (cntr < 200); + + if (!davinci_eth_phy_read(phy_addr, MII_BMSR, &tmp)) + return(0); + + if (!(tmp & BMSR_ANEGCOMPLETE)) + return(0); + + return(gen_get_link_speed(phy_addr)); +} +/* End of generic PHY functions */ + + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +static int davinci_mii_phy_read(struct mii_dev *bus, int addr, int devad, + int reg) +{ + unsigned short value = 0; + int retval = davinci_eth_phy_read(addr, reg, &value); + + return retval ? value : -EIO; +} + +static int davinci_mii_phy_write(struct mii_dev *bus, int addr, int devad, + int reg, u16 value) +{ + return davinci_eth_phy_write(addr, reg, value) ? 0 : 1; +} +#endif + +static void __attribute__((unused)) davinci_eth_gigabit_enable(int phy_addr) +{ + u_int16_t data; + + if (davinci_eth_phy_read(phy_addr, 0, &data)) { + if (data & (1 << 6)) { /* speed selection MSB */ + /* + * Check if link detected is giga-bit + * If Gigabit mode detected, enable gigbit in MAC + */ + writel(readl(&adap_emac->MACCONTROL) | + EMAC_MACCONTROL_GIGFORCE | + EMAC_MACCONTROL_GIGABIT_ENABLE, + &adap_emac->MACCONTROL); + } + } +} + +/* Eth device open */ +static int davinci_eth_open(struct eth_device *dev, bd_t *bis) +{ + dv_reg_p addr; + u_int32_t clkdiv, cnt, mac_control; + uint16_t __maybe_unused lpa_val; + volatile emac_desc *rx_desc; + int index; + + debug_emac("+ emac_open\n"); + + /* Reset EMAC module and disable interrupts in wrapper */ + writel(1, &adap_emac->SOFTRESET); + while (readl(&adap_emac->SOFTRESET) != 0) + ; +#if defined(DAVINCI_EMAC_VERSION2) + writel(1, &adap_ewrap->softrst); + while (readl(&adap_ewrap->softrst) != 0) + ; +#else + writel(0, &adap_ewrap->EWCTL); + for (cnt = 0; cnt < 5; cnt++) { + clkdiv = readl(&adap_ewrap->EWCTL); + } +#endif + +#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \ + defined(CONFIG_MACH_DAVINCI_DA850_EVM) + adap_ewrap->c0rxen = adap_ewrap->c1rxen = adap_ewrap->c2rxen = 0; + adap_ewrap->c0txen = adap_ewrap->c1txen = adap_ewrap->c2txen = 0; + adap_ewrap->c0miscen = adap_ewrap->c1miscen = adap_ewrap->c2miscen = 0; +#endif + rx_desc = emac_rx_desc; + + writel(1, &adap_emac->TXCONTROL); + writel(1, &adap_emac->RXCONTROL); + + davinci_eth_set_mac_addr(dev); + + /* Set DMA 8 TX / 8 RX Head pointers to 0 */ + addr = &adap_emac->TX0HDP; + for (cnt = 0; cnt < 8; cnt++) + writel(0, addr++); + + addr = &adap_emac->RX0HDP; + for (cnt = 0; cnt < 8; cnt++) + writel(0, addr++); + + /* Clear Statistics (do this before setting MacControl register) */ + addr = &adap_emac->RXGOODFRAMES; + for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++) + writel(0, addr++); + + /* No multicast addressing */ + writel(0, &adap_emac->MACHASH1); + writel(0, &adap_emac->MACHASH2); + + /* Create RX queue and set receive process in place */ + emac_rx_active_head = emac_rx_desc; + for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) { + rx_desc->next = BD_TO_HW((u_int32_t)(rx_desc + 1)); + rx_desc->buffer = &emac_rx_buffers[cnt * EMAC_RXBUF_SIZE]; + rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; + rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; + rx_desc++; + } + + /* Finalize the rx desc list */ + rx_desc--; + rx_desc->next = 0; + emac_rx_active_tail = rx_desc; + emac_rx_queue_active = 1; + + /* Enable TX/RX */ + writel(EMAC_MAX_ETHERNET_PKT_SIZE, &adap_emac->RXMAXLEN); + writel(0, &adap_emac->RXBUFFEROFFSET); + + /* + * No fancy configs - Use this for promiscous debug + * - EMAC_RXMBPENABLE_RXCAFEN_ENABLE + */ + writel(EMAC_RXMBPENABLE_RXBROADEN, &adap_emac->RXMBPENABLE); + + /* Enable ch 0 only */ + writel(1, &adap_emac->RXUNICASTSET); + + /* Init MDIO & get link state */ + clkdiv = CONFIG_SYS_EMAC_TI_CLKDIV; + writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT, + &adap_mdio->CONTROL); + + /* We need to wait for MDIO to start */ + udelay(1000); + + index = get_active_phy(); + if (index == -1) + return(0); + + /* Enable MII interface */ + mac_control = EMAC_MACCONTROL_MIIEN_ENABLE; +#ifdef DAVINCI_EMAC_GIG_ENABLE + davinci_eth_phy_read(active_phy_addr[index], MII_STAT1000, &lpa_val); + if (lpa_val & PHY_1000BTSR_1000FD) { + debug_emac("eth_open : gigabit negotiated\n"); + mac_control |= EMAC_MACCONTROL_FULLDUPLEX_ENABLE; + mac_control |= EMAC_MACCONTROL_GIGABIT_ENABLE; + } +#endif + + davinci_eth_phy_read(active_phy_addr[index], MII_LPA, &lpa_val); + if (lpa_val & (LPA_100FULL | LPA_10FULL)) + /* set EMAC for Full Duplex */ + mac_control |= EMAC_MACCONTROL_FULLDUPLEX_ENABLE; +#if defined(CONFIG_SOC_DA8XX) || \ + (defined(CONFIG_OMAP34XX) && defined(CONFIG_DRIVER_TI_EMAC_USE_RMII)) + mac_control |= EMAC_MACCONTROL_RMIISPEED_100; +#endif + writel(mac_control, &adap_emac->MACCONTROL); + /* Start receive process */ + writel(BD_TO_HW((u_int32_t)emac_rx_desc), &adap_emac->RX0HDP); + + debug_emac("- emac_open\n"); + + return(1); +} + +/* EMAC Channel Teardown */ +static void davinci_eth_ch_teardown(int ch) +{ + dv_reg dly = 0xff; + dv_reg cnt; + + debug_emac("+ emac_ch_teardown\n"); + + if (ch == EMAC_CH_TX) { + /* Init TX channel teardown */ + writel(0, &adap_emac->TXTEARDOWN); + do { + /* + * Wait here for Tx teardown completion interrupt to + * occur. Note: A task delay can be called here to pend + * rather than occupying CPU cycles - anyway it has + * been found that teardown takes very few cpu cycles + * and does not affect functionality + */ + dly--; + udelay(1); + if (dly == 0) + break; + cnt = readl(&adap_emac->TX0CP); + } while (cnt != 0xfffffffc); + writel(cnt, &adap_emac->TX0CP); + writel(0, &adap_emac->TX0HDP); + } else { + /* Init RX channel teardown */ + writel(0, &adap_emac->RXTEARDOWN); + do { + /* + * Wait here for Rx teardown completion interrupt to + * occur. Note: A task delay can be called here to pend + * rather than occupying CPU cycles - anyway it has + * been found that teardown takes very few cpu cycles + * and does not affect functionality + */ + dly--; + udelay(1); + if (dly == 0) + break; + cnt = readl(&adap_emac->RX0CP); + } while (cnt != 0xfffffffc); + writel(cnt, &adap_emac->RX0CP); + writel(0, &adap_emac->RX0HDP); + } + + debug_emac("- emac_ch_teardown\n"); +} + +/* Eth device close */ +static void davinci_eth_close(struct eth_device *dev) +{ + debug_emac("+ emac_close\n"); + + davinci_eth_ch_teardown(EMAC_CH_TX); /* TX Channel teardown */ + if (readl(&adap_emac->RXCONTROL) & 1) + davinci_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */ + + /* Reset EMAC module and disable interrupts in wrapper */ + writel(1, &adap_emac->SOFTRESET); +#if defined(DAVINCI_EMAC_VERSION2) + writel(1, &adap_ewrap->softrst); +#else + writel(0, &adap_ewrap->EWCTL); +#endif + +#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \ + defined(CONFIG_MACH_DAVINCI_DA850_EVM) + adap_ewrap->c0rxen = adap_ewrap->c1rxen = adap_ewrap->c2rxen = 0; + adap_ewrap->c0txen = adap_ewrap->c1txen = adap_ewrap->c2txen = 0; + adap_ewrap->c0miscen = adap_ewrap->c1miscen = adap_ewrap->c2miscen = 0; +#endif + debug_emac("- emac_close\n"); +} + +static int tx_send_loop = 0; + +/* + * This function sends a single packet on the network and returns + * positive number (number of bytes transmitted) or negative for error + */ +static int davinci_eth_send_packet (struct eth_device *dev, + void *packet, int length) +{ + int ret_status = -1; + int index; + tx_send_loop = 0; + + index = get_active_phy(); + if (index == -1) { + printf(" WARN: emac_send_packet: No link\n"); + return (ret_status); + } + + /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */ + if (length < EMAC_MIN_ETHERNET_PKT_SIZE) { + length = EMAC_MIN_ETHERNET_PKT_SIZE; + } + + /* Populate the TX descriptor */ + emac_tx_desc->next = 0; + emac_tx_desc->buffer = (u_int8_t *) packet; + emac_tx_desc->buff_off_len = (length & 0xffff); + emac_tx_desc->pkt_flag_len = ((length & 0xffff) | + EMAC_CPPI_SOP_BIT | + EMAC_CPPI_OWNERSHIP_BIT | + EMAC_CPPI_EOP_BIT); + + flush_dcache_range((unsigned long)packet, + (unsigned long)packet + ALIGN(length, PKTALIGN)); + + /* Send the packet */ + writel(BD_TO_HW((unsigned long)emac_tx_desc), &adap_emac->TX0HDP); + + /* Wait for packet to complete or link down */ + while (1) { + if (!phy[index].get_link_speed(active_phy_addr[index])) { + davinci_eth_ch_teardown (EMAC_CH_TX); + return (ret_status); + } + + if (readl(&adap_emac->TXINTSTATRAW) & 0x01) { + ret_status = length; + break; + } + tx_send_loop++; + } + + return (ret_status); +} + +/* + * This function handles receipt of a packet from the network + */ +static int davinci_eth_rcv_packet (struct eth_device *dev) +{ + volatile emac_desc *rx_curr_desc; + volatile emac_desc *curr_desc; + volatile emac_desc *tail_desc; + int status, ret = -1; + + rx_curr_desc = emac_rx_active_head; + if (!rx_curr_desc) + return 0; + status = rx_curr_desc->pkt_flag_len; + if ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0) { + if (status & EMAC_CPPI_RX_ERROR_FRAME) { + /* Error in packet - discard it and requeue desc */ + printf ("WARN: emac_rcv_pkt: Error in packet\n"); + } else { + unsigned long tmp = (unsigned long)rx_curr_desc->buffer; + unsigned short len = + rx_curr_desc->buff_off_len & 0xffff; + + invalidate_dcache_range(tmp, tmp + ALIGN(len, PKTALIGN)); + net_process_received_packet(rx_curr_desc->buffer, len); + ret = len; + } + + /* Ack received packet descriptor */ + writel(BD_TO_HW((ulong)rx_curr_desc), &adap_emac->RX0CP); + curr_desc = rx_curr_desc; + emac_rx_active_head = + (volatile emac_desc *) (HW_TO_BD(rx_curr_desc->next)); + + if (status & EMAC_CPPI_EOQ_BIT) { + if (emac_rx_active_head) { + writel(BD_TO_HW((ulong)emac_rx_active_head), + &adap_emac->RX0HDP); + } else { + emac_rx_queue_active = 0; + printf ("INFO:emac_rcv_packet: RX Queue not active\n"); + } + } + + /* Recycle RX descriptor */ + rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; + rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; + rx_curr_desc->next = 0; + + if (emac_rx_active_head == 0) { + printf ("INFO: emac_rcv_pkt: active queue head = 0\n"); + emac_rx_active_head = curr_desc; + emac_rx_active_tail = curr_desc; + if (emac_rx_queue_active != 0) { + writel(BD_TO_HW((ulong)emac_rx_active_head), + &adap_emac->RX0HDP); + printf ("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n"); + emac_rx_queue_active = 1; + } + } else { + tail_desc = emac_rx_active_tail; + emac_rx_active_tail = curr_desc; + tail_desc->next = BD_TO_HW((ulong) curr_desc); + status = tail_desc->pkt_flag_len; + if (status & EMAC_CPPI_EOQ_BIT) { + writel(BD_TO_HW((ulong)curr_desc), + &adap_emac->RX0HDP); + status &= ~EMAC_CPPI_EOQ_BIT; + tail_desc->pkt_flag_len = status; + } + } + return (ret); + } + return (0); +} + +/* + * This function initializes the emac hardware. It does NOT initialize + * EMAC modules power or pin multiplexors, that is done by board_init() + * much earlier in bootup process. Returns 1 on success, 0 otherwise. + */ +int davinci_emac_initialize(void) +{ + u_int32_t phy_id; + u_int16_t tmp; + int i; + int ret; + struct eth_device *dev; + + dev = malloc(sizeof *dev); + + if (dev == NULL) + return -1; + + memset(dev, 0, sizeof *dev); + strcpy(dev->name, "DaVinci-EMAC"); + + dev->iobase = 0; + dev->init = davinci_eth_open; + dev->halt = davinci_eth_close; + dev->send = davinci_eth_send_packet; + dev->recv = davinci_eth_rcv_packet; + dev->write_hwaddr = davinci_eth_set_mac_addr; + + eth_register(dev); + + davinci_eth_mdio_enable(); + + /* let the EMAC detect the PHYs */ + udelay(5000); + + for (i = 0; i < 256; i++) { + if (readl(&adap_mdio->ALIVE)) + break; + udelay(1000); + } + + if (i >= 256) { + printf("No ETH PHY detected!!!\n"); + return(0); + } + + /* Find if PHY(s) is/are connected */ + ret = davinci_eth_phy_detect(); + if (!ret) + return(0); + else + debug_emac(" %d ETH PHY detected\n", ret); + + /* Get PHY ID and initialize phy_ops for a detected PHY */ + for (i = 0; i < num_phy; i++) { + if (!davinci_eth_phy_read(active_phy_addr[i], MII_PHYSID1, + &tmp)) { + active_phy_addr[i] = 0xff; + continue; + } + + phy_id = (tmp << 16) & 0xffff0000; + + if (!davinci_eth_phy_read(active_phy_addr[i], MII_PHYSID2, + &tmp)) { + active_phy_addr[i] = 0xff; + continue; + } + + phy_id |= tmp & 0x0000ffff; + + switch (phy_id) { +#ifdef PHY_KSZ8873 + case PHY_KSZ8873: + sprintf(phy[i].name, "KSZ8873 @ 0x%02x", + active_phy_addr[i]); + phy[i].init = ksz8873_init_phy; + phy[i].is_phy_connected = ksz8873_is_phy_connected; + phy[i].get_link_speed = ksz8873_get_link_speed; + phy[i].auto_negotiate = ksz8873_auto_negotiate; + break; +#endif +#ifdef PHY_LXT972 + case PHY_LXT972: + sprintf(phy[i].name, "LXT972 @ 0x%02x", + active_phy_addr[i]); + phy[i].init = lxt972_init_phy; + phy[i].is_phy_connected = lxt972_is_phy_connected; + phy[i].get_link_speed = lxt972_get_link_speed; + phy[i].auto_negotiate = lxt972_auto_negotiate; + break; +#endif +#ifdef PHY_DP83848 + case PHY_DP83848: + sprintf(phy[i].name, "DP83848 @ 0x%02x", + active_phy_addr[i]); + phy[i].init = dp83848_init_phy; + phy[i].is_phy_connected = dp83848_is_phy_connected; + phy[i].get_link_speed = dp83848_get_link_speed; + phy[i].auto_negotiate = dp83848_auto_negotiate; + break; +#endif +#ifdef PHY_ET1011C + case PHY_ET1011C: + sprintf(phy[i].name, "ET1011C @ 0x%02x", + active_phy_addr[i]); + phy[i].init = gen_init_phy; + phy[i].is_phy_connected = gen_is_phy_connected; + phy[i].get_link_speed = et1011c_get_link_speed; + phy[i].auto_negotiate = gen_auto_negotiate; + break; +#endif + default: + sprintf(phy[i].name, "GENERIC @ 0x%02x", + active_phy_addr[i]); + phy[i].init = gen_init_phy; + phy[i].is_phy_connected = gen_is_phy_connected; + phy[i].get_link_speed = gen_get_link_speed; + phy[i].auto_negotiate = gen_auto_negotiate; + } + + debug("Ethernet PHY: %s\n", phy[i].name); + + int retval; + struct mii_dev *mdiodev = mdio_alloc(); + if (!mdiodev) + return -ENOMEM; + strncpy(mdiodev->name, phy[i].name, MDIO_NAME_LEN); + mdiodev->read = davinci_mii_phy_read; + mdiodev->write = davinci_mii_phy_write; + + retval = mdio_register(mdiodev); + if (retval < 0) + return retval; +#ifdef DAVINCI_EMAC_GIG_ENABLE +#define PHY_CONF_REG 22 + /* Enable PHY to clock out TX_CLK */ + davinci_eth_phy_read(active_phy_addr[i], PHY_CONF_REG, &tmp); + tmp |= PHY_CONF_TXCLKEN; + davinci_eth_phy_write(active_phy_addr[i], PHY_CONF_REG, tmp); + davinci_eth_phy_read(active_phy_addr[i], PHY_CONF_REG, &tmp); +#endif + } + +#if defined(CONFIG_TI816X) || (defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \ + defined(CONFIG_MACH_DAVINCI_DA850_EVM) && \ + !defined(CONFIG_DRIVER_TI_EMAC_RMII_NO_NEGOTIATE)) + for (i = 0; i < num_phy; i++) { + if (phy[i].is_phy_connected(i)) + phy[i].auto_negotiate(i); + } +#endif + return(1); +} diff --git a/drivers/net/ti/davinci_emac.h b/drivers/net/ti/davinci_emac.h new file mode 100644 index 00000000000..695855b4d54 --- /dev/null +++ b/drivers/net/ti/davinci_emac.h @@ -0,0 +1,304 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2011 Ilya Yanok, Emcraft Systems + * + * Based on: mach-davinci/emac_defs.h + * Copyright (C) 2007 Sergey Kubushyn + */ + +#ifndef _DAVINCI_EMAC_H_ +#define _DAVINCI_EMAC_H_ +/* Ethernet Min/Max packet size */ +#define EMAC_MIN_ETHERNET_PKT_SIZE 60 +#define EMAC_MAX_ETHERNET_PKT_SIZE 1518 +/* Buffer size (should be aligned on 32 byte and cache line) */ +#define EMAC_RXBUF_SIZE ALIGN(ALIGN(EMAC_MAX_ETHERNET_PKT_SIZE, 32),\ + ARCH_DMA_MINALIGN) + +/* Number of RX packet buffers + * NOTE: Only 1 buffer supported as of now + */ +#define EMAC_MAX_RX_BUFFERS 10 + + +/*********************************************** + ******** Internally used macros *************** + ***********************************************/ + +#define EMAC_CH_TX 1 +#define EMAC_CH_RX 0 + +/* Each descriptor occupies 4 words, lets start RX desc's at 0 and + * reserve space for 64 descriptors max + */ +#define EMAC_RX_DESC_BASE 0x0 +#define EMAC_TX_DESC_BASE 0x1000 + +/* EMAC Teardown value */ +#define EMAC_TEARDOWN_VALUE 0xfffffffc + +/* MII Status Register */ +#define MII_STATUS_REG 1 +/* PHY Configuration register */ +#define PHY_CONF_TXCLKEN (1 << 5) + +/* Number of statistics registers */ +#define EMAC_NUM_STATS 36 + + +/* EMAC Descriptor */ +typedef volatile struct _emac_desc +{ + u_int32_t next; /* Pointer to next descriptor + in chain */ + u_int8_t *buffer; /* Pointer to data buffer */ + u_int32_t buff_off_len; /* Buffer Offset(MSW) and Length(LSW) */ + u_int32_t pkt_flag_len; /* Packet Flags(MSW) and Length(LSW) */ +} emac_desc; + +/* CPPI bit positions */ +#define EMAC_CPPI_SOP_BIT (0x80000000) +#define EMAC_CPPI_EOP_BIT (0x40000000) +#define EMAC_CPPI_OWNERSHIP_BIT (0x20000000) +#define EMAC_CPPI_EOQ_BIT (0x10000000) +#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT (0x08000000) +#define EMAC_CPPI_PASS_CRC_BIT (0x04000000) + +#define EMAC_CPPI_RX_ERROR_FRAME (0x03fc0000) + +#define EMAC_MACCONTROL_MIIEN_ENABLE (0x20) +#define EMAC_MACCONTROL_FULLDUPLEX_ENABLE (0x1) +#define EMAC_MACCONTROL_GIGABIT_ENABLE (1 << 7) +#define EMAC_MACCONTROL_GIGFORCE (1 << 17) +#define EMAC_MACCONTROL_RMIISPEED_100 (1 << 15) + +#define EMAC_MAC_ADDR_MATCH (1 << 19) +#define EMAC_MAC_ADDR_IS_VALID (1 << 20) + +#define EMAC_RXMBPENABLE_RXCAFEN_ENABLE (0x200000) +#define EMAC_RXMBPENABLE_RXBROADEN (0x2000) + + +#define MDIO_CONTROL_IDLE (0x80000000) +#define MDIO_CONTROL_ENABLE (0x40000000) +#define MDIO_CONTROL_FAULT_ENABLE (0x40000) +#define MDIO_CONTROL_FAULT (0x80000) +#define MDIO_USERACCESS0_GO (0x80000000) +#define MDIO_USERACCESS0_WRITE_READ (0x0) +#define MDIO_USERACCESS0_WRITE_WRITE (0x40000000) +#define MDIO_USERACCESS0_ACK (0x20000000) + +/* Ethernet MAC Registers Structure */ +typedef struct { + dv_reg TXIDVER; + dv_reg TXCONTROL; + dv_reg TXTEARDOWN; + u_int8_t RSVD0[4]; + dv_reg RXIDVER; + dv_reg RXCONTROL; + dv_reg RXTEARDOWN; + u_int8_t RSVD1[100]; + dv_reg TXINTSTATRAW; + dv_reg TXINTSTATMASKED; + dv_reg TXINTMASKSET; + dv_reg TXINTMASKCLEAR; + dv_reg MACINVECTOR; + u_int8_t RSVD2[12]; + dv_reg RXINTSTATRAW; + dv_reg RXINTSTATMASKED; + dv_reg RXINTMASKSET; + dv_reg RXINTMASKCLEAR; + dv_reg MACINTSTATRAW; + dv_reg MACINTSTATMASKED; + dv_reg MACINTMASKSET; + dv_reg MACINTMASKCLEAR; + u_int8_t RSVD3[64]; + dv_reg RXMBPENABLE; + dv_reg RXUNICASTSET; + dv_reg RXUNICASTCLEAR; + dv_reg RXMAXLEN; + dv_reg RXBUFFEROFFSET; + dv_reg RXFILTERLOWTHRESH; + u_int8_t RSVD4[8]; + dv_reg RX0FLOWTHRESH; + dv_reg RX1FLOWTHRESH; + dv_reg RX2FLOWTHRESH; + dv_reg RX3FLOWTHRESH; + dv_reg RX4FLOWTHRESH; + dv_reg RX5FLOWTHRESH; + dv_reg RX6FLOWTHRESH; + dv_reg RX7FLOWTHRESH; + dv_reg RX0FREEBUFFER; + dv_reg RX1FREEBUFFER; + dv_reg RX2FREEBUFFER; + dv_reg RX3FREEBUFFER; + dv_reg RX4FREEBUFFER; + dv_reg RX5FREEBUFFER; + dv_reg RX6FREEBUFFER; + dv_reg RX7FREEBUFFER; + dv_reg MACCONTROL; + dv_reg MACSTATUS; + dv_reg EMCONTROL; + dv_reg FIFOCONTROL; + dv_reg MACCONFIG; + dv_reg SOFTRESET; + u_int8_t RSVD5[88]; + dv_reg MACSRCADDRLO; + dv_reg MACSRCADDRHI; + dv_reg MACHASH1; + dv_reg MACHASH2; + dv_reg BOFFTEST; + dv_reg TPACETEST; + dv_reg RXPAUSE; + dv_reg TXPAUSE; + u_int8_t RSVD6[16]; + dv_reg RXGOODFRAMES; + dv_reg RXBCASTFRAMES; + dv_reg RXMCASTFRAMES; + dv_reg RXPAUSEFRAMES; + dv_reg RXCRCERRORS; + dv_reg RXALIGNCODEERRORS; + dv_reg RXOVERSIZED; + dv_reg RXJABBER; + dv_reg RXUNDERSIZED; + dv_reg RXFRAGMENTS; + dv_reg RXFILTERED; + dv_reg RXQOSFILTERED; + dv_reg RXOCTETS; + dv_reg TXGOODFRAMES; + dv_reg TXBCASTFRAMES; + dv_reg TXMCASTFRAMES; + dv_reg TXPAUSEFRAMES; + dv_reg TXDEFERRED; + dv_reg TXCOLLISION; + dv_reg TXSINGLECOLL; + dv_reg TXMULTICOLL; + dv_reg TXEXCESSIVECOLL; + dv_reg TXLATECOLL; + dv_reg TXUNDERRUN; + dv_reg TXCARRIERSENSE; + dv_reg TXOCTETS; + dv_reg FRAME64; + dv_reg FRAME65T127; + dv_reg FRAME128T255; + dv_reg FRAME256T511; + dv_reg FRAME512T1023; + dv_reg FRAME1024TUP; + dv_reg NETOCTETS; + dv_reg RXSOFOVERRUNS; + dv_reg RXMOFOVERRUNS; + dv_reg RXDMAOVERRUNS; + u_int8_t RSVD7[624]; + dv_reg MACADDRLO; + dv_reg MACADDRHI; + dv_reg MACINDEX; + u_int8_t RSVD8[244]; + dv_reg TX0HDP; + dv_reg TX1HDP; + dv_reg TX2HDP; + dv_reg TX3HDP; + dv_reg TX4HDP; + dv_reg TX5HDP; + dv_reg TX6HDP; + dv_reg TX7HDP; + dv_reg RX0HDP; + dv_reg RX1HDP; + dv_reg RX2HDP; + dv_reg RX3HDP; + dv_reg RX4HDP; + dv_reg RX5HDP; + dv_reg RX6HDP; + dv_reg RX7HDP; + dv_reg TX0CP; + dv_reg TX1CP; + dv_reg TX2CP; + dv_reg TX3CP; + dv_reg TX4CP; + dv_reg TX5CP; + dv_reg TX6CP; + dv_reg TX7CP; + dv_reg RX0CP; + dv_reg RX1CP; + dv_reg RX2CP; + dv_reg RX3CP; + dv_reg RX4CP; + dv_reg RX5CP; + dv_reg RX6CP; + dv_reg RX7CP; +} emac_regs; + +/* EMAC Wrapper Registers Structure */ +typedef struct { +#ifdef DAVINCI_EMAC_VERSION2 + dv_reg idver; + dv_reg softrst; + dv_reg emctrl; + dv_reg c0rxthreshen; + dv_reg c0rxen; + dv_reg c0txen; + dv_reg c0miscen; + dv_reg c1rxthreshen; + dv_reg c1rxen; + dv_reg c1txen; + dv_reg c1miscen; + dv_reg c2rxthreshen; + dv_reg c2rxen; + dv_reg c2txen; + dv_reg c2miscen; + dv_reg c0rxthreshstat; + dv_reg c0rxstat; + dv_reg c0txstat; + dv_reg c0miscstat; + dv_reg c1rxthreshstat; + dv_reg c1rxstat; + dv_reg c1txstat; + dv_reg c1miscstat; + dv_reg c2rxthreshstat; + dv_reg c2rxstat; + dv_reg c2txstat; + dv_reg c2miscstat; + dv_reg c0rximax; + dv_reg c0tximax; + dv_reg c1rximax; + dv_reg c1tximax; + dv_reg c2rximax; + dv_reg c2tximax; +#else + u_int8_t RSVD0[4100]; + dv_reg EWCTL; + dv_reg EWINTTCNT; +#endif +} ewrap_regs; + +/* EMAC MDIO Registers Structure */ +typedef struct { + dv_reg VERSION; + dv_reg CONTROL; + dv_reg ALIVE; + dv_reg LINK; + dv_reg LINKINTRAW; + dv_reg LINKINTMASKED; + u_int8_t RSVD0[8]; + dv_reg USERINTRAW; + dv_reg USERINTMASKED; + dv_reg USERINTMASKSET; + dv_reg USERINTMASKCLEAR; + u_int8_t RSVD1[80]; + dv_reg USERACCESS0; + dv_reg USERPHYSEL0; + dv_reg USERACCESS1; + dv_reg USERPHYSEL1; +} mdio_regs; + +int davinci_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data); +int davinci_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data); + +typedef struct { + char name[64]; + int (*init)(int phy_addr); + int (*is_phy_connected)(int phy_addr); + int (*get_link_speed)(int phy_addr); + int (*auto_negotiate)(int phy_addr); +} phy_t; + +#endif /* _DAVINCI_EMAC_H_ */ diff --git a/drivers/net/ti/keystone_net.c b/drivers/net/ti/keystone_net.c new file mode 100644 index 00000000000..d4d909b983f --- /dev/null +++ b/drivers/net/ti/keystone_net.c @@ -0,0 +1,1170 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Ethernet driver for TI K2HK EVM. + * + * (C) Copyright 2012-2014 + * Texas Instruments Incorporated, + */ +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_DM_ETH +unsigned int emac_open; +static struct mii_dev *mdio_bus; +static unsigned int sys_has_mdio = 1; +#endif + +#ifdef KEYSTONE2_EMAC_GIG_ENABLE +#define emac_gigabit_enable(x) keystone2_eth_gigabit_enable(x) +#else +#define emac_gigabit_enable(x) /* no gigabit to enable */ +#endif + +#define RX_BUFF_NUMS 24 +#define RX_BUFF_LEN 1520 +#define MAX_SIZE_STREAM_BUFFER RX_BUFF_LEN +#define SGMII_ANEG_TIMEOUT 4000 + +static u8 rx_buffs[RX_BUFF_NUMS * RX_BUFF_LEN] __aligned(16); + +#ifndef CONFIG_DM_ETH +struct rx_buff_desc net_rx_buffs = { + .buff_ptr = rx_buffs, + .num_buffs = RX_BUFF_NUMS, + .buff_len = RX_BUFF_LEN, + .rx_flow = 22, +}; +#endif + +#ifdef CONFIG_DM_ETH + +enum link_type { + LINK_TYPE_SGMII_MAC_TO_MAC_AUTO = 0, + LINK_TYPE_SGMII_MAC_TO_PHY_MODE = 1, + LINK_TYPE_SGMII_MAC_TO_MAC_FORCED_MODE = 2, + LINK_TYPE_SGMII_MAC_TO_FIBRE_MODE = 3, + LINK_TYPE_SGMII_MAC_TO_PHY_NO_MDIO_MODE = 4, + LINK_TYPE_RGMII_LINK_MAC_PHY = 5, + LINK_TYPE_RGMII_LINK_MAC_MAC_FORCED = 6, + LINK_TYPE_RGMII_LINK_MAC_PHY_NO_MDIO = 7, + LINK_TYPE_10G_MAC_TO_PHY_MODE = 10, + LINK_TYPE_10G_MAC_TO_MAC_FORCED_MODE = 11, +}; + +#define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \ + ((mac)[2] << 16) | ((mac)[3] << 24)) +#define mac_lo(mac) (((mac)[4] << 0) | ((mac)[5] << 8)) + +#ifdef CONFIG_KSNET_NETCP_V1_0 + +#define EMAC_EMACSW_BASE_OFS 0x90800 +#define EMAC_EMACSW_PORT_BASE_OFS (EMAC_EMACSW_BASE_OFS + 0x60) + +/* CPSW Switch slave registers */ +#define CPGMACSL_REG_SA_LO 0x10 +#define CPGMACSL_REG_SA_HI 0x14 + +#define DEVICE_EMACSW_BASE(base, x) ((base) + EMAC_EMACSW_PORT_BASE_OFS + \ + (x) * 0x30) + +#elif defined CONFIG_KSNET_NETCP_V1_5 + +#define EMAC_EMACSW_PORT_BASE_OFS 0x222000 + +/* CPSW Switch slave registers */ +#define CPGMACSL_REG_SA_LO 0x308 +#define CPGMACSL_REG_SA_HI 0x30c + +#define DEVICE_EMACSW_BASE(base, x) ((base) + EMAC_EMACSW_PORT_BASE_OFS + \ + (x) * 0x1000) + +#endif + + +struct ks2_eth_priv { + struct udevice *dev; + struct phy_device *phydev; + struct mii_dev *mdio_bus; + int phy_addr; + phy_interface_t phy_if; + int sgmii_link_type; + void *mdio_base; + struct rx_buff_desc net_rx_buffs; + struct pktdma_cfg *netcp_pktdma; + void *hd; + int slave_port; + enum link_type link_type; + bool emac_open; + bool has_mdio; +}; +#endif + +/* MDIO */ + +static int keystone2_mdio_reset(struct mii_dev *bus) +{ + u_int32_t clkdiv; + struct mdio_regs *adap_mdio = bus->priv; + + clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; + + writel((clkdiv & 0xffff) | MDIO_CONTROL_ENABLE | + MDIO_CONTROL_FAULT | MDIO_CONTROL_FAULT_ENABLE, + &adap_mdio->control); + + while (readl(&adap_mdio->control) & MDIO_CONTROL_IDLE) + ; + + return 0; +} + +/** + * keystone2_mdio_read - read a PHY register via MDIO interface. + * Blocks until operation is complete. + */ +static int keystone2_mdio_read(struct mii_dev *bus, + int addr, int devad, int reg) +{ + int tmp; + struct mdio_regs *adap_mdio = bus->priv; + + while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO) + ; + + writel(MDIO_USERACCESS0_GO | MDIO_USERACCESS0_WRITE_READ | + ((reg & 0x1f) << 21) | ((addr & 0x1f) << 16), + &adap_mdio->useraccess0); + + /* Wait for command to complete */ + while ((tmp = readl(&adap_mdio->useraccess0)) & MDIO_USERACCESS0_GO) + ; + + if (tmp & MDIO_USERACCESS0_ACK) + return tmp & 0xffff; + + return -1; +} + +/** + * keystone2_mdio_write - write to a PHY register via MDIO interface. + * Blocks until operation is complete. + */ +static int keystone2_mdio_write(struct mii_dev *bus, + int addr, int devad, int reg, u16 val) +{ + struct mdio_regs *adap_mdio = bus->priv; + + while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO) + ; + + writel(MDIO_USERACCESS0_GO | MDIO_USERACCESS0_WRITE_WRITE | + ((reg & 0x1f) << 21) | ((addr & 0x1f) << 16) | + (val & 0xffff), &adap_mdio->useraccess0); + + /* Wait for command to complete */ + while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO) + ; + + return 0; +} + +#ifndef CONFIG_DM_ETH +static void __attribute__((unused)) + keystone2_eth_gigabit_enable(struct eth_device *dev) +{ + u_int16_t data; + struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv; + + if (sys_has_mdio) { + data = keystone2_mdio_read(mdio_bus, eth_priv->phy_addr, + MDIO_DEVAD_NONE, 0); + /* speed selection MSB */ + if (!(data & (1 << 6))) + return; + } + + /* + * Check if link detected is giga-bit + * If Gigabit mode detected, enable gigbit in MAC + */ + writel(readl(DEVICE_EMACSL_BASE(eth_priv->slave_port - 1) + + CPGMACSL_REG_CTL) | + EMAC_MACCONTROL_GIGFORCE | EMAC_MACCONTROL_GIGABIT_ENABLE, + DEVICE_EMACSL_BASE(eth_priv->slave_port - 1) + CPGMACSL_REG_CTL); +} +#else +static void __attribute__((unused)) + keystone2_eth_gigabit_enable(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + u_int16_t data; + + if (priv->has_mdio) { + data = keystone2_mdio_read(priv->mdio_bus, priv->phy_addr, + MDIO_DEVAD_NONE, 0); + /* speed selection MSB */ + if (!(data & (1 << 6))) + return; + } + + /* + * Check if link detected is giga-bit + * If Gigabit mode detected, enable gigbit in MAC + */ + writel(readl(DEVICE_EMACSL_BASE(priv->slave_port - 1) + + CPGMACSL_REG_CTL) | + EMAC_MACCONTROL_GIGFORCE | EMAC_MACCONTROL_GIGABIT_ENABLE, + DEVICE_EMACSL_BASE(priv->slave_port - 1) + CPGMACSL_REG_CTL); +} +#endif + +#ifdef CONFIG_SOC_K2G +int keystone_rgmii_config(struct phy_device *phy_dev) +{ + unsigned int i, status; + + i = 0; + do { + if (i > SGMII_ANEG_TIMEOUT) { + puts(" TIMEOUT !\n"); + phy_dev->link = 0; + return 0; + } + + if (ctrlc()) { + puts("user interrupt!\n"); + phy_dev->link = 0; + return -EINTR; + } + + if ((i++ % 500) == 0) + printf("."); + + udelay(1000); /* 1 ms */ + status = readl(RGMII_STATUS_REG); + } while (!(status & RGMII_REG_STATUS_LINK)); + + puts(" done\n"); + + return 0; +} +#else +int keystone_sgmii_config(struct phy_device *phy_dev, int port, int interface) +{ + unsigned int i, status, mask; + unsigned int mr_adv_ability, control; + + switch (interface) { + case SGMII_LINK_MAC_MAC_AUTONEG: + mr_adv_ability = (SGMII_REG_MR_ADV_ENABLE | + SGMII_REG_MR_ADV_LINK | + SGMII_REG_MR_ADV_FULL_DUPLEX | + SGMII_REG_MR_ADV_GIG_MODE); + control = (SGMII_REG_CONTROL_MASTER | + SGMII_REG_CONTROL_AUTONEG); + + break; + case SGMII_LINK_MAC_PHY: + case SGMII_LINK_MAC_PHY_FORCED: + mr_adv_ability = SGMII_REG_MR_ADV_ENABLE; + control = SGMII_REG_CONTROL_AUTONEG; + + break; + case SGMII_LINK_MAC_MAC_FORCED: + mr_adv_ability = (SGMII_REG_MR_ADV_ENABLE | + SGMII_REG_MR_ADV_LINK | + SGMII_REG_MR_ADV_FULL_DUPLEX | + SGMII_REG_MR_ADV_GIG_MODE); + control = SGMII_REG_CONTROL_MASTER; + + break; + case SGMII_LINK_MAC_FIBER: + mr_adv_ability = 0x20; + control = SGMII_REG_CONTROL_AUTONEG; + + break; + default: + mr_adv_ability = SGMII_REG_MR_ADV_ENABLE; + control = SGMII_REG_CONTROL_AUTONEG; + } + + __raw_writel(0, SGMII_CTL_REG(port)); + + /* + * Wait for the SerDes pll to lock, + * but don't trap if lock is never read + */ + for (i = 0; i < 1000; i++) { + udelay(2000); + status = __raw_readl(SGMII_STATUS_REG(port)); + if ((status & SGMII_REG_STATUS_LOCK) != 0) + break; + } + + __raw_writel(mr_adv_ability, SGMII_MRADV_REG(port)); + __raw_writel(control, SGMII_CTL_REG(port)); + + + mask = SGMII_REG_STATUS_LINK; + + if (control & SGMII_REG_CONTROL_AUTONEG) + mask |= SGMII_REG_STATUS_AUTONEG; + + status = __raw_readl(SGMII_STATUS_REG(port)); + if ((status & mask) == mask) + return 0; + + printf("\n%s Waiting for SGMII auto negotiation to complete", + phy_dev->dev->name); + while ((status & mask) != mask) { + /* + * Timeout reached ? + */ + if (i > SGMII_ANEG_TIMEOUT) { + puts(" TIMEOUT !\n"); + phy_dev->link = 0; + return 0; + } + + if (ctrlc()) { + puts("user interrupt!\n"); + phy_dev->link = 0; + return -EINTR; + } + + if ((i++ % 500) == 0) + printf("."); + + udelay(1000); /* 1 ms */ + status = __raw_readl(SGMII_STATUS_REG(port)); + } + puts(" done\n"); + + return 0; +} +#endif + +int mac_sl_reset(u32 port) +{ + u32 i, v; + + if (port >= DEVICE_N_GMACSL_PORTS) + return GMACSL_RET_INVALID_PORT; + + /* Set the soft reset bit */ + writel(CPGMAC_REG_RESET_VAL_RESET, + DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RESET); + + /* Wait for the bit to clear */ + for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) { + v = readl(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RESET); + if ((v & CPGMAC_REG_RESET_VAL_RESET_MASK) != + CPGMAC_REG_RESET_VAL_RESET) + return GMACSL_RET_OK; + } + + /* Timeout on the reset */ + return GMACSL_RET_WARN_RESET_INCOMPLETE; +} + +int mac_sl_config(u_int16_t port, struct mac_sl_cfg *cfg) +{ + u32 v, i; + int ret = GMACSL_RET_OK; + + if (port >= DEVICE_N_GMACSL_PORTS) + return GMACSL_RET_INVALID_PORT; + + if (cfg->max_rx_len > CPGMAC_REG_MAXLEN_LEN) { + cfg->max_rx_len = CPGMAC_REG_MAXLEN_LEN; + ret = GMACSL_RET_WARN_MAXLEN_TOO_BIG; + } + + /* Must wait if the device is undergoing reset */ + for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) { + v = readl(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RESET); + if ((v & CPGMAC_REG_RESET_VAL_RESET_MASK) != + CPGMAC_REG_RESET_VAL_RESET) + break; + } + + if (i == DEVICE_EMACSL_RESET_POLL_COUNT) + return GMACSL_RET_CONFIG_FAIL_RESET_ACTIVE; + + writel(cfg->max_rx_len, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_MAXLEN); + writel(cfg->ctl, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_CTL); + +#ifndef CONFIG_SOC_K2HK + /* Map RX packet flow priority to 0 */ + writel(0, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RX_PRI_MAP); +#endif + + return ret; +} + +int ethss_config(u32 ctl, u32 max_pkt_size) +{ + u32 i; + + /* Max length register */ + writel(max_pkt_size, DEVICE_CPSW_BASE + CPSW_REG_MAXLEN); + + /* Control register */ + writel(ctl, DEVICE_CPSW_BASE + CPSW_REG_CTL); + + /* All statistics enabled by default */ + writel(CPSW_REG_VAL_STAT_ENABLE_ALL, + DEVICE_CPSW_BASE + CPSW_REG_STAT_PORT_EN); + + /* Reset and enable the ALE */ + writel(CPSW_REG_VAL_ALE_CTL_RESET_AND_ENABLE | + CPSW_REG_VAL_ALE_CTL_BYPASS, + DEVICE_CPSW_BASE + CPSW_REG_ALE_CONTROL); + + /* All ports put into forward mode */ + for (i = 0; i < DEVICE_CPSW_NUM_PORTS; i++) + writel(CPSW_REG_VAL_PORTCTL_FORWARD_MODE, + DEVICE_CPSW_BASE + CPSW_REG_ALE_PORTCTL(i)); + + return 0; +} + +int ethss_start(void) +{ + int i; + struct mac_sl_cfg cfg; + + cfg.max_rx_len = MAX_SIZE_STREAM_BUFFER; + cfg.ctl = GMACSL_ENABLE | GMACSL_RX_ENABLE_EXT_CTL; + + for (i = 0; i < DEVICE_N_GMACSL_PORTS; i++) { + mac_sl_reset(i); + mac_sl_config(i, &cfg); + } + + return 0; +} + +int ethss_stop(void) +{ + int i; + + for (i = 0; i < DEVICE_N_GMACSL_PORTS; i++) + mac_sl_reset(i); + + return 0; +} + +struct ks2_serdes ks2_serdes_sgmii_156p25mhz = { + .clk = SERDES_CLOCK_156P25M, + .rate = SERDES_RATE_5G, + .rate_mode = SERDES_QUARTER_RATE, + .intf = SERDES_PHY_SGMII, + .loopback = 0, +}; + +#ifndef CONFIG_SOC_K2G +static void keystone2_net_serdes_setup(void) +{ + ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII_BASE, + &ks2_serdes_sgmii_156p25mhz, + CONFIG_KSNET_SERDES_LANES_PER_SGMII); + +#if defined(CONFIG_SOC_K2E) || defined(CONFIG_SOC_K2L) + ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII2_BASE, + &ks2_serdes_sgmii_156p25mhz, + CONFIG_KSNET_SERDES_LANES_PER_SGMII); +#endif + + /* wait till setup */ + udelay(5000); +} +#endif + +#ifndef CONFIG_DM_ETH + +int keystone2_eth_read_mac_addr(struct eth_device *dev) +{ + struct eth_priv_t *eth_priv; + u32 maca = 0; + u32 macb = 0; + + eth_priv = (struct eth_priv_t *)dev->priv; + + /* Read the e-fuse mac address */ + if (eth_priv->slave_port == 1) { + maca = __raw_readl(MAC_ID_BASE_ADDR); + macb = __raw_readl(MAC_ID_BASE_ADDR + 4); + } + + dev->enetaddr[0] = (macb >> 8) & 0xff; + dev->enetaddr[1] = (macb >> 0) & 0xff; + dev->enetaddr[2] = (maca >> 24) & 0xff; + dev->enetaddr[3] = (maca >> 16) & 0xff; + dev->enetaddr[4] = (maca >> 8) & 0xff; + dev->enetaddr[5] = (maca >> 0) & 0xff; + + return 0; +} + +int32_t cpmac_drv_send(u32 *buffer, int num_bytes, int slave_port_num) +{ + if (num_bytes < EMAC_MIN_ETHERNET_PKT_SIZE) + num_bytes = EMAC_MIN_ETHERNET_PKT_SIZE; + + return ksnav_send(&netcp_pktdma, buffer, + num_bytes, (slave_port_num) << 16); +} + +/* Eth device open */ +static int keystone2_eth_open(struct eth_device *dev, bd_t *bis) +{ + struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv; + struct phy_device *phy_dev = eth_priv->phy_dev; + + debug("+ emac_open\n"); + + net_rx_buffs.rx_flow = eth_priv->rx_flow; + + sys_has_mdio = + (eth_priv->sgmii_link_type == SGMII_LINK_MAC_PHY) ? 1 : 0; + + if (sys_has_mdio) + keystone2_mdio_reset(mdio_bus); + +#ifdef CONFIG_SOC_K2G + keystone_rgmii_config(phy_dev); +#else + keystone_sgmii_config(phy_dev, eth_priv->slave_port - 1, + eth_priv->sgmii_link_type); +#endif + + udelay(10000); + + /* On chip switch configuration */ + ethss_config(target_get_switch_ctl(), SWITCH_MAX_PKT_SIZE); + + /* TODO: add error handling code */ + if (qm_init()) { + printf("ERROR: qm_init()\n"); + return -1; + } + if (ksnav_init(&netcp_pktdma, &net_rx_buffs)) { + qm_close(); + printf("ERROR: netcp_init()\n"); + return -1; + } + + /* + * Streaming switch configuration. If not present this + * statement is defined to void in target.h. + * If present this is usually defined to a series of register writes + */ + hw_config_streaming_switch(); + + if (sys_has_mdio) { + keystone2_mdio_reset(mdio_bus); + + phy_startup(phy_dev); + if (phy_dev->link == 0) { + ksnav_close(&netcp_pktdma); + qm_close(); + return -1; + } + } + + emac_gigabit_enable(dev); + + ethss_start(); + + debug("- emac_open\n"); + + emac_open = 1; + + return 0; +} + +/* Eth device close */ +void keystone2_eth_close(struct eth_device *dev) +{ + struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv; + struct phy_device *phy_dev = eth_priv->phy_dev; + + debug("+ emac_close\n"); + + if (!emac_open) + return; + + ethss_stop(); + + ksnav_close(&netcp_pktdma); + qm_close(); + phy_shutdown(phy_dev); + + emac_open = 0; + + debug("- emac_close\n"); +} + +/* + * This function sends a single packet on the network and returns + * positive number (number of bytes transmitted) or negative for error + */ +static int keystone2_eth_send_packet(struct eth_device *dev, + void *packet, int length) +{ + int ret_status = -1; + struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv; + struct phy_device *phy_dev = eth_priv->phy_dev; + + genphy_update_link(phy_dev); + if (phy_dev->link == 0) + return -1; + + if (cpmac_drv_send((u32 *)packet, length, eth_priv->slave_port) != 0) + return ret_status; + + return length; +} + +/* + * This function handles receipt of a packet from the network + */ +static int keystone2_eth_rcv_packet(struct eth_device *dev) +{ + void *hd; + int pkt_size; + u32 *pkt; + + hd = ksnav_recv(&netcp_pktdma, &pkt, &pkt_size); + if (hd == NULL) + return 0; + + net_process_received_packet((uchar *)pkt, pkt_size); + + ksnav_release_rxhd(&netcp_pktdma, hd); + + return pkt_size; +} + +#ifdef CONFIG_MCAST_TFTP +static int keystone2_eth_bcast_addr(struct eth_device *dev, u32 ip, u8 set) +{ + return 0; +} +#endif + +/* + * This function initializes the EMAC hardware. + */ +int keystone2_emac_initialize(struct eth_priv_t *eth_priv) +{ + int res; + struct eth_device *dev; + struct phy_device *phy_dev; + struct mdio_regs *adap_mdio = (struct mdio_regs *)EMAC_MDIO_BASE_ADDR; + + dev = malloc(sizeof(struct eth_device)); + if (dev == NULL) + return -1; + + memset(dev, 0, sizeof(struct eth_device)); + + strcpy(dev->name, eth_priv->int_name); + dev->priv = eth_priv; + + keystone2_eth_read_mac_addr(dev); + + dev->iobase = 0; + dev->init = keystone2_eth_open; + dev->halt = keystone2_eth_close; + dev->send = keystone2_eth_send_packet; + dev->recv = keystone2_eth_rcv_packet; +#ifdef CONFIG_MCAST_TFTP + dev->mcast = keystone2_eth_bcast_addr; +#endif + + eth_register(dev); + + /* Register MDIO bus if it's not registered yet */ + if (!mdio_bus) { + mdio_bus = mdio_alloc(); + mdio_bus->read = keystone2_mdio_read; + mdio_bus->write = keystone2_mdio_write; + mdio_bus->reset = keystone2_mdio_reset; + mdio_bus->priv = (void *)EMAC_MDIO_BASE_ADDR; + strcpy(mdio_bus->name, "ethernet-mdio"); + + res = mdio_register(mdio_bus); + if (res) + return res; + } + +#ifndef CONFIG_SOC_K2G + keystone2_net_serdes_setup(); +#endif + + /* Create phy device and bind it with driver */ +#ifdef CONFIG_KSNET_MDIO_PHY_CONFIG_ENABLE + phy_dev = phy_connect(mdio_bus, eth_priv->phy_addr, + dev, eth_priv->phy_if); + phy_config(phy_dev); +#else + phy_dev = phy_find_by_mask(mdio_bus, 1 << eth_priv->phy_addr, + eth_priv->phy_if); + phy_dev->dev = dev; +#endif + eth_priv->phy_dev = phy_dev; + + return 0; +} + +#else + +static int ks2_eth_start(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + +#ifdef CONFIG_SOC_K2G + keystone_rgmii_config(priv->phydev); +#else + keystone_sgmii_config(priv->phydev, priv->slave_port - 1, + priv->sgmii_link_type); +#endif + + udelay(10000); + + /* On chip switch configuration */ + ethss_config(target_get_switch_ctl(), SWITCH_MAX_PKT_SIZE); + + qm_init(); + + if (ksnav_init(priv->netcp_pktdma, &priv->net_rx_buffs)) { + pr_err("ksnav_init failed\n"); + goto err_knav_init; + } + + /* + * Streaming switch configuration. If not present this + * statement is defined to void in target.h. + * If present this is usually defined to a series of register writes + */ + hw_config_streaming_switch(); + + if (priv->has_mdio) { + keystone2_mdio_reset(priv->mdio_bus); + + phy_startup(priv->phydev); + if (priv->phydev->link == 0) { + pr_err("phy startup failed\n"); + goto err_phy_start; + } + } + + emac_gigabit_enable(dev); + + ethss_start(); + + priv->emac_open = true; + + return 0; + +err_phy_start: + ksnav_close(priv->netcp_pktdma); +err_knav_init: + qm_close(); + + return -EFAULT; +} + +static int ks2_eth_send(struct udevice *dev, void *packet, int length) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + + genphy_update_link(priv->phydev); + if (priv->phydev->link == 0) + return -1; + + if (length < EMAC_MIN_ETHERNET_PKT_SIZE) + length = EMAC_MIN_ETHERNET_PKT_SIZE; + + return ksnav_send(priv->netcp_pktdma, (u32 *)packet, + length, (priv->slave_port) << 16); +} + +static int ks2_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + int pkt_size; + u32 *pkt = NULL; + + priv->hd = ksnav_recv(priv->netcp_pktdma, &pkt, &pkt_size); + if (priv->hd == NULL) + return -EAGAIN; + + *packetp = (uchar *)pkt; + + return pkt_size; +} + +static int ks2_eth_free_pkt(struct udevice *dev, uchar *packet, + int length) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + + ksnav_release_rxhd(priv->netcp_pktdma, priv->hd); + + return 0; +} + +static void ks2_eth_stop(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + + if (!priv->emac_open) + return; + ethss_stop(); + + ksnav_close(priv->netcp_pktdma); + qm_close(); + phy_shutdown(priv->phydev); + priv->emac_open = false; +} + +int ks2_eth_read_rom_hwaddr(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + u32 maca = 0; + u32 macb = 0; + + /* Read the e-fuse mac address */ + if (priv->slave_port == 1) { + maca = __raw_readl(MAC_ID_BASE_ADDR); + macb = __raw_readl(MAC_ID_BASE_ADDR + 4); + } + + pdata->enetaddr[0] = (macb >> 8) & 0xff; + pdata->enetaddr[1] = (macb >> 0) & 0xff; + pdata->enetaddr[2] = (maca >> 24) & 0xff; + pdata->enetaddr[3] = (maca >> 16) & 0xff; + pdata->enetaddr[4] = (maca >> 8) & 0xff; + pdata->enetaddr[5] = (maca >> 0) & 0xff; + + return 0; +} + +int ks2_eth_write_hwaddr(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + + writel(mac_hi(pdata->enetaddr), + DEVICE_EMACSW_BASE(pdata->iobase, priv->slave_port - 1) + + CPGMACSL_REG_SA_HI); + writel(mac_lo(pdata->enetaddr), + DEVICE_EMACSW_BASE(pdata->iobase, priv->slave_port - 1) + + CPGMACSL_REG_SA_LO); + + return 0; +} + +static int ks2_eth_probe(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + struct mii_dev *mdio_bus; + int ret; + + priv->dev = dev; + + /* These clock enables has to be moved to common location */ + if (cpu_is_k2g()) + writel(KS2_ETHERNET_RGMII, KS2_ETHERNET_CFG); + + /* By default, select PA PLL clock as PA clock source */ +#ifndef CONFIG_SOC_K2G + if (psc_enable_module(KS2_LPSC_PA)) + return -EACCES; +#endif + if (psc_enable_module(KS2_LPSC_CPGMAC)) + return -EACCES; + if (psc_enable_module(KS2_LPSC_CRYPTO)) + return -EACCES; + + if (cpu_is_k2e() || cpu_is_k2l()) + pll_pa_clk_sel(); + + + priv->net_rx_buffs.buff_ptr = rx_buffs; + priv->net_rx_buffs.num_buffs = RX_BUFF_NUMS; + priv->net_rx_buffs.buff_len = RX_BUFF_LEN; + + if (priv->slave_port == 1) { + /* + * Register MDIO bus for slave 0 only, other slave have + * to re-use the same + */ + mdio_bus = mdio_alloc(); + if (!mdio_bus) { + pr_err("MDIO alloc failed\n"); + return -ENOMEM; + } + priv->mdio_bus = mdio_bus; + mdio_bus->read = keystone2_mdio_read; + mdio_bus->write = keystone2_mdio_write; + mdio_bus->reset = keystone2_mdio_reset; + mdio_bus->priv = priv->mdio_base; + sprintf(mdio_bus->name, "ethernet-mdio"); + + ret = mdio_register(mdio_bus); + if (ret) { + pr_err("MDIO bus register failed\n"); + return ret; + } + } else { + /* Get the MDIO bus from slave 0 device */ + struct ks2_eth_priv *parent_priv; + + parent_priv = dev_get_priv(dev->parent); + priv->mdio_bus = parent_priv->mdio_bus; + } + +#ifndef CONFIG_SOC_K2G + keystone2_net_serdes_setup(); +#endif + + priv->netcp_pktdma = &netcp_pktdma; + + if (priv->has_mdio) { + priv->phydev = phy_connect(priv->mdio_bus, priv->phy_addr, + dev, priv->phy_if); + phy_config(priv->phydev); + } + + return 0; +} + +int ks2_eth_remove(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + + free(priv->phydev); + mdio_unregister(priv->mdio_bus); + mdio_free(priv->mdio_bus); + + return 0; +} + +static const struct eth_ops ks2_eth_ops = { + .start = ks2_eth_start, + .send = ks2_eth_send, + .recv = ks2_eth_recv, + .free_pkt = ks2_eth_free_pkt, + .stop = ks2_eth_stop, + .read_rom_hwaddr = ks2_eth_read_rom_hwaddr, + .write_hwaddr = ks2_eth_write_hwaddr, +}; + +static int ks2_eth_bind_slaves(struct udevice *dev, int gbe, int *gbe_0) +{ + const void *fdt = gd->fdt_blob; + struct udevice *sl_dev; + int interfaces; + int sec_slave; + int slave; + int ret; + char *slave_name; + + interfaces = fdt_subnode_offset(fdt, gbe, "interfaces"); + fdt_for_each_subnode(slave, fdt, interfaces) { + int slave_no; + + slave_no = fdtdec_get_int(fdt, slave, "slave-port", -ENOENT); + if (slave_no == -ENOENT) + continue; + + if (slave_no == 0) { + /* This is the current eth device */ + *gbe_0 = slave; + } else { + /* Slave devices to be registered */ + slave_name = malloc(20); + snprintf(slave_name, 20, "netcp@slave-%d", slave_no); + ret = device_bind_driver_to_node(dev, "eth_ks2_sl", + slave_name, offset_to_ofnode(slave), + &sl_dev); + if (ret) { + pr_err("ks2_net - not able to bind slave interfaces\n"); + return ret; + } + } + } + + sec_slave = fdt_subnode_offset(fdt, gbe, "secondary-slave-ports"); + fdt_for_each_subnode(slave, fdt, sec_slave) { + int slave_no; + + slave_no = fdtdec_get_int(fdt, slave, "slave-port", -ENOENT); + if (slave_no == -ENOENT) + continue; + + /* Slave devices to be registered */ + slave_name = malloc(20); + snprintf(slave_name, 20, "netcp@slave-%d", slave_no); + ret = device_bind_driver_to_node(dev, "eth_ks2_sl", slave_name, + offset_to_ofnode(slave), &sl_dev); + if (ret) { + pr_err("ks2_net - not able to bind slave interfaces\n"); + return ret; + } + } + + return 0; +} + +static int ks2_eth_parse_slave_interface(int netcp, int slave, + struct ks2_eth_priv *priv, + struct eth_pdata *pdata) +{ + const void *fdt = gd->fdt_blob; + int mdio; + int phy; + int dma_count; + u32 dma_channel[8]; + + priv->slave_port = fdtdec_get_int(fdt, slave, "slave-port", -1); + priv->net_rx_buffs.rx_flow = priv->slave_port * 8; + + /* U-Boot slave port number starts with 1 instead of 0 */ + priv->slave_port += 1; + + dma_count = fdtdec_get_int_array_count(fdt, netcp, + "ti,navigator-dmas", + dma_channel, 8); + + if (dma_count > (2 * priv->slave_port)) { + int dma_idx; + + dma_idx = priv->slave_port * 2 - 1; + priv->net_rx_buffs.rx_flow = dma_channel[dma_idx]; + } + + priv->link_type = fdtdec_get_int(fdt, slave, "link-interface", -1); + + phy = fdtdec_lookup_phandle(fdt, slave, "phy-handle"); + if (phy >= 0) { + priv->phy_addr = fdtdec_get_int(fdt, phy, "reg", -1); + + mdio = fdt_parent_offset(fdt, phy); + if (mdio < 0) { + pr_err("mdio dt not found\n"); + return -ENODEV; + } + priv->mdio_base = (void *)fdtdec_get_addr(fdt, mdio, "reg"); + } + + if (priv->link_type == LINK_TYPE_SGMII_MAC_TO_PHY_MODE) { + priv->phy_if = PHY_INTERFACE_MODE_SGMII; + pdata->phy_interface = priv->phy_if; + priv->sgmii_link_type = SGMII_LINK_MAC_PHY; + priv->has_mdio = true; + } else if (priv->link_type == LINK_TYPE_RGMII_LINK_MAC_PHY) { + priv->phy_if = PHY_INTERFACE_MODE_RGMII; + pdata->phy_interface = priv->phy_if; + priv->has_mdio = true; + } + + return 0; +} + +static int ks2_sl_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + const void *fdt = gd->fdt_blob; + int slave = dev_of_offset(dev); + int interfaces; + int gbe; + int netcp_devices; + int netcp; + + interfaces = fdt_parent_offset(fdt, slave); + gbe = fdt_parent_offset(fdt, interfaces); + netcp_devices = fdt_parent_offset(fdt, gbe); + netcp = fdt_parent_offset(fdt, netcp_devices); + + ks2_eth_parse_slave_interface(netcp, slave, priv, pdata); + + pdata->iobase = fdtdec_get_addr(fdt, netcp, "reg"); + + return 0; +} + +static int ks2_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + const void *fdt = gd->fdt_blob; + int gbe_0 = -ENODEV; + int netcp_devices; + int gbe; + + netcp_devices = fdt_subnode_offset(fdt, dev_of_offset(dev), + "netcp-devices"); + gbe = fdt_subnode_offset(fdt, netcp_devices, "gbe"); + + ks2_eth_bind_slaves(dev, gbe, &gbe_0); + + ks2_eth_parse_slave_interface(dev_of_offset(dev), gbe_0, priv, pdata); + + pdata->iobase = devfdt_get_addr(dev); + + return 0; +} + +static const struct udevice_id ks2_eth_ids[] = { + { .compatible = "ti,netcp-1.0" }, + { } +}; + +U_BOOT_DRIVER(eth_ks2_slave) = { + .name = "eth_ks2_sl", + .id = UCLASS_ETH, + .ofdata_to_platdata = ks2_sl_eth_ofdata_to_platdata, + .probe = ks2_eth_probe, + .remove = ks2_eth_remove, + .ops = &ks2_eth_ops, + .priv_auto_alloc_size = sizeof(struct ks2_eth_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; + +U_BOOT_DRIVER(eth_ks2) = { + .name = "eth_ks2", + .id = UCLASS_ETH, + .of_match = ks2_eth_ids, + .ofdata_to_platdata = ks2_eth_ofdata_to_platdata, + .probe = ks2_eth_probe, + .remove = ks2_eth_remove, + .ops = &ks2_eth_ops, + .priv_auto_alloc_size = sizeof(struct ks2_eth_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; +#endif -- cgit v1.2.3