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