diff options
Diffstat (limited to 'drivers/mmc')
52 files changed, 1215 insertions, 761 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index ec21388311db..2436eb4996a4 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only  #  # MMC subsystem configuration  # diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 26ab7af4e0f9..3ea0126a9a72 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only  #  # Makefile for the kernel mmc device drivers.  # diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index 2f38a7ad07e0..c12fe13e4b14 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only  #  # MMC core configuration  # diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 3a4402a79904..6a51f7a06ce7 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -363,11 +363,11 @@ int mmc_of_parse_voltage(struct device_node *np, u32 *mask)  	int num_ranges, i;  	voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges); -	num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;  	if (!voltage_ranges) {  		pr_debug("%pOF: voltage-ranges unspecified\n", np);  		return 0;  	} +	num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;  	if (!num_ranges) {  		pr_err("%pOF: voltage-ranges empty\n", np);  		return -EINVAL; @@ -429,8 +429,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)  	if (mmc_gpio_alloc(host)) {  		put_device(&host->class_dev); -		ida_simple_remove(&mmc_host_ida, host->index); -		kfree(host);  		return NULL;  	} diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index c5208fb312ae..a533cab8fccc 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -184,11 +184,7 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)  		if (err)  			break; -		/* if we're just probing, do a single pass */ -		if (ocr == 0) -			break; - -		/* otherwise wait until reset completes */ +		/* wait until reset completes */  		if (mmc_host_is_spi(host)) {  			if (!(cmd.resp[0] & R1_SPI_IDLE))  				break; @@ -200,6 +196,16 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)  		err = -ETIMEDOUT;  		mmc_delay(10); + +		/* +		 * According to eMMC specification v5.1 section 6.4.3, we +		 * should issue CMD1 repeatedly in the idle state until +		 * the eMMC is ready. Otherwise some eMMC devices seem to enter +		 * the inactive mode after mmc_init_card() issued CMD0 when +		 * the eMMC device is busy. +		 */ +		if (!ocr && !mmc_host_is_spi(host)) +			cmd.arg = cmd.resp[0] | BIT(30);  	}  	if (rocr && !mmc_host_is_spi(host)) diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c index efb8a7965dd4..154f4204d58c 100644 --- a/drivers/mmc/core/pwrseq_emmc.c +++ b/drivers/mmc/core/pwrseq_emmc.c @@ -30,19 +30,14 @@ struct mmc_pwrseq_emmc {  #define to_pwrseq_emmc(p) container_of(p, struct mmc_pwrseq_emmc, pwrseq) -static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq) -{ -	gpiod_set_value(pwrseq->reset_gpio, 1); -	udelay(1); -	gpiod_set_value(pwrseq->reset_gpio, 0); -	udelay(200); -} -  static void mmc_pwrseq_emmc_reset(struct mmc_host *host)  {  	struct mmc_pwrseq_emmc *pwrseq =  to_pwrseq_emmc(host->pwrseq); -	__mmc_pwrseq_emmc_reset(pwrseq); +	gpiod_set_value_cansleep(pwrseq->reset_gpio, 1); +	udelay(1); +	gpiod_set_value_cansleep(pwrseq->reset_gpio, 0); +	udelay(200);  }  static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, @@ -50,8 +45,11 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,  {  	struct mmc_pwrseq_emmc *pwrseq = container_of(this,  					struct mmc_pwrseq_emmc, reset_nb); +	gpiod_set_value(pwrseq->reset_gpio, 1); +	udelay(1); +	gpiod_set_value(pwrseq->reset_gpio, 0); +	udelay(200); -	__mmc_pwrseq_emmc_reset(pwrseq);  	return NOTIFY_DONE;  } @@ -72,14 +70,18 @@ static int mmc_pwrseq_emmc_probe(struct platform_device *pdev)  	if (IS_ERR(pwrseq->reset_gpio))  		return PTR_ERR(pwrseq->reset_gpio); -	/* -	 * register reset handler to ensure emmc reset also from -	 * emergency_reboot(), priority 255 is the highest priority -	 * so it will be executed before any system reboot handler. -	 */ -	pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb; -	pwrseq->reset_nb.priority = 255; -	register_restart_handler(&pwrseq->reset_nb); +	if (!gpiod_cansleep(pwrseq->reset_gpio)) { +		/* +		 * register reset handler to ensure emmc reset also from +		 * emergency_reboot(), priority 255 is the highest priority +		 * so it will be executed before any system reboot handler. +		 */ +		pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb; +		pwrseq->reset_nb.priority = 255; +		register_restart_handler(&pwrseq->reset_nb); +	} else { +		dev_notice(dev, "EMMC reset pin tied to a sleepy GPIO driver; reset on emergency-reboot disabled\n"); +	}  	pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops;  	pwrseq->pwrseq.dev = dev; diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 7c364a9c4eeb..b5b9c6142f08 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -472,6 +472,7 @@ void mmc_cleanup_queue(struct mmc_queue *mq)  		blk_mq_unquiesce_queue(q);  	blk_cleanup_queue(q); +	blk_mq_free_tag_set(&mq->tag_set);  	/*  	 * A request can be completed before the next request, potentially diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index dd2f73af8f2c..2d2d9ea8be4f 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -159,7 +159,7 @@ static inline void mmc_fixup_device(struct mmc_card *card,  		    (f->ext_csd_rev == EXT_CSD_REV_ANY ||  		     f->ext_csd_rev == card->ext_csd.rev) &&  		    rev >= f->rev_start && rev <= f->rev_end) { -			dev_dbg(&card->dev, "calling %pf\n", f->vendor_fixup); +			dev_dbg(&card->dev, "calling %ps\n", f->vendor_fixup);  			f->vendor_fixup(card, f->data);  		}  	} diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 265e1aeeb9d8..d3d32f9a2cb1 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -221,6 +221,14 @@ static int mmc_decode_scr(struct mmc_card *card)  	if (scr->sda_spec3)  		scr->cmds = UNSTUFF_BITS(resp, 32, 2); + +	/* SD Spec says: any SD Card shall set at least bits 0 and 2 */ +	if (!(scr->bus_widths & SD_SCR_BUS_WIDTH_1) || +	    !(scr->bus_widths & SD_SCR_BUS_WIDTH_4)) { +		pr_err("%s: invalid bus width\n", mmc_hostname(card->host)); +		return -EINVAL; +	} +  	return 0;  } diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 28fcd8f580a1..931770f17087 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only  #  # MMC/SD host controller drivers  # @@ -92,6 +93,7 @@ config MMC_SDHCI_PCI  	tristate "SDHCI support on PCI bus"  	depends on MMC_SDHCI && PCI  	select MMC_CQHCI +	select IOSF_MBI if X86  	help  	  This selects the PCI Secure Digital Host Controller Interface.  	  Most controllers found today are PCI devices. @@ -437,7 +439,7 @@ config MMC_WBSD  	depends on ISA_DMA_API  	help  	  This selects the Winbond(R) W83L51xD Secure digital and -          Multimedia card Interface. +	  Multimedia card Interface.  	  If you have a machine with a integrated W83L518D or W83L519D  	  SD/MMC card reader, say Y or M here. @@ -515,7 +517,7 @@ config MMC_TIFM_SD  	  'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support  	  (TIFM_7XX1)'. -          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 tifm_sd.  config MMC_MVSDIO @@ -531,12 +533,12 @@ config MMC_MVSDIO  	  module will be called mvsdio.  config MMC_DAVINCI -        tristate "TI DAVINCI Multimedia Card Interface support" -        depends on ARCH_DAVINCI -        help -          This selects the TI DAVINCI Multimedia card Interface. -          If you have an DAVINCI board with a Multimedia Card slot, -          say Y or M here.  If unsure, say N. +	tristate "TI DAVINCI Multimedia Card Interface support" +	depends on ARCH_DAVINCI +	help +	  This selects the TI DAVINCI Multimedia card Interface. +	  If you have an DAVINCI board with a Multimedia Card slot, +	  say Y or M here.  If unsure, say N.  config MMC_GOLDFISH  	tristate "goldfish qemu Multimedia Card Interface support" @@ -565,18 +567,18 @@ config MMC_S3C  	depends on S3C24XX_DMAC  	help  	  This selects a driver for the MCI interface found in -          Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs. +	  Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.  	  If you have a board based on one of those and a MMC/SD  	  slot, say Y or M here.  	  If unsure, say N.  config MMC_S3C_HW_SDIO_IRQ -       bool "Hardware support for SDIO IRQ" -       depends on MMC_S3C -       help -         Enable the hardware support for SDIO interrupts instead of using -	 the generic polling code. +	bool "Hardware support for SDIO IRQ" +	depends on MMC_S3C +	help +	  Enable the hardware support for SDIO interrupts instead of using +	  the generic polling code.  choice  	prompt "Samsung S3C SD/MMC transfer code" @@ -941,6 +943,7 @@ config MMC_BCM2835  config MMC_MTK  	tristate "MediaTek SD/MMC Card Interface support"  	depends on HAS_DMA +	select REGULATOR  	help  	  This selects the MediaTek(R) Secure digital and Multimedia card Interface.  	  If you have a machine with a integrated SD/MMC card reader, say Y or M here. @@ -948,15 +951,16 @@ config MMC_MTK  	  If unsure, say N.  config MMC_SDHCI_MICROCHIP_PIC32 -        tristate "Microchip PIC32MZDA SDHCI support" -        depends on MMC_SDHCI && PIC32MZDA && MMC_SDHCI_PLTFM -        help -          This selects the Secure Digital Host Controller Interface (SDHCI) -          for PIC32MZDA platform. +	tristate "Microchip PIC32MZDA SDHCI support" +	depends on MMC_SDHCI && PIC32MZDA && MMC_SDHCI_PLTFM +	help +	  This selects the Secure Digital Host Controller Interface (SDHCI) +	  for PIC32MZDA platform. -          If you have a controller with this interface, say Y or M here. +	  If you have a controller with this interface, say Y or M here. + +	  If unsure, say N. -          If unsure, say N.  config MMC_SDHCI_BRCMSTB  	tristate "Broadcom SDIO/SD/MMC support"  	depends on ARCH_BRCMSTB || BMIPS_GENERIC @@ -993,6 +997,7 @@ config MMC_SDHCI_OMAP  config MMC_SDHCI_AM654  	tristate "Support for the SDHCI Controller in TI's AM654 SOCs"  	depends on MMC_SDHCI_PLTFM && OF +	select MMC_SDHCI_IO_ACCESSORS  	help  	  This selects the Secure Digital Host Controller Interface (SDHCI)  	  support present in TI's AM654 SOCs. The controller supports diff --git a/drivers/mmc/host/alcor.c b/drivers/mmc/host/alcor.c index 82a97866e0cf..e481535cba2b 100644 --- a/drivers/mmc/host/alcor.c +++ b/drivers/mmc/host/alcor.c @@ -43,12 +43,10 @@ struct alcor_sdmmc_host {  	struct  device *dev;  	struct alcor_pci_priv *alcor_pci; -	struct mmc_host *mmc;  	struct mmc_request *mrq;  	struct mmc_command *cmd;  	struct mmc_data *data;  	unsigned int dma_on:1; -	unsigned int early_data:1;  	struct mutex cmd_mutex; @@ -118,6 +116,9 @@ static void alcor_reset(struct alcor_sdmmc_host *host, u8 val)  	dev_err(host->dev, "%s: timeout\n", __func__);  } +/* + * Perform DMA I/O of a single page. + */  static void alcor_data_set_dma(struct alcor_sdmmc_host *host)  {  	struct alcor_pci_priv *priv = host->alcor_pci; @@ -144,8 +145,7 @@ static void alcor_data_set_dma(struct alcor_sdmmc_host *host)  	host->sg_count--;  } -static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host, -					bool early) +static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host)  {  	struct alcor_pci_priv *priv = host->alcor_pci;  	struct mmc_data *data = host->data; @@ -155,19 +155,26 @@ static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host,  		ctrl |= AU6601_DATA_WRITE;  	if (data->host_cookie == COOKIE_MAPPED) { -		if (host->early_data) { -			host->early_data = false; -			return; -		} - -		host->early_data = early; - +		/* +		 * For DMA transfers, this function is called just once, +		 * at the start of the operation. The hardware can only +		 * perform DMA I/O on a single page at a time, so here +		 * we kick off the transfer with the first page, and expect +		 * subsequent pages to be transferred upon IRQ events +		 * indicating that the single-page DMA was completed. +		 */  		alcor_data_set_dma(host);  		ctrl |= AU6601_DATA_DMA_MODE;  		host->dma_on = 1;  		alcor_write32(priv, data->sg_count * 0x1000,  			       AU6601_REG_BLOCK_SIZE);  	} else { +		/* +		 * For PIO transfers, we break down each operation +		 * into several sector-sized transfers. When one sector has +		 * complete, the IRQ handler will call this function again +		 * to kick off the transfer of the next sector. +		 */  		alcor_write32(priv, data->blksz, AU6601_REG_BLOCK_SIZE);  	} @@ -231,6 +238,7 @@ static void alcor_prepare_sg_miter(struct alcor_sdmmc_host *host)  static void alcor_prepare_data(struct alcor_sdmmc_host *host,  			       struct mmc_command *cmd)  { +	struct alcor_pci_priv *priv = host->alcor_pci;  	struct mmc_data *data = cmd->data;  	if (!data) @@ -248,7 +256,7 @@ static void alcor_prepare_data(struct alcor_sdmmc_host *host,  	if (data->host_cookie != COOKIE_MAPPED)  		alcor_prepare_sg_miter(host); -	alcor_trigger_data_transfer(host, true); +	alcor_write8(priv, 0, AU6601_DATA_XFER_CTRL);  }  static void alcor_send_cmd(struct alcor_sdmmc_host *host, @@ -284,7 +292,7 @@ static void alcor_send_cmd(struct alcor_sdmmc_host *host,  		break;  	default:  		dev_err(host->dev, "%s: cmd->flag (0x%02x) is not valid\n", -			mmc_hostname(host->mmc), mmc_resp_type(cmd)); +			mmc_hostname(mmc_from_priv(host)), mmc_resp_type(cmd));  		break;  	} @@ -325,7 +333,7 @@ static void alcor_request_complete(struct alcor_sdmmc_host *host,  	host->data = NULL;  	host->dma_on = 0; -	mmc_request_done(host->mmc, mrq); +	mmc_request_done(mmc_from_priv(host), mrq);  }  static void alcor_finish_data(struct alcor_sdmmc_host *host) @@ -435,7 +443,7 @@ static int alcor_cmd_irq_done(struct alcor_sdmmc_host *host, u32 intmask)  	if (!host->data)  		return false; -	alcor_trigger_data_transfer(host, false); +	alcor_trigger_data_transfer(host);  	host->cmd = NULL;  	return true;  } @@ -456,7 +464,7 @@ static void alcor_cmd_irq_thread(struct alcor_sdmmc_host *host, u32 intmask)  	if (!host->data)  		alcor_request_complete(host, 1);  	else -		alcor_trigger_data_transfer(host, false); +		alcor_trigger_data_transfer(host);  	host->cmd = NULL;  } @@ -487,15 +495,9 @@ static int alcor_data_irq_done(struct alcor_sdmmc_host *host, u32 intmask)  		break;  	case AU6601_INT_READ_BUF_RDY:  		alcor_trf_block_pio(host, true); -		if (!host->blocks) -			break; -		alcor_trigger_data_transfer(host, false);  		return 1;  	case AU6601_INT_WRITE_BUF_RDY:  		alcor_trf_block_pio(host, false); -		if (!host->blocks) -			break; -		alcor_trigger_data_transfer(host, false);  		return 1;  	case AU6601_INT_DMA_END:  		if (!host->sg_count) @@ -508,8 +510,14 @@ static int alcor_data_irq_done(struct alcor_sdmmc_host *host, u32 intmask)  		break;  	} -	if (intmask & AU6601_INT_DATA_END) -		return 0; +	if (intmask & AU6601_INT_DATA_END) { +		if (!host->dma_on && host->blocks) { +			alcor_trigger_data_transfer(host); +			return 1; +		} else { +			return 0; +		} +	}  	return 1;  } @@ -555,7 +563,7 @@ static void alcor_cd_irq(struct alcor_sdmmc_host *host, u32 intmask)  		alcor_request_complete(host, 1);  	} -	mmc_detect_change(host->mmc, msecs_to_jiffies(1)); +	mmc_detect_change(mmc_from_priv(host), msecs_to_jiffies(1));  }  static irqreturn_t alcor_irq_thread(int irq, void *d) @@ -779,12 +787,17 @@ static void alcor_pre_req(struct mmc_host *mmc,  	data->host_cookie = COOKIE_UNMAPPED;  	/* FIXME: looks like the DMA engine works only with CMD18 */ -	if (cmd->opcode != 18) +	if (cmd->opcode != MMC_READ_MULTIPLE_BLOCK +			&& cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK)  		return;  	/*  	 * We don't do DMA on "complex" transfers, i.e. with -	 * non-word-aligned buffers or lengths. Also, we don't bother -	 * with all the DMA setup overhead for short transfers. +	 * non-word-aligned buffers or lengths. A future improvement +	 * could be made to use temporary DMA bounce-buffers when these +	 * requirements are not met. +	 * +	 * Also, we don't bother with all the DMA setup overhead for +	 * short transfers.  	 */  	if (data->blocks * data->blksz < AU6601_MAX_DMA_BLOCK_SIZE)  		return; @@ -795,6 +808,8 @@ static void alcor_pre_req(struct mmc_host *mmc,  	for_each_sg(data->sg, sg, data->sg_len, i) {  		if (sg->length != AU6601_MAX_DMA_BLOCK_SIZE)  			return; +		if (sg->offset != 0) +			return;  	}  	/* This data might be unmapped at this time */ @@ -967,7 +982,6 @@ static void alcor_timeout_timer(struct work_struct *work)  		alcor_request_complete(host, 0);  	} -	mmiowb();  	mutex_unlock(&host->cmd_mutex);  } @@ -1033,7 +1047,7 @@ static void alcor_hw_uninit(struct alcor_sdmmc_host *host)  static void alcor_init_mmc(struct alcor_sdmmc_host *host)  { -	struct mmc_host *mmc = host->mmc; +	struct mmc_host *mmc = mmc_from_priv(host);  	mmc->f_min = AU6601_MIN_CLOCK;  	mmc->f_max = AU6601_MAX_CLOCK; @@ -1045,26 +1059,21 @@ static void alcor_init_mmc(struct alcor_sdmmc_host *host)  	mmc->ops = &alcor_sdc_ops;  	/* The hardware does DMA data transfer of 4096 bytes to/from a single -	 * buffer address. Scatterlists are not supported, but upon DMA -	 * completion (signalled via IRQ), the original vendor driver does -	 * then immediately set up another DMA transfer of the next 4096 -	 * bytes. -	 * -	 * This means that we need to handle the I/O in 4096 byte chunks. -	 * Lacking a way to limit the sglist entries to 4096 bytes, we instead -	 * impose that only one segment is provided, with maximum size 4096, -	 * which also happens to be the minimum size. This means that the -	 * single-entry sglist handled by this driver can be handed directly -	 * to the hardware, nice and simple. +	 * buffer address. Scatterlists are not supported at the hardware +	 * level, however we can work with them at the driver level, +	 * provided that each segment is exactly 4096 bytes in size. +	 * Upon DMA completion of a single segment (signalled via IRQ), we +	 * immediately proceed to transfer the next segment from the +	 * scatterlist.  	 * -	 * Unfortunately though, that means we only do 4096 bytes I/O per -	 * MMC command. A future improvement would be to make the driver -	 * accept sg lists and entries of any size, and simply iterate -	 * through them 4096 bytes at a time. +	 * The overall request is limited to 240 sectors, matching the +	 * original vendor driver.  	 */  	mmc->max_segs = AU6601_MAX_DMA_SEGMENTS;  	mmc->max_seg_size = AU6601_MAX_DMA_BLOCK_SIZE; -	mmc->max_req_size = mmc->max_seg_size; +	mmc->max_blk_count = 240; +	mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size; +	dma_set_max_seg_size(host->dev, mmc->max_seg_size);  }  static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev) @@ -1081,7 +1090,6 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev)  	}  	host = mmc_priv(mmc); -	host->mmc = mmc;  	host->dev = &pdev->dev;  	host->cur_power_mode = MMC_POWER_UNDEFINED;  	host->alcor_pci = priv; @@ -1113,13 +1121,14 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev)  static int alcor_pci_sdmmc_drv_remove(struct platform_device *pdev)  {  	struct alcor_sdmmc_host *host = dev_get_drvdata(&pdev->dev); +	struct mmc_host *mmc = mmc_from_priv(host);  	if (cancel_delayed_work_sync(&host->timeout_work))  		alcor_request_complete(host, 0);  	alcor_hw_uninit(host); -	mmc_remove_host(host->mmc); -	mmc_free_host(host->mmc); +	mmc_remove_host(mmc); +	mmc_free_host(mmc);  	return 0;  } diff --git a/drivers/mmc/host/cqhci.c b/drivers/mmc/host/cqhci.c index a8af682a9182..d59cb0a51964 100644 --- a/drivers/mmc/host/cqhci.c +++ b/drivers/mmc/host/cqhci.c @@ -537,6 +537,8 @@ static void cqhci_prep_dcmd_desc(struct mmc_host *mmc,  		 CQHCI_ACT(0x5) |  		 CQHCI_CMD_INDEX(mrq->cmd->opcode) |  		 CQHCI_CMD_TIMING(timing) | CQHCI_RESP_TYPE(resp_type)); +	if (cq_host->ops->update_dcmd_desc) +		cq_host->ops->update_dcmd_desc(mmc, mrq, &data);  	*task_desc |= data;  	desc = (u8 *)task_desc;  	pr_debug("%s: cqhci: dcmd: cmd: %d timing: %d resp: %d\n", diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h index 9e68286a07b4..1e8e01d81015 100644 --- a/drivers/mmc/host/cqhci.h +++ b/drivers/mmc/host/cqhci.h @@ -88,6 +88,7 @@  /* send status config 1 */  #define CQHCI_SSC1			0x40 +#define CQHCI_SSC1_CBC_MASK		GENMASK(19, 16)  /* send status config 2 */  #define CQHCI_SSC2			0x44 @@ -147,6 +148,7 @@  struct cqhci_host_ops;  struct mmc_host; +struct mmc_request;  struct cqhci_slot;  struct cqhci_host { @@ -210,6 +212,8 @@ struct cqhci_host_ops {  	u32 (*read_l)(struct cqhci_host *host, int reg);  	void (*enable)(struct mmc_host *mmc);  	void (*disable)(struct mmc_host *mmc, bool recovery); +	void (*update_dcmd_desc)(struct mmc_host *mmc, struct mmc_request *mrq, +				 u64 *data);  };  static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg) diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index f37003df1e01..ebfaeb33bc8c 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1,23 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later  /*   * davinci_mmc.c - TI DaVinci MMC/SD/SDIO driver   *   * Copyright (C) 2006 Texas Instruments.   *       Original author: Purushotam Kumar   * Copyright (C) 2009 David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   */  #include <linux/module.h> diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 2eba507790e4..c5a8af4ca76b 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -23,6 +23,7 @@  #include <linux/init.h>  #include <linux/delay.h>  #include <linux/device.h> +#include <linux/iopoll.h>  #include <linux/of_device.h>  #include <linux/platform_device.h>  #include <linux/ioport.h> @@ -48,6 +49,8 @@  #define   CLK_CORE_PHASE_MASK GENMASK(9, 8)  #define   CLK_TX_PHASE_MASK GENMASK(11, 10)  #define   CLK_RX_PHASE_MASK GENMASK(13, 12) +#define   CLK_PHASE_0 0 +#define   CLK_PHASE_180 2  #define   CLK_V2_TX_DELAY_MASK GENMASK(19, 16)  #define   CLK_V2_RX_DELAY_MASK GENMASK(23, 20)  #define   CLK_V2_ALWAYS_ON BIT(24) @@ -56,10 +59,6 @@  #define   CLK_V3_RX_DELAY_MASK GENMASK(27, 22)  #define   CLK_V3_ALWAYS_ON BIT(28) -#define   CLK_DELAY_STEP_PS 200 -#define   CLK_PHASE_STEP 30 -#define   CLK_PHASE_POINT_NUM (360 / CLK_PHASE_STEP) -  #define   CLK_TX_DELAY_MASK(h)		(h->data->tx_delay_mask)  #define   CLK_RX_DELAY_MASK(h)		(h->data->rx_delay_mask)  #define   CLK_ALWAYS_ON(h)		(h->data->always_on) @@ -164,10 +163,10 @@ struct meson_host {  	void __iomem *regs;  	struct clk *core_clk; +	struct clk *mux_clk;  	struct clk *mmc_clk; -	struct clk *rx_clk; -	struct clk *tx_clk;  	unsigned long req_rate; +	bool ddr;  	struct pinctrl *pinctrl;  	struct pinctrl_state *pins_default; @@ -207,90 +206,6 @@ struct meson_host {  #define CMD_RESP_MASK GENMASK(31, 1)  #define CMD_RESP_SRAM BIT(0) -struct meson_mmc_phase { -	struct clk_hw hw; -	void __iomem *reg; -	unsigned long phase_mask; -	unsigned long delay_mask; -	unsigned int delay_step_ps; -}; - -#define to_meson_mmc_phase(_hw) container_of(_hw, struct meson_mmc_phase, hw) - -static int meson_mmc_clk_get_phase(struct clk_hw *hw) -{ -	struct meson_mmc_phase *mmc = to_meson_mmc_phase(hw); -	unsigned int phase_num = 1 <<  hweight_long(mmc->phase_mask); -	unsigned long period_ps, p, d; -		int degrees; -	u32 val; - -	val = readl(mmc->reg); -	p = (val & mmc->phase_mask) >> __ffs(mmc->phase_mask); -	degrees = p * 360 / phase_num; - -	if (mmc->delay_mask) { -		period_ps = DIV_ROUND_UP((unsigned long)NSEC_PER_SEC * 1000, -					 clk_get_rate(hw->clk)); -		d = (val & mmc->delay_mask) >> __ffs(mmc->delay_mask); -		degrees += d * mmc->delay_step_ps * 360 / period_ps; -		degrees %= 360; -	} - -	return degrees; -} - -static void meson_mmc_apply_phase_delay(struct meson_mmc_phase *mmc, -					unsigned int phase, -					unsigned int delay) -{ -	u32 val; - -	val = readl(mmc->reg); -	val &= ~mmc->phase_mask; -	val |= phase << __ffs(mmc->phase_mask); - -	if (mmc->delay_mask) { -		val &= ~mmc->delay_mask; -		val |= delay << __ffs(mmc->delay_mask); -	} - -	writel(val, mmc->reg); -} - -static int meson_mmc_clk_set_phase(struct clk_hw *hw, int degrees) -{ -	struct meson_mmc_phase *mmc = to_meson_mmc_phase(hw); -	unsigned int phase_num = 1 <<  hweight_long(mmc->phase_mask); -	unsigned long period_ps, d = 0, r; -	uint64_t p; - -	p = degrees % 360; - -	if (!mmc->delay_mask) { -		p = DIV_ROUND_CLOSEST_ULL(p, 360 / phase_num); -	} else { -		period_ps = DIV_ROUND_UP((unsigned long)NSEC_PER_SEC * 1000, -					 clk_get_rate(hw->clk)); - -		/* First compute the phase index (p), the remainder (r) is the -		 * part we'll try to acheive using the delays (d). -		 */ -		r = do_div(p, 360 / phase_num); -		d = DIV_ROUND_CLOSEST(r * period_ps, -				      360 * mmc->delay_step_ps); -		d = min(d, mmc->delay_mask >> __ffs(mmc->delay_mask)); -	} - -	meson_mmc_apply_phase_delay(mmc, p, d); -	return 0; -} - -static const struct clk_ops meson_mmc_clk_phase_ops = { -	.get_phase = meson_mmc_clk_get_phase, -	.set_phase = meson_mmc_clk_set_phase, -}; -  static unsigned int meson_mmc_get_timeout_msecs(struct mmc_data *data)  {  	unsigned int timeout = data->timeout_ns / NSEC_PER_MSEC; @@ -383,16 +298,6 @@ static void meson_mmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,  			     mmc_get_dma_dir(data));  } -static bool meson_mmc_timing_is_ddr(struct mmc_ios *ios) -{ -	if (ios->timing == MMC_TIMING_MMC_DDR52 || -	    ios->timing == MMC_TIMING_UHS_DDR50 || -	    ios->timing == MMC_TIMING_MMC_HS400) -		return true; - -	return false; -} -  /*   * Gating the clock on this controller is tricky.  It seems the mmc clock   * is also used by the controller.  It may crash during some operation if the @@ -429,36 +334,41 @@ static void meson_mmc_clk_ungate(struct meson_host *host)  	writel(cfg, host->regs + SD_EMMC_CFG);  } -static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios) +static int meson_mmc_clk_set(struct meson_host *host, unsigned long rate, +			     bool ddr)  {  	struct mmc_host *mmc = host->mmc; -	unsigned long rate = ios->clock;  	int ret;  	u32 cfg; -	/* DDR modes require higher module clock */ -	if (meson_mmc_timing_is_ddr(ios)) -		rate <<= 1; -  	/* Same request - bail-out */ -	if (host->req_rate == rate) +	if (host->ddr == ddr && host->req_rate == rate)  		return 0;  	/* stop clock */  	meson_mmc_clk_gate(host);  	host->req_rate = 0; +	mmc->actual_clock = 0; -	if (!rate) { -		mmc->actual_clock = 0; -		/* return with clock being stopped */ +	/* return with clock being stopped */ +	if (!rate)  		return 0; -	}  	/* Stop the clock during rate change to avoid glitches */  	cfg = readl(host->regs + SD_EMMC_CFG);  	cfg |= CFG_STOP_CLOCK;  	writel(cfg, host->regs + SD_EMMC_CFG); +	if (ddr) { +		/* DDR modes require higher module clock */ +		rate <<= 1; +		cfg |= CFG_DDR; +	} else { +		cfg &= ~CFG_DDR; +	} +	writel(cfg, host->regs + SD_EMMC_CFG); +	host->ddr = ddr; +  	ret = clk_set_rate(host->mmc_clk, rate);  	if (ret) {  		dev_err(host->dev, "Unable to set cfg_div_clk to %lu. ret=%d\n", @@ -470,12 +380,14 @@ static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios)  	mmc->actual_clock = clk_get_rate(host->mmc_clk);  	/* We should report the real output frequency of the controller */ -	if (meson_mmc_timing_is_ddr(ios)) +	if (ddr) { +		host->req_rate >>= 1;  		mmc->actual_clock >>= 1; +	}  	dev_dbg(host->dev, "clk rate: %u Hz\n", mmc->actual_clock); -	if (ios->clock != mmc->actual_clock) -		dev_dbg(host->dev, "requested rate was %u\n", ios->clock); +	if (rate != mmc->actual_clock) +		dev_dbg(host->dev, "requested rate was %lu\n", rate);  	/* (re)start clock */  	meson_mmc_clk_ungate(host); @@ -493,8 +405,6 @@ static int meson_mmc_clk_init(struct meson_host *host)  	struct clk_init_data init;  	struct clk_mux *mux;  	struct clk_divider *div; -	struct meson_mmc_phase *core, *tx, *rx; -	struct clk *clk;  	char clk_name[32];  	int i, ret = 0;  	const char *mux_parent_names[MUX_CLK_NUM_PARENTS]; @@ -502,9 +412,11 @@ static int meson_mmc_clk_init(struct meson_host *host)  	u32 clk_reg;  	/* init SD_EMMC_CLOCK to sane defaults w/min clock rate */ -	clk_reg = 0; -	clk_reg |= CLK_ALWAYS_ON(host); +	clk_reg = CLK_ALWAYS_ON(host);  	clk_reg |= CLK_DIV_MASK; +	clk_reg |= FIELD_PREP(CLK_CORE_PHASE_MASK, CLK_PHASE_180); +	clk_reg |= FIELD_PREP(CLK_TX_PHASE_MASK, CLK_PHASE_0); +	clk_reg |= FIELD_PREP(CLK_RX_PHASE_MASK, CLK_PHASE_0);  	writel(clk_reg, host->regs + SD_EMMC_CLOCK);  	/* get the mux parents */ @@ -540,9 +452,9 @@ static int meson_mmc_clk_init(struct meson_host *host)  	mux->mask = CLK_SRC_MASK >> mux->shift;  	mux->hw.init = &init; -	clk = devm_clk_register(host->dev, &mux->hw); -	if (WARN_ON(IS_ERR(clk))) -		return PTR_ERR(clk); +	host->mux_clk = devm_clk_register(host->dev, &mux->hw); +	if (WARN_ON(IS_ERR(host->mux_clk))) +		return PTR_ERR(host->mux_clk);  	/* create the divider */  	div = devm_kzalloc(host->dev, sizeof(*div), GFP_KERNEL); @@ -553,7 +465,7 @@ static int meson_mmc_clk_init(struct meson_host *host)  	init.name = clk_name;  	init.ops = &clk_divider_ops;  	init.flags = CLK_SET_RATE_PARENT; -	clk_parent[0] = __clk_get_name(clk); +	clk_parent[0] = __clk_get_name(host->mux_clk);  	init.parent_names = clk_parent;  	init.num_parents = 1; @@ -563,190 +475,104 @@ static int meson_mmc_clk_init(struct meson_host *host)  	div->hw.init = &init;  	div->flags = CLK_DIVIDER_ONE_BASED; -	clk = devm_clk_register(host->dev, &div->hw); -	if (WARN_ON(IS_ERR(clk))) -		return PTR_ERR(clk); - -	/* create the mmc core clock */ -	core = devm_kzalloc(host->dev, sizeof(*core), GFP_KERNEL); -	if (!core) -		return -ENOMEM; - -	snprintf(clk_name, sizeof(clk_name), "%s#core", dev_name(host->dev)); -	init.name = clk_name; -	init.ops = &meson_mmc_clk_phase_ops; -	init.flags = CLK_SET_RATE_PARENT; -	clk_parent[0] = __clk_get_name(clk); -	init.parent_names = clk_parent; -	init.num_parents = 1; - -	core->reg = host->regs + SD_EMMC_CLOCK; -	core->phase_mask = CLK_CORE_PHASE_MASK; -	core->hw.init = &init; - -	host->mmc_clk = devm_clk_register(host->dev, &core->hw); -	if (WARN_ON(PTR_ERR_OR_ZERO(host->mmc_clk))) +	host->mmc_clk = devm_clk_register(host->dev, &div->hw); +	if (WARN_ON(IS_ERR(host->mmc_clk)))  		return PTR_ERR(host->mmc_clk); -	/* create the mmc tx clock */ -	tx = devm_kzalloc(host->dev, sizeof(*tx), GFP_KERNEL); -	if (!tx) -		return -ENOMEM; - -	snprintf(clk_name, sizeof(clk_name), "%s#tx", dev_name(host->dev)); -	init.name = clk_name; -	init.ops = &meson_mmc_clk_phase_ops; -	init.flags = 0; -	clk_parent[0] = __clk_get_name(host->mmc_clk); -	init.parent_names = clk_parent; -	init.num_parents = 1; - -	tx->reg = host->regs + SD_EMMC_CLOCK; -	tx->phase_mask = CLK_TX_PHASE_MASK; -	tx->delay_mask = CLK_TX_DELAY_MASK(host); -	tx->delay_step_ps = CLK_DELAY_STEP_PS; -	tx->hw.init = &init; - -	host->tx_clk = devm_clk_register(host->dev, &tx->hw); -	if (WARN_ON(PTR_ERR_OR_ZERO(host->tx_clk))) -		return PTR_ERR(host->tx_clk); - -	/* create the mmc rx clock */ -	rx = devm_kzalloc(host->dev, sizeof(*rx), GFP_KERNEL); -	if (!rx) -		return -ENOMEM; - -	snprintf(clk_name, sizeof(clk_name), "%s#rx", dev_name(host->dev)); -	init.name = clk_name; -	init.ops = &meson_mmc_clk_phase_ops; -	init.flags = 0; -	clk_parent[0] = __clk_get_name(host->mmc_clk); -	init.parent_names = clk_parent; -	init.num_parents = 1; - -	rx->reg = host->regs + SD_EMMC_CLOCK; -	rx->phase_mask = CLK_RX_PHASE_MASK; -	rx->delay_mask = CLK_RX_DELAY_MASK(host); -	rx->delay_step_ps = CLK_DELAY_STEP_PS; -	rx->hw.init = &init; - -	host->rx_clk = devm_clk_register(host->dev, &rx->hw); -	if (WARN_ON(PTR_ERR_OR_ZERO(host->rx_clk))) -		return PTR_ERR(host->rx_clk); -  	/* init SD_EMMC_CLOCK to sane defaults w/min clock rate */  	host->mmc->f_min = clk_round_rate(host->mmc_clk, 400000);  	ret = clk_set_rate(host->mmc_clk, host->mmc->f_min);  	if (ret)  		return ret; -	clk_set_phase(host->mmc_clk, 180); -	clk_set_phase(host->tx_clk, 0); -	clk_set_phase(host->rx_clk, 0); -  	return clk_prepare_enable(host->mmc_clk);  } -static void meson_mmc_shift_map(unsigned long *map, unsigned long shift) +static void meson_mmc_disable_resampling(struct meson_host *host)  { -	DECLARE_BITMAP(left, CLK_PHASE_POINT_NUM); -	DECLARE_BITMAP(right, CLK_PHASE_POINT_NUM); +	unsigned int val = readl(host->regs + host->data->adjust); -	/* -	 * shift the bitmap right and reintroduce the dropped bits on the left -	 * of the bitmap -	 */ -	bitmap_shift_right(right, map, shift, CLK_PHASE_POINT_NUM); -	bitmap_shift_left(left, map, CLK_PHASE_POINT_NUM - shift, -			  CLK_PHASE_POINT_NUM); -	bitmap_or(map, left, right, CLK_PHASE_POINT_NUM); +	val &= ~ADJUST_ADJ_EN; +	writel(val, host->regs + host->data->adjust);  } -static void meson_mmc_find_next_region(unsigned long *map, -				       unsigned long *start, -				       unsigned long *stop) +static void meson_mmc_reset_resampling(struct meson_host *host)  { -	*start = find_next_bit(map, CLK_PHASE_POINT_NUM, *start); -	*stop = find_next_zero_bit(map, CLK_PHASE_POINT_NUM, *start); +	unsigned int val; + +	meson_mmc_disable_resampling(host); + +	val = readl(host->regs + host->data->adjust); +	val &= ~ADJUST_ADJ_DELAY_MASK; +	writel(val, host->regs + host->data->adjust);  } -static int meson_mmc_find_tuning_point(unsigned long *test) +static int meson_mmc_resampling_tuning(struct mmc_host *mmc, u32 opcode)  { -	unsigned long shift, stop, offset = 0, start = 0, size = 0; +	struct meson_host *host = mmc_priv(mmc); +	unsigned int val, dly, max_dly, i; +	int ret; -	/* Get the all good/all bad situation out the way */ -	if (bitmap_full(test, CLK_PHASE_POINT_NUM)) -		return 0; /* All points are good so point 0 will do */ -	else if (bitmap_empty(test, CLK_PHASE_POINT_NUM)) -		return -EIO; /* No successful tuning point */ +	/* Resampling is done using the source clock */ +	max_dly = DIV_ROUND_UP(clk_get_rate(host->mux_clk), +			       clk_get_rate(host->mmc_clk)); -	/* -	 * Now we know there is a least one region find. Make sure it does -	 * not wrap by the shifting the bitmap if necessary -	 */ -	shift = find_first_zero_bit(test, CLK_PHASE_POINT_NUM); -	if (shift != 0) -		meson_mmc_shift_map(test, shift); +	val = readl(host->regs + host->data->adjust); +	val |= ADJUST_ADJ_EN; +	writel(val, host->regs + host->data->adjust); -	while (start < CLK_PHASE_POINT_NUM) { -		meson_mmc_find_next_region(test, &start, &stop); +	if (mmc->doing_retune) +		dly = FIELD_GET(ADJUST_ADJ_DELAY_MASK, val) + 1; +	else +		dly = 0; -		if ((stop - start) > size) { -			offset = start; -			size = stop - start; -		} +	for (i = 0; i < max_dly; i++) { +		val &= ~ADJUST_ADJ_DELAY_MASK; +		val |= FIELD_PREP(ADJUST_ADJ_DELAY_MASK, (dly + i) % max_dly); +		writel(val, host->regs + host->data->adjust); -		start = stop; +		ret = mmc_send_tuning(mmc, opcode, NULL); +		if (!ret) { +			dev_dbg(mmc_dev(mmc), "resampling delay: %u\n", +				(dly + i) % max_dly); +			return 0; +		}  	} -	/* Get the center point of the region */ -	offset += (size / 2); - -	/* Shift the result back */ -	offset = (offset + shift) % CLK_PHASE_POINT_NUM; - -	return offset; +	meson_mmc_reset_resampling(host); +	return -EIO;  } -static int meson_mmc_clk_phase_tuning(struct mmc_host *mmc, u32 opcode, -				      struct clk *clk) +static int meson_mmc_prepare_ios_clock(struct meson_host *host, +				       struct mmc_ios *ios)  { -	int point, ret; -	DECLARE_BITMAP(test, CLK_PHASE_POINT_NUM); +	bool ddr; -	dev_dbg(mmc_dev(mmc), "%s phase/delay tunning...\n", -		__clk_get_name(clk)); -	bitmap_zero(test, CLK_PHASE_POINT_NUM); +	switch (ios->timing) { +	case MMC_TIMING_MMC_DDR52: +	case MMC_TIMING_UHS_DDR50: +		ddr = true; +		break; -	/* Explore tuning points */ -	for (point = 0; point < CLK_PHASE_POINT_NUM; point++) { -		clk_set_phase(clk, point * CLK_PHASE_STEP); -		ret = mmc_send_tuning(mmc, opcode, NULL); -		if (!ret) -			set_bit(point, test); +	default: +		ddr = false; +		break;  	} -	/* Find the optimal tuning point and apply it */ -	point = meson_mmc_find_tuning_point(test); -	if (point < 0) -		return point; /* tuning failed */ - -	clk_set_phase(clk, point * CLK_PHASE_STEP); -	dev_dbg(mmc_dev(mmc), "success with phase: %d\n", -		clk_get_phase(clk)); -	return 0; +	return meson_mmc_clk_set(host, ios->clock, ddr);  } -static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode) +static void meson_mmc_check_resampling(struct meson_host *host, +				       struct mmc_ios *ios)  { -	struct meson_host *host = mmc_priv(mmc); -	int adj = 0; - -	/* enable signal resampling w/o delay */ -	adj = ADJUST_ADJ_EN; -	writel(adj, host->regs + host->data->adjust); - -	return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); +	switch (ios->timing) { +	case MMC_TIMING_LEGACY: +	case MMC_TIMING_MMC_HS: +	case MMC_TIMING_SD_HS: +	case MMC_TIMING_MMC_DDR52: +		meson_mmc_disable_resampling(host); +		break; +	}  }  static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) @@ -775,12 +601,6 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  		if (!IS_ERR(mmc->supply.vmmc))  			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); -		/* disable signal resampling */ -		writel(0, host->regs + host->data->adjust); - -		/* Reset rx phase */ -		clk_set_phase(host->rx_clk, 0); -  		break;  	case MMC_POWER_ON: @@ -817,20 +637,13 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	val = readl(host->regs + SD_EMMC_CFG);  	val &= ~CFG_BUS_WIDTH_MASK;  	val |= FIELD_PREP(CFG_BUS_WIDTH_MASK, bus_width); +	writel(val, host->regs + SD_EMMC_CFG); -	val &= ~CFG_DDR; -	if (meson_mmc_timing_is_ddr(ios)) -		val |= CFG_DDR; - -	val &= ~CFG_CHK_DS; -	if (ios->timing == MMC_TIMING_MMC_HS400) -		val |= CFG_CHK_DS; - -	err = meson_mmc_clk_set(host, ios); +	meson_mmc_check_resampling(host, ios); +	err = meson_mmc_prepare_ios_clock(host, ios);  	if (err)  		dev_err(host->dev, "Failed to set clock: %d\n,", err); -	writel(val, host->regs + SD_EMMC_CFG);  	dev_dbg(host->dev, "SD_EMMC_CFG:  0x%08x\n", val);  } @@ -1081,9 +894,6 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id)  	}  out: -	/* ack all enabled interrupts */ -	writel(irq_en, host->regs + SD_EMMC_STATUS); -  	if (cmd->error) {  		/* Stop desc in case of errors */  		u32 start = readl(host->regs + SD_EMMC_START); @@ -1095,12 +905,14 @@ out:  	if (ret == IRQ_HANDLED)  		meson_mmc_request_done(host->mmc, cmd->mrq); +	/* ack all raised interrupts */ +	writel(status, host->regs + SD_EMMC_STATUS); +  	return ret;  }  static int meson_mmc_wait_desc_stop(struct meson_host *host)  { -	int loop;  	u32 status;  	/* @@ -1110,20 +922,10 @@ static int meson_mmc_wait_desc_stop(struct meson_host *host)  	 * If we don't confirm the descriptor is stopped, it might raise new  	 * IRQs after we have called mmc_request_done() which is bad.  	 */ -	for (loop = 50; loop; loop--) { -		status = readl(host->regs + SD_EMMC_STATUS); -		if (status & (STATUS_BUSY | STATUS_DESC_BUSY)) -			udelay(100); -		else -			break; -	} - -	if (status & (STATUS_BUSY | STATUS_DESC_BUSY)) { -		dev_err(host->dev, "Timed out waiting for host to stop\n"); -		return -ETIMEDOUT; -	} -	return 0; +	return readl_poll_timeout(host->regs + SD_EMMC_STATUS, status, +				  !(status & (STATUS_BUSY | STATUS_DESC_BUSY)), +				  100, 5000);  }  static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id) @@ -1227,7 +1029,7 @@ static const struct mmc_host_ops meson_mmc_ops = {  	.get_cd         = meson_mmc_get_cd,  	.pre_req	= meson_mmc_pre_req,  	.post_req	= meson_mmc_post_req, -	.execute_tuning = meson_mmc_execute_tuning, +	.execute_tuning = meson_mmc_resampling_tuning,  	.card_busy	= meson_mmc_card_busy,  	.start_signal_voltage_switch = meson_mmc_voltage_switch,  }; @@ -1338,7 +1140,7 @@ static int meson_mmc_probe(struct platform_device *pdev)  	       host->regs + SD_EMMC_IRQ_EN);  	ret = request_threaded_irq(host->irq, meson_mmc_irq, -				   meson_mmc_irq_thread, IRQF_SHARED, +				   meson_mmc_irq_thread, IRQF_ONESHOT,  				   dev_name(&pdev->dev), host);  	if (ret)  		goto err_init_clk; @@ -1349,6 +1151,13 @@ static int meson_mmc_probe(struct platform_device *pdev)  	mmc->max_segs = SD_EMMC_DESC_BUF_LEN / sizeof(struct sd_emmc_desc);  	mmc->max_seg_size = mmc->max_req_size; +	/* +	 * At the moment, we don't know how to reliably enable HS400. +	 * From the different datasheets, it is not even clear if this mode +	 * is officially supported by any of the SoCs +	 */ +	mmc->caps2 &= ~MMC_CAP2_HS400; +  	/* data bounce buffer */  	host->bounce_buf_size = mmc->max_req_size;  	host->bounce_buf = diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c index ec980bda071c..b61de360f26f 100644 --- a/drivers/mmc/host/meson-mx-sdio.c +++ b/drivers/mmc/host/meson-mx-sdio.c @@ -19,6 +19,7 @@  #include <linux/dma-mapping.h>  #include <linux/module.h>  #include <linux/interrupt.h> +#include <linux/io.h>  #include <linux/ioport.h>  #include <linux/platform_device.h>  #include <linux/of_platform.h> diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 1b1498805972..19544b121276 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1,5 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later  /* - * mmc_spi.c - Access SD/MMC cards through SPI master controllers + * Access SD/MMC cards through SPI master controllers   *   * (C) Copyright 2005, Intec Automation,   *		Mike Lavender (mike@steroidmicros) @@ -8,21 +9,6 @@   *		Hans-Peter Nilsson ([email protected])   * (C) Copyright 2007, ATRON electronic GmbH,   *		Jan Nikitenko <[email protected]> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   */  #include <linux/sched.h>  #include <linux/delay.h> @@ -197,7 +183,7 @@ mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len)  static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout,  			unsigned n, u8 byte)  { -	u8		*cp = host->data->status; +	u8 *cp = host->data->status;  	unsigned long start = jiffies;  	while (1) { @@ -220,7 +206,7 @@ static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout,  		 * We use jiffies here because we want to have a relation  		 * between elapsed time and the blocking of the scheduler.  		 */ -		if (time_is_before_jiffies(start+1)) +		if (time_is_before_jiffies(start + 1))  			schedule();  	}  	return -ETIMEDOUT; @@ -415,7 +401,7 @@ checkstatus:  	default:  		dev_dbg(&host->spi->dev, "bad response type %04x\n", -				mmc_spi_resp_type(cmd)); +			mmc_spi_resp_type(cmd));  		if (value >= 0)  			value = -EINVAL;  		goto done; @@ -467,8 +453,8 @@ mmc_spi_command_send(struct mmc_spi_host *host,  	memset(cp, 0xff, sizeof(data->status));  	cp[1] = 0x40 | cmd->opcode; -	put_unaligned_be32(cmd->arg, cp+2); -	cp[6] = crc7_be(0, cp+1, 5) | 0x01; +	put_unaligned_be32(cmd->arg, cp + 2); +	cp[6] = crc7_be(0, cp + 1, 5) | 0x01;  	cp += 7;  	/* Then, read up to 13 bytes (while writing all-ones): @@ -642,9 +628,7 @@ mmc_spi_setup_data_message(  	if (multiple || direction == DMA_TO_DEVICE) {  		t = &host->early_status;  		memset(t, 0, sizeof(*t)); -		t->len = (direction == DMA_TO_DEVICE) -				? sizeof(scratch->status) -				: 1; +		t->len = (direction == DMA_TO_DEVICE) ? sizeof(scratch->status) : 1;  		t->tx_buf = host->ones;  		t->tx_dma = host->ones_dma;  		t->rx_buf = scratch->status; @@ -677,8 +661,7 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,  	u32			pattern;  	if (host->mmc->use_spi_crc) -		scratch->crc_val = cpu_to_be16( -				crc_itu_t(0, t->tx_buf, t->len)); +		scratch->crc_val = cpu_to_be16(crc_itu_t(0, t->tx_buf, t->len));  	if (host->dma_dev)  		dma_sync_single_for_device(host->dma_dev,  				host->data_dma, sizeof(*scratch), @@ -819,6 +802,10 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,  	}  	status = spi_sync_locked(spi, &host->m); +	if (status < 0) { +		dev_dbg(&spi->dev, "read error %d\n", status); +		return status; +	}  	if (host->dma_dev) {  		dma_sync_single_for_cpu(host->dma_dev, @@ -855,9 +842,9 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,  		be16_to_cpus(&scratch->crc_val);  		if (scratch->crc_val != crc) { -			dev_dbg(&spi->dev, "read - crc error: crc_val=0x%04x, " -					"computed=0x%04x len=%d\n", -					scratch->crc_val, crc, t->len); +			dev_dbg(&spi->dev, +				"read - crc error: crc_val=0x%04x, computed=0x%04x len=%d\n", +				scratch->crc_val, crc, t->len);  			return -EILSEQ;  		}  	} @@ -945,9 +932,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,  			dev_dbg(&host->spi->dev,  				"    mmc_spi: %s block, %d bytes\n", -				(direction == DMA_TO_DEVICE) -				? "write" -				: "read", +				(direction == DMA_TO_DEVICE) ? "write" : "read",  				t->len);  			if (direction == DMA_TO_DEVICE) @@ -974,8 +959,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,  		if (status < 0) {  			data->error = status;  			dev_dbg(&spi->dev, "%s status %d\n", -				(direction == DMA_TO_DEVICE) -					? "write" : "read", +				(direction == DMA_TO_DEVICE) ? "write" : "read",  				status);  			break;  		} @@ -1249,8 +1233,7 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  				mres = spi_setup(host->spi);  				if (mres < 0)  					dev_dbg(&host->spi->dev, -						"switch back to SPI mode 3" -						" failed\n"); +						"switch back to SPI mode 3 failed\n");  			}  		} @@ -1470,7 +1453,7 @@ static int mmc_spi_probe(struct spi_device *spi)  	return 0;  fail_add_host: -	mmc_remove_host (mmc); +	mmc_remove_host(mmc);  fail_glue_init:  	if (host->dma_dev)  		dma_unmap_single(host->dma_dev, host->data_dma, @@ -1485,7 +1468,6 @@ fail_ones_dma:  fail_nobuf1:  	mmc_free_host(mmc);  	mmc_spi_put_pdata(spi); -	dev_set_drvdata(&spi->dev, NULL);  nomem:  	kfree(ones); @@ -1496,32 +1478,27 @@ nomem:  static int mmc_spi_remove(struct spi_device *spi)  {  	struct mmc_host		*mmc = dev_get_drvdata(&spi->dev); -	struct mmc_spi_host	*host; - -	if (mmc) { -		host = mmc_priv(mmc); +	struct mmc_spi_host	*host = mmc_priv(mmc); -		/* prevent new mmc_detect_change() calls */ -		if (host->pdata && host->pdata->exit) -			host->pdata->exit(&spi->dev, mmc); +	/* prevent new mmc_detect_change() calls */ +	if (host->pdata && host->pdata->exit) +		host->pdata->exit(&spi->dev, mmc); -		mmc_remove_host(mmc); +	mmc_remove_host(mmc); -		if (host->dma_dev) { -			dma_unmap_single(host->dma_dev, host->ones_dma, -				MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); -			dma_unmap_single(host->dma_dev, host->data_dma, -				sizeof(*host->data), DMA_BIDIRECTIONAL); -		} +	if (host->dma_dev) { +		dma_unmap_single(host->dma_dev, host->ones_dma, +			MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); +		dma_unmap_single(host->dma_dev, host->data_dma, +			sizeof(*host->data), DMA_BIDIRECTIONAL); +	} -		kfree(host->data); -		kfree(host->ones); +	kfree(host->data); +	kfree(host->ones); -		spi->max_speed_hz = mmc->f_max; -		mmc_free_host(mmc); -		mmc_spi_put_pdata(spi); -		dev_set_drvdata(&spi->dev, NULL); -	} +	spi->max_speed_hz = mmc->f_max; +	mmc_free_host(mmc); +	mmc_spi_put_pdata(spi);  	return 0;  } @@ -1542,8 +1519,7 @@ static struct spi_driver mmc_spi_driver = {  module_spi_driver(mmc_spi_driver); -MODULE_AUTHOR("Mike Lavender, David Brownell, " -		"Hans-Peter Nilsson, Jan Nikitenko"); +MODULE_AUTHOR("Mike Lavender, David Brownell, Hans-Peter Nilsson, Jan Nikitenko");  MODULE_DESCRIPTION("SPI SD/MMC host driver");  MODULE_LICENSE("GPL");  MODULE_ALIAS("spi:mmc_spi"); diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 387ff14587b8..356833a606d5 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -43,21 +43,11 @@  #include <asm/io.h>  #include "mmci.h" -#include "mmci_qcom_dml.h"  #define DRIVER_NAME "mmci-pl18x" -#ifdef CONFIG_DMA_ENGINE -void mmci_variant_init(struct mmci_host *host); -#else -static inline void mmci_variant_init(struct mmci_host *host) {} -#endif - -#ifdef CONFIG_MMC_STM32_SDMMC -void sdmmc_variant_init(struct mmci_host *host); -#else -static inline void sdmmc_variant_init(struct mmci_host *host) {} -#endif +static void mmci_variant_init(struct mmci_host *host); +static void ux500v2_variant_init(struct mmci_host *host);  static unsigned int fmax = 515633; @@ -70,7 +60,6 @@ static struct variant_data variant_arm = {  	.cmdreg_srsp		= MCI_CPSM_RESPONSE,  	.datalength_bits	= 16,  	.datactrl_blocksz	= 11, -	.datactrl_dpsm_enable	= MCI_DPSM_ENABLE,  	.pwrreg_powerup		= MCI_PWR_UP,  	.f_max			= 100000000,  	.reversed_irq_handling	= true, @@ -90,7 +79,6 @@ static struct variant_data variant_arm_extended_fifo = {  	.cmdreg_srsp		= MCI_CPSM_RESPONSE,  	.datalength_bits	= 16,  	.datactrl_blocksz	= 11, -	.datactrl_dpsm_enable	= MCI_DPSM_ENABLE,  	.pwrreg_powerup		= MCI_PWR_UP,  	.f_max			= 100000000,  	.mmcimask1		= true, @@ -110,7 +98,6 @@ static struct variant_data variant_arm_extended_fifo_hwfc = {  	.cmdreg_srsp		= MCI_CPSM_RESPONSE,  	.datalength_bits	= 16,  	.datactrl_blocksz	= 11, -	.datactrl_dpsm_enable	= MCI_DPSM_ENABLE,  	.pwrreg_powerup		= MCI_PWR_UP,  	.f_max			= 100000000,  	.mmcimask1		= true, @@ -131,7 +118,6 @@ static struct variant_data variant_u300 = {  	.cmdreg_srsp		= MCI_CPSM_RESPONSE,  	.datalength_bits	= 16,  	.datactrl_blocksz	= 11, -	.datactrl_dpsm_enable	= MCI_DPSM_ENABLE,  	.datactrl_mask_sdio	= MCI_DPSM_ST_SDIOEN,  	.st_sdio			= true,  	.pwrreg_powerup		= MCI_PWR_ON, @@ -157,7 +143,6 @@ static struct variant_data variant_nomadik = {  	.cmdreg_srsp		= MCI_CPSM_RESPONSE,  	.datalength_bits	= 24,  	.datactrl_blocksz	= 11, -	.datactrl_dpsm_enable	= MCI_DPSM_ENABLE,  	.datactrl_mask_sdio	= MCI_DPSM_ST_SDIOEN,  	.st_sdio		= true,  	.st_clkdiv		= true, @@ -186,7 +171,6 @@ static struct variant_data variant_ux500 = {  	.cmdreg_srsp		= MCI_CPSM_RESPONSE,  	.datalength_bits	= 24,  	.datactrl_blocksz	= 11, -	.datactrl_dpsm_enable	= MCI_DPSM_ENABLE,  	.datactrl_mask_sdio	= MCI_DPSM_ST_SDIOEN,  	.st_sdio		= true,  	.st_clkdiv		= true, @@ -220,11 +204,9 @@ static struct variant_data variant_ux500v2 = {  	.datactrl_mask_ddrmode	= MCI_DPSM_ST_DDRMODE,  	.datalength_bits	= 24,  	.datactrl_blocksz	= 11, -	.datactrl_dpsm_enable	= MCI_DPSM_ENABLE,  	.datactrl_mask_sdio	= MCI_DPSM_ST_SDIOEN,  	.st_sdio		= true,  	.st_clkdiv		= true, -	.blksz_datactrl16	= true,  	.pwrreg_powerup		= MCI_PWR_ON,  	.f_max			= 100000000,  	.signal_direction	= true, @@ -238,7 +220,7 @@ static struct variant_data variant_ux500v2 = {  	.irq_pio_mask		= MCI_IRQ_PIO_MASK,  	.start_err		= MCI_STARTBITERR,  	.opendrain		= MCI_OD, -	.init			= mmci_variant_init, +	.init			= ux500v2_variant_init,  };  static struct variant_data variant_stm32 = { @@ -255,7 +237,6 @@ static struct variant_data variant_stm32 = {  	.irq_pio_mask		= MCI_IRQ_PIO_MASK,  	.datalength_bits	= 24,  	.datactrl_blocksz	= 11, -	.datactrl_dpsm_enable	= MCI_DPSM_ENABLE,  	.datactrl_mask_sdio	= MCI_DPSM_ST_SDIOEN,  	.st_sdio		= true,  	.st_clkdiv		= true, @@ -299,10 +280,8 @@ static struct variant_data variant_qcom = {  	.cmdreg_srsp_crc	= MCI_CPSM_RESPONSE,  	.cmdreg_srsp		= MCI_CPSM_RESPONSE,  	.data_cmd_enable	= MCI_CPSM_QCOM_DATCMD, -	.blksz_datactrl4	= true,  	.datalength_bits	= 24,  	.datactrl_blocksz	= 11, -	.datactrl_dpsm_enable	= MCI_DPSM_ENABLE,  	.pwrreg_powerup		= MCI_PWR_UP,  	.f_max			= 208000000,  	.explicit_mclk_control	= true, @@ -624,6 +603,16 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)  	sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);  } +static u32 mmci_get_dctrl_cfg(struct mmci_host *host) +{ +	return MCI_DPSM_ENABLE | mmci_dctrl_blksz(host); +} + +static u32 ux500v2_get_dctrl_cfg(struct mmci_host *host) +{ +	return MCI_DPSM_ENABLE | (host->data->blksz << 16); +} +  /*   * All the DMA operation mode stuff goes inside this ifdef.   * This assumes that you have a generic DMA device interface, @@ -886,15 +875,11 @@ int mmci_dmae_prep_data(struct mmci_host *host,  int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl)  {  	struct mmci_dmae_priv *dmae = host->dma_priv; -	struct mmc_data *data = host->data;  	host->dma_in_progress = true;  	dmaengine_submit(dmae->desc_current);  	dma_async_issue_pending(dmae->cur); -	if (host->variant->qcom_dml) -		dml_start_xfer(host, data); -  	*datactrl |= MCI_DPSM_DMAENABLE;  	return 0; @@ -952,6 +937,7 @@ void mmci_dmae_unprep_data(struct mmci_host *host,  static struct mmci_host_ops mmci_variant_ops = {  	.prep_data = mmci_dmae_prep_data,  	.unprep_data = mmci_dmae_unprep_data, +	.get_datactrl_cfg = mmci_get_dctrl_cfg,  	.get_next_data = mmci_dmae_get_next_data,  	.dma_setup = mmci_dmae_setup,  	.dma_release = mmci_dmae_release, @@ -959,12 +945,22 @@ static struct mmci_host_ops mmci_variant_ops = {  	.dma_finalize = mmci_dmae_finalize,  	.dma_error = mmci_dmae_error,  }; +#else +static struct mmci_host_ops mmci_variant_ops = { +	.get_datactrl_cfg = mmci_get_dctrl_cfg, +}; +#endif  void mmci_variant_init(struct mmci_host *host)  {  	host->ops = &mmci_variant_ops;  } -#endif + +void ux500v2_variant_init(struct mmci_host *host) +{ +	host->ops = &mmci_variant_ops; +	host->ops->get_datactrl_cfg = ux500v2_get_dctrl_cfg; +}  static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq)  { @@ -1000,7 +996,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)  	unsigned int datactrl, timeout, irqmask;  	unsigned long long clks;  	void __iomem *base; -	int blksz_bits;  	dev_dbg(mmc_dev(host->mmc), "blksz %04x blks %04x flags %08x\n",  		data->blksz, data->blocks, data->flags); @@ -1018,18 +1013,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)  	writel(timeout, base + MMCIDATATIMER);  	writel(host->size, base + MMCIDATALENGTH); -	blksz_bits = ffs(data->blksz) - 1; -	BUG_ON(1 << blksz_bits != data->blksz); - -	if (variant->blksz_datactrl16) -		datactrl = variant->datactrl_dpsm_enable | (data->blksz << 16); -	else if (variant->blksz_datactrl4) -		datactrl = variant->datactrl_dpsm_enable | (data->blksz << 4); -	else -		datactrl = variant->datactrl_dpsm_enable | blksz_bits << 4; - -	if (data->flags & MMC_DATA_READ) -		datactrl |= MCI_DPSM_DIRECTION; +	datactrl = host->ops->get_datactrl_cfg(host); +	datactrl |= host->data->flags & MMC_DATA_READ ? MCI_DPSM_DIRECTION : 0;  	if (host->mmc->card && mmc_card_sdio(host->mmc->card)) {  		u32 clk; @@ -1220,12 +1205,13 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,  	     unsigned int status)  {  	void __iomem *base = host->base; -	bool sbc; +	bool sbc, busy_resp;  	if (!cmd)  		return;  	sbc = (cmd == host->mrq->sbc); +	busy_resp = !!(cmd->flags & MMC_RSP_BUSY);  	/*  	 * We need to be one of these interrupts to be considered worth @@ -1239,8 +1225,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,  	/*  	 * ST Micro variant: handle busy detection.  	 */ -	if (host->variant->busy_detect) { -		bool busy_resp = !!(cmd->flags & MMC_RSP_BUSY); +	if (busy_resp && host->variant->busy_detect) {  		/* We are busy with a command, return */  		if (host->busy_status && @@ -1253,7 +1238,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,  		 * that the special busy status bit is still set before  		 * proceeding.  		 */ -		if (!host->busy_status && busy_resp && +		if (!host->busy_status &&  		    !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) &&  		    (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { @@ -1550,9 +1535,10 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)  		}  		/* -		 * Don't poll for busy completion in irq context. +		 * Busy detection has been handled by mmci_cmd_irq() above. +		 * Clear the status bit to prevent polling in IRQ context.  		 */ -		if (host->variant->busy_detect && host->busy_status) +		if (host->variant->busy_detect_flag)  			status &= ~host->variant->busy_detect_flag;  		ret = 1; diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 14df81054438..4f071bd34e59 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -131,6 +131,11 @@  /* Control register extensions in the Qualcomm versions */  #define MCI_DPSM_QCOM_DATA_PEND	BIT(17)  #define MCI_DPSM_QCOM_RX_DATA_PEND BIT(20) +/* Control register extensions in STM32 versions */ +#define MCI_DPSM_STM32_MODE_BLOCK	(0 << 2) +#define MCI_DPSM_STM32_MODE_SDIO	(1 << 2) +#define MCI_DPSM_STM32_MODE_STREAM	(2 << 2) +#define MCI_DPSM_STM32_MODE_BLOCK_STOP	(3 << 2)  #define MMCIDATACNT		0x030  #define MMCISTATUS		0x034 @@ -275,12 +280,8 @@ struct mmci_host;   * @st_clkdiv: true if using a ST-specific clock divider algorithm   * @stm32_clkdiv: true if using a STM32-specific clock divider algorithm   * @datactrl_mask_ddrmode: ddr mode mask in datactrl register. - * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register - * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl - *		     register   * @datactrl_mask_sdio: SDIO enable mask in datactrl register   * @datactrl_blksz: block size in power of two - * @datactrl_dpsm_enable: enable value for DPSM   * @datactrl_first: true if data must be setup before send command   * @datacnt_useless: true if you could not use datacnt register to read   *		     remaining data @@ -325,14 +326,11 @@ struct variant_data {  	unsigned int		datactrl_mask_ddrmode;  	unsigned int		datactrl_mask_sdio;  	unsigned int		datactrl_blocksz; -	unsigned int		datactrl_dpsm_enable;  	u8			datactrl_first:1;  	u8			datacnt_useless:1;  	u8			st_sdio:1;  	u8			st_clkdiv:1;  	u8			stm32_clkdiv:1; -	u8			blksz_datactrl16:1; -	u8			blksz_datactrl4:1;  	u32			pwrreg_powerup;  	u32			f_max;  	u8			signal_direction:1; @@ -362,6 +360,7 @@ struct mmci_host_ops {  			 bool next);  	void (*unprep_data)(struct mmci_host *host, struct mmc_data *data,  			    int err); +	u32 (*get_datactrl_cfg)(struct mmci_host *host);  	void (*get_next_data)(struct mmci_host *host, struct mmc_data *data);  	int (*dma_setup)(struct mmci_host *host);  	void (*dma_release)(struct mmci_host *host); @@ -429,6 +428,12 @@ struct mmci_host {  void mmci_write_clkreg(struct mmci_host *host, u32 clk);  void mmci_write_pwrreg(struct mmci_host *host, u32 pwr); +static inline u32 mmci_dctrl_blksz(struct mmci_host *host) +{ +	return (ffs(host->data->blksz) - 1) << 4; +} + +#ifdef CONFIG_DMA_ENGINE  int mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data,  			bool next);  void mmci_dmae_unprep_data(struct mmci_host *host, struct mmc_data *data, @@ -439,3 +444,16 @@ void mmci_dmae_release(struct mmci_host *host);  int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl);  void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data);  void mmci_dmae_error(struct mmci_host *host); +#endif + +#ifdef CONFIG_MMC_QCOM_DML +void qcom_variant_init(struct mmci_host *host); +#else +static inline void qcom_variant_init(struct mmci_host *host) {} +#endif + +#ifdef CONFIG_MMC_STM32_SDMMC +void sdmmc_variant_init(struct mmci_host *host); +#else +static inline void sdmmc_variant_init(struct mmci_host *host) {} +#endif diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c index 25d0a75533ea..3af396b3e0a0 100644 --- a/drivers/mmc/host/mmci_qcom_dml.c +++ b/drivers/mmc/host/mmci_qcom_dml.c @@ -54,10 +54,15 @@  #define DML_OFFSET			0x800 -void dml_start_xfer(struct mmci_host *host, struct mmc_data *data) +static int qcom_dma_start(struct mmci_host *host, unsigned int *datactrl)  {  	u32 config;  	void __iomem *base = host->base + DML_OFFSET; +	struct mmc_data *data = host->data; +	int ret = mmci_dmae_start(host, datactrl); + +	if (ret) +		return ret;  	if (data->flags & MMC_DATA_READ) {  		/* Read operation: configure DML for producer operation */ @@ -96,6 +101,7 @@ void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)  	/* make sure the dml is configured before dma is triggered */  	wmb(); +	return 0;  }  static int of_get_dml_pipe_index(struct device_node *np, const char *name) @@ -133,7 +139,6 @@ static int qcom_dma_setup(struct mmci_host *host)  	producer_id = of_get_dml_pipe_index(np, "rx");  	if (producer_id < 0 || consumer_id < 0) { -		host->variant->qcom_dml = false;  		mmci_dmae_release(host);  		return -EINVAL;  	} @@ -183,13 +188,19 @@ static int qcom_dma_setup(struct mmci_host *host)  	return 0;  } +static u32 qcom_get_dctrl_cfg(struct mmci_host *host) +{ +	return MCI_DPSM_ENABLE | (host->data->blksz << 4); +} +  static struct mmci_host_ops qcom_variant_ops = {  	.prep_data = mmci_dmae_prep_data,  	.unprep_data = mmci_dmae_unprep_data, +	.get_datactrl_cfg = qcom_get_dctrl_cfg,  	.get_next_data = mmci_dmae_get_next_data,  	.dma_setup = qcom_dma_setup,  	.dma_release = mmci_dmae_release, -	.dma_start = mmci_dmae_start, +	.dma_start = qcom_dma_start,  	.dma_finalize = mmci_dmae_finalize,  	.dma_error = mmci_dmae_error,  }; diff --git a/drivers/mmc/host/mmci_qcom_dml.h b/drivers/mmc/host/mmci_qcom_dml.h deleted file mode 100644 index fa16f6f4d4ad..000000000000 --- a/drivers/mmc/host/mmci_qcom_dml.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Copyright (c) 2011, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - */ -#ifndef __MMC_QCOM_DML_H__ -#define __MMC_QCOM_DML_H__ - -#ifdef CONFIG_MMC_QCOM_DML -void qcom_variant_init(struct mmci_host *host); -void dml_start_xfer(struct mmci_host *host, struct mmc_data *data); -#else -static inline void qcom_variant_init(struct mmci_host *host) -{ -} -static inline void dml_start_xfer(struct mmci_host *host, struct mmc_data *data) -{ -} -#endif /* CONFIG_MMC_QCOM_DML */ - -#endif /* __MMC_QCOM_DML_H__ */ diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c index cfbfc6f1048f..8e83ae6920ae 100644 --- a/drivers/mmc/host/mmci_stm32_sdmmc.c +++ b/drivers/mmc/host/mmci_stm32_sdmmc.c @@ -265,10 +265,28 @@ static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr)  	}  } +static u32 sdmmc_get_dctrl_cfg(struct mmci_host *host) +{ +	u32 datactrl; + +	datactrl = mmci_dctrl_blksz(host); + +	if (host->mmc->card && mmc_card_sdio(host->mmc->card) && +	    host->data->blocks == 1) +		datactrl |= MCI_DPSM_STM32_MODE_SDIO; +	else if (host->data->stop && !host->mrq->sbc) +		datactrl |= MCI_DPSM_STM32_MODE_BLOCK_STOP; +	else +		datactrl |= MCI_DPSM_STM32_MODE_BLOCK; + +	return datactrl; +} +  static struct mmci_host_ops sdmmc_variant_ops = {  	.validate_data = sdmmc_idma_validate_data,  	.prep_data = sdmmc_idma_prep_data,  	.unprep_data = sdmmc_idma_unprep_data, +	.get_datactrl_cfg = sdmmc_get_dctrl_cfg,  	.dma_setup = sdmmc_idma_setup,  	.dma_start = sdmmc_idma_start,  	.dma_finalize = sdmmc_idma_finalize, diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 833ef0590af8..c518cc208a1f 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -300,6 +300,8 @@  #define CMD_TIMEOUT         (HZ/10 * 5)	/* 100ms x5 */  #define DAT_TIMEOUT         (HZ    * 5)	/* 1000ms x5 */ +#define DEFAULT_DEBOUNCE	(8)	/* 8 cycles CD debounce */ +  #define PAD_DELAY_MAX	32 /* PAD delay cells */  /*--------------------------------------------------------------------------*/  /* Descriptor Structure                                                     */ @@ -372,6 +374,7 @@ struct mtk_mmc_compatible {  	bool stop_clk_fix;  	bool enhance_rx;  	bool support_64g; +	bool use_internal_cd;  };  struct msdc_tune_para { @@ -430,6 +433,7 @@ struct msdc_host {  	bool hs400_cmd_resp_sel_rising;  				 /* cmd response sample selection for HS400 */  	bool hs400_mode;	/* current eMMC will run at hs400 mode */ +	bool internal_cd;	/* Use internal card-detect logic */  	struct msdc_save_para save_para; /* used when gate HCLK */  	struct msdc_tune_para def_tune_para; /* default tune setting */  	struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */ @@ -507,6 +511,28 @@ static const struct mtk_mmc_compatible mt7622_compat = {  	.support_64g = false,  }; +static const struct mtk_mmc_compatible mt8516_compat = { +	.clk_div_bits = 12, +	.hs400_tune = false, +	.pad_tune_reg = MSDC_PAD_TUNE0, +	.async_fifo = true, +	.data_tune = true, +	.busy_check = true, +	.stop_clk_fix = true, +}; + +static const struct mtk_mmc_compatible mt7620_compat = { +	.clk_div_bits = 8, +	.hs400_tune = false, +	.pad_tune_reg = MSDC_PAD_TUNE, +	.async_fifo = false, +	.data_tune = false, +	.busy_check = false, +	.stop_clk_fix = false, +	.enhance_rx = false, +	.use_internal_cd = true, +}; +  static const struct of_device_id msdc_of_ids[] = {  	{ .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},  	{ .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, @@ -514,6 +540,8 @@ static const struct of_device_id msdc_of_ids[] = {  	{ .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat},  	{ .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat},  	{ .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat}, +	{ .compatible = "mediatek,mt8516-mmc", .data = &mt8516_compat}, +	{ .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat},  	{}  };  MODULE_DEVICE_TABLE(of, msdc_of_ids); @@ -1407,6 +1435,12 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)  			sdio_signal_irq(host->mmc);  		} +		if ((events & event_mask) & MSDC_INT_CDSC) { +			if (host->internal_cd) +				mmc_detect_change(host->mmc, msecs_to_jiffies(20)); +			events &= ~MSDC_INT_CDSC; +		} +  		if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ)))  			break; @@ -1440,14 +1474,24 @@ static void msdc_init_hw(struct msdc_host *host)  	/* Reset */  	msdc_reset_hw(host); -	/* Disable card detection */ -	sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN); -  	/* Disable and clear all interrupts */  	writel(0, host->base + MSDC_INTEN);  	val = readl(host->base + MSDC_INT);  	writel(val, host->base + MSDC_INT); +	/* Configure card detection */ +	if (host->internal_cd) { +		sdr_set_field(host->base + MSDC_PS, MSDC_PS_CDDEBOUNCE, +			      DEFAULT_DEBOUNCE); +		sdr_set_bits(host->base + MSDC_PS, MSDC_PS_CDEN); +		sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_CDSC); +		sdr_set_bits(host->base + SDC_CFG, SDC_CFG_INSWKUP); +	} else { +		sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_INSWKUP); +		sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN); +		sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_CDSC); +	} +  	if (host->top_base) {  		writel(0, host->top_base + EMMC_TOP_CONTROL);  		writel(0, host->top_base + EMMC_TOP_CMD); @@ -1557,6 +1601,13 @@ static void msdc_init_hw(struct msdc_host *host)  static void msdc_deinit_hw(struct msdc_host *host)  {  	u32 val; + +	if (host->internal_cd) { +		/* Disabled card-detect */ +		sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN); +		sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_INSWKUP); +	} +  	/* Disable and clear all interrupts */  	writel(0, host->base + MSDC_INTEN); @@ -2055,13 +2106,31 @@ static void msdc_ack_sdio_irq(struct mmc_host *mmc)  	__msdc_enable_sdio_irq(mmc, 1);  } +static int msdc_get_cd(struct mmc_host *mmc) +{ +	struct msdc_host *host = mmc_priv(mmc); +	int val; + +	if (mmc->caps & MMC_CAP_NONREMOVABLE) +		return 1; + +	if (!host->internal_cd) +		return mmc_gpio_get_cd(mmc); + +	val = readl(host->base + MSDC_PS) & MSDC_PS_CDSTS; +	if (mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH) +		return !!val; +	else +		return !val; +} +  static const struct mmc_host_ops mt_msdc_ops = {  	.post_req = msdc_post_req,  	.pre_req = msdc_pre_req,  	.request = msdc_ops_request,  	.set_ios = msdc_ops_set_ios,  	.get_ro = mmc_gpio_get_ro, -	.get_cd = mmc_gpio_get_cd, +	.get_cd = msdc_get_cd,  	.enable_sdio_irq = msdc_enable_sdio_irq,  	.ack_sdio_irq = msdc_ack_sdio_irq,  	.start_signal_voltage_switch = msdc_ops_switch_volt, @@ -2123,9 +2192,11 @@ static int msdc_drv_probe(struct platform_device *pdev)  	}  	res = platform_get_resource(pdev, IORESOURCE_MEM, 1); -	host->top_base = devm_ioremap_resource(&pdev->dev, res); -	if (IS_ERR(host->top_base)) -		host->top_base = NULL; +	if (res) { +		host->top_base = devm_ioremap_resource(&pdev->dev, res); +		if (IS_ERR(host->top_base)) +			host->top_base = NULL; +	}  	ret = mmc_regulator_get_supply(mmc);  	if (ret) @@ -2191,6 +2262,16 @@ static int msdc_drv_probe(struct platform_device *pdev)  	else  		mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 4095); +	if (!(mmc->caps & MMC_CAP_NONREMOVABLE) && +	    !mmc_can_gpio_cd(mmc) && +	    host->dev_comp->use_internal_cd) { +		/* +		 * Is removable but no GPIO declared, so +		 * use internal functionality. +		 */ +		host->internal_cd = true; +	} +  	if (mmc->caps & MMC_CAP_SDIO_IRQ)  		mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; @@ -2227,7 +2308,7 @@ static int msdc_drv_probe(struct platform_device *pdev)  	msdc_init_hw(host);  	ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq, -		IRQF_TRIGGER_LOW | IRQF_ONESHOT, pdev->name, host); +			       IRQF_TRIGGER_NONE, pdev->name, host);  	if (ret)  		goto release; diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index e22bbff89c8d..9cb93e15b197 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -24,7 +24,7 @@  #include <linux/mmc/host.h>  #include <linux/mmc/slot-gpio.h> -#include <asm/sizes.h> +#include <linux/sizes.h>  #include <asm/unaligned.h>  #include "mvsdio.h" diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 4f06fb03c0a2..b334e81c5cab 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -1,23 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later  /*   * Portions copyright (C) 2003 Russell King, PXA MMCI Driver   * Portions copyright (C) 2004-2005 Pierre Ossman, W83L51xD SD/MMC driver   *   * Copyright 2008 Embedded Alley Solutions, Inc.   * Copyright 2009-2011 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.   */  #include <linux/kernel.h> @@ -648,7 +635,8 @@ static int mxs_mmc_probe(struct platform_device *pdev)  	/* set mmc core parameters */  	mmc->ops = &mxs_mmc_ops;  	mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | -		    MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL | MMC_CAP_CMD23; +		    MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL | MMC_CAP_CMD23 | +		    MMC_CAP_ERASE;  	host->broken_cd = of_property_read_bool(np, "broken-cd"); diff --git a/drivers/mmc/host/of_mmc_spi.c b/drivers/mmc/host/of_mmc_spi.c index 8a274b91804e..3c4d950a4755 100644 --- a/drivers/mmc/host/of_mmc_spi.c +++ b/drivers/mmc/host/of_mmc_spi.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later  /*   * OpenFirmware bindings for the MMC-over-SPI driver   *   * Copyright (c) MontaVista Software, Inc. 2008.   *   * Author: Anton Vorontsov <[email protected]> - * - * This program is free software; you can redistribute  it and/or modify it - * under  the terms of  the GNU General  Public License as published by the - * Free Software Foundation;  either version 2 of the  License, or (at your - * option) any later version.   */  #include <linux/kernel.h> diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 29a1ddaa7466..952fa4063ff8 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2077,7 +2077,7 @@ static int omap_hsmmc_runtime_suspend(struct device *dev)  	unsigned long flags;  	int ret = 0; -	host = platform_get_drvdata(to_platform_device(dev)); +	host = dev_get_drvdata(dev);  	omap_hsmmc_context_save(host);  	dev_dbg(dev, "disabled\n"); @@ -2118,7 +2118,7 @@ static int omap_hsmmc_runtime_resume(struct device *dev)  	struct omap_hsmmc_host *host;  	unsigned long flags; -	host = platform_get_drvdata(to_platform_device(dev)); +	host = dev_get_drvdata(dev);  	omap_hsmmc_context_restore(host);  	dev_dbg(dev, "enabled\n"); diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index c1d3f0e38921..e7d80c83da2c 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -35,7 +35,7 @@  #include <linux/of.h>  #include <linux/of_device.h> -#include <asm/sizes.h> +#include <linux/sizes.h>  #include <mach/hardware.h>  #include <linux/platform_data/mmc-pxamci.h> diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index 8394a7bb1fc1..c0504aa90857 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -3,7 +3,7 @@   * Renesas Mobile SDHI   *   * Copyright (C) 2017 Horms Solutions Ltd., Simon Horman - * Copyright (C) 2017 Renesas Electronics Corporation + * Copyright (C) 2017-19 Renesas Electronics Corporation   */  #ifndef RENESAS_SDHI_H diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 8742e27e4e8b..5e9e36ed2107 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -2,8 +2,8 @@  /*   * Renesas SDHI   * - * Copyright (C) 2015-17 Renesas Electronics Corporation - * Copyright (C) 2016-17 Sang Engineering, Wolfram Sang + * Copyright (C) 2015-19 Renesas Electronics Corporation + * Copyright (C) 2016-19 Sang Engineering, Wolfram Sang   * Copyright (C) 2016-17 Horms Solutions, Simon Horman   * Copyright (C) 2009 Magnus Damm   * @@ -779,14 +779,14 @@ int renesas_sdhi_probe(struct platform_device *pdev,  	if (ver < SDHI_VER_GEN2_SDR104 && mmc_data->max_blk_count > U16_MAX)  		mmc_data->max_blk_count = U16_MAX; -	ret = tmio_mmc_host_probe(host); -	if (ret < 0) -		goto edisclk; -  	/* One Gen2 SDHI incarnation does NOT have a CBSY bit */  	if (ver == SDHI_VER_GEN2_SDR50)  		mmc_data->flags &= ~TMIO_MMC_HAVE_CBSY; +	ret = tmio_mmc_host_probe(host); +	if (ret < 0) +		goto edisclk; +  	/* Enable tuning iff we have an SCC and a supported mode */  	if (of_data && of_data->scc_offset &&  	    (host->mmc->caps & MMC_CAP_UHS_SDR104 || diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 9dfafa2a90a3..751fe91c7571 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -2,8 +2,9 @@  /*   * DMA support for Internal DMAC with SDHI SD/SDIO controller   * - * Copyright (C) 2016-17 Renesas Electronics Corporation + * Copyright (C) 2016-19 Renesas Electronics Corporation   * Copyright (C) 2016-17 Horms Solutions, Simon Horman + * Copyright (C) 2018-19 Sang Engineering, Wolfram Sang   */  #include <linux/bitops.h> @@ -95,8 +96,8 @@ static const struct renesas_sdhi_of_data of_rza2_compatible = {  	.scc_offset	= 0 - 0x1000,  	.taps		= rcar_gen3_scc_taps,  	.taps_num	= ARRAY_SIZE(rcar_gen3_scc_taps), -	/* DMAC can handle 0xffffffff blk count but only 1 segment */ -	.max_blk_count	= 0xffffffff, +	/* DMAC can handle 32bit blk count but only 1 segment */ +	.max_blk_count	= UINT_MAX / TMIO_MAX_BLK_SIZE,  	.max_segs	= 1,  }; @@ -110,8 +111,8 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {  	.scc_offset	= 0x1000,  	.taps		= rcar_gen3_scc_taps,  	.taps_num	= ARRAY_SIZE(rcar_gen3_scc_taps), -	/* DMAC can handle 0xffffffff blk count but only 1 segment */ -	.max_blk_count	= 0xffffffff, +	/* DMAC can handle 32bit blk count but only 1 segment */ +	.max_blk_count	= UINT_MAX / TMIO_MAX_BLK_SIZE,  	.max_segs	= 1,  }; diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c index 02cd878e209f..1d29b822efb8 100644 --- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c @@ -2,8 +2,8 @@  /*   * DMA support use of SYS DMAC with SDHI SD/SDIO controller   * - * Copyright (C) 2016-17 Renesas Electronics Corporation - * Copyright (C) 2016-17 Sang Engineering, Wolfram Sang + * Copyright (C) 2016-19 Renesas Electronics Corporation + * Copyright (C) 2016-19 Sang Engineering, Wolfram Sang   * Copyright (C) 2017 Horms Solutions, Simon Horman   * Copyright (C) 2010-2011 Guennadi Liakhovetski   */ @@ -65,7 +65,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = {  	.scc_offset	= 0x0300,  	.taps		= rcar_gen2_scc_taps,  	.taps_num	= ARRAY_SIZE(rcar_gen2_scc_taps), -	.max_blk_count  = 0xffffffff, +	.max_blk_count	= UINT_MAX / TMIO_MAX_BLK_SIZE,  };  /* Definitions for sampling clocks */ diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 30bd8081307e..bd50935dc37d 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later  /* Realtek PCI-Express SD/MMC Card Interface driver   *   * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.   * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - *   * Author:   *   Wei WANG <[email protected]>   */ diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 8dbbc1f62b70..c391510e9ef4 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -14,6 +14,7 @@  #include <linux/clk.h>  #include <linux/module.h>  #include <linux/slab.h> +#include <linux/pm_qos.h>  #include <linux/mmc/host.h>  #include <linux/mmc/mmc.h>  #include <linux/mmc/sdio.h> @@ -73,6 +74,7 @@  #define ESDHC_STROBE_DLL_CTRL_ENABLE	(1 << 0)  #define ESDHC_STROBE_DLL_CTRL_RESET	(1 << 1)  #define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT	3 +#define ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT	(4 << 20)  #define ESDHC_STROBE_DLL_STATUS		0x74  #define ESDHC_STROBE_DLL_STS_REF_LOCK	(1 << 1) @@ -156,6 +158,8 @@  #define ESDHC_FLAG_HS400_ES		BIT(11)  /* The IP has Host Controller Interface for Command Queuing */  #define ESDHC_FLAG_CQHCI		BIT(12) +/* need request pmqos during low power */ +#define ESDHC_FLAG_PMQOS		BIT(13)  struct esdhc_soc_data {  	u32 flags; @@ -204,6 +208,12 @@ static const struct esdhc_soc_data usdhc_imx7d_data = {  			| ESDHC_FLAG_HS400,  }; +static struct esdhc_soc_data usdhc_imx7ulp_data = { +	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING +			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 +			| ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400, +}; +  static struct esdhc_soc_data usdhc_imx8qxp_data = {  	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING  			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 @@ -229,6 +239,7 @@ struct pltfm_imx_data {  		WAIT_FOR_INT,        /* sent CMD12, waiting for response INT */  	} multiblock_status;  	u32 is_ddr; +	struct pm_qos_request pm_qos_req;  };  static const struct platform_device_id imx_esdhc_devtype[] = { @@ -257,6 +268,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = {  	{ .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, },  	{ .compatible = "fsl,imx6ull-usdhc", .data = &usdhc_imx6ull_data, },  	{ .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, }, +	{ .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, },  	{ .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, },  	{ /* sentinel */ }  }; @@ -983,15 +995,19 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host)  	/* force a reset on strobe dll */  	writel(ESDHC_STROBE_DLL_CTRL_RESET,  		host->ioaddr + ESDHC_STROBE_DLL_CTRL); +	/* clear the reset bit on strobe dll before any setting */ +	writel(0, host->ioaddr + ESDHC_STROBE_DLL_CTRL); +  	/*  	 * enable strobe dll ctrl and adjust the delay target  	 * for the uSDHC loopback read clock  	 */  	v = ESDHC_STROBE_DLL_CTRL_ENABLE | +		ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT |  		(7 << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT);  	writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL); -	/* wait 1us to make sure strobe dll status register stable */ -	udelay(1); +	/* wait 5us to make sure strobe dll status register stable */ +	udelay(5);  	v = readl(host->ioaddr + ESDHC_STROBE_DLL_STATUS);  	if (!(v & ESDHC_STROBE_DLL_STS_REF_LOCK))  		dev_warn(mmc_dev(host->mmc), @@ -1436,6 +1452,10 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)  	imx_data->socdata = of_id ? of_id->data : (struct esdhc_soc_data *)  						  pdev->id_entry->driver_data; +	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) +		pm_qos_add_request(&imx_data->pm_qos_req, +			PM_QOS_CPU_DMA_LATENCY, 0); +  	imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg");  	if (IS_ERR(imx_data->clk_ipg)) {  		err = PTR_ERR(imx_data->clk_ipg); @@ -1557,6 +1577,8 @@ disable_ipg_clk:  disable_per_clk:  	clk_disable_unprepare(imx_data->clk_per);  free_sdhci: +	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) +		pm_qos_remove_request(&imx_data->pm_qos_req);  	sdhci_pltfm_free(pdev);  	return err;  } @@ -1578,6 +1600,9 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)  	clk_disable_unprepare(imx_data->clk_ipg);  	clk_disable_unprepare(imx_data->clk_ahb); +	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) +		pm_qos_remove_request(&imx_data->pm_qos_req); +  	sdhci_pltfm_free(pdev);  	return 0; @@ -1649,6 +1674,9 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev)  	}  	clk_disable_unprepare(imx_data->clk_ahb); +	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) +		pm_qos_remove_request(&imx_data->pm_qos_req); +  	return ret;  } @@ -1659,9 +1687,13 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)  	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);  	int err; +	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) +		pm_qos_add_request(&imx_data->pm_qos_req, +			PM_QOS_CPU_DMA_LATENCY, 0); +  	err = clk_prepare_enable(imx_data->clk_ahb);  	if (err) -		return err; +		goto remove_pm_qos_request;  	if (!sdhci_sdio_irq_enabled(host)) {  		err = clk_prepare_enable(imx_data->clk_per); @@ -1690,6 +1722,9 @@ disable_per_clk:  		clk_disable_unprepare(imx_data->clk_per);  disable_ahb_clk:  	clk_disable_unprepare(imx_data->clk_ahb); +remove_pm_qos_request: +	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) +		pm_qos_remove_request(&imx_data->pm_qos_req);  	return err;  }  #endif diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index 9d12c06c7fd6..2feb4ef32035 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -196,7 +196,8 @@ static const struct sdhci_ops sdhci_iproc_32only_ops = {  };  static const struct sdhci_pltfm_data sdhci_iproc_cygnus_pltfm_data = { -	.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK, +	.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | +		  SDHCI_QUIRK_NO_HISPD_BIT,  	.quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN | SDHCI_QUIRK2_HOST_OFF_CARD_ON,  	.ops = &sdhci_iproc_32only_ops,  }; @@ -219,7 +220,8 @@ static const struct sdhci_iproc_data iproc_cygnus_data = {  static const struct sdhci_pltfm_data sdhci_iproc_pltfm_data = {  	.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | -		  SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12, +		  SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 | +		  SDHCI_QUIRK_NO_HISPD_BIT,  	.quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN,  	.ops = &sdhci_iproc_ops,  }; diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index c9e3e050ccc8..88dc3f00a5be 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -832,7 +832,10 @@ static int sdhci_arasan_probe(struct platform_device *pdev)  		host->mmc_host_ops.start_signal_voltage_switch =  					sdhci_arasan_voltage_switch;  		sdhci_arasan->has_cqe = true; -		host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; +		host->mmc->caps2 |= MMC_CAP2_CQE; + +		if (!of_property_read_bool(np, "disable-cqe-dcmd")) +			host->mmc->caps2 |= MMC_CAP2_CQE_DCMD;  	}  	ret = sdhci_arasan_add_host(sdhci_arasan); diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 4e669b4edfc1..e20c00f14109 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -24,6 +24,7 @@  #include <linux/ktime.h>  #include <linux/dma-mapping.h>  #include <linux/mmc/host.h> +#include <linux/mmc/mmc.h>  #include "sdhci-pltfm.h"  #include "sdhci-esdhc.h" @@ -81,6 +82,7 @@ struct sdhci_esdhc {  	bool quirk_limited_clk_division;  	bool quirk_unreliable_pulse_detection;  	bool quirk_fixup_tuning; +	bool quirk_ignore_data_inhibit;  	unsigned int peripheral_clock;  	const struct esdhc_clk_fixup *clk_fixup;  	u32 div_ratio; @@ -147,6 +149,19 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host,  		return ret;  	} +	/* +	 * Some controllers have unreliable Data Line Active +	 * bit for commands with busy signal. This affects +	 * Command Inhibit (data) bit. Just ignore it since +	 * MMC core driver has already polled card status +	 * with CMD13 after any command with busy siganl. +	 */ +	if ((spec_reg == SDHCI_PRESENT_STATE) && +	(esdhc->quirk_ignore_data_inhibit == true)) { +		ret = value & ~SDHCI_DATA_INHIBIT; +		return ret; +	} +  	ret = value;  	return ret;  } @@ -694,6 +709,9 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)  	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);  	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); +	if (of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc")) +		mdelay(5); +  	if (mask & SDHCI_RESET_ALL) {  		val = sdhci_readl(host, ESDHC_TBCTL);  		val &= ~ESDHC_TB_EN; @@ -864,6 +882,25 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host,  		sdhci_set_uhs_signaling(host, timing);  } +static u32 esdhc_irq(struct sdhci_host *host, u32 intmask) +{ +	u32 command; + +	if (of_find_compatible_node(NULL, NULL, +				"fsl,p2020-esdhc")) { +		command = SDHCI_GET_CMD(sdhci_readw(host, +					SDHCI_COMMAND)); +		if (command == MMC_WRITE_MULTIPLE_BLOCK && +				sdhci_readw(host, SDHCI_BLOCK_COUNT) && +				intmask & SDHCI_INT_DATA_END) { +			intmask &= ~SDHCI_INT_DATA_END; +			sdhci_writel(host, SDHCI_INT_DATA_END, +					SDHCI_INT_STATUS); +		} +	} +	return intmask; +} +  #ifdef CONFIG_PM_SLEEP  static u32 esdhc_proctl;  static int esdhc_of_suspend(struct device *dev) @@ -911,6 +948,7 @@ static const struct sdhci_ops sdhci_esdhc_be_ops = {  	.set_bus_width = esdhc_pltfm_set_bus_width,  	.reset = esdhc_reset,  	.set_uhs_signaling = esdhc_set_uhs_signaling, +	.irq = esdhc_irq,  };  static const struct sdhci_ops sdhci_esdhc_le_ops = { @@ -928,6 +966,7 @@ static const struct sdhci_ops sdhci_esdhc_le_ops = {  	.set_bus_width = esdhc_pltfm_set_bus_width,  	.reset = esdhc_reset,  	.set_uhs_signaling = esdhc_set_uhs_signaling, +	.irq = esdhc_irq,  };  static const struct sdhci_pltfm_data sdhci_esdhc_be_pdata = { @@ -955,6 +994,7 @@ static struct soc_device_attribute soc_incorrect_hostver[] = {  static struct soc_device_attribute soc_fixup_sdhc_clkdivs[] = {  	{ .family = "QorIQ LX2160A", .revision = "1.0", }, +	{ .family = "QorIQ LX2160A", .revision = "2.0", },  	{ },  }; @@ -1074,6 +1114,11 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)  	if (esdhc->vendor_ver > VENDOR_V_22)  		host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; +	if (of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc")) { +		host->quirks2 |= SDHCI_QUIRK_RESET_AFTER_REQUEST; +		host->quirks2 |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; +	} +  	if (of_device_is_compatible(np, "fsl,p5040-esdhc") ||  	    of_device_is_compatible(np, "fsl,p5020-esdhc") ||  	    of_device_is_compatible(np, "fsl,p4080-esdhc") || @@ -1084,12 +1129,14 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)  	if (of_device_is_compatible(np, "fsl,ls1021a-esdhc"))  		host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; +	esdhc->quirk_ignore_data_inhibit = false;  	if (of_device_is_compatible(np, "fsl,p2020-esdhc")) {  		/*  		 * Freescale messed up with P2020 as it has a non-standard  		 * host control register  		 */  		host->quirks2 |= SDHCI_QUIRK2_BROKEN_HOST_CONTROL; +		esdhc->quirk_ignore_data_inhibit = true;  	}  	/* call to generic mmc_of_parse to support additional capabilities */ diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 5bbed477c9b1..bdb80c503fde 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -785,7 +785,7 @@ static void sdhci_omap_set_uhs_signaling(struct sdhci_host *host,  	sdhci_omap_start_clock(omap_host);  } -void sdhci_omap_reset(struct sdhci_host *host, u8 mask) +static void sdhci_omap_reset(struct sdhci_host *host, u8 mask)  {  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);  	struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); @@ -797,6 +797,43 @@ void sdhci_omap_reset(struct sdhci_host *host, u8 mask)  	sdhci_reset(host, mask);  } +#define CMD_ERR_MASK (SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX |\ +		      SDHCI_INT_TIMEOUT) +#define CMD_MASK (CMD_ERR_MASK | SDHCI_INT_RESPONSE) + +static u32 sdhci_omap_irq(struct sdhci_host *host, u32 intmask) +{ +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); + +	if (omap_host->is_tuning && host->cmd && !host->data_early && +	    (intmask & CMD_ERR_MASK)) { + +		/* +		 * Since we are not resetting data lines during tuning +		 * operation, data error or data complete interrupts +		 * might still arrive. Mark this request as a failure +		 * but still wait for the data interrupt +		 */ +		if (intmask & SDHCI_INT_TIMEOUT) +			host->cmd->error = -ETIMEDOUT; +		else +			host->cmd->error = -EILSEQ; + +		host->cmd = NULL; + +		/* +		 * Sometimes command error interrupts and command complete +		 * interrupt will arrive together. Clear all command related +		 * interrupts here. +		 */ +		sdhci_writel(host, intmask & CMD_MASK, SDHCI_INT_STATUS); +		intmask &= ~CMD_MASK; +	} + +	return intmask; +} +  static struct sdhci_ops sdhci_omap_ops = {  	.set_clock = sdhci_omap_set_clock,  	.set_power = sdhci_omap_set_power, @@ -807,6 +844,7 @@ static struct sdhci_ops sdhci_omap_ops = {  	.platform_send_init_74_clocks = sdhci_omap_init_74_clocks,  	.reset = sdhci_omap_reset,  	.set_uhs_signaling = sdhci_omap_set_uhs_signaling, +	.irq = sdhci_omap_irq,  };  static int sdhci_omap_set_capabilities(struct sdhci_omap_host *omap_host) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 99b0fec2836b..ab9e2b901094 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -31,6 +31,10 @@  #include <linux/mmc/sdhci-pci-data.h>  #include <linux/acpi.h> +#ifdef CONFIG_X86 +#include <asm/iosf_mbi.h> +#endif +  #include "cqhci.h"  #include "sdhci.h" @@ -451,6 +455,50 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {  	.probe_slot	= pch_hc_probe_slot,  }; +#ifdef CONFIG_X86 + +#define BYT_IOSF_SCCEP			0x63 +#define BYT_IOSF_OCP_NETCTRL0		0x1078 +#define BYT_IOSF_OCP_TIMEOUT_BASE	GENMASK(10, 8) + +static void byt_ocp_setting(struct pci_dev *pdev) +{ +	u32 val = 0; + +	if (pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC && +	    pdev->device != PCI_DEVICE_ID_INTEL_BYT_SDIO && +	    pdev->device != PCI_DEVICE_ID_INTEL_BYT_SD && +	    pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC2) +		return; + +	if (iosf_mbi_read(BYT_IOSF_SCCEP, MBI_CR_READ, BYT_IOSF_OCP_NETCTRL0, +			  &val)) { +		dev_err(&pdev->dev, "%s read error\n", __func__); +		return; +	} + +	if (!(val & BYT_IOSF_OCP_TIMEOUT_BASE)) +		return; + +	val &= ~BYT_IOSF_OCP_TIMEOUT_BASE; + +	if (iosf_mbi_write(BYT_IOSF_SCCEP, MBI_CR_WRITE, BYT_IOSF_OCP_NETCTRL0, +			   val)) { +		dev_err(&pdev->dev, "%s write error\n", __func__); +		return; +	} + +	dev_dbg(&pdev->dev, "%s completed\n", __func__); +} + +#else + +static inline void byt_ocp_setting(struct pci_dev *pdev) +{ +} + +#endif +  enum {  	INTEL_DSM_FNS		=  0,  	INTEL_DSM_V18_SWITCH	=  3, @@ -715,6 +763,8 @@ static void byt_probe_slot(struct sdhci_pci_slot *slot)  	byt_read_dsm(slot); +	byt_ocp_setting(slot->chip->pdev); +  	ops->execute_tuning = intel_execute_tuning;  	ops->start_signal_voltage_switch = intel_start_signal_voltage_switch; @@ -938,7 +988,35 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)  	return 0;  } +#ifdef CONFIG_PM_SLEEP + +static int byt_resume(struct sdhci_pci_chip *chip) +{ +	byt_ocp_setting(chip->pdev); + +	return sdhci_pci_resume_host(chip); +} + +#endif + +#ifdef CONFIG_PM + +static int byt_runtime_resume(struct sdhci_pci_chip *chip) +{ +	byt_ocp_setting(chip->pdev); + +	return sdhci_pci_runtime_resume_host(chip); +} + +#endif +  static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = { +#ifdef CONFIG_PM_SLEEP +	.resume		= byt_resume, +#endif +#ifdef CONFIG_PM +	.runtime_resume	= byt_runtime_resume, +#endif  	.allow_runtime_pm = true,  	.probe_slot	= byt_emmc_probe_slot,  	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | @@ -972,6 +1050,12 @@ static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = {  };  static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = { +#ifdef CONFIG_PM_SLEEP +	.resume		= byt_resume, +#endif +#ifdef CONFIG_PM +	.runtime_resume	= byt_runtime_resume, +#endif  	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |  			  SDHCI_QUIRK_NO_LED,  	.quirks2	= SDHCI_QUIRK2_HOST_OFF_CARD_ON | @@ -983,6 +1067,12 @@ static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = {  };  static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { +#ifdef CONFIG_PM_SLEEP +	.resume		= byt_resume, +#endif +#ifdef CONFIG_PM +	.runtime_resume	= byt_runtime_resume, +#endif  	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |  			  SDHCI_QUIRK_NO_LED,  	.quirks2	= SDHCI_QUIRK2_HOST_OFF_CARD_ON | @@ -994,6 +1084,12 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {  };  static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { +#ifdef CONFIG_PM_SLEEP +	.resume		= byt_resume, +#endif +#ifdef CONFIG_PM +	.runtime_resume	= byt_runtime_resume, +#endif  	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |  			  SDHCI_QUIRK_NO_LED,  	.quirks2	= SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | @@ -1576,6 +1672,8 @@ static const struct pci_device_id pci_ids[] = {  	SDHCI_PCI_DEVICE(INTEL, CNPH_SD,   intel_byt_sd),  	SDHCI_PCI_DEVICE(INTEL, ICP_EMMC,  intel_glk_emmc),  	SDHCI_PCI_DEVICE(INTEL, ICP_SD,    intel_byt_sd), +	SDHCI_PCI_DEVICE(INTEL, CML_EMMC,  intel_glk_emmc), +	SDHCI_PCI_DEVICE(INTEL, CML_SD,    intel_byt_sd),  	SDHCI_PCI_DEVICE(O2, 8120,     o2),  	SDHCI_PCI_DEVICE(O2, 8220,     o2),  	SDHCI_PCI_DEVICE(O2, 8221,     o2), diff --git a/drivers/mmc/host/sdhci-pci-data.c b/drivers/mmc/host/sdhci-pci-data.c index a611217769f5..18638fb363d8 100644 --- a/drivers/mmc/host/sdhci-pci-data.c +++ b/drivers/mmc/host/sdhci-pci-data.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only  #include <linux/module.h>  #include <linux/mmc/sdhci-pci-data.h> diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index 4ddb69a15cd7..e5dc6e44c7a4 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -50,6 +50,8 @@  #define PCI_DEVICE_ID_INTEL_CNPH_SD	0xa375  #define PCI_DEVICE_ID_INTEL_ICP_EMMC	0x34c4  #define PCI_DEVICE_ID_INTEL_ICP_SD	0x34f8 +#define PCI_DEVICE_ID_INTEL_CML_EMMC	0x02c4 +#define PCI_DEVICE_ID_INTEL_CML_SD	0x02f5  #define PCI_DEVICE_ID_SYSKONNECT_8000	0x8000  #define PCI_DEVICE_ID_VIA_95D0		0x95d0 diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c index 5eada6f87e60..e43143223320 100644 --- a/drivers/mmc/host/sdhci-sirf.c +++ b/drivers/mmc/host/sdhci-sirf.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later  /*   * SDHCI support for SiRF primaII and marco SoCs   *   * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. - * - * Licensed under GPLv2 or later.   */  #include <linux/delay.h> diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 32e62904c0d3..f608417ae967 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -66,6 +66,22 @@  #define SDHCI_VNDR_TUN_CTRL0_0				0x1c0  #define SDHCI_VNDR_TUN_CTRL0_TUN_HW_TAP			0x20000 +#define SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_MASK		0x03fc0000 +#define SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_SHIFT	18 +#define SDHCI_VNDR_TUN_CTRL0_MUL_M_MASK			0x00001fc0 +#define SDHCI_VNDR_TUN_CTRL0_MUL_M_SHIFT		6 +#define SDHCI_VNDR_TUN_CTRL0_TUN_ITER_MASK		0x000e000 +#define SDHCI_VNDR_TUN_CTRL0_TUN_ITER_SHIFT		13 +#define TRIES_128					2 +#define TRIES_256					4 +#define SDHCI_VNDR_TUN_CTRL0_TUN_WORD_SEL_MASK		0x7 + +#define SDHCI_TEGRA_VNDR_TUN_CTRL1_0			0x1c4 +#define SDHCI_TEGRA_VNDR_TUN_STATUS0			0x1C8 +#define SDHCI_TEGRA_VNDR_TUN_STATUS1			0x1CC +#define SDHCI_TEGRA_VNDR_TUN_STATUS1_TAP_MASK		0xFF +#define SDHCI_TEGRA_VNDR_TUN_STATUS1_END_TAP_SHIFT	0x8 +#define TUNING_WORD_BIT_SIZE				32  #define SDHCI_TEGRA_AUTO_CAL_CONFIG			0x1e4  #define SDHCI_AUTO_CAL_START				BIT(31) @@ -90,6 +106,7 @@  #define NVQUIRK_HAS_PADCALIB				BIT(6)  #define NVQUIRK_NEEDS_PAD_CONTROL			BIT(7)  #define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP			BIT(8) +#define NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING		BIT(9)  /* SDMMC CQE Base Address for Tegra Host Ver 4.1 and Higher */  #define SDHCI_TEGRA_CQE_BASE_ADDR			0xF000 @@ -97,6 +114,8 @@  struct sdhci_tegra_soc_data {  	const struct sdhci_pltfm_data *pdata;  	u32 nvquirks; +	u8 min_tap_delay; +	u8 max_tap_delay;  };  /* Magic pull up and pull down pad calibration offsets */ @@ -136,6 +155,8 @@ struct sdhci_tegra {  	u32 default_trim;  	u32 dqs_trim;  	bool enable_hwcq; +	unsigned long curr_clk_rate; +	u8 tuned_tap_delay;  };  static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) @@ -241,6 +262,7 @@ static void tegra210_sdhci_writew(struct sdhci_host *host, u16 val, int reg)  	if (is_tuning_cmd) {  		udelay(1); +		sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);  		tegra_sdhci_configure_card_clk(host, clk_enabled);  	}  } @@ -722,6 +744,7 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)  	 */  	host_clk = tegra_host->ddr_signaling ? clock * 2 : clock;  	clk_set_rate(pltfm_host->clk, host_clk); +	tegra_host->curr_clk_rate = host_clk;  	if (tegra_host->ddr_signaling)  		host->max_clk = host_clk;  	else @@ -770,6 +793,159 @@ static void tegra_sdhci_hs400_dll_cal(struct sdhci_host *host)  			"HS400 delay line calibration timed out\n");  } +static void tegra_sdhci_tap_correction(struct sdhci_host *host, u8 thd_up, +				       u8 thd_low, u8 fixed_tap) +{ +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); +	u32 val, tun_status; +	u8 word, bit, edge1, tap, window; +	bool tap_result; +	bool start_fail = false; +	bool start_pass = false; +	bool end_pass = false; +	bool first_fail = false; +	bool first_pass = false; +	u8 start_pass_tap = 0; +	u8 end_pass_tap = 0; +	u8 first_fail_tap = 0; +	u8 first_pass_tap = 0; +	u8 total_tuning_words = host->tuning_loop_count / TUNING_WORD_BIT_SIZE; + +	/* +	 * Read auto-tuned results and extract good valid passing window by +	 * filtering out un-wanted bubble/partial/merged windows. +	 */ +	for (word = 0; word < total_tuning_words; word++) { +		val = sdhci_readl(host, SDHCI_VNDR_TUN_CTRL0_0); +		val &= ~SDHCI_VNDR_TUN_CTRL0_TUN_WORD_SEL_MASK; +		val |= word; +		sdhci_writel(host, val, SDHCI_VNDR_TUN_CTRL0_0); +		tun_status = sdhci_readl(host, SDHCI_TEGRA_VNDR_TUN_STATUS0); +		bit = 0; +		while (bit < TUNING_WORD_BIT_SIZE) { +			tap = word * TUNING_WORD_BIT_SIZE + bit; +			tap_result = tun_status & (1 << bit); +			if (!tap_result && !start_fail) { +				start_fail = true; +				if (!first_fail) { +					first_fail_tap = tap; +					first_fail = true; +				} + +			} else if (tap_result && start_fail && !start_pass) { +				start_pass_tap = tap; +				start_pass = true; +				if (!first_pass) { +					first_pass_tap = tap; +					first_pass = true; +				} + +			} else if (!tap_result && start_fail && start_pass && +				   !end_pass) { +				end_pass_tap = tap - 1; +				end_pass = true; +			} else if (tap_result && start_pass && start_fail && +				   end_pass) { +				window = end_pass_tap - start_pass_tap; +				/* discard merged window and bubble window */ +				if (window >= thd_up || window < thd_low) { +					start_pass_tap = tap; +					end_pass = false; +				} else { +					/* set tap at middle of valid window */ +					tap = start_pass_tap + window / 2; +					tegra_host->tuned_tap_delay = tap; +					return; +				} +			} + +			bit++; +		} +	} + +	if (!first_fail) { +		WARN_ON("no edge detected, continue with hw tuned delay.\n"); +	} else if (first_pass) { +		/* set tap location at fixed tap relative to the first edge */ +		edge1 = first_fail_tap + (first_pass_tap - first_fail_tap) / 2; +		if (edge1 - 1 > fixed_tap) +			tegra_host->tuned_tap_delay = edge1 - fixed_tap; +		else +			tegra_host->tuned_tap_delay = edge1 + fixed_tap; +	} +} + +static void tegra_sdhci_post_tuning(struct sdhci_host *host) +{ +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); +	const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; +	u32 avg_tap_dly, val, min_tap_dly, max_tap_dly; +	u8 fixed_tap, start_tap, end_tap, window_width; +	u8 thdupper, thdlower; +	u8 num_iter; +	u32 clk_rate_mhz, period_ps, bestcase, worstcase; + +	/* retain HW tuned tap to use incase if no correction is needed */ +	val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); +	tegra_host->tuned_tap_delay = (val & SDHCI_CLOCK_CTRL_TAP_MASK) >> +				      SDHCI_CLOCK_CTRL_TAP_SHIFT; +	if (soc_data->min_tap_delay && soc_data->max_tap_delay) { +		min_tap_dly = soc_data->min_tap_delay; +		max_tap_dly = soc_data->max_tap_delay; +		clk_rate_mhz = tegra_host->curr_clk_rate / USEC_PER_SEC; +		period_ps = USEC_PER_SEC / clk_rate_mhz; +		bestcase = period_ps / min_tap_dly; +		worstcase = period_ps / max_tap_dly; +		/* +		 * Upper and Lower bound thresholds used to detect merged and +		 * bubble windows +		 */ +		thdupper = (2 * worstcase + bestcase) / 2; +		thdlower = worstcase / 4; +		/* +		 * fixed tap is used when HW tuning result contains single edge +		 * and tap is set at fixed tap delay relative to the first edge +		 */ +		avg_tap_dly = (period_ps * 2) / (min_tap_dly + max_tap_dly); +		fixed_tap = avg_tap_dly / 2; + +		val = sdhci_readl(host, SDHCI_TEGRA_VNDR_TUN_STATUS1); +		start_tap = val & SDHCI_TEGRA_VNDR_TUN_STATUS1_TAP_MASK; +		end_tap = (val >> SDHCI_TEGRA_VNDR_TUN_STATUS1_END_TAP_SHIFT) & +			  SDHCI_TEGRA_VNDR_TUN_STATUS1_TAP_MASK; +		window_width = end_tap - start_tap; +		num_iter = host->tuning_loop_count; +		/* +		 * partial window includes edges of the tuning range. +		 * merged window includes more taps so window width is higher +		 * than upper threshold. +		 */ +		if (start_tap == 0 || (end_tap == (num_iter - 1)) || +		    (end_tap == num_iter - 2) || window_width >= thdupper) { +			pr_debug("%s: Apply tuning correction\n", +				 mmc_hostname(host->mmc)); +			tegra_sdhci_tap_correction(host, thdupper, thdlower, +						   fixed_tap); +		} +	} + +	tegra_sdhci_set_tap(host, tegra_host->tuned_tap_delay); +} + +static int tegra_sdhci_execute_hw_tuning(struct mmc_host *mmc, u32 opcode) +{ +	struct sdhci_host *host = mmc_priv(mmc); +	int err; + +	err = sdhci_execute_tuning(mmc, opcode); +	if (!err && !host->tuning_err) +		tegra_sdhci_post_tuning(host); + +	return err; +} +  static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,  					  unsigned timing)  { @@ -778,16 +954,22 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,  	bool set_default_tap = false;  	bool set_dqs_trim = false;  	bool do_hs400_dll_cal = false; +	u8 iter = TRIES_256; +	u32 val; +	tegra_host->ddr_signaling = false;  	switch (timing) {  	case MMC_TIMING_UHS_SDR50: +		break;  	case MMC_TIMING_UHS_SDR104:  	case MMC_TIMING_MMC_HS200:  		/* Don't set default tap on tunable modes. */ +		iter = TRIES_128;  		break;  	case MMC_TIMING_MMC_HS400:  		set_dqs_trim = true;  		do_hs400_dll_cal = true; +		iter = TRIES_128;  		break;  	case MMC_TIMING_MMC_DDR52:  	case MMC_TIMING_UHS_DDR50: @@ -799,11 +981,25 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,  		break;  	} +	val = sdhci_readl(host, SDHCI_VNDR_TUN_CTRL0_0); +	val &= ~(SDHCI_VNDR_TUN_CTRL0_TUN_ITER_MASK | +		 SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_MASK | +		 SDHCI_VNDR_TUN_CTRL0_MUL_M_MASK); +	val |= (iter << SDHCI_VNDR_TUN_CTRL0_TUN_ITER_SHIFT | +		0 << SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_SHIFT | +		1 << SDHCI_VNDR_TUN_CTRL0_MUL_M_SHIFT); +	sdhci_writel(host, val, SDHCI_VNDR_TUN_CTRL0_0); +	sdhci_writel(host, 0, SDHCI_TEGRA_VNDR_TUN_CTRL1_0); + +	host->tuning_loop_count = (iter == TRIES_128) ? 128 : 256; +  	sdhci_set_uhs_signaling(host, timing);  	tegra_sdhci_pad_autocalib(host); -	if (set_default_tap) +	if (tegra_host->tuned_tap_delay && !set_default_tap) +		tegra_sdhci_set_tap(host, tegra_host->tuned_tap_delay); +	else  		tegra_sdhci_set_tap(host, tegra_host->default_tap);  	if (set_dqs_trim) @@ -928,23 +1124,86 @@ static void tegra_sdhci_voltage_switch(struct sdhci_host *host)  		tegra_host->pad_calib_required = true;  } +static void tegra_cqhci_writel(struct cqhci_host *cq_host, u32 val, int reg) +{ +	struct mmc_host *mmc = cq_host->mmc; +	u8 ctrl; +	ktime_t timeout; +	bool timed_out; + +	/* +	 * During CQE resume/unhalt, CQHCI driver unhalts CQE prior to +	 * cqhci_host_ops enable where SDHCI DMA and BLOCK_SIZE registers need +	 * to be re-configured. +	 * Tegra CQHCI/SDHCI prevents write access to block size register when +	 * CQE is unhalted. So handling CQE resume sequence here to configure +	 * SDHCI block registers prior to exiting CQE halt state. +	 */ +	if (reg == CQHCI_CTL && !(val & CQHCI_HALT) && +	    cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT) { +		sdhci_cqe_enable(mmc); +		writel(val, cq_host->mmio + reg); +		timeout = ktime_add_us(ktime_get(), 50); +		while (1) { +			timed_out = ktime_compare(ktime_get(), timeout) > 0; +			ctrl = cqhci_readl(cq_host, CQHCI_CTL); +			if (!(ctrl & CQHCI_HALT) || timed_out) +				break; +		} +		/* +		 * CQE usually resumes very quick, but incase if Tegra CQE +		 * doesn't resume retry unhalt. +		 */ +		if (timed_out) +			writel(val, cq_host->mmio + reg); +	} else { +		writel(val, cq_host->mmio + reg); +	} +} + +static void sdhci_tegra_update_dcmd_desc(struct mmc_host *mmc, +					 struct mmc_request *mrq, u64 *data) +{ +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(mmc_priv(mmc)); +	struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); +	const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; + +	if (soc_data->nvquirks & NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING && +	    mrq->cmd->flags & MMC_RSP_R1B) +		*data |= CQHCI_CMD_TIMING(1); +} +  static void sdhci_tegra_cqe_enable(struct mmc_host *mmc)  {  	struct cqhci_host *cq_host = mmc->cqe_private; -	u32 cqcfg = 0; +	u32 val;  	/* -	 * Tegra SDMMC Controller design prevents write access to BLOCK_COUNT -	 * registers when CQE is enabled. +	 * Tegra CQHCI/SDMMC design prevents write access to sdhci block size +	 * register when CQE is enabled and unhalted. +	 * CQHCI driver enables CQE prior to activation, so disable CQE before +	 * programming block size in sdhci controller and enable it back.  	 */ -	cqcfg = cqhci_readl(cq_host, CQHCI_CFG); -	if (cqcfg & CQHCI_ENABLE) -		cqhci_writel(cq_host, (cqcfg & ~CQHCI_ENABLE), CQHCI_CFG); - -	sdhci_cqe_enable(mmc); +	if (!cq_host->activated) { +		val = cqhci_readl(cq_host, CQHCI_CFG); +		if (val & CQHCI_ENABLE) +			cqhci_writel(cq_host, (val & ~CQHCI_ENABLE), +				     CQHCI_CFG); +		sdhci_cqe_enable(mmc); +		if (val & CQHCI_ENABLE) +			cqhci_writel(cq_host, val, CQHCI_CFG); +	} -	if (cqcfg & CQHCI_ENABLE) -		cqhci_writel(cq_host, cqcfg, CQHCI_CFG); +	/* +	 * CMD CRC errors are seen sometimes with some eMMC devices when status +	 * command is sent during transfer of last data block which is the +	 * default case as send status command block counter (CBC) is 1. +	 * Recommended fix to set CBC to 0 allowing send status command only +	 * when data lines are idle. +	 */ +	val = cqhci_readl(cq_host, CQHCI_SSC1); +	val &= ~CQHCI_SSC1_CBC_MASK; +	cqhci_writel(cq_host, val, CQHCI_SSC1);  }  static void sdhci_tegra_dumpregs(struct mmc_host *mmc) @@ -966,9 +1225,11 @@ static u32 sdhci_tegra_cqhci_irq(struct sdhci_host *host, u32 intmask)  }  static const struct cqhci_host_ops sdhci_tegra_cqhci_ops = { +	.write_l    = tegra_cqhci_writel,  	.enable	= sdhci_tegra_cqe_enable,  	.disable = sdhci_cqe_disable,  	.dumpregs = sdhci_tegra_dumpregs, +	.update_dcmd_desc = sdhci_tegra_update_dcmd_desc,  };  static const struct sdhci_ops tegra_sdhci_ops = { @@ -1109,6 +1370,8 @@ static const struct sdhci_tegra_soc_data soc_data_tegra210 = {  		    NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |  		    NVQUIRK_ENABLE_SDR50 |  		    NVQUIRK_ENABLE_SDR104, +	.min_tap_delay = 106, +	.max_tap_delay = 185,  };  static const struct sdhci_ops tegra186_sdhci_ops = { @@ -1148,10 +1411,25 @@ static const struct sdhci_tegra_soc_data soc_data_tegra186 = {  		    NVQUIRK_HAS_PADCALIB |  		    NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |  		    NVQUIRK_ENABLE_SDR50 | +		    NVQUIRK_ENABLE_SDR104 | +		    NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING, +	.min_tap_delay = 84, +	.max_tap_delay = 136, +}; + +static const struct sdhci_tegra_soc_data soc_data_tegra194 = { +	.pdata = &sdhci_tegra186_pdata, +	.nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | +		    NVQUIRK_HAS_PADCALIB | +		    NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | +		    NVQUIRK_ENABLE_SDR50 |  		    NVQUIRK_ENABLE_SDR104, +	.min_tap_delay = 96, +	.max_tap_delay = 139,  };  static const struct of_device_id sdhci_tegra_dt_match[] = { +	{ .compatible = "nvidia,tegra194-sdhci", .data = &soc_data_tegra194 },  	{ .compatible = "nvidia,tegra186-sdhci", .data = &soc_data_tegra186 },  	{ .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 },  	{ .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra124 }, @@ -1250,6 +1528,10 @@ static int sdhci_tegra_probe(struct platform_device *pdev)  	host->mmc_host_ops.hs400_enhanced_strobe =  			tegra_sdhci_hs400_enhanced_strobe; +	if (!host->ops->platform_execute_tuning) +		host->mmc_host_ops.execute_tuning = +				tegra_sdhci_execute_hw_tuning; +  	rc = mmc_of_parse(host->mmc);  	if (rc)  		goto err_parse_dt; @@ -1329,11 +1611,67 @@ static int sdhci_tegra_remove(struct platform_device *pdev)  	return 0;  } +#ifdef CONFIG_PM_SLEEP +static int __maybe_unused sdhci_tegra_suspend(struct device *dev) +{ +	struct sdhci_host *host = dev_get_drvdata(dev); +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	int ret; + +	if (host->mmc->caps2 & MMC_CAP2_CQE) { +		ret = cqhci_suspend(host->mmc); +		if (ret) +			return ret; +	} + +	ret = sdhci_suspend_host(host); +	if (ret) { +		cqhci_resume(host->mmc); +		return ret; +	} + +	clk_disable_unprepare(pltfm_host->clk); +	return 0; +} + +static int __maybe_unused sdhci_tegra_resume(struct device *dev) +{ +	struct sdhci_host *host = dev_get_drvdata(dev); +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	int ret; + +	ret = clk_prepare_enable(pltfm_host->clk); +	if (ret) +		return ret; + +	ret = sdhci_resume_host(host); +	if (ret) +		goto disable_clk; + +	if (host->mmc->caps2 & MMC_CAP2_CQE) { +		ret = cqhci_resume(host->mmc); +		if (ret) +			goto suspend_host; +	} + +	return 0; + +suspend_host: +	sdhci_suspend_host(host); +disable_clk: +	clk_disable_unprepare(pltfm_host->clk); +	return ret; +} +#endif + +static SIMPLE_DEV_PM_OPS(sdhci_tegra_dev_pm_ops, sdhci_tegra_suspend, +			 sdhci_tegra_resume); +  static struct platform_driver sdhci_tegra_driver = {  	.driver		= {  		.name	= "sdhci-tegra",  		.of_match_table = sdhci_tegra_dt_match, -		.pm	= &sdhci_pltfm_pmops, +		.pm	= &sdhci_tegra_dev_pm_ops,  	},  	.probe		= sdhci_tegra_probe,  	.remove		= sdhci_tegra_remove, diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a8141ff9be03..97158344b862 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -446,6 +446,28 @@ static inline void sdhci_led_deactivate(struct sdhci_host *host)  #endif +static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq, +			    unsigned long timeout) +{ +	if (sdhci_data_line_cmd(mrq->cmd)) +		mod_timer(&host->data_timer, timeout); +	else +		mod_timer(&host->timer, timeout); +} + +static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq) +{ +	if (sdhci_data_line_cmd(mrq->cmd)) +		del_timer(&host->data_timer); +	else +		del_timer(&host->timer); +} + +static inline bool sdhci_has_requests(struct sdhci_host *host) +{ +	return host->cmd || host->data_cmd; +} +  /*****************************************************************************\   *                                                                           *   * Core functions                                                            * @@ -1221,6 +1243,18 @@ static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)  {  	int i; +	if (host->cmd && host->cmd->mrq == mrq) +		host->cmd = NULL; + +	if (host->data_cmd && host->data_cmd->mrq == mrq) +		host->data_cmd = NULL; + +	if (host->data && host->data->mrq == mrq) +		host->data = NULL; + +	if (sdhci_needs_reset(host, mrq)) +		host->pending_reset = true; +  	for (i = 0; i < SDHCI_MAX_MRQS; i++) {  		if (host->mrqs_done[i] == mrq) {  			WARN_ON(1); @@ -1237,24 +1271,17 @@ static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)  	WARN_ON(i >= SDHCI_MAX_MRQS); -	tasklet_schedule(&host->finish_tasklet); +	sdhci_del_timer(host, mrq); + +	if (!sdhci_has_requests(host)) +		sdhci_led_deactivate(host);  }  static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)  { -	if (host->cmd && host->cmd->mrq == mrq) -		host->cmd = NULL; - -	if (host->data_cmd && host->data_cmd->mrq == mrq) -		host->data_cmd = NULL; - -	if (host->data && host->data->mrq == mrq) -		host->data = NULL; - -	if (sdhci_needs_reset(host, mrq)) -		host->pending_reset = true; -  	__sdhci_finish_mrq(host, mrq); + +	queue_work(host->complete_wq, &host->complete_work);  }  static void sdhci_finish_data(struct sdhci_host *host) @@ -1305,34 +1332,17 @@ static void sdhci_finish_data(struct sdhci_host *host)  		 * responsibility to send the stop command if required.  		 */  		if (data->mrq->cap_cmd_during_tfr) { -			sdhci_finish_mrq(host, data->mrq); +			__sdhci_finish_mrq(host, data->mrq);  		} else {  			/* Avoid triggering warning in sdhci_send_command() */  			host->cmd = NULL;  			sdhci_send_command(host, data->stop);  		}  	} else { -		sdhci_finish_mrq(host, data->mrq); +		__sdhci_finish_mrq(host, data->mrq);  	}  } -static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq, -			    unsigned long timeout) -{ -	if (sdhci_data_line_cmd(mrq->cmd)) -		mod_timer(&host->data_timer, timeout); -	else -		mod_timer(&host->timer, timeout); -} - -static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq) -{ -	if (sdhci_data_line_cmd(mrq->cmd)) -		del_timer(&host->data_timer); -	else -		del_timer(&host->timer); -} -  void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)  {  	int flags; @@ -1492,7 +1502,7 @@ static void sdhci_finish_command(struct sdhci_host *host)  			sdhci_finish_data(host);  		if (!cmd->data) -			sdhci_finish_mrq(host, cmd->mrq); +			__sdhci_finish_mrq(host, cmd->mrq);  	}  } @@ -1807,7 +1817,6 @@ void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)  			sdhci_send_command(host, mrq->cmd);  	} -	mmiowb();  	spin_unlock_irqrestore(&host->lock, flags);  }  EXPORT_SYMBOL_GPL(sdhci_request); @@ -2010,8 +2019,6 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	 */  	if (host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)  		sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); - -	mmiowb();  }  EXPORT_SYMBOL_GPL(sdhci_set_ios); @@ -2105,7 +2112,6 @@ static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)  		sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);  		sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); -		mmiowb();  	}  } @@ -2353,7 +2359,6 @@ void sdhci_send_tuning(struct sdhci_host *host, u32 opcode)  	host->tuning_done = 0; -	mmiowb();  	spin_unlock_irqrestore(&host->lock, flags);  	/* Wait for Buffer Read Ready interrupt */ @@ -2369,9 +2374,9 @@ static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)  	/*  	 * Issue opcode repeatedly till Execute Tuning is set to 0 or the number -	 * of loops reaches 40 times. +	 * of loops reaches tuning loop count.  	 */ -	for (i = 0; i < MAX_TUNING_LOOP; i++) { +	for (i = 0; i < host->tuning_loop_count; i++) {  		u16 ctrl;  		sdhci_send_tuning(host, opcode); @@ -2528,11 +2533,6 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)  		sdhci_pre_dma_transfer(host, mrq->data, COOKIE_PRE_MAPPED);  } -static inline bool sdhci_has_requests(struct sdhci_host *host) -{ -	return host->cmd || host->data_cmd; -} -  static void sdhci_error_out_mrqs(struct sdhci_host *host, int err)  {  	if (host->data_cmd) { @@ -2594,7 +2594,7 @@ static const struct mmc_host_ops sdhci_ops = {  /*****************************************************************************\   *                                                                           * - * Tasklets                                                                  * + * Request done                                                              *   *                                                                           *  \*****************************************************************************/ @@ -2617,8 +2617,6 @@ static bool sdhci_request_done(struct sdhci_host *host)  		return true;  	} -	sdhci_del_timer(host, mrq); -  	/*  	 * Always unmap the data buffers if they were mapped by  	 * sdhci_prepare_data() whenever we finish with a request. @@ -2700,12 +2698,8 @@ static bool sdhci_request_done(struct sdhci_host *host)  		host->pending_reset = false;  	} -	if (!sdhci_has_requests(host)) -		sdhci_led_deactivate(host); -  	host->mrqs_done[i] = NULL; -	mmiowb();  	spin_unlock_irqrestore(&host->lock, flags);  	mmc_request_done(host->mmc, mrq); @@ -2713,9 +2707,10 @@ static bool sdhci_request_done(struct sdhci_host *host)  	return false;  } -static void sdhci_tasklet_finish(unsigned long param) +static void sdhci_complete_work(struct work_struct *work)  { -	struct sdhci_host *host = (struct sdhci_host *)param; +	struct sdhci_host *host = container_of(work, struct sdhci_host, +					       complete_work);  	while (!sdhci_request_done(host))  		; @@ -2739,7 +2734,6 @@ static void sdhci_timeout_timer(struct timer_list *t)  		sdhci_finish_mrq(host, host->cmd->mrq);  	} -	mmiowb();  	spin_unlock_irqrestore(&host->lock, flags);  } @@ -2761,6 +2755,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t)  		if (host->data) {  			host->data->error = -ETIMEDOUT;  			sdhci_finish_data(host); +			queue_work(host->complete_wq, &host->complete_work);  		} else if (host->data_cmd) {  			host->data_cmd->error = -ETIMEDOUT;  			sdhci_finish_mrq(host, host->data_cmd->mrq); @@ -2770,7 +2765,6 @@ static void sdhci_timeout_data_timer(struct timer_list *t)  		}  	} -	mmiowb();  	spin_unlock_irqrestore(&host->lock, flags);  } @@ -2827,7 +2821,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p)  			return;  		} -		sdhci_finish_mrq(host, host->cmd->mrq); +		__sdhci_finish_mrq(host, host->cmd->mrq);  		return;  	} @@ -2841,7 +2835,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p)  		if (mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {  			mrq->sbc->error = err; -			sdhci_finish_mrq(host, mrq); +			__sdhci_finish_mrq(host, mrq);  			return;  		}  	} @@ -2905,7 +2899,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)  			if (intmask & SDHCI_INT_DATA_TIMEOUT) {  				host->data_cmd = NULL;  				data_cmd->error = -ETIMEDOUT; -				sdhci_finish_mrq(host, data_cmd->mrq); +				__sdhci_finish_mrq(host, data_cmd->mrq);  				return;  			}  			if (intmask & SDHCI_INT_DATA_END) { @@ -2918,7 +2912,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)  				if (host->cmd == data_cmd)  					return; -				sdhci_finish_mrq(host, data_cmd->mrq); +				__sdhci_finish_mrq(host, data_cmd->mrq);  				return;  			}  		} @@ -3001,12 +2995,24 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)  	}  } +static inline bool sdhci_defer_done(struct sdhci_host *host, +				    struct mmc_request *mrq) +{ +	struct mmc_data *data = mrq->data; + +	return host->pending_reset || +	       ((host->flags & SDHCI_REQ_USE_DMA) && data && +		data->host_cookie == COOKIE_MAPPED); +} +  static irqreturn_t sdhci_irq(int irq, void *dev_id)  { +	struct mmc_request *mrqs_done[SDHCI_MAX_MRQS] = {0};  	irqreturn_t result = IRQ_NONE;  	struct sdhci_host *host = dev_id;  	u32 intmask, mask, unexpected = 0;  	int max_loops = 16; +	int i;  	spin_lock(&host->lock); @@ -3100,9 +3106,30 @@ cont:  		intmask = sdhci_readl(host, SDHCI_INT_STATUS);  	} while (intmask && --max_loops); + +	/* Determine if mrqs can be completed immediately */ +	for (i = 0; i < SDHCI_MAX_MRQS; i++) { +		struct mmc_request *mrq = host->mrqs_done[i]; + +		if (!mrq) +			continue; + +		if (sdhci_defer_done(host, mrq)) { +			result = IRQ_WAKE_THREAD; +		} else { +			mrqs_done[i] = mrq; +			host->mrqs_done[i] = NULL; +		} +	}  out:  	spin_unlock(&host->lock); +	/* Process mrqs ready for immediate completion */ +	for (i = 0; i < SDHCI_MAX_MRQS; i++) { +		if (mrqs_done[i]) +			mmc_request_done(host->mmc, mrqs_done[i]); +	} +  	if (unexpected) {  		pr_err("%s: Unexpected interrupt 0x%08x.\n",  			   mmc_hostname(host->mmc), unexpected); @@ -3118,6 +3145,9 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)  	unsigned long flags;  	u32 isr; +	while (!sdhci_request_done(host)) +		; +  	spin_lock_irqsave(&host->lock, flags);  	isr = host->thread_isr;  	host->thread_isr = 0; @@ -3139,7 +3169,7 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)  		spin_unlock_irqrestore(&host->lock, flags);  	} -	return isr ? IRQ_HANDLED : IRQ_NONE; +	return IRQ_HANDLED;  }  /*****************************************************************************\ @@ -3251,7 +3281,6 @@ int sdhci_resume_host(struct sdhci_host *host)  		mmc->ops->set_ios(mmc, &mmc->ios);  	} else {  		sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); -		mmiowb();  	}  	if (host->irq_wake_enabled) { @@ -3391,7 +3420,6 @@ void sdhci_cqe_enable(struct mmc_host *mmc)  		 mmc_hostname(mmc), host->ier,  		 sdhci_readl(host, SDHCI_INT_STATUS)); -	mmiowb();  	spin_unlock_irqrestore(&host->lock, flags);  }  EXPORT_SYMBOL_GPL(sdhci_cqe_enable); @@ -3416,7 +3444,6 @@ void sdhci_cqe_disable(struct mmc_host *mmc, bool recovery)  		 mmc_hostname(mmc), host->ier,  		 sdhci_readl(host, SDHCI_INT_STATUS)); -	mmiowb();  	spin_unlock_irqrestore(&host->lock, flags);  }  EXPORT_SYMBOL_GPL(sdhci_cqe_disable); @@ -3494,6 +3521,7 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,  	host->cqe_err_ier = SDHCI_CQE_INT_ERR_MASK;  	host->tuning_delay = -1; +	host->tuning_loop_count = MAX_TUNING_LOOP;  	host->sdma_boundary = SDHCI_DEFAULT_BOUNDARY_ARG; @@ -4224,14 +4252,15 @@ EXPORT_SYMBOL_GPL(sdhci_cleanup_host);  int __sdhci_add_host(struct sdhci_host *host)  { +	unsigned int flags = WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI;  	struct mmc_host *mmc = host->mmc;  	int ret; -	/* -	 * Init tasklets. -	 */ -	tasklet_init(&host->finish_tasklet, -		sdhci_tasklet_finish, (unsigned long)host); +	host->complete_wq = alloc_workqueue("sdhci", flags, 0); +	if (!host->complete_wq) +		return -ENOMEM; + +	INIT_WORK(&host->complete_work, sdhci_complete_work);  	timer_setup(&host->timer, sdhci_timeout_timer, 0);  	timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0); @@ -4245,7 +4274,7 @@ int __sdhci_add_host(struct sdhci_host *host)  	if (ret) {  		pr_err("%s: Failed to request IRQ %d: %d\n",  		       mmc_hostname(mmc), host->irq, ret); -		goto untasklet; +		goto unwq;  	}  	ret = sdhci_led_register(host); @@ -4255,8 +4284,6 @@ int __sdhci_add_host(struct sdhci_host *host)  		goto unirq;  	} -	mmiowb(); -  	ret = mmc_add_host(mmc);  	if (ret)  		goto unled; @@ -4278,8 +4305,8 @@ unirq:  	sdhci_writel(host, 0, SDHCI_INT_ENABLE);  	sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);  	free_irq(host->irq, host); -untasklet: -	tasklet_kill(&host->finish_tasklet); +unwq: +	destroy_workqueue(host->complete_wq);  	return ret;  } @@ -4341,7 +4368,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)  	del_timer_sync(&host->timer);  	del_timer_sync(&host->data_timer); -	tasklet_kill(&host->finish_tasklet); +	destroy_workqueue(host->complete_wq);  	if (!IS_ERR(mmc->supply.vqmmc))  		regulator_disable(mmc->supply.vqmmc); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 01002cba1359..d6bcc584c92b 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -560,7 +560,8 @@ struct sdhci_host {  	unsigned int desc_sz;	/* ADMA descriptor size */ -	struct tasklet_struct finish_tasklet;	/* Tasklet structures */ +	struct workqueue_struct *complete_wq;	/* Request completion wq */ +	struct work_struct	complete_work;	/* Request completion work */  	struct timer_list timer;	/* Timer for timeouts */  	struct timer_list data_timer;	/* Timer for data timeouts */ @@ -596,6 +597,7 @@ struct sdhci_host {  #define SDHCI_TUNING_MODE_3	2  	/* Delay (ms) between tuning commands */  	int			tuning_delay; +	int			tuning_loop_count;  	/* Host SDMA buffer boundary. */  	u32			sdma_boundary; diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index eea183e90f1b..a91c0b45c48d 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -158,6 +158,27 @@ static void sdhci_am654_set_power(struct sdhci_host *host, unsigned char mode,  	sdhci_set_power_noreg(host, mode, vdd);  } +static void sdhci_am654_write_b(struct sdhci_host *host, u8 val, int reg) +{ +	unsigned char timing = host->mmc->ios.timing; + +	if (reg == SDHCI_HOST_CONTROL) { +		switch (timing) { +		/* +		 * According to the data manual, HISPD bit +		 * should not be set in these speed modes. +		 */ +		case MMC_TIMING_SD_HS: +		case MMC_TIMING_MMC_HS: +		case MMC_TIMING_UHS_SDR12: +		case MMC_TIMING_UHS_SDR25: +			val &= ~SDHCI_CTRL_HISPD; +		} +	} + +	writeb(val, host->ioaddr + reg); +} +  static struct sdhci_ops sdhci_am654_ops = {  	.get_max_clock = sdhci_pltfm_clk_get_max_clock,  	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock, @@ -165,6 +186,7 @@ static struct sdhci_ops sdhci_am654_ops = {  	.set_bus_width = sdhci_set_bus_width,  	.set_power = sdhci_am654_set_power,  	.set_clock = sdhci_am654_set_clock, +	.write_b = sdhci_am654_write_b,  	.reset = sdhci_reset,  }; diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index 9e46039282d2..a38b8b2a4e5c 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -1,23 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later  /*   *  sdricoh_cs.c - driver for Ricoh Secure Digital Card Readers that can be   *     found on some Ricoh RL5c476 II cardbus bridge   *   *  Copyright (C) 2006 - 2008 Sascha Sommer <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - *   */  /* diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index b6644ce296b2..35dd34b82a4d 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -889,7 +889,6 @@ static int tifm_sd_initialize_host(struct tifm_sd *host)  	struct tifm_dev *sock = host->dev;  	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); -	mmiowb();  	host->clk_div = 61;  	host->clk_freq = 20000000;  	writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL); @@ -940,7 +939,6 @@ static int tifm_sd_initialize_host(struct tifm_sd *host)  	writel(TIFM_MMCSD_CERR | TIFM_MMCSD_BRS | TIFM_MMCSD_EOC  	       | TIFM_MMCSD_ERRMASK,  	       sock->addr + SOCK_MMCSD_INT_ENABLE); -	mmiowb();  	return 0;  } @@ -1005,7 +1003,6 @@ static void tifm_sd_remove(struct tifm_dev *sock)  	spin_lock_irqsave(&sock->lock, flags);  	host->eject = 1;  	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); -	mmiowb();  	spin_unlock_irqrestore(&sock->lock, flags);  	tasklet_kill(&host->finish_tasklet); diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 2adb0d24360f..c5ba13fae399 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -4,8 +4,8 @@   *   * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3   * - * Copyright (C) 2015-17 Renesas Electronics Corporation - * Copyright (C) 2016-17 Sang Engineering, Wolfram Sang + * Copyright (C) 2015-19 Renesas Electronics Corporation + * Copyright (C) 2016-19 Sang Engineering, Wolfram Sang   * Copyright (C) 2016-17 Horms Solutions, Simon Horman   * Copyright (C) 2007 Ian Molton   * Copyright (C) 2004 Ian Molton @@ -105,6 +105,8 @@  		TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)  #define TMIO_MASK_IRQ     (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) +#define TMIO_MAX_BLK_SIZE 512 +  struct tmio_mmc_data;  struct tmio_mmc_host; diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 595949f1f001..130b91cb0f8a 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -4,8 +4,8 @@   *   * TC6393XB, TC6391XB, TC6387XB, T7L66XB, ASIC3, SH-Mobile SoCs   * - * Copyright (C) 2015-17 Renesas Electronics Corporation - * Copyright (C) 2016-17 Sang Engineering, Wolfram Sang + * Copyright (C) 2015-19 Renesas Electronics Corporation + * Copyright (C) 2016-19 Sang Engineering, Wolfram Sang   * Copyright (C) 2017 Horms Solutions, Simon Horman   * Copyright (C) 2011 Guennadi Liakhovetski   * Copyright (C) 2007 Ian Molton @@ -1186,7 +1186,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)  	mmc->caps |= MMC_CAP_4_BIT_DATA | pdata->capabilities;  	mmc->caps2 |= pdata->capabilities2;  	mmc->max_segs = pdata->max_segs ? : 32; -	mmc->max_blk_size = 512; +	mmc->max_blk_size = TMIO_MAX_BLK_SIZE;  	mmc->max_blk_count = pdata->max_blk_count ? :  		(PAGE_SIZE / mmc->max_blk_size) * mmc->max_segs;  	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index cd8b1b9d4d8a..b11ac2314328 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1339,7 +1339,7 @@ static int usdhi6_stop_cmd(struct usdhi6_host *host)  			host->wait = USDHI6_WAIT_FOR_STOP;  			return 0;  		} -		/* Unsupported STOP command */ +		/* fall through - Unsupported STOP command. */  	default:  		dev_err(mmc_dev(host->mmc),  			"unsupported stop CMD%d for CMD%d\n", @@ -1687,7 +1687,7 @@ static void usdhi6_timeout_work(struct work_struct *work)  	switch (host->wait) {  	default:  		dev_err(mmc_dev(host->mmc), "Invalid state %u\n", host->wait); -		/* mrq can be NULL in this actually impossible case */ +		/* fall through - mrq can be NULL, but is impossible. */  	case USDHI6_WAIT_FOR_CMD:  		usdhi6_error_code(host);  		if (mrq) @@ -1709,10 +1709,7 @@ static void usdhi6_timeout_work(struct work_struct *work)  			host->offset, data->blocks, data->blksz, data->sg_len,  			sg_dma_len(sg), sg->offset);  		usdhi6_sg_unmap(host, true); -		/* -		 * If USDHI6_WAIT_FOR_DATA_END times out, we have already unmapped -		 * the page -		 */ +		/* fall through - page unmapped in USDHI6_WAIT_FOR_DATA_END. */  	case USDHI6_WAIT_FOR_DATA_END:  		usdhi6_error_code(host);  		data->error = -ETIMEDOUT; diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 32c4211506fc..412395ac2935 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -686,7 +686,6 @@ static void via_sdc_request(struct mmc_host *mmc, struct mmc_request *mrq)  		via_sdc_send_command(host, mrq->cmd);  	} -	mmiowb();  	spin_unlock_irqrestore(&host->lock, flags);  } @@ -711,7 +710,6 @@ static void via_sdc_set_power(struct via_crdr_mmc_host *host,  		gatt &= ~VIA_CRDR_PCICLKGATT_PAD_PWRON;  	writeb(gatt, host->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); -	mmiowb();  	spin_unlock_irqrestore(&host->lock, flags);  	via_pwron_sleep(host); @@ -770,7 +768,6 @@ static void via_sdc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	if (readb(addrbase + VIA_CRDR_PCISDCCLK) != clock)  		writeb(clock, addrbase + VIA_CRDR_PCISDCCLK); -	mmiowb();  	spin_unlock_irqrestore(&host->lock, flags);  	if (ios->power_mode != MMC_POWER_OFF) @@ -830,7 +827,6 @@ static void via_reset_pcictrl(struct via_crdr_mmc_host *host)  	via_restore_pcictrlreg(host);  	via_restore_sdcreg(host); -	mmiowb();  	spin_unlock_irqrestore(&host->lock, flags);  } @@ -925,7 +921,6 @@ static irqreturn_t via_sdc_isr(int irq, void *dev_id)  	result = IRQ_HANDLED; -	mmiowb();  out:  	spin_unlock(&sdhost->lock); @@ -960,7 +955,6 @@ static void via_sdc_timeout(struct timer_list *t)  		}  	} -	mmiowb();  	spin_unlock_irqrestore(&sdhost->lock, flags);  } @@ -1012,7 +1006,6 @@ static void via_sdc_card_detect(struct work_struct *work)  			tasklet_schedule(&host->finish_tasklet);  		} -		mmiowb();  		spin_unlock_irqrestore(&host->lock, flags);  		via_reset_pcictrl(host); @@ -1020,7 +1013,6 @@ static void via_sdc_card_detect(struct work_struct *work)  		spin_lock_irqsave(&host->lock, flags);  	} -	mmiowb();  	spin_unlock_irqrestore(&host->lock, flags);  	via_print_pcictrl(host); @@ -1188,7 +1180,6 @@ static void via_sd_remove(struct pci_dev *pcidev)  	/* Disable generating further interrupts */  	writeb(0x0, sdhost->pcictrl_mmiobase + VIA_CRDR_PCIINTCTRL); -	mmiowb();  	if (sdhost->mrq) {  		pr_err("%s: Controller removed during " @@ -1197,7 +1188,6 @@ static void via_sd_remove(struct pci_dev *pcidev)  		/* make sure all DMA is stopped */  		writel(VIA_CRDR_DMACTRL_SFTRST,  			sdhost->ddma_mmiobase + VIA_CRDR_DMACTRL); -		mmiowb();  		sdhost->mrq->cmd->error = -ENOMEDIUM;  		if (sdhost->mrq->stop)  			sdhost->mrq->stop->error = -ENOMEDIUM;  |