#include <net.h>
#include <dp83848.h>
#include <asm/arch/emac_defs.h>
-#include "../../../drivers/net/davinci_emac.h"
+#include "../../../drivers/net/ti/davinci_emac.h"
#ifdef CONFIG_DRIVER_TI_EMAC
#include <net.h>
#include <miiphy.h>
#include <asm/arch/emac_defs.h>
-#include "../../../drivers/net/davinci_emac.h"
+#include "../../../drivers/net/ti/davinci_emac.h"
#ifdef CONFIG_DRIVER_TI_EMAC
#include <net.h>
#include <asm/arch/emac_defs.h>
#include <asm/io.h>
-#include "../../../drivers/net/davinci_emac.h"
+#include "../../../drivers/net/ti/davinci_emac.h"
int ksz8873_is_phy_connected(int phy_addr)
{
#include <miiphy.h>
#include <lxt971a.h>
#include <asm/arch/emac_defs.h>
-#include "../../../drivers/net/davinci_emac.h"
+#include "../../../drivers/net/ti/davinci_emac.h"
#ifdef CONFIG_DRIVER_TI_EMAC
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
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)
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
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
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/
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * CPSW common - libs used across TI ethernet devices.
- *
- * Copyright (C) 2016, Texas Instruments, Incorporated
- */
-
-#include <common.h>
-#include <dm.h>
-#include <environment.h>
-#include <fdt_support.h>
-#include <asm/io.h>
-#include <cpsw.h>
-
-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;
-}
+++ /dev/null
-/*
- * 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 <common.h>
-#include <command.h>
-#include <net.h>
-#include <miiphy.h>
-#include <malloc.h>
-#include <net.h>
-#include <netdev.h>
-#include <cpsw.h>
-#include <linux/errno.h>
-#include <asm/gpio.h>
-#include <asm/io.h>
-#include <phy.h>
-#include <asm/arch/cpu.h>
-#include <dm.h>
-#include <fdt_support.h>
-
-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 */
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Ethernet driver for TI TMS320DM644x (DaVinci) chips.
- *
- * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
- *
- * 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 <common.h>
-#include <command.h>
-#include <net.h>
-#include <miiphy.h>
-#include <malloc.h>
-#include <netdev.h>
-#include <linux/compiler.h>
-#include <asm/arch/emac_defs.h>
-#include <asm/io.h>
-#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);
-}
+++ /dev/null
-/* 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 <ksi@koi8.net>
- */
-
-#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_ */
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Ethernet driver for TI K2HK EVM.
- *
- * (C) Copyright 2012-2014
- * Texas Instruments Incorporated, <www.ti.com>
- */
-#include <common.h>
-#include <command.h>
-#include <console.h>
-
-#include <dm.h>
-#include <dm/lists.h>
-
-#include <net.h>
-#include <phy.h>
-#include <errno.h>
-#include <miiphy.h>
-#include <malloc.h>
-#include <asm/ti-common/keystone_nav.h>
-#include <asm/ti-common/keystone_net.h>
-#include <asm/ti-common/keystone_serdes.h>
-#include <asm/arch/psc_defs.h>
-
-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
--- /dev/null
+# 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
--- /dev/null
+# 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
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * CPSW common - libs used across TI ethernet devices.
+ *
+ * Copyright (C) 2016, Texas Instruments, Incorporated
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <environment.h>
+#include <fdt_support.h>
+#include <asm/io.h>
+#include <cpsw.h>
+
+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;
+}
--- /dev/null
+/*
+ * 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 <common.h>
+#include <command.h>
+#include <net.h>
+#include <miiphy.h>
+#include <malloc.h>
+#include <net.h>
+#include <netdev.h>
+#include <cpsw.h>
+#include <linux/errno.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <phy.h>
+#include <asm/arch/cpu.h>
+#include <dm.h>
+#include <fdt_support.h>
+
+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 */
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Ethernet driver for TI TMS320DM644x (DaVinci) chips.
+ *
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * 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 <common.h>
+#include <command.h>
+#include <net.h>
+#include <miiphy.h>
+#include <malloc.h>
+#include <netdev.h>
+#include <linux/compiler.h>
+#include <asm/arch/emac_defs.h>
+#include <asm/io.h>
+#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);
+}
--- /dev/null
+/* 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 <ksi@koi8.net>
+ */
+
+#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_ */
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Ethernet driver for TI K2HK EVM.
+ *
+ * (C) Copyright 2012-2014
+ * Texas Instruments Incorporated, <www.ti.com>
+ */
+#include <common.h>
+#include <command.h>
+#include <console.h>
+
+#include <dm.h>
+#include <dm/lists.h>
+
+#include <net.h>
+#include <phy.h>
+#include <errno.h>
+#include <miiphy.h>
+#include <malloc.h>
+#include <asm/ti-common/keystone_nav.h>
+#include <asm/ti-common/keystone_net.h>
+#include <asm/ti-common/keystone_serdes.h>
+#include <asm/arch/psc_defs.h>
+
+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