mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-11 07:34:31 +00:00
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:
commit
9e2a902809
41 changed files with 3758 additions and 2131 deletions
|
@ -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
|
@ -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_ */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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(ð_priv_cfg[j]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
void spl_board_init(void)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
17
doc/device-tree-bindings/net/mediatek,mt7628-eth.txt
Normal file
17
doc/device-tree-bindings/net/mediatek,mt7628-eth.txt
Normal 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>;
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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
644
drivers/net/mt7628-eth.c
Normal 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
20
drivers/net/ti/Kconfig
Normal 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
7
drivers/net/ti/Makefile
Normal 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
|
|
@ -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
203
drivers/net/ti/cpsw_mdio.c
Normal 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);
|
||||
}
|
18
drivers/net/ti/cpsw_mdio.h
Normal file
18
drivers/net/ti/cpsw_mdio.h
Normal 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_ */
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue