Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -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
+4 −0
Original line number Original line Diff line number Diff line
@@ -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");
+33 −11
Original line number Original line Diff line number Diff line
@@ -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);


	/*
	 * If your platform has 8-bit width support but is not a v3 controller,
	 * or if it requires special setup code, you should implement that in
	 * platform_8bit_width().
	 */
	if (host->ops->platform_8bit_width)
		host->ops->platform_8bit_width(host, ios->bus_width);
	else {
		ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
		ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);

		if (ios->bus_width == MMC_BUS_WIDTH_8) {
	if (ios->bus_width == MMC_BUS_WIDTH_8)
			ctrl &= ~SDHCI_CTRL_4BITBUS;
			if (host->version >= SDHCI_SPEC_300)
				ctrl |= SDHCI_CTRL_8BITBUS;
				ctrl |= SDHCI_CTRL_8BITBUS;
	else
		} else {
			if (host->version >= SDHCI_SPEC_300)
				ctrl &= ~SDHCI_CTRL_8BITBUS;
				ctrl &= ~SDHCI_CTRL_8BITBUS;

			if (ios->bus_width == MMC_BUS_WIDTH_4)
			if (ios->bus_width == MMC_BUS_WIDTH_4)
				ctrl |= SDHCI_CTRL_4BITBUS;
				ctrl |= SDHCI_CTRL_4BITBUS;
			else
			else
				ctrl &= ~SDHCI_CTRL_4BITBUS;
				ctrl &= ~SDHCI_CTRL_4BITBUS;
		}
		sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
	}

	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);


	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)
		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;
+4 −1
Original line number Original line Diff line number Diff line
@@ -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 {
	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);