Ethernet driver configures the CPSW, SGMI and Phy and uses the the Navigator APIs. The driver supports 4 Ethernet ports and can work with only one port at a time. Port configurations are defined in board.c. Signed-off-by: Vitaly Andrianov <vitalya@ti.com> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com> Signed-off-by: WingMan Kwok <w-kwok2@ti.com>master
parent
30fe8c150f
commit
fc9a8e8d40
@ -0,0 +1,240 @@ |
||||
/*
|
||||
* emac definitions for keystone2 devices |
||||
* |
||||
* (C) Copyright 2012-2014 |
||||
* Texas Instruments Incorporated, <www.ti.com> |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _EMAC_DEFS_H_ |
||||
#define _EMAC_DEFS_H_ |
||||
|
||||
#include <asm/arch/hardware.h> |
||||
#include <asm/io.h> |
||||
|
||||
#define DEVICE_REG32_R(a) readl(a) |
||||
#define DEVICE_REG32_W(a, v) writel(v, a) |
||||
|
||||
#define EMAC_EMACSL_BASE_ADDR (KS2_PASS_BASE + 0x00090900) |
||||
#define EMAC_MDIO_BASE_ADDR (KS2_PASS_BASE + 0x00090300) |
||||
#define EMAC_SGMII_BASE_ADDR (KS2_PASS_BASE + 0x00090100) |
||||
|
||||
#define KEYSTONE2_EMAC_GIG_ENABLE |
||||
|
||||
#define MAC_ID_BASE_ADDR (KS2_DEVICE_STATE_CTRL_BASE + 0x110) |
||||
|
||||
#ifdef CONFIG_SOC_K2HK |
||||
/* MDIO module input frequency */ |
||||
#define EMAC_MDIO_BUS_FREQ (clk_get_rate(pass_pll_clk)) |
||||
/* MDIO clock output frequency */ |
||||
#define EMAC_MDIO_CLOCK_FREQ 1000000 /* 1.0 MHz */ |
||||
#endif |
||||
|
||||
/* MII Status Register */ |
||||
#define MII_STATUS_REG 1 |
||||
#define MII_STATUS_LINK_MASK (0x4) |
||||
|
||||
/* Marvell 88E1111 PHY ID */ |
||||
#define PHY_MARVELL_88E1111 (0x01410cc0) |
||||
|
||||
#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 (1 << 7) |
||||
#define EMAC_MACCONTROL_GIGFORCE (1 << 17) |
||||
#define EMAC_MACCONTROL_RMIISPEED_100 (1 << 15) |
||||
|
||||
#define EMAC_MIN_ETHERNET_PKT_SIZE 60 |
||||
|
||||
struct mac_sl_cfg { |
||||
u_int32_t max_rx_len; /* Maximum receive packet length. */ |
||||
u_int32_t ctl; /* Control bitfield */ |
||||
}; |
||||
|
||||
/*
|
||||
* Definition: Control bitfields used in the ctl field of hwGmacSlCfg_t |
||||
*/ |
||||
#define GMACSL_RX_ENABLE_RCV_CONTROL_FRAMES (1 << 24) |
||||
#define GMACSL_RX_ENABLE_RCV_SHORT_FRAMES (1 << 23) |
||||
#define GMACSL_RX_ENABLE_RCV_ERROR_FRAMES (1 << 22) |
||||
#define GMACSL_RX_ENABLE_EXT_CTL (1 << 18) |
||||
#define GMACSL_RX_ENABLE_GIG_FORCE (1 << 17) |
||||
#define GMACSL_RX_ENABLE_IFCTL_B (1 << 16) |
||||
#define GMACSL_RX_ENABLE_IFCTL_A (1 << 15) |
||||
#define GMACSL_RX_ENABLE_CMD_IDLE (1 << 11) |
||||
#define GMACSL_TX_ENABLE_SHORT_GAP (1 << 10) |
||||
#define GMACSL_ENABLE_GIG_MODE (1 << 7) |
||||
#define GMACSL_TX_ENABLE_PACE (1 << 6) |
||||
#define GMACSL_ENABLE (1 << 5) |
||||
#define GMACSL_TX_ENABLE_FLOW_CTL (1 << 4) |
||||
#define GMACSL_RX_ENABLE_FLOW_CTL (1 << 3) |
||||
#define GMACSL_ENABLE_LOOPBACK (1 << 1) |
||||
#define GMACSL_ENABLE_FULL_DUPLEX (1 << 0) |
||||
|
||||
/*
|
||||
* DEFINTITION: function return values |
||||
*/ |
||||
#define GMACSL_RET_OK 0 |
||||
#define GMACSL_RET_INVALID_PORT -1 |
||||
#define GMACSL_RET_WARN_RESET_INCOMPLETE -2 |
||||
#define GMACSL_RET_WARN_MAXLEN_TOO_BIG -3 |
||||
#define GMACSL_RET_CONFIG_FAIL_RESET_ACTIVE -4 |
||||
|
||||
/* Register offsets */ |
||||
#define CPGMACSL_REG_ID 0x00 |
||||
#define CPGMACSL_REG_CTL 0x04 |
||||
#define CPGMACSL_REG_STATUS 0x08 |
||||
#define CPGMACSL_REG_RESET 0x0c |
||||
#define CPGMACSL_REG_MAXLEN 0x10 |
||||
#define CPGMACSL_REG_BOFF 0x14 |
||||
#define CPGMACSL_REG_RX_PAUSE 0x18 |
||||
#define CPGMACSL_REG_TX_PAURSE 0x1c |
||||
#define CPGMACSL_REG_EM_CTL 0x20 |
||||
#define CPGMACSL_REG_PRI 0x24 |
||||
|
||||
/* Soft reset register values */ |
||||
#define CPGMAC_REG_RESET_VAL_RESET_MASK (1 << 0) |
||||
#define CPGMAC_REG_RESET_VAL_RESET (1 << 0) |
||||
|
||||
/* Maxlen register values */ |
||||
#define CPGMAC_REG_MAXLEN_LEN 0x3fff |
||||
|
||||
/* Control bitfields */ |
||||
#define CPSW_CTL_P2_PASS_PRI_TAGGED (1 << 5) |
||||
#define CPSW_CTL_P1_PASS_PRI_TAGGED (1 << 4) |
||||
#define CPSW_CTL_P0_PASS_PRI_TAGGED (1 << 3) |
||||
#define CPSW_CTL_P0_ENABLE (1 << 2) |
||||
#define CPSW_CTL_VLAN_AWARE (1 << 1) |
||||
#define CPSW_CTL_FIFO_LOOPBACK (1 << 0) |
||||
|
||||
#define DEVICE_CPSW_NUM_PORTS 5 /* 5 switch ports */ |
||||
#define DEVICE_CPSW_BASE (0x02090800) |
||||
#define target_get_switch_ctl() CPSW_CTL_P0_ENABLE /* Enable port 0 */ |
||||
#define SWITCH_MAX_PKT_SIZE 9000 |
||||
|
||||
/* Register offsets */ |
||||
#define CPSW_REG_CTL 0x004 |
||||
#define CPSW_REG_STAT_PORT_EN 0x00c |
||||
#define CPSW_REG_MAXLEN 0x040 |
||||
#define CPSW_REG_ALE_CONTROL 0x608 |
||||
#define CPSW_REG_ALE_PORTCTL(x) (0x640 + (x)*4) |
||||
|
||||
/* Register values */ |
||||
#define CPSW_REG_VAL_STAT_ENABLE_ALL 0xf |
||||
#define CPSW_REG_VAL_ALE_CTL_RESET_AND_ENABLE ((u_int32_t)0xc0000000) |
||||
#define CPSW_REG_VAL_ALE_CTL_BYPASS ((u_int32_t)0x00000010) |
||||
#define CPSW_REG_VAL_PORTCTL_FORWARD_MODE 0x3 |
||||
|
||||
#define SGMII_REG_STATUS_LOCK BIT(4) |
||||
#define SGMII_REG_STATUS_LINK BIT(0) |
||||
#define SGMII_REG_STATUS_AUTONEG BIT(2) |
||||
#define SGMII_REG_CONTROL_AUTONEG BIT(0) |
||||
#define SGMII_REG_CONTROL_MASTER BIT(5) |
||||
#define SGMII_REG_MR_ADV_ENABLE BIT(0) |
||||
#define SGMII_REG_MR_ADV_LINK BIT(15) |
||||
#define SGMII_REG_MR_ADV_FULL_DUPLEX BIT(12) |
||||
#define SGMII_REG_MR_ADV_GIG_MODE BIT(11) |
||||
|
||||
#define SGMII_LINK_MAC_MAC_AUTONEG 0 |
||||
#define SGMII_LINK_MAC_PHY 1 |
||||
#define SGMII_LINK_MAC_MAC_FORCED 2 |
||||
#define SGMII_LINK_MAC_FIBER 3 |
||||
#define SGMII_LINK_MAC_PHY_FORCED 4 |
||||
|
||||
#define TARGET_SGMII_BASE KS2_PASS_BASE + 0x00090100 |
||||
#define TARGET_SGMII_BASE_ADDRESSES {KS2_PASS_BASE + 0x00090100, \ |
||||
KS2_PASS_BASE + 0x00090200, \
|
||||
KS2_PASS_BASE + 0x00090400, \
|
||||
KS2_PASS_BASE + 0x00090500} |
||||
|
||||
#define SGMII_OFFSET(x) ((x <= 1) ? (x * 0x100) : ((x * 0x100) + 0x100)) |
||||
|
||||
/*
|
||||
* SGMII registers |
||||
*/ |
||||
#define SGMII_IDVER_REG(x) (TARGET_SGMII_BASE + SGMII_OFFSET(x) + 0x000) |
||||
#define SGMII_SRESET_REG(x) (TARGET_SGMII_BASE + SGMII_OFFSET(x) + 0x004) |
||||
#define SGMII_CTL_REG(x) (TARGET_SGMII_BASE + SGMII_OFFSET(x) + 0x010) |
||||
#define SGMII_STATUS_REG(x) (TARGET_SGMII_BASE + SGMII_OFFSET(x) + 0x014) |
||||
#define SGMII_MRADV_REG(x) (TARGET_SGMII_BASE + SGMII_OFFSET(x) + 0x018) |
||||
#define SGMII_LPADV_REG(x) (TARGET_SGMII_BASE + SGMII_OFFSET(x) + 0x020) |
||||
#define SGMII_TXCFG_REG(x) (TARGET_SGMII_BASE + SGMII_OFFSET(x) + 0x030) |
||||
#define SGMII_RXCFG_REG(x) (TARGET_SGMII_BASE + SGMII_OFFSET(x) + 0x034) |
||||
#define SGMII_AUXCFG_REG(x) (TARGET_SGMII_BASE + SGMII_OFFSET(x) + 0x038) |
||||
|
||||
#define DEVICE_EMACSL_BASE(x) (KS2_PASS_BASE + 0x00090900 + (x) * 0x040) |
||||
#define DEVICE_N_GMACSL_PORTS 4 |
||||
#define DEVICE_EMACSL_RESET_POLL_COUNT 100 |
||||
|
||||
#define DEVICE_PSTREAM_CFG_REG_ADDR (KS2_PASS_BASE + 0x604) |
||||
|
||||
#ifdef CONFIG_SOC_K2HK |
||||
#define DEVICE_PSTREAM_CFG_REG_VAL_ROUTE_CPPI 0x06060606 |
||||
#endif |
||||
|
||||
#define hw_config_streaming_switch() \ |
||||
DEVICE_REG32_W(DEVICE_PSTREAM_CFG_REG_ADDR, \
|
||||
DEVICE_PSTREAM_CFG_REG_VAL_ROUTE_CPPI); |
||||
|
||||
/* EMAC MDIO Registers Structure */ |
||||
struct mdio_regs { |
||||
dv_reg version; |
||||
dv_reg control; |
||||
dv_reg alive; |
||||
dv_reg link; |
||||
dv_reg linkintraw; |
||||
dv_reg linkintmasked; |
||||
u_int8_t rsvd0[8]; |
||||
dv_reg userintraw; |
||||
dv_reg userintmasked; |
||||
dv_reg userintmaskset; |
||||
dv_reg userintmaskclear; |
||||
u_int8_t rsvd1[80]; |
||||
dv_reg useraccess0; |
||||
dv_reg userphysel0; |
||||
dv_reg useraccess1; |
||||
dv_reg userphysel1; |
||||
}; |
||||
|
||||
/* Ethernet MAC Registers Structure */ |
||||
struct emac_regs { |
||||
dv_reg idver; |
||||
dv_reg maccontrol; |
||||
dv_reg macstatus; |
||||
dv_reg soft_reset; |
||||
dv_reg rx_maxlen; |
||||
u32 rsvd0; |
||||
dv_reg rx_pause; |
||||
dv_reg tx_pause; |
||||
dv_reg emcontrol; |
||||
dv_reg pri_map; |
||||
u32 rsvd1[6]; |
||||
}; |
||||
|
||||
#define SGMII_ACCESS(port, reg) \ |
||||
*((volatile unsigned int *)(sgmiis[port] + reg)) |
||||
|
||||
struct eth_priv_t { |
||||
char int_name[32]; |
||||
int rx_flow; |
||||
int phy_addr; |
||||
int slave_port; |
||||
int sgmii_link_type; |
||||
}; |
||||
|
||||
extern struct eth_priv_t eth_priv_cfg[]; |
||||
|
||||
int keystone2_emac_initialize(struct eth_priv_t *eth_priv); |
||||
void sgmii_serdes_setup_156p25mhz(void); |
||||
void sgmii_serdes_shutdown(void); |
||||
|
||||
#endif /* _EMAC_DEFS_H_ */ |
@ -0,0 +1,716 @@ |
||||
/*
|
||||
* 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 <miiphy.h> |
||||
#include <malloc.h> |
||||
#include <asm/arch/emac_defs.h> |
||||
#include <asm/arch/psc_defs.h> |
||||
#include <asm/arch/keystone_nav.h> |
||||
|
||||
unsigned int emac_dbg; |
||||
|
||||
unsigned int emac_open; |
||||
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 |
||||
|
||||
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_eth_mdio_enable(void); |
||||
|
||||
static int gen_get_link_speed(int phy_addr); |
||||
|
||||
/* EMAC Addresses */ |
||||
static volatile struct emac_regs *adap_emac = |
||||
(struct emac_regs *)EMAC_EMACSL_BASE_ADDR; |
||||
static volatile struct mdio_regs *adap_mdio = |
||||
(struct mdio_regs *)EMAC_MDIO_BASE_ADDR; |
||||
|
||||
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; |
||||
} |
||||
|
||||
static void keystone2_eth_mdio_enable(void) |
||||
{ |
||||
u_int32_t clkdiv; |
||||
|
||||
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) |
||||
; |
||||
} |
||||
|
||||
/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */ |
||||
int keystone2_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data) |
||||
{ |
||||
int tmp; |
||||
|
||||
while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO) |
||||
; |
||||
|
||||
writel(MDIO_USERACCESS0_GO | |
||||
MDIO_USERACCESS0_WRITE_READ | |
||||
((reg_num & 0x1f) << 21) | |
||||
((phy_addr & 0x1f) << 16), |
||||
&adap_mdio->useraccess0); |
||||
|
||||
/* Wait for command to complete */ |
||||
while ((tmp = readl(&adap_mdio->useraccess0)) & MDIO_USERACCESS0_GO) |
||||
; |
||||
|
||||
if (tmp & MDIO_USERACCESS0_ACK) { |
||||
*data = tmp & 0xffff; |
||||
return 0; |
||||
} |
||||
|
||||
*data = -1; |
||||
return -1; |
||||
} |
||||
|
||||
/*
|
||||
* Write to a PHY register via MDIO inteface. |
||||
* Blocks until operation is complete. |
||||
*/ |
||||
int keystone2_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data) |
||||
{ |
||||
while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO) |
||||
; |
||||
|
||||
writel(MDIO_USERACCESS0_GO | |
||||
MDIO_USERACCESS0_WRITE_WRITE | |
||||
((reg_num & 0x1f) << 21) | |
||||
((phy_addr & 0x1f) << 16) | |
||||
(data & 0xffff), |
||||
&adap_mdio->useraccess0); |
||||
|
||||
/* Wait for command to complete */ |
||||
while (readl(&adap_mdio->useraccess0) & MDIO_USERACCESS0_GO) |
||||
; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/* PHY functions for a generic PHY */ |
||||
static int gen_get_link_speed(int phy_addr) |
||||
{ |
||||
u_int16_t tmp; |
||||
|
||||
if ((!keystone2_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp)) && |
||||
(tmp & 0x04)) { |
||||
return 0; |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
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) { |
||||
if (keystone2_eth_phy_read(eth_priv->phy_addr, 0, &data) || |
||||
!(data & (1 << 6))) /* speed selection MSB */ |
||||
return; |
||||
} |
||||
|
||||
/*
|
||||
* Check if link detected is giga-bit |
||||
* If Gigabit mode detected, enable gigbit in MAC |
||||
*/ |
||||
writel(readl(&(adap_emac[eth_priv->slave_port - 1].maccontrol)) | |
||||
EMAC_MACCONTROL_GIGFORCE | EMAC_MACCONTROL_GIGABIT_ENABLE, |
||||
&(adap_emac[eth_priv->slave_port - 1].maccontrol)) |
||||
; |
||||
} |
||||
|
||||
int keystone_sgmii_link_status(int port) |
||||
{ |
||||
u32 status = 0; |
||||
|
||||
status = __raw_readl(SGMII_STATUS_REG(port)); |
||||
|
||||
return status & SGMII_REG_STATUS_LINK; |
||||
} |
||||
|
||||
|
||||
int keystone_get_link_status(struct eth_device *dev) |
||||
{ |
||||
struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv; |
||||
int sgmii_link; |
||||
int link_state = 0; |
||||
#if CONFIG_GET_LINK_STATUS_ATTEMPTS > 1 |
||||
int j; |
||||
|
||||
for (j = 0; (j < CONFIG_GET_LINK_STATUS_ATTEMPTS) && (link_state == 0); |
||||
j++) { |
||||
#endif |
||||
sgmii_link = |
||||
keystone_sgmii_link_status(eth_priv->slave_port - 1); |
||||
|
||||
if (sgmii_link) { |
||||
link_state = 1; |
||||
|
||||
if (eth_priv->sgmii_link_type == SGMII_LINK_MAC_PHY) |
||||
if (gen_get_link_speed(eth_priv->phy_addr)) |
||||
link_state = 0; |
||||
} |
||||
#if CONFIG_GET_LINK_STATUS_ATTEMPTS > 1 |
||||
} |
||||
#endif |
||||
return link_state; |
||||
} |
||||
|
||||
int keystone_sgmii_config(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; |
||||
|
||||
for (i = 0; i < 1000; i++) { |
||||
status = __raw_readl(SGMII_STATUS_REG(port)); |
||||
if ((status & mask) == mask) |
||||
break; |
||||
} |
||||
|
||||
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 */ |
||||
DEVICE_REG32_W(DEVICE_EMACSL_BASE(port) + |
||||
CPGMACSL_REG_RESET, CPGMAC_REG_RESET_VAL_RESET); |
||||
|
||||
/* Wait for the bit to clear */ |
||||
for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) { |
||||
v = DEVICE_REG32_R(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 = DEVICE_REG32_R(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; |
||||
|
||||
DEVICE_REG32_W(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_MAXLEN, |
||||
cfg->max_rx_len); |
||||
|
||||
DEVICE_REG32_W(DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_CTL, |
||||
cfg->ctl); |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
int ethss_config(u32 ctl, u32 max_pkt_size) |
||||
{ |
||||
u32 i; |
||||
|
||||
/* Max length register */ |
||||
DEVICE_REG32_W(DEVICE_CPSW_BASE + CPSW_REG_MAXLEN, max_pkt_size); |
||||
|
||||
/* Control register */ |
||||
DEVICE_REG32_W(DEVICE_CPSW_BASE + CPSW_REG_CTL, ctl); |
||||
|
||||
/* All statistics enabled by default */ |
||||
DEVICE_REG32_W(DEVICE_CPSW_BASE + CPSW_REG_STAT_PORT_EN, |
||||
CPSW_REG_VAL_STAT_ENABLE_ALL); |
||||
|
||||
/* Reset and enable the ALE */ |
||||
DEVICE_REG32_W(DEVICE_CPSW_BASE + CPSW_REG_ALE_CONTROL, |
||||
CPSW_REG_VAL_ALE_CTL_RESET_AND_ENABLE | |
||||
CPSW_REG_VAL_ALE_CTL_BYPASS); |
||||
|
||||
/* All ports put into forward mode */ |
||||
for (i = 0; i < DEVICE_CPSW_NUM_PORTS; i++) |
||||
DEVICE_REG32_W(DEVICE_CPSW_BASE + CPSW_REG_ALE_PORTCTL(i), |
||||
CPSW_REG_VAL_PORTCTL_FORWARD_MODE); |
||||
|
||||
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 netcp_send(buffer, num_bytes, (slave_port_num) << 16); |
||||
} |
||||
|
||||
/* Eth device open */ |
||||
static int keystone2_eth_open(struct eth_device *dev, bd_t *bis) |
||||
{ |
||||
u_int32_t clkdiv; |
||||
int link; |
||||
struct eth_priv_t *eth_priv = (struct eth_priv_t *)dev->priv; |
||||
|
||||
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; |
||||
|
||||
psc_enable_module(KS2_LPSC_PA); |
||||
psc_enable_module(KS2_LPSC_CPGMAC); |
||||
|
||||
sgmii_serdes_setup_156p25mhz(); |
||||
|
||||
if (sys_has_mdio) |
||||
keystone2_eth_mdio_enable(); |
||||
|
||||
keystone_sgmii_config(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 (netcp_init(&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) { |
||||
/* Init MDIO & get link state */ |
||||
clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; |
||||
writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | |
||||
MDIO_CONTROL_FAULT, &adap_mdio->control) |
||||
; |
||||
|
||||
/* We need to wait for MDIO to start */ |
||||
udelay(1000); |
||||
|
||||
link = keystone_get_link_status(dev); |
||||
if (link == 0) { |
||||
netcp_close(); |
||||
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) |
||||
{ |
||||
debug("+ emac_close\n"); |
||||
|
||||
if (!emac_open) |
||||
return; |
||||
|
||||
ethss_stop(); |
||||
|
||||
netcp_close(); |
||||
qm_close(); |
||||
|
||||
emac_open = 0; |
||||
|
||||
debug("- emac_close\n"); |
||||
} |
||||
|
||||
static int tx_send_loop; |
||||
|
||||
/*
|
||||
* 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; |
||||
|
||||
tx_send_loop = 0; |
||||
|
||||
if (keystone_get_link_status(dev) == 0) |
||||
return -1; |
||||
|
||||
emac_gigabit_enable(dev); |
||||
|
||||
if (cpmac_drv_send((u32 *)packet, length, eth_priv->slave_port) != 0) |
||||
return ret_status; |
||||
|
||||
if (keystone_get_link_status(dev) == 0) |
||||
return -1; |
||||
|
||||
emac_gigabit_enable(dev); |
||||
|
||||
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 = netcp_recv(&pkt, &pkt_size); |
||||
if (hd == NULL) |
||||
return 0; |
||||
|
||||
NetReceive((uchar *)pkt, pkt_size); |
||||
|
||||
netcp_release_rxhd(hd); |
||||
|
||||
return pkt_size; |
||||
} |
||||
|
||||
/*
|
||||
* This function initializes the EMAC hardware. |
||||
*/ |
||||
int keystone2_emac_initialize(struct eth_priv_t *eth_priv) |
||||
{ |
||||
struct eth_device *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); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void sgmii_serdes_setup_156p25mhz(void) |
||||
{ |
||||
unsigned int cnt; |
||||
|
||||
/*
|
||||
* configure Serializer/Deserializer (SerDes) hardware. SerDes IP |
||||
* hardware vendor published only register addresses and their values |
||||
* to be used for configuring SerDes. So had to use hardcoded values |
||||
* below. |
||||
*/ |
||||
clrsetbits_le32(0x0232a000, 0xffff0000, 0x00800000); |
||||
clrsetbits_le32(0x0232a014, 0x0000ffff, 0x00008282); |
||||
clrsetbits_le32(0x0232a060, 0x00ffffff, 0x00142438); |
||||
clrsetbits_le32(0x0232a064, 0x00ffff00, 0x00c3c700); |
||||
clrsetbits_le32(0x0232a078, 0x0000ff00, 0x0000c000); |
||||
|
||||
clrsetbits_le32(0x0232a204, 0xff0000ff, 0x38000080); |
||||
clrsetbits_le32(0x0232a208, 0x000000ff, 0x00000000); |
||||
clrsetbits_le32(0x0232a20c, 0xff000000, 0x02000000); |
||||
clrsetbits_le32(0x0232a210, 0xff000000, 0x1b000000); |
||||
clrsetbits_le32(0x0232a214, 0x0000ffff, 0x00006fb8); |
||||
clrsetbits_le32(0x0232a218, 0xffff00ff, 0x758000e4); |
||||
clrsetbits_le32(0x0232a2ac, 0x0000ff00, 0x00004400); |
||||
clrsetbits_le32(0x0232a22c, 0x00ffff00, 0x00200800); |
||||
clrsetbits_le32(0x0232a280, 0x00ff00ff, 0x00820082); |
||||
clrsetbits_le32(0x0232a284, 0xffffffff, 0x1d0f0385); |
||||
|
||||
clrsetbits_le32(0x0232a404, 0xff0000ff, 0x38000080); |
||||
clrsetbits_le32(0x0232a408, 0x000000ff, 0x00000000); |
||||
clrsetbits_le32(0x0232a40c, 0xff000000, 0x02000000); |
||||
clrsetbits_le32(0x0232a410, 0xff000000, 0x1b000000); |
||||
clrsetbits_le32(0x0232a414, 0x0000ffff, 0x00006fb8); |
||||
clrsetbits_le32(0x0232a418, 0xffff00ff, 0x758000e4); |
||||
clrsetbits_le32(0x0232a4ac, 0x0000ff00, 0x00004400); |
||||
clrsetbits_le32(0x0232a42c, 0x00ffff00, 0x00200800); |
||||
clrsetbits_le32(0x0232a480, 0x00ff00ff, 0x00820082); |
||||
clrsetbits_le32(0x0232a484, 0xffffffff, 0x1d0f0385); |
||||
|
||||
clrsetbits_le32(0x0232a604, 0xff0000ff, 0x38000080); |
||||
clrsetbits_le32(0x0232a608, 0x000000ff, 0x00000000); |
||||
clrsetbits_le32(0x0232a60c, 0xff000000, 0x02000000); |
||||
clrsetbits_le32(0x0232a610, 0xff000000, 0x1b000000); |
||||
clrsetbits_le32(0x0232a614, 0x0000ffff, 0x00006fb8); |
||||
clrsetbits_le32(0x0232a618, 0xffff00ff, 0x758000e4); |
||||
clrsetbits_le32(0x0232a6ac, 0x0000ff00, 0x00004400); |
||||
clrsetbits_le32(0x0232a62c, 0x00ffff00, 0x00200800); |
||||
clrsetbits_le32(0x0232a680, 0x00ff00ff, 0x00820082); |
||||
clrsetbits_le32(0x0232a684, 0xffffffff, 0x1d0f0385); |
||||
|
||||
clrsetbits_le32(0x0232a804, 0xff0000ff, 0x38000080); |
||||
clrsetbits_le32(0x0232a808, 0x000000ff, 0x00000000); |
||||
clrsetbits_le32(0x0232a80c, 0xff000000, 0x02000000); |
||||
clrsetbits_le32(0x0232a810, 0xff000000, 0x1b000000); |
||||
clrsetbits_le32(0x0232a814, 0x0000ffff, 0x00006fb8); |
||||
clrsetbits_le32(0x0232a818, 0xffff00ff, 0x758000e4); |
||||
clrsetbits_le32(0x0232a8ac, 0x0000ff00, 0x00004400); |
||||
clrsetbits_le32(0x0232a82c, 0x00ffff00, 0x00200800); |
||||
clrsetbits_le32(0x0232a880, 0x00ff00ff, 0x00820082); |
||||
clrsetbits_le32(0x0232a884, 0xffffffff, 0x1d0f0385); |
||||
|
||||
clrsetbits_le32(0x0232aa00, 0x0000ff00, 0x00000800); |
||||
clrsetbits_le32(0x0232aa08, 0xffff0000, 0x38a20000); |
||||
clrsetbits_le32(0x0232aa30, 0x00ffff00, 0x008a8a00); |
||||
clrsetbits_le32(0x0232aa84, 0x0000ff00, 0x00000600); |
||||
clrsetbits_le32(0x0232aa94, 0xff000000, 0x10000000); |
||||
clrsetbits_le32(0x0232aaa0, 0xff000000, 0x81000000); |
||||
clrsetbits_le32(0x0232aabc, 0xff000000, 0xff000000); |
||||
clrsetbits_le32(0x0232aac0, 0x000000ff, 0x0000008b); |
||||
clrsetbits_le32(0x0232ab08, 0xffff0000, 0x583f0000); |
||||
clrsetbits_le32(0x0232ab0c, 0x000000ff, 0x0000004e); |
||||
clrsetbits_le32(0x0232a000, 0x000000ff, 0x00000003); |
||||
clrsetbits_le32(0x0232aa00, 0x000000ff, 0x0000005f); |
||||
|
||||
clrsetbits_le32(0x0232aa48, 0x00ffff00, 0x00fd8c00); |
||||
clrsetbits_le32(0x0232aa54, 0x00ffffff, 0x002fec72); |
||||
clrsetbits_le32(0x0232aa58, 0xffffff00, 0x00f92100); |
||||
clrsetbits_le32(0x0232aa5c, 0xffffffff, 0x00040060); |
||||
clrsetbits_le32(0x0232aa60, 0xffffffff, 0x00008000); |
||||
clrsetbits_le32(0x0232aa64, 0xffffffff, 0x0c581220); |
||||
clrsetbits_le32(0x0232aa68, 0xffffffff, 0xe13b0602); |
||||
clrsetbits_le32(0x0232aa6c, 0xffffffff, 0xb8074cc1); |
||||
clrsetbits_le32(0x0232aa70, 0xffffffff, 0x3f02e989); |
||||
clrsetbits_le32(0x0232aa74, 0x000000ff, 0x00000001); |
||||
clrsetbits_le32(0x0232ab20, 0x00ff0000, 0x00370000); |
||||
clrsetbits_le32(0x0232ab1c, 0xff000000, 0x37000000); |
||||
clrsetbits_le32(0x0232ab20, 0x000000ff, 0x0000005d); |
||||
|
||||
/*Bring SerDes out of Reset if SerDes is Shutdown & is in Reset Mode*/ |
||||
clrbits_le32(0x0232a010, 1 << 28); |
||||
|
||||
/* Enable TX and RX via the LANExCTL_STS 0x0000 + x*4 */ |
||||
clrbits_le32(0x0232a228, 1 << 29); |
||||
writel(0xF800F8C0, 0x0232bfe0); |
||||
clrbits_le32(0x0232a428, 1 << 29); |
||||
writel(0xF800F8C0, 0x0232bfe4); |
||||
clrbits_le32(0x0232a628, 1 << 29); |
||||
writel(0xF800F8C0, 0x0232bfe8); |
||||
clrbits_le32(0x0232a828, 1 << 29); |
||||
writel(0xF800F8C0, 0x0232bfec); |
||||
|
||||
/*Enable pll via the pll_ctrl 0x0014*/ |
||||
writel(0xe0000000, 0x0232bff4) |
||||
; |
||||
|
||||
/*Waiting for SGMII Serdes PLL lock.*/ |
||||
for (cnt = 10000; cnt > 0 && ((readl(0x02090114) & 0x10) == 0); cnt--) |
||||
; |
||||
|
||||
for (cnt = 10000; cnt > 0 && ((readl(0x02090214) & 0x10) == 0); cnt--) |
||||
; |
||||
|
||||
for (cnt = 10000; cnt > 0 && ((readl(0x02090414) & 0x10) == 0); cnt--) |
||||
; |
||||
|
||||
for (cnt = 10000; cnt > 0 && ((readl(0x02090514) & 0x10) == 0); cnt--) |
||||
; |
||||
|
||||
udelay(45000); |
||||
} |
||||
|
||||
void sgmii_serdes_shutdown(void) |
||||
{ |
||||
/*
|
||||
* shutdown SerDes hardware. SerDes hardware vendor published only |
||||
* register addresses and their values. So had to use hardcoded |
||||
* values below. |
||||
*/ |
||||
clrbits_le32(0x0232bfe0, 3 << 29 | 3 << 13); |
||||
setbits_le32(0x02320228, 1 << 29); |
||||
clrbits_le32(0x0232bfe4, 3 << 29 | 3 << 13); |
||||
setbits_le32(0x02320428, 1 << 29); |
||||
clrbits_le32(0x0232bfe8, 3 << 29 | 3 << 13); |
||||
setbits_le32(0x02320628, 1 << 29); |
||||
clrbits_le32(0x0232bfec, 3 << 29 | 3 << 13); |
||||
setbits_le32(0x02320828, 1 << 29); |
||||
|
||||
clrbits_le32(0x02320034, 3 << 29); |
||||
setbits_le32(0x02320010, 1 << 28); |
||||
} |
Loading…
Reference in new issue