1*09cdd1b9SBen Warren /* 2*09cdd1b9SBen Warren * Ethernet driver for TI TMS320DM644x (DaVinci) chips. 3*09cdd1b9SBen Warren * 4*09cdd1b9SBen Warren * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> 5*09cdd1b9SBen Warren * 6*09cdd1b9SBen Warren * Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright 7*09cdd1b9SBen Warren * follows: 8*09cdd1b9SBen Warren * 9*09cdd1b9SBen Warren * ---------------------------------------------------------------------------- 10*09cdd1b9SBen Warren * 11*09cdd1b9SBen Warren * dm644x_emac.c 12*09cdd1b9SBen Warren * 13*09cdd1b9SBen Warren * TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM 14*09cdd1b9SBen Warren * 15*09cdd1b9SBen Warren * Copyright (C) 2005 Texas Instruments. 16*09cdd1b9SBen Warren * 17*09cdd1b9SBen Warren * ---------------------------------------------------------------------------- 18*09cdd1b9SBen Warren * 19*09cdd1b9SBen Warren * This program is free software; you can redistribute it and/or modify 20*09cdd1b9SBen Warren * it under the terms of the GNU General Public License as published by 21*09cdd1b9SBen Warren * the Free Software Foundation; either version 2 of the License, or 22*09cdd1b9SBen Warren * (at your option) any later version. 23*09cdd1b9SBen Warren * 24*09cdd1b9SBen Warren * This program is distributed in the hope that it will be useful, 25*09cdd1b9SBen Warren * but WITHOUT ANY WARRANTY; without even the implied warranty of 26*09cdd1b9SBen Warren * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27*09cdd1b9SBen Warren * GNU General Public License for more details. 28*09cdd1b9SBen Warren * 29*09cdd1b9SBen Warren * You should have received a copy of the GNU General Public License 30*09cdd1b9SBen Warren * along with this program; if not, write to the Free Software 31*09cdd1b9SBen Warren * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 32*09cdd1b9SBen Warren * ---------------------------------------------------------------------------- 33*09cdd1b9SBen Warren 34*09cdd1b9SBen Warren * Modifications: 35*09cdd1b9SBen Warren * ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot. 36*09cdd1b9SBen Warren * ver 1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors 37*09cdd1b9SBen Warren * 38*09cdd1b9SBen Warren */ 39*09cdd1b9SBen Warren #include <common.h> 40*09cdd1b9SBen Warren #include <command.h> 41*09cdd1b9SBen Warren #include <net.h> 42*09cdd1b9SBen Warren #include <miiphy.h> 43*09cdd1b9SBen Warren #include <asm/arch/emac_defs.h> 44*09cdd1b9SBen Warren 45*09cdd1b9SBen Warren #ifdef CONFIG_DRIVER_TI_EMAC 46*09cdd1b9SBen Warren 47*09cdd1b9SBen Warren #ifdef CONFIG_CMD_NET 48*09cdd1b9SBen Warren 49*09cdd1b9SBen Warren unsigned int emac_dbg = 0; 50*09cdd1b9SBen Warren #define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args) 51*09cdd1b9SBen Warren 52*09cdd1b9SBen Warren /* Internal static functions */ 53*09cdd1b9SBen Warren static int davinci_eth_hw_init (void); 54*09cdd1b9SBen Warren static int davinci_eth_open (void); 55*09cdd1b9SBen Warren static int davinci_eth_close (void); 56*09cdd1b9SBen Warren static int davinci_eth_send_packet (volatile void *packet, int length); 57*09cdd1b9SBen Warren static int davinci_eth_rcv_packet (void); 58*09cdd1b9SBen Warren static void davinci_eth_mdio_enable(void); 59*09cdd1b9SBen Warren 60*09cdd1b9SBen Warren static int gen_init_phy(int phy_addr); 61*09cdd1b9SBen Warren static int gen_is_phy_connected(int phy_addr); 62*09cdd1b9SBen Warren static int gen_get_link_speed(int phy_addr); 63*09cdd1b9SBen Warren static int gen_auto_negotiate(int phy_addr); 64*09cdd1b9SBen Warren 65*09cdd1b9SBen Warren /* Wrappers exported to the U-Boot proper */ 66*09cdd1b9SBen Warren int eth_hw_init(void) 67*09cdd1b9SBen Warren { 68*09cdd1b9SBen Warren return(davinci_eth_hw_init()); 69*09cdd1b9SBen Warren } 70*09cdd1b9SBen Warren 71*09cdd1b9SBen Warren int eth_init(bd_t * bd) 72*09cdd1b9SBen Warren { 73*09cdd1b9SBen Warren return(davinci_eth_open()); 74*09cdd1b9SBen Warren } 75*09cdd1b9SBen Warren 76*09cdd1b9SBen Warren void eth_halt(void) 77*09cdd1b9SBen Warren { 78*09cdd1b9SBen Warren davinci_eth_close(); 79*09cdd1b9SBen Warren } 80*09cdd1b9SBen Warren 81*09cdd1b9SBen Warren int eth_send(volatile void *packet, int length) 82*09cdd1b9SBen Warren { 83*09cdd1b9SBen Warren return(davinci_eth_send_packet(packet, length)); 84*09cdd1b9SBen Warren } 85*09cdd1b9SBen Warren 86*09cdd1b9SBen Warren int eth_rx(void) 87*09cdd1b9SBen Warren { 88*09cdd1b9SBen Warren return(davinci_eth_rcv_packet()); 89*09cdd1b9SBen Warren } 90*09cdd1b9SBen Warren 91*09cdd1b9SBen Warren void eth_mdio_enable(void) 92*09cdd1b9SBen Warren { 93*09cdd1b9SBen Warren davinci_eth_mdio_enable(); 94*09cdd1b9SBen Warren } 95*09cdd1b9SBen Warren /* End of wrappers */ 96*09cdd1b9SBen Warren 97*09cdd1b9SBen Warren 98*09cdd1b9SBen Warren static u_int8_t davinci_eth_mac_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 99*09cdd1b9SBen Warren 100*09cdd1b9SBen Warren /* 101*09cdd1b9SBen Warren * This function must be called before emac_open() if you want to override 102*09cdd1b9SBen Warren * the default mac address. 103*09cdd1b9SBen Warren */ 104*09cdd1b9SBen Warren void davinci_eth_set_mac_addr(const u_int8_t *addr) 105*09cdd1b9SBen Warren { 106*09cdd1b9SBen Warren int i; 107*09cdd1b9SBen Warren 108*09cdd1b9SBen Warren for (i = 0; i < sizeof (davinci_eth_mac_addr); i++) { 109*09cdd1b9SBen Warren davinci_eth_mac_addr[i] = addr[i]; 110*09cdd1b9SBen Warren } 111*09cdd1b9SBen Warren } 112*09cdd1b9SBen Warren 113*09cdd1b9SBen Warren /* EMAC Addresses */ 114*09cdd1b9SBen Warren static volatile emac_regs *adap_emac = (emac_regs *)EMAC_BASE_ADDR; 115*09cdd1b9SBen Warren static volatile ewrap_regs *adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR; 116*09cdd1b9SBen Warren static volatile mdio_regs *adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR; 117*09cdd1b9SBen Warren 118*09cdd1b9SBen Warren /* EMAC descriptors */ 119*09cdd1b9SBen Warren static volatile emac_desc *emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE); 120*09cdd1b9SBen Warren static volatile emac_desc *emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE); 121*09cdd1b9SBen Warren static volatile emac_desc *emac_rx_active_head = 0; 122*09cdd1b9SBen Warren static volatile emac_desc *emac_rx_active_tail = 0; 123*09cdd1b9SBen Warren static int emac_rx_queue_active = 0; 124*09cdd1b9SBen Warren 125*09cdd1b9SBen Warren /* Receive packet buffers */ 126*09cdd1b9SBen Warren static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; 127*09cdd1b9SBen Warren 128*09cdd1b9SBen Warren /* PHY address for a discovered PHY (0xff - not found) */ 129*09cdd1b9SBen Warren static volatile u_int8_t active_phy_addr = 0xff; 130*09cdd1b9SBen Warren 131*09cdd1b9SBen Warren phy_t phy; 132*09cdd1b9SBen Warren 133*09cdd1b9SBen Warren static void davinci_eth_mdio_enable(void) 134*09cdd1b9SBen Warren { 135*09cdd1b9SBen Warren u_int32_t clkdiv; 136*09cdd1b9SBen Warren 137*09cdd1b9SBen Warren clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; 138*09cdd1b9SBen Warren 139*09cdd1b9SBen Warren adap_mdio->CONTROL = (clkdiv & 0xff) | 140*09cdd1b9SBen Warren MDIO_CONTROL_ENABLE | 141*09cdd1b9SBen Warren MDIO_CONTROL_FAULT | 142*09cdd1b9SBen Warren MDIO_CONTROL_FAULT_ENABLE; 143*09cdd1b9SBen Warren 144*09cdd1b9SBen Warren while (adap_mdio->CONTROL & MDIO_CONTROL_IDLE) {;} 145*09cdd1b9SBen Warren } 146*09cdd1b9SBen Warren 147*09cdd1b9SBen Warren /* 148*09cdd1b9SBen Warren * Tries to find an active connected PHY. Returns 1 if address if found. 149*09cdd1b9SBen Warren * If no active PHY (or more than one PHY) found returns 0. 150*09cdd1b9SBen Warren * Sets active_phy_addr variable. 151*09cdd1b9SBen Warren */ 152*09cdd1b9SBen Warren static int davinci_eth_phy_detect(void) 153*09cdd1b9SBen Warren { 154*09cdd1b9SBen Warren u_int32_t phy_act_state; 155*09cdd1b9SBen Warren int i; 156*09cdd1b9SBen Warren 157*09cdd1b9SBen Warren active_phy_addr = 0xff; 158*09cdd1b9SBen Warren 159*09cdd1b9SBen Warren if ((phy_act_state = adap_mdio->ALIVE) == 0) 160*09cdd1b9SBen Warren return(0); /* No active PHYs */ 161*09cdd1b9SBen Warren 162*09cdd1b9SBen Warren debug_emac("davinci_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state); 163*09cdd1b9SBen Warren 164*09cdd1b9SBen Warren for (i = 0; i < 32; i++) { 165*09cdd1b9SBen Warren if (phy_act_state & (1 << i)) { 166*09cdd1b9SBen Warren if (phy_act_state & ~(1 << i)) 167*09cdd1b9SBen Warren return(0); /* More than one PHY */ 168*09cdd1b9SBen Warren else { 169*09cdd1b9SBen Warren active_phy_addr = i; 170*09cdd1b9SBen Warren return(1); 171*09cdd1b9SBen Warren } 172*09cdd1b9SBen Warren } 173*09cdd1b9SBen Warren } 174*09cdd1b9SBen Warren 175*09cdd1b9SBen Warren return(0); /* Just to make GCC happy */ 176*09cdd1b9SBen Warren } 177*09cdd1b9SBen Warren 178*09cdd1b9SBen Warren 179*09cdd1b9SBen Warren /* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */ 180*09cdd1b9SBen Warren int davinci_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data) 181*09cdd1b9SBen Warren { 182*09cdd1b9SBen Warren int tmp; 183*09cdd1b9SBen Warren 184*09cdd1b9SBen Warren while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} 185*09cdd1b9SBen Warren 186*09cdd1b9SBen Warren adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | 187*09cdd1b9SBen Warren MDIO_USERACCESS0_WRITE_READ | 188*09cdd1b9SBen Warren ((reg_num & 0x1f) << 21) | 189*09cdd1b9SBen Warren ((phy_addr & 0x1f) << 16); 190*09cdd1b9SBen Warren 191*09cdd1b9SBen Warren /* Wait for command to complete */ 192*09cdd1b9SBen Warren while ((tmp = adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) {;} 193*09cdd1b9SBen Warren 194*09cdd1b9SBen Warren if (tmp & MDIO_USERACCESS0_ACK) { 195*09cdd1b9SBen Warren *data = tmp & 0xffff; 196*09cdd1b9SBen Warren return(1); 197*09cdd1b9SBen Warren } 198*09cdd1b9SBen Warren 199*09cdd1b9SBen Warren *data = -1; 200*09cdd1b9SBen Warren return(0); 201*09cdd1b9SBen Warren } 202*09cdd1b9SBen Warren 203*09cdd1b9SBen Warren /* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */ 204*09cdd1b9SBen Warren int davinci_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data) 205*09cdd1b9SBen Warren { 206*09cdd1b9SBen Warren 207*09cdd1b9SBen Warren while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} 208*09cdd1b9SBen Warren 209*09cdd1b9SBen Warren adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | 210*09cdd1b9SBen Warren MDIO_USERACCESS0_WRITE_WRITE | 211*09cdd1b9SBen Warren ((reg_num & 0x1f) << 21) | 212*09cdd1b9SBen Warren ((phy_addr & 0x1f) << 16) | 213*09cdd1b9SBen Warren (data & 0xffff); 214*09cdd1b9SBen Warren 215*09cdd1b9SBen Warren /* Wait for command to complete */ 216*09cdd1b9SBen Warren while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} 217*09cdd1b9SBen Warren 218*09cdd1b9SBen Warren return(1); 219*09cdd1b9SBen Warren } 220*09cdd1b9SBen Warren 221*09cdd1b9SBen Warren /* PHY functions for a generic PHY */ 222*09cdd1b9SBen Warren static int gen_init_phy(int phy_addr) 223*09cdd1b9SBen Warren { 224*09cdd1b9SBen Warren int ret = 1; 225*09cdd1b9SBen Warren 226*09cdd1b9SBen Warren if (gen_get_link_speed(phy_addr)) { 227*09cdd1b9SBen Warren /* Try another time */ 228*09cdd1b9SBen Warren ret = gen_get_link_speed(phy_addr); 229*09cdd1b9SBen Warren } 230*09cdd1b9SBen Warren 231*09cdd1b9SBen Warren return(ret); 232*09cdd1b9SBen Warren } 233*09cdd1b9SBen Warren 234*09cdd1b9SBen Warren static int gen_is_phy_connected(int phy_addr) 235*09cdd1b9SBen Warren { 236*09cdd1b9SBen Warren u_int16_t dummy; 237*09cdd1b9SBen Warren 238*09cdd1b9SBen Warren return(davinci_eth_phy_read(phy_addr, PHY_PHYIDR1, &dummy)); 239*09cdd1b9SBen Warren } 240*09cdd1b9SBen Warren 241*09cdd1b9SBen Warren static int gen_get_link_speed(int phy_addr) 242*09cdd1b9SBen Warren { 243*09cdd1b9SBen Warren u_int16_t tmp; 244*09cdd1b9SBen Warren 245*09cdd1b9SBen Warren if (davinci_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp) && (tmp & 0x04)) 246*09cdd1b9SBen Warren return(1); 247*09cdd1b9SBen Warren 248*09cdd1b9SBen Warren return(0); 249*09cdd1b9SBen Warren } 250*09cdd1b9SBen Warren 251*09cdd1b9SBen Warren static int gen_auto_negotiate(int phy_addr) 252*09cdd1b9SBen Warren { 253*09cdd1b9SBen Warren u_int16_t tmp; 254*09cdd1b9SBen Warren 255*09cdd1b9SBen Warren if (!davinci_eth_phy_read(phy_addr, PHY_BMCR, &tmp)) 256*09cdd1b9SBen Warren return(0); 257*09cdd1b9SBen Warren 258*09cdd1b9SBen Warren /* Restart Auto_negotiation */ 259*09cdd1b9SBen Warren tmp |= PHY_BMCR_AUTON; 260*09cdd1b9SBen Warren davinci_eth_phy_write(phy_addr, PHY_BMCR, tmp); 261*09cdd1b9SBen Warren 262*09cdd1b9SBen Warren /*check AutoNegotiate complete */ 263*09cdd1b9SBen Warren udelay (10000); 264*09cdd1b9SBen Warren if (!davinci_eth_phy_read(phy_addr, PHY_BMSR, &tmp)) 265*09cdd1b9SBen Warren return(0); 266*09cdd1b9SBen Warren 267*09cdd1b9SBen Warren if (!(tmp & PHY_BMSR_AUTN_COMP)) 268*09cdd1b9SBen Warren return(0); 269*09cdd1b9SBen Warren 270*09cdd1b9SBen Warren return(gen_get_link_speed(phy_addr)); 271*09cdd1b9SBen Warren } 272*09cdd1b9SBen Warren /* End of generic PHY functions */ 273*09cdd1b9SBen Warren 274*09cdd1b9SBen Warren 275*09cdd1b9SBen Warren #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) 276*09cdd1b9SBen Warren static int davinci_mii_phy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short *value) 277*09cdd1b9SBen Warren { 278*09cdd1b9SBen Warren return(davinci_eth_phy_read(addr, reg, value) ? 0 : 1); 279*09cdd1b9SBen Warren } 280*09cdd1b9SBen Warren 281*09cdd1b9SBen Warren static int davinci_mii_phy_write(char *devname, unsigned char addr, unsigned char reg, unsigned short value) 282*09cdd1b9SBen Warren { 283*09cdd1b9SBen Warren return(davinci_eth_phy_write(addr, reg, value) ? 0 : 1); 284*09cdd1b9SBen Warren } 285*09cdd1b9SBen Warren 286*09cdd1b9SBen Warren int davinci_eth_miiphy_initialize(bd_t *bis) 287*09cdd1b9SBen Warren { 288*09cdd1b9SBen Warren miiphy_register(phy.name, davinci_mii_phy_read, davinci_mii_phy_write); 289*09cdd1b9SBen Warren 290*09cdd1b9SBen Warren return(1); 291*09cdd1b9SBen Warren } 292*09cdd1b9SBen Warren #endif 293*09cdd1b9SBen Warren 294*09cdd1b9SBen Warren /* 295*09cdd1b9SBen Warren * This function initializes the emac hardware. It does NOT initialize 296*09cdd1b9SBen Warren * EMAC modules power or pin multiplexors, that is done by board_init() 297*09cdd1b9SBen Warren * much earlier in bootup process. Returns 1 on success, 0 otherwise. 298*09cdd1b9SBen Warren */ 299*09cdd1b9SBen Warren static int davinci_eth_hw_init(void) 300*09cdd1b9SBen Warren { 301*09cdd1b9SBen Warren u_int32_t phy_id; 302*09cdd1b9SBen Warren u_int16_t tmp; 303*09cdd1b9SBen Warren int i; 304*09cdd1b9SBen Warren 305*09cdd1b9SBen Warren davinci_eth_mdio_enable(); 306*09cdd1b9SBen Warren 307*09cdd1b9SBen Warren for (i = 0; i < 256; i++) { 308*09cdd1b9SBen Warren if (adap_mdio->ALIVE) 309*09cdd1b9SBen Warren break; 310*09cdd1b9SBen Warren udelay(10); 311*09cdd1b9SBen Warren } 312*09cdd1b9SBen Warren 313*09cdd1b9SBen Warren if (i >= 256) { 314*09cdd1b9SBen Warren printf("No ETH PHY detected!!!\n"); 315*09cdd1b9SBen Warren return(0); 316*09cdd1b9SBen Warren } 317*09cdd1b9SBen Warren 318*09cdd1b9SBen Warren /* Find if a PHY is connected and get it's address */ 319*09cdd1b9SBen Warren if (!davinci_eth_phy_detect()) 320*09cdd1b9SBen Warren return(0); 321*09cdd1b9SBen Warren 322*09cdd1b9SBen Warren /* Get PHY ID and initialize phy_ops for a detected PHY */ 323*09cdd1b9SBen Warren if (!davinci_eth_phy_read(active_phy_addr, PHY_PHYIDR1, &tmp)) { 324*09cdd1b9SBen Warren active_phy_addr = 0xff; 325*09cdd1b9SBen Warren return(0); 326*09cdd1b9SBen Warren } 327*09cdd1b9SBen Warren 328*09cdd1b9SBen Warren phy_id = (tmp << 16) & 0xffff0000; 329*09cdd1b9SBen Warren 330*09cdd1b9SBen Warren if (!davinci_eth_phy_read(active_phy_addr, PHY_PHYIDR2, &tmp)) { 331*09cdd1b9SBen Warren active_phy_addr = 0xff; 332*09cdd1b9SBen Warren return(0); 333*09cdd1b9SBen Warren } 334*09cdd1b9SBen Warren 335*09cdd1b9SBen Warren phy_id |= tmp & 0x0000ffff; 336*09cdd1b9SBen Warren 337*09cdd1b9SBen Warren switch (phy_id) { 338*09cdd1b9SBen Warren case PHY_LXT972: 339*09cdd1b9SBen Warren sprintf(phy.name, "LXT972 @ 0x%02x", active_phy_addr); 340*09cdd1b9SBen Warren phy.init = lxt972_init_phy; 341*09cdd1b9SBen Warren phy.is_phy_connected = lxt972_is_phy_connected; 342*09cdd1b9SBen Warren phy.get_link_speed = lxt972_get_link_speed; 343*09cdd1b9SBen Warren phy.auto_negotiate = lxt972_auto_negotiate; 344*09cdd1b9SBen Warren break; 345*09cdd1b9SBen Warren case PHY_DP83848: 346*09cdd1b9SBen Warren sprintf(phy.name, "DP83848 @ 0x%02x", active_phy_addr); 347*09cdd1b9SBen Warren phy.init = dp83848_init_phy; 348*09cdd1b9SBen Warren phy.is_phy_connected = dp83848_is_phy_connected; 349*09cdd1b9SBen Warren phy.get_link_speed = dp83848_get_link_speed; 350*09cdd1b9SBen Warren phy.auto_negotiate = dp83848_auto_negotiate; 351*09cdd1b9SBen Warren break; 352*09cdd1b9SBen Warren default: 353*09cdd1b9SBen Warren sprintf(phy.name, "GENERIC @ 0x%02x", active_phy_addr); 354*09cdd1b9SBen Warren phy.init = gen_init_phy; 355*09cdd1b9SBen Warren phy.is_phy_connected = gen_is_phy_connected; 356*09cdd1b9SBen Warren phy.get_link_speed = gen_get_link_speed; 357*09cdd1b9SBen Warren phy.auto_negotiate = gen_auto_negotiate; 358*09cdd1b9SBen Warren } 359*09cdd1b9SBen Warren 360*09cdd1b9SBen Warren printf("Ethernet PHY: %s\n", phy.name); 361*09cdd1b9SBen Warren 362*09cdd1b9SBen Warren return(1); 363*09cdd1b9SBen Warren } 364*09cdd1b9SBen Warren 365*09cdd1b9SBen Warren 366*09cdd1b9SBen Warren /* Eth device open */ 367*09cdd1b9SBen Warren static int davinci_eth_open(void) 368*09cdd1b9SBen Warren { 369*09cdd1b9SBen Warren dv_reg_p addr; 370*09cdd1b9SBen Warren u_int32_t clkdiv, cnt; 371*09cdd1b9SBen Warren volatile emac_desc *rx_desc; 372*09cdd1b9SBen Warren 373*09cdd1b9SBen Warren debug_emac("+ emac_open\n"); 374*09cdd1b9SBen Warren 375*09cdd1b9SBen Warren /* Reset EMAC module and disable interrupts in wrapper */ 376*09cdd1b9SBen Warren adap_emac->SOFTRESET = 1; 377*09cdd1b9SBen Warren while (adap_emac->SOFTRESET != 0) {;} 378*09cdd1b9SBen Warren adap_ewrap->EWCTL = 0; 379*09cdd1b9SBen Warren for (cnt = 0; cnt < 5; cnt++) { 380*09cdd1b9SBen Warren clkdiv = adap_ewrap->EWCTL; 381*09cdd1b9SBen Warren } 382*09cdd1b9SBen Warren 383*09cdd1b9SBen Warren rx_desc = emac_rx_desc; 384*09cdd1b9SBen Warren 385*09cdd1b9SBen Warren adap_emac->TXCONTROL = 0x01; 386*09cdd1b9SBen Warren adap_emac->RXCONTROL = 0x01; 387*09cdd1b9SBen Warren 388*09cdd1b9SBen Warren /* Set MAC Addresses & Init multicast Hash to 0 (disable any multicast receive) */ 389*09cdd1b9SBen Warren /* Using channel 0 only - other channels are disabled */ 390*09cdd1b9SBen Warren adap_emac->MACINDEX = 0; 391*09cdd1b9SBen Warren adap_emac->MACADDRHI = 392*09cdd1b9SBen Warren (davinci_eth_mac_addr[3] << 24) | 393*09cdd1b9SBen Warren (davinci_eth_mac_addr[2] << 16) | 394*09cdd1b9SBen Warren (davinci_eth_mac_addr[1] << 8) | 395*09cdd1b9SBen Warren (davinci_eth_mac_addr[0]); 396*09cdd1b9SBen Warren adap_emac->MACADDRLO = 397*09cdd1b9SBen Warren (davinci_eth_mac_addr[5] << 8) | 398*09cdd1b9SBen Warren (davinci_eth_mac_addr[4]); 399*09cdd1b9SBen Warren 400*09cdd1b9SBen Warren adap_emac->MACHASH1 = 0; 401*09cdd1b9SBen Warren adap_emac->MACHASH2 = 0; 402*09cdd1b9SBen Warren 403*09cdd1b9SBen Warren /* Set source MAC address - REQUIRED */ 404*09cdd1b9SBen Warren adap_emac->MACSRCADDRHI = 405*09cdd1b9SBen Warren (davinci_eth_mac_addr[3] << 24) | 406*09cdd1b9SBen Warren (davinci_eth_mac_addr[2] << 16) | 407*09cdd1b9SBen Warren (davinci_eth_mac_addr[1] << 8) | 408*09cdd1b9SBen Warren (davinci_eth_mac_addr[0]); 409*09cdd1b9SBen Warren adap_emac->MACSRCADDRLO = 410*09cdd1b9SBen Warren (davinci_eth_mac_addr[4] << 8) | 411*09cdd1b9SBen Warren (davinci_eth_mac_addr[5]); 412*09cdd1b9SBen Warren 413*09cdd1b9SBen Warren /* Set DMA 8 TX / 8 RX Head pointers to 0 */ 414*09cdd1b9SBen Warren addr = &adap_emac->TX0HDP; 415*09cdd1b9SBen Warren for(cnt = 0; cnt < 16; cnt++) 416*09cdd1b9SBen Warren *addr++ = 0; 417*09cdd1b9SBen Warren 418*09cdd1b9SBen Warren addr = &adap_emac->RX0HDP; 419*09cdd1b9SBen Warren for(cnt = 0; cnt < 16; cnt++) 420*09cdd1b9SBen Warren *addr++ = 0; 421*09cdd1b9SBen Warren 422*09cdd1b9SBen Warren /* Clear Statistics (do this before setting MacControl register) */ 423*09cdd1b9SBen Warren addr = &adap_emac->RXGOODFRAMES; 424*09cdd1b9SBen Warren for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++) 425*09cdd1b9SBen Warren *addr++ = 0; 426*09cdd1b9SBen Warren 427*09cdd1b9SBen Warren /* No multicast addressing */ 428*09cdd1b9SBen Warren adap_emac->MACHASH1 = 0; 429*09cdd1b9SBen Warren adap_emac->MACHASH2 = 0; 430*09cdd1b9SBen Warren 431*09cdd1b9SBen Warren /* Create RX queue and set receive process in place */ 432*09cdd1b9SBen Warren emac_rx_active_head = emac_rx_desc; 433*09cdd1b9SBen Warren for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) { 434*09cdd1b9SBen Warren rx_desc->next = (u_int32_t)(rx_desc + 1); 435*09cdd1b9SBen Warren rx_desc->buffer = &emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; 436*09cdd1b9SBen Warren rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; 437*09cdd1b9SBen Warren rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; 438*09cdd1b9SBen Warren rx_desc++; 439*09cdd1b9SBen Warren } 440*09cdd1b9SBen Warren 441*09cdd1b9SBen Warren /* Set the last descriptor's "next" parameter to 0 to end the RX desc list */ 442*09cdd1b9SBen Warren rx_desc--; 443*09cdd1b9SBen Warren rx_desc->next = 0; 444*09cdd1b9SBen Warren emac_rx_active_tail = rx_desc; 445*09cdd1b9SBen Warren emac_rx_queue_active = 1; 446*09cdd1b9SBen Warren 447*09cdd1b9SBen Warren /* Enable TX/RX */ 448*09cdd1b9SBen Warren adap_emac->RXMAXLEN = EMAC_MAX_ETHERNET_PKT_SIZE; 449*09cdd1b9SBen Warren adap_emac->RXBUFFEROFFSET = 0; 450*09cdd1b9SBen Warren 451*09cdd1b9SBen Warren /* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */ 452*09cdd1b9SBen Warren adap_emac->RXMBPENABLE = EMAC_RXMBPENABLE_RXBROADEN; 453*09cdd1b9SBen Warren 454*09cdd1b9SBen Warren /* Enable ch 0 only */ 455*09cdd1b9SBen Warren adap_emac->RXUNICASTSET = 0x01; 456*09cdd1b9SBen Warren 457*09cdd1b9SBen Warren /* Enable MII interface and Full duplex mode */ 458*09cdd1b9SBen Warren adap_emac->MACCONTROL = (EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE); 459*09cdd1b9SBen Warren 460*09cdd1b9SBen Warren /* Init MDIO & get link state */ 461*09cdd1b9SBen Warren clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; 462*09cdd1b9SBen Warren adap_mdio->CONTROL = ((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT); 463*09cdd1b9SBen Warren 464*09cdd1b9SBen Warren if (!phy.get_link_speed(active_phy_addr)) 465*09cdd1b9SBen Warren return(0); 466*09cdd1b9SBen Warren 467*09cdd1b9SBen Warren /* Start receive process */ 468*09cdd1b9SBen Warren adap_emac->RX0HDP = (u_int32_t)emac_rx_desc; 469*09cdd1b9SBen Warren 470*09cdd1b9SBen Warren debug_emac("- emac_open\n"); 471*09cdd1b9SBen Warren 472*09cdd1b9SBen Warren return(1); 473*09cdd1b9SBen Warren } 474*09cdd1b9SBen Warren 475*09cdd1b9SBen Warren /* EMAC Channel Teardown */ 476*09cdd1b9SBen Warren static void davinci_eth_ch_teardown(int ch) 477*09cdd1b9SBen Warren { 478*09cdd1b9SBen Warren dv_reg dly = 0xff; 479*09cdd1b9SBen Warren dv_reg cnt; 480*09cdd1b9SBen Warren 481*09cdd1b9SBen Warren debug_emac("+ emac_ch_teardown\n"); 482*09cdd1b9SBen Warren 483*09cdd1b9SBen Warren if (ch == EMAC_CH_TX) { 484*09cdd1b9SBen Warren /* Init TX channel teardown */ 485*09cdd1b9SBen Warren adap_emac->TXTEARDOWN = 1; 486*09cdd1b9SBen Warren for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->TX0CP) { 487*09cdd1b9SBen Warren /* Wait here for Tx teardown completion interrupt to occur 488*09cdd1b9SBen Warren * Note: A task delay can be called here to pend rather than 489*09cdd1b9SBen Warren * occupying CPU cycles - anyway it has been found that teardown 490*09cdd1b9SBen Warren * takes very few cpu cycles and does not affect functionality */ 491*09cdd1b9SBen Warren dly--; 492*09cdd1b9SBen Warren udelay(1); 493*09cdd1b9SBen Warren if (dly == 0) 494*09cdd1b9SBen Warren break; 495*09cdd1b9SBen Warren } 496*09cdd1b9SBen Warren adap_emac->TX0CP = cnt; 497*09cdd1b9SBen Warren adap_emac->TX0HDP = 0; 498*09cdd1b9SBen Warren } else { 499*09cdd1b9SBen Warren /* Init RX channel teardown */ 500*09cdd1b9SBen Warren adap_emac->RXTEARDOWN = 1; 501*09cdd1b9SBen Warren for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->RX0CP) { 502*09cdd1b9SBen Warren /* Wait here for Rx teardown completion interrupt to occur 503*09cdd1b9SBen Warren * Note: A task delay can be called here to pend rather than 504*09cdd1b9SBen Warren * occupying CPU cycles - anyway it has been found that teardown 505*09cdd1b9SBen Warren * takes very few cpu cycles and does not affect functionality */ 506*09cdd1b9SBen Warren dly--; 507*09cdd1b9SBen Warren udelay(1); 508*09cdd1b9SBen Warren if (dly == 0) 509*09cdd1b9SBen Warren break; 510*09cdd1b9SBen Warren } 511*09cdd1b9SBen Warren adap_emac->RX0CP = cnt; 512*09cdd1b9SBen Warren adap_emac->RX0HDP = 0; 513*09cdd1b9SBen Warren } 514*09cdd1b9SBen Warren 515*09cdd1b9SBen Warren debug_emac("- emac_ch_teardown\n"); 516*09cdd1b9SBen Warren } 517*09cdd1b9SBen Warren 518*09cdd1b9SBen Warren /* Eth device close */ 519*09cdd1b9SBen Warren static int davinci_eth_close(void) 520*09cdd1b9SBen Warren { 521*09cdd1b9SBen Warren debug_emac("+ emac_close\n"); 522*09cdd1b9SBen Warren 523*09cdd1b9SBen Warren davinci_eth_ch_teardown(EMAC_CH_TX); /* TX Channel teardown */ 524*09cdd1b9SBen Warren davinci_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */ 525*09cdd1b9SBen Warren 526*09cdd1b9SBen Warren /* Reset EMAC module and disable interrupts in wrapper */ 527*09cdd1b9SBen Warren adap_emac->SOFTRESET = 1; 528*09cdd1b9SBen Warren adap_ewrap->EWCTL = 0; 529*09cdd1b9SBen Warren 530*09cdd1b9SBen Warren debug_emac("- emac_close\n"); 531*09cdd1b9SBen Warren return(1); 532*09cdd1b9SBen Warren } 533*09cdd1b9SBen Warren 534*09cdd1b9SBen Warren static int tx_send_loop = 0; 535*09cdd1b9SBen Warren 536*09cdd1b9SBen Warren /* 537*09cdd1b9SBen Warren * This function sends a single packet on the network and returns 538*09cdd1b9SBen Warren * positive number (number of bytes transmitted) or negative for error 539*09cdd1b9SBen Warren */ 540*09cdd1b9SBen Warren static int davinci_eth_send_packet (volatile void *packet, int length) 541*09cdd1b9SBen Warren { 542*09cdd1b9SBen Warren int ret_status = -1; 543*09cdd1b9SBen Warren 544*09cdd1b9SBen Warren tx_send_loop = 0; 545*09cdd1b9SBen Warren 546*09cdd1b9SBen Warren /* Return error if no link */ 547*09cdd1b9SBen Warren if (!phy.get_link_speed (active_phy_addr)) { 548*09cdd1b9SBen Warren printf ("WARN: emac_send_packet: No link\n"); 549*09cdd1b9SBen Warren return (ret_status); 550*09cdd1b9SBen Warren } 551*09cdd1b9SBen Warren 552*09cdd1b9SBen Warren /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */ 553*09cdd1b9SBen Warren if (length < EMAC_MIN_ETHERNET_PKT_SIZE) { 554*09cdd1b9SBen Warren length = EMAC_MIN_ETHERNET_PKT_SIZE; 555*09cdd1b9SBen Warren } 556*09cdd1b9SBen Warren 557*09cdd1b9SBen Warren /* Populate the TX descriptor */ 558*09cdd1b9SBen Warren emac_tx_desc->next = 0; 559*09cdd1b9SBen Warren emac_tx_desc->buffer = (u_int8_t *) packet; 560*09cdd1b9SBen Warren emac_tx_desc->buff_off_len = (length & 0xffff); 561*09cdd1b9SBen Warren emac_tx_desc->pkt_flag_len = ((length & 0xffff) | 562*09cdd1b9SBen Warren EMAC_CPPI_SOP_BIT | 563*09cdd1b9SBen Warren EMAC_CPPI_OWNERSHIP_BIT | 564*09cdd1b9SBen Warren EMAC_CPPI_EOP_BIT); 565*09cdd1b9SBen Warren /* Send the packet */ 566*09cdd1b9SBen Warren adap_emac->TX0HDP = (unsigned int) emac_tx_desc; 567*09cdd1b9SBen Warren 568*09cdd1b9SBen Warren /* Wait for packet to complete or link down */ 569*09cdd1b9SBen Warren while (1) { 570*09cdd1b9SBen Warren if (!phy.get_link_speed (active_phy_addr)) { 571*09cdd1b9SBen Warren davinci_eth_ch_teardown (EMAC_CH_TX); 572*09cdd1b9SBen Warren return (ret_status); 573*09cdd1b9SBen Warren } 574*09cdd1b9SBen Warren if (adap_emac->TXINTSTATRAW & 0x01) { 575*09cdd1b9SBen Warren ret_status = length; 576*09cdd1b9SBen Warren break; 577*09cdd1b9SBen Warren } 578*09cdd1b9SBen Warren tx_send_loop++; 579*09cdd1b9SBen Warren } 580*09cdd1b9SBen Warren 581*09cdd1b9SBen Warren return (ret_status); 582*09cdd1b9SBen Warren } 583*09cdd1b9SBen Warren 584*09cdd1b9SBen Warren /* 585*09cdd1b9SBen Warren * This function handles receipt of a packet from the network 586*09cdd1b9SBen Warren */ 587*09cdd1b9SBen Warren static int davinci_eth_rcv_packet (void) 588*09cdd1b9SBen Warren { 589*09cdd1b9SBen Warren volatile emac_desc *rx_curr_desc; 590*09cdd1b9SBen Warren volatile emac_desc *curr_desc; 591*09cdd1b9SBen Warren volatile emac_desc *tail_desc; 592*09cdd1b9SBen Warren int status, ret = -1; 593*09cdd1b9SBen Warren 594*09cdd1b9SBen Warren rx_curr_desc = emac_rx_active_head; 595*09cdd1b9SBen Warren status = rx_curr_desc->pkt_flag_len; 596*09cdd1b9SBen Warren if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) { 597*09cdd1b9SBen Warren if (status & EMAC_CPPI_RX_ERROR_FRAME) { 598*09cdd1b9SBen Warren /* Error in packet - discard it and requeue desc */ 599*09cdd1b9SBen Warren printf ("WARN: emac_rcv_pkt: Error in packet\n"); 600*09cdd1b9SBen Warren } else { 601*09cdd1b9SBen Warren NetReceive (rx_curr_desc->buffer, 602*09cdd1b9SBen Warren (rx_curr_desc->buff_off_len & 0xffff)); 603*09cdd1b9SBen Warren ret = rx_curr_desc->buff_off_len & 0xffff; 604*09cdd1b9SBen Warren } 605*09cdd1b9SBen Warren 606*09cdd1b9SBen Warren /* Ack received packet descriptor */ 607*09cdd1b9SBen Warren adap_emac->RX0CP = (unsigned int) rx_curr_desc; 608*09cdd1b9SBen Warren curr_desc = rx_curr_desc; 609*09cdd1b9SBen Warren emac_rx_active_head = 610*09cdd1b9SBen Warren (volatile emac_desc *) rx_curr_desc->next; 611*09cdd1b9SBen Warren 612*09cdd1b9SBen Warren if (status & EMAC_CPPI_EOQ_BIT) { 613*09cdd1b9SBen Warren if (emac_rx_active_head) { 614*09cdd1b9SBen Warren adap_emac->RX0HDP = 615*09cdd1b9SBen Warren (unsigned int) emac_rx_active_head; 616*09cdd1b9SBen Warren } else { 617*09cdd1b9SBen Warren emac_rx_queue_active = 0; 618*09cdd1b9SBen Warren printf ("INFO:emac_rcv_packet: RX Queue not active\n"); 619*09cdd1b9SBen Warren } 620*09cdd1b9SBen Warren } 621*09cdd1b9SBen Warren 622*09cdd1b9SBen Warren /* Recycle RX descriptor */ 623*09cdd1b9SBen Warren rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; 624*09cdd1b9SBen Warren rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; 625*09cdd1b9SBen Warren rx_curr_desc->next = 0; 626*09cdd1b9SBen Warren 627*09cdd1b9SBen Warren if (emac_rx_active_head == 0) { 628*09cdd1b9SBen Warren printf ("INFO: emac_rcv_pkt: active queue head = 0\n"); 629*09cdd1b9SBen Warren emac_rx_active_head = curr_desc; 630*09cdd1b9SBen Warren emac_rx_active_tail = curr_desc; 631*09cdd1b9SBen Warren if (emac_rx_queue_active != 0) { 632*09cdd1b9SBen Warren adap_emac->RX0HDP = 633*09cdd1b9SBen Warren (unsigned int) emac_rx_active_head; 634*09cdd1b9SBen Warren printf ("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n"); 635*09cdd1b9SBen Warren emac_rx_queue_active = 1; 636*09cdd1b9SBen Warren } 637*09cdd1b9SBen Warren } else { 638*09cdd1b9SBen Warren tail_desc = emac_rx_active_tail; 639*09cdd1b9SBen Warren emac_rx_active_tail = curr_desc; 640*09cdd1b9SBen Warren tail_desc->next = (unsigned int) curr_desc; 641*09cdd1b9SBen Warren status = tail_desc->pkt_flag_len; 642*09cdd1b9SBen Warren if (status & EMAC_CPPI_EOQ_BIT) { 643*09cdd1b9SBen Warren adap_emac->RX0HDP = (unsigned int) curr_desc; 644*09cdd1b9SBen Warren status &= ~EMAC_CPPI_EOQ_BIT; 645*09cdd1b9SBen Warren tail_desc->pkt_flag_len = status; 646*09cdd1b9SBen Warren } 647*09cdd1b9SBen Warren } 648*09cdd1b9SBen Warren return (ret); 649*09cdd1b9SBen Warren } 650*09cdd1b9SBen Warren return (0); 651*09cdd1b9SBen Warren } 652*09cdd1b9SBen Warren 653*09cdd1b9SBen Warren #endif /* CONFIG_CMD_NET */ 654*09cdd1b9SBen Warren 655*09cdd1b9SBen Warren #endif /* CONFIG_DRIVER_TI_EMAC */ 656