diff options
Diffstat (limited to 'drivers/mmc')
41 files changed, 2416 insertions, 390 deletions
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 2c71a434c915..95b41c0891d0 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -408,38 +408,6 @@ static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr,  	return 0;  } -static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status, -				       u32 retries_max) -{ -	int err; -	u32 retry_count = 0; - -	if (!status || !retries_max) -		return -EINVAL; - -	do { -		err = __mmc_send_status(card, status, 5); -		if (err) -			break; - -		if (!R1_STATUS(*status) && -				(R1_CURRENT_STATE(*status) != R1_STATE_PRG)) -			break; /* RPMB programming operation complete */ - -		/* -		 * Rechedule to give the MMC device a chance to continue -		 * processing the previous command without being polled too -		 * frequently. -		 */ -		usleep_range(1000, 5000); -	} while (++retry_count < retries_max); - -	if (retry_count == retries_max) -		err = -EPERM; - -	return err; -} -  static int ioctl_do_sanitize(struct mmc_card *card)  {  	int err; @@ -468,6 +436,58 @@ out:  	return err;  } +static inline bool mmc_blk_in_tran_state(u32 status) +{ +	/* +	 * Some cards mishandle the status bits, so make sure to check both the +	 * busy indication and the card state. +	 */ +	return status & R1_READY_FOR_DATA && +	       (R1_CURRENT_STATE(status) == R1_STATE_TRAN); +} + +static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, +			    u32 *resp_errs) +{ +	unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); +	int err = 0; +	u32 status; + +	do { +		bool done = time_after(jiffies, timeout); + +		err = __mmc_send_status(card, &status, 5); +		if (err) { +			dev_err(mmc_dev(card->host), +				"error %d requesting status\n", err); +			return err; +		} + +		/* Accumulate any response error bits seen */ +		if (resp_errs) +			*resp_errs |= status; + +		/* +		 * Timeout if the device never becomes ready for data and never +		 * leaves the program state. +		 */ +		if (done) { +			dev_err(mmc_dev(card->host), +				"Card stuck in wrong state! %s status: %#x\n", +				 __func__, status); +			return -ETIMEDOUT; +		} + +		/* +		 * Some cards mishandle the status bits, +		 * so make sure to check both the busy +		 * indication and the card state. +		 */ +	} while (!mmc_blk_in_tran_state(status)); + +	return err; +} +  static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,  			       struct mmc_blk_ioc_data *idata)  { @@ -477,7 +497,6 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,  	struct scatterlist sg;  	int err;  	unsigned int target_part; -	u32 status = 0;  	if (!card || !md || !idata)  		return -EINVAL; @@ -611,16 +630,12 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,  	memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp)); -	if (idata->rpmb) { +	if (idata->rpmb || (cmd.flags & MMC_RSP_R1B)) {  		/* -		 * Ensure RPMB command has completed by polling CMD13 +		 * Ensure RPMB/R1B command has completed by polling CMD13  		 * "Send Status".  		 */ -		err = ioctl_rpmb_card_status_poll(card, &status, 5); -		if (err) -			dev_err(mmc_dev(card->host), -					"%s: Card Status=0x%08X, error %d\n", -					__func__, status, err); +		err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, NULL);  	}  	return err; @@ -970,58 +985,6 @@ static unsigned int mmc_blk_data_timeout_ms(struct mmc_host *host,  	return ms;  } -static inline bool mmc_blk_in_tran_state(u32 status) -{ -	/* -	 * Some cards mishandle the status bits, so make sure to check both the -	 * busy indication and the card state. -	 */ -	return status & R1_READY_FOR_DATA && -	       (R1_CURRENT_STATE(status) == R1_STATE_TRAN); -} - -static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, -			    struct request *req, u32 *resp_errs) -{ -	unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); -	int err = 0; -	u32 status; - -	do { -		bool done = time_after(jiffies, timeout); - -		err = __mmc_send_status(card, &status, 5); -		if (err) { -			pr_err("%s: error %d requesting status\n", -			       req->rq_disk->disk_name, err); -			return err; -		} - -		/* Accumulate any response error bits seen */ -		if (resp_errs) -			*resp_errs |= status; - -		/* -		 * Timeout if the device never becomes ready for data and never -		 * leaves the program state. -		 */ -		if (done) { -			pr_err("%s: Card stuck in wrong state! %s %s status: %#x\n", -				mmc_hostname(card->host), -				req->rq_disk->disk_name, __func__, status); -			return -ETIMEDOUT; -		} - -		/* -		 * Some cards mishandle the status bits, -		 * so make sure to check both the busy -		 * indication and the card state. -		 */ -	} while (!mmc_blk_in_tran_state(status)); - -	return err; -} -  static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,  			 int type)  { @@ -1671,7 +1634,7 @@ static int mmc_blk_fix_state(struct mmc_card *card, struct request *req)  	mmc_blk_send_stop(card, timeout); -	err = card_busy_detect(card, timeout, req, NULL); +	err = card_busy_detect(card, timeout, NULL);  	mmc_retune_release(card->host); @@ -1895,7 +1858,7 @@ static int mmc_blk_card_busy(struct mmc_card *card, struct request *req)  	if (mmc_host_is_spi(card->host) || rq_data_dir(req) == READ)  		return 0; -	err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, req, &status); +	err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, &status);  	/*  	 * Do not assume data transferred correctly if there are any error bits diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 221127324709..abf8f5eb0a1c 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1469,8 +1469,7 @@ void mmc_detach_bus(struct mmc_host *host)  	mmc_bus_put(host);  } -static void _mmc_detect_change(struct mmc_host *host, unsigned long delay, -				bool cd_irq) +void _mmc_detect_change(struct mmc_host *host, unsigned long delay, bool cd_irq)  {  	/*  	 * If the device is configured as wakeup, we prevent a new sleep for @@ -2129,7 +2128,7 @@ int mmc_hw_reset(struct mmc_host *host)  	ret = host->bus_ops->hw_reset(host);  	mmc_bus_put(host); -	if (ret) +	if (ret < 0)  		pr_warn("%s: tried to HW reset card, got error %d\n",  			mmc_hostname(host), ret); @@ -2297,11 +2296,8 @@ void mmc_rescan(struct work_struct *work)  	mmc_bus_get(host); -	/* -	 * if there is a _removable_ card registered, check whether it is -	 * still present -	 */ -	if (host->bus_ops && !host->bus_dead && mmc_card_is_removable(host)) +	/* Verify a registered card to be functional, else remove it. */ +	if (host->bus_ops && !host->bus_dead)  		host->bus_ops->detect(host);  	host->detect_change = 0; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 328c78dbee66..575ac0257af2 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -70,6 +70,8 @@ void mmc_rescan(struct work_struct *work);  void mmc_start_host(struct mmc_host *host);  void mmc_stop_host(struct mmc_host *host); +void _mmc_detect_change(struct mmc_host *host, unsigned long delay, +			bool cd_irq);  int _mmc_detect_card_removed(struct mmc_host *host);  int mmc_detect_card_removed(struct mmc_host *host); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index c8804895595f..f6912ded652d 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -297,7 +297,7 @@ static void mmc_manage_enhanced_area(struct mmc_card *card, u8 *ext_csd)  	}  } -static void mmc_part_add(struct mmc_card *card, unsigned int size, +static void mmc_part_add(struct mmc_card *card, u64 size,  			 unsigned int part_cfg, char *name, int idx, bool ro,  			 int area_type)  { @@ -313,7 +313,7 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd)  {  	int idx;  	u8 hc_erase_grp_sz, hc_wp_grp_sz; -	unsigned int part_size; +	u64 part_size;  	/*  	 * General purpose partition feature support -- @@ -343,8 +343,7 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd)  				(ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1]  				<< 8) +  				ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3]; -			part_size *= (size_t)(hc_erase_grp_sz * -				hc_wp_grp_sz); +			part_size *= (hc_erase_grp_sz * hc_wp_grp_sz);  			mmc_part_add(card, part_size << 19,  				EXT_CSD_PART_CONFIG_ACC_GP0 + idx,  				"gp%d", idx, false, @@ -362,7 +361,7 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd)  static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)  {  	int err = 0, idx; -	unsigned int part_size; +	u64 part_size;  	struct device_node *np;  	bool broken_hpi = false; diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index 2d2d9ea8be4f..3dba15bccce2 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -119,7 +119,14 @@ static const struct mmc_fixup mmc_ext_csd_fixups[] = {  	END_FIXUP  }; +  static const struct mmc_fixup sdio_fixup_methods[] = { +	SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251, +		   add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), + +	SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251, +		   add_quirk, MMC_QUIRK_DISABLE_CD), +  	SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,  		   add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 26cabd53ddc5..ebb387aa5158 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -1048,9 +1048,35 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)  	return ret;  } +/* + * SDIO HW reset + * + * Returns 0 if the HW reset was executed synchronously, returns 1 if the HW + * reset was asynchronously scheduled, else a negative error code. + */  static int mmc_sdio_hw_reset(struct mmc_host *host)  { -	mmc_power_cycle(host, host->card->ocr); +	struct mmc_card *card = host->card; + +	/* +	 * In case the card is shared among multiple func drivers, reset the +	 * card through a rescan work. In this way it will be removed and +	 * re-detected, thus all func drivers becomes informed about it. +	 */ +	if (atomic_read(&card->sdio_funcs_probed) > 1) { +		if (mmc_card_removed(card)) +			return 1; +		host->rescan_entered = 0; +		mmc_card_set_removed(card); +		_mmc_detect_change(host, 0, false); +		return 1; +	} + +	/* +	 * A single func driver has been probed, then let's skip the heavy +	 * hotplug dance above and execute the reset immediately. +	 */ +	mmc_power_cycle(host, card->ocr);  	return mmc_sdio_reinit_card(host);  } diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 2963e6542958..3cc928282af7 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -138,6 +138,8 @@ static int sdio_bus_probe(struct device *dev)  	if (ret)  		return ret; +	atomic_inc(&func->card->sdio_funcs_probed); +  	/* Unbound SDIO functions are always suspended.  	 * During probe, the function is set active and the usage count  	 * is incremented.  If the driver supports runtime PM, @@ -153,7 +155,10 @@ static int sdio_bus_probe(struct device *dev)  	/* Set the default block size so the driver is sure it's something  	 * sensible. */  	sdio_claim_host(func); -	ret = sdio_set_block_size(func, 0); +	if (mmc_card_removed(func->card)) +		ret = -ENOMEDIUM; +	else +		ret = sdio_set_block_size(func, 0);  	sdio_release_host(func);  	if (ret)  		goto disable_runtimepm; @@ -165,6 +170,7 @@ static int sdio_bus_probe(struct device *dev)  	return 0;  disable_runtimepm: +	atomic_dec(&func->card->sdio_funcs_probed);  	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)  		pm_runtime_put_noidle(dev);  	dev_pm_domain_detach(dev, false); @@ -181,6 +187,7 @@ static int sdio_bus_remove(struct device *dev)  		pm_runtime_get_sync(dev);  	drv->remove(func); +	atomic_dec(&func->card->sdio_funcs_probed);  	if (func->irq_handler) {  		pr_warn("WARNING: driver %s did not remove its interrupt handler!\n", diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 49ea02c467bf..d06b2dfe3c95 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -159,6 +159,7 @@ config MMC_SDHCI_OF_ASPEED  	tristate "SDHCI OF support for the ASPEED SDHCI controller"  	depends on MMC_SDHCI_PLTFM  	depends on OF && OF_ADDRESS +	select MMC_SDHCI_IO_ACCESSORS  	help  	  This selects the ASPEED Secure Digital Host Controller Interface. @@ -368,6 +369,17 @@ config MMC_SDHCI_F_SDH30  	  If unsure, say N. +config MMC_SDHCI_MILBEAUT +	tristate "SDHCI support for Socionext Milbeaut Serieas using F_SDH30" +	depends on MMC_SDHCI_PLTFM +	depends on OF +	help +	  This selects the Secure Digital Host Controller Interface (SDHCI) +	  Needed by Milbeaut SoC for MMC / SD / SDIO support. +	  If you have a controller with this interface, say Y or M here. + +	  If unsure, say N. +  config MMC_SDHCI_IPROC  	tristate "SDHCI support for the BCM2835 & iProc SD/MMC Controller"  	depends on ARCH_BCM2835 || ARCH_BCM_IPROC || COMPILE_TEST @@ -1011,6 +1023,7 @@ config MMC_SDHCI_AM654  	tristate "Support for the SDHCI Controller in TI's AM654 SOCs"  	depends on MMC_SDHCI_PLTFM && OF && REGMAP_MMIO  	select MMC_SDHCI_IO_ACCESSORS +	select MMC_CQHCI  	help  	  This selects the Secure Digital Host Controller Interface (SDHCI)  	  support present in TI's AM654 SOCs. The controller supports @@ -1019,3 +1032,11 @@ config MMC_SDHCI_AM654  	  If you have a controller with this interface, say Y or M here.  	  If unsure, say N. + +config MMC_OWL +	tristate "Actions Semi Owl SD/MMC Host Controller support" +	depends on HAS_DMA +	depends on ARCH_ACTIONS || COMPILE_TEST +	help +	  This selects support for the SD/MMC Host Controller on +	  Actions Semi Owl SoCs. diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 11c4598e91d9..21d9089e5eda 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_MMC_SDHCI_PXAV2)	+= sdhci-pxav2.o  obj-$(CONFIG_MMC_SDHCI_S3C)	+= sdhci-s3c.o  obj-$(CONFIG_MMC_SDHCI_SIRF)   	+= sdhci-sirf.o  obj-$(CONFIG_MMC_SDHCI_F_SDH30)	+= sdhci_f_sdh30.o +obj-$(CONFIG_MMC_SDHCI_MILBEAUT)	+= sdhci-milbeaut.o  obj-$(CONFIG_MMC_SDHCI_SPEAR)	+= sdhci-spear.o  obj-$(CONFIG_MMC_SDHCI_AM654)	+= sdhci_am654.o  obj-$(CONFIG_MMC_WBSD)		+= wbsd.o @@ -73,6 +74,7 @@ obj-$(CONFIG_MMC_SUNXI)		+= sunxi-mmc.o  obj-$(CONFIG_MMC_USDHI6ROL0)	+= usdhi6rol0.o  obj-$(CONFIG_MMC_TOSHIBA_PCI)	+= toshsd.o  obj-$(CONFIG_MMC_BCM2835)	+= bcm2835.o +obj-$(CONFIG_MMC_OWL)		+= owl-mmc.o  obj-$(CONFIG_MMC_REALTEK_PCI)	+= rtsx_pci_sdmmc.o  obj-$(CONFIG_MMC_REALTEK_USB)	+= rtsx_usb_sdmmc.o diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index c26fbe5f2222..6f065bb5c55a 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -583,11 +583,11 @@ static void atmci_init_debugfs(struct atmel_mci_slot *slot)  	debugfs_create_file("regs", S_IRUSR, root, host, &atmci_regs_fops);  	debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops); -	debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); -	debugfs_create_x32("pending_events", S_IRUSR, root, -			   (u32 *)&host->pending_events); -	debugfs_create_x32("completed_events", S_IRUSR, root, -			   (u32 *)&host->completed_events); +	debugfs_create_u32("state", S_IRUSR, root, &host->state); +	debugfs_create_xul("pending_events", S_IRUSR, root, +			   &host->pending_events); +	debugfs_create_xul("completed_events", S_IRUSR, root, +			   &host->completed_events);  }  #if defined(CONFIG_OF) @@ -2347,8 +2347,7 @@ static void atmci_cleanup_slot(struct atmel_mci_slot *slot,  static int atmci_configure_dma(struct atmel_mci *host)  { -	host->dma.chan = dma_request_slave_channel_reason(&host->pdev->dev, -							"rxtx"); +	host->dma.chan = dma_request_chan(&host->pdev->dev, "rxtx");  	if (PTR_ERR(host->dma.chan) == -ENODEV) {  		struct mci_platform_data *pdata = host->pdev->dev.platform_data; diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index 148414d7f0c9..99f61fd2a658 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -1357,7 +1357,6 @@ static int bcm2835_probe(struct platform_device *pdev)  {  	struct device *dev = &pdev->dev;  	struct clk *clk; -	struct resource *iomem;  	struct bcm2835_host *host;  	struct mmc_host *mmc;  	const __be32 *regaddr_p; @@ -1373,8 +1372,7 @@ static int bcm2835_probe(struct platform_device *pdev)  	host->pdev = pdev;  	spin_lock_init(&host->lock); -	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	host->ioaddr = devm_ioremap_resource(dev, iomem); +	host->ioaddr = devm_platform_ioremap_resource(pdev, 0);  	if (IS_ERR(host->ioaddr)) {  		ret = PTR_ERR(host->ioaddr);  		goto err; diff --git a/drivers/mmc/host/cavium-octeon.c b/drivers/mmc/host/cavium-octeon.c index 22aded1065ae..916746c6c2c7 100644 --- a/drivers/mmc/host/cavium-octeon.c +++ b/drivers/mmc/host/cavium-octeon.c @@ -148,7 +148,6 @@ static int octeon_mmc_probe(struct platform_device *pdev)  {  	struct device_node *cn, *node = pdev->dev.of_node;  	struct cvm_mmc_host *host; -	struct resource	*res;  	void __iomem *base;  	int mmc_irq[9];  	int i, ret = 0; @@ -205,23 +204,13 @@ static int octeon_mmc_probe(struct platform_device *pdev)  	host->last_slot = -1; -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) { -		dev_err(&pdev->dev, "Platform resource[0] is missing\n"); -		return -ENXIO; -	} -	base = devm_ioremap_resource(&pdev->dev, res); +	base = devm_platform_ioremap_resource(pdev, 0);  	if (IS_ERR(base))  		return PTR_ERR(base);  	host->base = (void __iomem *)base;  	host->reg_off = 0; -	res = platform_get_resource(pdev, IORESOURCE_MEM, 1); -	if (!res) { -		dev_err(&pdev->dev, "Platform resource[1] is missing\n"); -		return -EINVAL; -	} -	base = devm_ioremap_resource(&pdev->dev, res); +	base = devm_platform_ioremap_resource(pdev, 1);  	if (IS_ERR(base))  		return PTR_ERR(base);  	host->dma_base = (void __iomem *)base; diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 79c55c7b4afd..fc9d4d000f97 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -176,11 +176,11 @@ static void dw_mci_init_debugfs(struct dw_mci_slot *slot)  	debugfs_create_file("regs", S_IRUSR, root, host, &dw_mci_regs_fops);  	debugfs_create_file("req", S_IRUSR, root, slot, &dw_mci_req_fops); -	debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state); -	debugfs_create_x32("pending_events", S_IRUSR, root, -			   (u32 *)&host->pending_events); -	debugfs_create_x32("completed_events", S_IRUSR, root, -			   (u32 *)&host->completed_events); +	debugfs_create_u32("state", S_IRUSR, root, &host->state); +	debugfs_create_xul("pending_events", S_IRUSR, root, +			   &host->pending_events); +	debugfs_create_xul("completed_events", S_IRUSR, root, +			   &host->completed_events);  }  #endif /* defined(CONFIG_DEBUG_FS) */ @@ -3441,8 +3441,8 @@ int dw_mci_runtime_resume(struct device *dev)  	 * Restore the initial value at FIFOTH register  	 * And Invalidate the prev_blksz with zero  	 */ -	 mci_writel(host, FIFOTH, host->fifoth_val); -	 host->prev_blksz = 0; +	mci_writel(host, FIFOTH, host->fifoth_val); +	host->prev_blksz = 0;  	/* Put in max timeout */  	mci_writel(host, TMOUT, 0xFFFFFFFF); diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index f816c06ef916..78383f60a3dc 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -41,6 +41,7 @@  #define JZ_REG_MMC_RESP_FIFO	0x34  #define JZ_REG_MMC_RXFIFO	0x38  #define JZ_REG_MMC_TXFIFO	0x3C +#define JZ_REG_MMC_LPM		0x40  #define JZ_REG_MMC_DMAC		0x44  #define JZ_MMC_STRPCL_EXIT_MULTIPLE BIT(7) @@ -77,6 +78,8 @@  #define JZ_MMC_CMDAT_IO_ABORT BIT(11)  #define JZ_MMC_CMDAT_BUS_WIDTH_4BIT BIT(10) +#define JZ_MMC_CMDAT_BUS_WIDTH_8BIT (BIT(10) | BIT(9)) +#define	JZ_MMC_CMDAT_BUS_WIDTH_MASK (BIT(10) | BIT(9))  #define JZ_MMC_CMDAT_DMA_EN BIT(8)  #define JZ_MMC_CMDAT_INIT BIT(7)  #define JZ_MMC_CMDAT_BUSY BIT(6) @@ -98,12 +101,20 @@  #define JZ_MMC_DMAC_DMA_SEL BIT(1)  #define JZ_MMC_DMAC_DMA_EN BIT(0) +#define	JZ_MMC_LPM_DRV_RISING BIT(31) +#define	JZ_MMC_LPM_DRV_RISING_QTR_PHASE_DLY BIT(31) +#define	JZ_MMC_LPM_DRV_RISING_1NS_DLY BIT(30) +#define	JZ_MMC_LPM_SMP_RISING_QTR_OR_HALF_PHASE_DLY BIT(29) +#define	JZ_MMC_LPM_LOW_POWER_MODE_EN BIT(0) +  #define JZ_MMC_CLK_RATE 24000000  enum jz4740_mmc_version {  	JZ_MMC_JZ4740,  	JZ_MMC_JZ4725B, +	JZ_MMC_JZ4760,  	JZ_MMC_JZ4780, +	JZ_MMC_X1000,  };  enum jz4740_mmc_state { @@ -852,6 +863,22 @@ static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate)  	}  	writew(div, host->base + JZ_REG_MMC_CLKRT); + +	if (real_rate > 25000000) { +		if (host->version >= JZ_MMC_X1000) { +			writel(JZ_MMC_LPM_DRV_RISING_QTR_PHASE_DLY | +				   JZ_MMC_LPM_SMP_RISING_QTR_OR_HALF_PHASE_DLY | +				   JZ_MMC_LPM_LOW_POWER_MODE_EN, +				   host->base + JZ_REG_MMC_LPM); +		} else if (host->version >= JZ_MMC_JZ4760) { +			writel(JZ_MMC_LPM_DRV_RISING | +				   JZ_MMC_LPM_LOW_POWER_MODE_EN, +				   host->base + JZ_REG_MMC_LPM); +		} else if (host->version >= JZ_MMC_JZ4725B) +			writel(JZ_MMC_LPM_LOW_POWER_MODE_EN, +				   host->base + JZ_REG_MMC_LPM); +	} +  	return real_rate;  } @@ -895,11 +922,16 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	switch (ios->bus_width) {  	case MMC_BUS_WIDTH_1: -		host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_4BIT; +		host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_MASK;  		break;  	case MMC_BUS_WIDTH_4: +		host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_MASK;  		host->cmdat |= JZ_MMC_CMDAT_BUS_WIDTH_4BIT;  		break; +	case MMC_BUS_WIDTH_8: +		host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_MASK; +		host->cmdat |= JZ_MMC_CMDAT_BUS_WIDTH_8BIT; +		break;  	default:  		break;  	} @@ -924,7 +956,9 @@ static const struct mmc_host_ops jz4740_mmc_ops = {  static const struct of_device_id jz4740_mmc_of_match[] = {  	{ .compatible = "ingenic,jz4740-mmc", .data = (void *) JZ_MMC_JZ4740 },  	{ .compatible = "ingenic,jz4725b-mmc", .data = (void *)JZ_MMC_JZ4725B }, +	{ .compatible = "ingenic,jz4760-mmc", .data = (void *) JZ_MMC_JZ4760 },  	{ .compatible = "ingenic,jz4780-mmc", .data = (void *) JZ_MMC_JZ4780 }, +	{ .compatible = "ingenic,x1000-mmc", .data = (void *) JZ_MMC_X1000 },  	{},  };  MODULE_DEVICE_TABLE(of, jz4740_mmc_of_match); @@ -1025,11 +1059,12 @@ static int jz4740_mmc_probe(struct platform_device* pdev)  		dev_err(&pdev->dev, "Failed to add mmc host: %d\n", ret);  		goto err_release_dma;  	} -	dev_info(&pdev->dev, "JZ SD/MMC card driver registered\n"); +	dev_info(&pdev->dev, "Ingenic SD/MMC card driver registered\n");  	dev_info(&pdev->dev, "Using %s, %d-bit mode\n",  		 host->use_dma ? "DMA" : "PIO", -		 (mmc->caps & MMC_CAP_4_BIT_DATA) ? 4 : 1); +		 (mmc->caps & MMC_CAP_8_BIT_DATA) ? 8 : +		 ((mmc->caps & MMC_CAP_4_BIT_DATA) ? 4 : 1));  	return 0; diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 66e354d51ee9..74c6cfbf9172 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1421,7 +1421,7 @@ static int mmc_spi_probe(struct spi_device *spi)  	 * Index 0 is card detect  	 * Old boardfiles were specifying 1 ms as debounce  	 */ -	status = mmc_gpiod_request_cd(mmc, NULL, 0, false, 1, NULL); +	status = mmc_gpiod_request_cd(mmc, NULL, 0, false, 1000, NULL);  	if (status == -EPROBE_DEFER)  		goto fail_add_host;  	if (!status) { diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index c37e70dbe250..40e72c30ea84 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -44,6 +44,7 @@  #define DRIVER_NAME "mmci-pl18x"  static void mmci_variant_init(struct mmci_host *host); +static void ux500_variant_init(struct mmci_host *host);  static void ux500v2_variant_init(struct mmci_host *host);  static unsigned int fmax = 515633; @@ -184,7 +185,7 @@ static struct variant_data variant_ux500 = {  	.irq_pio_mask		= MCI_IRQ_PIO_MASK,  	.start_err		= MCI_STARTBITERR,  	.opendrain		= MCI_OD, -	.init			= mmci_variant_init, +	.init			= ux500_variant_init,  };  static struct variant_data variant_ux500v2 = { @@ -261,6 +262,10 @@ static struct variant_data variant_stm32_sdmmc = {  	.datalength_bits	= 25,  	.datactrl_blocksz	= 14,  	.stm32_idmabsize_mask	= GENMASK(12, 5), +	.busy_timeout		= true, +	.busy_detect		= true, +	.busy_detect_flag	= MCI_STM32_BUSYD0, +	.busy_detect_mask	= MCI_STM32_BUSYD0ENDMASK,  	.init			= sdmmc_variant_init,  }; @@ -419,7 +424,7 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)  	mmci_write_clkreg(host, clk);  } -void mmci_dma_release(struct mmci_host *host) +static void mmci_dma_release(struct mmci_host *host)  {  	if (host->ops && host->ops->dma_release)  		host->ops->dma_release(host); @@ -427,7 +432,7 @@ void mmci_dma_release(struct mmci_host *host)  	host->use_dma = false;  } -void mmci_dma_setup(struct mmci_host *host) +static void mmci_dma_setup(struct mmci_host *host)  {  	if (!host->ops || !host->ops->dma_setup)  		return; @@ -462,7 +467,7 @@ static int mmci_validate_data(struct mmci_host *host,  	return 0;  } -int mmci_prep_data(struct mmci_host *host, struct mmc_data *data, bool next) +static int mmci_prep_data(struct mmci_host *host, struct mmc_data *data, bool next)  {  	int err; @@ -478,7 +483,7 @@ int mmci_prep_data(struct mmci_host *host, struct mmc_data *data, bool next)  	return err;  } -void mmci_unprep_data(struct mmci_host *host, struct mmc_data *data, +static void mmci_unprep_data(struct mmci_host *host, struct mmc_data *data,  		      int err)  {  	if (host->ops && host->ops->unprep_data) @@ -487,7 +492,7 @@ void mmci_unprep_data(struct mmci_host *host, struct mmc_data *data,  	data->host_cookie = 0;  } -void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) +static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)  {  	WARN_ON(data->host_cookie && data->host_cookie != host->next_cookie); @@ -495,7 +500,7 @@ void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)  		host->ops->get_next_data(host, data);  } -int mmci_dma_start(struct mmci_host *host, unsigned int datactrl) +static int mmci_dma_start(struct mmci_host *host, unsigned int datactrl)  {  	struct mmc_data *data = host->data;  	int ret; @@ -530,7 +535,7 @@ int mmci_dma_start(struct mmci_host *host, unsigned int datactrl)  	return 0;  } -void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) +static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)  {  	if (!host->use_dma)  		return; @@ -539,7 +544,7 @@ void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)  		host->ops->dma_finalize(host, data);  } -void mmci_dma_error(struct mmci_host *host) +static void mmci_dma_error(struct mmci_host *host)  {  	if (!host->use_dma)  		return; @@ -610,6 +615,67 @@ static u32 ux500v2_get_dctrl_cfg(struct mmci_host *host)  	return MCI_DPSM_ENABLE | (host->data->blksz << 16);  } +static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk) +{ +	void __iomem *base = host->base; + +	/* +	 * Before unmasking for the busy end IRQ, confirm that the +	 * command was sent successfully. To keep track of having a +	 * command in-progress, waiting for busy signaling to end, +	 * store the status in host->busy_status. +	 * +	 * Note that, the card may need a couple of clock cycles before +	 * it starts signaling busy on DAT0, hence re-read the +	 * MMCISTATUS register here, to allow the busy bit to be set. +	 * Potentially we may even need to poll the register for a +	 * while, to allow it to be set, but tests indicates that it +	 * isn't needed. +	 */ +	if (!host->busy_status && !(status & err_msk) && +	    (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { +		writel(readl(base + MMCIMASK0) | +		       host->variant->busy_detect_mask, +		       base + MMCIMASK0); + +		host->busy_status = status & (MCI_CMDSENT | MCI_CMDRESPEND); +		return false; +	} + +	/* +	 * If there is a command in-progress that has been successfully +	 * sent, then bail out if busy status is set and wait for the +	 * busy end IRQ. +	 * +	 * Note that, the HW triggers an IRQ on both edges while +	 * monitoring DAT0 for busy completion, but there is only one +	 * status bit in MMCISTATUS for the busy state. Therefore +	 * both the start and the end interrupts needs to be cleared, +	 * one after the other. So, clear the busy start IRQ here. +	 */ +	if (host->busy_status && +	    (status & host->variant->busy_detect_flag)) { +		writel(host->variant->busy_detect_mask, base + MMCICLEAR); +		return false; +	} + +	/* +	 * If there is a command in-progress that has been successfully +	 * sent and the busy bit isn't set, it means we have received +	 * the busy end IRQ. Clear and mask the IRQ, then continue to +	 * process the command. +	 */ +	if (host->busy_status) { +		writel(host->variant->busy_detect_mask, base + MMCICLEAR); + +		writel(readl(base + MMCIMASK0) & +		       ~host->variant->busy_detect_mask, base + MMCIMASK0); +		host->busy_status = 0; +	} + +	return true; +} +  /*   * All the DMA operation mode stuff goes inside this ifdef.   * This assumes that you have a generic DMA device interface, @@ -948,14 +1014,21 @@ static struct mmci_host_ops mmci_variant_ops = {  };  #endif -void mmci_variant_init(struct mmci_host *host) +static void mmci_variant_init(struct mmci_host *host) +{ +	host->ops = &mmci_variant_ops; +} + +static void ux500_variant_init(struct mmci_host *host)  {  	host->ops = &mmci_variant_ops; +	host->ops->busy_complete = ux500_busy_complete;  } -void ux500v2_variant_init(struct mmci_host *host) +static void ux500v2_variant_init(struct mmci_host *host)  {  	host->ops = &mmci_variant_ops; +	host->ops->busy_complete = ux500_busy_complete;  	host->ops->get_datactrl_cfg = ux500v2_get_dctrl_cfg;  } @@ -1075,6 +1148,7 @@ static void  mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)  {  	void __iomem *base = host->base; +	unsigned long long clks;  	dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n",  	    cmd->opcode, cmd->arg, cmd->flags); @@ -1097,6 +1171,16 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)  		else  			c |= host->variant->cmdreg_srsp;  	} + +	if (host->variant->busy_timeout && cmd->flags & MMC_RSP_BUSY) { +		if (!cmd->busy_timeout) +			cmd->busy_timeout = 10 * MSEC_PER_SEC; + +		clks = (unsigned long long)cmd->busy_timeout * host->cclk; +		do_div(clks, MSEC_PER_SEC); +		writel_relaxed(clks, host->base + MMCIDATATIMER); +	} +  	if (/*interrupt*/0)  		c |= MCI_CPSM_INTERRUPT; @@ -1201,6 +1285,7 @@ static void  mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,  	     unsigned int status)  { +	u32 err_msk = MCI_CMDCRCFAIL | MCI_CMDTIMEOUT;  	void __iomem *base = host->base;  	bool sbc, busy_resp; @@ -1215,74 +1300,17 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,  	 * handling. Note that we tag on any latent IRQs postponed  	 * due to waiting for busy status.  	 */ -	if (!((status|host->busy_status) & -	      (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND))) +	if (host->variant->busy_timeout && busy_resp) +		err_msk |= MCI_DATATIMEOUT; + +	if (!((status | host->busy_status) & +	      (err_msk | MCI_CMDSENT | MCI_CMDRESPEND)))  		return;  	/* Handle busy detection on DAT0 if the variant supports it. */ -	if (busy_resp && host->variant->busy_detect) { - -		/* -		 * Before unmasking for the busy end IRQ, confirm that the -		 * command was sent successfully. To keep track of having a -		 * command in-progress, waiting for busy signaling to end, -		 * store the status in host->busy_status. -		 * -		 * Note that, the card may need a couple of clock cycles before -		 * it starts signaling busy on DAT0, hence re-read the -		 * MMCISTATUS register here, to allow the busy bit to be set. -		 * Potentially we may even need to poll the register for a -		 * while, to allow it to be set, but tests indicates that it -		 * isn't needed. -		 */ -		if (!host->busy_status && -		    !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) && -		    (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { - -			writel(readl(base + MMCIMASK0) | -			       host->variant->busy_detect_mask, -			       base + MMCIMASK0); - -			host->busy_status = -				status & (MCI_CMDSENT|MCI_CMDRESPEND); -			return; -		} - -		/* -		 * If there is a command in-progress that has been successfully -		 * sent, then bail out if busy status is set and wait for the -		 * busy end IRQ. -		 * -		 * Note that, the HW triggers an IRQ on both edges while -		 * monitoring DAT0 for busy completion, but there is only one -		 * status bit in MMCISTATUS for the busy state. Therefore -		 * both the start and the end interrupts needs to be cleared, -		 * one after the other. So, clear the busy start IRQ here. -		 */ -		if (host->busy_status && -		    (status & host->variant->busy_detect_flag)) { -			writel(host->variant->busy_detect_mask, -			       host->base + MMCICLEAR); +	if (busy_resp && host->variant->busy_detect) +		if (!host->ops->busy_complete(host, status, err_msk))  			return; -		} - -		/* -		 * If there is a command in-progress that has been successfully -		 * sent and the busy bit isn't set, it means we have received -		 * the busy end IRQ. Clear and mask the IRQ, then continue to -		 * process the command. -		 */ -		if (host->busy_status) { - -			writel(host->variant->busy_detect_mask, -			       host->base + MMCICLEAR); - -			writel(readl(base + MMCIMASK0) & -			       ~host->variant->busy_detect_mask, -			       base + MMCIMASK0); -			host->busy_status = 0; -		} -	}  	host->cmd = NULL; @@ -1290,6 +1318,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,  		cmd->error = -ETIMEDOUT;  	} else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) {  		cmd->error = -EILSEQ; +	} else if (host->variant->busy_timeout && busy_resp && +		   status & MCI_DATATIMEOUT) { +		cmd->error = -ETIMEDOUT;  	} else {  		cmd->resp[0] = readl(base + MMCIRESPONSE0);  		cmd->resp[1] = readl(base + MMCIRESPONSE1); @@ -1583,6 +1614,20 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)  	spin_unlock_irqrestore(&host->lock, flags);  } +static void mmci_set_max_busy_timeout(struct mmc_host *mmc) +{ +	struct mmci_host *host = mmc_priv(mmc); +	u32 max_busy_timeout = 0; + +	if (!host->variant->busy_detect) +		return; + +	if (host->variant->busy_timeout && mmc->actual_clock) +		max_busy_timeout = ~0UL / (mmc->actual_clock / MSEC_PER_SEC); + +	mmc->max_busy_timeout = max_busy_timeout; +} +  static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  {  	struct mmci_host *host = mmc_priv(mmc); @@ -1687,6 +1732,8 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	else  		mmci_set_clkreg(host, ios->clock); +	mmci_set_max_busy_timeout(mmc); +  	if (host->ops && host->ops->set_pwrreg)  		host->ops->set_pwrreg(host, pwr);  	else @@ -1957,7 +2004,6 @@ static int mmci_probe(struct amba_device *dev,  			mmci_write_datactrlreg(host,  					       host->variant->busy_dpsm_flag);  		mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; -		mmc->max_busy_timeout = 0;  	}  	/* Prepare a CMD12 - needed to clear the DPSM on some variants. */ diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 833236ecb31e..158e1231aa23 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -164,6 +164,7 @@  #define MCI_ST_CARDBUSY		(1 << 24)  /* Extended status bits for the STM32 variants */  #define MCI_STM32_BUSYD0	BIT(20) +#define MCI_STM32_BUSYD0END	BIT(21)  #define MMCICLEAR		0x038  #define MCI_CMDCRCFAILCLR	(1 << 0) @@ -287,6 +288,8 @@ struct mmci_host;   * @signal_direction: input/out direction of bus signals can be indicated   * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock   * @busy_detect: true if the variant supports busy detection on DAT0. + * @busy_timeout: true if the variant starts data timer when the DPSM + *		  enter in Wait_R or Busy state.   * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM   * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register   *		      indicating that the card is busy @@ -333,6 +336,7 @@ struct variant_data {  	u8			signal_direction:1;  	u8			pwrreg_clkgate:1;  	u8			busy_detect:1; +	u8			busy_timeout:1;  	u32			busy_dpsm_flag;  	u32			busy_detect_flag;  	u32			busy_detect_mask; @@ -366,6 +370,7 @@ struct mmci_host_ops {  	void (*dma_error)(struct mmci_host *host);  	void (*set_clkreg)(struct mmci_host *host, unsigned int desired);  	void (*set_pwrreg)(struct mmci_host *host, unsigned int pwr); +	bool (*busy_complete)(struct mmci_host *host, u32 status, u32 err_msk);  };  struct mmci_host { diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c index 8e83ae6920ae..a4f7e8e689d3 100644 --- a/drivers/mmc/host/mmci_stm32_sdmmc.c +++ b/drivers/mmc/host/mmci_stm32_sdmmc.c @@ -25,8 +25,8 @@ struct sdmmc_priv {  	void *sg_cpu;  }; -int sdmmc_idma_validate_data(struct mmci_host *host, -			     struct mmc_data *data) +static int sdmmc_idma_validate_data(struct mmci_host *host, +				    struct mmc_data *data)  {  	struct scatterlist *sg;  	int i; @@ -282,6 +282,47 @@ static u32 sdmmc_get_dctrl_cfg(struct mmci_host *host)  	return datactrl;  } +static bool sdmmc_busy_complete(struct mmci_host *host, u32 status, u32 err_msk) +{ +	void __iomem *base = host->base; +	u32 busy_d0, busy_d0end, mask, sdmmc_status; + +	mask = readl_relaxed(base + MMCIMASK0); +	sdmmc_status = readl_relaxed(base + MMCISTATUS); +	busy_d0end = sdmmc_status & MCI_STM32_BUSYD0END; +	busy_d0 = sdmmc_status & MCI_STM32_BUSYD0; + +	/* complete if there is an error or busy_d0end */ +	if ((status & err_msk) || busy_d0end) +		goto complete; + +	/* +	 * On response the busy signaling is reflected in the BUSYD0 flag. +	 * if busy_d0 is in-progress we must activate busyd0end interrupt +	 * to wait this completion. Else this request has no busy step. +	 */ +	if (busy_d0) { +		if (!host->busy_status) { +			writel_relaxed(mask | host->variant->busy_detect_mask, +				       base + MMCIMASK0); +			host->busy_status = status & +				(MCI_CMDSENT | MCI_CMDRESPEND); +		} +		return false; +	} + +complete: +	if (host->busy_status) { +		writel_relaxed(mask & ~host->variant->busy_detect_mask, +			       base + MMCIMASK0); +		writel_relaxed(host->variant->busy_detect_mask, +			       base + MMCICLEAR); +		host->busy_status = 0; +	} + +	return true; +} +  static struct mmci_host_ops sdmmc_variant_ops = {  	.validate_data = sdmmc_idma_validate_data,  	.prep_data = sdmmc_idma_prep_data, @@ -292,6 +333,7 @@ static struct mmci_host_ops sdmmc_variant_ops = {  	.dma_finalize = sdmmc_idma_finalize,  	.set_clkreg = mmci_sdmmc_set_clkreg,  	.set_pwrreg = mmci_sdmmc_set_pwrreg, +	.busy_complete = sdmmc_busy_complete,  };  void sdmmc_variant_init(struct mmci_host *host) diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c index a0670e9cd012..fc6b9cf27d0b 100644 --- a/drivers/mmc/host/moxart-mmc.c +++ b/drivers/mmc/host/moxart-mmc.c @@ -608,8 +608,8 @@ static int moxart_probe(struct platform_device *pdev)  	host->timeout = msecs_to_jiffies(1000);  	host->sysclk = clk_get_rate(clk);  	host->fifo_width = readl(host->base + REG_FEATURE) << 2; -	host->dma_chan_tx = dma_request_slave_channel_reason(dev, "tx"); -	host->dma_chan_rx = dma_request_slave_channel_reason(dev, "rx"); +	host->dma_chan_tx = dma_request_chan(dev, "tx"); +	host->dma_chan_rx = dma_request_chan(dev, "rx");  	spin_lock_init(&host->lock); diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 189e42674d85..010fe29a4888 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -228,6 +228,7 @@  #define MSDC_PATCH_BIT_SPCPUSH    (0x1 << 29)	/* RW */  #define MSDC_PATCH_BIT_DECRCTMO   (0x1 << 30)	/* RW */ +#define MSDC_PATCH_BIT1_CMDTA     (0x7 << 3)    /* RW */  #define MSDC_PATCH_BIT1_STOP_DLY  (0xf << 8)    /* RW */  #define MSDC_PATCH_BIT2_CFGRESP   (0x1 << 15)   /* RW */ @@ -1881,6 +1882,7 @@ static int hs400_tune_response(struct mmc_host *mmc, u32 opcode)  	/* select EMMC50 PAD CMD tune */  	sdr_set_bits(host->base + PAD_CMD_TUNE, BIT(0)); +	sdr_set_field(host->base + MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_CMDTA, 2);  	if (mmc->ios.timing == MMC_TIMING_MMC_HS200 ||  	    mmc->ios.timing == MMC_TIMING_UHS_SDR104) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 952fa4063ff8..767e964ca5a2 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1510,8 +1510,35 @@ static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)  {  	struct omap_hsmmc_host *host = mmc_priv(mmc); -	if (mmc_pdata(host)->init_card) -		mmc_pdata(host)->init_card(card); +	if (card->type == MMC_TYPE_SDIO || card->type == MMC_TYPE_SD_COMBO) { +		struct device_node *np = mmc_dev(mmc)->of_node; + +		/* +		 * REVISIT: should be moved to sdio core and made more +		 * general e.g. by expanding the DT bindings of child nodes +		 * to provide a mechanism to provide this information: +		 * Documentation/devicetree/bindings/mmc/mmc-card.txt +		 */ + +		np = of_get_compatible_child(np, "ti,wl1251"); +		if (np) { +			/* +			 * We have TI wl1251 attached to MMC3. Pass this +			 * information to the SDIO core because it can't be +			 * probed by normal methods. +			 */ + +			dev_info(host->dev, "found wl1251\n"); +			card->quirks |= MMC_QUIRK_NONSTD_SDIO; +			card->cccr.wide_bus = 1; +			card->cis.vendor = 0x104c; +			card->cis.device = 0x9066; +			card->cis.blksize = 512; +			card->cis.max_dtr = 24000000; +			card->ocr = 0x80; +			of_node_put(np); +		} +	}  }  static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable) diff --git a/drivers/mmc/host/owl-mmc.c b/drivers/mmc/host/owl-mmc.c new file mode 100644 index 000000000000..771e3d00f1bb --- /dev/null +++ b/drivers/mmc/host/owl-mmc.c @@ -0,0 +1,696 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Actions Semi Owl SoCs SD/MMC driver + * + * Copyright (c) 2014 Actions Semi Inc. + * Copyright (c) 2019 Manivannan Sadhasivam <[email protected]> + * + * TODO: SDIO support + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/dmaengine.h> +#include <linux/dma-direction.h> +#include <linux/dma-mapping.h> +#include <linux/interrupt.h> +#include <linux/mmc/host.h> +#include <linux/mmc/slot-gpio.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/reset.h> +#include <linux/spinlock.h> + +/* + * SDC registers + */ +#define OWL_REG_SD_EN			0x0000 +#define OWL_REG_SD_CTL			0x0004 +#define OWL_REG_SD_STATE		0x0008 +#define OWL_REG_SD_CMD			0x000c +#define OWL_REG_SD_ARG			0x0010 +#define OWL_REG_SD_RSPBUF0		0x0014 +#define OWL_REG_SD_RSPBUF1		0x0018 +#define OWL_REG_SD_RSPBUF2		0x001c +#define OWL_REG_SD_RSPBUF3		0x0020 +#define OWL_REG_SD_RSPBUF4		0x0024 +#define OWL_REG_SD_DAT			0x0028 +#define OWL_REG_SD_BLK_SIZE		0x002c +#define OWL_REG_SD_BLK_NUM		0x0030 +#define OWL_REG_SD_BUF_SIZE		0x0034 + +/* SD_EN Bits */ +#define OWL_SD_EN_RANE			BIT(31) +#define OWL_SD_EN_RAN_SEED(x)		(((x) & 0x3f) << 24) +#define OWL_SD_EN_S18EN			BIT(12) +#define OWL_SD_EN_RESE			BIT(10) +#define OWL_SD_EN_DAT1_S		BIT(9) +#define OWL_SD_EN_CLK_S			BIT(8) +#define OWL_SD_ENABLE			BIT(7) +#define OWL_SD_EN_BSEL			BIT(6) +#define OWL_SD_EN_SDIOEN		BIT(3) +#define OWL_SD_EN_DDREN			BIT(2) +#define OWL_SD_EN_DATAWID(x)		(((x) & 0x3) << 0) + +/* SD_CTL Bits */ +#define OWL_SD_CTL_TOUTEN		BIT(31) +#define OWL_SD_CTL_TOUTCNT(x)		(((x) & 0x7f) << 24) +#define OWL_SD_CTL_DELAY_MSK		GENMASK(23, 16) +#define OWL_SD_CTL_RDELAY(x)		(((x) & 0xf) << 20) +#define OWL_SD_CTL_WDELAY(x)		(((x) & 0xf) << 16) +#define OWL_SD_CTL_CMDLEN		BIT(13) +#define OWL_SD_CTL_SCC			BIT(12) +#define OWL_SD_CTL_TCN(x)		(((x) & 0xf) << 8) +#define OWL_SD_CTL_TS			BIT(7) +#define OWL_SD_CTL_LBE			BIT(6) +#define OWL_SD_CTL_C7EN			BIT(5) +#define OWL_SD_CTL_TM(x)		(((x) & 0xf) << 0) + +#define OWL_SD_DELAY_LOW_CLK		0x0f +#define OWL_SD_DELAY_MID_CLK		0x0a +#define OWL_SD_DELAY_HIGH_CLK		0x09 +#define OWL_SD_RDELAY_DDR50		0x0a +#define OWL_SD_WDELAY_DDR50		0x08 + +/* SD_STATE Bits */ +#define OWL_SD_STATE_DAT1BS		BIT(18) +#define OWL_SD_STATE_SDIOB_P		BIT(17) +#define OWL_SD_STATE_SDIOB_EN		BIT(16) +#define OWL_SD_STATE_TOUTE		BIT(15) +#define OWL_SD_STATE_BAEP		BIT(14) +#define OWL_SD_STATE_MEMRDY		BIT(12) +#define OWL_SD_STATE_CMDS		BIT(11) +#define OWL_SD_STATE_DAT1AS		BIT(10) +#define OWL_SD_STATE_SDIOA_P		BIT(9) +#define OWL_SD_STATE_SDIOA_EN		BIT(8) +#define OWL_SD_STATE_DAT0S		BIT(7) +#define OWL_SD_STATE_TEIE		BIT(6) +#define OWL_SD_STATE_TEI		BIT(5) +#define OWL_SD_STATE_CLNR		BIT(4) +#define OWL_SD_STATE_CLC		BIT(3) +#define OWL_SD_STATE_WC16ER		BIT(2) +#define OWL_SD_STATE_RC16ER		BIT(1) +#define OWL_SD_STATE_CRC7ER		BIT(0) + +struct owl_mmc_host { +	struct device *dev; +	struct reset_control *reset; +	void __iomem *base; +	struct clk *clk; +	struct completion sdc_complete; +	spinlock_t lock; +	int irq; +	u32 clock; +	bool ddr_50; + +	enum dma_data_direction dma_dir; +	struct dma_chan *dma; +	struct dma_async_tx_descriptor *desc; +	struct dma_slave_config dma_cfg; +	struct completion dma_complete; + +	struct mmc_host	*mmc; +	struct mmc_request *mrq; +	struct mmc_command *cmd; +	struct mmc_data	*data; +}; + +static void owl_mmc_update_reg(void __iomem *reg, unsigned int val, bool state) +{ +	unsigned int regval; + +	regval = readl(reg); + +	if (state) +		regval |= val; +	else +		regval &= ~val; + +	writel(regval, reg); +} + +static irqreturn_t owl_irq_handler(int irq, void *devid) +{ +	struct owl_mmc_host *owl_host = devid; +	unsigned long flags; +	u32 state; + +	spin_lock_irqsave(&owl_host->lock, flags); + +	state = readl(owl_host->base + OWL_REG_SD_STATE); +	if (state & OWL_SD_STATE_TEI) { +		state = readl(owl_host->base + OWL_REG_SD_STATE); +		state |= OWL_SD_STATE_TEI; +		writel(state, owl_host->base + OWL_REG_SD_STATE); +		complete(&owl_host->sdc_complete); +	} + +	spin_unlock_irqrestore(&owl_host->lock, flags); + +	return IRQ_HANDLED; +} + +static void owl_mmc_finish_request(struct owl_mmc_host *owl_host) +{ +	struct mmc_request *mrq = owl_host->mrq; +	struct mmc_data *data = mrq->data; + +	/* Should never be NULL */ +	WARN_ON(!mrq); + +	owl_host->mrq = NULL; + +	if (data) +		dma_unmap_sg(owl_host->dma->device->dev, data->sg, data->sg_len, +			     owl_host->dma_dir); + +	/* Finally finish request */ +	mmc_request_done(owl_host->mmc, mrq); +} + +static void owl_mmc_send_cmd(struct owl_mmc_host *owl_host, +			     struct mmc_command *cmd, +			     struct mmc_data *data) +{ +	u32 mode, state, resp[2]; +	u32 cmd_rsp_mask = 0; + +	init_completion(&owl_host->sdc_complete); + +	switch (mmc_resp_type(cmd)) { +	case MMC_RSP_NONE: +		mode = OWL_SD_CTL_TM(0); +		break; + +	case MMC_RSP_R1: +		if (data) { +			if (data->flags & MMC_DATA_READ) +				mode = OWL_SD_CTL_TM(4); +			else +				mode = OWL_SD_CTL_TM(5); +		} else { +			mode = OWL_SD_CTL_TM(1); +		} +		cmd_rsp_mask = OWL_SD_STATE_CLNR | OWL_SD_STATE_CRC7ER; + +		break; + +	case MMC_RSP_R1B: +		mode = OWL_SD_CTL_TM(3); +		cmd_rsp_mask = OWL_SD_STATE_CLNR | OWL_SD_STATE_CRC7ER; +		break; + +	case MMC_RSP_R2: +		mode = OWL_SD_CTL_TM(2); +		cmd_rsp_mask = OWL_SD_STATE_CLNR | OWL_SD_STATE_CRC7ER; +		break; + +	case MMC_RSP_R3: +		mode = OWL_SD_CTL_TM(1); +		cmd_rsp_mask = OWL_SD_STATE_CLNR; +		break; + +	default: +		dev_warn(owl_host->dev, "Unknown MMC command\n"); +		cmd->error = -EINVAL; +		return; +	} + +	/* Keep current WDELAY and RDELAY */ +	mode |= (readl(owl_host->base + OWL_REG_SD_CTL) & (0xff << 16)); + +	/* Start to send corresponding command type */ +	writel(cmd->arg, owl_host->base + OWL_REG_SD_ARG); +	writel(cmd->opcode, owl_host->base + OWL_REG_SD_CMD); + +	/* Set LBE to send clk at the end of last read block */ +	if (data) { +		mode |= (OWL_SD_CTL_TS | OWL_SD_CTL_LBE | 0x64000000); +	} else { +		mode &= ~(OWL_SD_CTL_TOUTEN | OWL_SD_CTL_LBE); +		mode |= OWL_SD_CTL_TS; +	} + +	owl_host->cmd = cmd; + +	/* Start transfer */ +	writel(mode, owl_host->base + OWL_REG_SD_CTL); + +	if (data) +		return; + +	if (!wait_for_completion_timeout(&owl_host->sdc_complete, 30 * HZ)) { +		dev_err(owl_host->dev, "CMD interrupt timeout\n"); +		cmd->error = -ETIMEDOUT; +		return; +	} + +	state = readl(owl_host->base + OWL_REG_SD_STATE); +	if (mmc_resp_type(cmd) & MMC_RSP_PRESENT) { +		if (cmd_rsp_mask & state) { +			if (state & OWL_SD_STATE_CLNR) { +				dev_err(owl_host->dev, "Error CMD_NO_RSP\n"); +				cmd->error = -EILSEQ; +				return; +			} + +			if (state & OWL_SD_STATE_CRC7ER) { +				dev_err(owl_host->dev, "Error CMD_RSP_CRC\n"); +				cmd->error = -EILSEQ; +				return; +			} +		} + +		if (mmc_resp_type(cmd) & MMC_RSP_136) { +			cmd->resp[3] = readl(owl_host->base + OWL_REG_SD_RSPBUF0); +			cmd->resp[2] = readl(owl_host->base + OWL_REG_SD_RSPBUF1); +			cmd->resp[1] = readl(owl_host->base + OWL_REG_SD_RSPBUF2); +			cmd->resp[0] = readl(owl_host->base + OWL_REG_SD_RSPBUF3); +		} else { +			resp[0] = readl(owl_host->base + OWL_REG_SD_RSPBUF0); +			resp[1] = readl(owl_host->base + OWL_REG_SD_RSPBUF1); +			cmd->resp[0] = resp[1] << 24 | resp[0] >> 8; +			cmd->resp[1] = resp[1] >> 8; +		} +	} +} + +static void owl_mmc_dma_complete(void *param) +{ +	struct owl_mmc_host *owl_host = param; +	struct mmc_data *data = owl_host->data; + +	if (data) +		complete(&owl_host->dma_complete); +} + +static int owl_mmc_prepare_data(struct owl_mmc_host *owl_host, +				struct mmc_data *data) +{ +	u32 total; + +	owl_mmc_update_reg(owl_host->base + OWL_REG_SD_EN, OWL_SD_EN_BSEL, +			   true); +	writel(data->blocks, owl_host->base + OWL_REG_SD_BLK_NUM); +	writel(data->blksz, owl_host->base + OWL_REG_SD_BLK_SIZE); +	total = data->blksz * data->blocks; + +	if (total < 512) +		writel(total, owl_host->base + OWL_REG_SD_BUF_SIZE); +	else +		writel(512, owl_host->base + OWL_REG_SD_BUF_SIZE); + +	if (data->flags & MMC_DATA_WRITE) { +		owl_host->dma_dir = DMA_TO_DEVICE; +		owl_host->dma_cfg.direction = DMA_MEM_TO_DEV; +	} else { +		owl_host->dma_dir = DMA_FROM_DEVICE; +		owl_host->dma_cfg.direction = DMA_DEV_TO_MEM; +	} + +	dma_map_sg(owl_host->dma->device->dev, data->sg, +		   data->sg_len, owl_host->dma_dir); + +	dmaengine_slave_config(owl_host->dma, &owl_host->dma_cfg); +	owl_host->desc = dmaengine_prep_slave_sg(owl_host->dma, data->sg, +						 data->sg_len, +						 owl_host->dma_cfg.direction, +						 DMA_PREP_INTERRUPT | +						 DMA_CTRL_ACK); +	if (!owl_host->desc) { +		dev_err(owl_host->dev, "Can't prepare slave sg\n"); +		return -EBUSY; +	} + +	owl_host->data = data; + +	owl_host->desc->callback = owl_mmc_dma_complete; +	owl_host->desc->callback_param = (void *)owl_host; +	data->error = 0; + +	return 0; +} + +static void owl_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ +	struct owl_mmc_host *owl_host = mmc_priv(mmc); +	struct mmc_data *data = mrq->data; +	int ret; + +	owl_host->mrq = mrq; +	if (mrq->data) { +		ret = owl_mmc_prepare_data(owl_host, data); +		if (ret < 0) { +			data->error = ret; +			goto err_out; +		} + +		init_completion(&owl_host->dma_complete); +		dmaengine_submit(owl_host->desc); +		dma_async_issue_pending(owl_host->dma); +	} + +	owl_mmc_send_cmd(owl_host, mrq->cmd, data); + +	if (data) { +		if (!wait_for_completion_timeout(&owl_host->sdc_complete, +						 10 * HZ)) { +			dev_err(owl_host->dev, "CMD interrupt timeout\n"); +			mrq->cmd->error = -ETIMEDOUT; +			dmaengine_terminate_all(owl_host->dma); +			goto err_out; +		} + +		if (!wait_for_completion_timeout(&owl_host->dma_complete, +						 5 * HZ)) { +			dev_err(owl_host->dev, "DMA interrupt timeout\n"); +			mrq->cmd->error = -ETIMEDOUT; +			dmaengine_terminate_all(owl_host->dma); +			goto err_out; +		} + +		if (data->stop) +			owl_mmc_send_cmd(owl_host, data->stop, NULL); + +		data->bytes_xfered = data->blocks * data->blksz; +	} + +err_out: +	owl_mmc_finish_request(owl_host); +} + +static int owl_mmc_set_clk_rate(struct owl_mmc_host *owl_host, +				unsigned int rate) +{ +	unsigned long clk_rate; +	int ret; +	u32 reg; + +	reg = readl(owl_host->base + OWL_REG_SD_CTL); +	reg &= ~OWL_SD_CTL_DELAY_MSK; + +	/* Set RDELAY and WDELAY based on the clock */ +	if (rate <= 1000000) { +		writel(reg | OWL_SD_CTL_RDELAY(OWL_SD_DELAY_LOW_CLK) | +		       OWL_SD_CTL_WDELAY(OWL_SD_DELAY_LOW_CLK), +		       owl_host->base + OWL_REG_SD_CTL); +	} else if ((rate > 1000000) && (rate <= 26000000)) { +		writel(reg | OWL_SD_CTL_RDELAY(OWL_SD_DELAY_MID_CLK) | +		       OWL_SD_CTL_WDELAY(OWL_SD_DELAY_MID_CLK), +		       owl_host->base + OWL_REG_SD_CTL); +	} else if ((rate > 26000000) && (rate <= 52000000) && !owl_host->ddr_50) { +		writel(reg | OWL_SD_CTL_RDELAY(OWL_SD_DELAY_HIGH_CLK) | +		       OWL_SD_CTL_WDELAY(OWL_SD_DELAY_HIGH_CLK), +		       owl_host->base + OWL_REG_SD_CTL); +	/* DDR50 mode has special delay chain */ +	} else if ((rate > 26000000) && (rate <= 52000000) && owl_host->ddr_50) { +		writel(reg | OWL_SD_CTL_RDELAY(OWL_SD_RDELAY_DDR50) | +		       OWL_SD_CTL_WDELAY(OWL_SD_WDELAY_DDR50), +		       owl_host->base + OWL_REG_SD_CTL); +	} else { +		dev_err(owl_host->dev, "SD clock rate not supported\n"); +		return -EINVAL; +	} + +	clk_rate = clk_round_rate(owl_host->clk, rate << 1); +	ret = clk_set_rate(owl_host->clk, clk_rate); + +	return ret; +} + +static void owl_mmc_set_clk(struct owl_mmc_host *owl_host, struct mmc_ios *ios) +{ +	if (!ios->clock) +		return; + +	owl_host->clock = ios->clock; +	owl_mmc_set_clk_rate(owl_host, ios->clock); +} + +static void owl_mmc_set_bus_width(struct owl_mmc_host *owl_host, +				  struct mmc_ios *ios) +{ +	u32 reg; + +	reg = readl(owl_host->base + OWL_REG_SD_EN); +	reg &= ~0x03; +	switch (ios->bus_width) { +	case MMC_BUS_WIDTH_1: +		break; +	case MMC_BUS_WIDTH_4: +		reg |= OWL_SD_EN_DATAWID(1); +		break; +	case MMC_BUS_WIDTH_8: +		reg |= OWL_SD_EN_DATAWID(2); +		break; +	} + +	writel(reg, owl_host->base + OWL_REG_SD_EN); +} + +static void owl_mmc_ctr_reset(struct owl_mmc_host *owl_host) +{ +	reset_control_assert(owl_host->reset); +	udelay(20); +	reset_control_deassert(owl_host->reset); +} + +static void owl_mmc_power_on(struct owl_mmc_host *owl_host) +{ +	u32 mode; + +	init_completion(&owl_host->sdc_complete); + +	/* Enable transfer end IRQ */ +	owl_mmc_update_reg(owl_host->base + OWL_REG_SD_STATE, +		       OWL_SD_STATE_TEIE, true); + +	/* Send init clk */ +	mode = (readl(owl_host->base + OWL_REG_SD_CTL) & (0xff << 16)); +	mode |= OWL_SD_CTL_TS | OWL_SD_CTL_TCN(5) | OWL_SD_CTL_TM(8); +	writel(mode, owl_host->base + OWL_REG_SD_CTL); + +	if (!wait_for_completion_timeout(&owl_host->sdc_complete, HZ)) { +		dev_err(owl_host->dev, "CMD interrupt timeout\n"); +		return; +	} +} + +static void owl_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ +	struct owl_mmc_host *owl_host = mmc_priv(mmc); + +	switch (ios->power_mode) { +	case MMC_POWER_UP: +		dev_dbg(owl_host->dev, "Powering card up\n"); + +		/* Reset the SDC controller to clear all previous states */ +		owl_mmc_ctr_reset(owl_host); +		clk_prepare_enable(owl_host->clk); +		writel(OWL_SD_ENABLE | OWL_SD_EN_RESE, +		       owl_host->base + OWL_REG_SD_EN); + +		break; + +	case MMC_POWER_ON: +		dev_dbg(owl_host->dev, "Powering card on\n"); +		owl_mmc_power_on(owl_host); + +		break; + +	case MMC_POWER_OFF: +		dev_dbg(owl_host->dev, "Powering card off\n"); +		clk_disable_unprepare(owl_host->clk); + +		return; + +	default: +		dev_dbg(owl_host->dev, "Ignoring unknown card power state\n"); +		break; +	} + +	if (ios->clock != owl_host->clock) +		owl_mmc_set_clk(owl_host, ios); + +	owl_mmc_set_bus_width(owl_host, ios); + +	/* Enable DDR mode if requested */ +	if (ios->timing == MMC_TIMING_UHS_DDR50) { +		owl_host->ddr_50 = 1; +		owl_mmc_update_reg(owl_host->base + OWL_REG_SD_EN, +			       OWL_SD_EN_DDREN, true); +	} else { +		owl_host->ddr_50 = 0; +	} +} + +static int owl_mmc_start_signal_voltage_switch(struct mmc_host *mmc, +					       struct mmc_ios *ios) +{ +	struct owl_mmc_host *owl_host = mmc_priv(mmc); + +	/* It is enough to change the pad ctrl bit for voltage switch */ +	switch (ios->signal_voltage) { +	case MMC_SIGNAL_VOLTAGE_330: +		owl_mmc_update_reg(owl_host->base + OWL_REG_SD_EN, +			       OWL_SD_EN_S18EN, false); +		break; +	case MMC_SIGNAL_VOLTAGE_180: +		owl_mmc_update_reg(owl_host->base + OWL_REG_SD_EN, +			       OWL_SD_EN_S18EN, true); +		break; +	default: +		return -ENOTSUPP; +	} + +	return 0; +} + +static const struct mmc_host_ops owl_mmc_ops = { +	.request	= owl_mmc_request, +	.set_ios	= owl_mmc_set_ios, +	.get_ro		= mmc_gpio_get_ro, +	.get_cd		= mmc_gpio_get_cd, +	.start_signal_voltage_switch = owl_mmc_start_signal_voltage_switch, +}; + +static int owl_mmc_probe(struct platform_device *pdev) +{ +	struct owl_mmc_host *owl_host; +	struct mmc_host *mmc; +	struct resource *res; +	int ret; + +	mmc = mmc_alloc_host(sizeof(struct owl_mmc_host), &pdev->dev); +	if (!mmc) { +		dev_err(&pdev->dev, "mmc alloc host failed\n"); +		return -ENOMEM; +	} +	platform_set_drvdata(pdev, mmc); + +	owl_host = mmc_priv(mmc); +	owl_host->dev = &pdev->dev; +	owl_host->mmc = mmc; +	spin_lock_init(&owl_host->lock); + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	owl_host->base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(owl_host->base)) { +		dev_err(&pdev->dev, "Failed to remap registers\n"); +		ret = PTR_ERR(owl_host->base); +		goto err_free_host; +	} + +	owl_host->clk = devm_clk_get(&pdev->dev, NULL); +	if (IS_ERR(owl_host->clk)) { +		dev_err(&pdev->dev, "No clock defined\n"); +		ret = PTR_ERR(owl_host->clk); +		goto err_free_host; +	} + +	owl_host->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL); +	if (IS_ERR(owl_host->reset)) { +		dev_err(&pdev->dev, "Could not get reset control\n"); +		ret = PTR_ERR(owl_host->reset); +		goto err_free_host; +	} + +	mmc->ops		= &owl_mmc_ops; +	mmc->max_blk_count	= 512; +	mmc->max_blk_size	= 512; +	mmc->max_segs		= 256; +	mmc->max_seg_size	= 262144; +	mmc->max_req_size	= 262144; +	/* 100kHz ~ 52MHz */ +	mmc->f_min		= 100000; +	mmc->f_max		= 52000000; +	mmc->caps	       |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | +				  MMC_CAP_4_BIT_DATA; +	mmc->caps2		= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_NO_SDIO); +	mmc->ocr_avail		= MMC_VDD_32_33 | MMC_VDD_33_34 | +				  MMC_VDD_165_195; + +	ret = mmc_of_parse(mmc); +	if (ret) +		goto err_free_host; + +	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; +	owl_host->dma = dma_request_slave_channel(&pdev->dev, "mmc"); +	if (!owl_host->dma) { +		dev_err(owl_host->dev, "Failed to get external DMA channel.\n"); +		ret = -ENXIO; +		goto err_free_host; +	} + +	dev_info(&pdev->dev, "Using %s for DMA transfers\n", +		 dma_chan_name(owl_host->dma)); + +	owl_host->dma_cfg.src_addr = res->start + OWL_REG_SD_DAT; +	owl_host->dma_cfg.dst_addr = res->start + OWL_REG_SD_DAT; +	owl_host->dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +	owl_host->dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +	owl_host->dma_cfg.device_fc = false; + +	owl_host->irq = platform_get_irq(pdev, 0); +	if (owl_host->irq < 0) { +		ret = -EINVAL; +		goto err_free_host; +	} + +	ret = devm_request_irq(&pdev->dev, owl_host->irq, owl_irq_handler, +			       0, dev_name(&pdev->dev), owl_host); +	if (ret) { +		dev_err(&pdev->dev, "Failed to request irq %d\n", +			owl_host->irq); +		goto err_free_host; +	} + +	ret = mmc_add_host(mmc); +	if (ret) { +		dev_err(&pdev->dev, "Failed to add host\n"); +		goto err_free_host; +	} + +	dev_dbg(&pdev->dev, "Owl MMC Controller Initialized\n"); + +	return 0; + +err_free_host: +	mmc_free_host(mmc); + +	return ret; +} + +static int owl_mmc_remove(struct platform_device *pdev) +{ +	struct mmc_host	*mmc = platform_get_drvdata(pdev); +	struct owl_mmc_host *owl_host = mmc_priv(mmc); + +	mmc_remove_host(mmc); +	disable_irq(owl_host->irq); +	mmc_free_host(mmc); + +	return 0; +} + +static const struct of_device_id owl_mmc_of_match[] = { +	{.compatible = "actions,owl-mmc",}, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, owl_mmc_of_match); + +static struct platform_driver owl_mmc_driver = { +	.driver = { +		.name	= "owl_mmc", +		.of_match_table = of_match_ptr(owl_mmc_of_match), +	}, +	.probe		= owl_mmc_probe, +	.remove		= owl_mmc_remove, +}; +module_platform_driver(owl_mmc_driver); + +MODULE_DESCRIPTION("Actions Semi Owl SoCs SD/MMC Driver"); +MODULE_AUTHOR("Actions Semi"); +MODULE_AUTHOR("Manivannan Sadhasivam <[email protected]>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index a66f8d6d61d1..18839a10594c 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -308,6 +308,7 @@ static const struct soc_device_attribute soc_whitelist[] = {  	  .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },  	/* generic ones */  	{ .soc_id = "r8a774a1" }, +	{ .soc_id = "r8a774b1" },  	{ .soc_id = "r8a774c0" },  	{ .soc_id = "r8a77470" },  	{ .soc_id = "r8a7795" }, diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 1604f512c7bd..105e73d4a3b9 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -61,7 +61,7 @@ struct sdhci_acpi_slot {  	mmc_pm_flag_t	pm_caps;  	unsigned int	flags;  	size_t		priv_size; -	int (*probe_slot)(struct platform_device *, const char *, const char *); +	int (*probe_slot)(struct platform_device *, struct acpi_device *);  	int (*remove_slot)(struct platform_device *);  	int (*free_slot)(struct platform_device *pdev);  	int (*setup_host)(struct platform_device *pdev); @@ -325,12 +325,10 @@ static bool sdhci_acpi_cht_pci_wifi(unsigned int vendor, unsigned int device,   * wifi card in the expected slot with an ACPI companion node, is used to   * indicate that acpi_device_fix_up_power() should be avoided.   */ -static inline bool sdhci_acpi_no_fixup_child_power(const char *hid, -						   const char *uid) +static inline bool sdhci_acpi_no_fixup_child_power(struct acpi_device *adev)  {  	return sdhci_acpi_cht() && -	       !strcmp(hid, "80860F14") && -	       !strcmp(uid, "2") && +	       acpi_dev_hid_uid_match(adev, "80860F14", "2") &&  	       sdhci_acpi_cht_pci_wifi(0x14e4, 0x43ec, 0, 28);  } @@ -345,8 +343,7 @@ static inline bool sdhci_acpi_byt_defer(struct device *dev)  	return false;  } -static inline bool sdhci_acpi_no_fixup_child_power(const char *hid, -						   const char *uid) +static inline bool sdhci_acpi_no_fixup_child_power(struct acpi_device *adev)  {  	return false;  } @@ -375,19 +372,18 @@ out:  	return ret;  } -static int intel_probe_slot(struct platform_device *pdev, const char *hid, -			    const char *uid) +static int intel_probe_slot(struct platform_device *pdev, struct acpi_device *adev)  {  	struct sdhci_acpi_host *c = platform_get_drvdata(pdev);  	struct intel_host *intel_host = sdhci_acpi_priv(c);  	struct sdhci_host *host = c->host; -	if (hid && uid && !strcmp(hid, "80860F14") && !strcmp(uid, "1") && +	if (acpi_dev_hid_uid_match(adev, "80860F14", "1") &&  	    sdhci_readl(host, SDHCI_CAPABILITIES) == 0x446cc8b2 &&  	    sdhci_readl(host, SDHCI_CAPABILITIES_1) == 0x00000807)  		host->timeout_clk = 1000; /* 1000 kHz i.e. 1 MHz */ -	if (hid && !strcmp(hid, "80865ACA")) +	if (acpi_dev_hid_uid_match(adev, "80865ACA", NULL))  		host->mmc_host_ops.get_cd = bxt_get_cd;  	intel_dsm_init(intel_host, &pdev->dev, host->mmc); @@ -473,8 +469,7 @@ static irqreturn_t sdhci_acpi_qcom_handler(int irq, void *ptr)  	return IRQ_HANDLED;  } -static int qcom_probe_slot(struct platform_device *pdev, const char *hid, -			   const char *uid) +static int qcom_probe_slot(struct platform_device *pdev, struct acpi_device *adev)  {  	struct sdhci_acpi_host *c = platform_get_drvdata(pdev);  	struct sdhci_host *host = c->host; @@ -482,7 +477,7 @@ static int qcom_probe_slot(struct platform_device *pdev, const char *hid,  	*irq = -EINVAL; -	if (strcmp(hid, "QCOM8051")) +	if (!acpi_dev_hid_uid_match(adev, "QCOM8051", NULL))  		return 0;  	*irq = platform_get_irq(pdev, 1); @@ -501,14 +496,12 @@ static int qcom_free_slot(struct platform_device *pdev)  	struct sdhci_host *host = c->host;  	struct acpi_device *adev;  	int *irq = sdhci_acpi_priv(c); -	const char *hid;  	adev = ACPI_COMPANION(dev);  	if (!adev)  		return -ENODEV; -	hid = acpi_device_hid(adev); -	if (strcmp(hid, "QCOM8051")) +	if (!acpi_dev_hid_uid_match(adev, "QCOM8051", NULL))  		return 0;  	if (*irq < 0) @@ -583,7 +576,7 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_amd = {  };  static int sdhci_acpi_emmc_amd_probe_slot(struct platform_device *pdev, -					  const char *hid, const char *uid) +					  struct acpi_device *adev)  {  	struct sdhci_acpi_host *c = platform_get_drvdata(pdev);  	struct sdhci_host *host   = c->host; @@ -654,17 +647,12 @@ static const struct acpi_device_id sdhci_acpi_ids[] = {  };  MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids); -static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid, -							 const char *uid) +static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(struct acpi_device *adev)  {  	const struct sdhci_acpi_uid_slot *u;  	for (u = sdhci_acpi_uids; u->hid; u++) { -		if (strcmp(u->hid, hid)) -			continue; -		if (!u->uid) -			return u->slot; -		if (uid && !strcmp(u->uid, uid)) +		if (acpi_dev_hid_uid_match(adev, u->hid, u->uid))  			return u->slot;  	}  	return NULL; @@ -680,22 +668,17 @@ static int sdhci_acpi_probe(struct platform_device *pdev)  	struct resource *iomem;  	resource_size_t len;  	size_t priv_size; -	const char *hid; -	const char *uid;  	int err;  	device = ACPI_COMPANION(dev);  	if (!device)  		return -ENODEV; -	hid = acpi_device_hid(device); -	uid = acpi_device_uid(device); - -	slot = sdhci_acpi_get_slot(hid, uid); +	slot = sdhci_acpi_get_slot(device);  	/* Power on the SDHCI controller and its children */  	acpi_device_fix_up_power(device); -	if (!sdhci_acpi_no_fixup_child_power(hid, uid)) { +	if (!sdhci_acpi_no_fixup_child_power(device)) {  		list_for_each_entry(child, &device->children, node)  			if (child->status.present && child->status.enabled)  				acpi_device_fix_up_power(child); @@ -745,7 +728,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)  	if (c->slot) {  		if (c->slot->probe_slot) { -			err = c->slot->probe_slot(pdev, hid, uid); +			err = c->slot->probe_slot(pdev, device);  			if (err)  				goto err_free;  		} diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index 57b582bf73d9..9289bb4d633e 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -51,6 +51,11 @@  #define ESDHC_CLOCK_HCKEN		0x00000002  #define ESDHC_CLOCK_IPGEN		0x00000001 +/* System Control 2 Register */ +#define ESDHC_SYSTEM_CONTROL_2		0x3c +#define ESDHC_SMPCLKSEL			0x00800000 +#define ESDHC_EXTN			0x00400000 +  /* Host Controller Capabilities Register 2 */  #define ESDHC_CAPABILITIES_1		0x114 @@ -59,7 +64,16 @@  #define ESDHC_HS400_WNDW_ADJUST		0x00000040  #define ESDHC_HS400_MODE		0x00000010  #define ESDHC_TB_EN			0x00000004 +#define ESDHC_TB_MODE_MASK		0x00000003 +#define ESDHC_TB_MODE_SW		0x00000003 +#define ESDHC_TB_MODE_3			0x00000002 + +#define ESDHC_TBSTAT			0x124 +  #define ESDHC_TBPTR			0x128 +#define ESDHC_WNDW_STRT_PTR_SHIFT	8 +#define ESDHC_WNDW_STRT_PTR_MASK	(0x7f << 8) +#define ESDHC_WNDW_END_PTR_MASK		0x7f  /* SD Clock Control Register */  #define ESDHC_SDCLKCTL			0x144 diff --git a/drivers/mmc/host/sdhci-milbeaut.c b/drivers/mmc/host/sdhci-milbeaut.c new file mode 100644 index 000000000000..a1aa21b9ae1c --- /dev/null +++ b/drivers/mmc/host/sdhci-milbeaut.c @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd + *              Vincent Yang <[email protected]> + * Copyright (C) 2015 Linaro Ltd  Andy Green <[email protected]> + * Copyright (C) 2019 Socionext Inc. + *              Takao Orito <[email protected]> + */ + +#include <linux/bits.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/property.h> + +#include "sdhci-pltfm.h" +#include "sdhci_f_sdh30.h" + +/* milbeaut bridge controller register */ +#define MLB_SOFT_RESET		0x0200 +#define  MLB_SOFT_RESET_RSTX		BIT(0) + +#define MLB_WP_CD_LED_SET	0x0210 +#define  MLB_WP_CD_LED_SET_LED_INV  BIT(2) + +#define MLB_CR_SET			0x0220 +#define  MLB_CR_SET_CR_TOCLKUNIT       BIT(24) +#define  MLB_CR_SET_CR_TOCLKFREQ_SFT   (16) +#define  MLB_CR_SET_CR_TOCLKFREQ_MASK  (0x3F << MLB_CR_SET_CR_TOCLKFREQ_SFT) +#define  MLB_CR_SET_CR_BCLKFREQ_SFT    (8) +#define  MLB_CR_SET_CR_BCLKFREQ_MASK   (0xFF << MLB_CR_SET_CR_BCLKFREQ_SFT) +#define  MLB_CR_SET_CR_RTUNTIMER_SFT   (4) +#define  MLB_CR_SET_CR_RTUNTIMER_MASK  (0xF << MLB_CR_SET_CR_RTUNTIMER_SFT) + +#define MLB_SD_TOCLK_I_DIV  16 +#define MLB_TOCLKFREQ_UNIT_THRES    16000000 +#define MLB_CAL_TOCLKFREQ_MHZ(rate) (rate / MLB_SD_TOCLK_I_DIV / 1000000) +#define MLB_CAL_TOCLKFREQ_KHZ(rate) (rate / MLB_SD_TOCLK_I_DIV / 1000) +#define MLB_TOCLKFREQ_MAX   63 +#define MLB_TOCLKFREQ_MIN    1 + +#define MLB_SD_BCLK_I_DIV   4 +#define MLB_CAL_BCLKFREQ(rate)  (rate / MLB_SD_BCLK_I_DIV / 1000000) +#define MLB_BCLKFREQ_MAX        255 +#define MLB_BCLKFREQ_MIN          1 + +#define MLB_CDR_SET			0x0230 +#define MLB_CDR_SET_CLK2POW16	3 + +struct f_sdhost_priv { +	struct clk *clk_iface; +	struct clk *clk; +	struct device *dev; +	bool enable_cmd_dat_delay; +}; + +static void sdhci_milbeaut_soft_voltage_switch(struct sdhci_host *host) +{ +	u32 ctrl = 0; + +	usleep_range(2500, 3000); +	ctrl = sdhci_readl(host, F_SDH30_IO_CONTROL2); +	ctrl |= F_SDH30_CRES_O_DN; +	sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2); +	ctrl |= F_SDH30_MSEL_O_1_8; +	sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2); + +	ctrl &= ~F_SDH30_CRES_O_DN; +	sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2); +	usleep_range(2500, 3000); + +	ctrl = sdhci_readl(host, F_SDH30_TUNING_SETTING); +	ctrl |= F_SDH30_CMD_CHK_DIS; +	sdhci_writel(host, ctrl, F_SDH30_TUNING_SETTING); +} + +static unsigned int sdhci_milbeaut_get_min_clock(struct sdhci_host *host) +{ +	return F_SDH30_MIN_CLOCK; +} + +static void sdhci_milbeaut_reset(struct sdhci_host *host, u8 mask) +{ +	struct f_sdhost_priv *priv = sdhci_priv(host); +	u16 clk; +	u32 ctl; +	ktime_t timeout; + +	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); +	clk = (clk & ~SDHCI_CLOCK_CARD_EN) | SDHCI_CLOCK_INT_EN; +	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + +	sdhci_reset(host, mask); + +	clk |= SDHCI_CLOCK_CARD_EN; +	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + +	timeout = ktime_add_ms(ktime_get(), 10); +	while (1) { +		bool timedout = ktime_after(ktime_get(), timeout); + +		clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); +		if (clk & SDHCI_CLOCK_INT_STABLE) +			break; +		if (timedout) { +			pr_err("%s: Internal clock never stabilised.\n", +				mmc_hostname(host->mmc)); +			sdhci_dumpregs(host); +			return; +		} +		udelay(10); +	} + +	if (priv->enable_cmd_dat_delay) { +		ctl = sdhci_readl(host, F_SDH30_ESD_CONTROL); +		ctl |= F_SDH30_CMD_DAT_DELAY; +		sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL); +	} +} + +static void sdhci_milbeaut_set_power(struct sdhci_host *host, +			unsigned char mode, unsigned short vdd) +{ +	if (!IS_ERR(host->mmc->supply.vmmc)) { +		struct mmc_host *mmc = host->mmc; + +		mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); +	} +	sdhci_set_power_noreg(host, mode, vdd); +} + +static const struct sdhci_ops sdhci_milbeaut_ops = { +	.voltage_switch = sdhci_milbeaut_soft_voltage_switch, +	.get_min_clock = sdhci_milbeaut_get_min_clock, +	.reset = sdhci_milbeaut_reset, +	.set_clock = sdhci_set_clock, +	.set_bus_width = sdhci_set_bus_width, +	.set_uhs_signaling = sdhci_set_uhs_signaling, +	.set_power = sdhci_milbeaut_set_power, +}; + +static void sdhci_milbeaut_bridge_reset(struct sdhci_host *host, +						int reset_flag) +{ +	if (reset_flag) +		sdhci_writel(host, 0, MLB_SOFT_RESET); +	else +		sdhci_writel(host, MLB_SOFT_RESET_RSTX, MLB_SOFT_RESET); +} + +static void sdhci_milbeaut_bridge_init(struct sdhci_host *host, +						int rate) +{ +	u32 val, clk; + +	/* IO_SDIO_CR_SET should be set while reset */ +	val = sdhci_readl(host, MLB_CR_SET); +	val &= ~(MLB_CR_SET_CR_TOCLKFREQ_MASK | MLB_CR_SET_CR_TOCLKUNIT | +			MLB_CR_SET_CR_BCLKFREQ_MASK); +	if (rate >= MLB_TOCLKFREQ_UNIT_THRES) { +		clk = MLB_CAL_TOCLKFREQ_MHZ(rate); +		clk = min_t(u32, MLB_TOCLKFREQ_MAX, clk); +		val |= MLB_CR_SET_CR_TOCLKUNIT | +			(clk << MLB_CR_SET_CR_TOCLKFREQ_SFT); +	} else { +		clk = MLB_CAL_TOCLKFREQ_KHZ(rate); +		clk = min_t(u32, MLB_TOCLKFREQ_MAX, clk); +		clk = max_t(u32, MLB_TOCLKFREQ_MIN, clk); +		val |= clk << MLB_CR_SET_CR_TOCLKFREQ_SFT; +	} + +	clk = MLB_CAL_BCLKFREQ(rate); +	clk = min_t(u32, MLB_BCLKFREQ_MAX, clk); +	clk = max_t(u32, MLB_BCLKFREQ_MIN, clk); +	val |=  clk << MLB_CR_SET_CR_BCLKFREQ_SFT; +	val &= ~MLB_CR_SET_CR_RTUNTIMER_MASK; +	sdhci_writel(host, val, MLB_CR_SET); + +	sdhci_writel(host, MLB_CDR_SET_CLK2POW16, MLB_CDR_SET); + +	sdhci_writel(host, MLB_WP_CD_LED_SET_LED_INV, MLB_WP_CD_LED_SET); +} + +static void sdhci_milbeaut_vendor_init(struct sdhci_host *host) +{ +	struct f_sdhost_priv *priv = sdhci_priv(host); +	u32 ctl; + +	ctl = sdhci_readl(host, F_SDH30_IO_CONTROL2); +	ctl |= F_SDH30_CRES_O_DN; +	sdhci_writel(host, ctl, F_SDH30_IO_CONTROL2); +	ctl &= ~F_SDH30_MSEL_O_1_8; +	sdhci_writel(host, ctl, F_SDH30_IO_CONTROL2); +	ctl &= ~F_SDH30_CRES_O_DN; +	sdhci_writel(host, ctl, F_SDH30_IO_CONTROL2); + +	ctl = sdhci_readw(host, F_SDH30_AHB_CONFIG); +	ctl |= F_SDH30_SIN | F_SDH30_AHB_INCR_16 | F_SDH30_AHB_INCR_8 | +	       F_SDH30_AHB_INCR_4; +	ctl &= ~(F_SDH30_AHB_BIGED | F_SDH30_BUSLOCK_EN); +	sdhci_writew(host, ctl, F_SDH30_AHB_CONFIG); + +	if (priv->enable_cmd_dat_delay) { +		ctl = sdhci_readl(host, F_SDH30_ESD_CONTROL); +		ctl |= F_SDH30_CMD_DAT_DELAY; +		sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL); +	} +} + +static const struct of_device_id mlb_dt_ids[] = { +	{ +		.compatible = "socionext,milbeaut-m10v-sdhci-3.0", +	}, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mlb_dt_ids); + +static void sdhci_milbeaut_init(struct sdhci_host *host) +{ +	struct f_sdhost_priv *priv = sdhci_priv(host); +	int rate = clk_get_rate(priv->clk); +	u16 ctl; + +	sdhci_milbeaut_bridge_reset(host, 0); + +	ctl = sdhci_readw(host, SDHCI_CLOCK_CONTROL); +	ctl &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN); +	sdhci_writew(host, ctl, SDHCI_CLOCK_CONTROL); + +	sdhci_milbeaut_bridge_reset(host, 1); + +	sdhci_milbeaut_bridge_init(host, rate); +	sdhci_milbeaut_bridge_reset(host, 0); + +	sdhci_milbeaut_vendor_init(host); +} + +static int sdhci_milbeaut_probe(struct platform_device *pdev) +{ +	struct sdhci_host *host; +	struct device *dev = &pdev->dev; +	struct resource *res; +	int irq, ret = 0; +	struct f_sdhost_priv *priv; + +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) { +		dev_err(dev, "%s: no irq specified\n", __func__); +		return irq; +	} + +	host = sdhci_alloc_host(dev, sizeof(struct f_sdhost_priv)); +	if (IS_ERR(host)) +		return PTR_ERR(host); + +	priv = sdhci_priv(host); +	priv->dev = dev; + +	host->quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | +			   SDHCI_QUIRK_INVERTED_WRITE_PROTECT | +			   SDHCI_QUIRK_CLOCK_BEFORE_RESET | +			   SDHCI_QUIRK_DELAY_AFTER_POWER; +	host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE | +			SDHCI_QUIRK2_TUNING_WORK_AROUND | +			SDHCI_QUIRK2_PRESET_VALUE_BROKEN; + +	priv->enable_cmd_dat_delay = device_property_read_bool(dev, +						"fujitsu,cmd-dat-delay-select"); + +	ret = mmc_of_parse(host->mmc); +	if (ret) +		goto err; + +	platform_set_drvdata(pdev, host); + +	host->hw_name = "f_sdh30"; +	host->ops = &sdhci_milbeaut_ops; +	host->irq = irq; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	host->ioaddr = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(host->ioaddr)) { +		ret = PTR_ERR(host->ioaddr); +		goto err; +	} + +	if (dev_of_node(dev)) { +		sdhci_get_of_property(pdev); + +		priv->clk_iface = devm_clk_get(&pdev->dev, "iface"); +		if (IS_ERR(priv->clk_iface)) { +			ret = PTR_ERR(priv->clk_iface); +			goto err; +		} + +		ret = clk_prepare_enable(priv->clk_iface); +		if (ret) +			goto err; + +		priv->clk = devm_clk_get(&pdev->dev, "core"); +		if (IS_ERR(priv->clk)) { +			ret = PTR_ERR(priv->clk); +			goto err_clk; +		} + +		ret = clk_prepare_enable(priv->clk); +		if (ret) +			goto err_clk; +	} + +	sdhci_milbeaut_init(host); + +	ret = sdhci_add_host(host); +	if (ret) +		goto err_add_host; + +	return 0; + +err_add_host: +	clk_disable_unprepare(priv->clk); +err_clk: +	clk_disable_unprepare(priv->clk_iface); +err: +	sdhci_free_host(host); +	return ret; +} + +static int sdhci_milbeaut_remove(struct platform_device *pdev) +{ +	struct sdhci_host *host = platform_get_drvdata(pdev); +	struct f_sdhost_priv *priv = sdhci_priv(host); + +	sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) == +			  0xffffffff); + +	clk_disable_unprepare(priv->clk_iface); +	clk_disable_unprepare(priv->clk); + +	sdhci_free_host(host); +	platform_set_drvdata(pdev, NULL); + +	return 0; +} + +static struct platform_driver sdhci_milbeaut_driver = { +	.driver = { +		.name = "sdhci-milbeaut", +		.of_match_table = of_match_ptr(mlb_dt_ids), +	}, +	.probe	= sdhci_milbeaut_probe, +	.remove	= sdhci_milbeaut_remove, +}; + +module_platform_driver(sdhci_milbeaut_driver); + +MODULE_DESCRIPTION("MILBEAUT SD Card Controller driver"); +MODULE_AUTHOR("Takao Orito <[email protected]>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sdhci-milbeaut"); diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index b75c82d8d6c1..3d0bb5e2e09b 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -99,7 +99,7 @@  #define CORE_PWRSAVE_DLL	BIT(3) -#define DDR_CONFIG_POR_VAL	0x80040853 +#define DDR_CONFIG_POR_VAL	0x80040873  #define INVALID_TUNING_PHASE	-1 @@ -148,8 +148,9 @@ struct sdhci_msm_offset {  	u32 core_ddr_200_cfg;  	u32 core_vendor_spec3;  	u32 core_dll_config_2; +	u32 core_dll_config_3; +	u32 core_ddr_config_old; /* Applicable to sdcc minor ver < 0x49 */  	u32 core_ddr_config; -	u32 core_ddr_config_2;  };  static const struct sdhci_msm_offset sdhci_msm_v5_offset = { @@ -177,8 +178,8 @@ static const struct sdhci_msm_offset sdhci_msm_v5_offset = {  	.core_ddr_200_cfg = 0x224,  	.core_vendor_spec3 = 0x250,  	.core_dll_config_2 = 0x254, -	.core_ddr_config = 0x258, -	.core_ddr_config_2 = 0x25c, +	.core_dll_config_3 = 0x258, +	.core_ddr_config = 0x25c,  };  static const struct sdhci_msm_offset sdhci_msm_mci_offset = { @@ -207,8 +208,8 @@ static const struct sdhci_msm_offset sdhci_msm_mci_offset = {  	.core_ddr_200_cfg = 0x184,  	.core_vendor_spec3 = 0x1b0,  	.core_dll_config_2 = 0x1b4, -	.core_ddr_config = 0x1b8, -	.core_ddr_config_2 = 0x1bc, +	.core_ddr_config_old = 0x1b8, +	.core_ddr_config = 0x1bc,  };  struct sdhci_msm_variant_ops { @@ -253,6 +254,7 @@ struct sdhci_msm_host {  	const struct sdhci_msm_offset *offset;  	bool use_cdr;  	u32 transfer_mode; +	bool updated_ddr_cfg;  };  static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host) @@ -924,8 +926,10 @@ out:  static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)  {  	struct mmc_host *mmc = host->mmc; -	u32 dll_status, config; +	u32 dll_status, config, ddr_cfg_offset;  	int ret; +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);  	const struct sdhci_msm_offset *msm_offset =  					sdhci_priv_msm_offset(host); @@ -938,8 +942,11 @@ static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)  	 * bootloaders. In the future, if this changes, then the desired  	 * values will need to be programmed appropriately.  	 */ -	writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr + -			msm_offset->core_ddr_config); +	if (msm_host->updated_ddr_cfg) +		ddr_cfg_offset = msm_offset->core_ddr_config; +	else +		ddr_cfg_offset = msm_offset->core_ddr_config_old; +	writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr + ddr_cfg_offset);  	if (mmc->ios.enhanced_strobe) {  		config = readl_relaxed(host->ioaddr + @@ -1899,6 +1906,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)  				msm_offset->core_vendor_spec_capabilities0);  	} +	if (core_major == 1 && core_minor >= 0x49) +		msm_host->updated_ddr_cfg = true; +  	/*  	 * Power on reset state may trigger power irq if previous status of  	 * PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 7023cbec4017..e49b44b4d82e 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -22,6 +22,7 @@  #include <linux/phy/phy.h>  #include <linux/regmap.h>  #include <linux/of.h> +#include <linux/firmware/xlnx-zynqmp.h>  #include "cqhci.h"  #include "sdhci-pltfm.h" @@ -32,6 +33,10 @@  #define PHY_CLK_TOO_SLOW_HZ		400000 +/* Default settings for ZynqMP Clock Phases */ +#define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63,  0,   0, 183, 54,  0, 0} +#define ZYNQMP_OCLK_PHASE {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0} +  /*   * On some SoCs the syscon area has a feature where the upper 16-bits of   * each 32-bit register act as a write mask for the lower 16-bits.  This allows @@ -72,13 +77,38 @@ struct sdhci_arasan_soc_ctl_map {  };  /** + * struct sdhci_arasan_clk_data + * @sdcardclk_hw:	Struct for the clock we might provide to a PHY. + * @sdcardclk:		Pointer to normal 'struct clock' for sdcardclk_hw. + * @sampleclk_hw:	Struct for the clock we might provide to a PHY. + * @sampleclk:		Pointer to normal 'struct clock' for sampleclk_hw. + * @clk_phase_in:	Array of Input Clock Phase Delays for all speed modes + * @clk_phase_out:	Array of Output Clock Phase Delays for all speed modes + * @set_clk_delays:	Function pointer for setting Clock Delays + * @clk_of_data:	Platform specific runtime clock data storage pointer + */ +struct sdhci_arasan_clk_data { +	struct clk_hw	sdcardclk_hw; +	struct clk      *sdcardclk; +	struct clk_hw	sampleclk_hw; +	struct clk      *sampleclk; +	int		clk_phase_in[MMC_TIMING_MMC_HS400 + 1]; +	int		clk_phase_out[MMC_TIMING_MMC_HS400 + 1]; +	void		(*set_clk_delays)(struct sdhci_host *host); +	void		*clk_of_data; +}; + +struct sdhci_arasan_zynqmp_clk_data { +	const struct zynqmp_eemi_ops *eemi_ops; +}; + +/**   * struct sdhci_arasan_data   * @host:		Pointer to the main SDHCI host structure.   * @clk_ahb:		Pointer to the AHB clock   * @phy:		Pointer to the generic phy   * @is_phy_on:		True if the PHY is on; false if not. - * @sdcardclk_hw:	Struct for the clock we might provide to a PHY. - * @sdcardclk:		Pointer to normal 'struct clock' for sdcardclk_hw. + * @clk_data:		Struct for the Arasan Controller Clock Data.   * @soc_ctl_base:	Pointer to regmap for syscon for soc_ctl registers.   * @soc_ctl_map:	Map to get offsets into soc_ctl registers.   */ @@ -89,8 +119,7 @@ struct sdhci_arasan_data {  	bool		is_phy_on;  	bool		has_cqe; -	struct clk_hw	sdcardclk_hw; -	struct clk      *sdcardclk; +	struct sdhci_arasan_clk_data clk_data;  	struct regmap	*soc_ctl_base;  	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; @@ -120,6 +149,12 @@ static const struct sdhci_arasan_soc_ctl_map intel_lgm_emmc_soc_ctl_map = {  	.hiword_update = false,  }; +static const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = { +	.baseclkfreq = { .reg = 0x80, .width = 8, .shift = 2 }, +	.clockmultiplier = { .reg = 0, .width = -1, .shift = -1 }, +	.hiword_update = false, +}; +  /**   * sdhci_arasan_syscon_write - Write to a field in soc_ctl registers   * @@ -174,6 +209,7 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)  {  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);  	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); +	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;  	bool ctrl_phy = false;  	if (!IS_ERR(sdhci_arasan->phy)) { @@ -215,6 +251,10 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)  		sdhci_arasan->is_phy_on = false;  	} +	/* Set the Input and Output Clock Phase Delays */ +	if (clk_data->set_clk_delays) +		clk_data->set_clk_delays(host); +  	sdhci_set_clock(host, clock);  	if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE) @@ -384,6 +424,11 @@ static struct sdhci_arasan_of_data intel_lgm_emmc_data = {  	.pdata = &sdhci_arasan_cqe_pdata,  }; +static struct sdhci_arasan_of_data intel_lgm_sdxc_data = { +	.soc_ctl_map = &intel_lgm_sdxc_soc_ctl_map, +	.pdata = &sdhci_arasan_cqe_pdata, +}; +  #ifdef CONFIG_PM_SLEEP  /**   * sdhci_arasan_suspend - Suspend method for the driver @@ -489,6 +534,10 @@ static const struct of_device_id sdhci_arasan_of_match[] = {  		.compatible = "intel,lgm-sdhci-5.1-emmc",  		.data = &intel_lgm_emmc_data,  	}, +	{ +		.compatible = "intel,lgm-sdhci-5.1-sdxc", +		.data = &intel_lgm_sdxc_data, +	},  	/* Generic compatible below here */  	{  		.compatible = "arasan,sdhci-8.9a", @@ -502,6 +551,10 @@ static const struct of_device_id sdhci_arasan_of_match[] = {  		.compatible = "arasan,sdhci-4.9a",  		.data = &sdhci_arasan_data,  	}, +	{ +		.compatible = "xlnx,zynqmp-8.9a", +		.data = &sdhci_arasan_data, +	},  	{ /* sentinel */ }  };  MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); @@ -520,8 +573,10 @@ static unsigned long sdhci_arasan_sdcardclk_recalc_rate(struct clk_hw *hw,  						      unsigned long parent_rate)  { +	struct sdhci_arasan_clk_data *clk_data = +		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);  	struct sdhci_arasan_data *sdhci_arasan = -		container_of(hw, struct sdhci_arasan_data, sdcardclk_hw); +		container_of(clk_data, struct sdhci_arasan_data, clk_data);  	struct sdhci_host *host = sdhci_arasan->host;  	return host->mmc->actual_clock; @@ -532,6 +587,177 @@ static const struct clk_ops arasan_sdcardclk_ops = {  };  /** + * sdhci_arasan_sampleclk_recalc_rate - Return the sampling clock rate + * + * Return the current actual rate of the sampling clock.  This can be used + * to communicate with out PHY. + * + * @hw:			Pointer to the hardware clock structure. + * @parent_rate		The parent rate (should be rate of clk_xin). + * Returns the sample clock rate. + */ +static unsigned long sdhci_arasan_sampleclk_recalc_rate(struct clk_hw *hw, +						      unsigned long parent_rate) + +{ +	struct sdhci_arasan_clk_data *clk_data = +		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); +	struct sdhci_arasan_data *sdhci_arasan = +		container_of(clk_data, struct sdhci_arasan_data, clk_data); +	struct sdhci_host *host = sdhci_arasan->host; + +	return host->mmc->actual_clock; +} + +static const struct clk_ops arasan_sampleclk_ops = { +	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate, +}; + +/** + * sdhci_zynqmp_sdcardclk_set_phase - Set the SD Output Clock Tap Delays + * + * Set the SD Output Clock Tap Delays for Output path + * + * @hw:			Pointer to the hardware clock structure. + * @degrees		The clock phase shift between 0 - 359. + * Return: 0 on success and error value on error + */ +static int sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees) + +{ +	struct sdhci_arasan_clk_data *clk_data = +		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); +	struct sdhci_arasan_data *sdhci_arasan = +		container_of(clk_data, struct sdhci_arasan_data, clk_data); +	struct sdhci_host *host = sdhci_arasan->host; +	struct sdhci_arasan_zynqmp_clk_data *zynqmp_clk_data = +		clk_data->clk_of_data; +	const struct zynqmp_eemi_ops *eemi_ops = zynqmp_clk_data->eemi_ops; +	const char *clk_name = clk_hw_get_name(hw); +	u32 node_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : NODE_SD_1; +	u8 tap_delay, tap_max = 0; +	int ret; + +	/* +	 * This is applicable for SDHCI_SPEC_300 and above +	 * ZynqMP does not set phase for <=25MHz clock. +	 * If degrees is zero, no need to do anything. +	 */ +	if (host->version < SDHCI_SPEC_300 || +	    host->timing == MMC_TIMING_LEGACY || +	    host->timing == MMC_TIMING_UHS_SDR12 || !degrees) +		return 0; + +	switch (host->timing) { +	case MMC_TIMING_MMC_HS: +	case MMC_TIMING_SD_HS: +	case MMC_TIMING_UHS_SDR25: +	case MMC_TIMING_UHS_DDR50: +	case MMC_TIMING_MMC_DDR52: +		/* For 50MHz clock, 30 Taps are available */ +		tap_max = 30; +		break; +	case MMC_TIMING_UHS_SDR50: +		/* For 100MHz clock, 15 Taps are available */ +		tap_max = 15; +		break; +	case MMC_TIMING_UHS_SDR104: +	case MMC_TIMING_MMC_HS200: +		/* For 200MHz clock, 8 Taps are available */ +		tap_max = 8; +	default: +		break; +	} + +	tap_delay = (degrees * tap_max) / 360; + +	/* Set the Clock Phase */ +	ret = eemi_ops->ioctl(node_id, IOCTL_SET_SD_TAPDELAY, +			      PM_TAPDELAY_OUTPUT, tap_delay, NULL); +	if (ret) +		pr_err("Error setting Output Tap Delay\n"); + +	return ret; +} + +static const struct clk_ops zynqmp_sdcardclk_ops = { +	.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate, +	.set_phase = sdhci_zynqmp_sdcardclk_set_phase, +}; + +/** + * sdhci_zynqmp_sampleclk_set_phase - Set the SD Input Clock Tap Delays + * + * Set the SD Input Clock Tap Delays for Input path + * + * @hw:			Pointer to the hardware clock structure. + * @degrees		The clock phase shift between 0 - 359. + * Return: 0 on success and error value on error + */ +static int sdhci_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees) + +{ +	struct sdhci_arasan_clk_data *clk_data = +		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); +	struct sdhci_arasan_data *sdhci_arasan = +		container_of(clk_data, struct sdhci_arasan_data, clk_data); +	struct sdhci_host *host = sdhci_arasan->host; +	struct sdhci_arasan_zynqmp_clk_data *zynqmp_clk_data = +		clk_data->clk_of_data; +	const struct zynqmp_eemi_ops *eemi_ops = zynqmp_clk_data->eemi_ops; +	const char *clk_name = clk_hw_get_name(hw); +	u32 node_id = !strcmp(clk_name, "clk_in_sd0") ? NODE_SD_0 : NODE_SD_1; +	u8 tap_delay, tap_max = 0; +	int ret; + +	/* +	 * This is applicable for SDHCI_SPEC_300 and above +	 * ZynqMP does not set phase for <=25MHz clock. +	 * If degrees is zero, no need to do anything. +	 */ +	if (host->version < SDHCI_SPEC_300 || +	    host->timing == MMC_TIMING_LEGACY || +	    host->timing == MMC_TIMING_UHS_SDR12 || !degrees) +		return 0; + +	switch (host->timing) { +	case MMC_TIMING_MMC_HS: +	case MMC_TIMING_SD_HS: +	case MMC_TIMING_UHS_SDR25: +	case MMC_TIMING_UHS_DDR50: +	case MMC_TIMING_MMC_DDR52: +		/* For 50MHz clock, 120 Taps are available */ +		tap_max = 120; +		break; +	case MMC_TIMING_UHS_SDR50: +		/* For 100MHz clock, 60 Taps are available */ +		tap_max = 60; +		break; +	case MMC_TIMING_UHS_SDR104: +	case MMC_TIMING_MMC_HS200: +		/* For 200MHz clock, 30 Taps are available */ +		tap_max = 30; +	default: +		break; +	} + +	tap_delay = (degrees * tap_max) / 360; + +	/* Set the Clock Phase */ +	ret = eemi_ops->ioctl(node_id, IOCTL_SET_SD_TAPDELAY, +			      PM_TAPDELAY_INPUT, tap_delay, NULL); +	if (ret) +		pr_err("Error setting Input Tap Delay\n"); + +	return ret; +} + +static const struct clk_ops zynqmp_sampleclk_ops = { +	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate, +	.set_phase = sdhci_zynqmp_sampleclk_set_phase, +}; + +/**   * sdhci_arasan_update_clockmultiplier - Set corecfg_clockmultiplier   *   * The corecfg_clockmultiplier is supposed to contain clock multiplier @@ -609,39 +835,128 @@ static void sdhci_arasan_update_baseclkfreq(struct sdhci_host *host)  	sdhci_arasan_syscon_write(host, &soc_ctl_map->baseclkfreq, mhz);  } +static void sdhci_arasan_set_clk_delays(struct sdhci_host *host) +{ +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); +	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; + +	clk_set_phase(clk_data->sampleclk, +		      clk_data->clk_phase_in[host->timing]); +	clk_set_phase(clk_data->sdcardclk, +		      clk_data->clk_phase_out[host->timing]); +} + +static void arasan_dt_read_clk_phase(struct device *dev, +				     struct sdhci_arasan_clk_data *clk_data, +				     unsigned int timing, const char *prop) +{ +	struct device_node *np = dev->of_node; + +	int clk_phase[2] = {0}; + +	/* +	 * Read Tap Delay values from DT, if the DT does not contain the +	 * Tap Values then use the pre-defined values. +	 */ +	if (of_property_read_variable_u32_array(np, prop, &clk_phase[0], +						2, 0)) { +		dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n", +			prop, clk_data->clk_phase_in[timing], +			clk_data->clk_phase_out[timing]); +		return; +	} + +	/* The values read are Input and Output Clock Delays in order */ +	clk_data->clk_phase_in[timing] = clk_phase[0]; +	clk_data->clk_phase_out[timing] = clk_phase[1]; +} +  /** - * sdhci_arasan_register_sdclk - Register the sdclk for a PHY to use + * arasan_dt_parse_clk_phases - Read Clock Delay values from DT + * + * Called at initialization to parse the values of Clock Delays. + * + * @dev:		Pointer to our struct device. + * @clk_data:		Pointer to the Clock Data structure + */ +static void arasan_dt_parse_clk_phases(struct device *dev, +				       struct sdhci_arasan_clk_data *clk_data) +{ +	int *iclk_phase, *oclk_phase; +	u32 mio_bank = 0; +	int i; + +	/* +	 * This has been kept as a pointer and is assigned a function here. +	 * So that different controller variants can assign their own handling +	 * function. +	 */ +	clk_data->set_clk_delays = sdhci_arasan_set_clk_delays; + +	if (of_device_is_compatible(dev->of_node, "xlnx,zynqmp-8.9a")) { +		iclk_phase = (int [MMC_TIMING_MMC_HS400 + 1]) ZYNQMP_ICLK_PHASE; +		oclk_phase = (int [MMC_TIMING_MMC_HS400 + 1]) ZYNQMP_OCLK_PHASE; + +		of_property_read_u32(dev->of_node, "xlnx,mio-bank", &mio_bank); +		if (mio_bank == 2) { +			oclk_phase[MMC_TIMING_UHS_SDR104] = 90; +			oclk_phase[MMC_TIMING_MMC_HS200] = 90; +		} + +		for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { +			clk_data->clk_phase_in[i] = iclk_phase[i]; +			clk_data->clk_phase_out[i] = oclk_phase[i]; +		} +	} + +	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY, +				 "clk-phase-legacy"); +	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS, +				 "clk-phase-mmc-hs"); +	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_SD_HS, +				 "clk-phase-sd-hs"); +	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR12, +				 "clk-phase-uhs-sdr12"); +	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR25, +				 "clk-phase-uhs-sdr25"); +	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR50, +				 "clk-phase-uhs-sdr50"); +	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR104, +				 "clk-phase-uhs-sdr104"); +	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_DDR50, +				 "clk-phase-uhs-ddr50"); +	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_DDR52, +				 "clk-phase-mmc-ddr52"); +	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS200, +				 "clk-phase-mmc-hs200"); +	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS400, +				 "clk-phase-mmc-hs400"); +} + +/** + * sdhci_arasan_register_sdcardclk - Register the sdcardclk for a PHY to use   *   * Some PHY devices need to know what the actual card clock is.  In order for   * them to find out, we'll provide a clock through the common clock framework   * for them to query.   * - * Note: without seriously re-architecting SDHCI's clock code and testing on - * all platforms, there's no way to create a totally beautiful clock here - * with all clock ops implemented.  Instead, we'll just create a clock that can - * be queried and set the CLK_GET_RATE_NOCACHE attribute to tell common clock - * framework that we're doing things behind its back.  This should be sufficient - * to create nice clean device tree bindings and later (if needed) we can try - * re-architecting SDHCI if we see some benefit to it. - *   * @sdhci_arasan:	Our private data structure.   * @clk_xin:		Pointer to the functional clock   * @dev:		Pointer to our struct device.   * Returns 0 on success and error value on error   */ -static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan, -				       struct clk *clk_xin, -				       struct device *dev) +static int +sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan, +				struct clk *clk_xin, +				struct device *dev)  { +	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;  	struct device_node *np = dev->of_node;  	struct clk_init_data sdcardclk_init;  	const char *parent_clk_name;  	int ret; -	/* Providing a clock to the PHY is optional; no error if missing */ -	if (!of_find_property(np, "#clock-cells", NULL)) -		return 0; -  	ret = of_property_read_string_index(np, "clock-output-names", 0,  					    &sdcardclk_init.name);  	if (ret) { @@ -653,17 +968,72 @@ static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan,  	sdcardclk_init.parent_names = &parent_clk_name;  	sdcardclk_init.num_parents = 1;  	sdcardclk_init.flags = CLK_GET_RATE_NOCACHE; -	sdcardclk_init.ops = &arasan_sdcardclk_ops; +	if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) +		sdcardclk_init.ops = &zynqmp_sdcardclk_ops; +	else +		sdcardclk_init.ops = &arasan_sdcardclk_ops; + +	clk_data->sdcardclk_hw.init = &sdcardclk_init; +	clk_data->sdcardclk = +		devm_clk_register(dev, &clk_data->sdcardclk_hw); +	clk_data->sdcardclk_hw.init = NULL; + +	ret = of_clk_add_provider(np, of_clk_src_simple_get, +				  clk_data->sdcardclk); +	if (ret) +		dev_err(dev, "Failed to add sdcard clock provider\n"); + +	return ret; +} + +/** + * sdhci_arasan_register_sampleclk - Register the sampleclk for a PHY to use + * + * Some PHY devices need to know what the actual card clock is.  In order for + * them to find out, we'll provide a clock through the common clock framework + * for them to query. + * + * @sdhci_arasan:	Our private data structure. + * @clk_xin:		Pointer to the functional clock + * @dev:		Pointer to our struct device. + * Returns 0 on success and error value on error + */ +static int +sdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan, +				struct clk *clk_xin, +				struct device *dev) +{ +	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; +	struct device_node *np = dev->of_node; +	struct clk_init_data sampleclk_init; +	const char *parent_clk_name; +	int ret; -	sdhci_arasan->sdcardclk_hw.init = &sdcardclk_init; -	sdhci_arasan->sdcardclk = -		devm_clk_register(dev, &sdhci_arasan->sdcardclk_hw); -	sdhci_arasan->sdcardclk_hw.init = NULL; +	ret = of_property_read_string_index(np, "clock-output-names", 1, +					    &sampleclk_init.name); +	if (ret) { +		dev_err(dev, "DT has #clock-cells but no clock-output-names\n"); +		return ret; +	} + +	parent_clk_name = __clk_get_name(clk_xin); +	sampleclk_init.parent_names = &parent_clk_name; +	sampleclk_init.num_parents = 1; +	sampleclk_init.flags = CLK_GET_RATE_NOCACHE; +	if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) +		sampleclk_init.ops = &zynqmp_sampleclk_ops; +	else +		sampleclk_init.ops = &arasan_sampleclk_ops; + +	clk_data->sampleclk_hw.init = &sampleclk_init; +	clk_data->sampleclk = +		devm_clk_register(dev, &clk_data->sampleclk_hw); +	clk_data->sampleclk_hw.init = NULL;  	ret = of_clk_add_provider(np, of_clk_src_simple_get, -				  sdhci_arasan->sdcardclk); +				  clk_data->sampleclk);  	if (ret) -		dev_err(dev, "Failed to add clock provider\n"); +		dev_err(dev, "Failed to add sample clock provider\n");  	return ret;  } @@ -686,6 +1056,54 @@ static void sdhci_arasan_unregister_sdclk(struct device *dev)  	of_clk_del_provider(dev->of_node);  } +/** + * sdhci_arasan_register_sdclk - Register the sdcardclk for a PHY to use + * + * Some PHY devices need to know what the actual card clock is.  In order for + * them to find out, we'll provide a clock through the common clock framework + * for them to query. + * + * Note: without seriously re-architecting SDHCI's clock code and testing on + * all platforms, there's no way to create a totally beautiful clock here + * with all clock ops implemented.  Instead, we'll just create a clock that can + * be queried and set the CLK_GET_RATE_NOCACHE attribute to tell common clock + * framework that we're doing things behind its back.  This should be sufficient + * to create nice clean device tree bindings and later (if needed) we can try + * re-architecting SDHCI if we see some benefit to it. + * + * @sdhci_arasan:	Our private data structure. + * @clk_xin:		Pointer to the functional clock + * @dev:		Pointer to our struct device. + * Returns 0 on success and error value on error + */ +static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan, +				       struct clk *clk_xin, +				       struct device *dev) +{ +	struct device_node *np = dev->of_node; +	u32 num_clks = 0; +	int ret; + +	/* Providing a clock to the PHY is optional; no error if missing */ +	if (of_property_read_u32(np, "#clock-cells", &num_clks) < 0) +		return 0; + +	ret = sdhci_arasan_register_sdcardclk(sdhci_arasan, clk_xin, dev); +	if (ret) +		return ret; + +	if (num_clks) { +		ret = sdhci_arasan_register_sampleclk(sdhci_arasan, clk_xin, +						      dev); +		if (ret) { +			sdhci_arasan_unregister_sdclk(dev); +			return ret; +		} +	} + +	return 0; +} +  static int sdhci_arasan_add_host(struct sdhci_arasan_data *sdhci_arasan)  {  	struct sdhci_host *host = sdhci_arasan->host; @@ -814,6 +1232,25 @@ static int sdhci_arasan_probe(struct platform_device *pdev)  	if (ret)  		goto clk_disable_all; +	if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) { +		struct sdhci_arasan_zynqmp_clk_data *zynqmp_clk_data; +		const struct zynqmp_eemi_ops *eemi_ops; + +		zynqmp_clk_data = devm_kzalloc(&pdev->dev, +					       sizeof(*zynqmp_clk_data), +					       GFP_KERNEL); +		eemi_ops = zynqmp_pm_get_eemi_ops(); +		if (IS_ERR(eemi_ops)) { +			ret = PTR_ERR(eemi_ops); +			goto unreg_clk; +		} + +		zynqmp_clk_data->eemi_ops = eemi_ops; +		sdhci_arasan->clk_data.clk_of_data = zynqmp_clk_data; +	} + +	arasan_dt_parse_clk_phases(&pdev->dev, &sdhci_arasan->clk_data); +  	ret = mmc_of_parse(host->mmc);  	if (ret) {  		if (ret != -EPROBE_DEFER) diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c index 8962f6664381..56912e30c47e 100644 --- a/drivers/mmc/host/sdhci-of-aspeed.c +++ b/drivers/mmc/host/sdhci-of-aspeed.c @@ -111,7 +111,19 @@ static void aspeed_sdhci_set_bus_width(struct sdhci_host *host, int width)  	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);  } +static u32 aspeed_sdhci_readl(struct sdhci_host *host, int reg) +{ +	u32 val = readl(host->ioaddr + reg); + +	if (unlikely(reg == SDHCI_PRESENT_STATE) && +	    (host->mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH)) +		val ^= SDHCI_CARD_PRESENT; + +	return val; +} +  static const struct sdhci_ops aspeed_sdhci_ops = { +	.read_l = aspeed_sdhci_readl,  	.set_clock = aspeed_sdhci_set_clock,  	.get_max_clock = aspeed_sdhci_get_max_clock,  	.set_bus_width = aspeed_sdhci_set_bus_width, diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 0ae986c42bc8..5959e394b416 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -27,6 +27,9 @@  #define SDMMC_CACR	0x230  #define		SDMMC_CACR_CAPWREN	BIT(0)  #define		SDMMC_CACR_KEY		(0x46 << 8) +#define SDMMC_CALCR	0x240 +#define		SDMMC_CALCR_EN		BIT(0) +#define		SDMMC_CALCR_ALWYSON	BIT(4)  #define SDHCI_AT91_PRESET_COMMON_CONF	0x400 /* drv type B, programmable clock mode */ @@ -35,6 +38,7 @@ struct sdhci_at91_priv {  	struct clk *gck;  	struct clk *mainck;  	bool restore_needed; +	bool cal_always_on;  };  static void sdhci_at91_set_force_card_detect(struct sdhci_host *host) @@ -116,10 +120,17 @@ static void sdhci_at91_set_uhs_signaling(struct sdhci_host *host,  static void sdhci_at91_reset(struct sdhci_host *host, u8 mask)  { +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host); +  	sdhci_reset(host, mask);  	if (host->mmc->caps & MMC_CAP_NONREMOVABLE)  		sdhci_at91_set_force_card_detect(host); + +	if (priv->cal_always_on && (mask & SDHCI_RESET_ALL)) +		sdhci_writel(host, SDMMC_CALCR_ALWYSON | SDMMC_CALCR_EN, +			     SDMMC_CALCR);  }  static const struct sdhci_ops sdhci_at91_sama5d2_ops = { @@ -345,6 +356,14 @@ static int sdhci_at91_probe(struct platform_device *pdev)  	priv->restore_needed = false; +	/* +	 * if SDCAL pin is wrongly connected, we must enable +	 * the analog calibration cell permanently. +	 */ +	priv->cal_always_on = +		device_property_read_bool(&pdev->dev, +					  "microchip,sdcal-inverted"); +  	ret = mmc_of_parse(host->mmc);  	if (ret)  		goto clocks_disable_unprepare; diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 1d1953dfc54b..500f70a6ee42 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -77,8 +77,11 @@ struct sdhci_esdhc {  	bool quirk_incorrect_hostver;  	bool quirk_limited_clk_division;  	bool quirk_unreliable_pulse_detection; -	bool quirk_fixup_tuning; +	bool quirk_tuning_erratum_type1; +	bool quirk_tuning_erratum_type2;  	bool quirk_ignore_data_inhibit; +	bool quirk_delay_before_data_reset; +	bool in_sw_tuning;  	unsigned int peripheral_clock;  	const struct esdhc_clk_fixup *clk_fixup;  	u32 div_ratio; @@ -408,6 +411,8 @@ static void esdhc_le_writel(struct sdhci_host *host, u32 val, int reg)  static void esdhc_be_writew(struct sdhci_host *host, u16 val, int reg)  { +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);  	int base = reg & ~0x3;  	u32 value;  	u32 ret; @@ -416,10 +421,24 @@ static void esdhc_be_writew(struct sdhci_host *host, u16 val, int reg)  	ret = esdhc_writew_fixup(host, reg, val, value);  	if (reg != SDHCI_TRANSFER_MODE)  		iowrite32be(ret, host->ioaddr + base); + +	/* Starting SW tuning requires ESDHC_SMPCLKSEL to be set +	 * 1us later after ESDHC_EXTN is set. +	 */ +	if (base == ESDHC_SYSTEM_CONTROL_2) { +		if (!(value & ESDHC_EXTN) && (ret & ESDHC_EXTN) && +		    esdhc->in_sw_tuning) { +			udelay(1); +			ret |= ESDHC_SMPCLKSEL; +			iowrite32be(ret, host->ioaddr + base); +		} +	}  }  static void esdhc_le_writew(struct sdhci_host *host, u16 val, int reg)  { +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);  	int base = reg & ~0x3;  	u32 value;  	u32 ret; @@ -428,6 +447,18 @@ static void esdhc_le_writew(struct sdhci_host *host, u16 val, int reg)  	ret = esdhc_writew_fixup(host, reg, val, value);  	if (reg != SDHCI_TRANSFER_MODE)  		iowrite32(ret, host->ioaddr + base); + +	/* Starting SW tuning requires ESDHC_SMPCLKSEL to be set +	 * 1us later after ESDHC_EXTN is set. +	 */ +	if (base == ESDHC_SYSTEM_CONTROL_2) { +		if (!(value & ESDHC_EXTN) && (ret & ESDHC_EXTN) && +		    esdhc->in_sw_tuning) { +			udelay(1); +			ret |= ESDHC_SMPCLKSEL; +			iowrite32(ret, host->ioaddr + base); +		} +	}  }  static void esdhc_be_writeb(struct sdhci_host *host, u8 val, int reg) @@ -560,6 +591,32 @@ static void esdhc_clock_enable(struct sdhci_host *host, bool enable)  	}  } +static void esdhc_flush_async_fifo(struct sdhci_host *host) +{ +	ktime_t timeout; +	u32 val; + +	val = sdhci_readl(host, ESDHC_DMA_SYSCTL); +	val |= ESDHC_FLUSH_ASYNC_FIFO; +	sdhci_writel(host, val, ESDHC_DMA_SYSCTL); + +	/* Wait max 20 ms */ +	timeout = ktime_add_ms(ktime_get(), 20); +	while (1) { +		bool timedout = ktime_after(ktime_get(), timeout); + +		if (!(sdhci_readl(host, ESDHC_DMA_SYSCTL) & +		      ESDHC_FLUSH_ASYNC_FIFO)) +			break; +		if (timedout) { +			pr_err("%s: flushing asynchronous FIFO timeout.\n", +				mmc_hostname(host->mmc)); +			break; +		} +		usleep_range(10, 20); +	} +} +  static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)  {  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -652,9 +709,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)  		sdhci_writel(host, temp | ESDHC_HS400_WNDW_ADJUST, ESDHC_TBCTL);  		esdhc_clock_enable(host, false); -		temp = sdhci_readl(host, ESDHC_DMA_SYSCTL); -		temp |= ESDHC_FLUSH_ASYNC_FIFO; -		sdhci_writel(host, temp, ESDHC_DMA_SYSCTL); +		esdhc_flush_async_fifo(host);  	}  	/* Wait max 20 ms */ @@ -705,14 +760,16 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)  	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);  	u32 val; +	if (esdhc->quirk_delay_before_data_reset && +	    (mask & SDHCI_RESET_DATA) && +	    (host->flags & SDHCI_REQ_USE_DMA)) +		mdelay(5); +  	sdhci_reset(host, 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; @@ -796,16 +853,21 @@ static int esdhc_signal_voltage_switch(struct mmc_host *mmc,  	}  } -static struct soc_device_attribute soc_fixup_tuning[] = { +static struct soc_device_attribute soc_tuning_erratum_type1[] = { +	{ .family = "QorIQ T1023", .revision = "1.0", },  	{ .family = "QorIQ T1040", .revision = "1.0", },  	{ .family = "QorIQ T2080", .revision = "1.0", }, -	{ .family = "QorIQ T1023", .revision = "1.0", },  	{ .family = "QorIQ LS1021A", .revision = "1.0", }, -	{ .family = "QorIQ LS1080A", .revision = "1.0", }, -	{ .family = "QorIQ LS2080A", .revision = "1.0", }, +	{ }, +}; + +static struct soc_device_attribute soc_tuning_erratum_type2[] = {  	{ .family = "QorIQ LS1012A", .revision = "1.0", },  	{ .family = "QorIQ LS1043A", .revision = "1.*", },  	{ .family = "QorIQ LS1046A", .revision = "1.0", }, +	{ .family = "QorIQ LS1080A", .revision = "1.0", }, +	{ .family = "QorIQ LS2080A", .revision = "1.0", }, +	{ .family = "QorIQ LA1575A", .revision = "1.0", },  	{ },  }; @@ -814,10 +876,7 @@ static void esdhc_tuning_block_enable(struct sdhci_host *host, bool enable)  	u32 val;  	esdhc_clock_enable(host, false); - -	val = sdhci_readl(host, ESDHC_DMA_SYSCTL); -	val |= ESDHC_FLUSH_ASYNC_FIFO; -	sdhci_writel(host, val, ESDHC_DMA_SYSCTL); +	esdhc_flush_async_fifo(host);  	val = sdhci_readl(host, ESDHC_TBCTL);  	if (enable) @@ -829,15 +888,97 @@ static void esdhc_tuning_block_enable(struct sdhci_host *host, bool enable)  	esdhc_clock_enable(host, true);  } +static void esdhc_prepare_sw_tuning(struct sdhci_host *host, u8 *window_start, +				    u8 *window_end) +{ +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); +	u8 tbstat_15_8, tbstat_7_0; +	u32 val; + +	if (esdhc->quirk_tuning_erratum_type1) { +		*window_start = 5 * esdhc->div_ratio; +		*window_end = 3 * esdhc->div_ratio; +		return; +	} + +	/* Write TBCTL[11:8]=4'h8 */ +	val = sdhci_readl(host, ESDHC_TBCTL); +	val &= ~(0xf << 8); +	val |= 8 << 8; +	sdhci_writel(host, val, ESDHC_TBCTL); + +	mdelay(1); + +	/* Read TBCTL[31:0] register and rewrite again */ +	val = sdhci_readl(host, ESDHC_TBCTL); +	sdhci_writel(host, val, ESDHC_TBCTL); + +	mdelay(1); + +	/* Read the TBSTAT[31:0] register twice */ +	val = sdhci_readl(host, ESDHC_TBSTAT); +	val = sdhci_readl(host, ESDHC_TBSTAT); + +	/* Reset data lines by setting ESDHCCTL[RSTD] */ +	sdhci_reset(host, SDHCI_RESET_DATA); +	/* Write 32'hFFFF_FFFF to IRQSTAT register */ +	sdhci_writel(host, 0xFFFFFFFF, SDHCI_INT_STATUS); + +	/* If TBSTAT[15:8]-TBSTAT[7:0] > 4 * div_ratio +	 * or TBSTAT[7:0]-TBSTAT[15:8] > 4 * div_ratio, +	 * then program TBPTR[TB_WNDW_END_PTR] = 4 * div_ratio +	 * and program TBPTR[TB_WNDW_START_PTR] = 8 * div_ratio. +	 */ +	tbstat_7_0 = val & 0xff; +	tbstat_15_8 = (val >> 8) & 0xff; + +	if (abs(tbstat_15_8 - tbstat_7_0) > (4 * esdhc->div_ratio)) { +		*window_start = 8 * esdhc->div_ratio; +		*window_end = 4 * esdhc->div_ratio; +	} else { +		*window_start = 5 * esdhc->div_ratio; +		*window_end = 3 * esdhc->div_ratio; +	} +} + +static int esdhc_execute_sw_tuning(struct mmc_host *mmc, u32 opcode, +				   u8 window_start, u8 window_end) +{ +	struct sdhci_host *host = mmc_priv(mmc); +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); +	u32 val; +	int ret; + +	/* Program TBPTR[TB_WNDW_END_PTR] and TBPTR[TB_WNDW_START_PTR] */ +	val = ((u32)window_start << ESDHC_WNDW_STRT_PTR_SHIFT) & +	      ESDHC_WNDW_STRT_PTR_MASK; +	val |= window_end & ESDHC_WNDW_END_PTR_MASK; +	sdhci_writel(host, val, ESDHC_TBPTR); + +	/* Program the software tuning mode by setting TBCTL[TB_MODE]=2'h3 */ +	val = sdhci_readl(host, ESDHC_TBCTL); +	val &= ~ESDHC_TB_MODE_MASK; +	val |= ESDHC_TB_MODE_SW; +	sdhci_writel(host, val, ESDHC_TBCTL); + +	esdhc->in_sw_tuning = true; +	ret = sdhci_execute_tuning(mmc, opcode); +	esdhc->in_sw_tuning = false; +	return ret; +} +  static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)  {  	struct sdhci_host *host = mmc_priv(mmc);  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);  	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); +	u8 window_start, window_end; +	int ret, retries = 1;  	bool hs400_tuning;  	unsigned int clk;  	u32 val; -	int ret;  	/* For tuning mode, the sd clock divisor value  	 * must be larger than 3 according to reference manual. @@ -846,39 +987,73 @@ static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)  	if (host->clock > clk)  		esdhc_of_set_clock(host, clk); -	if (esdhc->quirk_limited_clk_division && -	    host->flags & SDHCI_HS400_TUNING) -		esdhc_of_set_clock(host, host->clock); -  	esdhc_tuning_block_enable(host, true);  	hs400_tuning = host->flags & SDHCI_HS400_TUNING; -	ret = sdhci_execute_tuning(mmc, opcode); -	if (hs400_tuning) { -		val = sdhci_readl(host, ESDHC_SDTIMNGCTL); -		val |= ESDHC_FLW_CTL_BG; -		sdhci_writel(host, val, ESDHC_SDTIMNGCTL); -	} +	do { +		if (esdhc->quirk_limited_clk_division && +		    hs400_tuning) +			esdhc_of_set_clock(host, host->clock); -	if (host->tuning_err == -EAGAIN && esdhc->quirk_fixup_tuning) { +		/* Do HW tuning */ +		val = sdhci_readl(host, ESDHC_TBCTL); +		val &= ~ESDHC_TB_MODE_MASK; +		val |= ESDHC_TB_MODE_3; +		sdhci_writel(host, val, ESDHC_TBCTL); -		/* program TBPTR[TB_WNDW_END_PTR] = 3*DIV_RATIO and -		 * program TBPTR[TB_WNDW_START_PTR] = 5*DIV_RATIO -		 */ -		val = sdhci_readl(host, ESDHC_TBPTR); -		val = (val & ~((0x7f << 8) | 0x7f)) | -		(3 * esdhc->div_ratio) | ((5 * esdhc->div_ratio) << 8); -		sdhci_writel(host, val, ESDHC_TBPTR); +		ret = sdhci_execute_tuning(mmc, opcode); +		if (ret) +			break; -		/* program the software tuning mode by setting -		 * TBCTL[TB_MODE]=2'h3 +		/* If HW tuning fails and triggers erratum, +		 * try workaround.  		 */ -		val = sdhci_readl(host, ESDHC_TBCTL); -		val |= 0x3; -		sdhci_writel(host, val, ESDHC_TBCTL); -		sdhci_execute_tuning(mmc, opcode); +		ret = host->tuning_err; +		if (ret == -EAGAIN && +		    (esdhc->quirk_tuning_erratum_type1 || +		     esdhc->quirk_tuning_erratum_type2)) { +			/* Recover HS400 tuning flag */ +			if (hs400_tuning) +				host->flags |= SDHCI_HS400_TUNING; +			pr_info("%s: Hold on to use fixed sampling clock. Try SW tuning!\n", +				mmc_hostname(mmc)); +			/* Do SW tuning */ +			esdhc_prepare_sw_tuning(host, &window_start, +						&window_end); +			ret = esdhc_execute_sw_tuning(mmc, opcode, +						      window_start, +						      window_end); +			if (ret) +				break; + +			/* Retry both HW/SW tuning with reduced clock. */ +			ret = host->tuning_err; +			if (ret == -EAGAIN && retries) { +				/* Recover HS400 tuning flag */ +				if (hs400_tuning) +					host->flags |= SDHCI_HS400_TUNING; + +				clk = host->max_clk / (esdhc->div_ratio + 1); +				esdhc_of_set_clock(host, clk); +				pr_info("%s: Hold on to use fixed sampling clock. Try tuning with reduced clock!\n", +					mmc_hostname(mmc)); +			} else { +				break; +			} +		} else { +			break; +		} +	} while (retries--); + +	if (ret) { +		esdhc_tuning_block_enable(host, false); +	} else if (hs400_tuning) { +		val = sdhci_readl(host, ESDHC_SDTIMNGCTL); +		val |= ESDHC_FLW_CTL_BG; +		sdhci_writel(host, val, ESDHC_SDTIMNGCTL);  	} +  	return ret;  } @@ -1049,6 +1224,10 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)  	if (match)  		esdhc->clk_fixup = match->data;  	np = pdev->dev.of_node; + +	if (of_device_is_compatible(np, "fsl,p2020-esdhc")) +		esdhc->quirk_delay_before_data_reset = true; +  	clk = of_clk_get(np, 0);  	if (!IS_ERR(clk)) {  		/* @@ -1114,10 +1293,15 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)  	pltfm_host = sdhci_priv(host);  	esdhc = sdhci_pltfm_priv(pltfm_host); -	if (soc_device_match(soc_fixup_tuning)) -		esdhc->quirk_fixup_tuning = true; +	if (soc_device_match(soc_tuning_erratum_type1)) +		esdhc->quirk_tuning_erratum_type1 = true;  	else -		esdhc->quirk_fixup_tuning = false; +		esdhc->quirk_tuning_erratum_type1 = false; + +	if (soc_device_match(soc_tuning_erratum_type2)) +		esdhc->quirk_tuning_erratum_type2 = true; +	else +		esdhc->quirk_tuning_erratum_type2 = false;  	if (esdhc->vendor_ver == VENDOR_V_22)  		host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23; @@ -1126,8 +1310,8 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)  		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; +		host->quirks |= SDHCI_QUIRK_RESET_AFTER_REQUEST; +		host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;  	}  	if (of_device_is_compatible(np, "fsl,p5040-esdhc") || diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index eaffa85bc728..5091e2c1c0e5 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -21,11 +21,13 @@  #include <linux/mmc/mmc.h>  #include <linux/scatterlist.h>  #include <linux/io.h> +#include <linux/iopoll.h>  #include <linux/gpio.h>  #include <linux/pm_runtime.h>  #include <linux/mmc/slot-gpio.h>  #include <linux/mmc/sdhci-pci-data.h>  #include <linux/acpi.h> +#include <linux/dmi.h>  #ifdef CONFIG_X86  #include <asm/iosf_mbi.h> @@ -782,11 +784,18 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)  	return 0;  } +static bool glk_broken_cqhci(struct sdhci_pci_slot *slot) +{ +	return slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC && +	       dmi_match(DMI_BIOS_VENDOR, "LENOVO"); +} +  static int glk_emmc_probe_slot(struct sdhci_pci_slot *slot)  {  	int ret = byt_emmc_probe_slot(slot); -	slot->host->mmc->caps2 |= MMC_CAP2_CQE; +	if (!glk_broken_cqhci(slot)) +		slot->host->mmc->caps2 |= MMC_CAP2_CQE;  	if (slot->chip->pdev->device != PCI_DEVICE_ID_INTEL_GLK_EMMC) {  		slot->host->mmc->caps2 |= MMC_CAP2_HS400_ES, @@ -1590,11 +1599,59 @@ static int amd_probe(struct sdhci_pci_chip *chip)  	return 0;  } +static u32 sdhci_read_present_state(struct sdhci_host *host) +{ +	return sdhci_readl(host, SDHCI_PRESENT_STATE); +} + +static void amd_sdhci_reset(struct sdhci_host *host, u8 mask) +{ +	struct sdhci_pci_slot *slot = sdhci_priv(host); +	struct pci_dev *pdev = slot->chip->pdev; +	u32 present_state; + +	/* +	 * SDHC 0x7906 requires a hard reset to clear all internal state. +	 * Otherwise it can get into a bad state where the DATA lines are always +	 * read as zeros. +	 */ +	if (pdev->device == 0x7906 && (mask & SDHCI_RESET_ALL)) { +		pci_clear_master(pdev); + +		pci_save_state(pdev); + +		pci_set_power_state(pdev, PCI_D3cold); +		pr_debug("%s: power_state=%u\n", mmc_hostname(host->mmc), +			pdev->current_state); +		pci_set_power_state(pdev, PCI_D0); + +		pci_restore_state(pdev); + +		/* +		 * SDHCI_RESET_ALL says the card detect logic should not be +		 * reset, but since we need to reset the entire controller +		 * we should wait until the card detect logic has stabilized. +		 * +		 * This normally takes about 40ms. +		 */ +		readx_poll_timeout( +			sdhci_read_present_state, +			host, +			present_state, +			present_state & SDHCI_CD_STABLE, +			10000, +			100000 +		); +	} + +	return sdhci_reset(host, mask); +} +  static const struct sdhci_ops amd_sdhci_pci_ops = {  	.set_clock			= sdhci_set_clock,  	.enable_dma			= sdhci_pci_enable_dma,  	.set_bus_width			= sdhci_set_bus_width, -	.reset				= sdhci_reset, +	.reset				= amd_sdhci_reset,  	.set_uhs_signaling		= sdhci_set_uhs_signaling,  }; @@ -1673,6 +1730,8 @@ static const struct pci_device_id pci_ids[] = {  	SDHCI_PCI_DEVICE(INTEL, CML_EMMC,  intel_glk_emmc),  	SDHCI_PCI_DEVICE(INTEL, CML_SD,    intel_byt_sd),  	SDHCI_PCI_DEVICE(INTEL, CMLH_SD,   intel_byt_sd), +	SDHCI_PCI_DEVICE(INTEL, JSL_EMMC,  intel_glk_emmc), +	SDHCI_PCI_DEVICE(INTEL, JSL_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.h b/drivers/mmc/host/sdhci-pci.h index 558202fe64c6..981bbbe63aff 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -55,6 +55,8 @@  #define PCI_DEVICE_ID_INTEL_CML_EMMC	0x02c4  #define PCI_DEVICE_ID_INTEL_CML_SD	0x02f5  #define PCI_DEVICE_ID_INTEL_CMLH_SD	0x06f5 +#define PCI_DEVICE_ID_INTEL_JSL_EMMC	0x4dc4 +#define PCI_DEVICE_ID_INTEL_JSL_SD	0x4df8  #define PCI_DEVICE_ID_SYSKONNECT_8000	0x8000  #define PCI_DEVICE_ID_VIA_95D0		0x95d0 diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index b056400e34b1..1b1c26da3fe0 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -337,8 +337,19 @@ static void sdhci_init(struct sdhci_host *host, int soft)  static void sdhci_reinit(struct sdhci_host *host)  { +	u32 cd = host->ier & (SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); +  	sdhci_init(host, 0);  	sdhci_enable_card_detection(host); + +	/* +	 * A change to the card detect bits indicates a change in present state, +	 * refer sdhci_set_card_detection(). A card detect interrupt might have +	 * been missed while the host controller was being reset, so trigger a +	 * rescan to check. +	 */ +	if (cd != (host->ier & (SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT))) +		mmc_detect_change(host->mmc, msecs_to_jiffies(200));  }  static void __sdhci_led_activate(struct sdhci_host *host) @@ -1871,9 +1882,7 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)  		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;  	else if (timing == MMC_TIMING_UHS_SDR12)  		ctrl_2 |= SDHCI_CTRL_UHS_SDR12; -	else if (timing == MMC_TIMING_SD_HS || -		 timing == MMC_TIMING_MMC_HS || -		 timing == MMC_TIMING_UHS_SDR25) +	else if (timing == MMC_TIMING_UHS_SDR25)  		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;  	else if (timing == MMC_TIMING_UHS_SDR50)  		ctrl_2 |= SDHCI_CTRL_UHS_SDR50; @@ -2202,7 +2211,7 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,  		if (!(ctrl & SDHCI_CTRL_VDD_180))  			return 0; -		pr_warn("%s: 3.3V regulator output did not became stable\n", +		pr_warn("%s: 3.3V regulator output did not become stable\n",  			mmc_hostname(mmc));  		return -EAGAIN; @@ -2234,7 +2243,7 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,  		if (ctrl & SDHCI_CTRL_VDD_180)  			return 0; -		pr_warn("%s: 1.8V regulator output did not became stable\n", +		pr_warn("%s: 1.8V regulator output did not become stable\n",  			mmc_hostname(mmc));  		return -EAGAIN; @@ -2408,8 +2417,8 @@ static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)  		sdhci_send_tuning(host, opcode);  		if (!host->tuning_done) { -			pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n", -				mmc_hostname(host->mmc)); +			pr_debug("%s: Tuning timeout, falling back to fixed sampling clock\n", +				 mmc_hostname(host->mmc));  			sdhci_abort_tuning(host, opcode);  			return -ETIMEDOUT;  		} @@ -3758,6 +3767,9 @@ int sdhci_setup_host(struct sdhci_host *host)  		       mmc_hostname(mmc), host->version);  	} +	if (host->quirks & SDHCI_QUIRK_BROKEN_CQE) +		mmc->caps2 &= ~MMC_CAP2_CQE; +  	if (host->quirks & SDHCI_QUIRK_FORCE_DMA)  		host->flags |= SDHCI_USE_SDMA;  	else if (!(host->caps & SDHCI_CAN_DO_SDMA)) diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 0ed3e0eaef5f..fe83ece6965b 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -409,6 +409,8 @@ struct sdhci_host {  #define SDHCI_QUIRK_BROKEN_CARD_DETECTION		(1<<15)  /* Controller reports inverted write-protect state */  #define SDHCI_QUIRK_INVERTED_WRITE_PROTECT		(1<<16) +/* Controller has unusable command queue engine */ +#define SDHCI_QUIRK_BROKEN_CQE				(1<<17)  /* Controller does not like fast PIO transfers */  #define SDHCI_QUIRK_PIO_NEEDS_DELAY			(1<<18)  /* Controller does not have a LED */ diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index bb90757ecace..b8e897e31e2e 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -12,6 +12,7 @@  #include <linux/property.h>  #include <linux/regmap.h> +#include "cqhci.h"  #include "sdhci-pltfm.h"  /* CTL_CFG Registers */ @@ -68,6 +69,9 @@  #define CLOCK_TOO_SLOW_HZ	400000 +/* Command Queue Host Controller Interface Base address */ +#define SDHCI_AM654_CQE_BASE_ADDR 0x200 +  static struct regmap_config sdhci_am654_regmap_config = {  	.reg_bits = 32,  	.val_bits = 32, @@ -259,6 +263,19 @@ static const struct sdhci_am654_driver_data sdhci_am654_drvdata = {  	.flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT,  }; +static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask) +{ +	int cmd_error = 0; +	int data_error = 0; + +	if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) +		return intmask; + +	cqhci_irq(host->mmc, intmask, cmd_error, data_error); + +	return 0; +} +  static struct sdhci_ops sdhci_j721e_8bit_ops = {  	.get_max_clock = sdhci_pltfm_clk_get_max_clock,  	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock, @@ -267,6 +284,7 @@ static struct sdhci_ops sdhci_j721e_8bit_ops = {  	.set_power = sdhci_am654_set_power,  	.set_clock = sdhci_am654_set_clock,  	.write_b = sdhci_am654_write_b, +	.irq = sdhci_am654_cqhci_irq,  	.reset = sdhci_reset,  }; @@ -290,6 +308,7 @@ static struct sdhci_ops sdhci_j721e_4bit_ops = {  	.set_power = sdhci_am654_set_power,  	.set_clock = sdhci_j721e_4bit_set_clock,  	.write_b = sdhci_am654_write_b, +	.irq = sdhci_am654_cqhci_irq,  	.reset = sdhci_reset,  }; @@ -304,6 +323,40 @@ static const struct sdhci_am654_driver_data sdhci_j721e_4bit_drvdata = {  	.pdata = &sdhci_j721e_4bit_pdata,  	.flags = IOMUX_PRESENT,  }; + +static void sdhci_am654_dumpregs(struct mmc_host *mmc) +{ +	sdhci_dumpregs(mmc_priv(mmc)); +} + +static const struct cqhci_host_ops sdhci_am654_cqhci_ops = { +	.enable		= sdhci_cqe_enable, +	.disable	= sdhci_cqe_disable, +	.dumpregs	= sdhci_am654_dumpregs, +}; + +static int sdhci_am654_cqe_add_host(struct sdhci_host *host) +{ +	struct cqhci_host *cq_host; +	int ret; + +	cq_host = devm_kzalloc(host->mmc->parent, sizeof(struct cqhci_host), +			       GFP_KERNEL); +	if (!cq_host) +		return -ENOMEM; + +	cq_host->mmio = host->ioaddr + SDHCI_AM654_CQE_BASE_ADDR; +	cq_host->quirks |= CQHCI_QUIRK_SHORT_TXFR_DESC_SZ; +	cq_host->caps |= CQHCI_TASK_DESC_SZ_128; +	cq_host->ops = &sdhci_am654_cqhci_ops; + +	host->mmc->caps2 |= MMC_CAP2_CQE; + +	ret = cqhci_init(cq_host, host->mmc, 1); + +	return ret; +} +  static int sdhci_am654_init(struct sdhci_host *host)  {  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -344,7 +397,23 @@ static int sdhci_am654_init(struct sdhci_host *host)  	regmap_update_bits(sdhci_am654->base, CTL_CFG_2, SLOTTYPE_MASK,  			   ctl_cfg_2); -	return sdhci_add_host(host); +	ret = sdhci_setup_host(host); +	if (ret) +		return ret; + +	ret = sdhci_am654_cqe_add_host(host); +	if (ret) +		goto err_cleanup_host; + +	ret = __sdhci_add_host(host); +	if (ret) +		goto err_cleanup_host; + +	return 0; + +err_cleanup_host: +	sdhci_cleanup_host(host); +	return ret;  }  static int sdhci_am654_get_of_property(struct platform_device *pdev, diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c index f8b939e63e02..fa0dfc657c22 100644 --- a/drivers/mmc/host/sdhci_f_sdh30.c +++ b/drivers/mmc/host/sdhci_f_sdh30.c @@ -16,31 +16,7 @@  #include <linux/clk.h>  #include "sdhci-pltfm.h" - -/* F_SDH30 extended Controller registers */ -#define F_SDH30_AHB_CONFIG		0x100 -#define  F_SDH30_AHB_BIGED		0x00000040 -#define  F_SDH30_BUSLOCK_DMA		0x00000020 -#define  F_SDH30_BUSLOCK_EN		0x00000010 -#define  F_SDH30_SIN			0x00000008 -#define  F_SDH30_AHB_INCR_16		0x00000004 -#define  F_SDH30_AHB_INCR_8		0x00000002 -#define  F_SDH30_AHB_INCR_4		0x00000001 - -#define F_SDH30_TUNING_SETTING		0x108 -#define  F_SDH30_CMD_CHK_DIS		0x00010000 - -#define F_SDH30_IO_CONTROL2		0x114 -#define  F_SDH30_CRES_O_DN		0x00080000 -#define  F_SDH30_MSEL_O_1_8		0x00040000 - -#define F_SDH30_ESD_CONTROL		0x124 -#define  F_SDH30_EMMC_RST		0x00000002 -#define  F_SDH30_EMMC_HS200		0x01000000 - -#define F_SDH30_CMD_DAT_DELAY		0x200 - -#define F_SDH30_MIN_CLOCK		400000 +#include "sdhci_f_sdh30.h"  struct f_sdhost_priv {  	struct clk *clk_iface; diff --git a/drivers/mmc/host/sdhci_f_sdh30.h b/drivers/mmc/host/sdhci_f_sdh30.h new file mode 100644 index 000000000000..fc1ad28f7ca9 --- /dev/null +++ b/drivers/mmc/host/sdhci_f_sdh30.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd + *              Vincent Yang <[email protected]> + * Copyright (C) 2015 Linaro Ltd  Andy Green <[email protected]> + * Copyright (C) 2019 Socionext Inc. + * + */ + +/* F_SDH30 extended Controller registers */ +#define F_SDH30_AHB_CONFIG      0x100 +#define  F_SDH30_AHB_BIGED      BIT(6) +#define  F_SDH30_BUSLOCK_DMA    BIT(5) +#define  F_SDH30_BUSLOCK_EN     BIT(4) +#define  F_SDH30_SIN            BIT(3) +#define  F_SDH30_AHB_INCR_16    BIT(2) +#define  F_SDH30_AHB_INCR_8     BIT(1) +#define  F_SDH30_AHB_INCR_4     BIT(0) + +#define F_SDH30_TUNING_SETTING  0x108 +#define  F_SDH30_CMD_CHK_DIS    BIT(16) + +#define F_SDH30_IO_CONTROL2     0x114 +#define  F_SDH30_CRES_O_DN      BIT(19) +#define  F_SDH30_MSEL_O_1_8     BIT(18) + +#define F_SDH30_ESD_CONTROL     0x124 +#define	 F_SDH30_EMMC_RST		BIT(1) +#define  F_SDH30_CMD_DAT_DELAY	BIT(9) +#define	 F_SDH30_EMMC_HS200		BIT(24) + +#define F_SDH30_MIN_CLOCK		400000 diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 2f0b092d6dcc..c5ba13fae399 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -163,7 +163,6 @@ struct tmio_mmc_host {  	unsigned long		last_req_ts;  	struct mutex		ios_lock;	/* protect set_ios() context */  	bool			native_hotplug; -	bool			runtime_synced;  	bool			sdio_irq_enabled;  	/* Mandatory callback */ diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 9b6e1001e77c..c4a1d49fbea4 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -39,6 +39,7 @@  #include <linux/module.h>  #include <linux/pagemap.h>  #include <linux/platform_device.h> +#include <linux/pm_domain.h>  #include <linux/pm_qos.h>  #include <linux/pm_runtime.h>  #include <linux/regulator/consumer.h> @@ -1184,7 +1185,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)  	if (ret == -EPROBE_DEFER)  		return ret; -	mmc->caps |= MMC_CAP_4_BIT_DATA | pdata->capabilities; +	mmc->caps |= MMC_CAP_ERASE | MMC_CAP_4_BIT_DATA | pdata->capabilities;  	mmc->caps2 |= pdata->capabilities2;  	mmc->max_segs = pdata->max_segs ? : 32;  	mmc->max_blk_size = TMIO_MAX_BLK_SIZE; @@ -1248,10 +1249,12 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)  	/* See if we also get DMA */  	tmio_mmc_request_dma(_host, pdata); +	dev_pm_domain_start(&pdev->dev); +	pm_runtime_get_noresume(&pdev->dev); +	pm_runtime_set_active(&pdev->dev);  	pm_runtime_set_autosuspend_delay(&pdev->dev, 50);  	pm_runtime_use_autosuspend(&pdev->dev);  	pm_runtime_enable(&pdev->dev); -	pm_runtime_get_sync(&pdev->dev);  	ret = mmc_add_host(mmc);  	if (ret) @@ -1333,11 +1336,6 @@ int tmio_mmc_host_runtime_resume(struct device *dev)  {  	struct tmio_mmc_host *host = dev_get_drvdata(dev); -	if (!host->runtime_synced) { -		host->runtime_synced = true; -		return 0; -	} -  	tmio_mmc_clk_enable(host);  	tmio_mmc_hw_reset(host->mmc); diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index a3680c900689..6ced1b7f642f 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -2070,18 +2070,11 @@ static void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable)  	kref_put(&vub300->kref, vub300_delete);  } -static void vub300_init_card(struct mmc_host *mmc, struct mmc_card *card) -{				/* NOT irq */ -	struct vub300_mmc_host *vub300 = mmc_priv(mmc); -	dev_info(&vub300->udev->dev, "NO host QUIRKS for this card\n"); -} -  static const struct mmc_host_ops vub300_mmc_ops = {  	.request = vub300_mmc_request,  	.set_ios = vub300_mmc_set_ios,  	.get_ro = vub300_mmc_get_ro,  	.enable_sdio_irq = vub300_enable_sdio_irq, -	.init_card = vub300_init_card,  };  static int vub300_probe(struct usb_interface *interface,  |