提交 6b2a4f7a 编写于 作者: L Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (26 commits)
  mmc: SDHI should depend on SUPERH || ARCH_SHMOBILE
  mmc: tmio_mmc: Move some defines into a shared header
  mmc: tmio: support aggressive clock gating
  mmc: tmio: fix power-mode interpretation
  mmc: tmio: remove work-around for unmasked SDIO interrupts
  sh: fix SDHI IO address-range
  ARM: mach-shmobile: fix SDHI IO address-range
  mmc: tmio: only access registers above 0xff, if available
  mfd: remove now redundant sh_mobile_sdhi.h header
  sh: convert boards to use linux/mmc/sh_mobile_sdhi.h
  ARM: mach-shmobile: convert boards to use linux/mmc/sh_mobile_sdhi.h
  mmc: tmio: convert the SDHI MMC driver from MFD to a platform driver
  sh: ecovec: use the CONFIG_MMC_TMIO symbols instead of MFD
  mmc: tmio: split core functionality, DMA and MFD glue
  mmc: tmio: use PIO for short transfers
  mmc: tmio-mmc: Improve DMA stability on sh-mobile
  mmc: fix mmc_app_send_scr() for dma transfer
  mmc: sdhci-esdhc: enable esdhc on imx53
  mmc: sdhci-esdhc: use writel/readl as general APIs
  mmc: sdhci: add the abort CMDTYPE bits definition
  ...
