xref: /linux/drivers/mmc/host/dw_mmc.c (revision 90c2143a8f6d0cd1dbae1ea32fcd1befb81e4b0d)
1f95f3850SWill Newton /*
2f95f3850SWill Newton  * Synopsys DesignWare Multimedia Card Interface driver
3f95f3850SWill Newton  *  (Based on NXP driver for lpc 31xx)
4f95f3850SWill Newton  *
5f95f3850SWill Newton  * Copyright (C) 2009 NXP Semiconductors
6f95f3850SWill Newton  * Copyright (C) 2009, 2010 Imagination Technologies Ltd.
7f95f3850SWill Newton  *
8f95f3850SWill Newton  * This program is free software; you can redistribute it and/or modify
9f95f3850SWill Newton  * it under the terms of the GNU General Public License as published by
10f95f3850SWill Newton  * the Free Software Foundation; either version 2 of the License, or
11f95f3850SWill Newton  * (at your option) any later version.
12f95f3850SWill Newton  */
13f95f3850SWill Newton 
14f95f3850SWill Newton #include <linux/blkdev.h>
15f95f3850SWill Newton #include <linux/clk.h>
16f95f3850SWill Newton #include <linux/debugfs.h>
17f95f3850SWill Newton #include <linux/device.h>
18f95f3850SWill Newton #include <linux/dma-mapping.h>
19f95f3850SWill Newton #include <linux/err.h>
20f95f3850SWill Newton #include <linux/init.h>
21f95f3850SWill Newton #include <linux/interrupt.h>
22f95f3850SWill Newton #include <linux/ioport.h>
23f95f3850SWill Newton #include <linux/module.h>
24f95f3850SWill Newton #include <linux/platform_device.h>
25f95f3850SWill Newton #include <linux/seq_file.h>
26f95f3850SWill Newton #include <linux/slab.h>
27f95f3850SWill Newton #include <linux/stat.h>
28f95f3850SWill Newton #include <linux/delay.h>
29f95f3850SWill Newton #include <linux/irq.h>
30f95f3850SWill Newton #include <linux/mmc/host.h>
31f95f3850SWill Newton #include <linux/mmc/mmc.h>
32*90c2143aSSeungwon Jeon #include <linux/mmc/sdio.h>
33f95f3850SWill Newton #include <linux/mmc/dw_mmc.h>
34f95f3850SWill Newton #include <linux/bitops.h>
35c07946a3SJaehoon Chung #include <linux/regulator/consumer.h>
361791b13eSJames Hogan #include <linux/workqueue.h>
37c91eab4bSThomas Abraham #include <linux/of.h>
3855a6ceb2SDoug Anderson #include <linux/of_gpio.h>
39f95f3850SWill Newton 
40f95f3850SWill Newton #include "dw_mmc.h"
41f95f3850SWill Newton 
42f95f3850SWill Newton /* Common flag combinations */
433f7eec62SJaehoon Chung #define DW_MCI_DATA_ERROR_FLAGS	(SDMMC_INT_DRTO | SDMMC_INT_DCRC | \
44f95f3850SWill Newton 				 SDMMC_INT_HTO | SDMMC_INT_SBE  | \
45f95f3850SWill Newton 				 SDMMC_INT_EBE)
46f95f3850SWill Newton #define DW_MCI_CMD_ERROR_FLAGS	(SDMMC_INT_RTO | SDMMC_INT_RCRC | \
47f95f3850SWill Newton 				 SDMMC_INT_RESP_ERR)
48f95f3850SWill Newton #define DW_MCI_ERROR_FLAGS	(DW_MCI_DATA_ERROR_FLAGS | \
49f95f3850SWill Newton 				 DW_MCI_CMD_ERROR_FLAGS  | SDMMC_INT_HLE)
50f95f3850SWill Newton #define DW_MCI_SEND_STATUS	1
51f95f3850SWill Newton #define DW_MCI_RECV_STATUS	2
52f95f3850SWill Newton #define DW_MCI_DMA_THRESHOLD	16
53f95f3850SWill Newton 
541f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MAX	200000000	/* unit: HZ */
551f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MIN	400000		/* unit: HZ */
561f44a2a5SSeungwon Jeon 
57f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
58fc79a4d6SJoonyoung Shim #define IDMAC_INT_CLR		(SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \
59fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \
60fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
61fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_TI)
62fc79a4d6SJoonyoung Shim 
63f95f3850SWill Newton struct idmac_desc {
64f95f3850SWill Newton 	u32		des0;	/* Control Descriptor */
65f95f3850SWill Newton #define IDMAC_DES0_DIC	BIT(1)
66f95f3850SWill Newton #define IDMAC_DES0_LD	BIT(2)
67f95f3850SWill Newton #define IDMAC_DES0_FD	BIT(3)
68f95f3850SWill Newton #define IDMAC_DES0_CH	BIT(4)
69f95f3850SWill Newton #define IDMAC_DES0_ER	BIT(5)
70f95f3850SWill Newton #define IDMAC_DES0_CES	BIT(30)
71f95f3850SWill Newton #define IDMAC_DES0_OWN	BIT(31)
72f95f3850SWill Newton 
73f95f3850SWill Newton 	u32		des1;	/* Buffer sizes */
74f95f3850SWill Newton #define IDMAC_SET_BUFFER1_SIZE(d, s) \
759b7bbe10SShashidhar Hiremath 	((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff))
76f95f3850SWill Newton 
77f95f3850SWill Newton 	u32		des2;	/* buffer 1 physical address */
78f95f3850SWill Newton 
79f95f3850SWill Newton 	u32		des3;	/* buffer 2 physical address */
80f95f3850SWill Newton };
81f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */
82f95f3850SWill Newton 
830976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_4bit[] = {
840976f16dSSeungwon Jeon 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
850976f16dSSeungwon Jeon 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
860976f16dSSeungwon Jeon 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
870976f16dSSeungwon Jeon 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
880976f16dSSeungwon Jeon 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
890976f16dSSeungwon Jeon 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
900976f16dSSeungwon Jeon 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
910976f16dSSeungwon Jeon 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
920976f16dSSeungwon Jeon };
93f95f3850SWill Newton 
940976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_8bit[] = {
950976f16dSSeungwon Jeon 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
960976f16dSSeungwon Jeon 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
970976f16dSSeungwon Jeon 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
980976f16dSSeungwon Jeon 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
990976f16dSSeungwon Jeon 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
1000976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
1010976f16dSSeungwon Jeon 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
1020976f16dSSeungwon Jeon 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
1030976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
1040976f16dSSeungwon Jeon 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
1050976f16dSSeungwon Jeon 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
1060976f16dSSeungwon Jeon 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
1070976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
1080976f16dSSeungwon Jeon 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
1090976f16dSSeungwon Jeon 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
1100976f16dSSeungwon Jeon 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
111f95f3850SWill Newton };
112f95f3850SWill Newton 
113f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS)
114f95f3850SWill Newton static int dw_mci_req_show(struct seq_file *s, void *v)
115f95f3850SWill Newton {
116f95f3850SWill Newton 	struct dw_mci_slot *slot = s->private;
117f95f3850SWill Newton 	struct mmc_request *mrq;
118f95f3850SWill Newton 	struct mmc_command *cmd;
119f95f3850SWill Newton 	struct mmc_command *stop;
120f95f3850SWill Newton 	struct mmc_data	*data;
121f95f3850SWill Newton 
122f95f3850SWill Newton 	/* Make sure we get a consistent snapshot */
123f95f3850SWill Newton 	spin_lock_bh(&slot->host->lock);
124f95f3850SWill Newton 	mrq = slot->mrq;
125f95f3850SWill Newton 
126f95f3850SWill Newton 	if (mrq) {
127f95f3850SWill Newton 		cmd = mrq->cmd;
128f95f3850SWill Newton 		data = mrq->data;
129f95f3850SWill Newton 		stop = mrq->stop;
130f95f3850SWill Newton 
131f95f3850SWill Newton 		if (cmd)
132f95f3850SWill Newton 			seq_printf(s,
133f95f3850SWill Newton 				   "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
134f95f3850SWill Newton 				   cmd->opcode, cmd->arg, cmd->flags,
135f95f3850SWill Newton 				   cmd->resp[0], cmd->resp[1], cmd->resp[2],
136f95f3850SWill Newton 				   cmd->resp[2], cmd->error);
137f95f3850SWill Newton 		if (data)
138f95f3850SWill Newton 			seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
139f95f3850SWill Newton 				   data->bytes_xfered, data->blocks,
140f95f3850SWill Newton 				   data->blksz, data->flags, data->error);
141f95f3850SWill Newton 		if (stop)
142f95f3850SWill Newton 			seq_printf(s,
143f95f3850SWill Newton 				   "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
144f95f3850SWill Newton 				   stop->opcode, stop->arg, stop->flags,
145f95f3850SWill Newton 				   stop->resp[0], stop->resp[1], stop->resp[2],
146f95f3850SWill Newton 				   stop->resp[2], stop->error);
147f95f3850SWill Newton 	}
148f95f3850SWill Newton 
149f95f3850SWill Newton 	spin_unlock_bh(&slot->host->lock);
150f95f3850SWill Newton 
151f95f3850SWill Newton 	return 0;
152f95f3850SWill Newton }
153f95f3850SWill Newton 
154f95f3850SWill Newton static int dw_mci_req_open(struct inode *inode, struct file *file)
155f95f3850SWill Newton {
156f95f3850SWill Newton 	return single_open(file, dw_mci_req_show, inode->i_private);
157f95f3850SWill Newton }
158f95f3850SWill Newton 
159f95f3850SWill Newton static const struct file_operations dw_mci_req_fops = {
160f95f3850SWill Newton 	.owner		= THIS_MODULE,
161f95f3850SWill Newton 	.open		= dw_mci_req_open,
162f95f3850SWill Newton 	.read		= seq_read,
163f95f3850SWill Newton 	.llseek		= seq_lseek,
164f95f3850SWill Newton 	.release	= single_release,
165f95f3850SWill Newton };
166f95f3850SWill Newton 
167f95f3850SWill Newton static int dw_mci_regs_show(struct seq_file *s, void *v)
168f95f3850SWill Newton {
169f95f3850SWill Newton 	seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS);
170f95f3850SWill Newton 	seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS);
171f95f3850SWill Newton 	seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD);
172f95f3850SWill Newton 	seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL);
173f95f3850SWill Newton 	seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK);
174f95f3850SWill Newton 	seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA);
175f95f3850SWill Newton 
176f95f3850SWill Newton 	return 0;
177f95f3850SWill Newton }
178f95f3850SWill Newton 
179f95f3850SWill Newton static int dw_mci_regs_open(struct inode *inode, struct file *file)
180f95f3850SWill Newton {
181f95f3850SWill Newton 	return single_open(file, dw_mci_regs_show, inode->i_private);
182f95f3850SWill Newton }
183f95f3850SWill Newton 
184f95f3850SWill Newton static const struct file_operations dw_mci_regs_fops = {
185f95f3850SWill Newton 	.owner		= THIS_MODULE,
186f95f3850SWill Newton 	.open		= dw_mci_regs_open,
187f95f3850SWill Newton 	.read		= seq_read,
188f95f3850SWill Newton 	.llseek		= seq_lseek,
189f95f3850SWill Newton 	.release	= single_release,
190f95f3850SWill Newton };
191f95f3850SWill Newton 
192f95f3850SWill Newton static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
193f95f3850SWill Newton {
194f95f3850SWill Newton 	struct mmc_host	*mmc = slot->mmc;
195f95f3850SWill Newton 	struct dw_mci *host = slot->host;
196f95f3850SWill Newton 	struct dentry *root;
197f95f3850SWill Newton 	struct dentry *node;
198f95f3850SWill Newton 
199f95f3850SWill Newton 	root = mmc->debugfs_root;
200f95f3850SWill Newton 	if (!root)
201f95f3850SWill Newton 		return;
202f95f3850SWill Newton 
203f95f3850SWill Newton 	node = debugfs_create_file("regs", S_IRUSR, root, host,
204f95f3850SWill Newton 				   &dw_mci_regs_fops);
205f95f3850SWill Newton 	if (!node)
206f95f3850SWill Newton 		goto err;
207f95f3850SWill Newton 
208f95f3850SWill Newton 	node = debugfs_create_file("req", S_IRUSR, root, slot,
209f95f3850SWill Newton 				   &dw_mci_req_fops);
210f95f3850SWill Newton 	if (!node)
211f95f3850SWill Newton 		goto err;
212f95f3850SWill Newton 
213f95f3850SWill Newton 	node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
214f95f3850SWill Newton 	if (!node)
215f95f3850SWill Newton 		goto err;
216f95f3850SWill Newton 
217f95f3850SWill Newton 	node = debugfs_create_x32("pending_events", S_IRUSR, root,
218f95f3850SWill Newton 				  (u32 *)&host->pending_events);
219f95f3850SWill Newton 	if (!node)
220f95f3850SWill Newton 		goto err;
221f95f3850SWill Newton 
222f95f3850SWill Newton 	node = debugfs_create_x32("completed_events", S_IRUSR, root,
223f95f3850SWill Newton 				  (u32 *)&host->completed_events);
224f95f3850SWill Newton 	if (!node)
225f95f3850SWill Newton 		goto err;
226f95f3850SWill Newton 
227f95f3850SWill Newton 	return;
228f95f3850SWill Newton 
229f95f3850SWill Newton err:
230f95f3850SWill Newton 	dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
231f95f3850SWill Newton }
232f95f3850SWill Newton #endif /* defined(CONFIG_DEBUG_FS) */
233f95f3850SWill Newton 
234f95f3850SWill Newton static void dw_mci_set_timeout(struct dw_mci *host)
235f95f3850SWill Newton {
236f95f3850SWill Newton 	/* timeout (maximum) */
237f95f3850SWill Newton 	mci_writel(host, TMOUT, 0xffffffff);
238f95f3850SWill Newton }
239f95f3850SWill Newton 
240f95f3850SWill Newton static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
241f95f3850SWill Newton {
242f95f3850SWill Newton 	struct mmc_data	*data;
243800d78bfSThomas Abraham 	struct dw_mci_slot *slot = mmc_priv(mmc);
244e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
245f95f3850SWill Newton 	u32 cmdr;
246f95f3850SWill Newton 	cmd->error = -EINPROGRESS;
247f95f3850SWill Newton 
248f95f3850SWill Newton 	cmdr = cmd->opcode;
249f95f3850SWill Newton 
250*90c2143aSSeungwon Jeon 	if (cmd->opcode == MMC_STOP_TRANSMISSION ||
251*90c2143aSSeungwon Jeon 	    cmd->opcode == MMC_GO_IDLE_STATE ||
252*90c2143aSSeungwon Jeon 	    cmd->opcode == MMC_GO_INACTIVE_STATE ||
253*90c2143aSSeungwon Jeon 	    (cmd->opcode == SD_IO_RW_DIRECT &&
254*90c2143aSSeungwon Jeon 	     ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT))
255f95f3850SWill Newton 		cmdr |= SDMMC_CMD_STOP;
256f95f3850SWill Newton 	else
257*90c2143aSSeungwon Jeon 		if (cmd->opcode != MMC_SEND_STATUS && cmd->data)
258f95f3850SWill Newton 			cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
259f95f3850SWill Newton 
260f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_PRESENT) {
261f95f3850SWill Newton 		/* We expect a response, so set this bit */
262f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_EXP;
263f95f3850SWill Newton 		if (cmd->flags & MMC_RSP_136)
264f95f3850SWill Newton 			cmdr |= SDMMC_CMD_RESP_LONG;
265f95f3850SWill Newton 	}
266f95f3850SWill Newton 
267f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_CRC)
268f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_CRC;
269f95f3850SWill Newton 
270f95f3850SWill Newton 	data = cmd->data;
271f95f3850SWill Newton 	if (data) {
272f95f3850SWill Newton 		cmdr |= SDMMC_CMD_DAT_EXP;
273f95f3850SWill Newton 		if (data->flags & MMC_DATA_STREAM)
274f95f3850SWill Newton 			cmdr |= SDMMC_CMD_STRM_MODE;
275f95f3850SWill Newton 		if (data->flags & MMC_DATA_WRITE)
276f95f3850SWill Newton 			cmdr |= SDMMC_CMD_DAT_WR;
277f95f3850SWill Newton 	}
278f95f3850SWill Newton 
279cb27a843SJames Hogan 	if (drv_data && drv_data->prepare_command)
280cb27a843SJames Hogan 		drv_data->prepare_command(slot->host, &cmdr);
281800d78bfSThomas Abraham 
282f95f3850SWill Newton 	return cmdr;
283f95f3850SWill Newton }
284f95f3850SWill Newton 
285*90c2143aSSeungwon Jeon static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
286*90c2143aSSeungwon Jeon {
287*90c2143aSSeungwon Jeon 	struct mmc_command *stop;
288*90c2143aSSeungwon Jeon 	u32 cmdr;
289*90c2143aSSeungwon Jeon 
290*90c2143aSSeungwon Jeon 	if (!cmd->data)
291*90c2143aSSeungwon Jeon 		return 0;
292*90c2143aSSeungwon Jeon 
293*90c2143aSSeungwon Jeon 	stop = &host->stop_abort;
294*90c2143aSSeungwon Jeon 	cmdr = cmd->opcode;
295*90c2143aSSeungwon Jeon 	memset(stop, 0, sizeof(struct mmc_command));
296*90c2143aSSeungwon Jeon 
297*90c2143aSSeungwon Jeon 	if (cmdr == MMC_READ_SINGLE_BLOCK ||
298*90c2143aSSeungwon Jeon 	    cmdr == MMC_READ_MULTIPLE_BLOCK ||
299*90c2143aSSeungwon Jeon 	    cmdr == MMC_WRITE_BLOCK ||
300*90c2143aSSeungwon Jeon 	    cmdr == MMC_WRITE_MULTIPLE_BLOCK) {
301*90c2143aSSeungwon Jeon 		stop->opcode = MMC_STOP_TRANSMISSION;
302*90c2143aSSeungwon Jeon 		stop->arg = 0;
303*90c2143aSSeungwon Jeon 		stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
304*90c2143aSSeungwon Jeon 	} else if (cmdr == SD_IO_RW_EXTENDED) {
305*90c2143aSSeungwon Jeon 		stop->opcode = SD_IO_RW_DIRECT;
306*90c2143aSSeungwon Jeon 		stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) |
307*90c2143aSSeungwon Jeon 			     ((cmd->arg >> 28) & 0x7);
308*90c2143aSSeungwon Jeon 		stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
309*90c2143aSSeungwon Jeon 	} else {
310*90c2143aSSeungwon Jeon 		return 0;
311*90c2143aSSeungwon Jeon 	}
312*90c2143aSSeungwon Jeon 
313*90c2143aSSeungwon Jeon 	cmdr = stop->opcode | SDMMC_CMD_STOP |
314*90c2143aSSeungwon Jeon 		SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP;
315*90c2143aSSeungwon Jeon 
316*90c2143aSSeungwon Jeon 	return cmdr;
317*90c2143aSSeungwon Jeon }
318*90c2143aSSeungwon Jeon 
319f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host,
320f95f3850SWill Newton 				 struct mmc_command *cmd, u32 cmd_flags)
321f95f3850SWill Newton {
322f95f3850SWill Newton 	host->cmd = cmd;
3234a90920cSThomas Abraham 	dev_vdbg(host->dev,
324f95f3850SWill Newton 		 "start command: ARGR=0x%08x CMDR=0x%08x\n",
325f95f3850SWill Newton 		 cmd->arg, cmd_flags);
326f95f3850SWill Newton 
327f95f3850SWill Newton 	mci_writel(host, CMDARG, cmd->arg);
328f95f3850SWill Newton 	wmb();
329f95f3850SWill Newton 
330f95f3850SWill Newton 	mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
331f95f3850SWill Newton }
332f95f3850SWill Newton 
333*90c2143aSSeungwon Jeon static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data)
334f95f3850SWill Newton {
335*90c2143aSSeungwon Jeon 	struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort;
336*90c2143aSSeungwon Jeon 	dw_mci_start_command(host, stop, host->stop_cmdr);
337f95f3850SWill Newton }
338f95f3850SWill Newton 
339f95f3850SWill Newton /* DMA interface functions */
340f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host)
341f95f3850SWill Newton {
34203e8cb53SJames Hogan 	if (host->using_dma) {
343f95f3850SWill Newton 		host->dma_ops->stop(host);
344f95f3850SWill Newton 		host->dma_ops->cleanup(host);
345f95f3850SWill Newton 	} else {
346f95f3850SWill Newton 		/* Data transfer was stopped by the interrupt handler */
347f95f3850SWill Newton 		set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
348f95f3850SWill Newton 	}
349f95f3850SWill Newton }
350f95f3850SWill Newton 
3519aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data)
3529aa51408SSeungwon Jeon {
3539aa51408SSeungwon Jeon 	if (data->flags & MMC_DATA_WRITE)
3549aa51408SSeungwon Jeon 		return DMA_TO_DEVICE;
3559aa51408SSeungwon Jeon 	else
3569aa51408SSeungwon Jeon 		return DMA_FROM_DEVICE;
3579aa51408SSeungwon Jeon }
3589aa51408SSeungwon Jeon 
3599beee912SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
360f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host)
361f95f3850SWill Newton {
362f95f3850SWill Newton 	struct mmc_data *data = host->data;
363f95f3850SWill Newton 
364f95f3850SWill Newton 	if (data)
3659aa51408SSeungwon Jeon 		if (!data->host_cookie)
3664a90920cSThomas Abraham 			dma_unmap_sg(host->dev,
3679aa51408SSeungwon Jeon 				     data->sg,
3689aa51408SSeungwon Jeon 				     data->sg_len,
3699aa51408SSeungwon Jeon 				     dw_mci_get_dma_dir(data));
370f95f3850SWill Newton }
371f95f3850SWill Newton 
372f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host)
373f95f3850SWill Newton {
374f95f3850SWill Newton 	u32 temp;
375f95f3850SWill Newton 
376f95f3850SWill Newton 	/* Disable and reset the IDMAC interface */
377f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
378f95f3850SWill Newton 	temp &= ~SDMMC_CTRL_USE_IDMAC;
379f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_RESET;
380f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
381f95f3850SWill Newton 
382f95f3850SWill Newton 	/* Stop the IDMAC running */
383f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
384a5289a43SJaehoon Chung 	temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB);
385f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
386f95f3850SWill Newton }
387f95f3850SWill Newton 
388f95f3850SWill Newton static void dw_mci_idmac_complete_dma(struct dw_mci *host)
389f95f3850SWill Newton {
390f95f3850SWill Newton 	struct mmc_data *data = host->data;
391f95f3850SWill Newton 
3924a90920cSThomas Abraham 	dev_vdbg(host->dev, "DMA complete\n");
393f95f3850SWill Newton 
394f95f3850SWill Newton 	host->dma_ops->cleanup(host);
395f95f3850SWill Newton 
396f95f3850SWill Newton 	/*
397f95f3850SWill Newton 	 * If the card was removed, data will be NULL. No point in trying to
398f95f3850SWill Newton 	 * send the stop command or waiting for NBUSY in this case.
399f95f3850SWill Newton 	 */
400f95f3850SWill Newton 	if (data) {
401f95f3850SWill Newton 		set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
402f95f3850SWill Newton 		tasklet_schedule(&host->tasklet);
403f95f3850SWill Newton 	}
404f95f3850SWill Newton }
405f95f3850SWill Newton 
406f95f3850SWill Newton static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
407f95f3850SWill Newton 				    unsigned int sg_len)
408f95f3850SWill Newton {
409f95f3850SWill Newton 	int i;
410f95f3850SWill Newton 	struct idmac_desc *desc = host->sg_cpu;
411f95f3850SWill Newton 
412f95f3850SWill Newton 	for (i = 0; i < sg_len; i++, desc++) {
413f95f3850SWill Newton 		unsigned int length = sg_dma_len(&data->sg[i]);
414f95f3850SWill Newton 		u32 mem_addr = sg_dma_address(&data->sg[i]);
415f95f3850SWill Newton 
416f95f3850SWill Newton 		/* Set the OWN bit and disable interrupts for this descriptor */
417f95f3850SWill Newton 		desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH;
418f95f3850SWill Newton 
419f95f3850SWill Newton 		/* Buffer length */
420f95f3850SWill Newton 		IDMAC_SET_BUFFER1_SIZE(desc, length);
421f95f3850SWill Newton 
422f95f3850SWill Newton 		/* Physical address to DMA to/from */
423f95f3850SWill Newton 		desc->des2 = mem_addr;
424f95f3850SWill Newton 	}
425f95f3850SWill Newton 
426f95f3850SWill Newton 	/* Set first descriptor */
427f95f3850SWill Newton 	desc = host->sg_cpu;
428f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_FD;
429f95f3850SWill Newton 
430f95f3850SWill Newton 	/* Set last descriptor */
431f95f3850SWill Newton 	desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
432f95f3850SWill Newton 	desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
433f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_LD;
434f95f3850SWill Newton 
435f95f3850SWill Newton 	wmb();
436f95f3850SWill Newton }
437f95f3850SWill Newton 
438f95f3850SWill Newton static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
439f95f3850SWill Newton {
440f95f3850SWill Newton 	u32 temp;
441f95f3850SWill Newton 
442f95f3850SWill Newton 	dw_mci_translate_sglist(host, host->data, sg_len);
443f95f3850SWill Newton 
444f95f3850SWill Newton 	/* Select IDMAC interface */
445f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
446f95f3850SWill Newton 	temp |= SDMMC_CTRL_USE_IDMAC;
447f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
448f95f3850SWill Newton 
449f95f3850SWill Newton 	wmb();
450f95f3850SWill Newton 
451f95f3850SWill Newton 	/* Enable the IDMAC */
452f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
453a5289a43SJaehoon Chung 	temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB;
454f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
455f95f3850SWill Newton 
456f95f3850SWill Newton 	/* Start it running */
457f95f3850SWill Newton 	mci_writel(host, PLDMND, 1);
458f95f3850SWill Newton }
459f95f3850SWill Newton 
460f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host)
461f95f3850SWill Newton {
462f95f3850SWill Newton 	struct idmac_desc *p;
463897b69e7SSeungwon Jeon 	int i;
464f95f3850SWill Newton 
465f95f3850SWill Newton 	/* Number of descriptors in the ring buffer */
466f95f3850SWill Newton 	host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
467f95f3850SWill Newton 
468f95f3850SWill Newton 	/* Forward link the descriptor list */
469f95f3850SWill Newton 	for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
470f95f3850SWill Newton 		p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
471f95f3850SWill Newton 
472f95f3850SWill Newton 	/* Set the last descriptor as the end-of-ring descriptor */
473f95f3850SWill Newton 	p->des3 = host->sg_dma;
474f95f3850SWill Newton 	p->des0 = IDMAC_DES0_ER;
475f95f3850SWill Newton 
476141a712aSSeungwon Jeon 	mci_writel(host, BMOD, SDMMC_IDMAC_SWRESET);
477141a712aSSeungwon Jeon 
478f95f3850SWill Newton 	/* Mask out interrupts - get Tx & Rx complete only */
479fc79a4d6SJoonyoung Shim 	mci_writel(host, IDSTS, IDMAC_INT_CLR);
480f95f3850SWill Newton 	mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
481f95f3850SWill Newton 		   SDMMC_IDMAC_INT_TI);
482f95f3850SWill Newton 
483f95f3850SWill Newton 	/* Set the descriptor base address */
484f95f3850SWill Newton 	mci_writel(host, DBADDR, host->sg_dma);
485f95f3850SWill Newton 	return 0;
486f95f3850SWill Newton }
487f95f3850SWill Newton 
4888e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = {
489885c3e80SSeungwon Jeon 	.init = dw_mci_idmac_init,
490885c3e80SSeungwon Jeon 	.start = dw_mci_idmac_start_dma,
491885c3e80SSeungwon Jeon 	.stop = dw_mci_idmac_stop_dma,
492885c3e80SSeungwon Jeon 	.complete = dw_mci_idmac_complete_dma,
493885c3e80SSeungwon Jeon 	.cleanup = dw_mci_dma_cleanup,
494885c3e80SSeungwon Jeon };
495885c3e80SSeungwon Jeon #endif /* CONFIG_MMC_DW_IDMAC */
496885c3e80SSeungwon Jeon 
4979aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host,
4989aa51408SSeungwon Jeon 				   struct mmc_data *data,
4999aa51408SSeungwon Jeon 				   bool next)
500f95f3850SWill Newton {
501f95f3850SWill Newton 	struct scatterlist *sg;
5029aa51408SSeungwon Jeon 	unsigned int i, sg_len;
503f95f3850SWill Newton 
5049aa51408SSeungwon Jeon 	if (!next && data->host_cookie)
5059aa51408SSeungwon Jeon 		return data->host_cookie;
506f95f3850SWill Newton 
507f95f3850SWill Newton 	/*
508f95f3850SWill Newton 	 * We don't do DMA on "complex" transfers, i.e. with
509f95f3850SWill Newton 	 * non-word-aligned buffers or lengths. Also, we don't bother
510f95f3850SWill Newton 	 * with all the DMA setup overhead for short transfers.
511f95f3850SWill Newton 	 */
512f95f3850SWill Newton 	if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD)
513f95f3850SWill Newton 		return -EINVAL;
5149aa51408SSeungwon Jeon 
515f95f3850SWill Newton 	if (data->blksz & 3)
516f95f3850SWill Newton 		return -EINVAL;
517f95f3850SWill Newton 
518f95f3850SWill Newton 	for_each_sg(data->sg, sg, data->sg_len, i) {
519f95f3850SWill Newton 		if (sg->offset & 3 || sg->length & 3)
520f95f3850SWill Newton 			return -EINVAL;
521f95f3850SWill Newton 	}
522f95f3850SWill Newton 
5234a90920cSThomas Abraham 	sg_len = dma_map_sg(host->dev,
5249aa51408SSeungwon Jeon 			    data->sg,
5259aa51408SSeungwon Jeon 			    data->sg_len,
5269aa51408SSeungwon Jeon 			    dw_mci_get_dma_dir(data));
5279aa51408SSeungwon Jeon 	if (sg_len == 0)
5289aa51408SSeungwon Jeon 		return -EINVAL;
5299aa51408SSeungwon Jeon 
5309aa51408SSeungwon Jeon 	if (next)
5319aa51408SSeungwon Jeon 		data->host_cookie = sg_len;
5329aa51408SSeungwon Jeon 
5339aa51408SSeungwon Jeon 	return sg_len;
5349aa51408SSeungwon Jeon }
5359aa51408SSeungwon Jeon 
5369aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc,
5379aa51408SSeungwon Jeon 			   struct mmc_request *mrq,
5389aa51408SSeungwon Jeon 			   bool is_first_req)
5399aa51408SSeungwon Jeon {
5409aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
5419aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
5429aa51408SSeungwon Jeon 
5439aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
5449aa51408SSeungwon Jeon 		return;
5459aa51408SSeungwon Jeon 
5469aa51408SSeungwon Jeon 	if (data->host_cookie) {
5479aa51408SSeungwon Jeon 		data->host_cookie = 0;
5489aa51408SSeungwon Jeon 		return;
5499aa51408SSeungwon Jeon 	}
5509aa51408SSeungwon Jeon 
5519aa51408SSeungwon Jeon 	if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0)
5529aa51408SSeungwon Jeon 		data->host_cookie = 0;
5539aa51408SSeungwon Jeon }
5549aa51408SSeungwon Jeon 
5559aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc,
5569aa51408SSeungwon Jeon 			    struct mmc_request *mrq,
5579aa51408SSeungwon Jeon 			    int err)
5589aa51408SSeungwon Jeon {
5599aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
5609aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
5619aa51408SSeungwon Jeon 
5629aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
5639aa51408SSeungwon Jeon 		return;
5649aa51408SSeungwon Jeon 
5659aa51408SSeungwon Jeon 	if (data->host_cookie)
5664a90920cSThomas Abraham 		dma_unmap_sg(slot->host->dev,
5679aa51408SSeungwon Jeon 			     data->sg,
5689aa51408SSeungwon Jeon 			     data->sg_len,
5699aa51408SSeungwon Jeon 			     dw_mci_get_dma_dir(data));
5709aa51408SSeungwon Jeon 	data->host_cookie = 0;
5719aa51408SSeungwon Jeon }
5729aa51408SSeungwon Jeon 
57352426899SSeungwon Jeon static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
57452426899SSeungwon Jeon {
57552426899SSeungwon Jeon #ifdef CONFIG_MMC_DW_IDMAC
57652426899SSeungwon Jeon 	unsigned int blksz = data->blksz;
57752426899SSeungwon Jeon 	const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
57852426899SSeungwon Jeon 	u32 fifo_width = 1 << host->data_shift;
57952426899SSeungwon Jeon 	u32 blksz_depth = blksz / fifo_width, fifoth_val;
58052426899SSeungwon Jeon 	u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers;
58152426899SSeungwon Jeon 	int idx = (sizeof(mszs) / sizeof(mszs[0])) - 1;
58252426899SSeungwon Jeon 
58352426899SSeungwon Jeon 	tx_wmark = (host->fifo_depth) / 2;
58452426899SSeungwon Jeon 	tx_wmark_invers = host->fifo_depth - tx_wmark;
58552426899SSeungwon Jeon 
58652426899SSeungwon Jeon 	/*
58752426899SSeungwon Jeon 	 * MSIZE is '1',
58852426899SSeungwon Jeon 	 * if blksz is not a multiple of the FIFO width
58952426899SSeungwon Jeon 	 */
59052426899SSeungwon Jeon 	if (blksz % fifo_width) {
59152426899SSeungwon Jeon 		msize = 0;
59252426899SSeungwon Jeon 		rx_wmark = 1;
59352426899SSeungwon Jeon 		goto done;
59452426899SSeungwon Jeon 	}
59552426899SSeungwon Jeon 
59652426899SSeungwon Jeon 	do {
59752426899SSeungwon Jeon 		if (!((blksz_depth % mszs[idx]) ||
59852426899SSeungwon Jeon 		     (tx_wmark_invers % mszs[idx]))) {
59952426899SSeungwon Jeon 			msize = idx;
60052426899SSeungwon Jeon 			rx_wmark = mszs[idx] - 1;
60152426899SSeungwon Jeon 			break;
60252426899SSeungwon Jeon 		}
60352426899SSeungwon Jeon 	} while (--idx > 0);
60452426899SSeungwon Jeon 	/*
60552426899SSeungwon Jeon 	 * If idx is '0', it won't be tried
60652426899SSeungwon Jeon 	 * Thus, initial values are uesed
60752426899SSeungwon Jeon 	 */
60852426899SSeungwon Jeon done:
60952426899SSeungwon Jeon 	fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark);
61052426899SSeungwon Jeon 	mci_writel(host, FIFOTH, fifoth_val);
61152426899SSeungwon Jeon #endif
61252426899SSeungwon Jeon }
61352426899SSeungwon Jeon 
614f1d2736cSSeungwon Jeon static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)
615f1d2736cSSeungwon Jeon {
616f1d2736cSSeungwon Jeon 	unsigned int blksz = data->blksz;
617f1d2736cSSeungwon Jeon 	u32 blksz_depth, fifo_depth;
618f1d2736cSSeungwon Jeon 	u16 thld_size;
619f1d2736cSSeungwon Jeon 
620f1d2736cSSeungwon Jeon 	WARN_ON(!(data->flags & MMC_DATA_READ));
621f1d2736cSSeungwon Jeon 
622f1d2736cSSeungwon Jeon 	if (host->timing != MMC_TIMING_MMC_HS200 &&
623f1d2736cSSeungwon Jeon 	    host->timing != MMC_TIMING_UHS_SDR104)
624f1d2736cSSeungwon Jeon 		goto disable;
625f1d2736cSSeungwon Jeon 
626f1d2736cSSeungwon Jeon 	blksz_depth = blksz / (1 << host->data_shift);
627f1d2736cSSeungwon Jeon 	fifo_depth = host->fifo_depth;
628f1d2736cSSeungwon Jeon 
629f1d2736cSSeungwon Jeon 	if (blksz_depth > fifo_depth)
630f1d2736cSSeungwon Jeon 		goto disable;
631f1d2736cSSeungwon Jeon 
632f1d2736cSSeungwon Jeon 	/*
633f1d2736cSSeungwon Jeon 	 * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz'
634f1d2736cSSeungwon Jeon 	 * If (blksz_depth) <  (fifo_depth >> 1), should be thld_size = blksz
635f1d2736cSSeungwon Jeon 	 * Currently just choose blksz.
636f1d2736cSSeungwon Jeon 	 */
637f1d2736cSSeungwon Jeon 	thld_size = blksz;
638f1d2736cSSeungwon Jeon 	mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1));
639f1d2736cSSeungwon Jeon 	return;
640f1d2736cSSeungwon Jeon 
641f1d2736cSSeungwon Jeon disable:
642f1d2736cSSeungwon Jeon 	mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0));
643f1d2736cSSeungwon Jeon }
644f1d2736cSSeungwon Jeon 
6459aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
6469aa51408SSeungwon Jeon {
6479aa51408SSeungwon Jeon 	int sg_len;
6489aa51408SSeungwon Jeon 	u32 temp;
6499aa51408SSeungwon Jeon 
6509aa51408SSeungwon Jeon 	host->using_dma = 0;
6519aa51408SSeungwon Jeon 
6529aa51408SSeungwon Jeon 	/* If we don't have a channel, we can't do DMA */
6539aa51408SSeungwon Jeon 	if (!host->use_dma)
6549aa51408SSeungwon Jeon 		return -ENODEV;
6559aa51408SSeungwon Jeon 
6569aa51408SSeungwon Jeon 	sg_len = dw_mci_pre_dma_transfer(host, data, 0);
657a99aa9b9SSeungwon Jeon 	if (sg_len < 0) {
658a99aa9b9SSeungwon Jeon 		host->dma_ops->stop(host);
6599aa51408SSeungwon Jeon 		return sg_len;
660a99aa9b9SSeungwon Jeon 	}
6619aa51408SSeungwon Jeon 
66203e8cb53SJames Hogan 	host->using_dma = 1;
66303e8cb53SJames Hogan 
6644a90920cSThomas Abraham 	dev_vdbg(host->dev,
665f95f3850SWill Newton 		 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
666f95f3850SWill Newton 		 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
667f95f3850SWill Newton 		 sg_len);
668f95f3850SWill Newton 
66952426899SSeungwon Jeon 	/*
67052426899SSeungwon Jeon 	 * Decide the MSIZE and RX/TX Watermark.
67152426899SSeungwon Jeon 	 * If current block size is same with previous size,
67252426899SSeungwon Jeon 	 * no need to update fifoth.
67352426899SSeungwon Jeon 	 */
67452426899SSeungwon Jeon 	if (host->prev_blksz != data->blksz)
67552426899SSeungwon Jeon 		dw_mci_adjust_fifoth(host, data);
67652426899SSeungwon Jeon 
677f95f3850SWill Newton 	/* Enable the DMA interface */
678f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
679f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_ENABLE;
680f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
681f95f3850SWill Newton 
682f95f3850SWill Newton 	/* Disable RX/TX IRQs, let DMA handle it */
683f95f3850SWill Newton 	temp = mci_readl(host, INTMASK);
684f95f3850SWill Newton 	temp  &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR);
685f95f3850SWill Newton 	mci_writel(host, INTMASK, temp);
686f95f3850SWill Newton 
687f95f3850SWill Newton 	host->dma_ops->start(host, sg_len);
688f95f3850SWill Newton 
689f95f3850SWill Newton 	return 0;
690f95f3850SWill Newton }
691f95f3850SWill Newton 
692f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
693f95f3850SWill Newton {
694f95f3850SWill Newton 	u32 temp;
695f95f3850SWill Newton 
696f95f3850SWill Newton 	data->error = -EINPROGRESS;
697f95f3850SWill Newton 
698f95f3850SWill Newton 	WARN_ON(host->data);
699f95f3850SWill Newton 	host->sg = NULL;
700f95f3850SWill Newton 	host->data = data;
701f95f3850SWill Newton 
702f1d2736cSSeungwon Jeon 	if (data->flags & MMC_DATA_READ) {
70355c5efbcSJames Hogan 		host->dir_status = DW_MCI_RECV_STATUS;
704f1d2736cSSeungwon Jeon 		dw_mci_ctrl_rd_thld(host, data);
705f1d2736cSSeungwon Jeon 	} else {
70655c5efbcSJames Hogan 		host->dir_status = DW_MCI_SEND_STATUS;
707f1d2736cSSeungwon Jeon 	}
70855c5efbcSJames Hogan 
709f95f3850SWill Newton 	if (dw_mci_submit_data_dma(host, data)) {
710f9c2a0dcSSeungwon Jeon 		int flags = SG_MITER_ATOMIC;
711f9c2a0dcSSeungwon Jeon 		if (host->data->flags & MMC_DATA_READ)
712f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_TO_SG;
713f9c2a0dcSSeungwon Jeon 		else
714f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_FROM_SG;
715f9c2a0dcSSeungwon Jeon 
716f9c2a0dcSSeungwon Jeon 		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
717f95f3850SWill Newton 		host->sg = data->sg;
71834b664a2SJames Hogan 		host->part_buf_start = 0;
71934b664a2SJames Hogan 		host->part_buf_count = 0;
720f95f3850SWill Newton 
721b40af3aaSJames Hogan 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR);
722f95f3850SWill Newton 		temp = mci_readl(host, INTMASK);
723f95f3850SWill Newton 		temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR;
724f95f3850SWill Newton 		mci_writel(host, INTMASK, temp);
725f95f3850SWill Newton 
726f95f3850SWill Newton 		temp = mci_readl(host, CTRL);
727f95f3850SWill Newton 		temp &= ~SDMMC_CTRL_DMA_ENABLE;
728f95f3850SWill Newton 		mci_writel(host, CTRL, temp);
72952426899SSeungwon Jeon 
73052426899SSeungwon Jeon 		/*
73152426899SSeungwon Jeon 		 * Use the initial fifoth_val for PIO mode.
73252426899SSeungwon Jeon 		 * If next issued data may be transfered by DMA mode,
73352426899SSeungwon Jeon 		 * prev_blksz should be invalidated.
73452426899SSeungwon Jeon 		 */
73552426899SSeungwon Jeon 		mci_writel(host, FIFOTH, host->fifoth_val);
73652426899SSeungwon Jeon 		host->prev_blksz = 0;
73752426899SSeungwon Jeon 	} else {
73852426899SSeungwon Jeon 		/*
73952426899SSeungwon Jeon 		 * Keep the current block size.
74052426899SSeungwon Jeon 		 * It will be used to decide whether to update
74152426899SSeungwon Jeon 		 * fifoth register next time.
74252426899SSeungwon Jeon 		 */
74352426899SSeungwon Jeon 		host->prev_blksz = data->blksz;
744f95f3850SWill Newton 	}
745f95f3850SWill Newton }
746f95f3850SWill Newton 
747f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
748f95f3850SWill Newton {
749f95f3850SWill Newton 	struct dw_mci *host = slot->host;
750f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
751f95f3850SWill Newton 	unsigned int cmd_status = 0;
752f95f3850SWill Newton 
753f95f3850SWill Newton 	mci_writel(host, CMDARG, arg);
754f95f3850SWill Newton 	wmb();
755f95f3850SWill Newton 	mci_writel(host, CMD, SDMMC_CMD_START | cmd);
756f95f3850SWill Newton 
757f95f3850SWill Newton 	while (time_before(jiffies, timeout)) {
758f95f3850SWill Newton 		cmd_status = mci_readl(host, CMD);
759f95f3850SWill Newton 		if (!(cmd_status & SDMMC_CMD_START))
760f95f3850SWill Newton 			return;
761f95f3850SWill Newton 	}
762f95f3850SWill Newton 	dev_err(&slot->mmc->class_dev,
763f95f3850SWill Newton 		"Timeout sending command (cmd %#x arg %#x status %#x)\n",
764f95f3850SWill Newton 		cmd, arg, cmd_status);
765f95f3850SWill Newton }
766f95f3850SWill Newton 
767ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
768f95f3850SWill Newton {
769f95f3850SWill Newton 	struct dw_mci *host = slot->host;
770fdf492a1SDoug Anderson 	unsigned int clock = slot->clock;
771f95f3850SWill Newton 	u32 div;
7729623b5b9SDoug Anderson 	u32 clk_en_a;
773f95f3850SWill Newton 
774fdf492a1SDoug Anderson 	if (!clock) {
775fdf492a1SDoug Anderson 		mci_writel(host, CLKENA, 0);
776fdf492a1SDoug Anderson 		mci_send_cmd(slot,
777fdf492a1SDoug Anderson 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
778fdf492a1SDoug Anderson 	} else if (clock != host->current_speed || force_clkinit) {
779fdf492a1SDoug Anderson 		div = host->bus_hz / clock;
780fdf492a1SDoug Anderson 		if (host->bus_hz % clock && host->bus_hz > clock)
781f95f3850SWill Newton 			/*
782f95f3850SWill Newton 			 * move the + 1 after the divide to prevent
783f95f3850SWill Newton 			 * over-clocking the card.
784f95f3850SWill Newton 			 */
785e419990bSSeungwon Jeon 			div += 1;
786e419990bSSeungwon Jeon 
787fdf492a1SDoug Anderson 		div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0;
788f95f3850SWill Newton 
789fdf492a1SDoug Anderson 		if ((clock << div) != slot->__clk_old || force_clkinit)
790f95f3850SWill Newton 			dev_info(&slot->mmc->class_dev,
791fdf492a1SDoug Anderson 				 "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
792fdf492a1SDoug Anderson 				 slot->id, host->bus_hz, clock,
793fdf492a1SDoug Anderson 				 div ? ((host->bus_hz / div) >> 1) :
794fdf492a1SDoug Anderson 				 host->bus_hz, div);
795f95f3850SWill Newton 
796f95f3850SWill Newton 		/* disable clock */
797f95f3850SWill Newton 		mci_writel(host, CLKENA, 0);
798f95f3850SWill Newton 		mci_writel(host, CLKSRC, 0);
799f95f3850SWill Newton 
800f95f3850SWill Newton 		/* inform CIU */
801f95f3850SWill Newton 		mci_send_cmd(slot,
802f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
803f95f3850SWill Newton 
804f95f3850SWill Newton 		/* set clock to desired speed */
805f95f3850SWill Newton 		mci_writel(host, CLKDIV, div);
806f95f3850SWill Newton 
807f95f3850SWill Newton 		/* inform CIU */
808f95f3850SWill Newton 		mci_send_cmd(slot,
809f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
810f95f3850SWill Newton 
8119623b5b9SDoug Anderson 		/* enable clock; only low power if no SDIO */
8129623b5b9SDoug Anderson 		clk_en_a = SDMMC_CLKEN_ENABLE << slot->id;
8139623b5b9SDoug Anderson 		if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id)))
8149623b5b9SDoug Anderson 			clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id;
8159623b5b9SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a);
816f95f3850SWill Newton 
817f95f3850SWill Newton 		/* inform CIU */
818f95f3850SWill Newton 		mci_send_cmd(slot,
819f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
820f95f3850SWill Newton 
821fdf492a1SDoug Anderson 		/* keep the clock with reflecting clock dividor */
822fdf492a1SDoug Anderson 		slot->__clk_old = clock << div;
823f95f3850SWill Newton 	}
824f95f3850SWill Newton 
825fdf492a1SDoug Anderson 	host->current_speed = clock;
826fdf492a1SDoug Anderson 
827f95f3850SWill Newton 	/* Set the current slot bus width */
8281d56c453SSeungwon Jeon 	mci_writel(host, CTYPE, (slot->ctype << slot->id));
829f95f3850SWill Newton }
830f95f3850SWill Newton 
831053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host,
832053b3ce6SSeungwon Jeon 				   struct dw_mci_slot *slot,
833053b3ce6SSeungwon Jeon 				   struct mmc_command *cmd)
834f95f3850SWill Newton {
835f95f3850SWill Newton 	struct mmc_request *mrq;
836f95f3850SWill Newton 	struct mmc_data	*data;
837f95f3850SWill Newton 	u32 cmdflags;
838f95f3850SWill Newton 
839f95f3850SWill Newton 	mrq = slot->mrq;
840f95f3850SWill Newton 	if (host->pdata->select_slot)
841f95f3850SWill Newton 		host->pdata->select_slot(slot->id);
842f95f3850SWill Newton 
843f95f3850SWill Newton 	host->cur_slot = slot;
844f95f3850SWill Newton 	host->mrq = mrq;
845f95f3850SWill Newton 
846f95f3850SWill Newton 	host->pending_events = 0;
847f95f3850SWill Newton 	host->completed_events = 0;
848f95f3850SWill Newton 	host->data_status = 0;
849f95f3850SWill Newton 
850053b3ce6SSeungwon Jeon 	data = cmd->data;
851f95f3850SWill Newton 	if (data) {
852f95f3850SWill Newton 		dw_mci_set_timeout(host);
853f95f3850SWill Newton 		mci_writel(host, BYTCNT, data->blksz*data->blocks);
854f95f3850SWill Newton 		mci_writel(host, BLKSIZ, data->blksz);
855f95f3850SWill Newton 	}
856f95f3850SWill Newton 
857f95f3850SWill Newton 	cmdflags = dw_mci_prepare_command(slot->mmc, cmd);
858f95f3850SWill Newton 
859f95f3850SWill Newton 	/* this is the first command, send the initialization clock */
860f95f3850SWill Newton 	if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags))
861f95f3850SWill Newton 		cmdflags |= SDMMC_CMD_INIT;
862f95f3850SWill Newton 
863f95f3850SWill Newton 	if (data) {
864f95f3850SWill Newton 		dw_mci_submit_data(host, data);
865f95f3850SWill Newton 		wmb();
866f95f3850SWill Newton 	}
867f95f3850SWill Newton 
868f95f3850SWill Newton 	dw_mci_start_command(host, cmd, cmdflags);
869f95f3850SWill Newton 
870f95f3850SWill Newton 	if (mrq->stop)
871f95f3850SWill Newton 		host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
872*90c2143aSSeungwon Jeon 	else
873*90c2143aSSeungwon Jeon 		host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd);
874f95f3850SWill Newton }
875f95f3850SWill Newton 
876053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host,
877053b3ce6SSeungwon Jeon 				 struct dw_mci_slot *slot)
878053b3ce6SSeungwon Jeon {
879053b3ce6SSeungwon Jeon 	struct mmc_request *mrq = slot->mrq;
880053b3ce6SSeungwon Jeon 	struct mmc_command *cmd;
881053b3ce6SSeungwon Jeon 
882053b3ce6SSeungwon Jeon 	cmd = mrq->sbc ? mrq->sbc : mrq->cmd;
883053b3ce6SSeungwon Jeon 	__dw_mci_start_request(host, slot, cmd);
884053b3ce6SSeungwon Jeon }
885053b3ce6SSeungwon Jeon 
8867456caaeSJames Hogan /* must be called with host->lock held */
887f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot,
888f95f3850SWill Newton 				 struct mmc_request *mrq)
889f95f3850SWill Newton {
890f95f3850SWill Newton 	dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
891f95f3850SWill Newton 		 host->state);
892f95f3850SWill Newton 
893f95f3850SWill Newton 	slot->mrq = mrq;
894f95f3850SWill Newton 
895f95f3850SWill Newton 	if (host->state == STATE_IDLE) {
896f95f3850SWill Newton 		host->state = STATE_SENDING_CMD;
897f95f3850SWill Newton 		dw_mci_start_request(host, slot);
898f95f3850SWill Newton 	} else {
899f95f3850SWill Newton 		list_add_tail(&slot->queue_node, &host->queue);
900f95f3850SWill Newton 	}
901f95f3850SWill Newton }
902f95f3850SWill Newton 
903f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
904f95f3850SWill Newton {
905f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
906f95f3850SWill Newton 	struct dw_mci *host = slot->host;
907f95f3850SWill Newton 
908f95f3850SWill Newton 	WARN_ON(slot->mrq);
909f95f3850SWill Newton 
9107456caaeSJames Hogan 	/*
9117456caaeSJames Hogan 	 * The check for card presence and queueing of the request must be
9127456caaeSJames Hogan 	 * atomic, otherwise the card could be removed in between and the
9137456caaeSJames Hogan 	 * request wouldn't fail until another card was inserted.
9147456caaeSJames Hogan 	 */
9157456caaeSJames Hogan 	spin_lock_bh(&host->lock);
9167456caaeSJames Hogan 
917f95f3850SWill Newton 	if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
9187456caaeSJames Hogan 		spin_unlock_bh(&host->lock);
919f95f3850SWill Newton 		mrq->cmd->error = -ENOMEDIUM;
920f95f3850SWill Newton 		mmc_request_done(mmc, mrq);
921f95f3850SWill Newton 		return;
922f95f3850SWill Newton 	}
923f95f3850SWill Newton 
924f95f3850SWill Newton 	dw_mci_queue_request(host, slot, mrq);
9257456caaeSJames Hogan 
9267456caaeSJames Hogan 	spin_unlock_bh(&host->lock);
927f95f3850SWill Newton }
928f95f3850SWill Newton 
929f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
930f95f3850SWill Newton {
931f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
932e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
93341babf75SJaehoon Chung 	u32 regs;
934f95f3850SWill Newton 
935f95f3850SWill Newton 	switch (ios->bus_width) {
936f95f3850SWill Newton 	case MMC_BUS_WIDTH_4:
937f95f3850SWill Newton 		slot->ctype = SDMMC_CTYPE_4BIT;
938f95f3850SWill Newton 		break;
939c9b2a06fSJaehoon Chung 	case MMC_BUS_WIDTH_8:
940c9b2a06fSJaehoon Chung 		slot->ctype = SDMMC_CTYPE_8BIT;
941c9b2a06fSJaehoon Chung 		break;
942b2f7cb45SJaehoon Chung 	default:
943b2f7cb45SJaehoon Chung 		/* set default 1 bit mode */
944b2f7cb45SJaehoon Chung 		slot->ctype = SDMMC_CTYPE_1BIT;
945f95f3850SWill Newton 	}
946f95f3850SWill Newton 
94741babf75SJaehoon Chung 	regs = mci_readl(slot->host, UHS_REG);
9483f514291SSeungwon Jeon 
9493f514291SSeungwon Jeon 	/* DDR mode set */
9503f514291SSeungwon Jeon 	if (ios->timing == MMC_TIMING_UHS_DDR50)
951c69042a5SHyeonsu Kim 		regs |= ((0x1 << slot->id) << 16);
9523f514291SSeungwon Jeon 	else
953c69042a5SHyeonsu Kim 		regs &= ~((0x1 << slot->id) << 16);
9543f514291SSeungwon Jeon 
95541babf75SJaehoon Chung 	mci_writel(slot->host, UHS_REG, regs);
956f1d2736cSSeungwon Jeon 	slot->host->timing = ios->timing;
95741babf75SJaehoon Chung 
958f95f3850SWill Newton 	/*
959f95f3850SWill Newton 	 * Use mirror of ios->clock to prevent race with mmc
960f95f3850SWill Newton 	 * core ios update when finding the minimum.
961f95f3850SWill Newton 	 */
962f95f3850SWill Newton 	slot->clock = ios->clock;
963f95f3850SWill Newton 
964cb27a843SJames Hogan 	if (drv_data && drv_data->set_ios)
965cb27a843SJames Hogan 		drv_data->set_ios(slot->host, ios);
966800d78bfSThomas Abraham 
967bf7cb224SJaehoon Chung 	/* Slot specific timing and width adjustment */
968bf7cb224SJaehoon Chung 	dw_mci_setup_bus(slot, false);
969bf7cb224SJaehoon Chung 
970f95f3850SWill Newton 	switch (ios->power_mode) {
971f95f3850SWill Newton 	case MMC_POWER_UP:
972f95f3850SWill Newton 		set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
973e6f34e2fSJames Hogan 		/* Power up slot */
974e6f34e2fSJames Hogan 		if (slot->host->pdata->setpower)
975e6f34e2fSJames Hogan 			slot->host->pdata->setpower(slot->id, mmc->ocr_avail);
9764366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
9774366dcc5SJaehoon Chung 		regs |= (1 << slot->id);
9784366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
979e6f34e2fSJames Hogan 		break;
980e6f34e2fSJames Hogan 	case MMC_POWER_OFF:
981e6f34e2fSJames Hogan 		/* Power down slot */
982e6f34e2fSJames Hogan 		if (slot->host->pdata->setpower)
983e6f34e2fSJames Hogan 			slot->host->pdata->setpower(slot->id, 0);
9844366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
9854366dcc5SJaehoon Chung 		regs &= ~(1 << slot->id);
9864366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
987f95f3850SWill Newton 		break;
988f95f3850SWill Newton 	default:
989f95f3850SWill Newton 		break;
990f95f3850SWill Newton 	}
991f95f3850SWill Newton }
992f95f3850SWill Newton 
993f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc)
994f95f3850SWill Newton {
995f95f3850SWill Newton 	int read_only;
996f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
997f95f3850SWill Newton 	struct dw_mci_board *brd = slot->host->pdata;
998f95f3850SWill Newton 
999f95f3850SWill Newton 	/* Use platform get_ro function, else try on board write protect */
10009640639bSDoug Anderson 	if (slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT)
1001b4967aa5SThomas Abraham 		read_only = 0;
1002b4967aa5SThomas Abraham 	else if (brd->get_ro)
1003f95f3850SWill Newton 		read_only = brd->get_ro(slot->id);
100455a6ceb2SDoug Anderson 	else if (gpio_is_valid(slot->wp_gpio))
100555a6ceb2SDoug Anderson 		read_only = gpio_get_value(slot->wp_gpio);
1006f95f3850SWill Newton 	else
1007f95f3850SWill Newton 		read_only =
1008f95f3850SWill Newton 			mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0;
1009f95f3850SWill Newton 
1010f95f3850SWill Newton 	dev_dbg(&mmc->class_dev, "card is %s\n",
1011f95f3850SWill Newton 		read_only ? "read-only" : "read-write");
1012f95f3850SWill Newton 
1013f95f3850SWill Newton 	return read_only;
1014f95f3850SWill Newton }
1015f95f3850SWill Newton 
1016f95f3850SWill Newton static int dw_mci_get_cd(struct mmc_host *mmc)
1017f95f3850SWill Newton {
1018f95f3850SWill Newton 	int present;
1019f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
1020f95f3850SWill Newton 	struct dw_mci_board *brd = slot->host->pdata;
1021f95f3850SWill Newton 
1022f95f3850SWill Newton 	/* Use platform get_cd function, else try onboard card detect */
1023fc3d7720SJaehoon Chung 	if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
1024fc3d7720SJaehoon Chung 		present = 1;
1025fc3d7720SJaehoon Chung 	else if (brd->get_cd)
1026f95f3850SWill Newton 		present = !brd->get_cd(slot->id);
1027f95f3850SWill Newton 	else
1028f95f3850SWill Newton 		present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
1029f95f3850SWill Newton 			== 0 ? 1 : 0;
1030f95f3850SWill Newton 
1031f95f3850SWill Newton 	if (present)
1032f95f3850SWill Newton 		dev_dbg(&mmc->class_dev, "card is present\n");
1033f95f3850SWill Newton 	else
1034f95f3850SWill Newton 		dev_dbg(&mmc->class_dev, "card is not present\n");
1035f95f3850SWill Newton 
1036f95f3850SWill Newton 	return present;
1037f95f3850SWill Newton }
1038f95f3850SWill Newton 
10399623b5b9SDoug Anderson /*
10409623b5b9SDoug Anderson  * Disable lower power mode.
10419623b5b9SDoug Anderson  *
10429623b5b9SDoug Anderson  * Low power mode will stop the card clock when idle.  According to the
10439623b5b9SDoug Anderson  * description of the CLKENA register we should disable low power mode
10449623b5b9SDoug Anderson  * for SDIO cards if we need SDIO interrupts to work.
10459623b5b9SDoug Anderson  *
10469623b5b9SDoug Anderson  * This function is fast if low power mode is already disabled.
10479623b5b9SDoug Anderson  */
10489623b5b9SDoug Anderson static void dw_mci_disable_low_power(struct dw_mci_slot *slot)
10499623b5b9SDoug Anderson {
10509623b5b9SDoug Anderson 	struct dw_mci *host = slot->host;
10519623b5b9SDoug Anderson 	u32 clk_en_a;
10529623b5b9SDoug Anderson 	const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id;
10539623b5b9SDoug Anderson 
10549623b5b9SDoug Anderson 	clk_en_a = mci_readl(host, CLKENA);
10559623b5b9SDoug Anderson 
10569623b5b9SDoug Anderson 	if (clk_en_a & clken_low_pwr) {
10579623b5b9SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr);
10589623b5b9SDoug Anderson 		mci_send_cmd(slot, SDMMC_CMD_UPD_CLK |
10599623b5b9SDoug Anderson 			     SDMMC_CMD_PRV_DAT_WAIT, 0);
10609623b5b9SDoug Anderson 	}
10619623b5b9SDoug Anderson }
10629623b5b9SDoug Anderson 
10631a5c8e1fSShashidhar Hiremath static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
10641a5c8e1fSShashidhar Hiremath {
10651a5c8e1fSShashidhar Hiremath 	struct dw_mci_slot *slot = mmc_priv(mmc);
10661a5c8e1fSShashidhar Hiremath 	struct dw_mci *host = slot->host;
10671a5c8e1fSShashidhar Hiremath 	u32 int_mask;
10681a5c8e1fSShashidhar Hiremath 
10691a5c8e1fSShashidhar Hiremath 	/* Enable/disable Slot Specific SDIO interrupt */
10701a5c8e1fSShashidhar Hiremath 	int_mask = mci_readl(host, INTMASK);
10711a5c8e1fSShashidhar Hiremath 	if (enb) {
10729623b5b9SDoug Anderson 		/*
10739623b5b9SDoug Anderson 		 * Turn off low power mode if it was enabled.  This is a bit of
10749623b5b9SDoug Anderson 		 * a heavy operation and we disable / enable IRQs a lot, so
10759623b5b9SDoug Anderson 		 * we'll leave low power mode disabled and it will get
10769623b5b9SDoug Anderson 		 * re-enabled again in dw_mci_setup_bus().
10779623b5b9SDoug Anderson 		 */
10789623b5b9SDoug Anderson 		dw_mci_disable_low_power(slot);
10799623b5b9SDoug Anderson 
10801a5c8e1fSShashidhar Hiremath 		mci_writel(host, INTMASK,
1081705ad047SKyoungil Kim 			   (int_mask | SDMMC_INT_SDIO(slot->id)));
10821a5c8e1fSShashidhar Hiremath 	} else {
10831a5c8e1fSShashidhar Hiremath 		mci_writel(host, INTMASK,
1084705ad047SKyoungil Kim 			   (int_mask & ~SDMMC_INT_SDIO(slot->id)));
10851a5c8e1fSShashidhar Hiremath 	}
10861a5c8e1fSShashidhar Hiremath }
10871a5c8e1fSShashidhar Hiremath 
10880976f16dSSeungwon Jeon static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
10890976f16dSSeungwon Jeon {
10900976f16dSSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
10910976f16dSSeungwon Jeon 	struct dw_mci *host = slot->host;
10920976f16dSSeungwon Jeon 	const struct dw_mci_drv_data *drv_data = host->drv_data;
10930976f16dSSeungwon Jeon 	struct dw_mci_tuning_data tuning_data;
10940976f16dSSeungwon Jeon 	int err = -ENOSYS;
10950976f16dSSeungwon Jeon 
10960976f16dSSeungwon Jeon 	if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
10970976f16dSSeungwon Jeon 		if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
10980976f16dSSeungwon Jeon 			tuning_data.blk_pattern = tuning_blk_pattern_8bit;
10990976f16dSSeungwon Jeon 			tuning_data.blksz = sizeof(tuning_blk_pattern_8bit);
11000976f16dSSeungwon Jeon 		} else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
11010976f16dSSeungwon Jeon 			tuning_data.blk_pattern = tuning_blk_pattern_4bit;
11020976f16dSSeungwon Jeon 			tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
11030976f16dSSeungwon Jeon 		} else {
11040976f16dSSeungwon Jeon 			return -EINVAL;
11050976f16dSSeungwon Jeon 		}
11060976f16dSSeungwon Jeon 	} else if (opcode == MMC_SEND_TUNING_BLOCK) {
11070976f16dSSeungwon Jeon 		tuning_data.blk_pattern = tuning_blk_pattern_4bit;
11080976f16dSSeungwon Jeon 		tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
11090976f16dSSeungwon Jeon 	} else {
11100976f16dSSeungwon Jeon 		dev_err(host->dev,
11110976f16dSSeungwon Jeon 			"Undefined command(%d) for tuning\n", opcode);
11120976f16dSSeungwon Jeon 		return -EINVAL;
11130976f16dSSeungwon Jeon 	}
11140976f16dSSeungwon Jeon 
11150976f16dSSeungwon Jeon 	if (drv_data && drv_data->execute_tuning)
11160976f16dSSeungwon Jeon 		err = drv_data->execute_tuning(slot, opcode, &tuning_data);
11170976f16dSSeungwon Jeon 	return err;
11180976f16dSSeungwon Jeon }
11190976f16dSSeungwon Jeon 
1120f95f3850SWill Newton static const struct mmc_host_ops dw_mci_ops = {
1121f95f3850SWill Newton 	.request		= dw_mci_request,
11229aa51408SSeungwon Jeon 	.pre_req		= dw_mci_pre_req,
11239aa51408SSeungwon Jeon 	.post_req		= dw_mci_post_req,
1124f95f3850SWill Newton 	.set_ios		= dw_mci_set_ios,
1125f95f3850SWill Newton 	.get_ro			= dw_mci_get_ro,
1126f95f3850SWill Newton 	.get_cd			= dw_mci_get_cd,
11271a5c8e1fSShashidhar Hiremath 	.enable_sdio_irq	= dw_mci_enable_sdio_irq,
11280976f16dSSeungwon Jeon 	.execute_tuning		= dw_mci_execute_tuning,
1129f95f3850SWill Newton };
1130f95f3850SWill Newton 
1131f95f3850SWill Newton static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
1132f95f3850SWill Newton 	__releases(&host->lock)
1133f95f3850SWill Newton 	__acquires(&host->lock)
1134f95f3850SWill Newton {
1135f95f3850SWill Newton 	struct dw_mci_slot *slot;
1136f95f3850SWill Newton 	struct mmc_host	*prev_mmc = host->cur_slot->mmc;
1137f95f3850SWill Newton 
1138f95f3850SWill Newton 	WARN_ON(host->cmd || host->data);
1139f95f3850SWill Newton 
1140f95f3850SWill Newton 	host->cur_slot->mrq = NULL;
1141f95f3850SWill Newton 	host->mrq = NULL;
1142f95f3850SWill Newton 	if (!list_empty(&host->queue)) {
1143f95f3850SWill Newton 		slot = list_entry(host->queue.next,
1144f95f3850SWill Newton 				  struct dw_mci_slot, queue_node);
1145f95f3850SWill Newton 		list_del(&slot->queue_node);
11464a90920cSThomas Abraham 		dev_vdbg(host->dev, "list not empty: %s is next\n",
1147f95f3850SWill Newton 			 mmc_hostname(slot->mmc));
1148f95f3850SWill Newton 		host->state = STATE_SENDING_CMD;
1149f95f3850SWill Newton 		dw_mci_start_request(host, slot);
1150f95f3850SWill Newton 	} else {
11514a90920cSThomas Abraham 		dev_vdbg(host->dev, "list empty\n");
1152f95f3850SWill Newton 		host->state = STATE_IDLE;
1153f95f3850SWill Newton 	}
1154f95f3850SWill Newton 
1155f95f3850SWill Newton 	spin_unlock(&host->lock);
1156f95f3850SWill Newton 	mmc_request_done(prev_mmc, mrq);
1157f95f3850SWill Newton 	spin_lock(&host->lock);
1158f95f3850SWill Newton }
1159f95f3850SWill Newton 
1160f95f3850SWill Newton static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
1161f95f3850SWill Newton {
1162f95f3850SWill Newton 	u32 status = host->cmd_status;
1163f95f3850SWill Newton 
1164f95f3850SWill Newton 	host->cmd_status = 0;
1165f95f3850SWill Newton 
1166f95f3850SWill Newton 	/* Read the response from the card (up to 16 bytes) */
1167f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_PRESENT) {
1168f95f3850SWill Newton 		if (cmd->flags & MMC_RSP_136) {
1169f95f3850SWill Newton 			cmd->resp[3] = mci_readl(host, RESP0);
1170f95f3850SWill Newton 			cmd->resp[2] = mci_readl(host, RESP1);
1171f95f3850SWill Newton 			cmd->resp[1] = mci_readl(host, RESP2);
1172f95f3850SWill Newton 			cmd->resp[0] = mci_readl(host, RESP3);
1173f95f3850SWill Newton 		} else {
1174f95f3850SWill Newton 			cmd->resp[0] = mci_readl(host, RESP0);
1175f95f3850SWill Newton 			cmd->resp[1] = 0;
1176f95f3850SWill Newton 			cmd->resp[2] = 0;
1177f95f3850SWill Newton 			cmd->resp[3] = 0;
1178f95f3850SWill Newton 		}
1179f95f3850SWill Newton 	}
1180f95f3850SWill Newton 
1181f95f3850SWill Newton 	if (status & SDMMC_INT_RTO)
1182f95f3850SWill Newton 		cmd->error = -ETIMEDOUT;
1183f95f3850SWill Newton 	else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC))
1184f95f3850SWill Newton 		cmd->error = -EILSEQ;
1185f95f3850SWill Newton 	else if (status & SDMMC_INT_RESP_ERR)
1186f95f3850SWill Newton 		cmd->error = -EIO;
1187f95f3850SWill Newton 	else
1188f95f3850SWill Newton 		cmd->error = 0;
1189f95f3850SWill Newton 
1190f95f3850SWill Newton 	if (cmd->error) {
1191f95f3850SWill Newton 		/* newer ip versions need a delay between retries */
1192f95f3850SWill Newton 		if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY)
1193f95f3850SWill Newton 			mdelay(20);
1194f95f3850SWill Newton 	}
1195f95f3850SWill Newton }
1196f95f3850SWill Newton 
1197f95f3850SWill Newton static void dw_mci_tasklet_func(unsigned long priv)
1198f95f3850SWill Newton {
1199f95f3850SWill Newton 	struct dw_mci *host = (struct dw_mci *)priv;
1200f95f3850SWill Newton 	struct mmc_data	*data;
1201f95f3850SWill Newton 	struct mmc_command *cmd;
1202f95f3850SWill Newton 	enum dw_mci_state state;
1203f95f3850SWill Newton 	enum dw_mci_state prev_state;
120494dd5b33SJames Hogan 	u32 status, ctrl;
1205f95f3850SWill Newton 
1206f95f3850SWill Newton 	spin_lock(&host->lock);
1207f95f3850SWill Newton 
1208f95f3850SWill Newton 	state = host->state;
1209f95f3850SWill Newton 	data = host->data;
1210f95f3850SWill Newton 
1211f95f3850SWill Newton 	do {
1212f95f3850SWill Newton 		prev_state = state;
1213f95f3850SWill Newton 
1214f95f3850SWill Newton 		switch (state) {
1215f95f3850SWill Newton 		case STATE_IDLE:
1216f95f3850SWill Newton 			break;
1217f95f3850SWill Newton 
1218f95f3850SWill Newton 		case STATE_SENDING_CMD:
1219f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1220f95f3850SWill Newton 						&host->pending_events))
1221f95f3850SWill Newton 				break;
1222f95f3850SWill Newton 
1223f95f3850SWill Newton 			cmd = host->cmd;
1224f95f3850SWill Newton 			host->cmd = NULL;
1225f95f3850SWill Newton 			set_bit(EVENT_CMD_COMPLETE, &host->completed_events);
1226053b3ce6SSeungwon Jeon 			dw_mci_command_complete(host, cmd);
1227053b3ce6SSeungwon Jeon 			if (cmd == host->mrq->sbc && !cmd->error) {
1228053b3ce6SSeungwon Jeon 				prev_state = state = STATE_SENDING_CMD;
1229053b3ce6SSeungwon Jeon 				__dw_mci_start_request(host, host->cur_slot,
1230053b3ce6SSeungwon Jeon 						       host->mrq->cmd);
1231053b3ce6SSeungwon Jeon 				goto unlock;
1232053b3ce6SSeungwon Jeon 			}
1233053b3ce6SSeungwon Jeon 
123471abb133SSeungwon Jeon 			if (cmd->data && cmd->error) {
123571abb133SSeungwon Jeon 				dw_mci_stop_dma(host);
1236*90c2143aSSeungwon Jeon 				send_stop_abort(host, data);
123771abb133SSeungwon Jeon 				state = STATE_SENDING_STOP;
123871abb133SSeungwon Jeon 				break;
123971abb133SSeungwon Jeon 			}
124071abb133SSeungwon Jeon 
1241f95f3850SWill Newton 			if (!host->mrq->data || cmd->error) {
1242f95f3850SWill Newton 				dw_mci_request_end(host, host->mrq);
1243f95f3850SWill Newton 				goto unlock;
1244f95f3850SWill Newton 			}
1245f95f3850SWill Newton 
1246f95f3850SWill Newton 			prev_state = state = STATE_SENDING_DATA;
1247f95f3850SWill Newton 			/* fall through */
1248f95f3850SWill Newton 
1249f95f3850SWill Newton 		case STATE_SENDING_DATA:
1250f95f3850SWill Newton 			if (test_and_clear_bit(EVENT_DATA_ERROR,
1251f95f3850SWill Newton 					       &host->pending_events)) {
1252f95f3850SWill Newton 				dw_mci_stop_dma(host);
1253*90c2143aSSeungwon Jeon 				send_stop_abort(host, data);
1254f95f3850SWill Newton 				state = STATE_DATA_ERROR;
1255f95f3850SWill Newton 				break;
1256f95f3850SWill Newton 			}
1257f95f3850SWill Newton 
1258f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1259f95f3850SWill Newton 						&host->pending_events))
1260f95f3850SWill Newton 				break;
1261f95f3850SWill Newton 
1262f95f3850SWill Newton 			set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
1263f95f3850SWill Newton 			prev_state = state = STATE_DATA_BUSY;
1264f95f3850SWill Newton 			/* fall through */
1265f95f3850SWill Newton 
1266f95f3850SWill Newton 		case STATE_DATA_BUSY:
1267f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
1268f95f3850SWill Newton 						&host->pending_events))
1269f95f3850SWill Newton 				break;
1270f95f3850SWill Newton 
1271f95f3850SWill Newton 			host->data = NULL;
1272f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
1273f95f3850SWill Newton 			status = host->data_status;
1274f95f3850SWill Newton 
1275f95f3850SWill Newton 			if (status & DW_MCI_DATA_ERROR_FLAGS) {
12763f7eec62SJaehoon Chung 				if (status & SDMMC_INT_DRTO) {
1277f95f3850SWill Newton 					data->error = -ETIMEDOUT;
1278f95f3850SWill Newton 				} else if (status & SDMMC_INT_DCRC) {
1279f95f3850SWill Newton 					data->error = -EILSEQ;
128055c5efbcSJames Hogan 				} else if (status & SDMMC_INT_EBE &&
128155c5efbcSJames Hogan 					   host->dir_status ==
128255c5efbcSJames Hogan 							DW_MCI_SEND_STATUS) {
128355c5efbcSJames Hogan 					/*
128455c5efbcSJames Hogan 					 * No data CRC status was returned.
128555c5efbcSJames Hogan 					 * The number of bytes transferred will
128655c5efbcSJames Hogan 					 * be exaggerated in PIO mode.
128755c5efbcSJames Hogan 					 */
128855c5efbcSJames Hogan 					data->bytes_xfered = 0;
128955c5efbcSJames Hogan 					data->error = -ETIMEDOUT;
1290f95f3850SWill Newton 				} else {
12914a90920cSThomas Abraham 					dev_err(host->dev,
1292f95f3850SWill Newton 						"data FIFO error "
1293f95f3850SWill Newton 						"(status=%08x)\n",
1294f95f3850SWill Newton 						status);
1295f95f3850SWill Newton 					data->error = -EIO;
1296f95f3850SWill Newton 				}
129794dd5b33SJames Hogan 				/*
129894dd5b33SJames Hogan 				 * After an error, there may be data lingering
129994dd5b33SJames Hogan 				 * in the FIFO, so reset it - doing so
130094dd5b33SJames Hogan 				 * generates a block interrupt, hence setting
130194dd5b33SJames Hogan 				 * the scatter-gather pointer to NULL.
130294dd5b33SJames Hogan 				 */
1303f9c2a0dcSSeungwon Jeon 				sg_miter_stop(&host->sg_miter);
130494dd5b33SJames Hogan 				host->sg = NULL;
130594dd5b33SJames Hogan 				ctrl = mci_readl(host, CTRL);
130694dd5b33SJames Hogan 				ctrl |= SDMMC_CTRL_FIFO_RESET;
130794dd5b33SJames Hogan 				mci_writel(host, CTRL, ctrl);
1308f95f3850SWill Newton 			} else {
1309f95f3850SWill Newton 				data->bytes_xfered = data->blocks * data->blksz;
1310f95f3850SWill Newton 				data->error = 0;
1311f95f3850SWill Newton 			}
1312f95f3850SWill Newton 
1313*90c2143aSSeungwon Jeon 			if (!data->stop && !data->error) {
1314f95f3850SWill Newton 				dw_mci_request_end(host, host->mrq);
1315f95f3850SWill Newton 				goto unlock;
1316f95f3850SWill Newton 			}
1317f95f3850SWill Newton 
1318053b3ce6SSeungwon Jeon 			if (host->mrq->sbc && !data->error) {
1319053b3ce6SSeungwon Jeon 				data->stop->error = 0;
1320053b3ce6SSeungwon Jeon 				dw_mci_request_end(host, host->mrq);
1321053b3ce6SSeungwon Jeon 				goto unlock;
1322053b3ce6SSeungwon Jeon 			}
1323053b3ce6SSeungwon Jeon 
1324f95f3850SWill Newton 			prev_state = state = STATE_SENDING_STOP;
1325*90c2143aSSeungwon Jeon 			if (data->stop && !data->error) {
1326*90c2143aSSeungwon Jeon 				/* stop command for open-ended transfer*/
1327*90c2143aSSeungwon Jeon 				send_stop_abort(host, data);
1328*90c2143aSSeungwon Jeon 			}
1329f95f3850SWill Newton 			/* fall through */
1330f95f3850SWill Newton 
1331f95f3850SWill Newton 		case STATE_SENDING_STOP:
1332f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1333f95f3850SWill Newton 						&host->pending_events))
1334f95f3850SWill Newton 				break;
1335f95f3850SWill Newton 
133671abb133SSeungwon Jeon 			/* CMD error in data command */
133771abb133SSeungwon Jeon 			if (host->mrq->cmd->error && host->mrq->data) {
133871abb133SSeungwon Jeon 				sg_miter_stop(&host->sg_miter);
133971abb133SSeungwon Jeon 				host->sg = NULL;
134071abb133SSeungwon Jeon 				ctrl = mci_readl(host, CTRL);
134171abb133SSeungwon Jeon 				ctrl |= SDMMC_CTRL_FIFO_RESET;
134271abb133SSeungwon Jeon 				mci_writel(host, CTRL, ctrl);
134371abb133SSeungwon Jeon 			}
134471abb133SSeungwon Jeon 
1345f95f3850SWill Newton 			host->cmd = NULL;
134671abb133SSeungwon Jeon 			host->data = NULL;
1347*90c2143aSSeungwon Jeon 
1348*90c2143aSSeungwon Jeon 			if (host->mrq->stop)
1349f95f3850SWill Newton 				dw_mci_command_complete(host, host->mrq->stop);
1350*90c2143aSSeungwon Jeon 			else
1351*90c2143aSSeungwon Jeon 				host->cmd_status = 0;
1352*90c2143aSSeungwon Jeon 
1353f95f3850SWill Newton 			dw_mci_request_end(host, host->mrq);
1354f95f3850SWill Newton 			goto unlock;
1355f95f3850SWill Newton 
1356f95f3850SWill Newton 		case STATE_DATA_ERROR:
1357f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1358f95f3850SWill Newton 						&host->pending_events))
1359f95f3850SWill Newton 				break;
1360f95f3850SWill Newton 
1361f95f3850SWill Newton 			state = STATE_DATA_BUSY;
1362f95f3850SWill Newton 			break;
1363f95f3850SWill Newton 		}
1364f95f3850SWill Newton 	} while (state != prev_state);
1365f95f3850SWill Newton 
1366f95f3850SWill Newton 	host->state = state;
1367f95f3850SWill Newton unlock:
1368f95f3850SWill Newton 	spin_unlock(&host->lock);
1369f95f3850SWill Newton 
1370f95f3850SWill Newton }
1371f95f3850SWill Newton 
137234b664a2SJames Hogan /* push final bytes to part_buf, only use during push */
137334b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt)
137434b664a2SJames Hogan {
137534b664a2SJames Hogan 	memcpy((void *)&host->part_buf, buf, cnt);
137634b664a2SJames Hogan 	host->part_buf_count = cnt;
137734b664a2SJames Hogan }
137834b664a2SJames Hogan 
137934b664a2SJames Hogan /* append bytes to part_buf, only use during push */
138034b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt)
138134b664a2SJames Hogan {
138234b664a2SJames Hogan 	cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count);
138334b664a2SJames Hogan 	memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt);
138434b664a2SJames Hogan 	host->part_buf_count += cnt;
138534b664a2SJames Hogan 	return cnt;
138634b664a2SJames Hogan }
138734b664a2SJames Hogan 
138834b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */
138934b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt)
139034b664a2SJames Hogan {
139134b664a2SJames Hogan 	cnt = min(cnt, (int)host->part_buf_count);
139234b664a2SJames Hogan 	if (cnt) {
139334b664a2SJames Hogan 		memcpy(buf, (void *)&host->part_buf + host->part_buf_start,
139434b664a2SJames Hogan 		       cnt);
139534b664a2SJames Hogan 		host->part_buf_count -= cnt;
139634b664a2SJames Hogan 		host->part_buf_start += cnt;
139734b664a2SJames Hogan 	}
139834b664a2SJames Hogan 	return cnt;
139934b664a2SJames Hogan }
140034b664a2SJames Hogan 
140134b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */
140234b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt)
140334b664a2SJames Hogan {
140434b664a2SJames Hogan 	memcpy(buf, &host->part_buf, cnt);
140534b664a2SJames Hogan 	host->part_buf_start = cnt;
140634b664a2SJames Hogan 	host->part_buf_count = (1 << host->data_shift) - cnt;
140734b664a2SJames Hogan }
140834b664a2SJames Hogan 
1409f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
1410f95f3850SWill Newton {
1411cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1412cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1413cfbeb59cSMarkos Chandras 
141434b664a2SJames Hogan 	/* try and push anything in the part_buf */
141534b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
141634b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
141734b664a2SJames Hogan 		buf += len;
141834b664a2SJames Hogan 		cnt -= len;
1419cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 2) {
14204e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
14214e0a5adfSJaehoon Chung 					host->part_buf16);
142234b664a2SJames Hogan 			host->part_buf_count = 0;
142334b664a2SJames Hogan 		}
142434b664a2SJames Hogan 	}
142534b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
142634b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
142734b664a2SJames Hogan 		while (cnt >= 2) {
142834b664a2SJames Hogan 			u16 aligned_buf[64];
142934b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
143034b664a2SJames Hogan 			int items = len >> 1;
143134b664a2SJames Hogan 			int i;
143234b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
143334b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
143434b664a2SJames Hogan 			buf += len;
143534b664a2SJames Hogan 			cnt -= len;
143634b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
143734b664a2SJames Hogan 			for (i = 0; i < items; ++i)
14384e0a5adfSJaehoon Chung 				mci_writew(host, DATA(host->data_offset),
14394e0a5adfSJaehoon Chung 						aligned_buf[i]);
144034b664a2SJames Hogan 		}
144134b664a2SJames Hogan 	} else
144234b664a2SJames Hogan #endif
144334b664a2SJames Hogan 	{
144434b664a2SJames Hogan 		u16 *pdata = buf;
144534b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
14464e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset), *pdata++);
144734b664a2SJames Hogan 		buf = pdata;
144834b664a2SJames Hogan 	}
144934b664a2SJames Hogan 	/* put anything remaining in the part_buf */
145034b664a2SJames Hogan 	if (cnt) {
145134b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1452cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1453cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1454cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
14554e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
14564e0a5adfSJaehoon Chung 				   host->part_buf16);
1457f95f3850SWill Newton 	}
1458f95f3850SWill Newton }
1459f95f3850SWill Newton 
1460f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
1461f95f3850SWill Newton {
146234b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
146334b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
146434b664a2SJames Hogan 		while (cnt >= 2) {
146534b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
146634b664a2SJames Hogan 			u16 aligned_buf[64];
146734b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
146834b664a2SJames Hogan 			int items = len >> 1;
146934b664a2SJames Hogan 			int i;
147034b664a2SJames Hogan 			for (i = 0; i < items; ++i)
14714e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readw(host,
14724e0a5adfSJaehoon Chung 						DATA(host->data_offset));
147334b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
147434b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
147534b664a2SJames Hogan 			buf += len;
147634b664a2SJames Hogan 			cnt -= len;
147734b664a2SJames Hogan 		}
147834b664a2SJames Hogan 	} else
147934b664a2SJames Hogan #endif
148034b664a2SJames Hogan 	{
148134b664a2SJames Hogan 		u16 *pdata = buf;
148234b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
14834e0a5adfSJaehoon Chung 			*pdata++ = mci_readw(host, DATA(host->data_offset));
148434b664a2SJames Hogan 		buf = pdata;
148534b664a2SJames Hogan 	}
148634b664a2SJames Hogan 	if (cnt) {
14874e0a5adfSJaehoon Chung 		host->part_buf16 = mci_readw(host, DATA(host->data_offset));
148834b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1489f95f3850SWill Newton 	}
1490f95f3850SWill Newton }
1491f95f3850SWill Newton 
1492f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
1493f95f3850SWill Newton {
1494cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1495cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1496cfbeb59cSMarkos Chandras 
149734b664a2SJames Hogan 	/* try and push anything in the part_buf */
149834b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
149934b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
150034b664a2SJames Hogan 		buf += len;
150134b664a2SJames Hogan 		cnt -= len;
1502cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 4) {
15034e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
15044e0a5adfSJaehoon Chung 					host->part_buf32);
150534b664a2SJames Hogan 			host->part_buf_count = 0;
150634b664a2SJames Hogan 		}
150734b664a2SJames Hogan 	}
150834b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
150934b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
151034b664a2SJames Hogan 		while (cnt >= 4) {
151134b664a2SJames Hogan 			u32 aligned_buf[32];
151234b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
151334b664a2SJames Hogan 			int items = len >> 2;
151434b664a2SJames Hogan 			int i;
151534b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
151634b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
151734b664a2SJames Hogan 			buf += len;
151834b664a2SJames Hogan 			cnt -= len;
151934b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
152034b664a2SJames Hogan 			for (i = 0; i < items; ++i)
15214e0a5adfSJaehoon Chung 				mci_writel(host, DATA(host->data_offset),
15224e0a5adfSJaehoon Chung 						aligned_buf[i]);
152334b664a2SJames Hogan 		}
152434b664a2SJames Hogan 	} else
152534b664a2SJames Hogan #endif
152634b664a2SJames Hogan 	{
152734b664a2SJames Hogan 		u32 *pdata = buf;
152834b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
15294e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset), *pdata++);
153034b664a2SJames Hogan 		buf = pdata;
153134b664a2SJames Hogan 	}
153234b664a2SJames Hogan 	/* put anything remaining in the part_buf */
153334b664a2SJames Hogan 	if (cnt) {
153434b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1535cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1536cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1537cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
15384e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
15394e0a5adfSJaehoon Chung 				   host->part_buf32);
1540f95f3850SWill Newton 	}
1541f95f3850SWill Newton }
1542f95f3850SWill Newton 
1543f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
1544f95f3850SWill Newton {
154534b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
154634b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
154734b664a2SJames Hogan 		while (cnt >= 4) {
154834b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
154934b664a2SJames Hogan 			u32 aligned_buf[32];
155034b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
155134b664a2SJames Hogan 			int items = len >> 2;
155234b664a2SJames Hogan 			int i;
155334b664a2SJames Hogan 			for (i = 0; i < items; ++i)
15544e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readl(host,
15554e0a5adfSJaehoon Chung 						DATA(host->data_offset));
155634b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
155734b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
155834b664a2SJames Hogan 			buf += len;
155934b664a2SJames Hogan 			cnt -= len;
156034b664a2SJames Hogan 		}
156134b664a2SJames Hogan 	} else
156234b664a2SJames Hogan #endif
156334b664a2SJames Hogan 	{
156434b664a2SJames Hogan 		u32 *pdata = buf;
156534b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
15664e0a5adfSJaehoon Chung 			*pdata++ = mci_readl(host, DATA(host->data_offset));
156734b664a2SJames Hogan 		buf = pdata;
156834b664a2SJames Hogan 	}
156934b664a2SJames Hogan 	if (cnt) {
15704e0a5adfSJaehoon Chung 		host->part_buf32 = mci_readl(host, DATA(host->data_offset));
157134b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1572f95f3850SWill Newton 	}
1573f95f3850SWill Newton }
1574f95f3850SWill Newton 
1575f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
1576f95f3850SWill Newton {
1577cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1578cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1579cfbeb59cSMarkos Chandras 
158034b664a2SJames Hogan 	/* try and push anything in the part_buf */
158134b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
158234b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
158334b664a2SJames Hogan 		buf += len;
158434b664a2SJames Hogan 		cnt -= len;
1585c09fbd74SSeungwon Jeon 
1586cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 8) {
1587c09fbd74SSeungwon Jeon 			mci_writeq(host, DATA(host->data_offset),
15884e0a5adfSJaehoon Chung 					host->part_buf);
158934b664a2SJames Hogan 			host->part_buf_count = 0;
159034b664a2SJames Hogan 		}
159134b664a2SJames Hogan 	}
159234b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
159334b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
159434b664a2SJames Hogan 		while (cnt >= 8) {
159534b664a2SJames Hogan 			u64 aligned_buf[16];
159634b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
159734b664a2SJames Hogan 			int items = len >> 3;
159834b664a2SJames Hogan 			int i;
159934b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
160034b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
160134b664a2SJames Hogan 			buf += len;
160234b664a2SJames Hogan 			cnt -= len;
160334b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
160434b664a2SJames Hogan 			for (i = 0; i < items; ++i)
16054e0a5adfSJaehoon Chung 				mci_writeq(host, DATA(host->data_offset),
16064e0a5adfSJaehoon Chung 						aligned_buf[i]);
160734b664a2SJames Hogan 		}
160834b664a2SJames Hogan 	} else
160934b664a2SJames Hogan #endif
161034b664a2SJames Hogan 	{
161134b664a2SJames Hogan 		u64 *pdata = buf;
161234b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
16134e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset), *pdata++);
161434b664a2SJames Hogan 		buf = pdata;
161534b664a2SJames Hogan 	}
161634b664a2SJames Hogan 	/* put anything remaining in the part_buf */
161734b664a2SJames Hogan 	if (cnt) {
161834b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1619cfbeb59cSMarkos Chandras 		/* Push data if we have reached the expected data length */
1620cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1621cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
16224e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset),
16234e0a5adfSJaehoon Chung 				   host->part_buf);
1624f95f3850SWill Newton 	}
1625f95f3850SWill Newton }
1626f95f3850SWill Newton 
1627f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
1628f95f3850SWill Newton {
162934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
163034b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
163134b664a2SJames Hogan 		while (cnt >= 8) {
163234b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
163334b664a2SJames Hogan 			u64 aligned_buf[16];
163434b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
163534b664a2SJames Hogan 			int items = len >> 3;
163634b664a2SJames Hogan 			int i;
163734b664a2SJames Hogan 			for (i = 0; i < items; ++i)
16384e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readq(host,
16394e0a5adfSJaehoon Chung 						DATA(host->data_offset));
164034b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
164134b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
164234b664a2SJames Hogan 			buf += len;
164334b664a2SJames Hogan 			cnt -= len;
1644f95f3850SWill Newton 		}
164534b664a2SJames Hogan 	} else
164634b664a2SJames Hogan #endif
164734b664a2SJames Hogan 	{
164834b664a2SJames Hogan 		u64 *pdata = buf;
164934b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
16504e0a5adfSJaehoon Chung 			*pdata++ = mci_readq(host, DATA(host->data_offset));
165134b664a2SJames Hogan 		buf = pdata;
165234b664a2SJames Hogan 	}
165334b664a2SJames Hogan 	if (cnt) {
16544e0a5adfSJaehoon Chung 		host->part_buf = mci_readq(host, DATA(host->data_offset));
165534b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
165634b664a2SJames Hogan 	}
165734b664a2SJames Hogan }
165834b664a2SJames Hogan 
165934b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
166034b664a2SJames Hogan {
166134b664a2SJames Hogan 	int len;
166234b664a2SJames Hogan 
166334b664a2SJames Hogan 	/* get remaining partial bytes */
166434b664a2SJames Hogan 	len = dw_mci_pull_part_bytes(host, buf, cnt);
166534b664a2SJames Hogan 	if (unlikely(len == cnt))
166634b664a2SJames Hogan 		return;
166734b664a2SJames Hogan 	buf += len;
166834b664a2SJames Hogan 	cnt -= len;
166934b664a2SJames Hogan 
167034b664a2SJames Hogan 	/* get the rest of the data */
167134b664a2SJames Hogan 	host->pull_data(host, buf, cnt);
1672f95f3850SWill Newton }
1673f95f3850SWill Newton 
167487a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto)
1675f95f3850SWill Newton {
1676f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1677f9c2a0dcSSeungwon Jeon 	void *buf;
1678f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1679f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1680f95f3850SWill Newton 	int shift = host->data_shift;
1681f95f3850SWill Newton 	u32 status;
16823e4b0d8bSMarkos Chandras 	unsigned int len;
1683f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1684f95f3850SWill Newton 
1685f95f3850SWill Newton 	do {
1686f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1687f9c2a0dcSSeungwon Jeon 			goto done;
1688f95f3850SWill Newton 
16894225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1690f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1691f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1692f9c2a0dcSSeungwon Jeon 		offset = 0;
1693f9c2a0dcSSeungwon Jeon 
1694f9c2a0dcSSeungwon Jeon 		do {
1695f9c2a0dcSSeungwon Jeon 			fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS))
1696f9c2a0dcSSeungwon Jeon 					<< shift) + host->part_buf_count;
1697f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1698f9c2a0dcSSeungwon Jeon 			if (!len)
1699f9c2a0dcSSeungwon Jeon 				break;
1700f9c2a0dcSSeungwon Jeon 			dw_mci_pull_data(host, (void *)(buf + offset), len);
17013e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1702f95f3850SWill Newton 			offset += len;
1703f9c2a0dcSSeungwon Jeon 			remain -= len;
1704f9c2a0dcSSeungwon Jeon 		} while (remain);
1705f95f3850SWill Newton 
1706e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1707f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1708f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
170987a74d39SKyoungil Kim 	/* if the RXDR is ready read again */
171087a74d39SKyoungil Kim 	} while ((status & SDMMC_INT_RXDR) ||
171187a74d39SKyoungil Kim 		 (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS))));
1712f9c2a0dcSSeungwon Jeon 
1713f9c2a0dcSSeungwon Jeon 	if (!remain) {
1714f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1715f9c2a0dcSSeungwon Jeon 			goto done;
1716f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1717f9c2a0dcSSeungwon Jeon 	}
1718f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1719f95f3850SWill Newton 	return;
1720f95f3850SWill Newton 
1721f95f3850SWill Newton done:
1722f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1723f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1724f95f3850SWill Newton 	smp_wmb();
1725f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1726f95f3850SWill Newton }
1727f95f3850SWill Newton 
1728f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host)
1729f95f3850SWill Newton {
1730f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1731f9c2a0dcSSeungwon Jeon 	void *buf;
1732f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1733f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1734f95f3850SWill Newton 	int shift = host->data_shift;
1735f95f3850SWill Newton 	u32 status;
17363e4b0d8bSMarkos Chandras 	unsigned int len;
1737f9c2a0dcSSeungwon Jeon 	unsigned int fifo_depth = host->fifo_depth;
1738f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1739f95f3850SWill Newton 
1740f95f3850SWill Newton 	do {
1741f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1742f9c2a0dcSSeungwon Jeon 			goto done;
1743f95f3850SWill Newton 
17444225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1745f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1746f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1747f9c2a0dcSSeungwon Jeon 		offset = 0;
1748f9c2a0dcSSeungwon Jeon 
1749f9c2a0dcSSeungwon Jeon 		do {
1750f9c2a0dcSSeungwon Jeon 			fcnt = ((fifo_depth -
1751f9c2a0dcSSeungwon Jeon 				 SDMMC_GET_FCNT(mci_readl(host, STATUS)))
1752f9c2a0dcSSeungwon Jeon 					<< shift) - host->part_buf_count;
1753f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1754f9c2a0dcSSeungwon Jeon 			if (!len)
1755f9c2a0dcSSeungwon Jeon 				break;
1756f9c2a0dcSSeungwon Jeon 			host->push_data(host, (void *)(buf + offset), len);
17573e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1758f95f3850SWill Newton 			offset += len;
1759f9c2a0dcSSeungwon Jeon 			remain -= len;
1760f9c2a0dcSSeungwon Jeon 		} while (remain);
1761f95f3850SWill Newton 
1762e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1763f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1764f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1765f95f3850SWill Newton 	} while (status & SDMMC_INT_TXDR); /* if TXDR write again */
1766f9c2a0dcSSeungwon Jeon 
1767f9c2a0dcSSeungwon Jeon 	if (!remain) {
1768f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1769f9c2a0dcSSeungwon Jeon 			goto done;
1770f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1771f9c2a0dcSSeungwon Jeon 	}
1772f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1773f95f3850SWill Newton 	return;
1774f95f3850SWill Newton 
1775f95f3850SWill Newton done:
1776f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1777f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1778f95f3850SWill Newton 	smp_wmb();
1779f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1780f95f3850SWill Newton }
1781f95f3850SWill Newton 
1782f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
1783f95f3850SWill Newton {
1784f95f3850SWill Newton 	if (!host->cmd_status)
1785f95f3850SWill Newton 		host->cmd_status = status;
1786f95f3850SWill Newton 
1787f95f3850SWill Newton 	smp_wmb();
1788f95f3850SWill Newton 
1789f95f3850SWill Newton 	set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1790f95f3850SWill Newton 	tasklet_schedule(&host->tasklet);
1791f95f3850SWill Newton }
1792f95f3850SWill Newton 
1793f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
1794f95f3850SWill Newton {
1795f95f3850SWill Newton 	struct dw_mci *host = dev_id;
1796182c9081SSeungwon Jeon 	u32 pending;
17971a5c8e1fSShashidhar Hiremath 	int i;
1798f95f3850SWill Newton 
1799f95f3850SWill Newton 	pending = mci_readl(host, MINTSTS); /* read-only mask reg */
1800f95f3850SWill Newton 
1801f95f3850SWill Newton 	/*
1802f95f3850SWill Newton 	 * DTO fix - version 2.10a and below, and only if internal DMA
1803f95f3850SWill Newton 	 * is configured.
1804f95f3850SWill Newton 	 */
1805f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
1806f95f3850SWill Newton 		if (!pending &&
1807f95f3850SWill Newton 		    ((mci_readl(host, STATUS) >> 17) & 0x1fff))
1808f95f3850SWill Newton 			pending |= SDMMC_INT_DATA_OVER;
1809f95f3850SWill Newton 	}
1810f95f3850SWill Newton 
1811476d79f1SDoug Anderson 	if (pending) {
1812f95f3850SWill Newton 		if (pending & DW_MCI_CMD_ERROR_FLAGS) {
1813f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
1814182c9081SSeungwon Jeon 			host->cmd_status = pending;
1815f95f3850SWill Newton 			smp_wmb();
1816f95f3850SWill Newton 			set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1817f95f3850SWill Newton 		}
1818f95f3850SWill Newton 
1819f95f3850SWill Newton 		if (pending & DW_MCI_DATA_ERROR_FLAGS) {
1820f95f3850SWill Newton 			/* if there is an error report DATA_ERROR */
1821f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
1822182c9081SSeungwon Jeon 			host->data_status = pending;
1823f95f3850SWill Newton 			smp_wmb();
1824f95f3850SWill Newton 			set_bit(EVENT_DATA_ERROR, &host->pending_events);
1825f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
1826f95f3850SWill Newton 		}
1827f95f3850SWill Newton 
1828f95f3850SWill Newton 		if (pending & SDMMC_INT_DATA_OVER) {
1829f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
1830f95f3850SWill Newton 			if (!host->data_status)
1831182c9081SSeungwon Jeon 				host->data_status = pending;
1832f95f3850SWill Newton 			smp_wmb();
1833f95f3850SWill Newton 			if (host->dir_status == DW_MCI_RECV_STATUS) {
1834f95f3850SWill Newton 				if (host->sg != NULL)
183587a74d39SKyoungil Kim 					dw_mci_read_data_pio(host, true);
1836f95f3850SWill Newton 			}
1837f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
1838f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
1839f95f3850SWill Newton 		}
1840f95f3850SWill Newton 
1841f95f3850SWill Newton 		if (pending & SDMMC_INT_RXDR) {
1842f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
1843b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_RECV_STATUS && host->sg)
184487a74d39SKyoungil Kim 				dw_mci_read_data_pio(host, false);
1845f95f3850SWill Newton 		}
1846f95f3850SWill Newton 
1847f95f3850SWill Newton 		if (pending & SDMMC_INT_TXDR) {
1848f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1849b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_SEND_STATUS && host->sg)
1850f95f3850SWill Newton 				dw_mci_write_data_pio(host);
1851f95f3850SWill Newton 		}
1852f95f3850SWill Newton 
1853f95f3850SWill Newton 		if (pending & SDMMC_INT_CMD_DONE) {
1854f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
1855182c9081SSeungwon Jeon 			dw_mci_cmd_interrupt(host, pending);
1856f95f3850SWill Newton 		}
1857f95f3850SWill Newton 
1858f95f3850SWill Newton 		if (pending & SDMMC_INT_CD) {
1859f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CD);
186095dcc2cbSThomas Abraham 			queue_work(host->card_workqueue, &host->card_work);
1861f95f3850SWill Newton 		}
1862f95f3850SWill Newton 
18631a5c8e1fSShashidhar Hiremath 		/* Handle SDIO Interrupts */
18641a5c8e1fSShashidhar Hiremath 		for (i = 0; i < host->num_slots; i++) {
18651a5c8e1fSShashidhar Hiremath 			struct dw_mci_slot *slot = host->slot[i];
18661a5c8e1fSShashidhar Hiremath 			if (pending & SDMMC_INT_SDIO(i)) {
18671a5c8e1fSShashidhar Hiremath 				mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
18681a5c8e1fSShashidhar Hiremath 				mmc_signal_sdio_irq(slot->mmc);
18691a5c8e1fSShashidhar Hiremath 			}
18701a5c8e1fSShashidhar Hiremath 		}
18711a5c8e1fSShashidhar Hiremath 
18721fb5f68aSMarkos Chandras 	}
1873f95f3850SWill Newton 
1874f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
1875f95f3850SWill Newton 	/* Handle DMA interrupts */
1876f95f3850SWill Newton 	pending = mci_readl(host, IDSTS);
1877f95f3850SWill Newton 	if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
1878f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
1879f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
1880f95f3850SWill Newton 		host->dma_ops->complete(host);
1881f95f3850SWill Newton 	}
1882f95f3850SWill Newton #endif
1883f95f3850SWill Newton 
1884f95f3850SWill Newton 	return IRQ_HANDLED;
1885f95f3850SWill Newton }
1886f95f3850SWill Newton 
18871791b13eSJames Hogan static void dw_mci_work_routine_card(struct work_struct *work)
1888f95f3850SWill Newton {
18891791b13eSJames Hogan 	struct dw_mci *host = container_of(work, struct dw_mci, card_work);
1890f95f3850SWill Newton 	int i;
1891f95f3850SWill Newton 
1892f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
1893f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
1894f95f3850SWill Newton 		struct mmc_host *mmc = slot->mmc;
1895f95f3850SWill Newton 		struct mmc_request *mrq;
1896f95f3850SWill Newton 		int present;
1897f95f3850SWill Newton 		u32 ctrl;
1898f95f3850SWill Newton 
1899f95f3850SWill Newton 		present = dw_mci_get_cd(mmc);
1900f95f3850SWill Newton 		while (present != slot->last_detect_state) {
1901f95f3850SWill Newton 			dev_dbg(&slot->mmc->class_dev, "card %s\n",
1902f95f3850SWill Newton 				present ? "inserted" : "removed");
1903f95f3850SWill Newton 
19041791b13eSJames Hogan 			spin_lock_bh(&host->lock);
19051791b13eSJames Hogan 
1906f95f3850SWill Newton 			/* Card change detected */
1907f95f3850SWill Newton 			slot->last_detect_state = present;
1908f95f3850SWill Newton 
19091791b13eSJames Hogan 			/* Mark card as present if applicable */
19101791b13eSJames Hogan 			if (present != 0)
1911f95f3850SWill Newton 				set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
1912f95f3850SWill Newton 
1913f95f3850SWill Newton 			/* Clean up queue if present */
1914f95f3850SWill Newton 			mrq = slot->mrq;
1915f95f3850SWill Newton 			if (mrq) {
1916f95f3850SWill Newton 				if (mrq == host->mrq) {
1917f95f3850SWill Newton 					host->data = NULL;
1918f95f3850SWill Newton 					host->cmd = NULL;
1919f95f3850SWill Newton 
1920f95f3850SWill Newton 					switch (host->state) {
1921f95f3850SWill Newton 					case STATE_IDLE:
1922f95f3850SWill Newton 						break;
1923f95f3850SWill Newton 					case STATE_SENDING_CMD:
1924f95f3850SWill Newton 						mrq->cmd->error = -ENOMEDIUM;
1925f95f3850SWill Newton 						if (!mrq->data)
1926f95f3850SWill Newton 							break;
1927f95f3850SWill Newton 						/* fall through */
1928f95f3850SWill Newton 					case STATE_SENDING_DATA:
1929f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
1930f95f3850SWill Newton 						dw_mci_stop_dma(host);
1931f95f3850SWill Newton 						break;
1932f95f3850SWill Newton 					case STATE_DATA_BUSY:
1933f95f3850SWill Newton 					case STATE_DATA_ERROR:
1934f95f3850SWill Newton 						if (mrq->data->error == -EINPROGRESS)
1935f95f3850SWill Newton 							mrq->data->error = -ENOMEDIUM;
1936f95f3850SWill Newton 						/* fall through */
1937f95f3850SWill Newton 					case STATE_SENDING_STOP:
1938*90c2143aSSeungwon Jeon 						if (mrq->stop)
1939f95f3850SWill Newton 							mrq->stop->error = -ENOMEDIUM;
1940f95f3850SWill Newton 						break;
1941f95f3850SWill Newton 					}
1942f95f3850SWill Newton 
1943f95f3850SWill Newton 					dw_mci_request_end(host, mrq);
1944f95f3850SWill Newton 				} else {
1945f95f3850SWill Newton 					list_del(&slot->queue_node);
1946f95f3850SWill Newton 					mrq->cmd->error = -ENOMEDIUM;
1947f95f3850SWill Newton 					if (mrq->data)
1948f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
1949f95f3850SWill Newton 					if (mrq->stop)
1950f95f3850SWill Newton 						mrq->stop->error = -ENOMEDIUM;
1951f95f3850SWill Newton 
1952f95f3850SWill Newton 					spin_unlock(&host->lock);
1953f95f3850SWill Newton 					mmc_request_done(slot->mmc, mrq);
1954f95f3850SWill Newton 					spin_lock(&host->lock);
1955f95f3850SWill Newton 				}
1956f95f3850SWill Newton 			}
1957f95f3850SWill Newton 
1958f95f3850SWill Newton 			/* Power down slot */
1959f95f3850SWill Newton 			if (present == 0) {
1960f95f3850SWill Newton 				clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
1961f95f3850SWill Newton 
1962f95f3850SWill Newton 				/*
1963f95f3850SWill Newton 				 * Clear down the FIFO - doing so generates a
1964f95f3850SWill Newton 				 * block interrupt, hence setting the
1965f95f3850SWill Newton 				 * scatter-gather pointer to NULL.
1966f95f3850SWill Newton 				 */
1967f9c2a0dcSSeungwon Jeon 				sg_miter_stop(&host->sg_miter);
1968f95f3850SWill Newton 				host->sg = NULL;
1969f95f3850SWill Newton 
1970f95f3850SWill Newton 				ctrl = mci_readl(host, CTRL);
1971f95f3850SWill Newton 				ctrl |= SDMMC_CTRL_FIFO_RESET;
1972f95f3850SWill Newton 				mci_writel(host, CTRL, ctrl);
1973f95f3850SWill Newton 
1974f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
1975f95f3850SWill Newton 				ctrl = mci_readl(host, BMOD);
1976141a712aSSeungwon Jeon 				/* Software reset of DMA */
1977141a712aSSeungwon Jeon 				ctrl |= SDMMC_IDMAC_SWRESET;
1978f95f3850SWill Newton 				mci_writel(host, BMOD, ctrl);
1979f95f3850SWill Newton #endif
1980f95f3850SWill Newton 
1981f95f3850SWill Newton 			}
1982f95f3850SWill Newton 
19831791b13eSJames Hogan 			spin_unlock_bh(&host->lock);
19841791b13eSJames Hogan 
1985f95f3850SWill Newton 			present = dw_mci_get_cd(mmc);
1986f95f3850SWill Newton 		}
1987f95f3850SWill Newton 
1988f95f3850SWill Newton 		mmc_detect_change(slot->mmc,
1989f95f3850SWill Newton 			msecs_to_jiffies(host->pdata->detect_delay_ms));
1990f95f3850SWill Newton 	}
1991f95f3850SWill Newton }
1992f95f3850SWill Newton 
1993c91eab4bSThomas Abraham #ifdef CONFIG_OF
1994c91eab4bSThomas Abraham /* given a slot id, find out the device node representing that slot */
1995c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
1996c91eab4bSThomas Abraham {
1997c91eab4bSThomas Abraham 	struct device_node *np;
1998c91eab4bSThomas Abraham 	const __be32 *addr;
1999c91eab4bSThomas Abraham 	int len;
2000c91eab4bSThomas Abraham 
2001c91eab4bSThomas Abraham 	if (!dev || !dev->of_node)
2002c91eab4bSThomas Abraham 		return NULL;
2003c91eab4bSThomas Abraham 
2004c91eab4bSThomas Abraham 	for_each_child_of_node(dev->of_node, np) {
2005c91eab4bSThomas Abraham 		addr = of_get_property(np, "reg", &len);
2006c91eab4bSThomas Abraham 		if (!addr || (len < sizeof(int)))
2007c91eab4bSThomas Abraham 			continue;
2008c91eab4bSThomas Abraham 		if (be32_to_cpup(addr) == slot)
2009c91eab4bSThomas Abraham 			return np;
2010c91eab4bSThomas Abraham 	}
2011c91eab4bSThomas Abraham 	return NULL;
2012c91eab4bSThomas Abraham }
2013c91eab4bSThomas Abraham 
2014a70aaa64SDoug Anderson static struct dw_mci_of_slot_quirks {
2015a70aaa64SDoug Anderson 	char *quirk;
2016a70aaa64SDoug Anderson 	int id;
2017a70aaa64SDoug Anderson } of_slot_quirks[] = {
2018a70aaa64SDoug Anderson 	{
2019a70aaa64SDoug Anderson 		.quirk	= "disable-wp",
2020a70aaa64SDoug Anderson 		.id	= DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT,
2021a70aaa64SDoug Anderson 	},
2022a70aaa64SDoug Anderson };
2023a70aaa64SDoug Anderson 
2024a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
2025a70aaa64SDoug Anderson {
2026a70aaa64SDoug Anderson 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
2027a70aaa64SDoug Anderson 	int quirks = 0;
2028a70aaa64SDoug Anderson 	int idx;
2029a70aaa64SDoug Anderson 
2030a70aaa64SDoug Anderson 	/* get quirks */
2031a70aaa64SDoug Anderson 	for (idx = 0; idx < ARRAY_SIZE(of_slot_quirks); idx++)
2032a70aaa64SDoug Anderson 		if (of_get_property(np, of_slot_quirks[idx].quirk, NULL))
2033a70aaa64SDoug Anderson 			quirks |= of_slot_quirks[idx].id;
2034a70aaa64SDoug Anderson 
2035a70aaa64SDoug Anderson 	return quirks;
2036a70aaa64SDoug Anderson }
2037a70aaa64SDoug Anderson 
2038c91eab4bSThomas Abraham /* find out bus-width for a given slot */
2039c91eab4bSThomas Abraham static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
2040c91eab4bSThomas Abraham {
2041c91eab4bSThomas Abraham 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
2042c91eab4bSThomas Abraham 	u32 bus_wd = 1;
2043c91eab4bSThomas Abraham 
2044c91eab4bSThomas Abraham 	if (!np)
2045c91eab4bSThomas Abraham 		return 1;
2046c91eab4bSThomas Abraham 
2047c91eab4bSThomas Abraham 	if (of_property_read_u32(np, "bus-width", &bus_wd))
2048c91eab4bSThomas Abraham 		dev_err(dev, "bus-width property not found, assuming width"
2049c91eab4bSThomas Abraham 			       " as 1\n");
2050c91eab4bSThomas Abraham 	return bus_wd;
2051c91eab4bSThomas Abraham }
205255a6ceb2SDoug Anderson 
205355a6ceb2SDoug Anderson /* find the write protect gpio for a given slot; or -1 if none specified */
205455a6ceb2SDoug Anderson static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
205555a6ceb2SDoug Anderson {
205655a6ceb2SDoug Anderson 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
205755a6ceb2SDoug Anderson 	int gpio;
205855a6ceb2SDoug Anderson 
205955a6ceb2SDoug Anderson 	if (!np)
206055a6ceb2SDoug Anderson 		return -EINVAL;
206155a6ceb2SDoug Anderson 
206255a6ceb2SDoug Anderson 	gpio = of_get_named_gpio(np, "wp-gpios", 0);
206355a6ceb2SDoug Anderson 
206455a6ceb2SDoug Anderson 	/* Having a missing entry is valid; return silently */
206555a6ceb2SDoug Anderson 	if (!gpio_is_valid(gpio))
206655a6ceb2SDoug Anderson 		return -EINVAL;
206755a6ceb2SDoug Anderson 
206855a6ceb2SDoug Anderson 	if (devm_gpio_request(dev, gpio, "dw-mci-wp")) {
206955a6ceb2SDoug Anderson 		dev_warn(dev, "gpio [%d] request failed\n", gpio);
207055a6ceb2SDoug Anderson 		return -EINVAL;
207155a6ceb2SDoug Anderson 	}
207255a6ceb2SDoug Anderson 
207355a6ceb2SDoug Anderson 	return gpio;
207455a6ceb2SDoug Anderson }
2075c91eab4bSThomas Abraham #else /* CONFIG_OF */
2076a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
2077a70aaa64SDoug Anderson {
2078a70aaa64SDoug Anderson 	return 0;
2079a70aaa64SDoug Anderson }
2080c91eab4bSThomas Abraham static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
2081c91eab4bSThomas Abraham {
2082c91eab4bSThomas Abraham 	return 1;
2083c91eab4bSThomas Abraham }
2084c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
2085c91eab4bSThomas Abraham {
2086c91eab4bSThomas Abraham 	return NULL;
2087c91eab4bSThomas Abraham }
208855a6ceb2SDoug Anderson static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
208955a6ceb2SDoug Anderson {
209055a6ceb2SDoug Anderson 	return -EINVAL;
209155a6ceb2SDoug Anderson }
2092c91eab4bSThomas Abraham #endif /* CONFIG_OF */
2093c91eab4bSThomas Abraham 
209436c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
2095f95f3850SWill Newton {
2096f95f3850SWill Newton 	struct mmc_host *mmc;
2097f95f3850SWill Newton 	struct dw_mci_slot *slot;
2098e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
2099800d78bfSThomas Abraham 	int ctrl_id, ret;
21001f44a2a5SSeungwon Jeon 	u32 freq[2];
2101c91eab4bSThomas Abraham 	u8 bus_width;
2102f95f3850SWill Newton 
21034a90920cSThomas Abraham 	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
2104f95f3850SWill Newton 	if (!mmc)
2105f95f3850SWill Newton 		return -ENOMEM;
2106f95f3850SWill Newton 
2107f95f3850SWill Newton 	slot = mmc_priv(mmc);
2108f95f3850SWill Newton 	slot->id = id;
2109f95f3850SWill Newton 	slot->mmc = mmc;
2110f95f3850SWill Newton 	slot->host = host;
2111c91eab4bSThomas Abraham 	host->slot[id] = slot;
2112f95f3850SWill Newton 
2113a70aaa64SDoug Anderson 	slot->quirks = dw_mci_of_get_slot_quirks(host->dev, slot->id);
2114a70aaa64SDoug Anderson 
2115f95f3850SWill Newton 	mmc->ops = &dw_mci_ops;
21161f44a2a5SSeungwon Jeon 	if (of_property_read_u32_array(host->dev->of_node,
21171f44a2a5SSeungwon Jeon 				       "clock-freq-min-max", freq, 2)) {
21181f44a2a5SSeungwon Jeon 		mmc->f_min = DW_MCI_FREQ_MIN;
21191f44a2a5SSeungwon Jeon 		mmc->f_max = DW_MCI_FREQ_MAX;
21201f44a2a5SSeungwon Jeon 	} else {
21211f44a2a5SSeungwon Jeon 		mmc->f_min = freq[0];
21221f44a2a5SSeungwon Jeon 		mmc->f_max = freq[1];
21231f44a2a5SSeungwon Jeon 	}
2124f95f3850SWill Newton 
2125f95f3850SWill Newton 	if (host->pdata->get_ocr)
2126f95f3850SWill Newton 		mmc->ocr_avail = host->pdata->get_ocr(id);
2127f95f3850SWill Newton 	else
2128f95f3850SWill Newton 		mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
2129f95f3850SWill Newton 
2130f95f3850SWill Newton 	/*
2131f95f3850SWill Newton 	 * Start with slot power disabled, it will be enabled when a card
2132f95f3850SWill Newton 	 * is detected.
2133f95f3850SWill Newton 	 */
2134f95f3850SWill Newton 	if (host->pdata->setpower)
2135f95f3850SWill Newton 		host->pdata->setpower(id, 0);
2136f95f3850SWill Newton 
2137fc3d7720SJaehoon Chung 	if (host->pdata->caps)
2138fc3d7720SJaehoon Chung 		mmc->caps = host->pdata->caps;
2139fc3d7720SJaehoon Chung 
2140ab269128SAbhilash Kesavan 	if (host->pdata->pm_caps)
2141ab269128SAbhilash Kesavan 		mmc->pm_caps = host->pdata->pm_caps;
2142ab269128SAbhilash Kesavan 
2143800d78bfSThomas Abraham 	if (host->dev->of_node) {
2144800d78bfSThomas Abraham 		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
2145800d78bfSThomas Abraham 		if (ctrl_id < 0)
2146800d78bfSThomas Abraham 			ctrl_id = 0;
2147800d78bfSThomas Abraham 	} else {
2148800d78bfSThomas Abraham 		ctrl_id = to_platform_device(host->dev)->id;
2149800d78bfSThomas Abraham 	}
2150cb27a843SJames Hogan 	if (drv_data && drv_data->caps)
2151cb27a843SJames Hogan 		mmc->caps |= drv_data->caps[ctrl_id];
2152800d78bfSThomas Abraham 
21534f408cc6SSeungwon Jeon 	if (host->pdata->caps2)
21544f408cc6SSeungwon Jeon 		mmc->caps2 = host->pdata->caps2;
21554f408cc6SSeungwon Jeon 
2156f95f3850SWill Newton 	if (host->pdata->get_bus_wd)
2157c91eab4bSThomas Abraham 		bus_width = host->pdata->get_bus_wd(slot->id);
2158c91eab4bSThomas Abraham 	else if (host->dev->of_node)
2159c91eab4bSThomas Abraham 		bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
2160c91eab4bSThomas Abraham 	else
2161c91eab4bSThomas Abraham 		bus_width = 1;
2162c91eab4bSThomas Abraham 
2163c91eab4bSThomas Abraham 	switch (bus_width) {
2164c91eab4bSThomas Abraham 	case 8:
2165c91eab4bSThomas Abraham 		mmc->caps |= MMC_CAP_8_BIT_DATA;
2166c91eab4bSThomas Abraham 	case 4:
2167f95f3850SWill Newton 		mmc->caps |= MMC_CAP_4_BIT_DATA;
2168c91eab4bSThomas Abraham 	}
2169f95f3850SWill Newton 
2170f95f3850SWill Newton 	if (host->pdata->blk_settings) {
2171f95f3850SWill Newton 		mmc->max_segs = host->pdata->blk_settings->max_segs;
2172f95f3850SWill Newton 		mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
2173f95f3850SWill Newton 		mmc->max_blk_count = host->pdata->blk_settings->max_blk_count;
2174f95f3850SWill Newton 		mmc->max_req_size = host->pdata->blk_settings->max_req_size;
2175f95f3850SWill Newton 		mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
2176f95f3850SWill Newton 	} else {
2177f95f3850SWill Newton 		/* Useful defaults if platform data is unset. */
2178a39e5746SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
2179a39e5746SJaehoon Chung 		mmc->max_segs = host->ring_size;
2180a39e5746SJaehoon Chung 		mmc->max_blk_size = 65536;
2181a39e5746SJaehoon Chung 		mmc->max_blk_count = host->ring_size;
2182a39e5746SJaehoon Chung 		mmc->max_seg_size = 0x1000;
2183a39e5746SJaehoon Chung 		mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
2184a39e5746SJaehoon Chung #else
2185f95f3850SWill Newton 		mmc->max_segs = 64;
2186f95f3850SWill Newton 		mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
2187f95f3850SWill Newton 		mmc->max_blk_count = 512;
2188f95f3850SWill Newton 		mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
2189f95f3850SWill Newton 		mmc->max_seg_size = mmc->max_req_size;
2190f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */
2191a39e5746SJaehoon Chung 	}
2192f95f3850SWill Newton 
2193f95f3850SWill Newton 	if (dw_mci_get_cd(mmc))
2194f95f3850SWill Newton 		set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
2195f95f3850SWill Newton 	else
2196f95f3850SWill Newton 		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
2197f95f3850SWill Newton 
219855a6ceb2SDoug Anderson 	slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id);
219955a6ceb2SDoug Anderson 
22000cea529dSJaehoon Chung 	ret = mmc_add_host(mmc);
22010cea529dSJaehoon Chung 	if (ret)
22020cea529dSJaehoon Chung 		goto err_setup_bus;
2203f95f3850SWill Newton 
2204f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS)
2205f95f3850SWill Newton 	dw_mci_init_debugfs(slot);
2206f95f3850SWill Newton #endif
2207f95f3850SWill Newton 
2208f95f3850SWill Newton 	/* Card initially undetected */
2209f95f3850SWill Newton 	slot->last_detect_state = 0;
2210f95f3850SWill Newton 
2211f95f3850SWill Newton 	return 0;
2212800d78bfSThomas Abraham 
2213800d78bfSThomas Abraham err_setup_bus:
2214800d78bfSThomas Abraham 	mmc_free_host(mmc);
2215800d78bfSThomas Abraham 	return -EINVAL;
2216f95f3850SWill Newton }
2217f95f3850SWill Newton 
2218f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
2219f95f3850SWill Newton {
2220f95f3850SWill Newton 	/* Shutdown detect IRQ */
2221f95f3850SWill Newton 	if (slot->host->pdata->exit)
2222f95f3850SWill Newton 		slot->host->pdata->exit(id);
2223f95f3850SWill Newton 
2224f95f3850SWill Newton 	/* Debugfs stuff is cleaned up by mmc core */
2225f95f3850SWill Newton 	mmc_remove_host(slot->mmc);
2226f95f3850SWill Newton 	slot->host->slot[id] = NULL;
2227f95f3850SWill Newton 	mmc_free_host(slot->mmc);
2228f95f3850SWill Newton }
2229f95f3850SWill Newton 
2230f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host)
2231f95f3850SWill Newton {
2232f95f3850SWill Newton 	/* Alloc memory for sg translation */
2233780f22afSSeungwon Jeon 	host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
2234f95f3850SWill Newton 					  &host->sg_dma, GFP_KERNEL);
2235f95f3850SWill Newton 	if (!host->sg_cpu) {
22364a90920cSThomas Abraham 		dev_err(host->dev, "%s: could not alloc DMA memory\n",
2237f95f3850SWill Newton 			__func__);
2238f95f3850SWill Newton 		goto no_dma;
2239f95f3850SWill Newton 	}
2240f95f3850SWill Newton 
2241f95f3850SWill Newton 	/* Determine which DMA interface to use */
2242f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
2243f95f3850SWill Newton 	host->dma_ops = &dw_mci_idmac_ops;
224400956ea3SSeungwon Jeon 	dev_info(host->dev, "Using internal DMA controller.\n");
2245f95f3850SWill Newton #endif
2246f95f3850SWill Newton 
2247f95f3850SWill Newton 	if (!host->dma_ops)
2248f95f3850SWill Newton 		goto no_dma;
2249f95f3850SWill Newton 
2250e1631f98SJaehoon Chung 	if (host->dma_ops->init && host->dma_ops->start &&
2251e1631f98SJaehoon Chung 	    host->dma_ops->stop && host->dma_ops->cleanup) {
2252f95f3850SWill Newton 		if (host->dma_ops->init(host)) {
22534a90920cSThomas Abraham 			dev_err(host->dev, "%s: Unable to initialize "
2254f95f3850SWill Newton 				"DMA Controller.\n", __func__);
2255f95f3850SWill Newton 			goto no_dma;
2256f95f3850SWill Newton 		}
2257f95f3850SWill Newton 	} else {
22584a90920cSThomas Abraham 		dev_err(host->dev, "DMA initialization not found.\n");
2259f95f3850SWill Newton 		goto no_dma;
2260f95f3850SWill Newton 	}
2261f95f3850SWill Newton 
2262f95f3850SWill Newton 	host->use_dma = 1;
2263f95f3850SWill Newton 	return;
2264f95f3850SWill Newton 
2265f95f3850SWill Newton no_dma:
22664a90920cSThomas Abraham 	dev_info(host->dev, "Using PIO mode.\n");
2267f95f3850SWill Newton 	host->use_dma = 0;
2268f95f3850SWill Newton 	return;
2269f95f3850SWill Newton }
2270f95f3850SWill Newton 
2271f95f3850SWill Newton static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
2272f95f3850SWill Newton {
2273f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
2274f95f3850SWill Newton 	unsigned int ctrl;
2275f95f3850SWill Newton 
2276f95f3850SWill Newton 	mci_writel(host, CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET |
2277f95f3850SWill Newton 				SDMMC_CTRL_DMA_RESET));
2278f95f3850SWill Newton 
2279f95f3850SWill Newton 	/* wait till resets clear */
2280f95f3850SWill Newton 	do {
2281f95f3850SWill Newton 		ctrl = mci_readl(host, CTRL);
2282f95f3850SWill Newton 		if (!(ctrl & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET |
2283f95f3850SWill Newton 			      SDMMC_CTRL_DMA_RESET)))
2284f95f3850SWill Newton 			return true;
2285f95f3850SWill Newton 	} while (time_before(jiffies, timeout));
2286f95f3850SWill Newton 
2287f95f3850SWill Newton 	dev_err(dev, "Timeout resetting block (ctrl %#x)\n", ctrl);
2288f95f3850SWill Newton 
2289f95f3850SWill Newton 	return false;
2290f95f3850SWill Newton }
2291f95f3850SWill Newton 
2292c91eab4bSThomas Abraham #ifdef CONFIG_OF
2293c91eab4bSThomas Abraham static struct dw_mci_of_quirks {
2294c91eab4bSThomas Abraham 	char *quirk;
2295c91eab4bSThomas Abraham 	int id;
2296c91eab4bSThomas Abraham } of_quirks[] = {
2297c91eab4bSThomas Abraham 	{
2298c91eab4bSThomas Abraham 		.quirk	= "broken-cd",
2299c91eab4bSThomas Abraham 		.id	= DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
2300c91eab4bSThomas Abraham 	},
2301c91eab4bSThomas Abraham };
2302c91eab4bSThomas Abraham 
2303c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2304c91eab4bSThomas Abraham {
2305c91eab4bSThomas Abraham 	struct dw_mci_board *pdata;
2306c91eab4bSThomas Abraham 	struct device *dev = host->dev;
2307c91eab4bSThomas Abraham 	struct device_node *np = dev->of_node;
2308e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
2309800d78bfSThomas Abraham 	int idx, ret;
23103c6d89eaSDoug Anderson 	u32 clock_frequency;
2311c91eab4bSThomas Abraham 
2312c91eab4bSThomas Abraham 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
2313c91eab4bSThomas Abraham 	if (!pdata) {
2314c91eab4bSThomas Abraham 		dev_err(dev, "could not allocate memory for pdata\n");
2315c91eab4bSThomas Abraham 		return ERR_PTR(-ENOMEM);
2316c91eab4bSThomas Abraham 	}
2317c91eab4bSThomas Abraham 
2318c91eab4bSThomas Abraham 	/* find out number of slots supported */
2319c91eab4bSThomas Abraham 	if (of_property_read_u32(dev->of_node, "num-slots",
2320c91eab4bSThomas Abraham 				&pdata->num_slots)) {
2321c91eab4bSThomas Abraham 		dev_info(dev, "num-slots property not found, "
2322c91eab4bSThomas Abraham 				"assuming 1 slot is available\n");
2323c91eab4bSThomas Abraham 		pdata->num_slots = 1;
2324c91eab4bSThomas Abraham 	}
2325c91eab4bSThomas Abraham 
2326c91eab4bSThomas Abraham 	/* get quirks */
2327c91eab4bSThomas Abraham 	for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++)
2328c91eab4bSThomas Abraham 		if (of_get_property(np, of_quirks[idx].quirk, NULL))
2329c91eab4bSThomas Abraham 			pdata->quirks |= of_quirks[idx].id;
2330c91eab4bSThomas Abraham 
2331c91eab4bSThomas Abraham 	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
2332c91eab4bSThomas Abraham 		dev_info(dev, "fifo-depth property not found, using "
2333c91eab4bSThomas Abraham 				"value of FIFOTH register as default\n");
2334c91eab4bSThomas Abraham 
2335c91eab4bSThomas Abraham 	of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
2336c91eab4bSThomas Abraham 
23373c6d89eaSDoug Anderson 	if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
23383c6d89eaSDoug Anderson 		pdata->bus_hz = clock_frequency;
23393c6d89eaSDoug Anderson 
2340cb27a843SJames Hogan 	if (drv_data && drv_data->parse_dt) {
2341cb27a843SJames Hogan 		ret = drv_data->parse_dt(host);
2342800d78bfSThomas Abraham 		if (ret)
2343800d78bfSThomas Abraham 			return ERR_PTR(ret);
2344800d78bfSThomas Abraham 	}
2345800d78bfSThomas Abraham 
2346ab269128SAbhilash Kesavan 	if (of_find_property(np, "keep-power-in-suspend", NULL))
2347ab269128SAbhilash Kesavan 		pdata->pm_caps |= MMC_PM_KEEP_POWER;
2348ab269128SAbhilash Kesavan 
2349ab269128SAbhilash Kesavan 	if (of_find_property(np, "enable-sdio-wakeup", NULL))
2350ab269128SAbhilash Kesavan 		pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
2351ab269128SAbhilash Kesavan 
235210b49841SSeungwon Jeon 	if (of_find_property(np, "supports-highspeed", NULL))
235310b49841SSeungwon Jeon 		pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
235410b49841SSeungwon Jeon 
23555dd63f52SSeungwon Jeon 	if (of_find_property(np, "caps2-mmc-hs200-1_8v", NULL))
23565dd63f52SSeungwon Jeon 		pdata->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
23575dd63f52SSeungwon Jeon 
23585dd63f52SSeungwon Jeon 	if (of_find_property(np, "caps2-mmc-hs200-1_2v", NULL))
23595dd63f52SSeungwon Jeon 		pdata->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
23605dd63f52SSeungwon Jeon 
2361c91eab4bSThomas Abraham 	return pdata;
2362c91eab4bSThomas Abraham }
2363c91eab4bSThomas Abraham 
2364c91eab4bSThomas Abraham #else /* CONFIG_OF */
2365c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2366c91eab4bSThomas Abraham {
2367c91eab4bSThomas Abraham 	return ERR_PTR(-EINVAL);
2368c91eab4bSThomas Abraham }
2369c91eab4bSThomas Abraham #endif /* CONFIG_OF */
2370c91eab4bSThomas Abraham 
237162ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host)
2372f95f3850SWill Newton {
2373e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
237462ca8034SShashidhar Hiremath 	int width, i, ret = 0;
2375f95f3850SWill Newton 	u32 fifo_size;
23761c2215b7SThomas Abraham 	int init_slots = 0;
2377f95f3850SWill Newton 
2378c91eab4bSThomas Abraham 	if (!host->pdata) {
2379c91eab4bSThomas Abraham 		host->pdata = dw_mci_parse_dt(host);
2380c91eab4bSThomas Abraham 		if (IS_ERR(host->pdata)) {
2381c91eab4bSThomas Abraham 			dev_err(host->dev, "platform data not available\n");
2382c91eab4bSThomas Abraham 			return -EINVAL;
2383c91eab4bSThomas Abraham 		}
2384f95f3850SWill Newton 	}
2385f95f3850SWill Newton 
238662ca8034SShashidhar Hiremath 	if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
23874a90920cSThomas Abraham 		dev_err(host->dev,
2388f95f3850SWill Newton 			"Platform data must supply select_slot function\n");
238962ca8034SShashidhar Hiremath 		return -ENODEV;
2390f95f3850SWill Newton 	}
2391f95f3850SWill Newton 
2392780f22afSSeungwon Jeon 	host->biu_clk = devm_clk_get(host->dev, "biu");
2393f90a0612SThomas Abraham 	if (IS_ERR(host->biu_clk)) {
2394f90a0612SThomas Abraham 		dev_dbg(host->dev, "biu clock not available\n");
2395f90a0612SThomas Abraham 	} else {
2396f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->biu_clk);
2397f90a0612SThomas Abraham 		if (ret) {
2398f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable biu clock\n");
2399f90a0612SThomas Abraham 			return ret;
2400f90a0612SThomas Abraham 		}
2401f95f3850SWill Newton 	}
2402f95f3850SWill Newton 
2403780f22afSSeungwon Jeon 	host->ciu_clk = devm_clk_get(host->dev, "ciu");
2404f90a0612SThomas Abraham 	if (IS_ERR(host->ciu_clk)) {
2405f90a0612SThomas Abraham 		dev_dbg(host->dev, "ciu clock not available\n");
24063c6d89eaSDoug Anderson 		host->bus_hz = host->pdata->bus_hz;
2407f90a0612SThomas Abraham 	} else {
2408f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->ciu_clk);
2409f90a0612SThomas Abraham 		if (ret) {
2410f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable ciu clock\n");
2411f90a0612SThomas Abraham 			goto err_clk_biu;
2412f90a0612SThomas Abraham 		}
2413f90a0612SThomas Abraham 
24143c6d89eaSDoug Anderson 		if (host->pdata->bus_hz) {
24153c6d89eaSDoug Anderson 			ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz);
24163c6d89eaSDoug Anderson 			if (ret)
24173c6d89eaSDoug Anderson 				dev_warn(host->dev,
24183c6d89eaSDoug Anderson 					 "Unable to set bus rate to %ul\n",
24193c6d89eaSDoug Anderson 					 host->pdata->bus_hz);
24203c6d89eaSDoug Anderson 		}
2421f90a0612SThomas Abraham 		host->bus_hz = clk_get_rate(host->ciu_clk);
24223c6d89eaSDoug Anderson 	}
2423f90a0612SThomas Abraham 
2424002f0d5cSYuvaraj Kumar C D 	if (drv_data && drv_data->init) {
2425002f0d5cSYuvaraj Kumar C D 		ret = drv_data->init(host);
2426002f0d5cSYuvaraj Kumar C D 		if (ret) {
2427002f0d5cSYuvaraj Kumar C D 			dev_err(host->dev,
2428002f0d5cSYuvaraj Kumar C D 				"implementation specific init failed\n");
2429002f0d5cSYuvaraj Kumar C D 			goto err_clk_ciu;
2430002f0d5cSYuvaraj Kumar C D 		}
2431002f0d5cSYuvaraj Kumar C D 	}
2432002f0d5cSYuvaraj Kumar C D 
2433cb27a843SJames Hogan 	if (drv_data && drv_data->setup_clock) {
2434cb27a843SJames Hogan 		ret = drv_data->setup_clock(host);
2435800d78bfSThomas Abraham 		if (ret) {
2436800d78bfSThomas Abraham 			dev_err(host->dev,
2437800d78bfSThomas Abraham 				"implementation specific clock setup failed\n");
2438800d78bfSThomas Abraham 			goto err_clk_ciu;
2439800d78bfSThomas Abraham 		}
2440800d78bfSThomas Abraham 	}
2441800d78bfSThomas Abraham 
2442a55d6ff0SMark Brown 	host->vmmc = devm_regulator_get_optional(host->dev, "vmmc");
2443870556a3SDoug Anderson 	if (IS_ERR(host->vmmc)) {
2444870556a3SDoug Anderson 		ret = PTR_ERR(host->vmmc);
2445870556a3SDoug Anderson 		if (ret == -EPROBE_DEFER)
2446870556a3SDoug Anderson 			goto err_clk_ciu;
2447870556a3SDoug Anderson 
2448870556a3SDoug Anderson 		dev_info(host->dev, "no vmmc regulator found: %d\n", ret);
2449870556a3SDoug Anderson 		host->vmmc = NULL;
2450870556a3SDoug Anderson 	} else {
2451870556a3SDoug Anderson 		ret = regulator_enable(host->vmmc);
2452870556a3SDoug Anderson 		if (ret) {
2453870556a3SDoug Anderson 			if (ret != -EPROBE_DEFER)
2454870556a3SDoug Anderson 				dev_err(host->dev,
2455870556a3SDoug Anderson 					"regulator_enable fail: %d\n", ret);
2456870556a3SDoug Anderson 			goto err_clk_ciu;
2457870556a3SDoug Anderson 		}
2458870556a3SDoug Anderson 	}
2459870556a3SDoug Anderson 
2460f90a0612SThomas Abraham 	if (!host->bus_hz) {
2461f90a0612SThomas Abraham 		dev_err(host->dev,
2462f90a0612SThomas Abraham 			"Platform data must supply bus speed\n");
2463f90a0612SThomas Abraham 		ret = -ENODEV;
2464870556a3SDoug Anderson 		goto err_regulator;
2465f90a0612SThomas Abraham 	}
2466f90a0612SThomas Abraham 
246762ca8034SShashidhar Hiremath 	host->quirks = host->pdata->quirks;
2468f95f3850SWill Newton 
2469f95f3850SWill Newton 	spin_lock_init(&host->lock);
2470f95f3850SWill Newton 	INIT_LIST_HEAD(&host->queue);
2471f95f3850SWill Newton 
2472f95f3850SWill Newton 	/*
2473f95f3850SWill Newton 	 * Get the host data width - this assumes that HCON has been set with
2474f95f3850SWill Newton 	 * the correct values.
2475f95f3850SWill Newton 	 */
2476f95f3850SWill Newton 	i = (mci_readl(host, HCON) >> 7) & 0x7;
2477f95f3850SWill Newton 	if (!i) {
2478f95f3850SWill Newton 		host->push_data = dw_mci_push_data16;
2479f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data16;
2480f95f3850SWill Newton 		width = 16;
2481f95f3850SWill Newton 		host->data_shift = 1;
2482f95f3850SWill Newton 	} else if (i == 2) {
2483f95f3850SWill Newton 		host->push_data = dw_mci_push_data64;
2484f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data64;
2485f95f3850SWill Newton 		width = 64;
2486f95f3850SWill Newton 		host->data_shift = 3;
2487f95f3850SWill Newton 	} else {
2488f95f3850SWill Newton 		/* Check for a reserved value, and warn if it is */
2489f95f3850SWill Newton 		WARN((i != 1),
2490f95f3850SWill Newton 		     "HCON reports a reserved host data width!\n"
2491f95f3850SWill Newton 		     "Defaulting to 32-bit access.\n");
2492f95f3850SWill Newton 		host->push_data = dw_mci_push_data32;
2493f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data32;
2494f95f3850SWill Newton 		width = 32;
2495f95f3850SWill Newton 		host->data_shift = 2;
2496f95f3850SWill Newton 	}
2497f95f3850SWill Newton 
2498f95f3850SWill Newton 	/* Reset all blocks */
24994a90920cSThomas Abraham 	if (!mci_wait_reset(host->dev, host))
2500141a712aSSeungwon Jeon 		return -ENODEV;
2501141a712aSSeungwon Jeon 
2502141a712aSSeungwon Jeon 	host->dma_ops = host->pdata->dma_ops;
2503141a712aSSeungwon Jeon 	dw_mci_init_dma(host);
2504f95f3850SWill Newton 
2505f95f3850SWill Newton 	/* Clear the interrupts for the host controller */
2506f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2507f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2508f95f3850SWill Newton 
2509f95f3850SWill Newton 	/* Put in max timeout */
2510f95f3850SWill Newton 	mci_writel(host, TMOUT, 0xFFFFFFFF);
2511f95f3850SWill Newton 
2512f95f3850SWill Newton 	/*
2513f95f3850SWill Newton 	 * FIFO threshold settings  RxMark  = fifo_size / 2 - 1,
2514f95f3850SWill Newton 	 *                          Tx Mark = fifo_size / 2 DMA Size = 8
2515f95f3850SWill Newton 	 */
2516b86d8253SJames Hogan 	if (!host->pdata->fifo_depth) {
2517b86d8253SJames Hogan 		/*
2518b86d8253SJames Hogan 		 * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may
2519b86d8253SJames Hogan 		 * have been overwritten by the bootloader, just like we're
2520b86d8253SJames Hogan 		 * about to do, so if you know the value for your hardware, you
2521b86d8253SJames Hogan 		 * should put it in the platform data.
2522b86d8253SJames Hogan 		 */
2523f95f3850SWill Newton 		fifo_size = mci_readl(host, FIFOTH);
25248234e869SJaehoon Chung 		fifo_size = 1 + ((fifo_size >> 16) & 0xfff);
2525b86d8253SJames Hogan 	} else {
2526b86d8253SJames Hogan 		fifo_size = host->pdata->fifo_depth;
2527b86d8253SJames Hogan 	}
2528b86d8253SJames Hogan 	host->fifo_depth = fifo_size;
252952426899SSeungwon Jeon 	host->fifoth_val =
253052426899SSeungwon Jeon 		SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2);
2531e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
2532f95f3850SWill Newton 
2533f95f3850SWill Newton 	/* disable clock to CIU */
2534f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2535f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2536f95f3850SWill Newton 
253763008768SJames Hogan 	/*
253863008768SJames Hogan 	 * In 2.40a spec, Data offset is changed.
253963008768SJames Hogan 	 * Need to check the version-id and set data-offset for DATA register.
254063008768SJames Hogan 	 */
254163008768SJames Hogan 	host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
254263008768SJames Hogan 	dev_info(host->dev, "Version ID is %04x\n", host->verid);
254363008768SJames Hogan 
254463008768SJames Hogan 	if (host->verid < DW_MMC_240A)
254563008768SJames Hogan 		host->data_offset = DATA_OFFSET;
254663008768SJames Hogan 	else
254763008768SJames Hogan 		host->data_offset = DATA_240A_OFFSET;
254863008768SJames Hogan 
2549f95f3850SWill Newton 	tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
255095dcc2cbSThomas Abraham 	host->card_workqueue = alloc_workqueue("dw-mci-card",
25511791b13eSJames Hogan 			WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1);
2552ef7aef9aSWei Yongjun 	if (!host->card_workqueue) {
2553ef7aef9aSWei Yongjun 		ret = -ENOMEM;
25541791b13eSJames Hogan 		goto err_dmaunmap;
2555ef7aef9aSWei Yongjun 	}
25561791b13eSJames Hogan 	INIT_WORK(&host->card_work, dw_mci_work_routine_card);
2557780f22afSSeungwon Jeon 	ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
2558780f22afSSeungwon Jeon 			       host->irq_flags, "dw-mci", host);
2559f95f3850SWill Newton 	if (ret)
25601791b13eSJames Hogan 		goto err_workqueue;
2561f95f3850SWill Newton 
2562f95f3850SWill Newton 	if (host->pdata->num_slots)
2563f95f3850SWill Newton 		host->num_slots = host->pdata->num_slots;
2564f95f3850SWill Newton 	else
2565f95f3850SWill Newton 		host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1;
2566f95f3850SWill Newton 
25672da1d7f2SYuvaraj CD 	/*
25682da1d7f2SYuvaraj CD 	 * Enable interrupts for command done, data over, data empty, card det,
25692da1d7f2SYuvaraj CD 	 * receive ready and error such as transmit, receive timeout, crc error
25702da1d7f2SYuvaraj CD 	 */
25712da1d7f2SYuvaraj CD 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
25722da1d7f2SYuvaraj CD 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
25732da1d7f2SYuvaraj CD 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
25742da1d7f2SYuvaraj CD 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
25752da1d7f2SYuvaraj CD 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
25762da1d7f2SYuvaraj CD 
25772da1d7f2SYuvaraj CD 	dev_info(host->dev, "DW MMC controller at irq %d, "
25782da1d7f2SYuvaraj CD 		 "%d bit host data width, "
25792da1d7f2SYuvaraj CD 		 "%u deep fifo\n",
25802da1d7f2SYuvaraj CD 		 host->irq, width, fifo_size);
25812da1d7f2SYuvaraj CD 
2582f95f3850SWill Newton 	/* We need at least one slot to succeed */
2583f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2584f95f3850SWill Newton 		ret = dw_mci_init_slot(host, i);
25851c2215b7SThomas Abraham 		if (ret)
25861c2215b7SThomas Abraham 			dev_dbg(host->dev, "slot %d init failed\n", i);
25871c2215b7SThomas Abraham 		else
25881c2215b7SThomas Abraham 			init_slots++;
2589f95f3850SWill Newton 	}
25901c2215b7SThomas Abraham 
25911c2215b7SThomas Abraham 	if (init_slots) {
25921c2215b7SThomas Abraham 		dev_info(host->dev, "%d slots initialized\n", init_slots);
25931c2215b7SThomas Abraham 	} else {
25941c2215b7SThomas Abraham 		dev_dbg(host->dev, "attempted to initialize %d slots, "
25951c2215b7SThomas Abraham 					"but failed on all\n", host->num_slots);
2596780f22afSSeungwon Jeon 		goto err_workqueue;
2597f95f3850SWill Newton 	}
2598f95f3850SWill Newton 
2599f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
26004a90920cSThomas Abraham 		dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
2601f95f3850SWill Newton 
2602f95f3850SWill Newton 	return 0;
2603f95f3850SWill Newton 
26041791b13eSJames Hogan err_workqueue:
260595dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
26061791b13eSJames Hogan 
2607f95f3850SWill Newton err_dmaunmap:
2608f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2609f95f3850SWill Newton 		host->dma_ops->exit(host);
2610f95f3850SWill Newton 
2611870556a3SDoug Anderson err_regulator:
2612780f22afSSeungwon Jeon 	if (host->vmmc)
2613c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2614f90a0612SThomas Abraham 
2615f90a0612SThomas Abraham err_clk_ciu:
2616780f22afSSeungwon Jeon 	if (!IS_ERR(host->ciu_clk))
2617f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2618780f22afSSeungwon Jeon 
2619f90a0612SThomas Abraham err_clk_biu:
2620780f22afSSeungwon Jeon 	if (!IS_ERR(host->biu_clk))
2621f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2622780f22afSSeungwon Jeon 
2623f95f3850SWill Newton 	return ret;
2624f95f3850SWill Newton }
262562ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe);
2626f95f3850SWill Newton 
262762ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host)
2628f95f3850SWill Newton {
2629f95f3850SWill Newton 	int i;
2630f95f3850SWill Newton 
2631f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2632f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2633f95f3850SWill Newton 
2634f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
26354a90920cSThomas Abraham 		dev_dbg(host->dev, "remove slot %d\n", i);
2636f95f3850SWill Newton 		if (host->slot[i])
2637f95f3850SWill Newton 			dw_mci_cleanup_slot(host->slot[i], i);
2638f95f3850SWill Newton 	}
2639f95f3850SWill Newton 
2640f95f3850SWill Newton 	/* disable clock to CIU */
2641f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2642f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2643f95f3850SWill Newton 
264495dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
2645f95f3850SWill Newton 
2646f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2647f95f3850SWill Newton 		host->dma_ops->exit(host);
2648f95f3850SWill Newton 
2649780f22afSSeungwon Jeon 	if (host->vmmc)
2650c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2651c07946a3SJaehoon Chung 
2652f90a0612SThomas Abraham 	if (!IS_ERR(host->ciu_clk))
2653f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2654780f22afSSeungwon Jeon 
2655f90a0612SThomas Abraham 	if (!IS_ERR(host->biu_clk))
2656f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2657f95f3850SWill Newton }
265862ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove);
265962ca8034SShashidhar Hiremath 
266062ca8034SShashidhar Hiremath 
2661f95f3850SWill Newton 
26626fe8890dSJaehoon Chung #ifdef CONFIG_PM_SLEEP
2663f95f3850SWill Newton /*
2664f95f3850SWill Newton  * TODO: we should probably disable the clock to the card in the suspend path.
2665f95f3850SWill Newton  */
266662ca8034SShashidhar Hiremath int dw_mci_suspend(struct dw_mci *host)
2667f95f3850SWill Newton {
266862ca8034SShashidhar Hiremath 	int i, ret = 0;
2669f95f3850SWill Newton 
2670f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2671f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
2672f95f3850SWill Newton 		if (!slot)
2673f95f3850SWill Newton 			continue;
2674f95f3850SWill Newton 		ret = mmc_suspend_host(slot->mmc);
2675f95f3850SWill Newton 		if (ret < 0) {
2676f95f3850SWill Newton 			while (--i >= 0) {
2677f95f3850SWill Newton 				slot = host->slot[i];
2678f95f3850SWill Newton 				if (slot)
2679f95f3850SWill Newton 					mmc_resume_host(host->slot[i]->mmc);
2680f95f3850SWill Newton 			}
2681f95f3850SWill Newton 			return ret;
2682f95f3850SWill Newton 		}
2683f95f3850SWill Newton 	}
2684f95f3850SWill Newton 
2685c07946a3SJaehoon Chung 	if (host->vmmc)
2686c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2687c07946a3SJaehoon Chung 
2688f95f3850SWill Newton 	return 0;
2689f95f3850SWill Newton }
269062ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_suspend);
2691f95f3850SWill Newton 
269262ca8034SShashidhar Hiremath int dw_mci_resume(struct dw_mci *host)
2693f95f3850SWill Newton {
2694f95f3850SWill Newton 	int i, ret;
2695f95f3850SWill Newton 
2696f2f942ceSSachin Kamat 	if (host->vmmc) {
2697f2f942ceSSachin Kamat 		ret = regulator_enable(host->vmmc);
2698f2f942ceSSachin Kamat 		if (ret) {
2699f2f942ceSSachin Kamat 			dev_err(host->dev,
2700f2f942ceSSachin Kamat 				"failed to enable regulator: %d\n", ret);
2701f2f942ceSSachin Kamat 			return ret;
2702f2f942ceSSachin Kamat 		}
2703f2f942ceSSachin Kamat 	}
27041d6c4e0aSJaehoon Chung 
27054a90920cSThomas Abraham 	if (!mci_wait_reset(host->dev, host)) {
2706e61cf118SJaehoon Chung 		ret = -ENODEV;
2707e61cf118SJaehoon Chung 		return ret;
2708e61cf118SJaehoon Chung 	}
2709e61cf118SJaehoon Chung 
27103bfe619dSJonathan Kliegman 	if (host->use_dma && host->dma_ops->init)
2711141a712aSSeungwon Jeon 		host->dma_ops->init(host);
2712141a712aSSeungwon Jeon 
271352426899SSeungwon Jeon 	/*
271452426899SSeungwon Jeon 	 * Restore the initial value at FIFOTH register
271552426899SSeungwon Jeon 	 * And Invalidate the prev_blksz with zero
271652426899SSeungwon Jeon 	 */
2717e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
271852426899SSeungwon Jeon 	host->prev_blksz = 0;
2719e61cf118SJaehoon Chung 
27202eb2944fSDoug Anderson 	/* Put in max timeout */
27212eb2944fSDoug Anderson 	mci_writel(host, TMOUT, 0xFFFFFFFF);
27222eb2944fSDoug Anderson 
2723e61cf118SJaehoon Chung 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2724e61cf118SJaehoon Chung 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
2725e61cf118SJaehoon Chung 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
2726e61cf118SJaehoon Chung 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
2727e61cf118SJaehoon Chung 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
2728e61cf118SJaehoon Chung 
2729f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2730f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
2731f95f3850SWill Newton 		if (!slot)
2732f95f3850SWill Newton 			continue;
2733ab269128SAbhilash Kesavan 		if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
2734ab269128SAbhilash Kesavan 			dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
2735ab269128SAbhilash Kesavan 			dw_mci_setup_bus(slot, true);
2736ab269128SAbhilash Kesavan 		}
2737ab269128SAbhilash Kesavan 
2738f95f3850SWill Newton 		ret = mmc_resume_host(host->slot[i]->mmc);
2739f95f3850SWill Newton 		if (ret < 0)
2740f95f3850SWill Newton 			return ret;
2741f95f3850SWill Newton 	}
2742f95f3850SWill Newton 	return 0;
2743f95f3850SWill Newton }
274462ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_resume);
27456fe8890dSJaehoon Chung #endif /* CONFIG_PM_SLEEP */
27466fe8890dSJaehoon Chung 
2747f95f3850SWill Newton static int __init dw_mci_init(void)
2748f95f3850SWill Newton {
27498e1c4e4dSSachin Kamat 	pr_info("Synopsys Designware Multimedia Card Interface Driver\n");
275062ca8034SShashidhar Hiremath 	return 0;
2751f95f3850SWill Newton }
2752f95f3850SWill Newton 
2753f95f3850SWill Newton static void __exit dw_mci_exit(void)
2754f95f3850SWill Newton {
2755f95f3850SWill Newton }
2756f95f3850SWill Newton 
2757f95f3850SWill Newton module_init(dw_mci_init);
2758f95f3850SWill Newton module_exit(dw_mci_exit);
2759f95f3850SWill Newton 
2760f95f3850SWill Newton MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
2761f95f3850SWill Newton MODULE_AUTHOR("NXP Semiconductor VietNam");
2762f95f3850SWill Newton MODULE_AUTHOR("Imagination Technologies Ltd");
2763f95f3850SWill Newton MODULE_LICENSE("GPL v2");
2764