mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-27 20:38:52 +09:00
![Joe Hershberger](/assets/img/avatar_default.png)
Update the naming convention used in the network stack functions and variables that Ethernet drivers use to interact with it. This cleans up the temporary hacks that were added to this interface along with the DM support. This patch has a few remaining checkpatch.pl failures that would be out of the scope of this patch to fix (drivers that are in gross violation of checkpatch.pl). Signed-off-by: Joe Hershberger <joe.hershberger@ni.com> Acked-by: Simon Glass <sjg@chromium.org>
597 lines
13 KiB
C
597 lines
13 KiB
C
/*
|
|
* Ethernet driver for TI K2HK EVM.
|
|
*
|
|
* (C) Copyright 2012-2014
|
|
* Texas Instruments Incorporated, <www.ti.com>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
#include <common.h>
|
|
#include <command.h>
|
|
|
|
#include <net.h>
|
|
#include <phy.h>
|
|
#include <errno.h>
|
|
#include <miiphy.h>
|
|
#include <malloc.h>
|
|
#include <asm/ti-common/keystone_nav.h>
|
|
#include <asm/ti-common/keystone_net.h>
|
|
#include <asm/ti-common/keystone_serdes.h>
|
|
|
|
unsigned int emac_open;
|
|
static struct mii_dev *mdio_bus;
|
|
static unsigned int sys_has_mdio = 1;
|
|
|
|
#ifdef KEYSTONE2_EMAC_GIG_ENABLE
|
|
#define emac_gigabit_enable(x) keystone2_eth_gigabit_enable(x)
|
|
#else
|
|
#define emac_gigabit_enable(x) /* no gigabit to enable */
|
|
#endif
|
|
|
|
#define RX_BUFF_NUMS 24
|
|
#define RX_BUFF_LEN 1520
|
|
#define MAX_SIZE_STREAM_BUFFER RX_BUFF_LEN
|
|
#define SGMII_ANEG_TIMEOUT 4000
|
|
|
|
static u8 rx_buffs[RX_BUFF_NUMS * RX_BUFF_LEN] __aligned(16);
|
|
|
|
struct rx_buff_desc net_rx_buffs = {
|
|
.buff_ptr = rx_buffs,
|
|
.num_buffs = RX_BUFF_NUMS,
|
|
.buff_len = RX_BUFF_LEN,
|
|
.rx_flow = 22,
|
|
};
|
|
|
|
static void keystone2_net_serdes_setup(void);
|
|
|
|
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;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
int keystone_sgmii_link_status(int port)
|
|
{
|
|
u32 status = 0;
|
|
|
|
status = __raw_readl(SGMII_STATUS_REG(port));
|
|
|
|
return (status & SGMII_REG_STATUS_LOCK) &&
|
|
(status & SGMII_REG_STATUS_LINK);
|
|
}
|
|
|
|
int keystone_sgmii_config(struct phy_device *phy_dev, int port, int interface)
|
|
{
|
|
unsigned int i, status, mask;
|
|
unsigned int mr_adv_ability, control;
|
|
|
|
switch (interface) {
|
|
case SGMII_LINK_MAC_MAC_AUTONEG:
|
|
mr_adv_ability = (SGMII_REG_MR_ADV_ENABLE |
|
|
SGMII_REG_MR_ADV_LINK |
|
|
SGMII_REG_MR_ADV_FULL_DUPLEX |
|
|
SGMII_REG_MR_ADV_GIG_MODE);
|
|
control = (SGMII_REG_CONTROL_MASTER |
|
|
SGMII_REG_CONTROL_AUTONEG);
|
|
|
|
break;
|
|
case SGMII_LINK_MAC_PHY:
|
|
case SGMII_LINK_MAC_PHY_FORCED:
|
|
mr_adv_ability = SGMII_REG_MR_ADV_ENABLE;
|
|
control = SGMII_REG_CONTROL_AUTONEG;
|
|
|
|
break;
|
|
case SGMII_LINK_MAC_MAC_FORCED:
|
|
mr_adv_ability = (SGMII_REG_MR_ADV_ENABLE |
|
|
SGMII_REG_MR_ADV_LINK |
|
|
SGMII_REG_MR_ADV_FULL_DUPLEX |
|
|
SGMII_REG_MR_ADV_GIG_MODE);
|
|
control = SGMII_REG_CONTROL_MASTER;
|
|
|
|
break;
|
|
case SGMII_LINK_MAC_FIBER:
|
|
mr_adv_ability = 0x20;
|
|
control = SGMII_REG_CONTROL_AUTONEG;
|
|
|
|
break;
|
|
default:
|
|
mr_adv_ability = SGMII_REG_MR_ADV_ENABLE;
|
|
control = SGMII_REG_CONTROL_AUTONEG;
|
|
}
|
|
|
|
__raw_writel(0, SGMII_CTL_REG(port));
|
|
|
|
/*
|
|
* Wait for the SerDes pll to lock,
|
|
* but don't trap if lock is never read
|
|
*/
|
|
for (i = 0; i < 1000; i++) {
|
|
udelay(2000);
|
|
status = __raw_readl(SGMII_STATUS_REG(port));
|
|
if ((status & SGMII_REG_STATUS_LOCK) != 0)
|
|
break;
|
|
}
|
|
|
|
__raw_writel(mr_adv_ability, SGMII_MRADV_REG(port));
|
|
__raw_writel(control, SGMII_CTL_REG(port));
|
|
|
|
|
|
mask = SGMII_REG_STATUS_LINK;
|
|
|
|
if (control & SGMII_REG_CONTROL_AUTONEG)
|
|
mask |= SGMII_REG_STATUS_AUTONEG;
|
|
|
|
status = __raw_readl(SGMII_STATUS_REG(port));
|
|
if ((status & mask) == mask)
|
|
return 0;
|
|
|
|
printf("\n%s Waiting for SGMII auto negotiation to complete",
|
|
phy_dev->dev->name);
|
|
while ((status & mask) != mask) {
|
|
/*
|
|
* Timeout reached ?
|
|
*/
|
|
if (i > SGMII_ANEG_TIMEOUT) {
|
|
puts(" TIMEOUT !\n");
|
|
phy_dev->link = 0;
|
|
return 0;
|
|
}
|
|
|
|
if (ctrlc()) {
|
|
puts("user interrupt!\n");
|
|
phy_dev->link = 0;
|
|
return -EINTR;
|
|
}
|
|
|
|
if ((i++ % 500) == 0)
|
|
printf(".");
|
|
|
|
udelay(1000); /* 1 ms */
|
|
status = __raw_readl(SGMII_STATUS_REG(port));
|
|
}
|
|
puts(" done\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mac_sl_reset(u32 port)
|
|
{
|
|
u32 i, v;
|
|
|
|
if (port >= DEVICE_N_GMACSL_PORTS)
|
|
return GMACSL_RET_INVALID_PORT;
|
|
|
|
/* Set the soft reset bit */
|
|
writel(CPGMAC_REG_RESET_VAL_RESET,
|
|
DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RESET);
|
|
|
|
/* Wait for the bit to clear */
|
|
for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) {
|
|
v = readl(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RESET);
|
|
if ((v & CPGMAC_REG_RESET_VAL_RESET_MASK) !=
|
|
CPGMAC_REG_RESET_VAL_RESET)
|
|
return GMACSL_RET_OK;
|
|
}
|
|
|
|
/* Timeout on the reset */
|
|
return GMACSL_RET_WARN_RESET_INCOMPLETE;
|
|
}
|
|
|
|
int mac_sl_config(u_int16_t port, struct mac_sl_cfg *cfg)
|
|
{
|
|
u32 v, i;
|
|
int ret = GMACSL_RET_OK;
|
|
|
|
if (port >= DEVICE_N_GMACSL_PORTS)
|
|
return GMACSL_RET_INVALID_PORT;
|
|
|
|
if (cfg->max_rx_len > CPGMAC_REG_MAXLEN_LEN) {
|
|
cfg->max_rx_len = CPGMAC_REG_MAXLEN_LEN;
|
|
ret = GMACSL_RET_WARN_MAXLEN_TOO_BIG;
|
|
}
|
|
|
|
/* Must wait if the device is undergoing reset */
|
|
for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) {
|
|
v = readl(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RESET);
|
|
if ((v & CPGMAC_REG_RESET_VAL_RESET_MASK) !=
|
|
CPGMAC_REG_RESET_VAL_RESET)
|
|
break;
|
|
}
|
|
|
|
if (i == DEVICE_EMACSL_RESET_POLL_COUNT)
|
|
return GMACSL_RET_CONFIG_FAIL_RESET_ACTIVE;
|
|
|
|
writel(cfg->max_rx_len, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_MAXLEN);
|
|
writel(cfg->ctl, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_CTL);
|
|
|
|
#if defined(CONFIG_SOC_K2E) || defined(CONFIG_SOC_K2L)
|
|
/* Map RX packet flow priority to 0 */
|
|
writel(0, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RX_PRI_MAP);
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ethss_config(u32 ctl, u32 max_pkt_size)
|
|
{
|
|
u32 i;
|
|
|
|
/* Max length register */
|
|
writel(max_pkt_size, DEVICE_CPSW_BASE + CPSW_REG_MAXLEN);
|
|
|
|
/* Control register */
|
|
writel(ctl, DEVICE_CPSW_BASE + CPSW_REG_CTL);
|
|
|
|
/* All statistics enabled by default */
|
|
writel(CPSW_REG_VAL_STAT_ENABLE_ALL,
|
|
DEVICE_CPSW_BASE + CPSW_REG_STAT_PORT_EN);
|
|
|
|
/* Reset and enable the ALE */
|
|
writel(CPSW_REG_VAL_ALE_CTL_RESET_AND_ENABLE |
|
|
CPSW_REG_VAL_ALE_CTL_BYPASS,
|
|
DEVICE_CPSW_BASE + CPSW_REG_ALE_CONTROL);
|
|
|
|
/* All ports put into forward mode */
|
|
for (i = 0; i < DEVICE_CPSW_NUM_PORTS; i++)
|
|
writel(CPSW_REG_VAL_PORTCTL_FORWARD_MODE,
|
|
DEVICE_CPSW_BASE + CPSW_REG_ALE_PORTCTL(i));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ethss_start(void)
|
|
{
|
|
int i;
|
|
struct mac_sl_cfg cfg;
|
|
|
|
cfg.max_rx_len = MAX_SIZE_STREAM_BUFFER;
|
|
cfg.ctl = GMACSL_ENABLE | GMACSL_RX_ENABLE_EXT_CTL;
|
|
|
|
for (i = 0; i < DEVICE_N_GMACSL_PORTS; i++) {
|
|
mac_sl_reset(i);
|
|
mac_sl_config(i, &cfg);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ethss_stop(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < DEVICE_N_GMACSL_PORTS; i++)
|
|
mac_sl_reset(i);
|
|
|
|
return 0;
|
|
}
|
|
|
|
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);
|
|
|
|
keystone_sgmii_config(phy_dev, eth_priv->slave_port - 1,
|
|
eth_priv->sgmii_link_type);
|
|
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
|
|
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;
|
|
|
|
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;
|
|
sprintf(mdio_bus->name, "ethernet-mdio");
|
|
|
|
res = mdio_register(mdio_bus);
|
|
if (res)
|
|
return res;
|
|
}
|
|
|
|
keystone2_net_serdes_setup();
|
|
|
|
/* 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, PHY_INTERFACE_MODE_SGMII);
|
|
phy_config(phy_dev);
|
|
#else
|
|
phy_dev = phy_find_by_mask(mdio_bus, 1 << eth_priv->phy_addr,
|
|
PHY_INTERFACE_MODE_SGMII);
|
|
phy_dev->dev = dev;
|
|
#endif
|
|
eth_priv->phy_dev = phy_dev;
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct ks2_serdes ks2_serdes_sgmii_156p25mhz = {
|
|
.clk = SERDES_CLOCK_156P25M,
|
|
.rate = SERDES_RATE_5G,
|
|
.rate_mode = SERDES_QUARTER_RATE,
|
|
.intf = SERDES_PHY_SGMII,
|
|
.loopback = 0,
|
|
};
|
|
|
|
static void keystone2_net_serdes_setup(void)
|
|
{
|
|
ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII_BASE,
|
|
&ks2_serdes_sgmii_156p25mhz,
|
|
CONFIG_KSNET_SERDES_LANES_PER_SGMII);
|
|
|
|
#if defined(CONFIG_SOC_K2E) || defined(CONFIG_SOC_K2L)
|
|
ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII2_BASE,
|
|
&ks2_serdes_sgmii_156p25mhz,
|
|
CONFIG_KSNET_SERDES_LANES_PER_SGMII);
|
|
#endif
|
|
|
|
/* wait till setup */
|
|
udelay(5000);
|
|
}
|