Commit 15ec4461 authored by Philip Rakity's avatar Philip Rakity Committed by Chris Ball

mmc: sdhci: 8-bit bus width changes

We now:
 * check for a v3 controller before setting 8-bit bus width
 * offer a callback for platform code to switch to 8-bit mode, which
   allows non-v3 controllers to support it
 * rely on mmc->caps |= MMC_CAP_8_BIT_DATA; in platform code to specify
   that the board designers have indeed brought out all the pins for
   8-bit to the slot.

We were previously relying only on whether the *controller* supported
8-bit, which doesn't tell us anything about the pin configuration in
the board design.

This fixes the MMC card regression reported by Maxim Levitsky here:
   http://thread.gmane.org/gmane.linux.kernel.mmc/4336
by no longer assuming that 8-bit works by default.
Signed-off-by: default avatarPhilip Rakity <prakity@marvell.com>
Tested-by: default avatarGiuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent ed919b01
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
/* Require clock free running */ /* Require clock free running */
#define PXA_FLAG_DISABLE_CLOCK_GATING (1<<0) #define PXA_FLAG_DISABLE_CLOCK_GATING (1<<0)
/* Board design supports 8-bit data on SD/SDIO BUS */
#define PXA_FLAG_SD_8_BIT_CAPABLE_SLOT (1<<2)
/* /*
* struct pxa_sdhci_platdata() - Platform device data for PXA SDHCI * struct pxa_sdhci_platdata() - Platform device data for PXA SDHCI
* @max_speed: the maximum speed supported * @max_speed: the maximum speed supported
......
...@@ -141,6 +141,10 @@ static int __devinit sdhci_pxa_probe(struct platform_device *pdev) ...@@ -141,6 +141,10 @@ static int __devinit sdhci_pxa_probe(struct platform_device *pdev)
if (pdata->quirks) if (pdata->quirks)
host->quirks |= pdata->quirks; host->quirks |= pdata->quirks;
/* If slot design supports 8 bit data, indicate this to MMC. */
if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT)
host->mmc->caps |= MMC_CAP_8_BIT_DATA;
ret = sdhci_add_host(host); ret = sdhci_add_host(host);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to add host\n"); dev_err(&pdev->dev, "failed to add host\n");
......
...@@ -1185,17 +1185,31 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -1185,17 +1185,31 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (host->ops->platform_send_init_74_clocks) if (host->ops->platform_send_init_74_clocks)
host->ops->platform_send_init_74_clocks(host, ios->power_mode); host->ops->platform_send_init_74_clocks(host, ios->power_mode);
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); /*
* If your platform has 8-bit width support but is not a v3 controller,
if (ios->bus_width == MMC_BUS_WIDTH_8) * or if it requires special setup code, you should implement that in
ctrl |= SDHCI_CTRL_8BITBUS; * platform_8bit_width().
else */
ctrl &= ~SDHCI_CTRL_8BITBUS; if (host->ops->platform_8bit_width)
host->ops->platform_8bit_width(host, ios->bus_width);
else {
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
if (ios->bus_width == MMC_BUS_WIDTH_8) {
ctrl &= ~SDHCI_CTRL_4BITBUS;
if (host->version >= SDHCI_SPEC_300)
ctrl |= SDHCI_CTRL_8BITBUS;
} else {
if (host->version >= SDHCI_SPEC_300)
ctrl &= ~SDHCI_CTRL_8BITBUS;
if (ios->bus_width == MMC_BUS_WIDTH_4)
ctrl |= SDHCI_CTRL_4BITBUS;
else
ctrl &= ~SDHCI_CTRL_4BITBUS;
}
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
if (ios->bus_width == MMC_BUS_WIDTH_4) ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl |= SDHCI_CTRL_4BITBUS;
else
ctrl &= ~SDHCI_CTRL_4BITBUS;
if ((ios->timing == MMC_TIMING_SD_HS || if ((ios->timing == MMC_TIMING_SD_HS ||
ios->timing == MMC_TIMING_MMC_HS) ios->timing == MMC_TIMING_MMC_HS)
...@@ -1855,11 +1869,19 @@ int sdhci_add_host(struct sdhci_host *host) ...@@ -1855,11 +1869,19 @@ int sdhci_add_host(struct sdhci_host *host)
mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300; mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
else else
mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200; mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
mmc->f_max = host->max_clk; mmc->f_max = host->max_clk;
mmc->caps |= MMC_CAP_SDIO_IRQ; mmc->caps |= MMC_CAP_SDIO_IRQ;
/*
* A controller may support 8-bit width, but the board itself
* might not have the pins brought out. Boards that support
* 8-bit width must set "mmc->caps |= MMC_CAP_8_BIT_DATA;" in
* their platform code before calling sdhci_add_host(), and we
* won't assume 8-bit width for hosts without that CAP.
*/
if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA)) if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; mmc->caps |= MMC_CAP_4_BIT_DATA;
if (caps & SDHCI_CAN_DO_HISPD) if (caps & SDHCI_CAN_DO_HISPD)
mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
......
...@@ -76,7 +76,7 @@ ...@@ -76,7 +76,7 @@
#define SDHCI_CTRL_ADMA1 0x08 #define SDHCI_CTRL_ADMA1 0x08
#define SDHCI_CTRL_ADMA32 0x10 #define SDHCI_CTRL_ADMA32 0x10
#define SDHCI_CTRL_ADMA64 0x18 #define SDHCI_CTRL_ADMA64 0x18
#define SDHCI_CTRL_8BITBUS 0x20 #define SDHCI_CTRL_8BITBUS 0x20
#define SDHCI_POWER_CONTROL 0x29 #define SDHCI_POWER_CONTROL 0x29
#define SDHCI_POWER_ON 0x01 #define SDHCI_POWER_ON 0x01
...@@ -155,6 +155,7 @@ ...@@ -155,6 +155,7 @@
#define SDHCI_CLOCK_BASE_SHIFT 8 #define SDHCI_CLOCK_BASE_SHIFT 8
#define SDHCI_MAX_BLOCK_MASK 0x00030000 #define SDHCI_MAX_BLOCK_MASK 0x00030000
#define SDHCI_MAX_BLOCK_SHIFT 16 #define SDHCI_MAX_BLOCK_SHIFT 16
#define SDHCI_CAN_DO_8BIT 0x00040000
#define SDHCI_CAN_DO_ADMA2 0x00080000 #define SDHCI_CAN_DO_ADMA2 0x00080000
#define SDHCI_CAN_DO_ADMA1 0x00100000 #define SDHCI_CAN_DO_ADMA1 0x00100000
#define SDHCI_CAN_DO_HISPD 0x00200000 #define SDHCI_CAN_DO_HISPD 0x00200000
...@@ -215,6 +216,8 @@ struct sdhci_ops { ...@@ -215,6 +216,8 @@ struct sdhci_ops {
unsigned int (*get_max_clock)(struct sdhci_host *host); unsigned int (*get_max_clock)(struct sdhci_host *host);
unsigned int (*get_min_clock)(struct sdhci_host *host); unsigned int (*get_min_clock)(struct sdhci_host *host);
unsigned int (*get_timeout_clock)(struct sdhci_host *host); unsigned int (*get_timeout_clock)(struct sdhci_host *host);
int (*platform_8bit_width)(struct sdhci_host *host,
int width);
void (*platform_send_init_74_clocks)(struct sdhci_host *host, void (*platform_send_init_74_clocks)(struct sdhci_host *host,
u8 power_mode); u8 power_mode);
unsigned int (*get_ro)(struct sdhci_host *host); unsigned int (*get_ro)(struct sdhci_host *host);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment