[U-Boot] [PATCH 4/5] add TI da8xx support: new ethenet driver for da830 EMAC

Add a driver for the DA830 EMAC.
This is very similar to the davinci_emac driver. It has been restructured to make it as similar as possible. Potentially the two could be merged, but I don't have access to other davinci type platforms to test for breakage after the inevitable mangling required.
Signed-off-by: Nick Thompson nick.thompson@gefanuc.com --- Applies to u-boot-ti
drivers/net/Makefile | 1 + drivers/net/da8xx_emac.c | 654 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 655 insertions(+), 0 deletions(-)
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index be5c484..9cbe736 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -68,6 +68,7 @@ COBJS-$(CONFIG_DRIVER_SMC91111) += smc91111.o COBJS-$(CONFIG_SMC911X) += smc911x.o COBJS-$(CONFIG_TIGON3) += tigon3.o bcm570x_autoneg.o 5701rls.o COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o +COBJS-$(CONFIG_DRIVER_DA8XX_EMAC) += da8xx_emac.o COBJS-$(CONFIG_TSEC_ENET) += tsec.o COBJS-$(CONFIG_TSI108_ETH) += tsi108_eth.o COBJS-$(CONFIG_ULI526X) += uli526x.o diff --git a/drivers/net/da8xx_emac.c b/drivers/net/da8xx_emac.c new file mode 100644 index 0000000..e1d232f --- /dev/null +++ b/drivers/net/da8xx_emac.c @@ -0,0 +1,654 @@ +/* + * Ethernet driver for TI OMAP-L1x/DA8xx chips. + * + * Copyright (C) 2009 Nick Thompson, GE Fanuc, Ltd. nick.thompson@gefanuc.com + * + * Much of this is very similar to the davinci_emac driver. Possibly they + * could be merged, but I have no access to non DA8xx platforms + * and can't test for breakage after the inevitable mangling. + * + * Code base is not new. Original copyright follows: + * + * ---------------------------------------------------------------------------- + * + * Ethernet driver for TI TMS320DM644x (DaVinci) chips. + * + * Copyright (C) 2007 Sergey Kubushyn ksi@koi8.net + * + * Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright + * follows: + * + * ---------------------------------------------------------------------------- + * + * dm644x_emac.c + * + * TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM + * + * Copyright (C) 2005 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + */ +#include <common.h> +#include <command.h> +#include <net.h> +#include <miiphy.h> +#include <malloc.h> +#include <asm/arch/emac_defs.h> + +#ifdef CONFIG_DRIVER_DA8XX_EMAC + +#ifdef CONFIG_CMD_NET + +unsigned int emac_dbg = 0; +#define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args) + +/* Internal static functions */ +static int da8xx_eth_open (struct eth_device *dev, bd_t *bis); +static void da8xx_eth_close (struct eth_device *dev); +static int da8xx_eth_send_packet (struct eth_device *dev, volatile void *packet, int length); +static int da8xx_eth_rcv_packet (struct eth_device *dev); +static void da8xx_eth_mdio_enable(void); + +static int gen_init_phy(int phy_addr); +static int gen_is_phy_connected(int phy_addr); +static int gen_get_link_speed(int phy_addr); +static int gen_auto_negotiate(int phy_addr); + +/* mac address for EMAC registers only (not packet data) */ +static u_int8_t da8xx_eth_mac_addr[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0x00 }; + +/* + * This function must be called before emac_open() if you want to override + * the default mac address. + */ +void da8xx_eth_set_mac_addr(const u_int8_t *addr) +{ + int i; + + for (i = 0; i < sizeof (da8xx_eth_mac_addr); i++) { + da8xx_eth_mac_addr[i] = addr[i]; + } +} + +/* EMAC Addresses */ +static volatile emac_regs *adap_emac = (emac_regs *)EMAC_BASE_ADDR; +static volatile ewrap_regs *adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR; +static volatile mdio_regs *adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR; + +/* EMAC descriptors */ +static volatile emac_desc *emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE); +static volatile emac_desc *emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE); +static volatile emac_desc *emac_rx_active_head = 0; +static volatile emac_desc *emac_rx_active_tail = 0; +static int emac_rx_queue_active = 0; + +/* Receive packet buffers */ +static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; + +/* PHY address for a discovered PHY (0xff - not found) */ +static volatile u_int8_t active_phy_addr = 0xff; + +static int no_phy_init (int phy_addr) { return(1); } +static int no_phy_is_connected (int phy_addr) { return(1); } +static int no_phy_get_link_speed (int phy_addr) { return(1); } +static int no_phy_auto_negotiate (int phy_addr) { return(1); } +phy_t phy = { + .name = "da8xx_evm", + .init = no_phy_init, + .is_phy_connected = no_phy_is_connected, + .get_link_speed = no_phy_get_link_speed, + .auto_negotiate = no_phy_auto_negotiate +}; + +static void da8xx_eth_mdio_enable(void) +{ + u_int32_t clkdiv; + + clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; + + adap_mdio->CONTROL = (clkdiv & 0xff) | + MDIO_CONTROL_ENABLE | + MDIO_CONTROL_FAULT | + MDIO_CONTROL_FAULT_ENABLE; + + while (adap_mdio->CONTROL & MDIO_CONTROL_IDLE) {;} +} + +/* + * Tries to find an active connected PHY. Returns 1 if address if found. + * If no active PHY found returns 0. If more than one active PHY (switch) + * returns 2 + * Sets active_phy_addr variable when returns 1. + */ +static int da8xx_eth_phy_detect(void) +{ + u_int32_t phy_act_state; + int i; + + active_phy_addr = 0xff; + + if ((phy_act_state = adap_mdio->ALIVE) == 0) + return(0); /* No active PHYs */ + + debug_emac("da8xx_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state); + + for (i = 0; i < 32; i++) { + if (phy_act_state & (1 << i)) { + if (phy_act_state & ~(1 << i)) + return(2); /* More than one PHY */ + else { + active_phy_addr = i; + return(1); + } + } + } + + return(0); /* Just to make GCC happy */ +} + + +/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */ +int da8xx_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data) +{ + int tmp; + + while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + + adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | + MDIO_USERACCESS0_WRITE_READ | + ((reg_num & 0x1f) << 21) | + ((phy_addr & 0x1f) << 16); + + /* Wait for command to complete */ + while ((tmp = adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) {;} + + if (tmp & MDIO_USERACCESS0_ACK) { + *data = tmp & 0xffff; + return(1); + } + + *data = -1; + return(0); +} + +/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */ +int da8xx_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data) +{ + + while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + + adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | + MDIO_USERACCESS0_WRITE_WRITE | + ((reg_num & 0x1f) << 21) | + ((phy_addr & 0x1f) << 16) | + (data & 0xffff); + + /* Wait for command to complete */ + while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + + return(1); +} + +/* PHY functions for a generic PHY */ +static int gen_init_phy(int phy_addr) +{ + int ret = 1; + + if (gen_get_link_speed(phy_addr)) { + /* Try another time */ + ret = gen_get_link_speed(phy_addr); + } + + return(ret); +} + +static int gen_is_phy_connected(int phy_addr) +{ + u_int16_t dummy; + + return(da8xx_eth_phy_read(phy_addr, PHY_PHYIDR1, &dummy)); +} + +static int gen_get_link_speed(int phy_addr) +{ + u_int16_t tmp; + + if (da8xx_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp) && (tmp & 0x04)) + return(1); + + return(0); +} + +static int gen_auto_negotiate(int phy_addr) +{ + u_int16_t tmp; + + if (!da8xx_eth_phy_read(phy_addr, PHY_BMCR, &tmp)) + return(0); + + /* Restart Auto_negotiation */ + tmp |= PHY_BMCR_AUTON; + da8xx_eth_phy_write(phy_addr, PHY_BMCR, tmp); + + /*check AutoNegotiate complete */ + udelay (10000); + if (!da8xx_eth_phy_read(phy_addr, PHY_BMSR, &tmp)) + return(0); + + if (!(tmp & PHY_BMSR_AUTN_COMP)) + return(0); + + return(gen_get_link_speed(phy_addr)); +} +/* End of generic PHY functions */ + + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +static int da8xx_mii_phy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short *value) +{ + return(da8xx_eth_phy_read(addr, reg, value) ? 0 : 1); +} + +static int da8xx_mii_phy_write(char *devname, unsigned char addr, unsigned char reg, unsigned short value) +{ + return(da8xx_eth_phy_write(addr, reg, value) ? 0 : 1); +} + +#endif + +/* + * This function initializes the emac hardware. It does NOT initialize + * EMAC modules power or pin multiplexors, that is done by board_init() + * much earlier in bootup process. Returns 1 on success, 0 otherwise. + */ +int da8xx_eth_hw_init(void) +{ + u_int32_t phy_id; + u_int16_t tmp; + int i, ret; + struct eth_device *dev; + + /* register the ethernet driver functions */ + dev = malloc(sizeof *dev); + + if (dev == NULL) { + return -1; + } + + dev->iobase = 0; + dev->init = da8xx_eth_open; + dev->halt = da8xx_eth_close; + dev->send = da8xx_eth_send_packet; + dev->recv = da8xx_eth_rcv_packet; + + eth_register(dev); + + /* The RMII clock can be sources internally through the SYSCLK7 + * or can come externally through a dedicated pin. This selection is + * controlled by PinMux9[21]. PinMux registers are off-limits for ARM. + * In short, we just assume there is a 50MHz RMII clock available. + */ + + da8xx_eth_mdio_enable(); + + for (i = 0; i < 256; i++) { + if (adap_mdio->ALIVE) + break; + udelay(1000); + } + + if (i >= 256) { + printf("No ETH PHY detected!!!\n"); + return(0); + } + + /* Find if a PHY is connected and get it's address */ + ret = da8xx_eth_phy_detect(); + + if (ret == 0) + return 0; + + if (ret == 2) { + printf("More than one PHY detected.\n"); + } else { + /* Get PHY ID and initialize phy_ops for a detected PHY */ + if (!da8xx_eth_phy_read(active_phy_addr, PHY_PHYIDR1, &tmp)) { + active_phy_addr = 0xff; + return(0); + } + + phy_id = (tmp << 16) & 0xffff0000; + + if (!da8xx_eth_phy_read(active_phy_addr, PHY_PHYIDR2, &tmp)) { + active_phy_addr = 0xff; + return(0); + } + + phy_id |= tmp & 0x0000ffff; + + switch (phy_id) { + default: + sprintf(phy.name, "GENERIC @ 0x%02x", active_phy_addr); + phy.init = gen_init_phy; + phy.is_phy_connected = gen_is_phy_connected; + phy.get_link_speed = gen_get_link_speed; + phy.auto_negotiate = gen_auto_negotiate; + } + } + + miiphy_register(phy.name, da8xx_mii_phy_read, da8xx_mii_phy_write); + + return(1); +} + + +/* Eth device open */ +static int da8xx_eth_open(struct eth_device *dev, bd_t *bis) +{ + dv_reg_p addr; + u_int32_t clkdiv, cnt; + volatile emac_desc *rx_desc; + int i; + + debug_emac("+ emac_open\n"); + + /* Reset EMAC module and disable interrupts in wrapper */ + adap_emac->SOFTRESET = 1; + while (adap_emac->SOFTRESET != 0) {;} + adap_ewrap->SOFTRESET = 1; + while (adap_ewrap->SOFTRESET != 0) {;} + + adap_ewrap->C0RXEN = adap_ewrap->C1RXEN = adap_ewrap->C2RXEN = 0; + adap_ewrap->C0TXEN = adap_ewrap->C1TXEN = adap_ewrap->C2TXEN = 0; + adap_ewrap->C0MISCEN = adap_ewrap->C1MISCEN = adap_ewrap->C2MISCEN = 0; + + rx_desc = emac_rx_desc; + + adap_emac->TXCONTROL = 0x01; + adap_emac->RXCONTROL = 0x01; + + /* Set MAC Addresses & Init multicast Hash to 0 (disable any multicast receive) */ + /* Using channel 0 only - other channels are disabled */ + for (i = 0; i < 8; i++) { + adap_emac->MACINDEX = i; + adap_emac->MACADDRHI = + (da8xx_eth_mac_addr[3] << 24) | /* bits 23-16 */ + (da8xx_eth_mac_addr[2] << 16) | /* bits 31-24 */ + (da8xx_eth_mac_addr[1] << 8) | /* bits 39-32 */ + (da8xx_eth_mac_addr[0]); /* bits 47-40 */ + adap_emac->MACADDRLO = + (da8xx_eth_mac_addr[5] << 8) | /* bits 8-0*/ + (da8xx_eth_mac_addr[4]) | (1 << 19) | (1 << 20); /* bits 8-0 */ + } + + adap_emac->MACHASH1 = 0; + adap_emac->MACHASH2 = 0; + + /* Set source MAC address - REQUIRED for pause frames */ + adap_emac->MACSRCADDRHI = + (da8xx_eth_mac_addr[3] << 24) | /* bits 23-16 */ + (da8xx_eth_mac_addr[2] << 16) | /* bits 31-24 */ + (da8xx_eth_mac_addr[1] << 8) | /* bits 39-32 */ + (da8xx_eth_mac_addr[0]); /* bits 47-40 */ + adap_emac->MACSRCADDRLO = + (da8xx_eth_mac_addr[5] << 8) | /* bits 8-0 */ + (da8xx_eth_mac_addr[4]); /* bits 15-8 */ + + /* Set DMA 8 TX / 8 RX Head pointers to 0 */ + addr = &adap_emac->TX0HDP; + for(cnt = 0; cnt < 16; cnt++) + *addr++ = 0; + + addr = &adap_emac->TX0CP; + for(cnt = 0; cnt < 16; cnt++) + *addr++ = 0; + + /* Clear Statistics (do this before setting MacControl register) */ + addr = &adap_emac->RXGOODFRAMES; + for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++) + *addr++ = 0; + + /* No multicast addressing */ + adap_emac->MACHASH1 = 0; + adap_emac->MACHASH2 = 0; + + /* Create RX queue and set receive process in place */ + emac_rx_active_head = emac_rx_desc; + for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) { + rx_desc->next = (u_int32_t)(rx_desc + 1); + rx_desc->buffer = &emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; + rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; + rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; + rx_desc++; + } + + /* Set the last descriptor's "next" parameter to 0 to end the RX desc list */ + rx_desc--; + rx_desc->next = 0; + emac_rx_active_tail = rx_desc; + emac_rx_queue_active = 1; + + /* Enable TX/RX */ + adap_emac->RXMAXLEN = EMAC_MAX_ETHERNET_PKT_SIZE; + adap_emac->RXBUFFEROFFSET = 0; + + /* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */ + adap_emac->RXMBPENABLE = EMAC_RXMBPENABLE_RXBROADEN; + + /* Enable ch 0 only */ + adap_emac->RXUNICASTSET = 0x01; + + /* Enable MII interface and Full duplex mode */ + adap_emac->MACCONTROL = (EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE) | EMAC_MACCONTROL_RMIISPEED_100; + + /* Init MDIO & get link state */ + clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; + adap_mdio->CONTROL = ((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT); + + if (!phy.get_link_speed(active_phy_addr)) + return(0); + + /* Start receive process */ + adap_emac->RX0HDP = (u_int32_t)emac_rx_desc; + + debug_emac("- emac_open\n"); + + return(1); +} + +/* EMAC Channel Teardown */ +static void da8xx_eth_ch_teardown(int ch) +{ + dv_reg dly = 0xff; + dv_reg cnt; + + debug_emac("+ emac_ch_teardown\n"); + + if (ch == EMAC_CH_TX) { + /* Init TX channel teardown */ + adap_emac->TXTEARDOWN = 1; + for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->TX0CP) { + /* Wait here for Tx teardown completion interrupt to occur + * Note: A task delay can be called here to pend rather than + * occupying CPU cycles - anyway it has been found that teardown + * takes very few cpu cycles and does not affect functionality */ + dly--; + udelay(1); + if (dly == 0) + break; + } + adap_emac->TX0CP = cnt; + adap_emac->TX0HDP = 0; + } else { + /* Init RX channel teardown */ + adap_emac->RXTEARDOWN = 1; + for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->RX0CP) { + /* Wait here for Rx teardown completion interrupt to occur + * Note: A task delay can be called here to pend rather than + * occupying CPU cycles - anyway it has been found that teardown + * takes very few cpu cycles and does not affect functionality */ + dly--; + udelay(1); + if (dly == 0) + break; + } + adap_emac->RX0CP = cnt; + adap_emac->RX0HDP = 0; + } + + debug_emac("- emac_ch_teardown\n"); +} + +/* Eth device close */ +static void da8xx_eth_close(struct eth_device *dev) +{ + debug_emac("+ emac_close\n"); + + da8xx_eth_ch_teardown(EMAC_CH_TX); /* TX Channel teardown */ + da8xx_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */ + + /* Reset EMAC module and disable interrupts in wrapper */ + adap_emac->SOFTRESET = 1; + adap_ewrap->SOFTRESET = 1; + + adap_ewrap->C0RXEN = adap_ewrap->C1RXEN = adap_ewrap->C2RXEN = 0; + adap_ewrap->C0TXEN = adap_ewrap->C1TXEN = adap_ewrap->C2TXEN = 0; + adap_ewrap->C0MISCEN = adap_ewrap->C1MISCEN = adap_ewrap->C2MISCEN = 0; + + debug_emac("- emac_close\n"); +} + +static int tx_send_loop = 0; + +/* + * This function sends a single packet on the network and returns + * positive number (number of bytes transmitted) or negative for error + */ +static int da8xx_eth_send_packet(struct eth_device *dev, volatile void *packet, int length) +{ + int ret_status = -1; + tx_send_loop = 0; + + /* Return error if no link */ + if (!phy.get_link_speed(active_phy_addr)) + { + printf("WARN: emac_send_packet: No link\n"); + return (ret_status); + } + + /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */ + if (length < EMAC_MIN_ETHERNET_PKT_SIZE) + { + length = EMAC_MIN_ETHERNET_PKT_SIZE; + } + + /* Populate the TX descriptor */ + emac_tx_desc->next = 0; + emac_tx_desc->buffer = (u_int8_t *)packet; + emac_tx_desc->buff_off_len = (length & 0xffff); + emac_tx_desc->pkt_flag_len = ((length & 0xffff) | + EMAC_CPPI_SOP_BIT | + EMAC_CPPI_OWNERSHIP_BIT | + EMAC_CPPI_EOP_BIT); + /* Send the packet */ + adap_emac->TX0HDP = (unsigned int)emac_tx_desc; + + /* Wait for packet to complete or link down */ + while (1) { + if (!phy.get_link_speed(active_phy_addr)) { + da8xx_eth_ch_teardown(EMAC_CH_TX); + return (ret_status); + } + if (adap_emac->TXINTSTATRAW & 0x01) { + ret_status = length; + break; + } + tx_send_loop++; + } + + return(ret_status); +} + +/* + * This function handles receipt of a packet from the network + */ +static int da8xx_eth_rcv_packet(struct eth_device *dev) +{ + volatile emac_desc *rx_curr_desc; + volatile emac_desc *curr_desc; + volatile emac_desc *tail_desc; + int status, ret = -1; + + rx_curr_desc = emac_rx_active_head; + status = rx_curr_desc->pkt_flag_len; + if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) { + if (status & EMAC_CPPI_RX_ERROR_FRAME) { + /* Error in packet - discard it and requeue desc */ + printf("WARN: emac_rcv_pkt: Error in packet\n"); + } else { + NetReceive(rx_curr_desc->buffer, (rx_curr_desc->buff_off_len & 0xffff)); + ret = rx_curr_desc->buff_off_len & 0xffff; + } + + /* Ack received packet descriptor */ + adap_emac->RX0CP = (unsigned int)rx_curr_desc; + curr_desc = rx_curr_desc; + emac_rx_active_head = (volatile emac_desc *)rx_curr_desc->next; + + if (status & EMAC_CPPI_EOQ_BIT) { + if (emac_rx_active_head) { + adap_emac->RX0HDP = (unsigned int)emac_rx_active_head; + } else { + emac_rx_queue_active = 0; + printf("INFO:emac_rcv_packet: RX Queue not active\n"); + } + } + + /* Recycle RX descriptor */ + rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; + rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; + rx_curr_desc->next = 0; + + if (emac_rx_active_head == 0) { + printf("INFO: emac_rcv_pkt: active queue head = 0\n"); + emac_rx_active_head = curr_desc; + emac_rx_active_tail = curr_desc; + if (emac_rx_queue_active != 0) { + adap_emac->RX0HDP = (unsigned int)emac_rx_active_head; + printf("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n"); + emac_rx_queue_active = 1; + } + } else { + tail_desc = emac_rx_active_tail; + emac_rx_active_tail = curr_desc; + tail_desc->next = (unsigned int)curr_desc; + status = tail_desc->pkt_flag_len; + if (status & EMAC_CPPI_EOQ_BIT) { + adap_emac->RX0HDP = (unsigned int)curr_desc; + status &= ~EMAC_CPPI_EOQ_BIT; + tail_desc->pkt_flag_len = status; + } + } + return(ret); + } + return(0); +} + +#endif /* CONFIG_CMD_NET */ + +#endif /* CONFIG_DRIVER_DA8XX_EMAC */

