diff options
Diffstat (limited to 'drivers/mmc')
34 files changed, 784 insertions, 330 deletions
| diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 32d49100dff5..64a3492e8002 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -144,7 +144,7 @@ struct mmc_blk_data {  static dev_t mmc_rpmb_devt;  /* Bus type for RPMB character devices */ -static struct bus_type mmc_rpmb_bus_type = { +static const struct bus_type mmc_rpmb_bus_type = {  	.name = "mmc_rpmb",  }; @@ -206,7 +206,7 @@ static void mmc_blk_kref_release(struct kref *ref)  	int devidx;  	devidx = mmc_get_devidx(md->disk); -	ida_simple_remove(&mmc_blk_ida, devidx); +	ida_free(&mmc_blk_ida, devidx);  	mutex_lock(&open_lock);  	md->disk->private_data = NULL; @@ -874,10 +874,11 @@ static const struct block_device_operations mmc_bdops = {  static int mmc_blk_part_switch_pre(struct mmc_card *card,  				   unsigned int part_type)  { -	const unsigned int mask = EXT_CSD_PART_CONFIG_ACC_RPMB; +	const unsigned int mask = EXT_CSD_PART_CONFIG_ACC_MASK; +	const unsigned int rpmb = EXT_CSD_PART_CONFIG_ACC_RPMB;  	int ret = 0; -	if ((part_type & mask) == mask) { +	if ((part_type & mask) == rpmb) {  		if (card->ext_csd.cmdq_en) {  			ret = mmc_cmdq_disable(card);  			if (ret) @@ -892,10 +893,11 @@ static int mmc_blk_part_switch_pre(struct mmc_card *card,  static int mmc_blk_part_switch_post(struct mmc_card *card,  				    unsigned int part_type)  { -	const unsigned int mask = EXT_CSD_PART_CONFIG_ACC_RPMB; +	const unsigned int mask = EXT_CSD_PART_CONFIG_ACC_MASK; +	const unsigned int rpmb = EXT_CSD_PART_CONFIG_ACC_RPMB;  	int ret = 0; -	if ((part_type & mask) == mask) { +	if ((part_type & mask) == rpmb) {  		mmc_retune_unpause(card->host);  		if (card->reenable_cmdq && !card->ext_csd.cmdq_en)  			ret = mmc_cmdq_enable(card); @@ -2467,7 +2469,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,  	bool cache_enabled = false;  	bool fua_enabled = false; -	devidx = ida_simple_get(&mmc_blk_ida, 0, max_devices, GFP_KERNEL); +	devidx = ida_alloc_max(&mmc_blk_ida, max_devices - 1, GFP_KERNEL);  	if (devidx < 0) {  		/*  		 * We get -ENOSPC because there are no more any available @@ -2577,7 +2579,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,   err_kfree:  	kfree(md);   out: -	ida_simple_remove(&mmc_blk_ida, devidx); +	ida_free(&mmc_blk_ida, devidx);  	return ERR_PTR(ret);  } @@ -2703,7 +2705,7 @@ static void mmc_blk_rpmb_device_release(struct device *dev)  {  	struct mmc_rpmb_data *rpmb = dev_get_drvdata(dev); -	ida_simple_remove(&mmc_rpmb_ida, rpmb->id); +	ida_free(&mmc_rpmb_ida, rpmb->id);  	kfree(rpmb);  } @@ -2719,13 +2721,13 @@ static int mmc_blk_alloc_rpmb_part(struct mmc_card *card,  	struct mmc_rpmb_data *rpmb;  	/* This creates the minor number for the RPMB char device */ -	devidx = ida_simple_get(&mmc_rpmb_ida, 0, max_devices, GFP_KERNEL); +	devidx = ida_alloc_max(&mmc_rpmb_ida, max_devices - 1, GFP_KERNEL);  	if (devidx < 0)  		return devidx;  	rpmb = kzalloc(sizeof(*rpmb), GFP_KERNEL);  	if (!rpmb) { -		ida_simple_remove(&mmc_rpmb_ida, devidx); +		ida_free(&mmc_rpmb_ida, devidx);  		return -ENOMEM;  	} diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 0af96548e7da..0ddaee0eae54 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -214,7 +214,7 @@ static const struct dev_pm_ops mmc_bus_pm_ops = {  	SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume)  }; -static struct bus_type mmc_bus_type = { +static const struct bus_type mmc_bus_type = {  	.name		= "mmc",  	.dev_groups	= mmc_dev_groups,  	.uevent		= mmc_bus_uevent, @@ -272,7 +272,7 @@ static void mmc_release_card(struct device *dev)  /*   * Allocate and initialise a new MMC card structure.   */ -struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type) +struct mmc_card *mmc_alloc_card(struct mmc_host *host, const struct device_type *type)  {  	struct mmc_card *card; diff --git a/drivers/mmc/core/bus.h b/drivers/mmc/core/bus.h index 3996b191b68d..cfd0d02d3420 100644 --- a/drivers/mmc/core/bus.h +++ b/drivers/mmc/core/bus.h @@ -23,7 +23,7 @@ static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *a  static DEVICE_ATTR(name, S_IRUGO, mmc_##name##_show, NULL)  struct mmc_card *mmc_alloc_card(struct mmc_host *host, -	struct device_type *type); +				const struct device_type *type);  int mmc_add_card(struct mmc_card *card);  void mmc_remove_card(struct mmc_card *card); diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index cf396e8f34e9..8f8781d6c25e 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -76,7 +76,7 @@ static void mmc_host_classdev_release(struct device *dev)  	struct mmc_host *host = cls_dev_to_mmc_host(dev);  	wakeup_source_unregister(host->ws);  	if (of_alias_get_id(host->parent->of_node, "mmc") < 0) -		ida_simple_remove(&mmc_host_ida, host->index); +		ida_free(&mmc_host_ida, host->index);  	kfree(host);  } @@ -88,7 +88,7 @@ static int mmc_host_classdev_shutdown(struct device *dev)  	return 0;  } -static struct class mmc_host_class = { +static const struct class mmc_host_class = {  	.name		= "mmc_host",  	.dev_release	= mmc_host_classdev_release,  	.shutdown_pre	= mmc_host_classdev_shutdown, @@ -234,10 +234,8 @@ static void mmc_of_parse_timing_phase(struct device *dev, const char *prop,  }  void -mmc_of_parse_clk_phase(struct mmc_host *host, struct mmc_clk_phase_map *map) +mmc_of_parse_clk_phase(struct device *dev, struct mmc_clk_phase_map *map)  { -	struct device *dev = host->parent; -  	mmc_of_parse_timing_phase(dev, "clk-phase-legacy",  				  &map->phase[MMC_TIMING_LEGACY]);  	mmc_of_parse_timing_phase(dev, "clk-phase-mmc-hs", @@ -538,7 +536,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)  		min_idx = mmc_first_nonreserved_index();  		max_idx = 0; -		index = ida_simple_get(&mmc_host_ida, min_idx, max_idx, GFP_KERNEL); +		index = ida_alloc_range(&mmc_host_ida, min_idx, max_idx - 1, +					GFP_KERNEL);  		if (index < 0) {  			kfree(host);  			return NULL; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index f410bee50132..5b2f7c285461 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -883,7 +883,7 @@ static struct attribute *mmc_std_attrs[] = {  };  ATTRIBUTE_GROUPS(mmc_std); -static struct device_type mmc_type = { +static const struct device_type mmc_type = {  	.groups = mmc_std_groups,  }; @@ -1015,10 +1015,12 @@ static int mmc_select_bus_width(struct mmc_card *card)  	static unsigned ext_csd_bits[] = {  		EXT_CSD_BUS_WIDTH_8,  		EXT_CSD_BUS_WIDTH_4, +		EXT_CSD_BUS_WIDTH_1,  	};  	static unsigned bus_widths[] = {  		MMC_BUS_WIDTH_8,  		MMC_BUS_WIDTH_4, +		MMC_BUS_WIDTH_1,  	};  	struct mmc_host *host = card->host;  	unsigned idx, bus_width = 0; diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index a0a2412f62a7..241cdc2b2a2a 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -174,8 +174,8 @@ static struct scatterlist *mmc_alloc_sg(unsigned short sg_len, gfp_t gfp)  	return sg;  } -static void mmc_queue_setup_discard(struct request_queue *q, -				    struct mmc_card *card) +static void mmc_queue_setup_discard(struct mmc_card *card, +		struct queue_limits *lim)  {  	unsigned max_discard; @@ -183,15 +183,17 @@ static void mmc_queue_setup_discard(struct request_queue *q,  	if (!max_discard)  		return; -	blk_queue_max_discard_sectors(q, max_discard); -	q->limits.discard_granularity = card->pref_erase << 9; -	/* granularity must not be greater than max. discard */ -	if (card->pref_erase > max_discard) -		q->limits.discard_granularity = SECTOR_SIZE; +	lim->max_hw_discard_sectors = max_discard;  	if (mmc_can_secure_erase_trim(card)) -		blk_queue_max_secure_erase_sectors(q, max_discard); +		lim->max_secure_erase_sectors = max_discard;  	if (mmc_can_trim(card) && card->erased_byte == 0) -		blk_queue_max_write_zeroes_sectors(q, max_discard); +		lim->max_write_zeroes_sectors = max_discard; + +	/* granularity must not be greater than max. discard */ +	if (card->pref_erase > max_discard) +		lim->discard_granularity = SECTOR_SIZE; +	else +		lim->discard_granularity = card->pref_erase << 9;  }  static unsigned short mmc_get_max_segments(struct mmc_host *host) @@ -341,40 +343,50 @@ static const struct blk_mq_ops mmc_mq_ops = {  	.timeout	= mmc_mq_timed_out,  }; -static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card) +static struct gendisk *mmc_alloc_disk(struct mmc_queue *mq, +		struct mmc_card *card)  {  	struct mmc_host *host = card->host; -	unsigned block_size = 512; +	struct queue_limits lim = { }; +	struct gendisk *disk; -	blk_queue_flag_set(QUEUE_FLAG_NONROT, mq->queue); -	blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, mq->queue);  	if (mmc_can_erase(card)) -		mmc_queue_setup_discard(mq->queue, card); - -	if (!mmc_dev(host)->dma_mask || !*mmc_dev(host)->dma_mask) -		blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_HIGH); -	blk_queue_max_hw_sectors(mq->queue, -		min(host->max_blk_count, host->max_req_size / 512)); -	if (host->can_dma_map_merge) -		WARN(!blk_queue_can_use_dma_map_merging(mq->queue, -							mmc_dev(host)), -		     "merging was advertised but not possible"); -	blk_queue_max_segments(mq->queue, mmc_get_max_segments(host)); - -	if (mmc_card_mmc(card) && card->ext_csd.data_sector_size) { -		block_size = card->ext_csd.data_sector_size; -		WARN_ON(block_size != 512 && block_size != 4096); -	} +		mmc_queue_setup_discard(card, &lim); + +	lim.max_hw_sectors = min(host->max_blk_count, host->max_req_size / 512); + +	if (mmc_card_mmc(card) && card->ext_csd.data_sector_size) +		lim.logical_block_size = card->ext_csd.data_sector_size; +	else +		lim.logical_block_size = 512; + +	WARN_ON_ONCE(lim.logical_block_size != 512 && +		     lim.logical_block_size != 4096); -	blk_queue_logical_block_size(mq->queue, block_size);  	/* -	 * After blk_queue_can_use_dma_map_merging() was called with succeed, -	 * since it calls blk_queue_virt_boundary(), the mmc should not call -	 * both blk_queue_max_segment_size(). +	 * Setting a virt_boundary implicity sets a max_segment_size, so try +	 * to set the hardware one here.  	 */ -	if (!host->can_dma_map_merge) -		blk_queue_max_segment_size(mq->queue, -			round_down(host->max_seg_size, block_size)); +	if (host->can_dma_map_merge) { +		lim.virt_boundary_mask = dma_get_merge_boundary(mmc_dev(host)); +		lim.max_segments = MMC_DMA_MAP_MERGE_SEGMENTS; +	} else { +		lim.max_segment_size = +			round_down(host->max_seg_size, lim.logical_block_size); +		lim.max_segments = host->max_segs; +	} + +	disk = blk_mq_alloc_disk(&mq->tag_set, &lim, mq); +	if (IS_ERR(disk)) +		return disk; +	mq->queue = disk->queue; + +	if (mmc_host_is_spi(host) && host->use_spi_crc) +		blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, mq->queue); +	blk_queue_rq_timeout(mq->queue, 60 * HZ); + +	blk_queue_flag_set(QUEUE_FLAG_NONROT, mq->queue); +	blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, mq->queue);  	dma_set_max_seg_size(mmc_dev(host), queue_max_segment_size(mq->queue)); @@ -386,6 +398,7 @@ static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)  	init_waitqueue_head(&mq->wait);  	mmc_crypto_setup_queue(mq->queue, host); +	return disk;  }  static inline bool mmc_merge_capable(struct mmc_host *host) @@ -447,18 +460,9 @@ struct gendisk *mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card)  		return ERR_PTR(ret); -	disk = blk_mq_alloc_disk(&mq->tag_set, mq); -	if (IS_ERR(disk)) { +	disk = mmc_alloc_disk(mq, card); +	if (IS_ERR(disk))  		blk_mq_free_tag_set(&mq->tag_set); -		return disk; -	} -	mq->queue = disk->queue; - -	if (mmc_host_is_spi(host) && host->use_spi_crc) -		blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, mq->queue); -	blk_queue_rq_timeout(mq->queue, 60 * HZ); - -	mmc_setup_queue(mq, card);  	return disk;  } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index c3e554344c99..1c8148cdda50 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -805,7 +805,7 @@ static const struct attribute_group sd_std_group = {  };  __ATTRIBUTE_GROUPS(sd_std); -struct device_type sd_type = { +const struct device_type sd_type = {  	.groups = sd_std_groups,  }; diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h index 1af5a038bae9..fe6dd46927a4 100644 --- a/drivers/mmc/core/sd.h +++ b/drivers/mmc/core/sd.h @@ -4,7 +4,7 @@  #include <linux/types.h> -extern struct device_type sd_type; +extern const struct device_type sd_type;  struct mmc_host;  struct mmc_card; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 5914516df2f7..4fb247fde5c0 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -66,7 +66,7 @@ static struct attribute *sdio_std_attrs[] = {  };  ATTRIBUTE_GROUPS(sdio_std); -static struct device_type sdio_type = { +static const struct device_type sdio_type = {  	.groups = sdio_std_groups,  }; diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 47a48e902a24..71d885fbc228 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -244,7 +244,7 @@ static const struct dev_pm_ops sdio_bus_pm_ops = {  	)  }; -static struct bus_type sdio_bus_type = { +static const struct bus_type sdio_bus_type = {  	.name		= "sdio",  	.dev_groups	= sdio_dev_groups,  	.match		= sdio_bus_match, diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 81f2c4e05287..aebc587f77a7 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -798,6 +798,15 @@ config MMC_DW_HI3798CV200  	  Synopsys DesignWare Memory Card Interface driver. Select this option  	  for platforms based on HiSilicon Hi3798CV200 SoC. +config MMC_DW_HI3798MV200 +	tristate "Hi3798MV200 specific extensions for Synopsys DW Memory Card Interface" +	depends on MMC_DW +	select MMC_DW_PLTFM +	help +	  This selects support for HiSilicon Hi3798MV200 SoC specific extensions to the +	  Synopsys DesignWare Memory Card Interface driver. Select this option +	  for platforms based on HiSilicon Hi3798MV200 SoC. +  config MMC_DW_K3  	tristate "K3 specific extensions for Synopsys DW Memory Card Interface"  	depends on MMC_DW diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index d0be4465f3ec..f53f86d200ac 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_MMC_DW_PLTFM)	+= dw_mmc-pltfm.o  obj-$(CONFIG_MMC_DW_BLUEFIELD)	+= dw_mmc-bluefield.o  obj-$(CONFIG_MMC_DW_EXYNOS)	+= dw_mmc-exynos.o  obj-$(CONFIG_MMC_DW_HI3798CV200) += dw_mmc-hi3798cv200.o +obj-$(CONFIG_MMC_DW_HI3798MV200) += dw_mmc-hi3798mv200.o  obj-$(CONFIG_MMC_DW_K3)		+= dw_mmc-k3.o  obj-$(CONFIG_MMC_DW_PCI)	+= dw_mmc-pci.o  obj-$(CONFIG_MMC_DW_ROCKCHIP)	+= dw_mmc-rockchip.o diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index ee3b1a4e0848..8bd938919687 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -180,12 +180,6 @@ struct mmc_davinci_host {  #define DAVINCI_MMC_DATADIR_WRITE	2  	unsigned char data_dir; -	/* buffer is used during PIO of one scatterlist segment, and -	 * is updated along with buffer_bytes_left.  bytes_left applies -	 * to all N blocks of the PIO transfer. -	 */ -	u8 *buffer; -	u32 buffer_bytes_left;  	u32 bytes_left;  	struct dma_chan *dma_tx; @@ -196,8 +190,8 @@ struct mmc_davinci_host {  	bool active_request;  	/* For PIO we walk scatterlists one segment at a time. */ +	struct sg_mapping_iter sg_miter;  	unsigned int		sg_len; -	struct scatterlist *sg;  	/* Version of the MMC/SD controller */  	u8 version; @@ -213,30 +207,22 @@ struct mmc_davinci_host {  static irqreturn_t mmc_davinci_irq(int irq, void *dev_id);  /* PIO only */ -static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host) -{ -	host->buffer_bytes_left = sg_dma_len(host->sg); -	host->buffer = sg_virt(host->sg); -	if (host->buffer_bytes_left > host->bytes_left) -		host->buffer_bytes_left = host->bytes_left; -} -  static void davinci_fifo_data_trans(struct mmc_davinci_host *host,  					unsigned int n)  { +	struct sg_mapping_iter *sgm = &host->sg_miter;  	u8 *p;  	unsigned int i; -	if (host->buffer_bytes_left == 0) { -		host->sg = sg_next(host->data->sg); -		mmc_davinci_sg_to_buf(host); +	/* +	 * By adjusting sgm->consumed this will give a pointer to the +	 * current index into the sgm. +	 */ +	if (!sg_miter_next(sgm)) { +		dev_err(mmc_dev(host->mmc), "ran out of sglist prematurely\n"); +		return;  	} - -	p = host->buffer; -	if (n > host->buffer_bytes_left) -		n = host->buffer_bytes_left; -	host->buffer_bytes_left -= n; -	host->bytes_left -= n; +	p = sgm->addr;  	/* NOTE:  we never transfer more than rw_threshold bytes  	 * to/from the fifo here; there's no I/O overlap. @@ -261,7 +247,9 @@ static void davinci_fifo_data_trans(struct mmc_davinci_host *host,  			p = p + (n & 3);  		}  	} -	host->buffer = p; + +	sgm->consumed = n; +	host->bytes_left -= n;  }  static void mmc_davinci_start_command(struct mmc_davinci_host *host, @@ -517,6 +505,7 @@ mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request *req)  	int fifo_lev = (rw_threshold == 32) ? MMCFIFOCTL_FIFOLEV : 0;  	int timeout;  	struct mmc_data *data = req->data; +	unsigned int flags = SG_MITER_ATOMIC; /* Used from IRQ */  	if (host->version == MMC_CTLR_VERSION_2)  		fifo_lev = (rw_threshold == 64) ? MMCFIFOCTL_FIFOLEV : 0; @@ -545,12 +534,14 @@ mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request *req)  	/* Configure the FIFO */  	if (data->flags & MMC_DATA_WRITE) { +		flags |= SG_MITER_FROM_SG;  		host->data_dir = DAVINCI_MMC_DATADIR_WRITE;  		writel(fifo_lev | MMCFIFOCTL_FIFODIR_WR | MMCFIFOCTL_FIFORST,  			host->base + DAVINCI_MMCFIFOCTL);  		writel(fifo_lev | MMCFIFOCTL_FIFODIR_WR,  			host->base + DAVINCI_MMCFIFOCTL);  	} else { +		flags |= SG_MITER_TO_SG;  		host->data_dir = DAVINCI_MMC_DATADIR_READ;  		writel(fifo_lev | MMCFIFOCTL_FIFODIR_RD | MMCFIFOCTL_FIFORST,  			host->base + DAVINCI_MMCFIFOCTL); @@ -558,7 +549,6 @@ mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request *req)  			host->base + DAVINCI_MMCFIFOCTL);  	} -	host->buffer = NULL;  	host->bytes_left = data->blocks * data->blksz;  	/* For now we try to use DMA whenever we won't need partial FIFO @@ -576,8 +566,7 @@ mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request *req)  	} else {  		/* Revert to CPU Copy */  		host->sg_len = data->sg_len; -		host->sg = host->data->sg; -		mmc_davinci_sg_to_buf(host); +		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);  	}  } @@ -843,6 +832,8 @@ davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data)  {  	mmc_davinci_reset_ctrl(host, 1);  	mmc_davinci_reset_ctrl(host, 0); +	if (!host->do_dma) +		sg_miter_stop(&host->sg_miter);  }  static irqreturn_t mmc_davinci_sdio_irq(int irq, void *dev_id) @@ -919,11 +910,13 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)  	if (qstatus & MMCST0_DATDNE) {  		/* All blocks sent/received, and CRC checks passed */  		if (data != NULL) { -			if ((host->do_dma == 0) && (host->bytes_left > 0)) { -				/* if datasize < rw_threshold -				 * no RX ints are generated -				 */ -				davinci_fifo_data_trans(host, host->bytes_left); +			if (!host->do_dma) { +				if (host->bytes_left > 0) +					/* if datasize < rw_threshold +					 * no RX ints are generated +					 */ +					davinci_fifo_data_trans(host, host->bytes_left); +				sg_miter_stop(&host->sg_miter);  			}  			end_transfer = 1;  			data->bytes_xfered = data->blocks * data->blksz; diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 698408e8bad0..6dc057718d2c 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -11,7 +11,6 @@  #include <linux/mmc/host.h>  #include <linux/mmc/mmc.h>  #include <linux/of.h> -#include <linux/of_gpio.h>  #include <linux/pm_runtime.h>  #include <linux/slab.h> diff --git a/drivers/mmc/host/dw_mmc-hi3798cv200.c b/drivers/mmc/host/dw_mmc-hi3798cv200.c index e9470c50a348..61923a518369 100644 --- a/drivers/mmc/host/dw_mmc-hi3798cv200.c +++ b/drivers/mmc/host/dw_mmc-hi3798cv200.c @@ -201,4 +201,3 @@ module_platform_driver(dw_mci_hi3798cv200_driver);  MODULE_DESCRIPTION("HiSilicon Hi3798CV200 Specific DW-MSHC Driver Extension");  MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:dwmmc_hi3798cv200"); diff --git a/drivers/mmc/host/dw_mmc-hi3798mv200.c b/drivers/mmc/host/dw_mmc-hi3798mv200.c new file mode 100644 index 000000000000..989ae8dda722 --- /dev/null +++ b/drivers/mmc/host/dw_mmc-hi3798mv200.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Modified from dw_mmc-hi3798cv200.c + * + * Copyright (c) 2024 Yang Xiwen <[email protected]> + * Copyright (c) 2018 HiSilicon Technologies Co., Ltd. + */ + +#include <linux/clk.h> +#include <linux/mfd/syscon.h> +#include <linux/mmc/host.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#include "dw_mmc.h" +#include "dw_mmc-pltfm.h" + +#define SDMMC_TUNING_CTRL	0x118 +#define SDMMC_TUNING_FIND_EDGE	BIT(5) + +#define ALL_INT_CLR		0x1ffff + +/* DLL ctrl reg */ +#define SAP_DLL_CTRL_DLLMODE	BIT(16) + +struct dw_mci_hi3798mv200_priv { +	struct clk *sample_clk; +	struct clk *drive_clk; +	struct regmap *crg_reg; +	u32 sap_dll_offset; +	struct mmc_clk_phase_map phase_map; +}; + +static void dw_mci_hi3798mv200_set_ios(struct dw_mci *host, struct mmc_ios *ios) +{ +	struct dw_mci_hi3798mv200_priv *priv = host->priv; +	struct mmc_clk_phase phase = priv->phase_map.phase[ios->timing]; +	u32 val; + +	val = mci_readl(host, ENABLE_SHIFT); +	if (ios->timing == MMC_TIMING_MMC_DDR52 +	    || ios->timing == MMC_TIMING_UHS_DDR50) +		val |= SDMMC_ENABLE_PHASE; +	else +		val &= ~SDMMC_ENABLE_PHASE; +	mci_writel(host, ENABLE_SHIFT, val); + +	val = mci_readl(host, DDR_REG); +	if (ios->timing == MMC_TIMING_MMC_HS400) +		val |= SDMMC_DDR_HS400; +	else +		val &= ~SDMMC_DDR_HS400; +	mci_writel(host, DDR_REG, val); + +	if (clk_set_rate(host->ciu_clk, ios->clock)) +		dev_warn(host->dev, "Failed to set rate to %u\n", ios->clock); +	else +		/* +		 * CLK_MUX_ROUND_NEAREST is enabled for this clock +		 * The actual clock rate is not what we set, but a rounded value +		 * so we should get the rate once again +		 */ +		host->bus_hz = clk_get_rate(host->ciu_clk); + +	if (phase.valid) { +		clk_set_phase(priv->drive_clk, phase.out_deg); +		clk_set_phase(priv->sample_clk, phase.in_deg); +	} else { +		dev_warn(host->dev, +			 "The phase entry for timing mode %d is missing in device tree.\n", +			 ios->timing); +	} +} + +static inline int dw_mci_hi3798mv200_enable_tuning(struct dw_mci_slot *slot) +{ +	struct dw_mci_hi3798mv200_priv *priv = slot->host->priv; + +	return regmap_clear_bits(priv->crg_reg, priv->sap_dll_offset, SAP_DLL_CTRL_DLLMODE); +} + +static inline int dw_mci_hi3798mv200_disable_tuning(struct dw_mci_slot *slot) +{ +	struct dw_mci_hi3798mv200_priv *priv = slot->host->priv; + +	return regmap_set_bits(priv->crg_reg, priv->sap_dll_offset, SAP_DLL_CTRL_DLLMODE); +} + +static int dw_mci_hi3798mv200_execute_tuning_mix_mode(struct dw_mci_slot *slot, +					     u32 opcode) +{ +	static const int degrees[] = { 0, 45, 90, 135, 180, 225, 270, 315 }; +	struct dw_mci *host = slot->host; +	struct dw_mci_hi3798mv200_priv *priv = host->priv; +	int raise_point = -1, fall_point = -1, mid; +	int err, prev_err = -1; +	int found = 0; +	int regval; +	int i; +	int ret; + +	ret = dw_mci_hi3798mv200_enable_tuning(slot); +	if (ret < 0) +		return ret; + +	for (i = 0; i < ARRAY_SIZE(degrees); i++) { +		clk_set_phase(priv->sample_clk, degrees[i]); +		mci_writel(host, RINTSTS, ALL_INT_CLR); + +		/* +		 * HiSilicon implemented a tuning mechanism. +		 * It needs special interaction with the DLL. +		 * +		 * Treat edge(flip) found as an error too. +		 */ +		err = mmc_send_tuning(slot->mmc, opcode, NULL); +		regval = mci_readl(host, TUNING_CTRL); +		if (err || (regval & SDMMC_TUNING_FIND_EDGE)) +			err = 1; +		else +			found = 1; + +		if (i > 0) { +			if (err && !prev_err) +				fall_point = i - 1; +			if (!err && prev_err) +				raise_point = i; +		} + +		if (raise_point != -1 && fall_point != -1) +			goto tuning_out; + +		prev_err = err; +		err = 0; +	} + +tuning_out: +	ret = dw_mci_hi3798mv200_disable_tuning(slot); +	if (ret < 0) +		return ret; + +	if (found) { +		if (raise_point == -1) +			raise_point = 0; +		if (fall_point == -1) +			fall_point = ARRAY_SIZE(degrees) - 1; +		if (fall_point < raise_point) { +			if ((raise_point + fall_point) > +			    (ARRAY_SIZE(degrees) - 1)) +				mid = fall_point / 2; +			else +				mid = (raise_point + ARRAY_SIZE(degrees) - 1) / 2; +		} else { +			mid = (raise_point + fall_point) / 2; +		} + +		/* +		 * We don't care what timing we are tuning for, +		 * simply use the same phase for all timing needs tuning. +		 */ +		priv->phase_map.phase[MMC_TIMING_MMC_HS200].in_deg = degrees[mid]; +		priv->phase_map.phase[MMC_TIMING_MMC_HS400].in_deg = degrees[mid]; +		priv->phase_map.phase[MMC_TIMING_UHS_SDR104].in_deg = degrees[mid]; + +		clk_set_phase(priv->sample_clk, degrees[mid]); +		dev_dbg(host->dev, "Tuning clk_sample[%d, %d], set[%d]\n", +			raise_point, fall_point, degrees[mid]); +		ret = 0; +	} else { +		dev_err(host->dev, "No valid clk_sample shift!\n"); +		ret = -EINVAL; +	} + +	mci_writel(host, RINTSTS, ALL_INT_CLR); + +	return ret; +} + +static int dw_mci_hi3798mv200_init(struct dw_mci *host) +{ +	struct dw_mci_hi3798mv200_priv *priv; +	struct device_node *np = host->dev->of_node; +	int ret; + +	priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	mmc_of_parse_clk_phase(host->dev, &priv->phase_map); + +	priv->sample_clk = devm_clk_get_enabled(host->dev, "ciu-sample"); +	if (IS_ERR(priv->sample_clk)) +		return dev_err_probe(host->dev, PTR_ERR(priv->sample_clk), +				     "failed to get enabled ciu-sample clock\n"); + +	priv->drive_clk = devm_clk_get_enabled(host->dev, "ciu-drive"); +	if (IS_ERR(priv->drive_clk)) +		return dev_err_probe(host->dev, PTR_ERR(priv->drive_clk), +				     "failed to get enabled ciu-drive clock\n"); + +	priv->crg_reg = syscon_regmap_lookup_by_phandle(np, "hisilicon,sap-dll-reg"); +	if (IS_ERR(priv->crg_reg)) +		return dev_err_probe(host->dev, PTR_ERR(priv->crg_reg), +				     "failed to get CRG reg\n"); + +	ret = of_property_read_u32_index(np, "hisilicon,sap-dll-reg", 1, &priv->sap_dll_offset); +	if (ret) +		return dev_err_probe(host->dev, ret, "failed to get sample DLL register offset\n"); + +	host->priv = priv; +	return 0; +} + +static const struct dw_mci_drv_data hi3798mv200_data = { +	.common_caps = MMC_CAP_CMD23, +	.init = dw_mci_hi3798mv200_init, +	.set_ios = dw_mci_hi3798mv200_set_ios, +	.execute_tuning = dw_mci_hi3798mv200_execute_tuning_mix_mode, +}; + +static const struct of_device_id dw_mci_hi3798mv200_match[] = { +	{ .compatible = "hisilicon,hi3798mv200-dw-mshc" }, +	{}, +}; + +static int dw_mci_hi3798mv200_probe(struct platform_device *pdev) +{ +	return dw_mci_pltfm_register(pdev, &hi3798mv200_data); +} + +static void dw_mci_hi3798mv200_remove(struct platform_device *pdev) +{ +	dw_mci_pltfm_remove(pdev); +} + +MODULE_DEVICE_TABLE(of, dw_mci_hi3798mv200_match); +static struct platform_driver dw_mci_hi3798mv200_driver = { +	.probe = dw_mci_hi3798mv200_probe, +	.remove_new = dw_mci_hi3798mv200_remove, +	.driver = { +		.name = "dwmmc_hi3798mv200", +		.probe_type = PROBE_PREFER_ASYNCHRONOUS, +		.of_match_table = dw_mci_hi3798mv200_match, +	}, +}; +module_platform_driver(dw_mci_hi3798mv200_driver); + +MODULE_DESCRIPTION("HiSilicon Hi3798MV200 Specific DW-MSHC Driver Extension"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 829af2c98a44..8e2d676b9239 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -35,7 +35,6 @@  #include <linux/bitops.h>  #include <linux/regulator/consumer.h>  #include <linux/of.h> -#include <linux/of_gpio.h>  #include <linux/mmc/slot-gpio.h>  #include "dw_mmc.h" diff --git a/drivers/mmc/host/meson-mx-sdhc-clkc.c b/drivers/mmc/host/meson-mx-sdhc-clkc.c index 19200b7079a6..cbd17a596cd2 100644 --- a/drivers/mmc/host/meson-mx-sdhc-clkc.c +++ b/drivers/mmc/host/meson-mx-sdhc-clkc.c @@ -71,12 +71,23 @@ static int meson_mx_sdhc_clk_hw_register(struct device *dev,  static int meson_mx_sdhc_gate_clk_hw_register(struct device *dev,  					      const char *name_suffix,  					      struct clk_hw *parent, -					      struct clk_hw *hw) +					      struct clk_hw *hw, +					      struct clk_bulk_data *clk_bulk_data, +					      u8 bulk_index)  {  	struct clk_parent_data parent_data = { .hw = parent }; +	int ret; + +	ret = meson_mx_sdhc_clk_hw_register(dev, name_suffix, &parent_data, 1, +					    &clk_gate_ops, hw); +	if (ret) +		return ret; + +	clk_bulk_data[bulk_index].clk = devm_clk_hw_get_clk(dev, hw, name_suffix); +	if (IS_ERR(clk_bulk_data[bulk_index].clk)) +		return PTR_ERR(clk_bulk_data[bulk_index].clk); -	return meson_mx_sdhc_clk_hw_register(dev, name_suffix, &parent_data, 1, -					     &clk_gate_ops, hw); +	return 0;  }  int meson_mx_sdhc_register_clkc(struct device *dev, void __iomem *base, @@ -115,7 +126,8 @@ int meson_mx_sdhc_register_clkc(struct device *dev, void __iomem *base,  	clkc_data->mod_clk_en.bit_idx = 15;  	ret = meson_mx_sdhc_gate_clk_hw_register(dev, "mod_clk_on",  						 &clkc_data->div.hw, -						 &clkc_data->mod_clk_en.hw); +						 &clkc_data->mod_clk_en.hw, +						 clk_bulk_data, 0);  	if (ret)  		return ret; @@ -123,7 +135,8 @@ int meson_mx_sdhc_register_clkc(struct device *dev, void __iomem *base,  	clkc_data->tx_clk_en.bit_idx = 14;  	ret = meson_mx_sdhc_gate_clk_hw_register(dev, "tx_clk_on",  						 &clkc_data->div.hw, -						 &clkc_data->tx_clk_en.hw); +						 &clkc_data->tx_clk_en.hw, +						 clk_bulk_data, 1);  	if (ret)  		return ret; @@ -131,7 +144,8 @@ int meson_mx_sdhc_register_clkc(struct device *dev, void __iomem *base,  	clkc_data->rx_clk_en.bit_idx = 13;  	ret = meson_mx_sdhc_gate_clk_hw_register(dev, "rx_clk_on",  						 &clkc_data->div.hw, -						 &clkc_data->rx_clk_en.hw); +						 &clkc_data->rx_clk_en.hw, +						 clk_bulk_data, 2);  	if (ret)  		return ret; @@ -139,18 +153,7 @@ int meson_mx_sdhc_register_clkc(struct device *dev, void __iomem *base,  	clkc_data->sd_clk_en.bit_idx = 12;  	ret = meson_mx_sdhc_gate_clk_hw_register(dev, "sd_clk_on",  						 &clkc_data->div.hw, -						 &clkc_data->sd_clk_en.hw); -	if (ret) -		return ret; - -	/* -	 * TODO: Replace clk_hw.clk with devm_clk_hw_get_clk() once that is -	 * available. -	 */ -	clk_bulk_data[0].clk = clkc_data->mod_clk_en.hw.clk; -	clk_bulk_data[1].clk = clkc_data->sd_clk_en.hw.clk; -	clk_bulk_data[2].clk = clkc_data->tx_clk_en.hw.clk; -	clk_bulk_data[3].clk = clkc_data->rx_clk_en.hw.clk; - -	return 0; +						 &clkc_data->sd_clk_en.hw, +						 clk_bulk_data, 3); +	return ret;  } diff --git a/drivers/mmc/host/meson-mx-sdhc-mmc.c b/drivers/mmc/host/meson-mx-sdhc-mmc.c index 1ed9731e77ef..31f750301dc1 100644 --- a/drivers/mmc/host/meson-mx-sdhc-mmc.c +++ b/drivers/mmc/host/meson-mx-sdhc-mmc.c @@ -65,10 +65,8 @@ static const struct regmap_config meson_mx_sdhc_regmap_config = {  	.max_register = MESON_SDHC_CLK2,  }; -static void meson_mx_sdhc_hw_reset(struct mmc_host *mmc) +static void meson_mx_sdhc_reset(struct meson_mx_sdhc_host *host)  { -	struct meson_mx_sdhc_host *host = mmc_priv(mmc); -  	regmap_write(host->regmap, MESON_SDHC_SRST, MESON_SDHC_SRST_MAIN_CTRL |  		     MESON_SDHC_SRST_RXFIFO | MESON_SDHC_SRST_TXFIFO |  		     MESON_SDHC_SRST_DPHY_RX | MESON_SDHC_SRST_DPHY_TX | @@ -116,7 +114,7 @@ static void meson_mx_sdhc_wait_cmd_ready(struct mmc_host *mmc)  		dev_warn(mmc_dev(mmc),  			 "Failed to poll for CMD_BUSY while processing CMD%d\n",  			 host->cmd->opcode); -		meson_mx_sdhc_hw_reset(mmc); +		meson_mx_sdhc_reset(host);  	}  	ret = regmap_read_poll_timeout(host->regmap, MESON_SDHC_ESTA, esta, @@ -127,7 +125,7 @@ static void meson_mx_sdhc_wait_cmd_ready(struct mmc_host *mmc)  		dev_warn(mmc_dev(mmc),  			 "Failed to poll for ESTA[13:11] while processing CMD%d\n",  			 host->cmd->opcode); -		meson_mx_sdhc_hw_reset(mmc); +		meson_mx_sdhc_reset(host);  	}  } @@ -495,7 +493,6 @@ static int meson_mx_sdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)  }  static const struct mmc_host_ops meson_mx_sdhc_ops = { -	.card_hw_reset			= meson_mx_sdhc_hw_reset,  	.request			= meson_mx_sdhc_request,  	.set_ios			= meson_mx_sdhc_set_ios,  	.card_busy			= meson_mx_sdhc_card_busy, @@ -618,7 +615,7 @@ static irqreturn_t meson_mx_sdhc_irq_thread(int irq, void *irq_data)  	}  	if (cmd->error == -EIO || cmd->error == -ETIMEDOUT) -		meson_mx_sdhc_hw_reset(host->mmc); +		meson_mx_sdhc_reset(host);  	else if (cmd->data)  		/*  		 * Clear the FIFOs after completing data transfers to prevent @@ -728,7 +725,7 @@ static void meson_mx_sdhc_init_hw(struct mmc_host *mmc)  {  	struct meson_mx_sdhc_host *host = mmc_priv(mmc); -	meson_mx_sdhc_hw_reset(mmc); +	meson_mx_sdhc_reset(host);  	regmap_write(host->regmap, MESON_SDHC_CTRL,  		     FIELD_PREP(MESON_SDHC_CTRL_RX_PERIOD, 0xf) | diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index b8dda8160c4e..09d7a6a0dc1a 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -15,7 +15,6 @@  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/bio.h> -#include <linux/dma-direction.h>  #include <linux/crc7.h>  #include <linux/crc-itu-t.h>  #include <linux/scatterlist.h> @@ -510,10 +509,7 @@ mmc_spi_command_send(struct mmc_spi_host *host,   * so we explicitly initialize it to all ones on RX paths.   */  static void -mmc_spi_setup_data_message( -	struct mmc_spi_host	*host, -	bool			multiple, -	enum dma_data_direction	direction) +mmc_spi_setup_data_message(struct mmc_spi_host *host, bool multiple, bool write)  {  	struct spi_transfer	*t;  	struct scratch		*scratch = host->data; @@ -523,7 +519,7 @@ mmc_spi_setup_data_message(  	/* for reads, readblock() skips 0xff bytes before finding  	 * the token; for writes, this transfer issues that token.  	 */ -	if (direction == DMA_TO_DEVICE) { +	if (write) {  		t = &host->token;  		memset(t, 0, sizeof(*t));  		t->len = 1; @@ -547,7 +543,7 @@ mmc_spi_setup_data_message(  	t = &host->crc;  	memset(t, 0, sizeof(*t));  	t->len = 2; -	if (direction == DMA_TO_DEVICE) { +	if (write) {  		/* the actual CRC may get written later */  		t->tx_buf = &scratch->crc_val;  	} else { @@ -570,10 +566,10 @@ mmc_spi_setup_data_message(  	 * the next token (next data block, or STOP_TRAN).  We can try to  	 * minimize I/O ops by using a single read to collect end-of-busy.  	 */ -	if (multiple || direction == DMA_TO_DEVICE) { +	if (multiple || write) {  		t = &host->early_status;  		memset(t, 0, sizeof(*t)); -		t->len = (direction == DMA_TO_DEVICE) ? sizeof(scratch->status) : 1; +		t->len = write ? sizeof(scratch->status) : 1;  		t->tx_buf = host->ones;  		t->rx_buf = scratch->status;  		t->cs_change = 1; @@ -777,15 +773,15 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,  {  	struct spi_device	*spi = host->spi;  	struct spi_transfer	*t; -	enum dma_data_direction	direction = mmc_get_dma_dir(data);  	struct scatterlist	*sg;  	unsigned		n_sg;  	bool			multiple = (data->blocks > 1); -	const char		*write_or_read = (direction == DMA_TO_DEVICE) ? "write" : "read"; +	bool			write = (data->flags & MMC_DATA_WRITE); +	const char		*write_or_read = write ? "write" : "read";  	u32			clock_rate;  	unsigned long		timeout; -	mmc_spi_setup_data_message(host, multiple, direction); +	mmc_spi_setup_data_message(host, multiple, write);  	t = &host->t;  	if (t->speed_hz) @@ -807,7 +803,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,  		/* allow pio too; we don't allow highmem */  		kmap_addr = kmap(sg_page(sg)); -		if (direction == DMA_TO_DEVICE) +		if (write)  			t->tx_buf = kmap_addr + sg->offset;  		else  			t->rx_buf = kmap_addr + sg->offset; @@ -818,7 +814,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,  			dev_dbg(&spi->dev, "    %s block, %d bytes\n", write_or_read, t->len); -			if (direction == DMA_TO_DEVICE) +			if (write)  				status = mmc_spi_writeblock(host, t, timeout);  			else  				status = mmc_spi_readblock(host, t, timeout); @@ -833,7 +829,9 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,  		}  		/* discard mappings */ -		if (direction == DMA_FROM_DEVICE) +		if (write) +			/* nothing to do */; +		else  			flush_dcache_page(sg_page(sg));  		kunmap(sg_page(sg)); @@ -850,7 +848,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,  	 * that can affect the STOP_TRAN logic.   Complete (and current)  	 * MMC specs should sort that out before Linux starts using CMD23.  	 */ -	if (direction == DMA_TO_DEVICE && multiple) { +	if (write && multiple) {  		struct scratch	*scratch = host->data;  		int		tmp;  		const unsigned	statlen = sizeof(scratch->status); @@ -935,7 +933,7 @@ static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)  #endif  	/* request exclusive bus access */ -	spi_bus_lock(host->spi->master); +	spi_bus_lock(host->spi->controller);  crc_recover:  	/* issue command; then optionally data and stop */ @@ -967,7 +965,7 @@ crc_recover:  	}  	/* release the bus */ -	spi_bus_unlock(host->spi->master); +	spi_bus_unlock(host->spi->controller);  	mmc_request_done(host->mmc, mrq);  } @@ -1157,7 +1155,7 @@ static int mmc_spi_probe(struct spi_device *spi)  	/* We rely on full duplex transfers, mostly to reduce  	 * per-transfer overheads (by making fewer transfers).  	 */ -	if (spi->master->flags & SPI_CONTROLLER_HALF_DUPLEX) +	if (spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX)  		return -EINVAL;  	/* MMC and SD specs only seem to care that sampling is on the diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c index 35067e1e6cd8..f5da7f9baa52 100644 --- a/drivers/mmc/host/mmci_stm32_sdmmc.c +++ b/drivers/mmc/host/mmci_stm32_sdmmc.c @@ -225,6 +225,8 @@ static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl)  	struct scatterlist *sg;  	int i; +	host->dma_in_progress = true; +  	if (!host->variant->dma_lli || data->sg_len == 1 ||  	    idma->use_bounce_buffer) {  		u32 dma_addr; @@ -263,9 +265,30 @@ static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl)  	return 0;  } +static void sdmmc_idma_error(struct mmci_host *host) +{ +	struct mmc_data *data = host->data; +	struct sdmmc_idma *idma = host->dma_priv; + +	if (!dma_inprogress(host)) +		return; + +	writel_relaxed(0, host->base + MMCI_STM32_IDMACTRLR); +	host->dma_in_progress = false; +	data->host_cookie = 0; + +	if (!idma->use_bounce_buffer) +		dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, +			     mmc_get_dma_dir(data)); +} +  static void sdmmc_idma_finalize(struct mmci_host *host, struct mmc_data *data)  { +	if (!dma_inprogress(host)) +		return; +  	writel_relaxed(0, host->base + MMCI_STM32_IDMACTRLR); +	host->dma_in_progress = false;  	if (!data->host_cookie)  		sdmmc_idma_unprep_data(host, data, 0); @@ -676,6 +699,7 @@ static struct mmci_host_ops sdmmc_variant_ops = {  	.dma_setup = sdmmc_idma_setup,  	.dma_start = sdmmc_idma_start,  	.dma_finalize = sdmmc_idma_finalize, +	.dma_error = sdmmc_idma_error,  	.set_clkreg = mmci_sdmmc_set_clkreg,  	.set_pwrreg = mmci_sdmmc_set_pwrreg,  	.busy_complete = sdmmc_busy_complete, diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c index 5cfdd3a86e54..b88d6dec209f 100644 --- a/drivers/mmc/host/moxart-mmc.c +++ b/drivers/mmc/host/moxart-mmc.c @@ -131,12 +131,10 @@ struct moxart_host {  	struct dma_async_tx_descriptor	*tx_desc;  	struct mmc_host			*mmc;  	struct mmc_request		*mrq; -	struct scatterlist		*cur_sg;  	struct completion		dma_complete;  	struct completion		pio_complete; -	u32				num_sg; -	u32				data_remain; +	struct sg_mapping_iter		sg_miter;  	u32				data_len;  	u32				fifo_width;  	u32				timeout; @@ -148,35 +146,6 @@ struct moxart_host {  	bool				is_removed;  }; -static inline void moxart_init_sg(struct moxart_host *host, -				  struct mmc_data *data) -{ -	host->cur_sg = data->sg; -	host->num_sg = data->sg_len; -	host->data_remain = host->cur_sg->length; - -	if (host->data_remain > host->data_len) -		host->data_remain = host->data_len; -} - -static inline int moxart_next_sg(struct moxart_host *host) -{ -	int remain; -	struct mmc_data *data = host->mrq->cmd->data; - -	host->cur_sg++; -	host->num_sg--; - -	if (host->num_sg > 0) { -		host->data_remain = host->cur_sg->length; -		remain = host->data_len - data->bytes_xfered; -		if (remain > 0 && remain < host->data_remain) -			host->data_remain = remain; -	} - -	return host->num_sg; -} -  static int moxart_wait_for_status(struct moxart_host *host,  				  u32 mask, u32 *status)  { @@ -254,6 +223,11 @@ static void moxart_dma_complete(void *param)  	complete(&host->dma_complete);  } +static bool moxart_use_dma(struct moxart_host *host) +{ +	return (host->data_len > host->fifo_width) && host->have_dma; +} +  static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host)  {  	u32 len, dir_slave; @@ -291,11 +265,11 @@ static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host)  		dma_async_issue_pending(dma_chan);  	} -	data->bytes_xfered += host->data_remain; -  	wait_for_completion_interruptible_timeout(&host->dma_complete,  						  host->timeout); +	data->bytes_xfered = host->data_len; +  	dma_unmap_sg(dma_chan->device->dev,  		     data->sg, data->sg_len,  		     mmc_get_dma_dir(data)); @@ -304,14 +278,28 @@ static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host)  static void moxart_transfer_pio(struct moxart_host *host)  { +	struct sg_mapping_iter *sgm = &host->sg_miter;  	struct mmc_data *data = host->mrq->cmd->data;  	u32 *sgp, len = 0, remain, status;  	if (host->data_len == data->bytes_xfered)  		return; -	sgp = sg_virt(host->cur_sg); -	remain = host->data_remain; +	/* +	 * By updating sgm->consumes this will get a proper pointer into the +	 * buffer at any time. +	 */ +	if (!sg_miter_next(sgm)) { +		/* This shold not happen */ +		dev_err(mmc_dev(host->mmc), "ran out of scatterlist prematurely\n"); +		data->error = -EINVAL; +		complete(&host->pio_complete); +		return; +	} +	sgp = sgm->addr; +	remain = sgm->length; +	if (remain > host->data_len) +		remain = host->data_len;  	if (data->flags & MMC_DATA_WRITE) {  		while (remain > 0) { @@ -326,6 +314,7 @@ static void moxart_transfer_pio(struct moxart_host *host)  				sgp++;  				len += 4;  			} +			sgm->consumed += len;  			remain -= len;  		} @@ -342,22 +331,22 @@ static void moxart_transfer_pio(struct moxart_host *host)  				sgp++;  				len += 4;  			} +			sgm->consumed += len;  			remain -= len;  		}  	} -	data->bytes_xfered += host->data_remain - remain; -	host->data_remain = remain; - -	if (host->data_len != data->bytes_xfered) -		moxart_next_sg(host); -	else +	data->bytes_xfered += sgm->consumed; +	if (host->data_len == data->bytes_xfered) {  		complete(&host->pio_complete); +		return; +	}  }  static void moxart_prepare_data(struct moxart_host *host)  {  	struct mmc_data *data = host->mrq->cmd->data; +	unsigned int flags = SG_MITER_ATOMIC; /* Used from IRQ */  	u32 datactrl;  	int blksz_bits; @@ -368,15 +357,19 @@ static void moxart_prepare_data(struct moxart_host *host)  	blksz_bits = ffs(data->blksz) - 1;  	BUG_ON(1 << blksz_bits != data->blksz); -	moxart_init_sg(host, data); -  	datactrl = DCR_DATA_EN | (blksz_bits & DCR_BLK_SIZE); -	if (data->flags & MMC_DATA_WRITE) +	if (data->flags & MMC_DATA_WRITE) { +		flags |= SG_MITER_FROM_SG;  		datactrl |= DCR_DATA_WRITE; +	} else { +		flags |= SG_MITER_TO_SG; +	} -	if ((host->data_len > host->fifo_width) && host->have_dma) +	if (moxart_use_dma(host))  		datactrl |= DCR_DMA_EN; +	else +		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);  	writel(DCR_DATA_FIFO_RESET, host->base + REG_DATA_CONTROL);  	writel(MASK_DATA | FIFO_URUN | FIFO_ORUN, host->base + REG_CLEAR); @@ -407,7 +400,7 @@ static void moxart_request(struct mmc_host *mmc, struct mmc_request *mrq)  	moxart_send_command(host, host->mrq->cmd);  	if (mrq->cmd->data) { -		if ((host->data_len > host->fifo_width) && host->have_dma) { +		if (moxart_use_dma(host)) {  			writel(CARD_CHANGE, host->base + REG_INTERRUPT_MASK); @@ -449,6 +442,9 @@ static void moxart_request(struct mmc_host *mmc, struct mmc_request *mrq)  	}  request_done: +	if (!moxart_use_dma(host)) +		sg_miter_stop(&host->sg_miter); +  	spin_unlock_irqrestore(&host->lock, flags);  	mmc_request_done(host->mmc, mrq);  } diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index ca01b7d204ba..af7f21888e27 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -38,8 +38,9 @@ struct mvsd_host {  	unsigned int xfer_mode;  	unsigned int intr_en;  	unsigned int ctrl; +	bool use_pio; +	struct sg_mapping_iter sg_miter;  	unsigned int pio_size; -	void *pio_ptr;  	unsigned int sg_frags;  	unsigned int ns_per_clk;  	unsigned int clock; @@ -114,11 +115,18 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data)  		 * data when the buffer is not aligned on a 64 byte  		 * boundary.  		 */ +		unsigned int miter_flags = SG_MITER_ATOMIC; /* Used from IRQ */ + +		if (data->flags & MMC_DATA_READ) +			miter_flags |= SG_MITER_TO_SG; +		else +			miter_flags |= SG_MITER_FROM_SG; +  		host->pio_size = data->blocks * data->blksz; -		host->pio_ptr = sg_virt(data->sg); +		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, miter_flags);  		if (!nodma) -			dev_dbg(host->dev, "fallback to PIO for data at 0x%p size %d\n", -				host->pio_ptr, host->pio_size); +			dev_dbg(host->dev, "fallback to PIO for data\n"); +		host->use_pio = true;  		return 1;  	} else {  		dma_addr_t phys_addr; @@ -129,6 +137,7 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data)  		phys_addr = sg_dma_address(data->sg);  		mvsd_write(MVSD_SYS_ADDR_LOW, (u32)phys_addr & 0xffff);  		mvsd_write(MVSD_SYS_ADDR_HI,  (u32)phys_addr >> 16); +		host->use_pio = false;  		return 0;  	}  } @@ -288,8 +297,8 @@ static u32 mvsd_finish_data(struct mvsd_host *host, struct mmc_data *data,  {  	void __iomem *iobase = host->base; -	if (host->pio_ptr) { -		host->pio_ptr = NULL; +	if (host->use_pio) { +		sg_miter_stop(&host->sg_miter);  		host->pio_size = 0;  	} else {  		dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_frags, @@ -344,9 +353,12 @@ static u32 mvsd_finish_data(struct mvsd_host *host, struct mmc_data *data,  static irqreturn_t mvsd_irq(int irq, void *dev)  {  	struct mvsd_host *host = dev; +	struct sg_mapping_iter *sgm = &host->sg_miter;  	void __iomem *iobase = host->base;  	u32 intr_status, intr_done_mask;  	int irq_handled = 0; +	u16 *p; +	int s;  	intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);  	dev_dbg(host->dev, "intr 0x%04x intr_en 0x%04x hw_state 0x%04x\n", @@ -370,15 +382,36 @@ static irqreturn_t mvsd_irq(int irq, void *dev)  	spin_lock(&host->lock);  	/* PIO handling, if needed. Messy business... */ -	if (host->pio_size && +	if (host->use_pio) { +		/* +		 * As we set sgm->consumed this always gives a valid buffer +		 * position. +		 */ +		if (!sg_miter_next(sgm)) { +			/* This should not happen */ +			dev_err(host->dev, "ran out of scatter segments\n"); +			spin_unlock(&host->lock); +			host->intr_en &= +				~(MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W | +				  MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W); +			mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); +			return IRQ_HANDLED; +		} +		p = sgm->addr; +		s = sgm->length; +		if (s > host->pio_size) +			s = host->pio_size; +	} + +	if (host->use_pio &&  	    (intr_status & host->intr_en &  	     (MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W))) { -		u16 *p = host->pio_ptr; -		int s = host->pio_size; +  		while (s >= 32 && (intr_status & MVSD_NOR_RX_FIFO_8W)) {  			readsw(iobase + MVSD_FIFO, p, 16);  			p += 16;  			s -= 32; +			sgm->consumed += 32;  			intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);  		}  		/* @@ -391,6 +424,7 @@ static irqreturn_t mvsd_irq(int irq, void *dev)  				put_unaligned(mvsd_read(MVSD_FIFO), p++);  				put_unaligned(mvsd_read(MVSD_FIFO), p++);  				s -= 4; +				sgm->consumed += 4;  				intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);  			}  			if (s && s < 4 && (intr_status & MVSD_NOR_RX_READY)) { @@ -398,10 +432,13 @@ static irqreturn_t mvsd_irq(int irq, void *dev)  				val[0] = mvsd_read(MVSD_FIFO);  				val[1] = mvsd_read(MVSD_FIFO);  				memcpy(p, ((void *)&val) + 4 - s, s); +				sgm->consumed += s;  				s = 0;  				intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);  			} -			if (s == 0) { +			/* PIO transfer done */ +			host->pio_size -= sgm->consumed; +			if (host->pio_size == 0) {  				host->intr_en &=  				     ~(MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W);  				mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); @@ -413,14 +450,10 @@ static irqreturn_t mvsd_irq(int irq, void *dev)  		}  		dev_dbg(host->dev, "pio %d intr 0x%04x hw_state 0x%04x\n",  			s, intr_status, mvsd_read(MVSD_HW_STATE)); -		host->pio_ptr = p; -		host->pio_size = s;  		irq_handled = 1; -	} else if (host->pio_size && +	} else if (host->use_pio &&  		   (intr_status & host->intr_en &  		    (MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W))) { -		u16 *p = host->pio_ptr; -		int s = host->pio_size;  		/*  		 * The TX_FIFO_8W bit is unreliable. When set, bursting  		 * 16 halfwords all at once in the FIFO drops data. Actually @@ -431,6 +464,7 @@ static irqreturn_t mvsd_irq(int irq, void *dev)  			mvsd_write(MVSD_FIFO, get_unaligned(p++));  			mvsd_write(MVSD_FIFO, get_unaligned(p++));  			s -= 4; +			sgm->consumed += 4;  			intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);  		}  		if (s < 4) { @@ -439,10 +473,13 @@ static irqreturn_t mvsd_irq(int irq, void *dev)  				memcpy(((void *)&val) + 4 - s, p, s);  				mvsd_write(MVSD_FIFO, val[0]);  				mvsd_write(MVSD_FIFO, val[1]); +				sgm->consumed += s;  				s = 0;  				intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);  			} -			if (s == 0) { +			/* PIO transfer done */ +			host->pio_size -= sgm->consumed; +			if (host->pio_size == 0) {  				host->intr_en &=  				     ~(MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W);  				mvsd_write(MVSD_NOR_INTR_EN, host->intr_en); @@ -450,8 +487,6 @@ static irqreturn_t mvsd_irq(int irq, void *dev)  		}  		dev_dbg(host->dev, "pio %d intr 0x%04x hw_state 0x%04x\n",  			s, intr_status, mvsd_read(MVSD_HW_STATE)); -		host->pio_ptr = p; -		host->pio_size = s;  		irq_handled = 1;  	} diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 5b3ab0e20505..1edf65291354 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -266,11 +266,18 @@ static inline void buffer_swap32(u32 *buf, int len)  static void mxcmci_swap_buffers(struct mmc_data *data)  { -	struct scatterlist *sg; -	int i; +	struct sg_mapping_iter sgm; +	u32 *buf; + +	sg_miter_start(&sgm, data->sg, data->sg_len, +		       SG_MITER_TO_SG | SG_MITER_FROM_SG); + +	while (sg_miter_next(&sgm)) { +		buf = sgm.addr; +		buffer_swap32(buf, sgm.length); +	} -	for_each_sg(data->sg, sg, data->sg_len, i) -		buffer_swap32(sg_virt(sg), sg->length); +	sg_miter_stop(&sgm);  }  #else  static inline void mxcmci_swap_buffers(struct mmc_data *data) {} @@ -526,10 +533,9 @@ static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask)  	} while (1);  } -static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes) +static int mxcmci_pull(struct mxcmci_host *host, u32 *buf, int bytes)  {  	unsigned int stat; -	u32 *buf = _buf;  	while (bytes > 3) {  		stat = mxcmci_poll_status(host, @@ -555,10 +561,9 @@ static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes)  	return 0;  } -static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes) +static int mxcmci_push(struct mxcmci_host *host, u32 *buf, int bytes)  {  	unsigned int stat; -	u32 *buf = _buf;  	while (bytes > 3) {  		stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); @@ -586,31 +591,39 @@ static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes)  static int mxcmci_transfer_data(struct mxcmci_host *host)  {  	struct mmc_data *data = host->req->data; -	struct scatterlist *sg; -	int stat, i; +	struct sg_mapping_iter sgm; +	int stat; +	u32 *buf;  	host->data = data;  	host->datasize = 0; +	sg_miter_start(&sgm, data->sg, data->sg_len, +		       (data->flags & MMC_DATA_READ) ? SG_MITER_TO_SG : SG_MITER_FROM_SG);  	if (data->flags & MMC_DATA_READ) { -		for_each_sg(data->sg, sg, data->sg_len, i) { -			stat = mxcmci_pull(host, sg_virt(sg), sg->length); +		while (sg_miter_next(&sgm)) { +			buf = sgm.addr; +			stat = mxcmci_pull(host, buf, sgm.length);  			if (stat) -				return stat; -			host->datasize += sg->length; +				goto transfer_error; +			host->datasize += sgm.length;  		}  	} else { -		for_each_sg(data->sg, sg, data->sg_len, i) { -			stat = mxcmci_push(host, sg_virt(sg), sg->length); +		while (sg_miter_next(&sgm)) { +			buf = sgm.addr; +			stat = mxcmci_push(host, buf, sgm.length);  			if (stat) -				return stat; -			host->datasize += sg->length; +				goto transfer_error; +			host->datasize += sgm.length;  		}  		stat = mxcmci_poll_status(host, STATUS_WRITE_OP_DONE);  		if (stat) -			return stat; +			goto transfer_error;  	} -	return 0; + +transfer_error: +	sg_miter_stop(&sgm); +	return stat;  }  static void mxcmci_datawork(struct work_struct *work) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 9fb8995b43a1..088f8ed4fdc4 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -148,10 +148,8 @@ struct mmc_omap_host {  	struct work_struct      send_stop_work;  	struct mmc_data		*stop_data; +	struct sg_mapping_iter	sg_miter;  	unsigned int		sg_len; -	int			sg_idx; -	u16 *			buffer; -	u32			buffer_bytes_left;  	u32			total_bytes_left;  	unsigned		features; @@ -456,6 +454,8 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)  {  	if (host->dma_in_use)  		mmc_omap_release_dma(host, data, data->error); +	else +		sg_miter_stop(&host->sg_miter);  	host->data = NULL;  	host->sg_len = 0; @@ -651,19 +651,6 @@ mmc_omap_cmd_timer(struct timer_list *t)  	spin_unlock_irqrestore(&host->slot_lock, flags);  } -/* PIO only */ -static void -mmc_omap_sg_to_buf(struct mmc_omap_host *host) -{ -	struct scatterlist *sg; - -	sg = host->data->sg + host->sg_idx; -	host->buffer_bytes_left = sg->length; -	host->buffer = sg_virt(sg); -	if (host->buffer_bytes_left > host->total_bytes_left) -		host->buffer_bytes_left = host->total_bytes_left; -} -  static void  mmc_omap_clk_timer(struct timer_list *t)  { @@ -676,33 +663,37 @@ mmc_omap_clk_timer(struct timer_list *t)  static void  mmc_omap_xfer_data(struct mmc_omap_host *host, int write)  { +	struct sg_mapping_iter *sgm = &host->sg_miter;  	int n, nwords; +	u16 *buffer; -	if (host->buffer_bytes_left == 0) { -		host->sg_idx++; -		BUG_ON(host->sg_idx == host->sg_len); -		mmc_omap_sg_to_buf(host); +	if (!sg_miter_next(sgm)) { +		/* This should not happen */ +		dev_err(mmc_dev(host->mmc), "ran out of scatterlist prematurely\n"); +		return;  	} +	buffer = sgm->addr; +  	n = 64; -	if (n > host->buffer_bytes_left) -		n = host->buffer_bytes_left; +	if (n > sgm->length) +		n = sgm->length; +	if (n > host->total_bytes_left) +		n = host->total_bytes_left;  	/* Round up to handle odd number of bytes to transfer */  	nwords = DIV_ROUND_UP(n, 2); -	host->buffer_bytes_left -= n; +	sgm->consumed = n;  	host->total_bytes_left -= n;  	host->data->bytes_xfered += n;  	if (write) {  		__raw_writesw(host->virt_base + OMAP_MMC_REG(host, DATA), -			      host->buffer, nwords); +			      buffer, nwords);  	} else {  		__raw_readsw(host->virt_base + OMAP_MMC_REG(host, DATA), -			     host->buffer, nwords); +			     buffer, nwords);  	} - -	host->buffer += nwords;  }  #ifdef CONFIG_MMC_DEBUG @@ -956,6 +947,7 @@ static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_reque  static void  mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)  { +	unsigned int miter_flags = SG_MITER_ATOMIC; /* Used from IRQ */  	struct mmc_data *data = req->data;  	int i, use_dma = 1, block_size;  	struct scatterlist *sg; @@ -990,7 +982,6 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)  		}  	} -	host->sg_idx = 0;  	if (use_dma) {  		enum dma_data_direction dma_data_dir;  		struct dma_async_tx_descriptor *tx; @@ -1071,7 +1062,11 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)  	OMAP_MMC_WRITE(host, BUF, 0x1f1f);  	host->total_bytes_left = data->blocks * block_size;  	host->sg_len = sg_len; -	mmc_omap_sg_to_buf(host); +	if (data->flags & MMC_DATA_READ) +		miter_flags |= SG_MITER_TO_SG; +	else +		miter_flags |= SG_MITER_FROM_SG; +	sg_miter_start(&host->sg_miter, data->sg, data->sg_len, miter_flags);  	host->dma_in_use = 0;  } diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index c1fb9740eab0..586f94d4dbfd 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -9,6 +9,7 @@  #ifndef RENESAS_SDHI_H  #define RENESAS_SDHI_H +#include <linux/dmaengine.h>  #include <linux/platform_device.h>  #include "tmio_mmc.h" @@ -63,7 +64,7 @@ struct renesas_sdhi_of_data_with_quirks {  struct renesas_sdhi_dma {  	unsigned long end_flags;  	enum dma_slave_buswidth dma_buswidth; -	bool (*filter)(struct dma_chan *chan, void *arg); +	dma_filter_fn filter;  	void (*enable)(struct tmio_mmc_host *host, bool enable);  	struct completion dma_dataend;  	struct tasklet_struct dma_complete; diff --git a/drivers/mmc/host/sdhci-esdhc-mcf.c b/drivers/mmc/host/sdhci-esdhc-mcf.c index a07f8333cd6b..c97363e2d86c 100644 --- a/drivers/mmc/host/sdhci-esdhc-mcf.c +++ b/drivers/mmc/host/sdhci-esdhc-mcf.c @@ -299,9 +299,8 @@ static void esdhc_mcf_pltfm_set_bus_width(struct sdhci_host *host, int width)  static void esdhc_mcf_request_done(struct sdhci_host *host,  				   struct mmc_request *mrq)  { -	struct scatterlist *sg; +	struct sg_mapping_iter sgm;  	u32 *buffer; -	int i;  	if (!mrq->data || !mrq->data->bytes_xfered)  		goto exit_done; @@ -313,10 +312,13 @@ static void esdhc_mcf_request_done(struct sdhci_host *host,  	 * On mcf5441x there is no hw sdma option/flag to select the dma  	 * transfer endiannes. A swap after the transfer is needed.  	 */ -	for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i) { -		buffer = (u32 *)sg_virt(sg); -		esdhc_mcf_buffer_swap32(buffer, sg->length); +	sg_miter_start(&sgm, mrq->data->sg, mrq->data->sg_len, +		       SG_MITER_ATOMIC | SG_MITER_TO_SG | SG_MITER_FROM_SG); +	while (sg_miter_next(&sgm)) { +		buffer = sgm.addr; +		esdhc_mcf_buffer_swap32(buffer, sgm.length);  	} +	sg_miter_stop(&sgm);  exit_done:  	mmc_request_done(host->mmc, mrq); diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c index 42d54532cabe..430c1f90037b 100644 --- a/drivers/mmc/host/sdhci-of-aspeed.c +++ b/drivers/mmc/host/sdhci-of-aspeed.c @@ -435,7 +435,7 @@ static int aspeed_sdhci_probe(struct platform_device *pdev)  		goto err_sdhci_add;  	if (dev->phase_desc) -		mmc_of_parse_clk_phase(host->mmc, &dev->phase_map); +		mmc_of_parse_clk_phase(&pdev->dev, &dev->phase_map);  	ret = sdhci_add_host(host);  	if (ret) diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index a1f57af6acfb..ab4b964d4058 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -52,6 +52,20 @@  #define AT_CTRL_SWIN_TH_VAL_MASK	GENMASK(31, 24) /* bits [31:24] */  #define AT_CTRL_SWIN_TH_VAL		0x9  /* sampling window threshold */ +/* Sophgo CV18XX specific Registers */ +#define CV18XX_SDHCI_MSHC_CTRL			0x00 +#define  CV18XX_EMMC_FUNC_EN			BIT(0) +#define  CV18XX_LATANCY_1T			BIT(1) +#define CV18XX_SDHCI_PHY_TX_RX_DLY		0x40 +#define  CV18XX_PHY_TX_DLY_MSK			GENMASK(6, 0) +#define  CV18XX_PHY_TX_SRC_MSK			GENMASK(9, 8) +#define  CV18XX_PHY_TX_SRC_INVERT_CLK_TX	0x1 +#define  CV18XX_PHY_RX_DLY_MSK			GENMASK(22, 16) +#define  CV18XX_PHY_RX_SRC_MSK			GENMASK(25, 24) +#define  CV18XX_PHY_RX_SRC_INVERT_RX_CLK	0x1 +#define CV18XX_SDHCI_PHY_CONFIG			0x4c +#define  CV18XX_PHY_TX_BPS			BIT(0) +  /* Rockchip specific Registers */  #define DWCMSHC_EMMC_DLL_CTRL		0x800  #define DWCMSHC_EMMC_DLL_RXCLK		0x804 @@ -642,6 +656,35 @@ static void th1520_sdhci_reset(struct sdhci_host *host, u8 mask)  	}  } +static void cv18xx_sdhci_reset(struct sdhci_host *host, u8 mask) +{ +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); +	u32 val, emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO; + +	sdhci_reset(host, mask); + +	if ((host->mmc->caps2 & emmc_caps) == emmc_caps) { +		val = sdhci_readl(host, priv->vendor_specific_area1 + CV18XX_SDHCI_MSHC_CTRL); +		val |= CV18XX_EMMC_FUNC_EN; +		sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_MSHC_CTRL); +	} + +	val = sdhci_readl(host, priv->vendor_specific_area1 + CV18XX_SDHCI_MSHC_CTRL); +	val |= CV18XX_LATANCY_1T; +	sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_MSHC_CTRL); + +	val = sdhci_readl(host, priv->vendor_specific_area1 + CV18XX_SDHCI_PHY_CONFIG); +	val |= CV18XX_PHY_TX_BPS; +	sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_PHY_CONFIG); + +	val =  (FIELD_PREP(CV18XX_PHY_TX_DLY_MSK, 0) | +		FIELD_PREP(CV18XX_PHY_TX_SRC_MSK, CV18XX_PHY_TX_SRC_INVERT_CLK_TX) | +		FIELD_PREP(CV18XX_PHY_RX_DLY_MSK, 0) | +		FIELD_PREP(CV18XX_PHY_RX_SRC_MSK, CV18XX_PHY_RX_SRC_INVERT_RX_CLK)); +	sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_PHY_TX_RX_DLY); +} +  static const struct sdhci_ops sdhci_dwcmshc_ops = {  	.set_clock		= sdhci_set_clock,  	.set_bus_width		= sdhci_set_bus_width, @@ -671,6 +714,15 @@ static const struct sdhci_ops sdhci_dwcmshc_th1520_ops = {  	.platform_execute_tuning = &th1520_execute_tuning,  }; +static const struct sdhci_ops sdhci_dwcmshc_cv18xx_ops = { +	.set_clock		= sdhci_set_clock, +	.set_bus_width		= sdhci_set_bus_width, +	.set_uhs_signaling	= dwcmshc_set_uhs_signaling, +	.get_max_clock		= dwcmshc_get_max_clock, +	.reset			= cv18xx_sdhci_reset, +	.adma_write_desc	= dwcmshc_adma_write_desc, +}; +  static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {  	.ops = &sdhci_dwcmshc_ops,  	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, @@ -700,6 +752,12 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_th1520_pdata = {  	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,  }; +static const struct sdhci_pltfm_data sdhci_dwcmshc_cv18xx_pdata = { +	.ops = &sdhci_dwcmshc_cv18xx_ops, +	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, +	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, +}; +  static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)  {  	int err; @@ -769,6 +827,14 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {  		.data = &sdhci_dwcmshc_pdata,  	},  	{ +		.compatible = "sophgo,cv1800b-dwcmshc", +		.data = &sdhci_dwcmshc_cv18xx_pdata, +	}, +	{ +		.compatible = "sophgo,sg2002-dwcmshc", +		.data = &sdhci_dwcmshc_cv18xx_pdata, +	}, +	{  		.compatible = "thead,th1520-dwcmshc",  		.data = &sdhci_dwcmshc_th1520_pdata,  	}, diff --git a/drivers/mmc/host/sdhci-xenon-phy.c b/drivers/mmc/host/sdhci-xenon-phy.c index 8cf3a375de65..cc9d28b75eb9 100644 --- a/drivers/mmc/host/sdhci-xenon-phy.c +++ b/drivers/mmc/host/sdhci-xenon-phy.c @@ -11,6 +11,7 @@  #include <linux/slab.h>  #include <linux/delay.h>  #include <linux/ktime.h> +#include <linux/iopoll.h>  #include <linux/of_address.h>  #include "sdhci-pltfm.h" @@ -109,6 +110,8 @@  #define XENON_EMMC_PHY_LOGIC_TIMING_ADJUST	(XENON_EMMC_PHY_REG_BASE + 0x18)  #define XENON_LOGIC_TIMING_VALUE		0x00AA8977 +#define XENON_MAX_PHY_TIMEOUT_LOOPS		100 +  /*   * List offset of PHY registers and some special register values   * in eMMC PHY 5.0 or eMMC PHY 5.1 @@ -216,6 +219,19 @@ static int xenon_alloc_emmc_phy(struct sdhci_host *host)  	return 0;  } +static int xenon_check_stability_internal_clk(struct sdhci_host *host) +{ +	u32 reg; +	int err; + +	err = read_poll_timeout(sdhci_readw, reg, reg & SDHCI_CLOCK_INT_STABLE, +				1100, 20000, false, host, SDHCI_CLOCK_CONTROL); +	if (err) +		dev_err(mmc_dev(host->mmc), "phy_init: Internal clock never stabilized.\n"); + +	return err; +} +  /*   * eMMC 5.0/5.1 PHY init/re-init.   * eMMC PHY init should be executed after: @@ -232,6 +248,11 @@ static int xenon_emmc_phy_init(struct sdhci_host *host)  	struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);  	struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; +	int ret = xenon_check_stability_internal_clk(host); + +	if (ret) +		return ret; +  	reg = sdhci_readl(host, phy_regs->timing_adj);  	reg |= XENON_PHY_INITIALIZAION;  	sdhci_writel(host, reg, phy_regs->timing_adj); @@ -259,18 +280,27 @@ static int xenon_emmc_phy_init(struct sdhci_host *host)  	/* get the wait time */  	wait /= clock;  	wait++; -	/* wait for host eMMC PHY init completes */ -	udelay(wait); -	reg = sdhci_readl(host, phy_regs->timing_adj); -	reg &= XENON_PHY_INITIALIZAION; -	if (reg) { +	/* +	 * AC5X spec says bit must be polled until zero. +	 * We see cases in which timeout can take longer +	 * than the standard calculation on AC5X, which is +	 * expected following the spec comment above. +	 * According to the spec, we must wait as long as +	 * it takes for that bit to toggle on AC5X. +	 * Cap that with 100 delay loops so we won't get +	 * stuck here forever: +	 */ + +	ret = read_poll_timeout(sdhci_readl, reg, +				!(reg & XENON_PHY_INITIALIZAION), +				wait, XENON_MAX_PHY_TIMEOUT_LOOPS * wait, +				false, host, phy_regs->timing_adj); +	if (ret)  		dev_err(mmc_dev(host->mmc), "eMMC PHY init cannot complete after %d us\n", -			wait); -		return -ETIMEDOUT; -	} +			wait * XENON_MAX_PHY_TIMEOUT_LOOPS); -	return 0; +	return ret;  }  #define ARMADA_3700_SOC_PAD_1_8V	0x1 diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 077d711e964e..08b4312af94e 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -227,14 +227,12 @@ struct sh_mmcif_host {  	bool dying;  	long timeout;  	void __iomem *addr; -	u32 *pio_ptr;  	spinlock_t lock;		/* protect sh_mmcif_host::state */  	enum sh_mmcif_state state;  	enum sh_mmcif_wait_for wait_for;  	struct delayed_work timeout_work;  	size_t blocksize; -	int sg_idx; -	int sg_blkidx; +	struct sg_mapping_iter sg_miter;  	bool power;  	bool ccs_enable;		/* Command Completion Signal support */  	bool clk_ctrl2_enable; @@ -600,32 +598,17 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)  	return ret;  } -static bool sh_mmcif_next_block(struct sh_mmcif_host *host, u32 *p) -{ -	struct mmc_data *data = host->mrq->data; - -	host->sg_blkidx += host->blocksize; - -	/* data->sg->length must be a multiple of host->blocksize? */ -	BUG_ON(host->sg_blkidx > data->sg->length); - -	if (host->sg_blkidx == data->sg->length) { -		host->sg_blkidx = 0; -		if (++host->sg_idx < data->sg_len) -			host->pio_ptr = sg_virt(++data->sg); -	} else { -		host->pio_ptr = p; -	} - -	return host->sg_idx != data->sg_len; -} -  static void sh_mmcif_single_read(struct sh_mmcif_host *host,  				 struct mmc_request *mrq)  { +	struct mmc_data *data = mrq->data; +  	host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &  			   BLOCK_SIZE_MASK) + 3; +	sg_miter_start(&host->sg_miter, data->sg, data->sg_len, +		       SG_MITER_TO_SG); +  	host->wait_for = MMCIF_WAIT_FOR_READ;  	/* buf read enable */ @@ -634,20 +617,32 @@ static void sh_mmcif_single_read(struct sh_mmcif_host *host,  static bool sh_mmcif_read_block(struct sh_mmcif_host *host)  { +	struct sg_mapping_iter *sgm = &host->sg_miter;  	struct device *dev = sh_mmcif_host_to_dev(host);  	struct mmc_data *data = host->mrq->data; -	u32 *p = sg_virt(data->sg); +	u32 *p;  	int i;  	if (host->sd_error) { +		sg_miter_stop(sgm);  		data->error = sh_mmcif_error_manage(host);  		dev_dbg(dev, "%s(): %d\n", __func__, data->error);  		return false;  	} +	if (!sg_miter_next(sgm)) { +		/* This should not happen on single blocks */ +		sg_miter_stop(sgm); +		return false; +	} + +	p = sgm->addr; +  	for (i = 0; i < host->blocksize / 4; i++)  		*p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); +	sg_miter_stop(&host->sg_miter); +  	/* buffer read end */  	sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);  	host->wait_for = MMCIF_WAIT_FOR_READ_END; @@ -658,6 +653,7 @@ static bool sh_mmcif_read_block(struct sh_mmcif_host *host)  static void sh_mmcif_multi_read(struct sh_mmcif_host *host,  				struct mmc_request *mrq)  { +	struct sg_mapping_iter *sgm = &host->sg_miter;  	struct mmc_data *data = mrq->data;  	if (!data->sg_len || !data->sg->length) @@ -666,46 +662,63 @@ static void sh_mmcif_multi_read(struct sh_mmcif_host *host,  	host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &  		BLOCK_SIZE_MASK; +	sg_miter_start(sgm, data->sg, data->sg_len, +		       SG_MITER_TO_SG); + +	/* Advance to the first sglist entry */ +	if (!sg_miter_next(sgm)) { +		sg_miter_stop(sgm); +		return; +	} +  	host->wait_for = MMCIF_WAIT_FOR_MREAD; -	host->sg_idx = 0; -	host->sg_blkidx = 0; -	host->pio_ptr = sg_virt(data->sg);  	sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);  }  static bool sh_mmcif_mread_block(struct sh_mmcif_host *host)  { +	struct sg_mapping_iter *sgm = &host->sg_miter;  	struct device *dev = sh_mmcif_host_to_dev(host);  	struct mmc_data *data = host->mrq->data; -	u32 *p = host->pio_ptr; +	u32 *p;  	int i;  	if (host->sd_error) { +		sg_miter_stop(sgm);  		data->error = sh_mmcif_error_manage(host);  		dev_dbg(dev, "%s(): %d\n", __func__, data->error);  		return false;  	} -	BUG_ON(!data->sg->length); +	p = sgm->addr;  	for (i = 0; i < host->blocksize / 4; i++)  		*p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); -	if (!sh_mmcif_next_block(host, p)) -		return false; +	sgm->consumed = host->blocksize;  	sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); +	if (!sg_miter_next(sgm)) { +		sg_miter_stop(sgm); +		return false; +	} +  	return true;  }  static void sh_mmcif_single_write(struct sh_mmcif_host *host,  					struct mmc_request *mrq)  { +	struct mmc_data *data = mrq->data; +  	host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &  			   BLOCK_SIZE_MASK) + 3; +	sg_miter_start(&host->sg_miter, data->sg, data->sg_len, +		       SG_MITER_FROM_SG); +  	host->wait_for = MMCIF_WAIT_FOR_WRITE;  	/* buf write enable */ @@ -714,20 +727,32 @@ static void sh_mmcif_single_write(struct sh_mmcif_host *host,  static bool sh_mmcif_write_block(struct sh_mmcif_host *host)  { +	struct sg_mapping_iter *sgm = &host->sg_miter;  	struct device *dev = sh_mmcif_host_to_dev(host);  	struct mmc_data *data = host->mrq->data; -	u32 *p = sg_virt(data->sg); +	u32 *p;  	int i;  	if (host->sd_error) { +		sg_miter_stop(sgm);  		data->error = sh_mmcif_error_manage(host);  		dev_dbg(dev, "%s(): %d\n", __func__, data->error);  		return false;  	} +	if (!sg_miter_next(sgm)) { +		/* This should not happen on single blocks */ +		sg_miter_stop(sgm); +		return false; +	} + +	p = sgm->addr; +  	for (i = 0; i < host->blocksize / 4; i++)  		sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++); +	sg_miter_stop(&host->sg_miter); +  	/* buffer write end */  	sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);  	host->wait_for = MMCIF_WAIT_FOR_WRITE_END; @@ -738,6 +763,7 @@ static bool sh_mmcif_write_block(struct sh_mmcif_host *host)  static void sh_mmcif_multi_write(struct sh_mmcif_host *host,  				struct mmc_request *mrq)  { +	struct sg_mapping_iter *sgm = &host->sg_miter;  	struct mmc_data *data = mrq->data;  	if (!data->sg_len || !data->sg->length) @@ -746,34 +772,46 @@ static void sh_mmcif_multi_write(struct sh_mmcif_host *host,  	host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &  		BLOCK_SIZE_MASK; +	sg_miter_start(sgm, data->sg, data->sg_len, +		       SG_MITER_FROM_SG); + +	/* Advance to the first sglist entry */ +	if (!sg_miter_next(sgm)) { +		sg_miter_stop(sgm); +		return; +	} +  	host->wait_for = MMCIF_WAIT_FOR_MWRITE; -	host->sg_idx = 0; -	host->sg_blkidx = 0; -	host->pio_ptr = sg_virt(data->sg);  	sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);  }  static bool sh_mmcif_mwrite_block(struct sh_mmcif_host *host)  { +	struct sg_mapping_iter *sgm = &host->sg_miter;  	struct device *dev = sh_mmcif_host_to_dev(host);  	struct mmc_data *data = host->mrq->data; -	u32 *p = host->pio_ptr; +	u32 *p;  	int i;  	if (host->sd_error) { +		sg_miter_stop(sgm);  		data->error = sh_mmcif_error_manage(host);  		dev_dbg(dev, "%s(): %d\n", __func__, data->error);  		return false;  	} -	BUG_ON(!data->sg->length); +	p = sgm->addr;  	for (i = 0; i < host->blocksize / 4; i++)  		sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++); -	if (!sh_mmcif_next_block(host, p)) +	sgm->consumed = host->blocksize; + +	if (!sg_miter_next(sgm)) { +		sg_miter_stop(sgm);  		return false; +	}  	sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index be7f18fd4836..93e912afd3ae 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -259,6 +259,8 @@ static void tmio_mmc_reset_work(struct work_struct *work)  	else  		mrq->cmd->error = -ETIMEDOUT; +	/* No new calls yet, but disallow concurrent tmio_mmc_done_work() */ +	host->mrq = ERR_PTR(-EBUSY);  	host->cmd = NULL;  	host->data = NULL; @@ -970,6 +972,7 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  		return;  	} +	/* Disallow new mrqs and work handlers to run */  	host->mrq = ERR_PTR(-EBUSY);  	spin_unlock_irqrestore(&host->lock, flags); @@ -1004,8 +1007,9 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  			"%s.%d: IOS interrupted: clk %u, mode %u",  			current->comm, task_pid_nr(current),  			ios->clock, ios->power_mode); -	host->mrq = NULL; +	/* Ready for new mrqs */ +	host->mrq = NULL;  	host->clk_cache = ios->clock;  	mutex_unlock(&host->ios_lock); diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 001a468bc149..f0562f712d98 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -1284,8 +1284,6 @@ static int wbsd_scan(struct wbsd_host *host)  			continue;  		for (j = 0; j < ARRAY_SIZE(unlock_codes); j++) { -			id = 0xFFFF; -  			host->config = config_ports[i];  			host->unlock_code = unlock_codes[j]; diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index 77d5f1d24489..860380931b6c 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -883,7 +883,6 @@ static void wmt_mci_remove(struct platform_device *pdev)  {  	struct mmc_host *mmc;  	struct wmt_mci_priv *priv; -	struct resource *res;  	u32 reg_tmp;  	mmc = platform_get_drvdata(pdev); @@ -911,9 +910,6 @@ static void wmt_mci_remove(struct platform_device *pdev)  	clk_disable_unprepare(priv->clk_sdmmc);  	clk_put(priv->clk_sdmmc); -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	release_mem_region(res->start, resource_size(res)); -  	mmc_free_host(mmc);  	dev_info(&pdev->dev, "WMT MCI device removed\n"); |