813 lines
22 KiB
C
813 lines
22 KiB
C
/*
|
|
* comcerto_gem.c
|
|
* Mindspeed Comcerto GEMAC driver
|
|
*
|
|
* From TSEC.c
|
|
*
|
|
* This software may be used and distributed according to the
|
|
* terms of the GNU Public License, Version 2, incorporated
|
|
* herein by reference.
|
|
*
|
|
* Copyright 2004 Freescale Semiconductor.
|
|
* (C) Copyright 2003, Motorola, Inc.
|
|
* author Andy Fleming
|
|
*
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <config.h>
|
|
#include <asm/arch/hardware.h>
|
|
#include <asm/byteorder.h>
|
|
#include <malloc.h>
|
|
#include <net.h>
|
|
#include <command.h>
|
|
#include <miiphy.h>
|
|
|
|
#if defined(CONFIG_COMCERTO_GEMAC)
|
|
#include "comcerto_gem.h"
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
static struct gemac_info_struct gemac_info[] = {
|
|
#if defined(CONFIG_COMCERTO_900) || defined(CONFIG_COMCERTO_100)
|
|
{GEMAC_BASEADDR, MMGEM0_START, GEMAC0_PHY_ADDR, GEMAC0_CONFIG, GEMAC0_MODE, GEMAC0_PHY_FLAGS, GEMAC0_PHYIDX},
|
|
#elif defined(CONFIG_COMCERTO_1000)
|
|
{GEMAC_BASEADDR, GEMAC0_PHY_ADDR, GEMAC0_CONFIG, GEMAC0_MODE, GEMAC0_PHY_FLAGS, GEMAC0_PHYIDX},
|
|
#else
|
|
{0, 0, 0},
|
|
#endif
|
|
#if defined(CONFIG_COMCERTO_100)
|
|
{GEMAC1_BASEADDR, MMGEM1_START, GEMAC1_PHY_ADDR, GEMAC1_CONFIG, GEMAC1_MODE, GEMAC1_PHY_FLAGS, GEMAC1_PHYIDX},
|
|
#elif defined(CONFIG_COMCERTO_1000)
|
|
{GEMAC1_BASEADDR, GEMAC1_PHY_ADDR, GEMAC1_CONFIG, GEMAC1_MODE, GEMAC1_PHY_FLAGS, GEMAC1_PHYIDX},
|
|
#else
|
|
{0, 0, 0},
|
|
#endif
|
|
};
|
|
|
|
#define MAX_GEMACS 2
|
|
|
|
static struct gemac_dev *gemac_list[MAX_GEMACS];
|
|
|
|
#define NUM_RX_DESC 16
|
|
#define MAX_RX_BUFF_SIZE 2048
|
|
|
|
static u32 rx_next;
|
|
|
|
#if defined(CONFIG_COMCERTO_100)
|
|
static u8 rx_ring_data_buff[NUM_RX_DESC * MAX_RX_BUFF_SIZE] __attribute((aligned(4)));
|
|
static struct fdesc rx_ring[NUM_RX_DESC] __attribute((aligned(16)));
|
|
static struct fdesc tx_fdesc __attribute((aligned(16)));
|
|
#else
|
|
static u8 rx_ring_data_buff[NUM_RX_DESC * MAX_RX_BUFF_SIZE] __attribute((aligned(16)));
|
|
static struct rx_desc rx_ring[NUM_RX_DESC] __attribute((aligned(16)));
|
|
static struct tx_desc tx_fdesc[2] __attribute((aligned(8)));
|
|
#endif
|
|
|
|
/* Initialize device structure. Returns success if PHY
|
|
* initialization succeeded (i.e. if it recognizes the PHY)
|
|
*/
|
|
|
|
static void default_speed_duplex(struct gemac_dev *gemac, int *speed, int *duplex)
|
|
{
|
|
switch (gemac->mode & GEM_CONF_SPEED_MASK) {
|
|
case GEM_CONF_SPEED_GEM_10M:
|
|
*speed = _10BASET;
|
|
break;
|
|
|
|
case GEM_CONF_SPEED_GEM_100M:
|
|
*speed = _100BASET;
|
|
break;
|
|
|
|
case GEM_CONF_SPEED_GEM_1G:
|
|
default:
|
|
*speed = _1000BASET;
|
|
break;
|
|
}
|
|
|
|
if (gemac->mode & GEM_CONF_DUPLEX_GEM_FULL)
|
|
*duplex = FULL;
|
|
else
|
|
*duplex = HALF;
|
|
}
|
|
|
|
static void gemt_reinit(struct gemac_dev *gemac, int speed, int duplex)
|
|
{
|
|
switch (speed) {
|
|
case _1000BASET:
|
|
printf("PHY 1000Mbit ");
|
|
gem_set_speed(gemac, SPEED_1000M);
|
|
break;
|
|
|
|
case _100BASET:
|
|
printf("PHY 100Mbit ");
|
|
gem_set_speed(gemac, SPEED_100M);
|
|
break;
|
|
|
|
default:
|
|
case _10BASET:
|
|
printf("PHY 10Mbit ");
|
|
gem_set_speed(gemac, SPEED_10M);
|
|
break;
|
|
}
|
|
|
|
switch (duplex) {
|
|
case FULL:
|
|
printf("FD\n");
|
|
gem_full_duplex(gemac);
|
|
break;
|
|
|
|
default:
|
|
case HALF:
|
|
printf("HD\n");
|
|
gem_half_duplex(gemac);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
|
|
|
static int gemt_PHY_timeout(struct gemac_dev *gemac, int timeout)
|
|
{
|
|
while (!gem_phy_man_idle(gemac)) {
|
|
|
|
if (timeout-- <= 0) {
|
|
printf("PHY MDIO read/write timeout\n");
|
|
return -1;
|
|
}
|
|
|
|
udelay(1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct gemac_dev *get_gemac(char *devname)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_GEMACS; i++) {
|
|
if (!strcmp(gemac_list[i]->dev->name, devname))
|
|
return gemac_list[i];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int comcerto_miiphy_write(char *devname, unsigned char addr, unsigned char reg, unsigned short value)
|
|
{
|
|
struct gemac_dev *gemac = get_gemac(devname);
|
|
|
|
if (!gemac) {
|
|
printf("Unknown device %s\n", devname);
|
|
return -1;
|
|
}
|
|
|
|
if ((addr > 31) || (reg > 31))
|
|
return -1;
|
|
|
|
gem_phy_man_wr(gemac, addr, reg, value);
|
|
if (gemt_PHY_timeout(gemac, MDIO_TIMEOUT))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int comcerto_miiphy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short *value)
|
|
{
|
|
struct gemac_dev *gemac = get_gemac(devname);
|
|
|
|
if (!gemac) {
|
|
printf("Unknown device %s\n", devname);
|
|
return -1;
|
|
}
|
|
|
|
if ((addr > 31) || (reg > 31))
|
|
return -1;
|
|
|
|
gem_phy_man_rd(gemac, addr, reg);
|
|
if (gemt_PHY_timeout(gemac, MDIO_TIMEOUT))
|
|
return -1;
|
|
|
|
*value = gem_phy_man_data(gemac);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*=============================================================================
|
|
*
|
|
* NAME: gemt_config_PHY
|
|
*
|
|
* PARAMETERS:
|
|
* net_device *dev -INOUT
|
|
*
|
|
* DESCRIPTION
|
|
* Reconfigure PHY
|
|
* This function will set up the PHY device. This is a required external
|
|
* support routine.
|
|
* The parameters set up the maximum desired advertised ability for the
|
|
* device.
|
|
* TODO - read back negotiated ability and set MAC appropriately.
|
|
* duplex configuration to be done.
|
|
*
|
|
* ASSUMPTIONS
|
|
* None
|
|
*
|
|
* SIDE EFFECTS / STATIC DATA USE
|
|
* None
|
|
*
|
|
* RETURNS:
|
|
* int 0 -successful
|
|
* <0 -failed
|
|
*
|
|
*===========================================================================*/
|
|
static int gemt_config_PHY(struct gemac_dev *gemac, int phy_addr, MAC_SPEED speed, u8 duplex)
|
|
{
|
|
unsigned short anar, bmcr, btcr;
|
|
|
|
if (gemac->phyflags & GEMAC_M88E1111_PHY_RGMII_ADD_DELAY) {
|
|
unsigned short tmp;
|
|
|
|
if (!miiphy_read(gemac->dev->name, phy_addr, 20, &tmp)) {
|
|
tmp |= 0x82;
|
|
miiphy_write(gemac->dev->name, phy_addr, 20, tmp);
|
|
}
|
|
}
|
|
|
|
if (miiphy_reset(gemac->dev->name, gemac->phyaddr))
|
|
return -1;
|
|
|
|
switch (speed) {
|
|
case _10BASET:
|
|
if (duplex == FULL) {
|
|
anar = PHY_ANAR_10FD | PHY_ANAR_10;
|
|
btcr = 0x0;
|
|
bmcr = PHY_BMCR_DPLX | PHY_BMCR_10_MBPS;
|
|
} else {
|
|
anar = PHY_ANAR_10;
|
|
btcr = 0x0;
|
|
bmcr = PHY_BMCR_10_MBPS;
|
|
}
|
|
|
|
break;
|
|
|
|
case _100BASET:
|
|
default:
|
|
if (duplex == FULL) {
|
|
anar = PHY_ANAR_TXFD | PHY_ANAR_TX | PHY_ANAR_10FD | PHY_ANAR_10;
|
|
btcr = 0x0;
|
|
bmcr = PHY_BMCR_DPLX | PHY_BMCR_100_MBPS;
|
|
} else {
|
|
anar = PHY_ANAR_TX | PHY_ANAR_10;
|
|
btcr = 0x0;
|
|
bmcr = PHY_BMCR_100_MBPS;
|
|
}
|
|
|
|
break;
|
|
|
|
case _1000BASET:
|
|
if (duplex == FULL) {
|
|
anar = PHY_ANAR_TXFD | PHY_ANAR_TX | PHY_ANAR_10FD | PHY_ANAR_10;
|
|
btcr = PHY_1000BTCR_1000FD | PHY_1000BTCR_1000HD;
|
|
bmcr = PHY_BMCR_DPLX | PHY_BMCR_1000_MBPS;
|
|
} else {
|
|
anar = PHY_ANAR_TX | PHY_ANAR_10;
|
|
btcr = PHY_1000BTCR_1000HD;
|
|
bmcr = PHY_BMCR_1000_MBPS;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (gemac->phyflags & GEMAC_PHY_AUTONEG) {
|
|
if (miiphy_write(gemac->dev->name, phy_addr, PHY_ANAR, anar | PHY_ANAR_PSB_802_3))
|
|
return -1;
|
|
|
|
if (miiphy_supports_1000base_t(gemac->dev->name, phy_addr)) {
|
|
if (miiphy_write(gemac->dev->name, phy_addr, PHY_1000BTCR, btcr))
|
|
return -1;
|
|
}
|
|
|
|
if (miiphy_write(gemac->dev->name, phy_addr, PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG | bmcr))
|
|
return -1;
|
|
} else {
|
|
if (miiphy_write(gemac->dev->name, phy_addr, PHY_BMCR, bmcr))
|
|
return -1;
|
|
}
|
|
|
|
#if defined(CONFIG_GPHY_AR8035_DELAY_TUNING)
|
|
config_emac_phy_delay(phy_addr);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
|
|
|
|
/*=============================================================================
|
|
*
|
|
* NAME: gemt_reset_gem
|
|
*
|
|
* PARAMETERS:
|
|
* net_device *dev -INOUT
|
|
*
|
|
* DESCRIPTION
|
|
* Reset MAC hardware
|
|
* This function will reset MAC hardware after stop the MAC for both
|
|
* transmission and reception.
|
|
*
|
|
* ASSUMPTIONS
|
|
* None
|
|
*
|
|
* SIDE EFFECTS / STATIC DATA USE
|
|
* None
|
|
*
|
|
* RETURNS:
|
|
* None
|
|
*
|
|
*===========================================================================*/
|
|
static void gemt_reset_gem(struct gemac_dev *gemac)
|
|
{
|
|
gem_abort_tx(gemac);
|
|
gem_disable_rx(gemac);
|
|
|
|
gem_mask_irq(gemac, GEM_IRQ_ALL);
|
|
gem_get_irq_stat(gemac);
|
|
|
|
if (gem_reset(gemac) != 0)
|
|
printf("Failed to reset device!\n");
|
|
}
|
|
|
|
#if defined(CONFIG_COMCERTO_100)
|
|
static void gemac_rx_ring_init(struct gemac_dev *gemac)
|
|
{
|
|
u32 i;
|
|
u8 *pU8 = rx_ring_data_buff;
|
|
|
|
for (i = 0; i < NUM_RX_DESC - 1; i++) {
|
|
rx_ring[i].next = (void *)(__cpu_to_le32((u32)&(rx_ring[i + 1])));
|
|
rx_ring[i].system = __cpu_to_le32(i);
|
|
rx_ring[i].fstatus = __cpu_to_le32(0);
|
|
rx_ring[i].fcontrol = __cpu_to_le32(IDMA_FCONTROL_FREADY);
|
|
rx_ring[i].bdesc.bptr = (volatile u8 *)(__cpu_to_le32((u32)pU8));
|
|
rx_ring[i].bdesc.bcontrol = __cpu_to_le32(0);
|
|
pU8 += MAX_RX_BUFF_SIZE;
|
|
}
|
|
|
|
rx_ring[i].next = (void *)(__cpu_to_le32((u32)&(rx_ring[0])));
|
|
rx_ring[i].system = __cpu_to_le32(i);
|
|
rx_ring[i].fstatus = __cpu_to_le32(0);
|
|
rx_ring[i].fcontrol = __cpu_to_le32(0);
|
|
rx_ring[i].bdesc.bptr = (volatile u8 *)(__cpu_to_le32((u32)pU8));
|
|
rx_ring[i].bdesc.bcontrol = __cpu_to_le32(0);
|
|
|
|
rx_next = 0;
|
|
}
|
|
|
|
static int gemac_send(struct eth_device *dev, volatile void *packet, int length)
|
|
{
|
|
struct gemac_dev *gemac = (struct gemac_dev *)dev->priv;
|
|
int i;
|
|
|
|
if (length <= 0) {
|
|
printf("Comcerto_Emac: bad packet size: %d\n", length);
|
|
return (-1);
|
|
}
|
|
|
|
memset(&tx_fdesc, 0, sizeof(struct fdesc));
|
|
|
|
// build the tx frame descriptor here
|
|
tx_fdesc.fcontrol = __cpu_to_le32(IDMA_FCONTROL_FREADY | IDMA_FCONTROL_FLAST);
|
|
tx_fdesc.fstatus = __cpu_to_le32(0);
|
|
tx_fdesc.bdesc.bptr = (volatile u8 *)(__cpu_to_le32((u32)((u8 *)packet)));
|
|
tx_fdesc.bdesc.bcontrol = __cpu_to_le32(length | IDMA_BCONTROL_BLAST);
|
|
|
|
// Check if DMA Stopped
|
|
if (!(*(volatile u32 *)(gemac->idma_baseaddr + MMEM_START) & __cpu_to_le32(IDMA_START))) {
|
|
*(volatile u32 *)(gemac->idma_baseaddr + MMEM_HEAD) = __cpu_to_le32((u32) &tx_fdesc);
|
|
*(volatile u32 *)(gemac->idma_baseaddr + MMEM_START) |= __cpu_to_le32(IDMA_START);
|
|
} else {
|
|
printf("Emac: tx EDMA busy!\n");
|
|
return (-1);
|
|
}
|
|
|
|
i = 0;
|
|
while ((tx_fdesc.fstatus & __cpu_to_le32(IDMA_FSTATUS_FRAME_DONE_MASK)) == 0) {
|
|
udelay(100);
|
|
i++;
|
|
if (i == 50000) {
|
|
printf("Emac: tx timed out!\n");
|
|
return (-1);
|
|
}
|
|
}
|
|
|
|
if (*(volatile u32 *)(gemac->idma_baseaddr + MMEM_START) & __cpu_to_le32(IDMA_START)) {
|
|
printf("Error! Emac: tx did not stop after sending a packet!\n");
|
|
}
|
|
|
|
return (length);
|
|
}
|
|
|
|
static int gemac_recv(struct eth_device *dev)
|
|
{
|
|
struct gemac_dev *gemac = (struct gemac_dev *)dev->priv;
|
|
int rx_prev;
|
|
int length;
|
|
int total_length = 0;
|
|
|
|
// loop thru rx FDescs
|
|
while (1) {
|
|
if ((rx_ring[rx_next].fstatus & __cpu_to_le32(IDMA_FSTATUS_FRAME_DONE_MASK)) == 0)
|
|
break;
|
|
|
|
// mark rx_next not usable
|
|
rx_ring[rx_next].fcontrol = __cpu_to_le32(0);
|
|
|
|
length = __le32_to_cpu(rx_ring[rx_next].bdesc.bcontrol) & 0x0000ffff;
|
|
if (length > MAX_RX_BUFF_SIZE) {
|
|
printf("Comcerto_Emac: frame too big (%d bytes)!\n", length);
|
|
length = MAX_RX_BUFF_SIZE;
|
|
}
|
|
|
|
// Pass the packet up to the protocol layers.
|
|
NetReceive((volatile uchar *)(__le32_to_cpu((u32)(rx_ring[rx_next].bdesc.bptr))), length);
|
|
total_length += length;
|
|
|
|
// rx_prev can be used now
|
|
if (rx_next == 0)
|
|
rx_prev = NUM_RX_DESC - 1;
|
|
else
|
|
rx_prev = rx_next - 1;
|
|
|
|
rx_ring[rx_prev].fstatus = __cpu_to_le32(0);
|
|
rx_ring[rx_prev].fcontrol = __cpu_to_le32(IDMA_FCONTROL_FREADY);
|
|
|
|
rx_next++;
|
|
if (rx_next == NUM_RX_DESC)
|
|
rx_next = 0;
|
|
}
|
|
|
|
// Check if DMA Stopped
|
|
// if RX is stopped, restart
|
|
if (!(*(volatile u32 *)(gemac->idma_baseaddr + EMMM_START) & __cpu_to_le32(IDMA_START))) {
|
|
*(volatile u32 *)(gemac->idma_baseaddr + EMMM_HEAD) = __cpu_to_le32((u32) (&(rx_ring[rx_next])));
|
|
*(volatile u32 *)(gemac->idma_baseaddr + EMMM_START) |= __cpu_to_le32(IDMA_START);
|
|
}
|
|
|
|
return (total_length);
|
|
}
|
|
|
|
/* Stop the interface */
|
|
static void gemac_halt(struct eth_device *dev)
|
|
{
|
|
struct gemac_dev *gemac = (struct gemac_dev *)dev->priv;
|
|
|
|
*(volatile u32 *)(gemac->idma_baseaddr + MMEM_SOFT_RESET) = __cpu_to_le32(1);
|
|
*(volatile u32 *)(gemac->idma_baseaddr + EMMM_SOFT_RESET) = __cpu_to_le32(1);
|
|
|
|
gem_stop_tx(gemac);
|
|
gem_disable_rx(gemac);
|
|
}
|
|
|
|
#else
|
|
static void gemac_rx_ring_init(struct gemac_dev *gemac)
|
|
{
|
|
u8 *pU8;
|
|
int i;
|
|
|
|
// printf("%s()\n", __func__);
|
|
|
|
memset(rx_ring, 0, NUM_RX_DESC * sizeof(struct rx_desc));
|
|
pU8 = rx_ring_data_buff;
|
|
|
|
for (i = 0; i < NUM_RX_DESC - 1; i++) {
|
|
rx_ring[i].data = (volatile u8 *)(__cpu_to_le32((u32)pU8));
|
|
pU8 += MAX_RX_BUFF_SIZE;
|
|
}
|
|
|
|
rx_ring[i].data = (volatile u8 *)(__cpu_to_le32((u32)pU8));
|
|
rx_ring[i].status |= __cpu_to_le32(GEMRX_WRAP); // last descriptor in the list
|
|
rx_next = 0;
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_IP + GEM_RX_QPTR) = __cpu_to_le32((u32)rx_ring);
|
|
}
|
|
|
|
static int gemac_send(struct eth_device *dev, volatile void *packet, int length)
|
|
{
|
|
struct gemac_dev *gemac = (struct gemac_dev *)dev->priv;
|
|
int i, rc = -1;
|
|
|
|
if (length <= 0) {
|
|
printf("Comcerto_Emac: bad packet size: %d\n", length);
|
|
return (-1);
|
|
}
|
|
|
|
// build the tx frame descriptor here
|
|
memset(&tx_fdesc, 0, 2 * sizeof(struct tx_desc));
|
|
|
|
tx_fdesc[0].ctl |= __cpu_to_le32(TX_DESC_WORD1_LAST | TX_DESC_WORD1_FCS);
|
|
tx_fdesc[0].data = (volatile u8 *)(__cpu_to_le32((u32)packet));
|
|
tx_fdesc[0].ctl |= __cpu_to_le32(length & TX_DESC_WORD1_LEGTH_MASK);
|
|
tx_fdesc[1].ctl |= __cpu_to_le32(TX_DESC_WORD1_WRAP | TX_DESC_WORD1_USED);
|
|
|
|
// just enable queue0, let the other queues uninitialized
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_IP + GEM_QUEUE_BASE0) = __cpu_to_le32((u32)&tx_fdesc[0]);
|
|
|
|
gem_start_tx(gemac);
|
|
// Notify scheduler
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_SCH_PKT_QUEUED) = __cpu_to_le32((u32) length);
|
|
|
|
i = 0;
|
|
while ((tx_fdesc[0].ctl & __cpu_to_le32(TX_DESC_WORD1_USED)) == 0) {
|
|
udelay(100);
|
|
i++;
|
|
if (i == 50000) {
|
|
printf("Emac: tx timed out!\n");
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
rc = length;
|
|
// printf("gemac_send done \n");
|
|
out:
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int gemac_recv(struct eth_device *dev)
|
|
{
|
|
int length = 0;
|
|
int total_length = 0;
|
|
u32 rx_status;
|
|
u32 rx_data;
|
|
u32 rx_extstatus;
|
|
|
|
// loop thru rx FDescs
|
|
while (1) {
|
|
|
|
rx_extstatus = rx_ring[rx_next].extstatus;
|
|
if (((rx_extstatus & __cpu_to_le32(GEMRX_OWN)) == 0)) {
|
|
// printf("done %d index %d\n",total_length, rx_next);
|
|
break;
|
|
}
|
|
|
|
rx_data = __le32_to_cpu(rx_ring[rx_next].data);
|
|
rx_status = __le32_to_cpu(rx_ring[rx_next].status);
|
|
length = (rx_status & RX_STA_LEN_MASK) /*>>RX_STA_LEN_POS */ ;
|
|
|
|
// Pass the packet up to the protocol layers.
|
|
if (!(rx_status & RX_CHECK_ERROR)) {
|
|
NetReceive((u8 *)rx_data, length);
|
|
total_length += length;
|
|
}
|
|
|
|
//clear bits... the buffer can be reused
|
|
rx_ring[rx_next].status &= __cpu_to_le32(GEMRX_WRAP);
|
|
rx_ring[rx_next].extstatus = __cpu_to_le32(0);
|
|
length = 0;
|
|
|
|
rx_next++;
|
|
if (rx_next == NUM_RX_DESC)
|
|
rx_next = 0;
|
|
}
|
|
|
|
return (total_length);
|
|
}
|
|
|
|
/* Stop the interface */
|
|
static void gemac_halt(struct eth_device *dev)
|
|
{
|
|
struct gemac_dev *gemac = (struct gemac_dev *)dev->priv;
|
|
|
|
// printf("%s()\n", __func__);
|
|
|
|
gem_stop_tx(gemac);
|
|
gem_abort_tx(gemac);
|
|
gem_disable_rx(gemac);
|
|
}
|
|
#endif
|
|
|
|
#if (!defined(CONFIG_COMCERTO_1000) && (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)))
|
|
int miiphy_speed_duplex (char *devname, unsigned char addr, int *speed, int *duplex)
|
|
{
|
|
*speed = miiphy_speed (devname, addr);
|
|
*duplex = miiphy_duplex (devname, addr);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/* Initializes data structures and registers for the controller,
|
|
* and brings the interface up. Returns the link status, meaning
|
|
* that it returns success if the link is up, failure otherwise.
|
|
* This allows u-boot to find the first active controller. */
|
|
static int gemac_init(struct eth_device *dev, bd_t * bd)
|
|
{
|
|
struct gemac_dev *gemac = (struct gemac_dev *)dev->priv;
|
|
MAC_ADDR enet_addr;
|
|
int speed = _1000BASET, duplex = FULL;
|
|
|
|
// printf("%s()\n", __func__);
|
|
|
|
/* Make sure the controller is stopped */
|
|
gemac_halt(dev);
|
|
|
|
default_speed_duplex(gemac, &speed, &duplex);
|
|
|
|
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
|
if (!(gemac->phyflags & GEMAC_NO_PHY))
|
|
if (miiphy_speed_duplex(gemac->dev->name, gemac->phyaddr, &speed, &duplex))
|
|
return -1;
|
|
#endif /* defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
|
|
|
|
gemt_reinit(gemac, speed, duplex);
|
|
|
|
gem_disable_copy_all(gemac);
|
|
gem_allow_broadcast(gemac);
|
|
gem_enable_unicast(gemac);
|
|
gem_disable_multicast(gemac);
|
|
gem_disable_fcs_rx(gemac);
|
|
|
|
gem_enet_addr_byte_mac(dev->enetaddr, &enet_addr);
|
|
gem_set_laddr1(gemac, &enet_addr);
|
|
|
|
gemac_rx_ring_init(gemac);
|
|
|
|
/* Ready the device for tx/rx */
|
|
gem_start_tx(gemac);
|
|
gem_enable_rx(gemac);
|
|
|
|
return (1);
|
|
}
|
|
|
|
int comcerto_gemac_initialize(bd_t * bis, int index, char *devname)
|
|
{
|
|
struct eth_device *dev;
|
|
struct gemac_dev *gemac;
|
|
int i;
|
|
|
|
dev = (struct eth_device *)malloc(sizeof(struct eth_device));
|
|
if (!dev)
|
|
return -1;
|
|
|
|
memset(dev, 0, sizeof(struct eth_device));
|
|
|
|
gemac = (struct gemac_dev *)malloc(sizeof(struct gemac_dev));
|
|
if (!gemac)
|
|
return -1;
|
|
|
|
gemac_list[index] = gemac;
|
|
gemac->baseaddr = (void *)gemac_info[index].baseaddr;
|
|
gemac->registers = (void *)(gemac_info[index].baseaddr + GEM_IP);
|
|
gemac->phyregisters = (void *)(gemac_info[gemac_info[index].phyregidx].baseaddr + GEM_IP);
|
|
gemac->phyaddr = gemac_info[index].phyaddr;
|
|
gemac->mode = gemac_info[index].mode;
|
|
|
|
#if defined(CONFIG_COMCERTO_100)
|
|
gemac->idma_baseaddr = (void *)(gemac_info[index].idma_baseaddr);
|
|
#endif
|
|
gemac->phyflags = gemac_info[index].phyflags;
|
|
sprintf(dev->name, devname);
|
|
dev->iobase = 0;
|
|
dev->priv = gemac;
|
|
gemac->dev = dev;
|
|
dev->init = gemac_init;
|
|
dev->halt = gemac_halt;
|
|
dev->send = gemac_send;
|
|
dev->recv = gemac_recv;
|
|
|
|
/* Tell u-boot to get the addr from the env */
|
|
for (i = 0; i < 6; i++)
|
|
dev->enetaddr[i] = 0;
|
|
|
|
eth_register(dev);
|
|
|
|
/* put gemac out of reset */
|
|
#if defined(CONFIG_COMCERTO_100)
|
|
{
|
|
// TODO: please cleanup need centralize the reset bock
|
|
volatile int delay_count;
|
|
|
|
// get GEMAC out of reset
|
|
*(volatile u32 *)(BLOCK_RESET_REG) |= __cpu_to_le32(GEMAC0_RST << index);
|
|
// 20 ops delay
|
|
delay_count = 20;
|
|
while (delay_count--) ;
|
|
}
|
|
#else
|
|
{
|
|
// TODO: please cleanup need centralize the reset bock
|
|
volatile int delay_count;
|
|
|
|
// get GEMAC out of reset
|
|
*(volatile u32 *)(CLKCORE_BLK_RESET) |=
|
|
__cpu_to_le32((BLK_RESET_GEMAC0_AHB_RESET_N << index) | (BLK_RESET_GEMAC0_REF_RESET_N << index));
|
|
// 20 ops delay
|
|
delay_count = 20;
|
|
while (delay_count--) ;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(CONFIG_COMCERTO_MII_CFG_BOOTSTRAP)
|
|
// software config
|
|
switch (gemac_info[index].gemacconfig) {
|
|
case CONFIG_COMCERTO_USE_GMII:
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_CFG) = __cpu_to_le32(gemac->mode | GEM_CONF_MODE_SEL_GEM | GEM_CONF_MODE_GEM_GMII);
|
|
break;
|
|
case CONFIG_COMCERTO_USE_RGMII:
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_CFG) = __cpu_to_le32(gemac->mode | GEM_CONF_MODE_SEL_GEM | GEM_CONF_MODE_GEM_RGMII);
|
|
break;
|
|
case CONFIG_COMCERTO_USE_RMII:
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_CFG) = __cpu_to_le32(gemac->mode | GEM_CONF_MODE_SEL_GEM | GEM_CONF_MODE_GEM_RMII);
|
|
break;
|
|
case CONFIG_COMCERTO_USE_MII:
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_CFG) = __cpu_to_le32(gemac->mode | GEM_CONF_MODE_SEL_GEM | GEM_CONF_MODE_GEM_MII);
|
|
break;
|
|
default:
|
|
printf("comcerto gemac software config requires one MII mode defined %d\n");
|
|
return (-1);
|
|
}
|
|
#else
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_CFG) = __cpu_to_le32(gemac->mode);
|
|
#endif
|
|
|
|
#if defined(CONFIG_COMCERTO_1000)
|
|
if ((gemac->phyflags & GEMAC_GEM_DELAY_DISABLE))
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_DELAY_ELEMENT_CTRL) = __cpu_to_le32(0);
|
|
#endif
|
|
|
|
#if defined(CONFIG_COMCERTO_100)
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_TX_CTRL) = __cpu_to_le32(GEM_TXCTRL_DMAIF_EN | GEM_TXCTRL_CRC_EN | GEM_TXCTRL_RETR_EN);
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_RX_CTRL) = __cpu_to_le32(GEM_RXCTRL_DMAIF_EN);
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_RX_STAT_PKTSIZE) = __cpu_to_le32(0x100);
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_ARM_FIFO_CTRL) = __cpu_to_le32(ARM_FIFO_RXDREQWE | ARM_FIFO_TXDREQRE);
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_ARM_RX_FIFO_HIGH) = __cpu_to_le32(0x1D0);
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_ARM_RX_FIFO_LOW) = __cpu_to_le32(0x180);
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_RX_FIFO_HIGH) = __cpu_to_le32(0x1CD);
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_FIFO_CTRL) = __cpu_to_le32(GEM_FIFO_CTRL_TXFF_EN | GEM_FIFO_CTRL_HBTXRQ_EN | GEM_FIFO_CTRL_RXFF_EN | GEM_FIFO_CTRL_HBRXRQ_EN);
|
|
#else
|
|
/* configure DMA register */
|
|
/* enable scheduler */
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_IP + GEM_DMA_CONFIG) |= __cpu_to_le32((1UL << 31));
|
|
|
|
/* Master enable scheduler block*/
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_SCH_CTL) |= __cpu_to_le32(1UL);
|
|
|
|
/* enable 16 bytes aligned bursts */
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_IP + GEM_DMA_CONFIG) |= __cpu_to_le32((1UL << 27));
|
|
|
|
/* enable software buffer allocation (legacy mode) */
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_IP + GEM_DMA_CONFIG) |= __cpu_to_le32((1UL << 26));
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_IP + GEM_DMA_CONFIG) |= __cpu_to_le32((1UL << 25));
|
|
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_IP + GEM_DMA_CONFIG) &= __cpu_to_le32(~(0x00FF001F));
|
|
|
|
/* set buffer size to 2048 bytes */
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_IP + GEM_DMA_CONFIG) |= __cpu_to_le32(0x00200000);
|
|
|
|
/* attempt to use INCR16 AHB bursts */
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_IP + GEM_DMA_CONFIG) |= __cpu_to_le32(0x00000010);
|
|
|
|
/* disable admittance manager */
|
|
*(volatile u32 *)(gemac->baseaddr + GEM_IP + GEM_DMA_CONFIG) &= __cpu_to_le32(~(1UL << 12));
|
|
|
|
/* disable admittance master config bit */
|
|
*(volatile u32 *)(gemac->baseaddr + ADMITTANCE + ADM_CFG) &= ~(1UL);
|
|
|
|
#endif
|
|
/* Reset the MAC */
|
|
gemt_reset_gem(gemac);
|
|
|
|
if (index == 0) {
|
|
#if defined(CONFIG_COMCERTO_100)
|
|
/* todo remove this from this file */
|
|
// set ephy divider and switch to ref clk (25Mhz)
|
|
*(volatile u32 *)(CLKCORE_CLKDIV_CNTRL) &= __cpu_to_le32(~(0x1F << EPHY_CLKDIV_RATIO_SHIFT));
|
|
*(volatile u32 *)(CLKCORE_CLKDIV_CNTRL) |= __cpu_to_le32(((CFG_ARM_CLOCK / 25000000) << EPHY_CLKDIV_RATIO_SHIFT));
|
|
*(volatile u32 *)(CLKCORE_CLKDIV_CNTRL) &= __cpu_to_le32(~EPHY_CLKDIV_BYPASS);
|
|
#endif
|
|
reset_emac0_phy(1);
|
|
}
|
|
|
|
if (index == 1) {
|
|
reset_emac1_phy(1);
|
|
}
|
|
|
|
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
|
gem_enable_MDIO(gemac);
|
|
|
|
if (!(gemac->phyflags & GEMAC_NO_PHY)) {
|
|
int speed, duplex;
|
|
|
|
miiphy_register(dev->name, comcerto_miiphy_read, comcerto_miiphy_write);
|
|
|
|
default_speed_duplex(gemac, &speed, &duplex);
|
|
|
|
if (gemt_config_PHY(gemac, gemac->phyaddr, speed, duplex))
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* CONFIG_COMCERTO_GEMAC */
|