Merge branch 'master' of git://git.denx.de/u-boot-net into next

- ftgmac100 improvements
- TI: CPSW improvements
- VSC8584 PHY support
- Add MT7628 ethernet driver
This commit is contained in:
Tom Rini 2018-11-05 13:32:56 -05:00
commit 9e2a902809
41 changed files with 3758 additions and 2131 deletions

View file

@ -11,6 +11,11 @@
chosen {
stdout-path = &uart5;
};
aliases {
ethernet0 = &mac0;
ethernet1 = &mac1;
};
};
&uart5 {
@ -36,3 +41,21 @@
u-boot,dm-pre-reloc;
status = "okay";
};
&mac0 {
status = "okay";
phy-mode = "rgmii";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mac1link_default &pinctrl_mdio1_default>;
};
&mac1 {
status = "okay";
phy-mode = "rgmii";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mac2link_default &pinctrl_mdio2_default>;
};

File diff suppressed because it is too large Load diff

View file

@ -57,19 +57,6 @@
/* MDIO clock output frequency */
#define EMAC_MDIO_CLOCK_FREQ 2500000 /* 2.5 MHz */
/* MII Status Register */
#define MII_STATUS_REG 1
#define MII_STATUS_LINK_MASK 0x4
#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
#define EMAC_MACCONTROL_MIIEN_ENABLE 0x20
#define EMAC_MACCONTROL_FULLDUPLEX_ENABLE 0x1
#define EMAC_MACCONTROL_GIGABIT_ENABLE BIT(7)
@ -242,18 +229,4 @@ struct mdio_regs {
u32 userphysel1;
};
struct eth_priv_t {
char int_name[32];
int rx_flow;
int phy_addr;
int slave_port;
int sgmii_link_type;
phy_interface_t phy_if;
struct phy_device *phy_dev;
};
int keystone2_emac_initialize(struct eth_priv_t *eth_priv);
void sgmii_serdes_setup_156p25mhz(void);
void sgmii_serdes_shutdown(void);
#endif /* _KEYSTONE_NET_H_ */

View file

@ -12,7 +12,7 @@
#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

View file

@ -9,7 +9,7 @@
#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

View file

