diff options
Diffstat (limited to 'arch/arm/mach-orion5x/kurobox_pro-setup.c')
-rw-r--r-- | arch/arm/mach-orion5x/kurobox_pro-setup.c | 224 |
1 files changed, 183 insertions, 41 deletions
diff --git a/arch/arm/mach-orion5x/kurobox_pro-setup.c b/arch/arm/mach-orion5x/kurobox_pro-setup.c index f5074b877b7..84feac4a1fe 100644 --- a/arch/arm/mach-orion5x/kurobox_pro-setup.c +++ b/arch/arm/mach-orion5x/kurobox_pro-setup.c @@ -13,10 +13,12 @@ #include <linux/platform_device.h> #include <linux/pci.h> #include <linux/irq.h> +#include <linux/delay.h> #include <linux/mtd/physmap.h> #include <linux/mtd/nand.h> #include <linux/mv643xx_eth.h> #include <linux/i2c.h> +#include <linux/serial_reg.h> #include <linux/ata_platform.h> #include <asm/mach-types.h> #include <asm/gpio.h> @@ -25,6 +27,7 @@ #include <asm/arch/orion5x.h> #include <asm/plat-orion/orion_nand.h> #include "common.h" +#include "mpp.h" /***************************************************************************** * KUROBOX-PRO Info @@ -53,13 +56,11 @@ static struct mtd_partition kurobox_pro_nand_parts[] = { .name = "uImage", .offset = 0, .size = SZ_4M, - }, - { + }, { .name = "rootfs", .offset = SZ_4M, .size = SZ_64M, - }, - { + }, { .name = "extra", .offset = SZ_4M + SZ_64M, .size = SZ_256M - (SZ_4M + SZ_64M), @@ -132,8 +133,6 @@ static int __init kurobox_pro_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) /* * PCI isn't used on the Kuro */ - printk(KERN_ERR "kurobox_pro_pci_map_irq failed, unknown bus\n"); - return -1; } @@ -161,7 +160,6 @@ subsys_initcall(kurobox_pro_pci_init); static struct mv643xx_eth_platform_data kurobox_pro_eth_data = { .phy_addr = 8, - .force_phy_addr = 1, }; /***************************************************************************** @@ -175,12 +173,169 @@ static struct i2c_board_info __initdata kurobox_pro_i2c_rtc = { * SATA ****************************************************************************/ static struct mv_sata_platform_data kurobox_pro_sata_data = { - .n_ports = 2, + .n_ports = 2, }; /***************************************************************************** + * Kurobox Pro specific power off method via UART1-attached microcontroller + ****************************************************************************/ + +#define UART1_REG(x) (UART1_VIRT_BASE + ((UART_##x) << 2)) + +static int kurobox_pro_miconread(unsigned char *buf, int count) +{ + int i; + int timeout; + + for (i = 0; i < count; i++) { + timeout = 10; + + while (!(readl(UART1_REG(LSR)) & UART_LSR_DR)) { + if (--timeout == 0) + break; + udelay(1000); + } + + if (timeout == 0) + break; + buf[i] = readl(UART1_REG(RX)); + } + + /* return read bytes */ + return i; +} + +static int kurobox_pro_miconwrite(const unsigned char *buf, int count) +{ + int i = 0; + + while (count--) { + while (!(readl(UART1_REG(LSR)) & UART_LSR_THRE)) + barrier(); + writel(buf[i++], UART1_REG(TX)); + } + + return 0; +} + +static int kurobox_pro_miconsend(const unsigned char *data, int count) +{ + int i; + unsigned char checksum = 0; + unsigned char recv_buf[40]; + unsigned char send_buf[40]; + unsigned char correct_ack[3]; + int retry = 2; + + /* Generate checksum */ + for (i = 0; i < count; i++) + checksum -= data[i]; + + do { + /* Send data */ + kurobox_pro_miconwrite(data, count); + + /* send checksum */ + kurobox_pro_miconwrite(&checksum, 1); + + if (kurobox_pro_miconread(recv_buf, sizeof(recv_buf)) <= 3) { + printk(KERN_ERR ">%s: receive failed.\n", __func__); + + /* send preamble to clear the receive buffer */ + memset(&send_buf, 0xff, sizeof(send_buf)); + kurobox_pro_miconwrite(send_buf, sizeof(send_buf)); + + /* make dummy reads */ + mdelay(100); + kurobox_pro_miconread(recv_buf, sizeof(recv_buf)); + } else { + /* Generate expected ack */ + correct_ack[0] = 0x01; + correct_ack[1] = data[1]; + correct_ack[2] = 0x00; + + /* checksum Check */ + if ((recv_buf[0] + recv_buf[1] + recv_buf[2] + + recv_buf[3]) & 0xFF) { + printk(KERN_ERR ">%s: Checksum Error : " + "Received data[%02x, %02x, %02x, %02x]" + "\n", __func__, recv_buf[0], + recv_buf[1], recv_buf[2], recv_buf[3]); + } else { + /* Check Received Data */ + if (correct_ack[0] == recv_buf[0] && + correct_ack[1] == recv_buf[1] && + correct_ack[2] == recv_buf[2]) { + /* Interval for next command */ + mdelay(10); + + /* Receive ACK */ + return 0; + } + } + /* Received NAK or illegal Data */ + printk(KERN_ERR ">%s: Error : NAK or Illegal Data " + "Received\n", __func__); + } + } while (retry--); + + /* Interval for next command */ + mdelay(10); + + return -1; +} + +static void kurobox_pro_power_off(void) +{ + const unsigned char watchdogkill[] = {0x01, 0x35, 0x00}; + const unsigned char shutdownwait[] = {0x00, 0x0c}; + const unsigned char poweroff[] = {0x00, 0x06}; + /* 38400 baud divisor */ + const unsigned divisor = ((ORION5X_TCLK + (8 * 38400)) / (16 * 38400)); + + pr_info("%s: triggering power-off...\n", __func__); + + /* hijack uart1 and reset into sane state (38400,8n1,even parity) */ + writel(0x83, UART1_REG(LCR)); + writel(divisor & 0xff, UART1_REG(DLL)); + writel((divisor >> 8) & 0xff, UART1_REG(DLM)); + writel(0x1b, UART1_REG(LCR)); + writel(0x00, UART1_REG(IER)); + writel(0x07, UART1_REG(FCR)); + writel(0x00, UART1_REG(MCR)); + + /* Send the commands to shutdown the Kurobox Pro */ + kurobox_pro_miconsend(watchdogkill, sizeof(watchdogkill)) ; + kurobox_pro_miconsend(shutdownwait, sizeof(shutdownwait)) ; + kurobox_pro_miconsend(poweroff, sizeof(poweroff)); +} + +/***************************************************************************** * General Setup ****************************************************************************/ +static struct orion5x_mpp_mode kurobox_pro_mpp_modes[] __initdata = { + { 0, MPP_UNUSED }, + { 1, MPP_UNUSED }, + { 2, MPP_GPIO }, /* GPIO Micon */ + { 3, MPP_GPIO }, /* GPIO Rtc */ + { 4, MPP_UNUSED }, + { 5, MPP_UNUSED }, + { 6, MPP_NAND }, /* NAND Flash REn */ + { 7, MPP_NAND }, /* NAND Flash WEn */ + { 8, MPP_UNUSED }, + { 9, MPP_UNUSED }, + { 10, MPP_UNUSED }, + { 11, MPP_UNUSED }, + { 12, MPP_SATA_LED }, /* SATA 0 presence */ + { 13, MPP_SATA_LED }, /* SATA 1 presence */ + { 14, MPP_SATA_LED }, /* SATA 0 active */ + { 15, MPP_SATA_LED }, /* SATA 1 active */ + { 16, MPP_UART }, /* UART1 RXD */ + { 17, MPP_UART }, /* UART1 TXD */ + { 18, MPP_UART }, /* UART1 CTSn */ + { 19, MPP_UART }, /* UART1 RTSn */ + { -1 }, +}; static void __init kurobox_pro_init(void) { @@ -189,46 +344,33 @@ static void __init kurobox_pro_init(void) */ orion5x_init(); - /* - * Setup the CPU address decode windows for our devices - */ - orion5x_setup_dev_boot_win(KUROBOX_PRO_NOR_BOOT_BASE, - KUROBOX_PRO_NOR_BOOT_SIZE); - orion5x_setup_dev0_win(KUROBOX_PRO_NAND_BASE, KUROBOX_PRO_NAND_SIZE); + orion5x_mpp_conf(kurobox_pro_mpp_modes); /* - * Open a special address decode windows for the PCIe WA. + * Configure peripherals. */ - orion5x_setup_pcie_wa_win(ORION5X_PCIE_WA_PHYS_BASE, - ORION5X_PCIE_WA_SIZE); - - /* - * Setup Multiplexing Pins -- - * MPP[0-1] Not used - * MPP[2] GPIO Micon - * MPP[3] GPIO RTC - * MPP[4-5] Not used - * MPP[6] Nand Flash REn - * MPP[7] Nand Flash WEn - * MPP[8-11] Not used - * MPP[12] SATA 0 presence Indication - * MPP[13] SATA 1 presence Indication - * MPP[14] SATA 0 active Indication - * MPP[15] SATA 1 active indication - * MPP[16-19] Not used - */ - orion5x_write(MPP_0_7_CTRL, 0x44220003); - orion5x_write(MPP_8_15_CTRL, 0x55550000); - orion5x_write(MPP_16_19_CTRL, 0x0); - - orion5x_gpio_set_valid_pins(0x0000000c); + orion5x_ehci0_init(); + orion5x_ehci1_init(); + orion5x_eth_init(&kurobox_pro_eth_data); + orion5x_i2c_init(); + orion5x_sata_init(&kurobox_pro_sata_data); + orion5x_uart0_init(); + orion5x_uart1_init(); + orion5x_setup_dev_boot_win(KUROBOX_PRO_NOR_BOOT_BASE, + KUROBOX_PRO_NOR_BOOT_SIZE); platform_device_register(&kurobox_pro_nor_flash); - if (machine_is_kurobox_pro()) + + if (machine_is_kurobox_pro()) { + orion5x_setup_dev0_win(KUROBOX_PRO_NAND_BASE, + KUROBOX_PRO_NAND_SIZE); platform_device_register(&kurobox_pro_nand_flash); + } + i2c_register_board_info(0, &kurobox_pro_i2c_rtc, 1); - orion5x_eth_init(&kurobox_pro_eth_data); - orion5x_sata_init(&kurobox_pro_sata_data); + + /* register Kurobox Pro specific power-off method */ + pm_power_off = kurobox_pro_power_off; } #ifdef CONFIG_MACH_KUROBOX_PRO |