1 /* 2 * Dave Ethernet Controller driver 3 * 4 * Copyright (C) 2008 Dave S.r.l. <www.dave.eu> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 11 #include <common.h> 12 13 #ifndef CONFIG_DNET_AUTONEG_TIMEOUT 14 #define CONFIG_DNET_AUTONEG_TIMEOUT 5000000 /* default value */ 15 #endif 16 17 #include <net.h> 18 #include <malloc.h> 19 #include <linux/mii.h> 20 21 #include <miiphy.h> 22 #include <asm/io.h> 23 24 #include "dnet.h" 25 26 struct dnet_device { 27 struct dnet_registers *regs; 28 const struct device *dev; 29 struct eth_device netdev; 30 unsigned short phy_addr; 31 }; 32 33 /* get struct dnet_device from given struct netdev */ 34 #define to_dnet(_nd) container_of(_nd, struct dnet_device, netdev) 35 36 /* function for reading internal MAC register */ 37 u16 dnet_readw_mac(struct dnet_device *dnet, u16 reg) 38 { 39 u16 data_read; 40 41 /* issue a read */ 42 writel(reg, &dnet->regs->MACREG_ADDR); 43 44 /* since a read/write op to the MAC is very slow, 45 * we must wait before reading the data */ 46 udelay(1); 47 48 /* read data read from the MAC register */ 49 data_read = readl(&dnet->regs->MACREG_DATA); 50 51 /* all done */ 52 return data_read; 53 } 54 55 /* function for writing internal MAC register */ 56 void dnet_writew_mac(struct dnet_device *dnet, u16 reg, u16 val) 57 { 58 /* load data to write */ 59 writel(val, &dnet->regs->MACREG_DATA); 60 61 /* issue a write */ 62 writel(reg | DNET_INTERNAL_WRITE, &dnet->regs->MACREG_ADDR); 63 64 /* since a read/write op to the MAC is very slow, 65 * we must wait before exiting */ 66 udelay(1); 67 } 68 69 static void dnet_mdio_write(struct dnet_device *dnet, u8 reg, u16 value) 70 { 71 u16 tmp; 72 73 debug(DRIVERNAME "dnet_mdio_write %02x:%02x <- %04x\n", 74 dnet->phy_addr, reg, value); 75 76 while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & 77 DNET_INTERNAL_GMII_MNG_CMD_FIN)) 78 ; 79 80 /* prepare for a write operation */ 81 tmp = (1 << 13); 82 83 /* only 5 bits allowed for register offset */ 84 reg &= 0x1f; 85 86 /* prepare reg_value for a write */ 87 tmp |= (dnet->phy_addr << 8); 88 tmp |= reg; 89 90 /* write data to write first */ 91 dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG, value); 92 93 /* write control word */ 94 dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, tmp); 95 96 while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & 97 DNET_INTERNAL_GMII_MNG_CMD_FIN)) 98 ; 99 } 100 101 static u16 dnet_mdio_read(struct dnet_device *dnet, u8 reg) 102 { 103 u16 value; 104 105 while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & 106 DNET_INTERNAL_GMII_MNG_CMD_FIN)) 107 ; 108 109 /* only 5 bits allowed for register offset*/ 110 reg &= 0x1f; 111 112 /* prepare reg_value for a read */ 113 value = (dnet->phy_addr << 8); 114 value |= reg; 115 116 /* write control word */ 117 dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, value); 118 119 /* wait for end of transfer */ 120 while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) & 121 DNET_INTERNAL_GMII_MNG_CMD_FIN)) 122 ; 123 124 value = dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG); 125 126 debug(DRIVERNAME "dnet_mdio_read %02x:%02x <- %04x\n", 127 dnet->phy_addr, reg, value); 128 129 return value; 130 } 131 132 static int dnet_send(struct eth_device *netdev, volatile void *packet, 133 int length) 134 { 135 struct dnet_device *dnet = to_dnet(netdev); 136 int i, len, wrsz; 137 unsigned int *bufp; 138 unsigned int tx_cmd; 139 140 debug(DRIVERNAME "[%s] Sending %u bytes\n", __func__, length); 141 142 /* frame size (words) */ 143 len = (length + 3) >> 2; 144 145 bufp = (unsigned int *) (((u32)packet) & 0xFFFFFFFC); 146 wrsz = (u32)length + 3; 147 wrsz += ((u32)packet) & 0x3; 148 wrsz >>= 2; 149 tx_cmd = ((((unsigned int)(packet)) & 0x03) << 16) | (u32)length; 150 151 /* check if there is enough room for the current frame */ 152 if (wrsz < (DNET_FIFO_SIZE - readl(&dnet->regs->TX_FIFO_WCNT))) { 153 for (i = 0; i < wrsz; i++) 154 writel(*bufp++, &dnet->regs->TX_DATA_FIFO); 155 /* 156 * inform MAC that a packet's written and ready 157 * to be shipped out 158 */ 159 writel(tx_cmd, &dnet->regs->TX_LEN_FIFO); 160 } else { 161 printf(DRIVERNAME "No free space (actual %d, required %d " 162 "(words))\n", DNET_FIFO_SIZE - 163 readl(&dnet->regs->TX_FIFO_WCNT), wrsz); 164 } 165 166 /* No one cares anyway */ 167 return 0; 168 } 169 170 171 static int dnet_recv(struct eth_device *netdev) 172 { 173 struct dnet_device *dnet = to_dnet(netdev); 174 unsigned int *data_ptr; 175 int pkt_len, poll, i; 176 u32 cmd_word; 177 178 debug("Waiting for pkt (polling)\n"); 179 poll = 50; 180 while ((readl(&dnet->regs->RX_FIFO_WCNT) >> 16) == 0) { 181 udelay(10); /* wait 10 usec */ 182 if (--poll == 0) 183 return 0; /* no pkt available */ 184 } 185 186 cmd_word = readl(&dnet->regs->RX_LEN_FIFO); 187 pkt_len = cmd_word & 0xFFFF; 188 189 debug("Got pkt with size %d bytes\n", pkt_len); 190 191 if (cmd_word & 0xDF180000) 192 printf("%s packet receive error %x\n", __func__, cmd_word); 193 194 data_ptr = (unsigned int *) NetRxPackets[0]; 195 196 for (i = 0; i < (pkt_len + 3) >> 2; i++) 197 *data_ptr++ = readl(&dnet->regs->RX_DATA_FIFO); 198 199 NetReceive(NetRxPackets[0], pkt_len + 5); /* ok + 5 ?? */ 200 201 return 0; 202 } 203 204 static void dnet_set_hwaddr(struct eth_device *netdev) 205 { 206 struct dnet_device *dnet = to_dnet(netdev); 207 u16 tmp; 208 209 tmp = cpu_to_be16(*((u16 *)netdev->enetaddr)); 210 dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_0_REG, tmp); 211 tmp = cpu_to_be16(*((u16 *)(netdev->enetaddr + 2))); 212 dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_1_REG, tmp); 213 tmp = cpu_to_be16(*((u16 *)(netdev->enetaddr + 4))); 214 dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_2_REG, tmp); 215 } 216 217 static void dnet_phy_reset(struct dnet_device *dnet) 218 { 219 struct eth_device *netdev = &dnet->netdev; 220 int i; 221 u16 status, adv; 222 223 adv = ADVERTISE_CSMA | ADVERTISE_ALL; 224 dnet_mdio_write(dnet, MII_ADVERTISE, adv); 225 printf("%s: Starting autonegotiation...\n", netdev->name); 226 dnet_mdio_write(dnet, MII_BMCR, (BMCR_ANENABLE 227 | BMCR_ANRESTART)); 228 229 for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { 230 status = dnet_mdio_read(dnet, MII_BMSR); 231 if (status & BMSR_ANEGCOMPLETE) 232 break; 233 udelay(100); 234 } 235 236 if (status & BMSR_ANEGCOMPLETE) 237 printf("%s: Autonegotiation complete\n", netdev->name); 238 else 239 printf("%s: Autonegotiation timed out (status=0x%04x)\n", 240 netdev->name, status); 241 } 242 243 static int dnet_phy_init(struct dnet_device *dnet) 244 { 245 struct eth_device *netdev = &dnet->netdev; 246 u16 phy_id, status, adv, lpa; 247 int media, speed, duplex; 248 int i; 249 u32 ctl_reg; 250 251 /* Find a PHY */ 252 for (i = 0; i < 32; i++) { 253 dnet->phy_addr = i; 254 phy_id = dnet_mdio_read(dnet, MII_PHYSID1); 255 if (phy_id != 0xffff) { 256 /* ok we found it */ 257 printf("Found PHY at address %d PHYID (%04x:%04x)\n", 258 i, phy_id, 259 dnet_mdio_read(dnet, MII_PHYSID2)); 260 break; 261 } 262 } 263 264 /* Check if the PHY is up to snuff... */ 265 phy_id = dnet_mdio_read(dnet, MII_PHYSID1); 266 if (phy_id == 0xffff) { 267 printf("%s: No PHY present\n", netdev->name); 268 return -1; 269 } 270 271 status = dnet_mdio_read(dnet, MII_BMSR); 272 if (!(status & BMSR_LSTATUS)) { 273 /* Try to re-negotiate if we don't have link already. */ 274 dnet_phy_reset(dnet); 275 276 for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { 277 status = dnet_mdio_read(dnet, MII_BMSR); 278 if (status & BMSR_LSTATUS) 279 break; 280 udelay(100); 281 } 282 } 283 284 if (!(status & BMSR_LSTATUS)) { 285 printf("%s: link down (status: 0x%04x)\n", 286 netdev->name, status); 287 return -1; 288 } else { 289 adv = dnet_mdio_read(dnet, MII_ADVERTISE); 290 lpa = dnet_mdio_read(dnet, MII_LPA); 291 media = mii_nway_result(lpa & adv); 292 speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) 293 ? 1 : 0); 294 duplex = (media & ADVERTISE_FULL) ? 1 : 0; 295 /* 1000BaseT ethernet is not supported */ 296 printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", 297 netdev->name, 298 speed ? "100" : "10", 299 duplex ? "full" : "half", 300 lpa); 301 302 ctl_reg = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); 303 304 if (duplex) 305 ctl_reg &= ~(DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP); 306 else 307 ctl_reg |= DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP; 308 309 dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, ctl_reg); 310 311 return 0; 312 } 313 } 314 315 static int dnet_init(struct eth_device *netdev, bd_t *bd) 316 { 317 struct dnet_device *dnet = to_dnet(netdev); 318 u32 config; 319 320 /* 321 * dnet_halt should have been called at some point before now, 322 * so we'll assume the controller is idle. 323 */ 324 325 /* set hardware address */ 326 dnet_set_hwaddr(netdev); 327 328 if (dnet_phy_init(dnet) < 0) 329 return -1; 330 331 /* flush rx/tx fifos */ 332 writel(DNET_SYS_CTL_RXFIFOFLUSH | DNET_SYS_CTL_TXFIFOFLUSH, 333 &dnet->regs->SYS_CTL); 334 udelay(1000); 335 writel(0, &dnet->regs->SYS_CTL); 336 337 config = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); 338 339 config |= DNET_INTERNAL_RXTX_CONTROL_RXPAUSE | 340 DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST | 341 DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL | 342 DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS; 343 344 dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, config); 345 346 /* Enable TX and RX */ 347 dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 348 DNET_INTERNAL_MODE_RXEN | DNET_INTERNAL_MODE_TXEN); 349 350 return 0; 351 } 352 353 static void dnet_halt(struct eth_device *netdev) 354 { 355 struct dnet_device *dnet = to_dnet(netdev); 356 357 /* Disable TX and RX */ 358 dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 0); 359 } 360 361 int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr) 362 { 363 struct dnet_device *dnet; 364 struct eth_device *netdev; 365 unsigned int dev_capa; 366 367 dnet = malloc(sizeof(struct dnet_device)); 368 if (!dnet) { 369 printf("Error: Failed to allocate memory for DNET%d\n", id); 370 return -1; 371 } 372 memset(dnet, 0, sizeof(struct dnet_device)); 373 374 netdev = &dnet->netdev; 375 376 dnet->regs = (struct dnet_registers *)regs; 377 dnet->phy_addr = phy_addr; 378 379 sprintf(netdev->name, "dnet%d", id); 380 netdev->init = dnet_init; 381 netdev->halt = dnet_halt; 382 netdev->send = dnet_send; 383 netdev->recv = dnet_recv; 384 385 dev_capa = readl(&dnet->regs->VERCAPS) & 0xFFFF; 386 debug("%s: has %smdio, %sirq, %sgigabit, %sdma \n", netdev->name, 387 (dev_capa & DNET_HAS_MDIO) ? "" : "no ", 388 (dev_capa & DNET_HAS_IRQ) ? "" : "no ", 389 (dev_capa & DNET_HAS_GIGABIT) ? "" : "no ", 390 (dev_capa & DNET_HAS_DMA) ? "" : "no "); 391 392 eth_register(netdev); 393 394 return 0; 395 } 396