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