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, void *packet, int length) 134 { 135 struct dnet_device *dnet = to_dnet(netdev); 136 int i, wrsz; 137 unsigned int *bufp; 138 unsigned int tx_cmd; 139 140 debug(DRIVERNAME "[%s] Sending %u bytes\n", __func__, length); 141 142 bufp = (unsigned int *) (((u32)packet) & 0xFFFFFFFC); 143 wrsz = (u32)length + 3; 144 wrsz += ((u32)packet) & 0x3; 145 wrsz >>= 2; 146 tx_cmd = ((((unsigned int)(packet)) & 0x03) << 16) | (u32)length; 147 148 /* check if there is enough room for the current frame */ 149 if (wrsz < (DNET_FIFO_SIZE - readl(&dnet->regs->TX_FIFO_WCNT))) { 150 for (i = 0; i < wrsz; i++) 151 writel(*bufp++, &dnet->regs->TX_DATA_FIFO); 152 /* 153 * inform MAC that a packet's written and ready 154 * to be shipped out 155 */ 156 writel(tx_cmd, &dnet->regs->TX_LEN_FIFO); 157 } else { 158 printf(DRIVERNAME "No free space (actual %d, required %d " 159 "(words))\n", DNET_FIFO_SIZE - 160 readl(&dnet->regs->TX_FIFO_WCNT), wrsz); 161 } 162 163 /* No one cares anyway */ 164 return 0; 165 } 166 167 168 static int dnet_recv(struct eth_device *netdev) 169 { 170 struct dnet_device *dnet = to_dnet(netdev); 171 unsigned int *data_ptr; 172 int pkt_len, poll, i; 173 u32 cmd_word; 174 175 debug("Waiting for pkt (polling)\n"); 176 poll = 50; 177 while ((readl(&dnet->regs->RX_FIFO_WCNT) >> 16) == 0) { 178 udelay(10); /* wait 10 usec */ 179 if (--poll == 0) 180 return 0; /* no pkt available */ 181 } 182 183 cmd_word = readl(&dnet->regs->RX_LEN_FIFO); 184 pkt_len = cmd_word & 0xFFFF; 185 186 debug("Got pkt with size %d bytes\n", pkt_len); 187 188 if (cmd_word & 0xDF180000) 189 printf("%s packet receive error %x\n", __func__, cmd_word); 190 191 data_ptr = (unsigned int *) NetRxPackets[0]; 192 193 for (i = 0; i < (pkt_len + 3) >> 2; i++) 194 *data_ptr++ = readl(&dnet->regs->RX_DATA_FIFO); 195 196 NetReceive(NetRxPackets[0], pkt_len + 5); /* ok + 5 ?? */ 197 198 return 0; 199 } 200 201 static void dnet_set_hwaddr(struct eth_device *netdev) 202 { 203 struct dnet_device *dnet = to_dnet(netdev); 204 u16 tmp; 205 206 tmp = get_unaligned_be16(netdev->enetaddr); 207 dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_0_REG, tmp); 208 tmp = get_unaligned_be16(&netdev->enetaddr[2]); 209 dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_1_REG, tmp); 210 tmp = get_unaligned_be16(&netdev->enetaddr[4]); 211 dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_2_REG, tmp); 212 } 213 214 static void dnet_phy_reset(struct dnet_device *dnet) 215 { 216 struct eth_device *netdev = &dnet->netdev; 217 int i; 218 u16 status, adv; 219 220 adv = ADVERTISE_CSMA | ADVERTISE_ALL; 221 dnet_mdio_write(dnet, MII_ADVERTISE, adv); 222 printf("%s: Starting autonegotiation...\n", netdev->name); 223 dnet_mdio_write(dnet, MII_BMCR, (BMCR_ANENABLE 224 | BMCR_ANRESTART)); 225 226 for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { 227 status = dnet_mdio_read(dnet, MII_BMSR); 228 if (status & BMSR_ANEGCOMPLETE) 229 break; 230 udelay(100); 231 } 232 233 if (status & BMSR_ANEGCOMPLETE) 234 printf("%s: Autonegotiation complete\n", netdev->name); 235 else 236 printf("%s: Autonegotiation timed out (status=0x%04x)\n", 237 netdev->name, status); 238 } 239 240 static int dnet_phy_init(struct dnet_device *dnet) 241 { 242 struct eth_device *netdev = &dnet->netdev; 243 u16 phy_id, status, adv, lpa; 244 int media, speed, duplex; 245 int i; 246 u32 ctl_reg; 247 248 /* Find a PHY */ 249 for (i = 0; i < 32; i++) { 250 dnet->phy_addr = i; 251 phy_id = dnet_mdio_read(dnet, MII_PHYSID1); 252 if (phy_id != 0xffff) { 253 /* ok we found it */ 254 printf("Found PHY at address %d PHYID (%04x:%04x)\n", 255 i, phy_id, 256 dnet_mdio_read(dnet, MII_PHYSID2)); 257 break; 258 } 259 } 260 261 /* Check if the PHY is up to snuff... */ 262 phy_id = dnet_mdio_read(dnet, MII_PHYSID1); 263 if (phy_id == 0xffff) { 264 printf("%s: No PHY present\n", netdev->name); 265 return -1; 266 } 267 268 status = dnet_mdio_read(dnet, MII_BMSR); 269 if (!(status & BMSR_LSTATUS)) { 270 /* Try to re-negotiate if we don't have link already. */ 271 dnet_phy_reset(dnet); 272 273 for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) { 274 status = dnet_mdio_read(dnet, MII_BMSR); 275 if (status & BMSR_LSTATUS) 276 break; 277 udelay(100); 278 } 279 } 280 281 if (!(status & BMSR_LSTATUS)) { 282 printf("%s: link down (status: 0x%04x)\n", 283 netdev->name, status); 284 return -1; 285 } else { 286 adv = dnet_mdio_read(dnet, MII_ADVERTISE); 287 lpa = dnet_mdio_read(dnet, MII_LPA); 288 media = mii_nway_result(lpa & adv); 289 speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) 290 ? 1 : 0); 291 duplex = (media & ADVERTISE_FULL) ? 1 : 0; 292 /* 1000BaseT ethernet is not supported */ 293 printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", 294 netdev->name, 295 speed ? "100" : "10", 296 duplex ? "full" : "half", 297 lpa); 298 299 ctl_reg = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); 300 301 if (duplex) 302 ctl_reg &= ~(DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP); 303 else 304 ctl_reg |= DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP; 305 306 dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, ctl_reg); 307 308 return 0; 309 } 310 } 311 312 static int dnet_init(struct eth_device *netdev, bd_t *bd) 313 { 314 struct dnet_device *dnet = to_dnet(netdev); 315 u32 config; 316 317 /* 318 * dnet_halt should have been called at some point before now, 319 * so we'll assume the controller is idle. 320 */ 321 322 /* set hardware address */ 323 dnet_set_hwaddr(netdev); 324 325 if (dnet_phy_init(dnet) < 0) 326 return -1; 327 328 /* flush rx/tx fifos */ 329 writel(DNET_SYS_CTL_RXFIFOFLUSH | DNET_SYS_CTL_TXFIFOFLUSH, 330 &dnet->regs->SYS_CTL); 331 udelay(1000); 332 writel(0, &dnet->regs->SYS_CTL); 333 334 config = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG); 335 336 config |= DNET_INTERNAL_RXTX_CONTROL_RXPAUSE | 337 DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST | 338 DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL | 339 DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS; 340 341 dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, config); 342 343 /* Enable TX and RX */ 344 dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 345 DNET_INTERNAL_MODE_RXEN | DNET_INTERNAL_MODE_TXEN); 346 347 return 0; 348 } 349 350 static void dnet_halt(struct eth_device *netdev) 351 { 352 struct dnet_device *dnet = to_dnet(netdev); 353 354 /* Disable TX and RX */ 355 dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 0); 356 } 357 358 int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr) 359 { 360 struct dnet_device *dnet; 361 struct eth_device *netdev; 362 unsigned int dev_capa; 363 364 dnet = malloc(sizeof(struct dnet_device)); 365 if (!dnet) { 366 printf("Error: Failed to allocate memory for DNET%d\n", id); 367 return -1; 368 } 369 memset(dnet, 0, sizeof(struct dnet_device)); 370 371 netdev = &dnet->netdev; 372 373 dnet->regs = (struct dnet_registers *)regs; 374 dnet->phy_addr = phy_addr; 375 376 sprintf(netdev->name, "dnet%d", id); 377 netdev->init = dnet_init; 378 netdev->halt = dnet_halt; 379 netdev->send = dnet_send; 380 netdev->recv = dnet_recv; 381 382 dev_capa = readl(&dnet->regs->VERCAPS) & 0xFFFF; 383 debug("%s: has %smdio, %sirq, %sgigabit, %sdma \n", netdev->name, 384 (dev_capa & DNET_HAS_MDIO) ? "" : "no ", 385 (dev_capa & DNET_HAS_IRQ) ? "" : "no ", 386 (dev_capa & DNET_HAS_GIGABIT) ? "" : "no ", 387 (dev_capa & DNET_HAS_DMA) ? "" : "no "); 388 389 eth_register(netdev); 390 391 return 0; 392 } 393