From 7bb65fb9d7860faa4b9b1e07790fb5823a0249e2 Mon Sep 17 00:00:00 2001 From: Imre Kaloz Date: Wed, 4 Jun 2008 13:51:17 +0000 Subject: add preliminary Marvell Orion support SVN-Revision: 11352 --- ...mplement_power-off_method_for_kurobox_pro.patch | 192 +++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 target/linux/orion/patches/015-implement_power-off_method_for_kurobox_pro.patch (limited to 'target/linux/orion/patches/015-implement_power-off_method_for_kurobox_pro.patch') 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 0000000000..5814852388 --- /dev/null +++ b/target/linux/orion/patches/015-implement_power-off_method_for_kurobox_pro.patch @@ -0,0 +1,192 @@ +From: Sylver Bruneau + +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 +--- + 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 + #include + #include ++#include + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -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 -- cgit v1.2.3