xref: /linux/drivers/mmc/host/dw_mmc.c (revision 1f44a2a55787faa08a50266fa5dc99f0dcd36b7c)
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>
32f95f3850SWill Newton #include <linux/mmc/dw_mmc.h>
33f95f3850SWill Newton #include <linux/bitops.h>
34c07946a3SJaehoon Chung #include <linux/regulator/consumer.h>
351791b13eSJames Hogan #include <linux/workqueue.h>
36c91eab4bSThomas Abraham #include <linux/of.h>
3755a6ceb2SDoug Anderson #include <linux/of_gpio.h>
38f95f3850SWill Newton 
39f95f3850SWill Newton #include "dw_mmc.h"
40f95f3850SWill Newton 
41f95f3850SWill Newton /* Common flag combinations */
423f7eec62SJaehoon Chung #define DW_MCI_DATA_ERROR_FLAGS	(SDMMC_INT_DRTO | SDMMC_INT_DCRC | \
43f95f3850SWill Newton 				 SDMMC_INT_HTO | SDMMC_INT_SBE  | \
44f95f3850SWill Newton 				 SDMMC_INT_EBE)
45f95f3850SWill Newton #define DW_MCI_CMD_ERROR_FLAGS	(SDMMC_INT_RTO | SDMMC_INT_RCRC | \
46f95f3850SWill Newton 				 SDMMC_INT_RESP_ERR)
47f95f3850SWill Newton #define DW_MCI_ERROR_FLAGS	(DW_MCI_DATA_ERROR_FLAGS | \
48f95f3850SWill Newton 				 DW_MCI_CMD_ERROR_FLAGS  | SDMMC_INT_HLE)
49f95f3850SWill Newton #define DW_MCI_SEND_STATUS	1
50f95f3850SWill Newton #define DW_MCI_RECV_STATUS	2
51f95f3850SWill Newton #define DW_MCI_DMA_THRESHOLD	16
52f95f3850SWill Newton 
53*1f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MAX	200000000	/* unit: HZ */
54*1f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MIN	400000		/* unit: HZ */
55*1f44a2a5SSeungwon Jeon 
56f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
57fc79a4d6SJoonyoung Shim #define IDMAC_INT_CLR		(SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \
58fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \
59fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
60fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_TI)
61fc79a4d6SJoonyoung Shim 
62f95f3850SWill Newton struct idmac_desc {
63f95f3850SWill Newton 	u32		des0;	/* Control Descriptor */
64f95f3850SWill Newton #define IDMAC_DES0_DIC	BIT(1)
65f95f3850SWill Newton #define IDMAC_DES0_LD	BIT(2)
66f95f3850SWill Newton #define IDMAC_DES0_FD	BIT(3)
67f95f3850SWill Newton #define IDMAC_DES0_CH	BIT(4)
68f95f3850SWill Newton #define IDMAC_DES0_ER	BIT(5)
69f95f3850SWill Newton #define IDMAC_DES0_CES	BIT(30)
70f95f3850SWill Newton #define IDMAC_DES0_OWN	BIT(31)
71f95f3850SWill Newton 
72f95f3850SWill Newton 	u32		des1;	/* Buffer sizes */
73f95f3850SWill Newton #define IDMAC_SET_BUFFER1_SIZE(d, s) \
749b7bbe10SShashidhar Hiremath 	((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff))
75f95f3850SWill Newton 
76f95f3850SWill Newton 	u32		des2;	/* buffer 1 physical address */
77f95f3850SWill Newton 
78f95f3850SWill Newton 	u32		des3;	/* buffer 2 physical address */
79f95f3850SWill Newton };
80f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */
81f95f3850SWill Newton 
820976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_4bit[] = {
830976f16dSSeungwon Jeon 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
840976f16dSSeungwon Jeon 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
850976f16dSSeungwon Jeon 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
860976f16dSSeungwon Jeon 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
870976f16dSSeungwon Jeon 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
880976f16dSSeungwon Jeon 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
890976f16dSSeungwon Jeon 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
900976f16dSSeungwon Jeon 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
910976f16dSSeungwon Jeon };
92f95f3850SWill Newton 
930976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_8bit[] = {
940976f16dSSeungwon Jeon 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
950976f16dSSeungwon Jeon 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
960976f16dSSeungwon Jeon 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
970976f16dSSeungwon Jeon 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
980976f16dSSeungwon Jeon 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
990976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
1000976f16dSSeungwon Jeon 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
1010976f16dSSeungwon Jeon 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
1020976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
1030976f16dSSeungwon Jeon 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
1040976f16dSSeungwon Jeon 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
1050976f16dSSeungwon Jeon 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
1060976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
1070976f16dSSeungwon Jeon 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
1080976f16dSSeungwon Jeon 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
1090976f16dSSeungwon Jeon 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
110f95f3850SWill Newton };
111f95f3850SWill Newton 
112f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS)
113f95f3850SWill Newton static int dw_mci_req_show(struct seq_file *s, void *v)
114f95f3850SWill Newton {
115f95f3850SWill Newton 	struct dw_mci_slot *slot = s->private;
116f95f3850SWill Newton 	struct mmc_request *mrq;
117f95f3850SWill Newton 	struct mmc_command *cmd;
118f95f3850SWill Newton 	struct mmc_command *stop;
119f95f3850SWill Newton 	struct mmc_data	*data;
120f95f3850SWill Newton 
121f95f3850SWill Newton 	/* Make sure we get a consistent snapshot */
122f95f3850SWill Newton 	spin_lock_bh(&slot->host->lock);
123f95f3850SWill Newton 	mrq = slot->mrq;
124f95f3850SWill Newton 
125f95f3850SWill Newton 	if (mrq) {
126f95f3850SWill Newton 		cmd = mrq->cmd;
127f95f3850SWill Newton 		data = mrq->data;
128f95f3850SWill Newton 		stop = mrq->stop;
129f95f3850SWill Newton 
130f95f3850SWill Newton 		if (cmd)
131f95f3850SWill Newton 			seq_printf(s,
132f95f3850SWill Newton 				   "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
133f95f3850SWill Newton 				   cmd->opcode, cmd->arg, cmd->flags,
134f95f3850SWill Newton 				   cmd->resp[0], cmd->resp[1], cmd->resp[2],
135f95f3850SWill Newton 				   cmd->resp[2], cmd->error);
136f95f3850SWill Newton 		if (data)
137f95f3850SWill Newton 			seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
138f95f3850SWill Newton 				   data->bytes_xfered, data->blocks,
139f95f3850SWill Newton 				   data->blksz, data->flags, data->error);
140f95f3850SWill Newton 		if (stop)
141f95f3850SWill Newton 			seq_printf(s,
142f95f3850SWill Newton 				   "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
143f95f3850SWill Newton 				   stop->opcode, stop->arg, stop->flags,
144f95f3850SWill Newton 				   stop->resp[0], stop->resp[1], stop->resp[2],
145f95f3850SWill Newton 				   stop->resp[2], stop->error);
146f95f3850SWill Newton 	}
147f95f3850SWill Newton 
148f95f3850SWill Newton 	spin_unlock_bh(&slot->host->lock);
149f95f3850SWill Newton 
150f95f3850SWill Newton 	return 0;
151f95f3850SWill Newton }
152f95f3850SWill Newton 
153f95f3850SWill Newton static int dw_mci_req_open(struct inode *inode, struct file *file)
154f95f3850SWill Newton {
155f95f3850SWill Newton 	return single_open(file, dw_mci_req_show, inode->i_private);
156f95f3850SWill Newton }
157f95f3850SWill Newton 
158f95f3850SWill Newton static const struct file_operations dw_mci_req_fops = {
159f95f3850SWill Newton 	.owner		= THIS_MODULE,
160f95f3850SWill Newton 	.open		= dw_mci_req_open,
161f95f3850SWill Newton 	.read		= seq_read,
162f95f3850SWill Newton 	.llseek		= seq_lseek,
163f95f3850SWill Newton 	.release	= single_release,
164f95f3850SWill Newton };
165f95f3850SWill Newton 
166f95f3850SWill Newton static int dw_mci_regs_show(struct seq_file *s, void *v)
167f95f3850SWill Newton {
168f95f3850SWill Newton 	seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS);
169f95f3850SWill Newton 	seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS);
170f95f3850SWill Newton 	seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD);
171f95f3850SWill Newton 	seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL);
172f95f3850SWill Newton 	seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK);
173f95f3850SWill Newton 	seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA);
174f95f3850SWill Newton 
175f95f3850SWill Newton 	return 0;
176f95f3850SWill Newton }
177f95f3850SWill Newton 
178f95f3850SWill Newton static int dw_mci_regs_open(struct inode *inode, struct file *file)
179f95f3850SWill Newton {
180f95f3850SWill Newton 	return single_open(file, dw_mci_regs_show, inode->i_private);
181f95f3850SWill Newton }
182f95f3850SWill Newton 
183f95f3850SWill Newton static const struct file_operations dw_mci_regs_fops = {
184f95f3850SWill Newton 	.owner		= THIS_MODULE,
185f95f3850SWill Newton 	.open		= dw_mci_regs_open,
186f95f3850SWill Newton 	.read		= seq_read,
187f95f3850SWill Newton 	.llseek		= seq_lseek,
188f95f3850SWill Newton 	.release	= single_release,
189f95f3850SWill Newton };
190f95f3850SWill Newton 
191f95f3850SWill Newton static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
192f95f3850SWill Newton {
193f95f3850SWill Newton 	struct mmc_host	*mmc = slot->mmc;
194f95f3850SWill Newton 	struct dw_mci *host = slot->host;
195f95f3850SWill Newton 	struct dentry *root;
196f95f3850SWill Newton 	struct dentry *node;
197f95f3850SWill Newton 
198f95f3850SWill Newton 	root = mmc->debugfs_root;
199f95f3850SWill Newton 	if (!root)
200f95f3850SWill Newton 		return;
201f95f3850SWill Newton 
202f95f3850SWill Newton 	node = debugfs_create_file("regs", S_IRUSR, root, host,
203f95f3850SWill Newton 				   &dw_mci_regs_fops);
204f95f3850SWill Newton 	if (!node)
205f95f3850SWill Newton 		goto err;
206f95f3850SWill Newton 
207f95f3850SWill Newton 	node = debugfs_create_file("req", S_IRUSR, root, slot,
208f95f3850SWill Newton 				   &dw_mci_req_fops);
209f95f3850SWill Newton 	if (!node)
210f95f3850SWill Newton 		goto err;
211f95f3850SWill Newton 
212f95f3850SWill Newton 	node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
213f95f3850SWill Newton 	if (!node)
214f95f3850SWill Newton 		goto err;
215f95f3850SWill Newton 
216f95f3850SWill Newton 	node = debugfs_create_x32("pending_events", S_IRUSR, root,
217f95f3850SWill Newton 				  (u32 *)&host->pending_events);
218f95f3850SWill Newton 	if (!node)
219f95f3850SWill Newton 		goto err;
220f95f3850SWill Newton 
221f95f3850SWill Newton 	node = debugfs_create_x32("completed_events", S_IRUSR, root,
222f95f3850SWill Newton 				  (u32 *)&host->completed_events);
223f95f3850SWill Newton 	if (!node)
224f95f3850SWill Newton 		goto err;
225f95f3850SWill Newton 
226f95f3850SWill Newton 	return;
227f95f3850SWill Newton 
228f95f3850SWill Newton err:
229f95f3850SWill Newton 	dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
230f95f3850SWill Newton }
231f95f3850SWill Newton #endif /* defined(CONFIG_DEBUG_FS) */
232f95f3850SWill Newton 
233f95f3850SWill Newton static void dw_mci_set_timeout(struct dw_mci *host)
234f95f3850SWill Newton {
235f95f3850SWill Newton 	/* timeout (maximum) */
236f95f3850SWill Newton 	mci_writel(host, TMOUT, 0xffffffff);
237f95f3850SWill Newton }
238f95f3850SWill Newton 
239f95f3850SWill Newton static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
240f95f3850SWill Newton {
241f95f3850SWill Newton 	struct mmc_data	*data;
242800d78bfSThomas Abraham 	struct dw_mci_slot *slot = mmc_priv(mmc);
243e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
244f95f3850SWill Newton 	u32 cmdr;
245f95f3850SWill Newton 	cmd->error = -EINPROGRESS;
246f95f3850SWill Newton 
247f95f3850SWill Newton 	cmdr = cmd->opcode;
248f95f3850SWill Newton 
249f95f3850SWill Newton 	if (cmdr == MMC_STOP_TRANSMISSION)
250f95f3850SWill Newton 		cmdr |= SDMMC_CMD_STOP;
251f95f3850SWill Newton 	else
252f95f3850SWill Newton 		cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
253f95f3850SWill Newton 
254f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_PRESENT) {
255f95f3850SWill Newton 		/* We expect a response, so set this bit */
256f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_EXP;
257f95f3850SWill Newton 		if (cmd->flags & MMC_RSP_136)
258f95f3850SWill Newton 			cmdr |= SDMMC_CMD_RESP_LONG;
259f95f3850SWill Newton 	}
260f95f3850SWill Newton 
261f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_CRC)
262f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_CRC;
263f95f3850SWill Newton 
264f95f3850SWill Newton 	data = cmd->data;
265f95f3850SWill Newton 	if (data) {
266f95f3850SWill Newton 		cmdr |= SDMMC_CMD_DAT_EXP;
267f95f3850SWill Newton 		if (data->flags & MMC_DATA_STREAM)
268f95f3850SWill Newton 			cmdr |= SDMMC_CMD_STRM_MODE;
269f95f3850SWill Newton 		if (data->flags & MMC_DATA_WRITE)
270f95f3850SWill Newton 			cmdr |= SDMMC_CMD_DAT_WR;
271f95f3850SWill Newton 	}
272f95f3850SWill Newton 
273cb27a843SJames Hogan 	if (drv_data && drv_data->prepare_command)
274cb27a843SJames Hogan 		drv_data->prepare_command(slot->host, &cmdr);
275800d78bfSThomas Abraham 
276f95f3850SWill Newton 	return cmdr;
277f95f3850SWill Newton }
278f95f3850SWill Newton 
279f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host,
280f95f3850SWill Newton 				 struct mmc_command *cmd, u32 cmd_flags)
281f95f3850SWill Newton {
282f95f3850SWill Newton 	host->cmd = cmd;
2834a90920cSThomas Abraham 	dev_vdbg(host->dev,
284f95f3850SWill Newton 		 "start command: ARGR=0x%08x CMDR=0x%08x\n",
285f95f3850SWill Newton 		 cmd->arg, cmd_flags);
286f95f3850SWill Newton 
287f95f3850SWill Newton 	mci_writel(host, CMDARG, cmd->arg);
288f95f3850SWill Newton 	wmb();
289f95f3850SWill Newton 
290f95f3850SWill Newton 	mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
291f95f3850SWill Newton }
292f95f3850SWill Newton 
293f95f3850SWill Newton static void send_stop_cmd(struct dw_mci *host, struct mmc_data *data)
294f95f3850SWill Newton {
295f95f3850SWill Newton 	dw_mci_start_command(host, data->stop, host->stop_cmdr);
296f95f3850SWill Newton }
297f95f3850SWill Newton 
298f95f3850SWill Newton /* DMA interface functions */
299f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host)
300f95f3850SWill Newton {
30103e8cb53SJames Hogan 	if (host->using_dma) {
302f95f3850SWill Newton 		host->dma_ops->stop(host);
303f95f3850SWill Newton 		host->dma_ops->cleanup(host);
304f95f3850SWill Newton 	} else {
305f95f3850SWill Newton 		/* Data transfer was stopped by the interrupt handler */
306f95f3850SWill Newton 		set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
307f95f3850SWill Newton 	}
308f95f3850SWill Newton }
309f95f3850SWill Newton 
3109aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data)
3119aa51408SSeungwon Jeon {
3129aa51408SSeungwon Jeon 	if (data->flags & MMC_DATA_WRITE)
3139aa51408SSeungwon Jeon 		return DMA_TO_DEVICE;
3149aa51408SSeungwon Jeon 	else
3159aa51408SSeungwon Jeon 		return DMA_FROM_DEVICE;
3169aa51408SSeungwon Jeon }
3179aa51408SSeungwon Jeon 
3189beee912SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
319f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host)
320f95f3850SWill Newton {
321f95f3850SWill Newton 	struct mmc_data *data = host->data;
322f95f3850SWill Newton 
323f95f3850SWill Newton 	if (data)
3249aa51408SSeungwon Jeon 		if (!data->host_cookie)
3254a90920cSThomas Abraham 			dma_unmap_sg(host->dev,
3269aa51408SSeungwon Jeon 				     data->sg,
3279aa51408SSeungwon Jeon 				     data->sg_len,
3289aa51408SSeungwon Jeon 				     dw_mci_get_dma_dir(data));
329f95f3850SWill Newton }
330f95f3850SWill Newton 
331f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host)
332f95f3850SWill Newton {
333f95f3850SWill Newton 	u32 temp;
334f95f3850SWill Newton 
335f95f3850SWill Newton 	/* Disable and reset the IDMAC interface */
336f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
337f95f3850SWill Newton 	temp &= ~SDMMC_CTRL_USE_IDMAC;
338f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_RESET;
339f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
340f95f3850SWill Newton 
341f95f3850SWill Newton 	/* Stop the IDMAC running */
342f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
343a5289a43SJaehoon Chung 	temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB);
344f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
345f95f3850SWill Newton }
346f95f3850SWill Newton 
347f95f3850SWill Newton static void dw_mci_idmac_complete_dma(struct dw_mci *host)
348f95f3850SWill Newton {
349f95f3850SWill Newton 	struct mmc_data *data = host->data;
350f95f3850SWill Newton 
3514a90920cSThomas Abraham 	dev_vdbg(host->dev, "DMA complete\n");
352f95f3850SWill Newton 
353f95f3850SWill Newton 	host->dma_ops->cleanup(host);
354f95f3850SWill Newton 
355f95f3850SWill Newton 	/*
356f95f3850SWill Newton 	 * If the card was removed, data will be NULL. No point in trying to
357f95f3850SWill Newton 	 * send the stop command or waiting for NBUSY in this case.
358f95f3850SWill Newton 	 */
359f95f3850SWill Newton 	if (data) {
360f95f3850SWill Newton 		set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
361f95f3850SWill Newton 		tasklet_schedule(&host->tasklet);
362f95f3850SWill Newton 	}
363f95f3850SWill Newton }
364f95f3850SWill Newton 
365f95f3850SWill Newton static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
366f95f3850SWill Newton 				    unsigned int sg_len)
367f95f3850SWill Newton {
368f95f3850SWill Newton 	int i;
369f95f3850SWill Newton 	struct idmac_desc *desc = host->sg_cpu;
370f95f3850SWill Newton 
371f95f3850SWill Newton 	for (i = 0; i < sg_len; i++, desc++) {
372f95f3850SWill Newton 		unsigned int length = sg_dma_len(&data->sg[i]);
373f95f3850SWill Newton 		u32 mem_addr = sg_dma_address(&data->sg[i]);
374f95f3850SWill Newton 
375f95f3850SWill Newton 		/* Set the OWN bit and disable interrupts for this descriptor */
376f95f3850SWill Newton 		desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH;
377f95f3850SWill Newton 
378f95f3850SWill Newton 		/* Buffer length */
379f95f3850SWill Newton 		IDMAC_SET_BUFFER1_SIZE(desc, length);
380f95f3850SWill Newton 
381f95f3850SWill Newton 		/* Physical address to DMA to/from */
382f95f3850SWill Newton 		desc->des2 = mem_addr;
383f95f3850SWill Newton 	}
384f95f3850SWill Newton 
385f95f3850SWill Newton 	/* Set first descriptor */
386f95f3850SWill Newton 	desc = host->sg_cpu;
387f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_FD;
388f95f3850SWill Newton 
389f95f3850SWill Newton 	/* Set last descriptor */
390f95f3850SWill Newton 	desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
391f95f3850SWill Newton 	desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
392f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_LD;
393f95f3850SWill Newton 
394f95f3850SWill Newton 	wmb();
395f95f3850SWill Newton }
396f95f3850SWill Newton 
397f95f3850SWill Newton static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
398f95f3850SWill Newton {
399f95f3850SWill Newton 	u32 temp;
400f95f3850SWill Newton 
401f95f3850SWill Newton 	dw_mci_translate_sglist(host, host->data, sg_len);
402f95f3850SWill Newton 
403f95f3850SWill Newton 	/* Select IDMAC interface */
404f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
405f95f3850SWill Newton 	temp |= SDMMC_CTRL_USE_IDMAC;
406f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
407f95f3850SWill Newton 
408f95f3850SWill Newton 	wmb();
409f95f3850SWill Newton 
410f95f3850SWill Newton 	/* Enable the IDMAC */
411f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
412a5289a43SJaehoon Chung 	temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB;
413f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
414f95f3850SWill Newton 
415f95f3850SWill Newton 	/* Start it running */
416f95f3850SWill Newton 	mci_writel(host, PLDMND, 1);
417f95f3850SWill Newton }
418f95f3850SWill Newton 
419f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host)
420f95f3850SWill Newton {
421f95f3850SWill Newton 	struct idmac_desc *p;
422897b69e7SSeungwon Jeon 	int i;
423f95f3850SWill Newton 
424f95f3850SWill Newton 	/* Number of descriptors in the ring buffer */
425f95f3850SWill Newton 	host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
426f95f3850SWill Newton 
427f95f3850SWill Newton 	/* Forward link the descriptor list */
428f95f3850SWill Newton 	for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
429f95f3850SWill Newton 		p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
430f95f3850SWill Newton 
431f95f3850SWill Newton 	/* Set the last descriptor as the end-of-ring descriptor */
432f95f3850SWill Newton 	p->des3 = host->sg_dma;
433f95f3850SWill Newton 	p->des0 = IDMAC_DES0_ER;
434f95f3850SWill Newton 
435141a712aSSeungwon Jeon 	mci_writel(host, BMOD, SDMMC_IDMAC_SWRESET);
436141a712aSSeungwon Jeon 
437f95f3850SWill Newton 	/* Mask out interrupts - get Tx & Rx complete only */
438fc79a4d6SJoonyoung Shim 	mci_writel(host, IDSTS, IDMAC_INT_CLR);
439f95f3850SWill Newton 	mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
440f95f3850SWill Newton 		   SDMMC_IDMAC_INT_TI);
441f95f3850SWill Newton 
442f95f3850SWill Newton 	/* Set the descriptor base address */
443f95f3850SWill Newton 	mci_writel(host, DBADDR, host->sg_dma);
444f95f3850SWill Newton 	return 0;
445f95f3850SWill Newton }
446f95f3850SWill Newton 
4478e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = {
448885c3e80SSeungwon Jeon 	.init = dw_mci_idmac_init,
449885c3e80SSeungwon Jeon 	.start = dw_mci_idmac_start_dma,
450885c3e80SSeungwon Jeon 	.stop = dw_mci_idmac_stop_dma,
451885c3e80SSeungwon Jeon 	.complete = dw_mci_idmac_complete_dma,
452885c3e80SSeungwon Jeon 	.cleanup = dw_mci_dma_cleanup,
453885c3e80SSeungwon Jeon };
454885c3e80SSeungwon Jeon #endif /* CONFIG_MMC_DW_IDMAC */
455885c3e80SSeungwon Jeon 
4569aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host,
4579aa51408SSeungwon Jeon 				   struct mmc_data *data,
4589aa51408SSeungwon Jeon 				   bool next)
459f95f3850SWill Newton {
460f95f3850SWill Newton 	struct scatterlist *sg;
4619aa51408SSeungwon Jeon 	unsigned int i, sg_len;
462f95f3850SWill Newton 
4639aa51408SSeungwon Jeon 	if (!next && data->host_cookie)
4649aa51408SSeungwon Jeon 		return data->host_cookie;
465f95f3850SWill Newton 
466f95f3850SWill Newton 	/*
467f95f3850SWill Newton 	 * We don't do DMA on "complex" transfers, i.e. with
468f95f3850SWill Newton 	 * non-word-aligned buffers or lengths. Also, we don't bother
469f95f3850SWill Newton 	 * with all the DMA setup overhead for short transfers.
470f95f3850SWill Newton 	 */
471f95f3850SWill Newton 	if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD)
472f95f3850SWill Newton 		return -EINVAL;
4739aa51408SSeungwon Jeon 
474f95f3850SWill Newton 	if (data->blksz & 3)
475f95f3850SWill Newton 		return -EINVAL;
476f95f3850SWill Newton 
477f95f3850SWill Newton 	for_each_sg(data->sg, sg, data->sg_len, i) {
478f95f3850SWill Newton 		if (sg->offset & 3 || sg->length & 3)
479f95f3850SWill Newton 			return -EINVAL;
480f95f3850SWill Newton 	}
481f95f3850SWill Newton 
4824a90920cSThomas Abraham 	sg_len = dma_map_sg(host->dev,
4839aa51408SSeungwon Jeon 			    data->sg,
4849aa51408SSeungwon Jeon 			    data->sg_len,
4859aa51408SSeungwon Jeon 			    dw_mci_get_dma_dir(data));
4869aa51408SSeungwon Jeon 	if (sg_len == 0)
4879aa51408SSeungwon Jeon 		return -EINVAL;
4889aa51408SSeungwon Jeon 
4899aa51408SSeungwon Jeon 	if (next)
4909aa51408SSeungwon Jeon 		data->host_cookie = sg_len;
4919aa51408SSeungwon Jeon 
4929aa51408SSeungwon Jeon 	return sg_len;
4939aa51408SSeungwon Jeon }
4949aa51408SSeungwon Jeon 
4959aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc,
4969aa51408SSeungwon Jeon 			   struct mmc_request *mrq,
4979aa51408SSeungwon Jeon 			   bool is_first_req)
4989aa51408SSeungwon Jeon {
4999aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
5009aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
5019aa51408SSeungwon Jeon 
5029aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
5039aa51408SSeungwon Jeon 		return;
5049aa51408SSeungwon Jeon 
5059aa51408SSeungwon Jeon 	if (data->host_cookie) {
5069aa51408SSeungwon Jeon 		data->host_cookie = 0;
5079aa51408SSeungwon Jeon 		return;
5089aa51408SSeungwon Jeon 	}
5099aa51408SSeungwon Jeon 
5109aa51408SSeungwon Jeon 	if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0)
5119aa51408SSeungwon Jeon 		data->host_cookie = 0;
5129aa51408SSeungwon Jeon }
5139aa51408SSeungwon Jeon 
5149aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc,
5159aa51408SSeungwon Jeon 			    struct mmc_request *mrq,
5169aa51408SSeungwon Jeon 			    int err)
5179aa51408SSeungwon Jeon {
5189aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
5199aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
5209aa51408SSeungwon Jeon 
5219aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
5229aa51408SSeungwon Jeon 		return;
5239aa51408SSeungwon Jeon 
5249aa51408SSeungwon Jeon 	if (data->host_cookie)
5254a90920cSThomas Abraham 		dma_unmap_sg(slot->host->dev,
5269aa51408SSeungwon Jeon 			     data->sg,
5279aa51408SSeungwon Jeon 			     data->sg_len,
5289aa51408SSeungwon Jeon 			     dw_mci_get_dma_dir(data));
5299aa51408SSeungwon Jeon 	data->host_cookie = 0;
5309aa51408SSeungwon Jeon }
5319aa51408SSeungwon Jeon 
5329aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
5339aa51408SSeungwon Jeon {
5349aa51408SSeungwon Jeon 	int sg_len;
5359aa51408SSeungwon Jeon 	u32 temp;
5369aa51408SSeungwon Jeon 
5379aa51408SSeungwon Jeon 	host->using_dma = 0;
5389aa51408SSeungwon Jeon 
5399aa51408SSeungwon Jeon 	/* If we don't have a channel, we can't do DMA */
5409aa51408SSeungwon Jeon 	if (!host->use_dma)
5419aa51408SSeungwon Jeon 		return -ENODEV;
5429aa51408SSeungwon Jeon 
5439aa51408SSeungwon Jeon 	sg_len = dw_mci_pre_dma_transfer(host, data, 0);
544a99aa9b9SSeungwon Jeon 	if (sg_len < 0) {
545a99aa9b9SSeungwon Jeon 		host->dma_ops->stop(host);
5469aa51408SSeungwon Jeon 		return sg_len;
547a99aa9b9SSeungwon Jeon 	}
5489aa51408SSeungwon Jeon 
54903e8cb53SJames Hogan 	host->using_dma = 1;
55003e8cb53SJames Hogan 
5514a90920cSThomas Abraham 	dev_vdbg(host->dev,
552f95f3850SWill Newton 		 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
553f95f3850SWill Newton 		 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
554f95f3850SWill Newton 		 sg_len);
555f95f3850SWill Newton 
556f95f3850SWill Newton 	/* Enable the DMA interface */
557f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
558f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_ENABLE;
559f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
560f95f3850SWill Newton 
561f95f3850SWill Newton 	/* Disable RX/TX IRQs, let DMA handle it */
562f95f3850SWill Newton 	temp = mci_readl(host, INTMASK);
563f95f3850SWill Newton 	temp  &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR);
564f95f3850SWill Newton 	mci_writel(host, INTMASK, temp);
565f95f3850SWill Newton 
566f95f3850SWill Newton 	host->dma_ops->start(host, sg_len);
567f95f3850SWill Newton 
568f95f3850SWill Newton 	return 0;
569f95f3850SWill Newton }
570f95f3850SWill Newton 
571f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
572f95f3850SWill Newton {
573f95f3850SWill Newton 	u32 temp;
574f95f3850SWill Newton 
575f95f3850SWill Newton 	data->error = -EINPROGRESS;
576f95f3850SWill Newton 
577f95f3850SWill Newton 	WARN_ON(host->data);
578f95f3850SWill Newton 	host->sg = NULL;
579f95f3850SWill Newton 	host->data = data;
580f95f3850SWill Newton 
58155c5efbcSJames Hogan 	if (data->flags & MMC_DATA_READ)
58255c5efbcSJames Hogan 		host->dir_status = DW_MCI_RECV_STATUS;
58355c5efbcSJames Hogan 	else
58455c5efbcSJames Hogan 		host->dir_status = DW_MCI_SEND_STATUS;
58555c5efbcSJames Hogan 
586f95f3850SWill Newton 	if (dw_mci_submit_data_dma(host, data)) {
587f9c2a0dcSSeungwon Jeon 		int flags = SG_MITER_ATOMIC;
588f9c2a0dcSSeungwon Jeon 		if (host->data->flags & MMC_DATA_READ)
589f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_TO_SG;
590f9c2a0dcSSeungwon Jeon 		else
591f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_FROM_SG;
592f9c2a0dcSSeungwon Jeon 
593f9c2a0dcSSeungwon Jeon 		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
594f95f3850SWill Newton 		host->sg = data->sg;
59534b664a2SJames Hogan 		host->part_buf_start = 0;
59634b664a2SJames Hogan 		host->part_buf_count = 0;
597f95f3850SWill Newton 
598b40af3aaSJames Hogan 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR);
599f95f3850SWill Newton 		temp = mci_readl(host, INTMASK);
600f95f3850SWill Newton 		temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR;
601f95f3850SWill Newton 		mci_writel(host, INTMASK, temp);
602f95f3850SWill Newton 
603f95f3850SWill Newton 		temp = mci_readl(host, CTRL);
604f95f3850SWill Newton 		temp &= ~SDMMC_CTRL_DMA_ENABLE;
605f95f3850SWill Newton 		mci_writel(host, CTRL, temp);
606f95f3850SWill Newton 	}
607f95f3850SWill Newton }
608f95f3850SWill Newton 
609f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
610f95f3850SWill Newton {
611f95f3850SWill Newton 	struct dw_mci *host = slot->host;
612f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
613f95f3850SWill Newton 	unsigned int cmd_status = 0;
614f95f3850SWill Newton 
615f95f3850SWill Newton 	mci_writel(host, CMDARG, arg);
616f95f3850SWill Newton 	wmb();
617f95f3850SWill Newton 	mci_writel(host, CMD, SDMMC_CMD_START | cmd);
618f95f3850SWill Newton 
619f95f3850SWill Newton 	while (time_before(jiffies, timeout)) {
620f95f3850SWill Newton 		cmd_status = mci_readl(host, CMD);
621f95f3850SWill Newton 		if (!(cmd_status & SDMMC_CMD_START))
622f95f3850SWill Newton 			return;
623f95f3850SWill Newton 	}
624f95f3850SWill Newton 	dev_err(&slot->mmc->class_dev,
625f95f3850SWill Newton 		"Timeout sending command (cmd %#x arg %#x status %#x)\n",
626f95f3850SWill Newton 		cmd, arg, cmd_status);
627f95f3850SWill Newton }
628f95f3850SWill Newton 
629ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
630f95f3850SWill Newton {
631f95f3850SWill Newton 	struct dw_mci *host = slot->host;
632fdf492a1SDoug Anderson 	unsigned int clock = slot->clock;
633f95f3850SWill Newton 	u32 div;
6349623b5b9SDoug Anderson 	u32 clk_en_a;
635f95f3850SWill Newton 
636fdf492a1SDoug Anderson 	if (!clock) {
637fdf492a1SDoug Anderson 		mci_writel(host, CLKENA, 0);
638fdf492a1SDoug Anderson 		mci_send_cmd(slot,
639fdf492a1SDoug Anderson 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
640fdf492a1SDoug Anderson 	} else if (clock != host->current_speed || force_clkinit) {
641fdf492a1SDoug Anderson 		div = host->bus_hz / clock;
642fdf492a1SDoug Anderson 		if (host->bus_hz % clock && host->bus_hz > clock)
643f95f3850SWill Newton 			/*
644f95f3850SWill Newton 			 * move the + 1 after the divide to prevent
645f95f3850SWill Newton 			 * over-clocking the card.
646f95f3850SWill Newton 			 */
647e419990bSSeungwon Jeon 			div += 1;
648e419990bSSeungwon Jeon 
649fdf492a1SDoug Anderson 		div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0;
650f95f3850SWill Newton 
651fdf492a1SDoug Anderson 		if ((clock << div) != slot->__clk_old || force_clkinit)
652f95f3850SWill Newton 			dev_info(&slot->mmc->class_dev,
653fdf492a1SDoug Anderson 				 "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
654fdf492a1SDoug Anderson 				 slot->id, host->bus_hz, clock,
655fdf492a1SDoug Anderson 				 div ? ((host->bus_hz / div) >> 1) :
656fdf492a1SDoug Anderson 				 host->bus_hz, div);
657f95f3850SWill Newton 
658f95f3850SWill Newton 		/* disable clock */
659f95f3850SWill Newton 		mci_writel(host, CLKENA, 0);
660f95f3850SWill Newton 		mci_writel(host, CLKSRC, 0);
661f95f3850SWill Newton 
662f95f3850SWill Newton 		/* inform CIU */
663f95f3850SWill Newton 		mci_send_cmd(slot,
664f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
665f95f3850SWill Newton 
666f95f3850SWill Newton 		/* set clock to desired speed */
667f95f3850SWill Newton 		mci_writel(host, CLKDIV, div);
668f95f3850SWill Newton 
669f95f3850SWill Newton 		/* inform CIU */
670f95f3850SWill Newton 		mci_send_cmd(slot,
671f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
672f95f3850SWill Newton 
6739623b5b9SDoug Anderson 		/* enable clock; only low power if no SDIO */
6749623b5b9SDoug Anderson 		clk_en_a = SDMMC_CLKEN_ENABLE << slot->id;
6759623b5b9SDoug Anderson 		if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id)))
6769623b5b9SDoug Anderson 			clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id;
6779623b5b9SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a);
678f95f3850SWill Newton 
679f95f3850SWill Newton 		/* inform CIU */
680f95f3850SWill Newton 		mci_send_cmd(slot,
681f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
682f95f3850SWill Newton 
683fdf492a1SDoug Anderson 		/* keep the clock with reflecting clock dividor */
684fdf492a1SDoug Anderson 		slot->__clk_old = clock << div;
685f95f3850SWill Newton 	}
686f95f3850SWill Newton 
687fdf492a1SDoug Anderson 	host->current_speed = clock;
688fdf492a1SDoug Anderson 
689f95f3850SWill Newton 	/* Set the current slot bus width */
6901d56c453SSeungwon Jeon 	mci_writel(host, CTYPE, (slot->ctype << slot->id));
691f95f3850SWill Newton }
692f95f3850SWill Newton 
693053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host,
694053b3ce6SSeungwon Jeon 				   struct dw_mci_slot *slot,
695053b3ce6SSeungwon Jeon 				   struct mmc_command *cmd)
696f95f3850SWill Newton {
697f95f3850SWill Newton 	struct mmc_request *mrq;
698f95f3850SWill Newton 	struct mmc_data	*data;
699f95f3850SWill Newton 	u32 cmdflags;
700f95f3850SWill Newton 
701f95f3850SWill Newton 	mrq = slot->mrq;
702f95f3850SWill Newton 	if (host->pdata->select_slot)
703f95f3850SWill Newton 		host->pdata->select_slot(slot->id);
704f95f3850SWill Newton 
705f95f3850SWill Newton 	host->cur_slot = slot;
706f95f3850SWill Newton 	host->mrq = mrq;
707f95f3850SWill Newton 
708f95f3850SWill Newton 	host->pending_events = 0;
709f95f3850SWill Newton 	host->completed_events = 0;
710f95f3850SWill Newton 	host->data_status = 0;
711f95f3850SWill Newton 
712053b3ce6SSeungwon Jeon 	data = cmd->data;
713f95f3850SWill Newton 	if (data) {
714f95f3850SWill Newton 		dw_mci_set_timeout(host);
715f95f3850SWill Newton 		mci_writel(host, BYTCNT, data->blksz*data->blocks);
716f95f3850SWill Newton 		mci_writel(host, BLKSIZ, data->blksz);
717f95f3850SWill Newton 	}
718f95f3850SWill Newton 
719f95f3850SWill Newton 	cmdflags = dw_mci_prepare_command(slot->mmc, cmd);
720f95f3850SWill Newton 
721f95f3850SWill Newton 	/* this is the first command, send the initialization clock */
722f95f3850SWill Newton 	if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags))
723f95f3850SWill Newton 		cmdflags |= SDMMC_CMD_INIT;
724f95f3850SWill Newton 
725f95f3850SWill Newton 	if (data) {
726f95f3850SWill Newton 		dw_mci_submit_data(host, data);
727f95f3850SWill Newton 		wmb();
728f95f3850SWill Newton 	}
729f95f3850SWill Newton 
730f95f3850SWill Newton 	dw_mci_start_command(host, cmd, cmdflags);
731f95f3850SWill Newton 
732f95f3850SWill Newton 	if (mrq->stop)
733f95f3850SWill Newton 		host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
734f95f3850SWill Newton }
735f95f3850SWill Newton 
736053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host,
737053b3ce6SSeungwon Jeon 				 struct dw_mci_slot *slot)
738053b3ce6SSeungwon Jeon {
739053b3ce6SSeungwon Jeon 	struct mmc_request *mrq = slot->mrq;
740053b3ce6SSeungwon Jeon 	struct mmc_command *cmd;
741053b3ce6SSeungwon Jeon 
742053b3ce6SSeungwon Jeon 	cmd = mrq->sbc ? mrq->sbc : mrq->cmd;
743053b3ce6SSeungwon Jeon 	__dw_mci_start_request(host, slot, cmd);
744053b3ce6SSeungwon Jeon }
745053b3ce6SSeungwon Jeon 
7467456caaeSJames Hogan /* must be called with host->lock held */
747f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot,
748f95f3850SWill Newton 				 struct mmc_request *mrq)
749f95f3850SWill Newton {
750f95f3850SWill Newton 	dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
751f95f3850SWill Newton 		 host->state);
752f95f3850SWill Newton 
753f95f3850SWill Newton 	slot->mrq = mrq;
754f95f3850SWill Newton 
755f95f3850SWill Newton 	if (host->state == STATE_IDLE) {
756f95f3850SWill Newton 		host->state = STATE_SENDING_CMD;
757f95f3850SWill Newton 		dw_mci_start_request(host, slot);
758f95f3850SWill Newton 	} else {
759f95f3850SWill Newton 		list_add_tail(&slot->queue_node, &host->queue);
760f95f3850SWill Newton 	}
761f95f3850SWill Newton }
762f95f3850SWill Newton 
763f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
764f95f3850SWill Newton {
765f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
766f95f3850SWill Newton 	struct dw_mci *host = slot->host;
767f95f3850SWill Newton 
768f95f3850SWill Newton 	WARN_ON(slot->mrq);
769f95f3850SWill Newton 
7707456caaeSJames Hogan 	/*
7717456caaeSJames Hogan 	 * The check for card presence and queueing of the request must be
7727456caaeSJames Hogan 	 * atomic, otherwise the card could be removed in between and the
7737456caaeSJames Hogan 	 * request wouldn't fail until another card was inserted.
7747456caaeSJames Hogan 	 */
7757456caaeSJames Hogan 	spin_lock_bh(&host->lock);
7767456caaeSJames Hogan 
777f95f3850SWill Newton 	if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
7787456caaeSJames Hogan 		spin_unlock_bh(&host->lock);
779f95f3850SWill Newton 		mrq->cmd->error = -ENOMEDIUM;
780f95f3850SWill Newton 		mmc_request_done(mmc, mrq);
781f95f3850SWill Newton 		return;
782f95f3850SWill Newton 	}
783f95f3850SWill Newton 
784f95f3850SWill Newton 	dw_mci_queue_request(host, slot, mrq);
7857456caaeSJames Hogan 
7867456caaeSJames Hogan 	spin_unlock_bh(&host->lock);
787f95f3850SWill Newton }
788f95f3850SWill Newton 
789f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
790f95f3850SWill Newton {
791f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
792e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
79341babf75SJaehoon Chung 	u32 regs;
794f95f3850SWill Newton 
795f95f3850SWill Newton 	switch (ios->bus_width) {
796f95f3850SWill Newton 	case MMC_BUS_WIDTH_4:
797f95f3850SWill Newton 		slot->ctype = SDMMC_CTYPE_4BIT;
798f95f3850SWill Newton 		break;
799c9b2a06fSJaehoon Chung 	case MMC_BUS_WIDTH_8:
800c9b2a06fSJaehoon Chung 		slot->ctype = SDMMC_CTYPE_8BIT;
801c9b2a06fSJaehoon Chung 		break;
802b2f7cb45SJaehoon Chung 	default:
803b2f7cb45SJaehoon Chung 		/* set default 1 bit mode */
804b2f7cb45SJaehoon Chung 		slot->ctype = SDMMC_CTYPE_1BIT;
805f95f3850SWill Newton 	}
806f95f3850SWill Newton 
80741babf75SJaehoon Chung 	regs = mci_readl(slot->host, UHS_REG);
8083f514291SSeungwon Jeon 
8093f514291SSeungwon Jeon 	/* DDR mode set */
8103f514291SSeungwon Jeon 	if (ios->timing == MMC_TIMING_UHS_DDR50)
811c69042a5SHyeonsu Kim 		regs |= ((0x1 << slot->id) << 16);
8123f514291SSeungwon Jeon 	else
813c69042a5SHyeonsu Kim 		regs &= ~((0x1 << slot->id) << 16);
8143f514291SSeungwon Jeon 
81541babf75SJaehoon Chung 	mci_writel(slot->host, UHS_REG, regs);
81641babf75SJaehoon Chung 
817f95f3850SWill Newton 	/*
818f95f3850SWill Newton 	 * Use mirror of ios->clock to prevent race with mmc
819f95f3850SWill Newton 	 * core ios update when finding the minimum.
820f95f3850SWill Newton 	 */
821f95f3850SWill Newton 	slot->clock = ios->clock;
822f95f3850SWill Newton 
823cb27a843SJames Hogan 	if (drv_data && drv_data->set_ios)
824cb27a843SJames Hogan 		drv_data->set_ios(slot->host, ios);
825800d78bfSThomas Abraham 
826bf7cb224SJaehoon Chung 	/* Slot specific timing and width adjustment */
827bf7cb224SJaehoon Chung 	dw_mci_setup_bus(slot, false);
828bf7cb224SJaehoon Chung 
829f95f3850SWill Newton 	switch (ios->power_mode) {
830f95f3850SWill Newton 	case MMC_POWER_UP:
831f95f3850SWill Newton 		set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
832e6f34e2fSJames Hogan 		/* Power up slot */
833e6f34e2fSJames Hogan 		if (slot->host->pdata->setpower)
834e6f34e2fSJames Hogan 			slot->host->pdata->setpower(slot->id, mmc->ocr_avail);
8354366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
8364366dcc5SJaehoon Chung 		regs |= (1 << slot->id);
8374366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
838e6f34e2fSJames Hogan 		break;
839e6f34e2fSJames Hogan 	case MMC_POWER_OFF:
840e6f34e2fSJames Hogan 		/* Power down slot */
841e6f34e2fSJames Hogan 		if (slot->host->pdata->setpower)
842e6f34e2fSJames Hogan 			slot->host->pdata->setpower(slot->id, 0);
8434366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
8444366dcc5SJaehoon Chung 		regs &= ~(1 << slot->id);
8454366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
846f95f3850SWill Newton 		break;
847f95f3850SWill Newton 	default:
848f95f3850SWill Newton 		break;
849f95f3850SWill Newton 	}
850f95f3850SWill Newton }
851f95f3850SWill Newton 
852f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc)
853f95f3850SWill Newton {
854f95f3850SWill Newton 	int read_only;
855f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
856f95f3850SWill Newton 	struct dw_mci_board *brd = slot->host->pdata;
857f95f3850SWill Newton 
858f95f3850SWill Newton 	/* Use platform get_ro function, else try on board write protect */
8599640639bSDoug Anderson 	if (slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT)
860b4967aa5SThomas Abraham 		read_only = 0;
861b4967aa5SThomas Abraham 	else if (brd->get_ro)
862f95f3850SWill Newton 		read_only = brd->get_ro(slot->id);
86355a6ceb2SDoug Anderson 	else if (gpio_is_valid(slot->wp_gpio))
86455a6ceb2SDoug Anderson 		read_only = gpio_get_value(slot->wp_gpio);
865f95f3850SWill Newton 	else
866f95f3850SWill Newton 		read_only =
867f95f3850SWill Newton 			mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0;
868f95f3850SWill Newton 
869f95f3850SWill Newton 	dev_dbg(&mmc->class_dev, "card is %s\n",
870f95f3850SWill Newton 		read_only ? "read-only" : "read-write");
871f95f3850SWill Newton 
872f95f3850SWill Newton 	return read_only;
873f95f3850SWill Newton }
874f95f3850SWill Newton 
875f95f3850SWill Newton static int dw_mci_get_cd(struct mmc_host *mmc)
876f95f3850SWill Newton {
877f95f3850SWill Newton 	int present;
878f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
879f95f3850SWill Newton 	struct dw_mci_board *brd = slot->host->pdata;
880f95f3850SWill Newton 
881f95f3850SWill Newton 	/* Use platform get_cd function, else try onboard card detect */
882fc3d7720SJaehoon Chung 	if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
883fc3d7720SJaehoon Chung 		present = 1;
884fc3d7720SJaehoon Chung 	else if (brd->get_cd)
885f95f3850SWill Newton 		present = !brd->get_cd(slot->id);
886f95f3850SWill Newton 	else
887f95f3850SWill Newton 		present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
888f95f3850SWill Newton 			== 0 ? 1 : 0;
889f95f3850SWill Newton 
890f95f3850SWill Newton 	if (present)
891f95f3850SWill Newton 		dev_dbg(&mmc->class_dev, "card is present\n");
892f95f3850SWill Newton 	else
893f95f3850SWill Newton 		dev_dbg(&mmc->class_dev, "card is not present\n");
894f95f3850SWill Newton 
895f95f3850SWill Newton 	return present;
896f95f3850SWill Newton }
897f95f3850SWill Newton 
8989623b5b9SDoug Anderson /*
8999623b5b9SDoug Anderson  * Disable lower power mode.
9009623b5b9SDoug Anderson  *
9019623b5b9SDoug Anderson  * Low power mode will stop the card clock when idle.  According to the
9029623b5b9SDoug Anderson  * description of the CLKENA register we should disable low power mode
9039623b5b9SDoug Anderson  * for SDIO cards if we need SDIO interrupts to work.
9049623b5b9SDoug Anderson  *
9059623b5b9SDoug Anderson  * This function is fast if low power mode is already disabled.
9069623b5b9SDoug Anderson  */
9079623b5b9SDoug Anderson static void dw_mci_disable_low_power(struct dw_mci_slot *slot)
9089623b5b9SDoug Anderson {
9099623b5b9SDoug Anderson 	struct dw_mci *host = slot->host;
9109623b5b9SDoug Anderson 	u32 clk_en_a;
9119623b5b9SDoug Anderson 	const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id;
9129623b5b9SDoug Anderson 
9139623b5b9SDoug Anderson 	clk_en_a = mci_readl(host, CLKENA);
9149623b5b9SDoug Anderson 
9159623b5b9SDoug Anderson 	if (clk_en_a & clken_low_pwr) {
9169623b5b9SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr);
9179623b5b9SDoug Anderson 		mci_send_cmd(slot, SDMMC_CMD_UPD_CLK |
9189623b5b9SDoug Anderson 			     SDMMC_CMD_PRV_DAT_WAIT, 0);
9199623b5b9SDoug Anderson 	}
9209623b5b9SDoug Anderson }
9219623b5b9SDoug Anderson 
9221a5c8e1fSShashidhar Hiremath static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
9231a5c8e1fSShashidhar Hiremath {
9241a5c8e1fSShashidhar Hiremath 	struct dw_mci_slot *slot = mmc_priv(mmc);
9251a5c8e1fSShashidhar Hiremath 	struct dw_mci *host = slot->host;
9261a5c8e1fSShashidhar Hiremath 	u32 int_mask;
9271a5c8e1fSShashidhar Hiremath 
9281a5c8e1fSShashidhar Hiremath 	/* Enable/disable Slot Specific SDIO interrupt */
9291a5c8e1fSShashidhar Hiremath 	int_mask = mci_readl(host, INTMASK);
9301a5c8e1fSShashidhar Hiremath 	if (enb) {
9319623b5b9SDoug Anderson 		/*
9329623b5b9SDoug Anderson 		 * Turn off low power mode if it was enabled.  This is a bit of
9339623b5b9SDoug Anderson 		 * a heavy operation and we disable / enable IRQs a lot, so
9349623b5b9SDoug Anderson 		 * we'll leave low power mode disabled and it will get
9359623b5b9SDoug Anderson 		 * re-enabled again in dw_mci_setup_bus().
9369623b5b9SDoug Anderson 		 */
9379623b5b9SDoug Anderson 		dw_mci_disable_low_power(slot);
9389623b5b9SDoug Anderson 
9391a5c8e1fSShashidhar Hiremath 		mci_writel(host, INTMASK,
940705ad047SKyoungil Kim 			   (int_mask | SDMMC_INT_SDIO(slot->id)));
9411a5c8e1fSShashidhar Hiremath 	} else {
9421a5c8e1fSShashidhar Hiremath 		mci_writel(host, INTMASK,
943705ad047SKyoungil Kim 			   (int_mask & ~SDMMC_INT_SDIO(slot->id)));
9441a5c8e1fSShashidhar Hiremath 	}
9451a5c8e1fSShashidhar Hiremath }
9461a5c8e1fSShashidhar Hiremath 
9470976f16dSSeungwon Jeon static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
9480976f16dSSeungwon Jeon {
9490976f16dSSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
9500976f16dSSeungwon Jeon 	struct dw_mci *host = slot->host;
9510976f16dSSeungwon Jeon 	const struct dw_mci_drv_data *drv_data = host->drv_data;
9520976f16dSSeungwon Jeon 	struct dw_mci_tuning_data tuning_data;
9530976f16dSSeungwon Jeon 	int err = -ENOSYS;
9540976f16dSSeungwon Jeon 
9550976f16dSSeungwon Jeon 	if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
9560976f16dSSeungwon Jeon 		if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
9570976f16dSSeungwon Jeon 			tuning_data.blk_pattern = tuning_blk_pattern_8bit;
9580976f16dSSeungwon Jeon 			tuning_data.blksz = sizeof(tuning_blk_pattern_8bit);
9590976f16dSSeungwon Jeon 		} else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
9600976f16dSSeungwon Jeon 			tuning_data.blk_pattern = tuning_blk_pattern_4bit;
9610976f16dSSeungwon Jeon 			tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
9620976f16dSSeungwon Jeon 		} else {
9630976f16dSSeungwon Jeon 			return -EINVAL;
9640976f16dSSeungwon Jeon 		}
9650976f16dSSeungwon Jeon 	} else if (opcode == MMC_SEND_TUNING_BLOCK) {
9660976f16dSSeungwon Jeon 		tuning_data.blk_pattern = tuning_blk_pattern_4bit;
9670976f16dSSeungwon Jeon 		tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
9680976f16dSSeungwon Jeon 	} else {
9690976f16dSSeungwon Jeon 		dev_err(host->dev,
9700976f16dSSeungwon Jeon 			"Undefined command(%d) for tuning\n", opcode);
9710976f16dSSeungwon Jeon 		return -EINVAL;
9720976f16dSSeungwon Jeon 	}
9730976f16dSSeungwon Jeon 
9740976f16dSSeungwon Jeon 	if (drv_data && drv_data->execute_tuning)
9750976f16dSSeungwon Jeon 		err = drv_data->execute_tuning(slot, opcode, &tuning_data);
9760976f16dSSeungwon Jeon 	return err;
9770976f16dSSeungwon Jeon }
9780976f16dSSeungwon Jeon 
979f95f3850SWill Newton static const struct mmc_host_ops dw_mci_ops = {
980f95f3850SWill Newton 	.request		= dw_mci_request,
9819aa51408SSeungwon Jeon 	.pre_req		= dw_mci_pre_req,
9829aa51408SSeungwon Jeon 	.post_req		= dw_mci_post_req,
983f95f3850SWill Newton 	.set_ios		= dw_mci_set_ios,
984f95f3850SWill Newton 	.get_ro			= dw_mci_get_ro,
985f95f3850SWill Newton 	.get_cd			= dw_mci_get_cd,
9861a5c8e1fSShashidhar Hiremath 	.enable_sdio_irq	= dw_mci_enable_sdio_irq,
9870976f16dSSeungwon Jeon 	.execute_tuning		= dw_mci_execute_tuning,
988f95f3850SWill Newton };
989f95f3850SWill Newton 
990f95f3850SWill Newton static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
991f95f3850SWill Newton 	__releases(&host->lock)
992f95f3850SWill Newton 	__acquires(&host->lock)
993f95f3850SWill Newton {
994f95f3850SWill Newton 	struct dw_mci_slot *slot;
995f95f3850SWill Newton 	struct mmc_host	*prev_mmc = host->cur_slot->mmc;
996f95f3850SWill Newton 
997f95f3850SWill Newton 	WARN_ON(host->cmd || host->data);
998f95f3850SWill Newton 
999f95f3850SWill Newton 	host->cur_slot->mrq = NULL;
1000f95f3850SWill Newton 	host->mrq = NULL;
1001f95f3850SWill Newton 	if (!list_empty(&host->queue)) {
1002f95f3850SWill Newton 		slot = list_entry(host->queue.next,
1003f95f3850SWill Newton 				  struct dw_mci_slot, queue_node);
1004f95f3850SWill Newton 		list_del(&slot->queue_node);
10054a90920cSThomas Abraham 		dev_vdbg(host->dev, "list not empty: %s is next\n",
1006f95f3850SWill Newton 			 mmc_hostname(slot->mmc));
1007f95f3850SWill Newton 		host->state = STATE_SENDING_CMD;
1008f95f3850SWill Newton 		dw_mci_start_request(host, slot);
1009f95f3850SWill Newton 	} else {
10104a90920cSThomas Abraham 		dev_vdbg(host->dev, "list empty\n");
1011f95f3850SWill Newton 		host->state = STATE_IDLE;
1012f95f3850SWill Newton 	}
1013f95f3850SWill Newton 
1014f95f3850SWill Newton 	spin_unlock(&host->lock);
1015f95f3850SWill Newton 	mmc_request_done(prev_mmc, mrq);
1016f95f3850SWill Newton 	spin_lock(&host->lock);
1017f95f3850SWill Newton }
1018f95f3850SWill Newton 
1019f95f3850SWill Newton static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
1020f95f3850SWill Newton {
1021f95f3850SWill Newton 	u32 status = host->cmd_status;
1022f95f3850SWill Newton 
1023f95f3850SWill Newton 	host->cmd_status = 0;
1024f95f3850SWill Newton 
1025f95f3850SWill Newton 	/* Read the response from the card (up to 16 bytes) */
1026f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_PRESENT) {
1027f95f3850SWill Newton 		if (cmd->flags & MMC_RSP_136) {
1028f95f3850SWill Newton 			cmd->resp[3] = mci_readl(host, RESP0);
1029f95f3850SWill Newton 			cmd->resp[2] = mci_readl(host, RESP1);
1030f95f3850SWill Newton 			cmd->resp[1] = mci_readl(host, RESP2);
1031f95f3850SWill Newton 			cmd->resp[0] = mci_readl(host, RESP3);
1032f95f3850SWill Newton 		} else {
1033f95f3850SWill Newton 			cmd->resp[0] = mci_readl(host, RESP0);
1034f95f3850SWill Newton 			cmd->resp[1] = 0;
1035f95f3850SWill Newton 			cmd->resp[2] = 0;
1036f95f3850SWill Newton 			cmd->resp[3] = 0;
1037f95f3850SWill Newton 		}
1038f95f3850SWill Newton 	}
1039f95f3850SWill Newton 
1040f95f3850SWill Newton 	if (status & SDMMC_INT_RTO)
1041f95f3850SWill Newton 		cmd->error = -ETIMEDOUT;
1042f95f3850SWill Newton 	else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC))
1043f95f3850SWill Newton 		cmd->error = -EILSEQ;
1044f95f3850SWill Newton 	else if (status & SDMMC_INT_RESP_ERR)
1045f95f3850SWill Newton 		cmd->error = -EIO;
1046f95f3850SWill Newton 	else
1047f95f3850SWill Newton 		cmd->error = 0;
1048f95f3850SWill Newton 
1049f95f3850SWill Newton 	if (cmd->error) {
1050f95f3850SWill Newton 		/* newer ip versions need a delay between retries */
1051f95f3850SWill Newton 		if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY)
1052f95f3850SWill Newton 			mdelay(20);
1053f95f3850SWill Newton 
1054f95f3850SWill Newton 		if (cmd->data) {
1055f95f3850SWill Newton 			dw_mci_stop_dma(host);
1056fda5f736SSeungwon Jeon 			host->data = NULL;
1057f95f3850SWill Newton 		}
1058f95f3850SWill Newton 	}
1059f95f3850SWill Newton }
1060f95f3850SWill Newton 
1061f95f3850SWill Newton static void dw_mci_tasklet_func(unsigned long priv)
1062f95f3850SWill Newton {
1063f95f3850SWill Newton 	struct dw_mci *host = (struct dw_mci *)priv;
1064f95f3850SWill Newton 	struct mmc_data	*data;
1065f95f3850SWill Newton 	struct mmc_command *cmd;
1066f95f3850SWill Newton 	enum dw_mci_state state;
1067f95f3850SWill Newton 	enum dw_mci_state prev_state;
106894dd5b33SJames Hogan 	u32 status, ctrl;
1069f95f3850SWill Newton 
1070f95f3850SWill Newton 	spin_lock(&host->lock);
1071f95f3850SWill Newton 
1072f95f3850SWill Newton 	state = host->state;
1073f95f3850SWill Newton 	data = host->data;
1074f95f3850SWill Newton 
1075f95f3850SWill Newton 	do {
1076f95f3850SWill Newton 		prev_state = state;
1077f95f3850SWill Newton 
1078f95f3850SWill Newton 		switch (state) {
1079f95f3850SWill Newton 		case STATE_IDLE:
1080f95f3850SWill Newton 			break;
1081f95f3850SWill Newton 
1082f95f3850SWill Newton 		case STATE_SENDING_CMD:
1083f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1084f95f3850SWill Newton 						&host->pending_events))
1085f95f3850SWill Newton 				break;
1086f95f3850SWill Newton 
1087f95f3850SWill Newton 			cmd = host->cmd;
1088f95f3850SWill Newton 			host->cmd = NULL;
1089f95f3850SWill Newton 			set_bit(EVENT_CMD_COMPLETE, &host->completed_events);
1090053b3ce6SSeungwon Jeon 			dw_mci_command_complete(host, cmd);
1091053b3ce6SSeungwon Jeon 			if (cmd == host->mrq->sbc && !cmd->error) {
1092053b3ce6SSeungwon Jeon 				prev_state = state = STATE_SENDING_CMD;
1093053b3ce6SSeungwon Jeon 				__dw_mci_start_request(host, host->cur_slot,
1094053b3ce6SSeungwon Jeon 						       host->mrq->cmd);
1095053b3ce6SSeungwon Jeon 				goto unlock;
1096053b3ce6SSeungwon Jeon 			}
1097053b3ce6SSeungwon Jeon 
1098f95f3850SWill Newton 			if (!host->mrq->data || cmd->error) {
1099f95f3850SWill Newton 				dw_mci_request_end(host, host->mrq);
1100f95f3850SWill Newton 				goto unlock;
1101f95f3850SWill Newton 			}
1102f95f3850SWill Newton 
1103f95f3850SWill Newton 			prev_state = state = STATE_SENDING_DATA;
1104f95f3850SWill Newton 			/* fall through */
1105f95f3850SWill Newton 
1106f95f3850SWill Newton 		case STATE_SENDING_DATA:
1107f95f3850SWill Newton 			if (test_and_clear_bit(EVENT_DATA_ERROR,
1108f95f3850SWill Newton 					       &host->pending_events)) {
1109f95f3850SWill Newton 				dw_mci_stop_dma(host);
1110f95f3850SWill Newton 				if (data->stop)
1111f95f3850SWill Newton 					send_stop_cmd(host, data);
1112f95f3850SWill Newton 				state = STATE_DATA_ERROR;
1113f95f3850SWill Newton 				break;
1114f95f3850SWill Newton 			}
1115f95f3850SWill Newton 
1116f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1117f95f3850SWill Newton 						&host->pending_events))
1118f95f3850SWill Newton 				break;
1119f95f3850SWill Newton 
1120f95f3850SWill Newton 			set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
1121f95f3850SWill Newton 			prev_state = state = STATE_DATA_BUSY;
1122f95f3850SWill Newton 			/* fall through */
1123f95f3850SWill Newton 
1124f95f3850SWill Newton 		case STATE_DATA_BUSY:
1125f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
1126f95f3850SWill Newton 						&host->pending_events))
1127f95f3850SWill Newton 				break;
1128f95f3850SWill Newton 
1129f95f3850SWill Newton 			host->data = NULL;
1130f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
1131f95f3850SWill Newton 			status = host->data_status;
1132f95f3850SWill Newton 
1133f95f3850SWill Newton 			if (status & DW_MCI_DATA_ERROR_FLAGS) {
11343f7eec62SJaehoon Chung 				if (status & SDMMC_INT_DRTO) {
1135f95f3850SWill Newton 					data->error = -ETIMEDOUT;
1136f95f3850SWill Newton 				} else if (status & SDMMC_INT_DCRC) {
1137f95f3850SWill Newton 					data->error = -EILSEQ;
113855c5efbcSJames Hogan 				} else if (status & SDMMC_INT_EBE &&
113955c5efbcSJames Hogan 					   host->dir_status ==
114055c5efbcSJames Hogan 							DW_MCI_SEND_STATUS) {
114155c5efbcSJames Hogan 					/*
114255c5efbcSJames Hogan 					 * No data CRC status was returned.
114355c5efbcSJames Hogan 					 * The number of bytes transferred will
114455c5efbcSJames Hogan 					 * be exaggerated in PIO mode.
114555c5efbcSJames Hogan 					 */
114655c5efbcSJames Hogan 					data->bytes_xfered = 0;
114755c5efbcSJames Hogan 					data->error = -ETIMEDOUT;
1148f95f3850SWill Newton 				} else {
11494a90920cSThomas Abraham 					dev_err(host->dev,
1150f95f3850SWill Newton 						"data FIFO error "
1151f95f3850SWill Newton 						"(status=%08x)\n",
1152f95f3850SWill Newton 						status);
1153f95f3850SWill Newton 					data->error = -EIO;
1154f95f3850SWill Newton 				}
115594dd5b33SJames Hogan 				/*
115694dd5b33SJames Hogan 				 * After an error, there may be data lingering
115794dd5b33SJames Hogan 				 * in the FIFO, so reset it - doing so
115894dd5b33SJames Hogan 				 * generates a block interrupt, hence setting
115994dd5b33SJames Hogan 				 * the scatter-gather pointer to NULL.
116094dd5b33SJames Hogan 				 */
1161f9c2a0dcSSeungwon Jeon 				sg_miter_stop(&host->sg_miter);
116294dd5b33SJames Hogan 				host->sg = NULL;
116394dd5b33SJames Hogan 				ctrl = mci_readl(host, CTRL);
116494dd5b33SJames Hogan 				ctrl |= SDMMC_CTRL_FIFO_RESET;
116594dd5b33SJames Hogan 				mci_writel(host, CTRL, ctrl);
1166f95f3850SWill Newton 			} else {
1167f95f3850SWill Newton 				data->bytes_xfered = data->blocks * data->blksz;
1168f95f3850SWill Newton 				data->error = 0;
1169f95f3850SWill Newton 			}
1170f95f3850SWill Newton 
1171f95f3850SWill Newton 			if (!data->stop) {
1172f95f3850SWill Newton 				dw_mci_request_end(host, host->mrq);
1173f95f3850SWill Newton 				goto unlock;
1174f95f3850SWill Newton 			}
1175f95f3850SWill Newton 
1176053b3ce6SSeungwon Jeon 			if (host->mrq->sbc && !data->error) {
1177053b3ce6SSeungwon Jeon 				data->stop->error = 0;
1178053b3ce6SSeungwon Jeon 				dw_mci_request_end(host, host->mrq);
1179053b3ce6SSeungwon Jeon 				goto unlock;
1180053b3ce6SSeungwon Jeon 			}
1181053b3ce6SSeungwon Jeon 
1182f95f3850SWill Newton 			prev_state = state = STATE_SENDING_STOP;
1183f95f3850SWill Newton 			if (!data->error)
1184f95f3850SWill Newton 				send_stop_cmd(host, data);
1185f95f3850SWill Newton 			/* fall through */
1186f95f3850SWill Newton 
1187f95f3850SWill Newton 		case STATE_SENDING_STOP:
1188f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1189f95f3850SWill Newton 						&host->pending_events))
1190f95f3850SWill Newton 				break;
1191f95f3850SWill Newton 
1192f95f3850SWill Newton 			host->cmd = NULL;
1193f95f3850SWill Newton 			dw_mci_command_complete(host, host->mrq->stop);
1194f95f3850SWill Newton 			dw_mci_request_end(host, host->mrq);
1195f95f3850SWill Newton 			goto unlock;
1196f95f3850SWill Newton 
1197f95f3850SWill Newton 		case STATE_DATA_ERROR:
1198f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1199f95f3850SWill Newton 						&host->pending_events))
1200f95f3850SWill Newton 				break;
1201f95f3850SWill Newton 
1202f95f3850SWill Newton 			state = STATE_DATA_BUSY;
1203f95f3850SWill Newton 			break;
1204f95f3850SWill Newton 		}
1205f95f3850SWill Newton 	} while (state != prev_state);
1206f95f3850SWill Newton 
1207f95f3850SWill Newton 	host->state = state;
1208f95f3850SWill Newton unlock:
1209f95f3850SWill Newton 	spin_unlock(&host->lock);
1210f95f3850SWill Newton 
1211f95f3850SWill Newton }
1212f95f3850SWill Newton 
121334b664a2SJames Hogan /* push final bytes to part_buf, only use during push */
121434b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt)
121534b664a2SJames Hogan {
121634b664a2SJames Hogan 	memcpy((void *)&host->part_buf, buf, cnt);
121734b664a2SJames Hogan 	host->part_buf_count = cnt;
121834b664a2SJames Hogan }
121934b664a2SJames Hogan 
122034b664a2SJames Hogan /* append bytes to part_buf, only use during push */
122134b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt)
122234b664a2SJames Hogan {
122334b664a2SJames Hogan 	cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count);
122434b664a2SJames Hogan 	memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt);
122534b664a2SJames Hogan 	host->part_buf_count += cnt;
122634b664a2SJames Hogan 	return cnt;
122734b664a2SJames Hogan }
122834b664a2SJames Hogan 
122934b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */
123034b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt)
123134b664a2SJames Hogan {
123234b664a2SJames Hogan 	cnt = min(cnt, (int)host->part_buf_count);
123334b664a2SJames Hogan 	if (cnt) {
123434b664a2SJames Hogan 		memcpy(buf, (void *)&host->part_buf + host->part_buf_start,
123534b664a2SJames Hogan 		       cnt);
123634b664a2SJames Hogan 		host->part_buf_count -= cnt;
123734b664a2SJames Hogan 		host->part_buf_start += cnt;
123834b664a2SJames Hogan 	}
123934b664a2SJames Hogan 	return cnt;
124034b664a2SJames Hogan }
124134b664a2SJames Hogan 
124234b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */
124334b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt)
124434b664a2SJames Hogan {
124534b664a2SJames Hogan 	memcpy(buf, &host->part_buf, cnt);
124634b664a2SJames Hogan 	host->part_buf_start = cnt;
124734b664a2SJames Hogan 	host->part_buf_count = (1 << host->data_shift) - cnt;
124834b664a2SJames Hogan }
124934b664a2SJames Hogan 
1250f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
1251f95f3850SWill Newton {
1252cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1253cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1254cfbeb59cSMarkos Chandras 
125534b664a2SJames Hogan 	/* try and push anything in the part_buf */
125634b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
125734b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
125834b664a2SJames Hogan 		buf += len;
125934b664a2SJames Hogan 		cnt -= len;
1260cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 2) {
12614e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
12624e0a5adfSJaehoon Chung 					host->part_buf16);
126334b664a2SJames Hogan 			host->part_buf_count = 0;
126434b664a2SJames Hogan 		}
126534b664a2SJames Hogan 	}
126634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
126734b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
126834b664a2SJames Hogan 		while (cnt >= 2) {
126934b664a2SJames Hogan 			u16 aligned_buf[64];
127034b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
127134b664a2SJames Hogan 			int items = len >> 1;
127234b664a2SJames Hogan 			int i;
127334b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
127434b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
127534b664a2SJames Hogan 			buf += len;
127634b664a2SJames Hogan 			cnt -= len;
127734b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
127834b664a2SJames Hogan 			for (i = 0; i < items; ++i)
12794e0a5adfSJaehoon Chung 				mci_writew(host, DATA(host->data_offset),
12804e0a5adfSJaehoon Chung 						aligned_buf[i]);
128134b664a2SJames Hogan 		}
128234b664a2SJames Hogan 	} else
128334b664a2SJames Hogan #endif
128434b664a2SJames Hogan 	{
128534b664a2SJames Hogan 		u16 *pdata = buf;
128634b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
12874e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset), *pdata++);
128834b664a2SJames Hogan 		buf = pdata;
128934b664a2SJames Hogan 	}
129034b664a2SJames Hogan 	/* put anything remaining in the part_buf */
129134b664a2SJames Hogan 	if (cnt) {
129234b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1293cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1294cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1295cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
12964e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
12974e0a5adfSJaehoon Chung 				   host->part_buf16);
1298f95f3850SWill Newton 	}
1299f95f3850SWill Newton }
1300f95f3850SWill Newton 
1301f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
1302f95f3850SWill Newton {
130334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
130434b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
130534b664a2SJames Hogan 		while (cnt >= 2) {
130634b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
130734b664a2SJames Hogan 			u16 aligned_buf[64];
130834b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
130934b664a2SJames Hogan 			int items = len >> 1;
131034b664a2SJames Hogan 			int i;
131134b664a2SJames Hogan 			for (i = 0; i < items; ++i)
13124e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readw(host,
13134e0a5adfSJaehoon Chung 						DATA(host->data_offset));
131434b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
131534b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
131634b664a2SJames Hogan 			buf += len;
131734b664a2SJames Hogan 			cnt -= len;
131834b664a2SJames Hogan 		}
131934b664a2SJames Hogan 	} else
132034b664a2SJames Hogan #endif
132134b664a2SJames Hogan 	{
132234b664a2SJames Hogan 		u16 *pdata = buf;
132334b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
13244e0a5adfSJaehoon Chung 			*pdata++ = mci_readw(host, DATA(host->data_offset));
132534b664a2SJames Hogan 		buf = pdata;
132634b664a2SJames Hogan 	}
132734b664a2SJames Hogan 	if (cnt) {
13284e0a5adfSJaehoon Chung 		host->part_buf16 = mci_readw(host, DATA(host->data_offset));
132934b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1330f95f3850SWill Newton 	}
1331f95f3850SWill Newton }
1332f95f3850SWill Newton 
1333f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
1334f95f3850SWill Newton {
1335cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1336cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1337cfbeb59cSMarkos Chandras 
133834b664a2SJames Hogan 	/* try and push anything in the part_buf */
133934b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
134034b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
134134b664a2SJames Hogan 		buf += len;
134234b664a2SJames Hogan 		cnt -= len;
1343cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 4) {
13444e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
13454e0a5adfSJaehoon Chung 					host->part_buf32);
134634b664a2SJames Hogan 			host->part_buf_count = 0;
134734b664a2SJames Hogan 		}
134834b664a2SJames Hogan 	}
134934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
135034b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
135134b664a2SJames Hogan 		while (cnt >= 4) {
135234b664a2SJames Hogan 			u32 aligned_buf[32];
135334b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
135434b664a2SJames Hogan 			int items = len >> 2;
135534b664a2SJames Hogan 			int i;
135634b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
135734b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
135834b664a2SJames Hogan 			buf += len;
135934b664a2SJames Hogan 			cnt -= len;
136034b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
136134b664a2SJames Hogan 			for (i = 0; i < items; ++i)
13624e0a5adfSJaehoon Chung 				mci_writel(host, DATA(host->data_offset),
13634e0a5adfSJaehoon Chung 						aligned_buf[i]);
136434b664a2SJames Hogan 		}
136534b664a2SJames Hogan 	} else
136634b664a2SJames Hogan #endif
136734b664a2SJames Hogan 	{
136834b664a2SJames Hogan 		u32 *pdata = buf;
136934b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
13704e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset), *pdata++);
137134b664a2SJames Hogan 		buf = pdata;
137234b664a2SJames Hogan 	}
137334b664a2SJames Hogan 	/* put anything remaining in the part_buf */
137434b664a2SJames Hogan 	if (cnt) {
137534b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1376cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1377cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1378cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
13794e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
13804e0a5adfSJaehoon Chung 				   host->part_buf32);
1381f95f3850SWill Newton 	}
1382f95f3850SWill Newton }
1383f95f3850SWill Newton 
1384f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
1385f95f3850SWill Newton {
138634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
138734b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
138834b664a2SJames Hogan 		while (cnt >= 4) {
138934b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
139034b664a2SJames Hogan 			u32 aligned_buf[32];
139134b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
139234b664a2SJames Hogan 			int items = len >> 2;
139334b664a2SJames Hogan 			int i;
139434b664a2SJames Hogan 			for (i = 0; i < items; ++i)
13954e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readl(host,
13964e0a5adfSJaehoon Chung 						DATA(host->data_offset));
139734b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
139834b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
139934b664a2SJames Hogan 			buf += len;
140034b664a2SJames Hogan 			cnt -= len;
140134b664a2SJames Hogan 		}
140234b664a2SJames Hogan 	} else
140334b664a2SJames Hogan #endif
140434b664a2SJames Hogan 	{
140534b664a2SJames Hogan 		u32 *pdata = buf;
140634b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
14074e0a5adfSJaehoon Chung 			*pdata++ = mci_readl(host, DATA(host->data_offset));
140834b664a2SJames Hogan 		buf = pdata;
140934b664a2SJames Hogan 	}
141034b664a2SJames Hogan 	if (cnt) {
14114e0a5adfSJaehoon Chung 		host->part_buf32 = mci_readl(host, DATA(host->data_offset));
141234b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1413f95f3850SWill Newton 	}
1414f95f3850SWill Newton }
1415f95f3850SWill Newton 
1416f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
1417f95f3850SWill Newton {
1418cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1419cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1420cfbeb59cSMarkos Chandras 
142134b664a2SJames Hogan 	/* try and push anything in the part_buf */
142234b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
142334b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
142434b664a2SJames Hogan 		buf += len;
142534b664a2SJames Hogan 		cnt -= len;
1426c09fbd74SSeungwon Jeon 
1427cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 8) {
1428c09fbd74SSeungwon Jeon 			mci_writeq(host, DATA(host->data_offset),
14294e0a5adfSJaehoon Chung 					host->part_buf);
143034b664a2SJames Hogan 			host->part_buf_count = 0;
143134b664a2SJames Hogan 		}
143234b664a2SJames Hogan 	}
143334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
143434b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
143534b664a2SJames Hogan 		while (cnt >= 8) {
143634b664a2SJames Hogan 			u64 aligned_buf[16];
143734b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
143834b664a2SJames Hogan 			int items = len >> 3;
143934b664a2SJames Hogan 			int i;
144034b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
144134b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
144234b664a2SJames Hogan 			buf += len;
144334b664a2SJames Hogan 			cnt -= len;
144434b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
144534b664a2SJames Hogan 			for (i = 0; i < items; ++i)
14464e0a5adfSJaehoon Chung 				mci_writeq(host, DATA(host->data_offset),
14474e0a5adfSJaehoon Chung 						aligned_buf[i]);
144834b664a2SJames Hogan 		}
144934b664a2SJames Hogan 	} else
145034b664a2SJames Hogan #endif
145134b664a2SJames Hogan 	{
145234b664a2SJames Hogan 		u64 *pdata = buf;
145334b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
14544e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset), *pdata++);
145534b664a2SJames Hogan 		buf = pdata;
145634b664a2SJames Hogan 	}
145734b664a2SJames Hogan 	/* put anything remaining in the part_buf */
145834b664a2SJames Hogan 	if (cnt) {
145934b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1460cfbeb59cSMarkos Chandras 		/* Push data if we have reached the expected data length */
1461cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1462cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
14634e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset),
14644e0a5adfSJaehoon Chung 				   host->part_buf);
1465f95f3850SWill Newton 	}
1466f95f3850SWill Newton }
1467f95f3850SWill Newton 
1468f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
1469f95f3850SWill Newton {
147034b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
147134b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
147234b664a2SJames Hogan 		while (cnt >= 8) {
147334b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
147434b664a2SJames Hogan 			u64 aligned_buf[16];
147534b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
147634b664a2SJames Hogan 			int items = len >> 3;
147734b664a2SJames Hogan 			int i;
147834b664a2SJames Hogan 			for (i = 0; i < items; ++i)
14794e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readq(host,
14804e0a5adfSJaehoon Chung 						DATA(host->data_offset));
148134b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
148234b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
148334b664a2SJames Hogan 			buf += len;
148434b664a2SJames Hogan 			cnt -= len;
1485f95f3850SWill Newton 		}
148634b664a2SJames Hogan 	} else
148734b664a2SJames Hogan #endif
148834b664a2SJames Hogan 	{
148934b664a2SJames Hogan 		u64 *pdata = buf;
149034b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
14914e0a5adfSJaehoon Chung 			*pdata++ = mci_readq(host, DATA(host->data_offset));
149234b664a2SJames Hogan 		buf = pdata;
149334b664a2SJames Hogan 	}
149434b664a2SJames Hogan 	if (cnt) {
14954e0a5adfSJaehoon Chung 		host->part_buf = mci_readq(host, DATA(host->data_offset));
149634b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
149734b664a2SJames Hogan 	}
149834b664a2SJames Hogan }
149934b664a2SJames Hogan 
150034b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
150134b664a2SJames Hogan {
150234b664a2SJames Hogan 	int len;
150334b664a2SJames Hogan 
150434b664a2SJames Hogan 	/* get remaining partial bytes */
150534b664a2SJames Hogan 	len = dw_mci_pull_part_bytes(host, buf, cnt);
150634b664a2SJames Hogan 	if (unlikely(len == cnt))
150734b664a2SJames Hogan 		return;
150834b664a2SJames Hogan 	buf += len;
150934b664a2SJames Hogan 	cnt -= len;
151034b664a2SJames Hogan 
151134b664a2SJames Hogan 	/* get the rest of the data */
151234b664a2SJames Hogan 	host->pull_data(host, buf, cnt);
1513f95f3850SWill Newton }
1514f95f3850SWill Newton 
151587a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto)
1516f95f3850SWill Newton {
1517f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1518f9c2a0dcSSeungwon Jeon 	void *buf;
1519f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1520f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1521f95f3850SWill Newton 	int shift = host->data_shift;
1522f95f3850SWill Newton 	u32 status;
15233e4b0d8bSMarkos Chandras 	unsigned int len;
1524f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1525f95f3850SWill Newton 
1526f95f3850SWill Newton 	do {
1527f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1528f9c2a0dcSSeungwon Jeon 			goto done;
1529f95f3850SWill Newton 
15304225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1531f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1532f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1533f9c2a0dcSSeungwon Jeon 		offset = 0;
1534f9c2a0dcSSeungwon Jeon 
1535f9c2a0dcSSeungwon Jeon 		do {
1536f9c2a0dcSSeungwon Jeon 			fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS))
1537f9c2a0dcSSeungwon Jeon 					<< shift) + host->part_buf_count;
1538f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1539f9c2a0dcSSeungwon Jeon 			if (!len)
1540f9c2a0dcSSeungwon Jeon 				break;
1541f9c2a0dcSSeungwon Jeon 			dw_mci_pull_data(host, (void *)(buf + offset), len);
15423e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1543f95f3850SWill Newton 			offset += len;
1544f9c2a0dcSSeungwon Jeon 			remain -= len;
1545f9c2a0dcSSeungwon Jeon 		} while (remain);
1546f95f3850SWill Newton 
1547e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1548f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1549f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
155087a74d39SKyoungil Kim 	/* if the RXDR is ready read again */
155187a74d39SKyoungil Kim 	} while ((status & SDMMC_INT_RXDR) ||
155287a74d39SKyoungil Kim 		 (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS))));
1553f9c2a0dcSSeungwon Jeon 
1554f9c2a0dcSSeungwon Jeon 	if (!remain) {
1555f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1556f9c2a0dcSSeungwon Jeon 			goto done;
1557f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1558f9c2a0dcSSeungwon Jeon 	}
1559f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1560f95f3850SWill Newton 	return;
1561f95f3850SWill Newton 
1562f95f3850SWill Newton done:
1563f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1564f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1565f95f3850SWill Newton 	smp_wmb();
1566f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1567f95f3850SWill Newton }
1568f95f3850SWill Newton 
1569f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host)
1570f95f3850SWill Newton {
1571f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1572f9c2a0dcSSeungwon Jeon 	void *buf;
1573f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1574f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1575f95f3850SWill Newton 	int shift = host->data_shift;
1576f95f3850SWill Newton 	u32 status;
15773e4b0d8bSMarkos Chandras 	unsigned int len;
1578f9c2a0dcSSeungwon Jeon 	unsigned int fifo_depth = host->fifo_depth;
1579f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1580f95f3850SWill Newton 
1581f95f3850SWill Newton 	do {
1582f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1583f9c2a0dcSSeungwon Jeon 			goto done;
1584f95f3850SWill Newton 
15854225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1586f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1587f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1588f9c2a0dcSSeungwon Jeon 		offset = 0;
1589f9c2a0dcSSeungwon Jeon 
1590f9c2a0dcSSeungwon Jeon 		do {
1591f9c2a0dcSSeungwon Jeon 			fcnt = ((fifo_depth -
1592f9c2a0dcSSeungwon Jeon 				 SDMMC_GET_FCNT(mci_readl(host, STATUS)))
1593f9c2a0dcSSeungwon Jeon 					<< shift) - host->part_buf_count;
1594f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1595f9c2a0dcSSeungwon Jeon 			if (!len)
1596f9c2a0dcSSeungwon Jeon 				break;
1597f9c2a0dcSSeungwon Jeon 			host->push_data(host, (void *)(buf + offset), len);
15983e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1599f95f3850SWill Newton 			offset += len;
1600f9c2a0dcSSeungwon Jeon 			remain -= len;
1601f9c2a0dcSSeungwon Jeon 		} while (remain);
1602f95f3850SWill Newton 
1603e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1604f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1605f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1606f95f3850SWill Newton 	} while (status & SDMMC_INT_TXDR); /* if TXDR write again */
1607f9c2a0dcSSeungwon Jeon 
1608f9c2a0dcSSeungwon Jeon 	if (!remain) {
1609f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1610f9c2a0dcSSeungwon Jeon 			goto done;
1611f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1612f9c2a0dcSSeungwon Jeon 	}
1613f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1614f95f3850SWill Newton 	return;
1615f95f3850SWill Newton 
1616f95f3850SWill Newton done:
1617f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1618f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1619f95f3850SWill Newton 	smp_wmb();
1620f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1621f95f3850SWill Newton }
1622f95f3850SWill Newton 
1623f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
1624f95f3850SWill Newton {
1625f95f3850SWill Newton 	if (!host->cmd_status)
1626f95f3850SWill Newton 		host->cmd_status = status;
1627f95f3850SWill Newton 
1628f95f3850SWill Newton 	smp_wmb();
1629f95f3850SWill Newton 
1630f95f3850SWill Newton 	set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1631f95f3850SWill Newton 	tasklet_schedule(&host->tasklet);
1632f95f3850SWill Newton }
1633f95f3850SWill Newton 
1634f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
1635f95f3850SWill Newton {
1636f95f3850SWill Newton 	struct dw_mci *host = dev_id;
1637182c9081SSeungwon Jeon 	u32 pending;
16381a5c8e1fSShashidhar Hiremath 	int i;
1639f95f3850SWill Newton 
1640f95f3850SWill Newton 	pending = mci_readl(host, MINTSTS); /* read-only mask reg */
1641f95f3850SWill Newton 
1642f95f3850SWill Newton 	/*
1643f95f3850SWill Newton 	 * DTO fix - version 2.10a and below, and only if internal DMA
1644f95f3850SWill Newton 	 * is configured.
1645f95f3850SWill Newton 	 */
1646f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
1647f95f3850SWill Newton 		if (!pending &&
1648f95f3850SWill Newton 		    ((mci_readl(host, STATUS) >> 17) & 0x1fff))
1649f95f3850SWill Newton 			pending |= SDMMC_INT_DATA_OVER;
1650f95f3850SWill Newton 	}
1651f95f3850SWill Newton 
1652476d79f1SDoug Anderson 	if (pending) {
1653f95f3850SWill Newton 		if (pending & DW_MCI_CMD_ERROR_FLAGS) {
1654f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
1655182c9081SSeungwon Jeon 			host->cmd_status = pending;
1656f95f3850SWill Newton 			smp_wmb();
1657f95f3850SWill Newton 			set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1658f95f3850SWill Newton 		}
1659f95f3850SWill Newton 
1660f95f3850SWill Newton 		if (pending & DW_MCI_DATA_ERROR_FLAGS) {
1661f95f3850SWill Newton 			/* if there is an error report DATA_ERROR */
1662f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
1663182c9081SSeungwon Jeon 			host->data_status = pending;
1664f95f3850SWill Newton 			smp_wmb();
1665f95f3850SWill Newton 			set_bit(EVENT_DATA_ERROR, &host->pending_events);
1666f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
1667f95f3850SWill Newton 		}
1668f95f3850SWill Newton 
1669f95f3850SWill Newton 		if (pending & SDMMC_INT_DATA_OVER) {
1670f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
1671f95f3850SWill Newton 			if (!host->data_status)
1672182c9081SSeungwon Jeon 				host->data_status = pending;
1673f95f3850SWill Newton 			smp_wmb();
1674f95f3850SWill Newton 			if (host->dir_status == DW_MCI_RECV_STATUS) {
1675f95f3850SWill Newton 				if (host->sg != NULL)
167687a74d39SKyoungil Kim 					dw_mci_read_data_pio(host, true);
1677f95f3850SWill Newton 			}
1678f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
1679f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
1680f95f3850SWill Newton 		}
1681f95f3850SWill Newton 
1682f95f3850SWill Newton 		if (pending & SDMMC_INT_RXDR) {
1683f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
1684b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_RECV_STATUS && host->sg)
168587a74d39SKyoungil Kim 				dw_mci_read_data_pio(host, false);
1686f95f3850SWill Newton 		}
1687f95f3850SWill Newton 
1688f95f3850SWill Newton 		if (pending & SDMMC_INT_TXDR) {
1689f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1690b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_SEND_STATUS && host->sg)
1691f95f3850SWill Newton 				dw_mci_write_data_pio(host);
1692f95f3850SWill Newton 		}
1693f95f3850SWill Newton 
1694f95f3850SWill Newton 		if (pending & SDMMC_INT_CMD_DONE) {
1695f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
1696182c9081SSeungwon Jeon 			dw_mci_cmd_interrupt(host, pending);
1697f95f3850SWill Newton 		}
1698f95f3850SWill Newton 
1699f95f3850SWill Newton 		if (pending & SDMMC_INT_CD) {
1700f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CD);
170195dcc2cbSThomas Abraham 			queue_work(host->card_workqueue, &host->card_work);
1702f95f3850SWill Newton 		}
1703f95f3850SWill Newton 
17041a5c8e1fSShashidhar Hiremath 		/* Handle SDIO Interrupts */
17051a5c8e1fSShashidhar Hiremath 		for (i = 0; i < host->num_slots; i++) {
17061a5c8e1fSShashidhar Hiremath 			struct dw_mci_slot *slot = host->slot[i];
17071a5c8e1fSShashidhar Hiremath 			if (pending & SDMMC_INT_SDIO(i)) {
17081a5c8e1fSShashidhar Hiremath 				mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
17091a5c8e1fSShashidhar Hiremath 				mmc_signal_sdio_irq(slot->mmc);
17101a5c8e1fSShashidhar Hiremath 			}
17111a5c8e1fSShashidhar Hiremath 		}
17121a5c8e1fSShashidhar Hiremath 
17131fb5f68aSMarkos Chandras 	}
1714f95f3850SWill Newton 
1715f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
1716f95f3850SWill Newton 	/* Handle DMA interrupts */
1717f95f3850SWill Newton 	pending = mci_readl(host, IDSTS);
1718f95f3850SWill Newton 	if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
1719f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
1720f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
1721f95f3850SWill Newton 		host->dma_ops->complete(host);
1722f95f3850SWill Newton 	}
1723f95f3850SWill Newton #endif
1724f95f3850SWill Newton 
1725f95f3850SWill Newton 	return IRQ_HANDLED;
1726f95f3850SWill Newton }
1727f95f3850SWill Newton 
17281791b13eSJames Hogan static void dw_mci_work_routine_card(struct work_struct *work)
1729f95f3850SWill Newton {
17301791b13eSJames Hogan 	struct dw_mci *host = container_of(work, struct dw_mci, card_work);
1731f95f3850SWill Newton 	int i;
1732f95f3850SWill Newton 
1733f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
1734f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
1735f95f3850SWill Newton 		struct mmc_host *mmc = slot->mmc;
1736f95f3850SWill Newton 		struct mmc_request *mrq;
1737f95f3850SWill Newton 		int present;
1738f95f3850SWill Newton 		u32 ctrl;
1739f95f3850SWill Newton 
1740f95f3850SWill Newton 		present = dw_mci_get_cd(mmc);
1741f95f3850SWill Newton 		while (present != slot->last_detect_state) {
1742f95f3850SWill Newton 			dev_dbg(&slot->mmc->class_dev, "card %s\n",
1743f95f3850SWill Newton 				present ? "inserted" : "removed");
1744f95f3850SWill Newton 
17451791b13eSJames Hogan 			spin_lock_bh(&host->lock);
17461791b13eSJames Hogan 
1747f95f3850SWill Newton 			/* Card change detected */
1748f95f3850SWill Newton 			slot->last_detect_state = present;
1749f95f3850SWill Newton 
17501791b13eSJames Hogan 			/* Mark card as present if applicable */
17511791b13eSJames Hogan 			if (present != 0)
1752f95f3850SWill Newton 				set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
1753f95f3850SWill Newton 
1754f95f3850SWill Newton 			/* Clean up queue if present */
1755f95f3850SWill Newton 			mrq = slot->mrq;
1756f95f3850SWill Newton 			if (mrq) {
1757f95f3850SWill Newton 				if (mrq == host->mrq) {
1758f95f3850SWill Newton 					host->data = NULL;
1759f95f3850SWill Newton 					host->cmd = NULL;
1760f95f3850SWill Newton 
1761f95f3850SWill Newton 					switch (host->state) {
1762f95f3850SWill Newton 					case STATE_IDLE:
1763f95f3850SWill Newton 						break;
1764f95f3850SWill Newton 					case STATE_SENDING_CMD:
1765f95f3850SWill Newton 						mrq->cmd->error = -ENOMEDIUM;
1766f95f3850SWill Newton 						if (!mrq->data)
1767f95f3850SWill Newton 							break;
1768f95f3850SWill Newton 						/* fall through */
1769f95f3850SWill Newton 					case STATE_SENDING_DATA:
1770f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
1771f95f3850SWill Newton 						dw_mci_stop_dma(host);
1772f95f3850SWill Newton 						break;
1773f95f3850SWill Newton 					case STATE_DATA_BUSY:
1774f95f3850SWill Newton 					case STATE_DATA_ERROR:
1775f95f3850SWill Newton 						if (mrq->data->error == -EINPROGRESS)
1776f95f3850SWill Newton 							mrq->data->error = -ENOMEDIUM;
1777f95f3850SWill Newton 						if (!mrq->stop)
1778f95f3850SWill Newton 							break;
1779f95f3850SWill Newton 						/* fall through */
1780f95f3850SWill Newton 					case STATE_SENDING_STOP:
1781f95f3850SWill Newton 						mrq->stop->error = -ENOMEDIUM;
1782f95f3850SWill Newton 						break;
1783f95f3850SWill Newton 					}
1784f95f3850SWill Newton 
1785f95f3850SWill Newton 					dw_mci_request_end(host, mrq);
1786f95f3850SWill Newton 				} else {
1787f95f3850SWill Newton 					list_del(&slot->queue_node);
1788f95f3850SWill Newton 					mrq->cmd->error = -ENOMEDIUM;
1789f95f3850SWill Newton 					if (mrq->data)
1790f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
1791f95f3850SWill Newton 					if (mrq->stop)
1792f95f3850SWill Newton 						mrq->stop->error = -ENOMEDIUM;
1793f95f3850SWill Newton 
1794f95f3850SWill Newton 					spin_unlock(&host->lock);
1795f95f3850SWill Newton 					mmc_request_done(slot->mmc, mrq);
1796f95f3850SWill Newton 					spin_lock(&host->lock);
1797f95f3850SWill Newton 				}
1798f95f3850SWill Newton 			}
1799f95f3850SWill Newton 
1800f95f3850SWill Newton 			/* Power down slot */
1801f95f3850SWill Newton 			if (present == 0) {
1802f95f3850SWill Newton 				clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
1803f95f3850SWill Newton 
1804f95f3850SWill Newton 				/*
1805f95f3850SWill Newton 				 * Clear down the FIFO - doing so generates a
1806f95f3850SWill Newton 				 * block interrupt, hence setting the
1807f95f3850SWill Newton 				 * scatter-gather pointer to NULL.
1808f95f3850SWill Newton 				 */
1809f9c2a0dcSSeungwon Jeon 				sg_miter_stop(&host->sg_miter);
1810f95f3850SWill Newton 				host->sg = NULL;
1811f95f3850SWill Newton 
1812f95f3850SWill Newton 				ctrl = mci_readl(host, CTRL);
1813f95f3850SWill Newton 				ctrl |= SDMMC_CTRL_FIFO_RESET;
1814f95f3850SWill Newton 				mci_writel(host, CTRL, ctrl);
1815f95f3850SWill Newton 
1816f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
1817f95f3850SWill Newton 				ctrl = mci_readl(host, BMOD);
1818141a712aSSeungwon Jeon 				/* Software reset of DMA */
1819141a712aSSeungwon Jeon 				ctrl |= SDMMC_IDMAC_SWRESET;
1820f95f3850SWill Newton 				mci_writel(host, BMOD, ctrl);
1821f95f3850SWill Newton #endif
1822f95f3850SWill Newton 
1823f95f3850SWill Newton 			}
1824f95f3850SWill Newton 
18251791b13eSJames Hogan 			spin_unlock_bh(&host->lock);
18261791b13eSJames Hogan 
1827f95f3850SWill Newton 			present = dw_mci_get_cd(mmc);
1828f95f3850SWill Newton 		}
1829f95f3850SWill Newton 
1830f95f3850SWill Newton 		mmc_detect_change(slot->mmc,
1831f95f3850SWill Newton 			msecs_to_jiffies(host->pdata->detect_delay_ms));
1832f95f3850SWill Newton 	}
1833f95f3850SWill Newton }
1834f95f3850SWill Newton 
1835c91eab4bSThomas Abraham #ifdef CONFIG_OF
1836c91eab4bSThomas Abraham /* given a slot id, find out the device node representing that slot */
1837c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
1838c91eab4bSThomas Abraham {
1839c91eab4bSThomas Abraham 	struct device_node *np;
1840c91eab4bSThomas Abraham 	const __be32 *addr;
1841c91eab4bSThomas Abraham 	int len;
1842c91eab4bSThomas Abraham 
1843c91eab4bSThomas Abraham 	if (!dev || !dev->of_node)
1844c91eab4bSThomas Abraham 		return NULL;
1845c91eab4bSThomas Abraham 
1846c91eab4bSThomas Abraham 	for_each_child_of_node(dev->of_node, np) {
1847c91eab4bSThomas Abraham 		addr = of_get_property(np, "reg", &len);
1848c91eab4bSThomas Abraham 		if (!addr || (len < sizeof(int)))
1849c91eab4bSThomas Abraham 			continue;
1850c91eab4bSThomas Abraham 		if (be32_to_cpup(addr) == slot)
1851c91eab4bSThomas Abraham 			return np;
1852c91eab4bSThomas Abraham 	}
1853c91eab4bSThomas Abraham 	return NULL;
1854c91eab4bSThomas Abraham }
1855c91eab4bSThomas Abraham 
1856a70aaa64SDoug Anderson static struct dw_mci_of_slot_quirks {
1857a70aaa64SDoug Anderson 	char *quirk;
1858a70aaa64SDoug Anderson 	int id;
1859a70aaa64SDoug Anderson } of_slot_quirks[] = {
1860a70aaa64SDoug Anderson 	{
1861a70aaa64SDoug Anderson 		.quirk	= "disable-wp",
1862a70aaa64SDoug Anderson 		.id	= DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT,
1863a70aaa64SDoug Anderson 	},
1864a70aaa64SDoug Anderson };
1865a70aaa64SDoug Anderson 
1866a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
1867a70aaa64SDoug Anderson {
1868a70aaa64SDoug Anderson 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
1869a70aaa64SDoug Anderson 	int quirks = 0;
1870a70aaa64SDoug Anderson 	int idx;
1871a70aaa64SDoug Anderson 
1872a70aaa64SDoug Anderson 	/* get quirks */
1873a70aaa64SDoug Anderson 	for (idx = 0; idx < ARRAY_SIZE(of_slot_quirks); idx++)
1874a70aaa64SDoug Anderson 		if (of_get_property(np, of_slot_quirks[idx].quirk, NULL))
1875a70aaa64SDoug Anderson 			quirks |= of_slot_quirks[idx].id;
1876a70aaa64SDoug Anderson 
1877a70aaa64SDoug Anderson 	return quirks;
1878a70aaa64SDoug Anderson }
1879a70aaa64SDoug Anderson 
1880c91eab4bSThomas Abraham /* find out bus-width for a given slot */
1881c91eab4bSThomas Abraham static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
1882c91eab4bSThomas Abraham {
1883c91eab4bSThomas Abraham 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
1884c91eab4bSThomas Abraham 	u32 bus_wd = 1;
1885c91eab4bSThomas Abraham 
1886c91eab4bSThomas Abraham 	if (!np)
1887c91eab4bSThomas Abraham 		return 1;
1888c91eab4bSThomas Abraham 
1889c91eab4bSThomas Abraham 	if (of_property_read_u32(np, "bus-width", &bus_wd))
1890c91eab4bSThomas Abraham 		dev_err(dev, "bus-width property not found, assuming width"
1891c91eab4bSThomas Abraham 			       " as 1\n");
1892c91eab4bSThomas Abraham 	return bus_wd;
1893c91eab4bSThomas Abraham }
189455a6ceb2SDoug Anderson 
189555a6ceb2SDoug Anderson /* find the write protect gpio for a given slot; or -1 if none specified */
189655a6ceb2SDoug Anderson static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
189755a6ceb2SDoug Anderson {
189855a6ceb2SDoug Anderson 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
189955a6ceb2SDoug Anderson 	int gpio;
190055a6ceb2SDoug Anderson 
190155a6ceb2SDoug Anderson 	if (!np)
190255a6ceb2SDoug Anderson 		return -EINVAL;
190355a6ceb2SDoug Anderson 
190455a6ceb2SDoug Anderson 	gpio = of_get_named_gpio(np, "wp-gpios", 0);
190555a6ceb2SDoug Anderson 
190655a6ceb2SDoug Anderson 	/* Having a missing entry is valid; return silently */
190755a6ceb2SDoug Anderson 	if (!gpio_is_valid(gpio))
190855a6ceb2SDoug Anderson 		return -EINVAL;
190955a6ceb2SDoug Anderson 
191055a6ceb2SDoug Anderson 	if (devm_gpio_request(dev, gpio, "dw-mci-wp")) {
191155a6ceb2SDoug Anderson 		dev_warn(dev, "gpio [%d] request failed\n", gpio);
191255a6ceb2SDoug Anderson 		return -EINVAL;
191355a6ceb2SDoug Anderson 	}
191455a6ceb2SDoug Anderson 
191555a6ceb2SDoug Anderson 	return gpio;
191655a6ceb2SDoug Anderson }
1917c91eab4bSThomas Abraham #else /* CONFIG_OF */
1918a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
1919a70aaa64SDoug Anderson {
1920a70aaa64SDoug Anderson 	return 0;
1921a70aaa64SDoug Anderson }
1922c91eab4bSThomas Abraham static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
1923c91eab4bSThomas Abraham {
1924c91eab4bSThomas Abraham 	return 1;
1925c91eab4bSThomas Abraham }
1926c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
1927c91eab4bSThomas Abraham {
1928c91eab4bSThomas Abraham 	return NULL;
1929c91eab4bSThomas Abraham }
193055a6ceb2SDoug Anderson static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
193155a6ceb2SDoug Anderson {
193255a6ceb2SDoug Anderson 	return -EINVAL;
193355a6ceb2SDoug Anderson }
1934c91eab4bSThomas Abraham #endif /* CONFIG_OF */
1935c91eab4bSThomas Abraham 
193636c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
1937f95f3850SWill Newton {
1938f95f3850SWill Newton 	struct mmc_host *mmc;
1939f95f3850SWill Newton 	struct dw_mci_slot *slot;
1940e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
1941800d78bfSThomas Abraham 	int ctrl_id, ret;
1942*1f44a2a5SSeungwon Jeon 	u32 freq[2];
1943c91eab4bSThomas Abraham 	u8 bus_width;
1944f95f3850SWill Newton 
19454a90920cSThomas Abraham 	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
1946f95f3850SWill Newton 	if (!mmc)
1947f95f3850SWill Newton 		return -ENOMEM;
1948f95f3850SWill Newton 
1949f95f3850SWill Newton 	slot = mmc_priv(mmc);
1950f95f3850SWill Newton 	slot->id = id;
1951f95f3850SWill Newton 	slot->mmc = mmc;
1952f95f3850SWill Newton 	slot->host = host;
1953c91eab4bSThomas Abraham 	host->slot[id] = slot;
1954f95f3850SWill Newton 
1955a70aaa64SDoug Anderson 	slot->quirks = dw_mci_of_get_slot_quirks(host->dev, slot->id);
1956a70aaa64SDoug Anderson 
1957f95f3850SWill Newton 	mmc->ops = &dw_mci_ops;
1958*1f44a2a5SSeungwon Jeon 	if (of_property_read_u32_array(host->dev->of_node,
1959*1f44a2a5SSeungwon Jeon 				       "clock-freq-min-max", freq, 2)) {
1960*1f44a2a5SSeungwon Jeon 		mmc->f_min = DW_MCI_FREQ_MIN;
1961*1f44a2a5SSeungwon Jeon 		mmc->f_max = DW_MCI_FREQ_MAX;
1962*1f44a2a5SSeungwon Jeon 	} else {
1963*1f44a2a5SSeungwon Jeon 		mmc->f_min = freq[0];
1964*1f44a2a5SSeungwon Jeon 		mmc->f_max = freq[1];
1965*1f44a2a5SSeungwon Jeon 	}
1966f95f3850SWill Newton 
1967f95f3850SWill Newton 	if (host->pdata->get_ocr)
1968f95f3850SWill Newton 		mmc->ocr_avail = host->pdata->get_ocr(id);
1969f95f3850SWill Newton 	else
1970f95f3850SWill Newton 		mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
1971f95f3850SWill Newton 
1972f95f3850SWill Newton 	/*
1973f95f3850SWill Newton 	 * Start with slot power disabled, it will be enabled when a card
1974f95f3850SWill Newton 	 * is detected.
1975f95f3850SWill Newton 	 */
1976f95f3850SWill Newton 	if (host->pdata->setpower)
1977f95f3850SWill Newton 		host->pdata->setpower(id, 0);
1978f95f3850SWill Newton 
1979fc3d7720SJaehoon Chung 	if (host->pdata->caps)
1980fc3d7720SJaehoon Chung 		mmc->caps = host->pdata->caps;
1981fc3d7720SJaehoon Chung 
1982ab269128SAbhilash Kesavan 	if (host->pdata->pm_caps)
1983ab269128SAbhilash Kesavan 		mmc->pm_caps = host->pdata->pm_caps;
1984ab269128SAbhilash Kesavan 
1985800d78bfSThomas Abraham 	if (host->dev->of_node) {
1986800d78bfSThomas Abraham 		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
1987800d78bfSThomas Abraham 		if (ctrl_id < 0)
1988800d78bfSThomas Abraham 			ctrl_id = 0;
1989800d78bfSThomas Abraham 	} else {
1990800d78bfSThomas Abraham 		ctrl_id = to_platform_device(host->dev)->id;
1991800d78bfSThomas Abraham 	}
1992cb27a843SJames Hogan 	if (drv_data && drv_data->caps)
1993cb27a843SJames Hogan 		mmc->caps |= drv_data->caps[ctrl_id];
1994800d78bfSThomas Abraham 
19954f408cc6SSeungwon Jeon 	if (host->pdata->caps2)
19964f408cc6SSeungwon Jeon 		mmc->caps2 = host->pdata->caps2;
19974f408cc6SSeungwon Jeon 
1998f95f3850SWill Newton 	if (host->pdata->get_bus_wd)
1999c91eab4bSThomas Abraham 		bus_width = host->pdata->get_bus_wd(slot->id);
2000c91eab4bSThomas Abraham 	else if (host->dev->of_node)
2001c91eab4bSThomas Abraham 		bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
2002c91eab4bSThomas Abraham 	else
2003c91eab4bSThomas Abraham 		bus_width = 1;
2004c91eab4bSThomas Abraham 
2005c91eab4bSThomas Abraham 	switch (bus_width) {
2006c91eab4bSThomas Abraham 	case 8:
2007c91eab4bSThomas Abraham 		mmc->caps |= MMC_CAP_8_BIT_DATA;
2008c91eab4bSThomas Abraham 	case 4:
2009f95f3850SWill Newton 		mmc->caps |= MMC_CAP_4_BIT_DATA;
2010c91eab4bSThomas Abraham 	}
2011f95f3850SWill Newton 
2012f95f3850SWill Newton 	if (host->pdata->blk_settings) {
2013f95f3850SWill Newton 		mmc->max_segs = host->pdata->blk_settings->max_segs;
2014f95f3850SWill Newton 		mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
2015f95f3850SWill Newton 		mmc->max_blk_count = host->pdata->blk_settings->max_blk_count;
2016f95f3850SWill Newton 		mmc->max_req_size = host->pdata->blk_settings->max_req_size;
2017f95f3850SWill Newton 		mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
2018f95f3850SWill Newton 	} else {
2019f95f3850SWill Newton 		/* Useful defaults if platform data is unset. */
2020a39e5746SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
2021a39e5746SJaehoon Chung 		mmc->max_segs = host->ring_size;
2022a39e5746SJaehoon Chung 		mmc->max_blk_size = 65536;
2023a39e5746SJaehoon Chung 		mmc->max_blk_count = host->ring_size;
2024a39e5746SJaehoon Chung 		mmc->max_seg_size = 0x1000;
2025a39e5746SJaehoon Chung 		mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
2026a39e5746SJaehoon Chung #else
2027f95f3850SWill Newton 		mmc->max_segs = 64;
2028f95f3850SWill Newton 		mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
2029f95f3850SWill Newton 		mmc->max_blk_count = 512;
2030f95f3850SWill Newton 		mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
2031f95f3850SWill Newton 		mmc->max_seg_size = mmc->max_req_size;
2032f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */
2033a39e5746SJaehoon Chung 	}
2034f95f3850SWill Newton 
2035f95f3850SWill Newton 	if (dw_mci_get_cd(mmc))
2036f95f3850SWill Newton 		set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
2037f95f3850SWill Newton 	else
2038f95f3850SWill Newton 		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
2039f95f3850SWill Newton 
204055a6ceb2SDoug Anderson 	slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id);
204155a6ceb2SDoug Anderson 
20420cea529dSJaehoon Chung 	ret = mmc_add_host(mmc);
20430cea529dSJaehoon Chung 	if (ret)
20440cea529dSJaehoon Chung 		goto err_setup_bus;
2045f95f3850SWill Newton 
2046f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS)
2047f95f3850SWill Newton 	dw_mci_init_debugfs(slot);
2048f95f3850SWill Newton #endif
2049f95f3850SWill Newton 
2050f95f3850SWill Newton 	/* Card initially undetected */
2051f95f3850SWill Newton 	slot->last_detect_state = 0;
2052f95f3850SWill Newton 
2053f95f3850SWill Newton 	return 0;
2054800d78bfSThomas Abraham 
2055800d78bfSThomas Abraham err_setup_bus:
2056800d78bfSThomas Abraham 	mmc_free_host(mmc);
2057800d78bfSThomas Abraham 	return -EINVAL;
2058f95f3850SWill Newton }
2059f95f3850SWill Newton 
2060f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
2061f95f3850SWill Newton {
2062f95f3850SWill Newton 	/* Shutdown detect IRQ */
2063f95f3850SWill Newton 	if (slot->host->pdata->exit)
2064f95f3850SWill Newton 		slot->host->pdata->exit(id);
2065f95f3850SWill Newton 
2066f95f3850SWill Newton 	/* Debugfs stuff is cleaned up by mmc core */
2067f95f3850SWill Newton 	mmc_remove_host(slot->mmc);
2068f95f3850SWill Newton 	slot->host->slot[id] = NULL;
2069f95f3850SWill Newton 	mmc_free_host(slot->mmc);
2070f95f3850SWill Newton }
2071f95f3850SWill Newton 
2072f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host)
2073f95f3850SWill Newton {
2074f95f3850SWill Newton 	/* Alloc memory for sg translation */
2075780f22afSSeungwon Jeon 	host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
2076f95f3850SWill Newton 					  &host->sg_dma, GFP_KERNEL);
2077f95f3850SWill Newton 	if (!host->sg_cpu) {
20784a90920cSThomas Abraham 		dev_err(host->dev, "%s: could not alloc DMA memory\n",
2079f95f3850SWill Newton 			__func__);
2080f95f3850SWill Newton 		goto no_dma;
2081f95f3850SWill Newton 	}
2082f95f3850SWill Newton 
2083f95f3850SWill Newton 	/* Determine which DMA interface to use */
2084f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
2085f95f3850SWill Newton 	host->dma_ops = &dw_mci_idmac_ops;
208600956ea3SSeungwon Jeon 	dev_info(host->dev, "Using internal DMA controller.\n");
2087f95f3850SWill Newton #endif
2088f95f3850SWill Newton 
2089f95f3850SWill Newton 	if (!host->dma_ops)
2090f95f3850SWill Newton 		goto no_dma;
2091f95f3850SWill Newton 
2092e1631f98SJaehoon Chung 	if (host->dma_ops->init && host->dma_ops->start &&
2093e1631f98SJaehoon Chung 	    host->dma_ops->stop && host->dma_ops->cleanup) {
2094f95f3850SWill Newton 		if (host->dma_ops->init(host)) {
20954a90920cSThomas Abraham 			dev_err(host->dev, "%s: Unable to initialize "
2096f95f3850SWill Newton 				"DMA Controller.\n", __func__);
2097f95f3850SWill Newton 			goto no_dma;
2098f95f3850SWill Newton 		}
2099f95f3850SWill Newton 	} else {
21004a90920cSThomas Abraham 		dev_err(host->dev, "DMA initialization not found.\n");
2101f95f3850SWill Newton 		goto no_dma;
2102f95f3850SWill Newton 	}
2103f95f3850SWill Newton 
2104f95f3850SWill Newton 	host->use_dma = 1;
2105f95f3850SWill Newton 	return;
2106f95f3850SWill Newton 
2107f95f3850SWill Newton no_dma:
21084a90920cSThomas Abraham 	dev_info(host->dev, "Using PIO mode.\n");
2109f95f3850SWill Newton 	host->use_dma = 0;
2110f95f3850SWill Newton 	return;
2111f95f3850SWill Newton }
2112f95f3850SWill Newton 
2113f95f3850SWill Newton static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
2114f95f3850SWill Newton {
2115f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
2116f95f3850SWill Newton 	unsigned int ctrl;
2117f95f3850SWill Newton 
2118f95f3850SWill Newton 	mci_writel(host, CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET |
2119f95f3850SWill Newton 				SDMMC_CTRL_DMA_RESET));
2120f95f3850SWill Newton 
2121f95f3850SWill Newton 	/* wait till resets clear */
2122f95f3850SWill Newton 	do {
2123f95f3850SWill Newton 		ctrl = mci_readl(host, CTRL);
2124f95f3850SWill Newton 		if (!(ctrl & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET |
2125f95f3850SWill Newton 			      SDMMC_CTRL_DMA_RESET)))
2126f95f3850SWill Newton 			return true;
2127f95f3850SWill Newton 	} while (time_before(jiffies, timeout));
2128f95f3850SWill Newton 
2129f95f3850SWill Newton 	dev_err(dev, "Timeout resetting block (ctrl %#x)\n", ctrl);
2130f95f3850SWill Newton 
2131f95f3850SWill Newton 	return false;
2132f95f3850SWill Newton }
2133f95f3850SWill Newton 
2134c91eab4bSThomas Abraham #ifdef CONFIG_OF
2135c91eab4bSThomas Abraham static struct dw_mci_of_quirks {
2136c91eab4bSThomas Abraham 	char *quirk;
2137c91eab4bSThomas Abraham 	int id;
2138c91eab4bSThomas Abraham } of_quirks[] = {
2139c91eab4bSThomas Abraham 	{
2140c91eab4bSThomas Abraham 		.quirk	= "broken-cd",
2141c91eab4bSThomas Abraham 		.id	= DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
2142c91eab4bSThomas Abraham 	},
2143c91eab4bSThomas Abraham };
2144c91eab4bSThomas Abraham 
2145c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2146c91eab4bSThomas Abraham {
2147c91eab4bSThomas Abraham 	struct dw_mci_board *pdata;
2148c91eab4bSThomas Abraham 	struct device *dev = host->dev;
2149c91eab4bSThomas Abraham 	struct device_node *np = dev->of_node;
2150e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
2151800d78bfSThomas Abraham 	int idx, ret;
21523c6d89eaSDoug Anderson 	u32 clock_frequency;
2153c91eab4bSThomas Abraham 
2154c91eab4bSThomas Abraham 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
2155c91eab4bSThomas Abraham 	if (!pdata) {
2156c91eab4bSThomas Abraham 		dev_err(dev, "could not allocate memory for pdata\n");
2157c91eab4bSThomas Abraham 		return ERR_PTR(-ENOMEM);
2158c91eab4bSThomas Abraham 	}
2159c91eab4bSThomas Abraham 
2160c91eab4bSThomas Abraham 	/* find out number of slots supported */
2161c91eab4bSThomas Abraham 	if (of_property_read_u32(dev->of_node, "num-slots",
2162c91eab4bSThomas Abraham 				&pdata->num_slots)) {
2163c91eab4bSThomas Abraham 		dev_info(dev, "num-slots property not found, "
2164c91eab4bSThomas Abraham 				"assuming 1 slot is available\n");
2165c91eab4bSThomas Abraham 		pdata->num_slots = 1;
2166c91eab4bSThomas Abraham 	}
2167c91eab4bSThomas Abraham 
2168c91eab4bSThomas Abraham 	/* get quirks */
2169c91eab4bSThomas Abraham 	for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++)
2170c91eab4bSThomas Abraham 		if (of_get_property(np, of_quirks[idx].quirk, NULL))
2171c91eab4bSThomas Abraham 			pdata->quirks |= of_quirks[idx].id;
2172c91eab4bSThomas Abraham 
2173c91eab4bSThomas Abraham 	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
2174c91eab4bSThomas Abraham 		dev_info(dev, "fifo-depth property not found, using "
2175c91eab4bSThomas Abraham 				"value of FIFOTH register as default\n");
2176c91eab4bSThomas Abraham 
2177c91eab4bSThomas Abraham 	of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
2178c91eab4bSThomas Abraham 
21793c6d89eaSDoug Anderson 	if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
21803c6d89eaSDoug Anderson 		pdata->bus_hz = clock_frequency;
21813c6d89eaSDoug Anderson 
2182cb27a843SJames Hogan 	if (drv_data && drv_data->parse_dt) {
2183cb27a843SJames Hogan 		ret = drv_data->parse_dt(host);
2184800d78bfSThomas Abraham 		if (ret)
2185800d78bfSThomas Abraham 			return ERR_PTR(ret);
2186800d78bfSThomas Abraham 	}
2187800d78bfSThomas Abraham 
2188ab269128SAbhilash Kesavan 	if (of_find_property(np, "keep-power-in-suspend", NULL))
2189ab269128SAbhilash Kesavan 		pdata->pm_caps |= MMC_PM_KEEP_POWER;
2190ab269128SAbhilash Kesavan 
2191ab269128SAbhilash Kesavan 	if (of_find_property(np, "enable-sdio-wakeup", NULL))
2192ab269128SAbhilash Kesavan 		pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
2193ab269128SAbhilash Kesavan 
219410b49841SSeungwon Jeon 	if (of_find_property(np, "supports-highspeed", NULL))
219510b49841SSeungwon Jeon 		pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
219610b49841SSeungwon Jeon 
21975dd63f52SSeungwon Jeon 	if (of_find_property(np, "caps2-mmc-hs200-1_8v", NULL))
21985dd63f52SSeungwon Jeon 		pdata->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
21995dd63f52SSeungwon Jeon 
22005dd63f52SSeungwon Jeon 	if (of_find_property(np, "caps2-mmc-hs200-1_2v", NULL))
22015dd63f52SSeungwon Jeon 		pdata->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
22025dd63f52SSeungwon Jeon 
2203c91eab4bSThomas Abraham 	return pdata;
2204c91eab4bSThomas Abraham }
2205c91eab4bSThomas Abraham 
2206c91eab4bSThomas Abraham #else /* CONFIG_OF */
2207c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2208c91eab4bSThomas Abraham {
2209c91eab4bSThomas Abraham 	return ERR_PTR(-EINVAL);
2210c91eab4bSThomas Abraham }
2211c91eab4bSThomas Abraham #endif /* CONFIG_OF */
2212c91eab4bSThomas Abraham 
221362ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host)
2214f95f3850SWill Newton {
2215e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
221662ca8034SShashidhar Hiremath 	int width, i, ret = 0;
2217f95f3850SWill Newton 	u32 fifo_size;
22181c2215b7SThomas Abraham 	int init_slots = 0;
2219f95f3850SWill Newton 
2220c91eab4bSThomas Abraham 	if (!host->pdata) {
2221c91eab4bSThomas Abraham 		host->pdata = dw_mci_parse_dt(host);
2222c91eab4bSThomas Abraham 		if (IS_ERR(host->pdata)) {
2223c91eab4bSThomas Abraham 			dev_err(host->dev, "platform data not available\n");
2224c91eab4bSThomas Abraham 			return -EINVAL;
2225c91eab4bSThomas Abraham 		}
2226f95f3850SWill Newton 	}
2227f95f3850SWill Newton 
222862ca8034SShashidhar Hiremath 	if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
22294a90920cSThomas Abraham 		dev_err(host->dev,
2230f95f3850SWill Newton 			"Platform data must supply select_slot function\n");
223162ca8034SShashidhar Hiremath 		return -ENODEV;
2232f95f3850SWill Newton 	}
2233f95f3850SWill Newton 
2234780f22afSSeungwon Jeon 	host->biu_clk = devm_clk_get(host->dev, "biu");
2235f90a0612SThomas Abraham 	if (IS_ERR(host->biu_clk)) {
2236f90a0612SThomas Abraham 		dev_dbg(host->dev, "biu clock not available\n");
2237f90a0612SThomas Abraham 	} else {
2238f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->biu_clk);
2239f90a0612SThomas Abraham 		if (ret) {
2240f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable biu clock\n");
2241f90a0612SThomas Abraham 			return ret;
2242f90a0612SThomas Abraham 		}
2243f95f3850SWill Newton 	}
2244f95f3850SWill Newton 
2245780f22afSSeungwon Jeon 	host->ciu_clk = devm_clk_get(host->dev, "ciu");
2246f90a0612SThomas Abraham 	if (IS_ERR(host->ciu_clk)) {
2247f90a0612SThomas Abraham 		dev_dbg(host->dev, "ciu clock not available\n");
22483c6d89eaSDoug Anderson 		host->bus_hz = host->pdata->bus_hz;
2249f90a0612SThomas Abraham 	} else {
2250f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->ciu_clk);
2251f90a0612SThomas Abraham 		if (ret) {
2252f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable ciu clock\n");
2253f90a0612SThomas Abraham 			goto err_clk_biu;
2254f90a0612SThomas Abraham 		}
2255f90a0612SThomas Abraham 
22563c6d89eaSDoug Anderson 		if (host->pdata->bus_hz) {
22573c6d89eaSDoug Anderson 			ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz);
22583c6d89eaSDoug Anderson 			if (ret)
22593c6d89eaSDoug Anderson 				dev_warn(host->dev,
22603c6d89eaSDoug Anderson 					 "Unable to set bus rate to %ul\n",
22613c6d89eaSDoug Anderson 					 host->pdata->bus_hz);
22623c6d89eaSDoug Anderson 		}
2263f90a0612SThomas Abraham 		host->bus_hz = clk_get_rate(host->ciu_clk);
22643c6d89eaSDoug Anderson 	}
2265f90a0612SThomas Abraham 
2266002f0d5cSYuvaraj Kumar C D 	if (drv_data && drv_data->init) {
2267002f0d5cSYuvaraj Kumar C D 		ret = drv_data->init(host);
2268002f0d5cSYuvaraj Kumar C D 		if (ret) {
2269002f0d5cSYuvaraj Kumar C D 			dev_err(host->dev,
2270002f0d5cSYuvaraj Kumar C D 				"implementation specific init failed\n");
2271002f0d5cSYuvaraj Kumar C D 			goto err_clk_ciu;
2272002f0d5cSYuvaraj Kumar C D 		}
2273002f0d5cSYuvaraj Kumar C D 	}
2274002f0d5cSYuvaraj Kumar C D 
2275cb27a843SJames Hogan 	if (drv_data && drv_data->setup_clock) {
2276cb27a843SJames Hogan 		ret = drv_data->setup_clock(host);
2277800d78bfSThomas Abraham 		if (ret) {
2278800d78bfSThomas Abraham 			dev_err(host->dev,
2279800d78bfSThomas Abraham 				"implementation specific clock setup failed\n");
2280800d78bfSThomas Abraham 			goto err_clk_ciu;
2281800d78bfSThomas Abraham 		}
2282800d78bfSThomas Abraham 	}
2283800d78bfSThomas Abraham 
2284a55d6ff0SMark Brown 	host->vmmc = devm_regulator_get_optional(host->dev, "vmmc");
2285870556a3SDoug Anderson 	if (IS_ERR(host->vmmc)) {
2286870556a3SDoug Anderson 		ret = PTR_ERR(host->vmmc);
2287870556a3SDoug Anderson 		if (ret == -EPROBE_DEFER)
2288870556a3SDoug Anderson 			goto err_clk_ciu;
2289870556a3SDoug Anderson 
2290870556a3SDoug Anderson 		dev_info(host->dev, "no vmmc regulator found: %d\n", ret);
2291870556a3SDoug Anderson 		host->vmmc = NULL;
2292870556a3SDoug Anderson 	} else {
2293870556a3SDoug Anderson 		ret = regulator_enable(host->vmmc);
2294870556a3SDoug Anderson 		if (ret) {
2295870556a3SDoug Anderson 			if (ret != -EPROBE_DEFER)
2296870556a3SDoug Anderson 				dev_err(host->dev,
2297870556a3SDoug Anderson 					"regulator_enable fail: %d\n", ret);
2298870556a3SDoug Anderson 			goto err_clk_ciu;
2299870556a3SDoug Anderson 		}
2300870556a3SDoug Anderson 	}
2301870556a3SDoug Anderson 
2302f90a0612SThomas Abraham 	if (!host->bus_hz) {
2303f90a0612SThomas Abraham 		dev_err(host->dev,
2304f90a0612SThomas Abraham 			"Platform data must supply bus speed\n");
2305f90a0612SThomas Abraham 		ret = -ENODEV;
2306870556a3SDoug Anderson 		goto err_regulator;
2307f90a0612SThomas Abraham 	}
2308f90a0612SThomas Abraham 
230962ca8034SShashidhar Hiremath 	host->quirks = host->pdata->quirks;
2310f95f3850SWill Newton 
2311f95f3850SWill Newton 	spin_lock_init(&host->lock);
2312f95f3850SWill Newton 	INIT_LIST_HEAD(&host->queue);
2313f95f3850SWill Newton 
2314f95f3850SWill Newton 	/*
2315f95f3850SWill Newton 	 * Get the host data width - this assumes that HCON has been set with
2316f95f3850SWill Newton 	 * the correct values.
2317f95f3850SWill Newton 	 */
2318f95f3850SWill Newton 	i = (mci_readl(host, HCON) >> 7) & 0x7;
2319f95f3850SWill Newton 	if (!i) {
2320f95f3850SWill Newton 		host->push_data = dw_mci_push_data16;
2321f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data16;
2322f95f3850SWill Newton 		width = 16;
2323f95f3850SWill Newton 		host->data_shift = 1;
2324f95f3850SWill Newton 	} else if (i == 2) {
2325f95f3850SWill Newton 		host->push_data = dw_mci_push_data64;
2326f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data64;
2327f95f3850SWill Newton 		width = 64;
2328f95f3850SWill Newton 		host->data_shift = 3;
2329f95f3850SWill Newton 	} else {
2330f95f3850SWill Newton 		/* Check for a reserved value, and warn if it is */
2331f95f3850SWill Newton 		WARN((i != 1),
2332f95f3850SWill Newton 		     "HCON reports a reserved host data width!\n"
2333f95f3850SWill Newton 		     "Defaulting to 32-bit access.\n");
2334f95f3850SWill Newton 		host->push_data = dw_mci_push_data32;
2335f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data32;
2336f95f3850SWill Newton 		width = 32;
2337f95f3850SWill Newton 		host->data_shift = 2;
2338f95f3850SWill Newton 	}
2339f95f3850SWill Newton 
2340f95f3850SWill Newton 	/* Reset all blocks */
23414a90920cSThomas Abraham 	if (!mci_wait_reset(host->dev, host))
2342141a712aSSeungwon Jeon 		return -ENODEV;
2343141a712aSSeungwon Jeon 
2344141a712aSSeungwon Jeon 	host->dma_ops = host->pdata->dma_ops;
2345141a712aSSeungwon Jeon 	dw_mci_init_dma(host);
2346f95f3850SWill Newton 
2347f95f3850SWill Newton 	/* Clear the interrupts for the host controller */
2348f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2349f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2350f95f3850SWill Newton 
2351f95f3850SWill Newton 	/* Put in max timeout */
2352f95f3850SWill Newton 	mci_writel(host, TMOUT, 0xFFFFFFFF);
2353f95f3850SWill Newton 
2354f95f3850SWill Newton 	/*
2355f95f3850SWill Newton 	 * FIFO threshold settings  RxMark  = fifo_size / 2 - 1,
2356f95f3850SWill Newton 	 *                          Tx Mark = fifo_size / 2 DMA Size = 8
2357f95f3850SWill Newton 	 */
2358b86d8253SJames Hogan 	if (!host->pdata->fifo_depth) {
2359b86d8253SJames Hogan 		/*
2360b86d8253SJames Hogan 		 * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may
2361b86d8253SJames Hogan 		 * have been overwritten by the bootloader, just like we're
2362b86d8253SJames Hogan 		 * about to do, so if you know the value for your hardware, you
2363b86d8253SJames Hogan 		 * should put it in the platform data.
2364b86d8253SJames Hogan 		 */
2365f95f3850SWill Newton 		fifo_size = mci_readl(host, FIFOTH);
23668234e869SJaehoon Chung 		fifo_size = 1 + ((fifo_size >> 16) & 0xfff);
2367b86d8253SJames Hogan 	} else {
2368b86d8253SJames Hogan 		fifo_size = host->pdata->fifo_depth;
2369b86d8253SJames Hogan 	}
2370b86d8253SJames Hogan 	host->fifo_depth = fifo_size;
2371e61cf118SJaehoon Chung 	host->fifoth_val = ((0x2 << 28) | ((fifo_size/2 - 1) << 16) |
2372e61cf118SJaehoon Chung 			((fifo_size/2) << 0));
2373e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
2374f95f3850SWill Newton 
2375f95f3850SWill Newton 	/* disable clock to CIU */
2376f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2377f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2378f95f3850SWill Newton 
237963008768SJames Hogan 	/*
238063008768SJames Hogan 	 * In 2.40a spec, Data offset is changed.
238163008768SJames Hogan 	 * Need to check the version-id and set data-offset for DATA register.
238263008768SJames Hogan 	 */
238363008768SJames Hogan 	host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
238463008768SJames Hogan 	dev_info(host->dev, "Version ID is %04x\n", host->verid);
238563008768SJames Hogan 
238663008768SJames Hogan 	if (host->verid < DW_MMC_240A)
238763008768SJames Hogan 		host->data_offset = DATA_OFFSET;
238863008768SJames Hogan 	else
238963008768SJames Hogan 		host->data_offset = DATA_240A_OFFSET;
239063008768SJames Hogan 
2391f95f3850SWill Newton 	tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
239295dcc2cbSThomas Abraham 	host->card_workqueue = alloc_workqueue("dw-mci-card",
23931791b13eSJames Hogan 			WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1);
2394ef7aef9aSWei Yongjun 	if (!host->card_workqueue) {
2395ef7aef9aSWei Yongjun 		ret = -ENOMEM;
23961791b13eSJames Hogan 		goto err_dmaunmap;
2397ef7aef9aSWei Yongjun 	}
23981791b13eSJames Hogan 	INIT_WORK(&host->card_work, dw_mci_work_routine_card);
2399780f22afSSeungwon Jeon 	ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
2400780f22afSSeungwon Jeon 			       host->irq_flags, "dw-mci", host);
2401f95f3850SWill Newton 	if (ret)
24021791b13eSJames Hogan 		goto err_workqueue;
2403f95f3850SWill Newton 
2404f95f3850SWill Newton 	if (host->pdata->num_slots)
2405f95f3850SWill Newton 		host->num_slots = host->pdata->num_slots;
2406f95f3850SWill Newton 	else
2407f95f3850SWill Newton 		host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1;
2408f95f3850SWill Newton 
24092da1d7f2SYuvaraj CD 	/*
24102da1d7f2SYuvaraj CD 	 * Enable interrupts for command done, data over, data empty, card det,
24112da1d7f2SYuvaraj CD 	 * receive ready and error such as transmit, receive timeout, crc error
24122da1d7f2SYuvaraj CD 	 */
24132da1d7f2SYuvaraj CD 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
24142da1d7f2SYuvaraj CD 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
24152da1d7f2SYuvaraj CD 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
24162da1d7f2SYuvaraj CD 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
24172da1d7f2SYuvaraj CD 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
24182da1d7f2SYuvaraj CD 
24192da1d7f2SYuvaraj CD 	dev_info(host->dev, "DW MMC controller at irq %d, "
24202da1d7f2SYuvaraj CD 		 "%d bit host data width, "
24212da1d7f2SYuvaraj CD 		 "%u deep fifo\n",
24222da1d7f2SYuvaraj CD 		 host->irq, width, fifo_size);
24232da1d7f2SYuvaraj CD 
2424f95f3850SWill Newton 	/* We need at least one slot to succeed */
2425f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2426f95f3850SWill Newton 		ret = dw_mci_init_slot(host, i);
24271c2215b7SThomas Abraham 		if (ret)
24281c2215b7SThomas Abraham 			dev_dbg(host->dev, "slot %d init failed\n", i);
24291c2215b7SThomas Abraham 		else
24301c2215b7SThomas Abraham 			init_slots++;
2431f95f3850SWill Newton 	}
24321c2215b7SThomas Abraham 
24331c2215b7SThomas Abraham 	if (init_slots) {
24341c2215b7SThomas Abraham 		dev_info(host->dev, "%d slots initialized\n", init_slots);
24351c2215b7SThomas Abraham 	} else {
24361c2215b7SThomas Abraham 		dev_dbg(host->dev, "attempted to initialize %d slots, "
24371c2215b7SThomas Abraham 					"but failed on all\n", host->num_slots);
2438780f22afSSeungwon Jeon 		goto err_workqueue;
2439f95f3850SWill Newton 	}
2440f95f3850SWill Newton 
2441f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
24424a90920cSThomas Abraham 		dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
2443f95f3850SWill Newton 
2444f95f3850SWill Newton 	return 0;
2445f95f3850SWill Newton 
24461791b13eSJames Hogan err_workqueue:
244795dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
24481791b13eSJames Hogan 
2449f95f3850SWill Newton err_dmaunmap:
2450f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2451f95f3850SWill Newton 		host->dma_ops->exit(host);
2452f95f3850SWill Newton 
2453870556a3SDoug Anderson err_regulator:
2454780f22afSSeungwon Jeon 	if (host->vmmc)
2455c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2456f90a0612SThomas Abraham 
2457f90a0612SThomas Abraham err_clk_ciu:
2458780f22afSSeungwon Jeon 	if (!IS_ERR(host->ciu_clk))
2459f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2460780f22afSSeungwon Jeon 
2461f90a0612SThomas Abraham err_clk_biu:
2462780f22afSSeungwon Jeon 	if (!IS_ERR(host->biu_clk))
2463f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2464780f22afSSeungwon Jeon 
2465f95f3850SWill Newton 	return ret;
2466f95f3850SWill Newton }
246762ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe);
2468f95f3850SWill Newton 
246962ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host)
2470f95f3850SWill Newton {
2471f95f3850SWill Newton 	int i;
2472f95f3850SWill Newton 
2473f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2474f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2475f95f3850SWill Newton 
2476f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
24774a90920cSThomas Abraham 		dev_dbg(host->dev, "remove slot %d\n", i);
2478f95f3850SWill Newton 		if (host->slot[i])
2479f95f3850SWill Newton 			dw_mci_cleanup_slot(host->slot[i], i);
2480f95f3850SWill Newton 	}
2481f95f3850SWill Newton 
2482f95f3850SWill Newton 	/* disable clock to CIU */
2483f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2484f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2485f95f3850SWill Newton 
248695dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
2487f95f3850SWill Newton 
2488f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2489f95f3850SWill Newton 		host->dma_ops->exit(host);
2490f95f3850SWill Newton 
2491780f22afSSeungwon Jeon 	if (host->vmmc)
2492c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2493c07946a3SJaehoon Chung 
2494f90a0612SThomas Abraham 	if (!IS_ERR(host->ciu_clk))
2495f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2496780f22afSSeungwon Jeon 
2497f90a0612SThomas Abraham 	if (!IS_ERR(host->biu_clk))
2498f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2499f95f3850SWill Newton }
250062ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove);
250162ca8034SShashidhar Hiremath 
250262ca8034SShashidhar Hiremath 
2503f95f3850SWill Newton 
25046fe8890dSJaehoon Chung #ifdef CONFIG_PM_SLEEP
2505f95f3850SWill Newton /*
2506f95f3850SWill Newton  * TODO: we should probably disable the clock to the card in the suspend path.
2507f95f3850SWill Newton  */
250862ca8034SShashidhar Hiremath int dw_mci_suspend(struct dw_mci *host)
2509f95f3850SWill Newton {
251062ca8034SShashidhar Hiremath 	int i, ret = 0;
2511f95f3850SWill Newton 
2512f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2513f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
2514f95f3850SWill Newton 		if (!slot)
2515f95f3850SWill Newton 			continue;
2516f95f3850SWill Newton 		ret = mmc_suspend_host(slot->mmc);
2517f95f3850SWill Newton 		if (ret < 0) {
2518f95f3850SWill Newton 			while (--i >= 0) {
2519f95f3850SWill Newton 				slot = host->slot[i];
2520f95f3850SWill Newton 				if (slot)
2521f95f3850SWill Newton 					mmc_resume_host(host->slot[i]->mmc);
2522f95f3850SWill Newton 			}
2523f95f3850SWill Newton 			return ret;
2524f95f3850SWill Newton 		}
2525f95f3850SWill Newton 	}
2526f95f3850SWill Newton 
2527c07946a3SJaehoon Chung 	if (host->vmmc)
2528c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2529c07946a3SJaehoon Chung 
2530f95f3850SWill Newton 	return 0;
2531f95f3850SWill Newton }
253262ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_suspend);
2533f95f3850SWill Newton 
253462ca8034SShashidhar Hiremath int dw_mci_resume(struct dw_mci *host)
2535f95f3850SWill Newton {
2536f95f3850SWill Newton 	int i, ret;
2537f95f3850SWill Newton 
2538f2f942ceSSachin Kamat 	if (host->vmmc) {
2539f2f942ceSSachin Kamat 		ret = regulator_enable(host->vmmc);
2540f2f942ceSSachin Kamat 		if (ret) {
2541f2f942ceSSachin Kamat 			dev_err(host->dev,
2542f2f942ceSSachin Kamat 				"failed to enable regulator: %d\n", ret);
2543f2f942ceSSachin Kamat 			return ret;
2544f2f942ceSSachin Kamat 		}
2545f2f942ceSSachin Kamat 	}
25461d6c4e0aSJaehoon Chung 
25474a90920cSThomas Abraham 	if (!mci_wait_reset(host->dev, host)) {
2548e61cf118SJaehoon Chung 		ret = -ENODEV;
2549e61cf118SJaehoon Chung 		return ret;
2550e61cf118SJaehoon Chung 	}
2551e61cf118SJaehoon Chung 
25523bfe619dSJonathan Kliegman 	if (host->use_dma && host->dma_ops->init)
2553141a712aSSeungwon Jeon 		host->dma_ops->init(host);
2554141a712aSSeungwon Jeon 
2555e61cf118SJaehoon Chung 	/* Restore the old value at FIFOTH register */
2556e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
2557e61cf118SJaehoon Chung 
25582eb2944fSDoug Anderson 	/* Put in max timeout */
25592eb2944fSDoug Anderson 	mci_writel(host, TMOUT, 0xFFFFFFFF);
25602eb2944fSDoug Anderson 
2561e61cf118SJaehoon Chung 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2562e61cf118SJaehoon Chung 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
2563e61cf118SJaehoon Chung 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
2564e61cf118SJaehoon Chung 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
2565e61cf118SJaehoon Chung 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
2566e61cf118SJaehoon Chung 
2567f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2568f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
2569f95f3850SWill Newton 		if (!slot)
2570f95f3850SWill Newton 			continue;
2571ab269128SAbhilash Kesavan 		if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
2572ab269128SAbhilash Kesavan 			dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
2573ab269128SAbhilash Kesavan 			dw_mci_setup_bus(slot, true);
2574ab269128SAbhilash Kesavan 		}
2575ab269128SAbhilash Kesavan 
2576f95f3850SWill Newton 		ret = mmc_resume_host(host->slot[i]->mmc);
2577f95f3850SWill Newton 		if (ret < 0)
2578f95f3850SWill Newton 			return ret;
2579f95f3850SWill Newton 	}
2580f95f3850SWill Newton 	return 0;
2581f95f3850SWill Newton }
258262ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_resume);
25836fe8890dSJaehoon Chung #endif /* CONFIG_PM_SLEEP */
25846fe8890dSJaehoon Chung 
2585f95f3850SWill Newton static int __init dw_mci_init(void)
2586f95f3850SWill Newton {
25878e1c4e4dSSachin Kamat 	pr_info("Synopsys Designware Multimedia Card Interface Driver\n");
258862ca8034SShashidhar Hiremath 	return 0;
2589f95f3850SWill Newton }
2590f95f3850SWill Newton 
2591f95f3850SWill Newton static void __exit dw_mci_exit(void)
2592f95f3850SWill Newton {
2593f95f3850SWill Newton }
2594f95f3850SWill Newton 
2595f95f3850SWill Newton module_init(dw_mci_init);
2596f95f3850SWill Newton module_exit(dw_mci_exit);
2597f95f3850SWill Newton 
2598f95f3850SWill Newton MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
2599f95f3850SWill Newton MODULE_AUTHOR("NXP Semiconductor VietNam");
2600f95f3850SWill Newton MODULE_AUTHOR("Imagination Technologies Ltd");
2601f95f3850SWill Newton MODULE_LICENSE("GPL v2");
2602