Hi Nick,
Thompson, Nick (GE EntSol, Intelligent Platforms) wrote:
Add a driver for the DA830 EMAC.
This is very similar to the davinci_emac driver. It has been restructured to make it as similar as possible. Potentially the two could be merged, but I don't have access to other davinci type platforms to test for breakage after the inevitable mangling required.
There are enough similarities between this and the in-tree Davinci code that it makes no sense to have a different driver. It also appears like you used an older Davinci driver as your source.
Don't worry so much about not being able to test on other hardware, since other people can. Just try your best to not break anything, and post the patches.
As a general comment, please take great care to ensure that no lines have more than 78 characters, and that indentation is consistently by TAB, with tab width of 8 characters. Your patch has inconsistent indentation and long lines.
regards, Ben

Thompson, Nick (GE EntSol, Intelligent Platforms) wrote:
Add a driver for the DA830 EMAC.
This is very similar to the davinci_emac driver. It has been restructured to make it as similar as possible. Potentially the two could be merged, but I don't have access to other davinci type platforms to test for breakage after the inevitable mangling required.
Signed-off-by: Nick Thompson nick.thompson@gefanuc.com
Ben, Can I pass this review off to you ? Tom
Applies to u-boot-ti
drivers/net/Makefile | 1 + drivers/net/da8xx_emac.c | 654 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 655 insertions(+), 0 deletions(-)
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index be5c484..9cbe736 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -68,6 +68,7 @@ COBJS-$(CONFIG_DRIVER_SMC91111) += smc91111.o COBJS-$(CONFIG_SMC911X) += smc911x.o COBJS-$(CONFIG_TIGON3) += tigon3.o bcm570x_autoneg.o 5701rls.o COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o +COBJS-$(CONFIG_DRIVER_DA8XX_EMAC) += da8xx_emac.o COBJS-$(CONFIG_TSEC_ENET) += tsec.o COBJS-$(CONFIG_TSI108_ETH) += tsi108_eth.o COBJS-$(CONFIG_ULI526X) += uli526x.o diff --git a/drivers/net/da8xx_emac.c b/drivers/net/da8xx_emac.c new file mode 100644 index 0000000..e1d232f --- /dev/null +++ b/drivers/net/da8xx_emac.c @@ -0,0 +1,654 @@ +/*
- Ethernet driver for TI OMAP-L1x/DA8xx chips.
- Copyright (C) 2009 Nick Thompson, GE Fanuc, Ltd. nick.thompson@gefanuc.com
- Much of this is very similar to the davinci_emac driver. Possibly they
- could be merged, but I have no access to non DA8xx platforms
- and can't test for breakage after the inevitable mangling.
- Code base is not new. Original copyright follows:
- Ethernet driver for TI TMS320DM644x (DaVinci) chips.
- Copyright (C) 2007 Sergey Kubushyn ksi@koi8.net
- Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright
- follows:
- dm644x_emac.c
- TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM
- Copyright (C) 2005 Texas Instruments.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+#include <common.h> +#include <command.h> +#include <net.h> +#include <miiphy.h> +#include <malloc.h> +#include <asm/arch/emac_defs.h>
+#ifdef CONFIG_DRIVER_DA8XX_EMAC
+#ifdef CONFIG_CMD_NET
+unsigned int emac_dbg = 0; +#define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args)
+/* Internal static functions */ +static int da8xx_eth_open (struct eth_device *dev, bd_t *bis); +static void da8xx_eth_close (struct eth_device *dev); +static int da8xx_eth_send_packet (struct eth_device *dev, volatile void *packet, int length); +static int da8xx_eth_rcv_packet (struct eth_device *dev); +static void da8xx_eth_mdio_enable(void);
+static int gen_init_phy(int phy_addr); +static int gen_is_phy_connected(int phy_addr); +static int gen_get_link_speed(int phy_addr); +static int gen_auto_negotiate(int phy_addr);
+/* mac address for EMAC registers only (not packet data) */ +static u_int8_t da8xx_eth_mac_addr[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0x00 };
+/*
- This function must be called before emac_open() if you want to override
- the default mac address.
- */
+void da8xx_eth_set_mac_addr(const u_int8_t *addr) +{
- int i;
- for (i = 0; i < sizeof (da8xx_eth_mac_addr); i++) {
da8xx_eth_mac_addr[i] = addr[i];
- }
+}
+/* EMAC Addresses */ +static volatile emac_regs *adap_emac = (emac_regs *)EMAC_BASE_ADDR; +static volatile ewrap_regs *adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR; +static volatile mdio_regs *adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR;
+/* EMAC descriptors */ +static volatile emac_desc *emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE); +static volatile emac_desc *emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE); +static volatile emac_desc *emac_rx_active_head = 0; +static volatile emac_desc *emac_rx_active_tail = 0; +static int emac_rx_queue_active = 0;
+/* Receive packet buffers */ +static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)];
+/* PHY address for a discovered PHY (0xff - not found) */ +static volatile u_int8_t active_phy_addr = 0xff;
+static int no_phy_init (int phy_addr) { return(1); } +static int no_phy_is_connected (int phy_addr) { return(1); } +static int no_phy_get_link_speed (int phy_addr) { return(1); } +static int no_phy_auto_negotiate (int phy_addr) { return(1); } +phy_t phy = {
- .name = "da8xx_evm",
- .init = no_phy_init,
- .is_phy_connected = no_phy_is_connected,
- .get_link_speed = no_phy_get_link_speed,
- .auto_negotiate = no_phy_auto_negotiate
+};
+static void da8xx_eth_mdio_enable(void) +{
- u_int32_t clkdiv;
- clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
- adap_mdio->CONTROL = (clkdiv & 0xff) |
MDIO_CONTROL_ENABLE |
MDIO_CONTROL_FAULT |
MDIO_CONTROL_FAULT_ENABLE;
- while (adap_mdio->CONTROL & MDIO_CONTROL_IDLE) {;}
+}
+/*
- Tries to find an active connected PHY. Returns 1 if address if found.
- If no active PHY found returns 0. If more than one active PHY (switch)
- returns 2
- Sets active_phy_addr variable when returns 1.
- */
+static int da8xx_eth_phy_detect(void) +{
- u_int32_t phy_act_state;
- int i;
- active_phy_addr = 0xff;
- if ((phy_act_state = adap_mdio->ALIVE) == 0)
return(0); /* No active PHYs */
- debug_emac("da8xx_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state);
- for (i = 0; i < 32; i++) {
if (phy_act_state & (1 << i)) {
if (phy_act_state & ~(1 << i))
return(2); /* More than one PHY */
else {
active_phy_addr = i;
return(1);
}
}
- }
- return(0); /* Just to make GCC happy */
+}
+/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */ +int da8xx_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data) +{
- int tmp;
- while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;}
- adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO |
MDIO_USERACCESS0_WRITE_READ |
((reg_num & 0x1f) << 21) |
((phy_addr & 0x1f) << 16);
- /* Wait for command to complete */
- while ((tmp = adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) {;}
- if (tmp & MDIO_USERACCESS0_ACK) {
*data = tmp & 0xffff;
return(1);
- }
- *data = -1;
- return(0);
+}
+/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */ +int da8xx_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data) +{
- while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;}
- adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO |
MDIO_USERACCESS0_WRITE_WRITE |
((reg_num & 0x1f) << 21) |
((phy_addr & 0x1f) << 16) |
(data & 0xffff);
- /* Wait for command to complete */
- while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;}
- return(1);
+}
+/* PHY functions for a generic PHY */ +static int gen_init_phy(int phy_addr) +{
- int ret = 1;
- if (gen_get_link_speed(phy_addr)) {
/* Try another time */
ret = gen_get_link_speed(phy_addr);
- }
- return(ret);
+}
+static int gen_is_phy_connected(int phy_addr) +{
- u_int16_t dummy;
- return(da8xx_eth_phy_read(phy_addr, PHY_PHYIDR1, &dummy));
+}
+static int gen_get_link_speed(int phy_addr) +{
- u_int16_t tmp;
- if (da8xx_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp) && (tmp & 0x04))
return(1);
- return(0);
+}
+static int gen_auto_negotiate(int phy_addr) +{
- u_int16_t tmp;
- if (!da8xx_eth_phy_read(phy_addr, PHY_BMCR, &tmp))
return(0);
- /* Restart Auto_negotiation */
- tmp |= PHY_BMCR_AUTON;
- da8xx_eth_phy_write(phy_addr, PHY_BMCR, tmp);
- /*check AutoNegotiate complete */
- udelay (10000);
- if (!da8xx_eth_phy_read(phy_addr, PHY_BMSR, &tmp))
return(0);
- if (!(tmp & PHY_BMSR_AUTN_COMP))
return(0);
- return(gen_get_link_speed(phy_addr));
+} +/* End of generic PHY functions */
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +static int da8xx_mii_phy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short *value) +{
- return(da8xx_eth_phy_read(addr, reg, value) ? 0 : 1);
+}
+static int da8xx_mii_phy_write(char *devname, unsigned char addr, unsigned char reg, unsigned short value) +{
- return(da8xx_eth_phy_write(addr, reg, value) ? 0 : 1);
+}
+#endif
+/*
- This function initializes the emac hardware. It does NOT initialize
- EMAC modules power or pin multiplexors, that is done by board_init()
- much earlier in bootup process. Returns 1 on success, 0 otherwise.
- */
+int da8xx_eth_hw_init(void) +{
- u_int32_t phy_id;
- u_int16_t tmp;
- int i, ret;
- struct eth_device *dev;
- /* register the ethernet driver functions */
- dev = malloc(sizeof *dev);
- if (dev == NULL) {
return -1;
- }
- dev->iobase = 0;
- dev->init = da8xx_eth_open;
- dev->halt = da8xx_eth_close;
- dev->send = da8xx_eth_send_packet;
- dev->recv = da8xx_eth_rcv_packet;
- eth_register(dev);
- /* The RMII clock can be sources internally through the SYSCLK7
* or can come externally through a dedicated pin. This selection is
* controlled by PinMux9[21]. PinMux registers are off-limits for ARM.
* In short, we just assume there is a 50MHz RMII clock available.
*/
- da8xx_eth_mdio_enable();
- for (i = 0; i < 256; i++) {
if (adap_mdio->ALIVE)
break;
udelay(1000);
- }
- if (i >= 256) {
printf("No ETH PHY detected!!!\n");
return(0);
- }
- /* Find if a PHY is connected and get it's address */
- ret = da8xx_eth_phy_detect();
- if (ret == 0)
return 0;
- if (ret == 2) {
printf("More than one PHY detected.\n");
- } else {
/* Get PHY ID and initialize phy_ops for a detected PHY */
if (!da8xx_eth_phy_read(active_phy_addr, PHY_PHYIDR1, &tmp)) {
active_phy_addr = 0xff;
return(0);
}
phy_id = (tmp << 16) & 0xffff0000;
if (!da8xx_eth_phy_read(active_phy_addr, PHY_PHYIDR2, &tmp)) {
active_phy_addr = 0xff;
return(0);
}
phy_id |= tmp & 0x0000ffff;
switch (phy_id) {
default:
sprintf(phy.name, "GENERIC @ 0x%02x", active_phy_addr);
phy.init = gen_init_phy;
phy.is_phy_connected = gen_is_phy_connected;
phy.get_link_speed = gen_get_link_speed;
phy.auto_negotiate = gen_auto_negotiate;
}
- }
- miiphy_register(phy.name, da8xx_mii_phy_read, da8xx_mii_phy_write);
- return(1);
+}
+/* Eth device open */ +static int da8xx_eth_open(struct eth_device *dev, bd_t *bis) +{
- dv_reg_p addr;
- u_int32_t clkdiv, cnt;
- volatile emac_desc *rx_desc;
- int i;
- debug_emac("+ emac_open\n");
- /* Reset EMAC module and disable interrupts in wrapper */
- adap_emac->SOFTRESET = 1;
- while (adap_emac->SOFTRESET != 0) {;}
- adap_ewrap->SOFTRESET = 1;
- while (adap_ewrap->SOFTRESET != 0) {;}
- adap_ewrap->C0RXEN = adap_ewrap->C1RXEN = adap_ewrap->C2RXEN = 0;
- adap_ewrap->C0TXEN = adap_ewrap->C1TXEN = adap_ewrap->C2TXEN = 0;
- adap_ewrap->C0MISCEN = adap_ewrap->C1MISCEN = adap_ewrap->C2MISCEN = 0;
- rx_desc = emac_rx_desc;
- adap_emac->TXCONTROL = 0x01;
- adap_emac->RXCONTROL = 0x01;
- /* Set MAC Addresses & Init multicast Hash to 0 (disable any multicast receive) */
- /* Using channel 0 only - other channels are disabled */
- for (i = 0; i < 8; i++) {
adap_emac->MACINDEX = i;
adap_emac->MACADDRHI =
(da8xx_eth_mac_addr[3] << 24) | /* bits 23-16 */
(da8xx_eth_mac_addr[2] << 16) | /* bits 31-24 */
(da8xx_eth_mac_addr[1] << 8) | /* bits 39-32 */
(da8xx_eth_mac_addr[0]); /* bits 47-40 */
adap_emac->MACADDRLO =
(da8xx_eth_mac_addr[5] << 8) | /* bits 8-0*/
(da8xx_eth_mac_addr[4]) | (1 << 19) | (1 << 20); /* bits 8-0 */
- }
- adap_emac->MACHASH1 = 0;
- adap_emac->MACHASH2 = 0;
- /* Set source MAC address - REQUIRED for pause frames */
- adap_emac->MACSRCADDRHI =
(da8xx_eth_mac_addr[3] << 24) | /* bits 23-16 */
(da8xx_eth_mac_addr[2] << 16) | /* bits 31-24 */
(da8xx_eth_mac_addr[1] << 8) | /* bits 39-32 */
(da8xx_eth_mac_addr[0]); /* bits 47-40 */
- adap_emac->MACSRCADDRLO =
(da8xx_eth_mac_addr[5] << 8) | /* bits 8-0 */
(da8xx_eth_mac_addr[4]); /* bits 15-8 */
- /* Set DMA 8 TX / 8 RX Head pointers to 0 */
- addr = &adap_emac->TX0HDP;
- for(cnt = 0; cnt < 16; cnt++)
*addr++ = 0;
- addr = &adap_emac->TX0CP;
- for(cnt = 0; cnt < 16; cnt++)
*addr++ = 0;
- /* Clear Statistics (do this before setting MacControl register) */
- addr = &adap_emac->RXGOODFRAMES;
- for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
*addr++ = 0;
- /* No multicast addressing */
- adap_emac->MACHASH1 = 0;
- adap_emac->MACHASH2 = 0;
- /* Create RX queue and set receive process in place */
- emac_rx_active_head = emac_rx_desc;
- for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) {
rx_desc->next = (u_int32_t)(rx_desc + 1);
rx_desc->buffer = &emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)];
rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
rx_desc++;
- }
- /* Set the last descriptor's "next" parameter to 0 to end the RX desc list */
- rx_desc--;
- rx_desc->next = 0;
- emac_rx_active_tail = rx_desc;
- emac_rx_queue_active = 1;
- /* Enable TX/RX */
- adap_emac->RXMAXLEN = EMAC_MAX_ETHERNET_PKT_SIZE;
- adap_emac->RXBUFFEROFFSET = 0;
- /* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */
- adap_emac->RXMBPENABLE = EMAC_RXMBPENABLE_RXBROADEN;
- /* Enable ch 0 only */
- adap_emac->RXUNICASTSET = 0x01;
- /* Enable MII interface and Full duplex mode */
- adap_emac->MACCONTROL = (EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE) | EMAC_MACCONTROL_RMIISPEED_100;
- /* Init MDIO & get link state */
- clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
- adap_mdio->CONTROL = ((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT);
- if (!phy.get_link_speed(active_phy_addr))
return(0);
- /* Start receive process */
- adap_emac->RX0HDP = (u_int32_t)emac_rx_desc;
- debug_emac("- emac_open\n");
- return(1);
+}
+/* EMAC Channel Teardown */ +static void da8xx_eth_ch_teardown(int ch) +{
- dv_reg dly = 0xff;
- dv_reg cnt;
- debug_emac("+ emac_ch_teardown\n");
- if (ch == EMAC_CH_TX) {
/* Init TX channel teardown */
adap_emac->TXTEARDOWN = 1;
for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->TX0CP) {
/* Wait here for Tx teardown completion interrupt to occur
* Note: A task delay can be called here to pend rather than
* occupying CPU cycles - anyway it has been found that teardown
* takes very few cpu cycles and does not affect functionality */
dly--;
udelay(1);
if (dly == 0)
break;
}
adap_emac->TX0CP = cnt;
adap_emac->TX0HDP = 0;
- } else {
/* Init RX channel teardown */
adap_emac->RXTEARDOWN = 1;
for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->RX0CP) {
/* Wait here for Rx teardown completion interrupt to occur
* Note: A task delay can be called here to pend rather than
* occupying CPU cycles - anyway it has been found that teardown
* takes very few cpu cycles and does not affect functionality */
dly--;
udelay(1);
if (dly == 0)
break;
}
adap_emac->RX0CP = cnt;
adap_emac->RX0HDP = 0;
- }
- debug_emac("- emac_ch_teardown\n");
+}
+/* Eth device close */ +static void da8xx_eth_close(struct eth_device *dev) +{
- debug_emac("+ emac_close\n");
- da8xx_eth_ch_teardown(EMAC_CH_TX); /* TX Channel teardown */
- da8xx_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */
- /* Reset EMAC module and disable interrupts in wrapper */
- adap_emac->SOFTRESET = 1;
- adap_ewrap->SOFTRESET = 1;
- adap_ewrap->C0RXEN = adap_ewrap->C1RXEN = adap_ewrap->C2RXEN = 0;
- adap_ewrap->C0TXEN = adap_ewrap->C1TXEN = adap_ewrap->C2TXEN = 0;
- adap_ewrap->C0MISCEN = adap_ewrap->C1MISCEN = adap_ewrap->C2MISCEN = 0;
- debug_emac("- emac_close\n");
+}
+static int tx_send_loop = 0;
+/*
- This function sends a single packet on the network and returns
- positive number (number of bytes transmitted) or negative for error
- */
+static int da8xx_eth_send_packet(struct eth_device *dev, volatile void *packet, int length) +{
- int ret_status = -1;
- tx_send_loop = 0;
- /* Return error if no link */
- if (!phy.get_link_speed(active_phy_addr))
- {
printf("WARN: emac_send_packet: No link\n");
return (ret_status);
- }
- /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */
- if (length < EMAC_MIN_ETHERNET_PKT_SIZE)
- {
length = EMAC_MIN_ETHERNET_PKT_SIZE;
- }
- /* Populate the TX descriptor */
- emac_tx_desc->next = 0;
- emac_tx_desc->buffer = (u_int8_t *)packet;
- emac_tx_desc->buff_off_len = (length & 0xffff);
- emac_tx_desc->pkt_flag_len = ((length & 0xffff) |
EMAC_CPPI_SOP_BIT |
EMAC_CPPI_OWNERSHIP_BIT |
EMAC_CPPI_EOP_BIT);
- /* Send the packet */
- adap_emac->TX0HDP = (unsigned int)emac_tx_desc;
- /* Wait for packet to complete or link down */
- while (1) {
if (!phy.get_link_speed(active_phy_addr)) {
da8xx_eth_ch_teardown(EMAC_CH_TX);
return (ret_status);
}
if (adap_emac->TXINTSTATRAW & 0x01) {
ret_status = length;
break;
}
tx_send_loop++;
- }
- return(ret_status);
+}
+/*
- This function handles receipt of a packet from the network
- */
+static int da8xx_eth_rcv_packet(struct eth_device *dev) +{
- volatile emac_desc *rx_curr_desc;
- volatile emac_desc *curr_desc;
- volatile emac_desc *tail_desc;
- int status, ret = -1;
- rx_curr_desc = emac_rx_active_head;
- status = rx_curr_desc->pkt_flag_len;
- if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) {
if (status & EMAC_CPPI_RX_ERROR_FRAME) {
/* Error in packet - discard it and requeue desc */
printf("WARN: emac_rcv_pkt: Error in packet\n");
} else {
NetReceive(rx_curr_desc->buffer, (rx_curr_desc->buff_off_len & 0xffff));
ret = rx_curr_desc->buff_off_len & 0xffff;
}
/* Ack received packet descriptor */
adap_emac->RX0CP = (unsigned int)rx_curr_desc;
curr_desc = rx_curr_desc;
emac_rx_active_head = (volatile emac_desc *)rx_curr_desc->next;
if (status & EMAC_CPPI_EOQ_BIT) {
if (emac_rx_active_head) {
adap_emac->RX0HDP = (unsigned int)emac_rx_active_head;
} else {
emac_rx_queue_active = 0;
printf("INFO:emac_rcv_packet: RX Queue not active\n");
}
}
/* Recycle RX descriptor */
rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
rx_curr_desc->next = 0;
if (emac_rx_active_head == 0) {
printf("INFO: emac_rcv_pkt: active queue head = 0\n");
emac_rx_active_head = curr_desc;
emac_rx_active_tail = curr_desc;
if (emac_rx_queue_active != 0) {
adap_emac->RX0HDP = (unsigned int)emac_rx_active_head;
printf("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
emac_rx_queue_active = 1;
}
} else {
tail_desc = emac_rx_active_tail;
emac_rx_active_tail = curr_desc;
tail_desc->next = (unsigned int)curr_desc;
status = tail_desc->pkt_flag_len;
if (status & EMAC_CPPI_EOQ_BIT) {
adap_emac->RX0HDP = (unsigned int)curr_desc;
status &= ~EMAC_CPPI_EOQ_BIT;
tail_desc->pkt_flag_len = status;
}
}
return(ret);
- }
- return(0);
+}
+#endif /* CONFIG_CMD_NET */
+#endif /* CONFIG_DRIVER_DA8XX_EMAC */ _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hi Tom, On Sun, Oct 18, 2009 at 10:26 AM, Tom Tom.Rix@windriver.com wrote:
Thompson, Nick (GE EntSol, Intelligent Platforms) wrote:
Add a driver for the DA830 EMAC.
This is very similar to the davinci_emac driver. It has been restructured to make it as similar as possible. Potentially the two could be merged, but I don't have access to other davinci type platforms to test for breakage after the inevitable mangling required.
Signed-off-by: Nick Thompson nick.thompson@gefanuc.com
Ben, Can I pass this review off to you ? Tom
Yeah, I'll review the next spin. Since it won't require a new driver, it may make more sense to keep the patch parts together. Either way, I'll ACK/NAK it.
regards, Ben

