xref: /linux/drivers/mmc/host/dw_mmc.c (revision 3cf890fc42b2d3bd5a3a7e4c1f61b0637efbe2ec)
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>
3201730558SDoug Anderson #include <linux/mmc/sd.h>
3390c2143aSSeungwon Jeon #include <linux/mmc/sdio.h>
34f95f3850SWill Newton #include <linux/mmc/dw_mmc.h>
35f95f3850SWill Newton #include <linux/bitops.h>
36c07946a3SJaehoon Chung #include <linux/regulator/consumer.h>
371791b13eSJames Hogan #include <linux/workqueue.h>
38c91eab4bSThomas Abraham #include <linux/of.h>
3955a6ceb2SDoug Anderson #include <linux/of_gpio.h>
40bf626e55SZhangfei Gao #include <linux/mmc/slot-gpio.h>
41f95f3850SWill Newton 
42f95f3850SWill Newton #include "dw_mmc.h"
43f95f3850SWill Newton 
44f95f3850SWill Newton /* Common flag combinations */
453f7eec62SJaehoon Chung #define DW_MCI_DATA_ERROR_FLAGS	(SDMMC_INT_DRTO | SDMMC_INT_DCRC | \
46f95f3850SWill Newton 				 SDMMC_INT_HTO | SDMMC_INT_SBE  | \
47f95f3850SWill Newton 				 SDMMC_INT_EBE)
48f95f3850SWill Newton #define DW_MCI_CMD_ERROR_FLAGS	(SDMMC_INT_RTO | SDMMC_INT_RCRC | \
49f95f3850SWill Newton 				 SDMMC_INT_RESP_ERR)
50f95f3850SWill Newton #define DW_MCI_ERROR_FLAGS	(DW_MCI_DATA_ERROR_FLAGS | \
51f95f3850SWill Newton 				 DW_MCI_CMD_ERROR_FLAGS  | SDMMC_INT_HLE)
52f95f3850SWill Newton #define DW_MCI_SEND_STATUS	1
53f95f3850SWill Newton #define DW_MCI_RECV_STATUS	2
54f95f3850SWill Newton #define DW_MCI_DMA_THRESHOLD	16
55f95f3850SWill Newton 
561f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MAX	200000000	/* unit: HZ */
571f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MIN	400000		/* unit: HZ */
581f44a2a5SSeungwon Jeon 
59f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
60fc79a4d6SJoonyoung Shim #define IDMAC_INT_CLR		(SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \
61fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \
62fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
63fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_TI)
64fc79a4d6SJoonyoung Shim 
65f95f3850SWill Newton struct idmac_desc {
66f95f3850SWill Newton 	u32		des0;	/* Control Descriptor */
67f95f3850SWill Newton #define IDMAC_DES0_DIC	BIT(1)
68f95f3850SWill Newton #define IDMAC_DES0_LD	BIT(2)
69f95f3850SWill Newton #define IDMAC_DES0_FD	BIT(3)
70f95f3850SWill Newton #define IDMAC_DES0_CH	BIT(4)
71f95f3850SWill Newton #define IDMAC_DES0_ER	BIT(5)
72f95f3850SWill Newton #define IDMAC_DES0_CES	BIT(30)
73f95f3850SWill Newton #define IDMAC_DES0_OWN	BIT(31)
74f95f3850SWill Newton 
75f95f3850SWill Newton 	u32		des1;	/* Buffer sizes */
76f95f3850SWill Newton #define IDMAC_SET_BUFFER1_SIZE(d, s) \
779b7bbe10SShashidhar Hiremath 	((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff))
78f95f3850SWill Newton 
79f95f3850SWill Newton 	u32		des2;	/* buffer 1 physical address */
80f95f3850SWill Newton 
81f95f3850SWill Newton 	u32		des3;	/* buffer 2 physical address */
82f95f3850SWill Newton };
83f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */
84f95f3850SWill Newton 
850976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_4bit[] = {
860976f16dSSeungwon Jeon 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
870976f16dSSeungwon Jeon 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
880976f16dSSeungwon Jeon 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
890976f16dSSeungwon Jeon 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
900976f16dSSeungwon Jeon 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
910976f16dSSeungwon Jeon 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
920976f16dSSeungwon Jeon 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
930976f16dSSeungwon Jeon 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
940976f16dSSeungwon Jeon };
95f95f3850SWill Newton 
960976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_8bit[] = {
970976f16dSSeungwon Jeon 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
980976f16dSSeungwon Jeon 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
990976f16dSSeungwon Jeon 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
1000976f16dSSeungwon Jeon 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
1010976f16dSSeungwon Jeon 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
1020976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
1030976f16dSSeungwon Jeon 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
1040976f16dSSeungwon Jeon 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
1050976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
1060976f16dSSeungwon Jeon 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
1070976f16dSSeungwon Jeon 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
1080976f16dSSeungwon Jeon 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
1090976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
1100976f16dSSeungwon Jeon 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
1110976f16dSSeungwon Jeon 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
1120976f16dSSeungwon Jeon 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
113f95f3850SWill Newton };
114f95f3850SWill Newton 
1153a33a94cSSonny Rao static bool dw_mci_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 
23801730558SDoug Anderson static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg);
23901730558SDoug Anderson 
240f95f3850SWill Newton static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
241f95f3850SWill Newton {
242f95f3850SWill Newton 	struct mmc_data	*data;
243800d78bfSThomas Abraham 	struct dw_mci_slot *slot = mmc_priv(mmc);
24401730558SDoug Anderson 	struct dw_mci *host = slot->host;
245e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
246f95f3850SWill Newton 	u32 cmdr;
247f95f3850SWill Newton 	cmd->error = -EINPROGRESS;
248f95f3850SWill Newton 
249f95f3850SWill Newton 	cmdr = cmd->opcode;
250f95f3850SWill Newton 
25190c2143aSSeungwon Jeon 	if (cmd->opcode == MMC_STOP_TRANSMISSION ||
25290c2143aSSeungwon Jeon 	    cmd->opcode == MMC_GO_IDLE_STATE ||
25390c2143aSSeungwon Jeon 	    cmd->opcode == MMC_GO_INACTIVE_STATE ||
25490c2143aSSeungwon Jeon 	    (cmd->opcode == SD_IO_RW_DIRECT &&
25590c2143aSSeungwon Jeon 	     ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT))
256f95f3850SWill Newton 		cmdr |= SDMMC_CMD_STOP;
2574a1b27adSJaehoon Chung 	else if (cmd->opcode != MMC_SEND_STATUS && cmd->data)
258f95f3850SWill Newton 		cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
259f95f3850SWill Newton 
26001730558SDoug Anderson 	if (cmd->opcode == SD_SWITCH_VOLTAGE) {
26101730558SDoug Anderson 		u32 clk_en_a;
26201730558SDoug Anderson 
26301730558SDoug Anderson 		/* Special bit makes CMD11 not die */
26401730558SDoug Anderson 		cmdr |= SDMMC_CMD_VOLT_SWITCH;
26501730558SDoug Anderson 
26601730558SDoug Anderson 		/* Change state to continue to handle CMD11 weirdness */
26701730558SDoug Anderson 		WARN_ON(slot->host->state != STATE_SENDING_CMD);
26801730558SDoug Anderson 		slot->host->state = STATE_SENDING_CMD11;
26901730558SDoug Anderson 
27001730558SDoug Anderson 		/*
27101730558SDoug Anderson 		 * We need to disable low power mode (automatic clock stop)
27201730558SDoug Anderson 		 * while doing voltage switch so we don't confuse the card,
27301730558SDoug Anderson 		 * since stopping the clock is a specific part of the UHS
27401730558SDoug Anderson 		 * voltage change dance.
27501730558SDoug Anderson 		 *
27601730558SDoug Anderson 		 * Note that low power mode (SDMMC_CLKEN_LOW_PWR) will be
27701730558SDoug Anderson 		 * unconditionally turned back on in dw_mci_setup_bus() if it's
27801730558SDoug Anderson 		 * ever called with a non-zero clock.  That shouldn't happen
27901730558SDoug Anderson 		 * until the voltage change is all done.
28001730558SDoug Anderson 		 */
28101730558SDoug Anderson 		clk_en_a = mci_readl(host, CLKENA);
28201730558SDoug Anderson 		clk_en_a &= ~(SDMMC_CLKEN_LOW_PWR << slot->id);
28301730558SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a);
28401730558SDoug Anderson 		mci_send_cmd(slot, SDMMC_CMD_UPD_CLK |
28501730558SDoug Anderson 			     SDMMC_CMD_PRV_DAT_WAIT, 0);
28601730558SDoug Anderson 	}
28701730558SDoug Anderson 
288f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_PRESENT) {
289f95f3850SWill Newton 		/* We expect a response, so set this bit */
290f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_EXP;
291f95f3850SWill Newton 		if (cmd->flags & MMC_RSP_136)
292f95f3850SWill Newton 			cmdr |= SDMMC_CMD_RESP_LONG;
293f95f3850SWill Newton 	}
294f95f3850SWill Newton 
295f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_CRC)
296f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_CRC;
297f95f3850SWill Newton 
298f95f3850SWill Newton 	data = cmd->data;
299f95f3850SWill Newton 	if (data) {
300f95f3850SWill Newton 		cmdr |= SDMMC_CMD_DAT_EXP;
301f95f3850SWill Newton 		if (data->flags & MMC_DATA_STREAM)
302f95f3850SWill Newton 			cmdr |= SDMMC_CMD_STRM_MODE;
303f95f3850SWill Newton 		if (data->flags & MMC_DATA_WRITE)
304f95f3850SWill Newton 			cmdr |= SDMMC_CMD_DAT_WR;
305f95f3850SWill Newton 	}
306f95f3850SWill Newton 
307cb27a843SJames Hogan 	if (drv_data && drv_data->prepare_command)
308cb27a843SJames Hogan 		drv_data->prepare_command(slot->host, &cmdr);
309800d78bfSThomas Abraham 
310f95f3850SWill Newton 	return cmdr;
311f95f3850SWill Newton }
312f95f3850SWill Newton 
31390c2143aSSeungwon Jeon static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
31490c2143aSSeungwon Jeon {
31590c2143aSSeungwon Jeon 	struct mmc_command *stop;
31690c2143aSSeungwon Jeon 	u32 cmdr;
31790c2143aSSeungwon Jeon 
31890c2143aSSeungwon Jeon 	if (!cmd->data)
31990c2143aSSeungwon Jeon 		return 0;
32090c2143aSSeungwon Jeon 
32190c2143aSSeungwon Jeon 	stop = &host->stop_abort;
32290c2143aSSeungwon Jeon 	cmdr = cmd->opcode;
32390c2143aSSeungwon Jeon 	memset(stop, 0, sizeof(struct mmc_command));
32490c2143aSSeungwon Jeon 
32590c2143aSSeungwon Jeon 	if (cmdr == MMC_READ_SINGLE_BLOCK ||
32690c2143aSSeungwon Jeon 	    cmdr == MMC_READ_MULTIPLE_BLOCK ||
32790c2143aSSeungwon Jeon 	    cmdr == MMC_WRITE_BLOCK ||
32890c2143aSSeungwon Jeon 	    cmdr == MMC_WRITE_MULTIPLE_BLOCK) {
32990c2143aSSeungwon Jeon 		stop->opcode = MMC_STOP_TRANSMISSION;
33090c2143aSSeungwon Jeon 		stop->arg = 0;
33190c2143aSSeungwon Jeon 		stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
33290c2143aSSeungwon Jeon 	} else if (cmdr == SD_IO_RW_EXTENDED) {
33390c2143aSSeungwon Jeon 		stop->opcode = SD_IO_RW_DIRECT;
33490c2143aSSeungwon Jeon 		stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) |
33590c2143aSSeungwon Jeon 			     ((cmd->arg >> 28) & 0x7);
33690c2143aSSeungwon Jeon 		stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
33790c2143aSSeungwon Jeon 	} else {
33890c2143aSSeungwon Jeon 		return 0;
33990c2143aSSeungwon Jeon 	}
34090c2143aSSeungwon Jeon 
34190c2143aSSeungwon Jeon 	cmdr = stop->opcode | SDMMC_CMD_STOP |
34290c2143aSSeungwon Jeon 		SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP;
34390c2143aSSeungwon Jeon 
34490c2143aSSeungwon Jeon 	return cmdr;
34590c2143aSSeungwon Jeon }
34690c2143aSSeungwon Jeon 
347f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host,
348f95f3850SWill Newton 				 struct mmc_command *cmd, u32 cmd_flags)
349f95f3850SWill Newton {
350f95f3850SWill Newton 	host->cmd = cmd;
3514a90920cSThomas Abraham 	dev_vdbg(host->dev,
352f95f3850SWill Newton 		 "start command: ARGR=0x%08x CMDR=0x%08x\n",
353f95f3850SWill Newton 		 cmd->arg, cmd_flags);
354f95f3850SWill Newton 
355f95f3850SWill Newton 	mci_writel(host, CMDARG, cmd->arg);
356f95f3850SWill Newton 	wmb();
357f95f3850SWill Newton 
358f95f3850SWill Newton 	mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
359f95f3850SWill Newton }
360f95f3850SWill Newton 
36190c2143aSSeungwon Jeon static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data)
362f95f3850SWill Newton {
36390c2143aSSeungwon Jeon 	struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort;
36490c2143aSSeungwon Jeon 	dw_mci_start_command(host, stop, host->stop_cmdr);
365f95f3850SWill Newton }
366f95f3850SWill Newton 
367f95f3850SWill Newton /* DMA interface functions */
368f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host)
369f95f3850SWill Newton {
37003e8cb53SJames Hogan 	if (host->using_dma) {
371f95f3850SWill Newton 		host->dma_ops->stop(host);
372f95f3850SWill Newton 		host->dma_ops->cleanup(host);
373aa50f259SSeungwon Jeon 	}
374aa50f259SSeungwon Jeon 
375f95f3850SWill Newton 	/* Data transfer was stopped by the interrupt handler */
376f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
377f95f3850SWill Newton }
378f95f3850SWill Newton 
3799aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data)
3809aa51408SSeungwon Jeon {
3819aa51408SSeungwon Jeon 	if (data->flags & MMC_DATA_WRITE)
3829aa51408SSeungwon Jeon 		return DMA_TO_DEVICE;
3839aa51408SSeungwon Jeon 	else
3849aa51408SSeungwon Jeon 		return DMA_FROM_DEVICE;
3859aa51408SSeungwon Jeon }
3869aa51408SSeungwon Jeon 
3879beee912SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
388f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host)
389f95f3850SWill Newton {
390f95f3850SWill Newton 	struct mmc_data *data = host->data;
391f95f3850SWill Newton 
392f95f3850SWill Newton 	if (data)
3939aa51408SSeungwon Jeon 		if (!data->host_cookie)
3944a90920cSThomas Abraham 			dma_unmap_sg(host->dev,
3959aa51408SSeungwon Jeon 				     data->sg,
3969aa51408SSeungwon Jeon 				     data->sg_len,
3979aa51408SSeungwon Jeon 				     dw_mci_get_dma_dir(data));
398f95f3850SWill Newton }
399f95f3850SWill Newton 
4005ce9d961SSeungwon Jeon static void dw_mci_idmac_reset(struct dw_mci *host)
4015ce9d961SSeungwon Jeon {
4025ce9d961SSeungwon Jeon 	u32 bmod = mci_readl(host, BMOD);
4035ce9d961SSeungwon Jeon 	/* Software reset of DMA */
4045ce9d961SSeungwon Jeon 	bmod |= SDMMC_IDMAC_SWRESET;
4055ce9d961SSeungwon Jeon 	mci_writel(host, BMOD, bmod);
4065ce9d961SSeungwon Jeon }
4075ce9d961SSeungwon Jeon 
408f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host)
409f95f3850SWill Newton {
410f95f3850SWill Newton 	u32 temp;
411f95f3850SWill Newton 
412f95f3850SWill Newton 	/* Disable and reset the IDMAC interface */
413f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
414f95f3850SWill Newton 	temp &= ~SDMMC_CTRL_USE_IDMAC;
415f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_RESET;
416f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
417f95f3850SWill Newton 
418f95f3850SWill Newton 	/* Stop the IDMAC running */
419f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
420a5289a43SJaehoon Chung 	temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB);
4215ce9d961SSeungwon Jeon 	temp |= SDMMC_IDMAC_SWRESET;
422f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
423f95f3850SWill Newton }
424f95f3850SWill Newton 
425f95f3850SWill Newton static void dw_mci_idmac_complete_dma(struct dw_mci *host)
426f95f3850SWill Newton {
427f95f3850SWill Newton 	struct mmc_data *data = host->data;
428f95f3850SWill Newton 
4294a90920cSThomas Abraham 	dev_vdbg(host->dev, "DMA complete\n");
430f95f3850SWill Newton 
431f95f3850SWill Newton 	host->dma_ops->cleanup(host);
432f95f3850SWill Newton 
433f95f3850SWill Newton 	/*
434f95f3850SWill Newton 	 * If the card was removed, data will be NULL. No point in trying to
435f95f3850SWill Newton 	 * send the stop command or waiting for NBUSY in this case.
436f95f3850SWill Newton 	 */
437f95f3850SWill Newton 	if (data) {
438f95f3850SWill Newton 		set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
439f95f3850SWill Newton 		tasklet_schedule(&host->tasklet);
440f95f3850SWill Newton 	}
441f95f3850SWill Newton }
442f95f3850SWill Newton 
443f95f3850SWill Newton static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
444f95f3850SWill Newton 				    unsigned int sg_len)
445f95f3850SWill Newton {
446f95f3850SWill Newton 	int i;
447f95f3850SWill Newton 	struct idmac_desc *desc = host->sg_cpu;
448f95f3850SWill Newton 
449f95f3850SWill Newton 	for (i = 0; i < sg_len; i++, desc++) {
450f95f3850SWill Newton 		unsigned int length = sg_dma_len(&data->sg[i]);
451f95f3850SWill Newton 		u32 mem_addr = sg_dma_address(&data->sg[i]);
452f95f3850SWill Newton 
453f95f3850SWill Newton 		/* Set the OWN bit and disable interrupts for this descriptor */
454f95f3850SWill Newton 		desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH;
455f95f3850SWill Newton 
456f95f3850SWill Newton 		/* Buffer length */
457f95f3850SWill Newton 		IDMAC_SET_BUFFER1_SIZE(desc, length);
458f95f3850SWill Newton 
459f95f3850SWill Newton 		/* Physical address to DMA to/from */
460f95f3850SWill Newton 		desc->des2 = mem_addr;
461f95f3850SWill Newton 	}
462f95f3850SWill Newton 
463f95f3850SWill Newton 	/* Set first descriptor */
464f95f3850SWill Newton 	desc = host->sg_cpu;
465f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_FD;
466f95f3850SWill Newton 
467f95f3850SWill Newton 	/* Set last descriptor */
468f95f3850SWill Newton 	desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
469f95f3850SWill Newton 	desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
470f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_LD;
471f95f3850SWill Newton 
472f95f3850SWill Newton 	wmb();
473f95f3850SWill Newton }
474f95f3850SWill Newton 
475f95f3850SWill Newton static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
476f95f3850SWill Newton {
477f95f3850SWill Newton 	u32 temp;
478f95f3850SWill Newton 
479f95f3850SWill Newton 	dw_mci_translate_sglist(host, host->data, sg_len);
480f95f3850SWill Newton 
481f95f3850SWill Newton 	/* Select IDMAC interface */
482f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
483f95f3850SWill Newton 	temp |= SDMMC_CTRL_USE_IDMAC;
484f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
485f95f3850SWill Newton 
486f95f3850SWill Newton 	wmb();
487f95f3850SWill Newton 
488f95f3850SWill Newton 	/* Enable the IDMAC */
489f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
490a5289a43SJaehoon Chung 	temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB;
491f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
492f95f3850SWill Newton 
493f95f3850SWill Newton 	/* Start it running */
494f95f3850SWill Newton 	mci_writel(host, PLDMND, 1);
495f95f3850SWill Newton }
496f95f3850SWill Newton 
497f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host)
498f95f3850SWill Newton {
499f95f3850SWill Newton 	struct idmac_desc *p;
500897b69e7SSeungwon Jeon 	int i;
501f95f3850SWill Newton 
502f95f3850SWill Newton 	/* Number of descriptors in the ring buffer */
503f95f3850SWill Newton 	host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
504f95f3850SWill Newton 
505f95f3850SWill Newton 	/* Forward link the descriptor list */
506f95f3850SWill Newton 	for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
507f95f3850SWill Newton 		p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
508f95f3850SWill Newton 
509f95f3850SWill Newton 	/* Set the last descriptor as the end-of-ring descriptor */
510f95f3850SWill Newton 	p->des3 = host->sg_dma;
511f95f3850SWill Newton 	p->des0 = IDMAC_DES0_ER;
512f95f3850SWill Newton 
5135ce9d961SSeungwon Jeon 	dw_mci_idmac_reset(host);
514141a712aSSeungwon Jeon 
515f95f3850SWill Newton 	/* Mask out interrupts - get Tx & Rx complete only */
516fc79a4d6SJoonyoung Shim 	mci_writel(host, IDSTS, IDMAC_INT_CLR);
517f95f3850SWill Newton 	mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
518f95f3850SWill Newton 		   SDMMC_IDMAC_INT_TI);
519f95f3850SWill Newton 
520f95f3850SWill Newton 	/* Set the descriptor base address */
521f95f3850SWill Newton 	mci_writel(host, DBADDR, host->sg_dma);
522f95f3850SWill Newton 	return 0;
523f95f3850SWill Newton }
524f95f3850SWill Newton 
5258e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = {
526885c3e80SSeungwon Jeon 	.init = dw_mci_idmac_init,
527885c3e80SSeungwon Jeon 	.start = dw_mci_idmac_start_dma,
528885c3e80SSeungwon Jeon 	.stop = dw_mci_idmac_stop_dma,
529885c3e80SSeungwon Jeon 	.complete = dw_mci_idmac_complete_dma,
530885c3e80SSeungwon Jeon 	.cleanup = dw_mci_dma_cleanup,
531885c3e80SSeungwon Jeon };
532885c3e80SSeungwon Jeon #endif /* CONFIG_MMC_DW_IDMAC */
533885c3e80SSeungwon Jeon 
5349aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host,
5359aa51408SSeungwon Jeon 				   struct mmc_data *data,
5369aa51408SSeungwon Jeon 				   bool next)
537f95f3850SWill Newton {
538f95f3850SWill Newton 	struct scatterlist *sg;
5399aa51408SSeungwon Jeon 	unsigned int i, sg_len;
540f95f3850SWill Newton 
5419aa51408SSeungwon Jeon 	if (!next && data->host_cookie)
5429aa51408SSeungwon Jeon 		return data->host_cookie;
543f95f3850SWill Newton 
544f95f3850SWill Newton 	/*
545f95f3850SWill Newton 	 * We don't do DMA on "complex" transfers, i.e. with
546f95f3850SWill Newton 	 * non-word-aligned buffers or lengths. Also, we don't bother
547f95f3850SWill Newton 	 * with all the DMA setup overhead for short transfers.
548f95f3850SWill Newton 	 */
549f95f3850SWill Newton 	if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD)
550f95f3850SWill Newton 		return -EINVAL;
5519aa51408SSeungwon Jeon 
552f95f3850SWill Newton 	if (data->blksz & 3)
553f95f3850SWill Newton 		return -EINVAL;
554f95f3850SWill Newton 
555f95f3850SWill Newton 	for_each_sg(data->sg, sg, data->sg_len, i) {
556f95f3850SWill Newton 		if (sg->offset & 3 || sg->length & 3)
557f95f3850SWill Newton 			return -EINVAL;
558f95f3850SWill Newton 	}
559f95f3850SWill Newton 
5604a90920cSThomas Abraham 	sg_len = dma_map_sg(host->dev,
5619aa51408SSeungwon Jeon 			    data->sg,
5629aa51408SSeungwon Jeon 			    data->sg_len,
5639aa51408SSeungwon Jeon 			    dw_mci_get_dma_dir(data));
5649aa51408SSeungwon Jeon 	if (sg_len == 0)
5659aa51408SSeungwon Jeon 		return -EINVAL;
5669aa51408SSeungwon Jeon 
5679aa51408SSeungwon Jeon 	if (next)
5689aa51408SSeungwon Jeon 		data->host_cookie = sg_len;
5699aa51408SSeungwon Jeon 
5709aa51408SSeungwon Jeon 	return sg_len;
5719aa51408SSeungwon Jeon }
5729aa51408SSeungwon Jeon 
5739aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc,
5749aa51408SSeungwon Jeon 			   struct mmc_request *mrq,
5759aa51408SSeungwon Jeon 			   bool is_first_req)
5769aa51408SSeungwon Jeon {
5779aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
5789aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
5799aa51408SSeungwon Jeon 
5809aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
5819aa51408SSeungwon Jeon 		return;
5829aa51408SSeungwon Jeon 
5839aa51408SSeungwon Jeon 	if (data->host_cookie) {
5849aa51408SSeungwon Jeon 		data->host_cookie = 0;
5859aa51408SSeungwon Jeon 		return;
5869aa51408SSeungwon Jeon 	}
5879aa51408SSeungwon Jeon 
5889aa51408SSeungwon Jeon 	if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0)
5899aa51408SSeungwon Jeon 		data->host_cookie = 0;
5909aa51408SSeungwon Jeon }
5919aa51408SSeungwon Jeon 
5929aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc,
5939aa51408SSeungwon Jeon 			    struct mmc_request *mrq,
5949aa51408SSeungwon Jeon 			    int err)
5959aa51408SSeungwon Jeon {
5969aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
5979aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
5989aa51408SSeungwon Jeon 
5999aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
6009aa51408SSeungwon Jeon 		return;
6019aa51408SSeungwon Jeon 
6029aa51408SSeungwon Jeon 	if (data->host_cookie)
6034a90920cSThomas Abraham 		dma_unmap_sg(slot->host->dev,
6049aa51408SSeungwon Jeon 			     data->sg,
6059aa51408SSeungwon Jeon 			     data->sg_len,
6069aa51408SSeungwon Jeon 			     dw_mci_get_dma_dir(data));
6079aa51408SSeungwon Jeon 	data->host_cookie = 0;
6089aa51408SSeungwon Jeon }
6099aa51408SSeungwon Jeon 
61052426899SSeungwon Jeon static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
61152426899SSeungwon Jeon {
61252426899SSeungwon Jeon #ifdef CONFIG_MMC_DW_IDMAC
61352426899SSeungwon Jeon 	unsigned int blksz = data->blksz;
61452426899SSeungwon Jeon 	const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
61552426899SSeungwon Jeon 	u32 fifo_width = 1 << host->data_shift;
61652426899SSeungwon Jeon 	u32 blksz_depth = blksz / fifo_width, fifoth_val;
61752426899SSeungwon Jeon 	u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers;
61852426899SSeungwon Jeon 	int idx = (sizeof(mszs) / sizeof(mszs[0])) - 1;
61952426899SSeungwon Jeon 
62052426899SSeungwon Jeon 	tx_wmark = (host->fifo_depth) / 2;
62152426899SSeungwon Jeon 	tx_wmark_invers = host->fifo_depth - tx_wmark;
62252426899SSeungwon Jeon 
62352426899SSeungwon Jeon 	/*
62452426899SSeungwon Jeon 	 * MSIZE is '1',
62552426899SSeungwon Jeon 	 * if blksz is not a multiple of the FIFO width
62652426899SSeungwon Jeon 	 */
62752426899SSeungwon Jeon 	if (blksz % fifo_width) {
62852426899SSeungwon Jeon 		msize = 0;
62952426899SSeungwon Jeon 		rx_wmark = 1;
63052426899SSeungwon Jeon 		goto done;
63152426899SSeungwon Jeon 	}
63252426899SSeungwon Jeon 
63352426899SSeungwon Jeon 	do {
63452426899SSeungwon Jeon 		if (!((blksz_depth % mszs[idx]) ||
63552426899SSeungwon Jeon 		     (tx_wmark_invers % mszs[idx]))) {
63652426899SSeungwon Jeon 			msize = idx;
63752426899SSeungwon Jeon 			rx_wmark = mszs[idx] - 1;
63852426899SSeungwon Jeon 			break;
63952426899SSeungwon Jeon 		}
64052426899SSeungwon Jeon 	} while (--idx > 0);
64152426899SSeungwon Jeon 	/*
64252426899SSeungwon Jeon 	 * If idx is '0', it won't be tried
64352426899SSeungwon Jeon 	 * Thus, initial values are uesed
64452426899SSeungwon Jeon 	 */
64552426899SSeungwon Jeon done:
64652426899SSeungwon Jeon 	fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark);
64752426899SSeungwon Jeon 	mci_writel(host, FIFOTH, fifoth_val);
64852426899SSeungwon Jeon #endif
64952426899SSeungwon Jeon }
65052426899SSeungwon Jeon 
651f1d2736cSSeungwon Jeon static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)
652f1d2736cSSeungwon Jeon {
653f1d2736cSSeungwon Jeon 	unsigned int blksz = data->blksz;
654f1d2736cSSeungwon Jeon 	u32 blksz_depth, fifo_depth;
655f1d2736cSSeungwon Jeon 	u16 thld_size;
656f1d2736cSSeungwon Jeon 
657f1d2736cSSeungwon Jeon 	WARN_ON(!(data->flags & MMC_DATA_READ));
658f1d2736cSSeungwon Jeon 
659f1d2736cSSeungwon Jeon 	if (host->timing != MMC_TIMING_MMC_HS200 &&
660f1d2736cSSeungwon Jeon 	    host->timing != MMC_TIMING_UHS_SDR104)
661f1d2736cSSeungwon Jeon 		goto disable;
662f1d2736cSSeungwon Jeon 
663f1d2736cSSeungwon Jeon 	blksz_depth = blksz / (1 << host->data_shift);
664f1d2736cSSeungwon Jeon 	fifo_depth = host->fifo_depth;
665f1d2736cSSeungwon Jeon 
666f1d2736cSSeungwon Jeon 	if (blksz_depth > fifo_depth)
667f1d2736cSSeungwon Jeon 		goto disable;
668f1d2736cSSeungwon Jeon 
669f1d2736cSSeungwon Jeon 	/*
670f1d2736cSSeungwon Jeon 	 * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz'
671f1d2736cSSeungwon Jeon 	 * If (blksz_depth) <  (fifo_depth >> 1), should be thld_size = blksz
672f1d2736cSSeungwon Jeon 	 * Currently just choose blksz.
673f1d2736cSSeungwon Jeon 	 */
674f1d2736cSSeungwon Jeon 	thld_size = blksz;
675f1d2736cSSeungwon Jeon 	mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1));
676f1d2736cSSeungwon Jeon 	return;
677f1d2736cSSeungwon Jeon 
678f1d2736cSSeungwon Jeon disable:
679f1d2736cSSeungwon Jeon 	mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0));
680f1d2736cSSeungwon Jeon }
681f1d2736cSSeungwon Jeon 
6829aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
6839aa51408SSeungwon Jeon {
6849aa51408SSeungwon Jeon 	int sg_len;
6859aa51408SSeungwon Jeon 	u32 temp;
6869aa51408SSeungwon Jeon 
6879aa51408SSeungwon Jeon 	host->using_dma = 0;
6889aa51408SSeungwon Jeon 
6899aa51408SSeungwon Jeon 	/* If we don't have a channel, we can't do DMA */
6909aa51408SSeungwon Jeon 	if (!host->use_dma)
6919aa51408SSeungwon Jeon 		return -ENODEV;
6929aa51408SSeungwon Jeon 
6939aa51408SSeungwon Jeon 	sg_len = dw_mci_pre_dma_transfer(host, data, 0);
694a99aa9b9SSeungwon Jeon 	if (sg_len < 0) {
695a99aa9b9SSeungwon Jeon 		host->dma_ops->stop(host);
6969aa51408SSeungwon Jeon 		return sg_len;
697a99aa9b9SSeungwon Jeon 	}
6989aa51408SSeungwon Jeon 
69903e8cb53SJames Hogan 	host->using_dma = 1;
70003e8cb53SJames Hogan 
7014a90920cSThomas Abraham 	dev_vdbg(host->dev,
702f95f3850SWill Newton 		 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
703f95f3850SWill Newton 		 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
704f95f3850SWill Newton 		 sg_len);
705f95f3850SWill Newton 
70652426899SSeungwon Jeon 	/*
70752426899SSeungwon Jeon 	 * Decide the MSIZE and RX/TX Watermark.
70852426899SSeungwon Jeon 	 * If current block size is same with previous size,
70952426899SSeungwon Jeon 	 * no need to update fifoth.
71052426899SSeungwon Jeon 	 */
71152426899SSeungwon Jeon 	if (host->prev_blksz != data->blksz)
71252426899SSeungwon Jeon 		dw_mci_adjust_fifoth(host, data);
71352426899SSeungwon Jeon 
714f95f3850SWill Newton 	/* Enable the DMA interface */
715f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
716f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_ENABLE;
717f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
718f95f3850SWill Newton 
719f95f3850SWill Newton 	/* Disable RX/TX IRQs, let DMA handle it */
720f95f3850SWill Newton 	temp = mci_readl(host, INTMASK);
721f95f3850SWill Newton 	temp  &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR);
722f95f3850SWill Newton 	mci_writel(host, INTMASK, temp);
723f95f3850SWill Newton 
724f95f3850SWill Newton 	host->dma_ops->start(host, sg_len);
725f95f3850SWill Newton 
726f95f3850SWill Newton 	return 0;
727f95f3850SWill Newton }
728f95f3850SWill Newton 
729f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
730f95f3850SWill Newton {
731f95f3850SWill Newton 	u32 temp;
732f95f3850SWill Newton 
733f95f3850SWill Newton 	data->error = -EINPROGRESS;
734f95f3850SWill Newton 
735f95f3850SWill Newton 	WARN_ON(host->data);
736f95f3850SWill Newton 	host->sg = NULL;
737f95f3850SWill Newton 	host->data = data;
738f95f3850SWill Newton 
739f1d2736cSSeungwon Jeon 	if (data->flags & MMC_DATA_READ) {
74055c5efbcSJames Hogan 		host->dir_status = DW_MCI_RECV_STATUS;
741f1d2736cSSeungwon Jeon 		dw_mci_ctrl_rd_thld(host, data);
742f1d2736cSSeungwon Jeon 	} else {
74355c5efbcSJames Hogan 		host->dir_status = DW_MCI_SEND_STATUS;
744f1d2736cSSeungwon Jeon 	}
74555c5efbcSJames Hogan 
746f95f3850SWill Newton 	if (dw_mci_submit_data_dma(host, data)) {
747f9c2a0dcSSeungwon Jeon 		int flags = SG_MITER_ATOMIC;
748f9c2a0dcSSeungwon Jeon 		if (host->data->flags & MMC_DATA_READ)
749f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_TO_SG;
750f9c2a0dcSSeungwon Jeon 		else
751f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_FROM_SG;
752f9c2a0dcSSeungwon Jeon 
753f9c2a0dcSSeungwon Jeon 		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
754f95f3850SWill Newton 		host->sg = data->sg;
75534b664a2SJames Hogan 		host->part_buf_start = 0;
75634b664a2SJames Hogan 		host->part_buf_count = 0;
757f95f3850SWill Newton 
758b40af3aaSJames Hogan 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR);
759f95f3850SWill Newton 		temp = mci_readl(host, INTMASK);
760f95f3850SWill Newton 		temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR;
761f95f3850SWill Newton 		mci_writel(host, INTMASK, temp);
762f95f3850SWill Newton 
763f95f3850SWill Newton 		temp = mci_readl(host, CTRL);
764f95f3850SWill Newton 		temp &= ~SDMMC_CTRL_DMA_ENABLE;
765f95f3850SWill Newton 		mci_writel(host, CTRL, temp);
76652426899SSeungwon Jeon 
76752426899SSeungwon Jeon 		/*
76852426899SSeungwon Jeon 		 * Use the initial fifoth_val for PIO mode.
76952426899SSeungwon Jeon 		 * If next issued data may be transfered by DMA mode,
77052426899SSeungwon Jeon 		 * prev_blksz should be invalidated.
77152426899SSeungwon Jeon 		 */
77252426899SSeungwon Jeon 		mci_writel(host, FIFOTH, host->fifoth_val);
77352426899SSeungwon Jeon 		host->prev_blksz = 0;
77452426899SSeungwon Jeon 	} else {
77552426899SSeungwon Jeon 		/*
77652426899SSeungwon Jeon 		 * Keep the current block size.
77752426899SSeungwon Jeon 		 * It will be used to decide whether to update
77852426899SSeungwon Jeon 		 * fifoth register next time.
77952426899SSeungwon Jeon 		 */
78052426899SSeungwon Jeon 		host->prev_blksz = data->blksz;
781f95f3850SWill Newton 	}
782f95f3850SWill Newton }
783f95f3850SWill Newton 
784f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
785f95f3850SWill Newton {
786f95f3850SWill Newton 	struct dw_mci *host = slot->host;
787f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
788f95f3850SWill Newton 	unsigned int cmd_status = 0;
789f95f3850SWill Newton 
790f95f3850SWill Newton 	mci_writel(host, CMDARG, arg);
791f95f3850SWill Newton 	wmb();
792f95f3850SWill Newton 	mci_writel(host, CMD, SDMMC_CMD_START | cmd);
793f95f3850SWill Newton 
794f95f3850SWill Newton 	while (time_before(jiffies, timeout)) {
795f95f3850SWill Newton 		cmd_status = mci_readl(host, CMD);
796f95f3850SWill Newton 		if (!(cmd_status & SDMMC_CMD_START))
797f95f3850SWill Newton 			return;
798f95f3850SWill Newton 	}
799f95f3850SWill Newton 	dev_err(&slot->mmc->class_dev,
800f95f3850SWill Newton 		"Timeout sending command (cmd %#x arg %#x status %#x)\n",
801f95f3850SWill Newton 		cmd, arg, cmd_status);
802f95f3850SWill Newton }
803f95f3850SWill Newton 
804ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
805f95f3850SWill Newton {
806f95f3850SWill Newton 	struct dw_mci *host = slot->host;
807fdf492a1SDoug Anderson 	unsigned int clock = slot->clock;
808f95f3850SWill Newton 	u32 div;
8099623b5b9SDoug Anderson 	u32 clk_en_a;
81001730558SDoug Anderson 	u32 sdmmc_cmd_bits = SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT;
81101730558SDoug Anderson 
81201730558SDoug Anderson 	/* We must continue to set bit 28 in CMD until the change is complete */
81301730558SDoug Anderson 	if (host->state == STATE_WAITING_CMD11_DONE)
81401730558SDoug Anderson 		sdmmc_cmd_bits |= SDMMC_CMD_VOLT_SWITCH;
815f95f3850SWill Newton 
816fdf492a1SDoug Anderson 	if (!clock) {
817fdf492a1SDoug Anderson 		mci_writel(host, CLKENA, 0);
81801730558SDoug Anderson 		mci_send_cmd(slot, sdmmc_cmd_bits, 0);
819fdf492a1SDoug Anderson 	} else if (clock != host->current_speed || force_clkinit) {
820fdf492a1SDoug Anderson 		div = host->bus_hz / clock;
821fdf492a1SDoug Anderson 		if (host->bus_hz % clock && host->bus_hz > clock)
822f95f3850SWill Newton 			/*
823f95f3850SWill Newton 			 * move the + 1 after the divide to prevent
824f95f3850SWill Newton 			 * over-clocking the card.
825f95f3850SWill Newton 			 */
826e419990bSSeungwon Jeon 			div += 1;
827e419990bSSeungwon Jeon 
828fdf492a1SDoug Anderson 		div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0;
829f95f3850SWill Newton 
830fdf492a1SDoug Anderson 		if ((clock << div) != slot->__clk_old || force_clkinit)
831f95f3850SWill Newton 			dev_info(&slot->mmc->class_dev,
832fdf492a1SDoug Anderson 				 "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
833fdf492a1SDoug Anderson 				 slot->id, host->bus_hz, clock,
834fdf492a1SDoug Anderson 				 div ? ((host->bus_hz / div) >> 1) :
835fdf492a1SDoug Anderson 				 host->bus_hz, div);
836f95f3850SWill Newton 
837f95f3850SWill Newton 		/* disable clock */
838f95f3850SWill Newton 		mci_writel(host, CLKENA, 0);
839f95f3850SWill Newton 		mci_writel(host, CLKSRC, 0);
840f95f3850SWill Newton 
841f95f3850SWill Newton 		/* inform CIU */
84201730558SDoug Anderson 		mci_send_cmd(slot, sdmmc_cmd_bits, 0);
843f95f3850SWill Newton 
844f95f3850SWill Newton 		/* set clock to desired speed */
845f95f3850SWill Newton 		mci_writel(host, CLKDIV, div);
846f95f3850SWill Newton 
847f95f3850SWill Newton 		/* inform CIU */
84801730558SDoug Anderson 		mci_send_cmd(slot, sdmmc_cmd_bits, 0);
849f95f3850SWill Newton 
8509623b5b9SDoug Anderson 		/* enable clock; only low power if no SDIO */
8519623b5b9SDoug Anderson 		clk_en_a = SDMMC_CLKEN_ENABLE << slot->id;
8529623b5b9SDoug Anderson 		if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id)))
8539623b5b9SDoug Anderson 			clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id;
8549623b5b9SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a);
855f95f3850SWill Newton 
856f95f3850SWill Newton 		/* inform CIU */
85701730558SDoug Anderson 		mci_send_cmd(slot, sdmmc_cmd_bits, 0);
858f95f3850SWill Newton 
859fdf492a1SDoug Anderson 		/* keep the clock with reflecting clock dividor */
860fdf492a1SDoug Anderson 		slot->__clk_old = clock << div;
861f95f3850SWill Newton 	}
862f95f3850SWill Newton 
863fdf492a1SDoug Anderson 	host->current_speed = clock;
864fdf492a1SDoug Anderson 
865f95f3850SWill Newton 	/* Set the current slot bus width */
8661d56c453SSeungwon Jeon 	mci_writel(host, CTYPE, (slot->ctype << slot->id));
867f95f3850SWill Newton }
868f95f3850SWill Newton 
869053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host,
870053b3ce6SSeungwon Jeon 				   struct dw_mci_slot *slot,
871053b3ce6SSeungwon Jeon 				   struct mmc_command *cmd)
872f95f3850SWill Newton {
873f95f3850SWill Newton 	struct mmc_request *mrq;
874f95f3850SWill Newton 	struct mmc_data	*data;
875f95f3850SWill Newton 	u32 cmdflags;
876f95f3850SWill Newton 
877f95f3850SWill Newton 	mrq = slot->mrq;
878f95f3850SWill Newton 
879f95f3850SWill Newton 	host->cur_slot = slot;
880f95f3850SWill Newton 	host->mrq = mrq;
881f95f3850SWill Newton 
882f95f3850SWill Newton 	host->pending_events = 0;
883f95f3850SWill Newton 	host->completed_events = 0;
884e352c813SSeungwon Jeon 	host->cmd_status = 0;
885f95f3850SWill Newton 	host->data_status = 0;
886e352c813SSeungwon Jeon 	host->dir_status = 0;
887f95f3850SWill Newton 
888053b3ce6SSeungwon Jeon 	data = cmd->data;
889f95f3850SWill Newton 	if (data) {
890f16afa88SJaehoon Chung 		mci_writel(host, TMOUT, 0xFFFFFFFF);
891f95f3850SWill Newton 		mci_writel(host, BYTCNT, data->blksz*data->blocks);
892f95f3850SWill Newton 		mci_writel(host, BLKSIZ, data->blksz);
893f95f3850SWill Newton 	}
894f95f3850SWill Newton 
895f95f3850SWill Newton 	cmdflags = dw_mci_prepare_command(slot->mmc, cmd);
896f95f3850SWill Newton 
897f95f3850SWill Newton 	/* this is the first command, send the initialization clock */
898f95f3850SWill Newton 	if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags))
899f95f3850SWill Newton 		cmdflags |= SDMMC_CMD_INIT;
900f95f3850SWill Newton 
901f95f3850SWill Newton 	if (data) {
902f95f3850SWill Newton 		dw_mci_submit_data(host, data);
903f95f3850SWill Newton 		wmb();
904f95f3850SWill Newton 	}
905f95f3850SWill Newton 
906f95f3850SWill Newton 	dw_mci_start_command(host, cmd, cmdflags);
907f95f3850SWill Newton 
908f95f3850SWill Newton 	if (mrq->stop)
909f95f3850SWill Newton 		host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
91090c2143aSSeungwon Jeon 	else
91190c2143aSSeungwon Jeon 		host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd);
912f95f3850SWill Newton }
913f95f3850SWill Newton 
914053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host,
915053b3ce6SSeungwon Jeon 				 struct dw_mci_slot *slot)
916053b3ce6SSeungwon Jeon {
917053b3ce6SSeungwon Jeon 	struct mmc_request *mrq = slot->mrq;
918053b3ce6SSeungwon Jeon 	struct mmc_command *cmd;
919053b3ce6SSeungwon Jeon 
920053b3ce6SSeungwon Jeon 	cmd = mrq->sbc ? mrq->sbc : mrq->cmd;
921053b3ce6SSeungwon Jeon 	__dw_mci_start_request(host, slot, cmd);
922053b3ce6SSeungwon Jeon }
923053b3ce6SSeungwon Jeon 
9247456caaeSJames Hogan /* must be called with host->lock held */
925f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot,
926f95f3850SWill Newton 				 struct mmc_request *mrq)
927f95f3850SWill Newton {
928f95f3850SWill Newton 	dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
929f95f3850SWill Newton 		 host->state);
930f95f3850SWill Newton 
931f95f3850SWill Newton 	slot->mrq = mrq;
932f95f3850SWill Newton 
93301730558SDoug Anderson 	if (host->state == STATE_WAITING_CMD11_DONE) {
93401730558SDoug Anderson 		dev_warn(&slot->mmc->class_dev,
93501730558SDoug Anderson 			 "Voltage change didn't complete\n");
93601730558SDoug Anderson 		/*
93701730558SDoug Anderson 		 * this case isn't expected to happen, so we can
93801730558SDoug Anderson 		 * either crash here or just try to continue on
93901730558SDoug Anderson 		 * in the closest possible state
94001730558SDoug Anderson 		 */
94101730558SDoug Anderson 		host->state = STATE_IDLE;
94201730558SDoug Anderson 	}
94301730558SDoug Anderson 
944f95f3850SWill Newton 	if (host->state == STATE_IDLE) {
945f95f3850SWill Newton 		host->state = STATE_SENDING_CMD;
946f95f3850SWill Newton 		dw_mci_start_request(host, slot);
947f95f3850SWill Newton 	} else {
948f95f3850SWill Newton 		list_add_tail(&slot->queue_node, &host->queue);
949f95f3850SWill Newton 	}
950f95f3850SWill Newton }
951f95f3850SWill Newton 
952f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
953f95f3850SWill Newton {
954f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
955f95f3850SWill Newton 	struct dw_mci *host = slot->host;
956f95f3850SWill Newton 
957f95f3850SWill Newton 	WARN_ON(slot->mrq);
958f95f3850SWill Newton 
9597456caaeSJames Hogan 	/*
9607456caaeSJames Hogan 	 * The check for card presence and queueing of the request must be
9617456caaeSJames Hogan 	 * atomic, otherwise the card could be removed in between and the
9627456caaeSJames Hogan 	 * request wouldn't fail until another card was inserted.
9637456caaeSJames Hogan 	 */
9647456caaeSJames Hogan 	spin_lock_bh(&host->lock);
9657456caaeSJames Hogan 
966f95f3850SWill Newton 	if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
9677456caaeSJames Hogan 		spin_unlock_bh(&host->lock);
968f95f3850SWill Newton 		mrq->cmd->error = -ENOMEDIUM;
969f95f3850SWill Newton 		mmc_request_done(mmc, mrq);
970f95f3850SWill Newton 		return;
971f95f3850SWill Newton 	}
972f95f3850SWill Newton 
973f95f3850SWill Newton 	dw_mci_queue_request(host, slot, mrq);
9747456caaeSJames Hogan 
9757456caaeSJames Hogan 	spin_unlock_bh(&host->lock);
976f95f3850SWill Newton }
977f95f3850SWill Newton 
978f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
979f95f3850SWill Newton {
980f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
981e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
98241babf75SJaehoon Chung 	u32 regs;
98351da2240SYuvaraj CD 	int ret;
984f95f3850SWill Newton 
985f95f3850SWill Newton 	switch (ios->bus_width) {
986f95f3850SWill Newton 	case MMC_BUS_WIDTH_4:
987f95f3850SWill Newton 		slot->ctype = SDMMC_CTYPE_4BIT;
988f95f3850SWill Newton 		break;
989c9b2a06fSJaehoon Chung 	case MMC_BUS_WIDTH_8:
990c9b2a06fSJaehoon Chung 		slot->ctype = SDMMC_CTYPE_8BIT;
991c9b2a06fSJaehoon Chung 		break;
992b2f7cb45SJaehoon Chung 	default:
993b2f7cb45SJaehoon Chung 		/* set default 1 bit mode */
994b2f7cb45SJaehoon Chung 		slot->ctype = SDMMC_CTYPE_1BIT;
995f95f3850SWill Newton 	}
996f95f3850SWill Newton 
99741babf75SJaehoon Chung 	regs = mci_readl(slot->host, UHS_REG);
9983f514291SSeungwon Jeon 
9993f514291SSeungwon Jeon 	/* DDR mode set */
1000cab3a802SSeungwon Jeon 	if (ios->timing == MMC_TIMING_MMC_DDR52)
1001c69042a5SHyeonsu Kim 		regs |= ((0x1 << slot->id) << 16);
10023f514291SSeungwon Jeon 	else
1003c69042a5SHyeonsu Kim 		regs &= ~((0x1 << slot->id) << 16);
10043f514291SSeungwon Jeon 
100541babf75SJaehoon Chung 	mci_writel(slot->host, UHS_REG, regs);
1006f1d2736cSSeungwon Jeon 	slot->host->timing = ios->timing;
100741babf75SJaehoon Chung 
1008f95f3850SWill Newton 	/*
1009f95f3850SWill Newton 	 * Use mirror of ios->clock to prevent race with mmc
1010f95f3850SWill Newton 	 * core ios update when finding the minimum.
1011f95f3850SWill Newton 	 */
1012f95f3850SWill Newton 	slot->clock = ios->clock;
1013f95f3850SWill Newton 
1014cb27a843SJames Hogan 	if (drv_data && drv_data->set_ios)
1015cb27a843SJames Hogan 		drv_data->set_ios(slot->host, ios);
1016800d78bfSThomas Abraham 
1017bf7cb224SJaehoon Chung 	/* Slot specific timing and width adjustment */
1018bf7cb224SJaehoon Chung 	dw_mci_setup_bus(slot, false);
1019bf7cb224SJaehoon Chung 
102001730558SDoug Anderson 	if (slot->host->state == STATE_WAITING_CMD11_DONE && ios->clock != 0)
102101730558SDoug Anderson 		slot->host->state = STATE_IDLE;
102201730558SDoug Anderson 
1023f95f3850SWill Newton 	switch (ios->power_mode) {
1024f95f3850SWill Newton 	case MMC_POWER_UP:
102551da2240SYuvaraj CD 		if (!IS_ERR(mmc->supply.vmmc)) {
102651da2240SYuvaraj CD 			ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
102751da2240SYuvaraj CD 					ios->vdd);
102851da2240SYuvaraj CD 			if (ret) {
102951da2240SYuvaraj CD 				dev_err(slot->host->dev,
103051da2240SYuvaraj CD 					"failed to enable vmmc regulator\n");
103151da2240SYuvaraj CD 				/*return, if failed turn on vmmc*/
103251da2240SYuvaraj CD 				return;
103351da2240SYuvaraj CD 			}
103451da2240SYuvaraj CD 		}
103551da2240SYuvaraj CD 		if (!IS_ERR(mmc->supply.vqmmc) && !slot->host->vqmmc_enabled) {
103651da2240SYuvaraj CD 			ret = regulator_enable(mmc->supply.vqmmc);
103751da2240SYuvaraj CD 			if (ret < 0)
103851da2240SYuvaraj CD 				dev_err(slot->host->dev,
103951da2240SYuvaraj CD 					"failed to enable vqmmc regulator\n");
104051da2240SYuvaraj CD 			else
104151da2240SYuvaraj CD 				slot->host->vqmmc_enabled = true;
104251da2240SYuvaraj CD 		}
1043f95f3850SWill Newton 		set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
10444366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
10454366dcc5SJaehoon Chung 		regs |= (1 << slot->id);
10464366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
1047e6f34e2fSJames Hogan 		break;
1048e6f34e2fSJames Hogan 	case MMC_POWER_OFF:
104951da2240SYuvaraj CD 		if (!IS_ERR(mmc->supply.vmmc))
105051da2240SYuvaraj CD 			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
105151da2240SYuvaraj CD 
105251da2240SYuvaraj CD 		if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) {
105351da2240SYuvaraj CD 			regulator_disable(mmc->supply.vqmmc);
105451da2240SYuvaraj CD 			slot->host->vqmmc_enabled = false;
105551da2240SYuvaraj CD 		}
105651da2240SYuvaraj CD 
10574366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
10584366dcc5SJaehoon Chung 		regs &= ~(1 << slot->id);
10594366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
1060f95f3850SWill Newton 		break;
1061f95f3850SWill Newton 	default:
1062f95f3850SWill Newton 		break;
1063f95f3850SWill Newton 	}
1064f95f3850SWill Newton }
1065f95f3850SWill Newton 
106601730558SDoug Anderson static int dw_mci_card_busy(struct mmc_host *mmc)
106701730558SDoug Anderson {
106801730558SDoug Anderson 	struct dw_mci_slot *slot = mmc_priv(mmc);
106901730558SDoug Anderson 	u32 status;
107001730558SDoug Anderson 
107101730558SDoug Anderson 	/*
107201730558SDoug Anderson 	 * Check the busy bit which is low when DAT[3:0]
107301730558SDoug Anderson 	 * (the data lines) are 0000
107401730558SDoug Anderson 	 */
107501730558SDoug Anderson 	status = mci_readl(slot->host, STATUS);
107601730558SDoug Anderson 
107701730558SDoug Anderson 	return !!(status & SDMMC_STATUS_BUSY);
107801730558SDoug Anderson }
107901730558SDoug Anderson 
108001730558SDoug Anderson static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
108101730558SDoug Anderson {
108201730558SDoug Anderson 	struct dw_mci_slot *slot = mmc_priv(mmc);
108301730558SDoug Anderson 	struct dw_mci *host = slot->host;
108401730558SDoug Anderson 	u32 uhs;
108501730558SDoug Anderson 	u32 v18 = SDMMC_UHS_18V << slot->id;
108601730558SDoug Anderson 	int min_uv, max_uv;
108701730558SDoug Anderson 	int ret;
108801730558SDoug Anderson 
108901730558SDoug Anderson 	/*
109001730558SDoug Anderson 	 * Program the voltage.  Note that some instances of dw_mmc may use
109101730558SDoug Anderson 	 * the UHS_REG for this.  For other instances (like exynos) the UHS_REG
109201730558SDoug Anderson 	 * does no harm but you need to set the regulator directly.  Try both.
109301730558SDoug Anderson 	 */
109401730558SDoug Anderson 	uhs = mci_readl(host, UHS_REG);
109501730558SDoug Anderson 	if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
109601730558SDoug Anderson 		min_uv = 2700000;
109701730558SDoug Anderson 		max_uv = 3600000;
109801730558SDoug Anderson 		uhs &= ~v18;
109901730558SDoug Anderson 	} else {
110001730558SDoug Anderson 		min_uv = 1700000;
110101730558SDoug Anderson 		max_uv = 1950000;
110201730558SDoug Anderson 		uhs |= v18;
110301730558SDoug Anderson 	}
110401730558SDoug Anderson 	if (!IS_ERR(mmc->supply.vqmmc)) {
110501730558SDoug Anderson 		ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv);
110601730558SDoug Anderson 
110701730558SDoug Anderson 		if (ret) {
110801730558SDoug Anderson 			dev_err(&mmc->class_dev,
110901730558SDoug Anderson 					 "Regulator set error %d: %d - %d\n",
111001730558SDoug Anderson 					 ret, min_uv, max_uv);
111101730558SDoug Anderson 			return ret;
111201730558SDoug Anderson 		}
111301730558SDoug Anderson 	}
111401730558SDoug Anderson 	mci_writel(host, UHS_REG, uhs);
111501730558SDoug Anderson 
111601730558SDoug Anderson 	return 0;
111701730558SDoug Anderson }
111801730558SDoug Anderson 
1119f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc)
1120f95f3850SWill Newton {
1121f95f3850SWill Newton 	int read_only;
1122f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
11239795a846SJaehoon Chung 	int gpio_ro = mmc_gpio_get_ro(mmc);
1124f95f3850SWill Newton 
1125f95f3850SWill Newton 	/* Use platform get_ro function, else try on board write protect */
112626375b5cSJaehoon Chung 	if ((slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT) ||
112726375b5cSJaehoon Chung 			(slot->host->quirks & DW_MCI_QUIRK_NO_WRITE_PROTECT))
1128b4967aa5SThomas Abraham 		read_only = 0;
11299795a846SJaehoon Chung 	else if (!IS_ERR_VALUE(gpio_ro))
11309795a846SJaehoon Chung 		read_only = gpio_ro;
1131f95f3850SWill Newton 	else
1132f95f3850SWill Newton 		read_only =
1133f95f3850SWill Newton 			mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0;
1134f95f3850SWill Newton 
1135f95f3850SWill Newton 	dev_dbg(&mmc->class_dev, "card is %s\n",
1136f95f3850SWill Newton 		read_only ? "read-only" : "read-write");
1137f95f3850SWill Newton 
1138f95f3850SWill Newton 	return read_only;
1139f95f3850SWill Newton }
1140f95f3850SWill Newton 
1141f95f3850SWill Newton static int dw_mci_get_cd(struct mmc_host *mmc)
1142f95f3850SWill Newton {
1143f95f3850SWill Newton 	int present;
1144f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
1145f95f3850SWill Newton 	struct dw_mci_board *brd = slot->host->pdata;
11467cf347bdSZhangfei Gao 	struct dw_mci *host = slot->host;
11477cf347bdSZhangfei Gao 	int gpio_cd = mmc_gpio_get_cd(mmc);
1148f95f3850SWill Newton 
1149f95f3850SWill Newton 	/* Use platform get_cd function, else try onboard card detect */
1150fc3d7720SJaehoon Chung 	if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
1151fc3d7720SJaehoon Chung 		present = 1;
1152bf626e55SZhangfei Gao 	else if (!IS_ERR_VALUE(gpio_cd))
11537cf347bdSZhangfei Gao 		present = gpio_cd;
1154f95f3850SWill Newton 	else
1155f95f3850SWill Newton 		present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
1156f95f3850SWill Newton 			== 0 ? 1 : 0;
1157f95f3850SWill Newton 
11587cf347bdSZhangfei Gao 	spin_lock_bh(&host->lock);
1159bf626e55SZhangfei Gao 	if (present) {
1160bf626e55SZhangfei Gao 		set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
1161f95f3850SWill Newton 		dev_dbg(&mmc->class_dev, "card is present\n");
1162bf626e55SZhangfei Gao 	} else {
1163bf626e55SZhangfei Gao 		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
1164f95f3850SWill Newton 		dev_dbg(&mmc->class_dev, "card is not present\n");
1165bf626e55SZhangfei Gao 	}
11667cf347bdSZhangfei Gao 	spin_unlock_bh(&host->lock);
1167f95f3850SWill Newton 
1168f95f3850SWill Newton 	return present;
1169f95f3850SWill Newton }
1170f95f3850SWill Newton 
11719623b5b9SDoug Anderson /*
11729623b5b9SDoug Anderson  * Disable lower power mode.
11739623b5b9SDoug Anderson  *
11749623b5b9SDoug Anderson  * Low power mode will stop the card clock when idle.  According to the
11759623b5b9SDoug Anderson  * description of the CLKENA register we should disable low power mode
11769623b5b9SDoug Anderson  * for SDIO cards if we need SDIO interrupts to work.
11779623b5b9SDoug Anderson  *
11789623b5b9SDoug Anderson  * This function is fast if low power mode is already disabled.
11799623b5b9SDoug Anderson  */
11809623b5b9SDoug Anderson static void dw_mci_disable_low_power(struct dw_mci_slot *slot)
11819623b5b9SDoug Anderson {
11829623b5b9SDoug Anderson 	struct dw_mci *host = slot->host;
11839623b5b9SDoug Anderson 	u32 clk_en_a;
11849623b5b9SDoug Anderson 	const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id;
11859623b5b9SDoug Anderson 
11869623b5b9SDoug Anderson 	clk_en_a = mci_readl(host, CLKENA);
11879623b5b9SDoug Anderson 
11889623b5b9SDoug Anderson 	if (clk_en_a & clken_low_pwr) {
11899623b5b9SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr);
11909623b5b9SDoug Anderson 		mci_send_cmd(slot, SDMMC_CMD_UPD_CLK |
11919623b5b9SDoug Anderson 			     SDMMC_CMD_PRV_DAT_WAIT, 0);
11929623b5b9SDoug Anderson 	}
11939623b5b9SDoug Anderson }
11949623b5b9SDoug Anderson 
11951a5c8e1fSShashidhar Hiremath static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
11961a5c8e1fSShashidhar Hiremath {
11971a5c8e1fSShashidhar Hiremath 	struct dw_mci_slot *slot = mmc_priv(mmc);
11981a5c8e1fSShashidhar Hiremath 	struct dw_mci *host = slot->host;
11991a5c8e1fSShashidhar Hiremath 	u32 int_mask;
12001a5c8e1fSShashidhar Hiremath 
12011a5c8e1fSShashidhar Hiremath 	/* Enable/disable Slot Specific SDIO interrupt */
12021a5c8e1fSShashidhar Hiremath 	int_mask = mci_readl(host, INTMASK);
12031a5c8e1fSShashidhar Hiremath 	if (enb) {
12049623b5b9SDoug Anderson 		/*
12059623b5b9SDoug Anderson 		 * Turn off low power mode if it was enabled.  This is a bit of
12069623b5b9SDoug Anderson 		 * a heavy operation and we disable / enable IRQs a lot, so
12079623b5b9SDoug Anderson 		 * we'll leave low power mode disabled and it will get
12089623b5b9SDoug Anderson 		 * re-enabled again in dw_mci_setup_bus().
12099623b5b9SDoug Anderson 		 */
12109623b5b9SDoug Anderson 		dw_mci_disable_low_power(slot);
12119623b5b9SDoug Anderson 
12121a5c8e1fSShashidhar Hiremath 		mci_writel(host, INTMASK,
1213705ad047SKyoungil Kim 			   (int_mask | SDMMC_INT_SDIO(slot->id)));
12141a5c8e1fSShashidhar Hiremath 	} else {
12151a5c8e1fSShashidhar Hiremath 		mci_writel(host, INTMASK,
1216705ad047SKyoungil Kim 			   (int_mask & ~SDMMC_INT_SDIO(slot->id)));
12171a5c8e1fSShashidhar Hiremath 	}
12181a5c8e1fSShashidhar Hiremath }
12191a5c8e1fSShashidhar Hiremath 
12200976f16dSSeungwon Jeon static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
12210976f16dSSeungwon Jeon {
12220976f16dSSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
12230976f16dSSeungwon Jeon 	struct dw_mci *host = slot->host;
12240976f16dSSeungwon Jeon 	const struct dw_mci_drv_data *drv_data = host->drv_data;
12250976f16dSSeungwon Jeon 	struct dw_mci_tuning_data tuning_data;
12260976f16dSSeungwon Jeon 	int err = -ENOSYS;
12270976f16dSSeungwon Jeon 
12280976f16dSSeungwon Jeon 	if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
12290976f16dSSeungwon Jeon 		if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
12300976f16dSSeungwon Jeon 			tuning_data.blk_pattern = tuning_blk_pattern_8bit;
12310976f16dSSeungwon Jeon 			tuning_data.blksz = sizeof(tuning_blk_pattern_8bit);
12320976f16dSSeungwon Jeon 		} else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
12330976f16dSSeungwon Jeon 			tuning_data.blk_pattern = tuning_blk_pattern_4bit;
12340976f16dSSeungwon Jeon 			tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
12350976f16dSSeungwon Jeon 		} else {
12360976f16dSSeungwon Jeon 			return -EINVAL;
12370976f16dSSeungwon Jeon 		}
12380976f16dSSeungwon Jeon 	} else if (opcode == MMC_SEND_TUNING_BLOCK) {
12390976f16dSSeungwon Jeon 		tuning_data.blk_pattern = tuning_blk_pattern_4bit;
12400976f16dSSeungwon Jeon 		tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
12410976f16dSSeungwon Jeon 	} else {
12420976f16dSSeungwon Jeon 		dev_err(host->dev,
12430976f16dSSeungwon Jeon 			"Undefined command(%d) for tuning\n", opcode);
12440976f16dSSeungwon Jeon 		return -EINVAL;
12450976f16dSSeungwon Jeon 	}
12460976f16dSSeungwon Jeon 
12470976f16dSSeungwon Jeon 	if (drv_data && drv_data->execute_tuning)
12480976f16dSSeungwon Jeon 		err = drv_data->execute_tuning(slot, opcode, &tuning_data);
12490976f16dSSeungwon Jeon 	return err;
12500976f16dSSeungwon Jeon }
12510976f16dSSeungwon Jeon 
1252f95f3850SWill Newton static const struct mmc_host_ops dw_mci_ops = {
1253f95f3850SWill Newton 	.request		= dw_mci_request,
12549aa51408SSeungwon Jeon 	.pre_req		= dw_mci_pre_req,
12559aa51408SSeungwon Jeon 	.post_req		= dw_mci_post_req,
1256f95f3850SWill Newton 	.set_ios		= dw_mci_set_ios,
1257f95f3850SWill Newton 	.get_ro			= dw_mci_get_ro,
1258f95f3850SWill Newton 	.get_cd			= dw_mci_get_cd,
12591a5c8e1fSShashidhar Hiremath 	.enable_sdio_irq	= dw_mci_enable_sdio_irq,
12600976f16dSSeungwon Jeon 	.execute_tuning		= dw_mci_execute_tuning,
126101730558SDoug Anderson 	.card_busy		= dw_mci_card_busy,
126201730558SDoug Anderson 	.start_signal_voltage_switch = dw_mci_switch_voltage,
126301730558SDoug Anderson 
1264f95f3850SWill Newton };
1265f95f3850SWill Newton 
1266f95f3850SWill Newton static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
1267f95f3850SWill Newton 	__releases(&host->lock)
1268f95f3850SWill Newton 	__acquires(&host->lock)
1269f95f3850SWill Newton {
1270f95f3850SWill Newton 	struct dw_mci_slot *slot;
1271f95f3850SWill Newton 	struct mmc_host	*prev_mmc = host->cur_slot->mmc;
1272f95f3850SWill Newton 
1273f95f3850SWill Newton 	WARN_ON(host->cmd || host->data);
1274f95f3850SWill Newton 
1275f95f3850SWill Newton 	host->cur_slot->mrq = NULL;
1276f95f3850SWill Newton 	host->mrq = NULL;
1277f95f3850SWill Newton 	if (!list_empty(&host->queue)) {
1278f95f3850SWill Newton 		slot = list_entry(host->queue.next,
1279f95f3850SWill Newton 				  struct dw_mci_slot, queue_node);
1280f95f3850SWill Newton 		list_del(&slot->queue_node);
12814a90920cSThomas Abraham 		dev_vdbg(host->dev, "list not empty: %s is next\n",
1282f95f3850SWill Newton 			 mmc_hostname(slot->mmc));
1283f95f3850SWill Newton 		host->state = STATE_SENDING_CMD;
1284f95f3850SWill Newton 		dw_mci_start_request(host, slot);
1285f95f3850SWill Newton 	} else {
12864a90920cSThomas Abraham 		dev_vdbg(host->dev, "list empty\n");
128701730558SDoug Anderson 
128801730558SDoug Anderson 		if (host->state == STATE_SENDING_CMD11)
128901730558SDoug Anderson 			host->state = STATE_WAITING_CMD11_DONE;
129001730558SDoug Anderson 		else
1291f95f3850SWill Newton 			host->state = STATE_IDLE;
1292f95f3850SWill Newton 	}
1293f95f3850SWill Newton 
1294f95f3850SWill Newton 	spin_unlock(&host->lock);
1295f95f3850SWill Newton 	mmc_request_done(prev_mmc, mrq);
1296f95f3850SWill Newton 	spin_lock(&host->lock);
1297f95f3850SWill Newton }
1298f95f3850SWill Newton 
1299e352c813SSeungwon Jeon static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
1300f95f3850SWill Newton {
1301f95f3850SWill Newton 	u32 status = host->cmd_status;
1302f95f3850SWill Newton 
1303f95f3850SWill Newton 	host->cmd_status = 0;
1304f95f3850SWill Newton 
1305f95f3850SWill Newton 	/* Read the response from the card (up to 16 bytes) */
1306f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_PRESENT) {
1307f95f3850SWill Newton 		if (cmd->flags & MMC_RSP_136) {
1308f95f3850SWill Newton 			cmd->resp[3] = mci_readl(host, RESP0);
1309f95f3850SWill Newton 			cmd->resp[2] = mci_readl(host, RESP1);
1310f95f3850SWill Newton 			cmd->resp[1] = mci_readl(host, RESP2);
1311f95f3850SWill Newton 			cmd->resp[0] = mci_readl(host, RESP3);
1312f95f3850SWill Newton 		} else {
1313f95f3850SWill Newton 			cmd->resp[0] = mci_readl(host, RESP0);
1314f95f3850SWill Newton 			cmd->resp[1] = 0;
1315f95f3850SWill Newton 			cmd->resp[2] = 0;
1316f95f3850SWill Newton 			cmd->resp[3] = 0;
1317f95f3850SWill Newton 		}
1318f95f3850SWill Newton 	}
1319f95f3850SWill Newton 
1320f95f3850SWill Newton 	if (status & SDMMC_INT_RTO)
1321f95f3850SWill Newton 		cmd->error = -ETIMEDOUT;
1322f95f3850SWill Newton 	else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC))
1323f95f3850SWill Newton 		cmd->error = -EILSEQ;
1324f95f3850SWill Newton 	else if (status & SDMMC_INT_RESP_ERR)
1325f95f3850SWill Newton 		cmd->error = -EIO;
1326f95f3850SWill Newton 	else
1327f95f3850SWill Newton 		cmd->error = 0;
1328f95f3850SWill Newton 
1329f95f3850SWill Newton 	if (cmd->error) {
1330f95f3850SWill Newton 		/* newer ip versions need a delay between retries */
1331f95f3850SWill Newton 		if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY)
1332f95f3850SWill Newton 			mdelay(20);
1333f95f3850SWill Newton 	}
1334e352c813SSeungwon Jeon 
1335e352c813SSeungwon Jeon 	return cmd->error;
1336e352c813SSeungwon Jeon }
1337e352c813SSeungwon Jeon 
1338e352c813SSeungwon Jeon static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data)
1339e352c813SSeungwon Jeon {
134031bff450SSeungwon Jeon 	u32 status = host->data_status;
1341e352c813SSeungwon Jeon 
1342e352c813SSeungwon Jeon 	if (status & DW_MCI_DATA_ERROR_FLAGS) {
1343e352c813SSeungwon Jeon 		if (status & SDMMC_INT_DRTO) {
1344e352c813SSeungwon Jeon 			data->error = -ETIMEDOUT;
1345e352c813SSeungwon Jeon 		} else if (status & SDMMC_INT_DCRC) {
1346e352c813SSeungwon Jeon 			data->error = -EILSEQ;
1347e352c813SSeungwon Jeon 		} else if (status & SDMMC_INT_EBE) {
1348e352c813SSeungwon Jeon 			if (host->dir_status ==
1349e352c813SSeungwon Jeon 				DW_MCI_SEND_STATUS) {
1350e352c813SSeungwon Jeon 				/*
1351e352c813SSeungwon Jeon 				 * No data CRC status was returned.
1352e352c813SSeungwon Jeon 				 * The number of bytes transferred
1353e352c813SSeungwon Jeon 				 * will be exaggerated in PIO mode.
1354e352c813SSeungwon Jeon 				 */
1355e352c813SSeungwon Jeon 				data->bytes_xfered = 0;
1356e352c813SSeungwon Jeon 				data->error = -ETIMEDOUT;
1357e352c813SSeungwon Jeon 			} else if (host->dir_status ==
1358e352c813SSeungwon Jeon 					DW_MCI_RECV_STATUS) {
1359e352c813SSeungwon Jeon 				data->error = -EIO;
1360e352c813SSeungwon Jeon 			}
1361e352c813SSeungwon Jeon 		} else {
1362e352c813SSeungwon Jeon 			/* SDMMC_INT_SBE is included */
1363e352c813SSeungwon Jeon 			data->error = -EIO;
1364e352c813SSeungwon Jeon 		}
1365e352c813SSeungwon Jeon 
1366e6cc0123SDoug Anderson 		dev_dbg(host->dev, "data error, status 0x%08x\n", status);
1367e352c813SSeungwon Jeon 
1368e352c813SSeungwon Jeon 		/*
1369e352c813SSeungwon Jeon 		 * After an error, there may be data lingering
137031bff450SSeungwon Jeon 		 * in the FIFO
1371e352c813SSeungwon Jeon 		 */
13723a33a94cSSonny Rao 		dw_mci_reset(host);
1373e352c813SSeungwon Jeon 	} else {
1374e352c813SSeungwon Jeon 		data->bytes_xfered = data->blocks * data->blksz;
1375e352c813SSeungwon Jeon 		data->error = 0;
1376e352c813SSeungwon Jeon 	}
1377e352c813SSeungwon Jeon 
1378e352c813SSeungwon Jeon 	return data->error;
1379f95f3850SWill Newton }
1380f95f3850SWill Newton 
1381f95f3850SWill Newton static void dw_mci_tasklet_func(unsigned long priv)
1382f95f3850SWill Newton {
1383f95f3850SWill Newton 	struct dw_mci *host = (struct dw_mci *)priv;
1384f95f3850SWill Newton 	struct mmc_data	*data;
1385f95f3850SWill Newton 	struct mmc_command *cmd;
1386e352c813SSeungwon Jeon 	struct mmc_request *mrq;
1387f95f3850SWill Newton 	enum dw_mci_state state;
1388f95f3850SWill Newton 	enum dw_mci_state prev_state;
1389e352c813SSeungwon Jeon 	unsigned int err;
1390f95f3850SWill Newton 
1391f95f3850SWill Newton 	spin_lock(&host->lock);
1392f95f3850SWill Newton 
1393f95f3850SWill Newton 	state = host->state;
1394f95f3850SWill Newton 	data = host->data;
1395e352c813SSeungwon Jeon 	mrq = host->mrq;
1396f95f3850SWill Newton 
1397f95f3850SWill Newton 	do {
1398f95f3850SWill Newton 		prev_state = state;
1399f95f3850SWill Newton 
1400f95f3850SWill Newton 		switch (state) {
1401f95f3850SWill Newton 		case STATE_IDLE:
140201730558SDoug Anderson 		case STATE_WAITING_CMD11_DONE:
1403f95f3850SWill Newton 			break;
1404f95f3850SWill Newton 
140501730558SDoug Anderson 		case STATE_SENDING_CMD11:
1406f95f3850SWill Newton 		case STATE_SENDING_CMD:
1407f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1408f95f3850SWill Newton 						&host->pending_events))
1409f95f3850SWill Newton 				break;
1410f95f3850SWill Newton 
1411f95f3850SWill Newton 			cmd = host->cmd;
1412f95f3850SWill Newton 			host->cmd = NULL;
1413f95f3850SWill Newton 			set_bit(EVENT_CMD_COMPLETE, &host->completed_events);
1414e352c813SSeungwon Jeon 			err = dw_mci_command_complete(host, cmd);
1415e352c813SSeungwon Jeon 			if (cmd == mrq->sbc && !err) {
1416053b3ce6SSeungwon Jeon 				prev_state = state = STATE_SENDING_CMD;
1417053b3ce6SSeungwon Jeon 				__dw_mci_start_request(host, host->cur_slot,
1418e352c813SSeungwon Jeon 						       mrq->cmd);
1419053b3ce6SSeungwon Jeon 				goto unlock;
1420053b3ce6SSeungwon Jeon 			}
1421053b3ce6SSeungwon Jeon 
1422e352c813SSeungwon Jeon 			if (cmd->data && err) {
142371abb133SSeungwon Jeon 				dw_mci_stop_dma(host);
142490c2143aSSeungwon Jeon 				send_stop_abort(host, data);
142571abb133SSeungwon Jeon 				state = STATE_SENDING_STOP;
142671abb133SSeungwon Jeon 				break;
142771abb133SSeungwon Jeon 			}
142871abb133SSeungwon Jeon 
1429e352c813SSeungwon Jeon 			if (!cmd->data || err) {
1430e352c813SSeungwon Jeon 				dw_mci_request_end(host, mrq);
1431f95f3850SWill Newton 				goto unlock;
1432f95f3850SWill Newton 			}
1433f95f3850SWill Newton 
1434f95f3850SWill Newton 			prev_state = state = STATE_SENDING_DATA;
1435f95f3850SWill Newton 			/* fall through */
1436f95f3850SWill Newton 
1437f95f3850SWill Newton 		case STATE_SENDING_DATA:
14382aa35465SDoug Anderson 			/*
14392aa35465SDoug Anderson 			 * We could get a data error and never a transfer
14402aa35465SDoug Anderson 			 * complete so we'd better check for it here.
14412aa35465SDoug Anderson 			 *
14422aa35465SDoug Anderson 			 * Note that we don't really care if we also got a
14432aa35465SDoug Anderson 			 * transfer complete; stopping the DMA and sending an
14442aa35465SDoug Anderson 			 * abort won't hurt.
14452aa35465SDoug Anderson 			 */
1446f95f3850SWill Newton 			if (test_and_clear_bit(EVENT_DATA_ERROR,
1447f95f3850SWill Newton 					       &host->pending_events)) {
1448f95f3850SWill Newton 				dw_mci_stop_dma(host);
144990c2143aSSeungwon Jeon 				send_stop_abort(host, data);
1450f95f3850SWill Newton 				state = STATE_DATA_ERROR;
1451f95f3850SWill Newton 				break;
1452f95f3850SWill Newton 			}
1453f95f3850SWill Newton 
1454f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1455f95f3850SWill Newton 						&host->pending_events))
1456f95f3850SWill Newton 				break;
1457f95f3850SWill Newton 
1458f95f3850SWill Newton 			set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
14592aa35465SDoug Anderson 
14602aa35465SDoug Anderson 			/*
14612aa35465SDoug Anderson 			 * Handle an EVENT_DATA_ERROR that might have shown up
14622aa35465SDoug Anderson 			 * before the transfer completed.  This might not have
14632aa35465SDoug Anderson 			 * been caught by the check above because the interrupt
14642aa35465SDoug Anderson 			 * could have gone off between the previous check and
14652aa35465SDoug Anderson 			 * the check for transfer complete.
14662aa35465SDoug Anderson 			 *
14672aa35465SDoug Anderson 			 * Technically this ought not be needed assuming we
14682aa35465SDoug Anderson 			 * get a DATA_COMPLETE eventually (we'll notice the
14692aa35465SDoug Anderson 			 * error and end the request), but it shouldn't hurt.
14702aa35465SDoug Anderson 			 *
14712aa35465SDoug Anderson 			 * This has the advantage of sending the stop command.
14722aa35465SDoug Anderson 			 */
14732aa35465SDoug Anderson 			if (test_and_clear_bit(EVENT_DATA_ERROR,
14742aa35465SDoug Anderson 					       &host->pending_events)) {
14752aa35465SDoug Anderson 				dw_mci_stop_dma(host);
14762aa35465SDoug Anderson 				send_stop_abort(host, data);
14772aa35465SDoug Anderson 				state = STATE_DATA_ERROR;
14782aa35465SDoug Anderson 				break;
14792aa35465SDoug Anderson 			}
1480f95f3850SWill Newton 			prev_state = state = STATE_DATA_BUSY;
14812aa35465SDoug Anderson 
1482f95f3850SWill Newton 			/* fall through */
1483f95f3850SWill Newton 
1484f95f3850SWill Newton 		case STATE_DATA_BUSY:
1485f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
1486f95f3850SWill Newton 						&host->pending_events))
1487f95f3850SWill Newton 				break;
1488f95f3850SWill Newton 
1489f95f3850SWill Newton 			host->data = NULL;
1490f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
1491e352c813SSeungwon Jeon 			err = dw_mci_data_complete(host, data);
1492f95f3850SWill Newton 
1493e352c813SSeungwon Jeon 			if (!err) {
1494e352c813SSeungwon Jeon 				if (!data->stop || mrq->sbc) {
149517c8bc85SSachin Kamat 					if (mrq->sbc && data->stop)
1496053b3ce6SSeungwon Jeon 						data->stop->error = 0;
1497e352c813SSeungwon Jeon 					dw_mci_request_end(host, mrq);
1498053b3ce6SSeungwon Jeon 					goto unlock;
1499053b3ce6SSeungwon Jeon 				}
1500053b3ce6SSeungwon Jeon 
150190c2143aSSeungwon Jeon 				/* stop command for open-ended transfer*/
1502e352c813SSeungwon Jeon 				if (data->stop)
150390c2143aSSeungwon Jeon 					send_stop_abort(host, data);
15042aa35465SDoug Anderson 			} else {
15052aa35465SDoug Anderson 				/*
15062aa35465SDoug Anderson 				 * If we don't have a command complete now we'll
15072aa35465SDoug Anderson 				 * never get one since we just reset everything;
15082aa35465SDoug Anderson 				 * better end the request.
15092aa35465SDoug Anderson 				 *
15102aa35465SDoug Anderson 				 * If we do have a command complete we'll fall
15112aa35465SDoug Anderson 				 * through to the SENDING_STOP command and
15122aa35465SDoug Anderson 				 * everything will be peachy keen.
15132aa35465SDoug Anderson 				 */
15142aa35465SDoug Anderson 				if (!test_bit(EVENT_CMD_COMPLETE,
15152aa35465SDoug Anderson 					      &host->pending_events)) {
15162aa35465SDoug Anderson 					host->cmd = NULL;
15172aa35465SDoug Anderson 					dw_mci_request_end(host, mrq);
15182aa35465SDoug Anderson 					goto unlock;
15192aa35465SDoug Anderson 				}
152090c2143aSSeungwon Jeon 			}
1521e352c813SSeungwon Jeon 
1522e352c813SSeungwon Jeon 			/*
1523e352c813SSeungwon Jeon 			 * If err has non-zero,
1524e352c813SSeungwon Jeon 			 * stop-abort command has been already issued.
1525e352c813SSeungwon Jeon 			 */
1526e352c813SSeungwon Jeon 			prev_state = state = STATE_SENDING_STOP;
1527e352c813SSeungwon Jeon 
1528f95f3850SWill Newton 			/* fall through */
1529f95f3850SWill Newton 
1530f95f3850SWill Newton 		case STATE_SENDING_STOP:
1531f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1532f95f3850SWill Newton 						&host->pending_events))
1533f95f3850SWill Newton 				break;
1534f95f3850SWill Newton 
153571abb133SSeungwon Jeon 			/* CMD error in data command */
153631bff450SSeungwon Jeon 			if (mrq->cmd->error && mrq->data)
15373a33a94cSSonny Rao 				dw_mci_reset(host);
153871abb133SSeungwon Jeon 
1539f95f3850SWill Newton 			host->cmd = NULL;
154071abb133SSeungwon Jeon 			host->data = NULL;
154190c2143aSSeungwon Jeon 
1542e352c813SSeungwon Jeon 			if (mrq->stop)
1543e352c813SSeungwon Jeon 				dw_mci_command_complete(host, mrq->stop);
154490c2143aSSeungwon Jeon 			else
154590c2143aSSeungwon Jeon 				host->cmd_status = 0;
154690c2143aSSeungwon Jeon 
1547e352c813SSeungwon Jeon 			dw_mci_request_end(host, mrq);
1548f95f3850SWill Newton 			goto unlock;
1549f95f3850SWill Newton 
1550f95f3850SWill Newton 		case STATE_DATA_ERROR:
1551f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1552f95f3850SWill Newton 						&host->pending_events))
1553f95f3850SWill Newton 				break;
1554f95f3850SWill Newton 
1555f95f3850SWill Newton 			state = STATE_DATA_BUSY;
1556f95f3850SWill Newton 			break;
1557f95f3850SWill Newton 		}
1558f95f3850SWill Newton 	} while (state != prev_state);
1559f95f3850SWill Newton 
1560f95f3850SWill Newton 	host->state = state;
1561f95f3850SWill Newton unlock:
1562f95f3850SWill Newton 	spin_unlock(&host->lock);
1563f95f3850SWill Newton 
1564f95f3850SWill Newton }
1565f95f3850SWill Newton 
156634b664a2SJames Hogan /* push final bytes to part_buf, only use during push */
156734b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt)
156834b664a2SJames Hogan {
156934b664a2SJames Hogan 	memcpy((void *)&host->part_buf, buf, cnt);
157034b664a2SJames Hogan 	host->part_buf_count = cnt;
157134b664a2SJames Hogan }
157234b664a2SJames Hogan 
157334b664a2SJames Hogan /* append bytes to part_buf, only use during push */
157434b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt)
157534b664a2SJames Hogan {
157634b664a2SJames Hogan 	cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count);
157734b664a2SJames Hogan 	memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt);
157834b664a2SJames Hogan 	host->part_buf_count += cnt;
157934b664a2SJames Hogan 	return cnt;
158034b664a2SJames Hogan }
158134b664a2SJames Hogan 
158234b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */
158334b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt)
158434b664a2SJames Hogan {
158534b664a2SJames Hogan 	cnt = min(cnt, (int)host->part_buf_count);
158634b664a2SJames Hogan 	if (cnt) {
158734b664a2SJames Hogan 		memcpy(buf, (void *)&host->part_buf + host->part_buf_start,
158834b664a2SJames Hogan 		       cnt);
158934b664a2SJames Hogan 		host->part_buf_count -= cnt;
159034b664a2SJames Hogan 		host->part_buf_start += cnt;
159134b664a2SJames Hogan 	}
159234b664a2SJames Hogan 	return cnt;
159334b664a2SJames Hogan }
159434b664a2SJames Hogan 
159534b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */
159634b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt)
159734b664a2SJames Hogan {
159834b664a2SJames Hogan 	memcpy(buf, &host->part_buf, cnt);
159934b664a2SJames Hogan 	host->part_buf_start = cnt;
160034b664a2SJames Hogan 	host->part_buf_count = (1 << host->data_shift) - cnt;
160134b664a2SJames Hogan }
160234b664a2SJames Hogan 
1603f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
1604f95f3850SWill Newton {
1605cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1606cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1607cfbeb59cSMarkos Chandras 
160834b664a2SJames Hogan 	/* try and push anything in the part_buf */
160934b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
161034b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
161134b664a2SJames Hogan 		buf += len;
161234b664a2SJames Hogan 		cnt -= len;
1613cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 2) {
16144e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
16154e0a5adfSJaehoon Chung 					host->part_buf16);
161634b664a2SJames Hogan 			host->part_buf_count = 0;
161734b664a2SJames Hogan 		}
161834b664a2SJames Hogan 	}
161934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
162034b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
162134b664a2SJames Hogan 		while (cnt >= 2) {
162234b664a2SJames Hogan 			u16 aligned_buf[64];
162334b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
162434b664a2SJames Hogan 			int items = len >> 1;
162534b664a2SJames Hogan 			int i;
162634b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
162734b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
162834b664a2SJames Hogan 			buf += len;
162934b664a2SJames Hogan 			cnt -= len;
163034b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
163134b664a2SJames Hogan 			for (i = 0; i < items; ++i)
16324e0a5adfSJaehoon Chung 				mci_writew(host, DATA(host->data_offset),
16334e0a5adfSJaehoon Chung 						aligned_buf[i]);
163434b664a2SJames Hogan 		}
163534b664a2SJames Hogan 	} else
163634b664a2SJames Hogan #endif
163734b664a2SJames Hogan 	{
163834b664a2SJames Hogan 		u16 *pdata = buf;
163934b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
16404e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset), *pdata++);
164134b664a2SJames Hogan 		buf = pdata;
164234b664a2SJames Hogan 	}
164334b664a2SJames Hogan 	/* put anything remaining in the part_buf */
164434b664a2SJames Hogan 	if (cnt) {
164534b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1646cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1647cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1648cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
16494e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
16504e0a5adfSJaehoon Chung 				   host->part_buf16);
1651f95f3850SWill Newton 	}
1652f95f3850SWill Newton }
1653f95f3850SWill Newton 
1654f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
1655f95f3850SWill Newton {
165634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
165734b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
165834b664a2SJames Hogan 		while (cnt >= 2) {
165934b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
166034b664a2SJames Hogan 			u16 aligned_buf[64];
166134b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
166234b664a2SJames Hogan 			int items = len >> 1;
166334b664a2SJames Hogan 			int i;
166434b664a2SJames Hogan 			for (i = 0; i < items; ++i)
16654e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readw(host,
16664e0a5adfSJaehoon Chung 						DATA(host->data_offset));
166734b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
166834b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
166934b664a2SJames Hogan 			buf += len;
167034b664a2SJames Hogan 			cnt -= len;
167134b664a2SJames Hogan 		}
167234b664a2SJames Hogan 	} else
167334b664a2SJames Hogan #endif
167434b664a2SJames Hogan 	{
167534b664a2SJames Hogan 		u16 *pdata = buf;
167634b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
16774e0a5adfSJaehoon Chung 			*pdata++ = mci_readw(host, DATA(host->data_offset));
167834b664a2SJames Hogan 		buf = pdata;
167934b664a2SJames Hogan 	}
168034b664a2SJames Hogan 	if (cnt) {
16814e0a5adfSJaehoon Chung 		host->part_buf16 = mci_readw(host, DATA(host->data_offset));
168234b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1683f95f3850SWill Newton 	}
1684f95f3850SWill Newton }
1685f95f3850SWill Newton 
1686f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
1687f95f3850SWill Newton {
1688cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1689cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1690cfbeb59cSMarkos Chandras 
169134b664a2SJames Hogan 	/* try and push anything in the part_buf */
169234b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
169334b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
169434b664a2SJames Hogan 		buf += len;
169534b664a2SJames Hogan 		cnt -= len;
1696cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 4) {
16974e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
16984e0a5adfSJaehoon Chung 					host->part_buf32);
169934b664a2SJames Hogan 			host->part_buf_count = 0;
170034b664a2SJames Hogan 		}
170134b664a2SJames Hogan 	}
170234b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
170334b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
170434b664a2SJames Hogan 		while (cnt >= 4) {
170534b664a2SJames Hogan 			u32 aligned_buf[32];
170634b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
170734b664a2SJames Hogan 			int items = len >> 2;
170834b664a2SJames Hogan 			int i;
170934b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
171034b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
171134b664a2SJames Hogan 			buf += len;
171234b664a2SJames Hogan 			cnt -= len;
171334b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
171434b664a2SJames Hogan 			for (i = 0; i < items; ++i)
17154e0a5adfSJaehoon Chung 				mci_writel(host, DATA(host->data_offset),
17164e0a5adfSJaehoon Chung 						aligned_buf[i]);
171734b664a2SJames Hogan 		}
171834b664a2SJames Hogan 	} else
171934b664a2SJames Hogan #endif
172034b664a2SJames Hogan 	{
172134b664a2SJames Hogan 		u32 *pdata = buf;
172234b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
17234e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset), *pdata++);
172434b664a2SJames Hogan 		buf = pdata;
172534b664a2SJames Hogan 	}
172634b664a2SJames Hogan 	/* put anything remaining in the part_buf */
172734b664a2SJames Hogan 	if (cnt) {
172834b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1729cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1730cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1731cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
17324e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
17334e0a5adfSJaehoon Chung 				   host->part_buf32);
1734f95f3850SWill Newton 	}
1735f95f3850SWill Newton }
1736f95f3850SWill Newton 
1737f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
1738f95f3850SWill Newton {
173934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
174034b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
174134b664a2SJames Hogan 		while (cnt >= 4) {
174234b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
174334b664a2SJames Hogan 			u32 aligned_buf[32];
174434b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
174534b664a2SJames Hogan 			int items = len >> 2;
174634b664a2SJames Hogan 			int i;
174734b664a2SJames Hogan 			for (i = 0; i < items; ++i)
17484e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readl(host,
17494e0a5adfSJaehoon Chung 						DATA(host->data_offset));
175034b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
175134b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
175234b664a2SJames Hogan 			buf += len;
175334b664a2SJames Hogan 			cnt -= len;
175434b664a2SJames Hogan 		}
175534b664a2SJames Hogan 	} else
175634b664a2SJames Hogan #endif
175734b664a2SJames Hogan 	{
175834b664a2SJames Hogan 		u32 *pdata = buf;
175934b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
17604e0a5adfSJaehoon Chung 			*pdata++ = mci_readl(host, DATA(host->data_offset));
176134b664a2SJames Hogan 		buf = pdata;
176234b664a2SJames Hogan 	}
176334b664a2SJames Hogan 	if (cnt) {
17644e0a5adfSJaehoon Chung 		host->part_buf32 = mci_readl(host, DATA(host->data_offset));
176534b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1766f95f3850SWill Newton 	}
1767f95f3850SWill Newton }
1768f95f3850SWill Newton 
1769f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
1770f95f3850SWill Newton {
1771cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1772cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1773cfbeb59cSMarkos Chandras 
177434b664a2SJames Hogan 	/* try and push anything in the part_buf */
177534b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
177634b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
177734b664a2SJames Hogan 		buf += len;
177834b664a2SJames Hogan 		cnt -= len;
1779c09fbd74SSeungwon Jeon 
1780cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 8) {
1781c09fbd74SSeungwon Jeon 			mci_writeq(host, DATA(host->data_offset),
17824e0a5adfSJaehoon Chung 					host->part_buf);
178334b664a2SJames Hogan 			host->part_buf_count = 0;
178434b664a2SJames Hogan 		}
178534b664a2SJames Hogan 	}
178634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
178734b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
178834b664a2SJames Hogan 		while (cnt >= 8) {
178934b664a2SJames Hogan 			u64 aligned_buf[16];
179034b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
179134b664a2SJames Hogan 			int items = len >> 3;
179234b664a2SJames Hogan 			int i;
179334b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
179434b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
179534b664a2SJames Hogan 			buf += len;
179634b664a2SJames Hogan 			cnt -= len;
179734b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
179834b664a2SJames Hogan 			for (i = 0; i < items; ++i)
17994e0a5adfSJaehoon Chung 				mci_writeq(host, DATA(host->data_offset),
18004e0a5adfSJaehoon Chung 						aligned_buf[i]);
180134b664a2SJames Hogan 		}
180234b664a2SJames Hogan 	} else
180334b664a2SJames Hogan #endif
180434b664a2SJames Hogan 	{
180534b664a2SJames Hogan 		u64 *pdata = buf;
180634b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
18074e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset), *pdata++);
180834b664a2SJames Hogan 		buf = pdata;
180934b664a2SJames Hogan 	}
181034b664a2SJames Hogan 	/* put anything remaining in the part_buf */
181134b664a2SJames Hogan 	if (cnt) {
181234b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1813cfbeb59cSMarkos Chandras 		/* Push data if we have reached the expected data length */
1814cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1815cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
18164e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset),
18174e0a5adfSJaehoon Chung 				   host->part_buf);
1818f95f3850SWill Newton 	}
1819f95f3850SWill Newton }
1820f95f3850SWill Newton 
1821f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
1822f95f3850SWill Newton {
182334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
182434b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
182534b664a2SJames Hogan 		while (cnt >= 8) {
182634b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
182734b664a2SJames Hogan 			u64 aligned_buf[16];
182834b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
182934b664a2SJames Hogan 			int items = len >> 3;
183034b664a2SJames Hogan 			int i;
183134b664a2SJames Hogan 			for (i = 0; i < items; ++i)
18324e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readq(host,
18334e0a5adfSJaehoon Chung 						DATA(host->data_offset));
183434b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
183534b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
183634b664a2SJames Hogan 			buf += len;
183734b664a2SJames Hogan 			cnt -= len;
1838f95f3850SWill Newton 		}
183934b664a2SJames Hogan 	} else
184034b664a2SJames Hogan #endif
184134b664a2SJames Hogan 	{
184234b664a2SJames Hogan 		u64 *pdata = buf;
184334b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
18444e0a5adfSJaehoon Chung 			*pdata++ = mci_readq(host, DATA(host->data_offset));
184534b664a2SJames Hogan 		buf = pdata;
184634b664a2SJames Hogan 	}
184734b664a2SJames Hogan 	if (cnt) {
18484e0a5adfSJaehoon Chung 		host->part_buf = mci_readq(host, DATA(host->data_offset));
184934b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
185034b664a2SJames Hogan 	}
185134b664a2SJames Hogan }
185234b664a2SJames Hogan 
185334b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
185434b664a2SJames Hogan {
185534b664a2SJames Hogan 	int len;
185634b664a2SJames Hogan 
185734b664a2SJames Hogan 	/* get remaining partial bytes */
185834b664a2SJames Hogan 	len = dw_mci_pull_part_bytes(host, buf, cnt);
185934b664a2SJames Hogan 	if (unlikely(len == cnt))
186034b664a2SJames Hogan 		return;
186134b664a2SJames Hogan 	buf += len;
186234b664a2SJames Hogan 	cnt -= len;
186334b664a2SJames Hogan 
186434b664a2SJames Hogan 	/* get the rest of the data */
186534b664a2SJames Hogan 	host->pull_data(host, buf, cnt);
1866f95f3850SWill Newton }
1867f95f3850SWill Newton 
186887a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto)
1869f95f3850SWill Newton {
1870f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1871f9c2a0dcSSeungwon Jeon 	void *buf;
1872f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1873f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1874f95f3850SWill Newton 	int shift = host->data_shift;
1875f95f3850SWill Newton 	u32 status;
18763e4b0d8bSMarkos Chandras 	unsigned int len;
1877f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1878f95f3850SWill Newton 
1879f95f3850SWill Newton 	do {
1880f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1881f9c2a0dcSSeungwon Jeon 			goto done;
1882f95f3850SWill Newton 
18834225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1884f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1885f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1886f9c2a0dcSSeungwon Jeon 		offset = 0;
1887f9c2a0dcSSeungwon Jeon 
1888f9c2a0dcSSeungwon Jeon 		do {
1889f9c2a0dcSSeungwon Jeon 			fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS))
1890f9c2a0dcSSeungwon Jeon 					<< shift) + host->part_buf_count;
1891f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1892f9c2a0dcSSeungwon Jeon 			if (!len)
1893f9c2a0dcSSeungwon Jeon 				break;
1894f9c2a0dcSSeungwon Jeon 			dw_mci_pull_data(host, (void *)(buf + offset), len);
18953e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1896f95f3850SWill Newton 			offset += len;
1897f9c2a0dcSSeungwon Jeon 			remain -= len;
1898f9c2a0dcSSeungwon Jeon 		} while (remain);
1899f95f3850SWill Newton 
1900e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1901f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1902f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
190387a74d39SKyoungil Kim 	/* if the RXDR is ready read again */
190487a74d39SKyoungil Kim 	} while ((status & SDMMC_INT_RXDR) ||
190587a74d39SKyoungil Kim 		 (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS))));
1906f9c2a0dcSSeungwon Jeon 
1907f9c2a0dcSSeungwon Jeon 	if (!remain) {
1908f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1909f9c2a0dcSSeungwon Jeon 			goto done;
1910f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1911f9c2a0dcSSeungwon Jeon 	}
1912f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1913f95f3850SWill Newton 	return;
1914f95f3850SWill Newton 
1915f95f3850SWill Newton done:
1916f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1917f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1918f95f3850SWill Newton 	smp_wmb();
1919f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1920f95f3850SWill Newton }
1921f95f3850SWill Newton 
1922f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host)
1923f95f3850SWill Newton {
1924f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1925f9c2a0dcSSeungwon Jeon 	void *buf;
1926f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1927f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1928f95f3850SWill Newton 	int shift = host->data_shift;
1929f95f3850SWill Newton 	u32 status;
19303e4b0d8bSMarkos Chandras 	unsigned int len;
1931f9c2a0dcSSeungwon Jeon 	unsigned int fifo_depth = host->fifo_depth;
1932f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1933f95f3850SWill Newton 
1934f95f3850SWill Newton 	do {
1935f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1936f9c2a0dcSSeungwon Jeon 			goto done;
1937f95f3850SWill Newton 
19384225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1939f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1940f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1941f9c2a0dcSSeungwon Jeon 		offset = 0;
1942f9c2a0dcSSeungwon Jeon 
1943f9c2a0dcSSeungwon Jeon 		do {
1944f9c2a0dcSSeungwon Jeon 			fcnt = ((fifo_depth -
1945f9c2a0dcSSeungwon Jeon 				 SDMMC_GET_FCNT(mci_readl(host, STATUS)))
1946f9c2a0dcSSeungwon Jeon 					<< shift) - host->part_buf_count;
1947f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1948f9c2a0dcSSeungwon Jeon 			if (!len)
1949f9c2a0dcSSeungwon Jeon 				break;
1950f9c2a0dcSSeungwon Jeon 			host->push_data(host, (void *)(buf + offset), len);
19513e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1952f95f3850SWill Newton 			offset += len;
1953f9c2a0dcSSeungwon Jeon 			remain -= len;
1954f9c2a0dcSSeungwon Jeon 		} while (remain);
1955f95f3850SWill Newton 
1956e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1957f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1958f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1959f95f3850SWill Newton 	} while (status & SDMMC_INT_TXDR); /* if TXDR write again */
1960f9c2a0dcSSeungwon Jeon 
1961f9c2a0dcSSeungwon Jeon 	if (!remain) {
1962f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1963f9c2a0dcSSeungwon Jeon 			goto done;
1964f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1965f9c2a0dcSSeungwon Jeon 	}
1966f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1967f95f3850SWill Newton 	return;
1968f95f3850SWill Newton 
1969f95f3850SWill Newton done:
1970f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1971f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1972f95f3850SWill Newton 	smp_wmb();
1973f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1974f95f3850SWill Newton }
1975f95f3850SWill Newton 
1976f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
1977f95f3850SWill Newton {
1978f95f3850SWill Newton 	if (!host->cmd_status)
1979f95f3850SWill Newton 		host->cmd_status = status;
1980f95f3850SWill Newton 
1981f95f3850SWill Newton 	smp_wmb();
1982f95f3850SWill Newton 
1983f95f3850SWill Newton 	set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1984f95f3850SWill Newton 	tasklet_schedule(&host->tasklet);
1985f95f3850SWill Newton }
1986f95f3850SWill Newton 
1987f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
1988f95f3850SWill Newton {
1989f95f3850SWill Newton 	struct dw_mci *host = dev_id;
1990182c9081SSeungwon Jeon 	u32 pending;
19911a5c8e1fSShashidhar Hiremath 	int i;
1992f95f3850SWill Newton 
1993f95f3850SWill Newton 	pending = mci_readl(host, MINTSTS); /* read-only mask reg */
1994f95f3850SWill Newton 
1995f95f3850SWill Newton 	/*
1996f95f3850SWill Newton 	 * DTO fix - version 2.10a and below, and only if internal DMA
1997f95f3850SWill Newton 	 * is configured.
1998f95f3850SWill Newton 	 */
1999f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
2000f95f3850SWill Newton 		if (!pending &&
2001f95f3850SWill Newton 		    ((mci_readl(host, STATUS) >> 17) & 0x1fff))
2002f95f3850SWill Newton 			pending |= SDMMC_INT_DATA_OVER;
2003f95f3850SWill Newton 	}
2004f95f3850SWill Newton 
2005476d79f1SDoug Anderson 	if (pending) {
200601730558SDoug Anderson 		/* Check volt switch first, since it can look like an error */
200701730558SDoug Anderson 		if ((host->state == STATE_SENDING_CMD11) &&
200801730558SDoug Anderson 		    (pending & SDMMC_INT_VOLT_SWITCH)) {
200901730558SDoug Anderson 			mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH);
201001730558SDoug Anderson 			pending &= ~SDMMC_INT_VOLT_SWITCH;
201101730558SDoug Anderson 			dw_mci_cmd_interrupt(host, pending);
201201730558SDoug Anderson 		}
201301730558SDoug Anderson 
2014f95f3850SWill Newton 		if (pending & DW_MCI_CMD_ERROR_FLAGS) {
2015f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
2016182c9081SSeungwon Jeon 			host->cmd_status = pending;
2017f95f3850SWill Newton 			smp_wmb();
2018f95f3850SWill Newton 			set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
2019f95f3850SWill Newton 		}
2020f95f3850SWill Newton 
2021f95f3850SWill Newton 		if (pending & DW_MCI_DATA_ERROR_FLAGS) {
2022f95f3850SWill Newton 			/* if there is an error report DATA_ERROR */
2023f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
2024182c9081SSeungwon Jeon 			host->data_status = pending;
2025f95f3850SWill Newton 			smp_wmb();
2026f95f3850SWill Newton 			set_bit(EVENT_DATA_ERROR, &host->pending_events);
2027f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
2028f95f3850SWill Newton 		}
2029f95f3850SWill Newton 
2030f95f3850SWill Newton 		if (pending & SDMMC_INT_DATA_OVER) {
2031f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
2032f95f3850SWill Newton 			if (!host->data_status)
2033182c9081SSeungwon Jeon 				host->data_status = pending;
2034f95f3850SWill Newton 			smp_wmb();
2035f95f3850SWill Newton 			if (host->dir_status == DW_MCI_RECV_STATUS) {
2036f95f3850SWill Newton 				if (host->sg != NULL)
203787a74d39SKyoungil Kim 					dw_mci_read_data_pio(host, true);
2038f95f3850SWill Newton 			}
2039f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
2040f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
2041f95f3850SWill Newton 		}
2042f95f3850SWill Newton 
2043f95f3850SWill Newton 		if (pending & SDMMC_INT_RXDR) {
2044f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
2045b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_RECV_STATUS && host->sg)
204687a74d39SKyoungil Kim 				dw_mci_read_data_pio(host, false);
2047f95f3850SWill Newton 		}
2048f95f3850SWill Newton 
2049f95f3850SWill Newton 		if (pending & SDMMC_INT_TXDR) {
2050f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
2051b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_SEND_STATUS && host->sg)
2052f95f3850SWill Newton 				dw_mci_write_data_pio(host);
2053f95f3850SWill Newton 		}
2054f95f3850SWill Newton 
2055f95f3850SWill Newton 		if (pending & SDMMC_INT_CMD_DONE) {
2056f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
2057182c9081SSeungwon Jeon 			dw_mci_cmd_interrupt(host, pending);
2058f95f3850SWill Newton 		}
2059f95f3850SWill Newton 
2060f95f3850SWill Newton 		if (pending & SDMMC_INT_CD) {
2061f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CD);
206295dcc2cbSThomas Abraham 			queue_work(host->card_workqueue, &host->card_work);
2063f95f3850SWill Newton 		}
2064f95f3850SWill Newton 
20651a5c8e1fSShashidhar Hiremath 		/* Handle SDIO Interrupts */
20661a5c8e1fSShashidhar Hiremath 		for (i = 0; i < host->num_slots; i++) {
20671a5c8e1fSShashidhar Hiremath 			struct dw_mci_slot *slot = host->slot[i];
20681a5c8e1fSShashidhar Hiremath 			if (pending & SDMMC_INT_SDIO(i)) {
20691a5c8e1fSShashidhar Hiremath 				mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
20701a5c8e1fSShashidhar Hiremath 				mmc_signal_sdio_irq(slot->mmc);
20711a5c8e1fSShashidhar Hiremath 			}
20721a5c8e1fSShashidhar Hiremath 		}
20731a5c8e1fSShashidhar Hiremath 
20741fb5f68aSMarkos Chandras 	}
2075f95f3850SWill Newton 
2076f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
2077f95f3850SWill Newton 	/* Handle DMA interrupts */
2078f95f3850SWill Newton 	pending = mci_readl(host, IDSTS);
2079f95f3850SWill Newton 	if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
2080f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
2081f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
2082f95f3850SWill Newton 		host->dma_ops->complete(host);
2083f95f3850SWill Newton 	}
2084f95f3850SWill Newton #endif
2085f95f3850SWill Newton 
2086f95f3850SWill Newton 	return IRQ_HANDLED;
2087f95f3850SWill Newton }
2088f95f3850SWill Newton 
20891791b13eSJames Hogan static void dw_mci_work_routine_card(struct work_struct *work)
2090f95f3850SWill Newton {
20911791b13eSJames Hogan 	struct dw_mci *host = container_of(work, struct dw_mci, card_work);
2092f95f3850SWill Newton 	int i;
2093f95f3850SWill Newton 
2094f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2095f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
2096f95f3850SWill Newton 		struct mmc_host *mmc = slot->mmc;
2097f95f3850SWill Newton 		struct mmc_request *mrq;
2098f95f3850SWill Newton 		int present;
2099f95f3850SWill Newton 
2100f95f3850SWill Newton 		present = dw_mci_get_cd(mmc);
2101f95f3850SWill Newton 		while (present != slot->last_detect_state) {
2102f95f3850SWill Newton 			dev_dbg(&slot->mmc->class_dev, "card %s\n",
2103f95f3850SWill Newton 				present ? "inserted" : "removed");
2104f95f3850SWill Newton 
21051791b13eSJames Hogan 			spin_lock_bh(&host->lock);
21061791b13eSJames Hogan 
2107f95f3850SWill Newton 			/* Card change detected */
2108f95f3850SWill Newton 			slot->last_detect_state = present;
2109f95f3850SWill Newton 
2110f95f3850SWill Newton 			/* Clean up queue if present */
2111f95f3850SWill Newton 			mrq = slot->mrq;
2112f95f3850SWill Newton 			if (mrq) {
2113f95f3850SWill Newton 				if (mrq == host->mrq) {
2114f95f3850SWill Newton 					host->data = NULL;
2115f95f3850SWill Newton 					host->cmd = NULL;
2116f95f3850SWill Newton 
2117f95f3850SWill Newton 					switch (host->state) {
2118f95f3850SWill Newton 					case STATE_IDLE:
211901730558SDoug Anderson 					case STATE_WAITING_CMD11_DONE:
2120f95f3850SWill Newton 						break;
212101730558SDoug Anderson 					case STATE_SENDING_CMD11:
2122f95f3850SWill Newton 					case STATE_SENDING_CMD:
2123f95f3850SWill Newton 						mrq->cmd->error = -ENOMEDIUM;
2124f95f3850SWill Newton 						if (!mrq->data)
2125f95f3850SWill Newton 							break;
2126f95f3850SWill Newton 						/* fall through */
2127f95f3850SWill Newton 					case STATE_SENDING_DATA:
2128f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
2129f95f3850SWill Newton 						dw_mci_stop_dma(host);
2130f95f3850SWill Newton 						break;
2131f95f3850SWill Newton 					case STATE_DATA_BUSY:
2132f95f3850SWill Newton 					case STATE_DATA_ERROR:
2133f95f3850SWill Newton 						if (mrq->data->error == -EINPROGRESS)
2134f95f3850SWill Newton 							mrq->data->error = -ENOMEDIUM;
2135f95f3850SWill Newton 						/* fall through */
2136f95f3850SWill Newton 					case STATE_SENDING_STOP:
213790c2143aSSeungwon Jeon 						if (mrq->stop)
2138f95f3850SWill Newton 							mrq->stop->error = -ENOMEDIUM;
2139f95f3850SWill Newton 						break;
2140f95f3850SWill Newton 					}
2141f95f3850SWill Newton 
2142f95f3850SWill Newton 					dw_mci_request_end(host, mrq);
2143f95f3850SWill Newton 				} else {
2144f95f3850SWill Newton 					list_del(&slot->queue_node);
2145f95f3850SWill Newton 					mrq->cmd->error = -ENOMEDIUM;
2146f95f3850SWill Newton 					if (mrq->data)
2147f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
2148f95f3850SWill Newton 					if (mrq->stop)
2149f95f3850SWill Newton 						mrq->stop->error = -ENOMEDIUM;
2150f95f3850SWill Newton 
2151f95f3850SWill Newton 					spin_unlock(&host->lock);
2152f95f3850SWill Newton 					mmc_request_done(slot->mmc, mrq);
2153f95f3850SWill Newton 					spin_lock(&host->lock);
2154f95f3850SWill Newton 				}
2155f95f3850SWill Newton 			}
2156f95f3850SWill Newton 
2157f95f3850SWill Newton 			/* Power down slot */
21583a33a94cSSonny Rao 			if (present == 0)
21593a33a94cSSonny Rao 				dw_mci_reset(host);
2160f95f3850SWill Newton 
21611791b13eSJames Hogan 			spin_unlock_bh(&host->lock);
21621791b13eSJames Hogan 
2163f95f3850SWill Newton 			present = dw_mci_get_cd(mmc);
2164f95f3850SWill Newton 		}
2165f95f3850SWill Newton 
2166f95f3850SWill Newton 		mmc_detect_change(slot->mmc,
2167f95f3850SWill Newton 			msecs_to_jiffies(host->pdata->detect_delay_ms));
2168f95f3850SWill Newton 	}
2169f95f3850SWill Newton }
2170f95f3850SWill Newton 
2171c91eab4bSThomas Abraham #ifdef CONFIG_OF
2172c91eab4bSThomas Abraham /* given a slot id, find out the device node representing that slot */
2173c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
2174c91eab4bSThomas Abraham {
2175c91eab4bSThomas Abraham 	struct device_node *np;
2176c91eab4bSThomas Abraham 	const __be32 *addr;
2177c91eab4bSThomas Abraham 	int len;
2178c91eab4bSThomas Abraham 
2179c91eab4bSThomas Abraham 	if (!dev || !dev->of_node)
2180c91eab4bSThomas Abraham 		return NULL;
2181c91eab4bSThomas Abraham 
2182c91eab4bSThomas Abraham 	for_each_child_of_node(dev->of_node, np) {
2183c91eab4bSThomas Abraham 		addr = of_get_property(np, "reg", &len);
2184c91eab4bSThomas Abraham 		if (!addr || (len < sizeof(int)))
2185c91eab4bSThomas Abraham 			continue;
2186c91eab4bSThomas Abraham 		if (be32_to_cpup(addr) == slot)
2187c91eab4bSThomas Abraham 			return np;
2188c91eab4bSThomas Abraham 	}
2189c91eab4bSThomas Abraham 	return NULL;
2190c91eab4bSThomas Abraham }
2191c91eab4bSThomas Abraham 
2192a70aaa64SDoug Anderson static struct dw_mci_of_slot_quirks {
2193a70aaa64SDoug Anderson 	char *quirk;
2194a70aaa64SDoug Anderson 	int id;
2195a70aaa64SDoug Anderson } of_slot_quirks[] = {
2196a70aaa64SDoug Anderson 	{
2197a70aaa64SDoug Anderson 		.quirk	= "disable-wp",
2198a70aaa64SDoug Anderson 		.id	= DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT,
2199a70aaa64SDoug Anderson 	},
2200a70aaa64SDoug Anderson };
2201a70aaa64SDoug Anderson 
2202a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
2203a70aaa64SDoug Anderson {
2204a70aaa64SDoug Anderson 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
2205a70aaa64SDoug Anderson 	int quirks = 0;
2206a70aaa64SDoug Anderson 	int idx;
2207a70aaa64SDoug Anderson 
2208a70aaa64SDoug Anderson 	/* get quirks */
2209a70aaa64SDoug Anderson 	for (idx = 0; idx < ARRAY_SIZE(of_slot_quirks); idx++)
221026375b5cSJaehoon Chung 		if (of_get_property(np, of_slot_quirks[idx].quirk, NULL)) {
221126375b5cSJaehoon Chung 			dev_warn(dev, "Slot quirk %s is deprecated\n",
221226375b5cSJaehoon Chung 					of_slot_quirks[idx].quirk);
2213a70aaa64SDoug Anderson 			quirks |= of_slot_quirks[idx].id;
221426375b5cSJaehoon Chung 		}
2215a70aaa64SDoug Anderson 
2216a70aaa64SDoug Anderson 	return quirks;
2217a70aaa64SDoug Anderson }
2218c91eab4bSThomas Abraham #else /* CONFIG_OF */
2219a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
2220a70aaa64SDoug Anderson {
2221a70aaa64SDoug Anderson 	return 0;
2222a70aaa64SDoug Anderson }
2223c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
2224c91eab4bSThomas Abraham {
2225c91eab4bSThomas Abraham 	return NULL;
2226c91eab4bSThomas Abraham }
2227c91eab4bSThomas Abraham #endif /* CONFIG_OF */
2228c91eab4bSThomas Abraham 
222936c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
2230f95f3850SWill Newton {
2231f95f3850SWill Newton 	struct mmc_host *mmc;
2232f95f3850SWill Newton 	struct dw_mci_slot *slot;
2233e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
2234800d78bfSThomas Abraham 	int ctrl_id, ret;
22351f44a2a5SSeungwon Jeon 	u32 freq[2];
2236f95f3850SWill Newton 
22374a90920cSThomas Abraham 	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
2238f95f3850SWill Newton 	if (!mmc)
2239f95f3850SWill Newton 		return -ENOMEM;
2240f95f3850SWill Newton 
2241f95f3850SWill Newton 	slot = mmc_priv(mmc);
2242f95f3850SWill Newton 	slot->id = id;
2243f95f3850SWill Newton 	slot->mmc = mmc;
2244f95f3850SWill Newton 	slot->host = host;
2245c91eab4bSThomas Abraham 	host->slot[id] = slot;
2246f95f3850SWill Newton 
2247a70aaa64SDoug Anderson 	slot->quirks = dw_mci_of_get_slot_quirks(host->dev, slot->id);
2248a70aaa64SDoug Anderson 
2249f95f3850SWill Newton 	mmc->ops = &dw_mci_ops;
22501f44a2a5SSeungwon Jeon 	if (of_property_read_u32_array(host->dev->of_node,
22511f44a2a5SSeungwon Jeon 				       "clock-freq-min-max", freq, 2)) {
22521f44a2a5SSeungwon Jeon 		mmc->f_min = DW_MCI_FREQ_MIN;
22531f44a2a5SSeungwon Jeon 		mmc->f_max = DW_MCI_FREQ_MAX;
22541f44a2a5SSeungwon Jeon 	} else {
22551f44a2a5SSeungwon Jeon 		mmc->f_min = freq[0];
22561f44a2a5SSeungwon Jeon 		mmc->f_max = freq[1];
22571f44a2a5SSeungwon Jeon 	}
2258f95f3850SWill Newton 
225951da2240SYuvaraj CD 	/*if there are external regulators, get them*/
226051da2240SYuvaraj CD 	ret = mmc_regulator_get_supply(mmc);
226151da2240SYuvaraj CD 	if (ret == -EPROBE_DEFER)
2262*3cf890fcSDoug Anderson 		goto err_host_allocated;
226351da2240SYuvaraj CD 
226451da2240SYuvaraj CD 	if (!mmc->ocr_avail)
2265f95f3850SWill Newton 		mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
2266f95f3850SWill Newton 
2267fc3d7720SJaehoon Chung 	if (host->pdata->caps)
2268fc3d7720SJaehoon Chung 		mmc->caps = host->pdata->caps;
2269fc3d7720SJaehoon Chung 
2270ab269128SAbhilash Kesavan 	if (host->pdata->pm_caps)
2271ab269128SAbhilash Kesavan 		mmc->pm_caps = host->pdata->pm_caps;
2272ab269128SAbhilash Kesavan 
2273800d78bfSThomas Abraham 	if (host->dev->of_node) {
2274800d78bfSThomas Abraham 		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
2275800d78bfSThomas Abraham 		if (ctrl_id < 0)
2276800d78bfSThomas Abraham 			ctrl_id = 0;
2277800d78bfSThomas Abraham 	} else {
2278800d78bfSThomas Abraham 		ctrl_id = to_platform_device(host->dev)->id;
2279800d78bfSThomas Abraham 	}
2280cb27a843SJames Hogan 	if (drv_data && drv_data->caps)
2281cb27a843SJames Hogan 		mmc->caps |= drv_data->caps[ctrl_id];
2282800d78bfSThomas Abraham 
22834f408cc6SSeungwon Jeon 	if (host->pdata->caps2)
22844f408cc6SSeungwon Jeon 		mmc->caps2 = host->pdata->caps2;
22854f408cc6SSeungwon Jeon 
2286*3cf890fcSDoug Anderson 	ret = mmc_of_parse(mmc);
2287*3cf890fcSDoug Anderson 	if (ret)
2288*3cf890fcSDoug Anderson 		goto err_host_allocated;
2289f95f3850SWill Newton 
2290f95f3850SWill Newton 	if (host->pdata->blk_settings) {
2291f95f3850SWill Newton 		mmc->max_segs = host->pdata->blk_settings->max_segs;
2292f95f3850SWill Newton 		mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
2293f95f3850SWill Newton 		mmc->max_blk_count = host->pdata->blk_settings->max_blk_count;
2294f95f3850SWill Newton 		mmc->max_req_size = host->pdata->blk_settings->max_req_size;
2295f95f3850SWill Newton 		mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
2296f95f3850SWill Newton 	} else {
2297f95f3850SWill Newton 		/* Useful defaults if platform data is unset. */
2298a39e5746SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
2299a39e5746SJaehoon Chung 		mmc->max_segs = host->ring_size;
2300a39e5746SJaehoon Chung 		mmc->max_blk_size = 65536;
2301a39e5746SJaehoon Chung 		mmc->max_blk_count = host->ring_size;
2302a39e5746SJaehoon Chung 		mmc->max_seg_size = 0x1000;
2303a39e5746SJaehoon Chung 		mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
2304a39e5746SJaehoon Chung #else
2305f95f3850SWill Newton 		mmc->max_segs = 64;
2306f95f3850SWill Newton 		mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
2307f95f3850SWill Newton 		mmc->max_blk_count = 512;
2308f95f3850SWill Newton 		mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
2309f95f3850SWill Newton 		mmc->max_seg_size = mmc->max_req_size;
2310f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */
2311a39e5746SJaehoon Chung 	}
2312f95f3850SWill Newton 
2313ae0eb348SJaehoon Chung 	if (dw_mci_get_cd(mmc))
2314ae0eb348SJaehoon Chung 		set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
2315ae0eb348SJaehoon Chung 	else
2316ae0eb348SJaehoon Chung 		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
2317ae0eb348SJaehoon Chung 
23180cea529dSJaehoon Chung 	ret = mmc_add_host(mmc);
23190cea529dSJaehoon Chung 	if (ret)
2320*3cf890fcSDoug Anderson 		goto err_host_allocated;
2321f95f3850SWill Newton 
2322f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS)
2323f95f3850SWill Newton 	dw_mci_init_debugfs(slot);
2324f95f3850SWill Newton #endif
2325f95f3850SWill Newton 
2326f95f3850SWill Newton 	/* Card initially undetected */
2327f95f3850SWill Newton 	slot->last_detect_state = 0;
2328f95f3850SWill Newton 
2329f95f3850SWill Newton 	return 0;
2330800d78bfSThomas Abraham 
2331*3cf890fcSDoug Anderson err_host_allocated:
2332800d78bfSThomas Abraham 	mmc_free_host(mmc);
233351da2240SYuvaraj CD 	return ret;
2334f95f3850SWill Newton }
2335f95f3850SWill Newton 
2336f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
2337f95f3850SWill Newton {
2338f95f3850SWill Newton 	/* Debugfs stuff is cleaned up by mmc core */
2339f95f3850SWill Newton 	mmc_remove_host(slot->mmc);
2340f95f3850SWill Newton 	slot->host->slot[id] = NULL;
2341f95f3850SWill Newton 	mmc_free_host(slot->mmc);
2342f95f3850SWill Newton }
2343f95f3850SWill Newton 
2344f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host)
2345f95f3850SWill Newton {
2346f95f3850SWill Newton 	/* Alloc memory for sg translation */
2347780f22afSSeungwon Jeon 	host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
2348f95f3850SWill Newton 					  &host->sg_dma, GFP_KERNEL);
2349f95f3850SWill Newton 	if (!host->sg_cpu) {
23504a90920cSThomas Abraham 		dev_err(host->dev, "%s: could not alloc DMA memory\n",
2351f95f3850SWill Newton 			__func__);
2352f95f3850SWill Newton 		goto no_dma;
2353f95f3850SWill Newton 	}
2354f95f3850SWill Newton 
2355f95f3850SWill Newton 	/* Determine which DMA interface to use */
2356f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
2357f95f3850SWill Newton 	host->dma_ops = &dw_mci_idmac_ops;
235800956ea3SSeungwon Jeon 	dev_info(host->dev, "Using internal DMA controller.\n");
2359f95f3850SWill Newton #endif
2360f95f3850SWill Newton 
2361f95f3850SWill Newton 	if (!host->dma_ops)
2362f95f3850SWill Newton 		goto no_dma;
2363f95f3850SWill Newton 
2364e1631f98SJaehoon Chung 	if (host->dma_ops->init && host->dma_ops->start &&
2365e1631f98SJaehoon Chung 	    host->dma_ops->stop && host->dma_ops->cleanup) {
2366f95f3850SWill Newton 		if (host->dma_ops->init(host)) {
23674a90920cSThomas Abraham 			dev_err(host->dev, "%s: Unable to initialize "
2368f95f3850SWill Newton 				"DMA Controller.\n", __func__);
2369f95f3850SWill Newton 			goto no_dma;
2370f95f3850SWill Newton 		}
2371f95f3850SWill Newton 	} else {
23724a90920cSThomas Abraham 		dev_err(host->dev, "DMA initialization not found.\n");
2373f95f3850SWill Newton 		goto no_dma;
2374f95f3850SWill Newton 	}
2375f95f3850SWill Newton 
2376f95f3850SWill Newton 	host->use_dma = 1;
2377f95f3850SWill Newton 	return;
2378f95f3850SWill Newton 
2379f95f3850SWill Newton no_dma:
23804a90920cSThomas Abraham 	dev_info(host->dev, "Using PIO mode.\n");
2381f95f3850SWill Newton 	host->use_dma = 0;
2382f95f3850SWill Newton 	return;
2383f95f3850SWill Newton }
2384f95f3850SWill Newton 
238531bff450SSeungwon Jeon static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset)
2386f95f3850SWill Newton {
2387f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
238831bff450SSeungwon Jeon 	u32 ctrl;
2389f95f3850SWill Newton 
239031bff450SSeungwon Jeon 	ctrl = mci_readl(host, CTRL);
239131bff450SSeungwon Jeon 	ctrl |= reset;
239231bff450SSeungwon Jeon 	mci_writel(host, CTRL, ctrl);
2393f95f3850SWill Newton 
2394f95f3850SWill Newton 	/* wait till resets clear */
2395f95f3850SWill Newton 	do {
2396f95f3850SWill Newton 		ctrl = mci_readl(host, CTRL);
239731bff450SSeungwon Jeon 		if (!(ctrl & reset))
2398f95f3850SWill Newton 			return true;
2399f95f3850SWill Newton 	} while (time_before(jiffies, timeout));
2400f95f3850SWill Newton 
240131bff450SSeungwon Jeon 	dev_err(host->dev,
240231bff450SSeungwon Jeon 		"Timeout resetting block (ctrl reset %#x)\n",
240331bff450SSeungwon Jeon 		ctrl & reset);
2404f95f3850SWill Newton 
2405f95f3850SWill Newton 	return false;
2406f95f3850SWill Newton }
2407f95f3850SWill Newton 
24083a33a94cSSonny Rao static bool dw_mci_reset(struct dw_mci *host)
240931bff450SSeungwon Jeon {
24103a33a94cSSonny Rao 	u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET;
24113a33a94cSSonny Rao 	bool ret = false;
24123a33a94cSSonny Rao 
241331bff450SSeungwon Jeon 	/*
241431bff450SSeungwon Jeon 	 * Reseting generates a block interrupt, hence setting
241531bff450SSeungwon Jeon 	 * the scatter-gather pointer to NULL.
241631bff450SSeungwon Jeon 	 */
241731bff450SSeungwon Jeon 	if (host->sg) {
241831bff450SSeungwon Jeon 		sg_miter_stop(&host->sg_miter);
241931bff450SSeungwon Jeon 		host->sg = NULL;
242031bff450SSeungwon Jeon 	}
242131bff450SSeungwon Jeon 
24223a33a94cSSonny Rao 	if (host->use_dma)
24233a33a94cSSonny Rao 		flags |= SDMMC_CTRL_DMA_RESET;
24243a33a94cSSonny Rao 
24253a33a94cSSonny Rao 	if (dw_mci_ctrl_reset(host, flags)) {
24263a33a94cSSonny Rao 		/*
24273a33a94cSSonny Rao 		 * In all cases we clear the RAWINTS register to clear any
24283a33a94cSSonny Rao 		 * interrupts.
24293a33a94cSSonny Rao 		 */
24303a33a94cSSonny Rao 		mci_writel(host, RINTSTS, 0xFFFFFFFF);
24313a33a94cSSonny Rao 
24323a33a94cSSonny Rao 		/* if using dma we wait for dma_req to clear */
24333a33a94cSSonny Rao 		if (host->use_dma) {
24343a33a94cSSonny Rao 			unsigned long timeout = jiffies + msecs_to_jiffies(500);
24353a33a94cSSonny Rao 			u32 status;
24363a33a94cSSonny Rao 			do {
24373a33a94cSSonny Rao 				status = mci_readl(host, STATUS);
24383a33a94cSSonny Rao 				if (!(status & SDMMC_STATUS_DMA_REQ))
24393a33a94cSSonny Rao 					break;
24403a33a94cSSonny Rao 				cpu_relax();
24413a33a94cSSonny Rao 			} while (time_before(jiffies, timeout));
24423a33a94cSSonny Rao 
24433a33a94cSSonny Rao 			if (status & SDMMC_STATUS_DMA_REQ) {
24443a33a94cSSonny Rao 				dev_err(host->dev,
24453a33a94cSSonny Rao 					"%s: Timeout waiting for dma_req to "
24463a33a94cSSonny Rao 					"clear during reset\n", __func__);
24473a33a94cSSonny Rao 				goto ciu_out;
244831bff450SSeungwon Jeon 			}
244931bff450SSeungwon Jeon 
24503a33a94cSSonny Rao 			/* when using DMA next we reset the fifo again */
24513a33a94cSSonny Rao 			if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET))
24523a33a94cSSonny Rao 				goto ciu_out;
24533a33a94cSSonny Rao 		}
24543a33a94cSSonny Rao 	} else {
24553a33a94cSSonny Rao 		/* if the controller reset bit did clear, then set clock regs */
24563a33a94cSSonny Rao 		if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) {
24573a33a94cSSonny Rao 			dev_err(host->dev, "%s: fifo/dma reset bits didn't "
24583a33a94cSSonny Rao 				"clear but ciu was reset, doing clock update\n",
24593a33a94cSSonny Rao 				__func__);
24603a33a94cSSonny Rao 			goto ciu_out;
24613a33a94cSSonny Rao 		}
24623a33a94cSSonny Rao 	}
24633a33a94cSSonny Rao 
24643a33a94cSSonny Rao #if IS_ENABLED(CONFIG_MMC_DW_IDMAC)
24653a33a94cSSonny Rao 	/* It is also recommended that we reset and reprogram idmac */
24663a33a94cSSonny Rao 	dw_mci_idmac_reset(host);
24673a33a94cSSonny Rao #endif
24683a33a94cSSonny Rao 
24693a33a94cSSonny Rao 	ret = true;
24703a33a94cSSonny Rao 
24713a33a94cSSonny Rao ciu_out:
24723a33a94cSSonny Rao 	/* After a CTRL reset we need to have CIU set clock registers  */
24733a33a94cSSonny Rao 	mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0);
24743a33a94cSSonny Rao 
24753a33a94cSSonny Rao 	return ret;
247631bff450SSeungwon Jeon }
247731bff450SSeungwon Jeon 
2478c91eab4bSThomas Abraham #ifdef CONFIG_OF
2479c91eab4bSThomas Abraham static struct dw_mci_of_quirks {
2480c91eab4bSThomas Abraham 	char *quirk;
2481c91eab4bSThomas Abraham 	int id;
2482c91eab4bSThomas Abraham } of_quirks[] = {
2483c91eab4bSThomas Abraham 	{
2484c91eab4bSThomas Abraham 		.quirk	= "broken-cd",
2485c91eab4bSThomas Abraham 		.id	= DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
248626375b5cSJaehoon Chung 	}, {
248726375b5cSJaehoon Chung 		.quirk	= "disable-wp",
248826375b5cSJaehoon Chung 		.id	= DW_MCI_QUIRK_NO_WRITE_PROTECT,
2489c91eab4bSThomas Abraham 	},
2490c91eab4bSThomas Abraham };
2491c91eab4bSThomas Abraham 
2492c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2493c91eab4bSThomas Abraham {
2494c91eab4bSThomas Abraham 	struct dw_mci_board *pdata;
2495c91eab4bSThomas Abraham 	struct device *dev = host->dev;
2496c91eab4bSThomas Abraham 	struct device_node *np = dev->of_node;
2497e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
2498800d78bfSThomas Abraham 	int idx, ret;
24993c6d89eaSDoug Anderson 	u32 clock_frequency;
2500c91eab4bSThomas Abraham 
2501c91eab4bSThomas Abraham 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
2502c91eab4bSThomas Abraham 	if (!pdata) {
2503c91eab4bSThomas Abraham 		dev_err(dev, "could not allocate memory for pdata\n");
2504c91eab4bSThomas Abraham 		return ERR_PTR(-ENOMEM);
2505c91eab4bSThomas Abraham 	}
2506c91eab4bSThomas Abraham 
2507c91eab4bSThomas Abraham 	/* find out number of slots supported */
2508c91eab4bSThomas Abraham 	if (of_property_read_u32(dev->of_node, "num-slots",
2509c91eab4bSThomas Abraham 				&pdata->num_slots)) {
2510c91eab4bSThomas Abraham 		dev_info(dev, "num-slots property not found, "
2511c91eab4bSThomas Abraham 				"assuming 1 slot is available\n");
2512c91eab4bSThomas Abraham 		pdata->num_slots = 1;
2513c91eab4bSThomas Abraham 	}
2514c91eab4bSThomas Abraham 
2515c91eab4bSThomas Abraham 	/* get quirks */
2516c91eab4bSThomas Abraham 	for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++)
2517c91eab4bSThomas Abraham 		if (of_get_property(np, of_quirks[idx].quirk, NULL))
2518c91eab4bSThomas Abraham 			pdata->quirks |= of_quirks[idx].id;
2519c91eab4bSThomas Abraham 
2520c91eab4bSThomas Abraham 	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
2521c91eab4bSThomas Abraham 		dev_info(dev, "fifo-depth property not found, using "
2522c91eab4bSThomas Abraham 				"value of FIFOTH register as default\n");
2523c91eab4bSThomas Abraham 
2524c91eab4bSThomas Abraham 	of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
2525c91eab4bSThomas Abraham 
25263c6d89eaSDoug Anderson 	if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
25273c6d89eaSDoug Anderson 		pdata->bus_hz = clock_frequency;
25283c6d89eaSDoug Anderson 
2529cb27a843SJames Hogan 	if (drv_data && drv_data->parse_dt) {
2530cb27a843SJames Hogan 		ret = drv_data->parse_dt(host);
2531800d78bfSThomas Abraham 		if (ret)
2532800d78bfSThomas Abraham 			return ERR_PTR(ret);
2533800d78bfSThomas Abraham 	}
2534800d78bfSThomas Abraham 
253510b49841SSeungwon Jeon 	if (of_find_property(np, "supports-highspeed", NULL))
253610b49841SSeungwon Jeon 		pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
253710b49841SSeungwon Jeon 
2538c91eab4bSThomas Abraham 	return pdata;
2539c91eab4bSThomas Abraham }
2540c91eab4bSThomas Abraham 
2541c91eab4bSThomas Abraham #else /* CONFIG_OF */
2542c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2543c91eab4bSThomas Abraham {
2544c91eab4bSThomas Abraham 	return ERR_PTR(-EINVAL);
2545c91eab4bSThomas Abraham }
2546c91eab4bSThomas Abraham #endif /* CONFIG_OF */
2547c91eab4bSThomas Abraham 
254862ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host)
2549f95f3850SWill Newton {
2550e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
255162ca8034SShashidhar Hiremath 	int width, i, ret = 0;
2552f95f3850SWill Newton 	u32 fifo_size;
25531c2215b7SThomas Abraham 	int init_slots = 0;
2554f95f3850SWill Newton 
2555c91eab4bSThomas Abraham 	if (!host->pdata) {
2556c91eab4bSThomas Abraham 		host->pdata = dw_mci_parse_dt(host);
2557c91eab4bSThomas Abraham 		if (IS_ERR(host->pdata)) {
2558c91eab4bSThomas Abraham 			dev_err(host->dev, "platform data not available\n");
2559c91eab4bSThomas Abraham 			return -EINVAL;
2560c91eab4bSThomas Abraham 		}
2561f95f3850SWill Newton 	}
2562f95f3850SWill Newton 
2563907abd51SJaehoon Chung 	if (host->pdata->num_slots > 1) {
25644a90920cSThomas Abraham 		dev_err(host->dev,
2565907abd51SJaehoon Chung 			"Platform data must supply num_slots.\n");
256662ca8034SShashidhar Hiremath 		return -ENODEV;
2567f95f3850SWill Newton 	}
2568f95f3850SWill Newton 
2569780f22afSSeungwon Jeon 	host->biu_clk = devm_clk_get(host->dev, "biu");
2570f90a0612SThomas Abraham 	if (IS_ERR(host->biu_clk)) {
2571f90a0612SThomas Abraham 		dev_dbg(host->dev, "biu clock not available\n");
2572f90a0612SThomas Abraham 	} else {
2573f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->biu_clk);
2574f90a0612SThomas Abraham 		if (ret) {
2575f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable biu clock\n");
2576f90a0612SThomas Abraham 			return ret;
2577f90a0612SThomas Abraham 		}
2578f95f3850SWill Newton 	}
2579f95f3850SWill Newton 
2580780f22afSSeungwon Jeon 	host->ciu_clk = devm_clk_get(host->dev, "ciu");
2581f90a0612SThomas Abraham 	if (IS_ERR(host->ciu_clk)) {
2582f90a0612SThomas Abraham 		dev_dbg(host->dev, "ciu clock not available\n");
25833c6d89eaSDoug Anderson 		host->bus_hz = host->pdata->bus_hz;
2584f90a0612SThomas Abraham 	} else {
2585f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->ciu_clk);
2586f90a0612SThomas Abraham 		if (ret) {
2587f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable ciu clock\n");
2588f90a0612SThomas Abraham 			goto err_clk_biu;
2589f90a0612SThomas Abraham 		}
2590f90a0612SThomas Abraham 
25913c6d89eaSDoug Anderson 		if (host->pdata->bus_hz) {
25923c6d89eaSDoug Anderson 			ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz);
25933c6d89eaSDoug Anderson 			if (ret)
25943c6d89eaSDoug Anderson 				dev_warn(host->dev,
2595612de4c1SJaehoon Chung 					 "Unable to set bus rate to %uHz\n",
25963c6d89eaSDoug Anderson 					 host->pdata->bus_hz);
25973c6d89eaSDoug Anderson 		}
2598f90a0612SThomas Abraham 		host->bus_hz = clk_get_rate(host->ciu_clk);
25993c6d89eaSDoug Anderson 	}
2600f90a0612SThomas Abraham 
2601612de4c1SJaehoon Chung 	if (!host->bus_hz) {
2602612de4c1SJaehoon Chung 		dev_err(host->dev,
2603612de4c1SJaehoon Chung 			"Platform data must supply bus speed\n");
2604612de4c1SJaehoon Chung 		ret = -ENODEV;
2605612de4c1SJaehoon Chung 		goto err_clk_ciu;
2606612de4c1SJaehoon Chung 	}
2607612de4c1SJaehoon Chung 
2608002f0d5cSYuvaraj Kumar C D 	if (drv_data && drv_data->init) {
2609002f0d5cSYuvaraj Kumar C D 		ret = drv_data->init(host);
2610002f0d5cSYuvaraj Kumar C D 		if (ret) {
2611002f0d5cSYuvaraj Kumar C D 			dev_err(host->dev,
2612002f0d5cSYuvaraj Kumar C D 				"implementation specific init failed\n");
2613002f0d5cSYuvaraj Kumar C D 			goto err_clk_ciu;
2614002f0d5cSYuvaraj Kumar C D 		}
2615002f0d5cSYuvaraj Kumar C D 	}
2616002f0d5cSYuvaraj Kumar C D 
2617cb27a843SJames Hogan 	if (drv_data && drv_data->setup_clock) {
2618cb27a843SJames Hogan 		ret = drv_data->setup_clock(host);
2619800d78bfSThomas Abraham 		if (ret) {
2620800d78bfSThomas Abraham 			dev_err(host->dev,
2621800d78bfSThomas Abraham 				"implementation specific clock setup failed\n");
2622800d78bfSThomas Abraham 			goto err_clk_ciu;
2623800d78bfSThomas Abraham 		}
2624800d78bfSThomas Abraham 	}
2625800d78bfSThomas Abraham 
262662ca8034SShashidhar Hiremath 	host->quirks = host->pdata->quirks;
2627f95f3850SWill Newton 
2628f95f3850SWill Newton 	spin_lock_init(&host->lock);
2629f95f3850SWill Newton 	INIT_LIST_HEAD(&host->queue);
2630f95f3850SWill Newton 
2631f95f3850SWill Newton 	/*
2632f95f3850SWill Newton 	 * Get the host data width - this assumes that HCON has been set with
2633f95f3850SWill Newton 	 * the correct values.
2634f95f3850SWill Newton 	 */
2635f95f3850SWill Newton 	i = (mci_readl(host, HCON) >> 7) & 0x7;
2636f95f3850SWill Newton 	if (!i) {
2637f95f3850SWill Newton 		host->push_data = dw_mci_push_data16;
2638f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data16;
2639f95f3850SWill Newton 		width = 16;
2640f95f3850SWill Newton 		host->data_shift = 1;
2641f95f3850SWill Newton 	} else if (i == 2) {
2642f95f3850SWill Newton 		host->push_data = dw_mci_push_data64;
2643f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data64;
2644f95f3850SWill Newton 		width = 64;
2645f95f3850SWill Newton 		host->data_shift = 3;
2646f95f3850SWill Newton 	} else {
2647f95f3850SWill Newton 		/* Check for a reserved value, and warn if it is */
2648f95f3850SWill Newton 		WARN((i != 1),
2649f95f3850SWill Newton 		     "HCON reports a reserved host data width!\n"
2650f95f3850SWill Newton 		     "Defaulting to 32-bit access.\n");
2651f95f3850SWill Newton 		host->push_data = dw_mci_push_data32;
2652f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data32;
2653f95f3850SWill Newton 		width = 32;
2654f95f3850SWill Newton 		host->data_shift = 2;
2655f95f3850SWill Newton 	}
2656f95f3850SWill Newton 
2657f95f3850SWill Newton 	/* Reset all blocks */
26583a33a94cSSonny Rao 	if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS))
2659141a712aSSeungwon Jeon 		return -ENODEV;
2660141a712aSSeungwon Jeon 
2661141a712aSSeungwon Jeon 	host->dma_ops = host->pdata->dma_ops;
2662141a712aSSeungwon Jeon 	dw_mci_init_dma(host);
2663f95f3850SWill Newton 
2664f95f3850SWill Newton 	/* Clear the interrupts for the host controller */
2665f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2666f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2667f95f3850SWill Newton 
2668f95f3850SWill Newton 	/* Put in max timeout */
2669f95f3850SWill Newton 	mci_writel(host, TMOUT, 0xFFFFFFFF);
2670f95f3850SWill Newton 
2671f95f3850SWill Newton 	/*
2672f95f3850SWill Newton 	 * FIFO threshold settings  RxMark  = fifo_size / 2 - 1,
2673f95f3850SWill Newton 	 *                          Tx Mark = fifo_size / 2 DMA Size = 8
2674f95f3850SWill Newton 	 */
2675b86d8253SJames Hogan 	if (!host->pdata->fifo_depth) {
2676b86d8253SJames Hogan 		/*
2677b86d8253SJames Hogan 		 * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may
2678b86d8253SJames Hogan 		 * have been overwritten by the bootloader, just like we're
2679b86d8253SJames Hogan 		 * about to do, so if you know the value for your hardware, you
2680b86d8253SJames Hogan 		 * should put it in the platform data.
2681b86d8253SJames Hogan 		 */
2682f95f3850SWill Newton 		fifo_size = mci_readl(host, FIFOTH);
26838234e869SJaehoon Chung 		fifo_size = 1 + ((fifo_size >> 16) & 0xfff);
2684b86d8253SJames Hogan 	} else {
2685b86d8253SJames Hogan 		fifo_size = host->pdata->fifo_depth;
2686b86d8253SJames Hogan 	}
2687b86d8253SJames Hogan 	host->fifo_depth = fifo_size;
268852426899SSeungwon Jeon 	host->fifoth_val =
268952426899SSeungwon Jeon 		SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2);
2690e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
2691f95f3850SWill Newton 
2692f95f3850SWill Newton 	/* disable clock to CIU */
2693f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2694f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2695f95f3850SWill Newton 
269663008768SJames Hogan 	/*
269763008768SJames Hogan 	 * In 2.40a spec, Data offset is changed.
269863008768SJames Hogan 	 * Need to check the version-id and set data-offset for DATA register.
269963008768SJames Hogan 	 */
270063008768SJames Hogan 	host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
270163008768SJames Hogan 	dev_info(host->dev, "Version ID is %04x\n", host->verid);
270263008768SJames Hogan 
270363008768SJames Hogan 	if (host->verid < DW_MMC_240A)
270463008768SJames Hogan 		host->data_offset = DATA_OFFSET;
270563008768SJames Hogan 	else
270663008768SJames Hogan 		host->data_offset = DATA_240A_OFFSET;
270763008768SJames Hogan 
2708f95f3850SWill Newton 	tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
270995dcc2cbSThomas Abraham 	host->card_workqueue = alloc_workqueue("dw-mci-card",
271059ff3eb6SZhangZhen 			WQ_MEM_RECLAIM, 1);
2711ef7aef9aSWei Yongjun 	if (!host->card_workqueue) {
2712ef7aef9aSWei Yongjun 		ret = -ENOMEM;
27131791b13eSJames Hogan 		goto err_dmaunmap;
2714ef7aef9aSWei Yongjun 	}
27151791b13eSJames Hogan 	INIT_WORK(&host->card_work, dw_mci_work_routine_card);
2716780f22afSSeungwon Jeon 	ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
2717780f22afSSeungwon Jeon 			       host->irq_flags, "dw-mci", host);
2718f95f3850SWill Newton 	if (ret)
27191791b13eSJames Hogan 		goto err_workqueue;
2720f95f3850SWill Newton 
2721f95f3850SWill Newton 	if (host->pdata->num_slots)
2722f95f3850SWill Newton 		host->num_slots = host->pdata->num_slots;
2723f95f3850SWill Newton 	else
2724f95f3850SWill Newton 		host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1;
2725f95f3850SWill Newton 
27262da1d7f2SYuvaraj CD 	/*
27272da1d7f2SYuvaraj CD 	 * Enable interrupts for command done, data over, data empty, card det,
27282da1d7f2SYuvaraj CD 	 * receive ready and error such as transmit, receive timeout, crc error
27292da1d7f2SYuvaraj CD 	 */
27302da1d7f2SYuvaraj CD 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
27312da1d7f2SYuvaraj CD 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
27322da1d7f2SYuvaraj CD 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
27332da1d7f2SYuvaraj CD 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
27342da1d7f2SYuvaraj CD 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
27352da1d7f2SYuvaraj CD 
27362da1d7f2SYuvaraj CD 	dev_info(host->dev, "DW MMC controller at irq %d, "
27372da1d7f2SYuvaraj CD 		 "%d bit host data width, "
27382da1d7f2SYuvaraj CD 		 "%u deep fifo\n",
27392da1d7f2SYuvaraj CD 		 host->irq, width, fifo_size);
27402da1d7f2SYuvaraj CD 
2741f95f3850SWill Newton 	/* We need at least one slot to succeed */
2742f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2743f95f3850SWill Newton 		ret = dw_mci_init_slot(host, i);
27441c2215b7SThomas Abraham 		if (ret)
27451c2215b7SThomas Abraham 			dev_dbg(host->dev, "slot %d init failed\n", i);
27461c2215b7SThomas Abraham 		else
27471c2215b7SThomas Abraham 			init_slots++;
2748f95f3850SWill Newton 	}
27491c2215b7SThomas Abraham 
27501c2215b7SThomas Abraham 	if (init_slots) {
27511c2215b7SThomas Abraham 		dev_info(host->dev, "%d slots initialized\n", init_slots);
27521c2215b7SThomas Abraham 	} else {
27531c2215b7SThomas Abraham 		dev_dbg(host->dev, "attempted to initialize %d slots, "
27541c2215b7SThomas Abraham 					"but failed on all\n", host->num_slots);
2755780f22afSSeungwon Jeon 		goto err_workqueue;
2756f95f3850SWill Newton 	}
2757f95f3850SWill Newton 
2758f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
27594a90920cSThomas Abraham 		dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
2760f95f3850SWill Newton 
2761f95f3850SWill Newton 	return 0;
2762f95f3850SWill Newton 
27631791b13eSJames Hogan err_workqueue:
276495dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
27651791b13eSJames Hogan 
2766f95f3850SWill Newton err_dmaunmap:
2767f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2768f95f3850SWill Newton 		host->dma_ops->exit(host);
2769f90a0612SThomas Abraham 
2770f90a0612SThomas Abraham err_clk_ciu:
2771780f22afSSeungwon Jeon 	if (!IS_ERR(host->ciu_clk))
2772f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2773780f22afSSeungwon Jeon 
2774f90a0612SThomas Abraham err_clk_biu:
2775780f22afSSeungwon Jeon 	if (!IS_ERR(host->biu_clk))
2776f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2777780f22afSSeungwon Jeon 
2778f95f3850SWill Newton 	return ret;
2779f95f3850SWill Newton }
278062ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe);
2781f95f3850SWill Newton 
278262ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host)
2783f95f3850SWill Newton {
2784f95f3850SWill Newton 	int i;
2785f95f3850SWill Newton 
2786f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2787f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2788f95f3850SWill Newton 
2789f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
27904a90920cSThomas Abraham 		dev_dbg(host->dev, "remove slot %d\n", i);
2791f95f3850SWill Newton 		if (host->slot[i])
2792f95f3850SWill Newton 			dw_mci_cleanup_slot(host->slot[i], i);
2793f95f3850SWill Newton 	}
2794f95f3850SWill Newton 
2795f95f3850SWill Newton 	/* disable clock to CIU */
2796f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2797f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2798f95f3850SWill Newton 
279995dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
2800f95f3850SWill Newton 
2801f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2802f95f3850SWill Newton 		host->dma_ops->exit(host);
2803f95f3850SWill Newton 
2804f90a0612SThomas Abraham 	if (!IS_ERR(host->ciu_clk))
2805f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2806780f22afSSeungwon Jeon 
2807f90a0612SThomas Abraham 	if (!IS_ERR(host->biu_clk))
2808f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2809f95f3850SWill Newton }
281062ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove);
281162ca8034SShashidhar Hiremath 
281262ca8034SShashidhar Hiremath 
2813f95f3850SWill Newton 
28146fe8890dSJaehoon Chung #ifdef CONFIG_PM_SLEEP
2815f95f3850SWill Newton /*
2816f95f3850SWill Newton  * TODO: we should probably disable the clock to the card in the suspend path.
2817f95f3850SWill Newton  */
281862ca8034SShashidhar Hiremath int dw_mci_suspend(struct dw_mci *host)
2819f95f3850SWill Newton {
2820f95f3850SWill Newton 	return 0;
2821f95f3850SWill Newton }
282262ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_suspend);
2823f95f3850SWill Newton 
282462ca8034SShashidhar Hiremath int dw_mci_resume(struct dw_mci *host)
2825f95f3850SWill Newton {
2826f95f3850SWill Newton 	int i, ret;
2827f95f3850SWill Newton 
28283a33a94cSSonny Rao 	if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) {
2829e61cf118SJaehoon Chung 		ret = -ENODEV;
2830e61cf118SJaehoon Chung 		return ret;
2831e61cf118SJaehoon Chung 	}
2832e61cf118SJaehoon Chung 
28333bfe619dSJonathan Kliegman 	if (host->use_dma && host->dma_ops->init)
2834141a712aSSeungwon Jeon 		host->dma_ops->init(host);
2835141a712aSSeungwon Jeon 
283652426899SSeungwon Jeon 	/*
283752426899SSeungwon Jeon 	 * Restore the initial value at FIFOTH register
283852426899SSeungwon Jeon 	 * And Invalidate the prev_blksz with zero
283952426899SSeungwon Jeon 	 */
2840e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
284152426899SSeungwon Jeon 	host->prev_blksz = 0;
2842e61cf118SJaehoon Chung 
28432eb2944fSDoug Anderson 	/* Put in max timeout */
28442eb2944fSDoug Anderson 	mci_writel(host, TMOUT, 0xFFFFFFFF);
28452eb2944fSDoug Anderson 
2846e61cf118SJaehoon Chung 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2847e61cf118SJaehoon Chung 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
2848e61cf118SJaehoon Chung 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
2849e61cf118SJaehoon Chung 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
2850e61cf118SJaehoon Chung 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
2851e61cf118SJaehoon Chung 
2852f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2853f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
2854f95f3850SWill Newton 		if (!slot)
2855f95f3850SWill Newton 			continue;
2856ab269128SAbhilash Kesavan 		if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
2857ab269128SAbhilash Kesavan 			dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
2858ab269128SAbhilash Kesavan 			dw_mci_setup_bus(slot, true);
2859ab269128SAbhilash Kesavan 		}
2860f95f3850SWill Newton 	}
2861f95f3850SWill Newton 	return 0;
2862f95f3850SWill Newton }
286362ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_resume);
28646fe8890dSJaehoon Chung #endif /* CONFIG_PM_SLEEP */
28656fe8890dSJaehoon Chung 
2866f95f3850SWill Newton static int __init dw_mci_init(void)
2867f95f3850SWill Newton {
28688e1c4e4dSSachin Kamat 	pr_info("Synopsys Designware Multimedia Card Interface Driver\n");
286962ca8034SShashidhar Hiremath 	return 0;
2870f95f3850SWill Newton }
2871f95f3850SWill Newton 
2872f95f3850SWill Newton static void __exit dw_mci_exit(void)
2873f95f3850SWill Newton {
2874f95f3850SWill Newton }
2875f95f3850SWill Newton 
2876f95f3850SWill Newton module_init(dw_mci_init);
2877f95f3850SWill Newton module_exit(dw_mci_exit);
2878f95f3850SWill Newton 
2879f95f3850SWill Newton MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
2880f95f3850SWill Newton MODULE_AUTHOR("NXP Semiconductor VietNam");
2881f95f3850SWill Newton MODULE_AUTHOR("Imagination Technologies Ltd");
2882f95f3850SWill Newton MODULE_LICENSE("GPL v2");
2883