drivers: fsl_mcdmafec: conversion to dm
Full conversion to dm for all boards, legacy code removed. Signed-off-by: Angelo Durgehello <angelo.dureghello@timesys.com>
This commit is contained in:
parent
a7bcace28a
commit
05ffdc85ca
35
doc/device-tree-bindings/net/fsl,mcf-dma-fec.txt
Normal file
35
doc/device-tree-bindings/net/fsl,mcf-dma-fec.txt
Normal file
@ -0,0 +1,35 @@
|
||||
* Freescale ColdFire DMA-FEC ethernet controller
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "fsl,mcf-dma-fec"
|
||||
- reg: address and length of the register set for the device.
|
||||
- rx-task: dma channel
|
||||
- tx-task: dma channel
|
||||
- rx-priority: dma channel
|
||||
- tx-priority: dma channel
|
||||
- rx-init: dma channel
|
||||
- tx-init: dma channel
|
||||
|
||||
Optional properties:
|
||||
- mii-base: index of FEC reg area, 0 for FEC0, 1 for FEC1
|
||||
- max-speed: max speedm Mbits/sec
|
||||
- phy-addr: phy address
|
||||
- timeout-loop: integer value for driver loops time out
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
fec0: ethernet@9000 {
|
||||
compatible = "fsl,mcf-dma-fec";
|
||||
reg = <0x9000 0x800>;
|
||||
mii-base = <0>;
|
||||
phy-addr = <0>;
|
||||
timeout-loop = <5000>;
|
||||
rx-task = <0>;
|
||||
tx-task = <1>;
|
||||
rx-piority = <6>;
|
||||
tx-piority = <7>;
|
||||
rx-init = <16>;
|
||||
tx-init = <17>;
|
||||
status = "disabled";
|
||||
};
|
@ -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 */
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
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);
|
||||
#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;
|
||||
|
||||
/* 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)
|
||||
static void fec_set_hwaddr(volatile fecdma_t *fecp, u8 *mac)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 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;
|
||||
|
||||
/* wait for graceful stop to register */
|
||||
while ((counter--) && (!(fecp->eir & FEC_EIR_GRA))) ;
|
||||
|
||||
/* Disable DMA tasks */
|
||||
MCD_killDma(info->txTask);
|
||||
MCD_killDma(info->rxTask);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Issue a reset command to the FEC chip */
|
||||
fecp->ecr |= FEC_ECR_RESET;
|
||||
|
||||
/* wait at least 20 clock cycles */
|
||||
udelay(10000);
|
||||
miiphy_read(dev->name, info->phy_addr, MII_BMSR, &phy_status);
|
||||
|
||||
/* 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("Ethernet task stopped\n");
|
||||
printf("Cannot clean TBD %d, in use\n",
|
||||
info->clean_tbd_num);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Check for valid length of data. */
|
||||
if (length > 1500 || length <= 0)
|
||||
return -1;
|
||||
|
||||
/* Check the number of vacant TxBDs. */
|
||||
if (info->clean_tbd_num < 1) {
|
||||
printf("No available TxBDs ...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Enable DMA transmit task */
|
||||
MCD_continDma(info->tx_task);
|
||||
|
||||
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;
|
||||
struct fec_info_dma *info = dev->priv;
|
||||
volatile fecdma_t *fecp = (fecdma_t *)info->iobase;
|
||||
|
||||
cbd_t *prbd = &info->rxbd[info->rx_idx];
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
#ifdef ET_DEBUG
|
||||
printf("rxbd %x txbd %x\n",
|
||||
(int)fec_info[i].rxbd, (int)fec_info[i].txbd);
|
||||
#endif
|
||||
|
||||
fec_info[i].phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32);
|
||||
|
||||
eth_register(dev);
|
||||
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;
|
||||
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(mdiodev);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
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];
|
||||
|
||||
/* default speed */
|
||||
bis->bi_ethspeed = 10;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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),
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user