xref: /linux/drivers/mmc/host/dw_mmc.c (revision 2aa354650a8b024a507f5b0fd969b7cfa3848620)
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>
3290c2143aSSeungwon 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>
39bf626e55SZhangfei Gao #include <linux/mmc/slot-gpio.h>
40f95f3850SWill Newton 
41f95f3850SWill Newton #include "dw_mmc.h"
42f95f3850SWill Newton 
43f95f3850SWill Newton /* Common flag combinations */
443f7eec62SJaehoon Chung #define DW_MCI_DATA_ERROR_FLAGS	(SDMMC_INT_DRTO | SDMMC_INT_DCRC | \
45f95f3850SWill Newton 				 SDMMC_INT_HTO | SDMMC_INT_SBE  | \
46f95f3850SWill Newton 				 SDMMC_INT_EBE)
47f95f3850SWill Newton #define DW_MCI_CMD_ERROR_FLAGS	(SDMMC_INT_RTO | SDMMC_INT_RCRC | \
48f95f3850SWill Newton 				 SDMMC_INT_RESP_ERR)
49f95f3850SWill Newton #define DW_MCI_ERROR_FLAGS	(DW_MCI_DATA_ERROR_FLAGS | \
50f95f3850SWill Newton 				 DW_MCI_CMD_ERROR_FLAGS  | SDMMC_INT_HLE)
51f95f3850SWill Newton #define DW_MCI_SEND_STATUS	1
52f95f3850SWill Newton #define DW_MCI_RECV_STATUS	2
53f95f3850SWill Newton #define DW_MCI_DMA_THRESHOLD	16
54f95f3850SWill Newton 
551f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MAX	200000000	/* unit: HZ */
561f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MIN	400000		/* unit: HZ */
571f44a2a5SSeungwon Jeon 
58f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
59fc79a4d6SJoonyoung Shim #define IDMAC_INT_CLR		(SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \
60fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \
61fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
62fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_TI)
63fc79a4d6SJoonyoung Shim 
64f95f3850SWill Newton struct idmac_desc {
65f95f3850SWill Newton 	u32		des0;	/* Control Descriptor */
66f95f3850SWill Newton #define IDMAC_DES0_DIC	BIT(1)
67f95f3850SWill Newton #define IDMAC_DES0_LD	BIT(2)
68f95f3850SWill Newton #define IDMAC_DES0_FD	BIT(3)
69f95f3850SWill Newton #define IDMAC_DES0_CH	BIT(4)
70f95f3850SWill Newton #define IDMAC_DES0_ER	BIT(5)
71f95f3850SWill Newton #define IDMAC_DES0_CES	BIT(30)
72f95f3850SWill Newton #define IDMAC_DES0_OWN	BIT(31)
73f95f3850SWill Newton 
74f95f3850SWill Newton 	u32		des1;	/* Buffer sizes */
75f95f3850SWill Newton #define IDMAC_SET_BUFFER1_SIZE(d, s) \
769b7bbe10SShashidhar Hiremath 	((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff))
77f95f3850SWill Newton 
78f95f3850SWill Newton 	u32		des2;	/* buffer 1 physical address */
79f95f3850SWill Newton 
80f95f3850SWill Newton 	u32		des3;	/* buffer 2 physical address */
81f95f3850SWill Newton };
82f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */
83f95f3850SWill Newton 
840976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_4bit[] = {
850976f16dSSeungwon Jeon 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
860976f16dSSeungwon Jeon 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
870976f16dSSeungwon Jeon 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
880976f16dSSeungwon Jeon 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
890976f16dSSeungwon Jeon 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
900976f16dSSeungwon Jeon 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
910976f16dSSeungwon Jeon 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
920976f16dSSeungwon Jeon 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
930976f16dSSeungwon Jeon };
94f95f3850SWill Newton 
950976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_8bit[] = {
960976f16dSSeungwon Jeon 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
970976f16dSSeungwon Jeon 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
980976f16dSSeungwon Jeon 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
990976f16dSSeungwon Jeon 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
1000976f16dSSeungwon Jeon 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
1010976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
1020976f16dSSeungwon Jeon 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
1030976f16dSSeungwon Jeon 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
1040976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
1050976f16dSSeungwon Jeon 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
1060976f16dSSeungwon Jeon 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
1070976f16dSSeungwon Jeon 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
1080976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
1090976f16dSSeungwon Jeon 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
1100976f16dSSeungwon Jeon 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
1110976f16dSSeungwon Jeon 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
112f95f3850SWill Newton };
113f95f3850SWill Newton 
1143a33a94cSSonny Rao static bool dw_mci_reset(struct dw_mci *host);
11531bff450SSeungwon Jeon 
116f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS)
117f95f3850SWill Newton static int dw_mci_req_show(struct seq_file *s, void *v)
118f95f3850SWill Newton {
119f95f3850SWill Newton 	struct dw_mci_slot *slot = s->private;
120f95f3850SWill Newton 	struct mmc_request *mrq;
121f95f3850SWill Newton 	struct mmc_command *cmd;
122f95f3850SWill Newton 	struct mmc_command *stop;
123f95f3850SWill Newton 	struct mmc_data	*data;
124f95f3850SWill Newton 
125f95f3850SWill Newton 	/* Make sure we get a consistent snapshot */
126f95f3850SWill Newton 	spin_lock_bh(&slot->host->lock);
127f95f3850SWill Newton 	mrq = slot->mrq;
128f95f3850SWill Newton 
129f95f3850SWill Newton 	if (mrq) {
130f95f3850SWill Newton 		cmd = mrq->cmd;
131f95f3850SWill Newton 		data = mrq->data;
132f95f3850SWill Newton 		stop = mrq->stop;
133f95f3850SWill Newton 
134f95f3850SWill Newton 		if (cmd)
135f95f3850SWill Newton 			seq_printf(s,
136f95f3850SWill Newton 				   "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
137f95f3850SWill Newton 				   cmd->opcode, cmd->arg, cmd->flags,
138f95f3850SWill Newton 				   cmd->resp[0], cmd->resp[1], cmd->resp[2],
139f95f3850SWill Newton 				   cmd->resp[2], cmd->error);
140f95f3850SWill Newton 		if (data)
141f95f3850SWill Newton 			seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
142f95f3850SWill Newton 				   data->bytes_xfered, data->blocks,
143f95f3850SWill Newton 				   data->blksz, data->flags, data->error);
144f95f3850SWill Newton 		if (stop)
145f95f3850SWill Newton 			seq_printf(s,
146f95f3850SWill Newton 				   "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
147f95f3850SWill Newton 				   stop->opcode, stop->arg, stop->flags,
148f95f3850SWill Newton 				   stop->resp[0], stop->resp[1], stop->resp[2],
149f95f3850SWill Newton 				   stop->resp[2], stop->error);
150f95f3850SWill Newton 	}
151f95f3850SWill Newton 
152f95f3850SWill Newton 	spin_unlock_bh(&slot->host->lock);
153f95f3850SWill Newton 
154f95f3850SWill Newton 	return 0;
155f95f3850SWill Newton }
156f95f3850SWill Newton 
157f95f3850SWill Newton static int dw_mci_req_open(struct inode *inode, struct file *file)
158f95f3850SWill Newton {
159f95f3850SWill Newton 	return single_open(file, dw_mci_req_show, inode->i_private);
160f95f3850SWill Newton }
161f95f3850SWill Newton 
162f95f3850SWill Newton static const struct file_operations dw_mci_req_fops = {
163f95f3850SWill Newton 	.owner		= THIS_MODULE,
164f95f3850SWill Newton 	.open		= dw_mci_req_open,
165f95f3850SWill Newton 	.read		= seq_read,
166f95f3850SWill Newton 	.llseek		= seq_lseek,
167f95f3850SWill Newton 	.release	= single_release,
168f95f3850SWill Newton };
169f95f3850SWill Newton 
170f95f3850SWill Newton static int dw_mci_regs_show(struct seq_file *s, void *v)
171f95f3850SWill Newton {
172f95f3850SWill Newton 	seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS);
173f95f3850SWill Newton 	seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS);
174f95f3850SWill Newton 	seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD);
175f95f3850SWill Newton 	seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL);
176f95f3850SWill Newton 	seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK);
177f95f3850SWill Newton 	seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA);
178f95f3850SWill Newton 
179f95f3850SWill Newton 	return 0;
180f95f3850SWill Newton }
181f95f3850SWill Newton 
182f95f3850SWill Newton static int dw_mci_regs_open(struct inode *inode, struct file *file)
183f95f3850SWill Newton {
184f95f3850SWill Newton 	return single_open(file, dw_mci_regs_show, inode->i_private);
185f95f3850SWill Newton }
186f95f3850SWill Newton 
187f95f3850SWill Newton static const struct file_operations dw_mci_regs_fops = {
188f95f3850SWill Newton 	.owner		= THIS_MODULE,
189f95f3850SWill Newton 	.open		= dw_mci_regs_open,
190f95f3850SWill Newton 	.read		= seq_read,
191f95f3850SWill Newton 	.llseek		= seq_lseek,
192f95f3850SWill Newton 	.release	= single_release,
193f95f3850SWill Newton };
194f95f3850SWill Newton 
195f95f3850SWill Newton static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
196f95f3850SWill Newton {
197f95f3850SWill Newton 	struct mmc_host	*mmc = slot->mmc;
198f95f3850SWill Newton 	struct dw_mci *host = slot->host;
199f95f3850SWill Newton 	struct dentry *root;
200f95f3850SWill Newton 	struct dentry *node;
201f95f3850SWill Newton 
202f95f3850SWill Newton 	root = mmc->debugfs_root;
203f95f3850SWill Newton 	if (!root)
204f95f3850SWill Newton 		return;
205f95f3850SWill Newton 
206f95f3850SWill Newton 	node = debugfs_create_file("regs", S_IRUSR, root, host,
207f95f3850SWill Newton 				   &dw_mci_regs_fops);
208f95f3850SWill Newton 	if (!node)
209f95f3850SWill Newton 		goto err;
210f95f3850SWill Newton 
211f95f3850SWill Newton 	node = debugfs_create_file("req", S_IRUSR, root, slot,
212f95f3850SWill Newton 				   &dw_mci_req_fops);
213f95f3850SWill Newton 	if (!node)
214f95f3850SWill Newton 		goto err;
215f95f3850SWill Newton 
216f95f3850SWill Newton 	node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
217f95f3850SWill Newton 	if (!node)
218f95f3850SWill Newton 		goto err;
219f95f3850SWill Newton 
220f95f3850SWill Newton 	node = debugfs_create_x32("pending_events", S_IRUSR, root,
221f95f3850SWill Newton 				  (u32 *)&host->pending_events);
222f95f3850SWill Newton 	if (!node)
223f95f3850SWill Newton 		goto err;
224f95f3850SWill Newton 
225f95f3850SWill Newton 	node = debugfs_create_x32("completed_events", S_IRUSR, root,
226f95f3850SWill Newton 				  (u32 *)&host->completed_events);
227f95f3850SWill Newton 	if (!node)
228f95f3850SWill Newton 		goto err;
229f95f3850SWill Newton 
230f95f3850SWill Newton 	return;
231f95f3850SWill Newton 
232f95f3850SWill Newton err:
233f95f3850SWill Newton 	dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
234f95f3850SWill Newton }
235f95f3850SWill Newton #endif /* defined(CONFIG_DEBUG_FS) */
236f95f3850SWill Newton 
237f95f3850SWill Newton static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
238f95f3850SWill Newton {
239f95f3850SWill Newton 	struct mmc_data	*data;
240800d78bfSThomas Abraham 	struct dw_mci_slot *slot = mmc_priv(mmc);
241e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
242f95f3850SWill Newton 	u32 cmdr;
243f95f3850SWill Newton 	cmd->error = -EINPROGRESS;
244f95f3850SWill Newton 
245f95f3850SWill Newton 	cmdr = cmd->opcode;
246f95f3850SWill Newton 
24790c2143aSSeungwon Jeon 	if (cmd->opcode == MMC_STOP_TRANSMISSION ||
24890c2143aSSeungwon Jeon 	    cmd->opcode == MMC_GO_IDLE_STATE ||
24990c2143aSSeungwon Jeon 	    cmd->opcode == MMC_GO_INACTIVE_STATE ||
25090c2143aSSeungwon Jeon 	    (cmd->opcode == SD_IO_RW_DIRECT &&
25190c2143aSSeungwon Jeon 	     ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT))
252f95f3850SWill Newton 		cmdr |= SDMMC_CMD_STOP;
2534a1b27adSJaehoon Chung 	else if (cmd->opcode != MMC_SEND_STATUS && cmd->data)
254f95f3850SWill Newton 		cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
255f95f3850SWill Newton 
256f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_PRESENT) {
257f95f3850SWill Newton 		/* We expect a response, so set this bit */
258f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_EXP;
259f95f3850SWill Newton 		if (cmd->flags & MMC_RSP_136)
260f95f3850SWill Newton 			cmdr |= SDMMC_CMD_RESP_LONG;
261f95f3850SWill Newton 	}
262f95f3850SWill Newton 
263f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_CRC)
264f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_CRC;
265f95f3850SWill Newton 
266f95f3850SWill Newton 	data = cmd->data;
267f95f3850SWill Newton 	if (data) {
268f95f3850SWill Newton 		cmdr |= SDMMC_CMD_DAT_EXP;
269f95f3850SWill Newton 		if (data->flags & MMC_DATA_STREAM)
270f95f3850SWill Newton 			cmdr |= SDMMC_CMD_STRM_MODE;
271f95f3850SWill Newton 		if (data->flags & MMC_DATA_WRITE)
272f95f3850SWill Newton 			cmdr |= SDMMC_CMD_DAT_WR;
273f95f3850SWill Newton 	}
274f95f3850SWill Newton 
275cb27a843SJames Hogan 	if (drv_data && drv_data->prepare_command)
276cb27a843SJames Hogan 		drv_data->prepare_command(slot->host, &cmdr);
277800d78bfSThomas Abraham 
278f95f3850SWill Newton 	return cmdr;
279f95f3850SWill Newton }
280f95f3850SWill Newton 
28190c2143aSSeungwon Jeon static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
28290c2143aSSeungwon Jeon {
28390c2143aSSeungwon Jeon 	struct mmc_command *stop;
28490c2143aSSeungwon Jeon 	u32 cmdr;
28590c2143aSSeungwon Jeon 
28690c2143aSSeungwon Jeon 	if (!cmd->data)
28790c2143aSSeungwon Jeon 		return 0;
28890c2143aSSeungwon Jeon 
28990c2143aSSeungwon Jeon 	stop = &host->stop_abort;
29090c2143aSSeungwon Jeon 	cmdr = cmd->opcode;
29190c2143aSSeungwon Jeon 	memset(stop, 0, sizeof(struct mmc_command));
29290c2143aSSeungwon Jeon 
29390c2143aSSeungwon Jeon 	if (cmdr == MMC_READ_SINGLE_BLOCK ||
29490c2143aSSeungwon Jeon 	    cmdr == MMC_READ_MULTIPLE_BLOCK ||
29590c2143aSSeungwon Jeon 	    cmdr == MMC_WRITE_BLOCK ||
29690c2143aSSeungwon Jeon 	    cmdr == MMC_WRITE_MULTIPLE_BLOCK) {
29790c2143aSSeungwon Jeon 		stop->opcode = MMC_STOP_TRANSMISSION;
29890c2143aSSeungwon Jeon 		stop->arg = 0;
29990c2143aSSeungwon Jeon 		stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
30090c2143aSSeungwon Jeon 	} else if (cmdr == SD_IO_RW_EXTENDED) {
30190c2143aSSeungwon Jeon 		stop->opcode = SD_IO_RW_DIRECT;
30290c2143aSSeungwon Jeon 		stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) |
30390c2143aSSeungwon Jeon 			     ((cmd->arg >> 28) & 0x7);
30490c2143aSSeungwon Jeon 		stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
30590c2143aSSeungwon Jeon 	} else {
30690c2143aSSeungwon Jeon 		return 0;
30790c2143aSSeungwon Jeon 	}
30890c2143aSSeungwon Jeon 
30990c2143aSSeungwon Jeon 	cmdr = stop->opcode | SDMMC_CMD_STOP |
31090c2143aSSeungwon Jeon 		SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP;
31190c2143aSSeungwon Jeon 
31290c2143aSSeungwon Jeon 	return cmdr;
31390c2143aSSeungwon Jeon }
31490c2143aSSeungwon Jeon 
315f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host,
316f95f3850SWill Newton 				 struct mmc_command *cmd, u32 cmd_flags)
317f95f3850SWill Newton {
318f95f3850SWill Newton 	host->cmd = cmd;
3194a90920cSThomas Abraham 	dev_vdbg(host->dev,
320f95f3850SWill Newton 		 "start command: ARGR=0x%08x CMDR=0x%08x\n",
321f95f3850SWill Newton 		 cmd->arg, cmd_flags);
322f95f3850SWill Newton 
323f95f3850SWill Newton 	mci_writel(host, CMDARG, cmd->arg);
324f95f3850SWill Newton 	wmb();
325f95f3850SWill Newton 
326f95f3850SWill Newton 	mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
327f95f3850SWill Newton }
328f95f3850SWill Newton 
32990c2143aSSeungwon Jeon static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data)
330f95f3850SWill Newton {
33190c2143aSSeungwon Jeon 	struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort;
33290c2143aSSeungwon Jeon 	dw_mci_start_command(host, stop, host->stop_cmdr);
333f95f3850SWill Newton }
334f95f3850SWill Newton 
335f95f3850SWill Newton /* DMA interface functions */
336f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host)
337f95f3850SWill Newton {
33803e8cb53SJames Hogan 	if (host->using_dma) {
339f95f3850SWill Newton 		host->dma_ops->stop(host);
340f95f3850SWill Newton 		host->dma_ops->cleanup(host);
341aa50f259SSeungwon Jeon 	}
342aa50f259SSeungwon Jeon 
343f95f3850SWill Newton 	/* Data transfer was stopped by the interrupt handler */
344f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
345f95f3850SWill Newton }
346f95f3850SWill Newton 
3479aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data)
3489aa51408SSeungwon Jeon {
3499aa51408SSeungwon Jeon 	if (data->flags & MMC_DATA_WRITE)
3509aa51408SSeungwon Jeon 		return DMA_TO_DEVICE;
3519aa51408SSeungwon Jeon 	else
3529aa51408SSeungwon Jeon 		return DMA_FROM_DEVICE;
3539aa51408SSeungwon Jeon }
3549aa51408SSeungwon Jeon 
3559beee912SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
356f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host)
357f95f3850SWill Newton {
358f95f3850SWill Newton 	struct mmc_data *data = host->data;
359f95f3850SWill Newton 
360f95f3850SWill Newton 	if (data)
3619aa51408SSeungwon Jeon 		if (!data->host_cookie)
3624a90920cSThomas Abraham 			dma_unmap_sg(host->dev,
3639aa51408SSeungwon Jeon 				     data->sg,
3649aa51408SSeungwon Jeon 				     data->sg_len,
3659aa51408SSeungwon Jeon 				     dw_mci_get_dma_dir(data));
366f95f3850SWill Newton }
367f95f3850SWill Newton 
3685ce9d961SSeungwon Jeon static void dw_mci_idmac_reset(struct dw_mci *host)
3695ce9d961SSeungwon Jeon {
3705ce9d961SSeungwon Jeon 	u32 bmod = mci_readl(host, BMOD);
3715ce9d961SSeungwon Jeon 	/* Software reset of DMA */
3725ce9d961SSeungwon Jeon 	bmod |= SDMMC_IDMAC_SWRESET;
3735ce9d961SSeungwon Jeon 	mci_writel(host, BMOD, bmod);
3745ce9d961SSeungwon Jeon }
3755ce9d961SSeungwon Jeon 
376f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host)
377f95f3850SWill Newton {
378f95f3850SWill Newton 	u32 temp;
379f95f3850SWill Newton 
380f95f3850SWill Newton 	/* Disable and reset the IDMAC interface */
381f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
382f95f3850SWill Newton 	temp &= ~SDMMC_CTRL_USE_IDMAC;
383f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_RESET;
384f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
385f95f3850SWill Newton 
386f95f3850SWill Newton 	/* Stop the IDMAC running */
387f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
388a5289a43SJaehoon Chung 	temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB);
3895ce9d961SSeungwon Jeon 	temp |= SDMMC_IDMAC_SWRESET;
390f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
391f95f3850SWill Newton }
392f95f3850SWill Newton 
393f95f3850SWill Newton static void dw_mci_idmac_complete_dma(struct dw_mci *host)
394f95f3850SWill Newton {
395f95f3850SWill Newton 	struct mmc_data *data = host->data;
396f95f3850SWill Newton 
3974a90920cSThomas Abraham 	dev_vdbg(host->dev, "DMA complete\n");
398f95f3850SWill Newton 
399f95f3850SWill Newton 	host->dma_ops->cleanup(host);
400f95f3850SWill Newton 
401f95f3850SWill Newton 	/*
402f95f3850SWill Newton 	 * If the card was removed, data will be NULL. No point in trying to
403f95f3850SWill Newton 	 * send the stop command or waiting for NBUSY in this case.
404f95f3850SWill Newton 	 */
405f95f3850SWill Newton 	if (data) {
406f95f3850SWill Newton 		set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
407f95f3850SWill Newton 		tasklet_schedule(&host->tasklet);
408f95f3850SWill Newton 	}
409f95f3850SWill Newton }
410f95f3850SWill Newton 
411f95f3850SWill Newton static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
412f95f3850SWill Newton 				    unsigned int sg_len)
413f95f3850SWill Newton {
414f95f3850SWill Newton 	int i;
415f95f3850SWill Newton 	struct idmac_desc *desc = host->sg_cpu;
416f95f3850SWill Newton 
417f95f3850SWill Newton 	for (i = 0; i < sg_len; i++, desc++) {
418f95f3850SWill Newton 		unsigned int length = sg_dma_len(&data->sg[i]);
419f95f3850SWill Newton 		u32 mem_addr = sg_dma_address(&data->sg[i]);
420f95f3850SWill Newton 
421f95f3850SWill Newton 		/* Set the OWN bit and disable interrupts for this descriptor */
422f95f3850SWill Newton 		desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH;
423f95f3850SWill Newton 
424f95f3850SWill Newton 		/* Buffer length */
425f95f3850SWill Newton 		IDMAC_SET_BUFFER1_SIZE(desc, length);
426f95f3850SWill Newton 
427f95f3850SWill Newton 		/* Physical address to DMA to/from */
428f95f3850SWill Newton 		desc->des2 = mem_addr;
429f95f3850SWill Newton 	}
430f95f3850SWill Newton 
431f95f3850SWill Newton 	/* Set first descriptor */
432f95f3850SWill Newton 	desc = host->sg_cpu;
433f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_FD;
434f95f3850SWill Newton 
435f95f3850SWill Newton 	/* Set last descriptor */
436f95f3850SWill Newton 	desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
437f95f3850SWill Newton 	desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
438f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_LD;
439f95f3850SWill Newton 
440f95f3850SWill Newton 	wmb();
441f95f3850SWill Newton }
442f95f3850SWill Newton 
443f95f3850SWill Newton static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
444f95f3850SWill Newton {
445f95f3850SWill Newton 	u32 temp;
446f95f3850SWill Newton 
447f95f3850SWill Newton 	dw_mci_translate_sglist(host, host->data, sg_len);
448f95f3850SWill Newton 
449f95f3850SWill Newton 	/* Select IDMAC interface */
450f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
451f95f3850SWill Newton 	temp |= SDMMC_CTRL_USE_IDMAC;
452f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
453f95f3850SWill Newton 
454f95f3850SWill Newton 	wmb();
455f95f3850SWill Newton 
456f95f3850SWill Newton 	/* Enable the IDMAC */
457f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
458a5289a43SJaehoon Chung 	temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB;
459f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
460f95f3850SWill Newton 
461f95f3850SWill Newton 	/* Start it running */
462f95f3850SWill Newton 	mci_writel(host, PLDMND, 1);
463f95f3850SWill Newton }
464f95f3850SWill Newton 
465f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host)
466f95f3850SWill Newton {
467f95f3850SWill Newton 	struct idmac_desc *p;
468897b69e7SSeungwon Jeon 	int i;
469f95f3850SWill Newton 
470f95f3850SWill Newton 	/* Number of descriptors in the ring buffer */
471f95f3850SWill Newton 	host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
472f95f3850SWill Newton 
473f95f3850SWill Newton 	/* Forward link the descriptor list */
474f95f3850SWill Newton 	for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
475f95f3850SWill Newton 		p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
476f95f3850SWill Newton 
477f95f3850SWill Newton 	/* Set the last descriptor as the end-of-ring descriptor */
478f95f3850SWill Newton 	p->des3 = host->sg_dma;
479f95f3850SWill Newton 	p->des0 = IDMAC_DES0_ER;
480f95f3850SWill Newton 
4815ce9d961SSeungwon Jeon 	dw_mci_idmac_reset(host);
482141a712aSSeungwon Jeon 
483f95f3850SWill Newton 	/* Mask out interrupts - get Tx & Rx complete only */
484fc79a4d6SJoonyoung Shim 	mci_writel(host, IDSTS, IDMAC_INT_CLR);
485f95f3850SWill Newton 	mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
486f95f3850SWill Newton 		   SDMMC_IDMAC_INT_TI);
487f95f3850SWill Newton 
488f95f3850SWill Newton 	/* Set the descriptor base address */
489f95f3850SWill Newton 	mci_writel(host, DBADDR, host->sg_dma);
490f95f3850SWill Newton 	return 0;
491f95f3850SWill Newton }
492f95f3850SWill Newton 
4938e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = {
494885c3e80SSeungwon Jeon 	.init = dw_mci_idmac_init,
495885c3e80SSeungwon Jeon 	.start = dw_mci_idmac_start_dma,
496885c3e80SSeungwon Jeon 	.stop = dw_mci_idmac_stop_dma,
497885c3e80SSeungwon Jeon 	.complete = dw_mci_idmac_complete_dma,
498885c3e80SSeungwon Jeon 	.cleanup = dw_mci_dma_cleanup,
499885c3e80SSeungwon Jeon };
500885c3e80SSeungwon Jeon #endif /* CONFIG_MMC_DW_IDMAC */
501885c3e80SSeungwon Jeon 
5029aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host,
5039aa51408SSeungwon Jeon 				   struct mmc_data *data,
5049aa51408SSeungwon Jeon 				   bool next)
505f95f3850SWill Newton {
506f95f3850SWill Newton 	struct scatterlist *sg;
5079aa51408SSeungwon Jeon 	unsigned int i, sg_len;
508f95f3850SWill Newton 
5099aa51408SSeungwon Jeon 	if (!next && data->host_cookie)
5109aa51408SSeungwon Jeon 		return data->host_cookie;
511f95f3850SWill Newton 
512f95f3850SWill Newton 	/*
513f95f3850SWill Newton 	 * We don't do DMA on "complex" transfers, i.e. with
514f95f3850SWill Newton 	 * non-word-aligned buffers or lengths. Also, we don't bother
515f95f3850SWill Newton 	 * with all the DMA setup overhead for short transfers.
516f95f3850SWill Newton 	 */
517f95f3850SWill Newton 	if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD)
518f95f3850SWill Newton 		return -EINVAL;
5199aa51408SSeungwon Jeon 
520f95f3850SWill Newton 	if (data->blksz & 3)
521f95f3850SWill Newton 		return -EINVAL;
522f95f3850SWill Newton 
523f95f3850SWill Newton 	for_each_sg(data->sg, sg, data->sg_len, i) {
524f95f3850SWill Newton 		if (sg->offset & 3 || sg->length & 3)
525f95f3850SWill Newton 			return -EINVAL;
526f95f3850SWill Newton 	}
527f95f3850SWill Newton 
5284a90920cSThomas Abraham 	sg_len = dma_map_sg(host->dev,
5299aa51408SSeungwon Jeon 			    data->sg,
5309aa51408SSeungwon Jeon 			    data->sg_len,
5319aa51408SSeungwon Jeon 			    dw_mci_get_dma_dir(data));
5329aa51408SSeungwon Jeon 	if (sg_len == 0)
5339aa51408SSeungwon Jeon 		return -EINVAL;
5349aa51408SSeungwon Jeon 
5359aa51408SSeungwon Jeon 	if (next)
5369aa51408SSeungwon Jeon 		data->host_cookie = sg_len;
5379aa51408SSeungwon Jeon 
5389aa51408SSeungwon Jeon 	return sg_len;
5399aa51408SSeungwon Jeon }
5409aa51408SSeungwon Jeon 
5419aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc,
5429aa51408SSeungwon Jeon 			   struct mmc_request *mrq,
5439aa51408SSeungwon Jeon 			   bool is_first_req)
5449aa51408SSeungwon Jeon {
5459aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
5469aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
5479aa51408SSeungwon Jeon 
5489aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
5499aa51408SSeungwon Jeon 		return;
5509aa51408SSeungwon Jeon 
5519aa51408SSeungwon Jeon 	if (data->host_cookie) {
5529aa51408SSeungwon Jeon 		data->host_cookie = 0;
5539aa51408SSeungwon Jeon 		return;
5549aa51408SSeungwon Jeon 	}
5559aa51408SSeungwon Jeon 
5569aa51408SSeungwon Jeon 	if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0)
5579aa51408SSeungwon Jeon 		data->host_cookie = 0;
5589aa51408SSeungwon Jeon }
5599aa51408SSeungwon Jeon 
5609aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc,
5619aa51408SSeungwon Jeon 			    struct mmc_request *mrq,
5629aa51408SSeungwon Jeon 			    int err)
5639aa51408SSeungwon Jeon {
5649aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
5659aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
5669aa51408SSeungwon Jeon 
5679aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
5689aa51408SSeungwon Jeon 		return;
5699aa51408SSeungwon Jeon 
5709aa51408SSeungwon Jeon 	if (data->host_cookie)
5714a90920cSThomas Abraham 		dma_unmap_sg(slot->host->dev,
5729aa51408SSeungwon Jeon 			     data->sg,
5739aa51408SSeungwon Jeon 			     data->sg_len,
5749aa51408SSeungwon Jeon 			     dw_mci_get_dma_dir(data));
5759aa51408SSeungwon Jeon 	data->host_cookie = 0;
5769aa51408SSeungwon Jeon }
5779aa51408SSeungwon Jeon 
57852426899SSeungwon Jeon static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
57952426899SSeungwon Jeon {
58052426899SSeungwon Jeon #ifdef CONFIG_MMC_DW_IDMAC
58152426899SSeungwon Jeon 	unsigned int blksz = data->blksz;
58252426899SSeungwon Jeon 	const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
58352426899SSeungwon Jeon 	u32 fifo_width = 1 << host->data_shift;
58452426899SSeungwon Jeon 	u32 blksz_depth = blksz / fifo_width, fifoth_val;
58552426899SSeungwon Jeon 	u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers;
58652426899SSeungwon Jeon 	int idx = (sizeof(mszs) / sizeof(mszs[0])) - 1;
58752426899SSeungwon Jeon 
58852426899SSeungwon Jeon 	tx_wmark = (host->fifo_depth) / 2;
58952426899SSeungwon Jeon 	tx_wmark_invers = host->fifo_depth - tx_wmark;
59052426899SSeungwon Jeon 
59152426899SSeungwon Jeon 	/*
59252426899SSeungwon Jeon 	 * MSIZE is '1',
59352426899SSeungwon Jeon 	 * if blksz is not a multiple of the FIFO width
59452426899SSeungwon Jeon 	 */
59552426899SSeungwon Jeon 	if (blksz % fifo_width) {
59652426899SSeungwon Jeon 		msize = 0;
59752426899SSeungwon Jeon 		rx_wmark = 1;
59852426899SSeungwon Jeon 		goto done;
59952426899SSeungwon Jeon 	}
60052426899SSeungwon Jeon 
60152426899SSeungwon Jeon 	do {
60252426899SSeungwon Jeon 		if (!((blksz_depth % mszs[idx]) ||
60352426899SSeungwon Jeon 		     (tx_wmark_invers % mszs[idx]))) {
60452426899SSeungwon Jeon 			msize = idx;
60552426899SSeungwon Jeon 			rx_wmark = mszs[idx] - 1;
60652426899SSeungwon Jeon 			break;
60752426899SSeungwon Jeon 		}
60852426899SSeungwon Jeon 	} while (--idx > 0);
60952426899SSeungwon Jeon 	/*
61052426899SSeungwon Jeon 	 * If idx is '0', it won't be tried
61152426899SSeungwon Jeon 	 * Thus, initial values are uesed
61252426899SSeungwon Jeon 	 */
61352426899SSeungwon Jeon done:
61452426899SSeungwon Jeon 	fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark);
61552426899SSeungwon Jeon 	mci_writel(host, FIFOTH, fifoth_val);
61652426899SSeungwon Jeon #endif
61752426899SSeungwon Jeon }
61852426899SSeungwon Jeon 
619f1d2736cSSeungwon Jeon static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)
620f1d2736cSSeungwon Jeon {
621f1d2736cSSeungwon Jeon 	unsigned int blksz = data->blksz;
622f1d2736cSSeungwon Jeon 	u32 blksz_depth, fifo_depth;
623f1d2736cSSeungwon Jeon 	u16 thld_size;
624f1d2736cSSeungwon Jeon 
625f1d2736cSSeungwon Jeon 	WARN_ON(!(data->flags & MMC_DATA_READ));
626f1d2736cSSeungwon Jeon 
627f1d2736cSSeungwon Jeon 	if (host->timing != MMC_TIMING_MMC_HS200 &&
628f1d2736cSSeungwon Jeon 	    host->timing != MMC_TIMING_UHS_SDR104)
629f1d2736cSSeungwon Jeon 		goto disable;
630f1d2736cSSeungwon Jeon 
631f1d2736cSSeungwon Jeon 	blksz_depth = blksz / (1 << host->data_shift);
632f1d2736cSSeungwon Jeon 	fifo_depth = host->fifo_depth;
633f1d2736cSSeungwon Jeon 
634f1d2736cSSeungwon Jeon 	if (blksz_depth > fifo_depth)
635f1d2736cSSeungwon Jeon 		goto disable;
636f1d2736cSSeungwon Jeon 
637f1d2736cSSeungwon Jeon 	/*
638f1d2736cSSeungwon Jeon 	 * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz'
639f1d2736cSSeungwon Jeon 	 * If (blksz_depth) <  (fifo_depth >> 1), should be thld_size = blksz
640f1d2736cSSeungwon Jeon 	 * Currently just choose blksz.
641f1d2736cSSeungwon Jeon 	 */
642f1d2736cSSeungwon Jeon 	thld_size = blksz;
643f1d2736cSSeungwon Jeon 	mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1));
644f1d2736cSSeungwon Jeon 	return;
645f1d2736cSSeungwon Jeon 
646f1d2736cSSeungwon Jeon disable:
647f1d2736cSSeungwon Jeon 	mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0));
648f1d2736cSSeungwon Jeon }
649f1d2736cSSeungwon Jeon 
6509aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
6519aa51408SSeungwon Jeon {
6529aa51408SSeungwon Jeon 	int sg_len;
6539aa51408SSeungwon Jeon 	u32 temp;
6549aa51408SSeungwon Jeon 
6559aa51408SSeungwon Jeon 	host->using_dma = 0;
6569aa51408SSeungwon Jeon 
6579aa51408SSeungwon Jeon 	/* If we don't have a channel, we can't do DMA */
6589aa51408SSeungwon Jeon 	if (!host->use_dma)
6599aa51408SSeungwon Jeon 		return -ENODEV;
6609aa51408SSeungwon Jeon 
6619aa51408SSeungwon Jeon 	sg_len = dw_mci_pre_dma_transfer(host, data, 0);
662a99aa9b9SSeungwon Jeon 	if (sg_len < 0) {
663a99aa9b9SSeungwon Jeon 		host->dma_ops->stop(host);
6649aa51408SSeungwon Jeon 		return sg_len;
665a99aa9b9SSeungwon Jeon 	}
6669aa51408SSeungwon Jeon 
66703e8cb53SJames Hogan 	host->using_dma = 1;
66803e8cb53SJames Hogan 
6694a90920cSThomas Abraham 	dev_vdbg(host->dev,
670f95f3850SWill Newton 		 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
671f95f3850SWill Newton 		 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
672f95f3850SWill Newton 		 sg_len);
673f95f3850SWill Newton 
67452426899SSeungwon Jeon 	/*
67552426899SSeungwon Jeon 	 * Decide the MSIZE and RX/TX Watermark.
67652426899SSeungwon Jeon 	 * If current block size is same with previous size,
67752426899SSeungwon Jeon 	 * no need to update fifoth.
67852426899SSeungwon Jeon 	 */
67952426899SSeungwon Jeon 	if (host->prev_blksz != data->blksz)
68052426899SSeungwon Jeon 		dw_mci_adjust_fifoth(host, data);
68152426899SSeungwon Jeon 
682f95f3850SWill Newton 	/* Enable the DMA interface */
683f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
684f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_ENABLE;
685f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
686f95f3850SWill Newton 
687f95f3850SWill Newton 	/* Disable RX/TX IRQs, let DMA handle it */
688f95f3850SWill Newton 	temp = mci_readl(host, INTMASK);
689f95f3850SWill Newton 	temp  &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR);
690f95f3850SWill Newton 	mci_writel(host, INTMASK, temp);
691f95f3850SWill Newton 
692f95f3850SWill Newton 	host->dma_ops->start(host, sg_len);
693f95f3850SWill Newton 
694f95f3850SWill Newton 	return 0;
695f95f3850SWill Newton }
696f95f3850SWill Newton 
697f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
698f95f3850SWill Newton {
699f95f3850SWill Newton 	u32 temp;
700f95f3850SWill Newton 
701f95f3850SWill Newton 	data->error = -EINPROGRESS;
702f95f3850SWill Newton 
703f95f3850SWill Newton 	WARN_ON(host->data);
704f95f3850SWill Newton 	host->sg = NULL;
705f95f3850SWill Newton 	host->data = data;
706f95f3850SWill Newton 
707f1d2736cSSeungwon Jeon 	if (data->flags & MMC_DATA_READ) {
70855c5efbcSJames Hogan 		host->dir_status = DW_MCI_RECV_STATUS;
709f1d2736cSSeungwon Jeon 		dw_mci_ctrl_rd_thld(host, data);
710f1d2736cSSeungwon Jeon 	} else {
71155c5efbcSJames Hogan 		host->dir_status = DW_MCI_SEND_STATUS;
712f1d2736cSSeungwon Jeon 	}
71355c5efbcSJames Hogan 
714f95f3850SWill Newton 	if (dw_mci_submit_data_dma(host, data)) {
715f9c2a0dcSSeungwon Jeon 		int flags = SG_MITER_ATOMIC;
716f9c2a0dcSSeungwon Jeon 		if (host->data->flags & MMC_DATA_READ)
717f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_TO_SG;
718f9c2a0dcSSeungwon Jeon 		else
719f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_FROM_SG;
720f9c2a0dcSSeungwon Jeon 
721f9c2a0dcSSeungwon Jeon 		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
722f95f3850SWill Newton 		host->sg = data->sg;
72334b664a2SJames Hogan 		host->part_buf_start = 0;
72434b664a2SJames Hogan 		host->part_buf_count = 0;
725f95f3850SWill Newton 
726b40af3aaSJames Hogan 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR);
727f95f3850SWill Newton 		temp = mci_readl(host, INTMASK);
728f95f3850SWill Newton 		temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR;
729f95f3850SWill Newton 		mci_writel(host, INTMASK, temp);
730f95f3850SWill Newton 
731f95f3850SWill Newton 		temp = mci_readl(host, CTRL);
732f95f3850SWill Newton 		temp &= ~SDMMC_CTRL_DMA_ENABLE;
733f95f3850SWill Newton 		mci_writel(host, CTRL, temp);
73452426899SSeungwon Jeon 
73552426899SSeungwon Jeon 		/*
73652426899SSeungwon Jeon 		 * Use the initial fifoth_val for PIO mode.
73752426899SSeungwon Jeon 		 * If next issued data may be transfered by DMA mode,
73852426899SSeungwon Jeon 		 * prev_blksz should be invalidated.
73952426899SSeungwon Jeon 		 */
74052426899SSeungwon Jeon 		mci_writel(host, FIFOTH, host->fifoth_val);
74152426899SSeungwon Jeon 		host->prev_blksz = 0;
74252426899SSeungwon Jeon 	} else {
74352426899SSeungwon Jeon 		/*
74452426899SSeungwon Jeon 		 * Keep the current block size.
74552426899SSeungwon Jeon 		 * It will be used to decide whether to update
74652426899SSeungwon Jeon 		 * fifoth register next time.
74752426899SSeungwon Jeon 		 */
74852426899SSeungwon Jeon 		host->prev_blksz = data->blksz;
749f95f3850SWill Newton 	}
750f95f3850SWill Newton }
751f95f3850SWill Newton 
752f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
753f95f3850SWill Newton {
754f95f3850SWill Newton 	struct dw_mci *host = slot->host;
755f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
756f95f3850SWill Newton 	unsigned int cmd_status = 0;
757f95f3850SWill Newton 
758f95f3850SWill Newton 	mci_writel(host, CMDARG, arg);
759f95f3850SWill Newton 	wmb();
760f95f3850SWill Newton 	mci_writel(host, CMD, SDMMC_CMD_START | cmd);
761f95f3850SWill Newton 
762f95f3850SWill Newton 	while (time_before(jiffies, timeout)) {
763f95f3850SWill Newton 		cmd_status = mci_readl(host, CMD);
764f95f3850SWill Newton 		if (!(cmd_status & SDMMC_CMD_START))
765f95f3850SWill Newton 			return;
766f95f3850SWill Newton 	}
767f95f3850SWill Newton 	dev_err(&slot->mmc->class_dev,
768f95f3850SWill Newton 		"Timeout sending command (cmd %#x arg %#x status %#x)\n",
769f95f3850SWill Newton 		cmd, arg, cmd_status);
770f95f3850SWill Newton }
771f95f3850SWill Newton 
772ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
773f95f3850SWill Newton {
774f95f3850SWill Newton 	struct dw_mci *host = slot->host;
775fdf492a1SDoug Anderson 	unsigned int clock = slot->clock;
776f95f3850SWill Newton 	u32 div;
7779623b5b9SDoug Anderson 	u32 clk_en_a;
778f95f3850SWill Newton 
779fdf492a1SDoug Anderson 	if (!clock) {
780fdf492a1SDoug Anderson 		mci_writel(host, CLKENA, 0);
781fdf492a1SDoug Anderson 		mci_send_cmd(slot,
782fdf492a1SDoug Anderson 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
783fdf492a1SDoug Anderson 	} else if (clock != host->current_speed || force_clkinit) {
784fdf492a1SDoug Anderson 		div = host->bus_hz / clock;
785fdf492a1SDoug Anderson 		if (host->bus_hz % clock && host->bus_hz > clock)
786f95f3850SWill Newton 			/*
787f95f3850SWill Newton 			 * move the + 1 after the divide to prevent
788f95f3850SWill Newton 			 * over-clocking the card.
789f95f3850SWill Newton 			 */
790e419990bSSeungwon Jeon 			div += 1;
791e419990bSSeungwon Jeon 
792fdf492a1SDoug Anderson 		div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0;
793f95f3850SWill Newton 
794fdf492a1SDoug Anderson 		if ((clock << div) != slot->__clk_old || force_clkinit)
795f95f3850SWill Newton 			dev_info(&slot->mmc->class_dev,
796fdf492a1SDoug Anderson 				 "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
797fdf492a1SDoug Anderson 				 slot->id, host->bus_hz, clock,
798fdf492a1SDoug Anderson 				 div ? ((host->bus_hz / div) >> 1) :
799fdf492a1SDoug Anderson 				 host->bus_hz, div);
800f95f3850SWill Newton 
801f95f3850SWill Newton 		/* disable clock */
802f95f3850SWill Newton 		mci_writel(host, CLKENA, 0);
803f95f3850SWill Newton 		mci_writel(host, CLKSRC, 0);
804f95f3850SWill Newton 
805f95f3850SWill Newton 		/* inform CIU */
806f95f3850SWill Newton 		mci_send_cmd(slot,
807f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
808f95f3850SWill Newton 
809f95f3850SWill Newton 		/* set clock to desired speed */
810f95f3850SWill Newton 		mci_writel(host, CLKDIV, div);
811f95f3850SWill Newton 
812f95f3850SWill Newton 		/* inform CIU */
813f95f3850SWill Newton 		mci_send_cmd(slot,
814f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
815f95f3850SWill Newton 
8169623b5b9SDoug Anderson 		/* enable clock; only low power if no SDIO */
8179623b5b9SDoug Anderson 		clk_en_a = SDMMC_CLKEN_ENABLE << slot->id;
8189623b5b9SDoug Anderson 		if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id)))
8199623b5b9SDoug Anderson 			clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id;
8209623b5b9SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a);
821f95f3850SWill Newton 
822f95f3850SWill Newton 		/* inform CIU */
823f95f3850SWill Newton 		mci_send_cmd(slot,
824f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
825f95f3850SWill Newton 
826fdf492a1SDoug Anderson 		/* keep the clock with reflecting clock dividor */
827fdf492a1SDoug Anderson 		slot->__clk_old = clock << div;
828f95f3850SWill Newton 	}
829f95f3850SWill Newton 
830fdf492a1SDoug Anderson 	host->current_speed = clock;
831fdf492a1SDoug Anderson 
832f95f3850SWill Newton 	/* Set the current slot bus width */
8331d56c453SSeungwon Jeon 	mci_writel(host, CTYPE, (slot->ctype << slot->id));
834f95f3850SWill Newton }
835f95f3850SWill Newton 
836053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host,
837053b3ce6SSeungwon Jeon 				   struct dw_mci_slot *slot,
838053b3ce6SSeungwon Jeon 				   struct mmc_command *cmd)
839f95f3850SWill Newton {
840f95f3850SWill Newton 	struct mmc_request *mrq;
841f95f3850SWill Newton 	struct mmc_data	*data;
842f95f3850SWill Newton 	u32 cmdflags;
843f95f3850SWill Newton 
844f95f3850SWill Newton 	mrq = slot->mrq;
845f95f3850SWill Newton 
846f95f3850SWill Newton 	host->cur_slot = slot;
847f95f3850SWill Newton 	host->mrq = mrq;
848f95f3850SWill Newton 
849f95f3850SWill Newton 	host->pending_events = 0;
850f95f3850SWill Newton 	host->completed_events = 0;
851e352c813SSeungwon Jeon 	host->cmd_status = 0;
852f95f3850SWill Newton 	host->data_status = 0;
853e352c813SSeungwon Jeon 	host->dir_status = 0;
854f95f3850SWill Newton 
855053b3ce6SSeungwon Jeon 	data = cmd->data;
856f95f3850SWill Newton 	if (data) {
857f16afa88SJaehoon Chung 		mci_writel(host, TMOUT, 0xFFFFFFFF);
858f95f3850SWill Newton 		mci_writel(host, BYTCNT, data->blksz*data->blocks);
859f95f3850SWill Newton 		mci_writel(host, BLKSIZ, data->blksz);
860f95f3850SWill Newton 	}
861f95f3850SWill Newton 
862f95f3850SWill Newton 	cmdflags = dw_mci_prepare_command(slot->mmc, cmd);
863f95f3850SWill Newton 
864f95f3850SWill Newton 	/* this is the first command, send the initialization clock */
865f95f3850SWill Newton 	if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags))
866f95f3850SWill Newton 		cmdflags |= SDMMC_CMD_INIT;
867f95f3850SWill Newton 
868f95f3850SWill Newton 	if (data) {
869f95f3850SWill Newton 		dw_mci_submit_data(host, data);
870f95f3850SWill Newton 		wmb();
871f95f3850SWill Newton 	}
872f95f3850SWill Newton 
873f95f3850SWill Newton 	dw_mci_start_command(host, cmd, cmdflags);
874f95f3850SWill Newton 
875f95f3850SWill Newton 	if (mrq->stop)
876f95f3850SWill Newton 		host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
87790c2143aSSeungwon Jeon 	else
87890c2143aSSeungwon Jeon 		host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd);
879f95f3850SWill Newton }
880f95f3850SWill Newton 
881053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host,
882053b3ce6SSeungwon Jeon 				 struct dw_mci_slot *slot)
883053b3ce6SSeungwon Jeon {
884053b3ce6SSeungwon Jeon 	struct mmc_request *mrq = slot->mrq;
885053b3ce6SSeungwon Jeon 	struct mmc_command *cmd;
886053b3ce6SSeungwon Jeon 
887053b3ce6SSeungwon Jeon 	cmd = mrq->sbc ? mrq->sbc : mrq->cmd;
888053b3ce6SSeungwon Jeon 	__dw_mci_start_request(host, slot, cmd);
889053b3ce6SSeungwon Jeon }
890053b3ce6SSeungwon Jeon 
8917456caaeSJames Hogan /* must be called with host->lock held */
892f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot,
893f95f3850SWill Newton 				 struct mmc_request *mrq)
894f95f3850SWill Newton {
895f95f3850SWill Newton 	dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
896f95f3850SWill Newton 		 host->state);
897f95f3850SWill Newton 
898f95f3850SWill Newton 	slot->mrq = mrq;
899f95f3850SWill Newton 
900f95f3850SWill Newton 	if (host->state == STATE_IDLE) {
901f95f3850SWill Newton 		host->state = STATE_SENDING_CMD;
902f95f3850SWill Newton 		dw_mci_start_request(host, slot);
903f95f3850SWill Newton 	} else {
904f95f3850SWill Newton 		list_add_tail(&slot->queue_node, &host->queue);
905f95f3850SWill Newton 	}
906f95f3850SWill Newton }
907f95f3850SWill Newton 
908f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
909f95f3850SWill Newton {
910f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
911f95f3850SWill Newton 	struct dw_mci *host = slot->host;
912f95f3850SWill Newton 
913f95f3850SWill Newton 	WARN_ON(slot->mrq);
914f95f3850SWill Newton 
9157456caaeSJames Hogan 	/*
9167456caaeSJames Hogan 	 * The check for card presence and queueing of the request must be
9177456caaeSJames Hogan 	 * atomic, otherwise the card could be removed in between and the
9187456caaeSJames Hogan 	 * request wouldn't fail until another card was inserted.
9197456caaeSJames Hogan 	 */
9207456caaeSJames Hogan 	spin_lock_bh(&host->lock);
9217456caaeSJames Hogan 
922f95f3850SWill Newton 	if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
9237456caaeSJames Hogan 		spin_unlock_bh(&host->lock);
924f95f3850SWill Newton 		mrq->cmd->error = -ENOMEDIUM;
925f95f3850SWill Newton 		mmc_request_done(mmc, mrq);
926f95f3850SWill Newton 		return;
927f95f3850SWill Newton 	}
928f95f3850SWill Newton 
929f95f3850SWill Newton 	dw_mci_queue_request(host, slot, mrq);
9307456caaeSJames Hogan 
9317456caaeSJames Hogan 	spin_unlock_bh(&host->lock);
932f95f3850SWill Newton }
933f95f3850SWill Newton 
934f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
935f95f3850SWill Newton {
936f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
937e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
93841babf75SJaehoon Chung 	u32 regs;
939f95f3850SWill Newton 
940f95f3850SWill Newton 	switch (ios->bus_width) {
941f95f3850SWill Newton 	case MMC_BUS_WIDTH_4:
942f95f3850SWill Newton 		slot->ctype = SDMMC_CTYPE_4BIT;
943f95f3850SWill Newton 		break;
944c9b2a06fSJaehoon Chung 	case MMC_BUS_WIDTH_8:
945c9b2a06fSJaehoon Chung 		slot->ctype = SDMMC_CTYPE_8BIT;
946c9b2a06fSJaehoon Chung 		break;
947b2f7cb45SJaehoon Chung 	default:
948b2f7cb45SJaehoon Chung 		/* set default 1 bit mode */
949b2f7cb45SJaehoon Chung 		slot->ctype = SDMMC_CTYPE_1BIT;
950f95f3850SWill Newton 	}
951f95f3850SWill Newton 
95241babf75SJaehoon Chung 	regs = mci_readl(slot->host, UHS_REG);
9533f514291SSeungwon Jeon 
9543f514291SSeungwon Jeon 	/* DDR mode set */
955cab3a802SSeungwon Jeon 	if (ios->timing == MMC_TIMING_MMC_DDR52)
956c69042a5SHyeonsu Kim 		regs |= ((0x1 << slot->id) << 16);
9573f514291SSeungwon Jeon 	else
958c69042a5SHyeonsu Kim 		regs &= ~((0x1 << slot->id) << 16);
9593f514291SSeungwon Jeon 
96041babf75SJaehoon Chung 	mci_writel(slot->host, UHS_REG, regs);
961f1d2736cSSeungwon Jeon 	slot->host->timing = ios->timing;
96241babf75SJaehoon Chung 
963f95f3850SWill Newton 	/*
964f95f3850SWill Newton 	 * Use mirror of ios->clock to prevent race with mmc
965f95f3850SWill Newton 	 * core ios update when finding the minimum.
966f95f3850SWill Newton 	 */
967f95f3850SWill Newton 	slot->clock = ios->clock;
968f95f3850SWill Newton 
969cb27a843SJames Hogan 	if (drv_data && drv_data->set_ios)
970cb27a843SJames Hogan 		drv_data->set_ios(slot->host, ios);
971800d78bfSThomas Abraham 
972bf7cb224SJaehoon Chung 	/* Slot specific timing and width adjustment */
973bf7cb224SJaehoon Chung 	dw_mci_setup_bus(slot, false);
974bf7cb224SJaehoon Chung 
975f95f3850SWill Newton 	switch (ios->power_mode) {
976f95f3850SWill Newton 	case MMC_POWER_UP:
977f95f3850SWill Newton 		set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
9784366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
9794366dcc5SJaehoon Chung 		regs |= (1 << slot->id);
9804366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
981e6f34e2fSJames Hogan 		break;
982e6f34e2fSJames Hogan 	case MMC_POWER_OFF:
9834366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
9844366dcc5SJaehoon Chung 		regs &= ~(1 << slot->id);
9854366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
986f95f3850SWill Newton 		break;
987f95f3850SWill Newton 	default:
988f95f3850SWill Newton 		break;
989f95f3850SWill Newton 	}
990f95f3850SWill Newton }
991f95f3850SWill Newton 
992f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc)
993f95f3850SWill Newton {
994f95f3850SWill Newton 	int read_only;
995f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
9969795a846SJaehoon Chung 	int gpio_ro = mmc_gpio_get_ro(mmc);
997f95f3850SWill Newton 
998f95f3850SWill Newton 	/* Use platform get_ro function, else try on board write protect */
99926375b5cSJaehoon Chung 	if ((slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT) ||
100026375b5cSJaehoon Chung 			(slot->host->quirks & DW_MCI_QUIRK_NO_WRITE_PROTECT))
1001b4967aa5SThomas Abraham 		read_only = 0;
10029795a846SJaehoon Chung 	else if (!IS_ERR_VALUE(gpio_ro))
10039795a846SJaehoon Chung 		read_only = gpio_ro;
1004f95f3850SWill Newton 	else
1005f95f3850SWill Newton 		read_only =
1006f95f3850SWill Newton 			mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0;
1007f95f3850SWill Newton 
1008f95f3850SWill Newton 	dev_dbg(&mmc->class_dev, "card is %s\n",
1009f95f3850SWill Newton 		read_only ? "read-only" : "read-write");
1010f95f3850SWill Newton 
1011f95f3850SWill Newton 	return read_only;
1012f95f3850SWill Newton }
1013f95f3850SWill Newton 
1014f95f3850SWill Newton static int dw_mci_get_cd(struct mmc_host *mmc)
1015f95f3850SWill Newton {
1016f95f3850SWill Newton 	int present;
1017f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
1018f95f3850SWill Newton 	struct dw_mci_board *brd = slot->host->pdata;
10197cf347bdSZhangfei Gao 	struct dw_mci *host = slot->host;
10207cf347bdSZhangfei Gao 	int gpio_cd = mmc_gpio_get_cd(mmc);
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;
1025bf626e55SZhangfei Gao 	else if (!IS_ERR_VALUE(gpio_cd))
10267cf347bdSZhangfei Gao 		present = gpio_cd;
1027f95f3850SWill Newton 	else
1028f95f3850SWill Newton 		present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
1029f95f3850SWill Newton 			== 0 ? 1 : 0;
1030f95f3850SWill Newton 
10317cf347bdSZhangfei Gao 	spin_lock_bh(&host->lock);
1032bf626e55SZhangfei Gao 	if (present) {
1033bf626e55SZhangfei Gao 		set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
1034f95f3850SWill Newton 		dev_dbg(&mmc->class_dev, "card is present\n");
1035bf626e55SZhangfei Gao 	} else {
1036bf626e55SZhangfei Gao 		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
1037f95f3850SWill Newton 		dev_dbg(&mmc->class_dev, "card is not present\n");
1038bf626e55SZhangfei Gao 	}
10397cf347bdSZhangfei Gao 	spin_unlock_bh(&host->lock);
1040f95f3850SWill Newton 
1041f95f3850SWill Newton 	return present;
1042f95f3850SWill Newton }
1043f95f3850SWill Newton 
10449623b5b9SDoug Anderson /*
10459623b5b9SDoug Anderson  * Disable lower power mode.
10469623b5b9SDoug Anderson  *
10479623b5b9SDoug Anderson  * Low power mode will stop the card clock when idle.  According to the
10489623b5b9SDoug Anderson  * description of the CLKENA register we should disable low power mode
10499623b5b9SDoug Anderson  * for SDIO cards if we need SDIO interrupts to work.
10509623b5b9SDoug Anderson  *
10519623b5b9SDoug Anderson  * This function is fast if low power mode is already disabled.
10529623b5b9SDoug Anderson  */
10539623b5b9SDoug Anderson static void dw_mci_disable_low_power(struct dw_mci_slot *slot)
10549623b5b9SDoug Anderson {
10559623b5b9SDoug Anderson 	struct dw_mci *host = slot->host;
10569623b5b9SDoug Anderson 	u32 clk_en_a;
10579623b5b9SDoug Anderson 	const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id;
10589623b5b9SDoug Anderson 
10599623b5b9SDoug Anderson 	clk_en_a = mci_readl(host, CLKENA);
10609623b5b9SDoug Anderson 
10619623b5b9SDoug Anderson 	if (clk_en_a & clken_low_pwr) {
10629623b5b9SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr);
10639623b5b9SDoug Anderson 		mci_send_cmd(slot, SDMMC_CMD_UPD_CLK |
10649623b5b9SDoug Anderson 			     SDMMC_CMD_PRV_DAT_WAIT, 0);
10659623b5b9SDoug Anderson 	}
10669623b5b9SDoug Anderson }
10679623b5b9SDoug Anderson 
10681a5c8e1fSShashidhar Hiremath static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
10691a5c8e1fSShashidhar Hiremath {
10701a5c8e1fSShashidhar Hiremath 	struct dw_mci_slot *slot = mmc_priv(mmc);
10711a5c8e1fSShashidhar Hiremath 	struct dw_mci *host = slot->host;
10721a5c8e1fSShashidhar Hiremath 	u32 int_mask;
10731a5c8e1fSShashidhar Hiremath 
10741a5c8e1fSShashidhar Hiremath 	/* Enable/disable Slot Specific SDIO interrupt */
10751a5c8e1fSShashidhar Hiremath 	int_mask = mci_readl(host, INTMASK);
10761a5c8e1fSShashidhar Hiremath 	if (enb) {
10779623b5b9SDoug Anderson 		/*
10789623b5b9SDoug Anderson 		 * Turn off low power mode if it was enabled.  This is a bit of
10799623b5b9SDoug Anderson 		 * a heavy operation and we disable / enable IRQs a lot, so
10809623b5b9SDoug Anderson 		 * we'll leave low power mode disabled and it will get
10819623b5b9SDoug Anderson 		 * re-enabled again in dw_mci_setup_bus().
10829623b5b9SDoug Anderson 		 */
10839623b5b9SDoug Anderson 		dw_mci_disable_low_power(slot);
10849623b5b9SDoug Anderson 
10851a5c8e1fSShashidhar Hiremath 		mci_writel(host, INTMASK,
1086705ad047SKyoungil Kim 			   (int_mask | SDMMC_INT_SDIO(slot->id)));
10871a5c8e1fSShashidhar Hiremath 	} else {
10881a5c8e1fSShashidhar Hiremath 		mci_writel(host, INTMASK,
1089705ad047SKyoungil Kim 			   (int_mask & ~SDMMC_INT_SDIO(slot->id)));
10901a5c8e1fSShashidhar Hiremath 	}
10911a5c8e1fSShashidhar Hiremath }
10921a5c8e1fSShashidhar Hiremath 
10930976f16dSSeungwon Jeon static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
10940976f16dSSeungwon Jeon {
10950976f16dSSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
10960976f16dSSeungwon Jeon 	struct dw_mci *host = slot->host;
10970976f16dSSeungwon Jeon 	const struct dw_mci_drv_data *drv_data = host->drv_data;
10980976f16dSSeungwon Jeon 	struct dw_mci_tuning_data tuning_data;
10990976f16dSSeungwon Jeon 	int err = -ENOSYS;
11000976f16dSSeungwon Jeon 
11010976f16dSSeungwon Jeon 	if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
11020976f16dSSeungwon Jeon 		if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
11030976f16dSSeungwon Jeon 			tuning_data.blk_pattern = tuning_blk_pattern_8bit;
11040976f16dSSeungwon Jeon 			tuning_data.blksz = sizeof(tuning_blk_pattern_8bit);
11050976f16dSSeungwon Jeon 		} else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
11060976f16dSSeungwon Jeon 			tuning_data.blk_pattern = tuning_blk_pattern_4bit;
11070976f16dSSeungwon Jeon 			tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
11080976f16dSSeungwon Jeon 		} else {
11090976f16dSSeungwon Jeon 			return -EINVAL;
11100976f16dSSeungwon Jeon 		}
11110976f16dSSeungwon Jeon 	} else if (opcode == MMC_SEND_TUNING_BLOCK) {
11120976f16dSSeungwon Jeon 		tuning_data.blk_pattern = tuning_blk_pattern_4bit;
11130976f16dSSeungwon Jeon 		tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
11140976f16dSSeungwon Jeon 	} else {
11150976f16dSSeungwon Jeon 		dev_err(host->dev,
11160976f16dSSeungwon Jeon 			"Undefined command(%d) for tuning\n", opcode);
11170976f16dSSeungwon Jeon 		return -EINVAL;
11180976f16dSSeungwon Jeon 	}
11190976f16dSSeungwon Jeon 
11200976f16dSSeungwon Jeon 	if (drv_data && drv_data->execute_tuning)
11210976f16dSSeungwon Jeon 		err = drv_data->execute_tuning(slot, opcode, &tuning_data);
11220976f16dSSeungwon Jeon 	return err;
11230976f16dSSeungwon Jeon }
11240976f16dSSeungwon Jeon 
1125f95f3850SWill Newton static const struct mmc_host_ops dw_mci_ops = {
1126f95f3850SWill Newton 	.request		= dw_mci_request,
11279aa51408SSeungwon Jeon 	.pre_req		= dw_mci_pre_req,
11289aa51408SSeungwon Jeon 	.post_req		= dw_mci_post_req,
1129f95f3850SWill Newton 	.set_ios		= dw_mci_set_ios,
1130f95f3850SWill Newton 	.get_ro			= dw_mci_get_ro,
1131f95f3850SWill Newton 	.get_cd			= dw_mci_get_cd,
11321a5c8e1fSShashidhar Hiremath 	.enable_sdio_irq	= dw_mci_enable_sdio_irq,
11330976f16dSSeungwon Jeon 	.execute_tuning		= dw_mci_execute_tuning,
1134f95f3850SWill Newton };
1135f95f3850SWill Newton 
1136f95f3850SWill Newton static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
1137f95f3850SWill Newton 	__releases(&host->lock)
1138f95f3850SWill Newton 	__acquires(&host->lock)
1139f95f3850SWill Newton {
1140f95f3850SWill Newton 	struct dw_mci_slot *slot;
1141f95f3850SWill Newton 	struct mmc_host	*prev_mmc = host->cur_slot->mmc;
1142f95f3850SWill Newton 
1143f95f3850SWill Newton 	WARN_ON(host->cmd || host->data);
1144f95f3850SWill Newton 
1145f95f3850SWill Newton 	host->cur_slot->mrq = NULL;
1146f95f3850SWill Newton 	host->mrq = NULL;
1147f95f3850SWill Newton 	if (!list_empty(&host->queue)) {
1148f95f3850SWill Newton 		slot = list_entry(host->queue.next,
1149f95f3850SWill Newton 				  struct dw_mci_slot, queue_node);
1150f95f3850SWill Newton 		list_del(&slot->queue_node);
11514a90920cSThomas Abraham 		dev_vdbg(host->dev, "list not empty: %s is next\n",
1152f95f3850SWill Newton 			 mmc_hostname(slot->mmc));
1153f95f3850SWill Newton 		host->state = STATE_SENDING_CMD;
1154f95f3850SWill Newton 		dw_mci_start_request(host, slot);
1155f95f3850SWill Newton 	} else {
11564a90920cSThomas Abraham 		dev_vdbg(host->dev, "list empty\n");
1157f95f3850SWill Newton 		host->state = STATE_IDLE;
1158f95f3850SWill Newton 	}
1159f95f3850SWill Newton 
1160f95f3850SWill Newton 	spin_unlock(&host->lock);
1161f95f3850SWill Newton 	mmc_request_done(prev_mmc, mrq);
1162f95f3850SWill Newton 	spin_lock(&host->lock);
1163f95f3850SWill Newton }
1164f95f3850SWill Newton 
1165e352c813SSeungwon Jeon static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
1166f95f3850SWill Newton {
1167f95f3850SWill Newton 	u32 status = host->cmd_status;
1168f95f3850SWill Newton 
1169f95f3850SWill Newton 	host->cmd_status = 0;
1170f95f3850SWill Newton 
1171f95f3850SWill Newton 	/* Read the response from the card (up to 16 bytes) */
1172f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_PRESENT) {
1173f95f3850SWill Newton 		if (cmd->flags & MMC_RSP_136) {
1174f95f3850SWill Newton 			cmd->resp[3] = mci_readl(host, RESP0);
1175f95f3850SWill Newton 			cmd->resp[2] = mci_readl(host, RESP1);
1176f95f3850SWill Newton 			cmd->resp[1] = mci_readl(host, RESP2);
1177f95f3850SWill Newton 			cmd->resp[0] = mci_readl(host, RESP3);
1178f95f3850SWill Newton 		} else {
1179f95f3850SWill Newton 			cmd->resp[0] = mci_readl(host, RESP0);
1180f95f3850SWill Newton 			cmd->resp[1] = 0;
1181f95f3850SWill Newton 			cmd->resp[2] = 0;
1182f95f3850SWill Newton 			cmd->resp[3] = 0;
1183f95f3850SWill Newton 		}
1184f95f3850SWill Newton 	}
1185f95f3850SWill Newton 
1186f95f3850SWill Newton 	if (status & SDMMC_INT_RTO)
1187f95f3850SWill Newton 		cmd->error = -ETIMEDOUT;
1188f95f3850SWill Newton 	else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC))
1189f95f3850SWill Newton 		cmd->error = -EILSEQ;
1190f95f3850SWill Newton 	else if (status & SDMMC_INT_RESP_ERR)
1191f95f3850SWill Newton 		cmd->error = -EIO;
1192f95f3850SWill Newton 	else
1193f95f3850SWill Newton 		cmd->error = 0;
1194f95f3850SWill Newton 
1195f95f3850SWill Newton 	if (cmd->error) {
1196f95f3850SWill Newton 		/* newer ip versions need a delay between retries */
1197f95f3850SWill Newton 		if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY)
1198f95f3850SWill Newton 			mdelay(20);
1199f95f3850SWill Newton 	}
1200e352c813SSeungwon Jeon 
1201e352c813SSeungwon Jeon 	return cmd->error;
1202e352c813SSeungwon Jeon }
1203e352c813SSeungwon Jeon 
1204e352c813SSeungwon Jeon static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data)
1205e352c813SSeungwon Jeon {
120631bff450SSeungwon Jeon 	u32 status = host->data_status;
1207e352c813SSeungwon Jeon 
1208e352c813SSeungwon Jeon 	if (status & DW_MCI_DATA_ERROR_FLAGS) {
1209e352c813SSeungwon Jeon 		if (status & SDMMC_INT_DRTO) {
1210e352c813SSeungwon Jeon 			data->error = -ETIMEDOUT;
1211e352c813SSeungwon Jeon 		} else if (status & SDMMC_INT_DCRC) {
1212e352c813SSeungwon Jeon 			data->error = -EILSEQ;
1213e352c813SSeungwon Jeon 		} else if (status & SDMMC_INT_EBE) {
1214e352c813SSeungwon Jeon 			if (host->dir_status ==
1215e352c813SSeungwon Jeon 				DW_MCI_SEND_STATUS) {
1216e352c813SSeungwon Jeon 				/*
1217e352c813SSeungwon Jeon 				 * No data CRC status was returned.
1218e352c813SSeungwon Jeon 				 * The number of bytes transferred
1219e352c813SSeungwon Jeon 				 * will be exaggerated in PIO mode.
1220e352c813SSeungwon Jeon 				 */
1221e352c813SSeungwon Jeon 				data->bytes_xfered = 0;
1222e352c813SSeungwon Jeon 				data->error = -ETIMEDOUT;
1223e352c813SSeungwon Jeon 			} else if (host->dir_status ==
1224e352c813SSeungwon Jeon 					DW_MCI_RECV_STATUS) {
1225e352c813SSeungwon Jeon 				data->error = -EIO;
1226e352c813SSeungwon Jeon 			}
1227e352c813SSeungwon Jeon 		} else {
1228e352c813SSeungwon Jeon 			/* SDMMC_INT_SBE is included */
1229e352c813SSeungwon Jeon 			data->error = -EIO;
1230e352c813SSeungwon Jeon 		}
1231e352c813SSeungwon Jeon 
1232e6cc0123SDoug Anderson 		dev_dbg(host->dev, "data error, status 0x%08x\n", status);
1233e352c813SSeungwon Jeon 
1234e352c813SSeungwon Jeon 		/*
1235e352c813SSeungwon Jeon 		 * After an error, there may be data lingering
123631bff450SSeungwon Jeon 		 * in the FIFO
1237e352c813SSeungwon Jeon 		 */
12383a33a94cSSonny Rao 		dw_mci_reset(host);
1239e352c813SSeungwon Jeon 	} else {
1240e352c813SSeungwon Jeon 		data->bytes_xfered = data->blocks * data->blksz;
1241e352c813SSeungwon Jeon 		data->error = 0;
1242e352c813SSeungwon Jeon 	}
1243e352c813SSeungwon Jeon 
1244e352c813SSeungwon Jeon 	return data->error;
1245f95f3850SWill Newton }
1246f95f3850SWill Newton 
1247f95f3850SWill Newton static void dw_mci_tasklet_func(unsigned long priv)
1248f95f3850SWill Newton {
1249f95f3850SWill Newton 	struct dw_mci *host = (struct dw_mci *)priv;
1250f95f3850SWill Newton 	struct mmc_data	*data;
1251f95f3850SWill Newton 	struct mmc_command *cmd;
1252e352c813SSeungwon Jeon 	struct mmc_request *mrq;
1253f95f3850SWill Newton 	enum dw_mci_state state;
1254f95f3850SWill Newton 	enum dw_mci_state prev_state;
1255e352c813SSeungwon Jeon 	unsigned int err;
1256f95f3850SWill Newton 
1257f95f3850SWill Newton 	spin_lock(&host->lock);
1258f95f3850SWill Newton 
1259f95f3850SWill Newton 	state = host->state;
1260f95f3850SWill Newton 	data = host->data;
1261e352c813SSeungwon Jeon 	mrq = host->mrq;
1262f95f3850SWill Newton 
1263f95f3850SWill Newton 	do {
1264f95f3850SWill Newton 		prev_state = state;
1265f95f3850SWill Newton 
1266f95f3850SWill Newton 		switch (state) {
1267f95f3850SWill Newton 		case STATE_IDLE:
1268f95f3850SWill Newton 			break;
1269f95f3850SWill Newton 
1270f95f3850SWill Newton 		case STATE_SENDING_CMD:
1271f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1272f95f3850SWill Newton 						&host->pending_events))
1273f95f3850SWill Newton 				break;
1274f95f3850SWill Newton 
1275f95f3850SWill Newton 			cmd = host->cmd;
1276f95f3850SWill Newton 			host->cmd = NULL;
1277f95f3850SWill Newton 			set_bit(EVENT_CMD_COMPLETE, &host->completed_events);
1278e352c813SSeungwon Jeon 			err = dw_mci_command_complete(host, cmd);
1279e352c813SSeungwon Jeon 			if (cmd == mrq->sbc && !err) {
1280053b3ce6SSeungwon Jeon 				prev_state = state = STATE_SENDING_CMD;
1281053b3ce6SSeungwon Jeon 				__dw_mci_start_request(host, host->cur_slot,
1282e352c813SSeungwon Jeon 						       mrq->cmd);
1283053b3ce6SSeungwon Jeon 				goto unlock;
1284053b3ce6SSeungwon Jeon 			}
1285053b3ce6SSeungwon Jeon 
1286e352c813SSeungwon Jeon 			if (cmd->data && err) {
128771abb133SSeungwon Jeon 				dw_mci_stop_dma(host);
128890c2143aSSeungwon Jeon 				send_stop_abort(host, data);
128971abb133SSeungwon Jeon 				state = STATE_SENDING_STOP;
129071abb133SSeungwon Jeon 				break;
129171abb133SSeungwon Jeon 			}
129271abb133SSeungwon Jeon 
1293e352c813SSeungwon Jeon 			if (!cmd->data || err) {
1294e352c813SSeungwon Jeon 				dw_mci_request_end(host, mrq);
1295f95f3850SWill Newton 				goto unlock;
1296f95f3850SWill Newton 			}
1297f95f3850SWill Newton 
1298f95f3850SWill Newton 			prev_state = state = STATE_SENDING_DATA;
1299f95f3850SWill Newton 			/* fall through */
1300f95f3850SWill Newton 
1301f95f3850SWill Newton 		case STATE_SENDING_DATA:
1302*2aa35465SDoug Anderson 			/*
1303*2aa35465SDoug Anderson 			 * We could get a data error and never a transfer
1304*2aa35465SDoug Anderson 			 * complete so we'd better check for it here.
1305*2aa35465SDoug Anderson 			 *
1306*2aa35465SDoug Anderson 			 * Note that we don't really care if we also got a
1307*2aa35465SDoug Anderson 			 * transfer complete; stopping the DMA and sending an
1308*2aa35465SDoug Anderson 			 * abort won't hurt.
1309*2aa35465SDoug Anderson 			 */
1310f95f3850SWill Newton 			if (test_and_clear_bit(EVENT_DATA_ERROR,
1311f95f3850SWill Newton 					       &host->pending_events)) {
1312f95f3850SWill Newton 				dw_mci_stop_dma(host);
131390c2143aSSeungwon Jeon 				send_stop_abort(host, data);
1314f95f3850SWill Newton 				state = STATE_DATA_ERROR;
1315f95f3850SWill Newton 				break;
1316f95f3850SWill Newton 			}
1317f95f3850SWill Newton 
1318f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1319f95f3850SWill Newton 						&host->pending_events))
1320f95f3850SWill Newton 				break;
1321f95f3850SWill Newton 
1322f95f3850SWill Newton 			set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
1323*2aa35465SDoug Anderson 
1324*2aa35465SDoug Anderson 			/*
1325*2aa35465SDoug Anderson 			 * Handle an EVENT_DATA_ERROR that might have shown up
1326*2aa35465SDoug Anderson 			 * before the transfer completed.  This might not have
1327*2aa35465SDoug Anderson 			 * been caught by the check above because the interrupt
1328*2aa35465SDoug Anderson 			 * could have gone off between the previous check and
1329*2aa35465SDoug Anderson 			 * the check for transfer complete.
1330*2aa35465SDoug Anderson 			 *
1331*2aa35465SDoug Anderson 			 * Technically this ought not be needed assuming we
1332*2aa35465SDoug Anderson 			 * get a DATA_COMPLETE eventually (we'll notice the
1333*2aa35465SDoug Anderson 			 * error and end the request), but it shouldn't hurt.
1334*2aa35465SDoug Anderson 			 *
1335*2aa35465SDoug Anderson 			 * This has the advantage of sending the stop command.
1336*2aa35465SDoug Anderson 			 */
1337*2aa35465SDoug Anderson 			if (test_and_clear_bit(EVENT_DATA_ERROR,
1338*2aa35465SDoug Anderson 					       &host->pending_events)) {
1339*2aa35465SDoug Anderson 				dw_mci_stop_dma(host);
1340*2aa35465SDoug Anderson 				send_stop_abort(host, data);
1341*2aa35465SDoug Anderson 				state = STATE_DATA_ERROR;
1342*2aa35465SDoug Anderson 				break;
1343*2aa35465SDoug Anderson 			}
1344f95f3850SWill Newton 			prev_state = state = STATE_DATA_BUSY;
1345*2aa35465SDoug Anderson 
1346f95f3850SWill Newton 			/* fall through */
1347f95f3850SWill Newton 
1348f95f3850SWill Newton 		case STATE_DATA_BUSY:
1349f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
1350f95f3850SWill Newton 						&host->pending_events))
1351f95f3850SWill Newton 				break;
1352f95f3850SWill Newton 
1353f95f3850SWill Newton 			host->data = NULL;
1354f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
1355e352c813SSeungwon Jeon 			err = dw_mci_data_complete(host, data);
1356f95f3850SWill Newton 
1357e352c813SSeungwon Jeon 			if (!err) {
1358e352c813SSeungwon Jeon 				if (!data->stop || mrq->sbc) {
135917c8bc85SSachin Kamat 					if (mrq->sbc && data->stop)
1360053b3ce6SSeungwon Jeon 						data->stop->error = 0;
1361e352c813SSeungwon Jeon 					dw_mci_request_end(host, mrq);
1362053b3ce6SSeungwon Jeon 					goto unlock;
1363053b3ce6SSeungwon Jeon 				}
1364053b3ce6SSeungwon Jeon 
136590c2143aSSeungwon Jeon 				/* stop command for open-ended transfer*/
1366e352c813SSeungwon Jeon 				if (data->stop)
136790c2143aSSeungwon Jeon 					send_stop_abort(host, data);
1368*2aa35465SDoug Anderson 			} else {
1369*2aa35465SDoug Anderson 				/*
1370*2aa35465SDoug Anderson 				 * If we don't have a command complete now we'll
1371*2aa35465SDoug Anderson 				 * never get one since we just reset everything;
1372*2aa35465SDoug Anderson 				 * better end the request.
1373*2aa35465SDoug Anderson 				 *
1374*2aa35465SDoug Anderson 				 * If we do have a command complete we'll fall
1375*2aa35465SDoug Anderson 				 * through to the SENDING_STOP command and
1376*2aa35465SDoug Anderson 				 * everything will be peachy keen.
1377*2aa35465SDoug Anderson 				 */
1378*2aa35465SDoug Anderson 				if (!test_bit(EVENT_CMD_COMPLETE,
1379*2aa35465SDoug Anderson 					      &host->pending_events)) {
1380*2aa35465SDoug Anderson 					host->cmd = NULL;
1381*2aa35465SDoug Anderson 					dw_mci_request_end(host, mrq);
1382*2aa35465SDoug Anderson 					goto unlock;
1383*2aa35465SDoug Anderson 				}
138490c2143aSSeungwon Jeon 			}
1385e352c813SSeungwon Jeon 
1386e352c813SSeungwon Jeon 			/*
1387e352c813SSeungwon Jeon 			 * If err has non-zero,
1388e352c813SSeungwon Jeon 			 * stop-abort command has been already issued.
1389e352c813SSeungwon Jeon 			 */
1390e352c813SSeungwon Jeon 			prev_state = state = STATE_SENDING_STOP;
1391e352c813SSeungwon Jeon 
1392f95f3850SWill Newton 			/* fall through */
1393f95f3850SWill Newton 
1394f95f3850SWill Newton 		case STATE_SENDING_STOP:
1395f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1396f95f3850SWill Newton 						&host->pending_events))
1397f95f3850SWill Newton 				break;
1398f95f3850SWill Newton 
139971abb133SSeungwon Jeon 			/* CMD error in data command */
140031bff450SSeungwon Jeon 			if (mrq->cmd->error && mrq->data)
14013a33a94cSSonny Rao 				dw_mci_reset(host);
140271abb133SSeungwon Jeon 
1403f95f3850SWill Newton 			host->cmd = NULL;
140471abb133SSeungwon Jeon 			host->data = NULL;
140590c2143aSSeungwon Jeon 
1406e352c813SSeungwon Jeon 			if (mrq->stop)
1407e352c813SSeungwon Jeon 				dw_mci_command_complete(host, mrq->stop);
140890c2143aSSeungwon Jeon 			else
140990c2143aSSeungwon Jeon 				host->cmd_status = 0;
141090c2143aSSeungwon Jeon 
1411e352c813SSeungwon Jeon 			dw_mci_request_end(host, mrq);
1412f95f3850SWill Newton 			goto unlock;
1413f95f3850SWill Newton 
1414f95f3850SWill Newton 		case STATE_DATA_ERROR:
1415f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1416f95f3850SWill Newton 						&host->pending_events))
1417f95f3850SWill Newton 				break;
1418f95f3850SWill Newton 
1419f95f3850SWill Newton 			state = STATE_DATA_BUSY;
1420f95f3850SWill Newton 			break;
1421f95f3850SWill Newton 		}
1422f95f3850SWill Newton 	} while (state != prev_state);
1423f95f3850SWill Newton 
1424f95f3850SWill Newton 	host->state = state;
1425f95f3850SWill Newton unlock:
1426f95f3850SWill Newton 	spin_unlock(&host->lock);
1427f95f3850SWill Newton 
1428f95f3850SWill Newton }
1429f95f3850SWill Newton 
143034b664a2SJames Hogan /* push final bytes to part_buf, only use during push */
143134b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt)
143234b664a2SJames Hogan {
143334b664a2SJames Hogan 	memcpy((void *)&host->part_buf, buf, cnt);
143434b664a2SJames Hogan 	host->part_buf_count = cnt;
143534b664a2SJames Hogan }
143634b664a2SJames Hogan 
143734b664a2SJames Hogan /* append bytes to part_buf, only use during push */
143834b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt)
143934b664a2SJames Hogan {
144034b664a2SJames Hogan 	cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count);
144134b664a2SJames Hogan 	memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt);
144234b664a2SJames Hogan 	host->part_buf_count += cnt;
144334b664a2SJames Hogan 	return cnt;
144434b664a2SJames Hogan }
144534b664a2SJames Hogan 
144634b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */
144734b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt)
144834b664a2SJames Hogan {
144934b664a2SJames Hogan 	cnt = min(cnt, (int)host->part_buf_count);
145034b664a2SJames Hogan 	if (cnt) {
145134b664a2SJames Hogan 		memcpy(buf, (void *)&host->part_buf + host->part_buf_start,
145234b664a2SJames Hogan 		       cnt);
145334b664a2SJames Hogan 		host->part_buf_count -= cnt;
145434b664a2SJames Hogan 		host->part_buf_start += cnt;
145534b664a2SJames Hogan 	}
145634b664a2SJames Hogan 	return cnt;
145734b664a2SJames Hogan }
145834b664a2SJames Hogan 
145934b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */
146034b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt)
146134b664a2SJames Hogan {
146234b664a2SJames Hogan 	memcpy(buf, &host->part_buf, cnt);
146334b664a2SJames Hogan 	host->part_buf_start = cnt;
146434b664a2SJames Hogan 	host->part_buf_count = (1 << host->data_shift) - cnt;
146534b664a2SJames Hogan }
146634b664a2SJames Hogan 
1467f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
1468f95f3850SWill Newton {
1469cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1470cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1471cfbeb59cSMarkos Chandras 
147234b664a2SJames Hogan 	/* try and push anything in the part_buf */
147334b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
147434b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
147534b664a2SJames Hogan 		buf += len;
147634b664a2SJames Hogan 		cnt -= len;
1477cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 2) {
14784e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
14794e0a5adfSJaehoon Chung 					host->part_buf16);
148034b664a2SJames Hogan 			host->part_buf_count = 0;
148134b664a2SJames Hogan 		}
148234b664a2SJames Hogan 	}
148334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
148434b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
148534b664a2SJames Hogan 		while (cnt >= 2) {
148634b664a2SJames Hogan 			u16 aligned_buf[64];
148734b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
148834b664a2SJames Hogan 			int items = len >> 1;
148934b664a2SJames Hogan 			int i;
149034b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
149134b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
149234b664a2SJames Hogan 			buf += len;
149334b664a2SJames Hogan 			cnt -= len;
149434b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
149534b664a2SJames Hogan 			for (i = 0; i < items; ++i)
14964e0a5adfSJaehoon Chung 				mci_writew(host, DATA(host->data_offset),
14974e0a5adfSJaehoon Chung 						aligned_buf[i]);
149834b664a2SJames Hogan 		}
149934b664a2SJames Hogan 	} else
150034b664a2SJames Hogan #endif
150134b664a2SJames Hogan 	{
150234b664a2SJames Hogan 		u16 *pdata = buf;
150334b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
15044e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset), *pdata++);
150534b664a2SJames Hogan 		buf = pdata;
150634b664a2SJames Hogan 	}
150734b664a2SJames Hogan 	/* put anything remaining in the part_buf */
150834b664a2SJames Hogan 	if (cnt) {
150934b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1510cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1511cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1512cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
15134e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
15144e0a5adfSJaehoon Chung 				   host->part_buf16);
1515f95f3850SWill Newton 	}
1516f95f3850SWill Newton }
1517f95f3850SWill Newton 
1518f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
1519f95f3850SWill Newton {
152034b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
152134b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
152234b664a2SJames Hogan 		while (cnt >= 2) {
152334b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
152434b664a2SJames Hogan 			u16 aligned_buf[64];
152534b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
152634b664a2SJames Hogan 			int items = len >> 1;
152734b664a2SJames Hogan 			int i;
152834b664a2SJames Hogan 			for (i = 0; i < items; ++i)
15294e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readw(host,
15304e0a5adfSJaehoon Chung 						DATA(host->data_offset));
153134b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
153234b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
153334b664a2SJames Hogan 			buf += len;
153434b664a2SJames Hogan 			cnt -= len;
153534b664a2SJames Hogan 		}
153634b664a2SJames Hogan 	} else
153734b664a2SJames Hogan #endif
153834b664a2SJames Hogan 	{
153934b664a2SJames Hogan 		u16 *pdata = buf;
154034b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
15414e0a5adfSJaehoon Chung 			*pdata++ = mci_readw(host, DATA(host->data_offset));
154234b664a2SJames Hogan 		buf = pdata;
154334b664a2SJames Hogan 	}
154434b664a2SJames Hogan 	if (cnt) {
15454e0a5adfSJaehoon Chung 		host->part_buf16 = mci_readw(host, DATA(host->data_offset));
154634b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1547f95f3850SWill Newton 	}
1548f95f3850SWill Newton }
1549f95f3850SWill Newton 
1550f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
1551f95f3850SWill Newton {
1552cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1553cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1554cfbeb59cSMarkos Chandras 
155534b664a2SJames Hogan 	/* try and push anything in the part_buf */
155634b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
155734b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
155834b664a2SJames Hogan 		buf += len;
155934b664a2SJames Hogan 		cnt -= len;
1560cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 4) {
15614e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
15624e0a5adfSJaehoon Chung 					host->part_buf32);
156334b664a2SJames Hogan 			host->part_buf_count = 0;
156434b664a2SJames Hogan 		}
156534b664a2SJames Hogan 	}
156634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
156734b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
156834b664a2SJames Hogan 		while (cnt >= 4) {
156934b664a2SJames Hogan 			u32 aligned_buf[32];
157034b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
157134b664a2SJames Hogan 			int items = len >> 2;
157234b664a2SJames Hogan 			int i;
157334b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
157434b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
157534b664a2SJames Hogan 			buf += len;
157634b664a2SJames Hogan 			cnt -= len;
157734b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
157834b664a2SJames Hogan 			for (i = 0; i < items; ++i)
15794e0a5adfSJaehoon Chung 				mci_writel(host, DATA(host->data_offset),
15804e0a5adfSJaehoon Chung 						aligned_buf[i]);
158134b664a2SJames Hogan 		}
158234b664a2SJames Hogan 	} else
158334b664a2SJames Hogan #endif
158434b664a2SJames Hogan 	{
158534b664a2SJames Hogan 		u32 *pdata = buf;
158634b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
15874e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset), *pdata++);
158834b664a2SJames Hogan 		buf = pdata;
158934b664a2SJames Hogan 	}
159034b664a2SJames Hogan 	/* put anything remaining in the part_buf */
159134b664a2SJames Hogan 	if (cnt) {
159234b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1593cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1594cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1595cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
15964e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
15974e0a5adfSJaehoon Chung 				   host->part_buf32);
1598f95f3850SWill Newton 	}
1599f95f3850SWill Newton }
1600f95f3850SWill Newton 
1601f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
1602f95f3850SWill Newton {
160334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
160434b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
160534b664a2SJames Hogan 		while (cnt >= 4) {
160634b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
160734b664a2SJames Hogan 			u32 aligned_buf[32];
160834b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
160934b664a2SJames Hogan 			int items = len >> 2;
161034b664a2SJames Hogan 			int i;
161134b664a2SJames Hogan 			for (i = 0; i < items; ++i)
16124e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readl(host,
16134e0a5adfSJaehoon Chung 						DATA(host->data_offset));
161434b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
161534b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
161634b664a2SJames Hogan 			buf += len;
161734b664a2SJames Hogan 			cnt -= len;
161834b664a2SJames Hogan 		}
161934b664a2SJames Hogan 	} else
162034b664a2SJames Hogan #endif
162134b664a2SJames Hogan 	{
162234b664a2SJames Hogan 		u32 *pdata = buf;
162334b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
16244e0a5adfSJaehoon Chung 			*pdata++ = mci_readl(host, DATA(host->data_offset));
162534b664a2SJames Hogan 		buf = pdata;
162634b664a2SJames Hogan 	}
162734b664a2SJames Hogan 	if (cnt) {
16284e0a5adfSJaehoon Chung 		host->part_buf32 = mci_readl(host, DATA(host->data_offset));
162934b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1630f95f3850SWill Newton 	}
1631f95f3850SWill Newton }
1632f95f3850SWill Newton 
1633f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
1634f95f3850SWill Newton {
1635cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1636cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1637cfbeb59cSMarkos Chandras 
163834b664a2SJames Hogan 	/* try and push anything in the part_buf */
163934b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
164034b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
164134b664a2SJames Hogan 		buf += len;
164234b664a2SJames Hogan 		cnt -= len;
1643c09fbd74SSeungwon Jeon 
1644cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 8) {
1645c09fbd74SSeungwon Jeon 			mci_writeq(host, DATA(host->data_offset),
16464e0a5adfSJaehoon Chung 					host->part_buf);
164734b664a2SJames Hogan 			host->part_buf_count = 0;
164834b664a2SJames Hogan 		}
164934b664a2SJames Hogan 	}
165034b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
165134b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
165234b664a2SJames Hogan 		while (cnt >= 8) {
165334b664a2SJames Hogan 			u64 aligned_buf[16];
165434b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
165534b664a2SJames Hogan 			int items = len >> 3;
165634b664a2SJames Hogan 			int i;
165734b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
165834b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
165934b664a2SJames Hogan 			buf += len;
166034b664a2SJames Hogan 			cnt -= len;
166134b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
166234b664a2SJames Hogan 			for (i = 0; i < items; ++i)
16634e0a5adfSJaehoon Chung 				mci_writeq(host, DATA(host->data_offset),
16644e0a5adfSJaehoon Chung 						aligned_buf[i]);
166534b664a2SJames Hogan 		}
166634b664a2SJames Hogan 	} else
166734b664a2SJames Hogan #endif
166834b664a2SJames Hogan 	{
166934b664a2SJames Hogan 		u64 *pdata = buf;
167034b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
16714e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset), *pdata++);
167234b664a2SJames Hogan 		buf = pdata;
167334b664a2SJames Hogan 	}
167434b664a2SJames Hogan 	/* put anything remaining in the part_buf */
167534b664a2SJames Hogan 	if (cnt) {
167634b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1677cfbeb59cSMarkos Chandras 		/* Push data if we have reached the expected data length */
1678cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1679cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
16804e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset),
16814e0a5adfSJaehoon Chung 				   host->part_buf);
1682f95f3850SWill Newton 	}
1683f95f3850SWill Newton }
1684f95f3850SWill Newton 
1685f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
1686f95f3850SWill Newton {
168734b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
168834b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
168934b664a2SJames Hogan 		while (cnt >= 8) {
169034b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
169134b664a2SJames Hogan 			u64 aligned_buf[16];
169234b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
169334b664a2SJames Hogan 			int items = len >> 3;
169434b664a2SJames Hogan 			int i;
169534b664a2SJames Hogan 			for (i = 0; i < items; ++i)
16964e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readq(host,
16974e0a5adfSJaehoon Chung 						DATA(host->data_offset));
169834b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
169934b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
170034b664a2SJames Hogan 			buf += len;
170134b664a2SJames Hogan 			cnt -= len;
1702f95f3850SWill Newton 		}
170334b664a2SJames Hogan 	} else
170434b664a2SJames Hogan #endif
170534b664a2SJames Hogan 	{
170634b664a2SJames Hogan 		u64 *pdata = buf;
170734b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
17084e0a5adfSJaehoon Chung 			*pdata++ = mci_readq(host, DATA(host->data_offset));
170934b664a2SJames Hogan 		buf = pdata;
171034b664a2SJames Hogan 	}
171134b664a2SJames Hogan 	if (cnt) {
17124e0a5adfSJaehoon Chung 		host->part_buf = mci_readq(host, DATA(host->data_offset));
171334b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
171434b664a2SJames Hogan 	}
171534b664a2SJames Hogan }
171634b664a2SJames Hogan 
171734b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
171834b664a2SJames Hogan {
171934b664a2SJames Hogan 	int len;
172034b664a2SJames Hogan 
172134b664a2SJames Hogan 	/* get remaining partial bytes */
172234b664a2SJames Hogan 	len = dw_mci_pull_part_bytes(host, buf, cnt);
172334b664a2SJames Hogan 	if (unlikely(len == cnt))
172434b664a2SJames Hogan 		return;
172534b664a2SJames Hogan 	buf += len;
172634b664a2SJames Hogan 	cnt -= len;
172734b664a2SJames Hogan 
172834b664a2SJames Hogan 	/* get the rest of the data */
172934b664a2SJames Hogan 	host->pull_data(host, buf, cnt);
1730f95f3850SWill Newton }
1731f95f3850SWill Newton 
173287a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto)
1733f95f3850SWill Newton {
1734f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1735f9c2a0dcSSeungwon Jeon 	void *buf;
1736f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1737f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1738f95f3850SWill Newton 	int shift = host->data_shift;
1739f95f3850SWill Newton 	u32 status;
17403e4b0d8bSMarkos Chandras 	unsigned int len;
1741f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1742f95f3850SWill Newton 
1743f95f3850SWill Newton 	do {
1744f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1745f9c2a0dcSSeungwon Jeon 			goto done;
1746f95f3850SWill Newton 
17474225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1748f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1749f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1750f9c2a0dcSSeungwon Jeon 		offset = 0;
1751f9c2a0dcSSeungwon Jeon 
1752f9c2a0dcSSeungwon Jeon 		do {
1753f9c2a0dcSSeungwon Jeon 			fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS))
1754f9c2a0dcSSeungwon Jeon 					<< shift) + host->part_buf_count;
1755f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1756f9c2a0dcSSeungwon Jeon 			if (!len)
1757f9c2a0dcSSeungwon Jeon 				break;
1758f9c2a0dcSSeungwon Jeon 			dw_mci_pull_data(host, (void *)(buf + offset), len);
17593e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1760f95f3850SWill Newton 			offset += len;
1761f9c2a0dcSSeungwon Jeon 			remain -= len;
1762f9c2a0dcSSeungwon Jeon 		} while (remain);
1763f95f3850SWill Newton 
1764e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1765f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1766f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
176787a74d39SKyoungil Kim 	/* if the RXDR is ready read again */
176887a74d39SKyoungil Kim 	} while ((status & SDMMC_INT_RXDR) ||
176987a74d39SKyoungil Kim 		 (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS))));
1770f9c2a0dcSSeungwon Jeon 
1771f9c2a0dcSSeungwon Jeon 	if (!remain) {
1772f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1773f9c2a0dcSSeungwon Jeon 			goto done;
1774f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1775f9c2a0dcSSeungwon Jeon 	}
1776f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1777f95f3850SWill Newton 	return;
1778f95f3850SWill Newton 
1779f95f3850SWill Newton done:
1780f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1781f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1782f95f3850SWill Newton 	smp_wmb();
1783f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1784f95f3850SWill Newton }
1785f95f3850SWill Newton 
1786f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host)
1787f95f3850SWill Newton {
1788f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1789f9c2a0dcSSeungwon Jeon 	void *buf;
1790f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1791f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1792f95f3850SWill Newton 	int shift = host->data_shift;
1793f95f3850SWill Newton 	u32 status;
17943e4b0d8bSMarkos Chandras 	unsigned int len;
1795f9c2a0dcSSeungwon Jeon 	unsigned int fifo_depth = host->fifo_depth;
1796f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1797f95f3850SWill Newton 
1798f95f3850SWill Newton 	do {
1799f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1800f9c2a0dcSSeungwon Jeon 			goto done;
1801f95f3850SWill Newton 
18024225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1803f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1804f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1805f9c2a0dcSSeungwon Jeon 		offset = 0;
1806f9c2a0dcSSeungwon Jeon 
1807f9c2a0dcSSeungwon Jeon 		do {
1808f9c2a0dcSSeungwon Jeon 			fcnt = ((fifo_depth -
1809f9c2a0dcSSeungwon Jeon 				 SDMMC_GET_FCNT(mci_readl(host, STATUS)))
1810f9c2a0dcSSeungwon Jeon 					<< shift) - host->part_buf_count;
1811f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1812f9c2a0dcSSeungwon Jeon 			if (!len)
1813f9c2a0dcSSeungwon Jeon 				break;
1814f9c2a0dcSSeungwon Jeon 			host->push_data(host, (void *)(buf + offset), len);
18153e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1816f95f3850SWill Newton 			offset += len;
1817f9c2a0dcSSeungwon Jeon 			remain -= len;
1818f9c2a0dcSSeungwon Jeon 		} while (remain);
1819f95f3850SWill Newton 
1820e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1821f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1822f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1823f95f3850SWill Newton 	} while (status & SDMMC_INT_TXDR); /* if TXDR write again */
1824f9c2a0dcSSeungwon Jeon 
1825f9c2a0dcSSeungwon Jeon 	if (!remain) {
1826f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1827f9c2a0dcSSeungwon Jeon 			goto done;
1828f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1829f9c2a0dcSSeungwon Jeon 	}
1830f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1831f95f3850SWill Newton 	return;
1832f95f3850SWill Newton 
1833f95f3850SWill Newton done:
1834f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1835f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1836f95f3850SWill Newton 	smp_wmb();
1837f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1838f95f3850SWill Newton }
1839f95f3850SWill Newton 
1840f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
1841f95f3850SWill Newton {
1842f95f3850SWill Newton 	if (!host->cmd_status)
1843f95f3850SWill Newton 		host->cmd_status = status;
1844f95f3850SWill Newton 
1845f95f3850SWill Newton 	smp_wmb();
1846f95f3850SWill Newton 
1847f95f3850SWill Newton 	set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1848f95f3850SWill Newton 	tasklet_schedule(&host->tasklet);
1849f95f3850SWill Newton }
1850f95f3850SWill Newton 
1851f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
1852f95f3850SWill Newton {
1853f95f3850SWill Newton 	struct dw_mci *host = dev_id;
1854182c9081SSeungwon Jeon 	u32 pending;
18551a5c8e1fSShashidhar Hiremath 	int i;
1856f95f3850SWill Newton 
1857f95f3850SWill Newton 	pending = mci_readl(host, MINTSTS); /* read-only mask reg */
1858f95f3850SWill Newton 
1859f95f3850SWill Newton 	/*
1860f95f3850SWill Newton 	 * DTO fix - version 2.10a and below, and only if internal DMA
1861f95f3850SWill Newton 	 * is configured.
1862f95f3850SWill Newton 	 */
1863f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
1864f95f3850SWill Newton 		if (!pending &&
1865f95f3850SWill Newton 		    ((mci_readl(host, STATUS) >> 17) & 0x1fff))
1866f95f3850SWill Newton 			pending |= SDMMC_INT_DATA_OVER;
1867f95f3850SWill Newton 	}
1868f95f3850SWill Newton 
1869476d79f1SDoug Anderson 	if (pending) {
1870f95f3850SWill Newton 		if (pending & DW_MCI_CMD_ERROR_FLAGS) {
1871f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
1872182c9081SSeungwon Jeon 			host->cmd_status = pending;
1873f95f3850SWill Newton 			smp_wmb();
1874f95f3850SWill Newton 			set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1875f95f3850SWill Newton 		}
1876f95f3850SWill Newton 
1877f95f3850SWill Newton 		if (pending & DW_MCI_DATA_ERROR_FLAGS) {
1878f95f3850SWill Newton 			/* if there is an error report DATA_ERROR */
1879f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
1880182c9081SSeungwon Jeon 			host->data_status = pending;
1881f95f3850SWill Newton 			smp_wmb();
1882f95f3850SWill Newton 			set_bit(EVENT_DATA_ERROR, &host->pending_events);
1883f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
1884f95f3850SWill Newton 		}
1885f95f3850SWill Newton 
1886f95f3850SWill Newton 		if (pending & SDMMC_INT_DATA_OVER) {
1887f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
1888f95f3850SWill Newton 			if (!host->data_status)
1889182c9081SSeungwon Jeon 				host->data_status = pending;
1890f95f3850SWill Newton 			smp_wmb();
1891f95f3850SWill Newton 			if (host->dir_status == DW_MCI_RECV_STATUS) {
1892f95f3850SWill Newton 				if (host->sg != NULL)
189387a74d39SKyoungil Kim 					dw_mci_read_data_pio(host, true);
1894f95f3850SWill Newton 			}
1895f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
1896f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
1897f95f3850SWill Newton 		}
1898f95f3850SWill Newton 
1899f95f3850SWill Newton 		if (pending & SDMMC_INT_RXDR) {
1900f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
1901b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_RECV_STATUS && host->sg)
190287a74d39SKyoungil Kim 				dw_mci_read_data_pio(host, false);
1903f95f3850SWill Newton 		}
1904f95f3850SWill Newton 
1905f95f3850SWill Newton 		if (pending & SDMMC_INT_TXDR) {
1906f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1907b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_SEND_STATUS && host->sg)
1908f95f3850SWill Newton 				dw_mci_write_data_pio(host);
1909f95f3850SWill Newton 		}
1910f95f3850SWill Newton 
1911f95f3850SWill Newton 		if (pending & SDMMC_INT_CMD_DONE) {
1912f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
1913182c9081SSeungwon Jeon 			dw_mci_cmd_interrupt(host, pending);
1914f95f3850SWill Newton 		}
1915f95f3850SWill Newton 
1916f95f3850SWill Newton 		if (pending & SDMMC_INT_CD) {
1917f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CD);
191895dcc2cbSThomas Abraham 			queue_work(host->card_workqueue, &host->card_work);
1919f95f3850SWill Newton 		}
1920f95f3850SWill Newton 
19211a5c8e1fSShashidhar Hiremath 		/* Handle SDIO Interrupts */
19221a5c8e1fSShashidhar Hiremath 		for (i = 0; i < host->num_slots; i++) {
19231a5c8e1fSShashidhar Hiremath 			struct dw_mci_slot *slot = host->slot[i];
19241a5c8e1fSShashidhar Hiremath 			if (pending & SDMMC_INT_SDIO(i)) {
19251a5c8e1fSShashidhar Hiremath 				mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
19261a5c8e1fSShashidhar Hiremath 				mmc_signal_sdio_irq(slot->mmc);
19271a5c8e1fSShashidhar Hiremath 			}
19281a5c8e1fSShashidhar Hiremath 		}
19291a5c8e1fSShashidhar Hiremath 
19301fb5f68aSMarkos Chandras 	}
1931f95f3850SWill Newton 
1932f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
1933f95f3850SWill Newton 	/* Handle DMA interrupts */
1934f95f3850SWill Newton 	pending = mci_readl(host, IDSTS);
1935f95f3850SWill Newton 	if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
1936f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
1937f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
1938f95f3850SWill Newton 		host->dma_ops->complete(host);
1939f95f3850SWill Newton 	}
1940f95f3850SWill Newton #endif
1941f95f3850SWill Newton 
1942f95f3850SWill Newton 	return IRQ_HANDLED;
1943f95f3850SWill Newton }
1944f95f3850SWill Newton 
19451791b13eSJames Hogan static void dw_mci_work_routine_card(struct work_struct *work)
1946f95f3850SWill Newton {
19471791b13eSJames Hogan 	struct dw_mci *host = container_of(work, struct dw_mci, card_work);
1948f95f3850SWill Newton 	int i;
1949f95f3850SWill Newton 
1950f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
1951f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
1952f95f3850SWill Newton 		struct mmc_host *mmc = slot->mmc;
1953f95f3850SWill Newton 		struct mmc_request *mrq;
1954f95f3850SWill Newton 		int present;
1955f95f3850SWill Newton 
1956f95f3850SWill Newton 		present = dw_mci_get_cd(mmc);
1957f95f3850SWill Newton 		while (present != slot->last_detect_state) {
1958f95f3850SWill Newton 			dev_dbg(&slot->mmc->class_dev, "card %s\n",
1959f95f3850SWill Newton 				present ? "inserted" : "removed");
1960f95f3850SWill Newton 
19611791b13eSJames Hogan 			spin_lock_bh(&host->lock);
19621791b13eSJames Hogan 
1963f95f3850SWill Newton 			/* Card change detected */
1964f95f3850SWill Newton 			slot->last_detect_state = present;
1965f95f3850SWill Newton 
1966f95f3850SWill Newton 			/* Clean up queue if present */
1967f95f3850SWill Newton 			mrq = slot->mrq;
1968f95f3850SWill Newton 			if (mrq) {
1969f95f3850SWill Newton 				if (mrq == host->mrq) {
1970f95f3850SWill Newton 					host->data = NULL;
1971f95f3850SWill Newton 					host->cmd = NULL;
1972f95f3850SWill Newton 
1973f95f3850SWill Newton 					switch (host->state) {
1974f95f3850SWill Newton 					case STATE_IDLE:
1975f95f3850SWill Newton 						break;
1976f95f3850SWill Newton 					case STATE_SENDING_CMD:
1977f95f3850SWill Newton 						mrq->cmd->error = -ENOMEDIUM;
1978f95f3850SWill Newton 						if (!mrq->data)
1979f95f3850SWill Newton 							break;
1980f95f3850SWill Newton 						/* fall through */
1981f95f3850SWill Newton 					case STATE_SENDING_DATA:
1982f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
1983f95f3850SWill Newton 						dw_mci_stop_dma(host);
1984f95f3850SWill Newton 						break;
1985f95f3850SWill Newton 					case STATE_DATA_BUSY:
1986f95f3850SWill Newton 					case STATE_DATA_ERROR:
1987f95f3850SWill Newton 						if (mrq->data->error == -EINPROGRESS)
1988f95f3850SWill Newton 							mrq->data->error = -ENOMEDIUM;
1989f95f3850SWill Newton 						/* fall through */
1990f95f3850SWill Newton 					case STATE_SENDING_STOP:
199190c2143aSSeungwon Jeon 						if (mrq->stop)
1992f95f3850SWill Newton 							mrq->stop->error = -ENOMEDIUM;
1993f95f3850SWill Newton 						break;
1994f95f3850SWill Newton 					}
1995f95f3850SWill Newton 
1996f95f3850SWill Newton 					dw_mci_request_end(host, mrq);
1997f95f3850SWill Newton 				} else {
1998f95f3850SWill Newton 					list_del(&slot->queue_node);
1999f95f3850SWill Newton 					mrq->cmd->error = -ENOMEDIUM;
2000f95f3850SWill Newton 					if (mrq->data)
2001f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
2002f95f3850SWill Newton 					if (mrq->stop)
2003f95f3850SWill Newton 						mrq->stop->error = -ENOMEDIUM;
2004f95f3850SWill Newton 
2005f95f3850SWill Newton 					spin_unlock(&host->lock);
2006f95f3850SWill Newton 					mmc_request_done(slot->mmc, mrq);
2007f95f3850SWill Newton 					spin_lock(&host->lock);
2008f95f3850SWill Newton 				}
2009f95f3850SWill Newton 			}
2010f95f3850SWill Newton 
2011f95f3850SWill Newton 			/* Power down slot */
20123a33a94cSSonny Rao 			if (present == 0)
20133a33a94cSSonny Rao 				dw_mci_reset(host);
2014f95f3850SWill Newton 
20151791b13eSJames Hogan 			spin_unlock_bh(&host->lock);
20161791b13eSJames Hogan 
2017f95f3850SWill Newton 			present = dw_mci_get_cd(mmc);
2018f95f3850SWill Newton 		}
2019f95f3850SWill Newton 
2020f95f3850SWill Newton 		mmc_detect_change(slot->mmc,
2021f95f3850SWill Newton 			msecs_to_jiffies(host->pdata->detect_delay_ms));
2022f95f3850SWill Newton 	}
2023f95f3850SWill Newton }
2024f95f3850SWill Newton 
2025c91eab4bSThomas Abraham #ifdef CONFIG_OF
2026c91eab4bSThomas Abraham /* given a slot id, find out the device node representing that slot */
2027c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
2028c91eab4bSThomas Abraham {
2029c91eab4bSThomas Abraham 	struct device_node *np;
2030c91eab4bSThomas Abraham 	const __be32 *addr;
2031c91eab4bSThomas Abraham 	int len;
2032c91eab4bSThomas Abraham 
2033c91eab4bSThomas Abraham 	if (!dev || !dev->of_node)
2034c91eab4bSThomas Abraham 		return NULL;
2035c91eab4bSThomas Abraham 
2036c91eab4bSThomas Abraham 	for_each_child_of_node(dev->of_node, np) {
2037c91eab4bSThomas Abraham 		addr = of_get_property(np, "reg", &len);
2038c91eab4bSThomas Abraham 		if (!addr || (len < sizeof(int)))
2039c91eab4bSThomas Abraham 			continue;
2040c91eab4bSThomas Abraham 		if (be32_to_cpup(addr) == slot)
2041c91eab4bSThomas Abraham 			return np;
2042c91eab4bSThomas Abraham 	}
2043c91eab4bSThomas Abraham 	return NULL;
2044c91eab4bSThomas Abraham }
2045c91eab4bSThomas Abraham 
2046a70aaa64SDoug Anderson static struct dw_mci_of_slot_quirks {
2047a70aaa64SDoug Anderson 	char *quirk;
2048a70aaa64SDoug Anderson 	int id;
2049a70aaa64SDoug Anderson } of_slot_quirks[] = {
2050a70aaa64SDoug Anderson 	{
2051a70aaa64SDoug Anderson 		.quirk	= "disable-wp",
2052a70aaa64SDoug Anderson 		.id	= DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT,
2053a70aaa64SDoug Anderson 	},
2054a70aaa64SDoug Anderson };
2055a70aaa64SDoug Anderson 
2056a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
2057a70aaa64SDoug Anderson {
2058a70aaa64SDoug Anderson 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
2059a70aaa64SDoug Anderson 	int quirks = 0;
2060a70aaa64SDoug Anderson 	int idx;
2061a70aaa64SDoug Anderson 
2062a70aaa64SDoug Anderson 	/* get quirks */
2063a70aaa64SDoug Anderson 	for (idx = 0; idx < ARRAY_SIZE(of_slot_quirks); idx++)
206426375b5cSJaehoon Chung 		if (of_get_property(np, of_slot_quirks[idx].quirk, NULL)) {
206526375b5cSJaehoon Chung 			dev_warn(dev, "Slot quirk %s is deprecated\n",
206626375b5cSJaehoon Chung 					of_slot_quirks[idx].quirk);
2067a70aaa64SDoug Anderson 			quirks |= of_slot_quirks[idx].id;
206826375b5cSJaehoon Chung 		}
2069a70aaa64SDoug Anderson 
2070a70aaa64SDoug Anderson 	return quirks;
2071a70aaa64SDoug Anderson }
2072c91eab4bSThomas Abraham #else /* CONFIG_OF */
2073a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
2074a70aaa64SDoug Anderson {
2075a70aaa64SDoug Anderson 	return 0;
2076a70aaa64SDoug Anderson }
2077c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
2078c91eab4bSThomas Abraham {
2079c91eab4bSThomas Abraham 	return NULL;
2080c91eab4bSThomas Abraham }
2081c91eab4bSThomas Abraham #endif /* CONFIG_OF */
2082c91eab4bSThomas Abraham 
208336c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
2084f95f3850SWill Newton {
2085f95f3850SWill Newton 	struct mmc_host *mmc;
2086f95f3850SWill Newton 	struct dw_mci_slot *slot;
2087e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
2088800d78bfSThomas Abraham 	int ctrl_id, ret;
20891f44a2a5SSeungwon Jeon 	u32 freq[2];
2090f95f3850SWill Newton 
20914a90920cSThomas Abraham 	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
2092f95f3850SWill Newton 	if (!mmc)
2093f95f3850SWill Newton 		return -ENOMEM;
2094f95f3850SWill Newton 
2095f95f3850SWill Newton 	slot = mmc_priv(mmc);
2096f95f3850SWill Newton 	slot->id = id;
2097f95f3850SWill Newton 	slot->mmc = mmc;
2098f95f3850SWill Newton 	slot->host = host;
2099c91eab4bSThomas Abraham 	host->slot[id] = slot;
2100f95f3850SWill Newton 
2101a70aaa64SDoug Anderson 	slot->quirks = dw_mci_of_get_slot_quirks(host->dev, slot->id);
2102a70aaa64SDoug Anderson 
2103f95f3850SWill Newton 	mmc->ops = &dw_mci_ops;
21041f44a2a5SSeungwon Jeon 	if (of_property_read_u32_array(host->dev->of_node,
21051f44a2a5SSeungwon Jeon 				       "clock-freq-min-max", freq, 2)) {
21061f44a2a5SSeungwon Jeon 		mmc->f_min = DW_MCI_FREQ_MIN;
21071f44a2a5SSeungwon Jeon 		mmc->f_max = DW_MCI_FREQ_MAX;
21081f44a2a5SSeungwon Jeon 	} else {
21091f44a2a5SSeungwon Jeon 		mmc->f_min = freq[0];
21101f44a2a5SSeungwon Jeon 		mmc->f_max = freq[1];
21111f44a2a5SSeungwon Jeon 	}
2112f95f3850SWill Newton 
2113f95f3850SWill Newton 	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
2114f95f3850SWill Newton 
2115fc3d7720SJaehoon Chung 	if (host->pdata->caps)
2116fc3d7720SJaehoon Chung 		mmc->caps = host->pdata->caps;
2117fc3d7720SJaehoon Chung 
2118ab269128SAbhilash Kesavan 	if (host->pdata->pm_caps)
2119ab269128SAbhilash Kesavan 		mmc->pm_caps = host->pdata->pm_caps;
2120ab269128SAbhilash Kesavan 
2121800d78bfSThomas Abraham 	if (host->dev->of_node) {
2122800d78bfSThomas Abraham 		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
2123800d78bfSThomas Abraham 		if (ctrl_id < 0)
2124800d78bfSThomas Abraham 			ctrl_id = 0;
2125800d78bfSThomas Abraham 	} else {
2126800d78bfSThomas Abraham 		ctrl_id = to_platform_device(host->dev)->id;
2127800d78bfSThomas Abraham 	}
2128cb27a843SJames Hogan 	if (drv_data && drv_data->caps)
2129cb27a843SJames Hogan 		mmc->caps |= drv_data->caps[ctrl_id];
2130800d78bfSThomas Abraham 
21314f408cc6SSeungwon Jeon 	if (host->pdata->caps2)
21324f408cc6SSeungwon Jeon 		mmc->caps2 = host->pdata->caps2;
21334f408cc6SSeungwon Jeon 
2134d8a4fb0eSJaehoon Chung 	mmc_of_parse(mmc);
2135f95f3850SWill Newton 
2136f95f3850SWill Newton 	if (host->pdata->blk_settings) {
2137f95f3850SWill Newton 		mmc->max_segs = host->pdata->blk_settings->max_segs;
2138f95f3850SWill Newton 		mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
2139f95f3850SWill Newton 		mmc->max_blk_count = host->pdata->blk_settings->max_blk_count;
2140f95f3850SWill Newton 		mmc->max_req_size = host->pdata->blk_settings->max_req_size;
2141f95f3850SWill Newton 		mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
2142f95f3850SWill Newton 	} else {
2143f95f3850SWill Newton 		/* Useful defaults if platform data is unset. */
2144a39e5746SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
2145a39e5746SJaehoon Chung 		mmc->max_segs = host->ring_size;
2146a39e5746SJaehoon Chung 		mmc->max_blk_size = 65536;
2147a39e5746SJaehoon Chung 		mmc->max_blk_count = host->ring_size;
2148a39e5746SJaehoon Chung 		mmc->max_seg_size = 0x1000;
2149a39e5746SJaehoon Chung 		mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
2150a39e5746SJaehoon Chung #else
2151f95f3850SWill Newton 		mmc->max_segs = 64;
2152f95f3850SWill Newton 		mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
2153f95f3850SWill Newton 		mmc->max_blk_count = 512;
2154f95f3850SWill Newton 		mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
2155f95f3850SWill Newton 		mmc->max_seg_size = mmc->max_req_size;
2156f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */
2157a39e5746SJaehoon Chung 	}
2158f95f3850SWill Newton 
2159ae0eb348SJaehoon Chung 	if (dw_mci_get_cd(mmc))
2160ae0eb348SJaehoon Chung 		set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
2161ae0eb348SJaehoon Chung 	else
2162ae0eb348SJaehoon Chung 		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
2163ae0eb348SJaehoon Chung 
21640cea529dSJaehoon Chung 	ret = mmc_add_host(mmc);
21650cea529dSJaehoon Chung 	if (ret)
21660cea529dSJaehoon Chung 		goto err_setup_bus;
2167f95f3850SWill Newton 
2168f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS)
2169f95f3850SWill Newton 	dw_mci_init_debugfs(slot);
2170f95f3850SWill Newton #endif
2171f95f3850SWill Newton 
2172f95f3850SWill Newton 	/* Card initially undetected */
2173f95f3850SWill Newton 	slot->last_detect_state = 0;
2174f95f3850SWill Newton 
2175f95f3850SWill Newton 	return 0;
2176800d78bfSThomas Abraham 
2177800d78bfSThomas Abraham err_setup_bus:
2178800d78bfSThomas Abraham 	mmc_free_host(mmc);
2179800d78bfSThomas Abraham 	return -EINVAL;
2180f95f3850SWill Newton }
2181f95f3850SWill Newton 
2182f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
2183f95f3850SWill Newton {
2184f95f3850SWill Newton 	/* Debugfs stuff is cleaned up by mmc core */
2185f95f3850SWill Newton 	mmc_remove_host(slot->mmc);
2186f95f3850SWill Newton 	slot->host->slot[id] = NULL;
2187f95f3850SWill Newton 	mmc_free_host(slot->mmc);
2188f95f3850SWill Newton }
2189f95f3850SWill Newton 
2190f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host)
2191f95f3850SWill Newton {
2192f95f3850SWill Newton 	/* Alloc memory for sg translation */
2193780f22afSSeungwon Jeon 	host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
2194f95f3850SWill Newton 					  &host->sg_dma, GFP_KERNEL);
2195f95f3850SWill Newton 	if (!host->sg_cpu) {
21964a90920cSThomas Abraham 		dev_err(host->dev, "%s: could not alloc DMA memory\n",
2197f95f3850SWill Newton 			__func__);
2198f95f3850SWill Newton 		goto no_dma;
2199f95f3850SWill Newton 	}
2200f95f3850SWill Newton 
2201f95f3850SWill Newton 	/* Determine which DMA interface to use */
2202f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
2203f95f3850SWill Newton 	host->dma_ops = &dw_mci_idmac_ops;
220400956ea3SSeungwon Jeon 	dev_info(host->dev, "Using internal DMA controller.\n");
2205f95f3850SWill Newton #endif
2206f95f3850SWill Newton 
2207f95f3850SWill Newton 	if (!host->dma_ops)
2208f95f3850SWill Newton 		goto no_dma;
2209f95f3850SWill Newton 
2210e1631f98SJaehoon Chung 	if (host->dma_ops->init && host->dma_ops->start &&
2211e1631f98SJaehoon Chung 	    host->dma_ops->stop && host->dma_ops->cleanup) {
2212f95f3850SWill Newton 		if (host->dma_ops->init(host)) {
22134a90920cSThomas Abraham 			dev_err(host->dev, "%s: Unable to initialize "
2214f95f3850SWill Newton 				"DMA Controller.\n", __func__);
2215f95f3850SWill Newton 			goto no_dma;
2216f95f3850SWill Newton 		}
2217f95f3850SWill Newton 	} else {
22184a90920cSThomas Abraham 		dev_err(host->dev, "DMA initialization not found.\n");
2219f95f3850SWill Newton 		goto no_dma;
2220f95f3850SWill Newton 	}
2221f95f3850SWill Newton 
2222f95f3850SWill Newton 	host->use_dma = 1;
2223f95f3850SWill Newton 	return;
2224f95f3850SWill Newton 
2225f95f3850SWill Newton no_dma:
22264a90920cSThomas Abraham 	dev_info(host->dev, "Using PIO mode.\n");
2227f95f3850SWill Newton 	host->use_dma = 0;
2228f95f3850SWill Newton 	return;
2229f95f3850SWill Newton }
2230f95f3850SWill Newton 
223131bff450SSeungwon Jeon static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset)
2232f95f3850SWill Newton {
2233f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
223431bff450SSeungwon Jeon 	u32 ctrl;
2235f95f3850SWill Newton 
223631bff450SSeungwon Jeon 	ctrl = mci_readl(host, CTRL);
223731bff450SSeungwon Jeon 	ctrl |= reset;
223831bff450SSeungwon Jeon 	mci_writel(host, CTRL, ctrl);
2239f95f3850SWill Newton 
2240f95f3850SWill Newton 	/* wait till resets clear */
2241f95f3850SWill Newton 	do {
2242f95f3850SWill Newton 		ctrl = mci_readl(host, CTRL);
224331bff450SSeungwon Jeon 		if (!(ctrl & reset))
2244f95f3850SWill Newton 			return true;
2245f95f3850SWill Newton 	} while (time_before(jiffies, timeout));
2246f95f3850SWill Newton 
224731bff450SSeungwon Jeon 	dev_err(host->dev,
224831bff450SSeungwon Jeon 		"Timeout resetting block (ctrl reset %#x)\n",
224931bff450SSeungwon Jeon 		ctrl & reset);
2250f95f3850SWill Newton 
2251f95f3850SWill Newton 	return false;
2252f95f3850SWill Newton }
2253f95f3850SWill Newton 
22543a33a94cSSonny Rao static bool dw_mci_reset(struct dw_mci *host)
225531bff450SSeungwon Jeon {
22563a33a94cSSonny Rao 	u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET;
22573a33a94cSSonny Rao 	bool ret = false;
22583a33a94cSSonny Rao 
225931bff450SSeungwon Jeon 	/*
226031bff450SSeungwon Jeon 	 * Reseting generates a block interrupt, hence setting
226131bff450SSeungwon Jeon 	 * the scatter-gather pointer to NULL.
226231bff450SSeungwon Jeon 	 */
226331bff450SSeungwon Jeon 	if (host->sg) {
226431bff450SSeungwon Jeon 		sg_miter_stop(&host->sg_miter);
226531bff450SSeungwon Jeon 		host->sg = NULL;
226631bff450SSeungwon Jeon 	}
226731bff450SSeungwon Jeon 
22683a33a94cSSonny Rao 	if (host->use_dma)
22693a33a94cSSonny Rao 		flags |= SDMMC_CTRL_DMA_RESET;
22703a33a94cSSonny Rao 
22713a33a94cSSonny Rao 	if (dw_mci_ctrl_reset(host, flags)) {
22723a33a94cSSonny Rao 		/*
22733a33a94cSSonny Rao 		 * In all cases we clear the RAWINTS register to clear any
22743a33a94cSSonny Rao 		 * interrupts.
22753a33a94cSSonny Rao 		 */
22763a33a94cSSonny Rao 		mci_writel(host, RINTSTS, 0xFFFFFFFF);
22773a33a94cSSonny Rao 
22783a33a94cSSonny Rao 		/* if using dma we wait for dma_req to clear */
22793a33a94cSSonny Rao 		if (host->use_dma) {
22803a33a94cSSonny Rao 			unsigned long timeout = jiffies + msecs_to_jiffies(500);
22813a33a94cSSonny Rao 			u32 status;
22823a33a94cSSonny Rao 			do {
22833a33a94cSSonny Rao 				status = mci_readl(host, STATUS);
22843a33a94cSSonny Rao 				if (!(status & SDMMC_STATUS_DMA_REQ))
22853a33a94cSSonny Rao 					break;
22863a33a94cSSonny Rao 				cpu_relax();
22873a33a94cSSonny Rao 			} while (time_before(jiffies, timeout));
22883a33a94cSSonny Rao 
22893a33a94cSSonny Rao 			if (status & SDMMC_STATUS_DMA_REQ) {
22903a33a94cSSonny Rao 				dev_err(host->dev,
22913a33a94cSSonny Rao 					"%s: Timeout waiting for dma_req to "
22923a33a94cSSonny Rao 					"clear during reset\n", __func__);
22933a33a94cSSonny Rao 				goto ciu_out;
229431bff450SSeungwon Jeon 			}
229531bff450SSeungwon Jeon 
22963a33a94cSSonny Rao 			/* when using DMA next we reset the fifo again */
22973a33a94cSSonny Rao 			if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET))
22983a33a94cSSonny Rao 				goto ciu_out;
22993a33a94cSSonny Rao 		}
23003a33a94cSSonny Rao 	} else {
23013a33a94cSSonny Rao 		/* if the controller reset bit did clear, then set clock regs */
23023a33a94cSSonny Rao 		if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) {
23033a33a94cSSonny Rao 			dev_err(host->dev, "%s: fifo/dma reset bits didn't "
23043a33a94cSSonny Rao 				"clear but ciu was reset, doing clock update\n",
23053a33a94cSSonny Rao 				__func__);
23063a33a94cSSonny Rao 			goto ciu_out;
23073a33a94cSSonny Rao 		}
23083a33a94cSSonny Rao 	}
23093a33a94cSSonny Rao 
23103a33a94cSSonny Rao #if IS_ENABLED(CONFIG_MMC_DW_IDMAC)
23113a33a94cSSonny Rao 	/* It is also recommended that we reset and reprogram idmac */
23123a33a94cSSonny Rao 	dw_mci_idmac_reset(host);
23133a33a94cSSonny Rao #endif
23143a33a94cSSonny Rao 
23153a33a94cSSonny Rao 	ret = true;
23163a33a94cSSonny Rao 
23173a33a94cSSonny Rao ciu_out:
23183a33a94cSSonny Rao 	/* After a CTRL reset we need to have CIU set clock registers  */
23193a33a94cSSonny Rao 	mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0);
23203a33a94cSSonny Rao 
23213a33a94cSSonny Rao 	return ret;
232231bff450SSeungwon Jeon }
232331bff450SSeungwon Jeon 
2324c91eab4bSThomas Abraham #ifdef CONFIG_OF
2325c91eab4bSThomas Abraham static struct dw_mci_of_quirks {
2326c91eab4bSThomas Abraham 	char *quirk;
2327c91eab4bSThomas Abraham 	int id;
2328c91eab4bSThomas Abraham } of_quirks[] = {
2329c91eab4bSThomas Abraham 	{
2330c91eab4bSThomas Abraham 		.quirk	= "broken-cd",
2331c91eab4bSThomas Abraham 		.id	= DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
233226375b5cSJaehoon Chung 	}, {
233326375b5cSJaehoon Chung 		.quirk	= "disable-wp",
233426375b5cSJaehoon Chung 		.id	= DW_MCI_QUIRK_NO_WRITE_PROTECT,
2335c91eab4bSThomas Abraham 	},
2336c91eab4bSThomas Abraham };
2337c91eab4bSThomas Abraham 
2338c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2339c91eab4bSThomas Abraham {
2340c91eab4bSThomas Abraham 	struct dw_mci_board *pdata;
2341c91eab4bSThomas Abraham 	struct device *dev = host->dev;
2342c91eab4bSThomas Abraham 	struct device_node *np = dev->of_node;
2343e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
2344800d78bfSThomas Abraham 	int idx, ret;
23453c6d89eaSDoug Anderson 	u32 clock_frequency;
2346c91eab4bSThomas Abraham 
2347c91eab4bSThomas Abraham 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
2348c91eab4bSThomas Abraham 	if (!pdata) {
2349c91eab4bSThomas Abraham 		dev_err(dev, "could not allocate memory for pdata\n");
2350c91eab4bSThomas Abraham 		return ERR_PTR(-ENOMEM);
2351c91eab4bSThomas Abraham 	}
2352c91eab4bSThomas Abraham 
2353c91eab4bSThomas Abraham 	/* find out number of slots supported */
2354c91eab4bSThomas Abraham 	if (of_property_read_u32(dev->of_node, "num-slots",
2355c91eab4bSThomas Abraham 				&pdata->num_slots)) {
2356c91eab4bSThomas Abraham 		dev_info(dev, "num-slots property not found, "
2357c91eab4bSThomas Abraham 				"assuming 1 slot is available\n");
2358c91eab4bSThomas Abraham 		pdata->num_slots = 1;
2359c91eab4bSThomas Abraham 	}
2360c91eab4bSThomas Abraham 
2361c91eab4bSThomas Abraham 	/* get quirks */
2362c91eab4bSThomas Abraham 	for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++)
2363c91eab4bSThomas Abraham 		if (of_get_property(np, of_quirks[idx].quirk, NULL))
2364c91eab4bSThomas Abraham 			pdata->quirks |= of_quirks[idx].id;
2365c91eab4bSThomas Abraham 
2366c91eab4bSThomas Abraham 	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
2367c91eab4bSThomas Abraham 		dev_info(dev, "fifo-depth property not found, using "
2368c91eab4bSThomas Abraham 				"value of FIFOTH register as default\n");
2369c91eab4bSThomas Abraham 
2370c91eab4bSThomas Abraham 	of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
2371c91eab4bSThomas Abraham 
23723c6d89eaSDoug Anderson 	if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
23733c6d89eaSDoug Anderson 		pdata->bus_hz = clock_frequency;
23743c6d89eaSDoug Anderson 
2375cb27a843SJames Hogan 	if (drv_data && drv_data->parse_dt) {
2376cb27a843SJames Hogan 		ret = drv_data->parse_dt(host);
2377800d78bfSThomas Abraham 		if (ret)
2378800d78bfSThomas Abraham 			return ERR_PTR(ret);
2379800d78bfSThomas Abraham 	}
2380800d78bfSThomas Abraham 
238110b49841SSeungwon Jeon 	if (of_find_property(np, "supports-highspeed", NULL))
238210b49841SSeungwon Jeon 		pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
238310b49841SSeungwon Jeon 
2384c91eab4bSThomas Abraham 	return pdata;
2385c91eab4bSThomas Abraham }
2386c91eab4bSThomas Abraham 
2387c91eab4bSThomas Abraham #else /* CONFIG_OF */
2388c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2389c91eab4bSThomas Abraham {
2390c91eab4bSThomas Abraham 	return ERR_PTR(-EINVAL);
2391c91eab4bSThomas Abraham }
2392c91eab4bSThomas Abraham #endif /* CONFIG_OF */
2393c91eab4bSThomas Abraham 
239462ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host)
2395f95f3850SWill Newton {
2396e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
239762ca8034SShashidhar Hiremath 	int width, i, ret = 0;
2398f95f3850SWill Newton 	u32 fifo_size;
23991c2215b7SThomas Abraham 	int init_slots = 0;
2400f95f3850SWill Newton 
2401c91eab4bSThomas Abraham 	if (!host->pdata) {
2402c91eab4bSThomas Abraham 		host->pdata = dw_mci_parse_dt(host);
2403c91eab4bSThomas Abraham 		if (IS_ERR(host->pdata)) {
2404c91eab4bSThomas Abraham 			dev_err(host->dev, "platform data not available\n");
2405c91eab4bSThomas Abraham 			return -EINVAL;
2406c91eab4bSThomas Abraham 		}
2407f95f3850SWill Newton 	}
2408f95f3850SWill Newton 
2409907abd51SJaehoon Chung 	if (host->pdata->num_slots > 1) {
24104a90920cSThomas Abraham 		dev_err(host->dev,
2411907abd51SJaehoon Chung 			"Platform data must supply num_slots.\n");
241262ca8034SShashidhar Hiremath 		return -ENODEV;
2413f95f3850SWill Newton 	}
2414f95f3850SWill Newton 
2415780f22afSSeungwon Jeon 	host->biu_clk = devm_clk_get(host->dev, "biu");
2416f90a0612SThomas Abraham 	if (IS_ERR(host->biu_clk)) {
2417f90a0612SThomas Abraham 		dev_dbg(host->dev, "biu clock not available\n");
2418f90a0612SThomas Abraham 	} else {
2419f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->biu_clk);
2420f90a0612SThomas Abraham 		if (ret) {
2421f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable biu clock\n");
2422f90a0612SThomas Abraham 			return ret;
2423f90a0612SThomas Abraham 		}
2424f95f3850SWill Newton 	}
2425f95f3850SWill Newton 
2426780f22afSSeungwon Jeon 	host->ciu_clk = devm_clk_get(host->dev, "ciu");
2427f90a0612SThomas Abraham 	if (IS_ERR(host->ciu_clk)) {
2428f90a0612SThomas Abraham 		dev_dbg(host->dev, "ciu clock not available\n");
24293c6d89eaSDoug Anderson 		host->bus_hz = host->pdata->bus_hz;
2430f90a0612SThomas Abraham 	} else {
2431f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->ciu_clk);
2432f90a0612SThomas Abraham 		if (ret) {
2433f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable ciu clock\n");
2434f90a0612SThomas Abraham 			goto err_clk_biu;
2435f90a0612SThomas Abraham 		}
2436f90a0612SThomas Abraham 
24373c6d89eaSDoug Anderson 		if (host->pdata->bus_hz) {
24383c6d89eaSDoug Anderson 			ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz);
24393c6d89eaSDoug Anderson 			if (ret)
24403c6d89eaSDoug Anderson 				dev_warn(host->dev,
2441612de4c1SJaehoon Chung 					 "Unable to set bus rate to %uHz\n",
24423c6d89eaSDoug Anderson 					 host->pdata->bus_hz);
24433c6d89eaSDoug Anderson 		}
2444f90a0612SThomas Abraham 		host->bus_hz = clk_get_rate(host->ciu_clk);
24453c6d89eaSDoug Anderson 	}
2446f90a0612SThomas Abraham 
2447612de4c1SJaehoon Chung 	if (!host->bus_hz) {
2448612de4c1SJaehoon Chung 		dev_err(host->dev,
2449612de4c1SJaehoon Chung 			"Platform data must supply bus speed\n");
2450612de4c1SJaehoon Chung 		ret = -ENODEV;
2451612de4c1SJaehoon Chung 		goto err_clk_ciu;
2452612de4c1SJaehoon Chung 	}
2453612de4c1SJaehoon Chung 
2454002f0d5cSYuvaraj Kumar C D 	if (drv_data && drv_data->init) {
2455002f0d5cSYuvaraj Kumar C D 		ret = drv_data->init(host);
2456002f0d5cSYuvaraj Kumar C D 		if (ret) {
2457002f0d5cSYuvaraj Kumar C D 			dev_err(host->dev,
2458002f0d5cSYuvaraj Kumar C D 				"implementation specific init failed\n");
2459002f0d5cSYuvaraj Kumar C D 			goto err_clk_ciu;
2460002f0d5cSYuvaraj Kumar C D 		}
2461002f0d5cSYuvaraj Kumar C D 	}
2462002f0d5cSYuvaraj Kumar C D 
2463cb27a843SJames Hogan 	if (drv_data && drv_data->setup_clock) {
2464cb27a843SJames Hogan 		ret = drv_data->setup_clock(host);
2465800d78bfSThomas Abraham 		if (ret) {
2466800d78bfSThomas Abraham 			dev_err(host->dev,
2467800d78bfSThomas Abraham 				"implementation specific clock setup failed\n");
2468800d78bfSThomas Abraham 			goto err_clk_ciu;
2469800d78bfSThomas Abraham 		}
2470800d78bfSThomas Abraham 	}
2471800d78bfSThomas Abraham 
2472a55d6ff0SMark Brown 	host->vmmc = devm_regulator_get_optional(host->dev, "vmmc");
2473870556a3SDoug Anderson 	if (IS_ERR(host->vmmc)) {
2474870556a3SDoug Anderson 		ret = PTR_ERR(host->vmmc);
2475870556a3SDoug Anderson 		if (ret == -EPROBE_DEFER)
2476870556a3SDoug Anderson 			goto err_clk_ciu;
2477870556a3SDoug Anderson 
2478870556a3SDoug Anderson 		dev_info(host->dev, "no vmmc regulator found: %d\n", ret);
2479870556a3SDoug Anderson 		host->vmmc = NULL;
2480870556a3SDoug Anderson 	} else {
2481870556a3SDoug Anderson 		ret = regulator_enable(host->vmmc);
2482870556a3SDoug Anderson 		if (ret) {
2483870556a3SDoug Anderson 			if (ret != -EPROBE_DEFER)
2484870556a3SDoug Anderson 				dev_err(host->dev,
2485870556a3SDoug Anderson 					"regulator_enable fail: %d\n", ret);
2486870556a3SDoug Anderson 			goto err_clk_ciu;
2487870556a3SDoug Anderson 		}
2488870556a3SDoug Anderson 	}
2489870556a3SDoug Anderson 
249062ca8034SShashidhar Hiremath 	host->quirks = host->pdata->quirks;
2491f95f3850SWill Newton 
2492f95f3850SWill Newton 	spin_lock_init(&host->lock);
2493f95f3850SWill Newton 	INIT_LIST_HEAD(&host->queue);
2494f95f3850SWill Newton 
2495f95f3850SWill Newton 	/*
2496f95f3850SWill Newton 	 * Get the host data width - this assumes that HCON has been set with
2497f95f3850SWill Newton 	 * the correct values.
2498f95f3850SWill Newton 	 */
2499f95f3850SWill Newton 	i = (mci_readl(host, HCON) >> 7) & 0x7;
2500f95f3850SWill Newton 	if (!i) {
2501f95f3850SWill Newton 		host->push_data = dw_mci_push_data16;
2502f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data16;
2503f95f3850SWill Newton 		width = 16;
2504f95f3850SWill Newton 		host->data_shift = 1;
2505f95f3850SWill Newton 	} else if (i == 2) {
2506f95f3850SWill Newton 		host->push_data = dw_mci_push_data64;
2507f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data64;
2508f95f3850SWill Newton 		width = 64;
2509f95f3850SWill Newton 		host->data_shift = 3;
2510f95f3850SWill Newton 	} else {
2511f95f3850SWill Newton 		/* Check for a reserved value, and warn if it is */
2512f95f3850SWill Newton 		WARN((i != 1),
2513f95f3850SWill Newton 		     "HCON reports a reserved host data width!\n"
2514f95f3850SWill Newton 		     "Defaulting to 32-bit access.\n");
2515f95f3850SWill Newton 		host->push_data = dw_mci_push_data32;
2516f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data32;
2517f95f3850SWill Newton 		width = 32;
2518f95f3850SWill Newton 		host->data_shift = 2;
2519f95f3850SWill Newton 	}
2520f95f3850SWill Newton 
2521f95f3850SWill Newton 	/* Reset all blocks */
25223a33a94cSSonny Rao 	if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS))
2523141a712aSSeungwon Jeon 		return -ENODEV;
2524141a712aSSeungwon Jeon 
2525141a712aSSeungwon Jeon 	host->dma_ops = host->pdata->dma_ops;
2526141a712aSSeungwon Jeon 	dw_mci_init_dma(host);
2527f95f3850SWill Newton 
2528f95f3850SWill Newton 	/* Clear the interrupts for the host controller */
2529f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2530f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2531f95f3850SWill Newton 
2532f95f3850SWill Newton 	/* Put in max timeout */
2533f95f3850SWill Newton 	mci_writel(host, TMOUT, 0xFFFFFFFF);
2534f95f3850SWill Newton 
2535f95f3850SWill Newton 	/*
2536f95f3850SWill Newton 	 * FIFO threshold settings  RxMark  = fifo_size / 2 - 1,
2537f95f3850SWill Newton 	 *                          Tx Mark = fifo_size / 2 DMA Size = 8
2538f95f3850SWill Newton 	 */
2539b86d8253SJames Hogan 	if (!host->pdata->fifo_depth) {
2540b86d8253SJames Hogan 		/*
2541b86d8253SJames Hogan 		 * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may
2542b86d8253SJames Hogan 		 * have been overwritten by the bootloader, just like we're
2543b86d8253SJames Hogan 		 * about to do, so if you know the value for your hardware, you
2544b86d8253SJames Hogan 		 * should put it in the platform data.
2545b86d8253SJames Hogan 		 */
2546f95f3850SWill Newton 		fifo_size = mci_readl(host, FIFOTH);
25478234e869SJaehoon Chung 		fifo_size = 1 + ((fifo_size >> 16) & 0xfff);
2548b86d8253SJames Hogan 	} else {
2549b86d8253SJames Hogan 		fifo_size = host->pdata->fifo_depth;
2550b86d8253SJames Hogan 	}
2551b86d8253SJames Hogan 	host->fifo_depth = fifo_size;
255252426899SSeungwon Jeon 	host->fifoth_val =
255352426899SSeungwon Jeon 		SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2);
2554e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
2555f95f3850SWill Newton 
2556f95f3850SWill Newton 	/* disable clock to CIU */
2557f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2558f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2559f95f3850SWill Newton 
256063008768SJames Hogan 	/*
256163008768SJames Hogan 	 * In 2.40a spec, Data offset is changed.
256263008768SJames Hogan 	 * Need to check the version-id and set data-offset for DATA register.
256363008768SJames Hogan 	 */
256463008768SJames Hogan 	host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
256563008768SJames Hogan 	dev_info(host->dev, "Version ID is %04x\n", host->verid);
256663008768SJames Hogan 
256763008768SJames Hogan 	if (host->verid < DW_MMC_240A)
256863008768SJames Hogan 		host->data_offset = DATA_OFFSET;
256963008768SJames Hogan 	else
257063008768SJames Hogan 		host->data_offset = DATA_240A_OFFSET;
257163008768SJames Hogan 
2572f95f3850SWill Newton 	tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
257395dcc2cbSThomas Abraham 	host->card_workqueue = alloc_workqueue("dw-mci-card",
257459ff3eb6SZhangZhen 			WQ_MEM_RECLAIM, 1);
2575ef7aef9aSWei Yongjun 	if (!host->card_workqueue) {
2576ef7aef9aSWei Yongjun 		ret = -ENOMEM;
25771791b13eSJames Hogan 		goto err_dmaunmap;
2578ef7aef9aSWei Yongjun 	}
25791791b13eSJames Hogan 	INIT_WORK(&host->card_work, dw_mci_work_routine_card);
2580780f22afSSeungwon Jeon 	ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
2581780f22afSSeungwon Jeon 			       host->irq_flags, "dw-mci", host);
2582f95f3850SWill Newton 	if (ret)
25831791b13eSJames Hogan 		goto err_workqueue;
2584f95f3850SWill Newton 
2585f95f3850SWill Newton 	if (host->pdata->num_slots)
2586f95f3850SWill Newton 		host->num_slots = host->pdata->num_slots;
2587f95f3850SWill Newton 	else
2588f95f3850SWill Newton 		host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1;
2589f95f3850SWill Newton 
25902da1d7f2SYuvaraj CD 	/*
25912da1d7f2SYuvaraj CD 	 * Enable interrupts for command done, data over, data empty, card det,
25922da1d7f2SYuvaraj CD 	 * receive ready and error such as transmit, receive timeout, crc error
25932da1d7f2SYuvaraj CD 	 */
25942da1d7f2SYuvaraj CD 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
25952da1d7f2SYuvaraj CD 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
25962da1d7f2SYuvaraj CD 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
25972da1d7f2SYuvaraj CD 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
25982da1d7f2SYuvaraj CD 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
25992da1d7f2SYuvaraj CD 
26002da1d7f2SYuvaraj CD 	dev_info(host->dev, "DW MMC controller at irq %d, "
26012da1d7f2SYuvaraj CD 		 "%d bit host data width, "
26022da1d7f2SYuvaraj CD 		 "%u deep fifo\n",
26032da1d7f2SYuvaraj CD 		 host->irq, width, fifo_size);
26042da1d7f2SYuvaraj CD 
2605f95f3850SWill Newton 	/* We need at least one slot to succeed */
2606f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2607f95f3850SWill Newton 		ret = dw_mci_init_slot(host, i);
26081c2215b7SThomas Abraham 		if (ret)
26091c2215b7SThomas Abraham 			dev_dbg(host->dev, "slot %d init failed\n", i);
26101c2215b7SThomas Abraham 		else
26111c2215b7SThomas Abraham 			init_slots++;
2612f95f3850SWill Newton 	}
26131c2215b7SThomas Abraham 
26141c2215b7SThomas Abraham 	if (init_slots) {
26151c2215b7SThomas Abraham 		dev_info(host->dev, "%d slots initialized\n", init_slots);
26161c2215b7SThomas Abraham 	} else {
26171c2215b7SThomas Abraham 		dev_dbg(host->dev, "attempted to initialize %d slots, "
26181c2215b7SThomas Abraham 					"but failed on all\n", host->num_slots);
2619780f22afSSeungwon Jeon 		goto err_workqueue;
2620f95f3850SWill Newton 	}
2621f95f3850SWill Newton 
2622f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
26234a90920cSThomas Abraham 		dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
2624f95f3850SWill Newton 
2625f95f3850SWill Newton 	return 0;
2626f95f3850SWill Newton 
26271791b13eSJames Hogan err_workqueue:
262895dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
26291791b13eSJames Hogan 
2630f95f3850SWill Newton err_dmaunmap:
2631f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2632f95f3850SWill Newton 		host->dma_ops->exit(host);
2633780f22afSSeungwon Jeon 	if (host->vmmc)
2634c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2635f90a0612SThomas Abraham 
2636f90a0612SThomas Abraham err_clk_ciu:
2637780f22afSSeungwon Jeon 	if (!IS_ERR(host->ciu_clk))
2638f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2639780f22afSSeungwon Jeon 
2640f90a0612SThomas Abraham err_clk_biu:
2641780f22afSSeungwon Jeon 	if (!IS_ERR(host->biu_clk))
2642f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2643780f22afSSeungwon Jeon 
2644f95f3850SWill Newton 	return ret;
2645f95f3850SWill Newton }
264662ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe);
2647f95f3850SWill Newton 
264862ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host)
2649f95f3850SWill Newton {
2650f95f3850SWill Newton 	int i;
2651f95f3850SWill Newton 
2652f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2653f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2654f95f3850SWill Newton 
2655f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
26564a90920cSThomas Abraham 		dev_dbg(host->dev, "remove slot %d\n", i);
2657f95f3850SWill Newton 		if (host->slot[i])
2658f95f3850SWill Newton 			dw_mci_cleanup_slot(host->slot[i], i);
2659f95f3850SWill Newton 	}
2660f95f3850SWill Newton 
2661f95f3850SWill Newton 	/* disable clock to CIU */
2662f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2663f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2664f95f3850SWill Newton 
266595dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
2666f95f3850SWill Newton 
2667f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2668f95f3850SWill Newton 		host->dma_ops->exit(host);
2669f95f3850SWill Newton 
2670780f22afSSeungwon Jeon 	if (host->vmmc)
2671c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2672c07946a3SJaehoon Chung 
2673f90a0612SThomas Abraham 	if (!IS_ERR(host->ciu_clk))
2674f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2675780f22afSSeungwon Jeon 
2676f90a0612SThomas Abraham 	if (!IS_ERR(host->biu_clk))
2677f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2678f95f3850SWill Newton }
267962ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove);
268062ca8034SShashidhar Hiremath 
268162ca8034SShashidhar Hiremath 
2682f95f3850SWill Newton 
26836fe8890dSJaehoon Chung #ifdef CONFIG_PM_SLEEP
2684f95f3850SWill Newton /*
2685f95f3850SWill Newton  * TODO: we should probably disable the clock to the card in the suspend path.
2686f95f3850SWill Newton  */
268762ca8034SShashidhar Hiremath int dw_mci_suspend(struct dw_mci *host)
2688f95f3850SWill Newton {
2689c07946a3SJaehoon Chung 	if (host->vmmc)
2690c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2691c07946a3SJaehoon Chung 
2692f95f3850SWill Newton 	return 0;
2693f95f3850SWill Newton }
269462ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_suspend);
2695f95f3850SWill Newton 
269662ca8034SShashidhar Hiremath int dw_mci_resume(struct dw_mci *host)
2697f95f3850SWill Newton {
2698f95f3850SWill Newton 	int i, ret;
2699f95f3850SWill Newton 
2700f2f942ceSSachin Kamat 	if (host->vmmc) {
2701f2f942ceSSachin Kamat 		ret = regulator_enable(host->vmmc);
2702f2f942ceSSachin Kamat 		if (ret) {
2703f2f942ceSSachin Kamat 			dev_err(host->dev,
2704f2f942ceSSachin Kamat 				"failed to enable regulator: %d\n", ret);
2705f2f942ceSSachin Kamat 			return ret;
2706f2f942ceSSachin Kamat 		}
2707f2f942ceSSachin Kamat 	}
27081d6c4e0aSJaehoon Chung 
27093a33a94cSSonny Rao 	if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) {
2710e61cf118SJaehoon Chung 		ret = -ENODEV;
2711e61cf118SJaehoon Chung 		return ret;
2712e61cf118SJaehoon Chung 	}
2713e61cf118SJaehoon Chung 
27143bfe619dSJonathan Kliegman 	if (host->use_dma && host->dma_ops->init)
2715141a712aSSeungwon Jeon 		host->dma_ops->init(host);
2716141a712aSSeungwon Jeon 
271752426899SSeungwon Jeon 	/*
271852426899SSeungwon Jeon 	 * Restore the initial value at FIFOTH register
271952426899SSeungwon Jeon 	 * And Invalidate the prev_blksz with zero
272052426899SSeungwon Jeon 	 */
2721e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
272252426899SSeungwon Jeon 	host->prev_blksz = 0;
2723e61cf118SJaehoon Chung 
27242eb2944fSDoug Anderson 	/* Put in max timeout */
27252eb2944fSDoug Anderson 	mci_writel(host, TMOUT, 0xFFFFFFFF);
27262eb2944fSDoug Anderson 
2727e61cf118SJaehoon Chung 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2728e61cf118SJaehoon Chung 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
2729e61cf118SJaehoon Chung 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
2730e61cf118SJaehoon Chung 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
2731e61cf118SJaehoon Chung 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
2732e61cf118SJaehoon Chung 
2733f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2734f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
2735f95f3850SWill Newton 		if (!slot)
2736f95f3850SWill Newton 			continue;
2737ab269128SAbhilash Kesavan 		if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
2738ab269128SAbhilash Kesavan 			dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
2739ab269128SAbhilash Kesavan 			dw_mci_setup_bus(slot, true);
2740ab269128SAbhilash Kesavan 		}
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