linux/arch/arm/mach-orion5x/dns323-setup.c
<<
>>
Prefs
   1/*
   2 * arch/arm/mach-orion5x/dns323-setup.c
   3 *
   4 * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU Lesser General Public License as
   8 * published by the Free Software Foundation; either version 2 of the
   9 * License, or (at your option) any later version.
  10 *
  11 */
  12
  13#include <linux/kernel.h>
  14#include <linux/init.h>
  15#include <linux/platform_device.h>
  16#include <linux/pci.h>
  17#include <linux/irq.h>
  18#include <linux/mtd/physmap.h>
  19#include <linux/mv643xx_eth.h>
  20#include <linux/leds.h>
  21#include <linux/gpio_keys.h>
  22#include <linux/input.h>
  23#include <linux/i2c.h>
  24#include <linux/ata_platform.h>
  25#include <asm/mach-types.h>
  26#include <asm/gpio.h>
  27#include <asm/mach/arch.h>
  28#include <asm/mach/pci.h>
  29#include <mach/orion5x.h>
  30#include "common.h"
  31#include "mpp.h"
  32
  33#define DNS323_GPIO_LED_RIGHT_AMBER     1
  34#define DNS323_GPIO_LED_LEFT_AMBER      2
  35#define DNS323_GPIO_LED_POWER           5
  36#define DNS323_GPIO_OVERTEMP            6
  37#define DNS323_GPIO_RTC                 7
  38#define DNS323_GPIO_POWER_OFF           8
  39#define DNS323_GPIO_KEY_POWER           9
  40#define DNS323_GPIO_KEY_RESET           10
  41
  42/****************************************************************************
  43 * PCI setup
  44 */
  45
  46static int __init dns323_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
  47{
  48        int irq;
  49
  50        /*
  51         * Check for devices with hard-wired IRQs.
  52         */
  53        irq = orion5x_pci_map_irq(dev, slot, pin);
  54        if (irq != -1)
  55                return irq;
  56
  57        return -1;
  58}
  59
  60static struct hw_pci dns323_pci __initdata = {
  61        .nr_controllers = 2,
  62        .swizzle        = pci_std_swizzle,
  63        .setup          = orion5x_pci_sys_setup,
  64        .scan           = orion5x_pci_sys_scan_bus,
  65        .map_irq        = dns323_pci_map_irq,
  66};
  67
  68static int __init dns323_dev_id(void)
  69{
  70        u32 dev, rev;
  71
  72        orion5x_pcie_id(&dev, &rev);
  73
  74        return dev;
  75}
  76
  77static int __init dns323_pci_init(void)
  78{
  79        /* The 5182 doesn't really use its PCI bus, and initialising PCI
  80         * gets in the way of initialising the SATA controller.
  81         */
  82        if (machine_is_dns323() && dns323_dev_id() != MV88F5182_DEV_ID)
  83                pci_common_init(&dns323_pci);
  84
  85        return 0;
  86}
  87
  88subsys_initcall(dns323_pci_init);
  89
  90/****************************************************************************
  91 * 8MiB NOR flash (Spansion S29GL064M90TFIR4)
  92 *
  93 * Layout as used by D-Link:
  94 *  0x00000000-0x00010000 : "MTD1"
  95 *  0x00010000-0x00020000 : "MTD2"
  96 *  0x00020000-0x001a0000 : "Linux Kernel"
  97 *  0x001a0000-0x007d0000 : "File System"
  98 *  0x007d0000-0x00800000 : "u-boot"
  99 */
 100
 101#define DNS323_NOR_BOOT_BASE 0xf4000000
 102#define DNS323_NOR_BOOT_SIZE SZ_8M
 103
 104static struct mtd_partition dns323_partitions[] = {
 105        {
 106                .name   = "MTD1",
 107                .size   = 0x00010000,
 108                .offset = 0,
 109        }, {
 110                .name   = "MTD2",
 111                .size   = 0x00010000,
 112                .offset = 0x00010000,
 113        }, {
 114                .name   = "Linux Kernel",
 115                .size   = 0x00180000,
 116                .offset = 0x00020000,
 117        }, {
 118                .name   = "File System",
 119                .size   = 0x00630000,
 120                .offset = 0x001A0000,
 121        }, {
 122                .name   = "u-boot",
 123                .size   = 0x00030000,
 124                .offset = 0x007d0000,
 125        },
 126};
 127
 128static struct physmap_flash_data dns323_nor_flash_data = {
 129        .width          = 1,
 130        .parts          = dns323_partitions,
 131        .nr_parts       = ARRAY_SIZE(dns323_partitions)
 132};
 133
 134static struct resource dns323_nor_flash_resource = {
 135        .flags          = IORESOURCE_MEM,
 136        .start          = DNS323_NOR_BOOT_BASE,
 137        .end            = DNS323_NOR_BOOT_BASE + DNS323_NOR_BOOT_SIZE - 1,
 138};
 139
 140static struct platform_device dns323_nor_flash = {
 141        .name           = "physmap-flash",
 142        .id             = 0,
 143        .dev            = {
 144                .platform_data  = &dns323_nor_flash_data,
 145        },
 146        .resource       = &dns323_nor_flash_resource,
 147        .num_resources  = 1,
 148};
 149
 150/****************************************************************************
 151 * Ethernet
 152 */
 153
 154static struct mv643xx_eth_platform_data dns323_eth_data = {
 155        .phy_addr = MV643XX_ETH_PHY_ADDR(8),
 156};
 157
 158/* dns323_parse_hex_*() taken from tsx09-common.c; should a common copy of these
 159 * functions be kept somewhere?
 160 */
 161static int __init dns323_parse_hex_nibble(char n)
 162{
 163        if (n >= '0' && n <= '9')
 164                return n - '0';
 165
 166        if (n >= 'A' && n <= 'F')
 167                return n - 'A' + 10;
 168
 169        if (n >= 'a' && n <= 'f')
 170                return n - 'a' + 10;
 171
 172        return -1;
 173}
 174
 175static int __init dns323_parse_hex_byte(const char *b)
 176{
 177        int hi;
 178        int lo;
 179
 180        hi = dns323_parse_hex_nibble(b[0]);
 181        lo = dns323_parse_hex_nibble(b[1]);
 182
 183        if (hi < 0 || lo < 0)
 184                return -1;
 185
 186        return (hi << 4) | lo;
 187}
 188
 189static int __init dns323_read_mac_addr(void)
 190{
 191        u_int8_t addr[6];
 192        int i;
 193        char *mac_page;
 194
 195        /* MAC address is stored as a regular ol' string in /dev/mtdblock4
 196         * (0x007d0000-0x00800000) starting at offset 196480 (0x2ff80).
 197         */
 198        mac_page = ioremap(DNS323_NOR_BOOT_BASE + 0x7d0000 + 196480, 1024);
 199        if (!mac_page)
 200                return -ENOMEM;
 201
 202        /* Sanity check the string we're looking at */
 203        for (i = 0; i < 5; i++) {
 204                if (*(mac_page + (i * 3) + 2) != ':') {
 205                        goto error_fail;
 206                }
 207        }
 208
 209        for (i = 0; i < 6; i++) {
 210                int byte;
 211
 212                byte = dns323_parse_hex_byte(mac_page + (i * 3));
 213                if (byte < 0) {
 214                        goto error_fail;
 215                }
 216
 217                addr[i] = byte;
 218        }
 219
 220        iounmap(mac_page);
 221        printk("DNS323: Found ethernet MAC address: ");
 222        for (i = 0; i < 6; i++)
 223                printk("%.2x%s", addr[i], (i < 5) ? ":" : ".\n");
 224
 225        memcpy(dns323_eth_data.mac_addr, addr, 6);
 226
 227        return 0;
 228
 229error_fail:
 230        iounmap(mac_page);
 231        return -EINVAL;
 232}
 233
 234/****************************************************************************
 235 * GPIO LEDs (simple - doesn't use hardware blinking support)
 236 */
 237
 238static struct gpio_led dns323_leds[] = {
 239        {
 240                .name = "power:blue",
 241                .gpio = DNS323_GPIO_LED_POWER,
 242                .active_low = 1,
 243        }, {
 244                .name = "right:amber",
 245                .gpio = DNS323_GPIO_LED_RIGHT_AMBER,
 246                .active_low = 1,
 247        }, {
 248                .name = "left:amber",
 249                .gpio = DNS323_GPIO_LED_LEFT_AMBER,
 250                .active_low = 1,
 251        },
 252};
 253
 254static struct gpio_led_platform_data dns323_led_data = {
 255        .num_leds       = ARRAY_SIZE(dns323_leds),
 256        .leds           = dns323_leds,
 257};
 258
 259static struct platform_device dns323_gpio_leds = {
 260        .name           = "leds-gpio",
 261        .id             = -1,
 262        .dev            = {
 263                .platform_data  = &dns323_led_data,
 264        },
 265};
 266
 267/****************************************************************************
 268 * GPIO Attached Keys
 269 */
 270
 271static struct gpio_keys_button dns323_buttons[] = {
 272        {
 273                .code           = KEY_RESTART,
 274                .gpio           = DNS323_GPIO_KEY_RESET,
 275                .desc           = "Reset Button",
 276                .active_low     = 1,
 277        }, {
 278                .code           = KEY_POWER,
 279                .gpio           = DNS323_GPIO_KEY_POWER,
 280                .desc           = "Power Button",
 281                .active_low     = 1,
 282        },
 283};
 284
 285static struct gpio_keys_platform_data dns323_button_data = {
 286        .buttons        = dns323_buttons,
 287        .nbuttons       = ARRAY_SIZE(dns323_buttons),
 288};
 289
 290static struct platform_device dns323_button_device = {
 291        .name           = "gpio-keys",
 292        .id             = -1,
 293        .num_resources  = 0,
 294        .dev            = {
 295                .platform_data  = &dns323_button_data,
 296        },
 297};
 298
 299/*****************************************************************************
 300 * SATA
 301 */
 302static struct mv_sata_platform_data dns323_sata_data = {
 303       .n_ports        = 2,
 304};
 305
 306/****************************************************************************
 307 * General Setup
 308 */
 309static struct orion5x_mpp_mode dns323_mv88f5181_mpp_modes[] __initdata = {
 310        {  0, MPP_PCIE_RST_OUTn },
 311        {  1, MPP_GPIO },               /* right amber LED (sata ch0) */
 312        {  2, MPP_GPIO },               /* left amber LED (sata ch1) */
 313        {  3, MPP_UNUSED },
 314        {  4, MPP_GPIO },               /* power button LED */
 315        {  5, MPP_GPIO },               /* power button LED */
 316        {  6, MPP_GPIO },               /* GMT G751-2f overtemp */
 317        {  7, MPP_GPIO },               /* M41T80 nIRQ/OUT/SQW */
 318        {  8, MPP_GPIO },               /* triggers power off */
 319        {  9, MPP_GPIO },               /* power button switch */
 320        { 10, MPP_GPIO },               /* reset button switch */
 321        { 11, MPP_UNUSED },
 322        { 12, MPP_UNUSED },
 323        { 13, MPP_UNUSED },
 324        { 14, MPP_UNUSED },
 325        { 15, MPP_UNUSED },
 326        { 16, MPP_UNUSED },
 327        { 17, MPP_UNUSED },
 328        { 18, MPP_UNUSED },
 329        { 19, MPP_UNUSED },
 330        { -1 },
 331};
 332
 333static struct orion5x_mpp_mode dns323_mv88f5182_mpp_modes[] __initdata = {
 334        {  0, MPP_UNUSED },
 335        {  1, MPP_GPIO },               /* right amber LED (sata ch0) */
 336        {  2, MPP_GPIO },               /* left amber LED (sata ch1) */
 337        {  3, MPP_UNUSED },
 338        {  4, MPP_GPIO },               /* power button LED */
 339        {  5, MPP_GPIO },               /* power button LED */
 340        {  6, MPP_GPIO },               /* GMT G751-2f overtemp */
 341        {  7, MPP_GPIO },               /* M41T80 nIRQ/OUT/SQW */
 342        {  8, MPP_GPIO },               /* triggers power off */
 343        {  9, MPP_GPIO },               /* power button switch */
 344        { 10, MPP_GPIO },               /* reset button switch */
 345        { 11, MPP_UNUSED },
 346        { 12, MPP_SATA_LED },
 347        { 13, MPP_SATA_LED },
 348        { 14, MPP_SATA_LED },
 349        { 15, MPP_SATA_LED },
 350        { 16, MPP_UNUSED },
 351        { 17, MPP_UNUSED },
 352        { 18, MPP_UNUSED },
 353        { 19, MPP_UNUSED },
 354        { -1 },
 355};
 356
 357/*
 358 * On the DNS-323 the following devices are attached via I2C:
 359 *
 360 *  i2c addr | chip        | description
 361 *  0x3e     | GMT G760Af  | fan speed PWM controller
 362 *  0x48     | GMT G751-2f | temp. sensor and therm. watchdog (LM75 compatible)
 363 *  0x68     | ST M41T80   | RTC w/ alarm
 364 */
 365static struct i2c_board_info __initdata dns323_i2c_devices[] = {
 366        {
 367                I2C_BOARD_INFO("g760a", 0x3e),
 368        }, {
 369                I2C_BOARD_INFO("lm75", 0x48),
 370        }, {
 371                I2C_BOARD_INFO("m41t80", 0x68),
 372        },
 373};
 374
 375/* DNS-323 specific power off method */
 376static void dns323_power_off(void)
 377{
 378        pr_info("%s: triggering power-off...\n", __func__);
 379        gpio_set_value(DNS323_GPIO_POWER_OFF, 1);
 380}
 381
 382static void __init dns323_init(void)
 383{
 384        /* Setup basic Orion functions. Need to be called early. */
 385        orion5x_init();
 386
 387        /* Just to be tricky, the 5182 has a completely different
 388         * set of MPP modes to the 5181.
 389         */
 390        if (dns323_dev_id() == MV88F5182_DEV_ID)
 391                orion5x_mpp_conf(dns323_mv88f5182_mpp_modes);
 392        else {
 393                orion5x_mpp_conf(dns323_mv88f5181_mpp_modes);
 394                writel(0, MPP_DEV_CTRL);                /* DEV_D[31:16] */
 395        }
 396
 397        /* setup flash mapping
 398         * CS3 holds a 8 MB Spansion S29GL064M90TFIR4
 399         */
 400        orion5x_setup_dev_boot_win(DNS323_NOR_BOOT_BASE, DNS323_NOR_BOOT_SIZE);
 401        platform_device_register(&dns323_nor_flash);
 402
 403        platform_device_register(&dns323_gpio_leds);
 404
 405        platform_device_register(&dns323_button_device);
 406
 407        i2c_register_board_info(0, dns323_i2c_devices,
 408                                ARRAY_SIZE(dns323_i2c_devices));
 409
 410        /*
 411         * Configure peripherals.
 412         */
 413        if (dns323_read_mac_addr() < 0)
 414                printk("DNS323: Failed to read MAC address\n");
 415
 416        orion5x_ehci0_init();
 417        orion5x_eth_init(&dns323_eth_data);
 418        orion5x_i2c_init();
 419        orion5x_uart0_init();
 420
 421        /* The 5182 has its SATA controller on-chip, and needs its own little
 422         * init routine.
 423         */
 424        if (dns323_dev_id() == MV88F5182_DEV_ID)
 425                orion5x_sata_init(&dns323_sata_data);
 426
 427        /* register dns323 specific power-off method */
 428        if (gpio_request(DNS323_GPIO_POWER_OFF, "POWEROFF") != 0 ||
 429            gpio_direction_output(DNS323_GPIO_POWER_OFF, 0) != 0)
 430                pr_err("DNS323: failed to setup power-off GPIO\n");
 431        pm_power_off = dns323_power_off;
 432}
 433
 434/* Warning: D-Link uses a wrong mach-type (=526) in their bootloader */
 435MACHINE_START(DNS323, "D-Link DNS-323")
 436        /* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */
 437        .phys_io        = ORION5X_REGS_PHYS_BASE,
 438        .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 439        .boot_params    = 0x00000100,
 440        .init_machine   = dns323_init,
 441        .map_io         = orion5x_map_io,
 442        .init_irq       = orion5x_init_irq,
 443        .timer          = &orion5x_timer,
 444        .fixup          = tag_fixup_mem32,
 445MACHINE_END
 446
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.