diff options
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/card/block.c | 3 | ||||
| -rw-r--r-- | drivers/mmc/card/queue.h | 2 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc.c | 12 | ||||
| -rw-r--r-- | drivers/mmc/host/rtsx_usb_sdmmc.c | 7 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-esdhc-imx.c | 23 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-of-arasan.c | 26 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-pci-core.c | 54 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-pci.h | 2 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-pxav3.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.c | 42 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.h | 2 | 
11 files changed, 142 insertions, 33 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index c3335112e68c..709a872ed484 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -46,6 +46,7 @@  #include <asm/uaccess.h>  #include "queue.h" +#include "block.h"  MODULE_ALIAS("mmc:block");  #ifdef MODULE_PARAM_PREFIX @@ -1786,7 +1787,7 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,  	struct mmc_blk_data *md = mq->data;  	struct mmc_packed *packed = mqrq->packed;  	bool do_rel_wr, do_data_tag; -	u32 *packed_cmd_hdr; +	__le32 *packed_cmd_hdr;  	u8 hdr_blocks;  	u8 i = 1; diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h index 3c15a75bae86..342f1e3f301e 100644 --- a/drivers/mmc/card/queue.h +++ b/drivers/mmc/card/queue.h @@ -31,7 +31,7 @@ enum mmc_packed_type {  struct mmc_packed {  	struct list_head	list; -	u32			cmd_hdr[1024]; +	__le32			cmd_hdr[1024];  	unsigned int		blocks;  	u8			nr_entries;  	u8			retries; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 3486bc7fbb64..39fc5b2b96c5 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1263,6 +1263,16 @@ static int mmc_select_hs400es(struct mmc_card *card)  		goto out_err;  	} +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_2V) +		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); + +	if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V) +		err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); + +	/* If fails try again during next card power cycle */ +	if (err) +		goto out_err; +  	err = mmc_select_bus_width(card);  	if (err < 0)  		goto out_err; @@ -1272,6 +1282,8 @@ static int mmc_select_hs400es(struct mmc_card *card)  	if (err)  		goto out_err; +	mmc_set_clock(host, card->ext_csd.hs_max_dtr); +  	err = mmc_switch_status(card);  	if (err)  		goto out_err; diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c index 4106295527b9..6e9c0f8fddb1 100644 --- a/drivers/mmc/host/rtsx_usb_sdmmc.c +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -1138,11 +1138,6 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	dev_dbg(sdmmc_dev(host), "%s\n", __func__);  	mutex_lock(&ucr->dev_mutex); -	if (rtsx_usb_card_exclusive_check(ucr, RTSX_USB_SD_CARD)) { -		mutex_unlock(&ucr->dev_mutex); -		return; -	} -  	sd_set_power_mode(host, ios->power_mode);  	sd_set_bus_width(host, ios->bus_width);  	sd_set_timing(host, ios->timing, &host->ddr_mode); @@ -1314,6 +1309,7 @@ static void rtsx_usb_update_led(struct work_struct *work)  		container_of(work, struct rtsx_usb_sdmmc, led_work);  	struct rtsx_ucr *ucr = host->ucr; +	pm_runtime_get_sync(sdmmc_dev(host));  	mutex_lock(&ucr->dev_mutex);  	if (host->led.brightness == LED_OFF) @@ -1322,6 +1318,7 @@ static void rtsx_usb_update_led(struct work_struct *work)  		rtsx_usb_turn_on_led(ucr);  	mutex_unlock(&ucr->dev_mutex); +	pm_runtime_put(sdmmc_dev(host));  }  #endif diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 1f54fd8755c8..7123ef96ed18 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -346,7 +346,8 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)  	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);  	u32 data; -	if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { +	if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE || +			reg == SDHCI_INT_STATUS)) {  		if ((val & SDHCI_INT_CARD_INT) && !esdhc_is_usdhc(imx_data)) {  			/*  			 * Clear and then set D3CD bit to avoid missing the @@ -555,6 +556,25 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)  	esdhc_clrset_le(host, 0xffff, val, reg);  } +static u8 esdhc_readb_le(struct sdhci_host *host, int reg) +{ +	u8 ret; +	u32 val; + +	switch (reg) { +	case SDHCI_HOST_CONTROL: +		val = readl(host->ioaddr + reg); + +		ret = val & SDHCI_CTRL_LED; +		ret |= (val >> 5) & SDHCI_CTRL_DMA_MASK; +		ret |= (val & ESDHC_CTRL_4BITBUS); +		ret |= (val & ESDHC_CTRL_8BITBUS) << 3; +		return ret; +	} + +	return readb(host->ioaddr + reg); +} +  static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)  {  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -947,6 +967,7 @@ static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)  static struct sdhci_ops sdhci_esdhc_ops = {  	.read_l = esdhc_readl_le,  	.read_w = esdhc_readw_le, +	.read_b = esdhc_readb_le,  	.write_l = esdhc_writel_le,  	.write_w = esdhc_writew_le,  	.write_b = esdhc_writeb_le, diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index da8e40af6f85..410a55b1c25f 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -250,7 +250,7 @@ static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,  	writel(vendor, host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);  } -void sdhci_arasan_reset(struct sdhci_host *host, u8 mask) +static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask)  {  	u8 ctrl;  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -265,6 +265,28 @@ void sdhci_arasan_reset(struct sdhci_host *host, u8 mask)  	}  } +static int sdhci_arasan_voltage_switch(struct mmc_host *mmc, +				       struct mmc_ios *ios) +{ +	switch (ios->signal_voltage) { +	case MMC_SIGNAL_VOLTAGE_180: +		/* +		 * Plese don't switch to 1V8 as arasan,5.1 doesn't +		 * actually refer to this setting to indicate the +		 * signal voltage and the state machine will be broken +		 * actually if we force to enable 1V8. That's something +		 * like broken quirk but we could work around here. +		 */ +		return 0; +	case MMC_SIGNAL_VOLTAGE_330: +	case MMC_SIGNAL_VOLTAGE_120: +		/* We don't support 3V3 and 1V2 */ +		break; +	} + +	return -EINVAL; +} +  static struct sdhci_ops sdhci_arasan_ops = {  	.set_clock = sdhci_arasan_set_clock,  	.get_max_clock = sdhci_pltfm_clk_get_max_clock, @@ -661,6 +683,8 @@ static int sdhci_arasan_probe(struct platform_device *pdev)  		host->mmc_host_ops.hs400_enhanced_strobe =  					sdhci_arasan_hs400_enhanced_strobe; +		host->mmc_host_ops.start_signal_voltage_switch = +					sdhci_arasan_voltage_switch;  	}  	ret = sdhci_add_host(host); diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 72a1f1f5180a..1d9e00a00e9f 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -32,6 +32,14 @@  #include "sdhci-pci.h"  #include "sdhci-pci-o2micro.h" +static int sdhci_pci_enable_dma(struct sdhci_host *host); +static void sdhci_pci_set_bus_width(struct sdhci_host *host, int width); +static void sdhci_pci_hw_reset(struct sdhci_host *host); +static int sdhci_pci_select_drive_strength(struct sdhci_host *host, +					   struct mmc_card *card, +					   unsigned int max_dtr, int host_drv, +					   int card_drv, int *drv_type); +  /*****************************************************************************\   *                                                                           *   * Hardware specific quirk handling                                          * @@ -390,6 +398,45 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)  	return 0;  } +#define SDHCI_INTEL_PWR_TIMEOUT_CNT	20 +#define SDHCI_INTEL_PWR_TIMEOUT_UDELAY	100 + +static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode, +				  unsigned short vdd) +{ +	int cntr; +	u8 reg; + +	sdhci_set_power(host, mode, vdd); + +	if (mode == MMC_POWER_OFF) +		return; + +	/* +	 * Bus power might not enable after D3 -> D0 transition due to the +	 * present state not yet having propagated. Retry for up to 2ms. +	 */ +	for (cntr = 0; cntr < SDHCI_INTEL_PWR_TIMEOUT_CNT; cntr++) { +		reg = sdhci_readb(host, SDHCI_POWER_CONTROL); +		if (reg & SDHCI_POWER_ON) +			break; +		udelay(SDHCI_INTEL_PWR_TIMEOUT_UDELAY); +		reg |= SDHCI_POWER_ON; +		sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); +	} +} + +static const struct sdhci_ops sdhci_intel_byt_ops = { +	.set_clock		= sdhci_set_clock, +	.set_power		= sdhci_intel_set_power, +	.enable_dma		= sdhci_pci_enable_dma, +	.set_bus_width		= sdhci_pci_set_bus_width, +	.reset			= sdhci_reset, +	.set_uhs_signaling	= sdhci_set_uhs_signaling, +	.hw_reset		= sdhci_pci_hw_reset, +	.select_drive_strength	= sdhci_pci_select_drive_strength, +}; +  static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {  	.allow_runtime_pm = true,  	.probe_slot	= byt_emmc_probe_slot, @@ -397,6 +444,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {  	.quirks2	= SDHCI_QUIRK2_PRESET_VALUE_BROKEN |  			  SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 |  			  SDHCI_QUIRK2_STOP_WITH_TC, +	.ops		= &sdhci_intel_byt_ops,  };  static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { @@ -405,6 +453,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {  			SDHCI_QUIRK2_PRESET_VALUE_BROKEN,  	.allow_runtime_pm = true,  	.probe_slot	= byt_sdio_probe_slot, +	.ops		= &sdhci_intel_byt_ops,  };  static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { @@ -415,6 +464,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {  	.allow_runtime_pm = true,  	.own_cd_for_runtime_pm = true,  	.probe_slot	= byt_sd_probe_slot, +	.ops		= &sdhci_intel_byt_ops,  };  /* Define Host controllers for Intel Merrifield platform */ @@ -1648,7 +1698,9 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(  	}  	host->hw_name = "PCI"; -	host->ops = &sdhci_pci_ops; +	host->ops = chip->fixes && chip->fixes->ops ? +		    chip->fixes->ops : +		    &sdhci_pci_ops;  	host->quirks = chip->quirks;  	host->quirks2 = chip->quirks2; diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index 9c7c08b93223..6bccf56bc5ff 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -65,6 +65,8 @@ struct sdhci_pci_fixes {  	int			(*suspend) (struct sdhci_pci_chip *);  	int			(*resume) (struct sdhci_pci_chip *); + +	const struct sdhci_ops	*ops;  };  struct sdhci_pci_slot { diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index dd1938d341f7..d0f5c05fbc19 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -315,7 +315,7 @@ static void pxav3_set_power(struct sdhci_host *host, unsigned char mode,  	struct mmc_host *mmc = host->mmc;  	u8 pwr = host->pwr; -	sdhci_set_power(host, mode, vdd); +	sdhci_set_power_noreg(host, mode, vdd);  	if (host->pwr == pwr)  		return; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 48055666c655..71654b90227f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -687,7 +687,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)  			 * host->clock is in Hz.  target_timeout is in us.  			 * Hence, us = 1000000 * cycles / Hz.  Round up.  			 */ -			val = 1000000 * data->timeout_clks; +			val = 1000000ULL * data->timeout_clks;  			if (do_div(val, host->clock))  				target_timeout++;  			target_timeout += val; @@ -1077,6 +1077,10 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)  	/* Initially, a command has no error */  	cmd->error = 0; +	if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) && +	    cmd->opcode == MMC_STOP_TRANSMISSION) +		cmd->flags |= MMC_RSP_BUSY; +  	/* Wait max 10 ms */  	timeout = 10; @@ -1390,8 +1394,8 @@ static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,  		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);  } -void sdhci_set_power(struct sdhci_host *host, unsigned char mode, -		     unsigned short vdd) +void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, +			   unsigned short vdd)  {  	u8 pwr = 0; @@ -1455,20 +1459,17 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode,  			mdelay(10);  	}  } -EXPORT_SYMBOL_GPL(sdhci_set_power); +EXPORT_SYMBOL_GPL(sdhci_set_power_noreg); -static void __sdhci_set_power(struct sdhci_host *host, unsigned char mode, -			      unsigned short vdd) +void sdhci_set_power(struct sdhci_host *host, unsigned char mode, +		     unsigned short vdd)  { -	struct mmc_host *mmc = host->mmc; - -	if (host->ops->set_power) -		host->ops->set_power(host, mode, vdd); -	else if (!IS_ERR(mmc->supply.vmmc)) -		sdhci_set_power_reg(host, mode, vdd); +	if (IS_ERR(host->mmc->supply.vmmc)) +		sdhci_set_power_noreg(host, mode, vdd);  	else -		sdhci_set_power(host, mode, vdd); +		sdhci_set_power_reg(host, mode, vdd);  } +EXPORT_SYMBOL_GPL(sdhci_set_power);  /*****************************************************************************\   *                                                                           * @@ -1609,7 +1610,10 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  		}  	} -	__sdhci_set_power(host, ios->power_mode, ios->vdd); +	if (host->ops->set_power) +		host->ops->set_power(host, ios->power_mode, ios->vdd); +	else +		sdhci_set_power(host, ios->power_mode, ios->vdd);  	if (host->ops->platform_send_init_74_clocks)  		host->ops->platform_send_init_74_clocks(host, ios->power_mode); @@ -2409,7 +2413,7 @@ static void sdhci_timeout_data_timer(unsigned long data)   *                                                                           *  \*****************************************************************************/ -static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) +static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)  {  	if (!host->cmd) {  		/* @@ -2453,11 +2457,6 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)  		return;  	} -	if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) && -	    !(host->cmd->flags & MMC_RSP_BUSY) && !host->data && -	    host->cmd->opcode == MMC_STOP_TRANSMISSION) -		*mask &= ~SDHCI_INT_DATA_END; -  	if (intmask & SDHCI_INT_RESPONSE)  		sdhci_finish_command(host);  } @@ -2680,8 +2679,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)  		}  		if (intmask & SDHCI_INT_CMD_MASK) -			sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK, -				      &intmask); +			sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);  		if (intmask & SDHCI_INT_DATA_MASK)  			sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index c722cd23205c..766df17fb7eb 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -683,6 +683,8 @@ u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,  void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);  void sdhci_set_power(struct sdhci_host *host, unsigned char mode,  		     unsigned short vdd); +void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, +			   unsigned short vdd);  void sdhci_set_bus_width(struct sdhci_host *host, int width);  void sdhci_reset(struct sdhci_host *host, u8 mask);  void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);  | 
