X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fnet%2Ffsl_mcdmafec.c;h=73e92b7a0d2ccd09ac4e5f90b5f482da8c452155;hb=1099b2abef35c3c887f6afac1a8ef18c7924d5d2;hp=26c714cc04d2d72afb95df4e400309a112d07cb0;hpb=336aee50cf55d4d98ddf3a4412c18286e7f0a4c0;p=oweals%2Fu-boot.git diff --git a/drivers/net/fsl_mcdmafec.c b/drivers/net/fsl_mcdmafec.c index 26c714cc04..73e92b7a0d 100644 --- a/drivers/net/fsl_mcdmafec.c +++ b/drivers/net/fsl_mcdmafec.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2000-2004 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. @@ -5,15 +6,24 @@ * (C) Copyright 2007 Freescale Semiconductor, Inc. * TsiChung Liew (Tsi-Chung.Liew@freescale.com) * - * SPDX-License-Identifier: GPL-2.0+ + * Conversion to DM + * (C) 2019 Angelo Dureghello */ #include +#include +#include #include #include #include #include #include +#include +#include +#include +#include + +#include "MCD_dma.h" #undef ET_DEBUG #undef MII_DEBUG @@ -21,95 +31,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 -#include - -#include "MCD_dma.h" - DECLARE_GLOBAL_DATA_PTR; -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 */ +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; + + 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; -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); + fecp->frst = 0x01000000; + + /* 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); @@ -150,9 +159,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 | @@ -178,153 +188,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; } } @@ -348,30 +228,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 */ @@ -382,18 +260,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 Desriptors */ - info->rxIdx = 0; - info->txIdx = 0; + /* Setup Buffers and Buffer Descriptors */ + info->rx_idx = 0; + info->tx_idx = 0; /* Setup Receiver Buffer Descriptors (13.14.24.18) * Settings: Empty, Wrap */ @@ -413,8 +297,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; @@ -428,154 +312,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 void fec_halt(struct eth_device *dev) +static int mcdmafec_init(struct udevice *dev) +{ + return fec_init(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; + + if (ievent & (FEC_EIR_BABT | FEC_EIR_TXERR | FEC_EIR_RXERR)) { + printf("fec_recv: error\n"); + fec_halt(dev); + fec_init(dev); + 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); + } + } + } + + 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); +} - fec_info[i].phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32); +static const struct eth_ops mcdmafec_ops = { + .start = mcdmafec_init, + .send = mcdmafec_send, + .recv = mcdmafec_recv, + .stop = mcdmafec_halt, +}; - eth_register(dev); +/* + * 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), +};