Ben Warren wrote:
Hi Tom,
On Sun, Oct 18, 2009 at 10:26 AM, Tom <Tom.Rix@windriver.com mailto:Tom.Rix@windriver.com> wrote:
Thompson, Nick (GE EntSol, Intelligent Platforms) wrote: Add a driver for the DA830 EMAC. This is very similar to the davinci_emac driver. It has been restructured to make it as similar as possible. Potentially the two could be merged, but I don't have access to other davinci type platforms to test for breakage after the inevitable mangling required. Signed-off-by: Nick Thompson <nick.thompson@gefanuc.com <mailto:nick.thompson@gefanuc.com>> Ben, Can I pass this review off to you ? Tom
Yeah, I'll review the next spin. Since it won't require a new driver, it may make more sense to keep the patch parts together. Either way, I'll ACK/NAK it.
regards, Ben
Tom, Thank you for the very through review, I will go away and address the issues you raise and get some checking tools in place. Also I've figured out how to get Thunderbird on linux talking to my exchange server - I will test it's mangling abilities before my next patch.
Ben, You are right of course, I picked up the driver from an old TI u-boot and updated it for CONFIG_NET_MULTI, but shyed away from making functional changes as it seems to work just fine. I will switch to the davinci driver and pull in changes only as required - with inline statics where I can.
If I understood correctly, assuming the switch to davinci ethernet, you would prefer a single patch e-mail rather than 5? It will still be rather bigger than the 40kB suggested in the linux SubmittingPatches doc.
Thanks, Nick.
This next line is just a test please ignore: +static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)];

