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