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