diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/Kconfig | 16 | ||||
-rw-r--r-- | drivers/net/fsl_mcdmafec.c | 691 | ||||
-rw-r--r-- | drivers/net/mcffec.c | 587 | ||||
-rw-r--r-- | drivers/net/mcfmii.c | 48 |
4 files changed, 688 insertions, 654 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 142a2c6953..01d087f229 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -278,6 +278,22 @@ config FTGMAC100 applications. +config MCFFEC + bool "ColdFire Ethernet Support" + depends on DM_ETH + select PHYLIB + help + This driver supports the network interface units in the + ColdFire family. + +config FSLDMAFEC + bool "ColdFire DMA Ethernet Support" + depends on DM_ETH + select PHYLIB + help + This driver supports the network interface units in the + ColdFire family. + config MVGBE bool "Marvell Orion5x/Kirkwood network interface support" depends on KIRKWOOD || ORION5X diff --git a/drivers/net/fsl_mcdmafec.c b/drivers/net/fsl_mcdmafec.c index b2936b78d7..7838fb5c10 100644 --- a/drivers/net/fsl_mcdmafec.c +++ b/drivers/net/fsl_mcdmafec.c @@ -5,6 +5,9 @@ * * (C) Copyright 2007 Freescale Semiconductor, Inc. * TsiChung Liew (Tsi-Chung.Liew@freescale.com) + * + * Conversion to DM + * (C) 2019 Angelo Dureghello <angelo.dureghello@timesys.com> */ #include <common.h> @@ -15,6 +18,10 @@ #include <net.h> #include <miiphy.h> #include <linux/mii.h> +#include <asm/immap.h> +#include <asm/fsl_mcdmafec.h> + +#include "MCD_dma.h" #undef ET_DEBUG #undef MII_DEBUG @@ -22,93 +29,94 @@ /* Ethernet Transmit and Receive Buffers */ #define DBUF_LENGTH 1520 #define PKT_MAXBUF_SIZE 1518 -#define PKT_MINBUF_SIZE 64 -#define PKT_MAXBLR_SIZE 1536 -#define LAST_PKTBUFSRX PKTBUFSRX - 1 -#define BD_ENET_RX_W_E (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY) -#define BD_ENET_TX_RDY_LST (BD_ENET_TX_READY | BD_ENET_TX_LAST) #define FIFO_ERRSTAT (FIFO_STAT_RXW | FIFO_STAT_UF | FIFO_STAT_OF) /* RxBD bits definitions */ #define BD_ENET_RX_ERR (BD_ENET_RX_LG | BD_ENET_RX_NO | BD_ENET_RX_CR | \ BD_ENET_RX_OV | BD_ENET_RX_TR) -#include <asm/immap.h> -#include <asm/fsl_mcdmafec.h> +DECLARE_GLOBAL_DATA_PTR; -#include "MCD_dma.h" +static void init_eth_info(struct fec_info_dma *info) +{ + /* setup Receive and Transmit buffer descriptor */ +#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM + static u32 tmp; -struct fec_info_dma fec_info[] = { -#ifdef CONFIG_SYS_FEC0_IOBASE - { - 0, /* index */ - CONFIG_SYS_FEC0_IOBASE, /* io base */ - CONFIG_SYS_FEC0_PINMUX, /* gpio pin muxing */ - CONFIG_SYS_FEC0_MIIBASE, /* mii base */ - -1, /* phy_addr */ - 0, /* duplex and speed */ - 0, /* phy name */ - 0, /* phyname init */ - 0, /* RX BD */ - 0, /* TX BD */ - 0, /* rx Index */ - 0, /* tx Index */ - 0, /* tx buffer */ - 0, /* initialized flag */ - (struct fec_info_dma *)-1, /* next */ - FEC0_RX_TASK, /* rxTask */ - FEC0_TX_TASK, /* txTask */ - FEC0_RX_PRIORITY, /* rxPri */ - FEC0_TX_PRIORITY, /* txPri */ - FEC0_RX_INIT, /* rxInit */ - FEC0_TX_INIT, /* txInit */ - 0, /* usedTbdIndex */ - 0, /* cleanTbdNum */ - }, -#endif -#ifdef CONFIG_SYS_FEC1_IOBASE - { - 1, /* index */ - CONFIG_SYS_FEC1_IOBASE, /* io base */ - CONFIG_SYS_FEC1_PINMUX, /* gpio pin muxing */ - CONFIG_SYS_FEC1_MIIBASE, /* mii base */ - -1, /* phy_addr */ - 0, /* duplex and speed */ - 0, /* phy name */ - 0, /* phy name init */ -#ifdef CONFIG_SYS_DMA_USE_INTSRAM - (cbd_t *)DBUF_LENGTH, /* RX BD */ + if (info->index == 0) + tmp = CONFIG_SYS_INIT_RAM_ADDR + 0x1000; + else + info->rxbd = (cbd_t *)DBUF_LENGTH; + + info->rxbd = (cbd_t *)((u32)info->rxbd + tmp); + tmp = (u32)info->rxbd; + info->txbd = + (cbd_t *)((u32)info->txbd + tmp + + (PKTBUFSRX * sizeof(cbd_t))); + tmp = (u32)info->txbd; + info->txbuf = + (char *)((u32)info->txbuf + tmp + + (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t))); + tmp = (u32)info->txbuf; #else - 0, /* RX BD */ + info->rxbd = + (cbd_t *)memalign(CONFIG_SYS_CACHELINE_SIZE, + (PKTBUFSRX * sizeof(cbd_t))); + info->txbd = + (cbd_t *)memalign(CONFIG_SYS_CACHELINE_SIZE, + (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t))); + info->txbuf = + (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH); #endif - 0, /* TX BD */ - 0, /* rx Index */ - 0, /* tx Index */ - 0, /* tx buffer */ - 0, /* initialized flag */ - (struct fec_info_dma *)-1, /* next */ - FEC1_RX_TASK, /* rxTask */ - FEC1_TX_TASK, /* txTask */ - FEC1_RX_PRIORITY, /* rxPri */ - FEC1_TX_PRIORITY, /* txPri */ - FEC1_RX_INIT, /* rxInit */ - FEC1_TX_INIT, /* txInit */ - 0, /* usedTbdIndex */ - 0, /* cleanTbdNum */ - } + +#ifdef ET_DEBUG + printf("rxbd %x txbd %x\n", (int)info->rxbd, (int)info->txbd); #endif -}; + info->phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32); +} + +static void fec_halt(struct udevice *dev) +{ + struct fec_info_dma *info = dev->priv; + volatile fecdma_t *fecp = (fecdma_t *)info->iobase; + int counter = 0xffff; + + /* issue graceful stop command to the FEC transmitter if necessary */ + fecp->tcr |= FEC_TCR_GTS; + + /* wait for graceful stop to register */ + while ((counter--) && (!(fecp->eir & FEC_EIR_GRA))) + ; + + /* Disable DMA tasks */ + MCD_killDma(info->tx_task); + MCD_killDma(info->rx_task); + + /* Disable the Ethernet Controller */ + fecp->ecr &= ~FEC_ECR_ETHER_EN; + + /* Clear FIFO status registers */ + fecp->rfsr &= FIFO_ERRSTAT; + fecp->tfsr &= FIFO_ERRSTAT; + + fecp->frst = 0x01000000; -static int fec_send(struct eth_device *dev, void *packet, int length); -static int fec_recv(struct eth_device *dev); -static int fec_init(struct eth_device *dev, bd_t * bd); -static void fec_halt(struct eth_device *dev); + /* Issue a reset command to the FEC chip */ + fecp->ecr |= FEC_ECR_RESET; + + /* wait at least 20 clock cycles */ + mdelay(10); + +#ifdef ET_DEBUG + printf("Ethernet task stopped\n"); +#endif +} #ifdef ET_DEBUG static void dbg_fec_regs(struct eth_device *dev) { struct fec_info_dma *info = dev->priv; - volatile fecdma_t *fecp = (fecdma_t *) (info->iobase); + volatile fecdma_t *fecp = (fecdma_t *)info->iobase; printf("=====\n"); printf("ievent %x - %x\n", (int)&fecp->eir, fecp->eir); @@ -149,9 +157,10 @@ static void dbg_fec_regs(struct eth_device *dev) } #endif -static void set_fec_duplex_speed(volatile fecdma_t * fecp, bd_t * bd, - int dup_spd) +static void set_fec_duplex_speed(volatile fecdma_t *fecp, int dup_spd) { + bd_t *bd = gd->bd; + if ((dup_spd >> 16) == FULL) { /* Set maximum frame length */ fecp->rcr = FEC_RCR_MAX_FL(PKT_MAXBUF_SIZE) | FEC_RCR_MII_MODE | @@ -177,153 +186,23 @@ static void set_fec_duplex_speed(volatile fecdma_t * fecp, bd_t * bd, } } -static int fec_send(struct eth_device *dev, void *packet, int length) -{ - struct fec_info_dma *info = dev->priv; - cbd_t *pTbd, *pUsedTbd; - u16 phyStatus; - - miiphy_read(dev->name, info->phy_addr, MII_BMSR, &phyStatus); - - /* process all the consumed TBDs */ - while (info->cleanTbdNum < CONFIG_SYS_TX_ETH_BUFFER) { - pUsedTbd = &info->txbd[info->usedTbdIdx]; - if (pUsedTbd->cbd_sc & BD_ENET_TX_READY) { -#ifdef ET_DEBUG - printf("Cannot clean TBD %d, in use\n", - info->cleanTbdNum); -#endif - return 0; - } - - /* clean this buffer descriptor */ - if (info->usedTbdIdx == (CONFIG_SYS_TX_ETH_BUFFER - 1)) - pUsedTbd->cbd_sc = BD_ENET_TX_WRAP; - else - pUsedTbd->cbd_sc = 0; - - /* update some indeces for a correct handling of the TBD ring */ - info->cleanTbdNum++; - info->usedTbdIdx = (info->usedTbdIdx + 1) % CONFIG_SYS_TX_ETH_BUFFER; - } - - /* Check for valid length of data. */ - if ((length > 1500) || (length <= 0)) { - return -1; - } - - /* Check the number of vacant TxBDs. */ - if (info->cleanTbdNum < 1) { - printf("No available TxBDs ...\n"); - return -1; - } - - /* Get the first TxBD to send the mac header */ - pTbd = &info->txbd[info->txIdx]; - pTbd->cbd_datlen = length; - pTbd->cbd_bufaddr = (u32) packet; - pTbd->cbd_sc |= BD_ENET_TX_LAST | BD_ENET_TX_TC | BD_ENET_TX_READY; - info->txIdx = (info->txIdx + 1) % CONFIG_SYS_TX_ETH_BUFFER; - - /* Enable DMA transmit task */ - MCD_continDma(info->txTask); - - info->cleanTbdNum -= 1; - - /* wait until frame is sent . */ - while (pTbd->cbd_sc & BD_ENET_TX_READY) { - udelay(10); - } - - return (int)(info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_STATS); -} - -static int fec_recv(struct eth_device *dev) -{ - struct fec_info_dma *info = dev->priv; - volatile fecdma_t *fecp = (fecdma_t *) (info->iobase); - - cbd_t *prbd = &info->rxbd[info->rxIdx]; - u32 ievent; - int frame_length, len = 0; - - /* Check if any critical events have happened */ - ievent = fecp->eir; - if (ievent != 0) { - fecp->eir = ievent; - - if (ievent & (FEC_EIR_BABT | FEC_EIR_TXERR | FEC_EIR_RXERR)) { - printf("fec_recv: error\n"); - fec_halt(dev); - fec_init(dev, NULL); - return 0; - } - - if (ievent & FEC_EIR_HBERR) { - /* Heartbeat error */ - fecp->tcr |= FEC_TCR_GTS; - } - - if (ievent & FEC_EIR_GRA) { - /* Graceful stop complete */ - if (fecp->tcr & FEC_TCR_GTS) { - printf("fec_recv: tcr_gts\n"); - fec_halt(dev); - fecp->tcr &= ~FEC_TCR_GTS; - fec_init(dev, NULL); - } - } - } - - if (!(prbd->cbd_sc & BD_ENET_RX_EMPTY)) { - if ((prbd->cbd_sc & BD_ENET_RX_LAST) && - !(prbd->cbd_sc & BD_ENET_RX_ERR) && - ((prbd->cbd_datlen - 4) > 14)) { - - /* Get buffer address and size */ - frame_length = prbd->cbd_datlen - 4; - - /* Fill the buffer and pass it to upper layers */ - net_process_received_packet((uchar *)prbd->cbd_bufaddr, - frame_length); - len = frame_length; - } - - /* Reset buffer descriptor as empty */ - if ((info->rxIdx) == (PKTBUFSRX - 1)) - prbd->cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY); - else - prbd->cbd_sc = BD_ENET_RX_EMPTY; - - prbd->cbd_datlen = PKTSIZE_ALIGN; - - /* Now, we have an empty RxBD, restart the DMA receive task */ - MCD_continDma(info->rxTask); - - /* Increment BD count */ - info->rxIdx = (info->rxIdx + 1) % PKTBUFSRX; - } - - return len; -} - -static void fec_set_hwaddr(volatile fecdma_t * fecp, u8 * mac) +static void fec_set_hwaddr(volatile fecdma_t *fecp, u8 *mac) { - u8 currByte; /* byte for which to compute the CRC */ + u8 curr_byte; /* byte for which to compute the CRC */ int byte; /* loop - counter */ int bit; /* loop - counter */ u32 crc = 0xffffffff; /* initial value */ for (byte = 0; byte < 6; byte++) { - currByte = mac[byte]; + curr_byte = mac[byte]; for (bit = 0; bit < 8; bit++) { - if ((currByte & 0x01) ^ (crc & 0x01)) { + if ((curr_byte & 0x01) ^ (crc & 0x01)) { crc >>= 1; crc = crc ^ 0xedb88320; } else { crc >>= 1; } - currByte >>= 1; + curr_byte >>= 1; } } @@ -347,30 +226,28 @@ static void fec_set_hwaddr(volatile fecdma_t * fecp, u8 * mac) fecp->galr = 0; } -static int fec_init(struct eth_device *dev, bd_t * bd) +static int fec_init(struct udevice *dev) { struct fec_info_dma *info = dev->priv; - volatile fecdma_t *fecp = (fecdma_t *) (info->iobase); - int i; + volatile fecdma_t *fecp = (fecdma_t *)info->iobase; + int rval, i; uchar enetaddr[6]; #ifdef ET_DEBUG printf("fec_init: iobase 0x%08x ...\n", info->iobase); #endif - fecpin_setclear(dev, 1); - + fecpin_setclear(info, 1); fec_halt(dev); #if defined(CONFIG_CMD_MII) || defined (CONFIG_MII) || \ defined (CONFIG_SYS_DISCOVER_PHY) mii_init(); - - set_fec_duplex_speed(fecp, bd, info->dup_spd); + set_fec_duplex_speed(fecp, info->dup_spd); #else #ifndef CONFIG_SYS_DISCOVER_PHY - set_fec_duplex_speed(fecp, bd, (FECDUPLEX << 16) | FECSPEED); + set_fec_duplex_speed(fecp, (FECDUPLEX << 16) | FECSPEED); #endif /* ifndef CONFIG_SYS_DISCOVER_PHY */ #endif /* CONFIG_CMD_MII || CONFIG_MII */ @@ -381,18 +258,24 @@ static int fec_init(struct eth_device *dev, bd_t * bd) fecp->eir = 0xffffffff; /* Set station address */ - if ((u32) fecp == CONFIG_SYS_FEC0_IOBASE) - eth_env_get_enetaddr("ethaddr", enetaddr); + if (info->index == 0) + rval = eth_env_get_enetaddr("ethaddr", enetaddr); else - eth_env_get_enetaddr("eth1addr", enetaddr); + rval = eth_env_get_enetaddr("eth1addr", enetaddr); + + if (!rval) { + puts("Please set a valid MAC address\n"); + return -EINVAL; + } + fec_set_hwaddr(fecp, enetaddr); /* Set Opcode/Pause Duration Register */ fecp->opd = 0x00010020; /* Setup Buffers and Buffer Descriptors */ - info->rxIdx = 0; - info->txIdx = 0; + info->rx_idx = 0; + info->tx_idx = 0; /* Setup Receiver Buffer Descriptors (13.14.24.18) * Settings: Empty, Wrap */ @@ -412,8 +295,8 @@ static int fec_init(struct eth_device *dev, bd_t * bd) } info->txbd[CONFIG_SYS_TX_ETH_BUFFER - 1].cbd_sc |= BD_ENET_TX_WRAP; - info->usedTbdIdx = 0; - info->cleanTbdNum = CONFIG_SYS_TX_ETH_BUFFER; + info->used_tbd_idx = 0; + info->clean_tbd_num = CONFIG_SYS_TX_ETH_BUFFER; /* Set Rx FIFO alarm and granularity value */ fecp->rfcr = 0x0c000000; @@ -427,154 +310,288 @@ static int fec_init(struct eth_device *dev, bd_t * bd) fecp->ctcwr = 0x03000000; /* Enable DMA receive task */ - MCD_startDma(info->rxTask, /* Dma channel */ - (s8 *) info->rxbd, /*Source Address */ - 0, /* Source increment */ - (s8 *) (&fecp->rfdr), /* dest */ - 4, /* dest increment */ - 0, /* DMA size */ - 4, /* xfer size */ - info->rxInit, /* initiator */ - info->rxPri, /* priority */ - (MCD_FECRX_DMA | MCD_TT_FLAGS_DEF), /* Flags */ - (MCD_NO_CSUM | MCD_NO_BYTE_SWAP) /* Function description */ + MCD_startDma(info->rx_task, + (s8 *)info->rxbd, + 0, + (s8 *)&fecp->rfdr, + 4, + 0, + 4, + info->rx_init, + info->rx_pri, + (MCD_FECRX_DMA | MCD_TT_FLAGS_DEF), + (MCD_NO_CSUM | MCD_NO_BYTE_SWAP) ); /* Enable DMA tx task with no ready buffer descriptors */ - MCD_startDma(info->txTask, /* Dma channel */ - (s8 *) info->txbd, /*Source Address */ - 0, /* Source increment */ - (s8 *) (&fecp->tfdr), /* dest */ - 4, /* dest incr */ - 0, /* DMA size */ - 4, /* xfer size */ - info->txInit, /* initiator */ - info->txPri, /* priority */ - (MCD_FECTX_DMA | MCD_TT_FLAGS_DEF), /* Flags */ - (MCD_NO_CSUM | MCD_NO_BYTE_SWAP) /* Function description */ + MCD_startDma(info->tx_task, + (s8 *)info->txbd, + 0, + (s8 *)&fecp->tfdr, + 4, + 0, + 4, + info->tx_init, + info->tx_pri, + (MCD_FECTX_DMA | MCD_TT_FLAGS_DEF), + (MCD_NO_CSUM | MCD_NO_BYTE_SWAP) ); /* Now enable the transmit and receive processing */ fecp->ecr |= FEC_ECR_ETHER_EN; - return 1; + return 0; +} + +static int mcdmafec_init(struct udevice *dev) +{ + return fec_init(dev); } -static void fec_halt(struct eth_device *dev) +static int mcdmafec_send(struct udevice *dev, void *packet, int length) { struct fec_info_dma *info = dev->priv; - volatile fecdma_t *fecp = (fecdma_t *) (info->iobase); - int counter = 0xffff; + cbd_t *p_tbd, *p_used_tbd; + u16 phy_status; - /* issue graceful stop command to the FEC transmitter if necessary */ - fecp->tcr |= FEC_TCR_GTS; + miiphy_read(dev->name, info->phy_addr, MII_BMSR, &phy_status); - /* wait for graceful stop to register */ - while ((counter--) && (!(fecp->eir & FEC_EIR_GRA))) ; + /* process all the consumed TBDs */ + while (info->clean_tbd_num < CONFIG_SYS_TX_ETH_BUFFER) { + p_used_tbd = &info->txbd[info->used_tbd_idx]; + if (p_used_tbd->cbd_sc & BD_ENET_TX_READY) { +#ifdef ET_DEBUG + printf("Cannot clean TBD %d, in use\n", + info->clean_tbd_num); +#endif + return 0; + } - /* Disable DMA tasks */ - MCD_killDma(info->txTask); - MCD_killDma(info->rxTask); + /* clean this buffer descriptor */ + if (info->used_tbd_idx == (CONFIG_SYS_TX_ETH_BUFFER - 1)) + p_used_tbd->cbd_sc = BD_ENET_TX_WRAP; + else + p_used_tbd->cbd_sc = 0; - /* Disable the Ethernet Controller */ - fecp->ecr &= ~FEC_ECR_ETHER_EN; + /* update some indeces for a correct handling of TBD ring */ + info->clean_tbd_num++; + info->used_tbd_idx = (info->used_tbd_idx + 1) + % CONFIG_SYS_TX_ETH_BUFFER; + } - /* Clear FIFO status registers */ - fecp->rfsr &= FIFO_ERRSTAT; - fecp->tfsr &= FIFO_ERRSTAT; + /* Check for valid length of data. */ + if (length > 1500 || length <= 0) + return -1; - fecp->frst = 0x01000000; + /* Check the number of vacant TxBDs. */ + if (info->clean_tbd_num < 1) { + printf("No available TxBDs ...\n"); + return -1; + } - /* Issue a reset command to the FEC chip */ - fecp->ecr |= FEC_ECR_RESET; + /* Get the first TxBD to send the mac header */ + p_tbd = &info->txbd[info->tx_idx]; + p_tbd->cbd_datlen = length; + p_tbd->cbd_bufaddr = (u32)packet; + p_tbd->cbd_sc |= BD_ENET_TX_LAST | BD_ENET_TX_TC | BD_ENET_TX_READY; + info->tx_idx = (info->tx_idx + 1) % CONFIG_SYS_TX_ETH_BUFFER; - /* wait at least 20 clock cycles */ - udelay(10000); + /* Enable DMA transmit task */ + MCD_continDma(info->tx_task); -#ifdef ET_DEBUG - printf("Ethernet task stopped\n"); -#endif + info->clean_tbd_num -= 1; + + /* wait until frame is sent . */ + while (p_tbd->cbd_sc & BD_ENET_TX_READY) + udelay(10); + + return (int)(info->txbd[info->tx_idx].cbd_sc & BD_ENET_TX_STATS); } -int mcdmafec_initialize(bd_t * bis) +static int mcdmafec_recv(struct udevice *dev, int flags, uchar **packetp) { - struct eth_device *dev; - int i; -#ifdef CONFIG_SYS_DMA_USE_INTSRAM - u32 tmp = CONFIG_SYS_INTSRAM + 0x2000; -#endif + struct fec_info_dma *info = dev->priv; + volatile fecdma_t *fecp = (fecdma_t *)info->iobase; - for (i = 0; i < ARRAY_SIZE(fec_info); i++) { - - dev = - (struct eth_device *)memalign(CONFIG_SYS_CACHELINE_SIZE, - sizeof *dev); - if (dev == NULL) - hang(); - - memset(dev, 0, sizeof(*dev)); - - sprintf(dev->name, "FEC%d", fec_info[i].index); - - dev->priv = &fec_info[i]; - dev->init = fec_init; - dev->halt = fec_halt; - dev->send = fec_send; - dev->recv = fec_recv; - - /* setup Receive and Transmit buffer descriptor */ -#ifdef CONFIG_SYS_DMA_USE_INTSRAM - fec_info[i].rxbd = (cbd_t *)((u32)fec_info[i].rxbd + tmp); - tmp = (u32)fec_info[i].rxbd; - fec_info[i].txbd = - (cbd_t *)((u32)fec_info[i].txbd + tmp + - (PKTBUFSRX * sizeof(cbd_t))); - tmp = (u32)fec_info[i].txbd; - fec_info[i].txbuf = - (char *)((u32)fec_info[i].txbuf + tmp + - (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t))); - tmp = (u32)fec_info[i].txbuf; -#else - fec_info[i].rxbd = - (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE, - (PKTBUFSRX * sizeof(cbd_t))); - fec_info[i].txbd = - (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE, - (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t))); - fec_info[i].txbuf = - (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH); -#endif + cbd_t *prbd = &info->rxbd[info->rx_idx]; + u32 ievent; + int frame_length, len = 0; -#ifdef ET_DEBUG - printf("rxbd %x txbd %x\n", - (int)fec_info[i].rxbd, (int)fec_info[i].txbd); -#endif + /* Check if any critical events have happened */ + ievent = fecp->eir; + if (ievent != 0) { + fecp->eir = ievent; - fec_info[i].phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32); + if (ievent & (FEC_EIR_BABT | FEC_EIR_TXERR | FEC_EIR_RXERR)) { + printf("fec_recv: error\n"); + fec_halt(dev); + fec_init(dev); + return 0; + } - eth_register(dev); + if (ievent & FEC_EIR_HBERR) { + /* Heartbeat error */ + fecp->tcr |= FEC_TCR_GTS; + } + + if (ievent & FEC_EIR_GRA) { + /* Graceful stop complete */ + if (fecp->tcr & FEC_TCR_GTS) { + printf("fec_recv: tcr_gts\n"); + fec_halt(dev); + fecp->tcr &= ~FEC_TCR_GTS; + fec_init(dev); + } + } + } + + if (!(prbd->cbd_sc & BD_ENET_RX_EMPTY)) { + if ((prbd->cbd_sc & BD_ENET_RX_LAST) && + !(prbd->cbd_sc & BD_ENET_RX_ERR) && + ((prbd->cbd_datlen - 4) > 14)) { + /* Get buffer address and size */ + frame_length = prbd->cbd_datlen - 4; + + /* Fill the buffer and pass it to upper layers */ + net_process_received_packet((uchar *)prbd->cbd_bufaddr, + frame_length); + len = frame_length; + } + + /* Reset buffer descriptor as empty */ + if (info->rx_idx == (PKTBUFSRX - 1)) + prbd->cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY); + else + prbd->cbd_sc = BD_ENET_RX_EMPTY; + + prbd->cbd_datlen = PKTSIZE_ALIGN; + + /* Now, we have an empty RxBD, restart the DMA receive task */ + MCD_continDma(info->rx_task); + + /* Increment BD count */ + info->rx_idx = (info->rx_idx + 1) % PKTBUFSRX; + } + + return len; +} + +static void mcdmafec_halt(struct udevice *dev) +{ + fec_halt(dev); +} + +static const struct eth_ops mcdmafec_ops = { + .start = mcdmafec_init, + .send = mcdmafec_send, + .recv = mcdmafec_recv, + .stop = mcdmafec_halt, +}; + +/* + * Boot sequence, called just after mcffec_ofdata_to_platdata, + * as DM way, it replaces old mcffec_initialize. + */ +static int mcdmafec_probe(struct udevice *dev) +{ + struct fec_info_dma *info = dev->priv; + struct eth_pdata *pdata = dev_get_platdata(dev); + int node = dev_of_offset(dev); + int retval; + const u32 *val; + + info->index = dev->seq; + info->iobase = pdata->iobase; + info->miibase = pdata->iobase; + info->phy_addr = -1; + + val = fdt_getprop(gd->fdt_blob, node, "rx-task", NULL); + if (val) + info->rx_task = fdt32_to_cpu(*val); + + val = fdt_getprop(gd->fdt_blob, node, "tx-task", NULL); + if (val) + info->tx_task = fdt32_to_cpu(*val); + + val = fdt_getprop(gd->fdt_blob, node, "rx-prioprity", NULL); + if (val) + info->rx_pri = fdt32_to_cpu(*val); + + val = fdt_getprop(gd->fdt_blob, node, "tx-prioprity", NULL); + if (val) + info->tx_pri = fdt32_to_cpu(*val); + + val = fdt_getprop(gd->fdt_blob, node, "rx-init", NULL); + if (val) + info->rx_init = fdt32_to_cpu(*val); + + val = fdt_getprop(gd->fdt_blob, node, "tx-init", NULL); + if (val) + info->tx_init = fdt32_to_cpu(*val); + +#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM + u32 tmp = CONFIG_SYS_INIT_RAM_ADDR + 0x1000; +#endif + init_eth_info(info); #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) - int retval; - struct mii_dev *mdiodev = mdio_alloc(); - if (!mdiodev) - return -ENOMEM; - strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN); - mdiodev->read = mcffec_miiphy_read; - mdiodev->write = mcffec_miiphy_write; - - retval = mdio_register(mdiodev); - if (retval < 0) - return retval; + info->bus = mdio_alloc(); + if (!info->bus) + return -ENOMEM; + strncpy(info->bus->name, dev->name, MDIO_NAME_LEN); + info->bus->read = mcffec_miiphy_read; + info->bus->write = mcffec_miiphy_write; + + retval = mdio_register(info->bus); + if (retval < 0) + return retval; #endif - if (i > 0) - fec_info[i - 1].next = &fec_info[i]; - } - fec_info[i - 1].next = &fec_info[0]; + return 0; +} - /* default speed */ - bis->bi_ethspeed = 10; +static int mcdmafec_remove(struct udevice *dev) +{ + struct fec_info_dma *priv = dev_get_priv(dev); + + mdio_unregister(priv->bus); + mdio_free(priv->bus); return 0; } + +/* + * Boot sequence, called 1st + */ +static int mcdmafec_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + const u32 *val; + + pdata->iobase = (phys_addr_t)devfdt_get_addr(dev); + /* Default to 10Mbit/s */ + pdata->max_speed = 10; + + val = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "max-speed", NULL); + if (val) + pdata->max_speed = fdt32_to_cpu(*val); + + return 0; +} + +static const struct udevice_id mcdmafec_ids[] = { + { .compatible = "fsl,mcf-dma-fec" }, + { } +}; + +U_BOOT_DRIVER(mcffec) = { + .name = "mcdmafec", + .id = UCLASS_ETH, + .of_match = mcdmafec_ids, + .ofdata_to_platdata = mcdmafec_ofdata_to_platdata, + .probe = mcdmafec_probe, + .remove = mcdmafec_remove, + .ops = &mcdmafec_ops, + .priv_auto_alloc_size = sizeof(struct fec_info_dma), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/drivers/net/mcffec.c b/drivers/net/mcffec.c index 9a3a8455a1..4ec24362d0 100644 --- a/drivers/net/mcffec.c +++ b/drivers/net/mcffec.c @@ -5,17 +5,17 @@ * * (C) Copyright 2007 Freescale Semiconductor, Inc. * TsiChung Liew (Tsi-Chung.Liew@freescale.com) + * + * Conversion to DM + * (C) 2019 Angelo Dureghello <angelo.dureghello@timesys.com> */ #include <common.h> #include <env.h> #include <malloc.h> - #include <command.h> #include <net.h> -#include <netdev.h> #include <miiphy.h> - #include <asm/fec.h> #include <asm/immap.h> #include <linux/mii.h> @@ -27,64 +27,68 @@ #define DBUF_LENGTH 1520 #define TX_BUF_CNT 2 #define PKT_MAXBUF_SIZE 1518 -#define PKT_MINBUF_SIZE 64 #define PKT_MAXBLR_SIZE 1520 #define LAST_PKTBUFSRX PKTBUFSRX - 1 #define BD_ENET_RX_W_E (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY) #define BD_ENET_TX_RDY_LST (BD_ENET_TX_READY | BD_ENET_TX_LAST) -struct fec_info_s fec_info[] = { -#ifdef CONFIG_SYS_FEC0_IOBASE - { - 0, /* index */ - CONFIG_SYS_FEC0_IOBASE, /* io base */ - CONFIG_SYS_FEC0_PINMUX, /* gpio pin muxing */ - CONFIG_SYS_FEC0_MIIBASE, /* mii base */ - -1, /* phy_addr */ - 0, /* duplex and speed */ - 0, /* phy name */ - 0, /* phyname init */ - 0, /* RX BD */ - 0, /* TX BD */ - 0, /* rx Index */ - 0, /* tx Index */ - 0, /* tx buffer */ - 0, /* initialized flag */ - (struct fec_info_s *)-1, - }, -#endif -#ifdef CONFIG_SYS_FEC1_IOBASE - { - 1, /* index */ - CONFIG_SYS_FEC1_IOBASE, /* io base */ - CONFIG_SYS_FEC1_PINMUX, /* gpio pin muxing */ - CONFIG_SYS_FEC1_MIIBASE, /* mii base */ - -1, /* phy_addr */ - 0, /* duplex and speed */ - 0, /* phy name */ - 0, /* phy name init */ +DECLARE_GLOBAL_DATA_PTR; + +static void init_eth_info(struct fec_info_s *info) +{ #ifdef CONFIG_SYS_FEC_BUF_USE_SRAM - (cbd_t *)DBUF_LENGTH, /* RX BD */ + static u32 tmp; + + if (info->index == 0) + tmp = CONFIG_SYS_INIT_RAM_ADDR + 0x1000; + else + info->rxbd = (cbd_t *)DBUF_LENGTH; + + /* setup Receive and Transmit buffer descriptor */ + info->rxbd = (cbd_t *)((u32)info->rxbd + tmp); + tmp = (u32)info->rxbd; + info->txbd = + (cbd_t *)((u32)info->txbd + tmp + + (PKTBUFSRX * sizeof(cbd_t))); + tmp = (u32)info->txbd; + info->txbuf = + (char *)((u32)info->txbuf + tmp + + (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t))); + tmp = (u32)info->txbuf; #else - 0, /* RX BD */ + info->rxbd = + (cbd_t *)memalign(CONFIG_SYS_CACHELINE_SIZE, + (PKTBUFSRX * sizeof(cbd_t))); + info->txbd = + (cbd_t *)memalign(CONFIG_SYS_CACHELINE_SIZE, + (TX_BUF_CNT * sizeof(cbd_t))); + info->txbuf = + (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH); #endif - 0, /* TX BD */ - 0, /* rx Index */ - 0, /* tx Index */ - 0, /* tx buffer */ - 0, /* initialized flag */ - (struct fec_info_s *)-1, - } + +#ifdef ET_DEBUG + printf("rxbd %x txbd %x\n", (int)info->rxbd, (int)info->txbd); #endif -}; + info->phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32); +} + +static void fec_reset(struct fec_info_s *info) +{ + volatile fec_t *fecp = (fec_t *)(info->iobase); + int i; + + fecp->ecr = FEC_ECR_RESET; + for (i = 0; (fecp->ecr & FEC_ECR_RESET) && (i < FEC_RESET_DELAY); ++i) + udelay(1); -int fec_recv(struct eth_device *dev); -int fec_init(struct eth_device *dev, bd_t * bd); -void fec_halt(struct eth_device *dev); -void fec_reset(struct eth_device *dev); + if (i == FEC_RESET_DELAY) + printf("FEC_RESET_DELAY timeout\n"); +} -void setFecDuplexSpeed(volatile fec_t * fecp, bd_t * bd, int dup_spd) +static void set_fec_duplex_speed(volatile fec_t *fecp, int dup_spd) { + bd_t *bd = gd->bd; + if ((dup_spd >> 16) == FULL) { /* Set maximum frame length */ fecp->rcr = FEC_RCR_MAX_FL(PKT_MAXBUF_SIZE) | FEC_RCR_MII_MODE | @@ -116,138 +120,11 @@ void setFecDuplexSpeed(volatile fec_t * fecp, bd_t * bd, int dup_spd) } } -static int fec_send(struct eth_device *dev, void *packet, int length) -{ - struct fec_info_s *info = dev->priv; - volatile fec_t *fecp = (fec_t *) (info->iobase); - int j, rc; - u16 phyStatus; - - miiphy_read(dev->name, info->phy_addr, MII_BMSR, &phyStatus); - - /* section 16.9.23.3 - * Wait for ready - */ - j = 0; - while ((info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_READY) && - (j < MCFFEC_TOUT_LOOP)) { - udelay(1); - j++; - } - if (j >= MCFFEC_TOUT_LOOP) { - printf("TX not ready\n"); - } - - info->txbd[info->txIdx].cbd_bufaddr = (uint) packet; - info->txbd[info->txIdx].cbd_datlen = length; - info->txbd[info->txIdx].cbd_sc |= BD_ENET_TX_RDY_LST; - - /* Activate transmit Buffer Descriptor polling */ - fecp->tdar = 0x01000000; /* Descriptor polling active */ - -#ifndef CONFIG_SYS_FEC_BUF_USE_SRAM - /* - * FEC unable to initial transmit data packet. - * A nop will ensure the descriptor polling active completed. - * CF Internal RAM has shorter cycle access than DRAM. If use - * DRAM as Buffer descriptor and data, a nop is a must. - * Affect only V2 and V3. - */ - __asm__ ("nop"); - -#endif - -#ifdef CONFIG_SYS_UNIFY_CACHE - icache_invalid(); -#endif - - j = 0; - while ((info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_READY) && - (j < MCFFEC_TOUT_LOOP)) { - udelay(1); - j++; - } - if (j >= MCFFEC_TOUT_LOOP) { - printf("TX timeout\n"); - } - -#ifdef ET_DEBUG - printf("%s[%d] %s: cycles: %d status: %x retry cnt: %d\n", - __FILE__, __LINE__, __FUNCTION__, j, - info->txbd[info->txIdx].cbd_sc, - (info->txbd[info->txIdx].cbd_sc & 0x003C) >> 2); -#endif - - /* return only status bits */ - rc = (info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_STATS); - info->txIdx = (info->txIdx + 1) % TX_BUF_CNT; - - return rc; -} - -int fec_recv(struct eth_device *dev) -{ - struct fec_info_s *info = dev->priv; - volatile fec_t *fecp = (fec_t *) (info->iobase); - int length; - - for (;;) { -#ifndef CONFIG_SYS_FEC_BUF_USE_SRAM -#endif -#ifdef CONFIG_SYS_UNIFY_CACHE - icache_invalid(); -#endif - /* section 16.9.23.2 */ - if (info->rxbd[info->rxIdx].cbd_sc & BD_ENET_RX_EMPTY) { - length = -1; - break; /* nothing received - leave for() loop */ - } - - length = info->rxbd[info->rxIdx].cbd_datlen; - - if (info->rxbd[info->rxIdx].cbd_sc & 0x003f) { - printf("%s[%d] err: %x\n", - __FUNCTION__, __LINE__, - info->rxbd[info->rxIdx].cbd_sc); -#ifdef ET_DEBUG - printf("%s[%d] err: %x\n", - __FUNCTION__, __LINE__, - info->rxbd[info->rxIdx].cbd_sc); -#endif - } else { - - length -= 4; - /* Pass the packet up to the protocol layers. */ - net_process_received_packet(net_rx_packets[info->rxIdx], - length); - - fecp->eir |= FEC_EIR_RXF; - } - - /* Give the buffer back to the FEC. */ - info->rxbd[info->rxIdx].cbd_datlen = 0; - - /* wrap around buffer index when necessary */ - if (info->rxIdx == LAST_PKTBUFSRX) { - info->rxbd[PKTBUFSRX - 1].cbd_sc = BD_ENET_RX_W_E; - info->rxIdx = 0; - } else { - info->rxbd[info->rxIdx].cbd_sc = BD_ENET_RX_EMPTY; - info->rxIdx++; - } - - /* Try to fill Buffer Descriptors */ - fecp->rdar = 0x01000000; /* Descriptor polling active */ - } - - return length; -} - #ifdef ET_DEBUG -void dbgFecRegs(struct eth_device *dev) +static void dbg_fec_regs(struct udevice *dev) { struct fec_info_s *info = dev->priv; - volatile fec_t *fecp = (fec_t *) (info->iobase); + volatile fec_t *fecp = (fec_t *)(info->iobase); printf("=====\n"); printf("ievent %x - %x\n", (int)&fecp->eir, fecp->eir); @@ -394,28 +271,27 @@ void dbgFecRegs(struct eth_device *dev) } #endif -int fec_init(struct eth_device *dev, bd_t * bd) +int mcffec_init(struct udevice *dev) { struct fec_info_s *info = dev->priv; volatile fec_t *fecp = (fec_t *) (info->iobase); - int i; + int rval, i; uchar ea[6]; - fecpin_setclear(dev, 1); - - fec_reset(dev); + fecpin_setclear(info, 1); + fec_reset(info); #if defined(CONFIG_CMD_MII) || defined (CONFIG_MII) || \ defined (CONFIG_SYS_DISCOVER_PHY) mii_init(); - setFecDuplexSpeed(fecp, bd, info->dup_spd); + set_fec_duplex_speed(fecp, info->dup_spd); #else #ifndef CONFIG_SYS_DISCOVER_PHY - setFecDuplexSpeed(fecp, bd, (FECDUPLEX << 16) | FECSPEED); -#endif /* ifndef CONFIG_SYS_DISCOVER_PHY */ -#endif /* CONFIG_CMD_MII || CONFIG_MII */ + set_fec_duplex_speed(fecp, (FECDUPLEX << 16) | FECSPEED); +#endif /* ifndef CONFIG_SYS_DISCOVER_PHY */ +#endif /* CONFIG_CMD_MII || CONFIG_MII */ /* We use strictly polling mode only */ fecp->eimr = 0; @@ -424,34 +300,20 @@ int fec_init(struct eth_device *dev, bd_t * bd) fecp->eir = 0xffffffff; /* Set station address */ - if ((u32) fecp == CONFIG_SYS_FEC0_IOBASE) { -#ifdef CONFIG_SYS_FEC1_IOBASE - volatile fec_t *fecp1 = (fec_t *) (CONFIG_SYS_FEC1_IOBASE); - eth_env_get_enetaddr("eth1addr", ea); - fecp1->palr = - (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]); - fecp1->paur = (ea[4] << 24) | (ea[5] << 16); -#endif - eth_env_get_enetaddr("ethaddr", ea); - fecp->palr = - (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]); - fecp->paur = (ea[4] << 24) | (ea[5] << 16); - } else { -#ifdef CONFIG_SYS_FEC0_IOBASE - volatile fec_t *fecp0 = (fec_t *) (CONFIG_SYS_FEC0_IOBASE); - eth_env_get_enetaddr("ethaddr", ea); - fecp0->palr = - (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]); - fecp0->paur = (ea[4] << 24) | (ea[5] << 16); -#endif -#ifdef CONFIG_SYS_FEC1_IOBASE - eth_env_get_enetaddr("eth1addr", ea); - fecp->palr = - (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]); - fecp->paur = (ea[4] << 24) | (ea[5] << 16); -#endif + if (info->index == 0) + rval = eth_env_get_enetaddr("ethaddr", ea); + else + rval = eth_env_get_enetaddr("eth1addr", ea); + + if (!rval) { + puts("Please set a valid MAC address\n"); + return -EINVAL; } + fecp->palr = + (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]); + fecp->paur = (ea[4] << 24) | (ea[5] << 16); + /* Clear unicast address hash table */ fecp->iaur = 0; fecp->ialr = 0; @@ -466,8 +328,8 @@ int fec_init(struct eth_device *dev, bd_t * bd) /* * Setup Buffers and Buffer Descriptors */ - info->rxIdx = 0; - info->txIdx = 0; + info->rx_idx = 0; + info->tx_idx = 0; /* * Setup Receiver Buffer Descriptors (13.14.24.18) @@ -500,119 +362,256 @@ int fec_init(struct eth_device *dev, bd_t * bd) /* Now enable the transmit and receive processing */ fecp->ecr |= FEC_ECR_ETHER_EN; - /* And last, try to fill Rx Buffer Descriptors */ - fecp->rdar = 0x01000000; /* Descriptor polling active */ + /* And last, try to fill Rx Buffer Descriptors + * Descriptor polling active + */ + fecp->rdar = 0x01000000; - return 1; + return 0; } -void fec_reset(struct eth_device *dev) +static int mcffec_send(struct udevice *dev, void *packet, int length) { struct fec_info_s *info = dev->priv; - volatile fec_t *fecp = (fec_t *) (info->iobase); - int i; + volatile fec_t *fecp = (fec_t *)info->iobase; + int j, rc; + u16 phy_status; - fecp->ecr = FEC_ECR_RESET; - for (i = 0; (fecp->ecr & FEC_ECR_RESET) && (i < FEC_RESET_DELAY); ++i) { + miiphy_read(dev->name, info->phy_addr, MII_BMSR, &phy_status); + + /* section 16.9.23.3 + * Wait for ready + */ + j = 0; + while ((info->txbd[info->tx_idx].cbd_sc & BD_ENET_TX_READY) && + (j < info->to_loop)) { udelay(1); + j++; } - if (i == FEC_RESET_DELAY) { - printf("FEC_RESET_DELAY timeout\n"); + if (j >= info->to_loop) + printf("TX not ready\n"); + + info->txbd[info->tx_idx].cbd_bufaddr = (uint)packet; + info->txbd[info->tx_idx].cbd_datlen = length; + info->txbd[info->tx_idx].cbd_sc |= BD_ENET_TX_RDY_LST; + + /* Activate transmit Buffer Descriptor polling */ + fecp->tdar = 0x01000000; /* Descriptor polling active */ + +#ifndef CONFIG_SYS_FEC_BUF_USE_SRAM + /* + * FEC unable to initial transmit data packet. + * A nop will ensure the descriptor polling active completed. + * CF Internal RAM has shorter cycle access than DRAM. If use + * DRAM as Buffer descriptor and data, a nop is a must. + * Affect only V2 and V3. + */ + __asm__ ("nop"); +#endif + +#ifdef CONFIG_SYS_UNIFY_CACHE + icache_invalid(); +#endif + + j = 0; + while ((info->txbd[info->tx_idx].cbd_sc & BD_ENET_TX_READY) && + (j < info->to_loop)) { + udelay(1); + j++; + } + if (j >= info->to_loop) + printf("TX timeout\n"); + +#ifdef ET_DEBUG + printf("%s[%d] %s: cycles: %d status: %x retry cnt: %d\n", + __FILE__, __LINE__, __func__, j, + info->txbd[info->tx_idx].cbd_sc, + (info->txbd[info->tx_idx].cbd_sc & 0x003C) >> 2); +#endif + + /* return only status bits */ + rc = (info->txbd[info->tx_idx].cbd_sc & BD_ENET_TX_STATS); + info->tx_idx = (info->tx_idx + 1) % TX_BUF_CNT; + + return rc; +} + +static int mcffec_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct fec_info_s *info = dev->priv; + volatile fec_t *fecp = (fec_t *)info->iobase; + int length = -1; + + for (;;) { +#ifdef CONFIG_SYS_UNIFY_CACHE + icache_invalid(); +#endif + /* If nothing received - leave for() loop */ + if (info->rxbd[info->rx_idx].cbd_sc & BD_ENET_RX_EMPTY) + break; + + length = info->rxbd[info->rx_idx].cbd_datlen; + + if (info->rxbd[info->rx_idx].cbd_sc & 0x003f) { + printf("%s[%d] err: %x\n", + __func__, __LINE__, + info->rxbd[info->rx_idx].cbd_sc); + } else { + length -= 4; + + /* + * Pass the buffer ptr up to the protocol layers. + */ + *packetp = net_rx_packets[info->rx_idx]; + + fecp->eir |= FEC_EIR_RXF; + } + + /* Give the buffer back to the FEC. */ + info->rxbd[info->rx_idx].cbd_datlen = 0; + + /* wrap around buffer index when necessary */ + if (info->rx_idx == LAST_PKTBUFSRX) { + info->rxbd[PKTBUFSRX - 1].cbd_sc = BD_ENET_RX_W_E; + info->rx_idx = 0; + } else { + info->rxbd[info->rx_idx].cbd_sc = BD_ENET_RX_EMPTY; + info->rx_idx++; + } + + /* Try to fill Buffer Descriptors + * Descriptor polling active + */ + fecp->rdar = 0x01000000; } + + return length; } -void fec_halt(struct eth_device *dev) +static void mcffec_halt(struct udevice *dev) { struct fec_info_s *info = dev->priv; - fec_reset(dev); + fec_reset(info); + fecpin_setclear(info, 0); - fecpin_setclear(dev, 0); + info->rx_idx = 0; + info->tx_idx = 0; - info->rxIdx = info->txIdx = 0; memset(info->rxbd, 0, PKTBUFSRX * sizeof(cbd_t)); memset(info->txbd, 0, TX_BUF_CNT * sizeof(cbd_t)); memset(info->txbuf, 0, DBUF_LENGTH); } -int mcffec_initialize(bd_t * bis) +static const struct eth_ops mcffec_ops = { + .start = mcffec_init, + .send = mcffec_send, + .recv = mcffec_recv, + .stop = mcffec_halt, +}; + +/* + * Boot sequence, called just after mcffec_ofdata_to_platdata, + * as DM way, it replaces old mcffec_initialize. + */ +static int mcffec_probe(struct udevice *dev) { - struct eth_device *dev; - int i; -#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM - u32 tmp = CONFIG_SYS_INIT_RAM_ADDR + 0x1000; -#endif + struct eth_pdata *pdata = dev_get_platdata(dev); + struct fec_info_s *info = dev->priv; + int node = dev_of_offset(dev); + int retval, fec_idx; + const u32 *val; - for (i = 0; i < ARRAY_SIZE(fec_info); i++) { + info->index = dev->seq; + info->iobase = pdata->iobase; + info->phy_addr = -1; - dev = - (struct eth_device *)memalign(CONFIG_SYS_CACHELINE_SIZE, - sizeof *dev); - if (dev == NULL) - hang(); + val = fdt_getprop(gd->fdt_blob, node, "mii-base", NULL); + if (val) { + u32 fec_iobase; - memset(dev, 0, sizeof(*dev)); + fec_idx = fdt32_to_cpu(*val); + if (fec_idx == info->index) { + fec_iobase = info->iobase; + } else { + printf("mii base != base address, fec_idx %d\n", + fec_idx); + retval = fec_get_base_addr(fec_idx, &fec_iobase); + if (retval) + return retval; + } + info->miibase = fec_iobase; + } - sprintf(dev->name, "FEC%d", fec_info[i].index); + val = fdt_getprop(gd->fdt_blob, node, "phy-addr", NULL); + if (val) + info->phy_addr = fdt32_to_cpu(*val); - dev->priv = &fec_info[i]; - dev->init = fec_init; - dev->halt = fec_halt; - dev->send = fec_send; - dev->recv = fec_recv; + val = fdt_getprop(gd->fdt_blob, node, "timeout-loop", NULL); + if (val) + info->to_loop = fdt32_to_cpu(*val); - /* setup Receive and Transmit buffer descriptor */ -#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM - fec_info[i].rxbd = (cbd_t *)((u32)fec_info[i].rxbd + tmp); - tmp = (u32)fec_info[i].rxbd; - fec_info[i].txbd = - (cbd_t *)((u32)fec_info[i].txbd + tmp + - (PKTBUFSRX * sizeof(cbd_t))); - tmp = (u32)fec_info[i].txbd; - fec_info[i].txbuf = - (char *)((u32)fec_info[i].txbuf + tmp + - (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t))); - tmp = (u32)fec_info[i].txbuf; -#else - fec_info[i].rxbd = - (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE, - (PKTBUFSRX * sizeof(cbd_t))); - fec_info[i].txbd = - (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE, - (TX_BUF_CNT * sizeof(cbd_t))); - fec_info[i].txbuf = - (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH); -#endif + init_eth_info(info); -#ifdef ET_DEBUG - printf("rxbd %x txbd %x\n", - (int)fec_info[i].rxbd, (int)fec_info[i].txbd); +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + info->bus = mdio_alloc(); + if (!info->bus) + return -ENOMEM; + strcpy(info->bus->name, dev->name); + info->bus->read = mcffec_miiphy_read; + info->bus->write = mcffec_miiphy_write; + + retval = mdio_register(info->bus); + if (retval < 0) + return retval; #endif - fec_info[i].phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32); + return 0; +} - eth_register(dev); +static int mcffec_remove(struct udevice *dev) +{ + struct fec_info_s *priv = dev_get_priv(dev); -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) - int retval; - struct mii_dev *mdiodev = mdio_alloc(); - if (!mdiodev) - return -ENOMEM; - strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN); - mdiodev->read = mcffec_miiphy_read; - mdiodev->write = mcffec_miiphy_write; - - retval = mdio_register(mdiodev); - if (retval < 0) - return retval; -#endif - if (i > 0) - fec_info[i - 1].next = &fec_info[i]; - } - fec_info[i - 1].next = &fec_info[0]; + mdio_unregister(priv->bus); + mdio_free(priv->bus); + + return 0; +} + +/* + * Boot sequence, called 1st + */ +static int mcffec_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + const u32 *val; - /* default speed */ - bis->bi_ethspeed = 10; + pdata->iobase = (phys_addr_t)devfdt_get_addr(dev); + /* Default to 10Mbit/s */ + pdata->max_speed = 10; + + val = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), + "max-speed", NULL); + if (val) + pdata->max_speed = fdt32_to_cpu(*val); return 0; } + +static const struct udevice_id mcffec_ids[] = { + { .compatible = "fsl,mcf-fec" }, + { } +}; + +U_BOOT_DRIVER(mcffec) = { + .name = "mcffec", + .id = UCLASS_ETH, + .of_match = mcffec_ids, + .ofdata_to_platdata = mcffec_ofdata_to_platdata, + .probe = mcffec_probe, + .remove = mcffec_remove, + .ops = &mcffec_ops, + .priv_auto_alloc_size = sizeof(struct fec_info_s), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/drivers/net/mcfmii.c b/drivers/net/mcfmii.c index b8af2cc44b..3b8ee07c13 100644 --- a/drivers/net/mcfmii.c +++ b/drivers/net/mcfmii.c @@ -41,14 +41,6 @@ DECLARE_GLOBAL_DATA_PTR; # define CONFIG_SYS_UNSPEC_STRID 0 #endif -#ifdef CONFIG_MCF547x_8x -typedef struct fec_info_dma FEC_INFO_T; -#define FEC_T fecdma_t -#else -typedef struct fec_info_s FEC_INFO_T; -#define FEC_T fec_t -#endif - typedef struct phy_info_struct { u32 phyid; char *strid; @@ -78,7 +70,7 @@ phy_info_t phyinfo[] = { * mii_init -- Initialize the MII for MII command without ethernet * This function is a subset of eth_init */ -void mii_reset(FEC_INFO_T *info) +void mii_reset(fec_info_t *info) { volatile FEC_T *fecp = (FEC_T *) (info->miibase); int i; @@ -95,9 +87,13 @@ void mii_reset(FEC_INFO_T *info) /* send command to phy using mii, wait for result */ uint mii_send(uint mii_cmd) { - FEC_INFO_T *info; - volatile FEC_T *ep; +#ifdef CONFIG_DM_ETH + struct udevice *dev; +#else struct eth_device *dev; +#endif + fec_info_t *info; + volatile FEC_T *ep; uint mii_reply; int j = 0; @@ -110,11 +106,11 @@ uint mii_send(uint mii_cmd) ep->mmfr = mii_cmd; /* command to phy */ /* wait for mii complete */ - while (!(ep->eir & FEC_EIR_MII) && (j < MCFFEC_TOUT_LOOP)) { + while (!(ep->eir & FEC_EIR_MII) && (j < info->to_loop)) { udelay(1); j++; } - if (j >= MCFFEC_TOUT_LOOP) { + if (j >= info->to_loop) { printf("MII not complete\n"); return -1; } @@ -131,10 +127,9 @@ uint mii_send(uint mii_cmd) #endif /* CONFIG_SYS_DISCOVER_PHY || (CONFIG_MII) */ #if defined(CONFIG_SYS_DISCOVER_PHY) -int mii_discover_phy(struct eth_device *dev) +int mii_discover_phy(fec_info_t *info) { #define MAX_PHY_PASSES 11 - FEC_INFO_T *info = dev->priv; int phyaddr, pass; uint phyno, phytype; int i, found = 0; @@ -157,7 +152,7 @@ int mii_discover_phy(struct eth_device *dev) phytype = mii_send(mk_mii_read(phyno, MII_PHYSID1)); #ifdef ET_DEBUG - printf("PHY type 0x%x pass %d type\n", phytype, pass); + printf("PHY type 0x%x pass %d\n", phytype, pass); #endif if (phytype == 0xffff) continue; @@ -207,9 +202,13 @@ void mii_init(void) __attribute__((weak,alias("__mii_init"))); void __mii_init(void) { - FEC_INFO_T *info; - volatile FEC_T *fecp; +#ifdef CONFIG_DM_ETH + struct udevice *dev; +#else struct eth_device *dev; +#endif + fec_info_t *info; + volatile FEC_T *fecp; int miispd = 0, i = 0; u16 status = 0; u16 linkgood = 0; @@ -220,7 +219,7 @@ void __mii_init(void) fecp = (FEC_T *) info->miibase; - fecpin_setclear(dev, 1); + fecpin_setclear(info, 1); mii_reset(info); @@ -234,9 +233,13 @@ void __mii_init(void) miispd = (gd->bus_clk / 1000000) / 5; fecp->mscr = miispd << 1; - info->phy_addr = mii_discover_phy(dev); +#ifdef CONFIG_SYS_DISCOVER_PHY + info->phy_addr = mii_discover_phy(info); +#endif + if (info->phy_addr == -1) + return; - while (i < MCFFEC_TOUT_LOOP) { + while (i < info->to_loop) { status = 0; i++; /* Read PHY control register */ @@ -257,9 +260,8 @@ void __mii_init(void) udelay(1); } - if (i >= MCFFEC_TOUT_LOOP) { + if (i >= info->to_loop) printf("Link UP timeout\n"); - } /* adapt to the duplex and speed settings of the phy */ info->dup_spd = miiphy_duplex(dev->name, info->phy_addr) << 16; |