1 /* 2 * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org> 3 * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 #include <linux/init.h> 21 #include <linux/types.h> 22 #include <linux/module.h> 23 #include <linux/delay.h> 24 #include <linux/dma-mapping.h> 25 #include <linux/platform_device.h> 26 #include <linux/mtd/physmap.h> 27 #include <linux/serial.h> 28 #include <linux/serial_8250.h> 29 #include <linux/ioport.h> 30 #include <linux/io.h> 31 #include <linux/vlynq.h> 32 #include <linux/leds.h> 33 #include <linux/string.h> 34 #include <linux/etherdevice.h> 35 #include <linux/phy.h> 36 #include <linux/phy_fixed.h> 37 #include <linux/gpio.h> 38 #include <linux/clk.h> 39 40 #include <asm/addrspace.h> 41 #include <asm/mach-ar7/ar7.h> 42 #include <asm/mach-ar7/gpio.h> 43 #include <asm/mach-ar7/prom.h> 44 45 /***************************************************************************** 46 * VLYNQ Bus 47 ****************************************************************************/ 48 struct plat_vlynq_data { 49 struct plat_vlynq_ops ops; 50 int gpio_bit; 51 int reset_bit; 52 }; 53 54 static int vlynq_on(struct vlynq_device *dev) 55 { 56 int ret; 57 struct plat_vlynq_data *pdata = dev->dev.platform_data; 58 59 ret = gpio_request(pdata->gpio_bit, "vlynq"); 60 if (ret) 61 goto out; 62 63 ar7_device_reset(pdata->reset_bit); 64 65 ret = ar7_gpio_disable(pdata->gpio_bit); 66 if (ret) 67 goto out_enabled; 68 69 ret = ar7_gpio_enable(pdata->gpio_bit); 70 if (ret) 71 goto out_enabled; 72 73 ret = gpio_direction_output(pdata->gpio_bit, 0); 74 if (ret) 75 goto out_gpio_enabled; 76 77 msleep(50); 78 79 gpio_set_value(pdata->gpio_bit, 1); 80 81 msleep(50); 82 83 return 0; 84 85 out_gpio_enabled: 86 ar7_gpio_disable(pdata->gpio_bit); 87 out_enabled: 88 ar7_device_disable(pdata->reset_bit); 89 gpio_free(pdata->gpio_bit); 90 out: 91 return ret; 92 } 93 94 static void vlynq_off(struct vlynq_device *dev) 95 { 96 struct plat_vlynq_data *pdata = dev->dev.platform_data; 97 98 ar7_gpio_disable(pdata->gpio_bit); 99 gpio_free(pdata->gpio_bit); 100 ar7_device_disable(pdata->reset_bit); 101 } 102 103 static struct resource vlynq_low_res[] = { 104 { 105 .name = "regs", 106 .flags = IORESOURCE_MEM, 107 .start = AR7_REGS_VLYNQ0, 108 .end = AR7_REGS_VLYNQ0 + 0xff, 109 }, 110 { 111 .name = "irq", 112 .flags = IORESOURCE_IRQ, 113 .start = 29, 114 .end = 29, 115 }, 116 { 117 .name = "mem", 118 .flags = IORESOURCE_MEM, 119 .start = 0x04000000, 120 .end = 0x04ffffff, 121 }, 122 { 123 .name = "devirq", 124 .flags = IORESOURCE_IRQ, 125 .start = 80, 126 .end = 111, 127 }, 128 }; 129 130 static struct resource vlynq_high_res[] = { 131 { 132 .name = "regs", 133 .flags = IORESOURCE_MEM, 134 .start = AR7_REGS_VLYNQ1, 135 .end = AR7_REGS_VLYNQ1 + 0xff, 136 }, 137 { 138 .name = "irq", 139 .flags = IORESOURCE_IRQ, 140 .start = 33, 141 .end = 33, 142 }, 143 { 144 .name = "mem", 145 .flags = IORESOURCE_MEM, 146 .start = 0x0c000000, 147 .end = 0x0cffffff, 148 }, 149 { 150 .name = "devirq", 151 .flags = IORESOURCE_IRQ, 152 .start = 112, 153 .end = 143, 154 }, 155 }; 156 157 static struct plat_vlynq_data vlynq_low_data = { 158 .ops = { 159 .on = vlynq_on, 160 .off = vlynq_off, 161 }, 162 .reset_bit = 20, 163 .gpio_bit = 18, 164 }; 165 166 static struct plat_vlynq_data vlynq_high_data = { 167 .ops = { 168 .on = vlynq_on, 169 .off = vlynq_off, 170 }, 171 .reset_bit = 16, 172 .gpio_bit = 19, 173 }; 174 175 static struct platform_device vlynq_low = { 176 .id = 0, 177 .name = "vlynq", 178 .dev = { 179 .platform_data = &vlynq_low_data, 180 }, 181 .resource = vlynq_low_res, 182 .num_resources = ARRAY_SIZE(vlynq_low_res), 183 }; 184 185 static struct platform_device vlynq_high = { 186 .id = 1, 187 .name = "vlynq", 188 .dev = { 189 .platform_data = &vlynq_high_data, 190 }, 191 .resource = vlynq_high_res, 192 .num_resources = ARRAY_SIZE(vlynq_high_res), 193 }; 194 195 /***************************************************************************** 196 * Flash 197 ****************************************************************************/ 198 static struct resource physmap_flash_resource = { 199 .name = "mem", 200 .flags = IORESOURCE_MEM, 201 .start = 0x10000000, 202 .end = 0x107fffff, 203 }; 204 205 static const char *ar7_probe_types[] = { "ar7part", NULL }; 206 207 static struct physmap_flash_data physmap_flash_data = { 208 .width = 2, 209 .part_probe_types = ar7_probe_types, 210 }; 211 212 static struct platform_device physmap_flash = { 213 .name = "physmap-flash", 214 .dev = { 215 .platform_data = &physmap_flash_data, 216 }, 217 .resource = &physmap_flash_resource, 218 .num_resources = 1, 219 }; 220 221 /***************************************************************************** 222 * Ethernet 223 ****************************************************************************/ 224 static struct resource cpmac_low_res[] = { 225 { 226 .name = "regs", 227 .flags = IORESOURCE_MEM, 228 .start = AR7_REGS_MAC0, 229 .end = AR7_REGS_MAC0 + 0x7ff, 230 }, 231 { 232 .name = "irq", 233 .flags = IORESOURCE_IRQ, 234 .start = 27, 235 .end = 27, 236 }, 237 }; 238 239 static struct resource cpmac_high_res[] = { 240 { 241 .name = "regs", 242 .flags = IORESOURCE_MEM, 243 .start = AR7_REGS_MAC1, 244 .end = AR7_REGS_MAC1 + 0x7ff, 245 }, 246 { 247 .name = "irq", 248 .flags = IORESOURCE_IRQ, 249 .start = 41, 250 .end = 41, 251 }, 252 }; 253 254 static struct fixed_phy_status fixed_phy_status __initdata = { 255 .link = 1, 256 .speed = 100, 257 .duplex = 1, 258 }; 259 260 static struct plat_cpmac_data cpmac_low_data = { 261 .reset_bit = 17, 262 .power_bit = 20, 263 .phy_mask = 0x80000000, 264 }; 265 266 static struct plat_cpmac_data cpmac_high_data = { 267 .reset_bit = 21, 268 .power_bit = 22, 269 .phy_mask = 0x7fffffff, 270 }; 271 272 static u64 cpmac_dma_mask = DMA_BIT_MASK(32); 273 274 static struct platform_device cpmac_low = { 275 .id = 0, 276 .name = "cpmac", 277 .dev = { 278 .dma_mask = &cpmac_dma_mask, 279 .coherent_dma_mask = DMA_BIT_MASK(32), 280 .platform_data = &cpmac_low_data, 281 }, 282 .resource = cpmac_low_res, 283 .num_resources = ARRAY_SIZE(cpmac_low_res), 284 }; 285 286 static struct platform_device cpmac_high = { 287 .id = 1, 288 .name = "cpmac", 289 .dev = { 290 .dma_mask = &cpmac_dma_mask, 291 .coherent_dma_mask = DMA_BIT_MASK(32), 292 .platform_data = &cpmac_high_data, 293 }, 294 .resource = cpmac_high_res, 295 .num_resources = ARRAY_SIZE(cpmac_high_res), 296 }; 297 298 static void __init cpmac_get_mac(int instance, unsigned char *dev_addr) 299 { 300 char name[5], *mac; 301 302 sprintf(name, "mac%c", 'a' + instance); 303 mac = prom_getenv(name); 304 if (!mac && instance) { 305 sprintf(name, "mac%c", 'a'); 306 mac = prom_getenv(name); 307 } 308 309 if (mac) { 310 if (sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", 311 &dev_addr[0], &dev_addr[1], 312 &dev_addr[2], &dev_addr[3], 313 &dev_addr[4], &dev_addr[5]) != 6) { 314 pr_warning("cannot parse mac address, " 315 "using random address\n"); 316 eth_random_addr(dev_addr); 317 } 318 } else 319 eth_random_addr(dev_addr); 320 } 321 322 /***************************************************************************** 323 * USB 324 ****************************************************************************/ 325 static struct resource usb_res[] = { 326 { 327 .name = "regs", 328 .flags = IORESOURCE_MEM, 329 .start = AR7_REGS_USB, 330 .end = AR7_REGS_USB + 0xff, 331 }, 332 { 333 .name = "irq", 334 .flags = IORESOURCE_IRQ, 335 .start = 32, 336 .end = 32, 337 }, 338 { 339 .name = "mem", 340 .flags = IORESOURCE_MEM, 341 .start = 0x03400000, 342 .end = 0x03401fff, 343 }, 344 }; 345 346 static struct platform_device ar7_udc = { 347 .name = "ar7_udc", 348 .resource = usb_res, 349 .num_resources = ARRAY_SIZE(usb_res), 350 }; 351 352 /***************************************************************************** 353 * LEDs 354 ****************************************************************************/ 355 static struct gpio_led default_leds[] = { 356 { 357 .name = "status", 358 .gpio = 8, 359 .active_low = 1, 360 }, 361 }; 362 363 static struct gpio_led titan_leds[] = { 364 { .name = "status", .gpio = 8, .active_low = 1, }, 365 { .name = "wifi", .gpio = 13, .active_low = 1, }, 366 }; 367 368 static struct gpio_led dsl502t_leds[] = { 369 { 370 .name = "status", 371 .gpio = 9, 372 .active_low = 1, 373 }, 374 { 375 .name = "ethernet", 376 .gpio = 7, 377 .active_low = 1, 378 }, 379 { 380 .name = "usb", 381 .gpio = 12, 382 .active_low = 1, 383 }, 384 }; 385 386 static struct gpio_led dg834g_leds[] = { 387 { 388 .name = "ppp", 389 .gpio = 6, 390 .active_low = 1, 391 }, 392 { 393 .name = "status", 394 .gpio = 7, 395 .active_low = 1, 396 }, 397 { 398 .name = "adsl", 399 .gpio = 8, 400 .active_low = 1, 401 }, 402 { 403 .name = "wifi", 404 .gpio = 12, 405 .active_low = 1, 406 }, 407 { 408 .name = "power", 409 .gpio = 14, 410 .active_low = 1, 411 .default_trigger = "default-on", 412 }, 413 }; 414 415 static struct gpio_led fb_sl_leds[] = { 416 { 417 .name = "1", 418 .gpio = 7, 419 }, 420 { 421 .name = "2", 422 .gpio = 13, 423 .active_low = 1, 424 }, 425 { 426 .name = "3", 427 .gpio = 10, 428 .active_low = 1, 429 }, 430 { 431 .name = "4", 432 .gpio = 12, 433 .active_low = 1, 434 }, 435 { 436 .name = "5", 437 .gpio = 9, 438 .active_low = 1, 439 }, 440 }; 441 442 static struct gpio_led fb_fon_leds[] = { 443 { 444 .name = "1", 445 .gpio = 8, 446 }, 447 { 448 .name = "2", 449 .gpio = 3, 450 .active_low = 1, 451 }, 452 { 453 .name = "3", 454 .gpio = 5, 455 }, 456 { 457 .name = "4", 458 .gpio = 4, 459 .active_low = 1, 460 }, 461 { 462 .name = "5", 463 .gpio = 11, 464 .active_low = 1, 465 }, 466 }; 467 468 static struct gpio_led gt701_leds[] = { 469 { 470 .name = "inet:green", 471 .gpio = 13, 472 .active_low = 1, 473 }, 474 { 475 .name = "usb", 476 .gpio = 12, 477 .active_low = 1, 478 }, 479 { 480 .name = "inet:red", 481 .gpio = 9, 482 .active_low = 1, 483 }, 484 { 485 .name = "power:red", 486 .gpio = 7, 487 .active_low = 1, 488 }, 489 { 490 .name = "power:green", 491 .gpio = 8, 492 .active_low = 1, 493 .default_trigger = "default-on", 494 }, 495 { 496 .name = "ethernet", 497 .gpio = 10, 498 .active_low = 1, 499 }, 500 }; 501 502 static struct gpio_led_platform_data ar7_led_data; 503 504 static struct platform_device ar7_gpio_leds = { 505 .name = "leds-gpio", 506 .dev = { 507 .platform_data = &ar7_led_data, 508 } 509 }; 510 511 static void __init detect_leds(void) 512 { 513 char *prid, *usb_prod; 514 515 /* Default LEDs */ 516 ar7_led_data.num_leds = ARRAY_SIZE(default_leds); 517 ar7_led_data.leds = default_leds; 518 519 /* FIXME: the whole thing is unreliable */ 520 prid = prom_getenv("ProductID"); 521 usb_prod = prom_getenv("usb_prod"); 522 523 /* If we can't get the product id from PROM, use the default LEDs */ 524 if (!prid) 525 return; 526 527 if (strstr(prid, "Fritz_Box_FON")) { 528 ar7_led_data.num_leds = ARRAY_SIZE(fb_fon_leds); 529 ar7_led_data.leds = fb_fon_leds; 530 } else if (strstr(prid, "Fritz_Box_")) { 531 ar7_led_data.num_leds = ARRAY_SIZE(fb_sl_leds); 532 ar7_led_data.leds = fb_sl_leds; 533 } else if ((!strcmp(prid, "AR7RD") || !strcmp(prid, "AR7DB")) 534 && usb_prod != NULL && strstr(usb_prod, "DSL-502T")) { 535 ar7_led_data.num_leds = ARRAY_SIZE(dsl502t_leds); 536 ar7_led_data.leds = dsl502t_leds; 537 } else if (strstr(prid, "DG834")) { 538 ar7_led_data.num_leds = ARRAY_SIZE(dg834g_leds); 539 ar7_led_data.leds = dg834g_leds; 540 } else if (strstr(prid, "CYWM") || strstr(prid, "CYWL")) { 541 ar7_led_data.num_leds = ARRAY_SIZE(titan_leds); 542 ar7_led_data.leds = titan_leds; 543 } else if (strstr(prid, "GT701")) { 544 ar7_led_data.num_leds = ARRAY_SIZE(gt701_leds); 545 ar7_led_data.leds = gt701_leds; 546 } 547 } 548 549 /***************************************************************************** 550 * Watchdog 551 ****************************************************************************/ 552 static struct resource ar7_wdt_res = { 553 .name = "regs", 554 .flags = IORESOURCE_MEM, 555 .start = -1, /* Filled at runtime */ 556 .end = -1, /* Filled at runtime */ 557 }; 558 559 static struct platform_device ar7_wdt = { 560 .name = "ar7_wdt", 561 .resource = &ar7_wdt_res, 562 .num_resources = 1, 563 }; 564 565 /***************************************************************************** 566 * Init 567 ****************************************************************************/ 568 static int __init ar7_register_uarts(void) 569 { 570 #ifdef CONFIG_SERIAL_8250 571 static struct uart_port uart_port __initdata; 572 struct clk *bus_clk; 573 int res; 574 575 memset(&uart_port, 0, sizeof(struct uart_port)); 576 577 bus_clk = clk_get(NULL, "bus"); 578 if (IS_ERR(bus_clk)) 579 panic("unable to get bus clk"); 580 581 uart_port.type = PORT_AR7; 582 uart_port.uartclk = clk_get_rate(bus_clk) / 2; 583 uart_port.iotype = UPIO_MEM32; 584 uart_port.regshift = 2; 585 586 uart_port.line = 0; 587 uart_port.irq = AR7_IRQ_UART0; 588 uart_port.mapbase = AR7_REGS_UART0; 589 uart_port.membase = ioremap(uart_port.mapbase, 256); 590 591 res = early_serial_setup(&uart_port); 592 if (res) 593 return res; 594 595 /* Only TNETD73xx have a second serial port */ 596 if (ar7_has_second_uart()) { 597 uart_port.line = 1; 598 uart_port.irq = AR7_IRQ_UART1; 599 uart_port.mapbase = UR8_REGS_UART1; 600 uart_port.membase = ioremap(uart_port.mapbase, 256); 601 602 res = early_serial_setup(&uart_port); 603 if (res) 604 return res; 605 } 606 #endif 607 608 return 0; 609 } 610 611 static void __init titan_fixup_devices(void) 612 { 613 /* Set vlynq0 data */ 614 vlynq_low_data.reset_bit = 15; 615 vlynq_low_data.gpio_bit = 14; 616 617 /* Set vlynq1 data */ 618 vlynq_high_data.reset_bit = 16; 619 vlynq_high_data.gpio_bit = 7; 620 621 /* Set vlynq0 resources */ 622 vlynq_low_res[0].start = TITAN_REGS_VLYNQ0; 623 vlynq_low_res[0].end = TITAN_REGS_VLYNQ0 + 0xff; 624 vlynq_low_res[1].start = 33; 625 vlynq_low_res[1].end = 33; 626 vlynq_low_res[2].start = 0x0c000000; 627 vlynq_low_res[2].end = 0x0fffffff; 628 vlynq_low_res[3].start = 80; 629 vlynq_low_res[3].end = 111; 630 631 /* Set vlynq1 resources */ 632 vlynq_high_res[0].start = TITAN_REGS_VLYNQ1; 633 vlynq_high_res[0].end = TITAN_REGS_VLYNQ1 + 0xff; 634 vlynq_high_res[1].start = 34; 635 vlynq_high_res[1].end = 34; 636 vlynq_high_res[2].start = 0x40000000; 637 vlynq_high_res[2].end = 0x43ffffff; 638 vlynq_high_res[3].start = 112; 639 vlynq_high_res[3].end = 143; 640 641 /* Set cpmac0 data */ 642 cpmac_low_data.phy_mask = 0x40000000; 643 644 /* Set cpmac1 data */ 645 cpmac_high_data.phy_mask = 0x80000000; 646 647 /* Set cpmac0 resources */ 648 cpmac_low_res[0].start = TITAN_REGS_MAC0; 649 cpmac_low_res[0].end = TITAN_REGS_MAC0 + 0x7ff; 650 651 /* Set cpmac1 resources */ 652 cpmac_high_res[0].start = TITAN_REGS_MAC1; 653 cpmac_high_res[0].end = TITAN_REGS_MAC1 + 0x7ff; 654 } 655 656 static int __init ar7_register_devices(void) 657 { 658 void __iomem *bootcr; 659 u32 val; 660 int res; 661 662 res = ar7_register_uarts(); 663 if (res) 664 pr_err("unable to setup uart(s): %d\n", res); 665 666 res = platform_device_register(&physmap_flash); 667 if (res) 668 pr_warning("unable to register physmap-flash: %d\n", res); 669 670 if (ar7_is_titan()) 671 titan_fixup_devices(); 672 673 ar7_device_disable(vlynq_low_data.reset_bit); 674 res = platform_device_register(&vlynq_low); 675 if (res) 676 pr_warning("unable to register vlynq-low: %d\n", res); 677 678 if (ar7_has_high_vlynq()) { 679 ar7_device_disable(vlynq_high_data.reset_bit); 680 res = platform_device_register(&vlynq_high); 681 if (res) 682 pr_warning("unable to register vlynq-high: %d\n", res); 683 } 684 685 if (ar7_has_high_cpmac()) { 686 res = fixed_phy_add(PHY_POLL, cpmac_high.id, &fixed_phy_status); 687 if (!res) { 688 cpmac_get_mac(1, cpmac_high_data.dev_addr); 689 690 res = platform_device_register(&cpmac_high); 691 if (res) 692 pr_warning("unable to register cpmac-high: %d\n", res); 693 } else 694 pr_warning("unable to add cpmac-high phy: %d\n", res); 695 } else 696 cpmac_low_data.phy_mask = 0xffffffff; 697 698 res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status); 699 if (!res) { 700 cpmac_get_mac(0, cpmac_low_data.dev_addr); 701 res = platform_device_register(&cpmac_low); 702 if (res) 703 pr_warning("unable to register cpmac-low: %d\n", res); 704 } else 705 pr_warning("unable to add cpmac-low phy: %d\n", res); 706 707 detect_leds(); 708 res = platform_device_register(&ar7_gpio_leds); 709 if (res) 710 pr_warning("unable to register leds: %d\n", res); 711 712 res = platform_device_register(&ar7_udc); 713 if (res) 714 pr_warning("unable to register usb slave: %d\n", res); 715 716 /* Register watchdog only if enabled in hardware */ 717 bootcr = ioremap_nocache(AR7_REGS_DCL, 4); 718 val = readl(bootcr); 719 iounmap(bootcr); 720 if (val & AR7_WDT_HW_ENA) { 721 if (ar7_has_high_vlynq()) 722 ar7_wdt_res.start = UR8_REGS_WDT; 723 else 724 ar7_wdt_res.start = AR7_REGS_WDT; 725 726 ar7_wdt_res.end = ar7_wdt_res.start + 0x20; 727 res = platform_device_register(&ar7_wdt); 728 if (res) 729 pr_warning("unable to register watchdog: %d\n", res); 730 } 731 732 return 0; 733 } 734 device_initcall(ar7_register_devices); 735