linux/arch/mips/ar7/platform.c
<<
>>
Prefs
   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 ****************************************************************************/
  46struct plat_vlynq_data {
  47        struct plat_vlynq_ops ops;
  48        int gpio_bit;
  49        int reset_bit;
  50};
  51
  52static 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
  83out_gpio_enabled:
  84        ar7_gpio_disable(pdata->gpio_bit);
  85out_enabled:
  86        ar7_device_disable(pdata->reset_bit);
  87        gpio_free(pdata->gpio_bit);
  88out:
  89        return ret;
  90}
  91
  92static 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
 101static 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
 128static 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
 155static 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
 164static 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
 173static 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
 183static 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 ****************************************************************************/
 196static struct resource physmap_flash_resource = {
 197        .name   = "mem",
 198        .flags  = IORESOURCE_MEM,
 199        .start  = 0x10000000,
 200        .end    = 0x107fffff,
 201};
 202
 203static const char *ar7_probe_types[] = { "ar7part", NULL };
 204
 205static struct physmap_flash_data physmap_flash_data = {
 206        .width  = 2,
 207        .part_probe_types = ar7_probe_types,
 208};
 209
 210static 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 ****************************************************************************/
 222static 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
 237static 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
 252static struct fixed_phy_status fixed_phy_status __initdata = {
 253        .link           = 1,
 254        .speed          = 100,
 255        .duplex         = 1,
 256};
 257
 258static struct plat_cpmac_data cpmac_low_data = {
 259        .reset_bit      = 17,
 260        .power_bit      = 20,
 261        .phy_mask       = 0x80000000,
 262};
 263
 264static struct plat_cpmac_data cpmac_high_data = {
 265        .reset_bit      = 21,
 266        .power_bit      = 22,
 267        .phy_mask       = 0x7fffffff,
 268};
 269
 270static u64 cpmac_dma_mask = DMA_BIT_MASK(32);
 271
 272static 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
 284static 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
 296static 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 ****************************************************************************/
 319static 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
 340static 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 ****************************************************************************/
 349static const struct gpio_led default_leds[] = {
 350        {
 351                .name                   = "status",
 352                .gpio                   = 8,
 353                .active_low             = 1,
 354        },
 355};
 356
 357static const struct gpio_led titan_leds[] = {
 358        { .name = "status", .gpio = 8, .active_low = 1, },
 359        { .name = "wifi", .gpio = 13, .active_low = 1, },
 360};
 361
 362static const 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
 380static const 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
 409static const 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
 436static const 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
 462static const 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
 496static struct gpio_led_platform_data ar7_led_data;
 497
 498static struct platform_device ar7_gpio_leds = {
 499        .name = "leds-gpio",
 500        .dev = {
 501                .platform_data = &ar7_led_data,
 502        }
 503};
 504
 505static 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 ****************************************************************************/
 546static 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
 553static struct platform_device ar7_wdt = {
 554        .name           = "ar7_wdt",
 555        .resource       = &ar7_wdt_res,
 556        .num_resources  = 1,
 557};
 558
 559/*****************************************************************************
 560 * Init
 561 ****************************************************************************/
 562static 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.flags         = UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF;
 579        uart_port.regshift      = 2;
 580
 581        uart_port.line          = 0;
 582        uart_port.irq           = AR7_IRQ_UART0;
 583        uart_port.mapbase       = AR7_REGS_UART0;
 584        uart_port.membase       = ioremap(uart_port.mapbase, 256);
 585
 586        res = early_serial_setup(&uart_port);
 587        if (res)
 588                return res;
 589
 590        /* Only TNETD73xx have a second serial port */
 591        if (ar7_has_second_uart()) {
 592                uart_port.line          = 1;
 593                uart_port.irq           = AR7_IRQ_UART1;
 594                uart_port.mapbase       = UR8_REGS_UART1;
 595                uart_port.membase       = ioremap(uart_port.mapbase, 256);
 596
 597                res = early_serial_setup(&uart_port);
 598                if (res)
 599                        return res;
 600        }
 601#endif
 602
 603        return 0;
 604}
 605
 606static void __init titan_fixup_devices(void)
 607{
 608        /* Set vlynq0 data */
 609        vlynq_low_data.reset_bit = 15;
 610        vlynq_low_data.gpio_bit = 14;
 611
 612        /* Set vlynq1 data */
 613        vlynq_high_data.reset_bit = 16;
 614        vlynq_high_data.gpio_bit = 7;
 615
 616        /* Set vlynq0 resources */
 617        vlynq_low_res[0].start = TITAN_REGS_VLYNQ0;
 618        vlynq_low_res[0].end = TITAN_REGS_VLYNQ0 + 0xff;
 619        vlynq_low_res[1].start = 33;
 620        vlynq_low_res[1].end = 33;
 621        vlynq_low_res[2].start = 0x0c000000;
 622        vlynq_low_res[2].end = 0x0fffffff;
 623        vlynq_low_res[3].start = 80;
 624        vlynq_low_res[3].end = 111;
 625
 626        /* Set vlynq1 resources */
 627        vlynq_high_res[0].start = TITAN_REGS_VLYNQ1;
 628        vlynq_high_res[0].end = TITAN_REGS_VLYNQ1 + 0xff;
 629        vlynq_high_res[1].start = 34;
 630        vlynq_high_res[1].end = 34;
 631        vlynq_high_res[2].start = 0x40000000;
 632        vlynq_high_res[2].end = 0x43ffffff;
 633        vlynq_high_res[3].start = 112;
 634        vlynq_high_res[3].end = 143;
 635
 636        /* Set cpmac0 data */
 637        cpmac_low_data.phy_mask = 0x40000000;
 638
 639        /* Set cpmac1 data */
 640        cpmac_high_data.phy_mask = 0x80000000;
 641
 642        /* Set cpmac0 resources */
 643        cpmac_low_res[0].start = TITAN_REGS_MAC0;
 644        cpmac_low_res[0].end = TITAN_REGS_MAC0 + 0x7ff;
 645
 646        /* Set cpmac1 resources */
 647        cpmac_high_res[0].start = TITAN_REGS_MAC1;
 648        cpmac_high_res[0].end = TITAN_REGS_MAC1 + 0x7ff;
 649}
 650
 651static int __init ar7_register_devices(void)
 652{
 653        void __iomem *bootcr;
 654        u32 val;
 655        int res;
 656
 657        res = ar7_gpio_init();
 658        if (res)
 659                pr_warn("unable to register gpios: %d\n", res);
 660
 661        res = ar7_register_uarts();
 662        if (res)
 663                pr_err("unable to setup uart(s): %d\n", res);
 664
 665        res = platform_device_register(&physmap_flash);
 666        if (res)
 667                pr_warn("unable to register physmap-flash: %d\n", res);
 668
 669        if (ar7_is_titan())
 670                titan_fixup_devices();
 671
 672        ar7_device_disable(vlynq_low_data.reset_bit);
 673        res = platform_device_register(&vlynq_low);
 674        if (res)
 675                pr_warn("unable to register vlynq-low: %d\n", res);
 676
 677        if (ar7_has_high_vlynq()) {
 678                ar7_device_disable(vlynq_high_data.reset_bit);
 679                res = platform_device_register(&vlynq_high);
 680                if (res)
 681                        pr_warn("unable to register vlynq-high: %d\n", res);
 682        }
 683
 684        if (ar7_has_high_cpmac()) {
 685                res = fixed_phy_add(PHY_POLL, cpmac_high.id,
 686                                    &fixed_phy_status, -1);
 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_warn("unable to register cpmac-high: %d\n",
 693                                        res);
 694                } else
 695                        pr_warn("unable to add cpmac-high phy: %d\n", res);
 696        } else
 697                cpmac_low_data.phy_mask = 0xffffffff;
 698
 699        res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status, -1);
 700        if (!res) {
 701                cpmac_get_mac(0, cpmac_low_data.dev_addr);
 702                res = platform_device_register(&cpmac_low);
 703                if (res)
 704                        pr_warn("unable to register cpmac-low: %d\n", res);
 705        } else
 706                pr_warn("unable to add cpmac-low phy: %d\n", res);
 707
 708        detect_leds();
 709        res = platform_device_register(&ar7_gpio_leds);
 710        if (res)
 711                pr_warn("unable to register leds: %d\n", res);
 712
 713        res = platform_device_register(&ar7_udc);
 714        if (res)
 715                pr_warn("unable to register usb slave: %d\n", res);
 716
 717        /* Register watchdog only if enabled in hardware */
 718        bootcr = ioremap_nocache(AR7_REGS_DCL, 4);
 719        val = readl(bootcr);
 720        iounmap(bootcr);
 721        if (val & AR7_WDT_HW_ENA) {
 722                if (ar7_has_high_vlynq())
 723                        ar7_wdt_res.start = UR8_REGS_WDT;
 724                else
 725                        ar7_wdt_res.start = AR7_REGS_WDT;
 726
 727                ar7_wdt_res.end = ar7_wdt_res.start + 0x20;
 728                res = platform_device_register(&ar7_wdt);
 729                if (res)
 730                        pr_warn("unable to register watchdog: %d\n", res);
 731        }
 732
 733        return 0;
 734}
 735device_initcall(ar7_register_devices);
 736