Path: blob/master/arch/arm/mach-orion5x/dns323-setup.c
10817 views
/*1* arch/arm/mach-orion5x/dns323-setup.c2*3* Copyright (C) 2007 Herbert Valerio Riedel <[email protected]>4*5* Support for HW Rev C1:6*7* Copyright (C) 2010 Benjamin Herrenschmidt <[email protected]>8*9* This program is free software; you can redistribute it and/or modify10* it under the terms of the GNU Lesser General Public License as11* published by the Free Software Foundation; either version 2 of the12* License, or (at your option) any later version.13*14*/1516#include <linux/kernel.h>17#include <linux/init.h>18#include <linux/delay.h>19#include <linux/platform_device.h>20#include <linux/pci.h>21#include <linux/irq.h>22#include <linux/mtd/physmap.h>23#include <linux/mv643xx_eth.h>24#include <linux/leds.h>25#include <linux/gpio_keys.h>26#include <linux/input.h>27#include <linux/i2c.h>28#include <linux/ata_platform.h>29#include <linux/phy.h>30#include <linux/marvell_phy.h>31#include <asm/mach-types.h>32#include <asm/gpio.h>33#include <asm/mach/arch.h>34#include <asm/mach/pci.h>35#include <mach/orion5x.h>36#include "common.h"37#include "mpp.h"3839/* Rev A1 and B1 */40#define DNS323_GPIO_LED_RIGHT_AMBER 141#define DNS323_GPIO_LED_LEFT_AMBER 242#define DNS323_GPIO_SYSTEM_UP 343#define DNS323_GPIO_LED_POWER1 444#define DNS323_GPIO_LED_POWER2 545#define DNS323_GPIO_OVERTEMP 646#define DNS323_GPIO_RTC 747#define DNS323_GPIO_POWER_OFF 848#define DNS323_GPIO_KEY_POWER 949#define DNS323_GPIO_KEY_RESET 105051/* Rev C1 */52#define DNS323C_GPIO_KEY_POWER 153#define DNS323C_GPIO_POWER_OFF 254#define DNS323C_GPIO_LED_RIGHT_AMBER 855#define DNS323C_GPIO_LED_LEFT_AMBER 956#define DNS323C_GPIO_LED_POWER 1757#define DNS323C_GPIO_FAN_BIT1 1858#define DNS323C_GPIO_FAN_BIT0 195960/* Exposed to userspace, do not change */61enum {62DNS323_REV_A1, /* 0 */63DNS323_REV_B1, /* 1 */64DNS323_REV_C1, /* 2 */65};666768/****************************************************************************69* PCI setup70*/7172static int __init dns323_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)73{74int irq;7576/*77* Check for devices with hard-wired IRQs.78*/79irq = orion5x_pci_map_irq(dev, slot, pin);80if (irq != -1)81return irq;8283return -1;84}8586static struct hw_pci dns323_pci __initdata = {87.nr_controllers = 2,88.swizzle = pci_std_swizzle,89.setup = orion5x_pci_sys_setup,90.scan = orion5x_pci_sys_scan_bus,91.map_irq = dns323_pci_map_irq,92};9394static int __init dns323_pci_init(void)95{96/* Rev B1 and C1 doesn't really use its PCI bus, and initialising PCI97* gets in the way of initialising the SATA controller.98*/99if (machine_is_dns323() && system_rev == DNS323_REV_A1)100pci_common_init(&dns323_pci);101102return 0;103}104105subsys_initcall(dns323_pci_init);106107/****************************************************************************108* 8MiB NOR flash (Spansion S29GL064M90TFIR4)109*110* Layout as used by D-Link:111* 0x00000000-0x00010000 : "MTD1"112* 0x00010000-0x00020000 : "MTD2"113* 0x00020000-0x001a0000 : "Linux Kernel"114* 0x001a0000-0x007d0000 : "File System"115* 0x007d0000-0x00800000 : "u-boot"116*/117118#define DNS323_NOR_BOOT_BASE 0xf4000000119#define DNS323_NOR_BOOT_SIZE SZ_8M120121static struct mtd_partition dns323_partitions[] = {122{123.name = "MTD1",124.size = 0x00010000,125.offset = 0,126}, {127.name = "MTD2",128.size = 0x00010000,129.offset = 0x00010000,130}, {131.name = "Linux Kernel",132.size = 0x00180000,133.offset = 0x00020000,134}, {135.name = "File System",136.size = 0x00630000,137.offset = 0x001A0000,138}, {139.name = "u-boot",140.size = 0x00030000,141.offset = 0x007d0000,142},143};144145static struct physmap_flash_data dns323_nor_flash_data = {146.width = 1,147.parts = dns323_partitions,148.nr_parts = ARRAY_SIZE(dns323_partitions)149};150151static struct resource dns323_nor_flash_resource = {152.flags = IORESOURCE_MEM,153.start = DNS323_NOR_BOOT_BASE,154.end = DNS323_NOR_BOOT_BASE + DNS323_NOR_BOOT_SIZE - 1,155};156157static struct platform_device dns323_nor_flash = {158.name = "physmap-flash",159.id = 0,160.dev = {161.platform_data = &dns323_nor_flash_data,162},163.resource = &dns323_nor_flash_resource,164.num_resources = 1,165};166167/****************************************************************************168* Ethernet169*/170171static struct mv643xx_eth_platform_data dns323_eth_data = {172.phy_addr = MV643XX_ETH_PHY_ADDR(8),173};174175/* dns323_parse_hex_*() taken from tsx09-common.c; should a common copy of these176* functions be kept somewhere?177*/178static int __init dns323_parse_hex_nibble(char n)179{180if (n >= '0' && n <= '9')181return n - '0';182183if (n >= 'A' && n <= 'F')184return n - 'A' + 10;185186if (n >= 'a' && n <= 'f')187return n - 'a' + 10;188189return -1;190}191192static int __init dns323_parse_hex_byte(const char *b)193{194int hi;195int lo;196197hi = dns323_parse_hex_nibble(b[0]);198lo = dns323_parse_hex_nibble(b[1]);199200if (hi < 0 || lo < 0)201return -1;202203return (hi << 4) | lo;204}205206static int __init dns323_read_mac_addr(void)207{208u_int8_t addr[6];209int i;210char *mac_page;211212/* MAC address is stored as a regular ol' string in /dev/mtdblock4213* (0x007d0000-0x00800000) starting at offset 196480 (0x2ff80).214*/215mac_page = ioremap(DNS323_NOR_BOOT_BASE + 0x7d0000 + 196480, 1024);216if (!mac_page)217return -ENOMEM;218219/* Sanity check the string we're looking at */220for (i = 0; i < 5; i++) {221if (*(mac_page + (i * 3) + 2) != ':') {222goto error_fail;223}224}225226for (i = 0; i < 6; i++) {227int byte;228229byte = dns323_parse_hex_byte(mac_page + (i * 3));230if (byte < 0) {231goto error_fail;232}233234addr[i] = byte;235}236237iounmap(mac_page);238printk("DNS-323: Found ethernet MAC address: ");239for (i = 0; i < 6; i++)240printk("%.2x%s", addr[i], (i < 5) ? ":" : ".\n");241242memcpy(dns323_eth_data.mac_addr, addr, 6);243244return 0;245246error_fail:247iounmap(mac_page);248return -EINVAL;249}250251/****************************************************************************252* GPIO LEDs (simple - doesn't use hardware blinking support)253*/254255#define ORION_BLINK_HALF_PERIOD 100 /* ms */256257static int dns323_gpio_blink_set(unsigned gpio, int state,258unsigned long *delay_on, unsigned long *delay_off)259{260261if (delay_on && delay_off && !*delay_on && !*delay_off)262*delay_on = *delay_off = ORION_BLINK_HALF_PERIOD;263264switch(state) {265case GPIO_LED_NO_BLINK_LOW:266case GPIO_LED_NO_BLINK_HIGH:267orion_gpio_set_blink(gpio, 0);268gpio_set_value(gpio, state);269break;270case GPIO_LED_BLINK:271orion_gpio_set_blink(gpio, 1);272}273return 0;274}275276static struct gpio_led dns323ab_leds[] = {277{278.name = "power:blue",279.gpio = DNS323_GPIO_LED_POWER2,280.default_trigger = "default-on",281}, {282.name = "right:amber",283.gpio = DNS323_GPIO_LED_RIGHT_AMBER,284.active_low = 1,285}, {286.name = "left:amber",287.gpio = DNS323_GPIO_LED_LEFT_AMBER,288.active_low = 1,289},290};291292293static struct gpio_led dns323c_leds[] = {294{295.name = "power:blue",296.gpio = DNS323C_GPIO_LED_POWER,297.default_trigger = "timer",298.active_low = 1,299}, {300.name = "right:amber",301.gpio = DNS323C_GPIO_LED_RIGHT_AMBER,302.active_low = 1,303}, {304.name = "left:amber",305.gpio = DNS323C_GPIO_LED_LEFT_AMBER,306.active_low = 1,307},308};309310311static struct gpio_led_platform_data dns323ab_led_data = {312.num_leds = ARRAY_SIZE(dns323ab_leds),313.leds = dns323ab_leds,314.gpio_blink_set = dns323_gpio_blink_set,315};316317static struct gpio_led_platform_data dns323c_led_data = {318.num_leds = ARRAY_SIZE(dns323c_leds),319.leds = dns323c_leds,320.gpio_blink_set = dns323_gpio_blink_set,321};322323static struct platform_device dns323_gpio_leds = {324.name = "leds-gpio",325.id = -1,326.dev = {327.platform_data = &dns323ab_led_data,328},329};330331/****************************************************************************332* GPIO Attached Keys333*/334335static struct gpio_keys_button dns323ab_buttons[] = {336{337.code = KEY_RESTART,338.gpio = DNS323_GPIO_KEY_RESET,339.desc = "Reset Button",340.active_low = 1,341}, {342.code = KEY_POWER,343.gpio = DNS323_GPIO_KEY_POWER,344.desc = "Power Button",345.active_low = 1,346},347};348349static struct gpio_keys_platform_data dns323ab_button_data = {350.buttons = dns323ab_buttons,351.nbuttons = ARRAY_SIZE(dns323ab_buttons),352};353354static struct gpio_keys_button dns323c_buttons[] = {355{356.code = KEY_POWER,357.gpio = DNS323C_GPIO_KEY_POWER,358.desc = "Power Button",359.active_low = 1,360},361};362363static struct gpio_keys_platform_data dns323c_button_data = {364.buttons = dns323c_buttons,365.nbuttons = ARRAY_SIZE(dns323c_buttons),366};367368static struct platform_device dns323_button_device = {369.name = "gpio-keys",370.id = -1,371.num_resources = 0,372.dev = {373.platform_data = &dns323ab_button_data,374},375};376377/*****************************************************************************378* SATA379*/380static struct mv_sata_platform_data dns323_sata_data = {381.n_ports = 2,382};383384/****************************************************************************385* General Setup386*/387static unsigned int dns323a_mpp_modes[] __initdata = {388MPP0_PCIE_RST_OUTn,389MPP1_GPIO, /* right amber LED (sata ch0) */390MPP2_GPIO, /* left amber LED (sata ch1) */391MPP3_UNUSED,392MPP4_GPIO, /* power button LED */393MPP5_GPIO, /* power button LED */394MPP6_GPIO, /* GMT G751-2f overtemp */395MPP7_GPIO, /* M41T80 nIRQ/OUT/SQW */396MPP8_GPIO, /* triggers power off */397MPP9_GPIO, /* power button switch */398MPP10_GPIO, /* reset button switch */399MPP11_UNUSED,400MPP12_UNUSED,401MPP13_UNUSED,402MPP14_UNUSED,403MPP15_UNUSED,404MPP16_UNUSED,405MPP17_UNUSED,406MPP18_UNUSED,407MPP19_UNUSED,4080,409};410411static unsigned int dns323b_mpp_modes[] __initdata = {412MPP0_UNUSED,413MPP1_GPIO, /* right amber LED (sata ch0) */414MPP2_GPIO, /* left amber LED (sata ch1) */415MPP3_GPIO, /* system up flag */416MPP4_GPIO, /* power button LED */417MPP5_GPIO, /* power button LED */418MPP6_GPIO, /* GMT G751-2f overtemp */419MPP7_GPIO, /* M41T80 nIRQ/OUT/SQW */420MPP8_GPIO, /* triggers power off */421MPP9_GPIO, /* power button switch */422MPP10_GPIO, /* reset button switch */423MPP11_UNUSED,424MPP12_SATA_LED,425MPP13_SATA_LED,426MPP14_SATA_LED,427MPP15_SATA_LED,428MPP16_UNUSED,429MPP17_UNUSED,430MPP18_UNUSED,431MPP19_UNUSED,4320,433};434435static unsigned int dns323c_mpp_modes[] __initdata = {436MPP0_GPIO, /* ? input */437MPP1_GPIO, /* input power switch (0 = pressed) */438MPP2_GPIO, /* output power off */439MPP3_UNUSED, /* ? output */440MPP4_UNUSED, /* ? output */441MPP5_UNUSED, /* ? output */442MPP6_UNUSED, /* ? output */443MPP7_UNUSED, /* ? output */444MPP8_GPIO, /* i/o right amber LED */445MPP9_GPIO, /* i/o left amber LED */446MPP10_GPIO, /* input */447MPP11_UNUSED,448MPP12_SATA_LED,449MPP13_SATA_LED,450MPP14_SATA_LED,451MPP15_SATA_LED,452MPP16_UNUSED,453MPP17_GPIO, /* power button LED */454MPP18_GPIO, /* fan speed bit 0 */455MPP19_GPIO, /* fan speed bit 1 */4560,457};458459/* Rev C1 Fan speed notes:460*461* The fan is controlled by 2 GPIOs on this board. The settings462* of the bits is as follow:463*464* GPIO 18 GPIO 19 Fan465*466* 0 0 stopped467* 0 1 low speed468* 1 0 high speed469* 1 1 don't do that (*)470*471* (*) I think the two bits control two feed-in resistors into a fixed472* PWN circuit, setting both bits will basically go a 'bit' faster473* than high speed, but d-link doesn't do it and you may get out of474* HW spec so don't do it.475*/476477/*478* On the DNS-323 A1 and B1 the following devices are attached via I2C:479*480* i2c addr | chip | description481* 0x3e | GMT G760Af | fan speed PWM controller482* 0x48 | GMT G751-2f | temp. sensor and therm. watchdog (LM75 compatible)483* 0x68 | ST M41T80 | RTC w/ alarm484*/485static struct i2c_board_info __initdata dns323ab_i2c_devices[] = {486{487I2C_BOARD_INFO("g760a", 0x3e),488}, {489I2C_BOARD_INFO("lm75", 0x48),490}, {491I2C_BOARD_INFO("m41t80", 0x68),492},493};494495/*496* On the DNS-323 C1 the following devices are attached via I2C:497*498* i2c addr | chip | description499* 0x48 | GMT G751-2f | temp. sensor and therm. watchdog (LM75 compatible)500* 0x68 | ST M41T80 | RTC w/ alarm501*/502static struct i2c_board_info __initdata dns323c_i2c_devices[] = {503{504I2C_BOARD_INFO("lm75", 0x48),505}, {506I2C_BOARD_INFO("m41t80", 0x68),507},508};509510/* DNS-323 rev. A specific power off method */511static void dns323a_power_off(void)512{513pr_info("DNS-323: Triggering power-off...\n");514gpio_set_value(DNS323_GPIO_POWER_OFF, 1);515}516517/* DNS-323 rev B specific power off method */518static void dns323b_power_off(void)519{520pr_info("DNS-323: Triggering power-off...\n");521/* Pin has to be changed to 1 and back to 0 to do actual power off. */522gpio_set_value(DNS323_GPIO_POWER_OFF, 1);523mdelay(100);524gpio_set_value(DNS323_GPIO_POWER_OFF, 0);525}526527/* DNS-323 rev. C specific power off method */528static void dns323c_power_off(void)529{530pr_info("DNS-323: Triggering power-off...\n");531gpio_set_value(DNS323C_GPIO_POWER_OFF, 1);532}533534static int dns323c_phy_fixup(struct phy_device *phy)535{536phy->dev_flags |= MARVELL_PHY_M1118_DNS323_LEDS;537538return 0;539}540541static int __init dns323_identify_rev(void)542{543u32 dev, rev, i, reg;544545pr_debug("DNS-323: Identifying board ... \n");546547/* Rev A1 has a 5181 */548orion5x_pcie_id(&dev, &rev);549if (dev == MV88F5181_DEV_ID) {550pr_debug("DNS-323: 5181 found, board is A1\n");551return DNS323_REV_A1;552}553pr_debug("DNS-323: 5182 found, board is B1 or C1, checking PHY...\n");554555/* Rev B1 and C1 both have 5182, let's poke at the eth PHY. This is556* a bit gross but we want to do that without links into the eth557* driver so let's poke at it directly. We default to rev B1 in558* case the accesses fail559*/560561#define ETH_SMI_REG (ORION5X_ETH_VIRT_BASE + 0x2000 + 0x004)562#define SMI_BUSY 0x10000000563#define SMI_READ_VALID 0x08000000564#define SMI_OPCODE_READ 0x04000000565#define SMI_OPCODE_WRITE 0x00000000566567for (i = 0; i < 1000; i++) {568reg = readl(ETH_SMI_REG);569if (!(reg & SMI_BUSY))570break;571}572if (i >= 1000) {573pr_warning("DNS-323: Timeout accessing PHY, assuming rev B1\n");574return DNS323_REV_B1;575}576writel((3 << 21) /* phy ID reg */ |577(8 << 16) /* phy addr */ |578SMI_OPCODE_READ, ETH_SMI_REG);579for (i = 0; i < 1000; i++) {580reg = readl(ETH_SMI_REG);581if (reg & SMI_READ_VALID)582break;583}584if (i >= 1000) {585pr_warning("DNS-323: Timeout reading PHY, assuming rev B1\n");586return DNS323_REV_B1;587}588pr_debug("DNS-323: Ethernet PHY ID 0x%x\n", reg & 0xffff);589590/* Note: the Marvell tools mask the ID with 0x3f0 before comparison591* but I don't see that making a difference here, at least with592* any known Marvell PHY ID593*/594switch(reg & 0xfff0) {595case 0x0cc0: /* MV88E1111 */596return DNS323_REV_B1;597case 0x0e10: /* MV88E1118 */598return DNS323_REV_C1;599default:600pr_warning("DNS-323: Unknown PHY ID 0x%04x, assuming rev B1\n",601reg & 0xffff);602}603return DNS323_REV_B1;604}605606static void __init dns323_init(void)607{608/* Setup basic Orion functions. Need to be called early. */609orion5x_init();610611/* Identify revision */612system_rev = dns323_identify_rev();613pr_info("DNS-323: Identified HW revision %c1\n", 'A' + system_rev);614615/* Just to be tricky, the 5182 has a completely different616* set of MPP modes to the 5181.617*/618switch(system_rev) {619case DNS323_REV_A1:620orion5x_mpp_conf(dns323a_mpp_modes);621writel(0, MPP_DEV_CTRL); /* DEV_D[31:16] */622break;623case DNS323_REV_B1:624orion5x_mpp_conf(dns323b_mpp_modes);625break;626case DNS323_REV_C1:627orion5x_mpp_conf(dns323c_mpp_modes);628break;629}630631/* setup flash mapping632* CS3 holds a 8 MB Spansion S29GL064M90TFIR4633*/634orion5x_setup_dev_boot_win(DNS323_NOR_BOOT_BASE, DNS323_NOR_BOOT_SIZE);635platform_device_register(&dns323_nor_flash);636637/* Sort out LEDs, Buttons and i2c devices */638switch(system_rev) {639case DNS323_REV_A1:640/* The 5181 power LED is active low and requires641* DNS323_GPIO_LED_POWER1 to also be low.642*/643dns323ab_leds[0].active_low = 1;644gpio_request(DNS323_GPIO_LED_POWER1, "Power Led Enable");645gpio_direction_output(DNS323_GPIO_LED_POWER1, 0);646/* Fall through */647case DNS323_REV_B1:648i2c_register_board_info(0, dns323ab_i2c_devices,649ARRAY_SIZE(dns323ab_i2c_devices));650break;651case DNS323_REV_C1:652/* Hookup LEDs & Buttons */653dns323_gpio_leds.dev.platform_data = &dns323c_led_data;654dns323_button_device.dev.platform_data = &dns323c_button_data;655656/* Hookup i2c devices and fan driver */657i2c_register_board_info(0, dns323c_i2c_devices,658ARRAY_SIZE(dns323c_i2c_devices));659platform_device_register_simple("dns323c-fan", 0, NULL, 0);660661/* Register fixup for the PHY LEDs */662phy_register_fixup_for_uid(MARVELL_PHY_ID_88E1118,663MARVELL_PHY_ID_MASK,664dns323c_phy_fixup);665}666667platform_device_register(&dns323_gpio_leds);668platform_device_register(&dns323_button_device);669670/*671* Configure peripherals.672*/673if (dns323_read_mac_addr() < 0)674printk("DNS-323: Failed to read MAC address\n");675orion5x_ehci0_init();676orion5x_eth_init(&dns323_eth_data);677orion5x_i2c_init();678orion5x_uart0_init();679680/* Remaining GPIOs */681switch(system_rev) {682case DNS323_REV_A1:683/* Poweroff GPIO */684if (gpio_request(DNS323_GPIO_POWER_OFF, "POWEROFF") != 0 ||685gpio_direction_output(DNS323_GPIO_POWER_OFF, 0) != 0)686pr_err("DNS-323: failed to setup power-off GPIO\n");687pm_power_off = dns323a_power_off;688break;689case DNS323_REV_B1:690/* 5182 built-in SATA init */691orion5x_sata_init(&dns323_sata_data);692693/* The DNS323 rev B1 has flag to indicate the system is up.694* Without this flag set, power LED will flash and cannot be695* controlled via leds-gpio.696*/697if (gpio_request(DNS323_GPIO_SYSTEM_UP, "SYS_READY") == 0)698gpio_direction_output(DNS323_GPIO_SYSTEM_UP, 1);699700/* Poweroff GPIO */701if (gpio_request(DNS323_GPIO_POWER_OFF, "POWEROFF") != 0 ||702gpio_direction_output(DNS323_GPIO_POWER_OFF, 0) != 0)703pr_err("DNS-323: failed to setup power-off GPIO\n");704pm_power_off = dns323b_power_off;705break;706case DNS323_REV_C1:707/* 5182 built-in SATA init */708orion5x_sata_init(&dns323_sata_data);709710/* Poweroff GPIO */711if (gpio_request(DNS323C_GPIO_POWER_OFF, "POWEROFF") != 0 ||712gpio_direction_output(DNS323C_GPIO_POWER_OFF, 0) != 0)713pr_err("DNS-323: failed to setup power-off GPIO\n");714pm_power_off = dns323c_power_off;715716/* Now, -this- should theorically be done by the sata_mv driver717* once I figure out what's going on there. Maybe the behaviour718* of the LEDs should be somewhat passed via the platform_data.719* for now, just whack the register and make the LEDs happy720*721* Note: AFAIK, rev B1 needs the same treatement but I'll let722* somebody else test it.723*/724writel(0x5, ORION5X_SATA_VIRT_BASE | 0x2c);725break;726}727}728729/* Warning: D-Link uses a wrong mach-type (=526) in their bootloader */730MACHINE_START(DNS323, "D-Link DNS-323")731/* Maintainer: Herbert Valerio Riedel <[email protected]> */732.boot_params = 0x00000100,733.init_machine = dns323_init,734.map_io = orion5x_map_io,735.init_early = orion5x_init_early,736.init_irq = orion5x_init_irq,737.timer = &orion5x_timer,738.fixup = tag_fixup_mem32,739MACHINE_END740741742