Nick Thompson wrote:
Ben Warren wrote:
Hi Tom,
On Sun, Oct 18, 2009 at 10:26 AM, Tom <Tom.Rix@windriver.com mailto:Tom.Rix@windriver.com> wrote:
Thompson, Nick (GE EntSol, Intelligent Platforms) wrote: Add a driver for the DA830 EMAC. This is very similar to the davinci_emac driver. It has been restructured to make it as similar as possible. Potentially the two could be merged, but I don't have access to other davinci type platforms to test for breakage after the inevitable mangling required. Signed-off-by: Nick Thompson <nick.thompson@gefanuc.com <mailto:nick.thompson@gefanuc.com>> Ben, Can I pass this review off to you ? Tom
Yeah, I'll review the next spin. Since it won't require a new driver, it may make more sense to keep the patch parts together. Either way, I'll ACK/NAK it.
regards, Ben
Tom, Thank you for the very through review, I will go away and address the issues you raise and get some checking tools in place. Also I've figured out how to get Thunderbird on linux talking to my exchange server - I will test it's mangling abilities before my next patch.
Ben, You are right of course, I picked up the driver from an old TI u-boot and updated it for CONFIG_NET_MULTI, but shyed away from making functional changes as it seems to work just fine. I will switch to the davinci driver and pull in changes only as required - with inline statics where I can.
If I understood correctly, assuming the switch to davinci ethernet, you would prefer a single patch e-mail rather than 5? It will still be rather bigger than the 40kB suggested in the linux SubmittingPatches doc.
The way you did it with 5 is preferred. The 4/5 is a NET patch and that must be reviewed by Ben. The others are TI/ARM patches.
Tom
Thanks, Nick.
This next line is just a test please ignore: +static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)];
participants (4)
-
Ben Warren
-
Nick Thompson
-
Thompson, Nick (GE EntSol, Intelligent Platforms)
-
Tom