xref: /openbmc/linux/drivers/mmc/host/dw_mmc.c (revision 9795a846)
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 
11431bff450SSeungwon Jeon static inline bool dw_mci_fifo_reset(struct dw_mci *host);
11531bff450SSeungwon Jeon static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host);
11631bff450SSeungwon Jeon 
117f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS)
118f95f3850SWill Newton static int dw_mci_req_show(struct seq_file *s, void *v)
119f95f3850SWill Newton {
120f95f3850SWill Newton 	struct dw_mci_slot *slot = s->private;
121f95f3850SWill Newton 	struct mmc_request *mrq;
122f95f3850SWill Newton 	struct mmc_command *cmd;
123f95f3850SWill Newton 	struct mmc_command *stop;
124f95f3850SWill Newton 	struct mmc_data	*data;
125f95f3850SWill Newton 
126f95f3850SWill Newton 	/* Make sure we get a consistent snapshot */
127f95f3850SWill Newton 	spin_lock_bh(&slot->host->lock);
128f95f3850SWill Newton 	mrq = slot->mrq;
129f95f3850SWill Newton 
130f95f3850SWill Newton 	if (mrq) {
131f95f3850SWill Newton 		cmd = mrq->cmd;
132f95f3850SWill Newton 		data = mrq->data;
133f95f3850SWill Newton 		stop = mrq->stop;
134f95f3850SWill Newton 
135f95f3850SWill Newton 		if (cmd)
136f95f3850SWill Newton 			seq_printf(s,
137f95f3850SWill Newton 				   "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
138f95f3850SWill Newton 				   cmd->opcode, cmd->arg, cmd->flags,
139f95f3850SWill Newton 				   cmd->resp[0], cmd->resp[1], cmd->resp[2],
140f95f3850SWill Newton 				   cmd->resp[2], cmd->error);
141f95f3850SWill Newton 		if (data)
142f95f3850SWill Newton 			seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
143f95f3850SWill Newton 				   data->bytes_xfered, data->blocks,
144f95f3850SWill Newton 				   data->blksz, data->flags, data->error);
145f95f3850SWill Newton 		if (stop)
146f95f3850SWill Newton 			seq_printf(s,
147f95f3850SWill Newton 				   "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
148f95f3850SWill Newton 				   stop->opcode, stop->arg, stop->flags,
149f95f3850SWill Newton 				   stop->resp[0], stop->resp[1], stop->resp[2],
150f95f3850SWill Newton 				   stop->resp[2], stop->error);
151f95f3850SWill Newton 	}
152f95f3850SWill Newton 
153f95f3850SWill Newton 	spin_unlock_bh(&slot->host->lock);
154f95f3850SWill Newton 
155f95f3850SWill Newton 	return 0;
156f95f3850SWill Newton }
157f95f3850SWill Newton 
158f95f3850SWill Newton static int dw_mci_req_open(struct inode *inode, struct file *file)
159f95f3850SWill Newton {
160f95f3850SWill Newton 	return single_open(file, dw_mci_req_show, inode->i_private);
161f95f3850SWill Newton }
162f95f3850SWill Newton 
163f95f3850SWill Newton static const struct file_operations dw_mci_req_fops = {
164f95f3850SWill Newton 	.owner		= THIS_MODULE,
165f95f3850SWill Newton 	.open		= dw_mci_req_open,
166f95f3850SWill Newton 	.read		= seq_read,
167f95f3850SWill Newton 	.llseek		= seq_lseek,
168f95f3850SWill Newton 	.release	= single_release,
169f95f3850SWill Newton };
170f95f3850SWill Newton 
171f95f3850SWill Newton static int dw_mci_regs_show(struct seq_file *s, void *v)
172f95f3850SWill Newton {
173f95f3850SWill Newton 	seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS);
174f95f3850SWill Newton 	seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS);
175f95f3850SWill Newton 	seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD);
176f95f3850SWill Newton 	seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL);
177f95f3850SWill Newton 	seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK);
178f95f3850SWill Newton 	seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA);
179f95f3850SWill Newton 
180f95f3850SWill Newton 	return 0;
181f95f3850SWill Newton }
182f95f3850SWill Newton 
183f95f3850SWill Newton static int dw_mci_regs_open(struct inode *inode, struct file *file)
184f95f3850SWill Newton {
185f95f3850SWill Newton 	return single_open(file, dw_mci_regs_show, inode->i_private);
186f95f3850SWill Newton }
187f95f3850SWill Newton 
188f95f3850SWill Newton static const struct file_operations dw_mci_regs_fops = {
189f95f3850SWill Newton 	.owner		= THIS_MODULE,
190f95f3850SWill Newton 	.open		= dw_mci_regs_open,
191f95f3850SWill Newton 	.read		= seq_read,
192f95f3850SWill Newton 	.llseek		= seq_lseek,
193f95f3850SWill Newton 	.release	= single_release,
194f95f3850SWill Newton };
195f95f3850SWill Newton 
196f95f3850SWill Newton static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
197f95f3850SWill Newton {
198f95f3850SWill Newton 	struct mmc_host	*mmc = slot->mmc;
199f95f3850SWill Newton 	struct dw_mci *host = slot->host;
200f95f3850SWill Newton 	struct dentry *root;
201f95f3850SWill Newton 	struct dentry *node;
202f95f3850SWill Newton 
203f95f3850SWill Newton 	root = mmc->debugfs_root;
204f95f3850SWill Newton 	if (!root)
205f95f3850SWill Newton 		return;
206f95f3850SWill Newton 
207f95f3850SWill Newton 	node = debugfs_create_file("regs", S_IRUSR, root, host,
208f95f3850SWill Newton 				   &dw_mci_regs_fops);
209f95f3850SWill Newton 	if (!node)
210f95f3850SWill Newton 		goto err;
211f95f3850SWill Newton 
212f95f3850SWill Newton 	node = debugfs_create_file("req", S_IRUSR, root, slot,
213f95f3850SWill Newton 				   &dw_mci_req_fops);
214f95f3850SWill Newton 	if (!node)
215f95f3850SWill Newton 		goto err;
216f95f3850SWill Newton 
217f95f3850SWill Newton 	node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
218f95f3850SWill Newton 	if (!node)
219f95f3850SWill Newton 		goto err;
220f95f3850SWill Newton 
221f95f3850SWill Newton 	node = debugfs_create_x32("pending_events", S_IRUSR, root,
222f95f3850SWill Newton 				  (u32 *)&host->pending_events);
223f95f3850SWill Newton 	if (!node)
224f95f3850SWill Newton 		goto err;
225f95f3850SWill Newton 
226f95f3850SWill Newton 	node = debugfs_create_x32("completed_events", S_IRUSR, root,
227f95f3850SWill Newton 				  (u32 *)&host->completed_events);
228f95f3850SWill Newton 	if (!node)
229f95f3850SWill Newton 		goto err;
230f95f3850SWill Newton 
231f95f3850SWill Newton 	return;
232f95f3850SWill Newton 
233f95f3850SWill Newton err:
234f95f3850SWill Newton 	dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
235f95f3850SWill Newton }
236f95f3850SWill Newton #endif /* defined(CONFIG_DEBUG_FS) */
237f95f3850SWill Newton 
238f95f3850SWill Newton static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
239f95f3850SWill Newton {
240f95f3850SWill Newton 	struct mmc_data	*data;
241800d78bfSThomas Abraham 	struct dw_mci_slot *slot = mmc_priv(mmc);
242e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
243f95f3850SWill Newton 	u32 cmdr;
244f95f3850SWill Newton 	cmd->error = -EINPROGRESS;
245f95f3850SWill Newton 
246f95f3850SWill Newton 	cmdr = cmd->opcode;
247f95f3850SWill Newton 
24890c2143aSSeungwon Jeon 	if (cmd->opcode == MMC_STOP_TRANSMISSION ||
24990c2143aSSeungwon Jeon 	    cmd->opcode == MMC_GO_IDLE_STATE ||
25090c2143aSSeungwon Jeon 	    cmd->opcode == MMC_GO_INACTIVE_STATE ||
25190c2143aSSeungwon Jeon 	    (cmd->opcode == SD_IO_RW_DIRECT &&
25290c2143aSSeungwon Jeon 	     ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT))
253f95f3850SWill Newton 		cmdr |= SDMMC_CMD_STOP;
2544a1b27adSJaehoon Chung 	else if (cmd->opcode != MMC_SEND_STATUS && cmd->data)
255f95f3850SWill Newton 		cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
256f95f3850SWill Newton 
257f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_PRESENT) {
258f95f3850SWill Newton 		/* We expect a response, so set this bit */
259f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_EXP;
260f95f3850SWill Newton 		if (cmd->flags & MMC_RSP_136)
261f95f3850SWill Newton 			cmdr |= SDMMC_CMD_RESP_LONG;
262f95f3850SWill Newton 	}
263f95f3850SWill Newton 
264f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_CRC)
265f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_CRC;
266f95f3850SWill Newton 
267f95f3850SWill Newton 	data = cmd->data;
268f95f3850SWill Newton 	if (data) {
269f95f3850SWill Newton 		cmdr |= SDMMC_CMD_DAT_EXP;
270f95f3850SWill Newton 		if (data->flags & MMC_DATA_STREAM)
271f95f3850SWill Newton 			cmdr |= SDMMC_CMD_STRM_MODE;
272f95f3850SWill Newton 		if (data->flags & MMC_DATA_WRITE)
273f95f3850SWill Newton 			cmdr |= SDMMC_CMD_DAT_WR;
274f95f3850SWill Newton 	}
275f95f3850SWill Newton 
276cb27a843SJames Hogan 	if (drv_data && drv_data->prepare_command)
277cb27a843SJames Hogan 		drv_data->prepare_command(slot->host, &cmdr);
278800d78bfSThomas Abraham 
279f95f3850SWill Newton 	return cmdr;
280f95f3850SWill Newton }
281f95f3850SWill Newton 
28290c2143aSSeungwon Jeon static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
28390c2143aSSeungwon Jeon {
28490c2143aSSeungwon Jeon 	struct mmc_command *stop;
28590c2143aSSeungwon Jeon 	u32 cmdr;
28690c2143aSSeungwon Jeon 
28790c2143aSSeungwon Jeon 	if (!cmd->data)
28890c2143aSSeungwon Jeon 		return 0;
28990c2143aSSeungwon Jeon 
29090c2143aSSeungwon Jeon 	stop = &host->stop_abort;
29190c2143aSSeungwon Jeon 	cmdr = cmd->opcode;
29290c2143aSSeungwon Jeon 	memset(stop, 0, sizeof(struct mmc_command));
29390c2143aSSeungwon Jeon 
29490c2143aSSeungwon Jeon 	if (cmdr == MMC_READ_SINGLE_BLOCK ||
29590c2143aSSeungwon Jeon 	    cmdr == MMC_READ_MULTIPLE_BLOCK ||
29690c2143aSSeungwon Jeon 	    cmdr == MMC_WRITE_BLOCK ||
29790c2143aSSeungwon Jeon 	    cmdr == MMC_WRITE_MULTIPLE_BLOCK) {
29890c2143aSSeungwon Jeon 		stop->opcode = MMC_STOP_TRANSMISSION;
29990c2143aSSeungwon Jeon 		stop->arg = 0;
30090c2143aSSeungwon Jeon 		stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
30190c2143aSSeungwon Jeon 	} else if (cmdr == SD_IO_RW_EXTENDED) {
30290c2143aSSeungwon Jeon 		stop->opcode = SD_IO_RW_DIRECT;
30390c2143aSSeungwon Jeon 		stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) |
30490c2143aSSeungwon Jeon 			     ((cmd->arg >> 28) & 0x7);
30590c2143aSSeungwon Jeon 		stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
30690c2143aSSeungwon Jeon 	} else {
30790c2143aSSeungwon Jeon 		return 0;
30890c2143aSSeungwon Jeon 	}
30990c2143aSSeungwon Jeon 
31090c2143aSSeungwon Jeon 	cmdr = stop->opcode | SDMMC_CMD_STOP |
31190c2143aSSeungwon Jeon 		SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP;
31290c2143aSSeungwon Jeon 
31390c2143aSSeungwon Jeon 	return cmdr;
31490c2143aSSeungwon Jeon }
31590c2143aSSeungwon Jeon 
316f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host,
317f95f3850SWill Newton 				 struct mmc_command *cmd, u32 cmd_flags)
318f95f3850SWill Newton {
319f95f3850SWill Newton 	host->cmd = cmd;
3204a90920cSThomas Abraham 	dev_vdbg(host->dev,
321f95f3850SWill Newton 		 "start command: ARGR=0x%08x CMDR=0x%08x\n",
322f95f3850SWill Newton 		 cmd->arg, cmd_flags);
323f95f3850SWill Newton 
324f95f3850SWill Newton 	mci_writel(host, CMDARG, cmd->arg);
325f95f3850SWill Newton 	wmb();
326f95f3850SWill Newton 
327f95f3850SWill Newton 	mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
328f95f3850SWill Newton }
329f95f3850SWill Newton 
33090c2143aSSeungwon Jeon static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data)
331f95f3850SWill Newton {
33290c2143aSSeungwon Jeon 	struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort;
33390c2143aSSeungwon Jeon 	dw_mci_start_command(host, stop, host->stop_cmdr);
334f95f3850SWill Newton }
335f95f3850SWill Newton 
336f95f3850SWill Newton /* DMA interface functions */
337f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host)
338f95f3850SWill Newton {
33903e8cb53SJames Hogan 	if (host->using_dma) {
340f95f3850SWill Newton 		host->dma_ops->stop(host);
341f95f3850SWill Newton 		host->dma_ops->cleanup(host);
342aa50f259SSeungwon Jeon 	}
343aa50f259SSeungwon Jeon 
344f95f3850SWill Newton 	/* Data transfer was stopped by the interrupt handler */
345f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
346f95f3850SWill Newton }
347f95f3850SWill Newton 
3489aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data)
3499aa51408SSeungwon Jeon {
3509aa51408SSeungwon Jeon 	if (data->flags & MMC_DATA_WRITE)
3519aa51408SSeungwon Jeon 		return DMA_TO_DEVICE;
3529aa51408SSeungwon Jeon 	else
3539aa51408SSeungwon Jeon 		return DMA_FROM_DEVICE;
3549aa51408SSeungwon Jeon }
3559aa51408SSeungwon Jeon 
3569beee912SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
357f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host)
358f95f3850SWill Newton {
359f95f3850SWill Newton 	struct mmc_data *data = host->data;
360f95f3850SWill Newton 
361f95f3850SWill Newton 	if (data)
3629aa51408SSeungwon Jeon 		if (!data->host_cookie)
3634a90920cSThomas Abraham 			dma_unmap_sg(host->dev,
3649aa51408SSeungwon Jeon 				     data->sg,
3659aa51408SSeungwon Jeon 				     data->sg_len,
3669aa51408SSeungwon Jeon 				     dw_mci_get_dma_dir(data));
367f95f3850SWill Newton }
368f95f3850SWill Newton 
3695ce9d961SSeungwon Jeon static void dw_mci_idmac_reset(struct dw_mci *host)
3705ce9d961SSeungwon Jeon {
3715ce9d961SSeungwon Jeon 	u32 bmod = mci_readl(host, BMOD);
3725ce9d961SSeungwon Jeon 	/* Software reset of DMA */
3735ce9d961SSeungwon Jeon 	bmod |= SDMMC_IDMAC_SWRESET;
3745ce9d961SSeungwon Jeon 	mci_writel(host, BMOD, bmod);
3755ce9d961SSeungwon Jeon }
3765ce9d961SSeungwon Jeon 
377f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host)
378f95f3850SWill Newton {
379f95f3850SWill Newton 	u32 temp;
380f95f3850SWill Newton 
381f95f3850SWill Newton 	/* Disable and reset the IDMAC interface */
382f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
383f95f3850SWill Newton 	temp &= ~SDMMC_CTRL_USE_IDMAC;
384f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_RESET;
385f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
386f95f3850SWill Newton 
387f95f3850SWill Newton 	/* Stop the IDMAC running */
388f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
389a5289a43SJaehoon Chung 	temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB);
3905ce9d961SSeungwon Jeon 	temp |= SDMMC_IDMAC_SWRESET;
391f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
392f95f3850SWill Newton }
393f95f3850SWill Newton 
394f95f3850SWill Newton static void dw_mci_idmac_complete_dma(struct dw_mci *host)
395f95f3850SWill Newton {
396f95f3850SWill Newton 	struct mmc_data *data = host->data;
397f95f3850SWill Newton 
3984a90920cSThomas Abraham 	dev_vdbg(host->dev, "DMA complete\n");
399f95f3850SWill Newton 
400f95f3850SWill Newton 	host->dma_ops->cleanup(host);
401f95f3850SWill Newton 
402f95f3850SWill Newton 	/*
403f95f3850SWill Newton 	 * If the card was removed, data will be NULL. No point in trying to
404f95f3850SWill Newton 	 * send the stop command or waiting for NBUSY in this case.
405f95f3850SWill Newton 	 */
406f95f3850SWill Newton 	if (data) {
407f95f3850SWill Newton 		set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
408f95f3850SWill Newton 		tasklet_schedule(&host->tasklet);
409f95f3850SWill Newton 	}
410f95f3850SWill Newton }
411f95f3850SWill Newton 
412f95f3850SWill Newton static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
413f95f3850SWill Newton 				    unsigned int sg_len)
414f95f3850SWill Newton {
415f95f3850SWill Newton 	int i;
416f95f3850SWill Newton 	struct idmac_desc *desc = host->sg_cpu;
417f95f3850SWill Newton 
418f95f3850SWill Newton 	for (i = 0; i < sg_len; i++, desc++) {
419f95f3850SWill Newton 		unsigned int length = sg_dma_len(&data->sg[i]);
420f95f3850SWill Newton 		u32 mem_addr = sg_dma_address(&data->sg[i]);
421f95f3850SWill Newton 
422f95f3850SWill Newton 		/* Set the OWN bit and disable interrupts for this descriptor */
423f95f3850SWill Newton 		desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH;
424f95f3850SWill Newton 
425f95f3850SWill Newton 		/* Buffer length */
426f95f3850SWill Newton 		IDMAC_SET_BUFFER1_SIZE(desc, length);
427f95f3850SWill Newton 
428f95f3850SWill Newton 		/* Physical address to DMA to/from */
429f95f3850SWill Newton 		desc->des2 = mem_addr;
430f95f3850SWill Newton 	}
431f95f3850SWill Newton 
432f95f3850SWill Newton 	/* Set first descriptor */
433f95f3850SWill Newton 	desc = host->sg_cpu;
434f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_FD;
435f95f3850SWill Newton 
436f95f3850SWill Newton 	/* Set last descriptor */
437f95f3850SWill Newton 	desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
438f95f3850SWill Newton 	desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
439f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_LD;
440f95f3850SWill Newton 
441f95f3850SWill Newton 	wmb();
442f95f3850SWill Newton }
443f95f3850SWill Newton 
444f95f3850SWill Newton static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
445f95f3850SWill Newton {
446f95f3850SWill Newton 	u32 temp;
447f95f3850SWill Newton 
448f95f3850SWill Newton 	dw_mci_translate_sglist(host, host->data, sg_len);
449f95f3850SWill Newton 
450f95f3850SWill Newton 	/* Select IDMAC interface */
451f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
452f95f3850SWill Newton 	temp |= SDMMC_CTRL_USE_IDMAC;
453f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
454f95f3850SWill Newton 
455f95f3850SWill Newton 	wmb();
456f95f3850SWill Newton 
457f95f3850SWill Newton 	/* Enable the IDMAC */
458f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
459a5289a43SJaehoon Chung 	temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB;
460f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
461f95f3850SWill Newton 
462f95f3850SWill Newton 	/* Start it running */
463f95f3850SWill Newton 	mci_writel(host, PLDMND, 1);
464f95f3850SWill Newton }
465f95f3850SWill Newton 
466f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host)
467f95f3850SWill Newton {
468f95f3850SWill Newton 	struct idmac_desc *p;
469897b69e7SSeungwon Jeon 	int i;
470f95f3850SWill Newton 
471f95f3850SWill Newton 	/* Number of descriptors in the ring buffer */
472f95f3850SWill Newton 	host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
473f95f3850SWill Newton 
474f95f3850SWill Newton 	/* Forward link the descriptor list */
475f95f3850SWill Newton 	for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
476f95f3850SWill Newton 		p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
477f95f3850SWill Newton 
478f95f3850SWill Newton 	/* Set the last descriptor as the end-of-ring descriptor */
479f95f3850SWill Newton 	p->des3 = host->sg_dma;
480f95f3850SWill Newton 	p->des0 = IDMAC_DES0_ER;
481f95f3850SWill Newton 
4825ce9d961SSeungwon Jeon 	dw_mci_idmac_reset(host);
483141a712aSSeungwon Jeon 
484f95f3850SWill Newton 	/* Mask out interrupts - get Tx & Rx complete only */
485fc79a4d6SJoonyoung Shim 	mci_writel(host, IDSTS, IDMAC_INT_CLR);
486f95f3850SWill Newton 	mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
487f95f3850SWill Newton 		   SDMMC_IDMAC_INT_TI);
488f95f3850SWill Newton 
489f95f3850SWill Newton 	/* Set the descriptor base address */
490f95f3850SWill Newton 	mci_writel(host, DBADDR, host->sg_dma);
491f95f3850SWill Newton 	return 0;
492f95f3850SWill Newton }
493f95f3850SWill Newton 
4948e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = {
495885c3e80SSeungwon Jeon 	.init = dw_mci_idmac_init,
496885c3e80SSeungwon Jeon 	.start = dw_mci_idmac_start_dma,
497885c3e80SSeungwon Jeon 	.stop = dw_mci_idmac_stop_dma,
498885c3e80SSeungwon Jeon 	.complete = dw_mci_idmac_complete_dma,
499885c3e80SSeungwon Jeon 	.cleanup = dw_mci_dma_cleanup,
500885c3e80SSeungwon Jeon };
501885c3e80SSeungwon Jeon #endif /* CONFIG_MMC_DW_IDMAC */
502885c3e80SSeungwon Jeon 
5039aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host,
5049aa51408SSeungwon Jeon 				   struct mmc_data *data,
5059aa51408SSeungwon Jeon 				   bool next)
506f95f3850SWill Newton {
507f95f3850SWill Newton 	struct scatterlist *sg;
5089aa51408SSeungwon Jeon 	unsigned int i, sg_len;
509f95f3850SWill Newton 
5109aa51408SSeungwon Jeon 	if (!next && data->host_cookie)
5119aa51408SSeungwon Jeon 		return data->host_cookie;
512f95f3850SWill Newton 
513f95f3850SWill Newton 	/*
514f95f3850SWill Newton 	 * We don't do DMA on "complex" transfers, i.e. with
515f95f3850SWill Newton 	 * non-word-aligned buffers or lengths. Also, we don't bother
516f95f3850SWill Newton 	 * with all the DMA setup overhead for short transfers.
517f95f3850SWill Newton 	 */
518f95f3850SWill Newton 	if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD)
519f95f3850SWill Newton 		return -EINVAL;
5209aa51408SSeungwon Jeon 
521f95f3850SWill Newton 	if (data->blksz & 3)
522f95f3850SWill Newton 		return -EINVAL;
523f95f3850SWill Newton 
524f95f3850SWill Newton 	for_each_sg(data->sg, sg, data->sg_len, i) {
525f95f3850SWill Newton 		if (sg->offset & 3 || sg->length & 3)
526f95f3850SWill Newton 			return -EINVAL;
527f95f3850SWill Newton 	}
528f95f3850SWill Newton 
5294a90920cSThomas Abraham 	sg_len = dma_map_sg(host->dev,
5309aa51408SSeungwon Jeon 			    data->sg,
5319aa51408SSeungwon Jeon 			    data->sg_len,
5329aa51408SSeungwon Jeon 			    dw_mci_get_dma_dir(data));
5339aa51408SSeungwon Jeon 	if (sg_len == 0)
5349aa51408SSeungwon Jeon 		return -EINVAL;
5359aa51408SSeungwon Jeon 
5369aa51408SSeungwon Jeon 	if (next)
5379aa51408SSeungwon Jeon 		data->host_cookie = sg_len;
5389aa51408SSeungwon Jeon 
5399aa51408SSeungwon Jeon 	return sg_len;
5409aa51408SSeungwon Jeon }
5419aa51408SSeungwon Jeon 
5429aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc,
5439aa51408SSeungwon Jeon 			   struct mmc_request *mrq,
5449aa51408SSeungwon Jeon 			   bool is_first_req)
5459aa51408SSeungwon Jeon {
5469aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
5479aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
5489aa51408SSeungwon Jeon 
5499aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
5509aa51408SSeungwon Jeon 		return;
5519aa51408SSeungwon Jeon 
5529aa51408SSeungwon Jeon 	if (data->host_cookie) {
5539aa51408SSeungwon Jeon 		data->host_cookie = 0;
5549aa51408SSeungwon Jeon 		return;
5559aa51408SSeungwon Jeon 	}
5569aa51408SSeungwon Jeon 
5579aa51408SSeungwon Jeon 	if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0)
5589aa51408SSeungwon Jeon 		data->host_cookie = 0;
5599aa51408SSeungwon Jeon }
5609aa51408SSeungwon Jeon 
5619aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc,
5629aa51408SSeungwon Jeon 			    struct mmc_request *mrq,
5639aa51408SSeungwon Jeon 			    int err)
5649aa51408SSeungwon Jeon {
5659aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
5669aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
5679aa51408SSeungwon Jeon 
5689aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
5699aa51408SSeungwon Jeon 		return;
5709aa51408SSeungwon Jeon 
5719aa51408SSeungwon Jeon 	if (data->host_cookie)
5724a90920cSThomas Abraham 		dma_unmap_sg(slot->host->dev,
5739aa51408SSeungwon Jeon 			     data->sg,
5749aa51408SSeungwon Jeon 			     data->sg_len,
5759aa51408SSeungwon Jeon 			     dw_mci_get_dma_dir(data));
5769aa51408SSeungwon Jeon 	data->host_cookie = 0;
5779aa51408SSeungwon Jeon }
5789aa51408SSeungwon Jeon 
57952426899SSeungwon Jeon static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
58052426899SSeungwon Jeon {
58152426899SSeungwon Jeon #ifdef CONFIG_MMC_DW_IDMAC
58252426899SSeungwon Jeon 	unsigned int blksz = data->blksz;
58352426899SSeungwon Jeon 	const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
58452426899SSeungwon Jeon 	u32 fifo_width = 1 << host->data_shift;
58552426899SSeungwon Jeon 	u32 blksz_depth = blksz / fifo_width, fifoth_val;
58652426899SSeungwon Jeon 	u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers;
58752426899SSeungwon Jeon 	int idx = (sizeof(mszs) / sizeof(mszs[0])) - 1;
58852426899SSeungwon Jeon 
58952426899SSeungwon Jeon 	tx_wmark = (host->fifo_depth) / 2;
59052426899SSeungwon Jeon 	tx_wmark_invers = host->fifo_depth - tx_wmark;
59152426899SSeungwon Jeon 
59252426899SSeungwon Jeon 	/*
59352426899SSeungwon Jeon 	 * MSIZE is '1',
59452426899SSeungwon Jeon 	 * if blksz is not a multiple of the FIFO width
59552426899SSeungwon Jeon 	 */
59652426899SSeungwon Jeon 	if (blksz % fifo_width) {
59752426899SSeungwon Jeon 		msize = 0;
59852426899SSeungwon Jeon 		rx_wmark = 1;
59952426899SSeungwon Jeon 		goto done;
60052426899SSeungwon Jeon 	}
60152426899SSeungwon Jeon 
60252426899SSeungwon Jeon 	do {
60352426899SSeungwon Jeon 		if (!((blksz_depth % mszs[idx]) ||
60452426899SSeungwon Jeon 		     (tx_wmark_invers % mszs[idx]))) {
60552426899SSeungwon Jeon 			msize = idx;
60652426899SSeungwon Jeon 			rx_wmark = mszs[idx] - 1;
60752426899SSeungwon Jeon 			break;
60852426899SSeungwon Jeon 		}
60952426899SSeungwon Jeon 	} while (--idx > 0);
61052426899SSeungwon Jeon 	/*
61152426899SSeungwon Jeon 	 * If idx is '0', it won't be tried
61252426899SSeungwon Jeon 	 * Thus, initial values are uesed
61352426899SSeungwon Jeon 	 */
61452426899SSeungwon Jeon done:
61552426899SSeungwon Jeon 	fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark);
61652426899SSeungwon Jeon 	mci_writel(host, FIFOTH, fifoth_val);
61752426899SSeungwon Jeon #endif
61852426899SSeungwon Jeon }
61952426899SSeungwon Jeon 
620f1d2736cSSeungwon Jeon static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)
621f1d2736cSSeungwon Jeon {
622f1d2736cSSeungwon Jeon 	unsigned int blksz = data->blksz;
623f1d2736cSSeungwon Jeon 	u32 blksz_depth, fifo_depth;
624f1d2736cSSeungwon Jeon 	u16 thld_size;
625f1d2736cSSeungwon Jeon 
626f1d2736cSSeungwon Jeon 	WARN_ON(!(data->flags & MMC_DATA_READ));
627f1d2736cSSeungwon Jeon 
628f1d2736cSSeungwon Jeon 	if (host->timing != MMC_TIMING_MMC_HS200 &&
629f1d2736cSSeungwon Jeon 	    host->timing != MMC_TIMING_UHS_SDR104)
630f1d2736cSSeungwon Jeon 		goto disable;
631f1d2736cSSeungwon Jeon 
632f1d2736cSSeungwon Jeon 	blksz_depth = blksz / (1 << host->data_shift);
633f1d2736cSSeungwon Jeon 	fifo_depth = host->fifo_depth;
634f1d2736cSSeungwon Jeon 
635f1d2736cSSeungwon Jeon 	if (blksz_depth > fifo_depth)
636f1d2736cSSeungwon Jeon 		goto disable;
637f1d2736cSSeungwon Jeon 
638f1d2736cSSeungwon Jeon 	/*
639f1d2736cSSeungwon Jeon 	 * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz'
640f1d2736cSSeungwon Jeon 	 * If (blksz_depth) <  (fifo_depth >> 1), should be thld_size = blksz
641f1d2736cSSeungwon Jeon 	 * Currently just choose blksz.
642f1d2736cSSeungwon Jeon 	 */
643f1d2736cSSeungwon Jeon 	thld_size = blksz;
644f1d2736cSSeungwon Jeon 	mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1));
645f1d2736cSSeungwon Jeon 	return;
646f1d2736cSSeungwon Jeon 
647f1d2736cSSeungwon Jeon disable:
648f1d2736cSSeungwon Jeon 	mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0));
649f1d2736cSSeungwon Jeon }
650f1d2736cSSeungwon Jeon 
6519aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
6529aa51408SSeungwon Jeon {
6539aa51408SSeungwon Jeon 	int sg_len;
6549aa51408SSeungwon Jeon 	u32 temp;
6559aa51408SSeungwon Jeon 
6569aa51408SSeungwon Jeon 	host->using_dma = 0;
6579aa51408SSeungwon Jeon 
6589aa51408SSeungwon Jeon 	/* If we don't have a channel, we can't do DMA */
6599aa51408SSeungwon Jeon 	if (!host->use_dma)
6609aa51408SSeungwon Jeon 		return -ENODEV;
6619aa51408SSeungwon Jeon 
6629aa51408SSeungwon Jeon 	sg_len = dw_mci_pre_dma_transfer(host, data, 0);
663a99aa9b9SSeungwon Jeon 	if (sg_len < 0) {
664a99aa9b9SSeungwon Jeon 		host->dma_ops->stop(host);
6659aa51408SSeungwon Jeon 		return sg_len;
666a99aa9b9SSeungwon Jeon 	}
6679aa51408SSeungwon Jeon 
66803e8cb53SJames Hogan 	host->using_dma = 1;
66903e8cb53SJames Hogan 
6704a90920cSThomas Abraham 	dev_vdbg(host->dev,
671f95f3850SWill Newton 		 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
672f95f3850SWill Newton 		 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
673f95f3850SWill Newton 		 sg_len);
674f95f3850SWill Newton 
67552426899SSeungwon Jeon 	/*
67652426899SSeungwon Jeon 	 * Decide the MSIZE and RX/TX Watermark.
67752426899SSeungwon Jeon 	 * If current block size is same with previous size,
67852426899SSeungwon Jeon 	 * no need to update fifoth.
67952426899SSeungwon Jeon 	 */
68052426899SSeungwon Jeon 	if (host->prev_blksz != data->blksz)
68152426899SSeungwon Jeon 		dw_mci_adjust_fifoth(host, data);
68252426899SSeungwon Jeon 
683f95f3850SWill Newton 	/* Enable the DMA interface */
684f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
685f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_ENABLE;
686f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
687f95f3850SWill Newton 
688f95f3850SWill Newton 	/* Disable RX/TX IRQs, let DMA handle it */
689f95f3850SWill Newton 	temp = mci_readl(host, INTMASK);
690f95f3850SWill Newton 	temp  &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR);
691f95f3850SWill Newton 	mci_writel(host, INTMASK, temp);
692f95f3850SWill Newton 
693f95f3850SWill Newton 	host->dma_ops->start(host, sg_len);
694f95f3850SWill Newton 
695f95f3850SWill Newton 	return 0;
696f95f3850SWill Newton }
697f95f3850SWill Newton 
698f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
699f95f3850SWill Newton {
700f95f3850SWill Newton 	u32 temp;
701f95f3850SWill Newton 
702f95f3850SWill Newton 	data->error = -EINPROGRESS;
703f95f3850SWill Newton 
704f95f3850SWill Newton 	WARN_ON(host->data);
705f95f3850SWill Newton 	host->sg = NULL;
706f95f3850SWill Newton 	host->data = data;
707f95f3850SWill Newton 
708f1d2736cSSeungwon Jeon 	if (data->flags & MMC_DATA_READ) {
70955c5efbcSJames Hogan 		host->dir_status = DW_MCI_RECV_STATUS;
710f1d2736cSSeungwon Jeon 		dw_mci_ctrl_rd_thld(host, data);
711f1d2736cSSeungwon Jeon 	} else {
71255c5efbcSJames Hogan 		host->dir_status = DW_MCI_SEND_STATUS;
713f1d2736cSSeungwon Jeon 	}
71455c5efbcSJames Hogan 
715f95f3850SWill Newton 	if (dw_mci_submit_data_dma(host, data)) {
716f9c2a0dcSSeungwon Jeon 		int flags = SG_MITER_ATOMIC;
717f9c2a0dcSSeungwon Jeon 		if (host->data->flags & MMC_DATA_READ)
718f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_TO_SG;
719f9c2a0dcSSeungwon Jeon 		else
720f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_FROM_SG;
721f9c2a0dcSSeungwon Jeon 
722f9c2a0dcSSeungwon Jeon 		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
723f95f3850SWill Newton 		host->sg = data->sg;
72434b664a2SJames Hogan 		host->part_buf_start = 0;
72534b664a2SJames Hogan 		host->part_buf_count = 0;
726f95f3850SWill Newton 
727b40af3aaSJames Hogan 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR);
728f95f3850SWill Newton 		temp = mci_readl(host, INTMASK);
729f95f3850SWill Newton 		temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR;
730f95f3850SWill Newton 		mci_writel(host, INTMASK, temp);
731f95f3850SWill Newton 
732f95f3850SWill Newton 		temp = mci_readl(host, CTRL);
733f95f3850SWill Newton 		temp &= ~SDMMC_CTRL_DMA_ENABLE;
734f95f3850SWill Newton 		mci_writel(host, CTRL, temp);
73552426899SSeungwon Jeon 
73652426899SSeungwon Jeon 		/*
73752426899SSeungwon Jeon 		 * Use the initial fifoth_val for PIO mode.
73852426899SSeungwon Jeon 		 * If next issued data may be transfered by DMA mode,
73952426899SSeungwon Jeon 		 * prev_blksz should be invalidated.
74052426899SSeungwon Jeon 		 */
74152426899SSeungwon Jeon 		mci_writel(host, FIFOTH, host->fifoth_val);
74252426899SSeungwon Jeon 		host->prev_blksz = 0;
74352426899SSeungwon Jeon 	} else {
74452426899SSeungwon Jeon 		/*
74552426899SSeungwon Jeon 		 * Keep the current block size.
74652426899SSeungwon Jeon 		 * It will be used to decide whether to update
74752426899SSeungwon Jeon 		 * fifoth register next time.
74852426899SSeungwon Jeon 		 */
74952426899SSeungwon Jeon 		host->prev_blksz = data->blksz;
750f95f3850SWill Newton 	}
751f95f3850SWill Newton }
752f95f3850SWill Newton 
753f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
754f95f3850SWill Newton {
755f95f3850SWill Newton 	struct dw_mci *host = slot->host;
756f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
757f95f3850SWill Newton 	unsigned int cmd_status = 0;
758f95f3850SWill Newton 
759f95f3850SWill Newton 	mci_writel(host, CMDARG, arg);
760f95f3850SWill Newton 	wmb();
761f95f3850SWill Newton 	mci_writel(host, CMD, SDMMC_CMD_START | cmd);
762f95f3850SWill Newton 
763f95f3850SWill Newton 	while (time_before(jiffies, timeout)) {
764f95f3850SWill Newton 		cmd_status = mci_readl(host, CMD);
765f95f3850SWill Newton 		if (!(cmd_status & SDMMC_CMD_START))
766f95f3850SWill Newton 			return;
767f95f3850SWill Newton 	}
768f95f3850SWill Newton 	dev_err(&slot->mmc->class_dev,
769f95f3850SWill Newton 		"Timeout sending command (cmd %#x arg %#x status %#x)\n",
770f95f3850SWill Newton 		cmd, arg, cmd_status);
771f95f3850SWill Newton }
772f95f3850SWill Newton 
773ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
774f95f3850SWill Newton {
775f95f3850SWill Newton 	struct dw_mci *host = slot->host;
776fdf492a1SDoug Anderson 	unsigned int clock = slot->clock;
777f95f3850SWill Newton 	u32 div;
7789623b5b9SDoug Anderson 	u32 clk_en_a;
779f95f3850SWill Newton 
780fdf492a1SDoug Anderson 	if (!clock) {
781fdf492a1SDoug Anderson 		mci_writel(host, CLKENA, 0);
782fdf492a1SDoug Anderson 		mci_send_cmd(slot,
783fdf492a1SDoug Anderson 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
784fdf492a1SDoug Anderson 	} else if (clock != host->current_speed || force_clkinit) {
785fdf492a1SDoug Anderson 		div = host->bus_hz / clock;
786fdf492a1SDoug Anderson 		if (host->bus_hz % clock && host->bus_hz > clock)
787f95f3850SWill Newton 			/*
788f95f3850SWill Newton 			 * move the + 1 after the divide to prevent
789f95f3850SWill Newton 			 * over-clocking the card.
790f95f3850SWill Newton 			 */
791e419990bSSeungwon Jeon 			div += 1;
792e419990bSSeungwon Jeon 
793fdf492a1SDoug Anderson 		div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0;
794f95f3850SWill Newton 
795fdf492a1SDoug Anderson 		if ((clock << div) != slot->__clk_old || force_clkinit)
796f95f3850SWill Newton 			dev_info(&slot->mmc->class_dev,
797fdf492a1SDoug Anderson 				 "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
798fdf492a1SDoug Anderson 				 slot->id, host->bus_hz, clock,
799fdf492a1SDoug Anderson 				 div ? ((host->bus_hz / div) >> 1) :
800fdf492a1SDoug Anderson 				 host->bus_hz, div);
801f95f3850SWill Newton 
802f95f3850SWill Newton 		/* disable clock */
803f95f3850SWill Newton 		mci_writel(host, CLKENA, 0);
804f95f3850SWill Newton 		mci_writel(host, CLKSRC, 0);
805f95f3850SWill Newton 
806f95f3850SWill Newton 		/* inform CIU */
807f95f3850SWill Newton 		mci_send_cmd(slot,
808f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
809f95f3850SWill Newton 
810f95f3850SWill Newton 		/* set clock to desired speed */
811f95f3850SWill Newton 		mci_writel(host, CLKDIV, div);
812f95f3850SWill Newton 
813f95f3850SWill Newton 		/* inform CIU */
814f95f3850SWill Newton 		mci_send_cmd(slot,
815f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
816f95f3850SWill Newton 
8179623b5b9SDoug Anderson 		/* enable clock; only low power if no SDIO */
8189623b5b9SDoug Anderson 		clk_en_a = SDMMC_CLKEN_ENABLE << slot->id;
8199623b5b9SDoug Anderson 		if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id)))
8209623b5b9SDoug Anderson 			clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id;
8219623b5b9SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a);
822f95f3850SWill Newton 
823f95f3850SWill Newton 		/* inform CIU */
824f95f3850SWill Newton 		mci_send_cmd(slot,
825f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
826f95f3850SWill Newton 
827fdf492a1SDoug Anderson 		/* keep the clock with reflecting clock dividor */
828fdf492a1SDoug Anderson 		slot->__clk_old = clock << div;
829f95f3850SWill Newton 	}
830f95f3850SWill Newton 
831fdf492a1SDoug Anderson 	host->current_speed = clock;
832fdf492a1SDoug Anderson 
833f95f3850SWill Newton 	/* Set the current slot bus width */
8341d56c453SSeungwon Jeon 	mci_writel(host, CTYPE, (slot->ctype << slot->id));
835f95f3850SWill Newton }
836f95f3850SWill Newton 
837053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host,
838053b3ce6SSeungwon Jeon 				   struct dw_mci_slot *slot,
839053b3ce6SSeungwon Jeon 				   struct mmc_command *cmd)
840f95f3850SWill Newton {
841f95f3850SWill Newton 	struct mmc_request *mrq;
842f95f3850SWill Newton 	struct mmc_data	*data;
843f95f3850SWill Newton 	u32 cmdflags;
844f95f3850SWill Newton 
845f95f3850SWill Newton 	mrq = slot->mrq;
846f95f3850SWill Newton 
847f95f3850SWill Newton 	host->cur_slot = slot;
848f95f3850SWill Newton 	host->mrq = mrq;
849f95f3850SWill Newton 
850f95f3850SWill Newton 	host->pending_events = 0;
851f95f3850SWill Newton 	host->completed_events = 0;
852e352c813SSeungwon Jeon 	host->cmd_status = 0;
853f95f3850SWill Newton 	host->data_status = 0;
854e352c813SSeungwon Jeon 	host->dir_status = 0;
855f95f3850SWill Newton 
856053b3ce6SSeungwon Jeon 	data = cmd->data;
857f95f3850SWill Newton 	if (data) {
858f16afa88SJaehoon Chung 		mci_writel(host, TMOUT, 0xFFFFFFFF);
859f95f3850SWill Newton 		mci_writel(host, BYTCNT, data->blksz*data->blocks);
860f95f3850SWill Newton 		mci_writel(host, BLKSIZ, data->blksz);
861f95f3850SWill Newton 	}
862f95f3850SWill Newton 
863f95f3850SWill Newton 	cmdflags = dw_mci_prepare_command(slot->mmc, cmd);
864f95f3850SWill Newton 
865f95f3850SWill Newton 	/* this is the first command, send the initialization clock */
866f95f3850SWill Newton 	if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags))
867f95f3850SWill Newton 		cmdflags |= SDMMC_CMD_INIT;
868f95f3850SWill Newton 
869f95f3850SWill Newton 	if (data) {
870f95f3850SWill Newton 		dw_mci_submit_data(host, data);
871f95f3850SWill Newton 		wmb();
872f95f3850SWill Newton 	}
873f95f3850SWill Newton 
874f95f3850SWill Newton 	dw_mci_start_command(host, cmd, cmdflags);
875f95f3850SWill Newton 
876f95f3850SWill Newton 	if (mrq->stop)
877f95f3850SWill Newton 		host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
87890c2143aSSeungwon Jeon 	else
87990c2143aSSeungwon Jeon 		host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd);
880f95f3850SWill Newton }
881f95f3850SWill Newton 
882053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host,
883053b3ce6SSeungwon Jeon 				 struct dw_mci_slot *slot)
884053b3ce6SSeungwon Jeon {
885053b3ce6SSeungwon Jeon 	struct mmc_request *mrq = slot->mrq;
886053b3ce6SSeungwon Jeon 	struct mmc_command *cmd;
887053b3ce6SSeungwon Jeon 
888053b3ce6SSeungwon Jeon 	cmd = mrq->sbc ? mrq->sbc : mrq->cmd;
889053b3ce6SSeungwon Jeon 	__dw_mci_start_request(host, slot, cmd);
890053b3ce6SSeungwon Jeon }
891053b3ce6SSeungwon Jeon 
8927456caaeSJames Hogan /* must be called with host->lock held */
893f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot,
894f95f3850SWill Newton 				 struct mmc_request *mrq)
895f95f3850SWill Newton {
896f95f3850SWill Newton 	dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
897f95f3850SWill Newton 		 host->state);
898f95f3850SWill Newton 
899f95f3850SWill Newton 	slot->mrq = mrq;
900f95f3850SWill Newton 
901f95f3850SWill Newton 	if (host->state == STATE_IDLE) {
902f95f3850SWill Newton 		host->state = STATE_SENDING_CMD;
903f95f3850SWill Newton 		dw_mci_start_request(host, slot);
904f95f3850SWill Newton 	} else {
905f95f3850SWill Newton 		list_add_tail(&slot->queue_node, &host->queue);
906f95f3850SWill Newton 	}
907f95f3850SWill Newton }
908f95f3850SWill Newton 
909f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
910f95f3850SWill Newton {
911f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
912f95f3850SWill Newton 	struct dw_mci *host = slot->host;
913f95f3850SWill Newton 
914f95f3850SWill Newton 	WARN_ON(slot->mrq);
915f95f3850SWill Newton 
9167456caaeSJames Hogan 	/*
9177456caaeSJames Hogan 	 * The check for card presence and queueing of the request must be
9187456caaeSJames Hogan 	 * atomic, otherwise the card could be removed in between and the
9197456caaeSJames Hogan 	 * request wouldn't fail until another card was inserted.
9207456caaeSJames Hogan 	 */
9217456caaeSJames Hogan 	spin_lock_bh(&host->lock);
9227456caaeSJames Hogan 
923f95f3850SWill Newton 	if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
9247456caaeSJames Hogan 		spin_unlock_bh(&host->lock);
925f95f3850SWill Newton 		mrq->cmd->error = -ENOMEDIUM;
926f95f3850SWill Newton 		mmc_request_done(mmc, mrq);
927f95f3850SWill Newton 		return;
928f95f3850SWill Newton 	}
929f95f3850SWill Newton 
930f95f3850SWill Newton 	dw_mci_queue_request(host, slot, mrq);
9317456caaeSJames Hogan 
9327456caaeSJames Hogan 	spin_unlock_bh(&host->lock);
933f95f3850SWill Newton }
934f95f3850SWill Newton 
935f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
936f95f3850SWill Newton {
937f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
938e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
93941babf75SJaehoon Chung 	u32 regs;
940f95f3850SWill Newton 
941f95f3850SWill Newton 	switch (ios->bus_width) {
942f95f3850SWill Newton 	case MMC_BUS_WIDTH_4:
943f95f3850SWill Newton 		slot->ctype = SDMMC_CTYPE_4BIT;
944f95f3850SWill Newton 		break;
945c9b2a06fSJaehoon Chung 	case MMC_BUS_WIDTH_8:
946c9b2a06fSJaehoon Chung 		slot->ctype = SDMMC_CTYPE_8BIT;
947c9b2a06fSJaehoon Chung 		break;
948b2f7cb45SJaehoon Chung 	default:
949b2f7cb45SJaehoon Chung 		/* set default 1 bit mode */
950b2f7cb45SJaehoon Chung 		slot->ctype = SDMMC_CTYPE_1BIT;
951f95f3850SWill Newton 	}
952f95f3850SWill Newton 
95341babf75SJaehoon Chung 	regs = mci_readl(slot->host, UHS_REG);
9543f514291SSeungwon Jeon 
9553f514291SSeungwon Jeon 	/* DDR mode set */
956cab3a802SSeungwon Jeon 	if (ios->timing == MMC_TIMING_MMC_DDR52)
957c69042a5SHyeonsu Kim 		regs |= ((0x1 << slot->id) << 16);
9583f514291SSeungwon Jeon 	else
959c69042a5SHyeonsu Kim 		regs &= ~((0x1 << slot->id) << 16);
9603f514291SSeungwon Jeon 
96141babf75SJaehoon Chung 	mci_writel(slot->host, UHS_REG, regs);
962f1d2736cSSeungwon Jeon 	slot->host->timing = ios->timing;
96341babf75SJaehoon Chung 
964f95f3850SWill Newton 	/*
965f95f3850SWill Newton 	 * Use mirror of ios->clock to prevent race with mmc
966f95f3850SWill Newton 	 * core ios update when finding the minimum.
967f95f3850SWill Newton 	 */
968f95f3850SWill Newton 	slot->clock = ios->clock;
969f95f3850SWill Newton 
970cb27a843SJames Hogan 	if (drv_data && drv_data->set_ios)
971cb27a843SJames Hogan 		drv_data->set_ios(slot->host, ios);
972800d78bfSThomas Abraham 
973bf7cb224SJaehoon Chung 	/* Slot specific timing and width adjustment */
974bf7cb224SJaehoon Chung 	dw_mci_setup_bus(slot, false);
975bf7cb224SJaehoon Chung 
976f95f3850SWill Newton 	switch (ios->power_mode) {
977f95f3850SWill Newton 	case MMC_POWER_UP:
978f95f3850SWill Newton 		set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
9794366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
9804366dcc5SJaehoon Chung 		regs |= (1 << slot->id);
9814366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
982e6f34e2fSJames Hogan 		break;
983e6f34e2fSJames Hogan 	case MMC_POWER_OFF:
9844366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
9854366dcc5SJaehoon Chung 		regs &= ~(1 << slot->id);
9864366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
987f95f3850SWill Newton 		break;
988f95f3850SWill Newton 	default:
989f95f3850SWill Newton 		break;
990f95f3850SWill Newton 	}
991f95f3850SWill Newton }
992f95f3850SWill Newton 
993f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc)
994f95f3850SWill Newton {
995f95f3850SWill Newton 	int read_only;
996f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
997*9795a846SJaehoon Chung 	int gpio_ro = mmc_gpio_get_ro(mmc);
998f95f3850SWill Newton 
999f95f3850SWill Newton 	/* Use platform get_ro function, else try on board write protect */
10009640639bSDoug Anderson 	if (slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT)
1001b4967aa5SThomas Abraham 		read_only = 0;
1002*9795a846SJaehoon Chung 	else if (!IS_ERR_VALUE(gpio_ro))
1003*9795a846SJaehoon 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 
1232e352c813SSeungwon Jeon 		dev_err(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 		 */
123831bff450SSeungwon Jeon 		dw_mci_fifo_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:
1302f95f3850SWill Newton 			if (test_and_clear_bit(EVENT_DATA_ERROR,
1303f95f3850SWill Newton 					       &host->pending_events)) {
1304f95f3850SWill Newton 				dw_mci_stop_dma(host);
130590c2143aSSeungwon Jeon 				send_stop_abort(host, data);
1306f95f3850SWill Newton 				state = STATE_DATA_ERROR;
1307f95f3850SWill Newton 				break;
1308f95f3850SWill Newton 			}
1309f95f3850SWill Newton 
1310f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1311f95f3850SWill Newton 						&host->pending_events))
1312f95f3850SWill Newton 				break;
1313f95f3850SWill Newton 
1314f95f3850SWill Newton 			set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
1315f95f3850SWill Newton 			prev_state = state = STATE_DATA_BUSY;
1316f95f3850SWill Newton 			/* fall through */
1317f95f3850SWill Newton 
1318f95f3850SWill Newton 		case STATE_DATA_BUSY:
1319f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
1320f95f3850SWill Newton 						&host->pending_events))
1321f95f3850SWill Newton 				break;
1322f95f3850SWill Newton 
1323f95f3850SWill Newton 			host->data = NULL;
1324f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
1325e352c813SSeungwon Jeon 			err = dw_mci_data_complete(host, data);
1326f95f3850SWill Newton 
1327e352c813SSeungwon Jeon 			if (!err) {
1328e352c813SSeungwon Jeon 				if (!data->stop || mrq->sbc) {
132917c8bc85SSachin Kamat 					if (mrq->sbc && data->stop)
1330053b3ce6SSeungwon Jeon 						data->stop->error = 0;
1331e352c813SSeungwon Jeon 					dw_mci_request_end(host, mrq);
1332053b3ce6SSeungwon Jeon 					goto unlock;
1333053b3ce6SSeungwon Jeon 				}
1334053b3ce6SSeungwon Jeon 
133590c2143aSSeungwon Jeon 				/* stop command for open-ended transfer*/
1336e352c813SSeungwon Jeon 				if (data->stop)
133790c2143aSSeungwon Jeon 					send_stop_abort(host, data);
133890c2143aSSeungwon Jeon 			}
1339e352c813SSeungwon Jeon 
1340e352c813SSeungwon Jeon 			/*
1341e352c813SSeungwon Jeon 			 * If err has non-zero,
1342e352c813SSeungwon Jeon 			 * stop-abort command has been already issued.
1343e352c813SSeungwon Jeon 			 */
1344e352c813SSeungwon Jeon 			prev_state = state = STATE_SENDING_STOP;
1345e352c813SSeungwon Jeon 
1346f95f3850SWill Newton 			/* fall through */
1347f95f3850SWill Newton 
1348f95f3850SWill Newton 		case STATE_SENDING_STOP:
1349f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1350f95f3850SWill Newton 						&host->pending_events))
1351f95f3850SWill Newton 				break;
1352f95f3850SWill Newton 
135371abb133SSeungwon Jeon 			/* CMD error in data command */
135431bff450SSeungwon Jeon 			if (mrq->cmd->error && mrq->data)
135531bff450SSeungwon Jeon 				dw_mci_fifo_reset(host);
135671abb133SSeungwon Jeon 
1357f95f3850SWill Newton 			host->cmd = NULL;
135871abb133SSeungwon Jeon 			host->data = NULL;
135990c2143aSSeungwon Jeon 
1360e352c813SSeungwon Jeon 			if (mrq->stop)
1361e352c813SSeungwon Jeon 				dw_mci_command_complete(host, mrq->stop);
136290c2143aSSeungwon Jeon 			else
136390c2143aSSeungwon Jeon 				host->cmd_status = 0;
136490c2143aSSeungwon Jeon 
1365e352c813SSeungwon Jeon 			dw_mci_request_end(host, mrq);
1366f95f3850SWill Newton 			goto unlock;
1367f95f3850SWill Newton 
1368f95f3850SWill Newton 		case STATE_DATA_ERROR:
1369f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1370f95f3850SWill Newton 						&host->pending_events))
1371f95f3850SWill Newton 				break;
1372f95f3850SWill Newton 
1373f95f3850SWill Newton 			state = STATE_DATA_BUSY;
1374f95f3850SWill Newton 			break;
1375f95f3850SWill Newton 		}
1376f95f3850SWill Newton 	} while (state != prev_state);
1377f95f3850SWill Newton 
1378f95f3850SWill Newton 	host->state = state;
1379f95f3850SWill Newton unlock:
1380f95f3850SWill Newton 	spin_unlock(&host->lock);
1381f95f3850SWill Newton 
1382f95f3850SWill Newton }
1383f95f3850SWill Newton 
138434b664a2SJames Hogan /* push final bytes to part_buf, only use during push */
138534b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt)
138634b664a2SJames Hogan {
138734b664a2SJames Hogan 	memcpy((void *)&host->part_buf, buf, cnt);
138834b664a2SJames Hogan 	host->part_buf_count = cnt;
138934b664a2SJames Hogan }
139034b664a2SJames Hogan 
139134b664a2SJames Hogan /* append bytes to part_buf, only use during push */
139234b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt)
139334b664a2SJames Hogan {
139434b664a2SJames Hogan 	cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count);
139534b664a2SJames Hogan 	memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt);
139634b664a2SJames Hogan 	host->part_buf_count += cnt;
139734b664a2SJames Hogan 	return cnt;
139834b664a2SJames Hogan }
139934b664a2SJames Hogan 
140034b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */
140134b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt)
140234b664a2SJames Hogan {
140334b664a2SJames Hogan 	cnt = min(cnt, (int)host->part_buf_count);
140434b664a2SJames Hogan 	if (cnt) {
140534b664a2SJames Hogan 		memcpy(buf, (void *)&host->part_buf + host->part_buf_start,
140634b664a2SJames Hogan 		       cnt);
140734b664a2SJames Hogan 		host->part_buf_count -= cnt;
140834b664a2SJames Hogan 		host->part_buf_start += cnt;
140934b664a2SJames Hogan 	}
141034b664a2SJames Hogan 	return cnt;
141134b664a2SJames Hogan }
141234b664a2SJames Hogan 
141334b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */
141434b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt)
141534b664a2SJames Hogan {
141634b664a2SJames Hogan 	memcpy(buf, &host->part_buf, cnt);
141734b664a2SJames Hogan 	host->part_buf_start = cnt;
141834b664a2SJames Hogan 	host->part_buf_count = (1 << host->data_shift) - cnt;
141934b664a2SJames Hogan }
142034b664a2SJames Hogan 
1421f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
1422f95f3850SWill Newton {
1423cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1424cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1425cfbeb59cSMarkos Chandras 
142634b664a2SJames Hogan 	/* try and push anything in the part_buf */
142734b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
142834b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
142934b664a2SJames Hogan 		buf += len;
143034b664a2SJames Hogan 		cnt -= len;
1431cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 2) {
14324e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
14334e0a5adfSJaehoon Chung 					host->part_buf16);
143434b664a2SJames Hogan 			host->part_buf_count = 0;
143534b664a2SJames Hogan 		}
143634b664a2SJames Hogan 	}
143734b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
143834b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
143934b664a2SJames Hogan 		while (cnt >= 2) {
144034b664a2SJames Hogan 			u16 aligned_buf[64];
144134b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
144234b664a2SJames Hogan 			int items = len >> 1;
144334b664a2SJames Hogan 			int i;
144434b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
144534b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
144634b664a2SJames Hogan 			buf += len;
144734b664a2SJames Hogan 			cnt -= len;
144834b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
144934b664a2SJames Hogan 			for (i = 0; i < items; ++i)
14504e0a5adfSJaehoon Chung 				mci_writew(host, DATA(host->data_offset),
14514e0a5adfSJaehoon Chung 						aligned_buf[i]);
145234b664a2SJames Hogan 		}
145334b664a2SJames Hogan 	} else
145434b664a2SJames Hogan #endif
145534b664a2SJames Hogan 	{
145634b664a2SJames Hogan 		u16 *pdata = buf;
145734b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
14584e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset), *pdata++);
145934b664a2SJames Hogan 		buf = pdata;
146034b664a2SJames Hogan 	}
146134b664a2SJames Hogan 	/* put anything remaining in the part_buf */
146234b664a2SJames Hogan 	if (cnt) {
146334b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1464cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1465cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1466cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
14674e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
14684e0a5adfSJaehoon Chung 				   host->part_buf16);
1469f95f3850SWill Newton 	}
1470f95f3850SWill Newton }
1471f95f3850SWill Newton 
1472f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
1473f95f3850SWill Newton {
147434b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
147534b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
147634b664a2SJames Hogan 		while (cnt >= 2) {
147734b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
147834b664a2SJames Hogan 			u16 aligned_buf[64];
147934b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
148034b664a2SJames Hogan 			int items = len >> 1;
148134b664a2SJames Hogan 			int i;
148234b664a2SJames Hogan 			for (i = 0; i < items; ++i)
14834e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readw(host,
14844e0a5adfSJaehoon Chung 						DATA(host->data_offset));
148534b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
148634b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
148734b664a2SJames Hogan 			buf += len;
148834b664a2SJames Hogan 			cnt -= len;
148934b664a2SJames Hogan 		}
149034b664a2SJames Hogan 	} else
149134b664a2SJames Hogan #endif
149234b664a2SJames Hogan 	{
149334b664a2SJames Hogan 		u16 *pdata = buf;
149434b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
14954e0a5adfSJaehoon Chung 			*pdata++ = mci_readw(host, DATA(host->data_offset));
149634b664a2SJames Hogan 		buf = pdata;
149734b664a2SJames Hogan 	}
149834b664a2SJames Hogan 	if (cnt) {
14994e0a5adfSJaehoon Chung 		host->part_buf16 = mci_readw(host, DATA(host->data_offset));
150034b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1501f95f3850SWill Newton 	}
1502f95f3850SWill Newton }
1503f95f3850SWill Newton 
1504f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
1505f95f3850SWill Newton {
1506cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1507cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1508cfbeb59cSMarkos Chandras 
150934b664a2SJames Hogan 	/* try and push anything in the part_buf */
151034b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
151134b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
151234b664a2SJames Hogan 		buf += len;
151334b664a2SJames Hogan 		cnt -= len;
1514cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 4) {
15154e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
15164e0a5adfSJaehoon Chung 					host->part_buf32);
151734b664a2SJames Hogan 			host->part_buf_count = 0;
151834b664a2SJames Hogan 		}
151934b664a2SJames Hogan 	}
152034b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
152134b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
152234b664a2SJames Hogan 		while (cnt >= 4) {
152334b664a2SJames Hogan 			u32 aligned_buf[32];
152434b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
152534b664a2SJames Hogan 			int items = len >> 2;
152634b664a2SJames Hogan 			int i;
152734b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
152834b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
152934b664a2SJames Hogan 			buf += len;
153034b664a2SJames Hogan 			cnt -= len;
153134b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
153234b664a2SJames Hogan 			for (i = 0; i < items; ++i)
15334e0a5adfSJaehoon Chung 				mci_writel(host, DATA(host->data_offset),
15344e0a5adfSJaehoon Chung 						aligned_buf[i]);
153534b664a2SJames Hogan 		}
153634b664a2SJames Hogan 	} else
153734b664a2SJames Hogan #endif
153834b664a2SJames Hogan 	{
153934b664a2SJames Hogan 		u32 *pdata = buf;
154034b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
15414e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset), *pdata++);
154234b664a2SJames Hogan 		buf = pdata;
154334b664a2SJames Hogan 	}
154434b664a2SJames Hogan 	/* put anything remaining in the part_buf */
154534b664a2SJames Hogan 	if (cnt) {
154634b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1547cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1548cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1549cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
15504e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
15514e0a5adfSJaehoon Chung 				   host->part_buf32);
1552f95f3850SWill Newton 	}
1553f95f3850SWill Newton }
1554f95f3850SWill Newton 
1555f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
1556f95f3850SWill Newton {
155734b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
155834b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
155934b664a2SJames Hogan 		while (cnt >= 4) {
156034b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
156134b664a2SJames Hogan 			u32 aligned_buf[32];
156234b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
156334b664a2SJames Hogan 			int items = len >> 2;
156434b664a2SJames Hogan 			int i;
156534b664a2SJames Hogan 			for (i = 0; i < items; ++i)
15664e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readl(host,
15674e0a5adfSJaehoon Chung 						DATA(host->data_offset));
156834b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
156934b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
157034b664a2SJames Hogan 			buf += len;
157134b664a2SJames Hogan 			cnt -= len;
157234b664a2SJames Hogan 		}
157334b664a2SJames Hogan 	} else
157434b664a2SJames Hogan #endif
157534b664a2SJames Hogan 	{
157634b664a2SJames Hogan 		u32 *pdata = buf;
157734b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
15784e0a5adfSJaehoon Chung 			*pdata++ = mci_readl(host, DATA(host->data_offset));
157934b664a2SJames Hogan 		buf = pdata;
158034b664a2SJames Hogan 	}
158134b664a2SJames Hogan 	if (cnt) {
15824e0a5adfSJaehoon Chung 		host->part_buf32 = mci_readl(host, DATA(host->data_offset));
158334b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1584f95f3850SWill Newton 	}
1585f95f3850SWill Newton }
1586f95f3850SWill Newton 
1587f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
1588f95f3850SWill Newton {
1589cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1590cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1591cfbeb59cSMarkos Chandras 
159234b664a2SJames Hogan 	/* try and push anything in the part_buf */
159334b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
159434b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
159534b664a2SJames Hogan 		buf += len;
159634b664a2SJames Hogan 		cnt -= len;
1597c09fbd74SSeungwon Jeon 
1598cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 8) {
1599c09fbd74SSeungwon Jeon 			mci_writeq(host, DATA(host->data_offset),
16004e0a5adfSJaehoon Chung 					host->part_buf);
160134b664a2SJames Hogan 			host->part_buf_count = 0;
160234b664a2SJames Hogan 		}
160334b664a2SJames Hogan 	}
160434b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
160534b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
160634b664a2SJames Hogan 		while (cnt >= 8) {
160734b664a2SJames Hogan 			u64 aligned_buf[16];
160834b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
160934b664a2SJames Hogan 			int items = len >> 3;
161034b664a2SJames Hogan 			int i;
161134b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
161234b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
161334b664a2SJames Hogan 			buf += len;
161434b664a2SJames Hogan 			cnt -= len;
161534b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
161634b664a2SJames Hogan 			for (i = 0; i < items; ++i)
16174e0a5adfSJaehoon Chung 				mci_writeq(host, DATA(host->data_offset),
16184e0a5adfSJaehoon Chung 						aligned_buf[i]);
161934b664a2SJames Hogan 		}
162034b664a2SJames Hogan 	} else
162134b664a2SJames Hogan #endif
162234b664a2SJames Hogan 	{
162334b664a2SJames Hogan 		u64 *pdata = buf;
162434b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
16254e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset), *pdata++);
162634b664a2SJames Hogan 		buf = pdata;
162734b664a2SJames Hogan 	}
162834b664a2SJames Hogan 	/* put anything remaining in the part_buf */
162934b664a2SJames Hogan 	if (cnt) {
163034b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1631cfbeb59cSMarkos Chandras 		/* Push data if we have reached the expected data length */
1632cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1633cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
16344e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset),
16354e0a5adfSJaehoon Chung 				   host->part_buf);
1636f95f3850SWill Newton 	}
1637f95f3850SWill Newton }
1638f95f3850SWill Newton 
1639f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
1640f95f3850SWill Newton {
164134b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
164234b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
164334b664a2SJames Hogan 		while (cnt >= 8) {
164434b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
164534b664a2SJames Hogan 			u64 aligned_buf[16];
164634b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
164734b664a2SJames Hogan 			int items = len >> 3;
164834b664a2SJames Hogan 			int i;
164934b664a2SJames Hogan 			for (i = 0; i < items; ++i)
16504e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readq(host,
16514e0a5adfSJaehoon Chung 						DATA(host->data_offset));
165234b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
165334b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
165434b664a2SJames Hogan 			buf += len;
165534b664a2SJames Hogan 			cnt -= len;
1656f95f3850SWill Newton 		}
165734b664a2SJames Hogan 	} else
165834b664a2SJames Hogan #endif
165934b664a2SJames Hogan 	{
166034b664a2SJames Hogan 		u64 *pdata = buf;
166134b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
16624e0a5adfSJaehoon Chung 			*pdata++ = mci_readq(host, DATA(host->data_offset));
166334b664a2SJames Hogan 		buf = pdata;
166434b664a2SJames Hogan 	}
166534b664a2SJames Hogan 	if (cnt) {
16664e0a5adfSJaehoon Chung 		host->part_buf = mci_readq(host, DATA(host->data_offset));
166734b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
166834b664a2SJames Hogan 	}
166934b664a2SJames Hogan }
167034b664a2SJames Hogan 
167134b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
167234b664a2SJames Hogan {
167334b664a2SJames Hogan 	int len;
167434b664a2SJames Hogan 
167534b664a2SJames Hogan 	/* get remaining partial bytes */
167634b664a2SJames Hogan 	len = dw_mci_pull_part_bytes(host, buf, cnt);
167734b664a2SJames Hogan 	if (unlikely(len == cnt))
167834b664a2SJames Hogan 		return;
167934b664a2SJames Hogan 	buf += len;
168034b664a2SJames Hogan 	cnt -= len;
168134b664a2SJames Hogan 
168234b664a2SJames Hogan 	/* get the rest of the data */
168334b664a2SJames Hogan 	host->pull_data(host, buf, cnt);
1684f95f3850SWill Newton }
1685f95f3850SWill Newton 
168687a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto)
1687f95f3850SWill Newton {
1688f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1689f9c2a0dcSSeungwon Jeon 	void *buf;
1690f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1691f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1692f95f3850SWill Newton 	int shift = host->data_shift;
1693f95f3850SWill Newton 	u32 status;
16943e4b0d8bSMarkos Chandras 	unsigned int len;
1695f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1696f95f3850SWill Newton 
1697f95f3850SWill Newton 	do {
1698f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1699f9c2a0dcSSeungwon Jeon 			goto done;
1700f95f3850SWill Newton 
17014225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1702f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1703f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1704f9c2a0dcSSeungwon Jeon 		offset = 0;
1705f9c2a0dcSSeungwon Jeon 
1706f9c2a0dcSSeungwon Jeon 		do {
1707f9c2a0dcSSeungwon Jeon 			fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS))
1708f9c2a0dcSSeungwon Jeon 					<< shift) + host->part_buf_count;
1709f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1710f9c2a0dcSSeungwon Jeon 			if (!len)
1711f9c2a0dcSSeungwon Jeon 				break;
1712f9c2a0dcSSeungwon Jeon 			dw_mci_pull_data(host, (void *)(buf + offset), len);
17133e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1714f95f3850SWill Newton 			offset += len;
1715f9c2a0dcSSeungwon Jeon 			remain -= len;
1716f9c2a0dcSSeungwon Jeon 		} while (remain);
1717f95f3850SWill Newton 
1718e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1719f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1720f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
172187a74d39SKyoungil Kim 	/* if the RXDR is ready read again */
172287a74d39SKyoungil Kim 	} while ((status & SDMMC_INT_RXDR) ||
172387a74d39SKyoungil Kim 		 (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS))));
1724f9c2a0dcSSeungwon Jeon 
1725f9c2a0dcSSeungwon Jeon 	if (!remain) {
1726f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1727f9c2a0dcSSeungwon Jeon 			goto done;
1728f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1729f9c2a0dcSSeungwon Jeon 	}
1730f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1731f95f3850SWill Newton 	return;
1732f95f3850SWill Newton 
1733f95f3850SWill Newton done:
1734f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1735f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1736f95f3850SWill Newton 	smp_wmb();
1737f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1738f95f3850SWill Newton }
1739f95f3850SWill Newton 
1740f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host)
1741f95f3850SWill Newton {
1742f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1743f9c2a0dcSSeungwon Jeon 	void *buf;
1744f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1745f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1746f95f3850SWill Newton 	int shift = host->data_shift;
1747f95f3850SWill Newton 	u32 status;
17483e4b0d8bSMarkos Chandras 	unsigned int len;
1749f9c2a0dcSSeungwon Jeon 	unsigned int fifo_depth = host->fifo_depth;
1750f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1751f95f3850SWill Newton 
1752f95f3850SWill Newton 	do {
1753f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1754f9c2a0dcSSeungwon Jeon 			goto done;
1755f95f3850SWill Newton 
17564225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1757f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1758f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1759f9c2a0dcSSeungwon Jeon 		offset = 0;
1760f9c2a0dcSSeungwon Jeon 
1761f9c2a0dcSSeungwon Jeon 		do {
1762f9c2a0dcSSeungwon Jeon 			fcnt = ((fifo_depth -
1763f9c2a0dcSSeungwon Jeon 				 SDMMC_GET_FCNT(mci_readl(host, STATUS)))
1764f9c2a0dcSSeungwon Jeon 					<< shift) - host->part_buf_count;
1765f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1766f9c2a0dcSSeungwon Jeon 			if (!len)
1767f9c2a0dcSSeungwon Jeon 				break;
1768f9c2a0dcSSeungwon Jeon 			host->push_data(host, (void *)(buf + offset), len);
17693e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1770f95f3850SWill Newton 			offset += len;
1771f9c2a0dcSSeungwon Jeon 			remain -= len;
1772f9c2a0dcSSeungwon Jeon 		} while (remain);
1773f95f3850SWill Newton 
1774e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1775f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1776f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1777f95f3850SWill Newton 	} while (status & SDMMC_INT_TXDR); /* if TXDR write again */
1778f9c2a0dcSSeungwon Jeon 
1779f9c2a0dcSSeungwon Jeon 	if (!remain) {
1780f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1781f9c2a0dcSSeungwon Jeon 			goto done;
1782f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1783f9c2a0dcSSeungwon Jeon 	}
1784f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1785f95f3850SWill Newton 	return;
1786f95f3850SWill Newton 
1787f95f3850SWill Newton done:
1788f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1789f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1790f95f3850SWill Newton 	smp_wmb();
1791f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1792f95f3850SWill Newton }
1793f95f3850SWill Newton 
1794f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
1795f95f3850SWill Newton {
1796f95f3850SWill Newton 	if (!host->cmd_status)
1797f95f3850SWill Newton 		host->cmd_status = status;
1798f95f3850SWill Newton 
1799f95f3850SWill Newton 	smp_wmb();
1800f95f3850SWill Newton 
1801f95f3850SWill Newton 	set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1802f95f3850SWill Newton 	tasklet_schedule(&host->tasklet);
1803f95f3850SWill Newton }
1804f95f3850SWill Newton 
1805f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
1806f95f3850SWill Newton {
1807f95f3850SWill Newton 	struct dw_mci *host = dev_id;
1808182c9081SSeungwon Jeon 	u32 pending;
18091a5c8e1fSShashidhar Hiremath 	int i;
1810f95f3850SWill Newton 
1811f95f3850SWill Newton 	pending = mci_readl(host, MINTSTS); /* read-only mask reg */
1812f95f3850SWill Newton 
1813f95f3850SWill Newton 	/*
1814f95f3850SWill Newton 	 * DTO fix - version 2.10a and below, and only if internal DMA
1815f95f3850SWill Newton 	 * is configured.
1816f95f3850SWill Newton 	 */
1817f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
1818f95f3850SWill Newton 		if (!pending &&
1819f95f3850SWill Newton 		    ((mci_readl(host, STATUS) >> 17) & 0x1fff))
1820f95f3850SWill Newton 			pending |= SDMMC_INT_DATA_OVER;
1821f95f3850SWill Newton 	}
1822f95f3850SWill Newton 
1823476d79f1SDoug Anderson 	if (pending) {
1824f95f3850SWill Newton 		if (pending & DW_MCI_CMD_ERROR_FLAGS) {
1825f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
1826182c9081SSeungwon Jeon 			host->cmd_status = pending;
1827f95f3850SWill Newton 			smp_wmb();
1828f95f3850SWill Newton 			set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1829f95f3850SWill Newton 		}
1830f95f3850SWill Newton 
1831f95f3850SWill Newton 		if (pending & DW_MCI_DATA_ERROR_FLAGS) {
1832f95f3850SWill Newton 			/* if there is an error report DATA_ERROR */
1833f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
1834182c9081SSeungwon Jeon 			host->data_status = pending;
1835f95f3850SWill Newton 			smp_wmb();
1836f95f3850SWill Newton 			set_bit(EVENT_DATA_ERROR, &host->pending_events);
1837f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
1838f95f3850SWill Newton 		}
1839f95f3850SWill Newton 
1840f95f3850SWill Newton 		if (pending & SDMMC_INT_DATA_OVER) {
1841f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
1842f95f3850SWill Newton 			if (!host->data_status)
1843182c9081SSeungwon Jeon 				host->data_status = pending;
1844f95f3850SWill Newton 			smp_wmb();
1845f95f3850SWill Newton 			if (host->dir_status == DW_MCI_RECV_STATUS) {
1846f95f3850SWill Newton 				if (host->sg != NULL)
184787a74d39SKyoungil Kim 					dw_mci_read_data_pio(host, true);
1848f95f3850SWill Newton 			}
1849f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
1850f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
1851f95f3850SWill Newton 		}
1852f95f3850SWill Newton 
1853f95f3850SWill Newton 		if (pending & SDMMC_INT_RXDR) {
1854f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
1855b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_RECV_STATUS && host->sg)
185687a74d39SKyoungil Kim 				dw_mci_read_data_pio(host, false);
1857f95f3850SWill Newton 		}
1858f95f3850SWill Newton 
1859f95f3850SWill Newton 		if (pending & SDMMC_INT_TXDR) {
1860f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1861b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_SEND_STATUS && host->sg)
1862f95f3850SWill Newton 				dw_mci_write_data_pio(host);
1863f95f3850SWill Newton 		}
1864f95f3850SWill Newton 
1865f95f3850SWill Newton 		if (pending & SDMMC_INT_CMD_DONE) {
1866f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
1867182c9081SSeungwon Jeon 			dw_mci_cmd_interrupt(host, pending);
1868f95f3850SWill Newton 		}
1869f95f3850SWill Newton 
1870f95f3850SWill Newton 		if (pending & SDMMC_INT_CD) {
1871f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CD);
187295dcc2cbSThomas Abraham 			queue_work(host->card_workqueue, &host->card_work);
1873f95f3850SWill Newton 		}
1874f95f3850SWill Newton 
18751a5c8e1fSShashidhar Hiremath 		/* Handle SDIO Interrupts */
18761a5c8e1fSShashidhar Hiremath 		for (i = 0; i < host->num_slots; i++) {
18771a5c8e1fSShashidhar Hiremath 			struct dw_mci_slot *slot = host->slot[i];
18781a5c8e1fSShashidhar Hiremath 			if (pending & SDMMC_INT_SDIO(i)) {
18791a5c8e1fSShashidhar Hiremath 				mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
18801a5c8e1fSShashidhar Hiremath 				mmc_signal_sdio_irq(slot->mmc);
18811a5c8e1fSShashidhar Hiremath 			}
18821a5c8e1fSShashidhar Hiremath 		}
18831a5c8e1fSShashidhar Hiremath 
18841fb5f68aSMarkos Chandras 	}
1885f95f3850SWill Newton 
1886f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
1887f95f3850SWill Newton 	/* Handle DMA interrupts */
1888f95f3850SWill Newton 	pending = mci_readl(host, IDSTS);
1889f95f3850SWill Newton 	if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
1890f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
1891f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
1892f95f3850SWill Newton 		host->dma_ops->complete(host);
1893f95f3850SWill Newton 	}
1894f95f3850SWill Newton #endif
1895f95f3850SWill Newton 
1896f95f3850SWill Newton 	return IRQ_HANDLED;
1897f95f3850SWill Newton }
1898f95f3850SWill Newton 
18991791b13eSJames Hogan static void dw_mci_work_routine_card(struct work_struct *work)
1900f95f3850SWill Newton {
19011791b13eSJames Hogan 	struct dw_mci *host = container_of(work, struct dw_mci, card_work);
1902f95f3850SWill Newton 	int i;
1903f95f3850SWill Newton 
1904f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
1905f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
1906f95f3850SWill Newton 		struct mmc_host *mmc = slot->mmc;
1907f95f3850SWill Newton 		struct mmc_request *mrq;
1908f95f3850SWill Newton 		int present;
1909f95f3850SWill Newton 
1910f95f3850SWill Newton 		present = dw_mci_get_cd(mmc);
1911f95f3850SWill Newton 		while (present != slot->last_detect_state) {
1912f95f3850SWill Newton 			dev_dbg(&slot->mmc->class_dev, "card %s\n",
1913f95f3850SWill Newton 				present ? "inserted" : "removed");
1914f95f3850SWill Newton 
19151791b13eSJames Hogan 			spin_lock_bh(&host->lock);
19161791b13eSJames Hogan 
1917f95f3850SWill Newton 			/* Card change detected */
1918f95f3850SWill Newton 			slot->last_detect_state = present;
1919f95f3850SWill Newton 
1920f95f3850SWill Newton 			/* Clean up queue if present */
1921f95f3850SWill Newton 			mrq = slot->mrq;
1922f95f3850SWill Newton 			if (mrq) {
1923f95f3850SWill Newton 				if (mrq == host->mrq) {
1924f95f3850SWill Newton 					host->data = NULL;
1925f95f3850SWill Newton 					host->cmd = NULL;
1926f95f3850SWill Newton 
1927f95f3850SWill Newton 					switch (host->state) {
1928f95f3850SWill Newton 					case STATE_IDLE:
1929f95f3850SWill Newton 						break;
1930f95f3850SWill Newton 					case STATE_SENDING_CMD:
1931f95f3850SWill Newton 						mrq->cmd->error = -ENOMEDIUM;
1932f95f3850SWill Newton 						if (!mrq->data)
1933f95f3850SWill Newton 							break;
1934f95f3850SWill Newton 						/* fall through */
1935f95f3850SWill Newton 					case STATE_SENDING_DATA:
1936f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
1937f95f3850SWill Newton 						dw_mci_stop_dma(host);
1938f95f3850SWill Newton 						break;
1939f95f3850SWill Newton 					case STATE_DATA_BUSY:
1940f95f3850SWill Newton 					case STATE_DATA_ERROR:
1941f95f3850SWill Newton 						if (mrq->data->error == -EINPROGRESS)
1942f95f3850SWill Newton 							mrq->data->error = -ENOMEDIUM;
1943f95f3850SWill Newton 						/* fall through */
1944f95f3850SWill Newton 					case STATE_SENDING_STOP:
194590c2143aSSeungwon Jeon 						if (mrq->stop)
1946f95f3850SWill Newton 							mrq->stop->error = -ENOMEDIUM;
1947f95f3850SWill Newton 						break;
1948f95f3850SWill Newton 					}
1949f95f3850SWill Newton 
1950f95f3850SWill Newton 					dw_mci_request_end(host, mrq);
1951f95f3850SWill Newton 				} else {
1952f95f3850SWill Newton 					list_del(&slot->queue_node);
1953f95f3850SWill Newton 					mrq->cmd->error = -ENOMEDIUM;
1954f95f3850SWill Newton 					if (mrq->data)
1955f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
1956f95f3850SWill Newton 					if (mrq->stop)
1957f95f3850SWill Newton 						mrq->stop->error = -ENOMEDIUM;
1958f95f3850SWill Newton 
1959f95f3850SWill Newton 					spin_unlock(&host->lock);
1960f95f3850SWill Newton 					mmc_request_done(slot->mmc, mrq);
1961f95f3850SWill Newton 					spin_lock(&host->lock);
1962f95f3850SWill Newton 				}
1963f95f3850SWill Newton 			}
1964f95f3850SWill Newton 
1965f95f3850SWill Newton 			/* Power down slot */
1966f95f3850SWill Newton 			if (present == 0) {
196731bff450SSeungwon Jeon 				/* Clear down the FIFO */
196831bff450SSeungwon Jeon 				dw_mci_fifo_reset(host);
1969f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
19705ce9d961SSeungwon Jeon 				dw_mci_idmac_reset(host);
1971f95f3850SWill Newton #endif
1972f95f3850SWill Newton 
1973f95f3850SWill Newton 			}
1974f95f3850SWill Newton 
19751791b13eSJames Hogan 			spin_unlock_bh(&host->lock);
19761791b13eSJames Hogan 
1977f95f3850SWill Newton 			present = dw_mci_get_cd(mmc);
1978f95f3850SWill Newton 		}
1979f95f3850SWill Newton 
1980f95f3850SWill Newton 		mmc_detect_change(slot->mmc,
1981f95f3850SWill Newton 			msecs_to_jiffies(host->pdata->detect_delay_ms));
1982f95f3850SWill Newton 	}
1983f95f3850SWill Newton }
1984f95f3850SWill Newton 
1985c91eab4bSThomas Abraham #ifdef CONFIG_OF
1986c91eab4bSThomas Abraham /* given a slot id, find out the device node representing that slot */
1987c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
1988c91eab4bSThomas Abraham {
1989c91eab4bSThomas Abraham 	struct device_node *np;
1990c91eab4bSThomas Abraham 	const __be32 *addr;
1991c91eab4bSThomas Abraham 	int len;
1992c91eab4bSThomas Abraham 
1993c91eab4bSThomas Abraham 	if (!dev || !dev->of_node)
1994c91eab4bSThomas Abraham 		return NULL;
1995c91eab4bSThomas Abraham 
1996c91eab4bSThomas Abraham 	for_each_child_of_node(dev->of_node, np) {
1997c91eab4bSThomas Abraham 		addr = of_get_property(np, "reg", &len);
1998c91eab4bSThomas Abraham 		if (!addr || (len < sizeof(int)))
1999c91eab4bSThomas Abraham 			continue;
2000c91eab4bSThomas Abraham 		if (be32_to_cpup(addr) == slot)
2001c91eab4bSThomas Abraham 			return np;
2002c91eab4bSThomas Abraham 	}
2003c91eab4bSThomas Abraham 	return NULL;
2004c91eab4bSThomas Abraham }
2005c91eab4bSThomas Abraham 
2006a70aaa64SDoug Anderson static struct dw_mci_of_slot_quirks {
2007a70aaa64SDoug Anderson 	char *quirk;
2008a70aaa64SDoug Anderson 	int id;
2009a70aaa64SDoug Anderson } of_slot_quirks[] = {
2010a70aaa64SDoug Anderson 	{
2011a70aaa64SDoug Anderson 		.quirk	= "disable-wp",
2012a70aaa64SDoug Anderson 		.id	= DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT,
2013a70aaa64SDoug Anderson 	},
2014a70aaa64SDoug Anderson };
2015a70aaa64SDoug Anderson 
2016a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
2017a70aaa64SDoug Anderson {
2018a70aaa64SDoug Anderson 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
2019a70aaa64SDoug Anderson 	int quirks = 0;
2020a70aaa64SDoug Anderson 	int idx;
2021a70aaa64SDoug Anderson 
2022a70aaa64SDoug Anderson 	/* get quirks */
2023a70aaa64SDoug Anderson 	for (idx = 0; idx < ARRAY_SIZE(of_slot_quirks); idx++)
2024a70aaa64SDoug Anderson 		if (of_get_property(np, of_slot_quirks[idx].quirk, NULL))
2025a70aaa64SDoug Anderson 			quirks |= of_slot_quirks[idx].id;
2026a70aaa64SDoug Anderson 
2027a70aaa64SDoug Anderson 	return quirks;
2028a70aaa64SDoug Anderson }
2029c91eab4bSThomas Abraham #else /* CONFIG_OF */
2030a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
2031a70aaa64SDoug Anderson {
2032a70aaa64SDoug Anderson 	return 0;
2033a70aaa64SDoug Anderson }
2034c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
2035c91eab4bSThomas Abraham {
2036c91eab4bSThomas Abraham 	return NULL;
2037c91eab4bSThomas Abraham }
2038c91eab4bSThomas Abraham #endif /* CONFIG_OF */
2039c91eab4bSThomas Abraham 
204036c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
2041f95f3850SWill Newton {
2042f95f3850SWill Newton 	struct mmc_host *mmc;
2043f95f3850SWill Newton 	struct dw_mci_slot *slot;
2044e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
2045800d78bfSThomas Abraham 	int ctrl_id, ret;
20461f44a2a5SSeungwon Jeon 	u32 freq[2];
2047f95f3850SWill Newton 
20484a90920cSThomas Abraham 	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
2049f95f3850SWill Newton 	if (!mmc)
2050f95f3850SWill Newton 		return -ENOMEM;
2051f95f3850SWill Newton 
2052f95f3850SWill Newton 	slot = mmc_priv(mmc);
2053f95f3850SWill Newton 	slot->id = id;
2054f95f3850SWill Newton 	slot->mmc = mmc;
2055f95f3850SWill Newton 	slot->host = host;
2056c91eab4bSThomas Abraham 	host->slot[id] = slot;
2057f95f3850SWill Newton 
2058a70aaa64SDoug Anderson 	slot->quirks = dw_mci_of_get_slot_quirks(host->dev, slot->id);
2059a70aaa64SDoug Anderson 
2060f95f3850SWill Newton 	mmc->ops = &dw_mci_ops;
20611f44a2a5SSeungwon Jeon 	if (of_property_read_u32_array(host->dev->of_node,
20621f44a2a5SSeungwon Jeon 				       "clock-freq-min-max", freq, 2)) {
20631f44a2a5SSeungwon Jeon 		mmc->f_min = DW_MCI_FREQ_MIN;
20641f44a2a5SSeungwon Jeon 		mmc->f_max = DW_MCI_FREQ_MAX;
20651f44a2a5SSeungwon Jeon 	} else {
20661f44a2a5SSeungwon Jeon 		mmc->f_min = freq[0];
20671f44a2a5SSeungwon Jeon 		mmc->f_max = freq[1];
20681f44a2a5SSeungwon Jeon 	}
2069f95f3850SWill Newton 
2070f95f3850SWill Newton 	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
2071f95f3850SWill Newton 
2072fc3d7720SJaehoon Chung 	if (host->pdata->caps)
2073fc3d7720SJaehoon Chung 		mmc->caps = host->pdata->caps;
2074fc3d7720SJaehoon Chung 
2075ab269128SAbhilash Kesavan 	if (host->pdata->pm_caps)
2076ab269128SAbhilash Kesavan 		mmc->pm_caps = host->pdata->pm_caps;
2077ab269128SAbhilash Kesavan 
2078800d78bfSThomas Abraham 	if (host->dev->of_node) {
2079800d78bfSThomas Abraham 		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
2080800d78bfSThomas Abraham 		if (ctrl_id < 0)
2081800d78bfSThomas Abraham 			ctrl_id = 0;
2082800d78bfSThomas Abraham 	} else {
2083800d78bfSThomas Abraham 		ctrl_id = to_platform_device(host->dev)->id;
2084800d78bfSThomas Abraham 	}
2085cb27a843SJames Hogan 	if (drv_data && drv_data->caps)
2086cb27a843SJames Hogan 		mmc->caps |= drv_data->caps[ctrl_id];
2087800d78bfSThomas Abraham 
20884f408cc6SSeungwon Jeon 	if (host->pdata->caps2)
20894f408cc6SSeungwon Jeon 		mmc->caps2 = host->pdata->caps2;
20904f408cc6SSeungwon Jeon 
2091d8a4fb0eSJaehoon Chung 	mmc_of_parse(mmc);
2092f95f3850SWill Newton 
2093f95f3850SWill Newton 	if (host->pdata->blk_settings) {
2094f95f3850SWill Newton 		mmc->max_segs = host->pdata->blk_settings->max_segs;
2095f95f3850SWill Newton 		mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
2096f95f3850SWill Newton 		mmc->max_blk_count = host->pdata->blk_settings->max_blk_count;
2097f95f3850SWill Newton 		mmc->max_req_size = host->pdata->blk_settings->max_req_size;
2098f95f3850SWill Newton 		mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
2099f95f3850SWill Newton 	} else {
2100f95f3850SWill Newton 		/* Useful defaults if platform data is unset. */
2101a39e5746SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
2102a39e5746SJaehoon Chung 		mmc->max_segs = host->ring_size;
2103a39e5746SJaehoon Chung 		mmc->max_blk_size = 65536;
2104a39e5746SJaehoon Chung 		mmc->max_blk_count = host->ring_size;
2105a39e5746SJaehoon Chung 		mmc->max_seg_size = 0x1000;
2106a39e5746SJaehoon Chung 		mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
2107a39e5746SJaehoon Chung #else
2108f95f3850SWill Newton 		mmc->max_segs = 64;
2109f95f3850SWill Newton 		mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
2110f95f3850SWill Newton 		mmc->max_blk_count = 512;
2111f95f3850SWill Newton 		mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
2112f95f3850SWill Newton 		mmc->max_seg_size = mmc->max_req_size;
2113f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */
2114a39e5746SJaehoon Chung 	}
2115f95f3850SWill Newton 
21160cea529dSJaehoon Chung 	ret = mmc_add_host(mmc);
21170cea529dSJaehoon Chung 	if (ret)
21180cea529dSJaehoon Chung 		goto err_setup_bus;
2119f95f3850SWill Newton 
2120f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS)
2121f95f3850SWill Newton 	dw_mci_init_debugfs(slot);
2122f95f3850SWill Newton #endif
2123f95f3850SWill Newton 
2124f95f3850SWill Newton 	/* Card initially undetected */
2125f95f3850SWill Newton 	slot->last_detect_state = 0;
2126f95f3850SWill Newton 
2127f95f3850SWill Newton 	return 0;
2128800d78bfSThomas Abraham 
2129800d78bfSThomas Abraham err_setup_bus:
2130800d78bfSThomas Abraham 	mmc_free_host(mmc);
2131800d78bfSThomas Abraham 	return -EINVAL;
2132f95f3850SWill Newton }
2133f95f3850SWill Newton 
2134f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
2135f95f3850SWill Newton {
2136f95f3850SWill Newton 	/* Debugfs stuff is cleaned up by mmc core */
2137f95f3850SWill Newton 	mmc_remove_host(slot->mmc);
2138f95f3850SWill Newton 	slot->host->slot[id] = NULL;
2139f95f3850SWill Newton 	mmc_free_host(slot->mmc);
2140f95f3850SWill Newton }
2141f95f3850SWill Newton 
2142f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host)
2143f95f3850SWill Newton {
2144f95f3850SWill Newton 	/* Alloc memory for sg translation */
2145780f22afSSeungwon Jeon 	host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
2146f95f3850SWill Newton 					  &host->sg_dma, GFP_KERNEL);
2147f95f3850SWill Newton 	if (!host->sg_cpu) {
21484a90920cSThomas Abraham 		dev_err(host->dev, "%s: could not alloc DMA memory\n",
2149f95f3850SWill Newton 			__func__);
2150f95f3850SWill Newton 		goto no_dma;
2151f95f3850SWill Newton 	}
2152f95f3850SWill Newton 
2153f95f3850SWill Newton 	/* Determine which DMA interface to use */
2154f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
2155f95f3850SWill Newton 	host->dma_ops = &dw_mci_idmac_ops;
215600956ea3SSeungwon Jeon 	dev_info(host->dev, "Using internal DMA controller.\n");
2157f95f3850SWill Newton #endif
2158f95f3850SWill Newton 
2159f95f3850SWill Newton 	if (!host->dma_ops)
2160f95f3850SWill Newton 		goto no_dma;
2161f95f3850SWill Newton 
2162e1631f98SJaehoon Chung 	if (host->dma_ops->init && host->dma_ops->start &&
2163e1631f98SJaehoon Chung 	    host->dma_ops->stop && host->dma_ops->cleanup) {
2164f95f3850SWill Newton 		if (host->dma_ops->init(host)) {
21654a90920cSThomas Abraham 			dev_err(host->dev, "%s: Unable to initialize "
2166f95f3850SWill Newton 				"DMA Controller.\n", __func__);
2167f95f3850SWill Newton 			goto no_dma;
2168f95f3850SWill Newton 		}
2169f95f3850SWill Newton 	} else {
21704a90920cSThomas Abraham 		dev_err(host->dev, "DMA initialization not found.\n");
2171f95f3850SWill Newton 		goto no_dma;
2172f95f3850SWill Newton 	}
2173f95f3850SWill Newton 
2174f95f3850SWill Newton 	host->use_dma = 1;
2175f95f3850SWill Newton 	return;
2176f95f3850SWill Newton 
2177f95f3850SWill Newton no_dma:
21784a90920cSThomas Abraham 	dev_info(host->dev, "Using PIO mode.\n");
2179f95f3850SWill Newton 	host->use_dma = 0;
2180f95f3850SWill Newton 	return;
2181f95f3850SWill Newton }
2182f95f3850SWill Newton 
218331bff450SSeungwon Jeon static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset)
2184f95f3850SWill Newton {
2185f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
218631bff450SSeungwon Jeon 	u32 ctrl;
2187f95f3850SWill Newton 
218831bff450SSeungwon Jeon 	ctrl = mci_readl(host, CTRL);
218931bff450SSeungwon Jeon 	ctrl |= reset;
219031bff450SSeungwon Jeon 	mci_writel(host, CTRL, ctrl);
2191f95f3850SWill Newton 
2192f95f3850SWill Newton 	/* wait till resets clear */
2193f95f3850SWill Newton 	do {
2194f95f3850SWill Newton 		ctrl = mci_readl(host, CTRL);
219531bff450SSeungwon Jeon 		if (!(ctrl & reset))
2196f95f3850SWill Newton 			return true;
2197f95f3850SWill Newton 	} while (time_before(jiffies, timeout));
2198f95f3850SWill Newton 
219931bff450SSeungwon Jeon 	dev_err(host->dev,
220031bff450SSeungwon Jeon 		"Timeout resetting block (ctrl reset %#x)\n",
220131bff450SSeungwon Jeon 		ctrl & reset);
2202f95f3850SWill Newton 
2203f95f3850SWill Newton 	return false;
2204f95f3850SWill Newton }
2205f95f3850SWill Newton 
220631bff450SSeungwon Jeon static inline bool dw_mci_fifo_reset(struct dw_mci *host)
220731bff450SSeungwon Jeon {
220831bff450SSeungwon Jeon 	/*
220931bff450SSeungwon Jeon 	 * Reseting generates a block interrupt, hence setting
221031bff450SSeungwon Jeon 	 * the scatter-gather pointer to NULL.
221131bff450SSeungwon Jeon 	 */
221231bff450SSeungwon Jeon 	if (host->sg) {
221331bff450SSeungwon Jeon 		sg_miter_stop(&host->sg_miter);
221431bff450SSeungwon Jeon 		host->sg = NULL;
221531bff450SSeungwon Jeon 	}
221631bff450SSeungwon Jeon 
221731bff450SSeungwon Jeon 	return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET);
221831bff450SSeungwon Jeon }
221931bff450SSeungwon Jeon 
222031bff450SSeungwon Jeon static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host)
222131bff450SSeungwon Jeon {
222231bff450SSeungwon Jeon 	return dw_mci_ctrl_reset(host,
222331bff450SSeungwon Jeon 				 SDMMC_CTRL_FIFO_RESET |
222431bff450SSeungwon Jeon 				 SDMMC_CTRL_RESET |
222531bff450SSeungwon Jeon 				 SDMMC_CTRL_DMA_RESET);
222631bff450SSeungwon Jeon }
222731bff450SSeungwon Jeon 
2228c91eab4bSThomas Abraham #ifdef CONFIG_OF
2229c91eab4bSThomas Abraham static struct dw_mci_of_quirks {
2230c91eab4bSThomas Abraham 	char *quirk;
2231c91eab4bSThomas Abraham 	int id;
2232c91eab4bSThomas Abraham } of_quirks[] = {
2233c91eab4bSThomas Abraham 	{
2234c91eab4bSThomas Abraham 		.quirk	= "broken-cd",
2235c91eab4bSThomas Abraham 		.id	= DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
2236c91eab4bSThomas Abraham 	},
2237c91eab4bSThomas Abraham };
2238c91eab4bSThomas Abraham 
2239c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2240c91eab4bSThomas Abraham {
2241c91eab4bSThomas Abraham 	struct dw_mci_board *pdata;
2242c91eab4bSThomas Abraham 	struct device *dev = host->dev;
2243c91eab4bSThomas Abraham 	struct device_node *np = dev->of_node;
2244e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
2245800d78bfSThomas Abraham 	int idx, ret;
22463c6d89eaSDoug Anderson 	u32 clock_frequency;
2247c91eab4bSThomas Abraham 
2248c91eab4bSThomas Abraham 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
2249c91eab4bSThomas Abraham 	if (!pdata) {
2250c91eab4bSThomas Abraham 		dev_err(dev, "could not allocate memory for pdata\n");
2251c91eab4bSThomas Abraham 		return ERR_PTR(-ENOMEM);
2252c91eab4bSThomas Abraham 	}
2253c91eab4bSThomas Abraham 
2254c91eab4bSThomas Abraham 	/* find out number of slots supported */
2255c91eab4bSThomas Abraham 	if (of_property_read_u32(dev->of_node, "num-slots",
2256c91eab4bSThomas Abraham 				&pdata->num_slots)) {
2257c91eab4bSThomas Abraham 		dev_info(dev, "num-slots property not found, "
2258c91eab4bSThomas Abraham 				"assuming 1 slot is available\n");
2259c91eab4bSThomas Abraham 		pdata->num_slots = 1;
2260c91eab4bSThomas Abraham 	}
2261c91eab4bSThomas Abraham 
2262c91eab4bSThomas Abraham 	/* get quirks */
2263c91eab4bSThomas Abraham 	for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++)
2264c91eab4bSThomas Abraham 		if (of_get_property(np, of_quirks[idx].quirk, NULL))
2265c91eab4bSThomas Abraham 			pdata->quirks |= of_quirks[idx].id;
2266c91eab4bSThomas Abraham 
2267c91eab4bSThomas Abraham 	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
2268c91eab4bSThomas Abraham 		dev_info(dev, "fifo-depth property not found, using "
2269c91eab4bSThomas Abraham 				"value of FIFOTH register as default\n");
2270c91eab4bSThomas Abraham 
2271c91eab4bSThomas Abraham 	of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
2272c91eab4bSThomas Abraham 
22733c6d89eaSDoug Anderson 	if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
22743c6d89eaSDoug Anderson 		pdata->bus_hz = clock_frequency;
22753c6d89eaSDoug Anderson 
2276cb27a843SJames Hogan 	if (drv_data && drv_data->parse_dt) {
2277cb27a843SJames Hogan 		ret = drv_data->parse_dt(host);
2278800d78bfSThomas Abraham 		if (ret)
2279800d78bfSThomas Abraham 			return ERR_PTR(ret);
2280800d78bfSThomas Abraham 	}
2281800d78bfSThomas Abraham 
228210b49841SSeungwon Jeon 	if (of_find_property(np, "supports-highspeed", NULL))
228310b49841SSeungwon Jeon 		pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
228410b49841SSeungwon Jeon 
2285c91eab4bSThomas Abraham 	return pdata;
2286c91eab4bSThomas Abraham }
2287c91eab4bSThomas Abraham 
2288c91eab4bSThomas Abraham #else /* CONFIG_OF */
2289c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2290c91eab4bSThomas Abraham {
2291c91eab4bSThomas Abraham 	return ERR_PTR(-EINVAL);
2292c91eab4bSThomas Abraham }
2293c91eab4bSThomas Abraham #endif /* CONFIG_OF */
2294c91eab4bSThomas Abraham 
229562ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host)
2296f95f3850SWill Newton {
2297e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
229862ca8034SShashidhar Hiremath 	int width, i, ret = 0;
2299f95f3850SWill Newton 	u32 fifo_size;
23001c2215b7SThomas Abraham 	int init_slots = 0;
2301f95f3850SWill Newton 
2302c91eab4bSThomas Abraham 	if (!host->pdata) {
2303c91eab4bSThomas Abraham 		host->pdata = dw_mci_parse_dt(host);
2304c91eab4bSThomas Abraham 		if (IS_ERR(host->pdata)) {
2305c91eab4bSThomas Abraham 			dev_err(host->dev, "platform data not available\n");
2306c91eab4bSThomas Abraham 			return -EINVAL;
2307c91eab4bSThomas Abraham 		}
2308f95f3850SWill Newton 	}
2309f95f3850SWill Newton 
2310907abd51SJaehoon Chung 	if (host->pdata->num_slots > 1) {
23114a90920cSThomas Abraham 		dev_err(host->dev,
2312907abd51SJaehoon Chung 			"Platform data must supply num_slots.\n");
231362ca8034SShashidhar Hiremath 		return -ENODEV;
2314f95f3850SWill Newton 	}
2315f95f3850SWill Newton 
2316780f22afSSeungwon Jeon 	host->biu_clk = devm_clk_get(host->dev, "biu");
2317f90a0612SThomas Abraham 	if (IS_ERR(host->biu_clk)) {
2318f90a0612SThomas Abraham 		dev_dbg(host->dev, "biu clock not available\n");
2319f90a0612SThomas Abraham 	} else {
2320f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->biu_clk);
2321f90a0612SThomas Abraham 		if (ret) {
2322f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable biu clock\n");
2323f90a0612SThomas Abraham 			return ret;
2324f90a0612SThomas Abraham 		}
2325f95f3850SWill Newton 	}
2326f95f3850SWill Newton 
2327780f22afSSeungwon Jeon 	host->ciu_clk = devm_clk_get(host->dev, "ciu");
2328f90a0612SThomas Abraham 	if (IS_ERR(host->ciu_clk)) {
2329f90a0612SThomas Abraham 		dev_dbg(host->dev, "ciu clock not available\n");
23303c6d89eaSDoug Anderson 		host->bus_hz = host->pdata->bus_hz;
2331f90a0612SThomas Abraham 	} else {
2332f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->ciu_clk);
2333f90a0612SThomas Abraham 		if (ret) {
2334f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable ciu clock\n");
2335f90a0612SThomas Abraham 			goto err_clk_biu;
2336f90a0612SThomas Abraham 		}
2337f90a0612SThomas Abraham 
23383c6d89eaSDoug Anderson 		if (host->pdata->bus_hz) {
23393c6d89eaSDoug Anderson 			ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz);
23403c6d89eaSDoug Anderson 			if (ret)
23413c6d89eaSDoug Anderson 				dev_warn(host->dev,
2342612de4c1SJaehoon Chung 					 "Unable to set bus rate to %uHz\n",
23433c6d89eaSDoug Anderson 					 host->pdata->bus_hz);
23443c6d89eaSDoug Anderson 		}
2345f90a0612SThomas Abraham 		host->bus_hz = clk_get_rate(host->ciu_clk);
23463c6d89eaSDoug Anderson 	}
2347f90a0612SThomas Abraham 
2348612de4c1SJaehoon Chung 	if (!host->bus_hz) {
2349612de4c1SJaehoon Chung 		dev_err(host->dev,
2350612de4c1SJaehoon Chung 			"Platform data must supply bus speed\n");
2351612de4c1SJaehoon Chung 		ret = -ENODEV;
2352612de4c1SJaehoon Chung 		goto err_clk_ciu;
2353612de4c1SJaehoon Chung 	}
2354612de4c1SJaehoon Chung 
2355002f0d5cSYuvaraj Kumar C D 	if (drv_data && drv_data->init) {
2356002f0d5cSYuvaraj Kumar C D 		ret = drv_data->init(host);
2357002f0d5cSYuvaraj Kumar C D 		if (ret) {
2358002f0d5cSYuvaraj Kumar C D 			dev_err(host->dev,
2359002f0d5cSYuvaraj Kumar C D 				"implementation specific init failed\n");
2360002f0d5cSYuvaraj Kumar C D 			goto err_clk_ciu;
2361002f0d5cSYuvaraj Kumar C D 		}
2362002f0d5cSYuvaraj Kumar C D 	}
2363002f0d5cSYuvaraj Kumar C D 
2364cb27a843SJames Hogan 	if (drv_data && drv_data->setup_clock) {
2365cb27a843SJames Hogan 		ret = drv_data->setup_clock(host);
2366800d78bfSThomas Abraham 		if (ret) {
2367800d78bfSThomas Abraham 			dev_err(host->dev,
2368800d78bfSThomas Abraham 				"implementation specific clock setup failed\n");
2369800d78bfSThomas Abraham 			goto err_clk_ciu;
2370800d78bfSThomas Abraham 		}
2371800d78bfSThomas Abraham 	}
2372800d78bfSThomas Abraham 
2373a55d6ff0SMark Brown 	host->vmmc = devm_regulator_get_optional(host->dev, "vmmc");
2374870556a3SDoug Anderson 	if (IS_ERR(host->vmmc)) {
2375870556a3SDoug Anderson 		ret = PTR_ERR(host->vmmc);
2376870556a3SDoug Anderson 		if (ret == -EPROBE_DEFER)
2377870556a3SDoug Anderson 			goto err_clk_ciu;
2378870556a3SDoug Anderson 
2379870556a3SDoug Anderson 		dev_info(host->dev, "no vmmc regulator found: %d\n", ret);
2380870556a3SDoug Anderson 		host->vmmc = NULL;
2381870556a3SDoug Anderson 	} else {
2382870556a3SDoug Anderson 		ret = regulator_enable(host->vmmc);
2383870556a3SDoug Anderson 		if (ret) {
2384870556a3SDoug Anderson 			if (ret != -EPROBE_DEFER)
2385870556a3SDoug Anderson 				dev_err(host->dev,
2386870556a3SDoug Anderson 					"regulator_enable fail: %d\n", ret);
2387870556a3SDoug Anderson 			goto err_clk_ciu;
2388870556a3SDoug Anderson 		}
2389870556a3SDoug Anderson 	}
2390870556a3SDoug Anderson 
239162ca8034SShashidhar Hiremath 	host->quirks = host->pdata->quirks;
2392f95f3850SWill Newton 
2393f95f3850SWill Newton 	spin_lock_init(&host->lock);
2394f95f3850SWill Newton 	INIT_LIST_HEAD(&host->queue);
2395f95f3850SWill Newton 
2396f95f3850SWill Newton 	/*
2397f95f3850SWill Newton 	 * Get the host data width - this assumes that HCON has been set with
2398f95f3850SWill Newton 	 * the correct values.
2399f95f3850SWill Newton 	 */
2400f95f3850SWill Newton 	i = (mci_readl(host, HCON) >> 7) & 0x7;
2401f95f3850SWill Newton 	if (!i) {
2402f95f3850SWill Newton 		host->push_data = dw_mci_push_data16;
2403f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data16;
2404f95f3850SWill Newton 		width = 16;
2405f95f3850SWill Newton 		host->data_shift = 1;
2406f95f3850SWill Newton 	} else if (i == 2) {
2407f95f3850SWill Newton 		host->push_data = dw_mci_push_data64;
2408f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data64;
2409f95f3850SWill Newton 		width = 64;
2410f95f3850SWill Newton 		host->data_shift = 3;
2411f95f3850SWill Newton 	} else {
2412f95f3850SWill Newton 		/* Check for a reserved value, and warn if it is */
2413f95f3850SWill Newton 		WARN((i != 1),
2414f95f3850SWill Newton 		     "HCON reports a reserved host data width!\n"
2415f95f3850SWill Newton 		     "Defaulting to 32-bit access.\n");
2416f95f3850SWill Newton 		host->push_data = dw_mci_push_data32;
2417f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data32;
2418f95f3850SWill Newton 		width = 32;
2419f95f3850SWill Newton 		host->data_shift = 2;
2420f95f3850SWill Newton 	}
2421f95f3850SWill Newton 
2422f95f3850SWill Newton 	/* Reset all blocks */
242331bff450SSeungwon Jeon 	if (!dw_mci_ctrl_all_reset(host))
2424141a712aSSeungwon Jeon 		return -ENODEV;
2425141a712aSSeungwon Jeon 
2426141a712aSSeungwon Jeon 	host->dma_ops = host->pdata->dma_ops;
2427141a712aSSeungwon Jeon 	dw_mci_init_dma(host);
2428f95f3850SWill Newton 
2429f95f3850SWill Newton 	/* Clear the interrupts for the host controller */
2430f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2431f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2432f95f3850SWill Newton 
2433f95f3850SWill Newton 	/* Put in max timeout */
2434f95f3850SWill Newton 	mci_writel(host, TMOUT, 0xFFFFFFFF);
2435f95f3850SWill Newton 
2436f95f3850SWill Newton 	/*
2437f95f3850SWill Newton 	 * FIFO threshold settings  RxMark  = fifo_size / 2 - 1,
2438f95f3850SWill Newton 	 *                          Tx Mark = fifo_size / 2 DMA Size = 8
2439f95f3850SWill Newton 	 */
2440b86d8253SJames Hogan 	if (!host->pdata->fifo_depth) {
2441b86d8253SJames Hogan 		/*
2442b86d8253SJames Hogan 		 * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may
2443b86d8253SJames Hogan 		 * have been overwritten by the bootloader, just like we're
2444b86d8253SJames Hogan 		 * about to do, so if you know the value for your hardware, you
2445b86d8253SJames Hogan 		 * should put it in the platform data.
2446b86d8253SJames Hogan 		 */
2447f95f3850SWill Newton 		fifo_size = mci_readl(host, FIFOTH);
24488234e869SJaehoon Chung 		fifo_size = 1 + ((fifo_size >> 16) & 0xfff);
2449b86d8253SJames Hogan 	} else {
2450b86d8253SJames Hogan 		fifo_size = host->pdata->fifo_depth;
2451b86d8253SJames Hogan 	}
2452b86d8253SJames Hogan 	host->fifo_depth = fifo_size;
245352426899SSeungwon Jeon 	host->fifoth_val =
245452426899SSeungwon Jeon 		SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2);
2455e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
2456f95f3850SWill Newton 
2457f95f3850SWill Newton 	/* disable clock to CIU */
2458f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2459f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2460f95f3850SWill Newton 
246163008768SJames Hogan 	/*
246263008768SJames Hogan 	 * In 2.40a spec, Data offset is changed.
246363008768SJames Hogan 	 * Need to check the version-id and set data-offset for DATA register.
246463008768SJames Hogan 	 */
246563008768SJames Hogan 	host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
246663008768SJames Hogan 	dev_info(host->dev, "Version ID is %04x\n", host->verid);
246763008768SJames Hogan 
246863008768SJames Hogan 	if (host->verid < DW_MMC_240A)
246963008768SJames Hogan 		host->data_offset = DATA_OFFSET;
247063008768SJames Hogan 	else
247163008768SJames Hogan 		host->data_offset = DATA_240A_OFFSET;
247263008768SJames Hogan 
2473f95f3850SWill Newton 	tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
247495dcc2cbSThomas Abraham 	host->card_workqueue = alloc_workqueue("dw-mci-card",
247559ff3eb6SZhangZhen 			WQ_MEM_RECLAIM, 1);
2476ef7aef9aSWei Yongjun 	if (!host->card_workqueue) {
2477ef7aef9aSWei Yongjun 		ret = -ENOMEM;
24781791b13eSJames Hogan 		goto err_dmaunmap;
2479ef7aef9aSWei Yongjun 	}
24801791b13eSJames Hogan 	INIT_WORK(&host->card_work, dw_mci_work_routine_card);
2481780f22afSSeungwon Jeon 	ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
2482780f22afSSeungwon Jeon 			       host->irq_flags, "dw-mci", host);
2483f95f3850SWill Newton 	if (ret)
24841791b13eSJames Hogan 		goto err_workqueue;
2485f95f3850SWill Newton 
2486f95f3850SWill Newton 	if (host->pdata->num_slots)
2487f95f3850SWill Newton 		host->num_slots = host->pdata->num_slots;
2488f95f3850SWill Newton 	else
2489f95f3850SWill Newton 		host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1;
2490f95f3850SWill Newton 
24912da1d7f2SYuvaraj CD 	/*
24922da1d7f2SYuvaraj CD 	 * Enable interrupts for command done, data over, data empty, card det,
24932da1d7f2SYuvaraj CD 	 * receive ready and error such as transmit, receive timeout, crc error
24942da1d7f2SYuvaraj CD 	 */
24952da1d7f2SYuvaraj CD 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
24962da1d7f2SYuvaraj CD 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
24972da1d7f2SYuvaraj CD 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
24982da1d7f2SYuvaraj CD 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
24992da1d7f2SYuvaraj CD 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
25002da1d7f2SYuvaraj CD 
25012da1d7f2SYuvaraj CD 	dev_info(host->dev, "DW MMC controller at irq %d, "
25022da1d7f2SYuvaraj CD 		 "%d bit host data width, "
25032da1d7f2SYuvaraj CD 		 "%u deep fifo\n",
25042da1d7f2SYuvaraj CD 		 host->irq, width, fifo_size);
25052da1d7f2SYuvaraj CD 
2506f95f3850SWill Newton 	/* We need at least one slot to succeed */
2507f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2508f95f3850SWill Newton 		ret = dw_mci_init_slot(host, i);
25091c2215b7SThomas Abraham 		if (ret)
25101c2215b7SThomas Abraham 			dev_dbg(host->dev, "slot %d init failed\n", i);
25111c2215b7SThomas Abraham 		else
25121c2215b7SThomas Abraham 			init_slots++;
2513f95f3850SWill Newton 	}
25141c2215b7SThomas Abraham 
25151c2215b7SThomas Abraham 	if (init_slots) {
25161c2215b7SThomas Abraham 		dev_info(host->dev, "%d slots initialized\n", init_slots);
25171c2215b7SThomas Abraham 	} else {
25181c2215b7SThomas Abraham 		dev_dbg(host->dev, "attempted to initialize %d slots, "
25191c2215b7SThomas Abraham 					"but failed on all\n", host->num_slots);
2520780f22afSSeungwon Jeon 		goto err_workqueue;
2521f95f3850SWill Newton 	}
2522f95f3850SWill Newton 
2523f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
25244a90920cSThomas Abraham 		dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
2525f95f3850SWill Newton 
2526f95f3850SWill Newton 	return 0;
2527f95f3850SWill Newton 
25281791b13eSJames Hogan err_workqueue:
252995dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
25301791b13eSJames Hogan 
2531f95f3850SWill Newton err_dmaunmap:
2532f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2533f95f3850SWill Newton 		host->dma_ops->exit(host);
2534780f22afSSeungwon Jeon 	if (host->vmmc)
2535c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2536f90a0612SThomas Abraham 
2537f90a0612SThomas Abraham err_clk_ciu:
2538780f22afSSeungwon Jeon 	if (!IS_ERR(host->ciu_clk))
2539f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2540780f22afSSeungwon Jeon 
2541f90a0612SThomas Abraham err_clk_biu:
2542780f22afSSeungwon Jeon 	if (!IS_ERR(host->biu_clk))
2543f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2544780f22afSSeungwon Jeon 
2545f95f3850SWill Newton 	return ret;
2546f95f3850SWill Newton }
254762ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe);
2548f95f3850SWill Newton 
254962ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host)
2550f95f3850SWill Newton {
2551f95f3850SWill Newton 	int i;
2552f95f3850SWill Newton 
2553f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2554f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2555f95f3850SWill Newton 
2556f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
25574a90920cSThomas Abraham 		dev_dbg(host->dev, "remove slot %d\n", i);
2558f95f3850SWill Newton 		if (host->slot[i])
2559f95f3850SWill Newton 			dw_mci_cleanup_slot(host->slot[i], i);
2560f95f3850SWill Newton 	}
2561f95f3850SWill Newton 
2562f95f3850SWill Newton 	/* disable clock to CIU */
2563f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2564f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2565f95f3850SWill Newton 
256695dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
2567f95f3850SWill Newton 
2568f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2569f95f3850SWill Newton 		host->dma_ops->exit(host);
2570f95f3850SWill Newton 
2571780f22afSSeungwon Jeon 	if (host->vmmc)
2572c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2573c07946a3SJaehoon Chung 
2574f90a0612SThomas Abraham 	if (!IS_ERR(host->ciu_clk))
2575f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2576780f22afSSeungwon Jeon 
2577f90a0612SThomas Abraham 	if (!IS_ERR(host->biu_clk))
2578f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2579f95f3850SWill Newton }
258062ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove);
258162ca8034SShashidhar Hiremath 
258262ca8034SShashidhar Hiremath 
2583f95f3850SWill Newton 
25846fe8890dSJaehoon Chung #ifdef CONFIG_PM_SLEEP
2585f95f3850SWill Newton /*
2586f95f3850SWill Newton  * TODO: we should probably disable the clock to the card in the suspend path.
2587f95f3850SWill Newton  */
258862ca8034SShashidhar Hiremath int dw_mci_suspend(struct dw_mci *host)
2589f95f3850SWill Newton {
2590c07946a3SJaehoon Chung 	if (host->vmmc)
2591c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2592c07946a3SJaehoon Chung 
2593f95f3850SWill Newton 	return 0;
2594f95f3850SWill Newton }
259562ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_suspend);
2596f95f3850SWill Newton 
259762ca8034SShashidhar Hiremath int dw_mci_resume(struct dw_mci *host)
2598f95f3850SWill Newton {
2599f95f3850SWill Newton 	int i, ret;
2600f95f3850SWill Newton 
2601f2f942ceSSachin Kamat 	if (host->vmmc) {
2602f2f942ceSSachin Kamat 		ret = regulator_enable(host->vmmc);
2603f2f942ceSSachin Kamat 		if (ret) {
2604f2f942ceSSachin Kamat 			dev_err(host->dev,
2605f2f942ceSSachin Kamat 				"failed to enable regulator: %d\n", ret);
2606f2f942ceSSachin Kamat 			return ret;
2607f2f942ceSSachin Kamat 		}
2608f2f942ceSSachin Kamat 	}
26091d6c4e0aSJaehoon Chung 
261031bff450SSeungwon Jeon 	if (!dw_mci_ctrl_all_reset(host)) {
2611e61cf118SJaehoon Chung 		ret = -ENODEV;
2612e61cf118SJaehoon Chung 		return ret;
2613e61cf118SJaehoon Chung 	}
2614e61cf118SJaehoon Chung 
26153bfe619dSJonathan Kliegman 	if (host->use_dma && host->dma_ops->init)
2616141a712aSSeungwon Jeon 		host->dma_ops->init(host);
2617141a712aSSeungwon Jeon 
261852426899SSeungwon Jeon 	/*
261952426899SSeungwon Jeon 	 * Restore the initial value at FIFOTH register
262052426899SSeungwon Jeon 	 * And Invalidate the prev_blksz with zero
262152426899SSeungwon Jeon 	 */
2622e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
262352426899SSeungwon Jeon 	host->prev_blksz = 0;
2624e61cf118SJaehoon Chung 
26252eb2944fSDoug Anderson 	/* Put in max timeout */
26262eb2944fSDoug Anderson 	mci_writel(host, TMOUT, 0xFFFFFFFF);
26272eb2944fSDoug Anderson 
2628e61cf118SJaehoon Chung 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2629e61cf118SJaehoon Chung 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
2630e61cf118SJaehoon Chung 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
2631e61cf118SJaehoon Chung 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
2632e61cf118SJaehoon Chung 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
2633e61cf118SJaehoon Chung 
2634f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2635f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
2636f95f3850SWill Newton 		if (!slot)
2637f95f3850SWill Newton 			continue;
2638ab269128SAbhilash Kesavan 		if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
2639ab269128SAbhilash Kesavan 			dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
2640ab269128SAbhilash Kesavan 			dw_mci_setup_bus(slot, true);
2641ab269128SAbhilash Kesavan 		}
2642f95f3850SWill Newton 	}
2643f95f3850SWill Newton 	return 0;
2644f95f3850SWill Newton }
264562ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_resume);
26466fe8890dSJaehoon Chung #endif /* CONFIG_PM_SLEEP */
26476fe8890dSJaehoon Chung 
2648f95f3850SWill Newton static int __init dw_mci_init(void)
2649f95f3850SWill Newton {
26508e1c4e4dSSachin Kamat 	pr_info("Synopsys Designware Multimedia Card Interface Driver\n");
265162ca8034SShashidhar Hiremath 	return 0;
2652f95f3850SWill Newton }
2653f95f3850SWill Newton 
2654f95f3850SWill Newton static void __exit dw_mci_exit(void)
2655f95f3850SWill Newton {
2656f95f3850SWill Newton }
2657f95f3850SWill Newton 
2658f95f3850SWill Newton module_init(dw_mci_init);
2659f95f3850SWill Newton module_exit(dw_mci_exit);
2660f95f3850SWill Newton 
2661f95f3850SWill Newton MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
2662f95f3850SWill Newton MODULE_AUTHOR("NXP Semiconductor VietNam");
2663f95f3850SWill Newton MODULE_AUTHOR("Imagination Technologies Ltd");
2664f95f3850SWill Newton MODULE_LICENSE("GPL v2");
2665