|
|
|
@ -40,17 +40,21 @@ |
|
|
|
|
|
|
|
|
|
#include "macb.h" |
|
|
|
|
|
|
|
|
|
#define CONFIG_SYS_MACB_RX_BUFFER_SIZE 4096 |
|
|
|
|
#define CONFIG_SYS_MACB_RX_RING_SIZE (CONFIG_SYS_MACB_RX_BUFFER_SIZE / 128) |
|
|
|
|
#define CONFIG_SYS_MACB_TX_RING_SIZE 16 |
|
|
|
|
#define CONFIG_SYS_MACB_TX_TIMEOUT 1000 |
|
|
|
|
#define CONFIG_SYS_MACB_AUTONEG_TIMEOUT 5000000 |
|
|
|
|
#define MACB_RX_BUFFER_SIZE 4096 |
|
|
|
|
#define MACB_RX_RING_SIZE (MACB_RX_BUFFER_SIZE / 128) |
|
|
|
|
#define MACB_TX_RING_SIZE 16 |
|
|
|
|
#define MACB_TX_TIMEOUT 1000 |
|
|
|
|
#define MACB_AUTONEG_TIMEOUT 5000000 |
|
|
|
|
|
|
|
|
|
struct macb_dma_desc { |
|
|
|
|
u32 addr; |
|
|
|
|
u32 ctrl; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#define DMA_DESC_BYTES(n) (n * sizeof(struct macb_dma_desc)) |
|
|
|
|
#define MACB_TX_DMA_DESC_SIZE (DMA_DESC_BYTES(MACB_TX_RING_SIZE)) |
|
|
|
|
#define MACB_RX_DMA_DESC_SIZE (DMA_DESC_BYTES(MACB_RX_RING_SIZE)) |
|
|
|
|
|
|
|
|
|
#define RXADDR_USED 0x00000001 |
|
|
|
|
#define RXADDR_WRAP 0x00000002 |
|
|
|
|
|
|
|
|
@ -170,7 +174,7 @@ int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value) |
|
|
|
|
struct eth_device *dev = eth_get_dev_by_name(devname); |
|
|
|
|
struct macb_device *macb = to_macb(dev); |
|
|
|
|
|
|
|
|
|
if ( macb->phy_addr != phy_adr ) |
|
|
|
|
if (macb->phy_addr != phy_adr) |
|
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
arch_get_mdio_control(devname); |
|
|
|
@ -184,7 +188,7 @@ int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value) |
|
|
|
|
struct eth_device *dev = eth_get_dev_by_name(devname); |
|
|
|
|
struct macb_device *macb = to_macb(dev); |
|
|
|
|
|
|
|
|
|
if ( macb->phy_addr != phy_adr ) |
|
|
|
|
if (macb->phy_addr != phy_adr) |
|
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
arch_get_mdio_control(devname); |
|
|
|
@ -194,6 +198,39 @@ int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value) |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#define RX 1 |
|
|
|
|
#define TX 0 |
|
|
|
|
static inline void macb_invalidate_ring_desc(struct macb_device *macb, bool rx) |
|
|
|
|
{ |
|
|
|
|
if (rx) |
|
|
|
|
invalidate_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma + |
|
|
|
|
MACB_RX_DMA_DESC_SIZE); |
|
|
|
|
else |
|
|
|
|
invalidate_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma + |
|
|
|
|
MACB_TX_DMA_DESC_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static inline void macb_flush_ring_desc(struct macb_device *macb, bool rx) |
|
|
|
|
{ |
|
|
|
|
if (rx) |
|
|
|
|
flush_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma + |
|
|
|
|
MACB_RX_DMA_DESC_SIZE); |
|
|
|
|
else |
|
|
|
|
flush_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma + |
|
|
|
|
MACB_TX_DMA_DESC_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static inline void macb_flush_rx_buffer(struct macb_device *macb) |
|
|
|
|
{ |
|
|
|
|
flush_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma + |
|
|
|
|
MACB_RX_BUFFER_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static inline void macb_invalidate_rx_buffer(struct macb_device *macb) |
|
|
|
|
{ |
|
|
|
|
invalidate_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma + |
|
|
|
|
MACB_RX_BUFFER_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if defined(CONFIG_CMD_NET) |
|
|
|
|
|
|
|
|
@ -208,23 +245,28 @@ static int macb_send(struct eth_device *netdev, void *packet, int length) |
|
|
|
|
|
|
|
|
|
ctrl = length & TXBUF_FRMLEN_MASK; |
|
|
|
|
ctrl |= TXBUF_FRAME_END; |
|
|
|
|
if (tx_head == (CONFIG_SYS_MACB_TX_RING_SIZE - 1)) { |
|
|
|
|
if (tx_head == (MACB_TX_RING_SIZE - 1)) { |
|
|
|
|
ctrl |= TXBUF_WRAP; |
|
|
|
|
macb->tx_head = 0; |
|
|
|
|
} else |
|
|
|
|
} else { |
|
|
|
|
macb->tx_head++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
macb->tx_ring[tx_head].ctrl = ctrl; |
|
|
|
|
macb->tx_ring[tx_head].addr = paddr; |
|
|
|
|
barrier(); |
|
|
|
|
macb_flush_ring_desc(macb, TX); |
|
|
|
|
/* Do we need check paddr and length is dcache line aligned? */ |
|
|
|
|
flush_dcache_range(paddr, paddr + length); |
|
|
|
|
macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART)); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* I guess this is necessary because the networking core may |
|
|
|
|
* re-use the transmit buffer as soon as we return... |
|
|
|
|
*/ |
|
|
|
|
for (i = 0; i <= CONFIG_SYS_MACB_TX_TIMEOUT; i++) { |
|
|
|
|
for (i = 0; i <= MACB_TX_TIMEOUT; i++) { |
|
|
|
|
barrier(); |
|
|
|
|
macb_invalidate_ring_desc(macb, TX); |
|
|
|
|
ctrl = macb->tx_ring[tx_head].ctrl; |
|
|
|
|
if (ctrl & TXBUF_USED) |
|
|
|
|
break; |
|
|
|
@ -233,7 +275,7 @@ static int macb_send(struct eth_device *netdev, void *packet, int length) |
|
|
|
|
|
|
|
|
|
dma_unmap_single(packet, length, paddr); |
|
|
|
|
|
|
|
|
|
if (i <= CONFIG_SYS_MACB_TX_TIMEOUT) { |
|
|
|
|
if (i <= MACB_TX_TIMEOUT) { |
|
|
|
|
if (ctrl & TXBUF_UNDERRUN) |
|
|
|
|
printf("%s: TX underrun\n", netdev->name); |
|
|
|
|
if (ctrl & TXBUF_EXHAUSTED) |
|
|
|
@ -253,10 +295,12 @@ static void reclaim_rx_buffers(struct macb_device *macb, |
|
|
|
|
unsigned int i; |
|
|
|
|
|
|
|
|
|
i = macb->rx_tail; |
|
|
|
|
|
|
|
|
|
macb_invalidate_ring_desc(macb, RX); |
|
|
|
|
while (i > new_tail) { |
|
|
|
|
macb->rx_ring[i].addr &= ~RXADDR_USED; |
|
|
|
|
i++; |
|
|
|
|
if (i > CONFIG_SYS_MACB_RX_RING_SIZE) |
|
|
|
|
if (i > MACB_RX_RING_SIZE) |
|
|
|
|
i = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -266,6 +310,7 @@ static void reclaim_rx_buffers(struct macb_device *macb, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
barrier(); |
|
|
|
|
macb_flush_ring_desc(macb, RX); |
|
|
|
|
macb->rx_tail = new_tail; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -279,6 +324,8 @@ static int macb_recv(struct eth_device *netdev) |
|
|
|
|
u32 status; |
|
|
|
|
|
|
|
|
|
for (;;) { |
|
|
|
|
macb_invalidate_ring_desc(macb, RX); |
|
|
|
|
|
|
|
|
|
if (!(macb->rx_ring[rx_tail].addr & RXADDR_USED)) |
|
|
|
|
return -1; |
|
|
|
|
|
|
|
|
@ -292,10 +339,12 @@ static int macb_recv(struct eth_device *netdev) |
|
|
|
|
if (status & RXBUF_FRAME_END) { |
|
|
|
|
buffer = macb->rx_buffer + 128 * macb->rx_tail; |
|
|
|
|
length = status & RXBUF_FRMLEN_MASK; |
|
|
|
|
|
|
|
|
|
macb_invalidate_rx_buffer(macb); |
|
|
|
|
if (wrapped) { |
|
|
|
|
unsigned int headlen, taillen; |
|
|
|
|
|
|
|
|
|
headlen = 128 * (CONFIG_SYS_MACB_RX_RING_SIZE |
|
|
|
|
headlen = 128 * (MACB_RX_RING_SIZE |
|
|
|
|
- macb->rx_tail); |
|
|
|
|
taillen = length - headlen; |
|
|
|
|
memcpy((void *)NetRxPackets[0], |
|
|
|
@ -306,11 +355,11 @@ static int macb_recv(struct eth_device *netdev) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
NetReceive(buffer, length); |
|
|
|
|
if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE) |
|
|
|
|
if (++rx_tail >= MACB_RX_RING_SIZE) |
|
|
|
|
rx_tail = 0; |
|
|
|
|
reclaim_rx_buffers(macb, rx_tail); |
|
|
|
|
} else { |
|
|
|
|
if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE) { |
|
|
|
|
if (++rx_tail >= MACB_RX_RING_SIZE) { |
|
|
|
|
wrapped = 1; |
|
|
|
|
rx_tail = 0; |
|
|
|
|
} |
|
|
|
@ -333,7 +382,7 @@ static void macb_phy_reset(struct macb_device *macb) |
|
|
|
|
macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE |
|
|
|
|
| BMCR_ANRESTART)); |
|
|
|
|
|
|
|
|
|
for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) { |
|
|
|
|
for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { |
|
|
|
|
status = macb_mdio_read(macb, MII_BMSR); |
|
|
|
|
if (status & BMSR_ANEGCOMPLETE) |
|
|
|
|
break; |
|
|
|
@ -385,9 +434,8 @@ static int macb_phy_init(struct macb_device *macb) |
|
|
|
|
arch_get_mdio_control(netdev->name); |
|
|
|
|
#ifdef CONFIG_MACB_SEARCH_PHY |
|
|
|
|
/* Auto-detect phy_addr */ |
|
|
|
|
if (!macb_phy_find(macb)) { |
|
|
|
|
if (!macb_phy_find(macb)) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
#endif /* CONFIG_MACB_SEARCH_PHY */ |
|
|
|
|
|
|
|
|
|
/* Check if the PHY is up to snuff... */ |
|
|
|
@ -414,7 +462,7 @@ static int macb_phy_init(struct macb_device *macb) |
|
|
|
|
/* Try to re-negotiate if we don't have link already. */ |
|
|
|
|
macb_phy_reset(macb); |
|
|
|
|
|
|
|
|
|
for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) { |
|
|
|
|
for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { |
|
|
|
|
status = macb_mdio_read(macb, MII_BMSR); |
|
|
|
|
if (status & BMSR_LSTATUS) |
|
|
|
|
break; |
|
|
|
@ -499,21 +547,28 @@ static int macb_init(struct eth_device *netdev, bd_t *bd) |
|
|
|
|
|
|
|
|
|
/* initialize DMA descriptors */ |
|
|
|
|
paddr = macb->rx_buffer_dma; |
|
|
|
|
for (i = 0; i < CONFIG_SYS_MACB_RX_RING_SIZE; i++) { |
|
|
|
|
if (i == (CONFIG_SYS_MACB_RX_RING_SIZE - 1)) |
|
|
|
|
for (i = 0; i < MACB_RX_RING_SIZE; i++) { |
|
|
|
|
if (i == (MACB_RX_RING_SIZE - 1)) |
|
|
|
|
paddr |= RXADDR_WRAP; |
|
|
|
|
macb->rx_ring[i].addr = paddr; |
|
|
|
|
macb->rx_ring[i].ctrl = 0; |
|
|
|
|
paddr += 128; |
|
|
|
|
} |
|
|
|
|
for (i = 0; i < CONFIG_SYS_MACB_TX_RING_SIZE; i++) { |
|
|
|
|
macb_flush_ring_desc(macb, RX); |
|
|
|
|
macb_flush_rx_buffer(macb); |
|
|
|
|
|
|
|
|
|
for (i = 0; i < MACB_TX_RING_SIZE; i++) { |
|
|
|
|
macb->tx_ring[i].addr = 0; |
|
|
|
|
if (i == (CONFIG_SYS_MACB_TX_RING_SIZE - 1)) |
|
|
|
|
if (i == (MACB_TX_RING_SIZE - 1)) |
|
|
|
|
macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP; |
|
|
|
|
else |
|
|
|
|
macb->tx_ring[i].ctrl = TXBUF_USED; |
|
|
|
|
} |
|
|
|
|
macb->rx_tail = macb->tx_head = macb->tx_tail = 0; |
|
|
|
|
macb_flush_ring_desc(macb, TX); |
|
|
|
|
|
|
|
|
|
macb->rx_tail = 0; |
|
|
|
|
macb->tx_head = 0; |
|
|
|
|
macb->tx_tail = 0; |
|
|
|
|
|
|
|
|
|
macb_writel(macb, RBQP, macb->rx_ring_dma); |
|
|
|
|
macb_writel(macb, TBQP, macb->tx_ring_dma); |
|
|
|
@ -654,15 +709,15 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr) |
|
|
|
|
|
|
|
|
|
netdev = &macb->netdev; |
|
|
|
|
|
|
|
|
|
macb->rx_buffer = dma_alloc_coherent(CONFIG_SYS_MACB_RX_BUFFER_SIZE, |
|
|
|
|
macb->rx_buffer = dma_alloc_coherent(MACB_RX_BUFFER_SIZE, |
|
|
|
|
&macb->rx_buffer_dma); |
|
|
|
|
macb->rx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_RX_RING_SIZE |
|
|
|
|
* sizeof(struct macb_dma_desc), |
|
|
|
|
macb->rx_ring = dma_alloc_coherent(MACB_RX_DMA_DESC_SIZE, |
|
|
|
|
&macb->rx_ring_dma); |
|
|
|
|
macb->tx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_TX_RING_SIZE |
|
|
|
|
* sizeof(struct macb_dma_desc), |
|
|
|
|
macb->tx_ring = dma_alloc_coherent(MACB_TX_DMA_DESC_SIZE, |
|
|
|
|
&macb->tx_ring_dma); |
|
|
|
|
|
|
|
|
|
/* TODO: we need check the rx/tx_ring_dma is dcache line aligned */ |
|
|
|
|
|
|
|
|
|
macb->regs = regs; |
|
|
|
|
macb->phy_addr = phy_addr; |
|
|
|
|
|
|
|
|
|