diff options
author | Philippe Langlais <philippe.langlais@linaro.org> | 2012-03-19 09:23:29 +0100 |
---|---|---|
committer | Philippe Langlais <philippe.langlais@linaro.org> | 2012-03-19 09:23:29 +0100 |
commit | c9f2b2b3e3abea48315a2e2b7f5d2d0c94c9985a (patch) | |
tree | 0807dd9623f8364f61fb113c92cbba69dee41ea0 /arch | |
parent | 7446550602a61a55db3255d09ec207059db6ddb6 (diff) | |
parent | dc84273d06bd9a78f951ac56509df64f3581996b (diff) |
Merge topic branch 'storage-mmc' into integration-linux-ux500-3.3
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-ux500/board-mop500-sdi.c | 159 | ||||
-rw-r--r-- | arch/arm/mach-ux500/board-u5500-sdi.c | 232 |
2 files changed, 301 insertions, 90 deletions
diff --git a/arch/arm/mach-ux500/board-mop500-sdi.c b/arch/arm/mach-ux500/board-mop500-sdi.c index ae484d6b74e..118d29b863f 100644 --- a/arch/arm/mach-ux500/board-mop500-sdi.c +++ b/arch/arm/mach-ux500/board-mop500-sdi.c @@ -11,6 +11,7 @@ #include <linux/amba/mmci.h> #include <linux/mmc/host.h> #include <linux/platform_device.h> +#include <linux/delay.h> #include <asm/mach-types.h> #include <plat/ste_dma40.h> @@ -31,72 +32,101 @@ * SDI 0 (MicroSD slot) */ -/* MMCIPOWER bits */ -#define MCI_DATA2DIREN (1 << 2) -#define MCI_CMDDIREN (1 << 3) -#define MCI_DATA0DIREN (1 << 4) -#define MCI_DATA31DIREN (1 << 5) -#define MCI_FBCLKEN (1 << 7) - /* GPIO pins used by the sdi0 level shifter */ static int sdi0_en = -1; static int sdi0_vsel = -1; -static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd, - unsigned char power_mode) +static int mop500_sdi0_ios_handler(struct device *dev, struct mmc_ios *ios) { - switch (power_mode) { + static unsigned char power_mode = MMC_POWER_ON; + static unsigned char signal_voltage = MMC_SIGNAL_VOLTAGE_330; + + if (signal_voltage == ios->signal_voltage) + goto do_power; + + /* + * We need to re-init the levelshifter when switching I/O voltage level. + * Max discharge time according to ST6G3244ME spec is 1 ms. + */ + if (power_mode == MMC_POWER_ON) { + power_mode = MMC_POWER_OFF; + gpio_direction_output(sdi0_en, 0); + msleep(1); + } + + switch (ios->signal_voltage) { + case MMC_SIGNAL_VOLTAGE_330: + gpio_direction_output(sdi0_vsel, 0); + break; + case MMC_SIGNAL_VOLTAGE_180: + gpio_direction_output(sdi0_vsel, 1); + break; + default: + pr_warning("Non supported signal voltage for levelshifter.\n"); + break; + } + + signal_voltage = ios->signal_voltage; + +do_power: + if (power_mode == ios->power_mode) + return 0; + + switch (ios->power_mode) { case MMC_POWER_UP: + break; case MMC_POWER_ON: - /* - * Level shifter voltage should depend on vdd to when deciding - * on either 1.8V or 2.9V. Once the decision has been made the - * level shifter must be disabled and re-enabled with a changed - * select signal in order to switch the voltage. Since there is - * no framework support yet for indicating 1.8V in vdd, use the - * default 2.9V. - */ - gpio_direction_output(sdi0_vsel, 0); gpio_direction_output(sdi0_en, 1); + /* Max settling time according to ST6G3244ME spec is 100 us. */ + udelay(100); break; case MMC_POWER_OFF: - gpio_direction_output(sdi0_vsel, 0); gpio_direction_output(sdi0_en, 0); break; } - return MCI_FBCLKEN | MCI_CMDDIREN | MCI_DATA0DIREN | - MCI_DATA2DIREN | MCI_DATA31DIREN; + power_mode = ios->power_mode; + + return 0; } #ifdef CONFIG_STE_DMA40 struct stedma40_chan_cfg mop500_sdi0_dma_cfg_rx = { .mode = STEDMA40_MODE_LOGICAL, .dir = STEDMA40_PERIPH_TO_MEM, - .src_dev_type = DB8500_DMA_DEV29_SD_MM0_RX, + .src_dev_type = DB8500_DMA_DEV1_SD_MMC0_RX, .dst_dev_type = STEDMA40_DEV_DST_MEMORY, .src_info.data_width = STEDMA40_WORD_WIDTH, .dst_info.data_width = STEDMA40_WORD_WIDTH, + .use_fixed_channel = true, + .phy_channel = 0, }; static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = { .mode = STEDMA40_MODE_LOGICAL, .dir = STEDMA40_MEM_TO_PERIPH, .src_dev_type = STEDMA40_DEV_SRC_MEMORY, - .dst_dev_type = DB8500_DMA_DEV29_SD_MM0_TX, + .dst_dev_type = DB8500_DMA_DEV1_SD_MMC0_TX, .src_info.data_width = STEDMA40_WORD_WIDTH, .dst_info.data_width = STEDMA40_WORD_WIDTH, + .use_fixed_channel = true, + .phy_channel = 0, }; #endif static struct mmci_platform_data mop500_sdi0_data = { - .vdd_handler = mop500_sdi0_vdd_handler, - .ocr_mask = MMC_VDD_29_30, + .ios_handler = mop500_sdi0_ios_handler, .f_max = 50000000, .capabilities = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | - MMC_CAP_MMC_HIGHSPEED, + MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_UHS_SDR12 | + MMC_CAP_UHS_SDR25, .gpio_wp = -1, + .sigdir = MCI_ST_FBCLKEN | + MCI_ST_CMDDIREN | + MCI_ST_DATA0DIREN | + MCI_ST_DATA2DIREN, #ifdef CONFIG_STE_DMA40 .dma_filter = stedma40_filter, .dma_rx_param = &mop500_sdi0_dma_cfg_rx, @@ -104,36 +134,6 @@ static struct mmci_platform_data mop500_sdi0_data = { #endif }; -static void sdi0_configure(void) -{ - int ret; - - ret = gpio_request(sdi0_en, "level shifter enable"); - if (!ret) - ret = gpio_request(sdi0_vsel, - "level shifter 1v8-3v select"); - - if (ret) { - pr_warning("unable to config sdi0 gpios for level shifter.\n"); - return; - } - - /* Select the default 2.9V and enable level shifter */ - gpio_direction_output(sdi0_vsel, 0); - gpio_direction_output(sdi0_en, 1); - - /* Add the device, force v2 to subrevision 1 */ - db8500_add_sdi0(&mop500_sdi0_data, U8500_SDI_V2_PERIPHID); -} - -void mop500_sdi_tc35892_init(void) -{ - mop500_sdi0_data.gpio_cd = GPIO_SDMMC_CD; - sdi0_en = GPIO_SDMMC_EN; - sdi0_vsel = GPIO_SDMMC_1V8_3V_SEL; - sdi0_configure(); -} - /* * SDI1 (SDIO WLAN) */ @@ -170,10 +170,40 @@ static struct mmci_platform_data mop500_sdi1_data = { #endif }; +static void sdi0_sdi1_configure(void) +{ + int ret; + + ret = gpio_request(sdi0_en, "level shifter enable"); + if (!ret) + ret = gpio_request(sdi0_vsel, + "level shifter 1v8-3v select"); + + if (ret) { + pr_warning("unable to config sdi0 gpios for level shifter.\n"); + return; + } + + /* Select the default 2.9V and enable level shifter */ + gpio_direction_output(sdi0_vsel, 0); + gpio_direction_output(sdi0_en, 1); + + /* Add the device, force v2 to subrevision 1 */ + db8500_add_sdi0(&mop500_sdi0_data, U8500_SDI_V2_PERIPHID); + db8500_add_sdi1(&mop500_sdi1_data, U8500_SDI_V2_PERIPHID); +} + +void mop500_sdi_tc35892_init(void) +{ + mop500_sdi0_data.gpio_cd = GPIO_SDMMC_CD; + sdi0_en = GPIO_SDMMC_EN; + sdi0_vsel = GPIO_SDMMC_1V8_3V_SEL; + sdi0_sdi1_configure(); +} + /* * SDI 2 (POP eMMC, not on DB8500ed) */ - #ifdef CONFIG_STE_DMA40 struct stedma40_chan_cfg mop500_sdi2_dma_cfg_rx = { .mode = STEDMA40_MODE_LOGICAL, @@ -198,7 +228,9 @@ static struct mmci_platform_data mop500_sdi2_data = { .ocr_mask = MMC_VDD_165_195, .f_max = 50000000, .capabilities = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA | - MMC_CAP_MMC_HIGHSPEED, + MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_ERASE, + .capabilities2 = MMC_CAP2_NO_SLEEP_CMD, .gpio_cd = -1, .gpio_wp = -1, #ifdef CONFIG_STE_DMA40 @@ -233,7 +265,6 @@ static struct stedma40_chan_cfg mop500_sdi4_dma_cfg_tx = { #endif static struct mmci_platform_data mop500_sdi4_data = { - .ocr_mask = MMC_VDD_29_30, .f_max = 50000000, .capabilities = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA | MMC_CAP_MMC_HIGHSPEED, @@ -253,7 +284,7 @@ void __init mop500_sdi_init(void) /* On-board eMMC */ db8500_add_sdi4(&mop500_sdi4_data, U8500_SDI_V2_PERIPHID); /* - * On boards with the TC35892 GPIO expander, sdi0 will finally + * On boards with the TC35892 GPIO expander, sdi0 and sdi1 will finally * be added when the TC35892 initializes and calls * mop500_sdi_tc35892_init() above. */ @@ -270,7 +301,7 @@ void __init snowball_sdi_init(void) mop500_sdi0_data.cd_invert = true; sdi0_en = SNOWBALL_SDMMC_EN_GPIO; sdi0_vsel = SNOWBALL_SDMMC_1V8_3V_GPIO; - sdi0_configure(); + sdi0_sdi1_configure(); } void __init hrefv60_sdi_init(void) @@ -283,7 +314,5 @@ void __init hrefv60_sdi_init(void) mop500_sdi0_data.gpio_cd = HREFV60_SDMMC_CD_GPIO; sdi0_en = HREFV60_SDMMC_EN_GPIO; sdi0_vsel = HREFV60_SDMMC_1V8_3V_GPIO; - sdi0_configure(); - /* WLAN SDIO channel */ - db8500_add_sdi1(&mop500_sdi1_data, U8500_SDI_V2_PERIPHID); + sdi0_sdi1_configure(); } diff --git a/arch/arm/mach-ux500/board-u5500-sdi.c b/arch/arm/mach-ux500/board-u5500-sdi.c index 63c3f8058ff..101a69f2fbc 100644 --- a/arch/arm/mach-ux500/board-u5500-sdi.c +++ b/arch/arm/mach-ux500/board-u5500-sdi.c @@ -5,34 +5,28 @@ * License terms: GNU General Public License (GPL) version 2 */ +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/amba/bus.h> #include <linux/amba/mmci.h> #include <linux/mmc/host.h> +#include <linux/platform_device.h> +#include <linux/delay.h> -#include <plat/pincfg.h> -#include <plat/gpio-nomadik.h> -#include <mach/db5500-regs.h> +#include <asm/mach-types.h> #include <plat/ste_dma40.h> +#include <mach/devices.h> +#include <mach/hardware.h> +#include <mach/ste-dma40-db5500.h> -#include "pins-db5500.h" #include "devices-db5500.h" -#include "ste-dma40-db5500.h" - -static pin_cfg_t u5500_sdi_pins[] = { - /* SDI0 (POP eMMC) */ - GPIO5_MC0_DAT0 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO6_MC0_DAT1 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO7_MC0_DAT2 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO8_MC0_DAT3 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO9_MC0_DAT4 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO10_MC0_DAT5 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO11_MC0_DAT6 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO12_MC0_DAT7 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO13_MC0_CMD | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO14_MC0_CLK | PIN_DIR_OUTPUT | PIN_VAL_LOW, -}; +#include "board-u5500.h" +/* + * SDI 0 (eMMC) + */ #ifdef CONFIG_STE_DMA40 -struct stedma40_chan_cfg u5500_sdi0_dma_cfg_rx = { +static struct stedma40_chan_cfg sdi0_dma_cfg_rx = { .mode = STEDMA40_MODE_LOGICAL, .dir = STEDMA40_PERIPH_TO_MEM, .src_dev_type = DB5500_DMA_DEV24_SDMMC0_RX, @@ -41,7 +35,7 @@ struct stedma40_chan_cfg u5500_sdi0_dma_cfg_rx = { .dst_info.data_width = STEDMA40_WORD_WIDTH, }; -static struct stedma40_chan_cfg u5500_sdi0_dma_cfg_tx = { +static struct stedma40_chan_cfg sdi0_dma_cfg_tx = { .mode = STEDMA40_MODE_LOGICAL, .dir = STEDMA40_MEM_TO_PERIPH, .src_dev_type = STEDMA40_DEV_SRC_MEMORY, @@ -57,18 +51,206 @@ static struct mmci_platform_data u5500_sdi0_data = { .capabilities = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA | MMC_CAP_MMC_HIGHSPEED, + .capabilities2 = MMC_CAP2_NO_SLEEP_CMD, .gpio_cd = -1, .gpio_wp = -1, #ifdef CONFIG_STE_DMA40 .dma_filter = stedma40_filter, - .dma_rx_param = &u5500_sdi0_dma_cfg_rx, - .dma_tx_param = &u5500_sdi0_dma_cfg_tx, + .dma_rx_param = &sdi0_dma_cfg_rx, + .dma_tx_param = &sdi0_dma_cfg_tx, +#endif +}; + +/* + * SDI 1 (MicroSD slot) + */ + +static int u5500_sdi1_ios_handler(struct device *dev, struct mmc_ios *ios) +{ + static int power_mode = -1; + + if (power_mode == ios->power_mode) + return 0; + + switch (ios->power_mode) { + case MMC_POWER_UP: + break; + case MMC_POWER_ON: + /* + * Level shifter voltage should depend on vdd to when deciding + * on either 1.8V or 2.9V. Once the decision has been made the + * level shifter must be disabled and re-enabled with a changed + * select signal in order to switch the voltage. Since there is + * no framework support yet for indicating 1.8V in vdd, use the + * default 2.9V. + */ + gpio_set_value_cansleep(GPIO_MMC_CARD_CTRL, 1); + udelay(100); + break; + case MMC_POWER_OFF: + gpio_set_value_cansleep(GPIO_MMC_CARD_CTRL, 0); + break; + } + + power_mode = ios->power_mode; + return 0; +} + +#ifdef CONFIG_STE_DMA40 +static struct stedma40_chan_cfg sdi1_dma_cfg_rx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB5500_DMA_DEV34_SDMMC1_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg sdi1_dma_cfg_tx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB5500_DMA_DEV34_SDMMC1_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; +#endif + +static struct mmci_platform_data u5500_sdi1_data = { + .ios_handler = u5500_sdi1_ios_handler, + .ocr_mask = MMC_VDD_29_30, + .f_max = 50000000, + .capabilities = MMC_CAP_4_BIT_DATA | + MMC_CAP_SD_HIGHSPEED | + MMC_CAP_MMC_HIGHSPEED, + .gpio_cd = GPIO_SDMMC_CD, + .gpio_wp = -1, + .cd_invert = true, +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &sdi1_dma_cfg_rx, + .dma_tx_param = &sdi1_dma_cfg_tx, #endif }; +/* + * SDI2 (EMMC2) + */ + +static struct stedma40_chan_cfg sdi2_dma_cfg_rx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB5500_DMA_DEV26_SDMMC2_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg sdi2_dma_cfg_tx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB5500_DMA_DEV26_SDMMC2_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct mmci_platform_data u5500_sdi2_data = { + .ocr_mask = MMC_VDD_165_195, + .f_max = 50000000, + .capabilities = MMC_CAP_4_BIT_DATA | + MMC_CAP_8_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED, + .capabilities2 = MMC_CAP2_NO_SLEEP_CMD, + .gpio_cd = -1, + .gpio_wp = -1, +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &sdi2_dma_cfg_rx, + .dma_tx_param = &sdi2_dma_cfg_tx, +#endif +}; + +/* + * SDI 3 (SDIO WLAN) + */ +#ifdef SDIO_DMA_ON +#ifdef CONFIG_STE_DMA40 +static struct stedma40_chan_cfg sdi3_dma_cfg_rx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB5500_DMA_DEV27_SDMMC3_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg sdi3_dma_cfg_tx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB5500_DMA_DEV27_SDMMC3_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; +#endif +#endif + +static struct mmci_platform_data u5500_sdi3_data = { + .ocr_mask = MMC_VDD_29_30, + .f_max = 50000000, + .capabilities = MMC_CAP_4_BIT_DATA, + .gpio_cd = -1, + .gpio_wp = -1, +#ifdef SDIO_DMA_ON +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &sdi3_dma_cfg_rx, + .dma_tx_param = &sdi3_dma_cfg_tx, +#endif +#endif +}; + +static void sdi1_configure(void) +{ + int pin[2]; + int ret; + + /* Level-shifter GPIOs */ + pin[0] = GPIO_MMC_CARD_CTRL; + pin[1] = GPIO_MMC_CARD_VSEL; + + ret = gpio_request(pin[0], "MMC_CARD_CTRL"); + if (!ret) + ret = gpio_request(pin[1], "MMC_CARD_VSEL"); + + if (ret) { + pr_warning("unable to config sdi0 gpios for level shifter.\n"); + return; + } + /* Select the default 2.9V and eanble level shifter */ + gpio_direction_output(pin[0], 1); + gpio_direction_output(pin[1], 0); +} + void __init u5500_sdi_init(void) { - nmk_config_pins(u5500_sdi_pins, ARRAY_SIZE(u5500_sdi_pins)); + u32 periphid = 0x10480180; + + /* + * Fix me in 5500 v2.1 + * Dynamic detection of booting device by reading + * ROM debug register from BACKUP RAM and register the + * corresponding EMMC. + * This is done due to wrong configuration of MMC0 clock + * in ROM code for u5500 v2. + */ + if (u5500_get_boot_mmc() == 2) + db5500_add_sdi2(&u5500_sdi2_data, periphid); + else + db5500_add_sdi0(&u5500_sdi0_data, periphid); - db5500_add_sdi0(&u5500_sdi0_data); + sdi1_configure(); + db5500_add_sdi1(&u5500_sdi1_data, periphid); + db5500_add_sdi3(&u5500_sdi3_data, periphid); } |