xref: /openbmc/linux/drivers/mmc/host/dw_mmc.c (revision 0976f16d)
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 
53f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
54fc79a4d6SJoonyoung Shim #define IDMAC_INT_CLR		(SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \
55fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \
56fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
57fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_TI)
58fc79a4d6SJoonyoung Shim 
59f95f3850SWill Newton struct idmac_desc {
60f95f3850SWill Newton 	u32		des0;	/* Control Descriptor */
61f95f3850SWill Newton #define IDMAC_DES0_DIC	BIT(1)
62f95f3850SWill Newton #define IDMAC_DES0_LD	BIT(2)
63f95f3850SWill Newton #define IDMAC_DES0_FD	BIT(3)
64f95f3850SWill Newton #define IDMAC_DES0_CH	BIT(4)
65f95f3850SWill Newton #define IDMAC_DES0_ER	BIT(5)
66f95f3850SWill Newton #define IDMAC_DES0_CES	BIT(30)
67f95f3850SWill Newton #define IDMAC_DES0_OWN	BIT(31)
68f95f3850SWill Newton 
69f95f3850SWill Newton 	u32		des1;	/* Buffer sizes */
70f95f3850SWill Newton #define IDMAC_SET_BUFFER1_SIZE(d, s) \
719b7bbe10SShashidhar Hiremath 	((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff))
72f95f3850SWill Newton 
73f95f3850SWill Newton 	u32		des2;	/* buffer 1 physical address */
74f95f3850SWill Newton 
75f95f3850SWill Newton 	u32		des3;	/* buffer 2 physical address */
76f95f3850SWill Newton };
77f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */
78f95f3850SWill Newton 
790976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_4bit[] = {
800976f16dSSeungwon Jeon 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
810976f16dSSeungwon Jeon 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
820976f16dSSeungwon Jeon 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
830976f16dSSeungwon Jeon 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
840976f16dSSeungwon Jeon 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
850976f16dSSeungwon Jeon 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
860976f16dSSeungwon Jeon 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
870976f16dSSeungwon Jeon 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
880976f16dSSeungwon Jeon };
89f95f3850SWill Newton 
900976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_8bit[] = {
910976f16dSSeungwon Jeon 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
920976f16dSSeungwon Jeon 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
930976f16dSSeungwon Jeon 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
940976f16dSSeungwon Jeon 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
950976f16dSSeungwon Jeon 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
960976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
970976f16dSSeungwon Jeon 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
980976f16dSSeungwon Jeon 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
990976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
1000976f16dSSeungwon Jeon 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
1010976f16dSSeungwon Jeon 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
1020976f16dSSeungwon Jeon 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
1030976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
1040976f16dSSeungwon Jeon 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
1050976f16dSSeungwon Jeon 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
1060976f16dSSeungwon Jeon 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
107f95f3850SWill Newton };
108f95f3850SWill Newton 
109f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS)
110f95f3850SWill Newton static int dw_mci_req_show(struct seq_file *s, void *v)
111f95f3850SWill Newton {
112f95f3850SWill Newton 	struct dw_mci_slot *slot = s->private;
113f95f3850SWill Newton 	struct mmc_request *mrq;
114f95f3850SWill Newton 	struct mmc_command *cmd;
115f95f3850SWill Newton 	struct mmc_command *stop;
116f95f3850SWill Newton 	struct mmc_data	*data;
117f95f3850SWill Newton 
118f95f3850SWill Newton 	/* Make sure we get a consistent snapshot */
119f95f3850SWill Newton 	spin_lock_bh(&slot->host->lock);
120f95f3850SWill Newton 	mrq = slot->mrq;
121f95f3850SWill Newton 
122f95f3850SWill Newton 	if (mrq) {
123f95f3850SWill Newton 		cmd = mrq->cmd;
124f95f3850SWill Newton 		data = mrq->data;
125f95f3850SWill Newton 		stop = mrq->stop;
126f95f3850SWill Newton 
127f95f3850SWill Newton 		if (cmd)
128f95f3850SWill Newton 			seq_printf(s,
129f95f3850SWill Newton 				   "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
130f95f3850SWill Newton 				   cmd->opcode, cmd->arg, cmd->flags,
131f95f3850SWill Newton 				   cmd->resp[0], cmd->resp[1], cmd->resp[2],
132f95f3850SWill Newton 				   cmd->resp[2], cmd->error);
133f95f3850SWill Newton 		if (data)
134f95f3850SWill Newton 			seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
135f95f3850SWill Newton 				   data->bytes_xfered, data->blocks,
136f95f3850SWill Newton 				   data->blksz, data->flags, data->error);
137f95f3850SWill Newton 		if (stop)
138f95f3850SWill Newton 			seq_printf(s,
139f95f3850SWill Newton 				   "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
140f95f3850SWill Newton 				   stop->opcode, stop->arg, stop->flags,
141f95f3850SWill Newton 				   stop->resp[0], stop->resp[1], stop->resp[2],
142f95f3850SWill Newton 				   stop->resp[2], stop->error);
143f95f3850SWill Newton 	}
144f95f3850SWill Newton 
145f95f3850SWill Newton 	spin_unlock_bh(&slot->host->lock);
146f95f3850SWill Newton 
147f95f3850SWill Newton 	return 0;
148f95f3850SWill Newton }
149f95f3850SWill Newton 
150f95f3850SWill Newton static int dw_mci_req_open(struct inode *inode, struct file *file)
151f95f3850SWill Newton {
152f95f3850SWill Newton 	return single_open(file, dw_mci_req_show, inode->i_private);
153f95f3850SWill Newton }
154f95f3850SWill Newton 
155f95f3850SWill Newton static const struct file_operations dw_mci_req_fops = {
156f95f3850SWill Newton 	.owner		= THIS_MODULE,
157f95f3850SWill Newton 	.open		= dw_mci_req_open,
158f95f3850SWill Newton 	.read		= seq_read,
159f95f3850SWill Newton 	.llseek		= seq_lseek,
160f95f3850SWill Newton 	.release	= single_release,
161f95f3850SWill Newton };
162f95f3850SWill Newton 
163f95f3850SWill Newton static int dw_mci_regs_show(struct seq_file *s, void *v)
164f95f3850SWill Newton {
165f95f3850SWill Newton 	seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS);
166f95f3850SWill Newton 	seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS);
167f95f3850SWill Newton 	seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD);
168f95f3850SWill Newton 	seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL);
169f95f3850SWill Newton 	seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK);
170f95f3850SWill Newton 	seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA);
171f95f3850SWill Newton 
172f95f3850SWill Newton 	return 0;
173f95f3850SWill Newton }
174f95f3850SWill Newton 
175f95f3850SWill Newton static int dw_mci_regs_open(struct inode *inode, struct file *file)
176f95f3850SWill Newton {
177f95f3850SWill Newton 	return single_open(file, dw_mci_regs_show, inode->i_private);
178f95f3850SWill Newton }
179f95f3850SWill Newton 
180f95f3850SWill Newton static const struct file_operations dw_mci_regs_fops = {
181f95f3850SWill Newton 	.owner		= THIS_MODULE,
182f95f3850SWill Newton 	.open		= dw_mci_regs_open,
183f95f3850SWill Newton 	.read		= seq_read,
184f95f3850SWill Newton 	.llseek		= seq_lseek,
185f95f3850SWill Newton 	.release	= single_release,
186f95f3850SWill Newton };
187f95f3850SWill Newton 
188f95f3850SWill Newton static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
189f95f3850SWill Newton {
190f95f3850SWill Newton 	struct mmc_host	*mmc = slot->mmc;
191f95f3850SWill Newton 	struct dw_mci *host = slot->host;
192f95f3850SWill Newton 	struct dentry *root;
193f95f3850SWill Newton 	struct dentry *node;
194f95f3850SWill Newton 
195f95f3850SWill Newton 	root = mmc->debugfs_root;
196f95f3850SWill Newton 	if (!root)
197f95f3850SWill Newton 		return;
198f95f3850SWill Newton 
199f95f3850SWill Newton 	node = debugfs_create_file("regs", S_IRUSR, root, host,
200f95f3850SWill Newton 				   &dw_mci_regs_fops);
201f95f3850SWill Newton 	if (!node)
202f95f3850SWill Newton 		goto err;
203f95f3850SWill Newton 
204f95f3850SWill Newton 	node = debugfs_create_file("req", S_IRUSR, root, slot,
205f95f3850SWill Newton 				   &dw_mci_req_fops);
206f95f3850SWill Newton 	if (!node)
207f95f3850SWill Newton 		goto err;
208f95f3850SWill Newton 
209f95f3850SWill Newton 	node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
210f95f3850SWill Newton 	if (!node)
211f95f3850SWill Newton 		goto err;
212f95f3850SWill Newton 
213f95f3850SWill Newton 	node = debugfs_create_x32("pending_events", S_IRUSR, root,
214f95f3850SWill Newton 				  (u32 *)&host->pending_events);
215f95f3850SWill Newton 	if (!node)
216f95f3850SWill Newton 		goto err;
217f95f3850SWill Newton 
218f95f3850SWill Newton 	node = debugfs_create_x32("completed_events", S_IRUSR, root,
219f95f3850SWill Newton 				  (u32 *)&host->completed_events);
220f95f3850SWill Newton 	if (!node)
221f95f3850SWill Newton 		goto err;
222f95f3850SWill Newton 
223f95f3850SWill Newton 	return;
224f95f3850SWill Newton 
225f95f3850SWill Newton err:
226f95f3850SWill Newton 	dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
227f95f3850SWill Newton }
228f95f3850SWill Newton #endif /* defined(CONFIG_DEBUG_FS) */
229f95f3850SWill Newton 
230f95f3850SWill Newton static void dw_mci_set_timeout(struct dw_mci *host)
231f95f3850SWill Newton {
232f95f3850SWill Newton 	/* timeout (maximum) */
233f95f3850SWill Newton 	mci_writel(host, TMOUT, 0xffffffff);
234f95f3850SWill Newton }
235f95f3850SWill Newton 
236f95f3850SWill Newton static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
237f95f3850SWill Newton {
238f95f3850SWill Newton 	struct mmc_data	*data;
239800d78bfSThomas Abraham 	struct dw_mci_slot *slot = mmc_priv(mmc);
240e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
241f95f3850SWill Newton 	u32 cmdr;
242f95f3850SWill Newton 	cmd->error = -EINPROGRESS;
243f95f3850SWill Newton 
244f95f3850SWill Newton 	cmdr = cmd->opcode;
245f95f3850SWill Newton 
246f95f3850SWill Newton 	if (cmdr == MMC_STOP_TRANSMISSION)
247f95f3850SWill Newton 		cmdr |= SDMMC_CMD_STOP;
248f95f3850SWill Newton 	else
249f95f3850SWill Newton 		cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
250f95f3850SWill Newton 
251f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_PRESENT) {
252f95f3850SWill Newton 		/* We expect a response, so set this bit */
253f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_EXP;
254f95f3850SWill Newton 		if (cmd->flags & MMC_RSP_136)
255f95f3850SWill Newton 			cmdr |= SDMMC_CMD_RESP_LONG;
256f95f3850SWill Newton 	}
257f95f3850SWill Newton 
258f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_CRC)
259f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_CRC;
260f95f3850SWill Newton 
261f95f3850SWill Newton 	data = cmd->data;
262f95f3850SWill Newton 	if (data) {
263f95f3850SWill Newton 		cmdr |= SDMMC_CMD_DAT_EXP;
264f95f3850SWill Newton 		if (data->flags & MMC_DATA_STREAM)
265f95f3850SWill Newton 			cmdr |= SDMMC_CMD_STRM_MODE;
266f95f3850SWill Newton 		if (data->flags & MMC_DATA_WRITE)
267f95f3850SWill Newton 			cmdr |= SDMMC_CMD_DAT_WR;
268f95f3850SWill Newton 	}
269f95f3850SWill Newton 
270cb27a843SJames Hogan 	if (drv_data && drv_data->prepare_command)
271cb27a843SJames Hogan 		drv_data->prepare_command(slot->host, &cmdr);
272800d78bfSThomas Abraham 
273f95f3850SWill Newton 	return cmdr;
274f95f3850SWill Newton }
275f95f3850SWill Newton 
276f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host,
277f95f3850SWill Newton 				 struct mmc_command *cmd, u32 cmd_flags)
278f95f3850SWill Newton {
279f95f3850SWill Newton 	host->cmd = cmd;
2804a90920cSThomas Abraham 	dev_vdbg(host->dev,
281f95f3850SWill Newton 		 "start command: ARGR=0x%08x CMDR=0x%08x\n",
282f95f3850SWill Newton 		 cmd->arg, cmd_flags);
283f95f3850SWill Newton 
284f95f3850SWill Newton 	mci_writel(host, CMDARG, cmd->arg);
285f95f3850SWill Newton 	wmb();
286f95f3850SWill Newton 
287f95f3850SWill Newton 	mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
288f95f3850SWill Newton }
289f95f3850SWill Newton 
290f95f3850SWill Newton static void send_stop_cmd(struct dw_mci *host, struct mmc_data *data)
291f95f3850SWill Newton {
292f95f3850SWill Newton 	dw_mci_start_command(host, data->stop, host->stop_cmdr);
293f95f3850SWill Newton }
294f95f3850SWill Newton 
295f95f3850SWill Newton /* DMA interface functions */
296f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host)
297f95f3850SWill Newton {
29803e8cb53SJames Hogan 	if (host->using_dma) {
299f95f3850SWill Newton 		host->dma_ops->stop(host);
300f95f3850SWill Newton 		host->dma_ops->cleanup(host);
301f95f3850SWill Newton 	} else {
302f95f3850SWill Newton 		/* Data transfer was stopped by the interrupt handler */
303f95f3850SWill Newton 		set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
304f95f3850SWill Newton 	}
305f95f3850SWill Newton }
306f95f3850SWill Newton 
3079aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data)
3089aa51408SSeungwon Jeon {
3099aa51408SSeungwon Jeon 	if (data->flags & MMC_DATA_WRITE)
3109aa51408SSeungwon Jeon 		return DMA_TO_DEVICE;
3119aa51408SSeungwon Jeon 	else
3129aa51408SSeungwon Jeon 		return DMA_FROM_DEVICE;
3139aa51408SSeungwon Jeon }
3149aa51408SSeungwon Jeon 
3159beee912SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
316f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host)
317f95f3850SWill Newton {
318f95f3850SWill Newton 	struct mmc_data *data = host->data;
319f95f3850SWill Newton 
320f95f3850SWill Newton 	if (data)
3219aa51408SSeungwon Jeon 		if (!data->host_cookie)
3224a90920cSThomas Abraham 			dma_unmap_sg(host->dev,
3239aa51408SSeungwon Jeon 				     data->sg,
3249aa51408SSeungwon Jeon 				     data->sg_len,
3259aa51408SSeungwon Jeon 				     dw_mci_get_dma_dir(data));
326f95f3850SWill Newton }
327f95f3850SWill Newton 
328f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host)
329f95f3850SWill Newton {
330f95f3850SWill Newton 	u32 temp;
331f95f3850SWill Newton 
332f95f3850SWill Newton 	/* Disable and reset the IDMAC interface */
333f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
334f95f3850SWill Newton 	temp &= ~SDMMC_CTRL_USE_IDMAC;
335f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_RESET;
336f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
337f95f3850SWill Newton 
338f95f3850SWill Newton 	/* Stop the IDMAC running */
339f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
340a5289a43SJaehoon Chung 	temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB);
341f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
342f95f3850SWill Newton }
343f95f3850SWill Newton 
344f95f3850SWill Newton static void dw_mci_idmac_complete_dma(struct dw_mci *host)
345f95f3850SWill Newton {
346f95f3850SWill Newton 	struct mmc_data *data = host->data;
347f95f3850SWill Newton 
3484a90920cSThomas Abraham 	dev_vdbg(host->dev, "DMA complete\n");
349f95f3850SWill Newton 
350f95f3850SWill Newton 	host->dma_ops->cleanup(host);
351f95f3850SWill Newton 
352f95f3850SWill Newton 	/*
353f95f3850SWill Newton 	 * If the card was removed, data will be NULL. No point in trying to
354f95f3850SWill Newton 	 * send the stop command or waiting for NBUSY in this case.
355f95f3850SWill Newton 	 */
356f95f3850SWill Newton 	if (data) {
357f95f3850SWill Newton 		set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
358f95f3850SWill Newton 		tasklet_schedule(&host->tasklet);
359f95f3850SWill Newton 	}
360f95f3850SWill Newton }
361f95f3850SWill Newton 
362f95f3850SWill Newton static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
363f95f3850SWill Newton 				    unsigned int sg_len)
364f95f3850SWill Newton {
365f95f3850SWill Newton 	int i;
366f95f3850SWill Newton 	struct idmac_desc *desc = host->sg_cpu;
367f95f3850SWill Newton 
368f95f3850SWill Newton 	for (i = 0; i < sg_len; i++, desc++) {
369f95f3850SWill Newton 		unsigned int length = sg_dma_len(&data->sg[i]);
370f95f3850SWill Newton 		u32 mem_addr = sg_dma_address(&data->sg[i]);
371f95f3850SWill Newton 
372f95f3850SWill Newton 		/* Set the OWN bit and disable interrupts for this descriptor */
373f95f3850SWill Newton 		desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH;
374f95f3850SWill Newton 
375f95f3850SWill Newton 		/* Buffer length */
376f95f3850SWill Newton 		IDMAC_SET_BUFFER1_SIZE(desc, length);
377f95f3850SWill Newton 
378f95f3850SWill Newton 		/* Physical address to DMA to/from */
379f95f3850SWill Newton 		desc->des2 = mem_addr;
380f95f3850SWill Newton 	}
381f95f3850SWill Newton 
382f95f3850SWill Newton 	/* Set first descriptor */
383f95f3850SWill Newton 	desc = host->sg_cpu;
384f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_FD;
385f95f3850SWill Newton 
386f95f3850SWill Newton 	/* Set last descriptor */
387f95f3850SWill Newton 	desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
388f95f3850SWill Newton 	desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
389f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_LD;
390f95f3850SWill Newton 
391f95f3850SWill Newton 	wmb();
392f95f3850SWill Newton }
393f95f3850SWill Newton 
394f95f3850SWill Newton static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
395f95f3850SWill Newton {
396f95f3850SWill Newton 	u32 temp;
397f95f3850SWill Newton 
398f95f3850SWill Newton 	dw_mci_translate_sglist(host, host->data, sg_len);
399f95f3850SWill Newton 
400f95f3850SWill Newton 	/* Select IDMAC interface */
401f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
402f95f3850SWill Newton 	temp |= SDMMC_CTRL_USE_IDMAC;
403f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
404f95f3850SWill Newton 
405f95f3850SWill Newton 	wmb();
406f95f3850SWill Newton 
407f95f3850SWill Newton 	/* Enable the IDMAC */
408f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
409a5289a43SJaehoon Chung 	temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB;
410f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
411f95f3850SWill Newton 
412f95f3850SWill Newton 	/* Start it running */
413f95f3850SWill Newton 	mci_writel(host, PLDMND, 1);
414f95f3850SWill Newton }
415f95f3850SWill Newton 
416f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host)
417f95f3850SWill Newton {
418f95f3850SWill Newton 	struct idmac_desc *p;
419897b69e7SSeungwon Jeon 	int i;
420f95f3850SWill Newton 
421f95f3850SWill Newton 	/* Number of descriptors in the ring buffer */
422f95f3850SWill Newton 	host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
423f95f3850SWill Newton 
424f95f3850SWill Newton 	/* Forward link the descriptor list */
425f95f3850SWill Newton 	for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
426f95f3850SWill Newton 		p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
427f95f3850SWill Newton 
428f95f3850SWill Newton 	/* Set the last descriptor as the end-of-ring descriptor */
429f95f3850SWill Newton 	p->des3 = host->sg_dma;
430f95f3850SWill Newton 	p->des0 = IDMAC_DES0_ER;
431f95f3850SWill Newton 
432141a712aSSeungwon Jeon 	mci_writel(host, BMOD, SDMMC_IDMAC_SWRESET);
433141a712aSSeungwon Jeon 
434f95f3850SWill Newton 	/* Mask out interrupts - get Tx & Rx complete only */
435fc79a4d6SJoonyoung Shim 	mci_writel(host, IDSTS, IDMAC_INT_CLR);
436f95f3850SWill Newton 	mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
437f95f3850SWill Newton 		   SDMMC_IDMAC_INT_TI);
438f95f3850SWill Newton 
439f95f3850SWill Newton 	/* Set the descriptor base address */
440f95f3850SWill Newton 	mci_writel(host, DBADDR, host->sg_dma);
441f95f3850SWill Newton 	return 0;
442f95f3850SWill Newton }
443f95f3850SWill Newton 
4448e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = {
445885c3e80SSeungwon Jeon 	.init = dw_mci_idmac_init,
446885c3e80SSeungwon Jeon 	.start = dw_mci_idmac_start_dma,
447885c3e80SSeungwon Jeon 	.stop = dw_mci_idmac_stop_dma,
448885c3e80SSeungwon Jeon 	.complete = dw_mci_idmac_complete_dma,
449885c3e80SSeungwon Jeon 	.cleanup = dw_mci_dma_cleanup,
450885c3e80SSeungwon Jeon };
451885c3e80SSeungwon Jeon #endif /* CONFIG_MMC_DW_IDMAC */
452885c3e80SSeungwon Jeon 
4539aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host,
4549aa51408SSeungwon Jeon 				   struct mmc_data *data,
4559aa51408SSeungwon Jeon 				   bool next)
456f95f3850SWill Newton {
457f95f3850SWill Newton 	struct scatterlist *sg;
4589aa51408SSeungwon Jeon 	unsigned int i, sg_len;
459f95f3850SWill Newton 
4609aa51408SSeungwon Jeon 	if (!next && data->host_cookie)
4619aa51408SSeungwon Jeon 		return data->host_cookie;
462f95f3850SWill Newton 
463f95f3850SWill Newton 	/*
464f95f3850SWill Newton 	 * We don't do DMA on "complex" transfers, i.e. with
465f95f3850SWill Newton 	 * non-word-aligned buffers or lengths. Also, we don't bother
466f95f3850SWill Newton 	 * with all the DMA setup overhead for short transfers.
467f95f3850SWill Newton 	 */
468f95f3850SWill Newton 	if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD)
469f95f3850SWill Newton 		return -EINVAL;
4709aa51408SSeungwon Jeon 
471f95f3850SWill Newton 	if (data->blksz & 3)
472f95f3850SWill Newton 		return -EINVAL;
473f95f3850SWill Newton 
474f95f3850SWill Newton 	for_each_sg(data->sg, sg, data->sg_len, i) {
475f95f3850SWill Newton 		if (sg->offset & 3 || sg->length & 3)
476f95f3850SWill Newton 			return -EINVAL;
477f95f3850SWill Newton 	}
478f95f3850SWill Newton 
4794a90920cSThomas Abraham 	sg_len = dma_map_sg(host->dev,
4809aa51408SSeungwon Jeon 			    data->sg,
4819aa51408SSeungwon Jeon 			    data->sg_len,
4829aa51408SSeungwon Jeon 			    dw_mci_get_dma_dir(data));
4839aa51408SSeungwon Jeon 	if (sg_len == 0)
4849aa51408SSeungwon Jeon 		return -EINVAL;
4859aa51408SSeungwon Jeon 
4869aa51408SSeungwon Jeon 	if (next)
4879aa51408SSeungwon Jeon 		data->host_cookie = sg_len;
4889aa51408SSeungwon Jeon 
4899aa51408SSeungwon Jeon 	return sg_len;
4909aa51408SSeungwon Jeon }
4919aa51408SSeungwon Jeon 
4929aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc,
4939aa51408SSeungwon Jeon 			   struct mmc_request *mrq,
4949aa51408SSeungwon Jeon 			   bool is_first_req)
4959aa51408SSeungwon Jeon {
4969aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
4979aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
4989aa51408SSeungwon Jeon 
4999aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
5009aa51408SSeungwon Jeon 		return;
5019aa51408SSeungwon Jeon 
5029aa51408SSeungwon Jeon 	if (data->host_cookie) {
5039aa51408SSeungwon Jeon 		data->host_cookie = 0;
5049aa51408SSeungwon Jeon 		return;
5059aa51408SSeungwon Jeon 	}
5069aa51408SSeungwon Jeon 
5079aa51408SSeungwon Jeon 	if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0)
5089aa51408SSeungwon Jeon 		data->host_cookie = 0;
5099aa51408SSeungwon Jeon }
5109aa51408SSeungwon Jeon 
5119aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc,
5129aa51408SSeungwon Jeon 			    struct mmc_request *mrq,
5139aa51408SSeungwon Jeon 			    int err)
5149aa51408SSeungwon Jeon {
5159aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
5169aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
5179aa51408SSeungwon Jeon 
5189aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
5199aa51408SSeungwon Jeon 		return;
5209aa51408SSeungwon Jeon 
5219aa51408SSeungwon Jeon 	if (data->host_cookie)
5224a90920cSThomas Abraham 		dma_unmap_sg(slot->host->dev,
5239aa51408SSeungwon Jeon 			     data->sg,
5249aa51408SSeungwon Jeon 			     data->sg_len,
5259aa51408SSeungwon Jeon 			     dw_mci_get_dma_dir(data));
5269aa51408SSeungwon Jeon 	data->host_cookie = 0;
5279aa51408SSeungwon Jeon }
5289aa51408SSeungwon Jeon 
5299aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
5309aa51408SSeungwon Jeon {
5319aa51408SSeungwon Jeon 	int sg_len;
5329aa51408SSeungwon Jeon 	u32 temp;
5339aa51408SSeungwon Jeon 
5349aa51408SSeungwon Jeon 	host->using_dma = 0;
5359aa51408SSeungwon Jeon 
5369aa51408SSeungwon Jeon 	/* If we don't have a channel, we can't do DMA */
5379aa51408SSeungwon Jeon 	if (!host->use_dma)
5389aa51408SSeungwon Jeon 		return -ENODEV;
5399aa51408SSeungwon Jeon 
5409aa51408SSeungwon Jeon 	sg_len = dw_mci_pre_dma_transfer(host, data, 0);
541a99aa9b9SSeungwon Jeon 	if (sg_len < 0) {
542a99aa9b9SSeungwon Jeon 		host->dma_ops->stop(host);
5439aa51408SSeungwon Jeon 		return sg_len;
544a99aa9b9SSeungwon Jeon 	}
5459aa51408SSeungwon Jeon 
54603e8cb53SJames Hogan 	host->using_dma = 1;
54703e8cb53SJames Hogan 
5484a90920cSThomas Abraham 	dev_vdbg(host->dev,
549f95f3850SWill Newton 		 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
550f95f3850SWill Newton 		 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
551f95f3850SWill Newton 		 sg_len);
552f95f3850SWill Newton 
553f95f3850SWill Newton 	/* Enable the DMA interface */
554f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
555f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_ENABLE;
556f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
557f95f3850SWill Newton 
558f95f3850SWill Newton 	/* Disable RX/TX IRQs, let DMA handle it */
559f95f3850SWill Newton 	temp = mci_readl(host, INTMASK);
560f95f3850SWill Newton 	temp  &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR);
561f95f3850SWill Newton 	mci_writel(host, INTMASK, temp);
562f95f3850SWill Newton 
563f95f3850SWill Newton 	host->dma_ops->start(host, sg_len);
564f95f3850SWill Newton 
565f95f3850SWill Newton 	return 0;
566f95f3850SWill Newton }
567f95f3850SWill Newton 
568f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
569f95f3850SWill Newton {
570f95f3850SWill Newton 	u32 temp;
571f95f3850SWill Newton 
572f95f3850SWill Newton 	data->error = -EINPROGRESS;
573f95f3850SWill Newton 
574f95f3850SWill Newton 	WARN_ON(host->data);
575f95f3850SWill Newton 	host->sg = NULL;
576f95f3850SWill Newton 	host->data = data;
577f95f3850SWill Newton 
57855c5efbcSJames Hogan 	if (data->flags & MMC_DATA_READ)
57955c5efbcSJames Hogan 		host->dir_status = DW_MCI_RECV_STATUS;
58055c5efbcSJames Hogan 	else
58155c5efbcSJames Hogan 		host->dir_status = DW_MCI_SEND_STATUS;
58255c5efbcSJames Hogan 
583f95f3850SWill Newton 	if (dw_mci_submit_data_dma(host, data)) {
584f9c2a0dcSSeungwon Jeon 		int flags = SG_MITER_ATOMIC;
585f9c2a0dcSSeungwon Jeon 		if (host->data->flags & MMC_DATA_READ)
586f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_TO_SG;
587f9c2a0dcSSeungwon Jeon 		else
588f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_FROM_SG;
589f9c2a0dcSSeungwon Jeon 
590f9c2a0dcSSeungwon Jeon 		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
591f95f3850SWill Newton 		host->sg = data->sg;
59234b664a2SJames Hogan 		host->part_buf_start = 0;
59334b664a2SJames Hogan 		host->part_buf_count = 0;
594f95f3850SWill Newton 
595b40af3aaSJames Hogan 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR);
596f95f3850SWill Newton 		temp = mci_readl(host, INTMASK);
597f95f3850SWill Newton 		temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR;
598f95f3850SWill Newton 		mci_writel(host, INTMASK, temp);
599f95f3850SWill Newton 
600f95f3850SWill Newton 		temp = mci_readl(host, CTRL);
601f95f3850SWill Newton 		temp &= ~SDMMC_CTRL_DMA_ENABLE;
602f95f3850SWill Newton 		mci_writel(host, CTRL, temp);
603f95f3850SWill Newton 	}
604f95f3850SWill Newton }
605f95f3850SWill Newton 
606f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
607f95f3850SWill Newton {
608f95f3850SWill Newton 	struct dw_mci *host = slot->host;
609f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
610f95f3850SWill Newton 	unsigned int cmd_status = 0;
611f95f3850SWill Newton 
612f95f3850SWill Newton 	mci_writel(host, CMDARG, arg);
613f95f3850SWill Newton 	wmb();
614f95f3850SWill Newton 	mci_writel(host, CMD, SDMMC_CMD_START | cmd);
615f95f3850SWill Newton 
616f95f3850SWill Newton 	while (time_before(jiffies, timeout)) {
617f95f3850SWill Newton 		cmd_status = mci_readl(host, CMD);
618f95f3850SWill Newton 		if (!(cmd_status & SDMMC_CMD_START))
619f95f3850SWill Newton 			return;
620f95f3850SWill Newton 	}
621f95f3850SWill Newton 	dev_err(&slot->mmc->class_dev,
622f95f3850SWill Newton 		"Timeout sending command (cmd %#x arg %#x status %#x)\n",
623f95f3850SWill Newton 		cmd, arg, cmd_status);
624f95f3850SWill Newton }
625f95f3850SWill Newton 
626ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
627f95f3850SWill Newton {
628f95f3850SWill Newton 	struct dw_mci *host = slot->host;
629fdf492a1SDoug Anderson 	unsigned int clock = slot->clock;
630f95f3850SWill Newton 	u32 div;
6319623b5b9SDoug Anderson 	u32 clk_en_a;
632f95f3850SWill Newton 
633fdf492a1SDoug Anderson 	if (!clock) {
634fdf492a1SDoug Anderson 		mci_writel(host, CLKENA, 0);
635fdf492a1SDoug Anderson 		mci_send_cmd(slot,
636fdf492a1SDoug Anderson 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
637fdf492a1SDoug Anderson 	} else if (clock != host->current_speed || force_clkinit) {
638fdf492a1SDoug Anderson 		div = host->bus_hz / clock;
639fdf492a1SDoug Anderson 		if (host->bus_hz % clock && host->bus_hz > clock)
640f95f3850SWill Newton 			/*
641f95f3850SWill Newton 			 * move the + 1 after the divide to prevent
642f95f3850SWill Newton 			 * over-clocking the card.
643f95f3850SWill Newton 			 */
644e419990bSSeungwon Jeon 			div += 1;
645e419990bSSeungwon Jeon 
646fdf492a1SDoug Anderson 		div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0;
647f95f3850SWill Newton 
648fdf492a1SDoug Anderson 		if ((clock << div) != slot->__clk_old || force_clkinit)
649f95f3850SWill Newton 			dev_info(&slot->mmc->class_dev,
650fdf492a1SDoug Anderson 				 "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
651fdf492a1SDoug Anderson 				 slot->id, host->bus_hz, clock,
652fdf492a1SDoug Anderson 				 div ? ((host->bus_hz / div) >> 1) :
653fdf492a1SDoug Anderson 				 host->bus_hz, div);
654f95f3850SWill Newton 
655f95f3850SWill Newton 		/* disable clock */
656f95f3850SWill Newton 		mci_writel(host, CLKENA, 0);
657f95f3850SWill Newton 		mci_writel(host, CLKSRC, 0);
658f95f3850SWill Newton 
659f95f3850SWill Newton 		/* inform CIU */
660f95f3850SWill Newton 		mci_send_cmd(slot,
661f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
662f95f3850SWill Newton 
663f95f3850SWill Newton 		/* set clock to desired speed */
664f95f3850SWill Newton 		mci_writel(host, CLKDIV, div);
665f95f3850SWill Newton 
666f95f3850SWill Newton 		/* inform CIU */
667f95f3850SWill Newton 		mci_send_cmd(slot,
668f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
669f95f3850SWill Newton 
6709623b5b9SDoug Anderson 		/* enable clock; only low power if no SDIO */
6719623b5b9SDoug Anderson 		clk_en_a = SDMMC_CLKEN_ENABLE << slot->id;
6729623b5b9SDoug Anderson 		if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id)))
6739623b5b9SDoug Anderson 			clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id;
6749623b5b9SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a);
675f95f3850SWill Newton 
676f95f3850SWill Newton 		/* inform CIU */
677f95f3850SWill Newton 		mci_send_cmd(slot,
678f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
679f95f3850SWill Newton 
680fdf492a1SDoug Anderson 		/* keep the clock with reflecting clock dividor */
681fdf492a1SDoug Anderson 		slot->__clk_old = clock << div;
682f95f3850SWill Newton 	}
683f95f3850SWill Newton 
684fdf492a1SDoug Anderson 	host->current_speed = clock;
685fdf492a1SDoug Anderson 
686f95f3850SWill Newton 	/* Set the current slot bus width */
6871d56c453SSeungwon Jeon 	mci_writel(host, CTYPE, (slot->ctype << slot->id));
688f95f3850SWill Newton }
689f95f3850SWill Newton 
690053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host,
691053b3ce6SSeungwon Jeon 				   struct dw_mci_slot *slot,
692053b3ce6SSeungwon Jeon 				   struct mmc_command *cmd)
693f95f3850SWill Newton {
694f95f3850SWill Newton 	struct mmc_request *mrq;
695f95f3850SWill Newton 	struct mmc_data	*data;
696f95f3850SWill Newton 	u32 cmdflags;
697f95f3850SWill Newton 
698f95f3850SWill Newton 	mrq = slot->mrq;
699f95f3850SWill Newton 	if (host->pdata->select_slot)
700f95f3850SWill Newton 		host->pdata->select_slot(slot->id);
701f95f3850SWill Newton 
702f95f3850SWill Newton 	host->cur_slot = slot;
703f95f3850SWill Newton 	host->mrq = mrq;
704f95f3850SWill Newton 
705f95f3850SWill Newton 	host->pending_events = 0;
706f95f3850SWill Newton 	host->completed_events = 0;
707f95f3850SWill Newton 	host->data_status = 0;
708f95f3850SWill Newton 
709053b3ce6SSeungwon Jeon 	data = cmd->data;
710f95f3850SWill Newton 	if (data) {
711f95f3850SWill Newton 		dw_mci_set_timeout(host);
712f95f3850SWill Newton 		mci_writel(host, BYTCNT, data->blksz*data->blocks);
713f95f3850SWill Newton 		mci_writel(host, BLKSIZ, data->blksz);
714f95f3850SWill Newton 	}
715f95f3850SWill Newton 
716f95f3850SWill Newton 	cmdflags = dw_mci_prepare_command(slot->mmc, cmd);
717f95f3850SWill Newton 
718f95f3850SWill Newton 	/* this is the first command, send the initialization clock */
719f95f3850SWill Newton 	if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags))
720f95f3850SWill Newton 		cmdflags |= SDMMC_CMD_INIT;
721f95f3850SWill Newton 
722f95f3850SWill Newton 	if (data) {
723f95f3850SWill Newton 		dw_mci_submit_data(host, data);
724f95f3850SWill Newton 		wmb();
725f95f3850SWill Newton 	}
726f95f3850SWill Newton 
727f95f3850SWill Newton 	dw_mci_start_command(host, cmd, cmdflags);
728f95f3850SWill Newton 
729f95f3850SWill Newton 	if (mrq->stop)
730f95f3850SWill Newton 		host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
731f95f3850SWill Newton }
732f95f3850SWill Newton 
733053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host,
734053b3ce6SSeungwon Jeon 				 struct dw_mci_slot *slot)
735053b3ce6SSeungwon Jeon {
736053b3ce6SSeungwon Jeon 	struct mmc_request *mrq = slot->mrq;
737053b3ce6SSeungwon Jeon 	struct mmc_command *cmd;
738053b3ce6SSeungwon Jeon 
739053b3ce6SSeungwon Jeon 	cmd = mrq->sbc ? mrq->sbc : mrq->cmd;
740053b3ce6SSeungwon Jeon 	__dw_mci_start_request(host, slot, cmd);
741053b3ce6SSeungwon Jeon }
742053b3ce6SSeungwon Jeon 
7437456caaeSJames Hogan /* must be called with host->lock held */
744f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot,
745f95f3850SWill Newton 				 struct mmc_request *mrq)
746f95f3850SWill Newton {
747f95f3850SWill Newton 	dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
748f95f3850SWill Newton 		 host->state);
749f95f3850SWill Newton 
750f95f3850SWill Newton 	slot->mrq = mrq;
751f95f3850SWill Newton 
752f95f3850SWill Newton 	if (host->state == STATE_IDLE) {
753f95f3850SWill Newton 		host->state = STATE_SENDING_CMD;
754f95f3850SWill Newton 		dw_mci_start_request(host, slot);
755f95f3850SWill Newton 	} else {
756f95f3850SWill Newton 		list_add_tail(&slot->queue_node, &host->queue);
757f95f3850SWill Newton 	}
758f95f3850SWill Newton }
759f95f3850SWill Newton 
760f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
761f95f3850SWill Newton {
762f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
763f95f3850SWill Newton 	struct dw_mci *host = slot->host;
764f95f3850SWill Newton 
765f95f3850SWill Newton 	WARN_ON(slot->mrq);
766f95f3850SWill Newton 
7677456caaeSJames Hogan 	/*
7687456caaeSJames Hogan 	 * The check for card presence and queueing of the request must be
7697456caaeSJames Hogan 	 * atomic, otherwise the card could be removed in between and the
7707456caaeSJames Hogan 	 * request wouldn't fail until another card was inserted.
7717456caaeSJames Hogan 	 */
7727456caaeSJames Hogan 	spin_lock_bh(&host->lock);
7737456caaeSJames Hogan 
774f95f3850SWill Newton 	if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
7757456caaeSJames Hogan 		spin_unlock_bh(&host->lock);
776f95f3850SWill Newton 		mrq->cmd->error = -ENOMEDIUM;
777f95f3850SWill Newton 		mmc_request_done(mmc, mrq);
778f95f3850SWill Newton 		return;
779f95f3850SWill Newton 	}
780f95f3850SWill Newton 
781f95f3850SWill Newton 	dw_mci_queue_request(host, slot, mrq);
7827456caaeSJames Hogan 
7837456caaeSJames Hogan 	spin_unlock_bh(&host->lock);
784f95f3850SWill Newton }
785f95f3850SWill Newton 
786f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
787f95f3850SWill Newton {
788f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
789e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
79041babf75SJaehoon Chung 	u32 regs;
791f95f3850SWill Newton 
792f95f3850SWill Newton 	switch (ios->bus_width) {
793f95f3850SWill Newton 	case MMC_BUS_WIDTH_4:
794f95f3850SWill Newton 		slot->ctype = SDMMC_CTYPE_4BIT;
795f95f3850SWill Newton 		break;
796c9b2a06fSJaehoon Chung 	case MMC_BUS_WIDTH_8:
797c9b2a06fSJaehoon Chung 		slot->ctype = SDMMC_CTYPE_8BIT;
798c9b2a06fSJaehoon Chung 		break;
799b2f7cb45SJaehoon Chung 	default:
800b2f7cb45SJaehoon Chung 		/* set default 1 bit mode */
801b2f7cb45SJaehoon Chung 		slot->ctype = SDMMC_CTYPE_1BIT;
802f95f3850SWill Newton 	}
803f95f3850SWill Newton 
80441babf75SJaehoon Chung 	regs = mci_readl(slot->host, UHS_REG);
8053f514291SSeungwon Jeon 
8063f514291SSeungwon Jeon 	/* DDR mode set */
8073f514291SSeungwon Jeon 	if (ios->timing == MMC_TIMING_UHS_DDR50)
808c69042a5SHyeonsu Kim 		regs |= ((0x1 << slot->id) << 16);
8093f514291SSeungwon Jeon 	else
810c69042a5SHyeonsu Kim 		regs &= ~((0x1 << slot->id) << 16);
8113f514291SSeungwon Jeon 
81241babf75SJaehoon Chung 	mci_writel(slot->host, UHS_REG, regs);
81341babf75SJaehoon Chung 
814f95f3850SWill Newton 	/*
815f95f3850SWill Newton 	 * Use mirror of ios->clock to prevent race with mmc
816f95f3850SWill Newton 	 * core ios update when finding the minimum.
817f95f3850SWill Newton 	 */
818f95f3850SWill Newton 	slot->clock = ios->clock;
819f95f3850SWill Newton 
820cb27a843SJames Hogan 	if (drv_data && drv_data->set_ios)
821cb27a843SJames Hogan 		drv_data->set_ios(slot->host, ios);
822800d78bfSThomas Abraham 
823bf7cb224SJaehoon Chung 	/* Slot specific timing and width adjustment */
824bf7cb224SJaehoon Chung 	dw_mci_setup_bus(slot, false);
825bf7cb224SJaehoon Chung 
826f95f3850SWill Newton 	switch (ios->power_mode) {
827f95f3850SWill Newton 	case MMC_POWER_UP:
828f95f3850SWill Newton 		set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
829e6f34e2fSJames Hogan 		/* Power up slot */
830e6f34e2fSJames Hogan 		if (slot->host->pdata->setpower)
831e6f34e2fSJames Hogan 			slot->host->pdata->setpower(slot->id, mmc->ocr_avail);
8324366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
8334366dcc5SJaehoon Chung 		regs |= (1 << slot->id);
8344366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
835e6f34e2fSJames Hogan 		break;
836e6f34e2fSJames Hogan 	case MMC_POWER_OFF:
837e6f34e2fSJames Hogan 		/* Power down slot */
838e6f34e2fSJames Hogan 		if (slot->host->pdata->setpower)
839e6f34e2fSJames Hogan 			slot->host->pdata->setpower(slot->id, 0);
8404366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
8414366dcc5SJaehoon Chung 		regs &= ~(1 << slot->id);
8424366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
843f95f3850SWill Newton 		break;
844f95f3850SWill Newton 	default:
845f95f3850SWill Newton 		break;
846f95f3850SWill Newton 	}
847f95f3850SWill Newton }
848f95f3850SWill Newton 
849f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc)
850f95f3850SWill Newton {
851f95f3850SWill Newton 	int read_only;
852f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
853f95f3850SWill Newton 	struct dw_mci_board *brd = slot->host->pdata;
854f95f3850SWill Newton 
855f95f3850SWill Newton 	/* Use platform get_ro function, else try on board write protect */
8569640639bSDoug Anderson 	if (slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT)
857b4967aa5SThomas Abraham 		read_only = 0;
858b4967aa5SThomas Abraham 	else if (brd->get_ro)
859f95f3850SWill Newton 		read_only = brd->get_ro(slot->id);
86055a6ceb2SDoug Anderson 	else if (gpio_is_valid(slot->wp_gpio))
86155a6ceb2SDoug Anderson 		read_only = gpio_get_value(slot->wp_gpio);
862f95f3850SWill Newton 	else
863f95f3850SWill Newton 		read_only =
864f95f3850SWill Newton 			mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0;
865f95f3850SWill Newton 
866f95f3850SWill Newton 	dev_dbg(&mmc->class_dev, "card is %s\n",
867f95f3850SWill Newton 		read_only ? "read-only" : "read-write");
868f95f3850SWill Newton 
869f95f3850SWill Newton 	return read_only;
870f95f3850SWill Newton }
871f95f3850SWill Newton 
872f95f3850SWill Newton static int dw_mci_get_cd(struct mmc_host *mmc)
873f95f3850SWill Newton {
874f95f3850SWill Newton 	int present;
875f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
876f95f3850SWill Newton 	struct dw_mci_board *brd = slot->host->pdata;
877f95f3850SWill Newton 
878f95f3850SWill Newton 	/* Use platform get_cd function, else try onboard card detect */
879fc3d7720SJaehoon Chung 	if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
880fc3d7720SJaehoon Chung 		present = 1;
881fc3d7720SJaehoon Chung 	else if (brd->get_cd)
882f95f3850SWill Newton 		present = !brd->get_cd(slot->id);
883f95f3850SWill Newton 	else
884f95f3850SWill Newton 		present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
885f95f3850SWill Newton 			== 0 ? 1 : 0;
886f95f3850SWill Newton 
887f95f3850SWill Newton 	if (present)
888f95f3850SWill Newton 		dev_dbg(&mmc->class_dev, "card is present\n");
889f95f3850SWill Newton 	else
890f95f3850SWill Newton 		dev_dbg(&mmc->class_dev, "card is not present\n");
891f95f3850SWill Newton 
892f95f3850SWill Newton 	return present;
893f95f3850SWill Newton }
894f95f3850SWill Newton 
8959623b5b9SDoug Anderson /*
8969623b5b9SDoug Anderson  * Disable lower power mode.
8979623b5b9SDoug Anderson  *
8989623b5b9SDoug Anderson  * Low power mode will stop the card clock when idle.  According to the
8999623b5b9SDoug Anderson  * description of the CLKENA register we should disable low power mode
9009623b5b9SDoug Anderson  * for SDIO cards if we need SDIO interrupts to work.
9019623b5b9SDoug Anderson  *
9029623b5b9SDoug Anderson  * This function is fast if low power mode is already disabled.
9039623b5b9SDoug Anderson  */
9049623b5b9SDoug Anderson static void dw_mci_disable_low_power(struct dw_mci_slot *slot)
9059623b5b9SDoug Anderson {
9069623b5b9SDoug Anderson 	struct dw_mci *host = slot->host;
9079623b5b9SDoug Anderson 	u32 clk_en_a;
9089623b5b9SDoug Anderson 	const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id;
9099623b5b9SDoug Anderson 
9109623b5b9SDoug Anderson 	clk_en_a = mci_readl(host, CLKENA);
9119623b5b9SDoug Anderson 
9129623b5b9SDoug Anderson 	if (clk_en_a & clken_low_pwr) {
9139623b5b9SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr);
9149623b5b9SDoug Anderson 		mci_send_cmd(slot, SDMMC_CMD_UPD_CLK |
9159623b5b9SDoug Anderson 			     SDMMC_CMD_PRV_DAT_WAIT, 0);
9169623b5b9SDoug Anderson 	}
9179623b5b9SDoug Anderson }
9189623b5b9SDoug Anderson 
9191a5c8e1fSShashidhar Hiremath static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
9201a5c8e1fSShashidhar Hiremath {
9211a5c8e1fSShashidhar Hiremath 	struct dw_mci_slot *slot = mmc_priv(mmc);
9221a5c8e1fSShashidhar Hiremath 	struct dw_mci *host = slot->host;
9231a5c8e1fSShashidhar Hiremath 	u32 int_mask;
9241a5c8e1fSShashidhar Hiremath 
9251a5c8e1fSShashidhar Hiremath 	/* Enable/disable Slot Specific SDIO interrupt */
9261a5c8e1fSShashidhar Hiremath 	int_mask = mci_readl(host, INTMASK);
9271a5c8e1fSShashidhar Hiremath 	if (enb) {
9289623b5b9SDoug Anderson 		/*
9299623b5b9SDoug Anderson 		 * Turn off low power mode if it was enabled.  This is a bit of
9309623b5b9SDoug Anderson 		 * a heavy operation and we disable / enable IRQs a lot, so
9319623b5b9SDoug Anderson 		 * we'll leave low power mode disabled and it will get
9329623b5b9SDoug Anderson 		 * re-enabled again in dw_mci_setup_bus().
9339623b5b9SDoug Anderson 		 */
9349623b5b9SDoug Anderson 		dw_mci_disable_low_power(slot);
9359623b5b9SDoug Anderson 
9361a5c8e1fSShashidhar Hiremath 		mci_writel(host, INTMASK,
937705ad047SKyoungil Kim 			   (int_mask | SDMMC_INT_SDIO(slot->id)));
9381a5c8e1fSShashidhar Hiremath 	} else {
9391a5c8e1fSShashidhar Hiremath 		mci_writel(host, INTMASK,
940705ad047SKyoungil Kim 			   (int_mask & ~SDMMC_INT_SDIO(slot->id)));
9411a5c8e1fSShashidhar Hiremath 	}
9421a5c8e1fSShashidhar Hiremath }
9431a5c8e1fSShashidhar Hiremath 
9440976f16dSSeungwon Jeon static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
9450976f16dSSeungwon Jeon {
9460976f16dSSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
9470976f16dSSeungwon Jeon 	struct dw_mci *host = slot->host;
9480976f16dSSeungwon Jeon 	const struct dw_mci_drv_data *drv_data = host->drv_data;
9490976f16dSSeungwon Jeon 	struct dw_mci_tuning_data tuning_data;
9500976f16dSSeungwon Jeon 	int err = -ENOSYS;
9510976f16dSSeungwon Jeon 
9520976f16dSSeungwon Jeon 	if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
9530976f16dSSeungwon Jeon 		if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
9540976f16dSSeungwon Jeon 			tuning_data.blk_pattern = tuning_blk_pattern_8bit;
9550976f16dSSeungwon Jeon 			tuning_data.blksz = sizeof(tuning_blk_pattern_8bit);
9560976f16dSSeungwon Jeon 		} else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
9570976f16dSSeungwon Jeon 			tuning_data.blk_pattern = tuning_blk_pattern_4bit;
9580976f16dSSeungwon Jeon 			tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
9590976f16dSSeungwon Jeon 		} else {
9600976f16dSSeungwon Jeon 			return -EINVAL;
9610976f16dSSeungwon Jeon 		}
9620976f16dSSeungwon Jeon 	} else if (opcode == MMC_SEND_TUNING_BLOCK) {
9630976f16dSSeungwon Jeon 		tuning_data.blk_pattern = tuning_blk_pattern_4bit;
9640976f16dSSeungwon Jeon 		tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
9650976f16dSSeungwon Jeon 	} else {
9660976f16dSSeungwon Jeon 		dev_err(host->dev,
9670976f16dSSeungwon Jeon 			"Undefined command(%d) for tuning\n", opcode);
9680976f16dSSeungwon Jeon 		return -EINVAL;
9690976f16dSSeungwon Jeon 	}
9700976f16dSSeungwon Jeon 
9710976f16dSSeungwon Jeon 	if (drv_data && drv_data->execute_tuning)
9720976f16dSSeungwon Jeon 		err = drv_data->execute_tuning(slot, opcode, &tuning_data);
9730976f16dSSeungwon Jeon 	return err;
9740976f16dSSeungwon Jeon }
9750976f16dSSeungwon Jeon 
976f95f3850SWill Newton static const struct mmc_host_ops dw_mci_ops = {
977f95f3850SWill Newton 	.request		= dw_mci_request,
9789aa51408SSeungwon Jeon 	.pre_req		= dw_mci_pre_req,
9799aa51408SSeungwon Jeon 	.post_req		= dw_mci_post_req,
980f95f3850SWill Newton 	.set_ios		= dw_mci_set_ios,
981f95f3850SWill Newton 	.get_ro			= dw_mci_get_ro,
982f95f3850SWill Newton 	.get_cd			= dw_mci_get_cd,
9831a5c8e1fSShashidhar Hiremath 	.enable_sdio_irq	= dw_mci_enable_sdio_irq,
9840976f16dSSeungwon Jeon 	.execute_tuning		= dw_mci_execute_tuning,
985f95f3850SWill Newton };
986f95f3850SWill Newton 
987f95f3850SWill Newton static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
988f95f3850SWill Newton 	__releases(&host->lock)
989f95f3850SWill Newton 	__acquires(&host->lock)
990f95f3850SWill Newton {
991f95f3850SWill Newton 	struct dw_mci_slot *slot;
992f95f3850SWill Newton 	struct mmc_host	*prev_mmc = host->cur_slot->mmc;
993f95f3850SWill Newton 
994f95f3850SWill Newton 	WARN_ON(host->cmd || host->data);
995f95f3850SWill Newton 
996f95f3850SWill Newton 	host->cur_slot->mrq = NULL;
997f95f3850SWill Newton 	host->mrq = NULL;
998f95f3850SWill Newton 	if (!list_empty(&host->queue)) {
999f95f3850SWill Newton 		slot = list_entry(host->queue.next,
1000f95f3850SWill Newton 				  struct dw_mci_slot, queue_node);
1001f95f3850SWill Newton 		list_del(&slot->queue_node);
10024a90920cSThomas Abraham 		dev_vdbg(host->dev, "list not empty: %s is next\n",
1003f95f3850SWill Newton 			 mmc_hostname(slot->mmc));
1004f95f3850SWill Newton 		host->state = STATE_SENDING_CMD;
1005f95f3850SWill Newton 		dw_mci_start_request(host, slot);
1006f95f3850SWill Newton 	} else {
10074a90920cSThomas Abraham 		dev_vdbg(host->dev, "list empty\n");
1008f95f3850SWill Newton 		host->state = STATE_IDLE;
1009f95f3850SWill Newton 	}
1010f95f3850SWill Newton 
1011f95f3850SWill Newton 	spin_unlock(&host->lock);
1012f95f3850SWill Newton 	mmc_request_done(prev_mmc, mrq);
1013f95f3850SWill Newton 	spin_lock(&host->lock);
1014f95f3850SWill Newton }
1015f95f3850SWill Newton 
1016f95f3850SWill Newton static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
1017f95f3850SWill Newton {
1018f95f3850SWill Newton 	u32 status = host->cmd_status;
1019f95f3850SWill Newton 
1020f95f3850SWill Newton 	host->cmd_status = 0;
1021f95f3850SWill Newton 
1022f95f3850SWill Newton 	/* Read the response from the card (up to 16 bytes) */
1023f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_PRESENT) {
1024f95f3850SWill Newton 		if (cmd->flags & MMC_RSP_136) {
1025f95f3850SWill Newton 			cmd->resp[3] = mci_readl(host, RESP0);
1026f95f3850SWill Newton 			cmd->resp[2] = mci_readl(host, RESP1);
1027f95f3850SWill Newton 			cmd->resp[1] = mci_readl(host, RESP2);
1028f95f3850SWill Newton 			cmd->resp[0] = mci_readl(host, RESP3);
1029f95f3850SWill Newton 		} else {
1030f95f3850SWill Newton 			cmd->resp[0] = mci_readl(host, RESP0);
1031f95f3850SWill Newton 			cmd->resp[1] = 0;
1032f95f3850SWill Newton 			cmd->resp[2] = 0;
1033f95f3850SWill Newton 			cmd->resp[3] = 0;
1034f95f3850SWill Newton 		}
1035f95f3850SWill Newton 	}
1036f95f3850SWill Newton 
1037f95f3850SWill Newton 	if (status & SDMMC_INT_RTO)
1038f95f3850SWill Newton 		cmd->error = -ETIMEDOUT;
1039f95f3850SWill Newton 	else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC))
1040f95f3850SWill Newton 		cmd->error = -EILSEQ;
1041f95f3850SWill Newton 	else if (status & SDMMC_INT_RESP_ERR)
1042f95f3850SWill Newton 		cmd->error = -EIO;
1043f95f3850SWill Newton 	else
1044f95f3850SWill Newton 		cmd->error = 0;
1045f95f3850SWill Newton 
1046f95f3850SWill Newton 	if (cmd->error) {
1047f95f3850SWill Newton 		/* newer ip versions need a delay between retries */
1048f95f3850SWill Newton 		if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY)
1049f95f3850SWill Newton 			mdelay(20);
1050f95f3850SWill Newton 
1051f95f3850SWill Newton 		if (cmd->data) {
1052f95f3850SWill Newton 			dw_mci_stop_dma(host);
1053fda5f736SSeungwon Jeon 			host->data = NULL;
1054f95f3850SWill Newton 		}
1055f95f3850SWill Newton 	}
1056f95f3850SWill Newton }
1057f95f3850SWill Newton 
1058f95f3850SWill Newton static void dw_mci_tasklet_func(unsigned long priv)
1059f95f3850SWill Newton {
1060f95f3850SWill Newton 	struct dw_mci *host = (struct dw_mci *)priv;
1061f95f3850SWill Newton 	struct mmc_data	*data;
1062f95f3850SWill Newton 	struct mmc_command *cmd;
1063f95f3850SWill Newton 	enum dw_mci_state state;
1064f95f3850SWill Newton 	enum dw_mci_state prev_state;
106594dd5b33SJames Hogan 	u32 status, ctrl;
1066f95f3850SWill Newton 
1067f95f3850SWill Newton 	spin_lock(&host->lock);
1068f95f3850SWill Newton 
1069f95f3850SWill Newton 	state = host->state;
1070f95f3850SWill Newton 	data = host->data;
1071f95f3850SWill Newton 
1072f95f3850SWill Newton 	do {
1073f95f3850SWill Newton 		prev_state = state;
1074f95f3850SWill Newton 
1075f95f3850SWill Newton 		switch (state) {
1076f95f3850SWill Newton 		case STATE_IDLE:
1077f95f3850SWill Newton 			break;
1078f95f3850SWill Newton 
1079f95f3850SWill Newton 		case STATE_SENDING_CMD:
1080f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1081f95f3850SWill Newton 						&host->pending_events))
1082f95f3850SWill Newton 				break;
1083f95f3850SWill Newton 
1084f95f3850SWill Newton 			cmd = host->cmd;
1085f95f3850SWill Newton 			host->cmd = NULL;
1086f95f3850SWill Newton 			set_bit(EVENT_CMD_COMPLETE, &host->completed_events);
1087053b3ce6SSeungwon Jeon 			dw_mci_command_complete(host, cmd);
1088053b3ce6SSeungwon Jeon 			if (cmd == host->mrq->sbc && !cmd->error) {
1089053b3ce6SSeungwon Jeon 				prev_state = state = STATE_SENDING_CMD;
1090053b3ce6SSeungwon Jeon 				__dw_mci_start_request(host, host->cur_slot,
1091053b3ce6SSeungwon Jeon 						       host->mrq->cmd);
1092053b3ce6SSeungwon Jeon 				goto unlock;
1093053b3ce6SSeungwon Jeon 			}
1094053b3ce6SSeungwon Jeon 
1095f95f3850SWill Newton 			if (!host->mrq->data || cmd->error) {
1096f95f3850SWill Newton 				dw_mci_request_end(host, host->mrq);
1097f95f3850SWill Newton 				goto unlock;
1098f95f3850SWill Newton 			}
1099f95f3850SWill Newton 
1100f95f3850SWill Newton 			prev_state = state = STATE_SENDING_DATA;
1101f95f3850SWill Newton 			/* fall through */
1102f95f3850SWill Newton 
1103f95f3850SWill Newton 		case STATE_SENDING_DATA:
1104f95f3850SWill Newton 			if (test_and_clear_bit(EVENT_DATA_ERROR,
1105f95f3850SWill Newton 					       &host->pending_events)) {
1106f95f3850SWill Newton 				dw_mci_stop_dma(host);
1107f95f3850SWill Newton 				if (data->stop)
1108f95f3850SWill Newton 					send_stop_cmd(host, data);
1109f95f3850SWill Newton 				state = STATE_DATA_ERROR;
1110f95f3850SWill Newton 				break;
1111f95f3850SWill Newton 			}
1112f95f3850SWill Newton 
1113f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1114f95f3850SWill Newton 						&host->pending_events))
1115f95f3850SWill Newton 				break;
1116f95f3850SWill Newton 
1117f95f3850SWill Newton 			set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
1118f95f3850SWill Newton 			prev_state = state = STATE_DATA_BUSY;
1119f95f3850SWill Newton 			/* fall through */
1120f95f3850SWill Newton 
1121f95f3850SWill Newton 		case STATE_DATA_BUSY:
1122f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
1123f95f3850SWill Newton 						&host->pending_events))
1124f95f3850SWill Newton 				break;
1125f95f3850SWill Newton 
1126f95f3850SWill Newton 			host->data = NULL;
1127f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
1128f95f3850SWill Newton 			status = host->data_status;
1129f95f3850SWill Newton 
1130f95f3850SWill Newton 			if (status & DW_MCI_DATA_ERROR_FLAGS) {
11313f7eec62SJaehoon Chung 				if (status & SDMMC_INT_DRTO) {
1132f95f3850SWill Newton 					data->error = -ETIMEDOUT;
1133f95f3850SWill Newton 				} else if (status & SDMMC_INT_DCRC) {
1134f95f3850SWill Newton 					data->error = -EILSEQ;
113555c5efbcSJames Hogan 				} else if (status & SDMMC_INT_EBE &&
113655c5efbcSJames Hogan 					   host->dir_status ==
113755c5efbcSJames Hogan 							DW_MCI_SEND_STATUS) {
113855c5efbcSJames Hogan 					/*
113955c5efbcSJames Hogan 					 * No data CRC status was returned.
114055c5efbcSJames Hogan 					 * The number of bytes transferred will
114155c5efbcSJames Hogan 					 * be exaggerated in PIO mode.
114255c5efbcSJames Hogan 					 */
114355c5efbcSJames Hogan 					data->bytes_xfered = 0;
114455c5efbcSJames Hogan 					data->error = -ETIMEDOUT;
1145f95f3850SWill Newton 				} else {
11464a90920cSThomas Abraham 					dev_err(host->dev,
1147f95f3850SWill Newton 						"data FIFO error "
1148f95f3850SWill Newton 						"(status=%08x)\n",
1149f95f3850SWill Newton 						status);
1150f95f3850SWill Newton 					data->error = -EIO;
1151f95f3850SWill Newton 				}
115294dd5b33SJames Hogan 				/*
115394dd5b33SJames Hogan 				 * After an error, there may be data lingering
115494dd5b33SJames Hogan 				 * in the FIFO, so reset it - doing so
115594dd5b33SJames Hogan 				 * generates a block interrupt, hence setting
115694dd5b33SJames Hogan 				 * the scatter-gather pointer to NULL.
115794dd5b33SJames Hogan 				 */
1158f9c2a0dcSSeungwon Jeon 				sg_miter_stop(&host->sg_miter);
115994dd5b33SJames Hogan 				host->sg = NULL;
116094dd5b33SJames Hogan 				ctrl = mci_readl(host, CTRL);
116194dd5b33SJames Hogan 				ctrl |= SDMMC_CTRL_FIFO_RESET;
116294dd5b33SJames Hogan 				mci_writel(host, CTRL, ctrl);
1163f95f3850SWill Newton 			} else {
1164f95f3850SWill Newton 				data->bytes_xfered = data->blocks * data->blksz;
1165f95f3850SWill Newton 				data->error = 0;
1166f95f3850SWill Newton 			}
1167f95f3850SWill Newton 
1168f95f3850SWill Newton 			if (!data->stop) {
1169f95f3850SWill Newton 				dw_mci_request_end(host, host->mrq);
1170f95f3850SWill Newton 				goto unlock;
1171f95f3850SWill Newton 			}
1172f95f3850SWill Newton 
1173053b3ce6SSeungwon Jeon 			if (host->mrq->sbc && !data->error) {
1174053b3ce6SSeungwon Jeon 				data->stop->error = 0;
1175053b3ce6SSeungwon Jeon 				dw_mci_request_end(host, host->mrq);
1176053b3ce6SSeungwon Jeon 				goto unlock;
1177053b3ce6SSeungwon Jeon 			}
1178053b3ce6SSeungwon Jeon 
1179f95f3850SWill Newton 			prev_state = state = STATE_SENDING_STOP;
1180f95f3850SWill Newton 			if (!data->error)
1181f95f3850SWill Newton 				send_stop_cmd(host, data);
1182f95f3850SWill Newton 			/* fall through */
1183f95f3850SWill Newton 
1184f95f3850SWill Newton 		case STATE_SENDING_STOP:
1185f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1186f95f3850SWill Newton 						&host->pending_events))
1187f95f3850SWill Newton 				break;
1188f95f3850SWill Newton 
1189f95f3850SWill Newton 			host->cmd = NULL;
1190f95f3850SWill Newton 			dw_mci_command_complete(host, host->mrq->stop);
1191f95f3850SWill Newton 			dw_mci_request_end(host, host->mrq);
1192f95f3850SWill Newton 			goto unlock;
1193f95f3850SWill Newton 
1194f95f3850SWill Newton 		case STATE_DATA_ERROR:
1195f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1196f95f3850SWill Newton 						&host->pending_events))
1197f95f3850SWill Newton 				break;
1198f95f3850SWill Newton 
1199f95f3850SWill Newton 			state = STATE_DATA_BUSY;
1200f95f3850SWill Newton 			break;
1201f95f3850SWill Newton 		}
1202f95f3850SWill Newton 	} while (state != prev_state);
1203f95f3850SWill Newton 
1204f95f3850SWill Newton 	host->state = state;
1205f95f3850SWill Newton unlock:
1206f95f3850SWill Newton 	spin_unlock(&host->lock);
1207f95f3850SWill Newton 
1208f95f3850SWill Newton }
1209f95f3850SWill Newton 
121034b664a2SJames Hogan /* push final bytes to part_buf, only use during push */
121134b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt)
121234b664a2SJames Hogan {
121334b664a2SJames Hogan 	memcpy((void *)&host->part_buf, buf, cnt);
121434b664a2SJames Hogan 	host->part_buf_count = cnt;
121534b664a2SJames Hogan }
121634b664a2SJames Hogan 
121734b664a2SJames Hogan /* append bytes to part_buf, only use during push */
121834b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt)
121934b664a2SJames Hogan {
122034b664a2SJames Hogan 	cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count);
122134b664a2SJames Hogan 	memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt);
122234b664a2SJames Hogan 	host->part_buf_count += cnt;
122334b664a2SJames Hogan 	return cnt;
122434b664a2SJames Hogan }
122534b664a2SJames Hogan 
122634b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */
122734b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt)
122834b664a2SJames Hogan {
122934b664a2SJames Hogan 	cnt = min(cnt, (int)host->part_buf_count);
123034b664a2SJames Hogan 	if (cnt) {
123134b664a2SJames Hogan 		memcpy(buf, (void *)&host->part_buf + host->part_buf_start,
123234b664a2SJames Hogan 		       cnt);
123334b664a2SJames Hogan 		host->part_buf_count -= cnt;
123434b664a2SJames Hogan 		host->part_buf_start += cnt;
123534b664a2SJames Hogan 	}
123634b664a2SJames Hogan 	return cnt;
123734b664a2SJames Hogan }
123834b664a2SJames Hogan 
123934b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */
124034b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt)
124134b664a2SJames Hogan {
124234b664a2SJames Hogan 	memcpy(buf, &host->part_buf, cnt);
124334b664a2SJames Hogan 	host->part_buf_start = cnt;
124434b664a2SJames Hogan 	host->part_buf_count = (1 << host->data_shift) - cnt;
124534b664a2SJames Hogan }
124634b664a2SJames Hogan 
1247f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
1248f95f3850SWill Newton {
1249cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1250cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1251cfbeb59cSMarkos Chandras 
125234b664a2SJames Hogan 	/* try and push anything in the part_buf */
125334b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
125434b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
125534b664a2SJames Hogan 		buf += len;
125634b664a2SJames Hogan 		cnt -= len;
1257cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 2) {
12584e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
12594e0a5adfSJaehoon Chung 					host->part_buf16);
126034b664a2SJames Hogan 			host->part_buf_count = 0;
126134b664a2SJames Hogan 		}
126234b664a2SJames Hogan 	}
126334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
126434b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
126534b664a2SJames Hogan 		while (cnt >= 2) {
126634b664a2SJames Hogan 			u16 aligned_buf[64];
126734b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
126834b664a2SJames Hogan 			int items = len >> 1;
126934b664a2SJames Hogan 			int i;
127034b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
127134b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
127234b664a2SJames Hogan 			buf += len;
127334b664a2SJames Hogan 			cnt -= len;
127434b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
127534b664a2SJames Hogan 			for (i = 0; i < items; ++i)
12764e0a5adfSJaehoon Chung 				mci_writew(host, DATA(host->data_offset),
12774e0a5adfSJaehoon Chung 						aligned_buf[i]);
127834b664a2SJames Hogan 		}
127934b664a2SJames Hogan 	} else
128034b664a2SJames Hogan #endif
128134b664a2SJames Hogan 	{
128234b664a2SJames Hogan 		u16 *pdata = buf;
128334b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
12844e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset), *pdata++);
128534b664a2SJames Hogan 		buf = pdata;
128634b664a2SJames Hogan 	}
128734b664a2SJames Hogan 	/* put anything remaining in the part_buf */
128834b664a2SJames Hogan 	if (cnt) {
128934b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1290cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1291cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1292cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
12934e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
12944e0a5adfSJaehoon Chung 				   host->part_buf16);
1295f95f3850SWill Newton 	}
1296f95f3850SWill Newton }
1297f95f3850SWill Newton 
1298f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
1299f95f3850SWill Newton {
130034b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
130134b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
130234b664a2SJames Hogan 		while (cnt >= 2) {
130334b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
130434b664a2SJames Hogan 			u16 aligned_buf[64];
130534b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
130634b664a2SJames Hogan 			int items = len >> 1;
130734b664a2SJames Hogan 			int i;
130834b664a2SJames Hogan 			for (i = 0; i < items; ++i)
13094e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readw(host,
13104e0a5adfSJaehoon Chung 						DATA(host->data_offset));
131134b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
131234b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
131334b664a2SJames Hogan 			buf += len;
131434b664a2SJames Hogan 			cnt -= len;
131534b664a2SJames Hogan 		}
131634b664a2SJames Hogan 	} else
131734b664a2SJames Hogan #endif
131834b664a2SJames Hogan 	{
131934b664a2SJames Hogan 		u16 *pdata = buf;
132034b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
13214e0a5adfSJaehoon Chung 			*pdata++ = mci_readw(host, DATA(host->data_offset));
132234b664a2SJames Hogan 		buf = pdata;
132334b664a2SJames Hogan 	}
132434b664a2SJames Hogan 	if (cnt) {
13254e0a5adfSJaehoon Chung 		host->part_buf16 = mci_readw(host, DATA(host->data_offset));
132634b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1327f95f3850SWill Newton 	}
1328f95f3850SWill Newton }
1329f95f3850SWill Newton 
1330f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
1331f95f3850SWill Newton {
1332cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1333cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1334cfbeb59cSMarkos Chandras 
133534b664a2SJames Hogan 	/* try and push anything in the part_buf */
133634b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
133734b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
133834b664a2SJames Hogan 		buf += len;
133934b664a2SJames Hogan 		cnt -= len;
1340cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 4) {
13414e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
13424e0a5adfSJaehoon Chung 					host->part_buf32);
134334b664a2SJames Hogan 			host->part_buf_count = 0;
134434b664a2SJames Hogan 		}
134534b664a2SJames Hogan 	}
134634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
134734b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
134834b664a2SJames Hogan 		while (cnt >= 4) {
134934b664a2SJames Hogan 			u32 aligned_buf[32];
135034b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
135134b664a2SJames Hogan 			int items = len >> 2;
135234b664a2SJames Hogan 			int i;
135334b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
135434b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
135534b664a2SJames Hogan 			buf += len;
135634b664a2SJames Hogan 			cnt -= len;
135734b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
135834b664a2SJames Hogan 			for (i = 0; i < items; ++i)
13594e0a5adfSJaehoon Chung 				mci_writel(host, DATA(host->data_offset),
13604e0a5adfSJaehoon Chung 						aligned_buf[i]);
136134b664a2SJames Hogan 		}
136234b664a2SJames Hogan 	} else
136334b664a2SJames Hogan #endif
136434b664a2SJames Hogan 	{
136534b664a2SJames Hogan 		u32 *pdata = buf;
136634b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
13674e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset), *pdata++);
136834b664a2SJames Hogan 		buf = pdata;
136934b664a2SJames Hogan 	}
137034b664a2SJames Hogan 	/* put anything remaining in the part_buf */
137134b664a2SJames Hogan 	if (cnt) {
137234b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1373cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1374cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1375cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
13764e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
13774e0a5adfSJaehoon Chung 				   host->part_buf32);
1378f95f3850SWill Newton 	}
1379f95f3850SWill Newton }
1380f95f3850SWill Newton 
1381f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
1382f95f3850SWill Newton {
138334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
138434b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
138534b664a2SJames Hogan 		while (cnt >= 4) {
138634b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
138734b664a2SJames Hogan 			u32 aligned_buf[32];
138834b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
138934b664a2SJames Hogan 			int items = len >> 2;
139034b664a2SJames Hogan 			int i;
139134b664a2SJames Hogan 			for (i = 0; i < items; ++i)
13924e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readl(host,
13934e0a5adfSJaehoon Chung 						DATA(host->data_offset));
139434b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
139534b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
139634b664a2SJames Hogan 			buf += len;
139734b664a2SJames Hogan 			cnt -= len;
139834b664a2SJames Hogan 		}
139934b664a2SJames Hogan 	} else
140034b664a2SJames Hogan #endif
140134b664a2SJames Hogan 	{
140234b664a2SJames Hogan 		u32 *pdata = buf;
140334b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
14044e0a5adfSJaehoon Chung 			*pdata++ = mci_readl(host, DATA(host->data_offset));
140534b664a2SJames Hogan 		buf = pdata;
140634b664a2SJames Hogan 	}
140734b664a2SJames Hogan 	if (cnt) {
14084e0a5adfSJaehoon Chung 		host->part_buf32 = mci_readl(host, DATA(host->data_offset));
140934b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1410f95f3850SWill Newton 	}
1411f95f3850SWill Newton }
1412f95f3850SWill Newton 
1413f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
1414f95f3850SWill Newton {
1415cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1416cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1417cfbeb59cSMarkos Chandras 
141834b664a2SJames Hogan 	/* try and push anything in the part_buf */
141934b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
142034b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
142134b664a2SJames Hogan 		buf += len;
142234b664a2SJames Hogan 		cnt -= len;
1423c09fbd74SSeungwon Jeon 
1424cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 8) {
1425c09fbd74SSeungwon Jeon 			mci_writeq(host, DATA(host->data_offset),
14264e0a5adfSJaehoon Chung 					host->part_buf);
142734b664a2SJames Hogan 			host->part_buf_count = 0;
142834b664a2SJames Hogan 		}
142934b664a2SJames Hogan 	}
143034b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
143134b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
143234b664a2SJames Hogan 		while (cnt >= 8) {
143334b664a2SJames Hogan 			u64 aligned_buf[16];
143434b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
143534b664a2SJames Hogan 			int items = len >> 3;
143634b664a2SJames Hogan 			int i;
143734b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
143834b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
143934b664a2SJames Hogan 			buf += len;
144034b664a2SJames Hogan 			cnt -= len;
144134b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
144234b664a2SJames Hogan 			for (i = 0; i < items; ++i)
14434e0a5adfSJaehoon Chung 				mci_writeq(host, DATA(host->data_offset),
14444e0a5adfSJaehoon Chung 						aligned_buf[i]);
144534b664a2SJames Hogan 		}
144634b664a2SJames Hogan 	} else
144734b664a2SJames Hogan #endif
144834b664a2SJames Hogan 	{
144934b664a2SJames Hogan 		u64 *pdata = buf;
145034b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
14514e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset), *pdata++);
145234b664a2SJames Hogan 		buf = pdata;
145334b664a2SJames Hogan 	}
145434b664a2SJames Hogan 	/* put anything remaining in the part_buf */
145534b664a2SJames Hogan 	if (cnt) {
145634b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1457cfbeb59cSMarkos Chandras 		/* Push data if we have reached the expected data length */
1458cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1459cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
14604e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset),
14614e0a5adfSJaehoon Chung 				   host->part_buf);
1462f95f3850SWill Newton 	}
1463f95f3850SWill Newton }
1464f95f3850SWill Newton 
1465f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
1466f95f3850SWill Newton {
146734b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
146834b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
146934b664a2SJames Hogan 		while (cnt >= 8) {
147034b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
147134b664a2SJames Hogan 			u64 aligned_buf[16];
147234b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
147334b664a2SJames Hogan 			int items = len >> 3;
147434b664a2SJames Hogan 			int i;
147534b664a2SJames Hogan 			for (i = 0; i < items; ++i)
14764e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readq(host,
14774e0a5adfSJaehoon Chung 						DATA(host->data_offset));
147834b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
147934b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
148034b664a2SJames Hogan 			buf += len;
148134b664a2SJames Hogan 			cnt -= len;
1482f95f3850SWill Newton 		}
148334b664a2SJames Hogan 	} else
148434b664a2SJames Hogan #endif
148534b664a2SJames Hogan 	{
148634b664a2SJames Hogan 		u64 *pdata = buf;
148734b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
14884e0a5adfSJaehoon Chung 			*pdata++ = mci_readq(host, DATA(host->data_offset));
148934b664a2SJames Hogan 		buf = pdata;
149034b664a2SJames Hogan 	}
149134b664a2SJames Hogan 	if (cnt) {
14924e0a5adfSJaehoon Chung 		host->part_buf = mci_readq(host, DATA(host->data_offset));
149334b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
149434b664a2SJames Hogan 	}
149534b664a2SJames Hogan }
149634b664a2SJames Hogan 
149734b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
149834b664a2SJames Hogan {
149934b664a2SJames Hogan 	int len;
150034b664a2SJames Hogan 
150134b664a2SJames Hogan 	/* get remaining partial bytes */
150234b664a2SJames Hogan 	len = dw_mci_pull_part_bytes(host, buf, cnt);
150334b664a2SJames Hogan 	if (unlikely(len == cnt))
150434b664a2SJames Hogan 		return;
150534b664a2SJames Hogan 	buf += len;
150634b664a2SJames Hogan 	cnt -= len;
150734b664a2SJames Hogan 
150834b664a2SJames Hogan 	/* get the rest of the data */
150934b664a2SJames Hogan 	host->pull_data(host, buf, cnt);
1510f95f3850SWill Newton }
1511f95f3850SWill Newton 
151287a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto)
1513f95f3850SWill Newton {
1514f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1515f9c2a0dcSSeungwon Jeon 	void *buf;
1516f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1517f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1518f95f3850SWill Newton 	int shift = host->data_shift;
1519f95f3850SWill Newton 	u32 status;
15203e4b0d8bSMarkos Chandras 	unsigned int len;
1521f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1522f95f3850SWill Newton 
1523f95f3850SWill Newton 	do {
1524f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1525f9c2a0dcSSeungwon Jeon 			goto done;
1526f95f3850SWill Newton 
15274225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1528f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1529f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1530f9c2a0dcSSeungwon Jeon 		offset = 0;
1531f9c2a0dcSSeungwon Jeon 
1532f9c2a0dcSSeungwon Jeon 		do {
1533f9c2a0dcSSeungwon Jeon 			fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS))
1534f9c2a0dcSSeungwon Jeon 					<< shift) + host->part_buf_count;
1535f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1536f9c2a0dcSSeungwon Jeon 			if (!len)
1537f9c2a0dcSSeungwon Jeon 				break;
1538f9c2a0dcSSeungwon Jeon 			dw_mci_pull_data(host, (void *)(buf + offset), len);
15393e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1540f95f3850SWill Newton 			offset += len;
1541f9c2a0dcSSeungwon Jeon 			remain -= len;
1542f9c2a0dcSSeungwon Jeon 		} while (remain);
1543f95f3850SWill Newton 
1544e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1545f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1546f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
154787a74d39SKyoungil Kim 	/* if the RXDR is ready read again */
154887a74d39SKyoungil Kim 	} while ((status & SDMMC_INT_RXDR) ||
154987a74d39SKyoungil Kim 		 (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS))));
1550f9c2a0dcSSeungwon Jeon 
1551f9c2a0dcSSeungwon Jeon 	if (!remain) {
1552f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1553f9c2a0dcSSeungwon Jeon 			goto done;
1554f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1555f9c2a0dcSSeungwon Jeon 	}
1556f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1557f95f3850SWill Newton 	return;
1558f95f3850SWill Newton 
1559f95f3850SWill Newton done:
1560f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1561f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1562f95f3850SWill Newton 	smp_wmb();
1563f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1564f95f3850SWill Newton }
1565f95f3850SWill Newton 
1566f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host)
1567f95f3850SWill Newton {
1568f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1569f9c2a0dcSSeungwon Jeon 	void *buf;
1570f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1571f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1572f95f3850SWill Newton 	int shift = host->data_shift;
1573f95f3850SWill Newton 	u32 status;
15743e4b0d8bSMarkos Chandras 	unsigned int len;
1575f9c2a0dcSSeungwon Jeon 	unsigned int fifo_depth = host->fifo_depth;
1576f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1577f95f3850SWill Newton 
1578f95f3850SWill Newton 	do {
1579f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1580f9c2a0dcSSeungwon Jeon 			goto done;
1581f95f3850SWill Newton 
15824225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1583f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1584f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1585f9c2a0dcSSeungwon Jeon 		offset = 0;
1586f9c2a0dcSSeungwon Jeon 
1587f9c2a0dcSSeungwon Jeon 		do {
1588f9c2a0dcSSeungwon Jeon 			fcnt = ((fifo_depth -
1589f9c2a0dcSSeungwon Jeon 				 SDMMC_GET_FCNT(mci_readl(host, STATUS)))
1590f9c2a0dcSSeungwon Jeon 					<< shift) - host->part_buf_count;
1591f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1592f9c2a0dcSSeungwon Jeon 			if (!len)
1593f9c2a0dcSSeungwon Jeon 				break;
1594f9c2a0dcSSeungwon Jeon 			host->push_data(host, (void *)(buf + offset), len);
15953e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1596f95f3850SWill Newton 			offset += len;
1597f9c2a0dcSSeungwon Jeon 			remain -= len;
1598f9c2a0dcSSeungwon Jeon 		} while (remain);
1599f95f3850SWill Newton 
1600e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1601f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1602f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1603f95f3850SWill Newton 	} while (status & SDMMC_INT_TXDR); /* if TXDR write again */
1604f9c2a0dcSSeungwon Jeon 
1605f9c2a0dcSSeungwon Jeon 	if (!remain) {
1606f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1607f9c2a0dcSSeungwon Jeon 			goto done;
1608f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1609f9c2a0dcSSeungwon Jeon 	}
1610f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1611f95f3850SWill Newton 	return;
1612f95f3850SWill Newton 
1613f95f3850SWill Newton done:
1614f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1615f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1616f95f3850SWill Newton 	smp_wmb();
1617f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1618f95f3850SWill Newton }
1619f95f3850SWill Newton 
1620f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
1621f95f3850SWill Newton {
1622f95f3850SWill Newton 	if (!host->cmd_status)
1623f95f3850SWill Newton 		host->cmd_status = status;
1624f95f3850SWill Newton 
1625f95f3850SWill Newton 	smp_wmb();
1626f95f3850SWill Newton 
1627f95f3850SWill Newton 	set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1628f95f3850SWill Newton 	tasklet_schedule(&host->tasklet);
1629f95f3850SWill Newton }
1630f95f3850SWill Newton 
1631f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
1632f95f3850SWill Newton {
1633f95f3850SWill Newton 	struct dw_mci *host = dev_id;
1634182c9081SSeungwon Jeon 	u32 pending;
16351a5c8e1fSShashidhar Hiremath 	int i;
1636f95f3850SWill Newton 
1637f95f3850SWill Newton 	pending = mci_readl(host, MINTSTS); /* read-only mask reg */
1638f95f3850SWill Newton 
1639f95f3850SWill Newton 	/*
1640f95f3850SWill Newton 	 * DTO fix - version 2.10a and below, and only if internal DMA
1641f95f3850SWill Newton 	 * is configured.
1642f95f3850SWill Newton 	 */
1643f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
1644f95f3850SWill Newton 		if (!pending &&
1645f95f3850SWill Newton 		    ((mci_readl(host, STATUS) >> 17) & 0x1fff))
1646f95f3850SWill Newton 			pending |= SDMMC_INT_DATA_OVER;
1647f95f3850SWill Newton 	}
1648f95f3850SWill Newton 
1649476d79f1SDoug Anderson 	if (pending) {
1650f95f3850SWill Newton 		if (pending & DW_MCI_CMD_ERROR_FLAGS) {
1651f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
1652182c9081SSeungwon Jeon 			host->cmd_status = pending;
1653f95f3850SWill Newton 			smp_wmb();
1654f95f3850SWill Newton 			set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1655f95f3850SWill Newton 		}
1656f95f3850SWill Newton 
1657f95f3850SWill Newton 		if (pending & DW_MCI_DATA_ERROR_FLAGS) {
1658f95f3850SWill Newton 			/* if there is an error report DATA_ERROR */
1659f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
1660182c9081SSeungwon Jeon 			host->data_status = pending;
1661f95f3850SWill Newton 			smp_wmb();
1662f95f3850SWill Newton 			set_bit(EVENT_DATA_ERROR, &host->pending_events);
1663f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
1664f95f3850SWill Newton 		}
1665f95f3850SWill Newton 
1666f95f3850SWill Newton 		if (pending & SDMMC_INT_DATA_OVER) {
1667f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
1668f95f3850SWill Newton 			if (!host->data_status)
1669182c9081SSeungwon Jeon 				host->data_status = pending;
1670f95f3850SWill Newton 			smp_wmb();
1671f95f3850SWill Newton 			if (host->dir_status == DW_MCI_RECV_STATUS) {
1672f95f3850SWill Newton 				if (host->sg != NULL)
167387a74d39SKyoungil Kim 					dw_mci_read_data_pio(host, true);
1674f95f3850SWill Newton 			}
1675f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
1676f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
1677f95f3850SWill Newton 		}
1678f95f3850SWill Newton 
1679f95f3850SWill Newton 		if (pending & SDMMC_INT_RXDR) {
1680f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
1681b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_RECV_STATUS && host->sg)
168287a74d39SKyoungil Kim 				dw_mci_read_data_pio(host, false);
1683f95f3850SWill Newton 		}
1684f95f3850SWill Newton 
1685f95f3850SWill Newton 		if (pending & SDMMC_INT_TXDR) {
1686f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1687b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_SEND_STATUS && host->sg)
1688f95f3850SWill Newton 				dw_mci_write_data_pio(host);
1689f95f3850SWill Newton 		}
1690f95f3850SWill Newton 
1691f95f3850SWill Newton 		if (pending & SDMMC_INT_CMD_DONE) {
1692f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
1693182c9081SSeungwon Jeon 			dw_mci_cmd_interrupt(host, pending);
1694f95f3850SWill Newton 		}
1695f95f3850SWill Newton 
1696f95f3850SWill Newton 		if (pending & SDMMC_INT_CD) {
1697f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CD);
169895dcc2cbSThomas Abraham 			queue_work(host->card_workqueue, &host->card_work);
1699f95f3850SWill Newton 		}
1700f95f3850SWill Newton 
17011a5c8e1fSShashidhar Hiremath 		/* Handle SDIO Interrupts */
17021a5c8e1fSShashidhar Hiremath 		for (i = 0; i < host->num_slots; i++) {
17031a5c8e1fSShashidhar Hiremath 			struct dw_mci_slot *slot = host->slot[i];
17041a5c8e1fSShashidhar Hiremath 			if (pending & SDMMC_INT_SDIO(i)) {
17051a5c8e1fSShashidhar Hiremath 				mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
17061a5c8e1fSShashidhar Hiremath 				mmc_signal_sdio_irq(slot->mmc);
17071a5c8e1fSShashidhar Hiremath 			}
17081a5c8e1fSShashidhar Hiremath 		}
17091a5c8e1fSShashidhar Hiremath 
17101fb5f68aSMarkos Chandras 	}
1711f95f3850SWill Newton 
1712f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
1713f95f3850SWill Newton 	/* Handle DMA interrupts */
1714f95f3850SWill Newton 	pending = mci_readl(host, IDSTS);
1715f95f3850SWill Newton 	if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
1716f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
1717f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
1718f95f3850SWill Newton 		host->dma_ops->complete(host);
1719f95f3850SWill Newton 	}
1720f95f3850SWill Newton #endif
1721f95f3850SWill Newton 
1722f95f3850SWill Newton 	return IRQ_HANDLED;
1723f95f3850SWill Newton }
1724f95f3850SWill Newton 
17251791b13eSJames Hogan static void dw_mci_work_routine_card(struct work_struct *work)
1726f95f3850SWill Newton {
17271791b13eSJames Hogan 	struct dw_mci *host = container_of(work, struct dw_mci, card_work);
1728f95f3850SWill Newton 	int i;
1729f95f3850SWill Newton 
1730f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
1731f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
1732f95f3850SWill Newton 		struct mmc_host *mmc = slot->mmc;
1733f95f3850SWill Newton 		struct mmc_request *mrq;
1734f95f3850SWill Newton 		int present;
1735f95f3850SWill Newton 		u32 ctrl;
1736f95f3850SWill Newton 
1737f95f3850SWill Newton 		present = dw_mci_get_cd(mmc);
1738f95f3850SWill Newton 		while (present != slot->last_detect_state) {
1739f95f3850SWill Newton 			dev_dbg(&slot->mmc->class_dev, "card %s\n",
1740f95f3850SWill Newton 				present ? "inserted" : "removed");
1741f95f3850SWill Newton 
17421791b13eSJames Hogan 			spin_lock_bh(&host->lock);
17431791b13eSJames Hogan 
1744f95f3850SWill Newton 			/* Card change detected */
1745f95f3850SWill Newton 			slot->last_detect_state = present;
1746f95f3850SWill Newton 
17471791b13eSJames Hogan 			/* Mark card as present if applicable */
17481791b13eSJames Hogan 			if (present != 0)
1749f95f3850SWill Newton 				set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
1750f95f3850SWill Newton 
1751f95f3850SWill Newton 			/* Clean up queue if present */
1752f95f3850SWill Newton 			mrq = slot->mrq;
1753f95f3850SWill Newton 			if (mrq) {
1754f95f3850SWill Newton 				if (mrq == host->mrq) {
1755f95f3850SWill Newton 					host->data = NULL;
1756f95f3850SWill Newton 					host->cmd = NULL;
1757f95f3850SWill Newton 
1758f95f3850SWill Newton 					switch (host->state) {
1759f95f3850SWill Newton 					case STATE_IDLE:
1760f95f3850SWill Newton 						break;
1761f95f3850SWill Newton 					case STATE_SENDING_CMD:
1762f95f3850SWill Newton 						mrq->cmd->error = -ENOMEDIUM;
1763f95f3850SWill Newton 						if (!mrq->data)
1764f95f3850SWill Newton 							break;
1765f95f3850SWill Newton 						/* fall through */
1766f95f3850SWill Newton 					case STATE_SENDING_DATA:
1767f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
1768f95f3850SWill Newton 						dw_mci_stop_dma(host);
1769f95f3850SWill Newton 						break;
1770f95f3850SWill Newton 					case STATE_DATA_BUSY:
1771f95f3850SWill Newton 					case STATE_DATA_ERROR:
1772f95f3850SWill Newton 						if (mrq->data->error == -EINPROGRESS)
1773f95f3850SWill Newton 							mrq->data->error = -ENOMEDIUM;
1774f95f3850SWill Newton 						if (!mrq->stop)
1775f95f3850SWill Newton 							break;
1776f95f3850SWill Newton 						/* fall through */
1777f95f3850SWill Newton 					case STATE_SENDING_STOP:
1778f95f3850SWill Newton 						mrq->stop->error = -ENOMEDIUM;
1779f95f3850SWill Newton 						break;
1780f95f3850SWill Newton 					}
1781f95f3850SWill Newton 
1782f95f3850SWill Newton 					dw_mci_request_end(host, mrq);
1783f95f3850SWill Newton 				} else {
1784f95f3850SWill Newton 					list_del(&slot->queue_node);
1785f95f3850SWill Newton 					mrq->cmd->error = -ENOMEDIUM;
1786f95f3850SWill Newton 					if (mrq->data)
1787f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
1788f95f3850SWill Newton 					if (mrq->stop)
1789f95f3850SWill Newton 						mrq->stop->error = -ENOMEDIUM;
1790f95f3850SWill Newton 
1791f95f3850SWill Newton 					spin_unlock(&host->lock);
1792f95f3850SWill Newton 					mmc_request_done(slot->mmc, mrq);
1793f95f3850SWill Newton 					spin_lock(&host->lock);
1794f95f3850SWill Newton 				}
1795f95f3850SWill Newton 			}
1796f95f3850SWill Newton 
1797f95f3850SWill Newton 			/* Power down slot */
1798f95f3850SWill Newton 			if (present == 0) {
1799f95f3850SWill Newton 				clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
1800f95f3850SWill Newton 
1801f95f3850SWill Newton 				/*
1802f95f3850SWill Newton 				 * Clear down the FIFO - doing so generates a
1803f95f3850SWill Newton 				 * block interrupt, hence setting the
1804f95f3850SWill Newton 				 * scatter-gather pointer to NULL.
1805f95f3850SWill Newton 				 */
1806f9c2a0dcSSeungwon Jeon 				sg_miter_stop(&host->sg_miter);
1807f95f3850SWill Newton 				host->sg = NULL;
1808f95f3850SWill Newton 
1809f95f3850SWill Newton 				ctrl = mci_readl(host, CTRL);
1810f95f3850SWill Newton 				ctrl |= SDMMC_CTRL_FIFO_RESET;
1811f95f3850SWill Newton 				mci_writel(host, CTRL, ctrl);
1812f95f3850SWill Newton 
1813f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
1814f95f3850SWill Newton 				ctrl = mci_readl(host, BMOD);
1815141a712aSSeungwon Jeon 				/* Software reset of DMA */
1816141a712aSSeungwon Jeon 				ctrl |= SDMMC_IDMAC_SWRESET;
1817f95f3850SWill Newton 				mci_writel(host, BMOD, ctrl);
1818f95f3850SWill Newton #endif
1819f95f3850SWill Newton 
1820f95f3850SWill Newton 			}
1821f95f3850SWill Newton 
18221791b13eSJames Hogan 			spin_unlock_bh(&host->lock);
18231791b13eSJames Hogan 
1824f95f3850SWill Newton 			present = dw_mci_get_cd(mmc);
1825f95f3850SWill Newton 		}
1826f95f3850SWill Newton 
1827f95f3850SWill Newton 		mmc_detect_change(slot->mmc,
1828f95f3850SWill Newton 			msecs_to_jiffies(host->pdata->detect_delay_ms));
1829f95f3850SWill Newton 	}
1830f95f3850SWill Newton }
1831f95f3850SWill Newton 
1832c91eab4bSThomas Abraham #ifdef CONFIG_OF
1833c91eab4bSThomas Abraham /* given a slot id, find out the device node representing that slot */
1834c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
1835c91eab4bSThomas Abraham {
1836c91eab4bSThomas Abraham 	struct device_node *np;
1837c91eab4bSThomas Abraham 	const __be32 *addr;
1838c91eab4bSThomas Abraham 	int len;
1839c91eab4bSThomas Abraham 
1840c91eab4bSThomas Abraham 	if (!dev || !dev->of_node)
1841c91eab4bSThomas Abraham 		return NULL;
1842c91eab4bSThomas Abraham 
1843c91eab4bSThomas Abraham 	for_each_child_of_node(dev->of_node, np) {
1844c91eab4bSThomas Abraham 		addr = of_get_property(np, "reg", &len);
1845c91eab4bSThomas Abraham 		if (!addr || (len < sizeof(int)))
1846c91eab4bSThomas Abraham 			continue;
1847c91eab4bSThomas Abraham 		if (be32_to_cpup(addr) == slot)
1848c91eab4bSThomas Abraham 			return np;
1849c91eab4bSThomas Abraham 	}
1850c91eab4bSThomas Abraham 	return NULL;
1851c91eab4bSThomas Abraham }
1852c91eab4bSThomas Abraham 
1853a70aaa64SDoug Anderson static struct dw_mci_of_slot_quirks {
1854a70aaa64SDoug Anderson 	char *quirk;
1855a70aaa64SDoug Anderson 	int id;
1856a70aaa64SDoug Anderson } of_slot_quirks[] = {
1857a70aaa64SDoug Anderson 	{
1858a70aaa64SDoug Anderson 		.quirk	= "disable-wp",
1859a70aaa64SDoug Anderson 		.id	= DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT,
1860a70aaa64SDoug Anderson 	},
1861a70aaa64SDoug Anderson };
1862a70aaa64SDoug Anderson 
1863a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
1864a70aaa64SDoug Anderson {
1865a70aaa64SDoug Anderson 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
1866a70aaa64SDoug Anderson 	int quirks = 0;
1867a70aaa64SDoug Anderson 	int idx;
1868a70aaa64SDoug Anderson 
1869a70aaa64SDoug Anderson 	/* get quirks */
1870a70aaa64SDoug Anderson 	for (idx = 0; idx < ARRAY_SIZE(of_slot_quirks); idx++)
1871a70aaa64SDoug Anderson 		if (of_get_property(np, of_slot_quirks[idx].quirk, NULL))
1872a70aaa64SDoug Anderson 			quirks |= of_slot_quirks[idx].id;
1873a70aaa64SDoug Anderson 
1874a70aaa64SDoug Anderson 	return quirks;
1875a70aaa64SDoug Anderson }
1876a70aaa64SDoug Anderson 
1877c91eab4bSThomas Abraham /* find out bus-width for a given slot */
1878c91eab4bSThomas Abraham static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
1879c91eab4bSThomas Abraham {
1880c91eab4bSThomas Abraham 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
1881c91eab4bSThomas Abraham 	u32 bus_wd = 1;
1882c91eab4bSThomas Abraham 
1883c91eab4bSThomas Abraham 	if (!np)
1884c91eab4bSThomas Abraham 		return 1;
1885c91eab4bSThomas Abraham 
1886c91eab4bSThomas Abraham 	if (of_property_read_u32(np, "bus-width", &bus_wd))
1887c91eab4bSThomas Abraham 		dev_err(dev, "bus-width property not found, assuming width"
1888c91eab4bSThomas Abraham 			       " as 1\n");
1889c91eab4bSThomas Abraham 	return bus_wd;
1890c91eab4bSThomas Abraham }
189155a6ceb2SDoug Anderson 
189255a6ceb2SDoug Anderson /* find the write protect gpio for a given slot; or -1 if none specified */
189355a6ceb2SDoug Anderson static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
189455a6ceb2SDoug Anderson {
189555a6ceb2SDoug Anderson 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
189655a6ceb2SDoug Anderson 	int gpio;
189755a6ceb2SDoug Anderson 
189855a6ceb2SDoug Anderson 	if (!np)
189955a6ceb2SDoug Anderson 		return -EINVAL;
190055a6ceb2SDoug Anderson 
190155a6ceb2SDoug Anderson 	gpio = of_get_named_gpio(np, "wp-gpios", 0);
190255a6ceb2SDoug Anderson 
190355a6ceb2SDoug Anderson 	/* Having a missing entry is valid; return silently */
190455a6ceb2SDoug Anderson 	if (!gpio_is_valid(gpio))
190555a6ceb2SDoug Anderson 		return -EINVAL;
190655a6ceb2SDoug Anderson 
190755a6ceb2SDoug Anderson 	if (devm_gpio_request(dev, gpio, "dw-mci-wp")) {
190855a6ceb2SDoug Anderson 		dev_warn(dev, "gpio [%d] request failed\n", gpio);
190955a6ceb2SDoug Anderson 		return -EINVAL;
191055a6ceb2SDoug Anderson 	}
191155a6ceb2SDoug Anderson 
191255a6ceb2SDoug Anderson 	return gpio;
191355a6ceb2SDoug Anderson }
1914c91eab4bSThomas Abraham #else /* CONFIG_OF */
1915a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
1916a70aaa64SDoug Anderson {
1917a70aaa64SDoug Anderson 	return 0;
1918a70aaa64SDoug Anderson }
1919c91eab4bSThomas Abraham static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
1920c91eab4bSThomas Abraham {
1921c91eab4bSThomas Abraham 	return 1;
1922c91eab4bSThomas Abraham }
1923c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
1924c91eab4bSThomas Abraham {
1925c91eab4bSThomas Abraham 	return NULL;
1926c91eab4bSThomas Abraham }
192755a6ceb2SDoug Anderson static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
192855a6ceb2SDoug Anderson {
192955a6ceb2SDoug Anderson 	return -EINVAL;
193055a6ceb2SDoug Anderson }
1931c91eab4bSThomas Abraham #endif /* CONFIG_OF */
1932c91eab4bSThomas Abraham 
193336c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
1934f95f3850SWill Newton {
1935f95f3850SWill Newton 	struct mmc_host *mmc;
1936f95f3850SWill Newton 	struct dw_mci_slot *slot;
1937e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
1938800d78bfSThomas Abraham 	int ctrl_id, ret;
1939c91eab4bSThomas Abraham 	u8 bus_width;
1940f95f3850SWill Newton 
19414a90920cSThomas Abraham 	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
1942f95f3850SWill Newton 	if (!mmc)
1943f95f3850SWill Newton 		return -ENOMEM;
1944f95f3850SWill Newton 
1945f95f3850SWill Newton 	slot = mmc_priv(mmc);
1946f95f3850SWill Newton 	slot->id = id;
1947f95f3850SWill Newton 	slot->mmc = mmc;
1948f95f3850SWill Newton 	slot->host = host;
1949c91eab4bSThomas Abraham 	host->slot[id] = slot;
1950f95f3850SWill Newton 
1951a70aaa64SDoug Anderson 	slot->quirks = dw_mci_of_get_slot_quirks(host->dev, slot->id);
1952a70aaa64SDoug Anderson 
1953f95f3850SWill Newton 	mmc->ops = &dw_mci_ops;
1954f95f3850SWill Newton 	mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
1955f95f3850SWill Newton 	mmc->f_max = host->bus_hz;
1956f95f3850SWill Newton 
1957f95f3850SWill Newton 	if (host->pdata->get_ocr)
1958f95f3850SWill Newton 		mmc->ocr_avail = host->pdata->get_ocr(id);
1959f95f3850SWill Newton 	else
1960f95f3850SWill Newton 		mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
1961f95f3850SWill Newton 
1962f95f3850SWill Newton 	/*
1963f95f3850SWill Newton 	 * Start with slot power disabled, it will be enabled when a card
1964f95f3850SWill Newton 	 * is detected.
1965f95f3850SWill Newton 	 */
1966f95f3850SWill Newton 	if (host->pdata->setpower)
1967f95f3850SWill Newton 		host->pdata->setpower(id, 0);
1968f95f3850SWill Newton 
1969fc3d7720SJaehoon Chung 	if (host->pdata->caps)
1970fc3d7720SJaehoon Chung 		mmc->caps = host->pdata->caps;
1971fc3d7720SJaehoon Chung 
1972ab269128SAbhilash Kesavan 	if (host->pdata->pm_caps)
1973ab269128SAbhilash Kesavan 		mmc->pm_caps = host->pdata->pm_caps;
1974ab269128SAbhilash Kesavan 
1975800d78bfSThomas Abraham 	if (host->dev->of_node) {
1976800d78bfSThomas Abraham 		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
1977800d78bfSThomas Abraham 		if (ctrl_id < 0)
1978800d78bfSThomas Abraham 			ctrl_id = 0;
1979800d78bfSThomas Abraham 	} else {
1980800d78bfSThomas Abraham 		ctrl_id = to_platform_device(host->dev)->id;
1981800d78bfSThomas Abraham 	}
1982cb27a843SJames Hogan 	if (drv_data && drv_data->caps)
1983cb27a843SJames Hogan 		mmc->caps |= drv_data->caps[ctrl_id];
1984800d78bfSThomas Abraham 
19854f408cc6SSeungwon Jeon 	if (host->pdata->caps2)
19864f408cc6SSeungwon Jeon 		mmc->caps2 = host->pdata->caps2;
19874f408cc6SSeungwon Jeon 
1988f95f3850SWill Newton 	if (host->pdata->get_bus_wd)
1989c91eab4bSThomas Abraham 		bus_width = host->pdata->get_bus_wd(slot->id);
1990c91eab4bSThomas Abraham 	else if (host->dev->of_node)
1991c91eab4bSThomas Abraham 		bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
1992c91eab4bSThomas Abraham 	else
1993c91eab4bSThomas Abraham 		bus_width = 1;
1994c91eab4bSThomas Abraham 
1995c91eab4bSThomas Abraham 	switch (bus_width) {
1996c91eab4bSThomas Abraham 	case 8:
1997c91eab4bSThomas Abraham 		mmc->caps |= MMC_CAP_8_BIT_DATA;
1998c91eab4bSThomas Abraham 	case 4:
1999f95f3850SWill Newton 		mmc->caps |= MMC_CAP_4_BIT_DATA;
2000c91eab4bSThomas Abraham 	}
2001f95f3850SWill Newton 
2002f95f3850SWill Newton 	if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
20036daa7778SSeungwon Jeon 		mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
2004f95f3850SWill Newton 
2005f95f3850SWill Newton 	if (host->pdata->blk_settings) {
2006f95f3850SWill Newton 		mmc->max_segs = host->pdata->blk_settings->max_segs;
2007f95f3850SWill Newton 		mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
2008f95f3850SWill Newton 		mmc->max_blk_count = host->pdata->blk_settings->max_blk_count;
2009f95f3850SWill Newton 		mmc->max_req_size = host->pdata->blk_settings->max_req_size;
2010f95f3850SWill Newton 		mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
2011f95f3850SWill Newton 	} else {
2012f95f3850SWill Newton 		/* Useful defaults if platform data is unset. */
2013a39e5746SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
2014a39e5746SJaehoon Chung 		mmc->max_segs = host->ring_size;
2015a39e5746SJaehoon Chung 		mmc->max_blk_size = 65536;
2016a39e5746SJaehoon Chung 		mmc->max_blk_count = host->ring_size;
2017a39e5746SJaehoon Chung 		mmc->max_seg_size = 0x1000;
2018a39e5746SJaehoon Chung 		mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
2019a39e5746SJaehoon Chung #else
2020f95f3850SWill Newton 		mmc->max_segs = 64;
2021f95f3850SWill Newton 		mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
2022f95f3850SWill Newton 		mmc->max_blk_count = 512;
2023f95f3850SWill Newton 		mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
2024f95f3850SWill Newton 		mmc->max_seg_size = mmc->max_req_size;
2025f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */
2026a39e5746SJaehoon Chung 	}
2027f95f3850SWill Newton 
2028f95f3850SWill Newton 	if (dw_mci_get_cd(mmc))
2029f95f3850SWill Newton 		set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
2030f95f3850SWill Newton 	else
2031f95f3850SWill Newton 		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
2032f95f3850SWill Newton 
203355a6ceb2SDoug Anderson 	slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id);
203455a6ceb2SDoug Anderson 
20350cea529dSJaehoon Chung 	ret = mmc_add_host(mmc);
20360cea529dSJaehoon Chung 	if (ret)
20370cea529dSJaehoon Chung 		goto err_setup_bus;
2038f95f3850SWill Newton 
2039f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS)
2040f95f3850SWill Newton 	dw_mci_init_debugfs(slot);
2041f95f3850SWill Newton #endif
2042f95f3850SWill Newton 
2043f95f3850SWill Newton 	/* Card initially undetected */
2044f95f3850SWill Newton 	slot->last_detect_state = 0;
2045f95f3850SWill Newton 
2046f95f3850SWill Newton 	return 0;
2047800d78bfSThomas Abraham 
2048800d78bfSThomas Abraham err_setup_bus:
2049800d78bfSThomas Abraham 	mmc_free_host(mmc);
2050800d78bfSThomas Abraham 	return -EINVAL;
2051f95f3850SWill Newton }
2052f95f3850SWill Newton 
2053f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
2054f95f3850SWill Newton {
2055f95f3850SWill Newton 	/* Shutdown detect IRQ */
2056f95f3850SWill Newton 	if (slot->host->pdata->exit)
2057f95f3850SWill Newton 		slot->host->pdata->exit(id);
2058f95f3850SWill Newton 
2059f95f3850SWill Newton 	/* Debugfs stuff is cleaned up by mmc core */
2060f95f3850SWill Newton 	mmc_remove_host(slot->mmc);
2061f95f3850SWill Newton 	slot->host->slot[id] = NULL;
2062f95f3850SWill Newton 	mmc_free_host(slot->mmc);
2063f95f3850SWill Newton }
2064f95f3850SWill Newton 
2065f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host)
2066f95f3850SWill Newton {
2067f95f3850SWill Newton 	/* Alloc memory for sg translation */
2068780f22afSSeungwon Jeon 	host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
2069f95f3850SWill Newton 					  &host->sg_dma, GFP_KERNEL);
2070f95f3850SWill Newton 	if (!host->sg_cpu) {
20714a90920cSThomas Abraham 		dev_err(host->dev, "%s: could not alloc DMA memory\n",
2072f95f3850SWill Newton 			__func__);
2073f95f3850SWill Newton 		goto no_dma;
2074f95f3850SWill Newton 	}
2075f95f3850SWill Newton 
2076f95f3850SWill Newton 	/* Determine which DMA interface to use */
2077f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
2078f95f3850SWill Newton 	host->dma_ops = &dw_mci_idmac_ops;
207900956ea3SSeungwon Jeon 	dev_info(host->dev, "Using internal DMA controller.\n");
2080f95f3850SWill Newton #endif
2081f95f3850SWill Newton 
2082f95f3850SWill Newton 	if (!host->dma_ops)
2083f95f3850SWill Newton 		goto no_dma;
2084f95f3850SWill Newton 
2085e1631f98SJaehoon Chung 	if (host->dma_ops->init && host->dma_ops->start &&
2086e1631f98SJaehoon Chung 	    host->dma_ops->stop && host->dma_ops->cleanup) {
2087f95f3850SWill Newton 		if (host->dma_ops->init(host)) {
20884a90920cSThomas Abraham 			dev_err(host->dev, "%s: Unable to initialize "
2089f95f3850SWill Newton 				"DMA Controller.\n", __func__);
2090f95f3850SWill Newton 			goto no_dma;
2091f95f3850SWill Newton 		}
2092f95f3850SWill Newton 	} else {
20934a90920cSThomas Abraham 		dev_err(host->dev, "DMA initialization not found.\n");
2094f95f3850SWill Newton 		goto no_dma;
2095f95f3850SWill Newton 	}
2096f95f3850SWill Newton 
2097f95f3850SWill Newton 	host->use_dma = 1;
2098f95f3850SWill Newton 	return;
2099f95f3850SWill Newton 
2100f95f3850SWill Newton no_dma:
21014a90920cSThomas Abraham 	dev_info(host->dev, "Using PIO mode.\n");
2102f95f3850SWill Newton 	host->use_dma = 0;
2103f95f3850SWill Newton 	return;
2104f95f3850SWill Newton }
2105f95f3850SWill Newton 
2106f95f3850SWill Newton static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
2107f95f3850SWill Newton {
2108f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
2109f95f3850SWill Newton 	unsigned int ctrl;
2110f95f3850SWill Newton 
2111f95f3850SWill Newton 	mci_writel(host, CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET |
2112f95f3850SWill Newton 				SDMMC_CTRL_DMA_RESET));
2113f95f3850SWill Newton 
2114f95f3850SWill Newton 	/* wait till resets clear */
2115f95f3850SWill Newton 	do {
2116f95f3850SWill Newton 		ctrl = mci_readl(host, CTRL);
2117f95f3850SWill Newton 		if (!(ctrl & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET |
2118f95f3850SWill Newton 			      SDMMC_CTRL_DMA_RESET)))
2119f95f3850SWill Newton 			return true;
2120f95f3850SWill Newton 	} while (time_before(jiffies, timeout));
2121f95f3850SWill Newton 
2122f95f3850SWill Newton 	dev_err(dev, "Timeout resetting block (ctrl %#x)\n", ctrl);
2123f95f3850SWill Newton 
2124f95f3850SWill Newton 	return false;
2125f95f3850SWill Newton }
2126f95f3850SWill Newton 
2127c91eab4bSThomas Abraham #ifdef CONFIG_OF
2128c91eab4bSThomas Abraham static struct dw_mci_of_quirks {
2129c91eab4bSThomas Abraham 	char *quirk;
2130c91eab4bSThomas Abraham 	int id;
2131c91eab4bSThomas Abraham } of_quirks[] = {
2132c91eab4bSThomas Abraham 	{
2133c91eab4bSThomas Abraham 		.quirk	= "supports-highspeed",
2134c91eab4bSThomas Abraham 		.id	= DW_MCI_QUIRK_HIGHSPEED,
2135c91eab4bSThomas Abraham 	}, {
2136c91eab4bSThomas Abraham 		.quirk	= "broken-cd",
2137c91eab4bSThomas Abraham 		.id	= DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
2138c91eab4bSThomas Abraham 	},
2139c91eab4bSThomas Abraham };
2140c91eab4bSThomas Abraham 
2141c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2142c91eab4bSThomas Abraham {
2143c91eab4bSThomas Abraham 	struct dw_mci_board *pdata;
2144c91eab4bSThomas Abraham 	struct device *dev = host->dev;
2145c91eab4bSThomas Abraham 	struct device_node *np = dev->of_node;
2146e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
2147800d78bfSThomas Abraham 	int idx, ret;
21483c6d89eaSDoug Anderson 	u32 clock_frequency;
2149c91eab4bSThomas Abraham 
2150c91eab4bSThomas Abraham 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
2151c91eab4bSThomas Abraham 	if (!pdata) {
2152c91eab4bSThomas Abraham 		dev_err(dev, "could not allocate memory for pdata\n");
2153c91eab4bSThomas Abraham 		return ERR_PTR(-ENOMEM);
2154c91eab4bSThomas Abraham 	}
2155c91eab4bSThomas Abraham 
2156c91eab4bSThomas Abraham 	/* find out number of slots supported */
2157c91eab4bSThomas Abraham 	if (of_property_read_u32(dev->of_node, "num-slots",
2158c91eab4bSThomas Abraham 				&pdata->num_slots)) {
2159c91eab4bSThomas Abraham 		dev_info(dev, "num-slots property not found, "
2160c91eab4bSThomas Abraham 				"assuming 1 slot is available\n");
2161c91eab4bSThomas Abraham 		pdata->num_slots = 1;
2162c91eab4bSThomas Abraham 	}
2163c91eab4bSThomas Abraham 
2164c91eab4bSThomas Abraham 	/* get quirks */
2165c91eab4bSThomas Abraham 	for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++)
2166c91eab4bSThomas Abraham 		if (of_get_property(np, of_quirks[idx].quirk, NULL))
2167c91eab4bSThomas Abraham 			pdata->quirks |= of_quirks[idx].id;
2168c91eab4bSThomas Abraham 
2169c91eab4bSThomas Abraham 	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
2170c91eab4bSThomas Abraham 		dev_info(dev, "fifo-depth property not found, using "
2171c91eab4bSThomas Abraham 				"value of FIFOTH register as default\n");
2172c91eab4bSThomas Abraham 
2173c91eab4bSThomas Abraham 	of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
2174c91eab4bSThomas Abraham 
21753c6d89eaSDoug Anderson 	if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
21763c6d89eaSDoug Anderson 		pdata->bus_hz = clock_frequency;
21773c6d89eaSDoug Anderson 
2178cb27a843SJames Hogan 	if (drv_data && drv_data->parse_dt) {
2179cb27a843SJames Hogan 		ret = drv_data->parse_dt(host);
2180800d78bfSThomas Abraham 		if (ret)
2181800d78bfSThomas Abraham 			return ERR_PTR(ret);
2182800d78bfSThomas Abraham 	}
2183800d78bfSThomas Abraham 
2184ab269128SAbhilash Kesavan 	if (of_find_property(np, "keep-power-in-suspend", NULL))
2185ab269128SAbhilash Kesavan 		pdata->pm_caps |= MMC_PM_KEEP_POWER;
2186ab269128SAbhilash Kesavan 
2187ab269128SAbhilash Kesavan 	if (of_find_property(np, "enable-sdio-wakeup", NULL))
2188ab269128SAbhilash Kesavan 		pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
2189ab269128SAbhilash Kesavan 
2190c91eab4bSThomas Abraham 	return pdata;
2191c91eab4bSThomas Abraham }
2192c91eab4bSThomas Abraham 
2193c91eab4bSThomas Abraham #else /* CONFIG_OF */
2194c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2195c91eab4bSThomas Abraham {
2196c91eab4bSThomas Abraham 	return ERR_PTR(-EINVAL);
2197c91eab4bSThomas Abraham }
2198c91eab4bSThomas Abraham #endif /* CONFIG_OF */
2199c91eab4bSThomas Abraham 
220062ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host)
2201f95f3850SWill Newton {
2202e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
220362ca8034SShashidhar Hiremath 	int width, i, ret = 0;
2204f95f3850SWill Newton 	u32 fifo_size;
22051c2215b7SThomas Abraham 	int init_slots = 0;
2206f95f3850SWill Newton 
2207c91eab4bSThomas Abraham 	if (!host->pdata) {
2208c91eab4bSThomas Abraham 		host->pdata = dw_mci_parse_dt(host);
2209c91eab4bSThomas Abraham 		if (IS_ERR(host->pdata)) {
2210c91eab4bSThomas Abraham 			dev_err(host->dev, "platform data not available\n");
2211c91eab4bSThomas Abraham 			return -EINVAL;
2212c91eab4bSThomas Abraham 		}
2213f95f3850SWill Newton 	}
2214f95f3850SWill Newton 
221562ca8034SShashidhar Hiremath 	if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
22164a90920cSThomas Abraham 		dev_err(host->dev,
2217f95f3850SWill Newton 			"Platform data must supply select_slot function\n");
221862ca8034SShashidhar Hiremath 		return -ENODEV;
2219f95f3850SWill Newton 	}
2220f95f3850SWill Newton 
2221780f22afSSeungwon Jeon 	host->biu_clk = devm_clk_get(host->dev, "biu");
2222f90a0612SThomas Abraham 	if (IS_ERR(host->biu_clk)) {
2223f90a0612SThomas Abraham 		dev_dbg(host->dev, "biu clock not available\n");
2224f90a0612SThomas Abraham 	} else {
2225f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->biu_clk);
2226f90a0612SThomas Abraham 		if (ret) {
2227f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable biu clock\n");
2228f90a0612SThomas Abraham 			return ret;
2229f90a0612SThomas Abraham 		}
2230f95f3850SWill Newton 	}
2231f95f3850SWill Newton 
2232780f22afSSeungwon Jeon 	host->ciu_clk = devm_clk_get(host->dev, "ciu");
2233f90a0612SThomas Abraham 	if (IS_ERR(host->ciu_clk)) {
2234f90a0612SThomas Abraham 		dev_dbg(host->dev, "ciu clock not available\n");
22353c6d89eaSDoug Anderson 		host->bus_hz = host->pdata->bus_hz;
2236f90a0612SThomas Abraham 	} else {
2237f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->ciu_clk);
2238f90a0612SThomas Abraham 		if (ret) {
2239f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable ciu clock\n");
2240f90a0612SThomas Abraham 			goto err_clk_biu;
2241f90a0612SThomas Abraham 		}
2242f90a0612SThomas Abraham 
22433c6d89eaSDoug Anderson 		if (host->pdata->bus_hz) {
22443c6d89eaSDoug Anderson 			ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz);
22453c6d89eaSDoug Anderson 			if (ret)
22463c6d89eaSDoug Anderson 				dev_warn(host->dev,
22473c6d89eaSDoug Anderson 					 "Unable to set bus rate to %ul\n",
22483c6d89eaSDoug Anderson 					 host->pdata->bus_hz);
22493c6d89eaSDoug Anderson 		}
2250f90a0612SThomas Abraham 		host->bus_hz = clk_get_rate(host->ciu_clk);
22513c6d89eaSDoug Anderson 	}
2252f90a0612SThomas Abraham 
2253002f0d5cSYuvaraj Kumar C D 	if (drv_data && drv_data->init) {
2254002f0d5cSYuvaraj Kumar C D 		ret = drv_data->init(host);
2255002f0d5cSYuvaraj Kumar C D 		if (ret) {
2256002f0d5cSYuvaraj Kumar C D 			dev_err(host->dev,
2257002f0d5cSYuvaraj Kumar C D 				"implementation specific init failed\n");
2258002f0d5cSYuvaraj Kumar C D 			goto err_clk_ciu;
2259002f0d5cSYuvaraj Kumar C D 		}
2260002f0d5cSYuvaraj Kumar C D 	}
2261002f0d5cSYuvaraj Kumar C D 
2262cb27a843SJames Hogan 	if (drv_data && drv_data->setup_clock) {
2263cb27a843SJames Hogan 		ret = drv_data->setup_clock(host);
2264800d78bfSThomas Abraham 		if (ret) {
2265800d78bfSThomas Abraham 			dev_err(host->dev,
2266800d78bfSThomas Abraham 				"implementation specific clock setup failed\n");
2267800d78bfSThomas Abraham 			goto err_clk_ciu;
2268800d78bfSThomas Abraham 		}
2269800d78bfSThomas Abraham 	}
2270800d78bfSThomas Abraham 
2271a55d6ff0SMark Brown 	host->vmmc = devm_regulator_get_optional(host->dev, "vmmc");
2272870556a3SDoug Anderson 	if (IS_ERR(host->vmmc)) {
2273870556a3SDoug Anderson 		ret = PTR_ERR(host->vmmc);
2274870556a3SDoug Anderson 		if (ret == -EPROBE_DEFER)
2275870556a3SDoug Anderson 			goto err_clk_ciu;
2276870556a3SDoug Anderson 
2277870556a3SDoug Anderson 		dev_info(host->dev, "no vmmc regulator found: %d\n", ret);
2278870556a3SDoug Anderson 		host->vmmc = NULL;
2279870556a3SDoug Anderson 	} else {
2280870556a3SDoug Anderson 		ret = regulator_enable(host->vmmc);
2281870556a3SDoug Anderson 		if (ret) {
2282870556a3SDoug Anderson 			if (ret != -EPROBE_DEFER)
2283870556a3SDoug Anderson 				dev_err(host->dev,
2284870556a3SDoug Anderson 					"regulator_enable fail: %d\n", ret);
2285870556a3SDoug Anderson 			goto err_clk_ciu;
2286870556a3SDoug Anderson 		}
2287870556a3SDoug Anderson 	}
2288870556a3SDoug Anderson 
2289f90a0612SThomas Abraham 	if (!host->bus_hz) {
2290f90a0612SThomas Abraham 		dev_err(host->dev,
2291f90a0612SThomas Abraham 			"Platform data must supply bus speed\n");
2292f90a0612SThomas Abraham 		ret = -ENODEV;
2293870556a3SDoug Anderson 		goto err_regulator;
2294f90a0612SThomas Abraham 	}
2295f90a0612SThomas Abraham 
229662ca8034SShashidhar Hiremath 	host->quirks = host->pdata->quirks;
2297f95f3850SWill Newton 
2298f95f3850SWill Newton 	spin_lock_init(&host->lock);
2299f95f3850SWill Newton 	INIT_LIST_HEAD(&host->queue);
2300f95f3850SWill Newton 
2301f95f3850SWill Newton 	/*
2302f95f3850SWill Newton 	 * Get the host data width - this assumes that HCON has been set with
2303f95f3850SWill Newton 	 * the correct values.
2304f95f3850SWill Newton 	 */
2305f95f3850SWill Newton 	i = (mci_readl(host, HCON) >> 7) & 0x7;
2306f95f3850SWill Newton 	if (!i) {
2307f95f3850SWill Newton 		host->push_data = dw_mci_push_data16;
2308f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data16;
2309f95f3850SWill Newton 		width = 16;
2310f95f3850SWill Newton 		host->data_shift = 1;
2311f95f3850SWill Newton 	} else if (i == 2) {
2312f95f3850SWill Newton 		host->push_data = dw_mci_push_data64;
2313f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data64;
2314f95f3850SWill Newton 		width = 64;
2315f95f3850SWill Newton 		host->data_shift = 3;
2316f95f3850SWill Newton 	} else {
2317f95f3850SWill Newton 		/* Check for a reserved value, and warn if it is */
2318f95f3850SWill Newton 		WARN((i != 1),
2319f95f3850SWill Newton 		     "HCON reports a reserved host data width!\n"
2320f95f3850SWill Newton 		     "Defaulting to 32-bit access.\n");
2321f95f3850SWill Newton 		host->push_data = dw_mci_push_data32;
2322f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data32;
2323f95f3850SWill Newton 		width = 32;
2324f95f3850SWill Newton 		host->data_shift = 2;
2325f95f3850SWill Newton 	}
2326f95f3850SWill Newton 
2327f95f3850SWill Newton 	/* Reset all blocks */
23284a90920cSThomas Abraham 	if (!mci_wait_reset(host->dev, host))
2329141a712aSSeungwon Jeon 		return -ENODEV;
2330141a712aSSeungwon Jeon 
2331141a712aSSeungwon Jeon 	host->dma_ops = host->pdata->dma_ops;
2332141a712aSSeungwon Jeon 	dw_mci_init_dma(host);
2333f95f3850SWill Newton 
2334f95f3850SWill Newton 	/* Clear the interrupts for the host controller */
2335f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2336f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2337f95f3850SWill Newton 
2338f95f3850SWill Newton 	/* Put in max timeout */
2339f95f3850SWill Newton 	mci_writel(host, TMOUT, 0xFFFFFFFF);
2340f95f3850SWill Newton 
2341f95f3850SWill Newton 	/*
2342f95f3850SWill Newton 	 * FIFO threshold settings  RxMark  = fifo_size / 2 - 1,
2343f95f3850SWill Newton 	 *                          Tx Mark = fifo_size / 2 DMA Size = 8
2344f95f3850SWill Newton 	 */
2345b86d8253SJames Hogan 	if (!host->pdata->fifo_depth) {
2346b86d8253SJames Hogan 		/*
2347b86d8253SJames Hogan 		 * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may
2348b86d8253SJames Hogan 		 * have been overwritten by the bootloader, just like we're
2349b86d8253SJames Hogan 		 * about to do, so if you know the value for your hardware, you
2350b86d8253SJames Hogan 		 * should put it in the platform data.
2351b86d8253SJames Hogan 		 */
2352f95f3850SWill Newton 		fifo_size = mci_readl(host, FIFOTH);
23538234e869SJaehoon Chung 		fifo_size = 1 + ((fifo_size >> 16) & 0xfff);
2354b86d8253SJames Hogan 	} else {
2355b86d8253SJames Hogan 		fifo_size = host->pdata->fifo_depth;
2356b86d8253SJames Hogan 	}
2357b86d8253SJames Hogan 	host->fifo_depth = fifo_size;
2358e61cf118SJaehoon Chung 	host->fifoth_val = ((0x2 << 28) | ((fifo_size/2 - 1) << 16) |
2359e61cf118SJaehoon Chung 			((fifo_size/2) << 0));
2360e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
2361f95f3850SWill Newton 
2362f95f3850SWill Newton 	/* disable clock to CIU */
2363f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2364f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2365f95f3850SWill Newton 
236663008768SJames Hogan 	/*
236763008768SJames Hogan 	 * In 2.40a spec, Data offset is changed.
236863008768SJames Hogan 	 * Need to check the version-id and set data-offset for DATA register.
236963008768SJames Hogan 	 */
237063008768SJames Hogan 	host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
237163008768SJames Hogan 	dev_info(host->dev, "Version ID is %04x\n", host->verid);
237263008768SJames Hogan 
237363008768SJames Hogan 	if (host->verid < DW_MMC_240A)
237463008768SJames Hogan 		host->data_offset = DATA_OFFSET;
237563008768SJames Hogan 	else
237663008768SJames Hogan 		host->data_offset = DATA_240A_OFFSET;
237763008768SJames Hogan 
2378f95f3850SWill Newton 	tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
237995dcc2cbSThomas Abraham 	host->card_workqueue = alloc_workqueue("dw-mci-card",
23801791b13eSJames Hogan 			WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1);
2381ef7aef9aSWei Yongjun 	if (!host->card_workqueue) {
2382ef7aef9aSWei Yongjun 		ret = -ENOMEM;
23831791b13eSJames Hogan 		goto err_dmaunmap;
2384ef7aef9aSWei Yongjun 	}
23851791b13eSJames Hogan 	INIT_WORK(&host->card_work, dw_mci_work_routine_card);
2386780f22afSSeungwon Jeon 	ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
2387780f22afSSeungwon Jeon 			       host->irq_flags, "dw-mci", host);
2388f95f3850SWill Newton 	if (ret)
23891791b13eSJames Hogan 		goto err_workqueue;
2390f95f3850SWill Newton 
2391f95f3850SWill Newton 	if (host->pdata->num_slots)
2392f95f3850SWill Newton 		host->num_slots = host->pdata->num_slots;
2393f95f3850SWill Newton 	else
2394f95f3850SWill Newton 		host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1;
2395f95f3850SWill Newton 
23962da1d7f2SYuvaraj CD 	/*
23972da1d7f2SYuvaraj CD 	 * Enable interrupts for command done, data over, data empty, card det,
23982da1d7f2SYuvaraj CD 	 * receive ready and error such as transmit, receive timeout, crc error
23992da1d7f2SYuvaraj CD 	 */
24002da1d7f2SYuvaraj CD 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
24012da1d7f2SYuvaraj CD 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
24022da1d7f2SYuvaraj CD 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
24032da1d7f2SYuvaraj CD 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
24042da1d7f2SYuvaraj CD 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
24052da1d7f2SYuvaraj CD 
24062da1d7f2SYuvaraj CD 	dev_info(host->dev, "DW MMC controller at irq %d, "
24072da1d7f2SYuvaraj CD 		 "%d bit host data width, "
24082da1d7f2SYuvaraj CD 		 "%u deep fifo\n",
24092da1d7f2SYuvaraj CD 		 host->irq, width, fifo_size);
24102da1d7f2SYuvaraj CD 
2411f95f3850SWill Newton 	/* We need at least one slot to succeed */
2412f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2413f95f3850SWill Newton 		ret = dw_mci_init_slot(host, i);
24141c2215b7SThomas Abraham 		if (ret)
24151c2215b7SThomas Abraham 			dev_dbg(host->dev, "slot %d init failed\n", i);
24161c2215b7SThomas Abraham 		else
24171c2215b7SThomas Abraham 			init_slots++;
2418f95f3850SWill Newton 	}
24191c2215b7SThomas Abraham 
24201c2215b7SThomas Abraham 	if (init_slots) {
24211c2215b7SThomas Abraham 		dev_info(host->dev, "%d slots initialized\n", init_slots);
24221c2215b7SThomas Abraham 	} else {
24231c2215b7SThomas Abraham 		dev_dbg(host->dev, "attempted to initialize %d slots, "
24241c2215b7SThomas Abraham 					"but failed on all\n", host->num_slots);
2425780f22afSSeungwon Jeon 		goto err_workqueue;
2426f95f3850SWill Newton 	}
2427f95f3850SWill Newton 
2428f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
24294a90920cSThomas Abraham 		dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
2430f95f3850SWill Newton 
2431f95f3850SWill Newton 	return 0;
2432f95f3850SWill Newton 
24331791b13eSJames Hogan err_workqueue:
243495dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
24351791b13eSJames Hogan 
2436f95f3850SWill Newton err_dmaunmap:
2437f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2438f95f3850SWill Newton 		host->dma_ops->exit(host);
2439f95f3850SWill Newton 
2440870556a3SDoug Anderson err_regulator:
2441780f22afSSeungwon Jeon 	if (host->vmmc)
2442c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2443f90a0612SThomas Abraham 
2444f90a0612SThomas Abraham err_clk_ciu:
2445780f22afSSeungwon Jeon 	if (!IS_ERR(host->ciu_clk))
2446f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2447780f22afSSeungwon Jeon 
2448f90a0612SThomas Abraham err_clk_biu:
2449780f22afSSeungwon Jeon 	if (!IS_ERR(host->biu_clk))
2450f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2451780f22afSSeungwon Jeon 
2452f95f3850SWill Newton 	return ret;
2453f95f3850SWill Newton }
245462ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe);
2455f95f3850SWill Newton 
245662ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host)
2457f95f3850SWill Newton {
2458f95f3850SWill Newton 	int i;
2459f95f3850SWill Newton 
2460f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2461f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2462f95f3850SWill Newton 
2463f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
24644a90920cSThomas Abraham 		dev_dbg(host->dev, "remove slot %d\n", i);
2465f95f3850SWill Newton 		if (host->slot[i])
2466f95f3850SWill Newton 			dw_mci_cleanup_slot(host->slot[i], i);
2467f95f3850SWill Newton 	}
2468f95f3850SWill Newton 
2469f95f3850SWill Newton 	/* disable clock to CIU */
2470f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2471f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2472f95f3850SWill Newton 
247395dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
2474f95f3850SWill Newton 
2475f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2476f95f3850SWill Newton 		host->dma_ops->exit(host);
2477f95f3850SWill Newton 
2478780f22afSSeungwon Jeon 	if (host->vmmc)
2479c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2480c07946a3SJaehoon Chung 
2481f90a0612SThomas Abraham 	if (!IS_ERR(host->ciu_clk))
2482f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2483780f22afSSeungwon Jeon 
2484f90a0612SThomas Abraham 	if (!IS_ERR(host->biu_clk))
2485f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2486f95f3850SWill Newton }
248762ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove);
248862ca8034SShashidhar Hiremath 
248962ca8034SShashidhar Hiremath 
2490f95f3850SWill Newton 
24916fe8890dSJaehoon Chung #ifdef CONFIG_PM_SLEEP
2492f95f3850SWill Newton /*
2493f95f3850SWill Newton  * TODO: we should probably disable the clock to the card in the suspend path.
2494f95f3850SWill Newton  */
249562ca8034SShashidhar Hiremath int dw_mci_suspend(struct dw_mci *host)
2496f95f3850SWill Newton {
249762ca8034SShashidhar Hiremath 	int i, ret = 0;
2498f95f3850SWill Newton 
2499f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2500f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
2501f95f3850SWill Newton 		if (!slot)
2502f95f3850SWill Newton 			continue;
2503f95f3850SWill Newton 		ret = mmc_suspend_host(slot->mmc);
2504f95f3850SWill Newton 		if (ret < 0) {
2505f95f3850SWill Newton 			while (--i >= 0) {
2506f95f3850SWill Newton 				slot = host->slot[i];
2507f95f3850SWill Newton 				if (slot)
2508f95f3850SWill Newton 					mmc_resume_host(host->slot[i]->mmc);
2509f95f3850SWill Newton 			}
2510f95f3850SWill Newton 			return ret;
2511f95f3850SWill Newton 		}
2512f95f3850SWill Newton 	}
2513f95f3850SWill Newton 
2514c07946a3SJaehoon Chung 	if (host->vmmc)
2515c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2516c07946a3SJaehoon Chung 
2517f95f3850SWill Newton 	return 0;
2518f95f3850SWill Newton }
251962ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_suspend);
2520f95f3850SWill Newton 
252162ca8034SShashidhar Hiremath int dw_mci_resume(struct dw_mci *host)
2522f95f3850SWill Newton {
2523f95f3850SWill Newton 	int i, ret;
2524f95f3850SWill Newton 
2525f2f942ceSSachin Kamat 	if (host->vmmc) {
2526f2f942ceSSachin Kamat 		ret = regulator_enable(host->vmmc);
2527f2f942ceSSachin Kamat 		if (ret) {
2528f2f942ceSSachin Kamat 			dev_err(host->dev,
2529f2f942ceSSachin Kamat 				"failed to enable regulator: %d\n", ret);
2530f2f942ceSSachin Kamat 			return ret;
2531f2f942ceSSachin Kamat 		}
2532f2f942ceSSachin Kamat 	}
25331d6c4e0aSJaehoon Chung 
25344a90920cSThomas Abraham 	if (!mci_wait_reset(host->dev, host)) {
2535e61cf118SJaehoon Chung 		ret = -ENODEV;
2536e61cf118SJaehoon Chung 		return ret;
2537e61cf118SJaehoon Chung 	}
2538e61cf118SJaehoon Chung 
25393bfe619dSJonathan Kliegman 	if (host->use_dma && host->dma_ops->init)
2540141a712aSSeungwon Jeon 		host->dma_ops->init(host);
2541141a712aSSeungwon Jeon 
2542e61cf118SJaehoon Chung 	/* Restore the old value at FIFOTH register */
2543e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
2544e61cf118SJaehoon Chung 
25452eb2944fSDoug Anderson 	/* Put in max timeout */
25462eb2944fSDoug Anderson 	mci_writel(host, TMOUT, 0xFFFFFFFF);
25472eb2944fSDoug Anderson 
2548e61cf118SJaehoon Chung 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2549e61cf118SJaehoon Chung 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
2550e61cf118SJaehoon Chung 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
2551e61cf118SJaehoon Chung 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
2552e61cf118SJaehoon Chung 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
2553e61cf118SJaehoon Chung 
2554f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2555f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
2556f95f3850SWill Newton 		if (!slot)
2557f95f3850SWill Newton 			continue;
2558ab269128SAbhilash Kesavan 		if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
2559ab269128SAbhilash Kesavan 			dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
2560ab269128SAbhilash Kesavan 			dw_mci_setup_bus(slot, true);
2561ab269128SAbhilash Kesavan 		}
2562ab269128SAbhilash Kesavan 
2563f95f3850SWill Newton 		ret = mmc_resume_host(host->slot[i]->mmc);
2564f95f3850SWill Newton 		if (ret < 0)
2565f95f3850SWill Newton 			return ret;
2566f95f3850SWill Newton 	}
2567f95f3850SWill Newton 	return 0;
2568f95f3850SWill Newton }
256962ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_resume);
25706fe8890dSJaehoon Chung #endif /* CONFIG_PM_SLEEP */
25716fe8890dSJaehoon Chung 
2572f95f3850SWill Newton static int __init dw_mci_init(void)
2573f95f3850SWill Newton {
25748e1c4e4dSSachin Kamat 	pr_info("Synopsys Designware Multimedia Card Interface Driver\n");
257562ca8034SShashidhar Hiremath 	return 0;
2576f95f3850SWill Newton }
2577f95f3850SWill Newton 
2578f95f3850SWill Newton static void __exit dw_mci_exit(void)
2579f95f3850SWill Newton {
2580f95f3850SWill Newton }
2581f95f3850SWill Newton 
2582f95f3850SWill Newton module_init(dw_mci_init);
2583f95f3850SWill Newton module_exit(dw_mci_exit);
2584f95f3850SWill Newton 
2585f95f3850SWill Newton MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
2586f95f3850SWill Newton MODULE_AUTHOR("NXP Semiconductor VietNam");
2587f95f3850SWill Newton MODULE_AUTHOR("Imagination Technologies Ltd");
2588f95f3850SWill Newton MODULE_LICENSE("GPL v2");
2589