@ -19,7 +19,7 @@
#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)
{

View file

@ -13,7 +13,7 @@
#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

View file

@ -66,59 +66,6 @@ int board_init(void)
return 0;
}
#ifdef CONFIG_DRIVER_TI_KEYSTONE_NET
#ifndef CONFIG_DM_ETH
int get_eth_env_param(char *env_name)
{
char *env;
int res = -1;
env = env_get(env_name);
if (env)
res = simple_strtol(env, NULL, 0);
return res;
}
int board_eth_init(bd_t *bis)
{
int j;
int res;
int port_num;
char link_type_name[32];
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 -1;
#endif
if (psc_enable_module(KS2_LPSC_CPGMAC))
return -1;
if (psc_enable_module(KS2_LPSC_CRYPTO))
return -1;
if (cpu_is_k2e() || cpu_is_k2l())
pll_pa_clk_sel();
port_num = get_num_eth_ports();
for (j = 0; j < port_num; j++) {
sprintf(link_type_name, "sgmii%d_link_type", j);
res = get_eth_env_param(link_type_name);
if (res >= 0)
eth_priv_cfg[j].sgmii_link_type = res;
keystone2_emac_initialize(&eth_priv_cfg[j]);
}
return 0;
}
#endif
#endif
#ifdef CONFIG_SPL_BUILD
void spl_board_init(void)
{

View file

@ -12,8 +12,6 @@
#include <asm/ti-common/keystone_net.h>
#include "../common/board_detect.h"
extern struct eth_priv_t eth_priv_cfg[];
#if defined(CONFIG_TI_I2C_BOARD_DETECT)
static inline int board_is_k2g_gp(void)
{
@ -38,7 +36,6 @@ static inline int board_is_k2g_ice(void)
}
#endif
int get_num_eth_ports(void);
void spl_init_keystone_plls(void);
#endif

View file

@ -89,80 +89,6 @@ struct pll_init_data *get_pll_init_data(int pll)
return data;
}
#ifdef CONFIG_DRIVER_TI_KEYSTONE_NET
struct eth_priv_t eth_priv_cfg[] = {
{
.int_name = "K2E_EMAC0",
.rx_flow = 0,
.phy_addr = 0,
.slave_port = 1,
.sgmii_link_type = SGMII_LINK_MAC_PHY,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
{
.int_name = "K2E_EMAC1",
.rx_flow = 8,
.phy_addr = 1,
.slave_port = 2,
.sgmii_link_type = SGMII_LINK_MAC_PHY,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
{
.int_name = "K2E_EMAC2",
.rx_flow = 16,
.phy_addr = 2,
.slave_port = 3,
.sgmii_link_type = SGMII_LINK_MAC_MAC_FORCED,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
{
.int_name = "K2E_EMAC3",
.rx_flow = 24,
.phy_addr = 3,
.slave_port = 4,
.sgmii_link_type = SGMII_LINK_MAC_MAC_FORCED,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
{
.int_name = "K2E_EMAC4",
.rx_flow = 32,
.phy_addr = 4,
.slave_port = 5,
.sgmii_link_type = SGMII_LINK_MAC_MAC_FORCED,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
{
.int_name = "K2E_EMAC5",
.rx_flow = 40,
.phy_addr = 5,
.slave_port = 6,
.sgmii_link_type = SGMII_LINK_MAC_MAC_FORCED,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
{
.int_name = "K2E_EMAC6",
.rx_flow = 48,
.phy_addr = 6,
.slave_port = 7,
.sgmii_link_type = SGMII_LINK_MAC_MAC_FORCED,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
{
.int_name = "K2E_EMAC7",
.rx_flow = 56,
.phy_addr = 7,
.slave_port = 8,
.sgmii_link_type = SGMII_LINK_MAC_MAC_FORCED,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
};
int get_num_eth_ports(void)
{
return sizeof(eth_priv_cfg) / sizeof(struct eth_priv_t);
}
#endif
#if defined(CONFIG_MULTI_DTB_FIT)
int board_fit_config_name_match(const char *name)
{

View file

@ -354,24 +354,6 @@ void spl_init_keystone_plls(void)
}
#endif
#ifdef CONFIG_DRIVER_TI_KEYSTONE_NET
struct eth_priv_t eth_priv_cfg[] = {
{
.int_name = "K2G_EMAC",
.rx_flow = 0,
.phy_addr = 0,
.slave_port = 1,
.sgmii_link_type = SGMII_LINK_MAC_PHY,
.phy_if = PHY_INTERFACE_MODE_RGMII,
},
};
int get_num_eth_ports(void)
{
return sizeof(eth_priv_cfg) / sizeof(struct eth_priv_t);
}
#endif
#ifdef CONFIG_TI_SECURE_DEVICE
void board_pmmc_image_process(ulong pmmc_image, size_t pmmc_size)
{

View file

@ -96,48 +96,6 @@ struct pll_init_data *get_pll_init_data(int pll)
return data;
}
#ifdef CONFIG_DRIVER_TI_KEYSTONE_NET
struct eth_priv_t eth_priv_cfg[] = {
{
.int_name = "K2HK_EMAC",
.rx_flow = 22,
.phy_addr = 0,
.slave_port = 1,
.sgmii_link_type = SGMII_LINK_MAC_PHY,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
{
.int_name = "K2HK_EMAC1",
.rx_flow = 23,
.phy_addr = 1,
.slave_port = 2,
.sgmii_link_type = SGMII_LINK_MAC_PHY,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
{
.int_name = "K2HK_EMAC2",
.rx_flow = 24,
.phy_addr = 2,
.slave_port = 3,
.sgmii_link_type = SGMII_LINK_MAC_MAC_FORCED,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
{
.int_name = "K2HK_EMAC3",
.rx_flow = 25,
.phy_addr = 3,
.slave_port = 4,
.sgmii_link_type = SGMII_LINK_MAC_MAC_FORCED,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
};
int get_num_eth_ports(void)
{
return sizeof(eth_priv_cfg) / sizeof(struct eth_priv_t);
}
#endif
#ifdef CONFIG_BOARD_EARLY_INIT_F
int board_early_init_f(void)
{

View file

@ -84,48 +84,6 @@ struct pll_init_data *get_pll_init_data(int pll)
return data;
}
#ifdef CONFIG_DRIVER_TI_KEYSTONE_NET
struct eth_priv_t eth_priv_cfg[] = {
{
.int_name = "K2L_EMAC",
.rx_flow = 0,
.phy_addr = 0,
.slave_port = 1,
.sgmii_link_type = SGMII_LINK_MAC_PHY,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
{
.int_name = "K2L_EMAC1",
.rx_flow = 8,
.phy_addr = 1,
.slave_port = 2,
.sgmii_link_type = SGMII_LINK_MAC_PHY,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
{
.int_name = "K2L_EMAC2",
.rx_flow = 16,
.phy_addr = 2,
.slave_port = 3,
.sgmii_link_type = SGMII_LINK_MAC_MAC_FORCED,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
{
.int_name = "K2L_EMAC3",
.rx_flow = 32,
.phy_addr = 3,
.slave_port = 4,
.sgmii_link_type = SGMII_LINK_MAC_MAC_FORCED,
.phy_if = PHY_INTERFACE_MODE_SGMII,
},
};
int get_num_eth_ports(void)
{
return sizeof(eth_priv_cfg) / sizeof(struct eth_priv_t);
}
#endif
#ifdef CONFIG_BOARD_EARLY_INIT_F
int board_early_init_f(void)
{

View file

@ -25,3 +25,11 @@ CONFIG_SYS_NS16550=y
CONFIG_SYSRESET=y
CONFIG_TIMER=y
CONFIG_WDT=y
CONFIG_NETDEVICES=y
CONFIG_PHY=y
CONFIG_DM_ETH=y
CONFIG_FTGMAC100=y
CONFIG_PHY_REALTEK=y
CONFIG_CMD_PING=y
CONFIG_CMD_DHCP=y
CONFIG_CMD_MII=y

View file

@ -56,3 +56,4 @@ CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
CONFIG_USB_STORAGE=y
CONFIG_DRIVER_TI_KEYSTONE_NET=y

View file

@ -49,3 +49,4 @@ CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
CONFIG_USB_STORAGE=y
CONFIG_DRIVER_TI_KEYSTONE_NET=y

View file

@ -60,3 +60,4 @@ CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
CONFIG_USB_STORAGE=y
CONFIG_DRIVER_TI_KEYSTONE_NET=y

View file

@ -53,3 +53,4 @@ CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
CONFIG_USB_STORAGE=y
CONFIG_DRIVER_TI_KEYSTONE_NET=y

View file

@ -56,3 +56,4 @@ CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
CONFIG_USB_STORAGE=y
CONFIG_DRIVER_TI_KEYSTONE_NET=y

View file

@ -49,3 +49,4 @@ CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
CONFIG_USB_STORAGE=y
CONFIG_DRIVER_TI_KEYSTONE_NET=y

View file

@ -56,3 +56,4 @@ CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
CONFIG_USB_STORAGE=y
CONFIG_DRIVER_TI_KEYSTONE_NET=y

View file

@ -48,3 +48,4 @@ CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
CONFIG_USB_STORAGE=y
CONFIG_DRIVER_TI_KEYSTONE_NET=y

View file

@ -0,0 +1,17 @@
* MediaTek Frame Engine Ethernet controller
Required properties:
- compatible: should be "mediatek,mt7628-eth"
- reg: address and length of the register set for the frame
engine ethernet controller and the internal switch.
- syscon: phandle to the system controller
Example:
eth@10100000 {
compatible = "mediatek,mt7628-eth";
reg = <0x10100000 0x10000
0x10110000 0x8000>;
syscon = <&sysc>;
};

View file

@ -165,6 +165,35 @@ static ulong ast2500_clk_get_rate(struct clk *clk)
return rate;
}
struct ast2500_clock_config {
ulong input_rate;
ulong rate;
struct ast2500_div_config cfg;
};
static const struct ast2500_clock_config ast2500_clock_config_defaults[] = {
{ 24000000, 250000000, { .num = 124, .denum = 1, .post_div = 5 } },
};
static bool ast2500_get_clock_config_default(ulong input_rate,
ulong requested_rate,
struct ast2500_div_config *cfg)
{
int i;
for (i = 0; i < ARRAY_SIZE(ast2500_clock_config_defaults); i++) {
const struct ast2500_clock_config *default_cfg =
&ast2500_clock_config_defaults[i];
if (default_cfg->input_rate == input_rate &&
default_cfg->rate == requested_rate) {
*cfg = default_cfg->cfg;
return true;
}
}
return false;
}
/*
* @input_rate - the rate of input clock in Hz
* @requested_rate - desired output rate in Hz
@ -189,6 +218,12 @@ static ulong ast2500_calc_clock_config(ulong input_rate, ulong requested_rate,
ulong delta = rate_khz;
ulong new_rate_khz = 0;
/*
* Look for a well known frequency first.
*/
if (ast2500_get_clock_config_default(input_rate, requested_rate, cfg))
return requested_rate;
for (; it.denum <= max_vals.denum; ++it.denum) {
for (it.post_div = 0; it.post_div <= max_vals.post_div;
++it.post_div) {
@ -318,6 +353,9 @@ static ulong ast2500_configure_d2pll(struct ast2500_scu *scu, ulong rate)
/*
* The values and the meaning of the next three
* parameters are undocumented. Taken from Aspeed SDK.
*
* TODO(clg@kaod.org): the SIP and SIC values depend on the
* Numerator value
*/
const u32 d2_pll_ext_param = 0x2c;
const u32 d2_pll_sip = 0x11;
@ -411,6 +449,7 @@ static int ast2500_clk_enable(struct clk *clk)
break;
case PLL_D2PLL:
ast2500_configure_d2pll(priv->scu, D2PLL_DEFAULT_RATE);
break;
default:
return -ENOENT;
}

View file

@ -11,13 +11,6 @@ config DM_ETH
This is currently implemented in net/eth-uclass.c
Look in include/net.h for details.
config DRIVER_TI_CPSW
bool "TI Common Platform Ethernet Switch"
select PHYLIB
help
This driver supports the TI three port switch gigabit ethernet
subsystem found in the TI SoCs.
menuconfig NETDEVICES
bool "Network device support"
depends on NET
@ -186,6 +179,32 @@ config FTMAC100
help
This MAC is present in Andestech SoCs.
config FTGMAC100
bool "Ftgmac100 Ethernet Support"
depends on DM_ETH
select PHYLIB
help
This driver supports the Faraday's FTGMAC100 Gigabit SoC
Ethernet controller that can be found on Aspeed SoCs (which
include NCSI).
It is fully compliant with IEEE 802.3 specification for
10/100 Mbps Ethernet and IEEE 802.3z specification for 1000
Mbps Ethernet and includes Reduced Media Independent
Interface (RMII) and Reduced Gigabit Media Independent
Interface (RGMII) interfaces. It adopts an AHB bus interface
and integrates a link list DMA engine with direct M-Bus
accesses for transmitting and receiving packets. It has
independent TX/RX fifos, supports half and full duplex (1000
Mbps mode only supports full duplex), flow control for full
duplex and backpressure for half duplex.
The FTGMAC100 also implements IP, TCP, UDP checksum offloads
and supports IEEE 802.1Q VLAN tag insertion and removal. It
offers high-priority transmit queue for QoS and CoS
applications.
config MVGBE
bool "Marvell Orion5x/Kirkwood network interface support"
depends on KIRKWOOD || ORION5X
@ -227,6 +246,13 @@ config MACB_ZYNQ
The Cadence MACB ethernet interface was used on Zynq platform.
Say Y to enable support for the MACB/GEM in Zynq chip.
config MT7628_ETH
bool "MediaTek MT7628 Ethernet Interface"
depends on ARCH_MT7620
help
The MediaTek MT7628 ethernet interface is used on MT7628 and
MT7688 based boards.
config PCH_GBE
bool "Intel Platform Controller Hub EG20T GMAC driver"
depends on DM_ETH && DM_PCI
@ -322,10 +348,7 @@ config SH_ETHER
help
This driver supports the Ethernet for Renesas SH and ARM SoCs.
config DRIVER_TI_EMAC
bool "TI Davinci EMAC"
help
Support for davinci emac
source "drivers/net/ti/Kconfig"
config XILINX_AXIEMAC
depends on DM_ETH && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP)

View file

@ -30,13 +30,13 @@ obj-$(CONFIG_FTGMAC100) += ftgmac100.o
obj-$(CONFIG_FTMAC110) += ftmac110.o
obj-$(CONFIG_FTMAC100) += ftmac100.o
obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o
obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o
obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o
obj-$(CONFIG_LAN91C96) += lan91c96.o
obj-$(CONFIG_LPC32XX_ETH) += lpc32xx_eth.o
obj-$(CONFIG_MACB) += macb.o
obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
obj-$(CONFIG_MPC8XX_FEC) += mpc8xx_fec.o
obj-$(CONFIG_MT7628_ETH) += mt7628-eth.o
obj-$(CONFIG_MVGBE) += mvgbe.o
obj-$(CONFIG_MVNETA) += mvneta.o
obj-$(CONFIG_MVPP2) += mvpp2.o
@ -56,9 +56,7 @@ obj-$(CONFIG_SH_ETHER) += sh_eth.o
obj-$(CONFIG_RENESAS_RAVB) += ravb.o
obj-$(CONFIG_SMC91111) += smc91111.o
obj-$(CONFIG_SMC911X) += smc911x.o
obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
obj-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o
obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o cpsw-common.o
obj-$(CONFIG_FMAN_ENET) += fsl_mdio.o
obj-$(CONFIG_ULI526X) += uli526x.o
obj-$(CONFIG_VSC7385_ENET) += vsc7385.o
@ -73,3 +71,4 @@ obj-$(CONFIG_PIC32_ETH) += pic32_mdio.o pic32_eth.o
obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o
obj-$(CONFIG_FSL_PFE) += pfe_eth/
obj-$(CONFIG_SNI_AVE) += sni_ave.o
obj-y += ti/

View file

@ -7,321 +7,239 @@
*
* (C) Copyright 2010 Andes Technology
* Macpaul Lin <macpaul@andestech.com>
*
* Copyright (C) 2018, IBM Corporation.
*/
#include <config.h>
#include <common.h>
#include <malloc.h>
#include <clk.h>
#include <dm.h>
#include <miiphy.h>
#include <net.h>
#include <asm/io.h>
#include <asm/dma-mapping.h>
#include <linux/mii.h>
#include <wait_bit.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include "ftgmac100.h"
#define ETH_ZLEN 60
#define CFG_XBUF_SIZE 1536
/* Min frame ethernet frame size without FCS */
#define ETH_ZLEN 60
/* RBSR - hw default init value is also 0x640 */
#define RBSR_DEFAULT_VALUE 0x640
/* Receive Buffer Size Register - HW default is 0x640 */
#define FTGMAC100_RBSR_DEFAULT 0x640
/* PKTBUFSTX/PKTBUFSRX must both be power of 2 */
#define PKTBUFSTX 4 /* must be power of 2 */
/* Timeout for transmit */
#define FTGMAC100_TX_TIMEOUT_MS 1000
/* Timeout for a mdio read/write operation */
#define FTGMAC100_MDIO_TIMEOUT_USEC 10000
/*
* MDC clock cycle threshold
*
* 20us * 100 = 2ms > (1 / 2.5Mhz) * 0x34
*/
#define MDC_CYCTHR 0x34
/*
* ftgmac100 model variants
*/
enum ftgmac100_model {
FTGMAC100_MODEL_FARADAY,
FTGMAC100_MODEL_ASPEED,
};
/**
* struct ftgmac100_data - private data for the FTGMAC100 driver
*
* @iobase: The base address of the hardware registers
* @txdes: The array of transmit descriptors
* @rxdes: The array of receive descriptors
* @tx_index: Transmit descriptor index in @txdes
* @rx_index: Receive descriptor index in @rxdes
* @phy_addr: The PHY interface address to use
* @phydev: The PHY device backing the MAC
* @bus: The mdio bus
* @phy_mode: The mode of the PHY interface (rgmii, rmii, ...)
* @max_speed: Maximum speed of Ethernet connection supported by MAC
* @clks: The bulk of clocks assigned to the device in the DT
* @rxdes0_edorr_mask: The bit number identifying the end of the RX ring buffer
* @txdes0_edotr_mask: The bit number identifying the end of the TX ring buffer
*/
struct ftgmac100_data {
ulong txdes_dma;
struct ftgmac100_txdes *txdes;
ulong rxdes_dma;
struct ftgmac100_rxdes *rxdes;
struct ftgmac100 *iobase;
struct ftgmac100_txdes txdes[PKTBUFSTX];
struct ftgmac100_rxdes rxdes[PKTBUFSRX];
int tx_index;
int rx_index;
int phy_addr;
u32 phy_addr;
struct phy_device *phydev;
struct mii_dev *bus;
u32 phy_mode;
u32 max_speed;
struct clk_bulk clks;
/* End of RX/TX ring buffer bits. Depend on model */
u32 rxdes0_edorr_mask;
u32 txdes0_edotr_mask;
};
/*
* struct mii_bus functions
*/
static int ftgmac100_mdiobus_read(struct eth_device *dev, int phy_addr,
int regnum)
static int ftgmac100_mdio_read(struct mii_dev *bus, int phy_addr, int dev_addr,
int reg_addr)
{
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
int phycr;
int i;
phycr = readl(&ftgmac100->phycr);
/* preserve MDC cycle threshold */
phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr)
| FTGMAC100_PHYCR_REGAD(regnum)
| FTGMAC100_PHYCR_MIIRD;
writel(phycr, &ftgmac100->phycr);
for (i = 0; i < 10; i++) {
phycr = readl(&ftgmac100->phycr);
if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) {
int data;
data = readl(&ftgmac100->phydata);
return FTGMAC100_PHYDATA_MIIRDATA(data);
}
mdelay(10);
}
debug("mdio read timed out\n");
return -1;
}
static int ftgmac100_mdiobus_write(struct eth_device *dev, int phy_addr,
int regnum, u16 value)
{
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
struct ftgmac100_data *priv = bus->priv;
struct ftgmac100 *ftgmac100 = priv->iobase;
int phycr;
int data;
int i;
int ret;
phycr = readl(&ftgmac100->phycr);
phycr = FTGMAC100_PHYCR_MDC_CYCTHR(MDC_CYCTHR) |
FTGMAC100_PHYCR_PHYAD(phy_addr) |
FTGMAC100_PHYCR_REGAD(reg_addr) |
FTGMAC100_PHYCR_MIIRD;
writel(phycr, &ftgmac100->phycr);
/* preserve MDC cycle threshold */
phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
ret = readl_poll_timeout(&ftgmac100->phycr, phycr,
!(phycr & FTGMAC100_PHYCR_MIIRD),
FTGMAC100_MDIO_TIMEOUT_USEC);
if (ret) {
pr_err("%s: mdio read failed (phy:%d reg:%x)\n",
priv->phydev->dev->name, phy_addr, reg_addr);
return ret;
}
phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr)
| FTGMAC100_PHYCR_REGAD(regnum)
| FTGMAC100_PHYCR_MIIWR;
data = readl(&ftgmac100->phydata);
return FTGMAC100_PHYDATA_MIIRDATA(data);
}
static int ftgmac100_mdio_write(struct mii_dev *bus, int phy_addr, int dev_addr,
int reg_addr, u16 value)
{
struct ftgmac100_data *priv = bus->priv;
struct ftgmac100 *ftgmac100 = priv->iobase;
int phycr;
int data;
int ret;
phycr = FTGMAC100_PHYCR_MDC_CYCTHR(MDC_CYCTHR) |
FTGMAC100_PHYCR_PHYAD(phy_addr) |
FTGMAC100_PHYCR_REGAD(reg_addr) |
FTGMAC100_PHYCR_MIIWR;
data = FTGMAC100_PHYDATA_MIIWDATA(value);
writel(data, &ftgmac100->phydata);
writel(phycr, &ftgmac100->phycr);
for (i = 0; i < 10; i++) {
phycr = readl(&ftgmac100->phycr);
if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0) {
debug("(phycr & FTGMAC100_PHYCR_MIIWR) == 0: " \
"phy_addr: %x\n", phy_addr);
return 0;
}
mdelay(1);
ret = readl_poll_timeout(&ftgmac100->phycr, phycr,
!(phycr & FTGMAC100_PHYCR_MIIWR),
FTGMAC100_MDIO_TIMEOUT_USEC);
if (ret) {
pr_err("%s: mdio write failed (phy:%d reg:%x)\n",
priv->phydev->dev->name, phy_addr, reg_addr);
}
debug("mdio write timed out\n");
return -1;
return ret;
}
int ftgmac100_phy_read(struct eth_device *dev, int addr, int reg, u16 *value)
static int ftgmac100_mdio_init(struct udevice *dev)
{
*value = ftgmac100_mdiobus_read(dev , addr, reg);
struct ftgmac100_data *priv = dev_get_priv(dev);
struct mii_dev *bus;
int ret;
if (*value == -1)
return -1;
bus = mdio_alloc();
if (!bus)
return -ENOMEM;
bus->read = ftgmac100_mdio_read;
bus->write = ftgmac100_mdio_write;
bus->priv = priv;
ret = mdio_register_seq(bus, dev->seq);
if (ret) {
free(bus);
return ret;
}
priv->bus = bus;
return 0;
}
int ftgmac100_phy_write(struct eth_device *dev, int addr, int reg, u16 value)
static int ftgmac100_phy_adjust_link(struct ftgmac100_data *priv)
{
if (ftgmac100_mdiobus_write(dev, addr, reg, value) == -1)
return -1;
struct ftgmac100 *ftgmac100 = priv->iobase;
struct phy_device *phydev = priv->phydev;
u32 maccr;
return 0;
}
static int ftgmac100_phy_reset(struct eth_device *dev)
{
struct ftgmac100_data *priv = dev->priv;
int i;
u16 status, adv;
adv = ADVERTISE_CSMA | ADVERTISE_ALL;
ftgmac100_phy_write(dev, priv->phy_addr, MII_ADVERTISE, adv);
printf("%s: Starting autonegotiation...\n", dev->name);
ftgmac100_phy_write(dev, priv->phy_addr,
MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART));
for (i = 0; i < 100000 / 100; i++) {
ftgmac100_phy_read(dev, priv->phy_addr, MII_BMSR, &status);
if (status & BMSR_ANEGCOMPLETE)
break;
mdelay(1);
if (!phydev->link) {
dev_err(phydev->dev, "No link\n");
return -EREMOTEIO;
}
if (status & BMSR_ANEGCOMPLETE) {
printf("%s: Autonegotiation complete\n", dev->name);
} else {
printf("%s: Autonegotiation timed out (status=0x%04x)\n",
dev->name, status);
return 0;
}
return 1;
}
static int ftgmac100_phy_init(struct eth_device *dev)
{
struct ftgmac100_data *priv = dev->priv;
int phy_addr;
u16 phy_id, status, adv, lpa, stat_ge;
int media, speed, duplex;
int i;
/* Check if the PHY is up to snuff... */
for (phy_addr = 0; phy_addr < CONFIG_PHY_MAX_ADDR; phy_addr++) {
ftgmac100_phy_read(dev, phy_addr, MII_PHYSID1, &phy_id);
/*
* When it is unable to found PHY,
* the interface usually return 0xffff or 0x0000
*/
if (phy_id != 0xffff && phy_id != 0x0) {
printf("%s: found PHY at 0x%02x\n",
dev->name, phy_addr);
priv->phy_addr = phy_addr;
break;
}
}
if (phy_id == 0xffff || phy_id == 0x0) {
printf("%s: no PHY present\n", dev->name);
return 0;
}
ftgmac100_phy_read(dev, priv->phy_addr, MII_BMSR, &status);
if (!(status & BMSR_LSTATUS)) {
/* Try to re-negotiate if we don't have link already. */
ftgmac100_phy_reset(dev);
for (i = 0; i < 100000 / 100; i++) {
ftgmac100_phy_read(dev, priv->phy_addr,
MII_BMSR, &status);
if (status & BMSR_LSTATUS)
break;
udelay(100);
}
}
if (!(status & BMSR_LSTATUS)) {
printf("%s: link down\n", dev->name);
return 0;
}
#ifdef CONFIG_FTGMAC100_EGIGA
/* 1000 Base-T Status Register */
ftgmac100_phy_read(dev, priv->phy_addr,
MII_STAT1000, &stat_ge);
speed = (stat_ge & (LPA_1000FULL | LPA_1000HALF)
? 1 : 0);
duplex = ((stat_ge & LPA_1000FULL)
? 1 : 0);
if (speed) { /* Speed is 1000 */
printf("%s: link up, 1000bps %s-duplex\n",
dev->name, duplex ? "full" : "half");
return 0;
}
#endif
ftgmac100_phy_read(dev, priv->phy_addr, MII_ADVERTISE, &adv);
ftgmac100_phy_read(dev, priv->phy_addr, MII_LPA, &lpa);
media = mii_nway_result(lpa & adv);
speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? 1 : 0);
duplex = (media & ADVERTISE_FULL) ? 1 : 0;
printf("%s: link up, %sMbps %s-duplex\n",
dev->name, speed ? "100" : "10", duplex ? "full" : "half");
return 1;
}
static int ftgmac100_update_link_speed(struct eth_device *dev)
{
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
struct ftgmac100_data *priv = dev->priv;
unsigned short stat_fe;
unsigned short stat_ge;
unsigned int maccr;
#ifdef CONFIG_FTGMAC100_EGIGA
/* 1000 Base-T Status Register */
ftgmac100_phy_read(dev, priv->phy_addr, MII_STAT1000, &stat_ge);
#endif
ftgmac100_phy_read(dev, priv->phy_addr, MII_BMSR, &stat_fe);
if (!(stat_fe & BMSR_LSTATUS)) /* link status up? */
return 0;
/* read MAC control register and clear related bits */
maccr = readl(&ftgmac100->maccr) &
~(FTGMAC100_MACCR_GIGA_MODE |
FTGMAC100_MACCR_FAST_MODE |
FTGMAC100_MACCR_FULLDUP);
#ifdef CONFIG_FTGMAC100_EGIGA
if (stat_ge & LPA_1000FULL) {
/* set gmac for 1000BaseTX and Full Duplex */
maccr |= FTGMAC100_MACCR_GIGA_MODE | FTGMAC100_MACCR_FULLDUP;
}
if (stat_ge & LPA_1000HALF) {
/* set gmac for 1000BaseTX and Half Duplex */
if (phy_interface_is_rgmii(phydev) && phydev->speed == 1000)
maccr |= FTGMAC100_MACCR_GIGA_MODE;
}
#endif
if (stat_fe & BMSR_100FULL) {
/* set MII for 100BaseTX and Full Duplex */
maccr |= FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_FULLDUP;
}
if (stat_fe & BMSR_10FULL) {
/* set MII for 10BaseT and Full Duplex */
maccr |= FTGMAC100_MACCR_FULLDUP;
}
if (stat_fe & BMSR_100HALF) {
/* set MII for 100BaseTX and Half Duplex */
if (phydev->speed == 100)
maccr |= FTGMAC100_MACCR_FAST_MODE;
}
if (stat_fe & BMSR_10HALF) {
/* set MII for 10BaseT and Half Duplex */
/* we have already clear these bits, do nothing */
;
}
if (phydev->duplex)
maccr |= FTGMAC100_MACCR_FULLDUP;
/* update MII config into maccr */
writel(maccr, &ftgmac100->maccr);
return 1;
return 0;
}
static int ftgmac100_phy_init(struct udevice *dev)
{
struct ftgmac100_data *priv = dev_get_priv(dev);
struct phy_device *phydev;
int ret;
phydev = phy_connect(priv->bus, priv->phy_addr, dev, priv->phy_mode);
if (!phydev)
return -ENODEV;
phydev->supported &= PHY_GBIT_FEATURES;
if (priv->max_speed) {
ret = phy_set_supported(phydev, priv->max_speed);
if (ret)
return ret;
}
phydev->advertising = phydev->supported;
priv->phydev = phydev;
phy_config(phydev);
return 0;
}
/*
* Reset MAC
*/
static void ftgmac100_reset(struct eth_device *dev)
static void ftgmac100_reset(struct ftgmac100_data *priv)
{
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
struct ftgmac100 *ftgmac100 = priv->iobase;
debug("%s()\n", __func__);
writel(FTGMAC100_MACCR_SW_RST, &ftgmac100->maccr);
setbits_le32(&ftgmac100->maccr, FTGMAC100_MACCR_SW_RST);
while (readl(&ftgmac100->maccr) & FTGMAC100_MACCR_SW_RST)
;
@ -330,10 +248,10 @@ static void ftgmac100_reset(struct eth_device *dev)
/*
* Set MAC address
*/
static void ftgmac100_set_mac(struct eth_device *dev,
const unsigned char *mac)
static int ftgmac100_set_mac(struct ftgmac100_data *priv,
const unsigned char *mac)
{
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
struct ftgmac100 *ftgmac100 = priv->iobase;
unsigned int maddr = mac[0] << 8 | mac[1];
unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
@ -341,61 +259,42 @@ static void ftgmac100_set_mac(struct eth_device *dev,
writel(maddr, &ftgmac100->mac_madr);
writel(laddr, &ftgmac100->mac_ladr);
}
static void ftgmac100_set_mac_from_env(struct eth_device *dev)
{
eth_env_get_enetaddr("ethaddr", dev->enetaddr);
ftgmac100_set_mac(dev, dev->enetaddr);
return 0;
}
/*
* disable transmitter, receiver
*/
static void ftgmac100_halt(struct eth_device *dev)
static void ftgmac100_stop(struct udevice *dev)
{
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100 *ftgmac100 = priv->iobase;
debug("%s()\n", __func__);
writel(0, &ftgmac100->maccr);
phy_shutdown(priv->phydev);
}
static int ftgmac100_init(struct eth_device *dev, bd_t *bd)
static int ftgmac100_start(struct udevice *dev)
{
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
struct ftgmac100_data *priv = dev->priv;
struct ftgmac100_txdes *txdes;
struct ftgmac100_rxdes *rxdes;
struct eth_pdata *plat = dev_get_platdata(dev);
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100 *ftgmac100 = priv->iobase;
struct phy_device *phydev = priv->phydev;
unsigned int maccr;
void *buf;
ulong start, end;
int ret;
int i;
debug("%s()\n", __func__);
if (!priv->txdes) {
txdes = dma_alloc_coherent(
sizeof(*txdes) * PKTBUFSTX, &priv->txdes_dma);
if (!txdes)
panic("ftgmac100: out of memory\n");
memset(txdes, 0, sizeof(*txdes) * PKTBUFSTX);
priv->txdes = txdes;
}
txdes = priv->txdes;
if (!priv->rxdes) {
rxdes = dma_alloc_coherent(
sizeof(*rxdes) * PKTBUFSRX, &priv->rxdes_dma);
if (!rxdes)
panic("ftgmac100: out of memory\n");
memset(rxdes, 0, sizeof(*rxdes) * PKTBUFSRX);
priv->rxdes = rxdes;
}
rxdes = priv->rxdes;
ftgmac100_reset(priv);
/* set the ethernet address */
ftgmac100_set_mac_from_env(dev);
ftgmac100_set_mac(priv, plat->enetaddr);
/* disable all interrupts */
writel(0, &ftgmac100->ier);
@ -404,42 +303,37 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)
priv->tx_index = 0;
priv->rx_index = 0;
txdes[PKTBUFSTX - 1].txdes0 = FTGMAC100_TXDES0_EDOTR;
rxdes[PKTBUFSRX - 1].rxdes0 = FTGMAC100_RXDES0_EDORR;
for (i = 0; i < PKTBUFSTX; i++) {
/* TXBUF_BADR */
if (!txdes[i].txdes2) {
buf = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
if (!buf)
panic("ftgmac100: out of memory\n");
txdes[i].txdes3 = virt_to_phys(buf);
txdes[i].txdes2 = (uint)buf;
}
txdes[i].txdes1 = 0;
priv->txdes[i].txdes3 = 0;
priv->txdes[i].txdes0 = 0;
}
priv->txdes[PKTBUFSTX - 1].txdes0 = priv->txdes0_edotr_mask;
start = (ulong)&priv->txdes[0];
end = start + roundup(sizeof(priv->txdes), ARCH_DMA_MINALIGN);
flush_dcache_range(start, end);
for (i = 0; i < PKTBUFSRX; i++) {
/* RXBUF_BADR */
if (!rxdes[i].rxdes2) {
buf = net_rx_packets[i];
rxdes[i].rxdes3 = virt_to_phys(buf);
rxdes[i].rxdes2 = (uint)buf;
}
rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
priv->rxdes[i].rxdes3 = (unsigned int)net_rx_packets[i];
priv->rxdes[i].rxdes0 = 0;
}
priv->rxdes[PKTBUFSRX - 1].rxdes0 = priv->rxdes0_edorr_mask;
start = (ulong)&priv->rxdes[0];
end = start + roundup(sizeof(priv->rxdes), ARCH_DMA_MINALIGN);
flush_dcache_range(start, end);
/* transmit ring */
writel(priv->txdes_dma, &ftgmac100->txr_badr);
writel((u32)priv->txdes, &ftgmac100->txr_badr);
/* receive ring */
writel(priv->rxdes_dma, &ftgmac100->rxr_badr);
writel((u32)priv->rxdes, &ftgmac100->rxr_badr);
/* poll receive descriptor automatically */
writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc);
/* config receive buffer size register */
writel(FTGMAC100_RBSR_SIZE(RBSR_DEFAULT_VALUE), &ftgmac100->rbsr);
writel(FTGMAC100_RBSR_SIZE(FTGMAC100_RBSR_DEFAULT), &ftgmac100->rbsr);
/* enable transmitter, receiver */
maccr = FTGMAC100_MACCR_TXMAC_EN |
@ -453,34 +347,67 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)
writel(maccr, &ftgmac100->maccr);
if (!ftgmac100_phy_init(dev)) {
if (!ftgmac100_update_link_speed(dev))
return -1;
ret = phy_startup(phydev);
if (ret) {
dev_err(phydev->dev, "Could not start PHY\n");
return ret;
}
ret = ftgmac100_phy_adjust_link(priv);
if (ret) {
dev_err(phydev->dev, "Could not adjust link\n");
return ret;
}
printf("%s: link up, %d Mbps %s-duplex mac:%pM\n", phydev->dev->name,
phydev->speed, phydev->duplex ? "full" : "half", plat->enetaddr);
return 0;
}
static int ftgmac100_free_pkt(struct udevice *dev, uchar *packet, int length)
{
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100_rxdes *curr_des = &priv->rxdes[priv->rx_index];
ulong des_start = (ulong)curr_des;
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
/* Release buffer to DMA and flush descriptor */
curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
flush_dcache_range(des_start, des_end);
/* Move to next descriptor */
priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX;
return 0;
}
/*
* Get a data block via Ethernet
*/
static int ftgmac100_recv(struct eth_device *dev)
static int ftgmac100_recv(struct udevice *dev, int flags, uchar **packetp)
{
struct ftgmac100_data *priv = dev->priv;
struct ftgmac100_rxdes *curr_des;
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100_rxdes *curr_des = &priv->rxdes[priv->rx_index];
unsigned short rxlen;
ulong des_start = (ulong)curr_des;
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
ulong data_start = curr_des->rxdes3;
ulong data_end;
curr_des = &priv->rxdes[priv->rx_index];
invalidate_dcache_range(des_start, des_end);
if (!(curr_des->rxdes0 & FTGMAC100_RXDES0_RXPKT_RDY))
return -1;
return -EAGAIN;
if (curr_des->rxdes0 & (FTGMAC100_RXDES0_RX_ERR |
FTGMAC100_RXDES0_CRC_ERR |
FTGMAC100_RXDES0_FTL |
FTGMAC100_RXDES0_RUNT |
FTGMAC100_RXDES0_RX_ODD_NB)) {
return -1;
return -EAGAIN;
}
rxlen = FTGMAC100_RXDES0_VDBC(curr_des->rxdes0);
@ -488,95 +415,194 @@ static int ftgmac100_recv(struct eth_device *dev)
debug("%s(): RX buffer %d, %x received\n",
__func__, priv->rx_index, rxlen);
/* invalidate d-cache */
dma_map_single((void *)curr_des->rxdes2, rxlen, DMA_FROM_DEVICE);
/* Invalidate received data */
data_end = data_start + roundup(rxlen, ARCH_DMA_MINALIGN);
invalidate_dcache_range(data_start, data_end);
*packetp = (uchar *)data_start;
/* pass the packet up to the protocol layers. */
net_process_received_packet((void *)curr_des->rxdes2, rxlen);
/* release buffer to DMA */
curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
priv->rx_index = (priv->rx_index + 1) % PKTBUFSRX;
return 0;
return rxlen;
}
static u32 ftgmac100_read_txdesc(const void *desc)
{
const struct ftgmac100_txdes *txdes = desc;
ulong des_start = (ulong)txdes;
ulong des_end = des_start + roundup(sizeof(*txdes), ARCH_DMA_MINALIGN);
invalidate_dcache_range(des_start, des_end);
return txdes->txdes0;
}
BUILD_WAIT_FOR_BIT(ftgmac100_txdone, u32, ftgmac100_read_txdesc)
/*
* Send a data block via Ethernet
*/
static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
static int ftgmac100_send(struct udevice *dev, void *packet, int length)
{
struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
struct ftgmac100_data *priv = dev->priv;
struct ftgmac100_data *priv = dev_get_priv(dev);
struct ftgmac100 *ftgmac100 = priv->iobase;
struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
ulong des_start = (ulong)curr_des;
ulong des_end = des_start +
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
ulong data_start;
ulong data_end;
int rc;
invalidate_dcache_range(des_start, des_end);
if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
debug("%s(): no TX descriptor available\n", __func__);
return -1;
dev_err(dev, "no TX descriptor available\n");
return -EPERM;
}
debug("%s(%x, %x)\n", __func__, (int)packet, length);
length = (length < ETH_ZLEN) ? ETH_ZLEN : length;
memcpy((void *)curr_des->txdes2, (void *)packet, length);
dma_map_single((void *)curr_des->txdes2, length, DMA_TO_DEVICE);
curr_des->txdes3 = (unsigned int)packet;
/* only one descriptor on TXBUF */
curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
/* Flush data to be sent */
data_start = curr_des->txdes3;
data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
flush_dcache_range(data_start, data_end);
/* Only one segment on TXBUF */
curr_des->txdes0 &= priv->txdes0_edotr_mask;
curr_des->txdes0 |= FTGMAC100_TXDES0_FTS |
FTGMAC100_TXDES0_LTS |
FTGMAC100_TXDES0_TXBUF_SIZE(length) |
FTGMAC100_TXDES0_TXDMA_OWN ;
/* start transmit */
/* Flush modified buffer descriptor */
flush_dcache_range(des_start, des_end);
/* Start transmit */
writel(1, &ftgmac100->txpd);
rc = wait_for_bit_ftgmac100_txdone(curr_des,
FTGMAC100_TXDES0_TXDMA_OWN, false,
FTGMAC100_TX_TIMEOUT_MS, true);
if (rc)
return rc;
debug("%s(): packet sent\n", __func__);
/* Move to next descriptor */
priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX;
return 0;
}
int ftgmac100_initialize(bd_t *bd)
static int ftgmac100_write_hwaddr(struct udevice *dev)
{
struct eth_device *dev;
struct ftgmac100_data *priv;
struct eth_pdata *pdata = dev_get_platdata(dev);
struct ftgmac100_data *priv = dev_get_priv(dev);
dev = malloc(sizeof *dev);
if (!dev) {
printf("%s(): failed to allocate dev\n", __func__);
return ftgmac100_set_mac(priv, pdata->enetaddr);
}
static int ftgmac100_ofdata_to_platdata(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct ftgmac100_data *priv = dev_get_priv(dev);
const char *phy_mode;
pdata->iobase = devfdt_get_addr(dev);
pdata->phy_interface = -1;
phy_mode = dev_read_string(dev, "phy-mode");
if (phy_mode)
pdata->phy_interface = phy_get_interface_by_name(phy_mode);
if (pdata->phy_interface == -1) {
dev_err(dev, "Invalid PHY interface '%s'\n", phy_mode);
return -EINVAL;
}
pdata->max_speed = dev_read_u32_default(dev, "max-speed", 0);
if (dev_get_driver_data(dev) == FTGMAC100_MODEL_ASPEED) {
priv->rxdes0_edorr_mask = BIT(30);
priv->txdes0_edotr_mask = BIT(30);
} else {
priv->rxdes0_edorr_mask = BIT(15);
priv->txdes0_edotr_mask = BIT(15);
}
return clk_get_bulk(dev, &priv->clks);
}
static int ftgmac100_probe(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct ftgmac100_data *priv = dev_get_priv(dev);
int ret;
priv->iobase = (struct ftgmac100 *)pdata->iobase;
priv->phy_mode = pdata->phy_interface;
priv->max_speed = pdata->max_speed;
priv->phy_addr = 0;
ret = clk_enable_bulk(&priv->clks);
if (ret)
goto out;
ret = ftgmac100_mdio_init(dev);
if (ret) {
dev_err(dev, "Failed to initialize mdiobus: %d\n", ret);
goto out;
}
/* Transmit and receive descriptors should align to 16 bytes */
priv = memalign(16, sizeof(struct ftgmac100_data));
if (!priv) {
printf("%s(): failed to allocate priv\n", __func__);
goto free_dev;
ret = ftgmac100_phy_init(dev);
if (ret) {
dev_err(dev, "Failed to initialize PHY: %d\n", ret);
goto out;
}
memset(dev, 0, sizeof(*dev));
memset(priv, 0, sizeof(*priv));
strcpy(dev->name, "FTGMAC100");
dev->iobase = CONFIG_FTGMAC100_BASE;
dev->init = ftgmac100_init;
dev->halt = ftgmac100_halt;
dev->send = ftgmac100_send;
dev->recv = ftgmac100_recv;
dev->priv = priv;
eth_register(dev);
ftgmac100_reset(dev);
return 1;
free_dev:
free(dev);
out:
if (ret)
clk_release_bulk(&priv->clks);
return ret;
}
static int ftgmac100_remove(struct udevice *dev)
{
struct ftgmac100_data *priv = dev_get_priv(dev);
free(priv->phydev);
mdio_unregister(priv->bus);
mdio_free(priv->bus);
clk_release_bulk(&priv->clks);
return 0;
}
static const struct eth_ops ftgmac100_ops = {
.start = ftgmac100_start,
.send = ftgmac100_send,
.recv = ftgmac100_recv,
.stop = ftgmac100_stop,
.free_pkt = ftgmac100_free_pkt,
.write_hwaddr = ftgmac100_write_hwaddr,
};
static const struct udevice_id ftgmac100_ids[] = {
{ .compatible = "faraday,ftgmac100", .data = FTGMAC100_MODEL_FARADAY },
{ .compatible = "aspeed,ast2500-mac", .data = FTGMAC100_MODEL_ASPEED },
{ }
};
U_BOOT_DRIVER(ftgmac100) = {
.name = "ftgmac100",
.id = UCLASS_ETH,
.of_match = ftgmac100_ids,
.ofdata_to_platdata = ftgmac100_ofdata_to_platdata,
.probe = ftgmac100_probe,
.remove = ftgmac100_remove,
.ops = &ftgmac100_ops,
.priv_auto_alloc_size = sizeof(struct ftgmac100_data),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
};

View file

@ -70,48 +70,48 @@ struct ftgmac100 {
/*
* Interrupt status register & interrupt enable register
*/
#define FTGMAC100_INT_RPKT_BUF (1 << 0)
#define FTGMAC100_INT_RPKT_FIFO (1 << 1)
#define FTGMAC100_INT_NO_RXBUF (1 << 2)
#define FTGMAC100_INT_RPKT_LOST (1 << 3)
#define FTGMAC100_INT_XPKT_ETH (1 << 4)
#define FTGMAC100_INT_XPKT_FIFO (1 << 5)
#define FTGMAC100_INT_NO_NPTXBUF (1 << 6)
#define FTGMAC100_INT_XPKT_LOST (1 << 7)
#define FTGMAC100_INT_AHB_ERR (1 << 8)
#define FTGMAC100_INT_PHYSTS_CHG (1 << 9)
#define FTGMAC100_INT_NO_HPTXBUF (1 << 10)
#define FTGMAC100_INT_RPKT_BUF BIT(0)
#define FTGMAC100_INT_RPKT_FIFO BIT(1)
#define FTGMAC100_INT_NO_RXBUF BIT(2)
#define FTGMAC100_INT_RPKT_LOST BIT(3)
#define FTGMAC100_INT_XPKT_ETH BIT(4)
#define FTGMAC100_INT_XPKT_FIFO BIT(5)
#define FTGMAC100_INT_NO_NPTXBUF BIT(6)
#define FTGMAC100_INT_XPKT_LOST BIT(7)
#define FTGMAC100_INT_AHB_ERR BIT(8)
#define FTGMAC100_INT_PHYSTS_CHG BIT(9)
#define FTGMAC100_INT_NO_HPTXBUF BIT(10)
/*
* Interrupt timer control register
*/
#define FTGMAC100_ITC_RXINT_CNT(x) (((x) & 0xf) << 0)
#define FTGMAC100_ITC_RXINT_THR(x) (((x) & 0x7) << 4)
#define FTGMAC100_ITC_RXINT_TIME_SEL (1 << 7)
#define FTGMAC100_ITC_RXINT_TIME_SEL BIT(7)
#define FTGMAC100_ITC_TXINT_CNT(x) (((x) & 0xf) << 8)
#define FTGMAC100_ITC_TXINT_THR(x) (((x) & 0x7) << 12)
#define FTGMAC100_ITC_TXINT_TIME_SEL (1 << 15)
#define FTGMAC100_ITC_TXINT_TIME_SEL BIT(15)
/*
* Automatic polling timer control register
*/
#define FTGMAC100_APTC_RXPOLL_CNT(x) (((x) & 0xf) << 0)
#define FTGMAC100_APTC_RXPOLL_TIME_SEL (1 << 4)
#define FTGMAC100_APTC_RXPOLL_TIME_SEL BIT(4)
#define FTGMAC100_APTC_TXPOLL_CNT(x) (((x) & 0xf) << 8)
#define FTGMAC100_APTC_TXPOLL_TIME_SEL (1 << 12)
#define FTGMAC100_APTC_TXPOLL_TIME_SEL BIT(12)
/*
* DMA burst length and arbitration control register
*/
#define FTGMAC100_DBLAC_RXFIFO_LTHR(x) (((x) & 0x7) << 0)
#define FTGMAC100_DBLAC_RXFIFO_HTHR(x) (((x) & 0x7) << 3)
#define FTGMAC100_DBLAC_RX_THR_EN (1 << 6)
#define FTGMAC100_DBLAC_RX_THR_EN BIT(6)
#define FTGMAC100_DBLAC_RXBURST_SIZE(x) (((x) & 0x3) << 8)
#define FTGMAC100_DBLAC_TXBURST_SIZE(x) (((x) & 0x3) << 10)
#define FTGMAC100_DBLAC_RXDES_SIZE(x) (((x) & 0xf) << 12)
#define FTGMAC100_DBLAC_TXDES_SIZE(x) (((x) & 0xf) << 16)
#define FTGMAC100_DBLAC_IFG_CNT(x) (((x) & 0x7) << 20)
#define FTGMAC100_DBLAC_IFG_INC (1 << 23)
#define FTGMAC100_DBLAC_IFG_INC BIT(23)
/*
* DMA FIFO status register
@ -122,12 +122,12 @@ struct ftgmac100 {
#define FTGMAC100_DMAFIFOS_TXDMA1_SM(dmafifos) (((dmafifos) >> 12) & 0xf)
#define FTGMAC100_DMAFIFOS_TXDMA2_SM(dmafifos) (((dmafifos) >> 16) & 0x3)
#define FTGMAC100_DMAFIFOS_TXDMA3_SM(dmafifos) (((dmafifos) >> 18) & 0xf)
#define FTGMAC100_DMAFIFOS_RXFIFO_EMPTY (1 << 26)
#define FTGMAC100_DMAFIFOS_TXFIFO_EMPTY (1 << 27)
#define FTGMAC100_DMAFIFOS_RXDMA_GRANT (1 << 28)
#define FTGMAC100_DMAFIFOS_TXDMA_GRANT (1 << 29)
#define FTGMAC100_DMAFIFOS_RXDMA_REQ (1 << 30)
#define FTGMAC100_DMAFIFOS_TXDMA_REQ (1 << 31)
#define FTGMAC100_DMAFIFOS_RXFIFO_EMPTY BIT(26)
#define FTGMAC100_DMAFIFOS_TXFIFO_EMPTY BIT(27)
#define FTGMAC100_DMAFIFOS_RXDMA_GRANT BIT(28)
#define FTGMAC100_DMAFIFOS_TXDMA_GRANT BIT(29)
#define FTGMAC100_DMAFIFOS_RXDMA_REQ BIT(30)
#define FTGMAC100_DMAFIFOS_TXDMA_REQ BIT(31)
/*
* Receive buffer size register
@ -137,26 +137,26 @@ struct ftgmac100 {
/*
* MAC control register
*/
#define FTGMAC100_MACCR_TXDMA_EN (1 << 0)
#define FTGMAC100_MACCR_RXDMA_EN (1 << 1)
#define FTGMAC100_MACCR_TXMAC_EN (1 << 2)
#define FTGMAC100_MACCR_RXMAC_EN (1 << 3)
#define FTGMAC100_MACCR_RM_VLAN (1 << 4)
#define FTGMAC100_MACCR_HPTXR_EN (1 << 5)
#define FTGMAC100_MACCR_LOOP_EN (1 << 6)
#define FTGMAC100_MACCR_ENRX_IN_HALFTX (1 << 7)
#define FTGMAC100_MACCR_FULLDUP (1 << 8)
#define FTGMAC100_MACCR_GIGA_MODE (1 << 9)
#define FTGMAC100_MACCR_CRC_APD (1 << 10)
#define FTGMAC100_MACCR_RX_RUNT (1 << 12)
#define FTGMAC100_MACCR_JUMBO_LF (1 << 13)
#define FTGMAC100_MACCR_RX_ALL (1 << 14)
#define FTGMAC100_MACCR_HT_MULTI_EN (1 << 15)
#define FTGMAC100_MACCR_RX_MULTIPKT (1 << 16)
#define FTGMAC100_MACCR_RX_BROADPKT (1 << 17)
#define FTGMAC100_MACCR_DISCARD_CRCERR (1 << 18)
#define FTGMAC100_MACCR_FAST_MODE (1 << 19)
#define FTGMAC100_MACCR_SW_RST (1 << 31)
#define FTGMAC100_MACCR_TXDMA_EN BIT(0)
#define FTGMAC100_MACCR_RXDMA_EN BIT(1)
#define FTGMAC100_MACCR_TXMAC_EN BIT(2)
#define FTGMAC100_MACCR_RXMAC_EN BIT(3)
#define FTGMAC100_MACCR_RM_VLAN BIT(4)
#define FTGMAC100_MACCR_HPTXR_EN BIT(5)
#define FTGMAC100_MACCR_LOOP_EN BIT(6)
#define FTGMAC100_MACCR_ENRX_IN_HALFTX BIT(7)
#define FTGMAC100_MACCR_FULLDUP BIT(8)
#define FTGMAC100_MACCR_GIGA_MODE BIT(9)
#define FTGMAC100_MACCR_CRC_APD BIT(10)
#define FTGMAC100_MACCR_RX_RUNT BIT(12)
#define FTGMAC100_MACCR_JUMBO_LF BIT(13)
#define FTGMAC100_MACCR_RX_ALL BIT(14)
#define FTGMAC100_MACCR_HT_MULTI_EN BIT(15)
#define FTGMAC100_MACCR_RX_MULTIPKT BIT(16)
#define FTGMAC100_MACCR_RX_BROADPKT BIT(17)
#define FTGMAC100_MACCR_DISCARD_CRCERR BIT(18)
#define FTGMAC100_MACCR_FAST_MODE BIT(19)
#define FTGMAC100_MACCR_SW_RST BIT(31)
/*
* PHY control register
@ -165,8 +165,8 @@ struct ftgmac100 {
#define FTGMAC100_PHYCR_MDC_CYCTHR(x) ((x) & 0x3f)
#define FTGMAC100_PHYCR_PHYAD(x) (((x) & 0x1f) << 16)
#define FTGMAC100_PHYCR_REGAD(x) (((x) & 0x1f) << 21)
#define FTGMAC100_PHYCR_MIIRD (1 << 26)
#define FTGMAC100_PHYCR_MIIWR (1 << 27)
#define FTGMAC100_PHYCR_MIIRD BIT(26)
#define FTGMAC100_PHYCR_MIIWR BIT(27)
/*
* PHY data register
@ -182,23 +182,23 @@ struct ftgmac100_txdes {
unsigned int txdes1;
unsigned int txdes2; /* not used by HW */
unsigned int txdes3; /* TXBUF_BADR */
} __attribute__ ((aligned(16)));
} __aligned(16);
#define FTGMAC100_TXDES0_TXBUF_SIZE(x) ((x) & 0x3fff)
#define FTGMAC100_TXDES0_EDOTR (1 << 15)
#define FTGMAC100_TXDES0_CRC_ERR (1 << 19)
#define FTGMAC100_TXDES0_LTS (1 << 28)
#define FTGMAC100_TXDES0_FTS (1 << 29)
#define FTGMAC100_TXDES0_TXDMA_OWN (1 << 31)
#define FTGMAC100_TXDES0_EDOTR BIT(15)
#define FTGMAC100_TXDES0_CRC_ERR BIT(19)
#define FTGMAC100_TXDES0_LTS BIT(28)
#define FTGMAC100_TXDES0_FTS BIT(29)
#define FTGMAC100_TXDES0_TXDMA_OWN BIT(31)
#define FTGMAC100_TXDES1_VLANTAG_CI(x) ((x) & 0xffff)
#define FTGMAC100_TXDES1_INS_VLANTAG (1 << 16)
#define FTGMAC100_TXDES1_TCP_CHKSUM (1 << 17)
#define FTGMAC100_TXDES1_UDP_CHKSUM (1 << 18)
#define FTGMAC100_TXDES1_IP_CHKSUM (1 << 19)
#define FTGMAC100_TXDES1_LLC (1 << 22)
#define FTGMAC100_TXDES1_TX2FIC (1 << 30)
#define FTGMAC100_TXDES1_TXIC (1 << 31)
#define FTGMAC100_TXDES1_INS_VLANTAG BIT(16)
#define FTGMAC100_TXDES1_TCP_CHKSUM BIT(17)
#define FTGMAC100_TXDES1_UDP_CHKSUM BIT(18)
#define FTGMAC100_TXDES1_IP_CHKSUM BIT(19)
#define FTGMAC100_TXDES1_LLC BIT(22)
#define FTGMAC100_TXDES1_TX2FIC BIT(30)
#define FTGMAC100_TXDES1_TXIC BIT(31)
/*
* Receive descriptor, aligned to 16 bytes
@ -208,23 +208,23 @@ struct ftgmac100_rxdes {
unsigned int rxdes1;
unsigned int rxdes2; /* not used by HW */
unsigned int rxdes3; /* RXBUF_BADR */
} __attribute__ ((aligned(16)));
} __aligned(16);
#define FTGMAC100_RXDES0_VDBC(x) ((x) & 0x3fff)
#define FTGMAC100_RXDES0_EDORR (1 << 15)
#define FTGMAC100_RXDES0_MULTICAST (1 << 16)
#define FTGMAC100_RXDES0_BROADCAST (1 << 17)
#define FTGMAC100_RXDES0_RX_ERR (1 << 18)
#define FTGMAC100_RXDES0_CRC_ERR (1 << 19)
#define FTGMAC100_RXDES0_FTL (1 << 20)
#define FTGMAC100_RXDES0_RUNT (1 << 21)
#define FTGMAC100_RXDES0_RX_ODD_NB (1 << 22)
#define FTGMAC100_RXDES0_FIFO_FULL (1 << 23)
#define FTGMAC100_RXDES0_PAUSE_OPCODE (1 << 24)
#define FTGMAC100_RXDES0_PAUSE_FRAME (1 << 25)
#define FTGMAC100_RXDES0_LRS (1 << 28)
#define FTGMAC100_RXDES0_FRS (1 << 29)
#define FTGMAC100_RXDES0_RXPKT_RDY (1 << 31)
#define FTGMAC100_RXDES0_EDORR BIT(15)
#define FTGMAC100_RXDES0_MULTICAST BIT(16)
#define FTGMAC100_RXDES0_BROADCAST BIT(17)
#define FTGMAC100_RXDES0_RX_ERR BIT(18)
#define FTGMAC100_RXDES0_CRC_ERR BIT(19)
#define FTGMAC100_RXDES0_FTL BIT(20)
#define FTGMAC100_RXDES0_RUNT BIT(21)
#define FTGMAC100_RXDES0_RX_ODD_NB BIT(22)
#define FTGMAC100_RXDES0_FIFO_FULL BIT(23)
#define FTGMAC100_RXDES0_PAUSE_OPCODE BIT(24)
#define FTGMAC100_RXDES0_PAUSE_FRAME BIT(25)
#define FTGMAC100_RXDES0_LRS BIT(28)
#define FTGMAC100_RXDES0_FRS BIT(29)
#define FTGMAC100_RXDES0_RXPKT_RDY BIT(31)
#define FTGMAC100_RXDES1_VLANTAG_CI 0xffff
#define FTGMAC100_RXDES1_PROT_MASK (0x3 << 20)
@ -232,11 +232,11 @@ struct ftgmac100_rxdes {
#define FTGMAC100_RXDES1_PROT_IP (0x1 << 20)
#define FTGMAC100_RXDES1_PROT_TCPIP (0x2 << 20)
#define FTGMAC100_RXDES1_PROT_UDPIP (0x3 << 20)
#define FTGMAC100_RXDES1_LLC (1 << 22)
#define FTGMAC100_RXDES1_DF (1 << 23)
#define FTGMAC100_RXDES1_VLANTAG_AVAIL (1 << 24)
#define FTGMAC100_RXDES1_TCP_CHKSUM_ERR (1 << 25)
#define FTGMAC100_RXDES1_UDP_CHKSUM_ERR (1 << 26)
#define FTGMAC100_RXDES1_IP_CHKSUM_ERR (1 << 27)
#define FTGMAC100_RXDES1_LLC BIT(22)
#define FTGMAC100_RXDES1_DF BIT(23)
#define FTGMAC100_RXDES1_VLANTAG_AVAIL BIT(24)
#define FTGMAC100_RXDES1_TCP_CHKSUM_ERR BIT(25)
#define FTGMAC100_RXDES1_UDP_CHKSUM_ERR BIT(26)
#define FTGMAC100_RXDES1_IP_CHKSUM_ERR BIT(27)
#endif /* __FTGMAC100_H */

644
drivers/net/mt7628-eth.c Normal file
View file

@ -0,0 +1,644 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* MediaTek ethernet IP driver for U-Boot
*
* Copyright (C) 2018 Stefan Roese <sr@denx.de>
*
* This code is mostly based on the code extracted from this MediaTek
* github repository:
*
* https://github.com/MediaTek-Labs/linkit-smart-uboot.git
*
* I was not able to find a specific license or other developers
* copyrights here, so I can't add them here.
*/
#include <common.h>
#include <dm.h>
#include <malloc.h>
#include <miiphy.h>
#include <net.h>
#include <regmap.h>
#include <syscon.h>
#include <wait_bit.h>
#include <asm/io.h>
#include <linux/bitfield.h>
#include <linux/err.h>
/* System controller register */
#define MT7628_RSTCTRL_REG 0x34
#define RSTCTRL_EPHY_RST BIT(24)
#define MT7628_AGPIO_CFG_REG 0x3c
#define MT7628_EPHY_GPIO_AIO_EN GENMASK(20, 17)
#define MT7628_EPHY_P0_DIS BIT(16)
#define MT7628_GPIO2_MODE_REG 0x64
/* Ethernet frame engine register */
#define PDMA_RELATED 0x0800
#define TX_BASE_PTR0 (PDMA_RELATED + 0x000)
#define TX_MAX_CNT0 (PDMA_RELATED + 0x004)
#define TX_CTX_IDX0 (PDMA_RELATED + 0x008)
#define TX_DTX_IDX0 (PDMA_RELATED + 0x00c)
#define RX_BASE_PTR0 (PDMA_RELATED + 0x100)
#define RX_MAX_CNT0 (PDMA_RELATED + 0x104)
#define RX_CALC_IDX0 (PDMA_RELATED + 0x108)
#define PDMA_GLO_CFG (PDMA_RELATED + 0x204)
#define PDMA_RST_IDX (PDMA_RELATED + 0x208)
#define DLY_INT_CFG (PDMA_RELATED + 0x20c)
#define SDM_RELATED 0x0c00
#define SDM_MAC_ADRL (SDM_RELATED + 0x0c) /* MAC address LSB */
#define SDM_MAC_ADRH (SDM_RELATED + 0x10) /* MAC Address MSB */
#define RST_DTX_IDX0 BIT(0)
#define RST_DRX_IDX0 BIT(16)
#define TX_DMA_EN BIT(0)
#define TX_DMA_BUSY BIT(1)
#define RX_DMA_EN BIT(2)
#define RX_DMA_BUSY BIT(3)
#define TX_WB_DDONE BIT(6)
/* Ethernet switch register */
#define MT7628_SWITCH_FCT0 0x0008
#define MT7628_SWITCH_PFC1 0x0014
#define MT7628_SWITCH_FPA 0x0084
#define MT7628_SWITCH_SOCPC 0x008c
#define MT7628_SWITCH_POC0 0x0090
#define MT7628_SWITCH_POC2 0x0098
#define MT7628_SWITCH_SGC 0x009c
#define MT7628_SWITCH_PCR0 0x00c0
#define PCR0_PHY_ADDR GENMASK(4, 0)
#define PCR0_PHY_REG GENMASK(12, 8)
#define PCR0_WT_PHY_CMD BIT(13)
#define PCR0_RD_PHY_CMD BIT(14)
#define PCR0_WT_DATA GENMASK(31, 16)
#define MT7628_SWITCH_PCR1 0x00c4
#define PCR1_WT_DONE BIT(0)
#define PCR1_RD_RDY BIT(1)
#define PCR1_RD_DATA GENMASK(31, 16)
#define MT7628_SWITCH_FPA1 0x00c8
#define MT7628_SWITCH_FCT2 0x00cc
#define MT7628_SWITCH_SGC2 0x00e4
#define MT7628_SWITCH_BMU_CTRL 0x0110
/* rxd2 */
#define RX_DMA_DONE BIT(31)
#define RX_DMA_LSO BIT(30)
#define RX_DMA_PLEN0 GENMASK(29, 16)
#define RX_DMA_TAG BIT(15)
struct fe_rx_dma {
unsigned int rxd1;
unsigned int rxd2;
unsigned int rxd3;
unsigned int rxd4;
} __packed __aligned(4);
#define TX_DMA_PLEN0 GENMASK(29, 16)
#define TX_DMA_LS1 BIT(14)
#define TX_DMA_LS0 BIT(30)
#define TX_DMA_DONE BIT(31)
#define TX_DMA_INS_VLAN_MT7621 BIT(16)
#define TX_DMA_INS_VLAN BIT(7)
#define TX_DMA_INS_PPPOE BIT(12)
#define TX_DMA_PN GENMASK(26, 24)
struct fe_tx_dma {
unsigned int txd1;
unsigned int txd2;
unsigned int txd3;
unsigned int txd4;
} __packed __aligned(4);
#define NUM_RX_DESC 256
#define NUM_TX_DESC 4
#define PADDING_LENGTH 60
#define MTK_QDMA_PAGE_SIZE 2048
#define CONFIG_MDIO_TIMEOUT 100
#define CONFIG_DMA_STOP_TIMEOUT 100
#define CONFIG_TX_DMA_TIMEOUT 100
#define LINK_DELAY_TIME 500 /* 500 ms */
#define LINK_TIMEOUT 10000 /* 10 seconds */
struct mt7628_eth_dev {
void __iomem *base; /* frame engine base address */
void __iomem *eth_sw_base; /* switch base address */
struct regmap *sysctrl_regmap; /* system-controller reg-map */
struct mii_dev *bus;
struct fe_tx_dma *tx_ring;
struct fe_rx_dma *rx_ring;
u8 *rx_buf[NUM_RX_DESC];
/* Point to the next RXD DMA wants to use in RXD Ring0 */
int rx_dma_idx;
/* Point to the next TXD in TXD Ring0 CPU wants to use */
int tx_dma_idx;
};
static int mdio_wait_read(struct mt7628_eth_dev *priv, u32 mask, bool mask_set)
{
void __iomem *base = priv->eth_sw_base;
int ret;
ret = wait_for_bit_le32(base + MT7628_SWITCH_PCR1, mask, mask_set,
CONFIG_MDIO_TIMEOUT, false);
if (ret) {
printf("MDIO operation timeout!\n");
return -ETIMEDOUT;
}
return 0;
}
static int mii_mgr_read(struct mt7628_eth_dev *priv,
u32 phy_addr, u32 phy_register, u32 *read_data)
{
void __iomem *base = priv->eth_sw_base;
u32 status = 0;
u32 ret;
*read_data = 0xffff;
/* Make sure previous read operation is complete */
ret = mdio_wait_read(priv, PCR1_RD_RDY, false);
if (ret)
return ret;
writel(PCR0_RD_PHY_CMD |
FIELD_PREP(PCR0_PHY_REG, phy_register) |
FIELD_PREP(PCR0_PHY_ADDR, phy_addr),
base + MT7628_SWITCH_PCR0);
/* Make sure previous read operation is complete */
ret = mdio_wait_read(priv, PCR1_RD_RDY, true);
if (ret)
return ret;
status = readl(base + MT7628_SWITCH_PCR1);
*read_data = FIELD_GET(PCR1_RD_DATA, status);
return 0;
}
static int mii_mgr_write(struct mt7628_eth_dev *priv,
u32 phy_addr, u32 phy_register, u32 write_data)
{
void __iomem *base = priv->eth_sw_base;
u32 data;
int ret;
/* Make sure previous write operation is complete */
ret = mdio_wait_read(priv, PCR1_WT_DONE, false);
if (ret)
return ret;
data = FIELD_PREP(PCR0_WT_DATA, write_data) |
FIELD_PREP(PCR0_PHY_REG, phy_register) |
FIELD_PREP(PCR0_PHY_ADDR, phy_addr) |
PCR0_WT_PHY_CMD;
writel(data, base + MT7628_SWITCH_PCR0);
return mdio_wait_read(priv, PCR1_WT_DONE, true);
}
static int mt7628_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
{
u32 val;
int ret;
ret = mii_mgr_read(bus->priv, addr, reg, &val);
if (ret)
return ret;
return val;
}
static int mt7628_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
u16 value)
{
return mii_mgr_write(bus->priv, addr, reg, value);
}
static void mt7628_ephy_init(struct mt7628_eth_dev *priv)
{
int i;
mii_mgr_write(priv, 0, 31, 0x2000); /* change G2 page */
mii_mgr_write(priv, 0, 26, 0x0000);
for (i = 0; i < 5; i++) {
mii_mgr_write(priv, i, 31, 0x8000); /* change L0 page */
mii_mgr_write(priv, i, 0, 0x3100);
/* EEE disable */
mii_mgr_write(priv, i, 30, 0xa000);
mii_mgr_write(priv, i, 31, 0xa000); /* change L2 page */
mii_mgr_write(priv, i, 16, 0x0606);
mii_mgr_write(priv, i, 23, 0x0f0e);
mii_mgr_write(priv, i, 24, 0x1610);
mii_mgr_write(priv, i, 30, 0x1f15);
mii_mgr_write(priv, i, 28, 0x6111);
}
/* 100Base AOI setting */
mii_mgr_write(priv, 0, 31, 0x5000); /* change G5 page */
mii_mgr_write(priv, 0, 19, 0x004a);
mii_mgr_write(priv, 0, 20, 0x015a);
mii_mgr_write(priv, 0, 21, 0x00ee);
mii_mgr_write(priv, 0, 22, 0x0033);
mii_mgr_write(priv, 0, 23, 0x020a);
mii_mgr_write(priv, 0, 24, 0x0000);
mii_mgr_write(priv, 0, 25, 0x024a);
mii_mgr_write(priv, 0, 26, 0x035a);
mii_mgr_write(priv, 0, 27, 0x02ee);
mii_mgr_write(priv, 0, 28, 0x0233);
mii_mgr_write(priv, 0, 29, 0x000a);
mii_mgr_write(priv, 0, 30, 0x0000);
/* Fix EPHY idle state abnormal behavior */
mii_mgr_write(priv, 0, 31, 0x4000); /* change G4 page */
mii_mgr_write(priv, 0, 29, 0x000d);
mii_mgr_write(priv, 0, 30, 0x0500);
}
static void rt305x_esw_init(struct mt7628_eth_dev *priv)
{
void __iomem *base = priv->eth_sw_base;
/*
* FC_RLS_TH=200, FC_SET_TH=160
* DROP_RLS=120, DROP_SET_TH=80
*/
writel(0xc8a07850, base + MT7628_SWITCH_FCT0);
writel(0x00000000, base + MT7628_SWITCH_SGC2);
writel(0x00405555, base + MT7628_SWITCH_PFC1);
writel(0x00007f7f, base + MT7628_SWITCH_POC0);
writel(0x00007f7f, base + MT7628_SWITCH_POC2); /* disable VLAN */
writel(0x0002500c, base + MT7628_SWITCH_FCT2);
/* hashing algorithm=XOR48, aging interval=300sec */
writel(0x0008a301, base + MT7628_SWITCH_SGC);
writel(0x02404040, base + MT7628_SWITCH_SOCPC);
/* Ext PHY Addr=0x1f */
writel(0x3f502b28, base + MT7628_SWITCH_FPA1);
writel(0x00000000, base + MT7628_SWITCH_FPA);
/* 1us cycle number=125 (FE's clock=125Mhz) */
writel(0x7d000000, base + MT7628_SWITCH_BMU_CTRL);
/* Configure analog GPIO setup */
regmap_update_bits(priv->sysctrl_regmap, MT7628_AGPIO_CFG_REG,
MT7628_EPHY_P0_DIS, MT7628_EPHY_GPIO_AIO_EN);
/* Reset PHY */
regmap_update_bits(priv->sysctrl_regmap, MT7628_RSTCTRL_REG,
0, RSTCTRL_EPHY_RST);
regmap_update_bits(priv->sysctrl_regmap, MT7628_RSTCTRL_REG,
RSTCTRL_EPHY_RST, 0);
mdelay(10);
/* Set P0 EPHY LED mode */
regmap_update_bits(priv->sysctrl_regmap, MT7628_GPIO2_MODE_REG,
0x0ffc0ffc, 0x05540554);
mdelay(10);
mt7628_ephy_init(priv);
}
static void eth_dma_start(struct mt7628_eth_dev *priv)
{
void __iomem *base = priv->base;
setbits_le32(base + PDMA_GLO_CFG, TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN);
}
static void eth_dma_stop(struct mt7628_eth_dev *priv)
{
void __iomem *base = priv->base;
int ret;
clrbits_le32(base + PDMA_GLO_CFG, TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN);
/* Wait for DMA to stop */
ret = wait_for_bit_le32(base + PDMA_GLO_CFG,
RX_DMA_BUSY | TX_DMA_BUSY, false,
CONFIG_DMA_STOP_TIMEOUT, false);
if (ret)
printf("DMA stop timeout error!\n");
}
static int mt7628_eth_write_hwaddr(struct udevice *dev)
{
struct mt7628_eth_dev *priv = dev_get_priv(dev);
void __iomem *base = priv->base;
u8 *addr = ((struct eth_pdata *)dev_get_platdata(dev))->enetaddr;
u32 val;
/* Set MAC address. */
val = addr[0];
val = (val << 8) | addr[1];
writel(val, base + SDM_MAC_ADRH);
val = addr[2];
val = (val << 8) | addr[3];
val = (val << 8) | addr[4];
val = (val << 8) | addr[5];
writel(val, base + SDM_MAC_ADRL);
return 0;
}
static int mt7628_eth_send(struct udevice *dev, void *packet, int length)
{
struct mt7628_eth_dev *priv = dev_get_priv(dev);
void __iomem *base = priv->base;
int ret;
int idx;
int i;
idx = priv->tx_dma_idx;
/* Pad message to a minimum length */
if (length < PADDING_LENGTH) {
char *p = (char *)packet;
for (i = 0; i < PADDING_LENGTH - length; i++)
p[length + i] = 0;
length = PADDING_LENGTH;
}
/* Check if buffer is ready for next TX DMA */
ret = wait_for_bit_le32(&priv->tx_ring[idx].txd2, TX_DMA_DONE, true,
CONFIG_TX_DMA_TIMEOUT, false);
if (ret) {
printf("TX: DMA still busy on buffer %d\n", idx);
return ret;
}
flush_dcache_range((u32)packet, (u32)packet + length);
priv->tx_ring[idx].txd1 = CPHYSADDR(packet);
priv->tx_ring[idx].txd2 &= ~TX_DMA_PLEN0;
priv->tx_ring[idx].txd2 |= FIELD_PREP(TX_DMA_PLEN0, length);
priv->tx_ring[idx].txd2 &= ~TX_DMA_DONE;
idx = (idx + 1) % NUM_TX_DESC;
/* Make sure the writes executed at this place */
wmb();
writel(idx, base + TX_CTX_IDX0);
priv->tx_dma_idx = idx;
return 0;
}
static int mt7628_eth_recv(struct udevice *dev, int flags, uchar **packetp)
{
struct mt7628_eth_dev *priv = dev_get_priv(dev);
u32 rxd_info;
int length;
int idx;
idx = priv->rx_dma_idx;
rxd_info = priv->rx_ring[idx].rxd2;
if ((rxd_info & RX_DMA_DONE) == 0)
return -EAGAIN;
length = FIELD_GET(RX_DMA_PLEN0, priv->rx_ring[idx].rxd2);
if (length == 0 || length > MTK_QDMA_PAGE_SIZE) {
printf("%s: invalid length (%d bytes)\n", __func__, length);
return -EIO;
}
*packetp = priv->rx_buf[idx];
invalidate_dcache_range((u32)*packetp, (u32)*packetp + length);
priv->rx_ring[idx].rxd4 = 0;
priv->rx_ring[idx].rxd2 = RX_DMA_LSO;
/* Make sure the writes executed at this place */
wmb();
return length;
}
static int mt7628_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
{
struct mt7628_eth_dev *priv = dev_get_priv(dev);
void __iomem *base = priv->base;
int idx;
idx = priv->rx_dma_idx;
/* Move point to next RXD which wants to alloc */
writel(idx, base + RX_CALC_IDX0);
/* Update to Next packet point that was received */
idx = (idx + 1) % NUM_RX_DESC;
priv->rx_dma_idx = idx;
return 0;
}
static int phy_link_up(struct mt7628_eth_dev *priv)
{
u32 val;
mii_mgr_read(priv, 0x00, MII_BMSR, &val);
return !!(val & BMSR_LSTATUS);
}
static int mt7628_eth_start(struct udevice *dev)
{
struct mt7628_eth_dev *priv = dev_get_priv(dev);
void __iomem *base = priv->base;
uchar packet[MTK_QDMA_PAGE_SIZE];
uchar *packetp;
int i;
for (i = 0; i < NUM_RX_DESC; i++) {
memset((void *)&priv->rx_ring[i], 0, sizeof(priv->rx_ring[0]));
priv->rx_ring[i].rxd2 |= RX_DMA_LSO;
priv->rx_ring[i].rxd1 = CPHYSADDR(priv->rx_buf[i]);
}
for (i = 0; i < NUM_TX_DESC; i++) {
memset((void *)&priv->tx_ring[i], 0, sizeof(priv->tx_ring[0]));
priv->tx_ring[i].txd2 = TX_DMA_LS0 | TX_DMA_DONE;
priv->tx_ring[i].txd4 = FIELD_PREP(TX_DMA_PN, 1);
}
priv->rx_dma_idx = 0;
priv->tx_dma_idx = 0;
/* Make sure the writes executed at this place */
wmb();
/* disable delay interrupt */
writel(0, base + DLY_INT_CFG);
clrbits_le32(base + PDMA_GLO_CFG, 0xffff0000);
/* Tell the adapter where the TX/RX rings are located. */
writel(CPHYSADDR(&priv->rx_ring[0]), base + RX_BASE_PTR0);
writel(CPHYSADDR((u32)&priv->tx_ring[0]), base + TX_BASE_PTR0);
writel(NUM_RX_DESC, base + RX_MAX_CNT0);
writel(NUM_TX_DESC, base + TX_MAX_CNT0);
writel(priv->tx_dma_idx, base + TX_CTX_IDX0);
writel(RST_DTX_IDX0, base + PDMA_RST_IDX);
writel(NUM_RX_DESC - 1, base + RX_CALC_IDX0);
writel(RST_DRX_IDX0, base + PDMA_RST_IDX);
/* Make sure the writes executed at this place */
wmb();
eth_dma_start(priv);
/* Check if link is not up yet */
if (!phy_link_up(priv)) {
/* Wait for link to come up */
printf("Waiting for link to come up .");
for (i = 0; i < (LINK_TIMEOUT / LINK_DELAY_TIME); i++) {
mdelay(LINK_DELAY_TIME);
if (phy_link_up(priv)) {
mdelay(100); /* Ensure all is ready */
break;
}
printf(".");
}
if (phy_link_up(priv))
printf(" done\n");
else
printf(" timeout! Trying anyways\n");
}
/*
* The integrated switch seems to queue some received ethernet
* packets in some FIFO. Lets read the already queued packets
* out by using the receive routine, so that these old messages
* are dropped before the new xfer starts.
*/
packetp = &packet[0];
while (mt7628_eth_recv(dev, 0, &packetp) != -EAGAIN)
mt7628_eth_free_pkt(dev, packetp, 0);
return 0;
}
static void mt7628_eth_stop(struct udevice *dev)
{
struct mt7628_eth_dev *priv = dev_get_priv(dev);
eth_dma_stop(priv);
}
static int mt7628_eth_probe(struct udevice *dev)
{
struct mt7628_eth_dev *priv = dev_get_priv(dev);
struct udevice *syscon;
struct mii_dev *bus;
int ret;
int i;
/* Save frame-engine base address for later use */
priv->base = dev_remap_addr_index(dev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
/* Save switch base address for later use */
priv->eth_sw_base = dev_remap_addr_index(dev, 1);
if (IS_ERR(priv->eth_sw_base))
return PTR_ERR(priv->eth_sw_base);
/* Get system controller regmap */
ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
"syscon", &syscon);
if (ret) {
pr_err("unable to find syscon device\n");
return ret;
}
priv->sysctrl_regmap = syscon_get_regmap(syscon);
if (!priv->sysctrl_regmap) {
pr_err("unable to find regmap\n");
return -ENODEV;
}
/* Put rx and tx rings into KSEG1 area (uncached) */
priv->tx_ring = (struct fe_tx_dma *)
KSEG1ADDR(memalign(ARCH_DMA_MINALIGN,
sizeof(*priv->tx_ring) * NUM_TX_DESC));
priv->rx_ring = (struct fe_rx_dma *)
KSEG1ADDR(memalign(ARCH_DMA_MINALIGN,
sizeof(*priv->rx_ring) * NUM_RX_DESC));
for (i = 0; i < NUM_RX_DESC; i++)
priv->rx_buf[i] = memalign(PKTALIGN, MTK_QDMA_PAGE_SIZE);
bus = mdio_alloc();
if (!bus) {
printf("Failed to allocate MDIO bus\n");
return -ENOMEM;
}
bus->read = mt7628_mdio_read;
bus->write = mt7628_mdio_write;
snprintf(bus->name, sizeof(bus->name), dev->name);
bus->priv = (void *)priv;
ret = mdio_register(bus);
if (ret)
return ret;
/* Switch configuration */
rt305x_esw_init(priv);
return 0;
}
static const struct eth_ops mt7628_eth_ops = {
.start = mt7628_eth_start,
.send = mt7628_eth_send,
.recv = mt7628_eth_recv,
.free_pkt = mt7628_eth_free_pkt,
.stop = mt7628_eth_stop,
.write_hwaddr = mt7628_eth_write_hwaddr,
};
static const struct udevice_id mt7628_eth_ids[] = {
{ .compatible = "mediatek,mt7628-eth" },
{ }
};
U_BOOT_DRIVER(mt7628_eth) = {
.name = "mt7628_eth",
.id = UCLASS_ETH,
.of_match = mt7628_eth_ids,
.probe = mt7628_eth_probe,
.ops = &mt7628_eth_ops,
.priv_auto_alloc_size = sizeof(struct mt7628_eth_dev),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
};

File diff suppressed because it is too large Load diff

20
drivers/net/ti/Kconfig Normal file
View file

@ -0,0 +1,20 @@
# 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
config DRIVER_TI_KEYSTONE_NET
bool "TI Keystone 2 Ethernet"
help
This driver supports the TI Keystone 2 Ethernet subsystem

7
drivers/net/ti/Makefile Normal file
View file

@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o cpsw-common.o cpsw_mdio.o
obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o cpsw_mdio.o

View file

@ -1,16 +1,8 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* CPSW Ethernet Switch Driver
*
* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* Copyright (C) 2010-2018 Texas Instruments Incorporated - http://www.ti.com/
*/
#include <common.h>
@ -29,11 +21,11 @@
#include <dm.h>
#include <fdt_support.h>
#include "cpsw_mdio.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)
@ -84,37 +76,8 @@ DECLARE_GLOBAL_DATA_PTR;
* 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;
@ -492,100 +455,6 @@ static inline void cpsw_ale_port_state(struct cpsw_priv *priv, int port,
__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)
{
@ -1011,7 +880,7 @@ static int cpsw_phy_init(struct cpsw_priv *priv, struct cpsw_slave *slave)
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);
u16 alive = cpsw_mdio_get_alive(priv->bus);
int active = data->active_slave;
int new_addr = ffs(alive) - 1;
@ -1052,11 +921,12 @@ int _cpsw_register(struct cpsw_priv *priv)
idx = idx + 1;
}
cpsw_mdio_init(priv->dev->name, data->mdio_base, data->mdio_div);
priv->bus = cpsw_mdio_init(priv->dev->name, data->mdio_base, 0, 0);
if (!priv->bus)
return -EFAULT;
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);

203
drivers/net/ti/cpsw_mdio.c Normal file
View file

@ -0,0 +1,203 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* CPSW MDIO generic driver for TI AMxx/K2x/EMAC devices.
*
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
*/
#include <common.h>
#include <asm/io.h>
#include <miiphy.h>
#include <wait_bit.h>
struct cpsw_mdio_regs {
u32 version;
u32 control;
#define CONTROL_IDLE BIT(31)
#define CONTROL_ENABLE BIT(30)
#define CONTROL_FAULT BIT(19)
#define CONTROL_FAULT_ENABLE BIT(18)
#define CONTROL_DIV_MASK GENMASK(15, 0)
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_PHY_REG_SHIFT (21)
#define USERACCESS_PHY_ADDR_SHIFT (16)
#define USERACCESS_DATA GENMASK(15, 0)
} user[0];
};
#define CPSW_MDIO_DIV_DEF 0xff
#define PHY_REG_MASK 0x1f
#define PHY_ID_MASK 0x1f
/*
* 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 CPSW_MDIO_TIMEOUT 100 /* msecs */
struct cpsw_mdio {
struct cpsw_mdio_regs *regs;
struct mii_dev *bus;
int div;
};
/* wait until hardware is ready for another user access */
static int cpsw_mdio_wait_for_user_access(struct cpsw_mdio *mdio)
{
return wait_for_bit_le32(&mdio->regs->user[0].access,
USERACCESS_GO, false,
CPSW_MDIO_TIMEOUT, false);
}
static int cpsw_mdio_read(struct mii_dev *bus, int phy_id,
int dev_addr, int phy_reg)
{
struct cpsw_mdio *mdio = bus->priv;
int data, ret;
u32 reg;
if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
return -EINVAL;
ret = cpsw_mdio_wait_for_user_access(mdio);
if (ret)
return ret;
reg = (USERACCESS_GO | USERACCESS_READ |
(phy_reg << USERACCESS_PHY_REG_SHIFT) |
(phy_id << USERACCESS_PHY_ADDR_SHIFT));
writel(reg, &mdio->regs->user[0].access);
ret = cpsw_mdio_wait_for_user_access(mdio);
if (ret)
return ret;
reg = readl(&mdio->regs->user[0].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)
{
struct cpsw_mdio *mdio = bus->priv;
u32 reg;
int ret;
if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
return -EINVAL;
ret = cpsw_mdio_wait_for_user_access(mdio);
if (ret)
return ret;
reg = (USERACCESS_GO | USERACCESS_WRITE |
(phy_reg << USERACCESS_PHY_REG_SHIFT) |
(phy_id << USERACCESS_PHY_ADDR_SHIFT) |
(data & USERACCESS_DATA));
writel(reg, &mdio->regs->user[0].access);
return cpsw_mdio_wait_for_user_access(mdio);
}
u32 cpsw_mdio_get_alive(struct mii_dev *bus)
{
struct cpsw_mdio *mdio = bus->priv;
u32 val;
val = readl(&mdio->regs->control);
return val & GENMASK(15, 0);
}
struct mii_dev *cpsw_mdio_init(const char *name, u32 mdio_base,
u32 bus_freq, int fck_freq)
{
struct cpsw_mdio *cpsw_mdio;
int ret;
cpsw_mdio = calloc(1, sizeof(*cpsw_mdio));
if (!cpsw_mdio) {
debug("failed to alloc cpsw_mdio\n");
return NULL;
}
cpsw_mdio->bus = mdio_alloc();
if (!cpsw_mdio->bus) {
debug("failed to alloc mii bus\n");
free(cpsw_mdio);
return NULL;
}
cpsw_mdio->regs = (struct cpsw_mdio_regs *)mdio_base;
if (!bus_freq || !fck_freq)
cpsw_mdio->div = CPSW_MDIO_DIV_DEF;
else
cpsw_mdio->div = (fck_freq / bus_freq) - 1;
cpsw_mdio->div &= CONTROL_DIV_MASK;
/* set enable and clock divider */
writel(cpsw_mdio->div | CONTROL_ENABLE | CONTROL_FAULT |
CONTROL_FAULT_ENABLE, &cpsw_mdio->regs->control);
wait_for_bit_le32(&cpsw_mdio->regs->control,
CONTROL_IDLE, false, CPSW_MDIO_TIMEOUT, true);
/*
* 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.
*/
mdelay(1);
cpsw_mdio->bus->read = cpsw_mdio_read;
cpsw_mdio->bus->write = cpsw_mdio_write;
cpsw_mdio->bus->priv = cpsw_mdio;
snprintf(cpsw_mdio->bus->name, sizeof(cpsw_mdio->bus->name), name);
ret = mdio_register(cpsw_mdio->bus);
if (ret < 0) {
debug("failed to register mii bus\n");
goto free_bus;
}
return cpsw_mdio->bus;
free_bus:
mdio_free(cpsw_mdio->bus);
free(cpsw_mdio);
return NULL;
}
void cpsw_mdio_free(struct mii_dev *bus)
{
struct cpsw_mdio *mdio = bus->priv;
u32 reg;
/* disable mdio */
reg = readl(&mdio->regs->control);
reg &= ~CONTROL_ENABLE;
writel(reg, &mdio->regs->control);
mdio_unregister(bus);
mdio_free(bus);
free(mdio);
}

View file

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* CPSW MDIO generic driver API for TI AMxx/K2x/EMAC devices.
*
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
*/
#ifndef CPSW_MDIO_H_
#define CPSW_MDIO_H_
struct cpsw_mdio;
struct mii_dev *cpsw_mdio_init(const char *name, u32 mdio_base,
u32 bus_freq, int fck_freq);
void cpsw_mdio_free(struct mii_dev *bus);
u32 cpsw_mdio_get_alive(struct mii_dev *bus);
#endif /* CPSW_MDIO_H_ */

View file

@ -22,13 +22,9 @@
#include <asm/ti-common/keystone_serdes.h>
#include <asm/arch/psc_defs.h>
DECLARE_GLOBAL_DATA_PTR;
#include "cpsw_mdio.h"
#ifndef CONFIG_DM_ETH
unsigned int emac_open;
static struct mii_dev *mdio_bus;
static unsigned int sys_has_mdio = 1;
#endif
DECLARE_GLOBAL_DATA_PTR;
#ifdef KEYSTONE2_EMAC_GIG_ENABLE
#define emac_gigabit_enable(x) keystone2_eth_gigabit_enable(x)
@ -43,17 +39,6 @@ static unsigned int sys_has_mdio = 1;
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,
@ -83,7 +68,7 @@ enum link_type {
#define DEVICE_EMACSW_BASE(base, x) ((base) + EMAC_EMACSW_PORT_BASE_OFS + \
(x) * 0x30)
#elif defined CONFIG_KSNET_NETCP_V1_5
#elif defined(CONFIG_KSNET_NETCP_V1_5)
#define EMAC_EMACSW_PORT_BASE_OFS 0x222000
@ -113,126 +98,26 @@ struct ks2_eth_priv {
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
*/
if (priv->has_mdio) {
if (priv->phydev->speed != 1000)
return;
}
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)
@ -497,246 +382,6 @@ static void keystone2_net_serdes_setup(void)
}
#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);
@ -768,8 +413,6 @@ static int ks2_eth_start(struct udevice *dev)
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");
@ -889,9 +532,9 @@ 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;
priv->emac_open = false;
/* These clock enables has to be moved to common location */
if (cpu_is_k2g())
@ -910,45 +553,36 @@ static int ks2_eth_probe(struct udevice *dev)
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) {
#ifndef CONFIG_SOC_K2G
keystone2_net_serdes_setup();
#endif
/*
* Register MDIO bus for slave 0 only, other slave have
* to re-use the same
*/
mdio_bus = mdio_alloc();
mdio_bus = cpsw_mdio_init("ethernet-mdio",
(u32)priv->mdio_base,
EMAC_MDIO_CLOCK_FREQ,
EMAC_MDIO_BUS_FREQ);
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;
priv->mdio_base = parent_priv->mdio_base;
}
#ifndef CONFIG_SOC_K2G
keystone2_net_serdes_setup();
#endif
priv->netcp_pktdma = &netcp_pktdma;
if (priv->has_mdio) {
@ -964,9 +598,7 @@ 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);
cpsw_mdio_free(priv->mdio_bus);
return 0;
}
@ -1167,4 +799,3 @@ U_BOOT_DRIVER(eth_ks2) = {
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
};
#endif

View file

@ -128,7 +128,6 @@
#define CONFIG_KSNAV_NETCP_PDMA_TX_SND_QUEUE KS2_NETCP_PDMA_TX_SND_QUEUE
/* Keystone net */
#define CONFIG_DRIVER_TI_KEYSTONE_NET
#define CONFIG_KSNET_MAC_ID_BASE KS2_MAC_ID_BASE_ADDR
#define CONFIG_KSNET_NETCP_BASE KS2_NETCP_BASE
#define CONFIG_KSNET_SERDES_SGMII_BASE KS2_SGMII_SERDES_BASE

View file

@ -43,7 +43,6 @@ int ethoc_initialize(u8 dev_num, int base_addr);
int fec_initialize (bd_t *bis);
int fecmxc_initialize(bd_t *bis);
int fecmxc_initialize_multi(bd_t *bis, int dev_id, int phy_id, uint32_t addr);
int ftgmac100_initialize(bd_t *bits);
int ftmac100_initialize(bd_t *bits);
int ftmac110_initialize(bd_t *bits);
void gt6426x_eth_initialize(bd_t *bis);