Add a new driver for the Gigabit Ethernet MAC found on Intel Topcliff Platform Controller Hub. Tested under 10/100 half/full duplex and 1000 full duplex modes using ping and tftpboot commands. Signed-off-by: Bin Meng <bmeng.cn@gmail.com> Acked-by: Joe Hershberger <joe.hershberger@ni.com>master
parent
c58ea6cb8c
commit
8ee443b8eb
@ -0,0 +1,466 @@ |
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> |
||||
* |
||||
* Intel Platform Controller Hub EG20T (codename Topcliff) GMAC Driver |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <errno.h> |
||||
#include <asm/io.h> |
||||
#include <pci.h> |
||||
#include <malloc.h> |
||||
#include <miiphy.h> |
||||
#include "pch_gbe.h" |
||||
|
||||
#if !defined(CONFIG_PHYLIB) |
||||
# error "PCH Gigabit Ethernet driver requires PHYLIB - missing CONFIG_PHYLIB" |
||||
#endif |
||||
|
||||
static struct pci_device_id supported[] = { |
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_GBE }, |
||||
{ } |
||||
}; |
||||
|
||||
static void pch_gbe_mac_read(struct pch_gbe_regs *mac_regs, u8 *addr) |
||||
{ |
||||
u32 macid_hi, macid_lo; |
||||
|
||||
macid_hi = readl(&mac_regs->mac_adr[0].high); |
||||
macid_lo = readl(&mac_regs->mac_adr[0].low) & 0xffff; |
||||
debug("pch_gbe: macid_hi %#x macid_lo %#x\n", macid_hi, macid_lo); |
||||
|
||||
addr[0] = (u8)(macid_hi & 0xff); |
||||
addr[1] = (u8)((macid_hi >> 8) & 0xff); |
||||
addr[2] = (u8)((macid_hi >> 16) & 0xff); |
||||
addr[3] = (u8)((macid_hi >> 24) & 0xff); |
||||
addr[4] = (u8)(macid_lo & 0xff); |
||||
addr[5] = (u8)((macid_lo >> 8) & 0xff); |
||||
} |
||||
|
||||
static int pch_gbe_mac_write(struct pch_gbe_regs *mac_regs, u8 *addr) |
||||
{ |
||||
u32 macid_hi, macid_lo; |
||||
ulong start; |
||||
|
||||
macid_hi = addr[0] + (addr[1] << 8) + (addr[2] << 16) + (addr[3] << 24); |
||||
macid_lo = addr[4] + (addr[5] << 8); |
||||
|
||||
writel(macid_hi, &mac_regs->mac_adr[0].high); |
||||
writel(macid_lo, &mac_regs->mac_adr[0].low); |
||||
writel(0xfffe, &mac_regs->addr_mask); |
||||
|
||||
start = get_timer(0); |
||||
while (get_timer(start) < PCH_GBE_TIMEOUT) { |
||||
if (!(readl(&mac_regs->addr_mask) & PCH_GBE_BUSY)) |
||||
return 0; |
||||
|
||||
udelay(10); |
||||
} |
||||
|
||||
return -ETIME; |
||||
} |
||||
|
||||
static int pch_gbe_reset(struct eth_device *dev) |
||||
{ |
||||
struct pch_gbe_priv *priv = dev->priv; |
||||
struct pch_gbe_regs *mac_regs = priv->mac_regs; |
||||
ulong start; |
||||
|
||||
priv->rx_idx = 0; |
||||
priv->tx_idx = 0; |
||||
|
||||
writel(PCH_GBE_ALL_RST, &mac_regs->reset); |
||||
|
||||
/*
|
||||
* Configure the MAC to RGMII mode after reset |
||||
* |
||||
* For some unknown reason, we must do the configuration here right |
||||
* after resetting the whole MAC, otherwise the reset bit in the RESET |
||||
* register will never be cleared by the hardware. And there is another |
||||
* way of having the same magic, that is to configure the MODE register |
||||
* to have the MAC work in MII/GMII mode, which is how current Linux |
||||
* pch_gbe driver does. Since anyway we need program the MAC to RGMII |
||||
* mode in the driver, we just do it here. |
||||
* |
||||
* Note: this behavior is not documented in the hardware manual. |
||||
*/ |
||||
writel(PCH_GBE_RGMII_MODE_RGMII | PCH_GBE_CHIP_TYPE_INTERNAL, |
||||
&mac_regs->rgmii_ctrl); |
||||
|
||||
start = get_timer(0); |
||||
while (get_timer(start) < PCH_GBE_TIMEOUT) { |
||||
if (!(readl(&mac_regs->reset) & PCH_GBE_ALL_RST)) { |
||||
/*
|
||||
* Soft reset clears hardware MAC address registers, |
||||
* so we have to reload MAC address here in order to |
||||
* make linux pch_gbe driver happy. |
||||
*/ |
||||
return pch_gbe_mac_write(mac_regs, dev->enetaddr); |
||||
} |
||||
|
||||
udelay(10); |
||||
} |
||||
|
||||
debug("pch_gbe: reset timeout\n"); |
||||
return -ETIME; |
||||
} |
||||
|
||||
static void pch_gbe_rx_descs_init(struct eth_device *dev) |
||||
{ |
||||
struct pch_gbe_priv *priv = dev->priv; |
||||
struct pch_gbe_regs *mac_regs = priv->mac_regs; |
||||
struct pch_gbe_rx_desc *rx_desc = &priv->rx_desc[0]; |
||||
int i; |
||||
|
||||
memset(rx_desc, 0, sizeof(struct pch_gbe_rx_desc) * PCH_GBE_DESC_NUM); |
||||
for (i = 0; i < PCH_GBE_DESC_NUM; i++) |
||||
rx_desc->buffer_addr = pci_phys_to_mem(priv->bdf, |
||||
(u32)(priv->rx_buff[i])); |
||||
|
||||
writel(pci_phys_to_mem(priv->bdf, (u32)rx_desc), |
||||
&mac_regs->rx_dsc_base); |
||||
writel(sizeof(struct pch_gbe_rx_desc) * (PCH_GBE_DESC_NUM - 1), |
||||
&mac_regs->rx_dsc_size); |
||||
|
||||
writel(pci_phys_to_mem(priv->bdf, (u32)(rx_desc + 1)), |
||||
&mac_regs->rx_dsc_sw_p); |
||||
} |
||||
|
||||
static void pch_gbe_tx_descs_init(struct eth_device *dev) |
||||
{ |
||||
struct pch_gbe_priv *priv = dev->priv; |
||||
struct pch_gbe_regs *mac_regs = priv->mac_regs; |
||||
struct pch_gbe_tx_desc *tx_desc = &priv->tx_desc[0]; |
||||
|
||||
memset(tx_desc, 0, sizeof(struct pch_gbe_tx_desc) * PCH_GBE_DESC_NUM); |
||||
|
||||
writel(pci_phys_to_mem(priv->bdf, (u32)tx_desc), |
||||
&mac_regs->tx_dsc_base); |
||||
writel(sizeof(struct pch_gbe_tx_desc) * (PCH_GBE_DESC_NUM - 1), |
||||
&mac_regs->tx_dsc_size); |
||||
writel(pci_phys_to_mem(priv->bdf, (u32)(tx_desc + 1)), |
||||
&mac_regs->tx_dsc_sw_p); |
||||
} |
||||
|
||||
static void pch_gbe_adjust_link(struct pch_gbe_regs *mac_regs, |
||||
struct phy_device *phydev) |
||||
{ |
||||
if (!phydev->link) { |
||||
printf("%s: No link.\n", phydev->dev->name); |
||||
return; |
||||
} |
||||
|
||||
clrbits_le32(&mac_regs->rgmii_ctrl, |
||||
PCH_GBE_RGMII_RATE_2_5M | PCH_GBE_CRS_SEL); |
||||
clrbits_le32(&mac_regs->mode, |
||||
PCH_GBE_MODE_GMII_ETHER | PCH_GBE_MODE_FULL_DUPLEX); |
||||
|
||||
switch (phydev->speed) { |
||||
case 1000: |
||||
setbits_le32(&mac_regs->rgmii_ctrl, PCH_GBE_RGMII_RATE_125M); |
||||
setbits_le32(&mac_regs->mode, PCH_GBE_MODE_GMII_ETHER); |
||||
break; |
||||
case 100: |
||||
setbits_le32(&mac_regs->rgmii_ctrl, PCH_GBE_RGMII_RATE_25M); |
||||
setbits_le32(&mac_regs->mode, PCH_GBE_MODE_MII_ETHER); |
||||
break; |
||||
case 10: |
||||
setbits_le32(&mac_regs->rgmii_ctrl, PCH_GBE_RGMII_RATE_2_5M); |
||||
setbits_le32(&mac_regs->mode, PCH_GBE_MODE_MII_ETHER); |
||||
break; |
||||
} |
||||
|
||||
if (phydev->duplex) { |
||||
setbits_le32(&mac_regs->rgmii_ctrl, PCH_GBE_CRS_SEL); |
||||
setbits_le32(&mac_regs->mode, PCH_GBE_MODE_FULL_DUPLEX); |
||||
} |
||||
|
||||
printf("Speed: %d, %s duplex\n", phydev->speed, |
||||
(phydev->duplex) ? "full" : "half"); |
||||
|
||||
return; |
||||
} |
||||
|
||||
static int pch_gbe_init(struct eth_device *dev, bd_t *bis) |
||||
{ |
||||
struct pch_gbe_priv *priv = dev->priv; |
||||
struct pch_gbe_regs *mac_regs = priv->mac_regs; |
||||
|
||||
if (pch_gbe_reset(dev)) |
||||
return -1; |
||||
|
||||
pch_gbe_rx_descs_init(dev); |
||||
pch_gbe_tx_descs_init(dev); |
||||
|
||||
/* Enable frame bursting */ |
||||
writel(PCH_GBE_MODE_FR_BST, &mac_regs->mode); |
||||
/* Disable TCP/IP accelerator */ |
||||
writel(PCH_GBE_RX_TCPIPACC_OFF, &mac_regs->tcpip_acc); |
||||
/* Disable RX flow control */ |
||||
writel(0, &mac_regs->rx_fctrl); |
||||
/* Configure RX/TX mode */ |
||||
writel(PCH_GBE_RH_ALM_EMP_16 | PCH_GBE_RH_ALM_FULL_16 | |
||||
PCH_GBE_RH_RD_TRG_32, &mac_regs->rx_mode); |
||||
writel(PCH_GBE_TM_TH_TX_STRT_32 | PCH_GBE_TM_TH_ALM_EMP_16 | |
||||
PCH_GBE_TM_TH_ALM_FULL_32 | PCH_GBE_TM_ST_AND_FD | |
||||
PCH_GBE_TM_SHORT_PKT, &mac_regs->tx_mode); |
||||
|
||||
/* Start up the PHY */ |
||||
if (phy_startup(priv->phydev)) { |
||||
printf("Could not initialize PHY %s\n", |
||||
priv->phydev->dev->name); |
||||
return -1; |
||||
} |
||||
|
||||
pch_gbe_adjust_link(mac_regs, priv->phydev); |
||||
|
||||
if (!priv->phydev->link) |
||||
return -1; |
||||
|
||||
/* Enable TX & RX */ |
||||
writel(PCH_GBE_RX_DMA_EN | PCH_GBE_TX_DMA_EN, &mac_regs->dma_ctrl); |
||||
writel(PCH_GBE_MRE_MAC_RX_EN, &mac_regs->mac_rx_en); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void pch_gbe_halt(struct eth_device *dev) |
||||
{ |
||||
struct pch_gbe_priv *priv = dev->priv; |
||||
|
||||
pch_gbe_reset(dev); |
||||
|
||||
phy_shutdown(priv->phydev); |
||||
} |
||||
|
||||
static int pch_gbe_send(struct eth_device *dev, void *packet, int length) |
||||
{ |
||||
struct pch_gbe_priv *priv = dev->priv; |
||||
struct pch_gbe_regs *mac_regs = priv->mac_regs; |
||||
struct pch_gbe_tx_desc *tx_head, *tx_desc; |
||||
u16 frame_ctrl = 0; |
||||
u32 int_st; |
||||
ulong start; |
||||
|
||||
tx_head = &priv->tx_desc[0]; |
||||
tx_desc = &priv->tx_desc[priv->tx_idx]; |
||||
|
||||
if (length < 64) |
||||
frame_ctrl |= PCH_GBE_TXD_CTRL_APAD; |
||||
|
||||
tx_desc->buffer_addr = pci_phys_to_mem(priv->bdf, (u32)packet); |
||||
tx_desc->length = length; |
||||
tx_desc->tx_words_eob = length + 3; |
||||
tx_desc->tx_frame_ctrl = frame_ctrl; |
||||
tx_desc->dma_status = 0; |
||||
tx_desc->gbec_status = 0; |
||||
|
||||
/* Test the wrap-around condition */ |
||||
if (++priv->tx_idx >= PCH_GBE_DESC_NUM) |
||||
priv->tx_idx = 0; |
||||
|
||||
writel(pci_phys_to_mem(priv->bdf, (u32)(tx_head + priv->tx_idx)), |
||||
&mac_regs->tx_dsc_sw_p); |
||||
|
||||
start = get_timer(0); |
||||
while (get_timer(start) < PCH_GBE_TIMEOUT) { |
||||
int_st = readl(&mac_regs->int_st); |
||||
if (int_st & PCH_GBE_INT_TX_CMPLT) |
||||
return 0; |
||||
|
||||
udelay(10); |
||||
} |
||||
|
||||
debug("pch_gbe: sent failed\n"); |
||||
return -ETIME; |
||||
} |
||||
|
||||
static int pch_gbe_recv(struct eth_device *dev) |
||||
{ |
||||
struct pch_gbe_priv *priv = dev->priv; |
||||
struct pch_gbe_regs *mac_regs = priv->mac_regs; |
||||
struct pch_gbe_rx_desc *rx_head, *rx_desc; |
||||
u32 hw_desc, buffer_addr, length; |
||||
int rx_swp; |
||||
|
||||
rx_head = &priv->rx_desc[0]; |
||||
rx_desc = &priv->rx_desc[priv->rx_idx]; |
||||
|
||||
readl(&mac_regs->int_st); |
||||
hw_desc = readl(&mac_regs->rx_dsc_hw_p_hld); |
||||
|
||||
/* Just return if not receiving any packet */ |
||||
if ((u32)rx_desc == hw_desc) |
||||
return 0; |
||||
|
||||
buffer_addr = pci_mem_to_phys(priv->bdf, rx_desc->buffer_addr); |
||||
length = rx_desc->rx_words_eob - 3 - ETH_FCS_LEN; |
||||
NetReceive((uchar *)buffer_addr, length); |
||||
|
||||
/* Test the wrap-around condition */ |
||||
if (++priv->rx_idx >= PCH_GBE_DESC_NUM) |
||||
priv->rx_idx = 0; |
||||
rx_swp = priv->rx_idx; |
||||
if (++rx_swp >= PCH_GBE_DESC_NUM) |
||||
rx_swp = 0; |
||||
|
||||
writel(pci_phys_to_mem(priv->bdf, (u32)(rx_head + rx_swp)), |
||||
&mac_regs->rx_dsc_sw_p); |
||||
|
||||
return length; |
||||
} |
||||
|
||||
static int pch_gbe_mdio_ready(struct pch_gbe_regs *mac_regs) |
||||
{ |
||||
ulong start = get_timer(0); |
||||
|
||||
while (get_timer(start) < PCH_GBE_TIMEOUT) { |
||||
if (readl(&mac_regs->miim) & PCH_GBE_MIIM_OPER_READY) |
||||
return 0; |
||||
|
||||
udelay(10); |
||||
} |
||||
|
||||
return -ETIME; |
||||
} |
||||
|
||||
static int pch_gbe_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) |
||||
{ |
||||
struct pch_gbe_regs *mac_regs = bus->priv; |
||||
u32 miim; |
||||
|
||||
if (pch_gbe_mdio_ready(mac_regs)) |
||||
return -ETIME; |
||||
|
||||
miim = (addr << PCH_GBE_MIIM_PHY_ADDR_SHIFT) | |
||||
(reg << PCH_GBE_MIIM_REG_ADDR_SHIFT) | |
||||
PCH_GBE_MIIM_OPER_READ; |
||||
writel(miim, &mac_regs->miim); |
||||
|
||||
if (pch_gbe_mdio_ready(mac_regs)) |
||||
return -ETIME; |
||||
|
||||
return readl(&mac_regs->miim) & 0xffff; |
||||
} |
||||
|
||||
static int pch_gbe_mdio_write(struct mii_dev *bus, int addr, int devad, |
||||
int reg, u16 val) |
||||
{ |
||||
struct pch_gbe_regs *mac_regs = bus->priv; |
||||
u32 miim; |
||||
|
||||
if (pch_gbe_mdio_ready(mac_regs)) |
||||
return -ETIME; |
||||
|
||||
miim = (addr << PCH_GBE_MIIM_PHY_ADDR_SHIFT) | |
||||
(reg << PCH_GBE_MIIM_REG_ADDR_SHIFT) | |
||||
PCH_GBE_MIIM_OPER_WRITE | val; |
||||
writel(miim, &mac_regs->miim); |
||||
|
||||
if (pch_gbe_mdio_ready(mac_regs)) |
||||
return -ETIME; |
||||
else |
||||
return 0; |
||||
} |
||||
|
||||
static int pch_gbe_mdio_init(char *name, struct pch_gbe_regs *mac_regs) |
||||
{ |
||||
struct mii_dev *bus; |
||||
|
||||
bus = mdio_alloc(); |
||||
if (!bus) { |
||||
debug("pch_gbe: failed to allocate MDIO bus\n"); |
||||
return -ENOMEM; |
||||
} |
||||
|
||||
bus->read = pch_gbe_mdio_read; |
||||
bus->write = pch_gbe_mdio_write; |
||||
sprintf(bus->name, name); |
||||
|
||||
bus->priv = (void *)mac_regs; |
||||
|
||||
return mdio_register(bus); |
||||
} |
||||
|
||||
static int pch_gbe_phy_init(struct eth_device *dev) |
||||
{ |
||||
struct pch_gbe_priv *priv = dev->priv; |
||||
struct phy_device *phydev; |
||||
int mask = 0xffffffff; |
||||
|
||||
phydev = phy_find_by_mask(priv->bus, mask, priv->interface); |
||||
if (!phydev) { |
||||
printf("pch_gbe: cannot find the phy\n"); |
||||
return -1; |
||||
} |
||||
|
||||
phy_connect_dev(phydev, dev); |
||||
|
||||
phydev->supported &= PHY_GBIT_FEATURES; |
||||
phydev->advertising = phydev->supported; |
||||
|
||||
priv->phydev = phydev; |
||||
phy_config(phydev); |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
int pch_gbe_register(bd_t *bis) |
||||
{ |
||||
struct eth_device *dev; |
||||
struct pch_gbe_priv *priv; |
||||
pci_dev_t devno; |
||||
u32 iobase; |
||||
|
||||
devno = pci_find_devices(supported, 0); |
||||
if (devno == -1) |
||||
return -ENODEV; |
||||
|
||||
dev = (struct eth_device *)malloc(sizeof(*dev)); |
||||
if (!dev) |
||||
return -ENOMEM; |
||||
memset(dev, 0, sizeof(*dev)); |
||||
|
||||
/*
|
||||
* The priv structure contains the descriptors and frame buffers which |
||||
* need a strict buswidth alignment (64 bytes) |
||||
*/ |
||||
priv = (struct pch_gbe_priv *)memalign(PCH_GBE_ALIGN_SIZE, |
||||
sizeof(*priv)); |
||||
if (!priv) { |
||||
free(dev); |
||||
return -ENOMEM; |
||||
} |
||||
memset(priv, 0, sizeof(*priv)); |
||||
|
||||
dev->priv = priv; |
||||
priv->dev = dev; |
||||
priv->bdf = devno; |
||||
|
||||
pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase); |
||||
iobase &= PCI_BASE_ADDRESS_MEM_MASK; |
||||
iobase = pci_mem_to_phys(devno, iobase); |
||||
|
||||
dev->iobase = iobase; |
||||
priv->mac_regs = (struct pch_gbe_regs *)iobase; |
||||
|
||||
sprintf(dev->name, "pch_gbe.%x", iobase); |
||||
|
||||
/* Read MAC address from SROM and initialize dev->enetaddr with it */ |
||||
pch_gbe_mac_read(priv->mac_regs, dev->enetaddr); |
||||
|
||||
dev->init = pch_gbe_init; |
||||
dev->halt = pch_gbe_halt; |
||||
dev->send = pch_gbe_send; |
||||
dev->recv = pch_gbe_recv; |
||||
|
||||
eth_register(dev); |
||||
|
||||
priv->interface = PHY_INTERFACE_MODE_RGMII; |
||||
pch_gbe_mdio_init(dev->name, priv->mac_regs); |
||||
priv->bus = miiphy_get_dev_by_name(dev->name); |
||||
|
||||
return pch_gbe_phy_init(dev); |
||||
} |
@ -0,0 +1,300 @@ |
||||
/*
|
||||
* Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com> |
||||
* |
||||
* Intel Platform Controller Hub EG20T (codename Topcliff) GMAC Driver |
||||
* Adapted from linux drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _PCH_GBE_H_ |
||||
#define _PCH_GBE_H_ |
||||
|
||||
#define PCH_GBE_TIMEOUT (3 * CONFIG_SYS_HZ) |
||||
|
||||
#define PCH_GBE_DESC_NUM 4 |
||||
#define PCH_GBE_ALIGN_SIZE 64 |
||||
|
||||
/*
|
||||
* Topcliff GBE MAC supports receiving ethernet frames with normal frame size |
||||
* (64-1518 bytes) as well as up to 10318 bytes, however it does not have a |
||||
* register bit to turn off receiving 'jumbo frame', so we have to allocate |
||||
* our own buffer to store the received frames instead of using U-Boot's own. |
||||
*/ |
||||
#define PCH_GBE_RX_FRAME_LEN ROUND(10318, PCH_GBE_ALIGN_SIZE) |
||||
|
||||
/* Interrupt Status */ |
||||
/* Interrupt Status Hold */ |
||||
/* Interrupt Enable */ |
||||
#define PCH_GBE_INT_RX_DMA_CMPLT 0x00000001 |
||||
#define PCH_GBE_INT_RX_VALID 0x00000002 |
||||
#define PCH_GBE_INT_RX_FRAME_ERR 0x00000004 |
||||
#define PCH_GBE_INT_RX_FIFO_ERR 0x00000008 |
||||
#define PCH_GBE_INT_RX_DMA_ERR 0x00000010 |
||||
#define PCH_GBE_INT_RX_DSC_EMP 0x00000020 |
||||
#define PCH_GBE_INT_TX_CMPLT 0x00000100 |
||||
#define PCH_GBE_INT_TX_DMA_CMPLT 0x00000200 |
||||
#define PCH_GBE_INT_TX_FIFO_ERR 0x00000400 |
||||
#define PCH_GBE_INT_TX_DMA_ERR 0x00000800 |
||||
#define PCH_GBE_INT_PAUSE_CMPLT 0x00001000 |
||||
#define PCH_GBE_INT_MIIM_CMPLT 0x00010000 |
||||
#define PCH_GBE_INT_PHY_INT 0x00100000 |
||||
#define PCH_GBE_INT_WOL_DET 0x01000000 |
||||
#define PCH_GBE_INT_TCPIP_ERR 0x10000000 |
||||
|
||||
/* Mode */ |
||||
#define PCH_GBE_MODE_MII_ETHER 0x00000000 |
||||
#define PCH_GBE_MODE_GMII_ETHER 0x80000000 |
||||
#define PCH_GBE_MODE_HALF_DUPLEX 0x00000000 |
||||
#define PCH_GBE_MODE_FULL_DUPLEX 0x40000000 |
||||
#define PCH_GBE_MODE_FR_BST 0x04000000 |
||||
|
||||
/* Reset */ |
||||
#define PCH_GBE_ALL_RST 0x80000000 |
||||
#define PCH_GBE_TX_RST 0x00008000 |
||||
#define PCH_GBE_RX_RST 0x00004000 |
||||
|
||||
/* TCP/IP Accelerator Control */ |
||||
#define PCH_GBE_EX_LIST_EN 0x00000008 |
||||
#define PCH_GBE_RX_TCPIPACC_OFF 0x00000004 |
||||
#define PCH_GBE_TX_TCPIPACC_EN 0x00000002 |
||||
#define PCH_GBE_RX_TCPIPACC_EN 0x00000001 |
||||
|
||||
/* MAC RX Enable */ |
||||
#define PCH_GBE_MRE_MAC_RX_EN 0x00000001 |
||||
|
||||
/* RX Flow Control */ |
||||
#define PCH_GBE_FL_CTRL_EN 0x80000000 |
||||
|
||||
/* RX Mode */ |
||||
#define PCH_GBE_ADD_FIL_EN 0x80000000 |
||||
#define PCH_GBE_MLT_FIL_EN 0x40000000 |
||||
#define PCH_GBE_RH_ALM_EMP_4 0x00000000 |
||||
#define PCH_GBE_RH_ALM_EMP_8 0x00004000 |
||||
#define PCH_GBE_RH_ALM_EMP_16 0x00008000 |
||||
#define PCH_GBE_RH_ALM_EMP_32 0x0000c000 |
||||
#define PCH_GBE_RH_ALM_FULL_4 0x00000000 |
||||
#define PCH_GBE_RH_ALM_FULL_8 0x00001000 |
||||
#define PCH_GBE_RH_ALM_FULL_16 0x00002000 |
||||
#define PCH_GBE_RH_ALM_FULL_32 0x00003000 |
||||
#define PCH_GBE_RH_RD_TRG_4 0x00000000 |
||||
#define PCH_GBE_RH_RD_TRG_8 0x00000200 |
||||
#define PCH_GBE_RH_RD_TRG_16 0x00000400 |
||||
#define PCH_GBE_RH_RD_TRG_32 0x00000600 |
||||
#define PCH_GBE_RH_RD_TRG_64 0x00000800 |
||||
#define PCH_GBE_RH_RD_TRG_128 0x00000a00 |
||||
#define PCH_GBE_RH_RD_TRG_256 0x00000c00 |
||||
#define PCH_GBE_RH_RD_TRG_512 0x00000e00 |
||||
|
||||
/* TX Mode */ |
||||
#define PCH_GBE_TM_NO_RTRY 0x80000000 |
||||
#define PCH_GBE_TM_LONG_PKT 0x40000000 |
||||
#define PCH_GBE_TM_ST_AND_FD 0x20000000 |
||||
#define PCH_GBE_TM_SHORT_PKT 0x10000000 |
||||
#define PCH_GBE_TM_LTCOL_RETX 0x08000000 |
||||
#define PCH_GBE_TM_TH_TX_STRT_4 0x00000000 |
||||
#define PCH_GBE_TM_TH_TX_STRT_8 0x00004000 |
||||
#define PCH_GBE_TM_TH_TX_STRT_16 0x00008000 |
||||
#define PCH_GBE_TM_TH_TX_STRT_32 0x0000c000 |
||||
#define PCH_GBE_TM_TH_ALM_EMP_4 0x00000000 |
||||
#define PCH_GBE_TM_TH_ALM_EMP_8 0x00000800 |
||||
#define PCH_GBE_TM_TH_ALM_EMP_16 0x00001000 |
||||
#define PCH_GBE_TM_TH_ALM_EMP_32 0x00001800 |
||||
#define PCH_GBE_TM_TH_ALM_EMP_64 0x00002000 |
||||
#define PCH_GBE_TM_TH_ALM_EMP_128 0x00002800 |
||||
#define PCH_GBE_TM_TH_ALM_EMP_256 0x00003000 |
||||
#define PCH_GBE_TM_TH_ALM_EMP_512 0x00003800 |
||||
#define PCH_GBE_TM_TH_ALM_FULL_4 0x00000000 |
||||
#define PCH_GBE_TM_TH_ALM_FULL_8 0x00000200 |
||||
#define PCH_GBE_TM_TH_ALM_FULL_16 0x00000400 |
||||
#define PCH_GBE_TM_TH_ALM_FULL_32 0x00000600 |
||||
|
||||
/* MAC Address Mask */ |
||||
#define PCH_GBE_BUSY 0x80000000 |
||||
|
||||
/* MIIM */ |
||||
#define PCH_GBE_MIIM_OPER_WRITE 0x04000000 |
||||
#define PCH_GBE_MIIM_OPER_READ 0x00000000 |
||||
#define PCH_GBE_MIIM_OPER_READY 0x04000000 |
||||
#define PCH_GBE_MIIM_PHY_ADDR_SHIFT 21 |
||||
#define PCH_GBE_MIIM_REG_ADDR_SHIFT 16 |
||||
|
||||
/* RGMII Control */ |
||||
#define PCH_GBE_CRS_SEL 0x00000010 |
||||
#define PCH_GBE_RGMII_RATE_125M 0x00000000 |
||||
#define PCH_GBE_RGMII_RATE_25M 0x00000008 |
||||
#define PCH_GBE_RGMII_RATE_2_5M 0x0000000c |
||||
#define PCH_GBE_RGMII_MODE_GMII 0x00000000 |
||||
#define PCH_GBE_RGMII_MODE_RGMII 0x00000002 |
||||
#define PCH_GBE_CHIP_TYPE_EXTERNAL 0x00000000 |
||||
#define PCH_GBE_CHIP_TYPE_INTERNAL 0x00000001 |
||||
|
||||
/* DMA Control */ |
||||
#define PCH_GBE_RX_DMA_EN 0x00000002 |
||||
#define PCH_GBE_TX_DMA_EN 0x00000001 |
||||
|
||||
/* Receive Descriptor bit definitions */ |
||||
#define PCH_GBE_RXD_ACC_STAT_BCAST 0x00000400 |
||||
#define PCH_GBE_RXD_ACC_STAT_MCAST 0x00000200 |
||||
#define PCH_GBE_RXD_ACC_STAT_UCAST 0x00000100 |
||||
#define PCH_GBE_RXD_ACC_STAT_TCPIPOK 0x000000c0 |
||||
#define PCH_GBE_RXD_ACC_STAT_IPOK 0x00000080 |
||||
#define PCH_GBE_RXD_ACC_STAT_TCPOK 0x00000040 |
||||
#define PCH_GBE_RXD_ACC_STAT_IP6ERR 0x00000020 |
||||
#define PCH_GBE_RXD_ACC_STAT_OFLIST 0x00000010 |
||||
#define PCH_GBE_RXD_ACC_STAT_TYPEIP 0x00000008 |
||||
#define PCH_GBE_RXD_ACC_STAT_MACL 0x00000004 |
||||
#define PCH_GBE_RXD_ACC_STAT_PPPOE 0x00000002 |
||||
#define PCH_GBE_RXD_ACC_STAT_VTAGT 0x00000001 |
||||
#define PCH_GBE_RXD_GMAC_STAT_PAUSE 0x0200 |
||||
#define PCH_GBE_RXD_GMAC_STAT_MARBR 0x0100 |
||||
#define PCH_GBE_RXD_GMAC_STAT_MARMLT 0x0080 |
||||
#define PCH_GBE_RXD_GMAC_STAT_MARIND 0x0040 |
||||
#define PCH_GBE_RXD_GMAC_STAT_MARNOTMT 0x0020 |
||||
#define PCH_GBE_RXD_GMAC_STAT_TLONG 0x0010 |
||||
#define PCH_GBE_RXD_GMAC_STAT_TSHRT 0x0008 |
||||
#define PCH_GBE_RXD_GMAC_STAT_NOTOCTAL 0x0004 |
||||
#define PCH_GBE_RXD_GMAC_STAT_NBLERR 0x0002 |
||||
#define PCH_GBE_RXD_GMAC_STAT_CRCERR 0x0001 |
||||
|
||||
/* Transmit Descriptor bit definitions */ |
||||
#define PCH_GBE_TXD_CTRL_TCPIP_ACC_OFF 0x0008 |
||||
#define PCH_GBE_TXD_CTRL_ITAG 0x0004 |
||||
#define PCH_GBE_TXD_CTRL_ICRC 0x0002 |
||||
#define PCH_GBE_TXD_CTRL_APAD 0x0001 |
||||
#define PCH_GBE_TXD_WORDS_SHIFT 2 |
||||
#define PCH_GBE_TXD_GMAC_STAT_CMPLT 0x2000 |
||||
#define PCH_GBE_TXD_GMAC_STAT_ABT 0x1000 |
||||
#define PCH_GBE_TXD_GMAC_STAT_EXCOL 0x0800 |
||||
#define PCH_GBE_TXD_GMAC_STAT_SNGCOL 0x0400 |
||||
#define PCH_GBE_TXD_GMAC_STAT_MLTCOL 0x0200 |
||||
#define PCH_GBE_TXD_GMAC_STAT_CRSER 0x0100 |
||||
#define PCH_GBE_TXD_GMAC_STAT_TLNG 0x0080 |
||||
#define PCH_GBE_TXD_GMAC_STAT_TSHRT 0x0040 |
||||
#define PCH_GBE_TXD_GMAC_STAT_LTCOL 0x0020 |
||||
#define PCH_GBE_TXD_GMAC_STAT_TFUNDFLW 0x0010 |
||||
|
||||
/**
|
||||
* struct pch_gbe_rx_desc - Receive Descriptor |
||||
* @buffer_addr: RX Frame Buffer Address |
||||
* @tcp_ip_status: TCP/IP Accelerator Status |
||||
* @rx_words_eob: RX word count and Byte position |
||||
* @gbec_status: GMAC Status |
||||
* @dma_status: DMA Status |
||||
* @reserved1: Reserved |
||||
* @reserved2: Reserved |
||||
*/ |
||||
struct pch_gbe_rx_desc { |
||||
u32 buffer_addr; |
||||
u32 tcp_ip_status; |
||||
u16 rx_words_eob; |
||||
u16 gbec_status; |
||||
u8 dma_status; |
||||
u8 reserved1; |
||||
u16 reserved2; |
||||
}; |
||||
|
||||
/**
|
||||
* struct pch_gbe_tx_desc - Transmit Descriptor |
||||
* @buffer_addr: TX Frame Buffer Address |
||||
* @length: Data buffer length |
||||
* @reserved1: Reserved |
||||
* @tx_words_eob: TX word count and Byte position |
||||
* @tx_frame_ctrl: TX Frame Control |
||||
* @dma_status: DMA Status |
||||
* @reserved2: Reserved |
||||
* @gbec_status: GMAC Status |
||||
*/ |
||||
struct pch_gbe_tx_desc { |
||||
u32 buffer_addr; |
||||
u16 length; |
||||
u16 reserved1; |
||||
u16 tx_words_eob; |
||||
u16 tx_frame_ctrl; |
||||
u8 dma_status; |
||||
u8 reserved2; |
||||
u16 gbec_status; |
||||
}; |
||||
|
||||
/**
|
||||
* pch_gbe_regs_mac_adr - structure holding values of mac address registers |
||||
* |
||||
* @high Denotes the 1st to 4th byte from the initial of MAC address |
||||
* @low Denotes the 5th to 6th byte from the initial of MAC address |
||||
*/ |
||||
struct pch_gbe_regs_mac_adr { |
||||
u32 high; |
||||
u32 low; |
||||
}; |
||||
|
||||
/**
|
||||
* pch_gbe_regs - structure holding values of MAC registers |
||||
*/ |
||||
struct pch_gbe_regs { |
||||
u32 int_st; |
||||
u32 int_en; |
||||
u32 mode; |
||||
u32 reset; |
||||
u32 tcpip_acc; |
||||
u32 ex_list; |
||||
u32 int_st_hold; |
||||
u32 phy_int_ctrl; |
||||
u32 mac_rx_en; |
||||
u32 rx_fctrl; |
||||
u32 pause_req; |
||||
u32 rx_mode; |
||||
u32 tx_mode; |
||||
u32 rx_fifo_st; |
||||
u32 tx_fifo_st; |
||||
u32 tx_fid; |
||||
u32 tx_result; |
||||
u32 pause_pkt1; |
||||
u32 pause_pkt2; |
||||
u32 pause_pkt3; |
||||
u32 pause_pkt4; |
||||
u32 pause_pkt5; |
||||
u32 reserve[2]; |
||||
struct pch_gbe_regs_mac_adr mac_adr[16]; |
||||
u32 addr_mask; |
||||
u32 miim; |
||||
u32 mac_addr_load; |
||||
u32 rgmii_st; |
||||
u32 rgmii_ctrl; |
||||
u32 reserve3[3]; |
||||
u32 dma_ctrl; |
||||
u32 reserve4[3]; |
||||
u32 rx_dsc_base; |
||||
u32 rx_dsc_size; |
||||
u32 rx_dsc_hw_p; |
||||
u32 rx_dsc_hw_p_hld; |
||||
u32 rx_dsc_sw_p; |
||||
u32 reserve5[3]; |
||||
u32 tx_dsc_base; |
||||
u32 tx_dsc_size; |
||||
u32 tx_dsc_hw_p; |
||||
u32 tx_dsc_hw_p_hld; |
||||
u32 tx_dsc_sw_p; |
||||
u32 reserve6[3]; |
||||
u32 rx_dma_st; |
||||
u32 tx_dma_st; |
||||
u32 reserve7[2]; |
||||
u32 wol_st; |
||||
u32 wol_ctrl; |
||||
u32 wol_addr_mask; |
||||
}; |
||||
|
||||
struct pch_gbe_priv { |
||||
struct pch_gbe_rx_desc rx_desc[PCH_GBE_DESC_NUM]; |
||||
struct pch_gbe_tx_desc tx_desc[PCH_GBE_DESC_NUM]; |
||||
char rx_buff[PCH_GBE_DESC_NUM][PCH_GBE_RX_FRAME_LEN]; |
||||
struct eth_device *dev; |
||||
struct phy_device *phydev; |
||||
struct mii_dev *bus; |
||||
struct pch_gbe_regs *mac_regs; |
||||
pci_dev_t bdf; |
||||
u32 interface; |
||||
int rx_idx; |
||||
int tx_idx; |
||||
}; |
||||
|
||||
#endif /* _PCH_GBE_H_ */ |
Loading…
Reference in new issue