diff options
author | kaloz <kaloz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-06-04 13:51:17 +0000 |
---|---|---|
committer | kaloz <kaloz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-06-04 13:51:17 +0000 |
commit | fc35f54386655faec7483c691ca12c00c226a813 (patch) | |
tree | b23043472ad11463f5e978310b30d1cebd104bb1 /target/linux/orion/patches/015-implement_power-off_method_for_kurobox_pro.patch | |
parent | 42bda49cb1b8eeefdeafd4dc6b37f8c80dad3942 (diff) |
add preliminary Marvell Orion support
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@11352 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/orion/patches/015-implement_power-off_method_for_kurobox_pro.patch')
-rw-r--r-- | target/linux/orion/patches/015-implement_power-off_method_for_kurobox_pro.patch | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/target/linux/orion/patches/015-implement_power-off_method_for_kurobox_pro.patch b/target/linux/orion/patches/015-implement_power-off_method_for_kurobox_pro.patch new file mode 100644 index 000000000..581485238 --- /dev/null +++ b/target/linux/orion/patches/015-implement_power-off_method_for_kurobox_pro.patch @@ -0,0 +1,192 @@ +From: Sylver Bruneau <sylver.bruneau@googlemail.com> + +This patch implements the communication with the microcontroller on the +Kurobox Pro and Linkstation Pro/Live boards. This is allowing to send +the commands needed to power-off the board correctly. + +Signed-off-by: Sylver Bruneau <sylver.bruneau@googlemail.com> +--- + arch/arm/mach-orion5x/kurobox_pro-setup.c | 147 ++++++++++++++++++++++++++++- + 1 files changed, 143 insertions(+), 4 deletions(-) + +--- 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> +@@ -177,6 +179,140 @@ + }; + + /***************************************************************************** ++ * 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 + ****************************************************************************/ + +@@ -203,10 +339,10 @@ + orion5x_mpp_conf(13, MPP_SATA_LED); /* SATA 1 presence */ + orion5x_mpp_conf(14, MPP_SATA_LED); /* SATA 0 active */ + orion5x_mpp_conf(15, MPP_SATA_LED); /* SATA 1 active */ +- orion5x_mpp_conf(16, MPP_UNUSED); +- orion5x_mpp_conf(17, MPP_UNUSED); +- orion5x_mpp_conf(18, MPP_UNUSED); +- orion5x_mpp_conf(19, MPP_UNUSED); ++ orion5x_mpp_conf(16, MPP_UART); /* UART1 RXD */ ++ orion5x_mpp_conf(17, MPP_UART); /* UART1 TXD */ ++ orion5x_mpp_conf(18, MPP_UART); /* UART1 CTSn */ ++ orion5x_mpp_conf(19, MPP_UART); /* UART1 RTSn */ + + /* + * Configure peripherals. +@@ -229,6 +365,9 @@ + } + + i2c_register_board_info(0, &kurobox_pro_i2c_rtc, 1); ++ ++ /* register Kurobox Pro specific power-off method */ ++ pm_power_off = kurobox_pro_power_off; + } + + #ifdef CONFIG_MACH_KUROBOX_PRO |