xref: /linux/drivers/mmc/host/dw_mmc.c (revision 4a1b27ad3463736aebe9ccd4ae7ee10b24060977)
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 void dw_mci_set_timeout(struct dw_mci *host)
239f95f3850SWill Newton {
240f95f3850SWill Newton 	/* timeout (maximum) */
241f95f3850SWill Newton 	mci_writel(host, TMOUT, 0xffffffff);
242f95f3850SWill Newton }
243f95f3850SWill Newton 
244f95f3850SWill Newton static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
245f95f3850SWill Newton {
246f95f3850SWill Newton 	struct mmc_data	*data;
247800d78bfSThomas Abraham 	struct dw_mci_slot *slot = mmc_priv(mmc);
248e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
249f95f3850SWill Newton 	u32 cmdr;
250f95f3850SWill Newton 	cmd->error = -EINPROGRESS;
251f95f3850SWill Newton 
252f95f3850SWill Newton 	cmdr = cmd->opcode;
253f95f3850SWill Newton 
25490c2143aSSeungwon Jeon 	if (cmd->opcode == MMC_STOP_TRANSMISSION ||
25590c2143aSSeungwon Jeon 	    cmd->opcode == MMC_GO_IDLE_STATE ||
25690c2143aSSeungwon Jeon 	    cmd->opcode == MMC_GO_INACTIVE_STATE ||
25790c2143aSSeungwon Jeon 	    (cmd->opcode == SD_IO_RW_DIRECT &&
25890c2143aSSeungwon Jeon 	     ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT))
259f95f3850SWill Newton 		cmdr |= SDMMC_CMD_STOP;
260*4a1b27adSJaehoon Chung 	else if (cmd->opcode != MMC_SEND_STATUS && cmd->data)
261f95f3850SWill Newton 		cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
262f95f3850SWill Newton 
263f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_PRESENT) {
264f95f3850SWill Newton 		/* We expect a response, so set this bit */
265f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_EXP;
266f95f3850SWill Newton 		if (cmd->flags & MMC_RSP_136)
267f95f3850SWill Newton 			cmdr |= SDMMC_CMD_RESP_LONG;
268f95f3850SWill Newton 	}
269f95f3850SWill Newton 
270f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_CRC)
271f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_CRC;
272f95f3850SWill Newton 
273f95f3850SWill Newton 	data = cmd->data;
274f95f3850SWill Newton 	if (data) {
275f95f3850SWill Newton 		cmdr |= SDMMC_CMD_DAT_EXP;
276f95f3850SWill Newton 		if (data->flags & MMC_DATA_STREAM)
277f95f3850SWill Newton 			cmdr |= SDMMC_CMD_STRM_MODE;
278f95f3850SWill Newton 		if (data->flags & MMC_DATA_WRITE)
279f95f3850SWill Newton 			cmdr |= SDMMC_CMD_DAT_WR;
280f95f3850SWill Newton 	}
281f95f3850SWill Newton 
282cb27a843SJames Hogan 	if (drv_data && drv_data->prepare_command)
283cb27a843SJames Hogan 		drv_data->prepare_command(slot->host, &cmdr);
284800d78bfSThomas Abraham 
285f95f3850SWill Newton 	return cmdr;
286f95f3850SWill Newton }
287f95f3850SWill Newton 
28890c2143aSSeungwon Jeon static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
28990c2143aSSeungwon Jeon {
29090c2143aSSeungwon Jeon 	struct mmc_command *stop;
29190c2143aSSeungwon Jeon 	u32 cmdr;
29290c2143aSSeungwon Jeon 
29390c2143aSSeungwon Jeon 	if (!cmd->data)
29490c2143aSSeungwon Jeon 		return 0;
29590c2143aSSeungwon Jeon 
29690c2143aSSeungwon Jeon 	stop = &host->stop_abort;
29790c2143aSSeungwon Jeon 	cmdr = cmd->opcode;
29890c2143aSSeungwon Jeon 	memset(stop, 0, sizeof(struct mmc_command));
29990c2143aSSeungwon Jeon 
30090c2143aSSeungwon Jeon 	if (cmdr == MMC_READ_SINGLE_BLOCK ||
30190c2143aSSeungwon Jeon 	    cmdr == MMC_READ_MULTIPLE_BLOCK ||
30290c2143aSSeungwon Jeon 	    cmdr == MMC_WRITE_BLOCK ||
30390c2143aSSeungwon Jeon 	    cmdr == MMC_WRITE_MULTIPLE_BLOCK) {
30490c2143aSSeungwon Jeon 		stop->opcode = MMC_STOP_TRANSMISSION;
30590c2143aSSeungwon Jeon 		stop->arg = 0;
30690c2143aSSeungwon Jeon 		stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
30790c2143aSSeungwon Jeon 	} else if (cmdr == SD_IO_RW_EXTENDED) {
30890c2143aSSeungwon Jeon 		stop->opcode = SD_IO_RW_DIRECT;
30990c2143aSSeungwon Jeon 		stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) |
31090c2143aSSeungwon Jeon 			     ((cmd->arg >> 28) & 0x7);
31190c2143aSSeungwon Jeon 		stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
31290c2143aSSeungwon Jeon 	} else {
31390c2143aSSeungwon Jeon 		return 0;
31490c2143aSSeungwon Jeon 	}
31590c2143aSSeungwon Jeon 
31690c2143aSSeungwon Jeon 	cmdr = stop->opcode | SDMMC_CMD_STOP |
31790c2143aSSeungwon Jeon 		SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP;
31890c2143aSSeungwon Jeon 
31990c2143aSSeungwon Jeon 	return cmdr;
32090c2143aSSeungwon Jeon }
32190c2143aSSeungwon Jeon 
322f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host,
323f95f3850SWill Newton 				 struct mmc_command *cmd, u32 cmd_flags)
324f95f3850SWill Newton {
325f95f3850SWill Newton 	host->cmd = cmd;
3264a90920cSThomas Abraham 	dev_vdbg(host->dev,
327f95f3850SWill Newton 		 "start command: ARGR=0x%08x CMDR=0x%08x\n",
328f95f3850SWill Newton 		 cmd->arg, cmd_flags);
329f95f3850SWill Newton 
330f95f3850SWill Newton 	mci_writel(host, CMDARG, cmd->arg);
331f95f3850SWill Newton 	wmb();
332f95f3850SWill Newton 
333f95f3850SWill Newton 	mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
334f95f3850SWill Newton }
335f95f3850SWill Newton 
33690c2143aSSeungwon Jeon static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data)
337f95f3850SWill Newton {
33890c2143aSSeungwon Jeon 	struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort;
33990c2143aSSeungwon Jeon 	dw_mci_start_command(host, stop, host->stop_cmdr);
340f95f3850SWill Newton }
341f95f3850SWill Newton 
342f95f3850SWill Newton /* DMA interface functions */
343f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host)
344f95f3850SWill Newton {
34503e8cb53SJames Hogan 	if (host->using_dma) {
346f95f3850SWill Newton 		host->dma_ops->stop(host);
347f95f3850SWill Newton 		host->dma_ops->cleanup(host);
348aa50f259SSeungwon Jeon 	}
349aa50f259SSeungwon Jeon 
350f95f3850SWill Newton 	/* Data transfer was stopped by the interrupt handler */
351f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
352f95f3850SWill Newton }
353f95f3850SWill Newton 
3549aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data)
3559aa51408SSeungwon Jeon {
3569aa51408SSeungwon Jeon 	if (data->flags & MMC_DATA_WRITE)
3579aa51408SSeungwon Jeon 		return DMA_TO_DEVICE;
3589aa51408SSeungwon Jeon 	else
3599aa51408SSeungwon Jeon 		return DMA_FROM_DEVICE;
3609aa51408SSeungwon Jeon }
3619aa51408SSeungwon Jeon 
3629beee912SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
363f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host)
364f95f3850SWill Newton {
365f95f3850SWill Newton 	struct mmc_data *data = host->data;
366f95f3850SWill Newton 
367f95f3850SWill Newton 	if (data)
3689aa51408SSeungwon Jeon 		if (!data->host_cookie)
3694a90920cSThomas Abraham 			dma_unmap_sg(host->dev,
3709aa51408SSeungwon Jeon 				     data->sg,
3719aa51408SSeungwon Jeon 				     data->sg_len,
3729aa51408SSeungwon Jeon 				     dw_mci_get_dma_dir(data));
373f95f3850SWill Newton }
374f95f3850SWill Newton 
3755ce9d961SSeungwon Jeon static void dw_mci_idmac_reset(struct dw_mci *host)
3765ce9d961SSeungwon Jeon {
3775ce9d961SSeungwon Jeon 	u32 bmod = mci_readl(host, BMOD);
3785ce9d961SSeungwon Jeon 	/* Software reset of DMA */
3795ce9d961SSeungwon Jeon 	bmod |= SDMMC_IDMAC_SWRESET;
3805ce9d961SSeungwon Jeon 	mci_writel(host, BMOD, bmod);
3815ce9d961SSeungwon Jeon }
3825ce9d961SSeungwon Jeon 
383f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host)
384f95f3850SWill Newton {
385f95f3850SWill Newton 	u32 temp;
386f95f3850SWill Newton 
387f95f3850SWill Newton 	/* Disable and reset the IDMAC interface */
388f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
389f95f3850SWill Newton 	temp &= ~SDMMC_CTRL_USE_IDMAC;
390f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_RESET;
391f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
392f95f3850SWill Newton 
393f95f3850SWill Newton 	/* Stop the IDMAC running */
394f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
395a5289a43SJaehoon Chung 	temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB);
3965ce9d961SSeungwon Jeon 	temp |= SDMMC_IDMAC_SWRESET;
397f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
398f95f3850SWill Newton }
399f95f3850SWill Newton 
400f95f3850SWill Newton static void dw_mci_idmac_complete_dma(struct dw_mci *host)
401f95f3850SWill Newton {
402f95f3850SWill Newton 	struct mmc_data *data = host->data;
403f95f3850SWill Newton 
4044a90920cSThomas Abraham 	dev_vdbg(host->dev, "DMA complete\n");
405f95f3850SWill Newton 
406f95f3850SWill Newton 	host->dma_ops->cleanup(host);
407f95f3850SWill Newton 
408f95f3850SWill Newton 	/*
409f95f3850SWill Newton 	 * If the card was removed, data will be NULL. No point in trying to
410f95f3850SWill Newton 	 * send the stop command or waiting for NBUSY in this case.
411f95f3850SWill Newton 	 */
412f95f3850SWill Newton 	if (data) {
413f95f3850SWill Newton 		set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
414f95f3850SWill Newton 		tasklet_schedule(&host->tasklet);
415f95f3850SWill Newton 	}
416f95f3850SWill Newton }
417f95f3850SWill Newton 
418f95f3850SWill Newton static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
419f95f3850SWill Newton 				    unsigned int sg_len)
420f95f3850SWill Newton {
421f95f3850SWill Newton 	int i;
422f95f3850SWill Newton 	struct idmac_desc *desc = host->sg_cpu;
423f95f3850SWill Newton 
424f95f3850SWill Newton 	for (i = 0; i < sg_len; i++, desc++) {
425f95f3850SWill Newton 		unsigned int length = sg_dma_len(&data->sg[i]);
426f95f3850SWill Newton 		u32 mem_addr = sg_dma_address(&data->sg[i]);
427f95f3850SWill Newton 
428f95f3850SWill Newton 		/* Set the OWN bit and disable interrupts for this descriptor */
429f95f3850SWill Newton 		desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH;
430f95f3850SWill Newton 
431f95f3850SWill Newton 		/* Buffer length */
432f95f3850SWill Newton 		IDMAC_SET_BUFFER1_SIZE(desc, length);
433f95f3850SWill Newton 
434f95f3850SWill Newton 		/* Physical address to DMA to/from */
435f95f3850SWill Newton 		desc->des2 = mem_addr;
436f95f3850SWill Newton 	}
437f95f3850SWill Newton 
438f95f3850SWill Newton 	/* Set first descriptor */
439f95f3850SWill Newton 	desc = host->sg_cpu;
440f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_FD;
441f95f3850SWill Newton 
442f95f3850SWill Newton 	/* Set last descriptor */
443f95f3850SWill Newton 	desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
444f95f3850SWill Newton 	desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
445f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_LD;
446f95f3850SWill Newton 
447f95f3850SWill Newton 	wmb();
448f95f3850SWill Newton }
449f95f3850SWill Newton 
450f95f3850SWill Newton static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
451f95f3850SWill Newton {
452f95f3850SWill Newton 	u32 temp;
453f95f3850SWill Newton 
454f95f3850SWill Newton 	dw_mci_translate_sglist(host, host->data, sg_len);
455f95f3850SWill Newton 
456f95f3850SWill Newton 	/* Select IDMAC interface */
457f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
458f95f3850SWill Newton 	temp |= SDMMC_CTRL_USE_IDMAC;
459f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
460f95f3850SWill Newton 
461f95f3850SWill Newton 	wmb();
462f95f3850SWill Newton 
463f95f3850SWill Newton 	/* Enable the IDMAC */
464f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
465a5289a43SJaehoon Chung 	temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB;
466f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
467f95f3850SWill Newton 
468f95f3850SWill Newton 	/* Start it running */
469f95f3850SWill Newton 	mci_writel(host, PLDMND, 1);
470f95f3850SWill Newton }
471f95f3850SWill Newton 
472f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host)
473f95f3850SWill Newton {
474f95f3850SWill Newton 	struct idmac_desc *p;
475897b69e7SSeungwon Jeon 	int i;
476f95f3850SWill Newton 
477f95f3850SWill Newton 	/* Number of descriptors in the ring buffer */
478f95f3850SWill Newton 	host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
479f95f3850SWill Newton 
480f95f3850SWill Newton 	/* Forward link the descriptor list */
481f95f3850SWill Newton 	for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
482f95f3850SWill Newton 		p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
483f95f3850SWill Newton 
484f95f3850SWill Newton 	/* Set the last descriptor as the end-of-ring descriptor */
485f95f3850SWill Newton 	p->des3 = host->sg_dma;
486f95f3850SWill Newton 	p->des0 = IDMAC_DES0_ER;
487f95f3850SWill Newton 
4885ce9d961SSeungwon Jeon 	dw_mci_idmac_reset(host);
489141a712aSSeungwon Jeon 
490f95f3850SWill Newton 	/* Mask out interrupts - get Tx & Rx complete only */
491fc79a4d6SJoonyoung Shim 	mci_writel(host, IDSTS, IDMAC_INT_CLR);
492f95f3850SWill Newton 	mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
493f95f3850SWill Newton 		   SDMMC_IDMAC_INT_TI);
494f95f3850SWill Newton 
495f95f3850SWill Newton 	/* Set the descriptor base address */
496f95f3850SWill Newton 	mci_writel(host, DBADDR, host->sg_dma);
497f95f3850SWill Newton 	return 0;
498f95f3850SWill Newton }
499f95f3850SWill Newton 
5008e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = {
501885c3e80SSeungwon Jeon 	.init = dw_mci_idmac_init,
502885c3e80SSeungwon Jeon 	.start = dw_mci_idmac_start_dma,
503885c3e80SSeungwon Jeon 	.stop = dw_mci_idmac_stop_dma,
504885c3e80SSeungwon Jeon 	.complete = dw_mci_idmac_complete_dma,
505885c3e80SSeungwon Jeon 	.cleanup = dw_mci_dma_cleanup,
506885c3e80SSeungwon Jeon };
507885c3e80SSeungwon Jeon #endif /* CONFIG_MMC_DW_IDMAC */
508885c3e80SSeungwon Jeon 
5099aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host,
5109aa51408SSeungwon Jeon 				   struct mmc_data *data,
5119aa51408SSeungwon Jeon 				   bool next)
512f95f3850SWill Newton {
513f95f3850SWill Newton 	struct scatterlist *sg;
5149aa51408SSeungwon Jeon 	unsigned int i, sg_len;
515f95f3850SWill Newton 
5169aa51408SSeungwon Jeon 	if (!next && data->host_cookie)
5179aa51408SSeungwon Jeon 		return data->host_cookie;
518f95f3850SWill Newton 
519f95f3850SWill Newton 	/*
520f95f3850SWill Newton 	 * We don't do DMA on "complex" transfers, i.e. with
521f95f3850SWill Newton 	 * non-word-aligned buffers or lengths. Also, we don't bother
522f95f3850SWill Newton 	 * with all the DMA setup overhead for short transfers.
523f95f3850SWill Newton 	 */
524f95f3850SWill Newton 	if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD)
525f95f3850SWill Newton 		return -EINVAL;
5269aa51408SSeungwon Jeon 
527f95f3850SWill Newton 	if (data->blksz & 3)
528f95f3850SWill Newton 		return -EINVAL;
529f95f3850SWill Newton 
530f95f3850SWill Newton 	for_each_sg(data->sg, sg, data->sg_len, i) {
531f95f3850SWill Newton 		if (sg->offset & 3 || sg->length & 3)
532f95f3850SWill Newton 			return -EINVAL;
533f95f3850SWill Newton 	}
534f95f3850SWill Newton 
5354a90920cSThomas Abraham 	sg_len = dma_map_sg(host->dev,
5369aa51408SSeungwon Jeon 			    data->sg,
5379aa51408SSeungwon Jeon 			    data->sg_len,
5389aa51408SSeungwon Jeon 			    dw_mci_get_dma_dir(data));
5399aa51408SSeungwon Jeon 	if (sg_len == 0)
5409aa51408SSeungwon Jeon 		return -EINVAL;
5419aa51408SSeungwon Jeon 
5429aa51408SSeungwon Jeon 	if (next)
5439aa51408SSeungwon Jeon 		data->host_cookie = sg_len;
5449aa51408SSeungwon Jeon 
5459aa51408SSeungwon Jeon 	return sg_len;
5469aa51408SSeungwon Jeon }
5479aa51408SSeungwon Jeon 
5489aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc,
5499aa51408SSeungwon Jeon 			   struct mmc_request *mrq,
5509aa51408SSeungwon Jeon 			   bool is_first_req)
5519aa51408SSeungwon Jeon {
5529aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
5539aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
5549aa51408SSeungwon Jeon 
5559aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
5569aa51408SSeungwon Jeon 		return;
5579aa51408SSeungwon Jeon 
5589aa51408SSeungwon Jeon 	if (data->host_cookie) {
5599aa51408SSeungwon Jeon 		data->host_cookie = 0;
5609aa51408SSeungwon Jeon 		return;
5619aa51408SSeungwon Jeon 	}
5629aa51408SSeungwon Jeon 
5639aa51408SSeungwon Jeon 	if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0)
5649aa51408SSeungwon Jeon 		data->host_cookie = 0;
5659aa51408SSeungwon Jeon }
5669aa51408SSeungwon Jeon 
5679aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc,
5689aa51408SSeungwon Jeon 			    struct mmc_request *mrq,
5699aa51408SSeungwon Jeon 			    int err)
5709aa51408SSeungwon Jeon {
5719aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
5729aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
5739aa51408SSeungwon Jeon 
5749aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
5759aa51408SSeungwon Jeon 		return;
5769aa51408SSeungwon Jeon 
5779aa51408SSeungwon Jeon 	if (data->host_cookie)
5784a90920cSThomas Abraham 		dma_unmap_sg(slot->host->dev,
5799aa51408SSeungwon Jeon 			     data->sg,
5809aa51408SSeungwon Jeon 			     data->sg_len,
5819aa51408SSeungwon Jeon 			     dw_mci_get_dma_dir(data));
5829aa51408SSeungwon Jeon 	data->host_cookie = 0;
5839aa51408SSeungwon Jeon }
5849aa51408SSeungwon Jeon 
58552426899SSeungwon Jeon static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
58652426899SSeungwon Jeon {
58752426899SSeungwon Jeon #ifdef CONFIG_MMC_DW_IDMAC
58852426899SSeungwon Jeon 	unsigned int blksz = data->blksz;
58952426899SSeungwon Jeon 	const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
59052426899SSeungwon Jeon 	u32 fifo_width = 1 << host->data_shift;
59152426899SSeungwon Jeon 	u32 blksz_depth = blksz / fifo_width, fifoth_val;
59252426899SSeungwon Jeon 	u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers;
59352426899SSeungwon Jeon 	int idx = (sizeof(mszs) / sizeof(mszs[0])) - 1;
59452426899SSeungwon Jeon 
59552426899SSeungwon Jeon 	tx_wmark = (host->fifo_depth) / 2;
59652426899SSeungwon Jeon 	tx_wmark_invers = host->fifo_depth - tx_wmark;
59752426899SSeungwon Jeon 
59852426899SSeungwon Jeon 	/*
59952426899SSeungwon Jeon 	 * MSIZE is '1',
60052426899SSeungwon Jeon 	 * if blksz is not a multiple of the FIFO width
60152426899SSeungwon Jeon 	 */
60252426899SSeungwon Jeon 	if (blksz % fifo_width) {
60352426899SSeungwon Jeon 		msize = 0;
60452426899SSeungwon Jeon 		rx_wmark = 1;
60552426899SSeungwon Jeon 		goto done;
60652426899SSeungwon Jeon 	}
60752426899SSeungwon Jeon 
60852426899SSeungwon Jeon 	do {
60952426899SSeungwon Jeon 		if (!((blksz_depth % mszs[idx]) ||
61052426899SSeungwon Jeon 		     (tx_wmark_invers % mszs[idx]))) {
61152426899SSeungwon Jeon 			msize = idx;
61252426899SSeungwon Jeon 			rx_wmark = mszs[idx] - 1;
61352426899SSeungwon Jeon 			break;
61452426899SSeungwon Jeon 		}
61552426899SSeungwon Jeon 	} while (--idx > 0);
61652426899SSeungwon Jeon 	/*
61752426899SSeungwon Jeon 	 * If idx is '0', it won't be tried
61852426899SSeungwon Jeon 	 * Thus, initial values are uesed
61952426899SSeungwon Jeon 	 */
62052426899SSeungwon Jeon done:
62152426899SSeungwon Jeon 	fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark);
62252426899SSeungwon Jeon 	mci_writel(host, FIFOTH, fifoth_val);
62352426899SSeungwon Jeon #endif
62452426899SSeungwon Jeon }
62552426899SSeungwon Jeon 
626f1d2736cSSeungwon Jeon static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)
627f1d2736cSSeungwon Jeon {
628f1d2736cSSeungwon Jeon 	unsigned int blksz = data->blksz;
629f1d2736cSSeungwon Jeon 	u32 blksz_depth, fifo_depth;
630f1d2736cSSeungwon Jeon 	u16 thld_size;
631f1d2736cSSeungwon Jeon 
632f1d2736cSSeungwon Jeon 	WARN_ON(!(data->flags & MMC_DATA_READ));
633f1d2736cSSeungwon Jeon 
634f1d2736cSSeungwon Jeon 	if (host->timing != MMC_TIMING_MMC_HS200 &&
635f1d2736cSSeungwon Jeon 	    host->timing != MMC_TIMING_UHS_SDR104)
636f1d2736cSSeungwon Jeon 		goto disable;
637f1d2736cSSeungwon Jeon 
638f1d2736cSSeungwon Jeon 	blksz_depth = blksz / (1 << host->data_shift);
639f1d2736cSSeungwon Jeon 	fifo_depth = host->fifo_depth;
640f1d2736cSSeungwon Jeon 
641f1d2736cSSeungwon Jeon 	if (blksz_depth > fifo_depth)
642f1d2736cSSeungwon Jeon 		goto disable;
643f1d2736cSSeungwon Jeon 
644f1d2736cSSeungwon Jeon 	/*
645f1d2736cSSeungwon Jeon 	 * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz'
646f1d2736cSSeungwon Jeon 	 * If (blksz_depth) <  (fifo_depth >> 1), should be thld_size = blksz
647f1d2736cSSeungwon Jeon 	 * Currently just choose blksz.
648f1d2736cSSeungwon Jeon 	 */
649f1d2736cSSeungwon Jeon 	thld_size = blksz;
650f1d2736cSSeungwon Jeon 	mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1));
651f1d2736cSSeungwon Jeon 	return;
652f1d2736cSSeungwon Jeon 
653f1d2736cSSeungwon Jeon disable:
654f1d2736cSSeungwon Jeon 	mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0));
655f1d2736cSSeungwon Jeon }
656f1d2736cSSeungwon Jeon 
6579aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
6589aa51408SSeungwon Jeon {
6599aa51408SSeungwon Jeon 	int sg_len;
6609aa51408SSeungwon Jeon 	u32 temp;
6619aa51408SSeungwon Jeon 
6629aa51408SSeungwon Jeon 	host->using_dma = 0;
6639aa51408SSeungwon Jeon 
6649aa51408SSeungwon Jeon 	/* If we don't have a channel, we can't do DMA */
6659aa51408SSeungwon Jeon 	if (!host->use_dma)
6669aa51408SSeungwon Jeon 		return -ENODEV;
6679aa51408SSeungwon Jeon 
6689aa51408SSeungwon Jeon 	sg_len = dw_mci_pre_dma_transfer(host, data, 0);
669a99aa9b9SSeungwon Jeon 	if (sg_len < 0) {
670a99aa9b9SSeungwon Jeon 		host->dma_ops->stop(host);
6719aa51408SSeungwon Jeon 		return sg_len;
672a99aa9b9SSeungwon Jeon 	}
6739aa51408SSeungwon Jeon 
67403e8cb53SJames Hogan 	host->using_dma = 1;
67503e8cb53SJames Hogan 
6764a90920cSThomas Abraham 	dev_vdbg(host->dev,
677f95f3850SWill Newton 		 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
678f95f3850SWill Newton 		 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
679f95f3850SWill Newton 		 sg_len);
680f95f3850SWill Newton 
68152426899SSeungwon Jeon 	/*
68252426899SSeungwon Jeon 	 * Decide the MSIZE and RX/TX Watermark.
68352426899SSeungwon Jeon 	 * If current block size is same with previous size,
68452426899SSeungwon Jeon 	 * no need to update fifoth.
68552426899SSeungwon Jeon 	 */
68652426899SSeungwon Jeon 	if (host->prev_blksz != data->blksz)
68752426899SSeungwon Jeon 		dw_mci_adjust_fifoth(host, data);
68852426899SSeungwon Jeon 
689f95f3850SWill Newton 	/* Enable the DMA interface */
690f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
691f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_ENABLE;
692f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
693f95f3850SWill Newton 
694f95f3850SWill Newton 	/* Disable RX/TX IRQs, let DMA handle it */
695f95f3850SWill Newton 	temp = mci_readl(host, INTMASK);
696f95f3850SWill Newton 	temp  &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR);
697f95f3850SWill Newton 	mci_writel(host, INTMASK, temp);
698f95f3850SWill Newton 
699f95f3850SWill Newton 	host->dma_ops->start(host, sg_len);
700f95f3850SWill Newton 
701f95f3850SWill Newton 	return 0;
702f95f3850SWill Newton }
703f95f3850SWill Newton 
704f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
705f95f3850SWill Newton {
706f95f3850SWill Newton 	u32 temp;
707f95f3850SWill Newton 
708f95f3850SWill Newton 	data->error = -EINPROGRESS;
709f95f3850SWill Newton 
710f95f3850SWill Newton 	WARN_ON(host->data);
711f95f3850SWill Newton 	host->sg = NULL;
712f95f3850SWill Newton 	host->data = data;
713f95f3850SWill Newton 
714f1d2736cSSeungwon Jeon 	if (data->flags & MMC_DATA_READ) {
71555c5efbcSJames Hogan 		host->dir_status = DW_MCI_RECV_STATUS;
716f1d2736cSSeungwon Jeon 		dw_mci_ctrl_rd_thld(host, data);
717f1d2736cSSeungwon Jeon 	} else {
71855c5efbcSJames Hogan 		host->dir_status = DW_MCI_SEND_STATUS;
719f1d2736cSSeungwon Jeon 	}
72055c5efbcSJames Hogan 
721f95f3850SWill Newton 	if (dw_mci_submit_data_dma(host, data)) {
722f9c2a0dcSSeungwon Jeon 		int flags = SG_MITER_ATOMIC;
723f9c2a0dcSSeungwon Jeon 		if (host->data->flags & MMC_DATA_READ)
724f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_TO_SG;
725f9c2a0dcSSeungwon Jeon 		else
726f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_FROM_SG;
727f9c2a0dcSSeungwon Jeon 
728f9c2a0dcSSeungwon Jeon 		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
729f95f3850SWill Newton 		host->sg = data->sg;
73034b664a2SJames Hogan 		host->part_buf_start = 0;
73134b664a2SJames Hogan 		host->part_buf_count = 0;
732f95f3850SWill Newton 
733b40af3aaSJames Hogan 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR);
734f95f3850SWill Newton 		temp = mci_readl(host, INTMASK);
735f95f3850SWill Newton 		temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR;
736f95f3850SWill Newton 		mci_writel(host, INTMASK, temp);
737f95f3850SWill Newton 
738f95f3850SWill Newton 		temp = mci_readl(host, CTRL);
739f95f3850SWill Newton 		temp &= ~SDMMC_CTRL_DMA_ENABLE;
740f95f3850SWill Newton 		mci_writel(host, CTRL, temp);
74152426899SSeungwon Jeon 
74252426899SSeungwon Jeon 		/*
74352426899SSeungwon Jeon 		 * Use the initial fifoth_val for PIO mode.
74452426899SSeungwon Jeon 		 * If next issued data may be transfered by DMA mode,
74552426899SSeungwon Jeon 		 * prev_blksz should be invalidated.
74652426899SSeungwon Jeon 		 */
74752426899SSeungwon Jeon 		mci_writel(host, FIFOTH, host->fifoth_val);
74852426899SSeungwon Jeon 		host->prev_blksz = 0;
74952426899SSeungwon Jeon 	} else {
75052426899SSeungwon Jeon 		/*
75152426899SSeungwon Jeon 		 * Keep the current block size.
75252426899SSeungwon Jeon 		 * It will be used to decide whether to update
75352426899SSeungwon Jeon 		 * fifoth register next time.
75452426899SSeungwon Jeon 		 */
75552426899SSeungwon Jeon 		host->prev_blksz = data->blksz;
756f95f3850SWill Newton 	}
757f95f3850SWill Newton }
758f95f3850SWill Newton 
759f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
760f95f3850SWill Newton {
761f95f3850SWill Newton 	struct dw_mci *host = slot->host;
762f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
763f95f3850SWill Newton 	unsigned int cmd_status = 0;
764f95f3850SWill Newton 
765f95f3850SWill Newton 	mci_writel(host, CMDARG, arg);
766f95f3850SWill Newton 	wmb();
767f95f3850SWill Newton 	mci_writel(host, CMD, SDMMC_CMD_START | cmd);
768f95f3850SWill Newton 
769f95f3850SWill Newton 	while (time_before(jiffies, timeout)) {
770f95f3850SWill Newton 		cmd_status = mci_readl(host, CMD);
771f95f3850SWill Newton 		if (!(cmd_status & SDMMC_CMD_START))
772f95f3850SWill Newton 			return;
773f95f3850SWill Newton 	}
774f95f3850SWill Newton 	dev_err(&slot->mmc->class_dev,
775f95f3850SWill Newton 		"Timeout sending command (cmd %#x arg %#x status %#x)\n",
776f95f3850SWill Newton 		cmd, arg, cmd_status);
777f95f3850SWill Newton }
778f95f3850SWill Newton 
779ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
780f95f3850SWill Newton {
781f95f3850SWill Newton 	struct dw_mci *host = slot->host;
782fdf492a1SDoug Anderson 	unsigned int clock = slot->clock;
783f95f3850SWill Newton 	u32 div;
7849623b5b9SDoug Anderson 	u32 clk_en_a;
785f95f3850SWill Newton 
786fdf492a1SDoug Anderson 	if (!clock) {
787fdf492a1SDoug Anderson 		mci_writel(host, CLKENA, 0);
788fdf492a1SDoug Anderson 		mci_send_cmd(slot,
789fdf492a1SDoug Anderson 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
790fdf492a1SDoug Anderson 	} else if (clock != host->current_speed || force_clkinit) {
791fdf492a1SDoug Anderson 		div = host->bus_hz / clock;
792fdf492a1SDoug Anderson 		if (host->bus_hz % clock && host->bus_hz > clock)
793f95f3850SWill Newton 			/*
794f95f3850SWill Newton 			 * move the + 1 after the divide to prevent
795f95f3850SWill Newton 			 * over-clocking the card.
796f95f3850SWill Newton 			 */
797e419990bSSeungwon Jeon 			div += 1;
798e419990bSSeungwon Jeon 
799fdf492a1SDoug Anderson 		div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0;
800f95f3850SWill Newton 
801fdf492a1SDoug Anderson 		if ((clock << div) != slot->__clk_old || force_clkinit)
802f95f3850SWill Newton 			dev_info(&slot->mmc->class_dev,
803fdf492a1SDoug Anderson 				 "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
804fdf492a1SDoug Anderson 				 slot->id, host->bus_hz, clock,
805fdf492a1SDoug Anderson 				 div ? ((host->bus_hz / div) >> 1) :
806fdf492a1SDoug Anderson 				 host->bus_hz, div);
807f95f3850SWill Newton 
808f95f3850SWill Newton 		/* disable clock */
809f95f3850SWill Newton 		mci_writel(host, CLKENA, 0);
810f95f3850SWill Newton 		mci_writel(host, CLKSRC, 0);
811f95f3850SWill Newton 
812f95f3850SWill Newton 		/* inform CIU */
813f95f3850SWill Newton 		mci_send_cmd(slot,
814f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
815f95f3850SWill Newton 
816f95f3850SWill Newton 		/* set clock to desired speed */
817f95f3850SWill Newton 		mci_writel(host, CLKDIV, div);
818f95f3850SWill Newton 
819f95f3850SWill Newton 		/* inform CIU */
820f95f3850SWill Newton 		mci_send_cmd(slot,
821f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
822f95f3850SWill Newton 
8239623b5b9SDoug Anderson 		/* enable clock; only low power if no SDIO */
8249623b5b9SDoug Anderson 		clk_en_a = SDMMC_CLKEN_ENABLE << slot->id;
8259623b5b9SDoug Anderson 		if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id)))
8269623b5b9SDoug Anderson 			clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id;
8279623b5b9SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a);
828f95f3850SWill Newton 
829f95f3850SWill Newton 		/* inform CIU */
830f95f3850SWill Newton 		mci_send_cmd(slot,
831f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
832f95f3850SWill Newton 
833fdf492a1SDoug Anderson 		/* keep the clock with reflecting clock dividor */
834fdf492a1SDoug Anderson 		slot->__clk_old = clock << div;
835f95f3850SWill Newton 	}
836f95f3850SWill Newton 
837fdf492a1SDoug Anderson 	host->current_speed = clock;
838fdf492a1SDoug Anderson 
839f95f3850SWill Newton 	/* Set the current slot bus width */
8401d56c453SSeungwon Jeon 	mci_writel(host, CTYPE, (slot->ctype << slot->id));
841f95f3850SWill Newton }
842f95f3850SWill Newton 
843053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host,
844053b3ce6SSeungwon Jeon 				   struct dw_mci_slot *slot,
845053b3ce6SSeungwon Jeon 				   struct mmc_command *cmd)
846f95f3850SWill Newton {
847f95f3850SWill Newton 	struct mmc_request *mrq;
848f95f3850SWill Newton 	struct mmc_data	*data;
849f95f3850SWill Newton 	u32 cmdflags;
850f95f3850SWill Newton 
851f95f3850SWill Newton 	mrq = slot->mrq;
852f95f3850SWill Newton 
853f95f3850SWill Newton 	host->cur_slot = slot;
854f95f3850SWill Newton 	host->mrq = mrq;
855f95f3850SWill Newton 
856f95f3850SWill Newton 	host->pending_events = 0;
857f95f3850SWill Newton 	host->completed_events = 0;
858e352c813SSeungwon Jeon 	host->cmd_status = 0;
859f95f3850SWill Newton 	host->data_status = 0;
860e352c813SSeungwon Jeon 	host->dir_status = 0;
861f95f3850SWill Newton 
862053b3ce6SSeungwon Jeon 	data = cmd->data;
863f95f3850SWill Newton 	if (data) {
864f95f3850SWill Newton 		dw_mci_set_timeout(host);
865f95f3850SWill Newton 		mci_writel(host, BYTCNT, data->blksz*data->blocks);
866f95f3850SWill Newton 		mci_writel(host, BLKSIZ, data->blksz);
867f95f3850SWill Newton 	}
868f95f3850SWill Newton 
869f95f3850SWill Newton 	cmdflags = dw_mci_prepare_command(slot->mmc, cmd);
870f95f3850SWill Newton 
871f95f3850SWill Newton 	/* this is the first command, send the initialization clock */
872f95f3850SWill Newton 	if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags))
873f95f3850SWill Newton 		cmdflags |= SDMMC_CMD_INIT;
874f95f3850SWill Newton 
875f95f3850SWill Newton 	if (data) {
876f95f3850SWill Newton 		dw_mci_submit_data(host, data);
877f95f3850SWill Newton 		wmb();
878f95f3850SWill Newton 	}
879f95f3850SWill Newton 
880f95f3850SWill Newton 	dw_mci_start_command(host, cmd, cmdflags);
881f95f3850SWill Newton 
882f95f3850SWill Newton 	if (mrq->stop)
883f95f3850SWill Newton 		host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
88490c2143aSSeungwon Jeon 	else
88590c2143aSSeungwon Jeon 		host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd);
886f95f3850SWill Newton }
887f95f3850SWill Newton 
888053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host,
889053b3ce6SSeungwon Jeon 				 struct dw_mci_slot *slot)
890053b3ce6SSeungwon Jeon {
891053b3ce6SSeungwon Jeon 	struct mmc_request *mrq = slot->mrq;
892053b3ce6SSeungwon Jeon 	struct mmc_command *cmd;
893053b3ce6SSeungwon Jeon 
894053b3ce6SSeungwon Jeon 	cmd = mrq->sbc ? mrq->sbc : mrq->cmd;
895053b3ce6SSeungwon Jeon 	__dw_mci_start_request(host, slot, cmd);
896053b3ce6SSeungwon Jeon }
897053b3ce6SSeungwon Jeon 
8987456caaeSJames Hogan /* must be called with host->lock held */
899f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot,
900f95f3850SWill Newton 				 struct mmc_request *mrq)
901f95f3850SWill Newton {
902f95f3850SWill Newton 	dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
903f95f3850SWill Newton 		 host->state);
904f95f3850SWill Newton 
905f95f3850SWill Newton 	slot->mrq = mrq;
906f95f3850SWill Newton 
907f95f3850SWill Newton 	if (host->state == STATE_IDLE) {
908f95f3850SWill Newton 		host->state = STATE_SENDING_CMD;
909f95f3850SWill Newton 		dw_mci_start_request(host, slot);
910f95f3850SWill Newton 	} else {
911f95f3850SWill Newton 		list_add_tail(&slot->queue_node, &host->queue);
912f95f3850SWill Newton 	}
913f95f3850SWill Newton }
914f95f3850SWill Newton 
915f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
916f95f3850SWill Newton {
917f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
918f95f3850SWill Newton 	struct dw_mci *host = slot->host;
919f95f3850SWill Newton 
920f95f3850SWill Newton 	WARN_ON(slot->mrq);
921f95f3850SWill Newton 
9227456caaeSJames Hogan 	/*
9237456caaeSJames Hogan 	 * The check for card presence and queueing of the request must be
9247456caaeSJames Hogan 	 * atomic, otherwise the card could be removed in between and the
9257456caaeSJames Hogan 	 * request wouldn't fail until another card was inserted.
9267456caaeSJames Hogan 	 */
9277456caaeSJames Hogan 	spin_lock_bh(&host->lock);
9287456caaeSJames Hogan 
929f95f3850SWill Newton 	if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
9307456caaeSJames Hogan 		spin_unlock_bh(&host->lock);
931f95f3850SWill Newton 		mrq->cmd->error = -ENOMEDIUM;
932f95f3850SWill Newton 		mmc_request_done(mmc, mrq);
933f95f3850SWill Newton 		return;
934f95f3850SWill Newton 	}
935f95f3850SWill Newton 
936f95f3850SWill Newton 	dw_mci_queue_request(host, slot, mrq);
9377456caaeSJames Hogan 
9387456caaeSJames Hogan 	spin_unlock_bh(&host->lock);
939f95f3850SWill Newton }
940f95f3850SWill Newton 
941f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
942f95f3850SWill Newton {
943f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
944e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
94541babf75SJaehoon Chung 	u32 regs;
946f95f3850SWill Newton 
947f95f3850SWill Newton 	switch (ios->bus_width) {
948f95f3850SWill Newton 	case MMC_BUS_WIDTH_4:
949f95f3850SWill Newton 		slot->ctype = SDMMC_CTYPE_4BIT;
950f95f3850SWill Newton 		break;
951c9b2a06fSJaehoon Chung 	case MMC_BUS_WIDTH_8:
952c9b2a06fSJaehoon Chung 		slot->ctype = SDMMC_CTYPE_8BIT;
953c9b2a06fSJaehoon Chung 		break;
954b2f7cb45SJaehoon Chung 	default:
955b2f7cb45SJaehoon Chung 		/* set default 1 bit mode */
956b2f7cb45SJaehoon Chung 		slot->ctype = SDMMC_CTYPE_1BIT;
957f95f3850SWill Newton 	}
958f95f3850SWill Newton 
95941babf75SJaehoon Chung 	regs = mci_readl(slot->host, UHS_REG);
9603f514291SSeungwon Jeon 
9613f514291SSeungwon Jeon 	/* DDR mode set */
962cab3a802SSeungwon Jeon 	if (ios->timing == MMC_TIMING_MMC_DDR52)
963c69042a5SHyeonsu Kim 		regs |= ((0x1 << slot->id) << 16);
9643f514291SSeungwon Jeon 	else
965c69042a5SHyeonsu Kim 		regs &= ~((0x1 << slot->id) << 16);
9663f514291SSeungwon Jeon 
96741babf75SJaehoon Chung 	mci_writel(slot->host, UHS_REG, regs);
968f1d2736cSSeungwon Jeon 	slot->host->timing = ios->timing;
96941babf75SJaehoon Chung 
970f95f3850SWill Newton 	/*
971f95f3850SWill Newton 	 * Use mirror of ios->clock to prevent race with mmc
972f95f3850SWill Newton 	 * core ios update when finding the minimum.
973f95f3850SWill Newton 	 */
974f95f3850SWill Newton 	slot->clock = ios->clock;
975f95f3850SWill Newton 
976cb27a843SJames Hogan 	if (drv_data && drv_data->set_ios)
977cb27a843SJames Hogan 		drv_data->set_ios(slot->host, ios);
978800d78bfSThomas Abraham 
979bf7cb224SJaehoon Chung 	/* Slot specific timing and width adjustment */
980bf7cb224SJaehoon Chung 	dw_mci_setup_bus(slot, false);
981bf7cb224SJaehoon Chung 
982f95f3850SWill Newton 	switch (ios->power_mode) {
983f95f3850SWill Newton 	case MMC_POWER_UP:
984f95f3850SWill Newton 		set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
9854366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
9864366dcc5SJaehoon Chung 		regs |= (1 << slot->id);
9874366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
988e6f34e2fSJames Hogan 		break;
989e6f34e2fSJames Hogan 	case MMC_POWER_OFF:
9904366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
9914366dcc5SJaehoon Chung 		regs &= ~(1 << slot->id);
9924366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
993f95f3850SWill Newton 		break;
994f95f3850SWill Newton 	default:
995f95f3850SWill Newton 		break;
996f95f3850SWill Newton 	}
997f95f3850SWill Newton }
998f95f3850SWill Newton 
999f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc)
1000f95f3850SWill Newton {
1001f95f3850SWill Newton 	int read_only;
1002f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
1003f95f3850SWill Newton 
1004f95f3850SWill Newton 	/* Use platform get_ro function, else try on board write protect */
10059640639bSDoug Anderson 	if (slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT)
1006b4967aa5SThomas Abraham 		read_only = 0;
100755a6ceb2SDoug Anderson 	else if (gpio_is_valid(slot->wp_gpio))
100855a6ceb2SDoug Anderson 		read_only = gpio_get_value(slot->wp_gpio);
1009f95f3850SWill Newton 	else
1010f95f3850SWill Newton 		read_only =
1011f95f3850SWill Newton 			mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0;
1012f95f3850SWill Newton 
1013f95f3850SWill Newton 	dev_dbg(&mmc->class_dev, "card is %s\n",
1014f95f3850SWill Newton 		read_only ? "read-only" : "read-write");
1015f95f3850SWill Newton 
1016f95f3850SWill Newton 	return read_only;
1017f95f3850SWill Newton }
1018f95f3850SWill Newton 
1019f95f3850SWill Newton static int dw_mci_get_cd(struct mmc_host *mmc)
1020f95f3850SWill Newton {
1021f95f3850SWill Newton 	int present;
1022f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
1023f95f3850SWill Newton 	struct dw_mci_board *brd = slot->host->pdata;
10247cf347bdSZhangfei Gao 	struct dw_mci *host = slot->host;
10257cf347bdSZhangfei Gao 	int gpio_cd = mmc_gpio_get_cd(mmc);
1026f95f3850SWill Newton 
1027f95f3850SWill Newton 	/* Use platform get_cd function, else try onboard card detect */
1028fc3d7720SJaehoon Chung 	if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
1029fc3d7720SJaehoon Chung 		present = 1;
1030bf626e55SZhangfei Gao 	else if (!IS_ERR_VALUE(gpio_cd))
10317cf347bdSZhangfei Gao 		present = gpio_cd;
1032f95f3850SWill Newton 	else
1033f95f3850SWill Newton 		present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
1034f95f3850SWill Newton 			== 0 ? 1 : 0;
1035f95f3850SWill Newton 
10367cf347bdSZhangfei Gao 	spin_lock_bh(&host->lock);
1037bf626e55SZhangfei Gao 	if (present) {
1038bf626e55SZhangfei Gao 		set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
1039f95f3850SWill Newton 		dev_dbg(&mmc->class_dev, "card is present\n");
1040bf626e55SZhangfei Gao 	} else {
1041bf626e55SZhangfei Gao 		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
1042f95f3850SWill Newton 		dev_dbg(&mmc->class_dev, "card is not present\n");
1043bf626e55SZhangfei Gao 	}
10447cf347bdSZhangfei Gao 	spin_unlock_bh(&host->lock);
1045f95f3850SWill Newton 
1046f95f3850SWill Newton 	return present;
1047f95f3850SWill Newton }
1048f95f3850SWill Newton 
10499623b5b9SDoug Anderson /*
10509623b5b9SDoug Anderson  * Disable lower power mode.
10519623b5b9SDoug Anderson  *
10529623b5b9SDoug Anderson  * Low power mode will stop the card clock when idle.  According to the
10539623b5b9SDoug Anderson  * description of the CLKENA register we should disable low power mode
10549623b5b9SDoug Anderson  * for SDIO cards if we need SDIO interrupts to work.
10559623b5b9SDoug Anderson  *
10569623b5b9SDoug Anderson  * This function is fast if low power mode is already disabled.
10579623b5b9SDoug Anderson  */
10589623b5b9SDoug Anderson static void dw_mci_disable_low_power(struct dw_mci_slot *slot)
10599623b5b9SDoug Anderson {
10609623b5b9SDoug Anderson 	struct dw_mci *host = slot->host;
10619623b5b9SDoug Anderson 	u32 clk_en_a;
10629623b5b9SDoug Anderson 	const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id;
10639623b5b9SDoug Anderson 
10649623b5b9SDoug Anderson 	clk_en_a = mci_readl(host, CLKENA);
10659623b5b9SDoug Anderson 
10669623b5b9SDoug Anderson 	if (clk_en_a & clken_low_pwr) {
10679623b5b9SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr);
10689623b5b9SDoug Anderson 		mci_send_cmd(slot, SDMMC_CMD_UPD_CLK |
10699623b5b9SDoug Anderson 			     SDMMC_CMD_PRV_DAT_WAIT, 0);
10709623b5b9SDoug Anderson 	}
10719623b5b9SDoug Anderson }
10729623b5b9SDoug Anderson 
10731a5c8e1fSShashidhar Hiremath static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
10741a5c8e1fSShashidhar Hiremath {
10751a5c8e1fSShashidhar Hiremath 	struct dw_mci_slot *slot = mmc_priv(mmc);
10761a5c8e1fSShashidhar Hiremath 	struct dw_mci *host = slot->host;
10771a5c8e1fSShashidhar Hiremath 	u32 int_mask;
10781a5c8e1fSShashidhar Hiremath 
10791a5c8e1fSShashidhar Hiremath 	/* Enable/disable Slot Specific SDIO interrupt */
10801a5c8e1fSShashidhar Hiremath 	int_mask = mci_readl(host, INTMASK);
10811a5c8e1fSShashidhar Hiremath 	if (enb) {
10829623b5b9SDoug Anderson 		/*
10839623b5b9SDoug Anderson 		 * Turn off low power mode if it was enabled.  This is a bit of
10849623b5b9SDoug Anderson 		 * a heavy operation and we disable / enable IRQs a lot, so
10859623b5b9SDoug Anderson 		 * we'll leave low power mode disabled and it will get
10869623b5b9SDoug Anderson 		 * re-enabled again in dw_mci_setup_bus().
10879623b5b9SDoug Anderson 		 */
10889623b5b9SDoug Anderson 		dw_mci_disable_low_power(slot);
10899623b5b9SDoug Anderson 
10901a5c8e1fSShashidhar Hiremath 		mci_writel(host, INTMASK,
1091705ad047SKyoungil Kim 			   (int_mask | SDMMC_INT_SDIO(slot->id)));
10921a5c8e1fSShashidhar Hiremath 	} else {
10931a5c8e1fSShashidhar Hiremath 		mci_writel(host, INTMASK,
1094705ad047SKyoungil Kim 			   (int_mask & ~SDMMC_INT_SDIO(slot->id)));
10951a5c8e1fSShashidhar Hiremath 	}
10961a5c8e1fSShashidhar Hiremath }
10971a5c8e1fSShashidhar Hiremath 
10980976f16dSSeungwon Jeon static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
10990976f16dSSeungwon Jeon {
11000976f16dSSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
11010976f16dSSeungwon Jeon 	struct dw_mci *host = slot->host;
11020976f16dSSeungwon Jeon 	const struct dw_mci_drv_data *drv_data = host->drv_data;
11030976f16dSSeungwon Jeon 	struct dw_mci_tuning_data tuning_data;
11040976f16dSSeungwon Jeon 	int err = -ENOSYS;
11050976f16dSSeungwon Jeon 
11060976f16dSSeungwon Jeon 	if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
11070976f16dSSeungwon Jeon 		if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
11080976f16dSSeungwon Jeon 			tuning_data.blk_pattern = tuning_blk_pattern_8bit;
11090976f16dSSeungwon Jeon 			tuning_data.blksz = sizeof(tuning_blk_pattern_8bit);
11100976f16dSSeungwon Jeon 		} else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
11110976f16dSSeungwon Jeon 			tuning_data.blk_pattern = tuning_blk_pattern_4bit;
11120976f16dSSeungwon Jeon 			tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
11130976f16dSSeungwon Jeon 		} else {
11140976f16dSSeungwon Jeon 			return -EINVAL;
11150976f16dSSeungwon Jeon 		}
11160976f16dSSeungwon Jeon 	} else if (opcode == MMC_SEND_TUNING_BLOCK) {
11170976f16dSSeungwon Jeon 		tuning_data.blk_pattern = tuning_blk_pattern_4bit;
11180976f16dSSeungwon Jeon 		tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
11190976f16dSSeungwon Jeon 	} else {
11200976f16dSSeungwon Jeon 		dev_err(host->dev,
11210976f16dSSeungwon Jeon 			"Undefined command(%d) for tuning\n", opcode);
11220976f16dSSeungwon Jeon 		return -EINVAL;
11230976f16dSSeungwon Jeon 	}
11240976f16dSSeungwon Jeon 
11250976f16dSSeungwon Jeon 	if (drv_data && drv_data->execute_tuning)
11260976f16dSSeungwon Jeon 		err = drv_data->execute_tuning(slot, opcode, &tuning_data);
11270976f16dSSeungwon Jeon 	return err;
11280976f16dSSeungwon Jeon }
11290976f16dSSeungwon Jeon 
1130f95f3850SWill Newton static const struct mmc_host_ops dw_mci_ops = {
1131f95f3850SWill Newton 	.request		= dw_mci_request,
11329aa51408SSeungwon Jeon 	.pre_req		= dw_mci_pre_req,
11339aa51408SSeungwon Jeon 	.post_req		= dw_mci_post_req,
1134f95f3850SWill Newton 	.set_ios		= dw_mci_set_ios,
1135f95f3850SWill Newton 	.get_ro			= dw_mci_get_ro,
1136f95f3850SWill Newton 	.get_cd			= dw_mci_get_cd,
11371a5c8e1fSShashidhar Hiremath 	.enable_sdio_irq	= dw_mci_enable_sdio_irq,
11380976f16dSSeungwon Jeon 	.execute_tuning		= dw_mci_execute_tuning,
1139f95f3850SWill Newton };
1140f95f3850SWill Newton 
1141f95f3850SWill Newton static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
1142f95f3850SWill Newton 	__releases(&host->lock)
1143f95f3850SWill Newton 	__acquires(&host->lock)
1144f95f3850SWill Newton {
1145f95f3850SWill Newton 	struct dw_mci_slot *slot;
1146f95f3850SWill Newton 	struct mmc_host	*prev_mmc = host->cur_slot->mmc;
1147f95f3850SWill Newton 
1148f95f3850SWill Newton 	WARN_ON(host->cmd || host->data);
1149f95f3850SWill Newton 
1150f95f3850SWill Newton 	host->cur_slot->mrq = NULL;
1151f95f3850SWill Newton 	host->mrq = NULL;
1152f95f3850SWill Newton 	if (!list_empty(&host->queue)) {
1153f95f3850SWill Newton 		slot = list_entry(host->queue.next,
1154f95f3850SWill Newton 				  struct dw_mci_slot, queue_node);
1155f95f3850SWill Newton 		list_del(&slot->queue_node);
11564a90920cSThomas Abraham 		dev_vdbg(host->dev, "list not empty: %s is next\n",
1157f95f3850SWill Newton 			 mmc_hostname(slot->mmc));
1158f95f3850SWill Newton 		host->state = STATE_SENDING_CMD;
1159f95f3850SWill Newton 		dw_mci_start_request(host, slot);
1160f95f3850SWill Newton 	} else {
11614a90920cSThomas Abraham 		dev_vdbg(host->dev, "list empty\n");
1162f95f3850SWill Newton 		host->state = STATE_IDLE;
1163f95f3850SWill Newton 	}
1164f95f3850SWill Newton 
1165f95f3850SWill Newton 	spin_unlock(&host->lock);
1166f95f3850SWill Newton 	mmc_request_done(prev_mmc, mrq);
1167f95f3850SWill Newton 	spin_lock(&host->lock);
1168f95f3850SWill Newton }
1169f95f3850SWill Newton 
1170e352c813SSeungwon Jeon static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
1171f95f3850SWill Newton {
1172f95f3850SWill Newton 	u32 status = host->cmd_status;
1173f95f3850SWill Newton 
1174f95f3850SWill Newton 	host->cmd_status = 0;
1175f95f3850SWill Newton 
1176f95f3850SWill Newton 	/* Read the response from the card (up to 16 bytes) */
1177f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_PRESENT) {
1178f95f3850SWill Newton 		if (cmd->flags & MMC_RSP_136) {
1179f95f3850SWill Newton 			cmd->resp[3] = mci_readl(host, RESP0);
1180f95f3850SWill Newton 			cmd->resp[2] = mci_readl(host, RESP1);
1181f95f3850SWill Newton 			cmd->resp[1] = mci_readl(host, RESP2);
1182f95f3850SWill Newton 			cmd->resp[0] = mci_readl(host, RESP3);
1183f95f3850SWill Newton 		} else {
1184f95f3850SWill Newton 			cmd->resp[0] = mci_readl(host, RESP0);
1185f95f3850SWill Newton 			cmd->resp[1] = 0;
1186f95f3850SWill Newton 			cmd->resp[2] = 0;
1187f95f3850SWill Newton 			cmd->resp[3] = 0;
1188f95f3850SWill Newton 		}
1189f95f3850SWill Newton 	}
1190f95f3850SWill Newton 
1191f95f3850SWill Newton 	if (status & SDMMC_INT_RTO)
1192f95f3850SWill Newton 		cmd->error = -ETIMEDOUT;
1193f95f3850SWill Newton 	else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC))
1194f95f3850SWill Newton 		cmd->error = -EILSEQ;
1195f95f3850SWill Newton 	else if (status & SDMMC_INT_RESP_ERR)
1196f95f3850SWill Newton 		cmd->error = -EIO;
1197f95f3850SWill Newton 	else
1198f95f3850SWill Newton 		cmd->error = 0;
1199f95f3850SWill Newton 
1200f95f3850SWill Newton 	if (cmd->error) {
1201f95f3850SWill Newton 		/* newer ip versions need a delay between retries */
1202f95f3850SWill Newton 		if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY)
1203f95f3850SWill Newton 			mdelay(20);
1204f95f3850SWill Newton 	}
1205e352c813SSeungwon Jeon 
1206e352c813SSeungwon Jeon 	return cmd->error;
1207e352c813SSeungwon Jeon }
1208e352c813SSeungwon Jeon 
1209e352c813SSeungwon Jeon static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data)
1210e352c813SSeungwon Jeon {
121131bff450SSeungwon Jeon 	u32 status = host->data_status;
1212e352c813SSeungwon Jeon 
1213e352c813SSeungwon Jeon 	if (status & DW_MCI_DATA_ERROR_FLAGS) {
1214e352c813SSeungwon Jeon 		if (status & SDMMC_INT_DRTO) {
1215e352c813SSeungwon Jeon 			data->error = -ETIMEDOUT;
1216e352c813SSeungwon Jeon 		} else if (status & SDMMC_INT_DCRC) {
1217e352c813SSeungwon Jeon 			data->error = -EILSEQ;
1218e352c813SSeungwon Jeon 		} else if (status & SDMMC_INT_EBE) {
1219e352c813SSeungwon Jeon 			if (host->dir_status ==
1220e352c813SSeungwon Jeon 				DW_MCI_SEND_STATUS) {
1221e352c813SSeungwon Jeon 				/*
1222e352c813SSeungwon Jeon 				 * No data CRC status was returned.
1223e352c813SSeungwon Jeon 				 * The number of bytes transferred
1224e352c813SSeungwon Jeon 				 * will be exaggerated in PIO mode.
1225e352c813SSeungwon Jeon 				 */
1226e352c813SSeungwon Jeon 				data->bytes_xfered = 0;
1227e352c813SSeungwon Jeon 				data->error = -ETIMEDOUT;
1228e352c813SSeungwon Jeon 			} else if (host->dir_status ==
1229e352c813SSeungwon Jeon 					DW_MCI_RECV_STATUS) {
1230e352c813SSeungwon Jeon 				data->error = -EIO;
1231e352c813SSeungwon Jeon 			}
1232e352c813SSeungwon Jeon 		} else {
1233e352c813SSeungwon Jeon 			/* SDMMC_INT_SBE is included */
1234e352c813SSeungwon Jeon 			data->error = -EIO;
1235e352c813SSeungwon Jeon 		}
1236e352c813SSeungwon Jeon 
1237e352c813SSeungwon Jeon 		dev_err(host->dev, "data error, status 0x%08x\n", status);
1238e352c813SSeungwon Jeon 
1239e352c813SSeungwon Jeon 		/*
1240e352c813SSeungwon Jeon 		 * After an error, there may be data lingering
124131bff450SSeungwon Jeon 		 * in the FIFO
1242e352c813SSeungwon Jeon 		 */
124331bff450SSeungwon Jeon 		dw_mci_fifo_reset(host);
1244e352c813SSeungwon Jeon 	} else {
1245e352c813SSeungwon Jeon 		data->bytes_xfered = data->blocks * data->blksz;
1246e352c813SSeungwon Jeon 		data->error = 0;
1247e352c813SSeungwon Jeon 	}
1248e352c813SSeungwon Jeon 
1249e352c813SSeungwon Jeon 	return data->error;
1250f95f3850SWill Newton }
1251f95f3850SWill Newton 
1252f95f3850SWill Newton static void dw_mci_tasklet_func(unsigned long priv)
1253f95f3850SWill Newton {
1254f95f3850SWill Newton 	struct dw_mci *host = (struct dw_mci *)priv;
1255f95f3850SWill Newton 	struct mmc_data	*data;
1256f95f3850SWill Newton 	struct mmc_command *cmd;
1257e352c813SSeungwon Jeon 	struct mmc_request *mrq;
1258f95f3850SWill Newton 	enum dw_mci_state state;
1259f95f3850SWill Newton 	enum dw_mci_state prev_state;
1260e352c813SSeungwon Jeon 	unsigned int err;
1261f95f3850SWill Newton 
1262f95f3850SWill Newton 	spin_lock(&host->lock);
1263f95f3850SWill Newton 
1264f95f3850SWill Newton 	state = host->state;
1265f95f3850SWill Newton 	data = host->data;
1266e352c813SSeungwon Jeon 	mrq = host->mrq;
1267f95f3850SWill Newton 
1268f95f3850SWill Newton 	do {
1269f95f3850SWill Newton 		prev_state = state;
1270f95f3850SWill Newton 
1271f95f3850SWill Newton 		switch (state) {
1272f95f3850SWill Newton 		case STATE_IDLE:
1273f95f3850SWill Newton 			break;
1274f95f3850SWill Newton 
1275f95f3850SWill Newton 		case STATE_SENDING_CMD:
1276f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1277f95f3850SWill Newton 						&host->pending_events))
1278f95f3850SWill Newton 				break;
1279f95f3850SWill Newton 
1280f95f3850SWill Newton 			cmd = host->cmd;
1281f95f3850SWill Newton 			host->cmd = NULL;
1282f95f3850SWill Newton 			set_bit(EVENT_CMD_COMPLETE, &host->completed_events);
1283e352c813SSeungwon Jeon 			err = dw_mci_command_complete(host, cmd);
1284e352c813SSeungwon Jeon 			if (cmd == mrq->sbc && !err) {
1285053b3ce6SSeungwon Jeon 				prev_state = state = STATE_SENDING_CMD;
1286053b3ce6SSeungwon Jeon 				__dw_mci_start_request(host, host->cur_slot,
1287e352c813SSeungwon Jeon 						       mrq->cmd);
1288053b3ce6SSeungwon Jeon 				goto unlock;
1289053b3ce6SSeungwon Jeon 			}
1290053b3ce6SSeungwon Jeon 
1291e352c813SSeungwon Jeon 			if (cmd->data && err) {
129271abb133SSeungwon Jeon 				dw_mci_stop_dma(host);
129390c2143aSSeungwon Jeon 				send_stop_abort(host, data);
129471abb133SSeungwon Jeon 				state = STATE_SENDING_STOP;
129571abb133SSeungwon Jeon 				break;
129671abb133SSeungwon Jeon 			}
129771abb133SSeungwon Jeon 
1298e352c813SSeungwon Jeon 			if (!cmd->data || err) {
1299e352c813SSeungwon Jeon 				dw_mci_request_end(host, mrq);
1300f95f3850SWill Newton 				goto unlock;
1301f95f3850SWill Newton 			}
1302f95f3850SWill Newton 
1303f95f3850SWill Newton 			prev_state = state = STATE_SENDING_DATA;
1304f95f3850SWill Newton 			/* fall through */
1305f95f3850SWill Newton 
1306f95f3850SWill Newton 		case STATE_SENDING_DATA:
1307f95f3850SWill Newton 			if (test_and_clear_bit(EVENT_DATA_ERROR,
1308f95f3850SWill Newton 					       &host->pending_events)) {
1309f95f3850SWill Newton 				dw_mci_stop_dma(host);
131090c2143aSSeungwon Jeon 				send_stop_abort(host, data);
1311f95f3850SWill Newton 				state = STATE_DATA_ERROR;
1312f95f3850SWill Newton 				break;
1313f95f3850SWill Newton 			}
1314f95f3850SWill Newton 
1315f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1316f95f3850SWill Newton 						&host->pending_events))
1317f95f3850SWill Newton 				break;
1318f95f3850SWill Newton 
1319f95f3850SWill Newton 			set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
1320f95f3850SWill Newton 			prev_state = state = STATE_DATA_BUSY;
1321f95f3850SWill Newton 			/* fall through */
1322f95f3850SWill Newton 
1323f95f3850SWill Newton 		case STATE_DATA_BUSY:
1324f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
1325f95f3850SWill Newton 						&host->pending_events))
1326f95f3850SWill Newton 				break;
1327f95f3850SWill Newton 
1328f95f3850SWill Newton 			host->data = NULL;
1329f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
1330e352c813SSeungwon Jeon 			err = dw_mci_data_complete(host, data);
1331f95f3850SWill Newton 
1332e352c813SSeungwon Jeon 			if (!err) {
1333e352c813SSeungwon Jeon 				if (!data->stop || mrq->sbc) {
133417c8bc85SSachin Kamat 					if (mrq->sbc && data->stop)
1335053b3ce6SSeungwon Jeon 						data->stop->error = 0;
1336e352c813SSeungwon Jeon 					dw_mci_request_end(host, mrq);
1337053b3ce6SSeungwon Jeon 					goto unlock;
1338053b3ce6SSeungwon Jeon 				}
1339053b3ce6SSeungwon Jeon 
134090c2143aSSeungwon Jeon 				/* stop command for open-ended transfer*/
1341e352c813SSeungwon Jeon 				if (data->stop)
134290c2143aSSeungwon Jeon 					send_stop_abort(host, data);
134390c2143aSSeungwon Jeon 			}
1344e352c813SSeungwon Jeon 
1345e352c813SSeungwon Jeon 			/*
1346e352c813SSeungwon Jeon 			 * If err has non-zero,
1347e352c813SSeungwon Jeon 			 * stop-abort command has been already issued.
1348e352c813SSeungwon Jeon 			 */
1349e352c813SSeungwon Jeon 			prev_state = state = STATE_SENDING_STOP;
1350e352c813SSeungwon Jeon 
1351f95f3850SWill Newton 			/* fall through */
1352f95f3850SWill Newton 
1353f95f3850SWill Newton 		case STATE_SENDING_STOP:
1354f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1355f95f3850SWill Newton 						&host->pending_events))
1356f95f3850SWill Newton 				break;
1357f95f3850SWill Newton 
135871abb133SSeungwon Jeon 			/* CMD error in data command */
135931bff450SSeungwon Jeon 			if (mrq->cmd->error && mrq->data)
136031bff450SSeungwon Jeon 				dw_mci_fifo_reset(host);
136171abb133SSeungwon Jeon 
1362f95f3850SWill Newton 			host->cmd = NULL;
136371abb133SSeungwon Jeon 			host->data = NULL;
136490c2143aSSeungwon Jeon 
1365e352c813SSeungwon Jeon 			if (mrq->stop)
1366e352c813SSeungwon Jeon 				dw_mci_command_complete(host, mrq->stop);
136790c2143aSSeungwon Jeon 			else
136890c2143aSSeungwon Jeon 				host->cmd_status = 0;
136990c2143aSSeungwon Jeon 
1370e352c813SSeungwon Jeon 			dw_mci_request_end(host, mrq);
1371f95f3850SWill Newton 			goto unlock;
1372f95f3850SWill Newton 
1373f95f3850SWill Newton 		case STATE_DATA_ERROR:
1374f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1375f95f3850SWill Newton 						&host->pending_events))
1376f95f3850SWill Newton 				break;
1377f95f3850SWill Newton 
1378f95f3850SWill Newton 			state = STATE_DATA_BUSY;
1379f95f3850SWill Newton 			break;
1380f95f3850SWill Newton 		}
1381f95f3850SWill Newton 	} while (state != prev_state);
1382f95f3850SWill Newton 
1383f95f3850SWill Newton 	host->state = state;
1384f95f3850SWill Newton unlock:
1385f95f3850SWill Newton 	spin_unlock(&host->lock);
1386f95f3850SWill Newton 
1387f95f3850SWill Newton }
1388f95f3850SWill Newton 
138934b664a2SJames Hogan /* push final bytes to part_buf, only use during push */
139034b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt)
139134b664a2SJames Hogan {
139234b664a2SJames Hogan 	memcpy((void *)&host->part_buf, buf, cnt);
139334b664a2SJames Hogan 	host->part_buf_count = cnt;
139434b664a2SJames Hogan }
139534b664a2SJames Hogan 
139634b664a2SJames Hogan /* append bytes to part_buf, only use during push */
139734b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt)
139834b664a2SJames Hogan {
139934b664a2SJames Hogan 	cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count);
140034b664a2SJames Hogan 	memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt);
140134b664a2SJames Hogan 	host->part_buf_count += cnt;
140234b664a2SJames Hogan 	return cnt;
140334b664a2SJames Hogan }
140434b664a2SJames Hogan 
140534b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */
140634b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt)
140734b664a2SJames Hogan {
140834b664a2SJames Hogan 	cnt = min(cnt, (int)host->part_buf_count);
140934b664a2SJames Hogan 	if (cnt) {
141034b664a2SJames Hogan 		memcpy(buf, (void *)&host->part_buf + host->part_buf_start,
141134b664a2SJames Hogan 		       cnt);
141234b664a2SJames Hogan 		host->part_buf_count -= cnt;
141334b664a2SJames Hogan 		host->part_buf_start += cnt;
141434b664a2SJames Hogan 	}
141534b664a2SJames Hogan 	return cnt;
141634b664a2SJames Hogan }
141734b664a2SJames Hogan 
141834b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */
141934b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt)
142034b664a2SJames Hogan {
142134b664a2SJames Hogan 	memcpy(buf, &host->part_buf, cnt);
142234b664a2SJames Hogan 	host->part_buf_start = cnt;
142334b664a2SJames Hogan 	host->part_buf_count = (1 << host->data_shift) - cnt;
142434b664a2SJames Hogan }
142534b664a2SJames Hogan 
1426f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
1427f95f3850SWill Newton {
1428cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1429cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1430cfbeb59cSMarkos Chandras 
143134b664a2SJames Hogan 	/* try and push anything in the part_buf */
143234b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
143334b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
143434b664a2SJames Hogan 		buf += len;
143534b664a2SJames Hogan 		cnt -= len;
1436cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 2) {
14374e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
14384e0a5adfSJaehoon Chung 					host->part_buf16);
143934b664a2SJames Hogan 			host->part_buf_count = 0;
144034b664a2SJames Hogan 		}
144134b664a2SJames Hogan 	}
144234b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
144334b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
144434b664a2SJames Hogan 		while (cnt >= 2) {
144534b664a2SJames Hogan 			u16 aligned_buf[64];
144634b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
144734b664a2SJames Hogan 			int items = len >> 1;
144834b664a2SJames Hogan 			int i;
144934b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
145034b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
145134b664a2SJames Hogan 			buf += len;
145234b664a2SJames Hogan 			cnt -= len;
145334b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
145434b664a2SJames Hogan 			for (i = 0; i < items; ++i)
14554e0a5adfSJaehoon Chung 				mci_writew(host, DATA(host->data_offset),
14564e0a5adfSJaehoon Chung 						aligned_buf[i]);
145734b664a2SJames Hogan 		}
145834b664a2SJames Hogan 	} else
145934b664a2SJames Hogan #endif
146034b664a2SJames Hogan 	{
146134b664a2SJames Hogan 		u16 *pdata = buf;
146234b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
14634e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset), *pdata++);
146434b664a2SJames Hogan 		buf = pdata;
146534b664a2SJames Hogan 	}
146634b664a2SJames Hogan 	/* put anything remaining in the part_buf */
146734b664a2SJames Hogan 	if (cnt) {
146834b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1469cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1470cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1471cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
14724e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
14734e0a5adfSJaehoon Chung 				   host->part_buf16);
1474f95f3850SWill Newton 	}
1475f95f3850SWill Newton }
1476f95f3850SWill Newton 
1477f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
1478f95f3850SWill Newton {
147934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
148034b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
148134b664a2SJames Hogan 		while (cnt >= 2) {
148234b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
148334b664a2SJames Hogan 			u16 aligned_buf[64];
148434b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
148534b664a2SJames Hogan 			int items = len >> 1;
148634b664a2SJames Hogan 			int i;
148734b664a2SJames Hogan 			for (i = 0; i < items; ++i)
14884e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readw(host,
14894e0a5adfSJaehoon Chung 						DATA(host->data_offset));
149034b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
149134b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
149234b664a2SJames Hogan 			buf += len;
149334b664a2SJames Hogan 			cnt -= len;
149434b664a2SJames Hogan 		}
149534b664a2SJames Hogan 	} else
149634b664a2SJames Hogan #endif
149734b664a2SJames Hogan 	{
149834b664a2SJames Hogan 		u16 *pdata = buf;
149934b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
15004e0a5adfSJaehoon Chung 			*pdata++ = mci_readw(host, DATA(host->data_offset));
150134b664a2SJames Hogan 		buf = pdata;
150234b664a2SJames Hogan 	}
150334b664a2SJames Hogan 	if (cnt) {
15044e0a5adfSJaehoon Chung 		host->part_buf16 = mci_readw(host, DATA(host->data_offset));
150534b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1506f95f3850SWill Newton 	}
1507f95f3850SWill Newton }
1508f95f3850SWill Newton 
1509f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
1510f95f3850SWill Newton {
1511cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1512cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1513cfbeb59cSMarkos Chandras 
151434b664a2SJames Hogan 	/* try and push anything in the part_buf */
151534b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
151634b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
151734b664a2SJames Hogan 		buf += len;
151834b664a2SJames Hogan 		cnt -= len;
1519cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 4) {
15204e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
15214e0a5adfSJaehoon Chung 					host->part_buf32);
152234b664a2SJames Hogan 			host->part_buf_count = 0;
152334b664a2SJames Hogan 		}
152434b664a2SJames Hogan 	}
152534b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
152634b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
152734b664a2SJames Hogan 		while (cnt >= 4) {
152834b664a2SJames Hogan 			u32 aligned_buf[32];
152934b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
153034b664a2SJames Hogan 			int items = len >> 2;
153134b664a2SJames Hogan 			int i;
153234b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
153334b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
153434b664a2SJames Hogan 			buf += len;
153534b664a2SJames Hogan 			cnt -= len;
153634b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
153734b664a2SJames Hogan 			for (i = 0; i < items; ++i)
15384e0a5adfSJaehoon Chung 				mci_writel(host, DATA(host->data_offset),
15394e0a5adfSJaehoon Chung 						aligned_buf[i]);
154034b664a2SJames Hogan 		}
154134b664a2SJames Hogan 	} else
154234b664a2SJames Hogan #endif
154334b664a2SJames Hogan 	{
154434b664a2SJames Hogan 		u32 *pdata = buf;
154534b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
15464e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset), *pdata++);
154734b664a2SJames Hogan 		buf = pdata;
154834b664a2SJames Hogan 	}
154934b664a2SJames Hogan 	/* put anything remaining in the part_buf */
155034b664a2SJames Hogan 	if (cnt) {
155134b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1552cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1553cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1554cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
15554e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
15564e0a5adfSJaehoon Chung 				   host->part_buf32);
1557f95f3850SWill Newton 	}
1558f95f3850SWill Newton }
1559f95f3850SWill Newton 
1560f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
1561f95f3850SWill Newton {
156234b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
156334b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
156434b664a2SJames Hogan 		while (cnt >= 4) {
156534b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
156634b664a2SJames Hogan 			u32 aligned_buf[32];
156734b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
156834b664a2SJames Hogan 			int items = len >> 2;
156934b664a2SJames Hogan 			int i;
157034b664a2SJames Hogan 			for (i = 0; i < items; ++i)
15714e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readl(host,
15724e0a5adfSJaehoon Chung 						DATA(host->data_offset));
157334b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
157434b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
157534b664a2SJames Hogan 			buf += len;
157634b664a2SJames Hogan 			cnt -= len;
157734b664a2SJames Hogan 		}
157834b664a2SJames Hogan 	} else
157934b664a2SJames Hogan #endif
158034b664a2SJames Hogan 	{
158134b664a2SJames Hogan 		u32 *pdata = buf;
158234b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
15834e0a5adfSJaehoon Chung 			*pdata++ = mci_readl(host, DATA(host->data_offset));
158434b664a2SJames Hogan 		buf = pdata;
158534b664a2SJames Hogan 	}
158634b664a2SJames Hogan 	if (cnt) {
15874e0a5adfSJaehoon Chung 		host->part_buf32 = mci_readl(host, DATA(host->data_offset));
158834b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1589f95f3850SWill Newton 	}
1590f95f3850SWill Newton }
1591f95f3850SWill Newton 
1592f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
1593f95f3850SWill Newton {
1594cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1595cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1596cfbeb59cSMarkos Chandras 
159734b664a2SJames Hogan 	/* try and push anything in the part_buf */
159834b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
159934b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
160034b664a2SJames Hogan 		buf += len;
160134b664a2SJames Hogan 		cnt -= len;
1602c09fbd74SSeungwon Jeon 
1603cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 8) {
1604c09fbd74SSeungwon Jeon 			mci_writeq(host, DATA(host->data_offset),
16054e0a5adfSJaehoon Chung 					host->part_buf);
160634b664a2SJames Hogan 			host->part_buf_count = 0;
160734b664a2SJames Hogan 		}
160834b664a2SJames Hogan 	}
160934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
161034b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
161134b664a2SJames Hogan 		while (cnt >= 8) {
161234b664a2SJames Hogan 			u64 aligned_buf[16];
161334b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
161434b664a2SJames Hogan 			int items = len >> 3;
161534b664a2SJames Hogan 			int i;
161634b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
161734b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
161834b664a2SJames Hogan 			buf += len;
161934b664a2SJames Hogan 			cnt -= len;
162034b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
162134b664a2SJames Hogan 			for (i = 0; i < items; ++i)
16224e0a5adfSJaehoon Chung 				mci_writeq(host, DATA(host->data_offset),
16234e0a5adfSJaehoon Chung 						aligned_buf[i]);
162434b664a2SJames Hogan 		}
162534b664a2SJames Hogan 	} else
162634b664a2SJames Hogan #endif
162734b664a2SJames Hogan 	{
162834b664a2SJames Hogan 		u64 *pdata = buf;
162934b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
16304e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset), *pdata++);
163134b664a2SJames Hogan 		buf = pdata;
163234b664a2SJames Hogan 	}
163334b664a2SJames Hogan 	/* put anything remaining in the part_buf */
163434b664a2SJames Hogan 	if (cnt) {
163534b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1636cfbeb59cSMarkos Chandras 		/* Push data if we have reached the expected data length */
1637cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1638cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
16394e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset),
16404e0a5adfSJaehoon Chung 				   host->part_buf);
1641f95f3850SWill Newton 	}
1642f95f3850SWill Newton }
1643f95f3850SWill Newton 
1644f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
1645f95f3850SWill Newton {
164634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
164734b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
164834b664a2SJames Hogan 		while (cnt >= 8) {
164934b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
165034b664a2SJames Hogan 			u64 aligned_buf[16];
165134b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
165234b664a2SJames Hogan 			int items = len >> 3;
165334b664a2SJames Hogan 			int i;
165434b664a2SJames Hogan 			for (i = 0; i < items; ++i)
16554e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readq(host,
16564e0a5adfSJaehoon Chung 						DATA(host->data_offset));
165734b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
165834b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
165934b664a2SJames Hogan 			buf += len;
166034b664a2SJames Hogan 			cnt -= len;
1661f95f3850SWill Newton 		}
166234b664a2SJames Hogan 	} else
166334b664a2SJames Hogan #endif
166434b664a2SJames Hogan 	{
166534b664a2SJames Hogan 		u64 *pdata = buf;
166634b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
16674e0a5adfSJaehoon Chung 			*pdata++ = mci_readq(host, DATA(host->data_offset));
166834b664a2SJames Hogan 		buf = pdata;
166934b664a2SJames Hogan 	}
167034b664a2SJames Hogan 	if (cnt) {
16714e0a5adfSJaehoon Chung 		host->part_buf = mci_readq(host, DATA(host->data_offset));
167234b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
167334b664a2SJames Hogan 	}
167434b664a2SJames Hogan }
167534b664a2SJames Hogan 
167634b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
167734b664a2SJames Hogan {
167834b664a2SJames Hogan 	int len;
167934b664a2SJames Hogan 
168034b664a2SJames Hogan 	/* get remaining partial bytes */
168134b664a2SJames Hogan 	len = dw_mci_pull_part_bytes(host, buf, cnt);
168234b664a2SJames Hogan 	if (unlikely(len == cnt))
168334b664a2SJames Hogan 		return;
168434b664a2SJames Hogan 	buf += len;
168534b664a2SJames Hogan 	cnt -= len;
168634b664a2SJames Hogan 
168734b664a2SJames Hogan 	/* get the rest of the data */
168834b664a2SJames Hogan 	host->pull_data(host, buf, cnt);
1689f95f3850SWill Newton }
1690f95f3850SWill Newton 
169187a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto)
1692f95f3850SWill Newton {
1693f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1694f9c2a0dcSSeungwon Jeon 	void *buf;
1695f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1696f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1697f95f3850SWill Newton 	int shift = host->data_shift;
1698f95f3850SWill Newton 	u32 status;
16993e4b0d8bSMarkos Chandras 	unsigned int len;
1700f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1701f95f3850SWill Newton 
1702f95f3850SWill Newton 	do {
1703f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1704f9c2a0dcSSeungwon Jeon 			goto done;
1705f95f3850SWill Newton 
17064225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1707f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1708f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1709f9c2a0dcSSeungwon Jeon 		offset = 0;
1710f9c2a0dcSSeungwon Jeon 
1711f9c2a0dcSSeungwon Jeon 		do {
1712f9c2a0dcSSeungwon Jeon 			fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS))
1713f9c2a0dcSSeungwon Jeon 					<< shift) + host->part_buf_count;
1714f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1715f9c2a0dcSSeungwon Jeon 			if (!len)
1716f9c2a0dcSSeungwon Jeon 				break;
1717f9c2a0dcSSeungwon Jeon 			dw_mci_pull_data(host, (void *)(buf + offset), len);
17183e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1719f95f3850SWill Newton 			offset += len;
1720f9c2a0dcSSeungwon Jeon 			remain -= len;
1721f9c2a0dcSSeungwon Jeon 		} while (remain);
1722f95f3850SWill Newton 
1723e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1724f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1725f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
172687a74d39SKyoungil Kim 	/* if the RXDR is ready read again */
172787a74d39SKyoungil Kim 	} while ((status & SDMMC_INT_RXDR) ||
172887a74d39SKyoungil Kim 		 (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS))));
1729f9c2a0dcSSeungwon Jeon 
1730f9c2a0dcSSeungwon Jeon 	if (!remain) {
1731f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1732f9c2a0dcSSeungwon Jeon 			goto done;
1733f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1734f9c2a0dcSSeungwon Jeon 	}
1735f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1736f95f3850SWill Newton 	return;
1737f95f3850SWill Newton 
1738f95f3850SWill Newton done:
1739f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1740f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1741f95f3850SWill Newton 	smp_wmb();
1742f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1743f95f3850SWill Newton }
1744f95f3850SWill Newton 
1745f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host)
1746f95f3850SWill Newton {
1747f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1748f9c2a0dcSSeungwon Jeon 	void *buf;
1749f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1750f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1751f95f3850SWill Newton 	int shift = host->data_shift;
1752f95f3850SWill Newton 	u32 status;
17533e4b0d8bSMarkos Chandras 	unsigned int len;
1754f9c2a0dcSSeungwon Jeon 	unsigned int fifo_depth = host->fifo_depth;
1755f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1756f95f3850SWill Newton 
1757f95f3850SWill Newton 	do {
1758f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1759f9c2a0dcSSeungwon Jeon 			goto done;
1760f95f3850SWill Newton 
17614225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1762f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1763f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1764f9c2a0dcSSeungwon Jeon 		offset = 0;
1765f9c2a0dcSSeungwon Jeon 
1766f9c2a0dcSSeungwon Jeon 		do {
1767f9c2a0dcSSeungwon Jeon 			fcnt = ((fifo_depth -
1768f9c2a0dcSSeungwon Jeon 				 SDMMC_GET_FCNT(mci_readl(host, STATUS)))
1769f9c2a0dcSSeungwon Jeon 					<< shift) - host->part_buf_count;
1770f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1771f9c2a0dcSSeungwon Jeon 			if (!len)
1772f9c2a0dcSSeungwon Jeon 				break;
1773f9c2a0dcSSeungwon Jeon 			host->push_data(host, (void *)(buf + offset), len);
17743e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1775f95f3850SWill Newton 			offset += len;
1776f9c2a0dcSSeungwon Jeon 			remain -= len;
1777f9c2a0dcSSeungwon Jeon 		} while (remain);
1778f95f3850SWill Newton 
1779e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1780f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1781f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1782f95f3850SWill Newton 	} while (status & SDMMC_INT_TXDR); /* if TXDR write again */
1783f9c2a0dcSSeungwon Jeon 
1784f9c2a0dcSSeungwon Jeon 	if (!remain) {
1785f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1786f9c2a0dcSSeungwon Jeon 			goto done;
1787f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1788f9c2a0dcSSeungwon Jeon 	}
1789f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1790f95f3850SWill Newton 	return;
1791f95f3850SWill Newton 
1792f95f3850SWill Newton done:
1793f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1794f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1795f95f3850SWill Newton 	smp_wmb();
1796f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1797f95f3850SWill Newton }
1798f95f3850SWill Newton 
1799f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
1800f95f3850SWill Newton {
1801f95f3850SWill Newton 	if (!host->cmd_status)
1802f95f3850SWill Newton 		host->cmd_status = status;
1803f95f3850SWill Newton 
1804f95f3850SWill Newton 	smp_wmb();
1805f95f3850SWill Newton 
1806f95f3850SWill Newton 	set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1807f95f3850SWill Newton 	tasklet_schedule(&host->tasklet);
1808f95f3850SWill Newton }
1809f95f3850SWill Newton 
1810f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
1811f95f3850SWill Newton {
1812f95f3850SWill Newton 	struct dw_mci *host = dev_id;
1813182c9081SSeungwon Jeon 	u32 pending;
18141a5c8e1fSShashidhar Hiremath 	int i;
1815f95f3850SWill Newton 
1816f95f3850SWill Newton 	pending = mci_readl(host, MINTSTS); /* read-only mask reg */
1817f95f3850SWill Newton 
1818f95f3850SWill Newton 	/*
1819f95f3850SWill Newton 	 * DTO fix - version 2.10a and below, and only if internal DMA
1820f95f3850SWill Newton 	 * is configured.
1821f95f3850SWill Newton 	 */
1822f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
1823f95f3850SWill Newton 		if (!pending &&
1824f95f3850SWill Newton 		    ((mci_readl(host, STATUS) >> 17) & 0x1fff))
1825f95f3850SWill Newton 			pending |= SDMMC_INT_DATA_OVER;
1826f95f3850SWill Newton 	}
1827f95f3850SWill Newton 
1828476d79f1SDoug Anderson 	if (pending) {
1829f95f3850SWill Newton 		if (pending & DW_MCI_CMD_ERROR_FLAGS) {
1830f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
1831182c9081SSeungwon Jeon 			host->cmd_status = pending;
1832f95f3850SWill Newton 			smp_wmb();
1833f95f3850SWill Newton 			set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1834f95f3850SWill Newton 		}
1835f95f3850SWill Newton 
1836f95f3850SWill Newton 		if (pending & DW_MCI_DATA_ERROR_FLAGS) {
1837f95f3850SWill Newton 			/* if there is an error report DATA_ERROR */
1838f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
1839182c9081SSeungwon Jeon 			host->data_status = pending;
1840f95f3850SWill Newton 			smp_wmb();
1841f95f3850SWill Newton 			set_bit(EVENT_DATA_ERROR, &host->pending_events);
1842f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
1843f95f3850SWill Newton 		}
1844f95f3850SWill Newton 
1845f95f3850SWill Newton 		if (pending & SDMMC_INT_DATA_OVER) {
1846f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
1847f95f3850SWill Newton 			if (!host->data_status)
1848182c9081SSeungwon Jeon 				host->data_status = pending;
1849f95f3850SWill Newton 			smp_wmb();
1850f95f3850SWill Newton 			if (host->dir_status == DW_MCI_RECV_STATUS) {
1851f95f3850SWill Newton 				if (host->sg != NULL)
185287a74d39SKyoungil Kim 					dw_mci_read_data_pio(host, true);
1853f95f3850SWill Newton 			}
1854f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
1855f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
1856f95f3850SWill Newton 		}
1857f95f3850SWill Newton 
1858f95f3850SWill Newton 		if (pending & SDMMC_INT_RXDR) {
1859f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
1860b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_RECV_STATUS && host->sg)
186187a74d39SKyoungil Kim 				dw_mci_read_data_pio(host, false);
1862f95f3850SWill Newton 		}
1863f95f3850SWill Newton 
1864f95f3850SWill Newton 		if (pending & SDMMC_INT_TXDR) {
1865f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1866b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_SEND_STATUS && host->sg)
1867f95f3850SWill Newton 				dw_mci_write_data_pio(host);
1868f95f3850SWill Newton 		}
1869f95f3850SWill Newton 
1870f95f3850SWill Newton 		if (pending & SDMMC_INT_CMD_DONE) {
1871f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
1872182c9081SSeungwon Jeon 			dw_mci_cmd_interrupt(host, pending);
1873f95f3850SWill Newton 		}
1874f95f3850SWill Newton 
1875f95f3850SWill Newton 		if (pending & SDMMC_INT_CD) {
1876f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CD);
187795dcc2cbSThomas Abraham 			queue_work(host->card_workqueue, &host->card_work);
1878f95f3850SWill Newton 		}
1879f95f3850SWill Newton 
18801a5c8e1fSShashidhar Hiremath 		/* Handle SDIO Interrupts */
18811a5c8e1fSShashidhar Hiremath 		for (i = 0; i < host->num_slots; i++) {
18821a5c8e1fSShashidhar Hiremath 			struct dw_mci_slot *slot = host->slot[i];
18831a5c8e1fSShashidhar Hiremath 			if (pending & SDMMC_INT_SDIO(i)) {
18841a5c8e1fSShashidhar Hiremath 				mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
18851a5c8e1fSShashidhar Hiremath 				mmc_signal_sdio_irq(slot->mmc);
18861a5c8e1fSShashidhar Hiremath 			}
18871a5c8e1fSShashidhar Hiremath 		}
18881a5c8e1fSShashidhar Hiremath 
18891fb5f68aSMarkos Chandras 	}
1890f95f3850SWill Newton 
1891f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
1892f95f3850SWill Newton 	/* Handle DMA interrupts */
1893f95f3850SWill Newton 	pending = mci_readl(host, IDSTS);
1894f95f3850SWill Newton 	if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
1895f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
1896f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
1897f95f3850SWill Newton 		host->dma_ops->complete(host);
1898f95f3850SWill Newton 	}
1899f95f3850SWill Newton #endif
1900f95f3850SWill Newton 
1901f95f3850SWill Newton 	return IRQ_HANDLED;
1902f95f3850SWill Newton }
1903f95f3850SWill Newton 
19041791b13eSJames Hogan static void dw_mci_work_routine_card(struct work_struct *work)
1905f95f3850SWill Newton {
19061791b13eSJames Hogan 	struct dw_mci *host = container_of(work, struct dw_mci, card_work);
1907f95f3850SWill Newton 	int i;
1908f95f3850SWill Newton 
1909f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
1910f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
1911f95f3850SWill Newton 		struct mmc_host *mmc = slot->mmc;
1912f95f3850SWill Newton 		struct mmc_request *mrq;
1913f95f3850SWill Newton 		int present;
1914f95f3850SWill Newton 
1915f95f3850SWill Newton 		present = dw_mci_get_cd(mmc);
1916f95f3850SWill Newton 		while (present != slot->last_detect_state) {
1917f95f3850SWill Newton 			dev_dbg(&slot->mmc->class_dev, "card %s\n",
1918f95f3850SWill Newton 				present ? "inserted" : "removed");
1919f95f3850SWill Newton 
19201791b13eSJames Hogan 			spin_lock_bh(&host->lock);
19211791b13eSJames Hogan 
1922f95f3850SWill Newton 			/* Card change detected */
1923f95f3850SWill Newton 			slot->last_detect_state = present;
1924f95f3850SWill Newton 
1925f95f3850SWill Newton 			/* Clean up queue if present */
1926f95f3850SWill Newton 			mrq = slot->mrq;
1927f95f3850SWill Newton 			if (mrq) {
1928f95f3850SWill Newton 				if (mrq == host->mrq) {
1929f95f3850SWill Newton 					host->data = NULL;
1930f95f3850SWill Newton 					host->cmd = NULL;
1931f95f3850SWill Newton 
1932f95f3850SWill Newton 					switch (host->state) {
1933f95f3850SWill Newton 					case STATE_IDLE:
1934f95f3850SWill Newton 						break;
1935f95f3850SWill Newton 					case STATE_SENDING_CMD:
1936f95f3850SWill Newton 						mrq->cmd->error = -ENOMEDIUM;
1937f95f3850SWill Newton 						if (!mrq->data)
1938f95f3850SWill Newton 							break;
1939f95f3850SWill Newton 						/* fall through */
1940f95f3850SWill Newton 					case STATE_SENDING_DATA:
1941f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
1942f95f3850SWill Newton 						dw_mci_stop_dma(host);
1943f95f3850SWill Newton 						break;
1944f95f3850SWill Newton 					case STATE_DATA_BUSY:
1945f95f3850SWill Newton 					case STATE_DATA_ERROR:
1946f95f3850SWill Newton 						if (mrq->data->error == -EINPROGRESS)
1947f95f3850SWill Newton 							mrq->data->error = -ENOMEDIUM;
1948f95f3850SWill Newton 						/* fall through */
1949f95f3850SWill Newton 					case STATE_SENDING_STOP:
195090c2143aSSeungwon Jeon 						if (mrq->stop)
1951f95f3850SWill Newton 							mrq->stop->error = -ENOMEDIUM;
1952f95f3850SWill Newton 						break;
1953f95f3850SWill Newton 					}
1954f95f3850SWill Newton 
1955f95f3850SWill Newton 					dw_mci_request_end(host, mrq);
1956f95f3850SWill Newton 				} else {
1957f95f3850SWill Newton 					list_del(&slot->queue_node);
1958f95f3850SWill Newton 					mrq->cmd->error = -ENOMEDIUM;
1959f95f3850SWill Newton 					if (mrq->data)
1960f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
1961f95f3850SWill Newton 					if (mrq->stop)
1962f95f3850SWill Newton 						mrq->stop->error = -ENOMEDIUM;
1963f95f3850SWill Newton 
1964f95f3850SWill Newton 					spin_unlock(&host->lock);
1965f95f3850SWill Newton 					mmc_request_done(slot->mmc, mrq);
1966f95f3850SWill Newton 					spin_lock(&host->lock);
1967f95f3850SWill Newton 				}
1968f95f3850SWill Newton 			}
1969f95f3850SWill Newton 
1970f95f3850SWill Newton 			/* Power down slot */
1971f95f3850SWill Newton 			if (present == 0) {
197231bff450SSeungwon Jeon 				/* Clear down the FIFO */
197331bff450SSeungwon Jeon 				dw_mci_fifo_reset(host);
1974f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
19755ce9d961SSeungwon Jeon 				dw_mci_idmac_reset(host);
1976f95f3850SWill Newton #endif
1977f95f3850SWill Newton 
1978f95f3850SWill Newton 			}
1979f95f3850SWill Newton 
19801791b13eSJames Hogan 			spin_unlock_bh(&host->lock);
19811791b13eSJames Hogan 
1982f95f3850SWill Newton 			present = dw_mci_get_cd(mmc);
1983f95f3850SWill Newton 		}
1984f95f3850SWill Newton 
1985f95f3850SWill Newton 		mmc_detect_change(slot->mmc,
1986f95f3850SWill Newton 			msecs_to_jiffies(host->pdata->detect_delay_ms));
1987f95f3850SWill Newton 	}
1988f95f3850SWill Newton }
1989f95f3850SWill Newton 
1990c91eab4bSThomas Abraham #ifdef CONFIG_OF
1991c91eab4bSThomas Abraham /* given a slot id, find out the device node representing that slot */
1992c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
1993c91eab4bSThomas Abraham {
1994c91eab4bSThomas Abraham 	struct device_node *np;
1995c91eab4bSThomas Abraham 	const __be32 *addr;
1996c91eab4bSThomas Abraham 	int len;
1997c91eab4bSThomas Abraham 
1998c91eab4bSThomas Abraham 	if (!dev || !dev->of_node)
1999c91eab4bSThomas Abraham 		return NULL;
2000c91eab4bSThomas Abraham 
2001c91eab4bSThomas Abraham 	for_each_child_of_node(dev->of_node, np) {
2002c91eab4bSThomas Abraham 		addr = of_get_property(np, "reg", &len);
2003c91eab4bSThomas Abraham 		if (!addr || (len < sizeof(int)))
2004c91eab4bSThomas Abraham 			continue;
2005c91eab4bSThomas Abraham 		if (be32_to_cpup(addr) == slot)
2006c91eab4bSThomas Abraham 			return np;
2007c91eab4bSThomas Abraham 	}
2008c91eab4bSThomas Abraham 	return NULL;
2009c91eab4bSThomas Abraham }
2010c91eab4bSThomas Abraham 
2011a70aaa64SDoug Anderson static struct dw_mci_of_slot_quirks {
2012a70aaa64SDoug Anderson 	char *quirk;
2013a70aaa64SDoug Anderson 	int id;
2014a70aaa64SDoug Anderson } of_slot_quirks[] = {
2015a70aaa64SDoug Anderson 	{
2016a70aaa64SDoug Anderson 		.quirk	= "disable-wp",
2017a70aaa64SDoug Anderson 		.id	= DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT,
2018a70aaa64SDoug Anderson 	},
2019a70aaa64SDoug Anderson };
2020a70aaa64SDoug Anderson 
2021a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
2022a70aaa64SDoug Anderson {
2023a70aaa64SDoug Anderson 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
2024a70aaa64SDoug Anderson 	int quirks = 0;
2025a70aaa64SDoug Anderson 	int idx;
2026a70aaa64SDoug Anderson 
2027a70aaa64SDoug Anderson 	/* get quirks */
2028a70aaa64SDoug Anderson 	for (idx = 0; idx < ARRAY_SIZE(of_slot_quirks); idx++)
2029a70aaa64SDoug Anderson 		if (of_get_property(np, of_slot_quirks[idx].quirk, NULL))
2030a70aaa64SDoug Anderson 			quirks |= of_slot_quirks[idx].id;
2031a70aaa64SDoug Anderson 
2032a70aaa64SDoug Anderson 	return quirks;
2033a70aaa64SDoug Anderson }
2034a70aaa64SDoug Anderson 
203555a6ceb2SDoug Anderson /* find the write protect gpio for a given slot; or -1 if none specified */
203655a6ceb2SDoug Anderson static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
203755a6ceb2SDoug Anderson {
203855a6ceb2SDoug Anderson 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
203955a6ceb2SDoug Anderson 	int gpio;
204055a6ceb2SDoug Anderson 
204155a6ceb2SDoug Anderson 	if (!np)
204255a6ceb2SDoug Anderson 		return -EINVAL;
204355a6ceb2SDoug Anderson 
204455a6ceb2SDoug Anderson 	gpio = of_get_named_gpio(np, "wp-gpios", 0);
204555a6ceb2SDoug Anderson 
204655a6ceb2SDoug Anderson 	/* Having a missing entry is valid; return silently */
204755a6ceb2SDoug Anderson 	if (!gpio_is_valid(gpio))
204855a6ceb2SDoug Anderson 		return -EINVAL;
204955a6ceb2SDoug Anderson 
205055a6ceb2SDoug Anderson 	if (devm_gpio_request(dev, gpio, "dw-mci-wp")) {
205155a6ceb2SDoug Anderson 		dev_warn(dev, "gpio [%d] request failed\n", gpio);
205255a6ceb2SDoug Anderson 		return -EINVAL;
205355a6ceb2SDoug Anderson 	}
205455a6ceb2SDoug Anderson 
205555a6ceb2SDoug Anderson 	return gpio;
205655a6ceb2SDoug Anderson }
2057bf626e55SZhangfei Gao 
20587cf347bdSZhangfei Gao /* find the cd gpio for a given slot */
2059bf626e55SZhangfei Gao static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
2060bf626e55SZhangfei Gao 					struct mmc_host *mmc)
2061bf626e55SZhangfei Gao {
2062bf626e55SZhangfei Gao 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
2063bf626e55SZhangfei Gao 	int gpio;
2064bf626e55SZhangfei Gao 
2065bf626e55SZhangfei Gao 	if (!np)
2066bf626e55SZhangfei Gao 		return;
2067bf626e55SZhangfei Gao 
2068bf626e55SZhangfei Gao 	gpio = of_get_named_gpio(np, "cd-gpios", 0);
2069bf626e55SZhangfei Gao 
2070bf626e55SZhangfei Gao 	/* Having a missing entry is valid; return silently */
2071bf626e55SZhangfei Gao 	if (!gpio_is_valid(gpio))
2072bf626e55SZhangfei Gao 		return;
2073bf626e55SZhangfei Gao 
2074bf626e55SZhangfei Gao 	if (mmc_gpio_request_cd(mmc, gpio, 0))
2075bf626e55SZhangfei Gao 		dev_warn(dev, "gpio [%d] request failed\n", gpio);
2076bf626e55SZhangfei Gao }
2077c91eab4bSThomas Abraham #else /* CONFIG_OF */
2078a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
2079a70aaa64SDoug Anderson {
2080a70aaa64SDoug Anderson 	return 0;
2081a70aaa64SDoug Anderson }
2082c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
2083c91eab4bSThomas Abraham {
2084c91eab4bSThomas Abraham 	return NULL;
2085c91eab4bSThomas Abraham }
208655a6ceb2SDoug Anderson static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
208755a6ceb2SDoug Anderson {
208855a6ceb2SDoug Anderson 	return -EINVAL;
208955a6ceb2SDoug Anderson }
2090bf626e55SZhangfei Gao static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
2091bf626e55SZhangfei Gao 					struct mmc_host *mmc)
2092bf626e55SZhangfei Gao {
2093bf626e55SZhangfei Gao 	return;
2094bf626e55SZhangfei Gao }
2095c91eab4bSThomas Abraham #endif /* CONFIG_OF */
2096c91eab4bSThomas Abraham 
209736c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
2098f95f3850SWill Newton {
2099f95f3850SWill Newton 	struct mmc_host *mmc;
2100f95f3850SWill Newton 	struct dw_mci_slot *slot;
2101e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
2102800d78bfSThomas Abraham 	int ctrl_id, ret;
21031f44a2a5SSeungwon Jeon 	u32 freq[2];
2104f95f3850SWill Newton 
21054a90920cSThomas Abraham 	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
2106f95f3850SWill Newton 	if (!mmc)
2107f95f3850SWill Newton 		return -ENOMEM;
2108f95f3850SWill Newton 
2109f95f3850SWill Newton 	slot = mmc_priv(mmc);
2110f95f3850SWill Newton 	slot->id = id;
2111f95f3850SWill Newton 	slot->mmc = mmc;
2112f95f3850SWill Newton 	slot->host = host;
2113c91eab4bSThomas Abraham 	host->slot[id] = slot;
2114f95f3850SWill Newton 
2115a70aaa64SDoug Anderson 	slot->quirks = dw_mci_of_get_slot_quirks(host->dev, slot->id);
2116a70aaa64SDoug Anderson 
2117f95f3850SWill Newton 	mmc->ops = &dw_mci_ops;
21181f44a2a5SSeungwon Jeon 	if (of_property_read_u32_array(host->dev->of_node,
21191f44a2a5SSeungwon Jeon 				       "clock-freq-min-max", freq, 2)) {
21201f44a2a5SSeungwon Jeon 		mmc->f_min = DW_MCI_FREQ_MIN;
21211f44a2a5SSeungwon Jeon 		mmc->f_max = DW_MCI_FREQ_MAX;
21221f44a2a5SSeungwon Jeon 	} else {
21231f44a2a5SSeungwon Jeon 		mmc->f_min = freq[0];
21241f44a2a5SSeungwon Jeon 		mmc->f_max = freq[1];
21251f44a2a5SSeungwon Jeon 	}
2126f95f3850SWill Newton 
2127f95f3850SWill Newton 	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
2128f95f3850SWill Newton 
2129fc3d7720SJaehoon Chung 	if (host->pdata->caps)
2130fc3d7720SJaehoon Chung 		mmc->caps = host->pdata->caps;
2131fc3d7720SJaehoon Chung 
2132ab269128SAbhilash Kesavan 	if (host->pdata->pm_caps)
2133ab269128SAbhilash Kesavan 		mmc->pm_caps = host->pdata->pm_caps;
2134ab269128SAbhilash Kesavan 
2135800d78bfSThomas Abraham 	if (host->dev->of_node) {
2136800d78bfSThomas Abraham 		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
2137800d78bfSThomas Abraham 		if (ctrl_id < 0)
2138800d78bfSThomas Abraham 			ctrl_id = 0;
2139800d78bfSThomas Abraham 	} else {
2140800d78bfSThomas Abraham 		ctrl_id = to_platform_device(host->dev)->id;
2141800d78bfSThomas Abraham 	}
2142cb27a843SJames Hogan 	if (drv_data && drv_data->caps)
2143cb27a843SJames Hogan 		mmc->caps |= drv_data->caps[ctrl_id];
2144800d78bfSThomas Abraham 
21454f408cc6SSeungwon Jeon 	if (host->pdata->caps2)
21464f408cc6SSeungwon Jeon 		mmc->caps2 = host->pdata->caps2;
21474f408cc6SSeungwon Jeon 
2148d8a4fb0eSJaehoon Chung 	mmc_of_parse(mmc);
2149f95f3850SWill Newton 
2150f95f3850SWill Newton 	if (host->pdata->blk_settings) {
2151f95f3850SWill Newton 		mmc->max_segs = host->pdata->blk_settings->max_segs;
2152f95f3850SWill Newton 		mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
2153f95f3850SWill Newton 		mmc->max_blk_count = host->pdata->blk_settings->max_blk_count;
2154f95f3850SWill Newton 		mmc->max_req_size = host->pdata->blk_settings->max_req_size;
2155f95f3850SWill Newton 		mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
2156f95f3850SWill Newton 	} else {
2157f95f3850SWill Newton 		/* Useful defaults if platform data is unset. */
2158a39e5746SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
2159a39e5746SJaehoon Chung 		mmc->max_segs = host->ring_size;
2160a39e5746SJaehoon Chung 		mmc->max_blk_size = 65536;
2161a39e5746SJaehoon Chung 		mmc->max_blk_count = host->ring_size;
2162a39e5746SJaehoon Chung 		mmc->max_seg_size = 0x1000;
2163a39e5746SJaehoon Chung 		mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
2164a39e5746SJaehoon Chung #else
2165f95f3850SWill Newton 		mmc->max_segs = 64;
2166f95f3850SWill Newton 		mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
2167f95f3850SWill Newton 		mmc->max_blk_count = 512;
2168f95f3850SWill Newton 		mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
2169f95f3850SWill Newton 		mmc->max_seg_size = mmc->max_req_size;
2170f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */
2171a39e5746SJaehoon Chung 	}
2172f95f3850SWill Newton 
217355a6ceb2SDoug Anderson 	slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id);
2174bf626e55SZhangfei Gao 	dw_mci_of_get_cd_gpio(host->dev, slot->id, mmc);
217555a6ceb2SDoug Anderson 
21760cea529dSJaehoon Chung 	ret = mmc_add_host(mmc);
21770cea529dSJaehoon Chung 	if (ret)
21780cea529dSJaehoon Chung 		goto err_setup_bus;
2179f95f3850SWill Newton 
2180f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS)
2181f95f3850SWill Newton 	dw_mci_init_debugfs(slot);
2182f95f3850SWill Newton #endif
2183f95f3850SWill Newton 
2184f95f3850SWill Newton 	/* Card initially undetected */
2185f95f3850SWill Newton 	slot->last_detect_state = 0;
2186f95f3850SWill Newton 
2187f95f3850SWill Newton 	return 0;
2188800d78bfSThomas Abraham 
2189800d78bfSThomas Abraham err_setup_bus:
2190800d78bfSThomas Abraham 	mmc_free_host(mmc);
2191800d78bfSThomas Abraham 	return -EINVAL;
2192f95f3850SWill Newton }
2193f95f3850SWill Newton 
2194f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
2195f95f3850SWill Newton {
2196f95f3850SWill Newton 	/* Debugfs stuff is cleaned up by mmc core */
2197f95f3850SWill Newton 	mmc_remove_host(slot->mmc);
2198f95f3850SWill Newton 	slot->host->slot[id] = NULL;
2199f95f3850SWill Newton 	mmc_free_host(slot->mmc);
2200f95f3850SWill Newton }
2201f95f3850SWill Newton 
2202f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host)
2203f95f3850SWill Newton {
2204f95f3850SWill Newton 	/* Alloc memory for sg translation */
2205780f22afSSeungwon Jeon 	host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
2206f95f3850SWill Newton 					  &host->sg_dma, GFP_KERNEL);
2207f95f3850SWill Newton 	if (!host->sg_cpu) {
22084a90920cSThomas Abraham 		dev_err(host->dev, "%s: could not alloc DMA memory\n",
2209f95f3850SWill Newton 			__func__);
2210f95f3850SWill Newton 		goto no_dma;
2211f95f3850SWill Newton 	}
2212f95f3850SWill Newton 
2213f95f3850SWill Newton 	/* Determine which DMA interface to use */
2214f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
2215f95f3850SWill Newton 	host->dma_ops = &dw_mci_idmac_ops;
221600956ea3SSeungwon Jeon 	dev_info(host->dev, "Using internal DMA controller.\n");
2217f95f3850SWill Newton #endif
2218f95f3850SWill Newton 
2219f95f3850SWill Newton 	if (!host->dma_ops)
2220f95f3850SWill Newton 		goto no_dma;
2221f95f3850SWill Newton 
2222e1631f98SJaehoon Chung 	if (host->dma_ops->init && host->dma_ops->start &&
2223e1631f98SJaehoon Chung 	    host->dma_ops->stop && host->dma_ops->cleanup) {
2224f95f3850SWill Newton 		if (host->dma_ops->init(host)) {
22254a90920cSThomas Abraham 			dev_err(host->dev, "%s: Unable to initialize "
2226f95f3850SWill Newton 				"DMA Controller.\n", __func__);
2227f95f3850SWill Newton 			goto no_dma;
2228f95f3850SWill Newton 		}
2229f95f3850SWill Newton 	} else {
22304a90920cSThomas Abraham 		dev_err(host->dev, "DMA initialization not found.\n");
2231f95f3850SWill Newton 		goto no_dma;
2232f95f3850SWill Newton 	}
2233f95f3850SWill Newton 
2234f95f3850SWill Newton 	host->use_dma = 1;
2235f95f3850SWill Newton 	return;
2236f95f3850SWill Newton 
2237f95f3850SWill Newton no_dma:
22384a90920cSThomas Abraham 	dev_info(host->dev, "Using PIO mode.\n");
2239f95f3850SWill Newton 	host->use_dma = 0;
2240f95f3850SWill Newton 	return;
2241f95f3850SWill Newton }
2242f95f3850SWill Newton 
224331bff450SSeungwon Jeon static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset)
2244f95f3850SWill Newton {
2245f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
224631bff450SSeungwon Jeon 	u32 ctrl;
2247f95f3850SWill Newton 
224831bff450SSeungwon Jeon 	ctrl = mci_readl(host, CTRL);
224931bff450SSeungwon Jeon 	ctrl |= reset;
225031bff450SSeungwon Jeon 	mci_writel(host, CTRL, ctrl);
2251f95f3850SWill Newton 
2252f95f3850SWill Newton 	/* wait till resets clear */
2253f95f3850SWill Newton 	do {
2254f95f3850SWill Newton 		ctrl = mci_readl(host, CTRL);
225531bff450SSeungwon Jeon 		if (!(ctrl & reset))
2256f95f3850SWill Newton 			return true;
2257f95f3850SWill Newton 	} while (time_before(jiffies, timeout));
2258f95f3850SWill Newton 
225931bff450SSeungwon Jeon 	dev_err(host->dev,
226031bff450SSeungwon Jeon 		"Timeout resetting block (ctrl reset %#x)\n",
226131bff450SSeungwon Jeon 		ctrl & reset);
2262f95f3850SWill Newton 
2263f95f3850SWill Newton 	return false;
2264f95f3850SWill Newton }
2265f95f3850SWill Newton 
226631bff450SSeungwon Jeon static inline bool dw_mci_fifo_reset(struct dw_mci *host)
226731bff450SSeungwon Jeon {
226831bff450SSeungwon Jeon 	/*
226931bff450SSeungwon Jeon 	 * Reseting generates a block interrupt, hence setting
227031bff450SSeungwon Jeon 	 * the scatter-gather pointer to NULL.
227131bff450SSeungwon Jeon 	 */
227231bff450SSeungwon Jeon 	if (host->sg) {
227331bff450SSeungwon Jeon 		sg_miter_stop(&host->sg_miter);
227431bff450SSeungwon Jeon 		host->sg = NULL;
227531bff450SSeungwon Jeon 	}
227631bff450SSeungwon Jeon 
227731bff450SSeungwon Jeon 	return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET);
227831bff450SSeungwon Jeon }
227931bff450SSeungwon Jeon 
228031bff450SSeungwon Jeon static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host)
228131bff450SSeungwon Jeon {
228231bff450SSeungwon Jeon 	return dw_mci_ctrl_reset(host,
228331bff450SSeungwon Jeon 				 SDMMC_CTRL_FIFO_RESET |
228431bff450SSeungwon Jeon 				 SDMMC_CTRL_RESET |
228531bff450SSeungwon Jeon 				 SDMMC_CTRL_DMA_RESET);
228631bff450SSeungwon Jeon }
228731bff450SSeungwon Jeon 
2288c91eab4bSThomas Abraham #ifdef CONFIG_OF
2289c91eab4bSThomas Abraham static struct dw_mci_of_quirks {
2290c91eab4bSThomas Abraham 	char *quirk;
2291c91eab4bSThomas Abraham 	int id;
2292c91eab4bSThomas Abraham } of_quirks[] = {
2293c91eab4bSThomas Abraham 	{
2294c91eab4bSThomas Abraham 		.quirk	= "broken-cd",
2295c91eab4bSThomas Abraham 		.id	= DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
2296c91eab4bSThomas Abraham 	},
2297c91eab4bSThomas Abraham };
2298c91eab4bSThomas Abraham 
2299c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2300c91eab4bSThomas Abraham {
2301c91eab4bSThomas Abraham 	struct dw_mci_board *pdata;
2302c91eab4bSThomas Abraham 	struct device *dev = host->dev;
2303c91eab4bSThomas Abraham 	struct device_node *np = dev->of_node;
2304e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
2305800d78bfSThomas Abraham 	int idx, ret;
23063c6d89eaSDoug Anderson 	u32 clock_frequency;
2307c91eab4bSThomas Abraham 
2308c91eab4bSThomas Abraham 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
2309c91eab4bSThomas Abraham 	if (!pdata) {
2310c91eab4bSThomas Abraham 		dev_err(dev, "could not allocate memory for pdata\n");
2311c91eab4bSThomas Abraham 		return ERR_PTR(-ENOMEM);
2312c91eab4bSThomas Abraham 	}
2313c91eab4bSThomas Abraham 
2314c91eab4bSThomas Abraham 	/* find out number of slots supported */
2315c91eab4bSThomas Abraham 	if (of_property_read_u32(dev->of_node, "num-slots",
2316c91eab4bSThomas Abraham 				&pdata->num_slots)) {
2317c91eab4bSThomas Abraham 		dev_info(dev, "num-slots property not found, "
2318c91eab4bSThomas Abraham 				"assuming 1 slot is available\n");
2319c91eab4bSThomas Abraham 		pdata->num_slots = 1;
2320c91eab4bSThomas Abraham 	}
2321c91eab4bSThomas Abraham 
2322c91eab4bSThomas Abraham 	/* get quirks */
2323c91eab4bSThomas Abraham 	for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++)
2324c91eab4bSThomas Abraham 		if (of_get_property(np, of_quirks[idx].quirk, NULL))
2325c91eab4bSThomas Abraham 			pdata->quirks |= of_quirks[idx].id;
2326c91eab4bSThomas Abraham 
2327c91eab4bSThomas Abraham 	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
2328c91eab4bSThomas Abraham 		dev_info(dev, "fifo-depth property not found, using "
2329c91eab4bSThomas Abraham 				"value of FIFOTH register as default\n");
2330c91eab4bSThomas Abraham 
2331c91eab4bSThomas Abraham 	of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
2332c91eab4bSThomas Abraham 
23333c6d89eaSDoug Anderson 	if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
23343c6d89eaSDoug Anderson 		pdata->bus_hz = clock_frequency;
23353c6d89eaSDoug Anderson 
2336cb27a843SJames Hogan 	if (drv_data && drv_data->parse_dt) {
2337cb27a843SJames Hogan 		ret = drv_data->parse_dt(host);
2338800d78bfSThomas Abraham 		if (ret)
2339800d78bfSThomas Abraham 			return ERR_PTR(ret);
2340800d78bfSThomas Abraham 	}
2341800d78bfSThomas Abraham 
234210b49841SSeungwon Jeon 	if (of_find_property(np, "supports-highspeed", NULL))
234310b49841SSeungwon Jeon 		pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
234410b49841SSeungwon Jeon 
2345c91eab4bSThomas Abraham 	return pdata;
2346c91eab4bSThomas Abraham }
2347c91eab4bSThomas Abraham 
2348c91eab4bSThomas Abraham #else /* CONFIG_OF */
2349c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2350c91eab4bSThomas Abraham {
2351c91eab4bSThomas Abraham 	return ERR_PTR(-EINVAL);
2352c91eab4bSThomas Abraham }
2353c91eab4bSThomas Abraham #endif /* CONFIG_OF */
2354c91eab4bSThomas Abraham 
235562ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host)
2356f95f3850SWill Newton {
2357e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
235862ca8034SShashidhar Hiremath 	int width, i, ret = 0;
2359f95f3850SWill Newton 	u32 fifo_size;
23601c2215b7SThomas Abraham 	int init_slots = 0;
2361f95f3850SWill Newton 
2362c91eab4bSThomas Abraham 	if (!host->pdata) {
2363c91eab4bSThomas Abraham 		host->pdata = dw_mci_parse_dt(host);
2364c91eab4bSThomas Abraham 		if (IS_ERR(host->pdata)) {
2365c91eab4bSThomas Abraham 			dev_err(host->dev, "platform data not available\n");
2366c91eab4bSThomas Abraham 			return -EINVAL;
2367c91eab4bSThomas Abraham 		}
2368f95f3850SWill Newton 	}
2369f95f3850SWill Newton 
2370907abd51SJaehoon Chung 	if (host->pdata->num_slots > 1) {
23714a90920cSThomas Abraham 		dev_err(host->dev,
2372907abd51SJaehoon Chung 			"Platform data must supply num_slots.\n");
237362ca8034SShashidhar Hiremath 		return -ENODEV;
2374f95f3850SWill Newton 	}
2375f95f3850SWill Newton 
2376780f22afSSeungwon Jeon 	host->biu_clk = devm_clk_get(host->dev, "biu");
2377f90a0612SThomas Abraham 	if (IS_ERR(host->biu_clk)) {
2378f90a0612SThomas Abraham 		dev_dbg(host->dev, "biu clock not available\n");
2379f90a0612SThomas Abraham 	} else {
2380f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->biu_clk);
2381f90a0612SThomas Abraham 		if (ret) {
2382f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable biu clock\n");
2383f90a0612SThomas Abraham 			return ret;
2384f90a0612SThomas Abraham 		}
2385f95f3850SWill Newton 	}
2386f95f3850SWill Newton 
2387780f22afSSeungwon Jeon 	host->ciu_clk = devm_clk_get(host->dev, "ciu");
2388f90a0612SThomas Abraham 	if (IS_ERR(host->ciu_clk)) {
2389f90a0612SThomas Abraham 		dev_dbg(host->dev, "ciu clock not available\n");
23903c6d89eaSDoug Anderson 		host->bus_hz = host->pdata->bus_hz;
2391f90a0612SThomas Abraham 	} else {
2392f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->ciu_clk);
2393f90a0612SThomas Abraham 		if (ret) {
2394f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable ciu clock\n");
2395f90a0612SThomas Abraham 			goto err_clk_biu;
2396f90a0612SThomas Abraham 		}
2397f90a0612SThomas Abraham 
23983c6d89eaSDoug Anderson 		if (host->pdata->bus_hz) {
23993c6d89eaSDoug Anderson 			ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz);
24003c6d89eaSDoug Anderson 			if (ret)
24013c6d89eaSDoug Anderson 				dev_warn(host->dev,
2402612de4c1SJaehoon Chung 					 "Unable to set bus rate to %uHz\n",
24033c6d89eaSDoug Anderson 					 host->pdata->bus_hz);
24043c6d89eaSDoug Anderson 		}
2405f90a0612SThomas Abraham 		host->bus_hz = clk_get_rate(host->ciu_clk);
24063c6d89eaSDoug Anderson 	}
2407f90a0612SThomas Abraham 
2408612de4c1SJaehoon Chung 	if (!host->bus_hz) {
2409612de4c1SJaehoon Chung 		dev_err(host->dev,
2410612de4c1SJaehoon Chung 			"Platform data must supply bus speed\n");
2411612de4c1SJaehoon Chung 		ret = -ENODEV;
2412612de4c1SJaehoon Chung 		goto err_clk_ciu;
2413612de4c1SJaehoon Chung 	}
2414612de4c1SJaehoon Chung 
2415002f0d5cSYuvaraj Kumar C D 	if (drv_data && drv_data->init) {
2416002f0d5cSYuvaraj Kumar C D 		ret = drv_data->init(host);
2417002f0d5cSYuvaraj Kumar C D 		if (ret) {
2418002f0d5cSYuvaraj Kumar C D 			dev_err(host->dev,
2419002f0d5cSYuvaraj Kumar C D 				"implementation specific init failed\n");
2420002f0d5cSYuvaraj Kumar C D 			goto err_clk_ciu;
2421002f0d5cSYuvaraj Kumar C D 		}
2422002f0d5cSYuvaraj Kumar C D 	}
2423002f0d5cSYuvaraj Kumar C D 
2424cb27a843SJames Hogan 	if (drv_data && drv_data->setup_clock) {
2425cb27a843SJames Hogan 		ret = drv_data->setup_clock(host);
2426800d78bfSThomas Abraham 		if (ret) {
2427800d78bfSThomas Abraham 			dev_err(host->dev,
2428800d78bfSThomas Abraham 				"implementation specific clock setup failed\n");
2429800d78bfSThomas Abraham 			goto err_clk_ciu;
2430800d78bfSThomas Abraham 		}
2431800d78bfSThomas Abraham 	}
2432800d78bfSThomas Abraham 
2433a55d6ff0SMark Brown 	host->vmmc = devm_regulator_get_optional(host->dev, "vmmc");
2434870556a3SDoug Anderson 	if (IS_ERR(host->vmmc)) {
2435870556a3SDoug Anderson 		ret = PTR_ERR(host->vmmc);
2436870556a3SDoug Anderson 		if (ret == -EPROBE_DEFER)
2437870556a3SDoug Anderson 			goto err_clk_ciu;
2438870556a3SDoug Anderson 
2439870556a3SDoug Anderson 		dev_info(host->dev, "no vmmc regulator found: %d\n", ret);
2440870556a3SDoug Anderson 		host->vmmc = NULL;
2441870556a3SDoug Anderson 	} else {
2442870556a3SDoug Anderson 		ret = regulator_enable(host->vmmc);
2443870556a3SDoug Anderson 		if (ret) {
2444870556a3SDoug Anderson 			if (ret != -EPROBE_DEFER)
2445870556a3SDoug Anderson 				dev_err(host->dev,
2446870556a3SDoug Anderson 					"regulator_enable fail: %d\n", ret);
2447870556a3SDoug Anderson 			goto err_clk_ciu;
2448870556a3SDoug Anderson 		}
2449870556a3SDoug Anderson 	}
2450870556a3SDoug Anderson 
245162ca8034SShashidhar Hiremath 	host->quirks = host->pdata->quirks;
2452f95f3850SWill Newton 
2453f95f3850SWill Newton 	spin_lock_init(&host->lock);
2454f95f3850SWill Newton 	INIT_LIST_HEAD(&host->queue);
2455f95f3850SWill Newton 
2456f95f3850SWill Newton 	/*
2457f95f3850SWill Newton 	 * Get the host data width - this assumes that HCON has been set with
2458f95f3850SWill Newton 	 * the correct values.
2459f95f3850SWill Newton 	 */
2460f95f3850SWill Newton 	i = (mci_readl(host, HCON) >> 7) & 0x7;
2461f95f3850SWill Newton 	if (!i) {
2462f95f3850SWill Newton 		host->push_data = dw_mci_push_data16;
2463f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data16;
2464f95f3850SWill Newton 		width = 16;
2465f95f3850SWill Newton 		host->data_shift = 1;
2466f95f3850SWill Newton 	} else if (i == 2) {
2467f95f3850SWill Newton 		host->push_data = dw_mci_push_data64;
2468f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data64;
2469f95f3850SWill Newton 		width = 64;
2470f95f3850SWill Newton 		host->data_shift = 3;
2471f95f3850SWill Newton 	} else {
2472f95f3850SWill Newton 		/* Check for a reserved value, and warn if it is */
2473f95f3850SWill Newton 		WARN((i != 1),
2474f95f3850SWill Newton 		     "HCON reports a reserved host data width!\n"
2475f95f3850SWill Newton 		     "Defaulting to 32-bit access.\n");
2476f95f3850SWill Newton 		host->push_data = dw_mci_push_data32;
2477f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data32;
2478f95f3850SWill Newton 		width = 32;
2479f95f3850SWill Newton 		host->data_shift = 2;
2480f95f3850SWill Newton 	}
2481f95f3850SWill Newton 
2482f95f3850SWill Newton 	/* Reset all blocks */
248331bff450SSeungwon Jeon 	if (!dw_mci_ctrl_all_reset(host))
2484141a712aSSeungwon Jeon 		return -ENODEV;
2485141a712aSSeungwon Jeon 
2486141a712aSSeungwon Jeon 	host->dma_ops = host->pdata->dma_ops;
2487141a712aSSeungwon Jeon 	dw_mci_init_dma(host);
2488f95f3850SWill Newton 
2489f95f3850SWill Newton 	/* Clear the interrupts for the host controller */
2490f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2491f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2492f95f3850SWill Newton 
2493f95f3850SWill Newton 	/* Put in max timeout */
2494f95f3850SWill Newton 	mci_writel(host, TMOUT, 0xFFFFFFFF);
2495f95f3850SWill Newton 
2496f95f3850SWill Newton 	/*
2497f95f3850SWill Newton 	 * FIFO threshold settings  RxMark  = fifo_size / 2 - 1,
2498f95f3850SWill Newton 	 *                          Tx Mark = fifo_size / 2 DMA Size = 8
2499f95f3850SWill Newton 	 */
2500b86d8253SJames Hogan 	if (!host->pdata->fifo_depth) {
2501b86d8253SJames Hogan 		/*
2502b86d8253SJames Hogan 		 * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may
2503b86d8253SJames Hogan 		 * have been overwritten by the bootloader, just like we're
2504b86d8253SJames Hogan 		 * about to do, so if you know the value for your hardware, you
2505b86d8253SJames Hogan 		 * should put it in the platform data.
2506b86d8253SJames Hogan 		 */
2507f95f3850SWill Newton 		fifo_size = mci_readl(host, FIFOTH);
25088234e869SJaehoon Chung 		fifo_size = 1 + ((fifo_size >> 16) & 0xfff);
2509b86d8253SJames Hogan 	} else {
2510b86d8253SJames Hogan 		fifo_size = host->pdata->fifo_depth;
2511b86d8253SJames Hogan 	}
2512b86d8253SJames Hogan 	host->fifo_depth = fifo_size;
251352426899SSeungwon Jeon 	host->fifoth_val =
251452426899SSeungwon Jeon 		SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2);
2515e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
2516f95f3850SWill Newton 
2517f95f3850SWill Newton 	/* disable clock to CIU */
2518f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2519f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2520f95f3850SWill Newton 
252163008768SJames Hogan 	/*
252263008768SJames Hogan 	 * In 2.40a spec, Data offset is changed.
252363008768SJames Hogan 	 * Need to check the version-id and set data-offset for DATA register.
252463008768SJames Hogan 	 */
252563008768SJames Hogan 	host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
252663008768SJames Hogan 	dev_info(host->dev, "Version ID is %04x\n", host->verid);
252763008768SJames Hogan 
252863008768SJames Hogan 	if (host->verid < DW_MMC_240A)
252963008768SJames Hogan 		host->data_offset = DATA_OFFSET;
253063008768SJames Hogan 	else
253163008768SJames Hogan 		host->data_offset = DATA_240A_OFFSET;
253263008768SJames Hogan 
2533f95f3850SWill Newton 	tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
253495dcc2cbSThomas Abraham 	host->card_workqueue = alloc_workqueue("dw-mci-card",
253559ff3eb6SZhangZhen 			WQ_MEM_RECLAIM, 1);
2536ef7aef9aSWei Yongjun 	if (!host->card_workqueue) {
2537ef7aef9aSWei Yongjun 		ret = -ENOMEM;
25381791b13eSJames Hogan 		goto err_dmaunmap;
2539ef7aef9aSWei Yongjun 	}
25401791b13eSJames Hogan 	INIT_WORK(&host->card_work, dw_mci_work_routine_card);
2541780f22afSSeungwon Jeon 	ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
2542780f22afSSeungwon Jeon 			       host->irq_flags, "dw-mci", host);
2543f95f3850SWill Newton 	if (ret)
25441791b13eSJames Hogan 		goto err_workqueue;
2545f95f3850SWill Newton 
2546f95f3850SWill Newton 	if (host->pdata->num_slots)
2547f95f3850SWill Newton 		host->num_slots = host->pdata->num_slots;
2548f95f3850SWill Newton 	else
2549f95f3850SWill Newton 		host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1;
2550f95f3850SWill Newton 
25512da1d7f2SYuvaraj CD 	/*
25522da1d7f2SYuvaraj CD 	 * Enable interrupts for command done, data over, data empty, card det,
25532da1d7f2SYuvaraj CD 	 * receive ready and error such as transmit, receive timeout, crc error
25542da1d7f2SYuvaraj CD 	 */
25552da1d7f2SYuvaraj CD 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
25562da1d7f2SYuvaraj CD 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
25572da1d7f2SYuvaraj CD 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
25582da1d7f2SYuvaraj CD 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
25592da1d7f2SYuvaraj CD 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
25602da1d7f2SYuvaraj CD 
25612da1d7f2SYuvaraj CD 	dev_info(host->dev, "DW MMC controller at irq %d, "
25622da1d7f2SYuvaraj CD 		 "%d bit host data width, "
25632da1d7f2SYuvaraj CD 		 "%u deep fifo\n",
25642da1d7f2SYuvaraj CD 		 host->irq, width, fifo_size);
25652da1d7f2SYuvaraj CD 
2566f95f3850SWill Newton 	/* We need at least one slot to succeed */
2567f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2568f95f3850SWill Newton 		ret = dw_mci_init_slot(host, i);
25691c2215b7SThomas Abraham 		if (ret)
25701c2215b7SThomas Abraham 			dev_dbg(host->dev, "slot %d init failed\n", i);
25711c2215b7SThomas Abraham 		else
25721c2215b7SThomas Abraham 			init_slots++;
2573f95f3850SWill Newton 	}
25741c2215b7SThomas Abraham 
25751c2215b7SThomas Abraham 	if (init_slots) {
25761c2215b7SThomas Abraham 		dev_info(host->dev, "%d slots initialized\n", init_slots);
25771c2215b7SThomas Abraham 	} else {
25781c2215b7SThomas Abraham 		dev_dbg(host->dev, "attempted to initialize %d slots, "
25791c2215b7SThomas Abraham 					"but failed on all\n", host->num_slots);
2580780f22afSSeungwon Jeon 		goto err_workqueue;
2581f95f3850SWill Newton 	}
2582f95f3850SWill Newton 
2583f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
25844a90920cSThomas Abraham 		dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
2585f95f3850SWill Newton 
2586f95f3850SWill Newton 	return 0;
2587f95f3850SWill Newton 
25881791b13eSJames Hogan err_workqueue:
258995dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
25901791b13eSJames Hogan 
2591f95f3850SWill Newton err_dmaunmap:
2592f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2593f95f3850SWill Newton 		host->dma_ops->exit(host);
2594780f22afSSeungwon Jeon 	if (host->vmmc)
2595c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2596f90a0612SThomas Abraham 
2597f90a0612SThomas Abraham err_clk_ciu:
2598780f22afSSeungwon Jeon 	if (!IS_ERR(host->ciu_clk))
2599f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2600780f22afSSeungwon Jeon 
2601f90a0612SThomas Abraham err_clk_biu:
2602780f22afSSeungwon Jeon 	if (!IS_ERR(host->biu_clk))
2603f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2604780f22afSSeungwon Jeon 
2605f95f3850SWill Newton 	return ret;
2606f95f3850SWill Newton }
260762ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe);
2608f95f3850SWill Newton 
260962ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host)
2610f95f3850SWill Newton {
2611f95f3850SWill Newton 	int i;
2612f95f3850SWill Newton 
2613f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2614f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2615f95f3850SWill Newton 
2616f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
26174a90920cSThomas Abraham 		dev_dbg(host->dev, "remove slot %d\n", i);
2618f95f3850SWill Newton 		if (host->slot[i])
2619f95f3850SWill Newton 			dw_mci_cleanup_slot(host->slot[i], i);
2620f95f3850SWill Newton 	}
2621f95f3850SWill Newton 
2622f95f3850SWill Newton 	/* disable clock to CIU */
2623f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2624f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2625f95f3850SWill Newton 
262695dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
2627f95f3850SWill Newton 
2628f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2629f95f3850SWill Newton 		host->dma_ops->exit(host);
2630f95f3850SWill Newton 
2631780f22afSSeungwon Jeon 	if (host->vmmc)
2632c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2633c07946a3SJaehoon Chung 
2634f90a0612SThomas Abraham 	if (!IS_ERR(host->ciu_clk))
2635f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2636780f22afSSeungwon Jeon 
2637f90a0612SThomas Abraham 	if (!IS_ERR(host->biu_clk))
2638f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2639f95f3850SWill Newton }
264062ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove);
264162ca8034SShashidhar Hiremath 
264262ca8034SShashidhar Hiremath 
2643f95f3850SWill Newton 
26446fe8890dSJaehoon Chung #ifdef CONFIG_PM_SLEEP
2645f95f3850SWill Newton /*
2646f95f3850SWill Newton  * TODO: we should probably disable the clock to the card in the suspend path.
2647f95f3850SWill Newton  */
264862ca8034SShashidhar Hiremath int dw_mci_suspend(struct dw_mci *host)
2649f95f3850SWill Newton {
2650c07946a3SJaehoon Chung 	if (host->vmmc)
2651c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2652c07946a3SJaehoon Chung 
2653f95f3850SWill Newton 	return 0;
2654f95f3850SWill Newton }
265562ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_suspend);
2656f95f3850SWill Newton 
265762ca8034SShashidhar Hiremath int dw_mci_resume(struct dw_mci *host)
2658f95f3850SWill Newton {
2659f95f3850SWill Newton 	int i, ret;
2660f95f3850SWill Newton 
2661f2f942ceSSachin Kamat 	if (host->vmmc) {
2662f2f942ceSSachin Kamat 		ret = regulator_enable(host->vmmc);
2663f2f942ceSSachin Kamat 		if (ret) {
2664f2f942ceSSachin Kamat 			dev_err(host->dev,
2665f2f942ceSSachin Kamat 				"failed to enable regulator: %d\n", ret);
2666f2f942ceSSachin Kamat 			return ret;
2667f2f942ceSSachin Kamat 		}
2668f2f942ceSSachin Kamat 	}
26691d6c4e0aSJaehoon Chung 
267031bff450SSeungwon Jeon 	if (!dw_mci_ctrl_all_reset(host)) {
2671e61cf118SJaehoon Chung 		ret = -ENODEV;
2672e61cf118SJaehoon Chung 		return ret;
2673e61cf118SJaehoon Chung 	}
2674e61cf118SJaehoon Chung 
26753bfe619dSJonathan Kliegman 	if (host->use_dma && host->dma_ops->init)
2676141a712aSSeungwon Jeon 		host->dma_ops->init(host);
2677141a712aSSeungwon Jeon 
267852426899SSeungwon Jeon 	/*
267952426899SSeungwon Jeon 	 * Restore the initial value at FIFOTH register
268052426899SSeungwon Jeon 	 * And Invalidate the prev_blksz with zero
268152426899SSeungwon Jeon 	 */
2682e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
268352426899SSeungwon Jeon 	host->prev_blksz = 0;
2684e61cf118SJaehoon Chung 
26852eb2944fSDoug Anderson 	/* Put in max timeout */
26862eb2944fSDoug Anderson 	mci_writel(host, TMOUT, 0xFFFFFFFF);
26872eb2944fSDoug Anderson 
2688e61cf118SJaehoon Chung 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2689e61cf118SJaehoon Chung 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
2690e61cf118SJaehoon Chung 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
2691e61cf118SJaehoon Chung 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
2692e61cf118SJaehoon Chung 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
2693e61cf118SJaehoon Chung 
2694f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2695f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
2696f95f3850SWill Newton 		if (!slot)
2697f95f3850SWill Newton 			continue;
2698ab269128SAbhilash Kesavan 		if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
2699ab269128SAbhilash Kesavan 			dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
2700ab269128SAbhilash Kesavan 			dw_mci_setup_bus(slot, true);
2701ab269128SAbhilash Kesavan 		}
2702f95f3850SWill Newton 	}
2703f95f3850SWill Newton 	return 0;
2704f95f3850SWill Newton }
270562ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_resume);
27066fe8890dSJaehoon Chung #endif /* CONFIG_PM_SLEEP */
27076fe8890dSJaehoon Chung 
2708f95f3850SWill Newton static int __init dw_mci_init(void)
2709f95f3850SWill Newton {
27108e1c4e4dSSachin Kamat 	pr_info("Synopsys Designware Multimedia Card Interface Driver\n");
271162ca8034SShashidhar Hiremath 	return 0;
2712f95f3850SWill Newton }
2713f95f3850SWill Newton 
2714f95f3850SWill Newton static void __exit dw_mci_exit(void)
2715f95f3850SWill Newton {
2716f95f3850SWill Newton }
2717f95f3850SWill Newton 
2718f95f3850SWill Newton module_init(dw_mci_init);
2719f95f3850SWill Newton module_exit(dw_mci_exit);
2720f95f3850SWill Newton 
2721f95f3850SWill Newton MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
2722f95f3850SWill Newton MODULE_AUTHOR("NXP Semiconductor VietNam");
2723f95f3850SWill Newton MODULE_AUTHOR("Imagination Technologies Ltd");
2724f95f3850SWill Newton MODULE_LICENSE("GPL v2");
2725