1 /* 2 * (C) Copyright 2010 3 * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. 4 * 5 * See file CREDITS for list of people who contributed to this 6 * project. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 * MA 02111-1307 USA 22 */ 23 24 /* 25 * Designware ethernet IP driver for u-boot 26 */ 27 28 #include <common.h> 29 #include <miiphy.h> 30 #include <malloc.h> 31 #include <linux/compiler.h> 32 #include <linux/err.h> 33 #include <asm/io.h> 34 #include "designware.h" 35 36 static int configure_phy(struct eth_device *dev); 37 38 static void tx_descs_init(struct eth_device *dev) 39 { 40 struct dw_eth_dev *priv = dev->priv; 41 struct eth_dma_regs *dma_p = priv->dma_regs_p; 42 struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0]; 43 char *txbuffs = &priv->txbuffs[0]; 44 struct dmamacdescr *desc_p; 45 u32 idx; 46 47 for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) { 48 desc_p = &desc_table_p[idx]; 49 desc_p->dmamac_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE]; 50 desc_p->dmamac_next = &desc_table_p[idx + 1]; 51 52 #if defined(CONFIG_DW_ALTDESCRIPTOR) 53 desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST | 54 DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS | \ 55 DESC_TXSTS_TXCHECKINSCTRL | \ 56 DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS); 57 58 desc_p->txrx_status |= DESC_TXSTS_TXCHAIN; 59 desc_p->dmamac_cntl = 0; 60 desc_p->txrx_status &= ~(DESC_TXSTS_MSK | DESC_TXSTS_OWNBYDMA); 61 #else 62 desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN; 63 desc_p->txrx_status = 0; 64 #endif 65 } 66 67 /* Correcting the last pointer of the chain */ 68 desc_p->dmamac_next = &desc_table_p[0]; 69 70 writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr); 71 } 72 73 static void rx_descs_init(struct eth_device *dev) 74 { 75 struct dw_eth_dev *priv = dev->priv; 76 struct eth_dma_regs *dma_p = priv->dma_regs_p; 77 struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0]; 78 char *rxbuffs = &priv->rxbuffs[0]; 79 struct dmamacdescr *desc_p; 80 u32 idx; 81 82 for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) { 83 desc_p = &desc_table_p[idx]; 84 desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE]; 85 desc_p->dmamac_next = &desc_table_p[idx + 1]; 86 87 desc_p->dmamac_cntl = 88 (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \ 89 DESC_RXCTRL_RXCHAIN; 90 91 desc_p->txrx_status = DESC_RXSTS_OWNBYDMA; 92 } 93 94 /* Correcting the last pointer of the chain */ 95 desc_p->dmamac_next = &desc_table_p[0]; 96 97 writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr); 98 } 99 100 static void descs_init(struct eth_device *dev) 101 { 102 tx_descs_init(dev); 103 rx_descs_init(dev); 104 } 105 106 static int mac_reset(struct eth_device *dev) 107 { 108 struct dw_eth_dev *priv = dev->priv; 109 struct eth_mac_regs *mac_p = priv->mac_regs_p; 110 struct eth_dma_regs *dma_p = priv->dma_regs_p; 111 112 ulong start; 113 int timeout = CONFIG_MACRESET_TIMEOUT; 114 115 writel(DMAMAC_SRST, &dma_p->busmode); 116 117 if (priv->interface != PHY_INTERFACE_MODE_RGMII) 118 writel(MII_PORTSELECT, &mac_p->conf); 119 120 start = get_timer(0); 121 while (get_timer(start) < timeout) { 122 if (!(readl(&dma_p->busmode) & DMAMAC_SRST)) 123 return 0; 124 125 /* Try again after 10usec */ 126 udelay(10); 127 }; 128 129 return -1; 130 } 131 132 static int dw_write_hwaddr(struct eth_device *dev) 133 { 134 struct dw_eth_dev *priv = dev->priv; 135 struct eth_mac_regs *mac_p = priv->mac_regs_p; 136 u32 macid_lo, macid_hi; 137 u8 *mac_id = &dev->enetaddr[0]; 138 139 macid_lo = mac_id[0] + (mac_id[1] << 8) + \ 140 (mac_id[2] << 16) + (mac_id[3] << 24); 141 macid_hi = mac_id[4] + (mac_id[5] << 8); 142 143 writel(macid_hi, &mac_p->macaddr0hi); 144 writel(macid_lo, &mac_p->macaddr0lo); 145 146 return 0; 147 } 148 149 static int dw_eth_init(struct eth_device *dev, bd_t *bis) 150 { 151 struct dw_eth_dev *priv = dev->priv; 152 struct eth_mac_regs *mac_p = priv->mac_regs_p; 153 struct eth_dma_regs *dma_p = priv->dma_regs_p; 154 u32 conf; 155 156 if (priv->phy_configured != 1) 157 configure_phy(dev); 158 159 /* Print link status only once */ 160 if (!priv->link_printed) { 161 printf("ENET Speed is %d Mbps - %s duplex connection\n", 162 priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL"); 163 priv->link_printed = 1; 164 } 165 166 /* Reset ethernet hardware */ 167 if (mac_reset(dev) < 0) 168 return -1; 169 170 /* Resore the HW MAC address as it has been lost during MAC reset */ 171 dw_write_hwaddr(dev); 172 173 writel(FIXEDBURST | PRIORXTX_41 | BURST_16, 174 &dma_p->busmode); 175 176 writel(readl(&dma_p->opmode) | FLUSHTXFIFO | STOREFORWARD | 177 TXSECONDFRAME, &dma_p->opmode); 178 179 conf = FRAMEBURSTENABLE | DISABLERXOWN; 180 181 if (priv->speed != 1000) 182 conf |= MII_PORTSELECT; 183 184 if ((priv->interface != PHY_INTERFACE_MODE_MII) && 185 (priv->interface != PHY_INTERFACE_MODE_GMII)) { 186 187 if (priv->speed == 100) 188 conf |= FES_100; 189 } 190 191 if (priv->duplex == FULL) 192 conf |= FULLDPLXMODE; 193 194 writel(conf, &mac_p->conf); 195 196 descs_init(dev); 197 198 /* 199 * Start/Enable xfer at dma as well as mac level 200 */ 201 writel(readl(&dma_p->opmode) | RXSTART, &dma_p->opmode); 202 writel(readl(&dma_p->opmode) | TXSTART, &dma_p->opmode); 203 204 writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf); 205 206 return 0; 207 } 208 209 static int dw_eth_send(struct eth_device *dev, void *packet, int length) 210 { 211 struct dw_eth_dev *priv = dev->priv; 212 struct eth_dma_regs *dma_p = priv->dma_regs_p; 213 u32 desc_num = priv->tx_currdescnum; 214 struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num]; 215 216 /* Check if the descriptor is owned by CPU */ 217 if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) { 218 printf("CPU not owner of tx frame\n"); 219 return -1; 220 } 221 222 memcpy((void *)desc_p->dmamac_addr, packet, length); 223 224 #if defined(CONFIG_DW_ALTDESCRIPTOR) 225 desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST; 226 desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & \ 227 DESC_TXCTRL_SIZE1MASK; 228 229 desc_p->txrx_status &= ~(DESC_TXSTS_MSK); 230 desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA; 231 #else 232 desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & \ 233 DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | \ 234 DESC_TXCTRL_TXFIRST; 235 236 desc_p->txrx_status = DESC_TXSTS_OWNBYDMA; 237 #endif 238 239 /* Test the wrap-around condition. */ 240 if (++desc_num >= CONFIG_TX_DESCR_NUM) 241 desc_num = 0; 242 243 priv->tx_currdescnum = desc_num; 244 245 /* Start the transmission */ 246 writel(POLL_DATA, &dma_p->txpolldemand); 247 248 return 0; 249 } 250 251 static int dw_eth_recv(struct eth_device *dev) 252 { 253 struct dw_eth_dev *priv = dev->priv; 254 u32 desc_num = priv->rx_currdescnum; 255 struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num]; 256 257 u32 status = desc_p->txrx_status; 258 int length = 0; 259 260 /* Check if the owner is the CPU */ 261 if (!(status & DESC_RXSTS_OWNBYDMA)) { 262 263 length = (status & DESC_RXSTS_FRMLENMSK) >> \ 264 DESC_RXSTS_FRMLENSHFT; 265 266 NetReceive(desc_p->dmamac_addr, length); 267 268 /* 269 * Make the current descriptor valid again and go to 270 * the next one 271 */ 272 desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA; 273 274 /* Test the wrap-around condition. */ 275 if (++desc_num >= CONFIG_RX_DESCR_NUM) 276 desc_num = 0; 277 } 278 279 priv->rx_currdescnum = desc_num; 280 281 return length; 282 } 283 284 static void dw_eth_halt(struct eth_device *dev) 285 { 286 struct dw_eth_dev *priv = dev->priv; 287 288 mac_reset(dev); 289 priv->tx_currdescnum = priv->rx_currdescnum = 0; 290 } 291 292 static int eth_mdio_read(struct eth_device *dev, u8 addr, u8 reg, u16 *val) 293 { 294 struct dw_eth_dev *priv = dev->priv; 295 struct eth_mac_regs *mac_p = priv->mac_regs_p; 296 ulong start; 297 u32 miiaddr; 298 int timeout = CONFIG_MDIO_TIMEOUT; 299 300 miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ 301 ((reg << MIIREGSHIFT) & MII_REGMSK); 302 303 writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); 304 305 start = get_timer(0); 306 while (get_timer(start) < timeout) { 307 if (!(readl(&mac_p->miiaddr) & MII_BUSY)) { 308 *val = readl(&mac_p->miidata); 309 return 0; 310 } 311 312 /* Try again after 10usec */ 313 udelay(10); 314 }; 315 316 return -1; 317 } 318 319 static int eth_mdio_write(struct eth_device *dev, u8 addr, u8 reg, u16 val) 320 { 321 struct dw_eth_dev *priv = dev->priv; 322 struct eth_mac_regs *mac_p = priv->mac_regs_p; 323 ulong start; 324 u32 miiaddr; 325 int ret = -1, timeout = CONFIG_MDIO_TIMEOUT; 326 u16 value; 327 328 writel(val, &mac_p->miidata); 329 miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ 330 ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE; 331 332 writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); 333 334 start = get_timer(0); 335 while (get_timer(start) < timeout) { 336 if (!(readl(&mac_p->miiaddr) & MII_BUSY)) { 337 ret = 0; 338 break; 339 } 340 341 /* Try again after 10usec */ 342 udelay(10); 343 }; 344 345 /* Needed as a fix for ST-Phy */ 346 eth_mdio_read(dev, addr, reg, &value); 347 348 return ret; 349 } 350 351 #if defined(CONFIG_DW_SEARCH_PHY) 352 static int find_phy(struct eth_device *dev) 353 { 354 int phy_addr = 0; 355 u16 ctrl, oldctrl; 356 357 do { 358 eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); 359 oldctrl = ctrl & BMCR_ANENABLE; 360 361 ctrl ^= BMCR_ANENABLE; 362 eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl); 363 eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); 364 ctrl &= BMCR_ANENABLE; 365 366 if (ctrl == oldctrl) { 367 phy_addr++; 368 } else { 369 ctrl ^= BMCR_ANENABLE; 370 eth_mdio_write(dev, phy_addr, MII_BMCR, ctrl); 371 372 return phy_addr; 373 } 374 } while (phy_addr < 32); 375 376 return -1; 377 } 378 #endif 379 380 static int dw_reset_phy(struct eth_device *dev) 381 { 382 struct dw_eth_dev *priv = dev->priv; 383 u16 ctrl; 384 ulong start; 385 int timeout = CONFIG_PHYRESET_TIMEOUT; 386 u32 phy_addr = priv->address; 387 388 eth_mdio_write(dev, phy_addr, MII_BMCR, BMCR_RESET); 389 390 start = get_timer(0); 391 while (get_timer(start) < timeout) { 392 eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl); 393 if (!(ctrl & BMCR_RESET)) 394 break; 395 396 /* Try again after 10usec */ 397 udelay(10); 398 }; 399 400 if (get_timer(start) >= CONFIG_PHYRESET_TIMEOUT) 401 return -1; 402 403 #ifdef CONFIG_PHY_RESET_DELAY 404 udelay(CONFIG_PHY_RESET_DELAY); 405 #endif 406 return 0; 407 } 408 409 /* 410 * Add weak default function for board specific PHY configuration 411 */ 412 int __weak designware_board_phy_init(struct eth_device *dev, int phy_addr, 413 int (*mii_write)(struct eth_device *, u8, u8, u16), 414 int dw_reset_phy(struct eth_device *)) 415 { 416 return 0; 417 } 418 419 static int configure_phy(struct eth_device *dev) 420 { 421 struct dw_eth_dev *priv = dev->priv; 422 int phy_addr; 423 u16 bmcr; 424 #if defined(CONFIG_DW_AUTONEG) 425 u16 bmsr; 426 u32 timeout; 427 ulong start; 428 #endif 429 430 #if defined(CONFIG_DW_SEARCH_PHY) 431 phy_addr = find_phy(dev); 432 if (phy_addr >= 0) 433 priv->address = phy_addr; 434 else 435 return -1; 436 #else 437 phy_addr = priv->address; 438 #endif 439 440 /* 441 * Some boards need board specific PHY initialization. This is 442 * after the main driver init code but before the auto negotiation 443 * is run. 444 */ 445 if (designware_board_phy_init(dev, phy_addr, 446 eth_mdio_write, dw_reset_phy) < 0) 447 return -1; 448 449 if (dw_reset_phy(dev) < 0) 450 return -1; 451 452 #if defined(CONFIG_DW_AUTONEG) 453 /* Set Auto-Neg Advertisement capabilities to 10/100 half/full */ 454 eth_mdio_write(dev, phy_addr, MII_ADVERTISE, 0x1E1); 455 456 bmcr = BMCR_ANENABLE | BMCR_ANRESTART; 457 #else 458 bmcr = BMCR_SPEED100 | BMCR_FULLDPLX; 459 460 #if defined(CONFIG_DW_SPEED10M) 461 bmcr &= ~BMCR_SPEED100; 462 #endif 463 #if defined(CONFIG_DW_DUPLEXHALF) 464 bmcr &= ~BMCR_FULLDPLX; 465 #endif 466 #endif 467 if (eth_mdio_write(dev, phy_addr, MII_BMCR, bmcr) < 0) 468 return -1; 469 470 /* Read the phy status register and populate priv structure */ 471 #if defined(CONFIG_DW_AUTONEG) 472 timeout = CONFIG_AUTONEG_TIMEOUT; 473 start = get_timer(0); 474 puts("Waiting for PHY auto negotiation to complete"); 475 while (get_timer(start) < timeout) { 476 eth_mdio_read(dev, phy_addr, MII_BMSR, &bmsr); 477 if (bmsr & BMSR_ANEGCOMPLETE) { 478 priv->phy_configured = 1; 479 break; 480 } 481 482 /* Print dot all 1s to show progress */ 483 if ((get_timer(start) % 1000) == 0) 484 putc('.'); 485 486 /* Try again after 1msec */ 487 udelay(1000); 488 }; 489 490 if (!(bmsr & BMSR_ANEGCOMPLETE)) 491 puts(" TIMEOUT!\n"); 492 else 493 puts(" done\n"); 494 #else 495 priv->phy_configured = 1; 496 #endif 497 498 priv->speed = miiphy_speed(dev->name, phy_addr); 499 priv->duplex = miiphy_duplex(dev->name, phy_addr); 500 501 return 0; 502 } 503 504 #if defined(CONFIG_MII) 505 static int dw_mii_read(const char *devname, u8 addr, u8 reg, u16 *val) 506 { 507 struct eth_device *dev; 508 509 dev = eth_get_dev_by_name(devname); 510 if (dev) 511 eth_mdio_read(dev, addr, reg, val); 512 513 return 0; 514 } 515 516 static int dw_mii_write(const char *devname, u8 addr, u8 reg, u16 val) 517 { 518 struct eth_device *dev; 519 520 dev = eth_get_dev_by_name(devname); 521 if (dev) 522 eth_mdio_write(dev, addr, reg, val); 523 524 return 0; 525 } 526 #endif 527 528 int designware_initialize(u32 id, ulong base_addr, u32 phy_addr, u32 interface) 529 { 530 struct eth_device *dev; 531 struct dw_eth_dev *priv; 532 533 dev = (struct eth_device *) malloc(sizeof(struct eth_device)); 534 if (!dev) 535 return -ENOMEM; 536 537 /* 538 * Since the priv structure contains the descriptors which need a strict 539 * buswidth alignment, memalign is used to allocate memory 540 */ 541 priv = (struct dw_eth_dev *) memalign(16, sizeof(struct dw_eth_dev)); 542 if (!priv) { 543 free(dev); 544 return -ENOMEM; 545 } 546 547 memset(dev, 0, sizeof(struct eth_device)); 548 memset(priv, 0, sizeof(struct dw_eth_dev)); 549 550 sprintf(dev->name, "mii%d", id); 551 dev->iobase = (int)base_addr; 552 dev->priv = priv; 553 554 eth_getenv_enetaddr_by_index("eth", id, &dev->enetaddr[0]); 555 556 priv->dev = dev; 557 priv->mac_regs_p = (struct eth_mac_regs *)base_addr; 558 priv->dma_regs_p = (struct eth_dma_regs *)(base_addr + 559 DW_DMA_BASE_OFFSET); 560 priv->address = phy_addr; 561 priv->phy_configured = 0; 562 priv->interface = interface; 563 564 dev->init = dw_eth_init; 565 dev->send = dw_eth_send; 566 dev->recv = dw_eth_recv; 567 dev->halt = dw_eth_halt; 568 dev->write_hwaddr = dw_write_hwaddr; 569 570 eth_register(dev); 571 572 #if defined(CONFIG_MII) 573 miiphy_register(dev->name, dw_mii_read, dw_mii_write); 574 #endif 575 return 1; 576 } 577