...@@ -24,9 +24,9 @@ ...@@ -24,9 +24,9 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/mfd/tmio.h> #include <linux/mfd/tmio.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
...@@ -312,7 +312,7 @@ static struct resource sdhi0_resources[] = { ...@@ -312,7 +312,7 @@ static struct resource sdhi0_resources[] = {
[0] = { [0] = {
.name = "SDHI0", .name = "SDHI0",
.start = 0xe6850000, .start = 0xe6850000,
.end = 0xe68501ff, .end = 0xe68500ff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { [1] = {
...@@ -345,7 +345,7 @@ static struct resource sdhi1_resources[] = { ...@@ -345,7 +345,7 @@ static struct resource sdhi1_resources[] = {
[0] = { [0] = {
.name = "SDHI1", .name = "SDHI1",
.start = 0xe6860000, .start = 0xe6860000,
.end = 0xe68601ff, .end = 0xe68600ff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { [1] = {
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/input/sh_keysc.h> #include <linux/input/sh_keysc.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mfd/sh_mobile_sdhi.h> #include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <mach/sh7377.h> #include <mach/sh7377.h>
#include <mach/common.h> #include <mach/common.h>
...@@ -205,7 +205,7 @@ static struct resource sdhi0_resources[] = { ...@@ -205,7 +205,7 @@ static struct resource sdhi0_resources[] = {
[0] = { [0] = {
.name = "SDHI0", .name = "SDHI0",
.start = 0xe6d50000, .start = 0xe6d50000,
.end = 0xe6d501ff, .end = 0xe6d50nff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { [1] = {
...@@ -232,7 +232,7 @@ static struct resource sdhi1_resources[] = { ...@@ -232,7 +232,7 @@ static struct resource sdhi1_resources[] = {
[0] = { [0] = {
.name = "SDHI1", .name = "SDHI1",
.start = 0xe6d60000, .start = 0xe6d60000,
.end = 0xe6d601ff, .end = 0xe6d600ff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { [1] = {
......
...@@ -32,10 +32,10 @@ ...@@ -32,10 +32,10 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/mfd/tmio.h> #include <linux/mfd/tmio.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/sh_mmcif.h> #include <linux/mmc/sh_mmcif.h>
#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
...@@ -690,7 +690,7 @@ static struct resource sdhi0_resources[] = { ...@@ -690,7 +690,7 @@ static struct resource sdhi0_resources[] = {
[0] = { [0] = {
.name = "SDHI0", .name = "SDHI0",
.start = 0xe6850000, .start = 0xe6850000,
.end = 0xe68501ff, .end = 0xe68500ff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { [1] = {
...@@ -725,7 +725,7 @@ static struct resource sdhi1_resources[] = { ...@@ -725,7 +725,7 @@ static struct resource sdhi1_resources[] = {
[0] = { [0] = {
.name = "SDHI1", .name = "SDHI1",
.start = 0xe6860000, .start = 0xe6860000,
.end = 0xe68601ff, .end = 0xe68600ff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { [1] = {
...@@ -768,7 +768,7 @@ static struct resource sdhi2_resources[] = { ...@@ -768,7 +768,7 @@ static struct resource sdhi2_resources[] = {
[0] = { [0] = {
.name = "SDHI2", .name = "SDHI2",
.start = 0xe6870000, .start = 0xe6870000,
.end = 0xe68701ff, .end = 0xe68700ff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { [1] = {
......
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
#include <linux/mtd/sh_flctl.h> #include <linux/mtd/sh_flctl.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -423,7 +423,7 @@ static struct resource sdhi0_cn3_resources[] = { ...@@ -423,7 +423,7 @@ static struct resource sdhi0_cn3_resources[] = {
[0] = { [0] = {
.name = "SDHI0", .name = "SDHI0",
.start = 0x04ce0000, .start = 0x04ce0000,
.end = 0x04ce01ff, .end = 0x04ce00ff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { [1] = {
...@@ -453,7 +453,7 @@ static struct resource sdhi1_cn7_resources[] = { ...@@ -453,7 +453,7 @@ static struct resource sdhi1_cn7_resources[] = {
[0] = { [0] = {
.name = "SDHI1", .name = "SDHI1",
.start = 0x04cf0000, .start = 0x04cf0000,
.end = 0x04cf01ff, .end = 0x04cf00ff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { [1] = {
......
...@@ -11,9 +11,9 @@ ...@@ -11,9 +11,9 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/sh_mmcif.h> #include <linux/mmc/sh_mmcif.h>
#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -464,7 +464,7 @@ static struct i2c_board_info ts_i2c_clients = { ...@@ -464,7 +464,7 @@ static struct i2c_board_info ts_i2c_clients = {
.irq = IRQ0, .irq = IRQ0,
}; };
#ifdef CONFIG_MFD_SH_MOBILE_SDHI #if defined(CONFIG_MMC_TMIO) || defined(CONFIG_MMC_TMIO_MODULE)
/* SDHI0 */ /* SDHI0 */
static void sdhi0_set_pwr(struct platform_device *pdev, int state) static void sdhi0_set_pwr(struct platform_device *pdev, int state)
{ {
...@@ -482,7 +482,7 @@ static struct resource sdhi0_resources[] = { ...@@ -482,7 +482,7 @@ static struct resource sdhi0_resources[] = {
[0] = { [0] = {
.name = "SDHI0", .name = "SDHI0",
.start = 0x04ce0000, .start = 0x04ce0000,
.end = 0x04ce01ff, .end = 0x04ce00ff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { [1] = {
...@@ -522,7 +522,7 @@ static struct resource sdhi1_resources[] = { ...@@ -522,7 +522,7 @@ static struct resource sdhi1_resources[] = {
[0] = { [0] = {
.name = "SDHI1", .name = "SDHI1",
.start = 0x04cf0000, .start = 0x04cf0000,
.end = 0x04cf01ff, .end = 0x04cf00ff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { [1] = {
...@@ -880,7 +880,7 @@ static struct platform_device *ecovec_devices[] __initdata = { ...@@ -880,7 +880,7 @@ static struct platform_device *ecovec_devices[] __initdata = {
&ceu0_device, &ceu0_device,
&ceu1_device, &ceu1_device,
&keysc_device, &keysc_device,
#ifdef CONFIG_MFD_SH_MOBILE_SDHI #if defined(CONFIG_MMC_TMIO) || defined(CONFIG_MMC_TMIO_MODULE)
&sdhi0_device, &sdhi0_device,
#if !defined(CONFIG_MMC_SH_MMCIF) #if !defined(CONFIG_MMC_SH_MMCIF)
&sdhi1_device, &sdhi1_device,
...@@ -1162,7 +1162,7 @@ static int __init arch_setup(void) ...@@ -1162,7 +1162,7 @@ static int __init arch_setup(void)
gpio_direction_input(GPIO_PTR5); gpio_direction_input(GPIO_PTR5);
gpio_direction_input(GPIO_PTR6); gpio_direction_input(GPIO_PTR6);
#ifdef CONFIG_MFD_SH_MOBILE_SDHI #if defined(CONFIG_MMC_TMIO) || defined(CONFIG_MMC_TMIO_MODULE)
/* enable SDHI0 on CN11 (needs DS2.4 set to ON) */ /* enable SDHI0 on CN11 (needs DS2.4 set to ON) */
gpio_request(GPIO_FN_SDHI0CD, NULL); gpio_request(GPIO_FN_SDHI0CD, NULL);
gpio_request(GPIO_FN_SDHI0WP, NULL); gpio_request(GPIO_FN_SDHI0WP, NULL);
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mfd/tmio.h> #include <linux/mfd/tmio.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
#include <linux/mtd/onenand.h> #include <linux/mtd/onenand.h>
...@@ -354,7 +354,7 @@ static struct resource kfr2r09_sh_sdhi0_resources[] = { ...@@ -354,7 +354,7 @@ static struct resource kfr2r09_sh_sdhi0_resources[] = {
[0] = { [0] = {
.name = "SDHI0", .name = "SDHI0",
.start = 0x04ce0000, .start = 0x04ce0000,
.end = 0x04ce01ff, .end = 0x04ce00ff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { [1] = {
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/input/sh_keysc.h> #include <linux/input/sh_keysc.h>
#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
#include <linux/mtd/nand.h> #include <linux/mtd/nand.h>
#include <linux/i2c.h> #include <linux/i2c.h>
...@@ -399,7 +399,7 @@ static struct resource sdhi_cn9_resources[] = { ...@@ -399,7 +399,7 @@ static struct resource sdhi_cn9_resources[] = {
[0] = { [0] = {
.name = "SDHI", .name = "SDHI",
.start = 0x04ce0000, .start = 0x04ce0000,
.end = 0x04ce01ff, .end = 0x04ce00ff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { [1] = {
......
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/smc91x.h> #include <linux/smc91x.h>
...@@ -456,7 +456,7 @@ static struct resource sdhi0_cn7_resources[] = { ...@@ -456,7 +456,7 @@ static struct resource sdhi0_cn7_resources[] = {
[0] = { [0] = {
.name = "SDHI0", .name = "SDHI0",
.start = 0x04ce0000, .start = 0x04ce0000,
.end = 0x04ce01ff, .end = 0x04ce00ff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { [1] = {
...@@ -488,7 +488,7 @@ static struct resource sdhi1_cn8_resources[] = { ...@@ -488,7 +488,7 @@ static struct resource sdhi1_cn8_resources[] = {
[0] = { [0] = {
.name = "SDHI1", .name = "SDHI1",
.start = 0x04cf0000, .start = 0x04cf0000,
.end = 0x04cf01ff, .end = 0x04cf00ff,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}, },
[1] = { [1] = {
......
...@@ -60,15 +60,6 @@ config MFD_ASIC3 ...@@ -60,15 +60,6 @@ config MFD_ASIC3
This driver supports the ASIC3 multifunction chip found on many This driver supports the ASIC3 multifunction chip found on many
PDAs (mainly iPAQ and HTC based ones) PDAs (mainly iPAQ and HTC based ones)
config MFD_SH_MOBILE_SDHI
bool "Support for SuperH Mobile SDHI"
depends on SUPERH || ARCH_SHMOBILE
select MFD_CORE
select TMIO_MMC_DMA
---help---
This driver supports the SDHI hardware block found in many
SuperH Mobile SoCs.
config MFD_DAVINCI_VOICECODEC config MFD_DAVINCI_VOICECODEC
tristate tristate
select MFD_CORE select MFD_CORE
...@@ -266,11 +257,6 @@ config MFD_TMIO ...@@ -266,11 +257,6 @@ config MFD_TMIO
bool bool
default n default n
config TMIO_MMC_DMA
bool
select DMA_ENGINE
select DMADEVICES
config MFD_T7L66XB config MFD_T7L66XB
bool "Support Toshiba T7L66XB" bool "Support Toshiba T7L66XB"
depends on ARM && HAVE_CLK depends on ARM && HAVE_CLK
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o
obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_MFD_SM501) += sm501.o
obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
obj-$(CONFIG_MFD_SH_MOBILE_SDHI) += sh_mobile_sdhi.o
obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
......
...@@ -1875,7 +1875,7 @@ static int mmc_test_seq_perf(struct mmc_test_card *test, int write, ...@@ -1875,7 +1875,7 @@ static int mmc_test_seq_perf(struct mmc_test_card *test, int write,
unsigned int tot_sz, int max_scatter) unsigned int tot_sz, int max_scatter)
{ {
unsigned int dev_addr, i, cnt, sz, ssz; unsigned int dev_addr, i, cnt, sz, ssz;
struct timespec ts1, ts2, ts; struct timespec ts1, ts2;
int ret; int ret;
sz = test->area.max_tfr; sz = test->area.max_tfr;
...@@ -1912,7 +1912,6 @@ static int mmc_test_seq_perf(struct mmc_test_card *test, int write, ...@@ -1912,7 +1912,6 @@ static int mmc_test_seq_perf(struct mmc_test_card *test, int write,
} }
getnstimeofday(&ts2); getnstimeofday(&ts2);
ts = timespec_sub(ts2, ts1);
mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
return 0; return 0;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* your option) any later version. * your option) any later version.
*/ */
#include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
...@@ -252,6 +253,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) ...@@ -252,6 +253,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
struct mmc_command cmd; struct mmc_command cmd;
struct mmc_data data; struct mmc_data data;
struct scatterlist sg; struct scatterlist sg;
void *data_buf;
BUG_ON(!card); BUG_ON(!card);
BUG_ON(!card->host); BUG_ON(!card->host);
...@@ -263,6 +265,13 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) ...@@ -263,6 +265,13 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
if (err) if (err)
return err; return err;
/* dma onto stack is unsafe/nonportable, but callers to this
* routine normally provide temporary on-stack buffers ...
*/
data_buf = kmalloc(sizeof(card->raw_scr), GFP_KERNEL);
if (data_buf == NULL)
return -ENOMEM;
memset(&mrq, 0, sizeof(struct mmc_request)); memset(&mrq, 0, sizeof(struct mmc_request));
memset(&cmd, 0, sizeof(struct mmc_command)); memset(&cmd, 0, sizeof(struct mmc_command));
memset(&data, 0, sizeof(struct mmc_data)); memset(&data, 0, sizeof(struct mmc_data));
...@@ -280,12 +289,15 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) ...@@ -280,12 +289,15 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
data.sg = &sg; data.sg = &sg;
data.sg_len = 1; data.sg_len = 1;
sg_init_one(&sg, scr, 8); sg_init_one(&sg, data_buf, 8);
mmc_set_data_timeout(&data, card); mmc_set_data_timeout(&data, card);
mmc_wait_for_req(card->host, &mrq); mmc_wait_for_req(card->host, &mrq);
memcpy(scr, data_buf, sizeof(card->raw_scr));
kfree(data_buf);
if (cmd.error) if (cmd.error)
return cmd.error; return cmd.error;
if (data.error) if (data.error)
......
...@@ -439,13 +439,25 @@ config MMC_SDRICOH_CS ...@@ -439,13 +439,25 @@ config MMC_SDRICOH_CS
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called sdricoh_cs. module will be called sdricoh_cs.
config MMC_TMIO_CORE
tristate
config MMC_TMIO config MMC_TMIO
tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support" tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support"
depends on MFD_TMIO || MFD_ASIC3 || MFD_SH_MOBILE_SDHI depends on MFD_TMIO || MFD_ASIC3
select MMC_TMIO_CORE
help help
This provides support for the SD/MMC cell found in TC6393XB, This provides support for the SD/MMC cell found in TC6393XB,
T7L66XB and also HTC ASIC3 T7L66XB and also HTC ASIC3
config MMC_SDHI
tristate "SH-Mobile SDHI SD/SDIO controller support"
depends on SUPERH || ARCH_SHMOBILE
select MMC_TMIO_CORE
help
This provides support for the SDHI SD/SDIO controller found in
SuperH and ARM SH-Mobile SoCs
config MMC_CB710 config MMC_CB710
tristate "ENE CB710 MMC/SD Interface support" tristate "ENE CB710 MMC/SD Interface support"
depends on PCI depends on PCI
......
...@@ -29,7 +29,13 @@ endif ...@@ -29,7 +29,13 @@ endif
obj-$(CONFIG_MMC_S3C) += s3cmci.o obj-$(CONFIG_MMC_S3C) += s3cmci.o
obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
obj-$(CONFIG_MMC_CB710) += cb710-mmc.o obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o
tmio_mmc_core-y := tmio_mmc_pio.o
ifneq ($(CONFIG_MMC_SDHI),n)
tmio_mmc_core-y += tmio_mmc_dma.o
endif
obj-$(CONFIG_MMC_SDHI) += sh_mobile_sdhi.o
obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
obj-$(CONFIG_MMC_DW) += dw_mmc.o obj-$(CONFIG_MMC_DW) += dw_mmc.o
......
...@@ -316,7 +316,7 @@ static void dw_mci_idmac_stop_dma(struct dw_mci *host) ...@@ -316,7 +316,7 @@ static void dw_mci_idmac_stop_dma(struct dw_mci *host)
/* Stop the IDMAC running */ /* Stop the IDMAC running */
temp = mci_readl(host, BMOD); temp = mci_readl(host, BMOD);
temp &= ~SDMMC_IDMAC_ENABLE; temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB);
mci_writel(host, BMOD, temp); mci_writel(host, BMOD, temp);
} }
...@@ -385,7 +385,7 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) ...@@ -385,7 +385,7 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
/* Enable the IDMAC */ /* Enable the IDMAC */
temp = mci_readl(host, BMOD); temp = mci_readl(host, BMOD);
temp |= SDMMC_IDMAC_ENABLE; temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB;
mci_writel(host, BMOD, temp); mci_writel(host, BMOD, temp);
/* Start it running */ /* Start it running */
......
...@@ -68,6 +68,12 @@ static struct variant_data variant_arm = { ...@@ -68,6 +68,12 @@ static struct variant_data variant_arm = {
.datalength_bits = 16, .datalength_bits = 16,
}; };
static struct variant_data variant_arm_extended_fifo = {
.fifosize = 128 * 4,
.fifohalfsize = 64 * 4,
.datalength_bits = 16,
};
static struct variant_data variant_u300 = { static struct variant_data variant_u300 = {
.fifosize = 16 * 4, .fifosize = 16 * 4,
.fifohalfsize = 8 * 4, .fifohalfsize = 8 * 4,
...@@ -1277,9 +1283,14 @@ static int mmci_resume(struct amba_device *dev) ...@@ -1277,9 +1283,14 @@ static int mmci_resume(struct amba_device *dev)
static struct amba_id mmci_ids[] = { static struct amba_id mmci_ids[] = {
{ {
.id = 0x00041180, .id = 0x00041180,
.mask = 0x000fffff, .mask = 0xff0fffff,
.data = &variant_arm, .data = &variant_arm,
}, },
{
.id = 0x01041180,
.mask = 0xff0fffff,
.data = &variant_arm_extended_fifo,
},
{ {
.id = 0x00041181, .id = 0x00041181,
.mask = 0x000fffff, .mask = 0x000fffff,
......
...@@ -15,9 +15,11 @@ ...@@ -15,9 +15,11 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/irq.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/mmc_spi.h> #include <linux/spi/mmc_spi.h>
#include <linux/mmc/core.h> #include <linux/mmc/core.h>
......
...@@ -16,14 +16,40 @@ ...@@ -16,14 +16,40 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/sdhci-pltfm.h> #include <linux/mmc/sdhci-pltfm.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sdio.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/esdhc.h> #include <mach/esdhc.h>
#include "sdhci.h" #include "sdhci.h"
#include "sdhci-pltfm.h" #include "sdhci-pltfm.h"
#include "sdhci-esdhc.h" #include "sdhci-esdhc.h"
/* VENDOR SPEC register */
#define SDHCI_VENDOR_SPEC 0xC0
#define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002
#define ESDHC_FLAG_GPIO_FOR_CD_WP (1 << 0)
/*
* The CMDTYPE of the CMD register (offset 0xE) should be set to
* "11" when the STOP CMD12 is issued on imx53 to abort one
* open ended multi-blk IO. Otherwise the TC INT wouldn't
* be generated.
* In exact block transfer, the controller doesn't complete the
* operations automatically as required at the end of the
* transfer and remains on hold if the abort command is not sent.
* As a result, the TC flag is not asserted and SW received timeout
* exeception. Bit1 of Vendor Spec registor is used to fix it.
*/
#define ESDHC_FLAG_MULTIBLK_NO_INT (1 << 1)
struct pltfm_imx_data {
int flags;
u32 scratchpad;
};
static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
{ {
void __iomem *base = host->ioaddr + (reg & ~0x3); void __iomem *base = host->ioaddr + (reg & ~0x3);
...@@ -34,10 +60,14 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i ...@@ -34,10 +60,14 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i
static u32 esdhc_readl_le(struct sdhci_host *host, int reg) static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv;
/* fake CARD_PRESENT flag on mx25/35 */ /* fake CARD_PRESENT flag on mx25/35 */
u32 val = readl(host->ioaddr + reg); u32 val = readl(host->ioaddr + reg);
if (unlikely(reg == SDHCI_PRESENT_STATE)) { if (unlikely((reg == SDHCI_PRESENT_STATE)
&& (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP))) {
struct esdhc_platform_data *boarddata = struct esdhc_platform_data *boarddata =
host->mmc->parent->platform_data; host->mmc->parent->platform_data;
...@@ -55,13 +85,26 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) ...@@ -55,13 +85,26 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
{ {
if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv;
if (unlikely((reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)
&& (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP)))
/* /*
* these interrupts won't work with a custom card_detect gpio * these interrupts won't work with a custom card_detect gpio
* (only applied to mx25/35) * (only applied to mx25/35)
*/ */
val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
&& (reg == SDHCI_INT_STATUS)
&& (val & SDHCI_INT_DATA_END))) {
u32 v;
v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK;
writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
}
writel(val, host->ioaddr + reg); writel(val, host->ioaddr + reg);
} }
...@@ -76,6 +119,7 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg) ...@@ -76,6 +119,7 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv;
switch (reg) { switch (reg) {
case SDHCI_TRANSFER_MODE: case SDHCI_TRANSFER_MODE:
...@@ -83,10 +127,22 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) ...@@ -83,10 +127,22 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
* Postpone this write, we must do it together with a * Postpone this write, we must do it together with a
* command write that is down below. * command write that is down below.
*/ */
pltfm_host->scratchpad = val; if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
&& (host->cmd->opcode == SD_IO_RW_EXTENDED)
&& (host->cmd->data->blocks > 1)
&& (host->cmd->data->flags & MMC_DATA_READ)) {
u32 v;
v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK;
writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
}
imx_data->scratchpad = val;
return; return;
case SDHCI_COMMAND: case SDHCI_COMMAND:
writel(val << 16 | pltfm_host->scratchpad, if ((host->cmd->opcode == MMC_STOP_TRANSMISSION)
&& (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
val |= SDHCI_CMD_ABORTCMD;
writel(val << 16 | imx_data->scratchpad,
host->ioaddr + SDHCI_TRANSFER_MODE); host->ioaddr + SDHCI_TRANSFER_MODE);
return; return;
case SDHCI_BLOCK_SIZE: case SDHCI_BLOCK_SIZE:
...@@ -146,7 +202,9 @@ static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) ...@@ -146,7 +202,9 @@ static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
} }
static struct sdhci_ops sdhci_esdhc_ops = { static struct sdhci_ops sdhci_esdhc_ops = {
.read_l = esdhc_readl_le,
.read_w = esdhc_readw_le, .read_w = esdhc_readw_le,
.write_l = esdhc_writel_le,
.write_w = esdhc_writew_le, .write_w = esdhc_writew_le,
.write_b = esdhc_writeb_le, .write_b = esdhc_writeb_le,
.set_clock = esdhc_set_clock, .set_clock = esdhc_set_clock,
...@@ -168,6 +226,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd ...@@ -168,6 +226,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
struct clk *clk; struct clk *clk;
int err; int err;
struct pltfm_imx_data *imx_data;
clk = clk_get(mmc_dev(host->mmc), NULL); clk = clk_get(mmc_dev(host->mmc), NULL);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
...@@ -177,7 +236,15 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd ...@@ -177,7 +236,15 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
clk_enable(clk); clk_enable(clk);
pltfm_host->clk = clk; pltfm_host->clk = clk;
if (cpu_is_mx35() || cpu_is_mx51()) imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
if (!imx_data) {
clk_disable(pltfm_host->clk);
clk_put(pltfm_host->clk);
return -ENOMEM;
}
pltfm_host->priv = imx_data;
if (!cpu_is_mx25())
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
if (cpu_is_mx25() || cpu_is_mx35()) { if (cpu_is_mx25() || cpu_is_mx35()) {
...@@ -187,6 +254,9 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd ...@@ -187,6 +254,9 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro; sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro;
} }
if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()))
imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
if (boarddata) { if (boarddata) {
err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
if (err) { if (err) {
...@@ -214,8 +284,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd ...@@ -214,8 +284,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
goto no_card_detect_irq; goto no_card_detect_irq;
} }
sdhci_esdhc_ops.write_l = esdhc_writel_le; imx_data->flags |= ESDHC_FLAG_GPIO_FOR_CD_WP;
sdhci_esdhc_ops.read_l = esdhc_readl_le;
/* Now we have a working card_detect again */ /* Now we have a working card_detect again */
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
} }
...@@ -227,6 +296,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd ...@@ -227,6 +296,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
no_card_detect_pin: no_card_detect_pin:
boarddata->cd_gpio = err; boarddata->cd_gpio = err;
not_supported: not_supported:
kfree(imx_data);
return 0; return 0;
} }
...@@ -234,6 +304,7 @@ static void esdhc_pltfm_exit(struct sdhci_host *host) ...@@ -234,6 +304,7 @@ static void esdhc_pltfm_exit(struct sdhci_host *host)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
struct pltfm_imx_data *imx_data = pltfm_host->priv;
if (boarddata && gpio_is_valid(boarddata->wp_gpio)) if (boarddata && gpio_is_valid(boarddata->wp_gpio))
gpio_free(boarddata->wp_gpio); gpio_free(boarddata->wp_gpio);
...@@ -247,6 +318,7 @@ static void esdhc_pltfm_exit(struct sdhci_host *host) ...@@ -247,6 +318,7 @@ static void esdhc_pltfm_exit(struct sdhci_host *host)
clk_disable(pltfm_host->clk); clk_disable(pltfm_host->clk);
clk_put(pltfm_host->clk); clk_put(pltfm_host->clk);
kfree(imx_data);
} }
struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
......
...@@ -23,8 +23,7 @@ ...@@ -23,8 +23,7 @@
SDHCI_QUIRK_NONSTANDARD_CLOCK | \ SDHCI_QUIRK_NONSTANDARD_CLOCK | \
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
SDHCI_QUIRK_PIO_NEEDS_DELAY | \ SDHCI_QUIRK_PIO_NEEDS_DELAY | \
SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET | \ SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
SDHCI_QUIRK_NO_CARD_NO_RESET)
#define ESDHC_SYSTEM_CONTROL 0x2c #define ESDHC_SYSTEM_CONTROL 0x2c
#define ESDHC_CLOCK_MASK 0x0000fff0 #define ESDHC_CLOCK_MASK 0x0000fff0
......
...@@ -74,7 +74,8 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) ...@@ -74,7 +74,8 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
struct sdhci_of_data sdhci_esdhc = { struct sdhci_of_data sdhci_esdhc = {
/* card detection could be handled via GPIO */ /* card detection could be handled via GPIO */
.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION, .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
| SDHCI_QUIRK_NO_CARD_NO_RESET,
.ops = { .ops = {
.read_l = sdhci_be32bs_readl, .read_l = sdhci_be32bs_readl,
.read_w = esdhc_readw, .read_w = esdhc_readw,
......
...@@ -1016,16 +1016,14 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, ...@@ -1016,16 +1016,14 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
struct sdhci_pci_chip *chip; struct sdhci_pci_chip *chip;
struct sdhci_pci_slot *slot; struct sdhci_pci_slot *slot;
u8 slots, rev, first_bar; u8 slots, first_bar;
int ret, i; int ret, i;
BUG_ON(pdev == NULL); BUG_ON(pdev == NULL);
BUG_ON(ent == NULL); BUG_ON(ent == NULL);
pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
dev_info(&pdev->dev, "SDHCI controller found [%04x:%04x] (rev %x)\n", dev_info(&pdev->dev, "SDHCI controller found [%04x:%04x] (rev %x)\n",
(int)pdev->vendor, (int)pdev->device, (int)rev); (int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots); ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
if (ret) if (ret)
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
struct sdhci_pltfm_host { struct sdhci_pltfm_host {
struct clk *clk; struct clk *clk;
u32 scratchpad; /* to handle quirks across io-accessor calls */ void *priv; /* to handle quirks across io-accessor calls */
}; };
extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata; extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata;
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#define SDHCI_CMD_CRC 0x08 #define SDHCI_CMD_CRC 0x08
#define SDHCI_CMD_INDEX 0x10 #define SDHCI_CMD_INDEX 0x10
#define SDHCI_CMD_DATA 0x20 #define SDHCI_CMD_DATA 0x20
#define SDHCI_CMD_ABORTCMD 0xC0
#define SDHCI_CMD_RESP_NONE 0x00 #define SDHCI_CMD_RESP_NONE 0x00
#define SDHCI_CMD_RESP_LONG 0x01 #define SDHCI_CMD_RESP_LONG 0x01
......
...@@ -23,51 +23,30 @@ ...@@ -23,51 +23,30 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mfd/core.h> #include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mfd/tmio.h> #include <linux/mfd/tmio.h>
#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/sh_dma.h> #include <linux/sh_dma.h>
#include "tmio_mmc.h"
struct sh_mobile_sdhi { struct sh_mobile_sdhi {
struct clk *clk; struct clk *clk;
struct tmio_mmc_data mmc_data; struct tmio_mmc_data mmc_data;
struct mfd_cell cell_mmc;
struct sh_dmae_slave param_tx; struct sh_dmae_slave param_tx;
struct sh_dmae_slave param_rx; struct sh_dmae_slave param_rx;
struct tmio_mmc_dma dma_priv; struct tmio_mmc_dma dma_priv;
}; };
static struct resource sh_mobile_sdhi_resources[] = { static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state)
{
.start = 0x000,
.end = 0x1ff,
.flags = IORESOURCE_MEM,
},
{
.start = 0,
.end = 0,
.flags = IORESOURCE_IRQ,
},
};
static struct mfd_cell sh_mobile_sdhi_cell = {
.name = "tmio-mmc",
.num_resources = ARRAY_SIZE(sh_mobile_sdhi_resources),
.resources = sh_mobile_sdhi_resources,
};
static void sh_mobile_sdhi_set_pwr(struct platform_device *tmio, int state)
{ {
struct platform_device *pdev = to_platform_device(tmio->dev.parent);
struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
if (p && p->set_pwr) if (p && p->set_pwr)
p->set_pwr(pdev, state); p->set_pwr(pdev, state);
} }
static int sh_mobile_sdhi_get_cd(struct platform_device *tmio) static int sh_mobile_sdhi_get_cd(struct platform_device *pdev)
{ {
struct platform_device *pdev = to_platform_device(tmio->dev.parent);
struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
if (p && p->get_cd) if (p && p->get_cd)
...@@ -81,20 +60,9 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) ...@@ -81,20 +60,9 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
struct sh_mobile_sdhi *priv; struct sh_mobile_sdhi *priv;
struct tmio_mmc_data *mmc_data; struct tmio_mmc_data *mmc_data;
struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
struct resource *mem; struct tmio_mmc_host *host;
char clk_name[8]; char clk_name[8];
int ret, irq; int ret;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem)
dev_err(&pdev->dev, "missing MEM resource\n");
irq = platform_get_irq(pdev, 0);
if (irq < 0)
dev_err(&pdev->dev, "missing IRQ resource\n");
if (!mem || (irq < 0))
return -EINVAL;
priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL); priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
if (priv == NULL) { if (priv == NULL) {
...@@ -109,8 +77,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) ...@@ -109,8 +77,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
if (IS_ERR(priv->clk)) { if (IS_ERR(priv->clk)) {
dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
ret = PTR_ERR(priv->clk); ret = PTR_ERR(priv->clk);
kfree(priv); goto eclkget;
return ret;
} }
clk_enable(priv->clk); clk_enable(priv->clk);
...@@ -123,6 +90,15 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) ...@@ -123,6 +90,15 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
mmc_data->flags = p->tmio_flags; mmc_data->flags = p->tmio_flags;
mmc_data->ocr_mask = p->tmio_ocr_mask; mmc_data->ocr_mask = p->tmio_ocr_mask;
mmc_data->capabilities |= p->tmio_caps; mmc_data->capabilities |= p->tmio_caps;
if (p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) {
priv->param_tx.slave_id = p->dma_slave_tx;
priv->param_rx.slave_id = p->dma_slave_rx;
priv->dma_priv.chan_priv_tx = &priv->param_tx;
priv->dma_priv.chan_priv_rx = &priv->param_rx;
priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */
mmc_data->dma = &priv->dma_priv;
}
} }
/* /*
...@@ -136,36 +112,30 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) ...@@ -136,36 +112,30 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
*/ */
mmc_data->flags |= TMIO_MMC_SDIO_IRQ; mmc_data->flags |= TMIO_MMC_SDIO_IRQ;
if (p && p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) { ret = tmio_mmc_host_probe(&host, pdev, mmc_data);
priv->param_tx.slave_id = p->dma_slave_tx; if (ret < 0)
priv->param_rx.slave_id = p->dma_slave_rx; goto eprobe;
priv->dma_priv.chan_priv_tx = &priv->param_tx;
priv->dma_priv.chan_priv_rx = &priv->param_rx;
priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */
mmc_data->dma = &priv->dma_priv;
}
memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc)); pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
priv->cell_mmc.mfd_data = mmc_data; (unsigned long)host->ctl, host->irq);
platform_set_drvdata(pdev, priv); return ret;
ret = mfd_add_devices(&pdev->dev, pdev->id,
&priv->cell_mmc, 1, mem, irq);
if (ret) {
clk_disable(priv->clk);
clk_put(priv->clk);
kfree(priv);
}
eprobe:
clk_disable(priv->clk);
clk_put(priv->clk);
eclkget:
kfree(priv);
return ret; return ret;
} }
static int sh_mobile_sdhi_remove(struct platform_device *pdev) static int sh_mobile_sdhi_remove(struct platform_device *pdev)
{ {
struct sh_mobile_sdhi *priv = platform_get_drvdata(pdev); struct mmc_host *mmc = platform_get_drvdata(pdev);
struct tmio_mmc_host *host = mmc_priv(mmc);
struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
mfd_remove_devices(&pdev->dev); tmio_mmc_host_remove(host);
clk_disable(priv->clk); clk_disable(priv->clk);
clk_put(priv->clk); clk_put(priv->clk);
kfree(priv); kfree(priv);
...@@ -198,3 +168,4 @@ module_exit(sh_mobile_sdhi_exit); ...@@ -198,3 +168,4 @@ module_exit(sh_mobile_sdhi_exit);
MODULE_DESCRIPTION("SuperH Mobile SDHI driver"); MODULE_DESCRIPTION("SuperH Mobile SDHI driver");
MODULE_AUTHOR("Magnus Damm"); MODULE_AUTHOR("Magnus Damm");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:sh_mobile_sdhi");
此差异已折叠。
/*
* linux/drivers/mmc/host/tmio_mmc.h
*
* Copyright (C) 2007 Ian Molton
* Copyright (C) 2004 Ian Molton
*
* 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.
*
* Driver for the MMC / SD / SDIO cell found in:
*
* TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
*/
#ifndef TMIO_MMC_H
#define TMIO_MMC_H
#include <linux/highmem.h>
#include <linux/mmc/tmio.h>
#include <linux/pagemap.h>
/* Definitions for values the CTRL_SDIO_STATUS register can take. */
#define TMIO_SDIO_STAT_IOIRQ 0x0001
#define TMIO_SDIO_STAT_EXPUB52 0x4000
#define TMIO_SDIO_STAT_EXWT 0x8000
#define TMIO_SDIO_MASK_ALL 0xc007
/* Define some IRQ masks */
/* This is the mask used at reset by the chip */
#define TMIO_MASK_ALL 0x837f031d
#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND)
#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND)
#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \
TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD)
struct tmio_mmc_data;
struct tmio_mmc_host {
void __iomem *ctl;
unsigned long bus_shift;
struct mmc_command *cmd;
struct mmc_request *mrq;
struct mmc_data *data;
struct mmc_host *mmc;
int irq;
unsigned int sdio_irq_enabled;
/* Callbacks for clock / power control */
void (*set_pwr)(struct platform_device *host, int state);
void (*set_clk_div)(struct platform_device *host, int state);
/* pio related stuff */
struct scatterlist *sg_ptr;
struct scatterlist *sg_orig;
unsigned int sg_len;
unsigned int sg_off;
struct platform_device *pdev;
struct tmio_mmc_data *pdata;
/* DMA support */
bool force_pio;
struct dma_chan *chan_rx;
struct dma_chan *chan_tx;
struct tasklet_struct dma_complete;
struct tasklet_struct dma_issue;
struct scatterlist bounce_sg;
u8 *bounce_buf;
/* Track lost interrupts */
struct delayed_work delayed_reset_work;
spinlock_t lock;
unsigned long last_req_ts;
};
int tmio_mmc_host_probe(struct tmio_mmc_host **host,
struct platform_device *pdev,
struct tmio_mmc_data *pdata);
void tmio_mmc_host_remove(struct tmio_mmc_host *host);
void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
unsigned long *flags)
{
local_irq_save(*flags);
return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
}
static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg,
unsigned long *flags, void *virt)
{
kunmap_atomic(virt - sg->offset, KM_BIO_SRC_IRQ);
local_irq_restore(*flags);
}
#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data);
void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata);
void tmio_mmc_release_dma(struct tmio_mmc_host *host);
#else
static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host,
struct mmc_data *data)
{
}
static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host,
struct tmio_mmc_data *pdata)
{
host->chan_tx = NULL;
host->chan_rx = NULL;
}
static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host)
{
}
#endif
#endif
/*
* linux/drivers/mmc/tmio_mmc_dma.c
*
* Copyright (C) 2010-2011 Guennadi Liakhovetski
*
* 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.
*
* DMA function for TMIO MMC implementations
*/
#include <linux/device.h>
#include <linux/dmaengine.h>
#include <linux/mfd/tmio.h>
#include <linux/mmc/host.h>
#include <linux/mmc/tmio.h>
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
#include "tmio_mmc.h"
#define TMIO_MMC_MIN_DMA_LEN 8
static void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
{
#if defined(CONFIG_SUPERH) || defined(CONFIG_ARCH_SHMOBILE)
/* Switch DMA mode on or off - SuperH specific? */
writew(enable ? 2 : 0, host->ctl + (0xd8 << host->bus_shift));
#endif
}
static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
{
struct scatterlist *sg = host->sg_ptr, *sg_tmp;
struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *chan = host->chan_rx;
struct tmio_mmc_data *pdata = host->pdata;
dma_cookie_t cookie;
int ret, i;
bool aligned = true, multiple = true;
unsigned int align = (1 << pdata->dma->alignment_shift) - 1;
for_each_sg(sg, sg_tmp, host->sg_len, i) {
if (sg_tmp->offset & align)
aligned = false;
if (sg_tmp->length & align) {
multiple = false;
break;
}
}
if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE ||
(align & PAGE_MASK))) || !multiple) {
ret = -EINVAL;
goto pio;
}
if (sg->length < TMIO_MMC_MIN_DMA_LEN) {
host->force_pio = true;
return;
}
tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_RXRDY);
/* The only sg element can be unaligned, use our bounce buffer then */
if (!aligned) {
sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
host->sg_ptr = &host->bounce_sg;
sg = host->sg_ptr;
}
ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE);
if (ret > 0)
desc = chan->device->device_prep_slave_sg(chan, sg, ret,
DMA_FROM_DEVICE, DMA_CTRL_ACK);
if (desc) {
cookie = dmaengine_submit(desc);
if (cookie < 0) {
desc = NULL;
ret = cookie;
}
}
dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
__func__, host->sg_len, ret, cookie, host->mrq);
pio:
if (!desc) {
/* DMA failed, fall back to PIO */
if (ret >= 0)
ret = -EIO;
host->chan_rx = NULL;
dma_release_channel(chan);
/* Free the Tx channel too */
chan = host->chan_tx;
if (chan) {
host->chan_tx = NULL;
dma_release_channel(chan);
}
dev_warn(&host->pdev->dev,
"DMA failed: %d, falling back to PIO\n", ret);
tmio_mmc_enable_dma(host, false);
}
dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__,
desc, cookie, host->sg_len);
}
static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
{
struct scatterlist *sg = host->sg_ptr, *sg_tmp;
struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *chan = host->chan_tx;
struct tmio_mmc_data *pdata = host->pdata;
dma_cookie_t cookie;
int ret, i;
bool aligned = true, multiple = true;
unsigned int align = (1 << pdata->dma->alignment_shift) - 1;
for_each_sg(sg, sg_tmp, host->sg_len, i) {
if (sg_tmp->offset & align)
aligned = false;
if (sg_tmp->length & align) {
multiple = false;
break;
}
}
if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE ||
(align & PAGE_MASK))) || !multiple) {
ret = -EINVAL;
goto pio;
}
if (sg->length < TMIO_MMC_MIN_DMA_LEN) {
host->force_pio = true;
return;
}
tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_TXRQ);
/* The only sg element can be unaligned, use our bounce buffer then */
if (!aligned) {
unsigned long flags;
void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags);
sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length);
tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr);
host->sg_ptr = &host->bounce_sg;
sg = host->sg_ptr;
}
ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE);
if (ret > 0)
desc = chan->device->device_prep_slave_sg(chan, sg, ret,
DMA_TO_DEVICE, DMA_CTRL_ACK);
if (desc) {
cookie = dmaengine_submit(desc);
if (cookie < 0) {
desc = NULL;
ret = cookie;
}
}
dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
__func__, host->sg_len, ret, cookie, host->mrq);
pio:
if (!desc) {
/* DMA failed, fall back to PIO */
if (ret >= 0)
ret = -EIO;
host->chan_tx = NULL;
dma_release_channel(chan);
/* Free the Rx channel too */
chan = host->chan_rx;
if (chan) {
host->chan_rx = NULL;
dma_release_channel(chan);
}
dev_warn(&host->pdev->dev,
"DMA failed: %d, falling back to PIO\n", ret);
tmio_mmc_enable_dma(host, false);
}
dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d\n", __func__,
desc, cookie);
}
void tmio_mmc_start_dma(struct tmio_mmc_host *host,
struct mmc_data *data)
{
if (data->flags & MMC_DATA_READ) {
if (host->chan_rx)
tmio_mmc_start_dma_rx(host);
} else {
if (host->chan_tx)
tmio_mmc_start_dma_tx(host);
}
}
static void tmio_mmc_issue_tasklet_fn(unsigned long priv)
{
struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv;
struct dma_chan *chan = NULL;
spin_lock_irq(&host->lock);
if (host && host->data) {
if (host->data->flags & MMC_DATA_READ)
chan = host->chan_rx;
else
chan = host->chan_tx;
}
spin_unlock_irq(&host->lock);
tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
if (chan)
dma_async_issue_pending(chan);
}
static void tmio_mmc_tasklet_fn(unsigned long arg)
{
struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
spin_lock_irq(&host->lock);
if (!host->data)
goto out;
if (host->data->flags & MMC_DATA_READ)
dma_unmap_sg(host->chan_rx->device->dev,
host->sg_ptr, host->sg_len,
DMA_FROM_DEVICE);
else
dma_unmap_sg(host->chan_tx->device->dev,
host->sg_ptr, host->sg_len,
DMA_TO_DEVICE);
tmio_mmc_do_data_irq(host);
out:
spin_unlock_irq(&host->lock);
}
/* It might be necessary to make filter MFD specific */
static bool tmio_mmc_filter(struct dma_chan *chan, void *arg)
{
dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg);
chan->private = arg;
return true;
}
void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata)
{
/* We can only either use DMA for both Tx and Rx or not use it at all */
if (pdata->dma) {
dma_cap_mask_t mask;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
host->chan_tx = dma_request_channel(mask, tmio_mmc_filter,
pdata->dma->chan_priv_tx);
dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__,
host->chan_tx);
if (!host->chan_tx)
return;
host->chan_rx = dma_request_channel(mask, tmio_mmc_filter,
pdata->dma->chan_priv_rx);
dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__,
host->chan_rx);
if (!host->chan_rx)
goto ereqrx;
host->bounce_buf = (u8 *)__get_free_page(GFP_KERNEL | GFP_DMA);
if (!host->bounce_buf)
goto ebouncebuf;
tasklet_init(&host->dma_complete, tmio_mmc_tasklet_fn, (unsigned long)host);
tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn, (unsigned long)host);
tmio_mmc_enable_dma(host, true);
return;
ebouncebuf:
dma_release_channel(host->chan_rx);
host->chan_rx = NULL;
ereqrx:
dma_release_channel(host->chan_tx);
host->chan_tx = NULL;
return;
}
}
void tmio_mmc_release_dma(struct tmio_mmc_host *host)
{
if (host->chan_tx) {
struct dma_chan *chan = host->chan_tx;
host->chan_tx = NULL;
dma_release_channel(chan);
}
if (host->chan_rx) {
struct dma_chan *chan = host->chan_rx;
host->chan_rx = NULL;
dma_release_channel(chan);
}
if (host->bounce_buf) {
free_pages((unsigned long)host->bounce_buf, 0);
host->bounce_buf = NULL;
}
}
此差异已折叠。
...@@ -1087,14 +1087,13 @@ static int __devinit via_sd_probe(struct pci_dev *pcidev, ...@@ -1087,14 +1087,13 @@ static int __devinit via_sd_probe(struct pci_dev *pcidev,
struct mmc_host *mmc; struct mmc_host *mmc;
struct via_crdr_mmc_host *sdhost; struct via_crdr_mmc_host *sdhost;
u32 base, len; u32 base, len;
u8 rev, gatt; u8 gatt;
int ret; int ret;
pci_read_config_byte(pcidev, PCI_CLASS_REVISION, &rev);
pr_info(DRV_NAME pr_info(DRV_NAME
": VIA SDMMC controller found at %s [%04x:%04x] (rev %x)\n", ": VIA SDMMC controller found at %s [%04x:%04x] (rev %x)\n",
pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device, pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device,
(int)rev); (int)pcidev->revision);
ret = pci_enable_device(pcidev); ret = pci_enable_device(pcidev);
if (ret) if (ret)
......
/*
* include/linux/mmc/tmio.h
*
* Copyright (C) 2007 Ian Molton
* Copyright (C) 2004 Ian Molton
*
* 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.
*
* Driver for the MMC / SD / SDIO cell found in:
*
* TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
*/
#ifndef _LINUX_MMC_TMIO_H_
#define _LINUX_MMC_TMIO_H_
#define CTL_SD_CMD 0x00
#define CTL_ARG_REG 0x04
#define CTL_STOP_INTERNAL_ACTION 0x08
#define CTL_XFER_BLK_COUNT 0xa
#define CTL_RESPONSE 0x0c
#define CTL_STATUS 0x1c
#define CTL_IRQ_MASK 0x20
#define CTL_SD_CARD_CLK_CTL 0x24
#define CTL_SD_XFER_LEN 0x26
#define CTL_SD_MEM_CARD_OPT 0x28
#define CTL_SD_ERROR_DETAIL_STATUS 0x2c
#define CTL_SD_DATA_PORT 0x30
#define CTL_TRANSACTION_CTL 0x34
#define CTL_SDIO_STATUS 0x36
#define CTL_SDIO_IRQ_MASK 0x38
#define CTL_RESET_SD 0xe0
#define CTL_SDIO_REGS 0x100
#define CTL_CLK_AND_WAIT_CTL 0x138
#define CTL_RESET_SDIO 0x1e0
/* Definitions for values the CTRL_STATUS register can take. */
#define TMIO_STAT_CMDRESPEND 0x00000001
#define TMIO_STAT_DATAEND 0x00000004
#define TMIO_STAT_CARD_REMOVE 0x00000008
#define TMIO_STAT_CARD_INSERT 0x00000010
#define TMIO_STAT_SIGSTATE 0x00000020
#define TMIO_STAT_WRPROTECT 0x00000080
#define TMIO_STAT_CARD_REMOVE_A 0x00000100
#define TMIO_STAT_CARD_INSERT_A 0x00000200
#define TMIO_STAT_SIGSTATE_A 0x00000400
#define TMIO_STAT_CMD_IDX_ERR 0x00010000
#define TMIO_STAT_CRCFAIL 0x00020000
#define TMIO_STAT_STOPBIT_ERR 0x00040000
#define TMIO_STAT_DATATIMEOUT 0x00080000
#define TMIO_STAT_RXOVERFLOW 0x00100000
#define TMIO_STAT_TXUNDERRUN 0x00200000
#define TMIO_STAT_CMDTIMEOUT 0x00400000
#define TMIO_STAT_RXRDY 0x01000000
#define TMIO_STAT_TXRQ 0x02000000
#define TMIO_STAT_ILL_FUNC 0x20000000
#define TMIO_STAT_CMD_BUSY 0x40000000
#define TMIO_STAT_ILL_ACCESS 0x80000000
#define TMIO_BBS 512 /* Boot block size */
#endif /* _LINUX_MMC_TMIO_H_ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册