diff --git a/debian/changelog b/debian/changelog index 8bdbc3655..fe14e8633 100644 --- a/debian/changelog +++ b/debian/changelog @@ -57,6 +57,15 @@ linux-2.6 (2.6.29~rc8-1~experimental.1) UNRELEASED; urgency=low * [arm, armel] Enable various V4L USB devices. (Closes: #518582) * [arm/orion5x] Build the SENSORS_LM75 module since it's needed on the D-Link DNS-323. + * Add patches from git.marvell.com to improve Kirkwood support: + - Orion: make gpio /input/output validation separate + - Kirkwood: MPP initialization code + - SDIO driver for Marvell SoCs + - Kirkwood: SDIO driver registration for DB6281 and RD6281 + - Kirkwood: register internal devices in a common place + - Kirkwood: Marvell SheevaPlug support + - Kirkwood: SheevaPlug USB Power Enable setup + - Kirkwood: SheevaPlug LED support [ Ben Hutchings ] * Remove firmware from drivers and make them use request_firmware(): diff --git a/debian/patches/features/arm/kw-mpp.patch b/debian/patches/features/arm/kw-mpp.patch new file mode 100644 index 000000000..cf9aba309 --- /dev/null +++ b/debian/patches/features/arm/kw-mpp.patch @@ -0,0 +1,436 @@ +From: Nicolas Pitre +Date: Sat, 31 Jan 2009 03:44:20 +0000 (-0500) +Subject: [ARM] Kirkwood: MPP initialization code +X-Git-Url: http://git.marvell.com/?p=orion.git;a=commitdiff_plain;h=0100defd2803f6c3df6bfd400a10af0cf9b8536a + +[ARM] Kirkwood: MPP initialization code + +This allows for board support code to set up their MPP config if the +bootloader didn't do it all or did it wrong. This also allows to +register usable GPIOs. + +Signed-off-by: Nicolas Pitre +--- + +diff --git a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile +index b96c55d..fdff35c 100644 +--- a/arch/arm/mach-kirkwood/Makefile ++++ b/arch/arm/mach-kirkwood/Makefile +@@ -1,4 +1,4 @@ +-obj-y += common.o addr-map.o irq.o pcie.o ++obj-y += common.o addr-map.o irq.o pcie.o mpp.o + + obj-$(CONFIG_MACH_DB88F6281_BP) += db88f6281-bp-setup.o + obj-$(CONFIG_MACH_RD88F6192_NAS) += rd88f6192-nas-setup.o +diff --git a/arch/arm/mach-kirkwood/mpp.c b/arch/arm/mach-kirkwood/mpp.c +new file mode 100644 +index 0000000..63c4493 +--- /dev/null ++++ b/arch/arm/mach-kirkwood/mpp.c +@@ -0,0 +1,97 @@ ++/* ++ * arch/arm/mach-kirkwood/mpp.c ++ * ++ * MPP functions for Marvell Kirkwood SoCs ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "common.h" ++#include "mpp.h" ++ ++static unsigned int __init kirkwood_variant(void) ++{ ++ u32 dev, rev; ++ ++ kirkwood_pcie_id(&dev, &rev); ++ ++ if (dev == MV88F6281_DEV_ID && rev >= MV88F6281_REV_A0) ++ return MPP_F6281_MASK; ++ if (dev == MV88F6192_DEV_ID && rev >= MV88F6192_REV_A0) ++ return MPP_F6192_MASK; ++ if (dev == MV88F6180_DEV_ID) ++ return MPP_F6180_MASK; ++ ++ printk(KERN_ERR "MPP setup: unknown kirkwood variant " ++ "(dev %#x rev %#x)\n", dev, rev); ++ return 0; ++} ++ ++#define MPP_CTRL(i) (DEV_BUS_VIRT_BASE + (i) * 4) ++#define MPP_NR_REGS (1 + MPP_MAX/8) ++ ++void __init kirkwood_mpp_conf(unsigned int *mpp_list) ++{ ++ u32 mpp_ctrl[MPP_NR_REGS]; ++ unsigned int variant_mask; ++ int i; ++ ++ variant_mask = kirkwood_variant(); ++ if (!variant_mask) ++ return; ++ ++ printk(KERN_DEBUG "initial MPP regs:"); ++ for (i = 0; i < MPP_NR_REGS; i++) { ++ mpp_ctrl[i] = readl(MPP_CTRL(i)); ++ printk(" %08x", mpp_ctrl[i]); ++ } ++ printk("\n"); ++ ++ while (*mpp_list) { ++ unsigned int num = MPP_NUM(*mpp_list); ++ unsigned int sel = MPP_SEL(*mpp_list); ++ int shift, gpio_mode; ++ ++ if (num > MPP_MAX) { ++ printk(KERN_ERR "kirkwood_mpp_conf: invalid MPP " ++ "number (%u)\n", num); ++ continue; ++ } ++ if (!(*mpp_list & variant_mask)) { ++ printk(KERN_WARNING ++ "kirkwood_mpp_conf: requested MPP%u config " ++ "unavailable on this hardware\n", num); ++ continue; ++ } ++ ++ shift = (num & 7) << 2; ++ mpp_ctrl[num / 8] &= ~(0xf << shift); ++ mpp_ctrl[num / 8] |= sel << shift; ++ ++ gpio_mode = 0; ++ if (*mpp_list & MPP_INPUT_MASK) ++ gpio_mode |= GPIO_INPUT_OK; ++ if (*mpp_list & MPP_OUTPUT_MASK) ++ gpio_mode |= GPIO_OUTPUT_OK; ++ if (sel != 0) ++ gpio_mode = 0; ++ orion_gpio_set_valid(num, gpio_mode); ++ ++ mpp_list++; ++ } ++ ++ printk(KERN_DEBUG " final MPP regs:"); ++ for (i = 0; i < MPP_NR_REGS; i++) { ++ writel(mpp_ctrl[i], MPP_CTRL(i)); ++ printk(" %08x", mpp_ctrl[i]); ++ } ++ printk("\n"); ++} +diff --git a/arch/arm/mach-kirkwood/mpp.h b/arch/arm/mach-kirkwood/mpp.h +new file mode 100644 +index 0000000..45cccb7 +--- /dev/null ++++ b/arch/arm/mach-kirkwood/mpp.h +@@ -0,0 +1,303 @@ ++/* ++ * linux/arch/arm/mach-kirkwood/mpp.h -- Multi Purpose Pins ++ * ++ * Copyright 2009: Marvell Technology Group Ltd. ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#ifndef __KIRKWOOD_MPP_H ++#define __KIRKWOOD_MPP_H ++ ++#define MPP(_num, _sel, _in, _out, _F6180, _F6190, _F6192, _F6281) ( \ ++ /* MPP number */ ((_num) & 0xff) | \ ++ /* MPP select value */ (((_sel) & 0xf) << 8) | \ ++ /* may be input signal */ ((!!(_in)) << 12) | \ ++ /* may be output signal */ ((!!(_out)) << 13) | \ ++ /* available on F6180 */ ((!!(_F6180)) << 14) | \ ++ /* available on F6190 */ ((!!(_F6190)) << 15) | \ ++ /* available on F6192 */ ((!!(_F6192)) << 16) | \ ++ /* available on F6281 */ ((!!(_F6281)) << 17)) ++ ++#define MPP_NUM(x) ((x) & 0xff) ++#define MPP_SEL(x) (((x) >> 8) & 0xf) ++ ++ /* num sel i o 6180 6190 6192 6281 */ ++ ++#define MPP_INPUT_MASK MPP( 0, 0x0, 1, 0, 0, 0, 0, 0 ) ++#define MPP_OUTPUT_MASK MPP( 0, 0x0, 0, 1, 0, 0, 0, 0 ) ++ ++#define MPP_F6180_MASK MPP( 0, 0x0, 0, 0, 1, 0, 0, 0 ) ++#define MPP_F6190_MASK MPP( 0, 0x0, 0, 0, 0, 1, 0, 0 ) ++#define MPP_F6192_MASK MPP( 0, 0x0, 0, 0, 0, 0, 1, 0 ) ++#define MPP_F6281_MASK MPP( 0, 0x0, 0, 0, 0, 0, 0, 1 ) ++ ++#define MPP0_GPIO MPP( 0, 0x0, 1, 1, 1, 1, 1, 1 ) ++#define MPP0_NF_IO2 MPP( 0, 0x1, 1, 1, 1, 1, 1, 1 ) ++#define MPP0_SPI_SCn MPP( 0, 0x2, 0, 1, 1, 1, 1, 1 ) ++ ++#define MPP1_GPO MPP( 1, 0x0, 0, 1, 1, 1, 1, 1 ) ++#define MPP1_NF_IO3 MPP( 1, 0x1, 1, 1, 1, 1, 1, 1 ) ++#define MPP1_SPI_MOSI MPP( 1, 0x2, 0, 1, 1, 1, 1, 1 ) ++ ++#define MPP2_GPO MPP( 2, 0x0, 0, 1, 1, 1, 1, 1 ) ++#define MPP2_NF_IO4 MPP( 2, 0x1, 1, 1, 1, 1, 1, 1 ) ++#define MPP2_SPI_SCK MPP( 2, 0x2, 0, 1, 1, 1, 1, 1 ) ++ ++#define MPP3_GPO MPP( 3, 0x0, 0, 1, 1, 1, 1, 1 ) ++#define MPP3_NF_IO5 MPP( 3, 0x1, 1, 1, 1, 1, 1, 1 ) ++#define MPP3_SPI_MISO MPP( 3, 0x2, 1, 0, 1, 1, 1, 1 ) ++ ++#define MPP4_GPIO MPP( 4, 0x0, 1, 1, 1, 1, 1, 1 ) ++#define MPP4_NF_IO6 MPP( 4, 0x1, 1, 1, 1, 1, 1, 1 ) ++#define MPP4_UART0_RXD MPP( 4, 0x2, 1, 0, 1, 1, 1, 1 ) ++#define MPP4_SATA1_ACTn MPP( 4, 0x5, 0, 1, 0, 0, 1, 1 ) ++#define MPP4_PTP_CLK MPP( 4, 0xd, 1, 0, 1, 1, 1, 1 ) ++ ++#define MPP5_GPO MPP( 5, 0x0, 0, 1, 1, 1, 1, 1 ) ++#define MPP5_NF_IO7 MPP( 5, 0x1, 1, 1, 1, 1, 1, 1 ) ++#define MPP5_UART0_TXD MPP( 5, 0x2, 0, 1, 1, 1, 1, 1 ) ++#define MPP5_PTP_TRIG_GEN MPP( 5, 0x4, 0, 1, 1, 1, 1, 1 ) ++#define MPP5_SATA0_ACTn MPP( 5, 0x5, 0, 1, 0, 1, 1, 1 ) ++ ++#define MPP6_SYSRST_OUTn MPP( 6, 0x1, 0, 1, 1, 1, 1, 1 ) ++#define MPP6_SPI_MOSI MPP( 6, 0x2, 0, 1, 1, 1, 1, 1 ) ++#define MPP6_PTP_TRIG_GEN MPP( 6, 0x3, 0, 1, 1, 1, 1, 1 ) ++ ++#define MPP7_GPO MPP( 7, 0x0, 0, 1, 1, 1, 1, 1 ) ++#define MPP7_PEX_RST_OUTn MPP( 7, 0x1, 0, 1, 1, 1, 1, 1 ) ++#define MPP7_SPI_SCn MPP( 7, 0x2, 0, 1, 1, 1, 1, 1 ) ++#define MPP7_PTP_TRIG_GEN MPP( 7, 0x3, 0, 1, 1, 1, 1, 1 ) ++ ++#define MPP8_GPIO MPP( 8, 0x0, 1, 1, 1, 1, 1, 1 ) ++#define MPP8_TW_SDA MPP( 8, 0x1, 1, 1, 1, 1, 1, 1 ) ++#define MPP8_UART0_RTS MPP( 8, 0x2, 0, 1, 1, 1, 1, 1 ) ++#define MPP8_UART1_RTS MPP( 8, 0x3, 0, 1, 1, 1, 1, 1 ) ++#define MPP8_MII0_RXERR MPP( 8, 0x4, 1, 0, 0, 1, 1, 1 ) ++#define MPP8_SATA1_PRESENTn MPP( 8, 0x5, 0, 1, 0, 0, 1, 1 ) ++#define MPP8_PTP_CLK MPP( 8, 0xc, 1, 0, 1, 1, 1, 1 ) ++#define MPP8_MII0_COL MPP( 8, 0xd, 1, 0, 1, 1, 1, 1 ) ++ ++#define MPP9_GPIO MPP( 9, 0x0, 1, 1, 1, 1, 1, 1 ) ++#define MPP9_TW_SCK MPP( 9, 0x1, 1, 1, 1, 1, 1, 1 ) ++#define MPP9_UART0_CTS MPP( 9, 0x2, 1, 0, 1, 1, 1, 1 ) ++#define MPP9_UART1_CTS MPP( 9, 0x3, 1, 0, 1, 1, 1, 1 ) ++#define MPP9_SATA0_PRESENTn MPP( 9, 0x5, 0, 1, 0, 1, 1, 1 ) ++#define MPP9_PTP_EVENT_REQ MPP( 9, 0xc, 1, 0, 1, 1, 1, 1 ) ++#define MPP9_MII0_CRS MPP( 9, 0xd, 1, 0, 1, 1, 1, 1 ) ++ ++#define MPP10_GPO MPP( 10, 0x0, 0, 1, 1, 1, 1, 1 ) ++#define MPP10_SPI_SCK MPP( 10, 0x2, 0, 1, 1, 1, 1, 1 ) ++#define MPP10_UArt0_TXD MPP( 10, 0X3, 0, 1, 1, 1, 1, 1 ) ++#define MPP10_SATA1_ACTn MPP( 10, 0x5, 0, 1, 0, 0, 1, 1 ) ++#define MPP10_PTP_TRIG_GEN MPP( 10, 0xc, 0, 1, 1, 1, 1, 1 ) ++ ++#define MPP11_GPIO MPP( 11, 0x0, 1, 1, 1, 1, 1, 1 ) ++#define MPP11_SPI_MISO MPP( 11, 0x2, 1, 0, 1, 1, 1, 1 ) ++#define MPP11_UArt0_RXD MPP( 11, 0x3, 1, 0, 1, 1, 1, 1 ) ++#define MPP11_PTP_EVENT_REQ MPP( 11, 0x4, 1, 0, 1, 1, 1, 1 ) ++#define MPP11_PTP_TRIG_GEN MPP( 11, 0xc, 0, 1, 1, 1, 1, 1 ) ++#define MPP11_PTP_CLK MPP( 11, 0xd, 1, 0, 1, 1, 1, 1 ) ++#define MPP11_SATA0_ACTn MPP( 11, 0x5, 0, 1, 0, 1, 1, 1 ) ++ ++#define MPP12_GPO MPP( 12, 0x0, 0, 1, 1, 1, 1, 1 ) ++#define MPP12_SD_CLK MPP( 12, 0x1, 0, 1, 1, 1, 1, 1 ) ++ ++#define MPP13_GPIO MPP( 13, 0x0, 1, 1, 1, 1, 1, 1 ) ++#define MPP13_SD_CMD MPP( 13, 0x1, 1, 1, 1, 1, 1, 1 ) ++#define MPP13_UART1_TXD MPP( 13, 0x3, 0, 1, 1, 1, 1, 1 ) ++ ++#define MPP14_GPIO MPP( 14, 0x0, 1, 1, 1, 1, 1, 1 ) ++#define MPP14_SD_D0 MPP( 14, 0x1, 1, 1, 1, 1, 1, 1 ) ++#define MPP14_UART1_RXD MPP( 14, 0x3, 1, 0, 1, 1, 1, 1 ) ++#define MPP14_SATA1_PRESENTn MPP( 14, 0x4, 0, 1, 0, 0, 1, 1 ) ++#define MPP14_MII0_COL MPP( 14, 0xd, 1, 0, 1, 1, 1, 1 ) ++ ++#define MPP15_GPIO MPP( 15, 0x0, 1, 1, 1, 1, 1, 1 ) ++#define MPP15_SD_D1 MPP( 15, 0x1, 1, 1, 1, 1, 1, 1 ) ++#define MPP15_UART0_RTS MPP( 15, 0x2, 0, 1, 1, 1, 1, 1 ) ++#define MPP15_UART1_TXD MPP( 15, 0x3, 0, 1, 1, 1, 1, 1 ) ++#define MPP15_SATA0_ACTn MPP( 15, 0x4, 0, 1, 0, 1, 1, 1 ) ++ ++#define MPP16_GPIO MPP( 16, 0x0, 1, 1, 1, 1, 1, 1 ) ++#define MPP16_SD_D2 MPP( 16, 0x1, 1, 1, 1, 1, 1, 1 ) ++#define MPP16_UART0_CTS MPP( 16, 0x2, 1, 0, 1, 1, 1, 1 ) ++#define MPP16_UART1_RXD MPP( 16, 0x3, 1, 0, 1, 1, 1, 1 ) ++#define MPP16_SATA1_ACTn MPP( 16, 0x4, 0, 1, 0, 0, 1, 1 ) ++#define MPP16_MII0_CRS MPP( 16, 0xd, 1, 0, 1, 1, 1, 1 ) ++ ++#define MPP17_GPIO MPP( 17, 0x0, 1, 1, 1, 1, 1, 1 ) ++#define MPP17_SD_D3 MPP( 17, 0x1, 1, 1, 1, 1, 1, 1 ) ++#define MPP17_SATA0_PRESENTn MPP( 17, 0x4, 0, 1, 0, 1, 1, 1 ) ++ ++#define MPP18_GPO MPP( 18, 0x0, 0, 1, 1, 1, 1, 1 ) ++#define MPP18_NF_IO0 MPP( 18, 0x1, 1, 1, 1, 1, 1, 1 ) ++ ++#define MPP19_GPO MPP( 19, 0x0, 0, 1, 1, 1, 1, 1 ) ++#define MPP19_NF_IO1 MPP( 19, 0x1, 1, 1, 1, 1, 1, 1 ) ++ ++#define MPP20_GPIO MPP( 20, 0x0, 1, 1, 0, 1, 1, 1 ) ++#define MPP20_TSMP0 MPP( 20, 0x1, 1, 1, 0, 0, 1, 1 ) ++#define MPP20_TDM_CH0_TX_QL MPP( 20, 0x2, 0, 1, 0, 0, 1, 1 ) ++#define MPP20_GE1_0 MPP( 20, 0x3, 0, 0, 0, 1, 1, 1 ) ++#define MPP20_AUDIO_SPDIFI MPP( 20, 0x4, 1, 0, 0, 0, 1, 1 ) ++#define MPP20_SATA1_ACTn MPP( 20, 0x5, 0, 1, 0, 0, 1, 1 ) ++ ++#define MPP21_GPIO MPP( 21, 0x0, 1, 1, 0, 1, 1, 1 ) ++#define MPP21_TSMP1 MPP( 21, 0x1, 1, 1, 0, 0, 1, 1 ) ++#define MPP21_TDM_CH0_RX_QL MPP( 21, 0x2, 0, 1, 0, 0, 1, 1 ) ++#define MPP21_GE1_1 MPP( 21, 0x3, 0, 0, 0, 1, 1, 1 ) ++#define MPP21_AUDIO_SPDIFO MPP( 21, 0x4, 0, 1, 0, 0, 1, 1 ) ++#define MPP21_SATA0_ACTn MPP( 21, 0x5, 0, 1, 0, 1, 1, 1 ) ++ ++#define MPP22_GPIO MPP( 22, 0x0, 1, 1, 0, 1, 1, 1 ) ++#define MPP22_TSMP2 MPP( 22, 0x1, 1, 1, 0, 0, 1, 1 ) ++#define MPP22_TDM_CH2_TX_QL MPP( 22, 0x2, 0, 1, 0, 0, 1, 1 ) ++#define MPP22_GE1_2 MPP( 22, 0x3, 0, 0, 0, 1, 1, 1 ) ++#define MPP22_AUDIO_SPDIFRMKCLK MPP( 22, 0x4, 0, 1, 0, 0, 1, 1 ) ++#define MPP22_SATA1_PRESENTn MPP( 22, 0x5, 0, 1, 0, 0, 1, 1 ) ++ ++#define MPP23_GPIO MPP( 23, 0x0, 1, 1, 0, 1, 1, 1 ) ++#define MPP23_TSMP3 MPP( 23, 0x1, 1, 1, 0, 0, 1, 1 ) ++#define MPP23_TDM_CH2_RX_QL MPP( 23, 0x2, 1, 0, 0, 0, 1, 1 ) ++#define MPP23_GE1_3 MPP( 23, 0x3, 0, 0, 0, 1, 1, 1 ) ++#define MPP23_AUDIO_I2SBCLK MPP( 23, 0x4, 0, 1, 0, 0, 1, 1 ) ++#define MPP23_SATA0_PRESENTn MPP( 23, 0x5, 0, 1, 0, 1, 1, 1 ) ++ ++#define MPP24_GPIO MPP( 24, 0x0, 1, 1, 0, 1, 1, 1 ) ++#define MPP24_TSMP4 MPP( 24, 0x1, 1, 1, 0, 0, 1, 1 ) ++#define MPP24_TDM_SPI_CS0 DEV( 24, 0x2, 0, 1, 0, 0, 1, 1 ) ++#define MPP24_GE1_4 MPP( 24, 0x3, 0, 0, 0, 1, 1, 1 ) ++#define MPP24_AUDIO_I2SDO MPP( 24, 0x4, 0, 1, 0, 0, 1, 1 ) ++ ++#define MPP25_GPIO MPP( 25, 0x0, 1, 1, 0, 1, 1, 1 ) ++#define MPP25_TSMP5 MPP( 25, 0x1, 1, 1, 0, 0, 1, 1 ) ++#define MPP25_TDM_SPI_SCK MPP( 25, 0x2, 0, 1, 0, 0, 1, 1 ) ++#define MPP25_GE1_5 MPP( 25, 0x3, 0, 0, 0, 1, 1, 1 ) ++#define MPP25_AUDIO_I2SLRCLK MPP( 25, 0x4, 0, 1, 0, 0, 1, 1 ) ++ ++#define MPP26_GPIO MPP( 26, 0x0, 1, 1, 0, 1, 1, 1 ) ++#define MPP26_TSMP6 MPP( 26, 0x1, 1, 1, 0, 0, 1, 1 ) ++#define MPP26_TDM_SPI_MISO MPP( 26, 0x2, 1, 0, 0, 0, 1, 1 ) ++#define MPP26_GE1_6 MPP( 26, 0x3, 0, 0, 0, 1, 1, 1 ) ++#define MPP26_AUDIO_I2SMCLK MPP( 26, 0x4, 0, 1, 0, 0, 1, 1 ) ++ ++#define MPP27_GPIO MPP( 27, 0x0, 1, 1, 0, 1, 1, 1 ) ++#define MPP27_TSMP7 MPP( 27, 0x1, 1, 1, 0, 0, 1, 1 ) ++#define MPP27_TDM_SPI_MOSI MPP( 27, 0x2, 0, 1, 0, 0, 1, 1 ) ++#define MPP27_GE1_7 MPP( 27, 0x3, 0, 0, 0, 1, 1, 1 ) ++#define MPP27_AUDIO_I2SDI MPP( 27, 0x4, 1, 0, 0, 0, 1, 1 ) ++ ++#define MPP28_GPIO MPP( 28, 0x0, 1, 1, 0, 1, 1, 1 ) ++#define MPP28_TSMP8 MPP( 28, 0x1, 1, 1, 0, 0, 1, 1 ) ++#define MPP28_TDM_CODEC_INTn MPP( 28, 0x2, 0, 0, 0, 0, 1, 1 ) ++#define MPP28_GE1_8 MPP( 28, 0x3, 0, 0, 0, 1, 1, 1 ) ++#define MPP28_AUDIO_EXTCLK MPP( 28, 0x4, 1, 0, 0, 0, 1, 1 ) ++ ++#define MPP29_GPIO MPP( 29, 0x0, 1, 1, 0, 1, 1, 1 ) ++#define MPP29_TSMP9 MPP( 29, 0x1, 1, 1, 0, 0, 1, 1 ) ++#define MPP29_TDM_CODEC_RSTn MPP( 29, 0x2, 0, 0, 0, 0, 1, 1 ) ++#define MPP29_GE1_9 MPP( 29, 0x3, 0, 0, 0, 1, 1, 1 ) ++ ++#define MPP30_GPIO MPP( 30, 0x0, 1, 1, 0, 1, 1, 1 ) ++#define MPP30_TSMP10 MPP( 30, 0x1, 1, 1, 0, 0, 1, 1 ) ++#define MPP30_TDM_PCLK MPP( 30, 0x2, 1, 1, 0, 0, 1, 1 ) ++#define MPP30_GE1_10 MPP( 30, 0x3, 0, 0, 0, 1, 1, 1 ) ++ ++#define MPP31_GPIO MPP( 31, 0x0, 1, 1, 0, 1, 1, 1 ) ++#define MPP31_TSMP11 MPP( 31, 0x1, 1, 1, 0, 0, 1, 1 ) ++#define MPP31_TDM_FS MPP( 31, 0x2, 1, 1, 0, 0, 1, 1 ) ++#define MPP31_GE1_11 MPP( 31, 0x3, 0, 0, 0, 1, 1, 1 ) ++ ++#define MPP32_GPIO MPP( 32, 0x0, 1, 1, 0, 1, 1, 1 ) ++#define MPP32_TSMP12 MPP( 32, 0x1, 1, 1, 0, 0, 1, 1 ) ++#define MPP32_TDM_DRX MPP( 32, 0x2, 1, 0, 0, 0, 1, 1 ) ++#define MPP32_GE1_12 MPP( 32, 0x3, 0, 0, 0, 1, 1, 1 ) ++ ++#define MPP33_GPIO MPP( 33, 0x0, 1, 1, 0, 1, 1, 1 ) ++#define MPP33_TDM_DTX MPP( 33, 0x2, 0, 1, 0, 0, 1, 1 ) ++#define MPP33_GE1_13 MPP( 33, 0x3, 0, 0, 0, 1, 1, 1 ) ++ ++#define MPP34_GPIO MPP( 34, 0x0, 1, 1, 0, 1, 1, 1 ) ++#define MPP34_TDM_SPI_CS1 MPP( 34, 0x2, 0, 1, 0, 0, 1, 1 ) ++#define MPP34_GE1_14 MPP( 34, 0x3, 0, 0, 0, 1, 1, 1 ) ++ ++#define MPP35_GPIO MPP( 35, 0x0, 1, 1, 1, 1, 1, 1 ) ++#define MPP35_TDM_CH0_TX_QL MPP( 35, 0x2, 0, 1, 0, 0, 1, 1 ) ++#define MPP35_GE1_15 MPP( 35, 0x3, 0, 0, 0, 1, 1, 1 ) ++#define MPP35_SATA0_ACTn MPP( 35, 0x5, 0, 1, 0, 1, 1, 1 ) ++#define MPP35_MII0_RXERR MPP( 35, 0xc, 1, 0, 1, 1, 1, 1 ) ++ ++#define MPP36_GPIO MPP( 36, 0x0, 1, 1, 1, 0, 0, 1 ) ++#define MPP36_TSMP0 MPP( 36, 0x1, 1, 1, 0, 0, 0, 1 ) ++#define MPP36_TDM_SPI_CS1 MPP( 36, 0x2, 0, 1, 0, 0, 0, 1 ) ++#define MPP36_AUDIO_SPDIFI MPP( 36, 0x4, 1, 0, 1, 0, 0, 1 ) ++ ++#define MPP37_GPIO MPP( 37, 0x0, 1, 1, 1, 0, 0, 1 ) ++#define MPP37_TSMP1 MPP( 37, 0x1, 1, 1, 0, 0, 0, 1 ) ++#define MPP37_TDM_CH2_TX_QL MPP( 37, 0x2, 0, 1, 0, 0, 0, 1 ) ++#define MPP37_AUDIO_SPDIFO MPP( 37, 0x4, 0, 1, 1, 0, 0, 1 ) ++ ++#define MPP38_GPIO MPP( 38, 0x0, 1, 1, 1, 0, 0, 1 ) ++#define MPP38_TSMP2 MPP( 38, 0x1, 1, 1, 0, 0, 0, 1 ) ++#define MPP38_TDM_CH2_RX_QL MPP( 38, 0x2, 0, 1, 0, 0, 0, 1 ) ++#define MPP38_AUDIO_SPDIFRMLCLK MPP( 38, 0x4, 0, 1, 1, 0, 0, 1 ) ++ ++#define MPP39_GPIO MPP( 39, 0x0, 1, 1, 1, 0, 0, 1 ) ++#define MPP39_TSMP3 MPP( 39, 0x1, 1, 1, 0, 0, 0, 1 ) ++#define MPP39_TDM_SPI_CS0 MPP( 39, 0x2, 0, 1, 0, 0, 0, 1 ) ++#define MPP39_AUDIO_I2SBCLK MPP( 39, 0x4, 0, 1, 1, 0, 0, 1 ) ++ ++#define MPP40_GPIO MPP( 40, 0x0, 1, 1, 1, 0, 0, 1 ) ++#define MPP40_TSMP4 MPP( 40, 0x1, 1, 1, 0, 0, 0, 1 ) ++#define MPP40_TDM_SPI_SCK MPP( 40, 0x2, 0, 1, 0, 0, 0, 1 ) ++#define MPP40_AUDIO_I2SDO MPP( 40, 0x4, 0, 1, 1, 0, 0, 1 ) ++ ++#define MPP41_GPIO MPP( 41, 0x0, 1, 1, 1, 0, 0, 1 ) ++#define MPP41_TSMP5 MPP( 41, 0x1, 1, 1, 0, 0, 0, 1 ) ++#define MPP41_TDM_SPI_MISO MPP( 41, 0x2, 1, 0, 0, 0, 0, 1 ) ++#define MPP41_AUDIO_I2SLRC MPP( 41, 0x4, 0, 1, 1, 0, 0, 1 ) ++ ++#define MPP42_GPIO MPP( 42, 0x0, 1, 1, 1, 0, 0, 1 ) ++#define MPP42_TSMP6 MPP( 42, 0x1, 1, 1, 0, 0, 0, 1 ) ++#define MPP42_TDM_SPI_MOSI MPP( 42, 0x2, 0, 1, 0, 0, 0, 1 ) ++#define MPP42_AUDIO_I2SMCLK MPP( 42, 0x4, 0, 1, 1, 0, 0, 1 ) ++ ++#define MPP43_GPIO MPP( 43, 0x0, 1, 1, 1, 0, 0, 1 ) ++#define MPP43_TSMP7 MPP( 43, 0x1, 1, 1, 0, 0, 0, 1 ) ++#define MPP43_TDM_CODEC_INTn MPP( 43, 0x2, 0, 0, 0, 0, 0, 1 ) ++#define MPP43_AUDIO_I2SDI MPP( 43, 0x4, 1, 0, 1, 0, 0, 1 ) ++ ++#define MPP44_GPIO MPP( 44, 0x0, 1, 1, 1, 0, 0, 1 ) ++#define MPP44_TSMP8 MPP( 44, 0x1, 1, 1, 0, 0, 0, 1 ) ++#define MPP44_TDM_CODEC_RSTn MPP( 44, 0x2, 0, 0, 0, 0, 0, 1 ) ++#define MPP44_AUDIO_EXTCLK MPP( 44, 0x4, 1, 0, 1, 0, 0, 1 ) ++ ++#define MPP45_GPIO MPP( 45, 0x0, 1, 1, 0, 0, 0, 1 ) ++#define MPP45_TSMP9 MPP( 45, 0x1, 1, 1, 0, 0, 0, 1 ) ++#define MPP45_TDM_PCLK MPP( 45, 0x2, 1, 1, 0, 0, 0, 1 ) ++ ++#define MPP46_GPIO MPP( 46, 0x0, 1, 1, 0, 0, 0, 1 ) ++#define MPP46_TSMP10 MPP( 46, 0x1, 1, 1, 0, 0, 0, 1 ) ++#define MPP46_TDM_FS MPP( 46, 0x2, 1, 1, 0, 0, 0, 1 ) ++ ++#define MPP47_GPIO MPP( 47, 0x0, 1, 1, 0, 0, 0, 1 ) ++#define MPP47_TSMP11 MPP( 47, 0x1, 1, 1, 0, 0, 0, 1 ) ++#define MPP47_TDM_DRX MPP( 47, 0x2, 1, 0, 0, 0, 0, 1 ) ++ ++#define MPP48_GPIO MPP( 48, 0x0, 1, 1, 0, 0, 0, 1 ) ++#define MPP48_TSMP12 MPP( 48, 0x1, 1, 1, 0, 0, 0, 1 ) ++#define MPP48_TDM_DTX MPP( 48. 0x2, 0, 1, 0, 0, 0, 1 ) ++ ++#define MPP49_GPIO MPP( 49, 0x0, 1, 1, 0, 0, 0, 1 ) ++#define MPP49_TSMP9 MPP( 49, 0x1, 1, 1, 0, 0, 0, 1 ) ++#define MPP49_TDM_CH0_RX_QL MPP( 49, 0x2, 0, 1, 0, 0, 0, 1 ) ++#define MPP49_PTP_CLK MPP( 49, 0x5, 1, 0, 0, 0, 0, 1 ) ++ ++#define MPP_MAX 49 ++ ++void kirkwood_mpp_conf(unsigned int *mpp_list); ++ ++#endif diff --git a/debian/patches/features/arm/kw-register-internal-devices.patch b/debian/patches/features/arm/kw-register-internal-devices.patch new file mode 100644 index 000000000..bf548f333 --- /dev/null +++ b/debian/patches/features/arm/kw-register-internal-devices.patch @@ -0,0 +1,114 @@ +From: Nicolas Pitre +Date: Fri, 27 Feb 2009 03:55:59 +0000 (-0500) +Subject: [ARM] Kirkwood: register internal devices in a common place +X-Git-Url: http://git.marvell.com/?p=orion.git;a=commitdiff_plain;h=5b99d5348304a32dfca92238d27ac4de2b365175 + +[ARM] Kirkwood: register internal devices in a common place + +The RTC and the two XOR engines are internal to the chip, and therefore +always available since they don't depend on a particular board layout. + +Signed-off-by: Nicolas Pitre +--- + + +--- a/arch/arm/mach-kirkwood/rd88f6281-setup.c~ 2009-03-14 08:03:45.000000000 +0000 ++++ b/arch/arm/mach-kirkwood/rd88f6281-setup.c 2009-03-14 08:03:54.000000000 +0000 +@@ -124,7 +124,6 @@ + } + kirkwood_ge00_switch_init(&rd88f6281_switch_data, NO_IRQ); + +- kirkwood_rtc_init(); + kirkwood_sata_init(&rd88f6281_sata_data); + kirkwood_sdio_init(&rd88f6281_mvsdio_data); + kirkwood_uart0_init(); +--- a/arch/arm/mach-kirkwood/db88f6281-bp-setup.c~ 2009-03-14 08:03:32.000000000 +0000 ++++ b/arch/arm/mach-kirkwood/db88f6281-bp-setup.c 2009-03-14 08:03:54.000000000 +0000 +@@ -55,7 +55,6 @@ + + kirkwood_ehci_init(); + kirkwood_ge00_init(&db88f6281_ge00_data); +- kirkwood_rtc_init(); + kirkwood_sata_init(&db88f6281_sata_data); + kirkwood_uart0_init(); + kirkwood_sdio_init(&db88f6281_mvsdio_data); +diff --git a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c +index b1d1a87..913ea94 100644 +--- a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c ++++ b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c +@@ -61,14 +61,11 @@ static void __init rd88f6192_init(void) + + kirkwood_ehci_init(); + kirkwood_ge00_init(&rd88f6192_ge00_data); +- kirkwood_rtc_init(); + kirkwood_sata_init(&rd88f6192_sata_data); + spi_register_board_info(rd88F6192_spi_slave_info, + ARRAY_SIZE(rd88F6192_spi_slave_info)); + kirkwood_spi_init(); + kirkwood_uart0_init(); +- kirkwood_xor0_init(); +- kirkwood_xor1_init(); + } + + static int __init rd88f6192_pci_init(void) + +diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c +index e5076aa..9f01255 100644 +--- a/arch/arm/mach-kirkwood/common.c ++++ b/arch/arm/mach-kirkwood/common.c +@@ -255,7 +255,7 @@ static struct resource kirkwood_rtc_resource = { + .flags = IORESOURCE_MEM, + }; + +-void __init kirkwood_rtc_init(void) ++static void __init kirkwood_rtc_init(void) + { + platform_device_register_simple("rtc-mv", -1, &kirkwood_rtc_resource, 1); + } +@@ -547,7 +547,7 @@ static struct platform_device kirkwood_xor01_channel = { + }, + }; + +-void __init kirkwood_xor0_init(void) ++static void __init kirkwood_xor0_init(void) + { + platform_device_register(&kirkwood_xor0_shared); + +@@ -645,7 +645,7 @@ static struct platform_device kirkwood_xor11_channel = { + }, + }; + +-void __init kirkwood_xor1_init(void) ++static void __init kirkwood_xor1_init(void) + { + platform_device_register(&kirkwood_xor1_shared); + +@@ -753,4 +753,9 @@ void __init kirkwood_init(void) + #ifdef CONFIG_CACHE_FEROCEON_L2 + kirkwood_l2_init(); + #endif ++ ++ /* internal devices that every board has */ ++ kirkwood_rtc_init(); ++ kirkwood_xor0_init(); ++ kirkwood_xor1_init(); + } +diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h +index 5827940..9e52826 100644 +--- a/arch/arm/mach-kirkwood/common.h ++++ b/arch/arm/mach-kirkwood/common.h +@@ -34,14 +34,11 @@ void kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data); + void kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data); + void kirkwood_ge00_switch_init(struct dsa_platform_data *d, int irq); + void kirkwood_pcie_init(void); +-void kirkwood_rtc_init(void); + void kirkwood_sata_init(struct mv_sata_platform_data *sata_data); + void kirkwood_sdio_init(struct mvsdio_platform_data *mvsdio_data); + void kirkwood_spi_init(void); + void kirkwood_uart0_init(void); + void kirkwood_uart1_init(void); +-void kirkwood_xor0_init(void); +-void kirkwood_xor1_init(void); + + extern struct sys_timer kirkwood_timer; + diff --git a/debian/patches/features/arm/kw-register-sdio.patch b/debian/patches/features/arm/kw-register-sdio.patch new file mode 100644 index 000000000..b506c97db --- /dev/null +++ b/debian/patches/features/arm/kw-register-sdio.patch @@ -0,0 +1,198 @@ +From: Nicolas Pitre +Date: Sat, 14 Feb 2009 08:15:55 +0000 (-0500) +Subject: [ARM] Kirkwood: SDIO driver registration for DB6281 and RD6281 +X-Git-Url: http://git.marvell.com/?p=orion.git;a=commitdiff_plain;h=8235ee009cd839265f5dc2dace2758471a823e68 + +[ARM] Kirkwood: SDIO driver registration for DB6281 and RD6281 + +Signed-off-by: Nicolas Pitre +--- + +diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c +index b3404b7..e5076aa 100644 +--- a/arch/arm/mach-kirkwood/common.c ++++ b/arch/arm/mach-kirkwood/common.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -296,6 +297,50 @@ void __init kirkwood_sata_init(struct mv_sata_platform_data *sata_data) + + + /***************************************************************************** ++ * SD/SDIO/MMC ++ ****************************************************************************/ ++static struct resource mvsdio_resources[] = { ++ [0] = { ++ .start = SDIO_PHYS_BASE, ++ .end = SDIO_PHYS_BASE + SZ_1K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = IRQ_KIRKWOOD_SDIO, ++ .end = IRQ_KIRKWOOD_SDIO, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static u64 mvsdio_dmamask = 0xffffffffUL; ++ ++static struct platform_device kirkwood_sdio = { ++ .name = "mvsdio", ++ .id = -1, ++ .dev = { ++ .dma_mask = &mvsdio_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ }, ++ .num_resources = ARRAY_SIZE(mvsdio_resources), ++ .resource = mvsdio_resources, ++}; ++ ++void __init kirkwood_sdio_init(struct mvsdio_platform_data *mvsdio_data) ++{ ++ u32 dev, rev; ++ ++ kirkwood_pcie_id(&dev, &rev); ++ if (rev == 0) /* catch all Kirkwood Z0's */ ++ mvsdio_data->clock = 100000000; ++ else ++ mvsdio_data->clock = 200000000; ++ mvsdio_data->dram = &kirkwood_mbus_dram_info; ++ kirkwood_sdio.dev.platform_data = mvsdio_data; ++ platform_device_register(&kirkwood_sdio); ++} ++ ++ ++/***************************************************************************** + * SPI + ****************************************************************************/ + static struct orion_spi_info kirkwood_spi_plat_data = { +diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h +index fe367c1..5827940 100644 +--- a/arch/arm/mach-kirkwood/common.h ++++ b/arch/arm/mach-kirkwood/common.h +@@ -14,6 +14,7 @@ + struct dsa_platform_data; + struct mv643xx_eth_platform_data; + struct mv_sata_platform_data; ++struct mvsdio_platform_data; + + /* + * Basic Kirkwood init functions used early by machine-setup. +@@ -35,6 +36,7 @@ void kirkwood_ge00_switch_init(struct dsa_platform_data *d, int irq); + void kirkwood_pcie_init(void); + void kirkwood_rtc_init(void); + void kirkwood_sata_init(struct mv_sata_platform_data *sata_data); ++void kirkwood_sdio_init(struct mvsdio_platform_data *mvsdio_data); + void kirkwood_spi_init(void); + void kirkwood_uart0_init(void); + void kirkwood_uart1_init(void); +diff --git a/arch/arm/mach-kirkwood/db88f6281-bp-setup.c b/arch/arm/mach-kirkwood/db88f6281-bp-setup.c +index a14c294..5c3b40d 100644 +--- a/arch/arm/mach-kirkwood/db88f6281-bp-setup.c ++++ b/arch/arm/mach-kirkwood/db88f6281-bp-setup.c +@@ -22,7 +22,9 @@ + #include + #include + #include ++#include + #include "common.h" ++#include "mpp.h" + + static struct mv643xx_eth_platform_data db88f6281_ge00_data = { + .phy_addr = MV643XX_ETH_PHY_ADDR(8), +@@ -32,18 +34,31 @@ static struct mv_sata_platform_data db88f6281_sata_data = { + .n_ports = 2, + }; + ++static struct mvsdio_platform_data db88f6281_mvsdio_data = { ++ .gpio_write_protect = 37, ++ .gpio_card_detect = 38, ++}; ++ ++static unsigned int db88f6281_mpp_config[] __initdata = { ++ MPP37_GPIO, ++ MPP38_GPIO, ++ 0 ++}; ++ + static void __init db88f6281_init(void) + { + /* + * Basic setup. Needs to be called early. + */ + kirkwood_init(); ++ kirkwood_mpp_conf(db88f6281_mpp_config); + + kirkwood_ehci_init(); + kirkwood_ge00_init(&db88f6281_ge00_data); + kirkwood_rtc_init(); + kirkwood_sata_init(&db88f6281_sata_data); + kirkwood_uart0_init(); ++ kirkwood_sdio_init(&db88f6281_mvsdio_data); + } + + static int __init db88f6281_pci_init(void) +diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h +index ada480c..d3db30f 100644 +--- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h ++++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h +@@ -116,5 +116,7 @@ + + #define SATA_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x80000) + ++#define SDIO_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x90000) ++ + + #endif +diff --git a/arch/arm/mach-kirkwood/rd88f6281-setup.c b/arch/arm/mach-kirkwood/rd88f6281-setup.c +index a1ef8a9..a8b88a5 100644 +--- a/arch/arm/mach-kirkwood/rd88f6281-setup.c ++++ b/arch/arm/mach-kirkwood/rd88f6281-setup.c +@@ -24,8 +24,10 @@ + #include + #include + #include ++#include + #include + #include "common.h" ++#include "mpp.h" + + static struct mtd_partition rd88f6281_nand_parts[] = { + { +@@ -91,6 +93,15 @@ static struct mv_sata_platform_data rd88f6281_sata_data = { + .n_ports = 2, + }; + ++static struct mvsdio_platform_data rd88f6281_mvsdio_data = { ++ .gpio_card_detect = 28, ++}; ++ ++static unsigned int rd88f6281_mpp_config[] __initdata = { ++ MPP28_GPIO, ++ 0 ++}; ++ + static void __init rd88f6281_init(void) + { + u32 dev, rev; +@@ -99,6 +110,7 @@ static void __init rd88f6281_init(void) + * Basic setup. Needs to be called early. + */ + kirkwood_init(); ++ kirkwood_mpp_conf(rd88f6281_mpp_config); + + kirkwood_ehci_init(); + +@@ -114,6 +126,7 @@ + + kirkwood_rtc_init(); + kirkwood_sata_init(&rd88f6281_sata_data); ++ kirkwood_sdio_init(&rd88f6281_mvsdio_data); + kirkwood_uart0_init(); + + platform_device_register(&rd88f6281_nand_flash); diff --git a/debian/patches/features/arm/kw-sheevaplug-led.patch b/debian/patches/features/arm/kw-sheevaplug-led.patch new file mode 100644 index 000000000..12927f7ed --- /dev/null +++ b/debian/patches/features/arm/kw-sheevaplug-led.patch @@ -0,0 +1,62 @@ +From: Nicolas Pitre +Date: Tue, 3 Mar 2009 06:16:07 +0000 (-0500) +Subject: [ARM] Kirkwood: SheevaPlug LED support +X-Git-Url: http://git.marvell.com/?p=orion.git;a=commitdiff_plain;h=efd8c1bb08a981f0e6581aedb7a842924816a78c + +[ARM] Kirkwood: SheevaPlug LED support + +Signed-off-by: Nicolas Pitre +--- + +diff --git a/arch/arm/mach-kirkwood/sheevaplug-setup.c b/arch/arm/mach-kirkwood/sheevaplug-setup.c +index c1cb9f4..831e4a5 100644 +--- a/arch/arm/mach-kirkwood/sheevaplug-setup.c ++++ b/arch/arm/mach-kirkwood/sheevaplug-setup.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -73,8 +74,31 @@ static struct mvsdio_platform_data sheevaplug_mvsdio_data = { + // unfortunately the CD signal has not been connected */ + }; + ++static struct gpio_led sheevaplug_led_pins[] = { ++ { ++ .name = "plug:green:health", ++ .default_trigger = "default-on", ++ .gpio = 49, ++ .active_low = 1, ++ }, ++}; ++ ++static struct gpio_led_platform_data sheevaplug_led_data = { ++ .leds = sheevaplug_led_pins, ++ .num_leds = ARRAY_SIZE(sheevaplug_led_pins), ++}; ++ ++static struct platform_device sheevaplug_leds = { ++ .name = "leds-gpio", ++ .id = -1, ++ .dev = { ++ .platform_data = &sheevaplug_led_data, ++ } ++}; ++ + static unsigned int sheevaplug_mpp_config[] __initdata = { + MPP29_GPIO, /* USB Power Enable */ ++ MPP49_GPIO, /* LED */ + 0 + }; + +@@ -97,6 +121,7 @@ static void __init sheevaplug_init(void) + kirkwood_sdio_init(&sheevaplug_mvsdio_data); + + platform_device_register(&sheevaplug_nand_flash); ++ platform_device_register(&sheevaplug_leds); + } + + MACHINE_START(SHEEVAPLUG, "Marvell SheevaPlug Reference Board") diff --git a/debian/patches/features/arm/kw-sheevaplug-usb-power.patch b/debian/patches/features/arm/kw-sheevaplug-usb-power.patch new file mode 100644 index 000000000..01016157e --- /dev/null +++ b/debian/patches/features/arm/kw-sheevaplug-usb-power.patch @@ -0,0 +1,59 @@ +From: Nicolas Pitre +Date: Tue, 3 Mar 2009 04:44:41 +0000 (-0500) +Subject: [ARM] Kirkwood: SheevaPlug USB Power Enable setup +X-Git-Url: http://git.marvell.com/?p=orion.git;a=commitdiff_plain;h=3361de48dd360be04f02f0ebda969b15835ed39f + +[ARM] Kirkwood: SheevaPlug USB Power Enable setup + +Ideally, the default should be set to 0 and let the EHCI driver turn +it on as needed. This makes USB usable in the mean time. + +Signed-off-by: Nicolas Pitre +--- + +diff --git a/arch/arm/mach-kirkwood/sheevaplug-setup.c b/arch/arm/mach-kirkwood/sheevaplug-setup.c +index d48989d..c1cb9f4 100644 +--- a/arch/arm/mach-kirkwood/sheevaplug-setup.c ++++ b/arch/arm/mach-kirkwood/sheevaplug-setup.c +@@ -14,12 +14,14 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include + #include "common.h" ++#include "mpp.h" + + static struct mtd_partition sheevaplug_nand_parts[] = { + { +@@ -71,15 +73,26 @@ static struct mvsdio_platform_data sheevaplug_mvsdio_data = { + // unfortunately the CD signal has not been connected */ + }; + ++static unsigned int sheevaplug_mpp_config[] __initdata = { ++ MPP29_GPIO, /* USB Power Enable */ ++ 0 ++}; ++ + static void __init sheevaplug_init(void) + { + /* + * Basic setup. Needs to be called early. + */ + kirkwood_init(); ++ kirkwood_mpp_conf(sheevaplug_mpp_config); + + kirkwood_uart0_init(); ++ ++ if (gpio_request(29, "USB Power Enable") != 0 || ++ gpio_direction_output(29, 1) != 0) ++ printk(KERN_ERR "can't set up GPIO 29 (USB Power Enable)\n"); + kirkwood_ehci_init(); ++ + kirkwood_ge00_init(&sheevaplug_ge00_data); + kirkwood_sdio_init(&sheevaplug_mvsdio_data); + diff --git a/debian/patches/features/arm/kw-sheevaplug.patch b/debian/patches/features/arm/kw-sheevaplug.patch new file mode 100644 index 000000000..2075a8dfa --- /dev/null +++ b/debian/patches/features/arm/kw-sheevaplug.patch @@ -0,0 +1,149 @@ +From: Shadi Ammouri +Date: Tue, 24 Feb 2009 20:26:23 +0000 (-0500) +Subject: [ARM] Kirkwood: Marvell SheevaPlug support +X-Git-Url: http://git.marvell.com/?p=orion.git;a=commitdiff_plain;h=cb418a5633f257755359347055f8b76e1524f585 + +[ARM] Kirkwood: Marvell SheevaPlug support + +Signed-off-by: Nicolas Pitre +--- + +diff --git a/arch/arm/mach-kirkwood/Kconfig b/arch/arm/mach-kirkwood/Kconfig +index 3600cd9..5324436 100644 +--- a/arch/arm/mach-kirkwood/Kconfig ++++ b/arch/arm/mach-kirkwood/Kconfig +@@ -20,6 +20,12 @@ config MACH_RD88F6281 + Say 'Y' here if you want your kernel to support the + Marvell RD-88F6281 Reference Board. + ++config MACH_SHEEVAPLUG ++ bool "Marvell SheevaPlug Reference Board" ++ help ++ Say 'Y' here if you want your kernel to support the ++ Marvell SheevaPlug Reference Board. ++ + endmenu + + endif +diff --git a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile +index fdff35c..de81b4b 100644 +--- a/arch/arm/mach-kirkwood/Makefile ++++ b/arch/arm/mach-kirkwood/Makefile +@@ -3,3 +3,4 @@ obj-y += common.o addr-map.o irq.o pcie.o mpp.o + obj-$(CONFIG_MACH_DB88F6281_BP) += db88f6281-bp-setup.o + obj-$(CONFIG_MACH_RD88F6192_NAS) += rd88f6192-nas-setup.o + obj-$(CONFIG_MACH_RD88F6281) += rd88f6281-setup.o ++obj-$(CONFIG_MACH_SHEEVAPLUG) += sheevaplug-setup.o +diff --git a/arch/arm/mach-kirkwood/sheevaplug-setup.c b/arch/arm/mach-kirkwood/sheevaplug-setup.c +new file mode 100644 +index 0000000..d48989d +--- /dev/null ++++ b/arch/arm/mach-kirkwood/sheevaplug-setup.c +@@ -0,0 +1,98 @@ ++/* ++ * arch/arm/mach-kirkwood/sheevaplug-setup.c ++ * ++ * Marvell SheevaPlug Reference Board Setup ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "common.h" ++ ++static struct mtd_partition sheevaplug_nand_parts[] = { ++ { ++ .name = "u-boot", ++ .offset = 0, ++ .size = SZ_1M ++ }, { ++ .name = "uImage", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = SZ_4M ++ }, { ++ .name = "root", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = MTDPART_SIZ_FULL ++ }, ++}; ++ ++static struct resource sheevaplug_nand_resource = { ++ .flags = IORESOURCE_MEM, ++ .start = KIRKWOOD_NAND_MEM_PHYS_BASE, ++ .end = KIRKWOOD_NAND_MEM_PHYS_BASE + ++ KIRKWOOD_NAND_MEM_SIZE - 1, ++}; ++ ++static struct orion_nand_data sheevaplug_nand_data = { ++ .parts = sheevaplug_nand_parts, ++ .nr_parts = ARRAY_SIZE(sheevaplug_nand_parts), ++ .cle = 0, ++ .ale = 1, ++ .width = 8, ++ .chip_delay = 25, ++}; ++ ++static struct platform_device sheevaplug_nand_flash = { ++ .name = "orion_nand", ++ .id = -1, ++ .dev = { ++ .platform_data = &sheevaplug_nand_data, ++ }, ++ .resource = &sheevaplug_nand_resource, ++ .num_resources = 1, ++}; ++ ++static struct mv643xx_eth_platform_data sheevaplug_ge00_data = { ++ .phy_addr = MV643XX_ETH_PHY_ADDR(0), ++}; ++ ++static struct mvsdio_platform_data sheevaplug_mvsdio_data = { ++ // unfortunately the CD signal has not been connected */ ++}; ++ ++static void __init sheevaplug_init(void) ++{ ++ /* ++ * Basic setup. Needs to be called early. ++ */ ++ kirkwood_init(); ++ ++ kirkwood_uart0_init(); ++ kirkwood_ehci_init(); ++ kirkwood_ge00_init(&sheevaplug_ge00_data); ++ kirkwood_sdio_init(&sheevaplug_mvsdio_data); ++ ++ platform_device_register(&sheevaplug_nand_flash); ++} ++ ++MACHINE_START(SHEEVAPLUG, "Marvell SheevaPlug Reference Board") ++ /* Maintainer: shadi Ammouri */ ++ .phys_io = KIRKWOOD_REGS_PHYS_BASE, ++ .io_pg_offst = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc, ++ .boot_params = 0x00000100, ++ .init_machine = sheevaplug_init, ++ .map_io = kirkwood_map_io, ++ .init_irq = kirkwood_init_irq, ++ .timer = &kirkwood_timer, ++MACHINE_END +diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types +index fd23c0e..1fbfcac 100644 +--- a/arch/arm/tools/mach-types ++++ b/arch/arm/tools/mach-types +@@ -1994,3 +1994,4 @@ benzina MACH_BENZINA BENZINA 2003 + blaze MACH_BLAZE BLAZE 2004 + linkstation_ls_hgl MACH_LINKSTATION_LS_HGL LINKSTATION_LS_HGL 2005 + htcvenus MACH_HTCVENUS HTCVENUS 2006 ++sheevaplug MACH_SHEEVAPLUG SHEEVAPLUG 2097 diff --git a/debian/patches/features/arm/mv-sdio.patch b/debian/patches/features/arm/mv-sdio.patch new file mode 100644 index 000000000..bbe0910de --- /dev/null +++ b/debian/patches/features/arm/mv-sdio.patch @@ -0,0 +1,1158 @@ +From: Maen Suleiman +Date: Sat, 14 Feb 2009 08:07:26 +0000 (-0500) +Subject: [MMC] SDIO driver for Marvell SoCs +X-Git-Url: http://git.marvell.com/?p=orion.git;a=commitdiff_plain;h=4c4f07fb0d12809cdc6a1e3ebf948c00188d8cf9 + +[MMC] SDIO driver for Marvell SoCs + +This supports MMC/SD/SDIO currently found on the Kirkwood 88F6281 and +88F6192 SoC controllers. + +Signed-off-by: Nicolas Pitre +--- + +diff --git a/arch/arm/plat-orion/include/plat/mvsdio.h b/arch/arm/plat-orion/include/plat/mvsdio.h +new file mode 100644 +index 0000000..14ca886 +--- /dev/null ++++ b/arch/arm/plat-orion/include/plat/mvsdio.h +@@ -0,0 +1,21 @@ ++/* ++ * arch/arm/plat-orion/include/plat/mvsdio.h ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#ifndef __MACH_MVSDIO_H ++#define __MACH_MVSDIO_H ++ ++#include ++ ++struct mvsdio_platform_data { ++ struct mbus_dram_target_info *dram; ++ unsigned int clock; ++ int gpio_card_detect; ++ int gpio_write_protect; ++}; ++ ++#endif +diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig +index 99d4b28..092baf6 100644 +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -171,6 +171,17 @@ config MMC_TIFM_SD + To compile this driver as a module, choose M here: the + module will be called tifm_sd. + ++config MMC_MVSDIO ++ tristate "Marvell MMC/SD/SDIO host driver" ++ depends on PLAT_ORION ++ ---help--- ++ This selects the Marvell SDIO host driver. ++ SDIO may currently be found on the Kirkwood 88F6281 and 88F6192 ++ SoC controllers. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called mvsdio. ++ + config MMC_SPI + tristate "MMC/SD/SDIO over SPI" + depends on SPI_MASTER && !HIGHMEM && HAS_DMA +diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile +index dedec55..c006eb4 100644 +--- a/drivers/mmc/host/Makefile ++++ b/drivers/mmc/host/Makefile +@@ -20,6 +20,7 @@ obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o + obj-$(CONFIG_MMC_AT91) += at91_mci.o + obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o + obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o ++obj-$(CONFIG_MMC_MVSDIO) += mvsdio.o + obj-$(CONFIG_MMC_SPI) += mmc_spi.o + ifeq ($(CONFIG_OF),y) + obj-$(CONFIG_MMC_SPI) += of_mmc_spi.o +diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c +new file mode 100644 +index 0000000..e4d69d8 +--- /dev/null ++++ b/drivers/mmc/host/mvsdio.c +@@ -0,0 +1,882 @@ ++/* ++ * Marvell MMC/SD/SDIO driver ++ * ++ * Authors: Maen Suleiman, Nicolas Pitre ++ * Copyright (C) 2008-2009 Marvell Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "mvsdio.h" ++ ++#define DRIVER_NAME "mvsdio" ++ ++static int maxfreq = MVSD_CLOCKRATE_MAX; ++static int nodma; ++ ++struct mvsd_host { ++ void __iomem *base; ++ struct mmc_request *mrq; ++ spinlock_t lock; ++ unsigned int xfer_mode; ++ unsigned int intr_en; ++ unsigned int ctrl; ++ unsigned int pio_size; ++ void *pio_ptr; ++ unsigned int sg_frags; ++ unsigned int ns_per_clk; ++ unsigned int clock; ++ unsigned int base_clock; ++ struct timer_list timer; ++ struct mmc_host *mmc; ++ struct device *dev; ++ struct resource *res; ++ int irq; ++ int gpio_card_detect; ++ int gpio_write_protect; ++}; ++ ++#define mvsd_write(offs, val) writel(val, iobase + (offs)) ++#define mvsd_read(offs) readl(iobase + (offs)) ++ ++static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data) ++{ ++ void __iomem *iobase = host->base; ++ unsigned int tmout; ++ int tmout_index; ++ ++ /* If timeout=0 then maximum timeout index is used. */ ++ tmout = DIV_ROUND_UP(data->timeout_ns, host->ns_per_clk); ++ tmout += data->timeout_clks; ++ tmout_index = fls(tmout - 1) - 12; ++ if (tmout_index < 0) ++ tmout_index = 0; ++ if (tmout_index > MVSD_HOST_CTRL_TMOUT_MAX) ++ tmout_index = MVSD_HOST_CTRL_TMOUT_MAX; ++ ++ dev_dbg(host->dev, "data %s at 0x%08x: blocks=%d blksz=%d tmout=%u (%d)\n", ++ (data->flags & MMC_DATA_READ) ? "read" : "write", ++ (u32)sg_virt(data->sg), data->blocks, data->blksz, ++ tmout, tmout_index); ++ ++ host->ctrl &= ~MVSD_HOST_CTRL_TMOUT_MASK; ++ host->ctrl |= MVSD_HOST_CTRL_TMOUT(tmout_index); ++ mvsd_write(MVSD_HOST_CTRL, host->ctrl); ++ mvsd_write(MVSD_BLK_COUNT, data->blocks); ++ mvsd_write(MVSD_BLK_SIZE, data->blksz); ++ ++ if (nodma || (data->blksz | data->sg->offset) & 3) { ++ /* ++ * We cannot do DMA on a buffer which offset or size ++ * is not aligned on a 4-byte boundary. ++ */ ++ host->pio_size = data->blocks * data->blksz; ++ host->pio_ptr = sg_virt(data->sg); ++ if (!nodma) ++ printk(KERN_DEBUG "%s: fallback to PIO for data " ++ "at 0x%p size %d\n", ++ mmc_hostname(host->mmc), ++ host->pio_ptr, host->pio_size); ++ return 1; ++ } else { ++ dma_addr_t phys_addr; ++ int dma_dir = (data->flags & MMC_DATA_READ) ? ++ DMA_FROM_DEVICE : DMA_TO_DEVICE; ++ host->sg_frags = dma_map_sg(mmc_dev(host->mmc), data->sg, ++ data->sg_len, dma_dir); ++ phys_addr = sg_dma_address(data->sg); ++ mvsd_write(MVSD_SYS_ADDR_LOW, (u32)phys_addr & 0xffff); ++ mvsd_write(MVSD_SYS_ADDR_HI, (u32)phys_addr >> 16); ++ return 0; ++ } ++} ++ ++static void mvsd_request(struct mmc_host *mmc, struct mmc_request *mrq) ++{ ++ struct mvsd_host *host = mmc_priv(mmc); ++ void __iomem *iobase = host->base; ++ struct mmc_command *cmd = mrq->cmd; ++ u32 cmdreg = 0, xfer = 0, intr = 0; ++ unsigned long flags; ++ ++ BUG_ON(host->mrq != NULL); ++ host->mrq = mrq; ++ ++ dev_dbg(host->dev, "cmd %d (hw state 0x%04x)\n", ++ cmd->opcode, mvsd_read(MVSD_HW_STATE)); ++ ++ cmdreg = MVSD_CMD_INDEX(cmd->opcode); ++ ++ if (cmd->flags & MMC_RSP_BUSY) ++ cmdreg |= MVSD_CMD_RSP_48BUSY; ++ else if (cmd->flags & MMC_RSP_136) ++ cmdreg |= MVSD_CMD_RSP_136; ++ else if (cmd->flags & MMC_RSP_PRESENT) ++ cmdreg |= MVSD_CMD_RSP_48; ++ else ++ cmdreg |= MVSD_CMD_RSP_NONE; ++ ++ if (cmd->flags & MMC_RSP_CRC) ++ cmdreg |= MVSD_CMD_CHECK_CMDCRC; ++ ++ if (cmd->flags & MMC_RSP_OPCODE) ++ cmdreg |= MVSD_CMD_INDX_CHECK; ++ ++ if (cmd->flags & MMC_RSP_PRESENT) { ++ cmdreg |= MVSD_UNEXPECTED_RESP; ++ intr |= MVSD_NOR_UNEXP_RSP; ++ } ++ ++ if (mrq->data) { ++ struct mmc_data *data = mrq->data; ++ int pio; ++ ++ cmdreg |= MVSD_CMD_DATA_PRESENT | MVSD_CMD_CHECK_DATACRC16; ++ xfer |= MVSD_XFER_MODE_HW_WR_DATA_EN; ++ if (data->flags & MMC_DATA_READ) ++ xfer |= MVSD_XFER_MODE_TO_HOST; ++ ++ pio = mvsd_setup_data(host, data); ++ if (pio) { ++ xfer |= MVSD_XFER_MODE_PIO; ++ /* PIO section of mvsd_irq has comments on those bits */ ++ if (data->flags & MMC_DATA_WRITE) ++ intr |= MVSD_NOR_TX_AVAIL; ++ else if (host->pio_size > 32) ++ intr |= MVSD_NOR_RX_FIFO_8W; ++ else ++ intr |= MVSD_NOR_RX_READY; ++ } ++ ++ if (data->stop) { ++ struct mmc_command *stop = data->stop; ++ u32 cmd12reg = 0; ++ ++ mvsd_write(MVSD_AUTOCMD12_ARG_LOW, stop->arg & 0xffff); ++ mvsd_write(MVSD_AUTOCMD12_ARG_HI, stop->arg >> 16); ++ ++ if (stop->flags & MMC_RSP_BUSY) ++ cmd12reg |= MVSD_AUTOCMD12_BUSY; ++ if (stop->flags & MMC_RSP_OPCODE) ++ cmd12reg |= MVSD_AUTOCMD12_INDX_CHECK; ++ cmd12reg |= MVSD_AUTOCMD12_INDEX(stop->opcode); ++ mvsd_write(MVSD_AUTOCMD12_CMD, cmd12reg); ++ ++ xfer |= MVSD_XFER_MODE_AUTO_CMD12; ++ intr |= MVSD_NOR_AUTOCMD12_DONE; ++ } else { ++ intr |= MVSD_NOR_XFER_DONE; ++ } ++ } else { ++ intr |= MVSD_NOR_CMD_DONE; ++ } ++ ++ mvsd_write(MVSD_ARG_LOW, cmd->arg & 0xffff); ++ mvsd_write(MVSD_ARG_HI, cmd->arg >> 16); ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ host->xfer_mode &= MVSD_XFER_MODE_INT_CHK_EN; ++ host->xfer_mode |= xfer; ++ mvsd_write(MVSD_XFER_MODE, host->xfer_mode); ++ ++ mvsd_write(MVSD_NOR_INTR_STATUS, ~MVSD_NOR_CARD_INT); ++ mvsd_write(MVSD_ERR_INTR_STATUS, 0xffff); ++ mvsd_write(MVSD_CMD, cmdreg); ++ ++ host->intr_en &= MVSD_NOR_CARD_INT; ++ host->intr_en |= intr | MVSD_NOR_ERROR; ++ mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); ++ mvsd_write(MVSD_ERR_INTR_EN, 0xffff); ++ ++ mod_timer(&host->timer, jiffies + 5 * HZ); ++ ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++static u32 mvsd_finish_cmd(struct mvsd_host *host, struct mmc_command *cmd, ++ u32 err_status) ++{ ++ void __iomem *iobase = host->base; ++ ++ if (cmd->flags & MMC_RSP_136) { ++ unsigned int response[8], i; ++ for (i = 0; i < 8; i++) ++ response[i] = mvsd_read(MVSD_RSP(i)); ++ cmd->resp[0] = ((response[0] & 0x03ff) << 22) | ++ ((response[1] & 0xffff) << 6) | ++ ((response[2] & 0xfc00) >> 10); ++ cmd->resp[1] = ((response[2] & 0x03ff) << 22) | ++ ((response[3] & 0xffff) << 6) | ++ ((response[4] & 0xfc00) >> 10); ++ cmd->resp[2] = ((response[4] & 0x03ff) << 22) | ++ ((response[5] & 0xffff) << 6) | ++ ((response[6] & 0xfc00) >> 10); ++ cmd->resp[3] = ((response[6] & 0x03ff) << 22) | ++ ((response[7] & 0x3fff) << 8); ++ } else if (cmd->flags & MMC_RSP_PRESENT) { ++ unsigned int response[3], i; ++ for (i = 0; i < 3; i++) ++ response[i] = mvsd_read(MVSD_RSP(i)); ++ cmd->resp[0] = ((response[2] & 0x003f) << (8 - 8)) | ++ ((response[1] & 0xffff) << (14 - 8)) | ++ ((response[0] & 0x03ff) << (30 - 8)); ++ cmd->resp[1] = ((response[0] & 0xfc00) >> 10); ++ cmd->resp[2] = 0; ++ cmd->resp[3] = 0; ++ } ++ ++ if (err_status & MVSD_ERR_CMD_TIMEOUT) { ++ cmd->error = -ETIMEDOUT; ++ } else if (err_status & (MVSD_ERR_CMD_CRC | MVSD_ERR_CMD_ENDBIT | ++ MVSD_ERR_CMD_INDEX | MVSD_ERR_CMD_STARTBIT)) { ++ cmd->error = -EILSEQ; ++ } ++ err_status &= ~(MVSD_ERR_CMD_TIMEOUT | MVSD_ERR_CMD_CRC | ++ MVSD_ERR_CMD_ENDBIT | MVSD_ERR_CMD_INDEX | ++ MVSD_ERR_CMD_STARTBIT); ++ ++ return err_status; ++} ++ ++static u32 mvsd_finish_data(struct mvsd_host *host, struct mmc_data *data, ++ u32 err_status) ++{ ++ void __iomem *iobase = host->base; ++ ++ if (host->pio_ptr) { ++ host->pio_ptr = NULL; ++ host->pio_size = 0; ++ } else { ++ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_frags, ++ (data->flags & MMC_DATA_READ) ? ++ DMA_FROM_DEVICE : DMA_TO_DEVICE); ++ } ++ ++ if (err_status & MVSD_ERR_DATA_TIMEOUT) ++ data->error = -ETIMEDOUT; ++ else if (err_status & (MVSD_ERR_DATA_CRC | MVSD_ERR_DATA_ENDBIT)) ++ data->error = -EILSEQ; ++ else if (err_status & MVSD_ERR_XFER_SIZE) ++ data->error = -EBADE; ++ err_status &= ~(MVSD_ERR_DATA_TIMEOUT | MVSD_ERR_DATA_CRC | ++ MVSD_ERR_DATA_ENDBIT | MVSD_ERR_XFER_SIZE); ++ ++ data->bytes_xfered = ++ (data->blocks - mvsd_read(MVSD_CURR_BLK_LEFT)) * data->blksz; ++ dev_dbg(host->dev, "data done: blocks_left=%d, bytes_left=%d\n", ++ mvsd_read(MVSD_CURR_BLK_LEFT), mvsd_read(MVSD_CURR_BYTE_LEFT)); ++ ++ /* Handle Auto cmd 12 response */ ++ if (data->stop) { ++ unsigned int response[3], i; ++ for (i = 0; i < 3; i++) ++ response[i] = mvsd_read(MVSD_AUTO_RSP(i)); ++ data->stop->resp[0] = ((response[2] & 0x003f) << (8 - 8)) | ++ ((response[1] & 0xffff) << (14 - 8)) | ++ ((response[0] & 0x03ff) << (30 - 8)); ++ data->stop->resp[1] = ((response[0] & 0xfc00) >> 10); ++ data->stop->resp[2] = 0; ++ data->stop->resp[3] = 0; ++ ++ if (err_status & MVSD_ERR_AUTOCMD12) { ++ u32 err_cmd12 = mvsd_read(MVSD_AUTOCMD12_ERR_STATUS); ++ dev_dbg(host->dev, "c12err 0x%04x\n", err_cmd12); ++ if (err_cmd12 & MVSD_AUTOCMD12_ERR_NOTEXE) ++ data->stop->error = -ENOEXEC; ++ else if (err_cmd12 & MVSD_AUTOCMD12_ERR_TIMEOUT) ++ data->stop->error = -ETIMEDOUT; ++ else if (err_cmd12) ++ data->stop->error = -EILSEQ; ++ err_status &= ~MVSD_ERR_AUTOCMD12; ++ } ++ } ++ ++ return err_status; ++} ++ ++static irqreturn_t mvsd_irq(int irq, void *dev) ++{ ++ struct mvsd_host *host = dev; ++ void __iomem *iobase = host->base; ++ u32 intr_status, intr_done_mask; ++ int irq_handled = 0; ++ ++ intr_status = mvsd_read(MVSD_NOR_INTR_STATUS); ++ dev_dbg(host->dev, "intr 0x%04x intr_en 0x%04x hw_state 0x%04x\n", ++ intr_status, mvsd_read(MVSD_NOR_INTR_EN), ++ mvsd_read(MVSD_HW_STATE)); ++ ++ spin_lock(&host->lock); ++ ++ /* PIO handling, if needed. Messy business... */ ++ if (host->pio_size && ++ (intr_status & host->intr_en & ++ (MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W))) { ++ u16 *p = host->pio_ptr; ++ int s = host->pio_size; ++ while (s >= 32 && (intr_status & MVSD_NOR_RX_FIFO_8W)) { ++ readsw(iobase + MVSD_FIFO, p, 16); ++ p += 16; ++ s -= 32; ++ intr_status = mvsd_read(MVSD_NOR_INTR_STATUS); ++ } ++ /* ++ * Normally we'd use < 32 here, but the RX_FIFO_8W bit ++ * doesn't appear to assert when there is exactly 32 bytes ++ * (8 words) left to fetch in a transfer. ++ */ ++ if (s <= 32) { ++ while (s >= 4 && (intr_status & MVSD_NOR_RX_READY)) { ++ put_unaligned(mvsd_read(MVSD_FIFO), p++); ++ put_unaligned(mvsd_read(MVSD_FIFO), p++); ++ s -= 4; ++ intr_status = mvsd_read(MVSD_NOR_INTR_STATUS); ++ } ++ if (s && s < 4 && (intr_status & MVSD_NOR_RX_READY)) { ++ u16 val[2] = {0, 0}; ++ val[0] = mvsd_read(MVSD_FIFO); ++ val[1] = mvsd_read(MVSD_FIFO); ++ memcpy(p, &val, s); ++ s = 0; ++ intr_status = mvsd_read(MVSD_NOR_INTR_STATUS); ++ } ++ if (s == 0) { ++ host->intr_en &= ++ ~(MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W); ++ mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); ++ } else if (host->intr_en & MVSD_NOR_RX_FIFO_8W) { ++ host->intr_en &= ~MVSD_NOR_RX_FIFO_8W; ++ host->intr_en |= MVSD_NOR_RX_READY; ++ mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); ++ } ++ } ++ dev_dbg(host->dev, "pio %d intr 0x%04x hw_state 0x%04x\n", ++ s, intr_status, mvsd_read(MVSD_HW_STATE)); ++ host->pio_ptr = p; ++ host->pio_size = s; ++ irq_handled = 1; ++ } else if (host->pio_size && ++ (intr_status & host->intr_en & ++ (MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W))) { ++ u16 *p = host->pio_ptr; ++ int s = host->pio_size; ++ /* ++ * The TX_FIFO_8W bit is unreliable. When set, bursting ++ * 16 halfwords all at once in the FIFO drops data. Actually ++ * TX_AVAIL does go off after only one word is pushed even if ++ * TX_FIFO_8W remains set. ++ */ ++ while (s >= 4 && (intr_status & MVSD_NOR_TX_AVAIL)) { ++ mvsd_write(MVSD_FIFO, get_unaligned(p++)); ++ mvsd_write(MVSD_FIFO, get_unaligned(p++)); ++ s -= 4; ++ intr_status = mvsd_read(MVSD_NOR_INTR_STATUS); ++ } ++ if (s < 4) { ++ if (s && (intr_status & MVSD_NOR_TX_AVAIL)) { ++ u16 val[2] = {0, 0}; ++ memcpy(&val, p, s); ++ mvsd_write(MVSD_FIFO, val[0]); ++ mvsd_write(MVSD_FIFO, val[1]); ++ s = 0; ++ intr_status = mvsd_read(MVSD_NOR_INTR_STATUS); ++ } ++ if (s == 0) { ++ host->intr_en &= ++ ~(MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W); ++ mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); ++ } ++ } ++ dev_dbg(host->dev, "pio %d intr 0x%04x hw_state 0x%04x\n", ++ s, intr_status, mvsd_read(MVSD_HW_STATE)); ++ host->pio_ptr = p; ++ host->pio_size = s; ++ irq_handled = 1; ++ } ++ ++ mvsd_write(MVSD_NOR_INTR_STATUS, intr_status); ++ ++ intr_done_mask = MVSD_NOR_CARD_INT | MVSD_NOR_RX_READY | ++ MVSD_NOR_RX_FIFO_8W | MVSD_NOR_TX_FIFO_8W; ++ if (intr_status & host->intr_en & ~intr_done_mask) { ++ struct mmc_request *mrq = host->mrq; ++ struct mmc_command *cmd = mrq->cmd; ++ u32 err_status = 0; ++ ++ del_timer(&host->timer); ++ host->mrq = NULL; ++ ++ host->intr_en &= MVSD_NOR_CARD_INT; ++ mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); ++ mvsd_write(MVSD_ERR_INTR_EN, 0); ++ ++ spin_unlock(&host->lock); ++ ++ if (intr_status & MVSD_NOR_UNEXP_RSP) { ++ cmd->error = -EPROTO; ++ } else if (intr_status & MVSD_NOR_ERROR) { ++ err_status = mvsd_read(MVSD_ERR_INTR_STATUS); ++ dev_dbg(host->dev, "err 0x%04x\n", err_status); ++ } ++ ++ err_status = mvsd_finish_cmd(host, cmd, err_status); ++ if (mrq->data) ++ err_status = mvsd_finish_data(host, mrq->data, err_status); ++ if (err_status) { ++ printk(KERN_ERR "%s: unhandled error status %#04x\n", ++ mmc_hostname(host->mmc), err_status); ++ cmd->error = -ENOMSG; ++ } ++ ++ mmc_request_done(host->mmc, mrq); ++ irq_handled = 1; ++ } else ++ spin_unlock(&host->lock); ++ ++ if (intr_status & MVSD_NOR_CARD_INT) { ++ mmc_signal_sdio_irq(host->mmc); ++ irq_handled = 1; ++ } ++ ++ if (irq_handled) ++ return IRQ_HANDLED; ++ ++ printk(KERN_ERR "%s: unhandled interrupt status=0x%04x en=0x%04x " ++ "pio=%d\n", mmc_hostname(host->mmc), intr_status, ++ host->intr_en, host->pio_size); ++ return IRQ_NONE; ++} ++ ++static void mvsd_timeout_timer(unsigned long data) ++{ ++ struct mvsd_host *host = (struct mvsd_host *)data; ++ void __iomem *iobase = host->base; ++ struct mmc_request *mrq; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ mrq = host->mrq; ++ if (mrq) { ++ printk(KERN_ERR "%s: Timeout waiting for hardware interrupt.\n", ++ mmc_hostname(host->mmc)); ++ printk(KERN_ERR "%s: hw_state=0x%04x, intr_status=0x%04x " ++ "intr_en=0x%04x\n", mmc_hostname(host->mmc), ++ mvsd_read(MVSD_HW_STATE), ++ mvsd_read(MVSD_NOR_INTR_STATUS), ++ mvsd_read(MVSD_NOR_INTR_EN)); ++ ++ host->mrq = NULL; ++ ++ mvsd_write(MVSD_SW_RESET, MVSD_SW_RESET_NOW); ++ ++ host->xfer_mode &= MVSD_XFER_MODE_INT_CHK_EN; ++ mvsd_write(MVSD_XFER_MODE, host->xfer_mode); ++ ++ host->intr_en &= MVSD_NOR_CARD_INT; ++ mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); ++ mvsd_write(MVSD_ERR_INTR_EN, 0); ++ mvsd_write(MVSD_ERR_INTR_STATUS, 0xffff); ++ ++ mrq->cmd->error = -ETIMEDOUT; ++ mvsd_finish_cmd(host, mrq->cmd, 0); ++ if (mrq->data) { ++ mrq->data->error = -ETIMEDOUT; ++ mvsd_finish_data(host, mrq->data, 0); ++ } ++ } ++ spin_unlock_irqrestore(&host->lock, flags); ++ ++ if (mrq) ++ mmc_request_done(host->mmc, mrq); ++} ++ ++static irqreturn_t mvsd_card_detect_irq(int irq, void *dev) ++{ ++ struct mvsd_host *host = dev; ++ mmc_detect_change(host->mmc, msecs_to_jiffies(100)); ++ return IRQ_HANDLED; ++} ++ ++static void mvsd_enable_sdio_irq(struct mmc_host *mmc, int enable) ++{ ++ struct mvsd_host *host = mmc_priv(mmc); ++ void __iomem *iobase = host->base; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ if (enable) { ++ host->xfer_mode |= MVSD_XFER_MODE_INT_CHK_EN; ++ host->intr_en |= MVSD_NOR_CARD_INT; ++ } else { ++ host->xfer_mode &= ~MVSD_XFER_MODE_INT_CHK_EN; ++ host->intr_en &= ~MVSD_NOR_CARD_INT; ++ } ++ mvsd_write(MVSD_XFER_MODE, host->xfer_mode); ++ mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++static int mvsd_get_ro(struct mmc_host *mmc) ++{ ++ struct mvsd_host *host = mmc_priv(mmc); ++ ++ if (host->gpio_write_protect) ++ return gpio_get_value(host->gpio_write_protect); ++ ++ /* ++ * Board doesn't support read only detection; let the mmc core ++ * decide what to do. ++ */ ++ return -ENOSYS; ++} ++ ++static void mvsd_power_up(struct mvsd_host *host) ++{ ++ void __iomem *iobase = host->base; ++ dev_dbg(host->dev, "power up\n"); ++ mvsd_write(MVSD_NOR_INTR_EN, 0); ++ mvsd_write(MVSD_ERR_INTR_EN, 0); ++ mvsd_write(MVSD_SW_RESET, MVSD_SW_RESET_NOW); ++ mvsd_write(MVSD_XFER_MODE, 0); ++ mvsd_write(MVSD_NOR_STATUS_EN, 0xffff); ++ mvsd_write(MVSD_ERR_STATUS_EN, 0xffff); ++ mvsd_write(MVSD_NOR_INTR_STATUS, 0xffff); ++ mvsd_write(MVSD_ERR_INTR_STATUS, 0xffff); ++} ++ ++static void mvsd_power_down(struct mvsd_host *host) ++{ ++ void __iomem *iobase = host->base; ++ dev_dbg(host->dev, "power down\n"); ++ mvsd_write(MVSD_NOR_INTR_EN, 0); ++ mvsd_write(MVSD_ERR_INTR_EN, 0); ++ mvsd_write(MVSD_SW_RESET, MVSD_SW_RESET_NOW); ++ mvsd_write(MVSD_XFER_MODE, MVSD_XFER_MODE_STOP_CLK); ++ mvsd_write(MVSD_NOR_STATUS_EN, 0); ++ mvsd_write(MVSD_ERR_STATUS_EN, 0); ++ mvsd_write(MVSD_NOR_INTR_STATUS, 0xffff); ++ mvsd_write(MVSD_ERR_INTR_STATUS, 0xffff); ++} ++ ++static void mvsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ struct mvsd_host *host = mmc_priv(mmc); ++ void __iomem *iobase = host->base; ++ u32 ctrl_reg = 0; ++ ++ if (ios->power_mode == MMC_POWER_UP) ++ mvsd_power_up(host); ++ ++ if (ios->clock == 0) { ++ mvsd_write(MVSD_XFER_MODE, MVSD_XFER_MODE_STOP_CLK); ++ mvsd_write(MVSD_CLK_DIV, MVSD_BASE_DIV_MAX); ++ host->clock = 0; ++ dev_dbg(host->dev, "clock off\n"); ++ } else if (ios->clock != host->clock) { ++ u32 m = DIV_ROUND_UP(host->base_clock, ios->clock) - 1; ++ if (m > MVSD_BASE_DIV_MAX) ++ m = MVSD_BASE_DIV_MAX; ++ mvsd_write(MVSD_CLK_DIV, m); ++ host->clock = ios->clock; ++ host->ns_per_clk = 1000000000 / (host->base_clock / (m+1)); ++ dev_dbg(host->dev, "clock=%d (%d), div=0x%04x\n", ++ ios->clock, host->base_clock / (m+1), m); ++ } ++ ++ /* default transfer mode */ ++ ctrl_reg |= MVSD_HOST_CTRL_BIG_ENDIAN; ++ ctrl_reg &= ~MVSD_HOST_CTRL_LSB_FIRST; ++ ++ /* default to maximum timeout */ ++ ctrl_reg |= MVSD_HOST_CTRL_TMOUT_MASK; ++ ctrl_reg |= MVSD_HOST_CTRL_TMOUT_EN; ++ ++ if (ios->bus_mode == MMC_BUSMODE_PUSHPULL) ++ ctrl_reg |= MVSD_HOST_CTRL_PUSH_PULL_EN; ++ ++ if (ios->bus_width == MMC_BUS_WIDTH_4) ++ ctrl_reg |= MVSD_HOST_CTRL_DATA_WIDTH_4_BITS; ++ ++ if (ios->timing == MMC_TIMING_MMC_HS || ++ ios->timing == MMC_TIMING_SD_HS) ++ ctrl_reg |= MVSD_HOST_CTRL_HI_SPEED_EN; ++ ++ host->ctrl = ctrl_reg; ++ mvsd_write(MVSD_HOST_CTRL, ctrl_reg); ++ dev_dbg(host->dev, "ctrl 0x%04x: %s %s %s\n", ctrl_reg, ++ (ctrl_reg & MVSD_HOST_CTRL_PUSH_PULL_EN) ? ++ "push-pull" : "open-drain", ++ (ctrl_reg & MVSD_HOST_CTRL_DATA_WIDTH_4_BITS) ? ++ "4bit-width" : "1bit-width", ++ (ctrl_reg & MVSD_HOST_CTRL_HI_SPEED_EN) ? ++ "high-speed" : ""); ++ ++ if (ios->power_mode == MMC_POWER_OFF) ++ mvsd_power_down(host); ++} ++ ++static const struct mmc_host_ops mvsd_ops = { ++ .request = mvsd_request, ++ .get_ro = mvsd_get_ro, ++ .set_ios = mvsd_set_ios, ++ .enable_sdio_irq = mvsd_enable_sdio_irq, ++}; ++ ++static void __init mv_conf_mbus_windows(struct mvsd_host *host, ++ struct mbus_dram_target_info *dram) ++{ ++ void __iomem *iobase = host->base; ++ int i; ++ ++ for (i = 0; i < 4; i++) { ++ writel(0, iobase + MVSD_WINDOW_CTRL(i)); ++ writel(0, iobase + MVSD_WINDOW_BASE(i)); ++ } ++ ++ for (i = 0; i < dram->num_cs; i++) { ++ struct mbus_dram_window *cs = dram->cs + i; ++ writel(((cs->size - 1) & 0xffff0000) | ++ (cs->mbus_attr << 8) | ++ (dram->mbus_dram_target_id << 4) | 1, ++ iobase + MVSD_WINDOW_CTRL(i)); ++ writel(cs->base, iobase + MVSD_WINDOW_BASE(i)); ++ } ++} ++ ++static int __init mvsd_probe(struct platform_device *pdev) ++{ ++ struct mmc_host *mmc = NULL; ++ struct mvsd_host *host = NULL; ++ const struct mvsdio_platform_data *mvsd_data; ++ struct resource *r; ++ int ret, irq; ++ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irq = platform_get_irq(pdev, 0); ++ mvsd_data = pdev->dev.platform_data; ++ if (!r || irq < 0 || !mvsd_data) ++ return -ENXIO; ++ ++ r = request_mem_region(r->start, SZ_1K, DRIVER_NAME); ++ if (!r) ++ return -EBUSY; ++ ++ mmc = mmc_alloc_host(sizeof(struct mvsd_host), &pdev->dev); ++ if (!mmc) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ host = mmc_priv(mmc); ++ host->mmc = mmc; ++ host->dev = &pdev->dev; ++ host->res = r; ++ host->base_clock = mvsd_data->clock / 2; ++ ++ mmc->ops = &mvsd_ops; ++ ++ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; ++ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ | ++ MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; ++ ++ mmc->f_min = DIV_ROUND_UP(host->base_clock, MVSD_BASE_DIV_MAX); ++ mmc->f_max = maxfreq; ++ ++ mmc->max_blk_size = 2048; ++ mmc->max_blk_count = 65535; ++ ++ mmc->max_hw_segs = 1; ++ mmc->max_phys_segs = 1; ++ mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count; ++ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; ++ ++ spin_lock_init(&host->lock); ++ ++ host->base = ioremap(r->start, SZ_4K); ++ if (!host->base) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ /* (Re-)program MBUS remapping windows if we are asked to. */ ++ if (mvsd_data->dram != NULL) ++ mv_conf_mbus_windows(host, mvsd_data->dram); ++ ++ mvsd_power_down(host); ++ ++ ret = request_irq(irq, mvsd_irq, 0, DRIVER_NAME, host); ++ if (ret) { ++ printk(KERN_ERR "%s: cannot assign irq %d\n", DRIVER_NAME, irq); ++ goto out; ++ } else ++ host->irq = irq; ++ ++ if (mvsd_data->gpio_card_detect) { ++ ret = gpio_request(mvsd_data->gpio_card_detect, ++ DRIVER_NAME " cd"); ++ if (ret == 0) { ++ gpio_direction_input(mvsd_data->gpio_card_detect); ++ irq = gpio_to_irq(mvsd_data->gpio_card_detect); ++ ret = request_irq(irq, mvsd_card_detect_irq, ++ IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING, ++ DRIVER_NAME " cd", host); ++ if (ret == 0) ++ host->gpio_card_detect = ++ mvsd_data->gpio_card_detect; ++ else ++ gpio_free(mvsd_data->gpio_card_detect); ++ } ++ } ++ if (!host->gpio_card_detect) ++ mmc->caps |= MMC_CAP_NEEDS_POLL; ++ ++ if (mvsd_data->gpio_write_protect) { ++ ret = gpio_request(mvsd_data->gpio_write_protect, ++ DRIVER_NAME " wp"); ++ if (ret == 0) { ++ gpio_direction_input(mvsd_data->gpio_write_protect); ++ host->gpio_write_protect = ++ mvsd_data->gpio_write_protect; ++ } ++ } ++ ++ setup_timer(&host->timer, mvsd_timeout_timer, (unsigned long)host); ++ platform_set_drvdata(pdev, mmc); ++ ret = mmc_add_host(mmc); ++ if (ret) ++ goto out; ++ ++ printk(KERN_NOTICE "%s: %s driver initialized, ", ++ mmc_hostname(mmc), DRIVER_NAME); ++ if (host->gpio_card_detect) ++ printk("using GPIO %d for card detection\n", ++ host->gpio_card_detect); ++ else ++ printk("lacking card detect (fall back to polling)\n"); ++ return 0; ++ ++out: ++ if (host) { ++ if (host->irq) ++ free_irq(host->irq, host); ++ if (host->gpio_card_detect) { ++ free_irq(gpio_to_irq(host->gpio_card_detect), host); ++ gpio_free(host->gpio_card_detect); ++ } ++ if (host->gpio_write_protect) ++ gpio_free(host->gpio_write_protect); ++ if (host->base) ++ iounmap(host->base); ++ } ++ if (r) ++ release_resource(r); ++ if (mmc) ++ mmc_free_host(mmc); ++ ++ return ret; ++} ++ ++static int __exit mvsd_remove(struct platform_device *pdev) ++{ ++ struct mmc_host *mmc = platform_get_drvdata(pdev); ++ ++ if (mmc) { ++ struct mvsd_host *host = mmc_priv(mmc); ++ ++ if (host->gpio_card_detect) { ++ free_irq(gpio_to_irq(host->gpio_card_detect), host); ++ gpio_free(host->gpio_card_detect); ++ } ++ mmc_remove_host(mmc); ++ free_irq(host->irq, host); ++ if (host->gpio_write_protect) ++ gpio_free(host->gpio_write_protect); ++ del_timer_sync(&host->timer); ++ mvsd_power_down(host); ++ iounmap(host->base); ++ release_resource(host->res); ++ mmc_free_host(mmc); ++ } ++ platform_set_drvdata(pdev, NULL); ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int mvsd_suspend(struct platform_device *dev, pm_message_t state, ++ u32 level) ++{ ++ struct mmc_host *mmc = platform_get_drvdata(dev); ++ int ret = 0; ++ ++ if (mmc && level == SUSPEND_DISABLE) ++ ret = mmc_suspend_host(mmc, state); ++ ++ return ret; ++} ++ ++static int mvsd_resume(struct platform_device *dev, u32 level) ++{ ++ struct mmc_host *mmc = platform_dev_get_drvdata(dev); ++ int ret = 0; ++ ++ if (mmc && level == RESUME_ENABLE) ++ ret = mmc_resume_host(mmc); ++ ++ return ret; ++} ++#else ++#define mvsd_suspend NULL ++#define mvsd_resume NULL ++#endif ++ ++static struct platform_driver mvsd_driver = { ++ .remove = __exit_p(mvsd_remove), ++ .suspend = mvsd_suspend, ++ .resume = mvsd_resume, ++ .driver = { ++ .name = DRIVER_NAME, ++ }, ++}; ++ ++static int __init mvsd_init(void) ++{ ++ return platform_driver_probe(&mvsd_driver, mvsd_probe); ++} ++ ++static void __exit mvsd_exit(void) ++{ ++ platform_driver_unregister(&mvsd_driver); ++} ++ ++module_init(mvsd_init); ++module_exit(mvsd_exit); ++ ++/* maximum card clock frequency (default 50MHz) */ ++module_param(maxfreq, int, 0); ++ ++/* force PIO transfers all the time */ ++module_param(nodma, int, 0); ++ ++MODULE_AUTHOR("Maen Suleiman, Nicolas Pitre"); ++MODULE_DESCRIPTION("Marvell MMC,SD,SDIO Host Controller driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mmc/host/mvsdio.h b/drivers/mmc/host/mvsdio.h +new file mode 100644 +index 0000000..7d9727b +--- /dev/null ++++ b/drivers/mmc/host/mvsdio.h +@@ -0,0 +1,190 @@ ++/* ++ * Copyright (C) 2008 Marvell Semiconductors, All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __MVSDIO_H ++#define __MVSDIO_H ++ ++/* ++ * Clock rates ++ */ ++ ++#define MVSD_CLOCKRATE_MAX 50000000 ++#define MVSD_BASE_DIV_MAX 0x7ff ++ ++ ++/* ++ * Register offsets ++ */ ++ ++#define MVSD_SYS_ADDR_LOW 0x000 ++#define MVSD_SYS_ADDR_HI 0x004 ++#define MVSD_BLK_SIZE 0x008 ++#define MVSD_BLK_COUNT 0x00c ++#define MVSD_ARG_LOW 0x010 ++#define MVSD_ARG_HI 0x014 ++#define MVSD_XFER_MODE 0x018 ++#define MVSD_CMD 0x01c ++#define MVSD_RSP(i) (0x020 + ((i)<<2)) ++#define MVSD_RSP0 0x020 ++#define MVSD_RSP1 0x024 ++#define MVSD_RSP2 0x028 ++#define MVSD_RSP3 0x02c ++#define MVSD_RSP4 0x030 ++#define MVSD_RSP5 0x034 ++#define MVSD_RSP6 0x038 ++#define MVSD_RSP7 0x03c ++#define MVSD_FIFO 0x040 ++#define MVSD_RSP_CRC7 0x044 ++#define MVSD_HW_STATE 0x048 ++#define MVSD_HOST_CTRL 0x050 ++#define MVSD_BLK_GAP_CTRL 0x054 ++#define MVSD_CLK_CTRL 0x058 ++#define MVSD_SW_RESET 0x05c ++#define MVSD_NOR_INTR_STATUS 0x060 ++#define MVSD_ERR_INTR_STATUS 0x064 ++#define MVSD_NOR_STATUS_EN 0x068 ++#define MVSD_ERR_STATUS_EN 0x06c ++#define MVSD_NOR_INTR_EN 0x070 ++#define MVSD_ERR_INTR_EN 0x074 ++#define MVSD_AUTOCMD12_ERR_STATUS 0x078 ++#define MVSD_CURR_BYTE_LEFT 0x07c ++#define MVSD_CURR_BLK_LEFT 0x080 ++#define MVSD_AUTOCMD12_ARG_LOW 0x084 ++#define MVSD_AUTOCMD12_ARG_HI 0x088 ++#define MVSD_AUTOCMD12_CMD 0x08c ++#define MVSD_AUTO_RSP(i) (0x090 + ((i)<<2)) ++#define MVSD_AUTO_RSP0 0x090 ++#define MVSD_AUTO_RSP1 0x094 ++#define MVSD_AUTO_RSP2 0x098 ++#define MVSD_CLK_DIV 0x128 ++ ++#define MVSD_WINDOW_CTRL(i) (0x108 + ((i) << 3)) ++#define MVSD_WINDOW_BASE(i) (0x10c + ((i) << 3)) ++ ++ ++/* ++ * MVSD_CMD ++ */ ++ ++#define MVSD_CMD_RSP_NONE (0 << 0) ++#define MVSD_CMD_RSP_136 (1 << 0) ++#define MVSD_CMD_RSP_48 (2 << 0) ++#define MVSD_CMD_RSP_48BUSY (3 << 0) ++ ++#define MVSD_CMD_CHECK_DATACRC16 (1 << 2) ++#define MVSD_CMD_CHECK_CMDCRC (1 << 3) ++#define MVSD_CMD_INDX_CHECK (1 << 4) ++#define MVSD_CMD_DATA_PRESENT (1 << 5) ++#define MVSD_UNEXPECTED_RESP (1 << 7) ++#define MVSD_CMD_INDEX(x) ((x) << 8) ++ ++ ++/* ++ * MVSD_AUTOCMD12_CMD ++ */ ++ ++#define MVSD_AUTOCMD12_BUSY (1 << 0) ++#define MVSD_AUTOCMD12_INDX_CHECK (1 << 1) ++#define MVSD_AUTOCMD12_INDEX(x) ((x) << 8) ++ ++/* ++ * MVSD_XFER_MODE ++ */ ++ ++#define MVSD_XFER_MODE_WR_DATA_START (1 << 0) ++#define MVSD_XFER_MODE_HW_WR_DATA_EN (1 << 1) ++#define MVSD_XFER_MODE_AUTO_CMD12 (1 << 2) ++#define MVSD_XFER_MODE_INT_CHK_EN (1 << 3) ++#define MVSD_XFER_MODE_TO_HOST (1 << 4) ++#define MVSD_XFER_MODE_STOP_CLK (1 << 5) ++#define MVSD_XFER_MODE_PIO (1 << 6) ++ ++ ++/* ++ * MVSD_HOST_CTRL ++ */ ++ ++#define MVSD_HOST_CTRL_PUSH_PULL_EN (1 << 0) ++ ++#define MVSD_HOST_CTRL_CARD_TYPE_MEM_ONLY (0 << 1) ++#define MVSD_HOST_CTRL_CARD_TYPE_IO_ONLY (1 << 1) ++#define MVSD_HOST_CTRL_CARD_TYPE_IO_MEM_COMBO (2 << 1) ++#define MVSD_HOST_CTRL_CARD_TYPE_IO_MMC (3 << 1) ++#define MVSD_HOST_CTRL_CARD_TYPE_MASK (3 << 1) ++ ++#define MVSD_HOST_CTRL_BIG_ENDIAN (1 << 3) ++#define MVSD_HOST_CTRL_LSB_FIRST (1 << 4) ++#define MVSD_HOST_CTRL_DATA_WIDTH_4_BITS (1 << 9) ++#define MVSD_HOST_CTRL_HI_SPEED_EN (1 << 10) ++ ++#define MVSD_HOST_CTRL_TMOUT_MAX 0xf ++#define MVSD_HOST_CTRL_TMOUT_MASK (0xf << 11) ++#define MVSD_HOST_CTRL_TMOUT(x) ((x) << 11) ++#define MVSD_HOST_CTRL_TMOUT_EN (1 << 15) ++ ++ ++/* ++ * MVSD_SW_RESET ++ */ ++ ++#define MVSD_SW_RESET_NOW (1 << 8) ++ ++ ++/* ++ * Normal interrupt status bits ++ */ ++ ++#define MVSD_NOR_CMD_DONE (1 << 0) ++#define MVSD_NOR_XFER_DONE (1 << 1) ++#define MVSD_NOR_BLK_GAP_EVT (1 << 2) ++#define MVSD_NOR_DMA_DONE (1 << 3) ++#define MVSD_NOR_TX_AVAIL (1 << 4) ++#define MVSD_NOR_RX_READY (1 << 5) ++#define MVSD_NOR_CARD_INT (1 << 8) ++#define MVSD_NOR_READ_WAIT_ON (1 << 9) ++#define MVSD_NOR_RX_FIFO_8W (1 << 10) ++#define MVSD_NOR_TX_FIFO_8W (1 << 11) ++#define MVSD_NOR_SUSPEND_ON (1 << 12) ++#define MVSD_NOR_AUTOCMD12_DONE (1 << 13) ++#define MVSD_NOR_UNEXP_RSP (1 << 14) ++#define MVSD_NOR_ERROR (1 << 15) ++ ++ ++/* ++ * Error status bits ++ */ ++ ++#define MVSD_ERR_CMD_TIMEOUT (1 << 0) ++#define MVSD_ERR_CMD_CRC (1 << 1) ++#define MVSD_ERR_CMD_ENDBIT (1 << 2) ++#define MVSD_ERR_CMD_INDEX (1 << 3) ++#define MVSD_ERR_DATA_TIMEOUT (1 << 4) ++#define MVSD_ERR_DATA_CRC (1 << 5) ++#define MVSD_ERR_DATA_ENDBIT (1 << 6) ++#define MVSD_ERR_AUTOCMD12 (1 << 8) ++#define MVSD_ERR_CMD_STARTBIT (1 << 9) ++#define MVSD_ERR_XFER_SIZE (1 << 10) ++#define MVSD_ERR_RESP_T_BIT (1 << 11) ++#define MVSD_ERR_CRC_ENDBIT (1 << 12) ++#define MVSD_ERR_CRC_STARTBIT (1 << 13) ++#define MVSD_ERR_CRC_STATUS (1 << 14) ++ ++ ++/* ++ * CMD12 error status bits ++ */ ++ ++#define MVSD_AUTOCMD12_ERR_NOTEXE (1 << 0) ++#define MVSD_AUTOCMD12_ERR_TIMEOUT (1 << 1) ++#define MVSD_AUTOCMD12_ERR_CRC (1 << 2) ++#define MVSD_AUTOCMD12_ERR_ENDBIT (1 << 3) ++#define MVSD_AUTOCMD12_ERR_INDEX (1 << 4) ++#define MVSD_AUTOCMD12_ERR_RESP_T_BIT (1 << 5) ++#define MVSD_AUTOCMD12_ERR_RESP_STARTBIT (1 << 6) ++ ++#endif diff --git a/debian/patches/features/arm/orion-gpio-input-output.patch b/debian/patches/features/arm/orion-gpio-input-output.patch new file mode 100644 index 000000000..61673098e --- /dev/null +++ b/debian/patches/features/arm/orion-gpio-input-output.patch @@ -0,0 +1,110 @@ +From: Nicolas Pitre +Date: Mon, 2 Feb 2009 20:27:55 +0000 (-0500) +Subject: [ARM] Orion: make gpio /input/output validation separate +X-Git-Url: http://git.marvell.com/?p=orion.git;a=commitdiff_plain;h=28d27cf4ce8378180eda32aa7d8e778c9e72a54f + +[ARM] Orion: make gpio /input/output validation separate + +Especially on Kirkwood, a couple GPIOs are actually only output capable. +Let's separate the ability to configure a GPIO as input or output to +accommodate this restriction. + +Signed-off-by: Nicolas Pitre +--- + +diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c +index 0d12c21..32eb9e3 100644 +--- a/arch/arm/plat-orion/gpio.c ++++ b/arch/arm/plat-orion/gpio.c +@@ -19,7 +19,8 @@ + + static DEFINE_SPINLOCK(gpio_lock); + static const char *gpio_label[GPIO_MAX]; /* non null for allocated GPIOs */ +-static unsigned long gpio_valid[BITS_TO_LONGS(GPIO_MAX)]; ++static unsigned long gpio_valid_input[BITS_TO_LONGS(GPIO_MAX)]; ++static unsigned long gpio_valid_output[BITS_TO_LONGS(GPIO_MAX)]; + + static inline void __set_direction(unsigned pin, int input) + { +@@ -53,7 +54,7 @@ int gpio_direction_input(unsigned pin) + { + unsigned long flags; + +- if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { ++ if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid_input)) { + pr_debug("%s: invalid GPIO %d\n", __func__, pin); + return -EINVAL; + } +@@ -83,7 +84,7 @@ int gpio_direction_output(unsigned pin, int value) + unsigned long flags; + u32 u; + +- if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { ++ if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid_output)) { + pr_debug("%s: invalid GPIO %d\n", __func__, pin); + return -EINVAL; + } +@@ -161,7 +162,9 @@ int gpio_request(unsigned pin, const char *label) + unsigned long flags; + int ret; + +- if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { ++ if (pin >= GPIO_MAX || ++ !(test_bit(pin, gpio_valid_input) || ++ test_bit(pin, gpio_valid_output))) { + pr_debug("%s: invalid GPIO %d\n", __func__, pin); + return -EINVAL; + } +@@ -183,7 +186,9 @@ EXPORT_SYMBOL(gpio_request); + + void gpio_free(unsigned pin) + { +- if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { ++ if (pin >= GPIO_MAX || ++ !(test_bit(pin, gpio_valid_input) || ++ test_bit(pin, gpio_valid_output))) { + pr_debug("%s: invalid GPIO %d\n", __func__, pin); + return; + } +@@ -208,12 +213,18 @@ void __init orion_gpio_set_unused(unsigned pin) + __set_direction(pin, 0); + } + +-void __init orion_gpio_set_valid(unsigned pin, int valid) ++void __init orion_gpio_set_valid(unsigned pin, int mode) + { +- if (valid) +- __set_bit(pin, gpio_valid); ++ if (mode == 1) ++ mode = GPIO_INPUT_OK | GPIO_OUTPUT_OK; ++ if (mode & GPIO_INPUT_OK) ++ __set_bit(pin, gpio_valid_input); + else +- __clear_bit(pin, gpio_valid); ++ __clear_bit(pin, gpio_valid_input); ++ if (mode & GPIO_OUTPUT_OK) ++ __set_bit(pin, gpio_valid_output); ++ else ++ __clear_bit(pin, gpio_valid_output); + } + + void orion_gpio_set_blink(unsigned pin, int blink) +diff --git a/arch/arm/plat-orion/include/plat/gpio.h b/arch/arm/plat-orion/include/plat/gpio.h +index ec743e8..33f6c6a 100644 +--- a/arch/arm/plat-orion/include/plat/gpio.h ++++ b/arch/arm/plat-orion/include/plat/gpio.h +@@ -25,9 +25,13 @@ void gpio_set_value(unsigned pin, int value); + * Orion-specific GPIO API extensions. + */ + void orion_gpio_set_unused(unsigned pin); +-void orion_gpio_set_valid(unsigned pin, int valid); + void orion_gpio_set_blink(unsigned pin, int blink); + ++#define GPIO_BIDI_OK (1 << 0) ++#define GPIO_INPUT_OK (1 << 1) ++#define GPIO_OUTPUT_OK (1 << 2) ++void orion_gpio_set_valid(unsigned pin, int mode); ++ + /* + * GPIO interrupt handling. + */ diff --git a/debian/patches/series/1~experimental.1 b/debian/patches/series/1~experimental.1 index 2bde4d5e7..0dd61b781 100644 --- a/debian/patches/series/1~experimental.1 +++ b/debian/patches/series/1~experimental.1 @@ -26,3 +26,12 @@ + bugfix/powerpc/lpar-console.patch #+ bugfix/all/wireless-regulatory-default-EU.patch + features/sparc/video-sunxvr500-intergraph.patch +# Kirkwood support, will be in 2.6.30 ++ features/arm/orion-gpio-input-output.patch ++ features/arm/kw-mpp.patch ++ features/arm/mv-sdio.patch ++ features/arm/kw-register-sdio.patch ++ features/arm/kw-register-internal-devices.patch ++ features/arm/kw-sheevaplug.patch ++ features/arm/kw-sheevaplug-usb-power.patch ++ features/arm/kw-sheevaplug-led.patch