xref: /linux/drivers/mmc/host/dw_mmc.c (revision 7cf347bd20ec8169add381ad23f9fb25c6c076f0)
1f95f3850SWill Newton /*
2f95f3850SWill Newton  * Synopsys DesignWare Multimedia Card Interface driver
3f95f3850SWill Newton  *  (Based on NXP driver for lpc 31xx)
4f95f3850SWill Newton  *
5f95f3850SWill Newton  * Copyright (C) 2009 NXP Semiconductors
6f95f3850SWill Newton  * Copyright (C) 2009, 2010 Imagination Technologies Ltd.
7f95f3850SWill Newton  *
8f95f3850SWill Newton  * This program is free software; you can redistribute it and/or modify
9f95f3850SWill Newton  * it under the terms of the GNU General Public License as published by
10f95f3850SWill Newton  * the Free Software Foundation; either version 2 of the License, or
11f95f3850SWill Newton  * (at your option) any later version.
12f95f3850SWill Newton  */
13f95f3850SWill Newton 
14f95f3850SWill Newton #include <linux/blkdev.h>
15f95f3850SWill Newton #include <linux/clk.h>
16f95f3850SWill Newton #include <linux/debugfs.h>
17f95f3850SWill Newton #include <linux/device.h>
18f95f3850SWill Newton #include <linux/dma-mapping.h>
19f95f3850SWill Newton #include <linux/err.h>
20f95f3850SWill Newton #include <linux/init.h>
21f95f3850SWill Newton #include <linux/interrupt.h>
22f95f3850SWill Newton #include <linux/ioport.h>
23f95f3850SWill Newton #include <linux/module.h>
24f95f3850SWill Newton #include <linux/platform_device.h>
25f95f3850SWill Newton #include <linux/seq_file.h>
26f95f3850SWill Newton #include <linux/slab.h>
27f95f3850SWill Newton #include <linux/stat.h>
28f95f3850SWill Newton #include <linux/delay.h>
29f95f3850SWill Newton #include <linux/irq.h>
30f95f3850SWill Newton #include <linux/mmc/host.h>
31f95f3850SWill Newton #include <linux/mmc/mmc.h>
3290c2143aSSeungwon Jeon #include <linux/mmc/sdio.h>
33f95f3850SWill Newton #include <linux/mmc/dw_mmc.h>
34f95f3850SWill Newton #include <linux/bitops.h>
35c07946a3SJaehoon Chung #include <linux/regulator/consumer.h>
361791b13eSJames Hogan #include <linux/workqueue.h>
37c91eab4bSThomas Abraham #include <linux/of.h>
3855a6ceb2SDoug Anderson #include <linux/of_gpio.h>
39bf626e55SZhangfei Gao #include <linux/mmc/slot-gpio.h>
40f95f3850SWill Newton 
41f95f3850SWill Newton #include "dw_mmc.h"
42f95f3850SWill Newton 
43f95f3850SWill Newton /* Common flag combinations */
443f7eec62SJaehoon Chung #define DW_MCI_DATA_ERROR_FLAGS	(SDMMC_INT_DRTO | SDMMC_INT_DCRC | \
45f95f3850SWill Newton 				 SDMMC_INT_HTO | SDMMC_INT_SBE  | \
46f95f3850SWill Newton 				 SDMMC_INT_EBE)
47f95f3850SWill Newton #define DW_MCI_CMD_ERROR_FLAGS	(SDMMC_INT_RTO | SDMMC_INT_RCRC | \
48f95f3850SWill Newton 				 SDMMC_INT_RESP_ERR)
49f95f3850SWill Newton #define DW_MCI_ERROR_FLAGS	(DW_MCI_DATA_ERROR_FLAGS | \
50f95f3850SWill Newton 				 DW_MCI_CMD_ERROR_FLAGS  | SDMMC_INT_HLE)
51f95f3850SWill Newton #define DW_MCI_SEND_STATUS	1
52f95f3850SWill Newton #define DW_MCI_RECV_STATUS	2
53f95f3850SWill Newton #define DW_MCI_DMA_THRESHOLD	16
54f95f3850SWill Newton 
551f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MAX	200000000	/* unit: HZ */
561f44a2a5SSeungwon Jeon #define DW_MCI_FREQ_MIN	400000		/* unit: HZ */
571f44a2a5SSeungwon Jeon 
58f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
59fc79a4d6SJoonyoung Shim #define IDMAC_INT_CLR		(SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \
60fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \
61fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
62fc79a4d6SJoonyoung Shim 				 SDMMC_IDMAC_INT_TI)
63fc79a4d6SJoonyoung Shim 
64f95f3850SWill Newton struct idmac_desc {
65f95f3850SWill Newton 	u32		des0;	/* Control Descriptor */
66f95f3850SWill Newton #define IDMAC_DES0_DIC	BIT(1)
67f95f3850SWill Newton #define IDMAC_DES0_LD	BIT(2)
68f95f3850SWill Newton #define IDMAC_DES0_FD	BIT(3)
69f95f3850SWill Newton #define IDMAC_DES0_CH	BIT(4)
70f95f3850SWill Newton #define IDMAC_DES0_ER	BIT(5)
71f95f3850SWill Newton #define IDMAC_DES0_CES	BIT(30)
72f95f3850SWill Newton #define IDMAC_DES0_OWN	BIT(31)
73f95f3850SWill Newton 
74f95f3850SWill Newton 	u32		des1;	/* Buffer sizes */
75f95f3850SWill Newton #define IDMAC_SET_BUFFER1_SIZE(d, s) \
769b7bbe10SShashidhar Hiremath 	((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff))
77f95f3850SWill Newton 
78f95f3850SWill Newton 	u32		des2;	/* buffer 1 physical address */
79f95f3850SWill Newton 
80f95f3850SWill Newton 	u32		des3;	/* buffer 2 physical address */
81f95f3850SWill Newton };
82f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */
83f95f3850SWill Newton 
840976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_4bit[] = {
850976f16dSSeungwon Jeon 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
860976f16dSSeungwon Jeon 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
870976f16dSSeungwon Jeon 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
880976f16dSSeungwon Jeon 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
890976f16dSSeungwon Jeon 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
900976f16dSSeungwon Jeon 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
910976f16dSSeungwon Jeon 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
920976f16dSSeungwon Jeon 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
930976f16dSSeungwon Jeon };
94f95f3850SWill Newton 
950976f16dSSeungwon Jeon static const u8 tuning_blk_pattern_8bit[] = {
960976f16dSSeungwon Jeon 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
970976f16dSSeungwon Jeon 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
980976f16dSSeungwon Jeon 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
990976f16dSSeungwon Jeon 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
1000976f16dSSeungwon Jeon 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
1010976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
1020976f16dSSeungwon Jeon 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
1030976f16dSSeungwon Jeon 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
1040976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
1050976f16dSSeungwon Jeon 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
1060976f16dSSeungwon Jeon 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
1070976f16dSSeungwon Jeon 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
1080976f16dSSeungwon Jeon 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
1090976f16dSSeungwon Jeon 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
1100976f16dSSeungwon Jeon 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
1110976f16dSSeungwon Jeon 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
112f95f3850SWill Newton };
113f95f3850SWill Newton 
11431bff450SSeungwon Jeon static inline bool dw_mci_fifo_reset(struct dw_mci *host);
11531bff450SSeungwon Jeon static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host);
11631bff450SSeungwon Jeon 
117f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS)
118f95f3850SWill Newton static int dw_mci_req_show(struct seq_file *s, void *v)
119f95f3850SWill Newton {
120f95f3850SWill Newton 	struct dw_mci_slot *slot = s->private;
121f95f3850SWill Newton 	struct mmc_request *mrq;
122f95f3850SWill Newton 	struct mmc_command *cmd;
123f95f3850SWill Newton 	struct mmc_command *stop;
124f95f3850SWill Newton 	struct mmc_data	*data;
125f95f3850SWill Newton 
126f95f3850SWill Newton 	/* Make sure we get a consistent snapshot */
127f95f3850SWill Newton 	spin_lock_bh(&slot->host->lock);
128f95f3850SWill Newton 	mrq = slot->mrq;
129f95f3850SWill Newton 
130f95f3850SWill Newton 	if (mrq) {
131f95f3850SWill Newton 		cmd = mrq->cmd;
132f95f3850SWill Newton 		data = mrq->data;
133f95f3850SWill Newton 		stop = mrq->stop;
134f95f3850SWill Newton 
135f95f3850SWill Newton 		if (cmd)
136f95f3850SWill Newton 			seq_printf(s,
137f95f3850SWill Newton 				   "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
138f95f3850SWill Newton 				   cmd->opcode, cmd->arg, cmd->flags,
139f95f3850SWill Newton 				   cmd->resp[0], cmd->resp[1], cmd->resp[2],
140f95f3850SWill Newton 				   cmd->resp[2], cmd->error);
141f95f3850SWill Newton 		if (data)
142f95f3850SWill Newton 			seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
143f95f3850SWill Newton 				   data->bytes_xfered, data->blocks,
144f95f3850SWill Newton 				   data->blksz, data->flags, data->error);
145f95f3850SWill Newton 		if (stop)
146f95f3850SWill Newton 			seq_printf(s,
147f95f3850SWill Newton 				   "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
148f95f3850SWill Newton 				   stop->opcode, stop->arg, stop->flags,
149f95f3850SWill Newton 				   stop->resp[0], stop->resp[1], stop->resp[2],
150f95f3850SWill Newton 				   stop->resp[2], stop->error);
151f95f3850SWill Newton 	}
152f95f3850SWill Newton 
153f95f3850SWill Newton 	spin_unlock_bh(&slot->host->lock);
154f95f3850SWill Newton 
155f95f3850SWill Newton 	return 0;
156f95f3850SWill Newton }
157f95f3850SWill Newton 
158f95f3850SWill Newton static int dw_mci_req_open(struct inode *inode, struct file *file)
159f95f3850SWill Newton {
160f95f3850SWill Newton 	return single_open(file, dw_mci_req_show, inode->i_private);
161f95f3850SWill Newton }
162f95f3850SWill Newton 
163f95f3850SWill Newton static const struct file_operations dw_mci_req_fops = {
164f95f3850SWill Newton 	.owner		= THIS_MODULE,
165f95f3850SWill Newton 	.open		= dw_mci_req_open,
166f95f3850SWill Newton 	.read		= seq_read,
167f95f3850SWill Newton 	.llseek		= seq_lseek,
168f95f3850SWill Newton 	.release	= single_release,
169f95f3850SWill Newton };
170f95f3850SWill Newton 
171f95f3850SWill Newton static int dw_mci_regs_show(struct seq_file *s, void *v)
172f95f3850SWill Newton {
173f95f3850SWill Newton 	seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS);
174f95f3850SWill Newton 	seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS);
175f95f3850SWill Newton 	seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD);
176f95f3850SWill Newton 	seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL);
177f95f3850SWill Newton 	seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK);
178f95f3850SWill Newton 	seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA);
179f95f3850SWill Newton 
180f95f3850SWill Newton 	return 0;
181f95f3850SWill Newton }
182f95f3850SWill Newton 
183f95f3850SWill Newton static int dw_mci_regs_open(struct inode *inode, struct file *file)
184f95f3850SWill Newton {
185f95f3850SWill Newton 	return single_open(file, dw_mci_regs_show, inode->i_private);
186f95f3850SWill Newton }
187f95f3850SWill Newton 
188f95f3850SWill Newton static const struct file_operations dw_mci_regs_fops = {
189f95f3850SWill Newton 	.owner		= THIS_MODULE,
190f95f3850SWill Newton 	.open		= dw_mci_regs_open,
191f95f3850SWill Newton 	.read		= seq_read,
192f95f3850SWill Newton 	.llseek		= seq_lseek,
193f95f3850SWill Newton 	.release	= single_release,
194f95f3850SWill Newton };
195f95f3850SWill Newton 
196f95f3850SWill Newton static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
197f95f3850SWill Newton {
198f95f3850SWill Newton 	struct mmc_host	*mmc = slot->mmc;
199f95f3850SWill Newton 	struct dw_mci *host = slot->host;
200f95f3850SWill Newton 	struct dentry *root;
201f95f3850SWill Newton 	struct dentry *node;
202f95f3850SWill Newton 
203f95f3850SWill Newton 	root = mmc->debugfs_root;
204f95f3850SWill Newton 	if (!root)
205f95f3850SWill Newton 		return;
206f95f3850SWill Newton 
207f95f3850SWill Newton 	node = debugfs_create_file("regs", S_IRUSR, root, host,
208f95f3850SWill Newton 				   &dw_mci_regs_fops);
209f95f3850SWill Newton 	if (!node)
210f95f3850SWill Newton 		goto err;
211f95f3850SWill Newton 
212f95f3850SWill Newton 	node = debugfs_create_file("req", S_IRUSR, root, slot,
213f95f3850SWill Newton 				   &dw_mci_req_fops);
214f95f3850SWill Newton 	if (!node)
215f95f3850SWill Newton 		goto err;
216f95f3850SWill Newton 
217f95f3850SWill Newton 	node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
218f95f3850SWill Newton 	if (!node)
219f95f3850SWill Newton 		goto err;
220f95f3850SWill Newton 
221f95f3850SWill Newton 	node = debugfs_create_x32("pending_events", S_IRUSR, root,
222f95f3850SWill Newton 				  (u32 *)&host->pending_events);
223f95f3850SWill Newton 	if (!node)
224f95f3850SWill Newton 		goto err;
225f95f3850SWill Newton 
226f95f3850SWill Newton 	node = debugfs_create_x32("completed_events", S_IRUSR, root,
227f95f3850SWill Newton 				  (u32 *)&host->completed_events);
228f95f3850SWill Newton 	if (!node)
229f95f3850SWill Newton 		goto err;
230f95f3850SWill Newton 
231f95f3850SWill Newton 	return;
232f95f3850SWill Newton 
233f95f3850SWill Newton err:
234f95f3850SWill Newton 	dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
235f95f3850SWill Newton }
236f95f3850SWill Newton #endif /* defined(CONFIG_DEBUG_FS) */
237f95f3850SWill Newton 
238f95f3850SWill Newton static void dw_mci_set_timeout(struct dw_mci *host)
239f95f3850SWill Newton {
240f95f3850SWill Newton 	/* timeout (maximum) */
241f95f3850SWill Newton 	mci_writel(host, TMOUT, 0xffffffff);
242f95f3850SWill Newton }
243f95f3850SWill Newton 
244f95f3850SWill Newton static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
245f95f3850SWill Newton {
246f95f3850SWill Newton 	struct mmc_data	*data;
247800d78bfSThomas Abraham 	struct dw_mci_slot *slot = mmc_priv(mmc);
248e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
249f95f3850SWill Newton 	u32 cmdr;
250f95f3850SWill Newton 	cmd->error = -EINPROGRESS;
251f95f3850SWill Newton 
252f95f3850SWill Newton 	cmdr = cmd->opcode;
253f95f3850SWill Newton 
25490c2143aSSeungwon Jeon 	if (cmd->opcode == MMC_STOP_TRANSMISSION ||
25590c2143aSSeungwon Jeon 	    cmd->opcode == MMC_GO_IDLE_STATE ||
25690c2143aSSeungwon Jeon 	    cmd->opcode == MMC_GO_INACTIVE_STATE ||
25790c2143aSSeungwon Jeon 	    (cmd->opcode == SD_IO_RW_DIRECT &&
25890c2143aSSeungwon Jeon 	     ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT))
259f95f3850SWill Newton 		cmdr |= SDMMC_CMD_STOP;
260f95f3850SWill Newton 	else
26190c2143aSSeungwon Jeon 		if (cmd->opcode != MMC_SEND_STATUS && cmd->data)
262f95f3850SWill Newton 			cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
263f95f3850SWill Newton 
264f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_PRESENT) {
265f95f3850SWill Newton 		/* We expect a response, so set this bit */
266f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_EXP;
267f95f3850SWill Newton 		if (cmd->flags & MMC_RSP_136)
268f95f3850SWill Newton 			cmdr |= SDMMC_CMD_RESP_LONG;
269f95f3850SWill Newton 	}
270f95f3850SWill Newton 
271f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_CRC)
272f95f3850SWill Newton 		cmdr |= SDMMC_CMD_RESP_CRC;
273f95f3850SWill Newton 
274f95f3850SWill Newton 	data = cmd->data;
275f95f3850SWill Newton 	if (data) {
276f95f3850SWill Newton 		cmdr |= SDMMC_CMD_DAT_EXP;
277f95f3850SWill Newton 		if (data->flags & MMC_DATA_STREAM)
278f95f3850SWill Newton 			cmdr |= SDMMC_CMD_STRM_MODE;
279f95f3850SWill Newton 		if (data->flags & MMC_DATA_WRITE)
280f95f3850SWill Newton 			cmdr |= SDMMC_CMD_DAT_WR;
281f95f3850SWill Newton 	}
282f95f3850SWill Newton 
283cb27a843SJames Hogan 	if (drv_data && drv_data->prepare_command)
284cb27a843SJames Hogan 		drv_data->prepare_command(slot->host, &cmdr);
285800d78bfSThomas Abraham 
286f95f3850SWill Newton 	return cmdr;
287f95f3850SWill Newton }
288f95f3850SWill Newton 
28990c2143aSSeungwon Jeon static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
29090c2143aSSeungwon Jeon {
29190c2143aSSeungwon Jeon 	struct mmc_command *stop;
29290c2143aSSeungwon Jeon 	u32 cmdr;
29390c2143aSSeungwon Jeon 
29490c2143aSSeungwon Jeon 	if (!cmd->data)
29590c2143aSSeungwon Jeon 		return 0;
29690c2143aSSeungwon Jeon 
29790c2143aSSeungwon Jeon 	stop = &host->stop_abort;
29890c2143aSSeungwon Jeon 	cmdr = cmd->opcode;
29990c2143aSSeungwon Jeon 	memset(stop, 0, sizeof(struct mmc_command));
30090c2143aSSeungwon Jeon 
30190c2143aSSeungwon Jeon 	if (cmdr == MMC_READ_SINGLE_BLOCK ||
30290c2143aSSeungwon Jeon 	    cmdr == MMC_READ_MULTIPLE_BLOCK ||
30390c2143aSSeungwon Jeon 	    cmdr == MMC_WRITE_BLOCK ||
30490c2143aSSeungwon Jeon 	    cmdr == MMC_WRITE_MULTIPLE_BLOCK) {
30590c2143aSSeungwon Jeon 		stop->opcode = MMC_STOP_TRANSMISSION;
30690c2143aSSeungwon Jeon 		stop->arg = 0;
30790c2143aSSeungwon Jeon 		stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
30890c2143aSSeungwon Jeon 	} else if (cmdr == SD_IO_RW_EXTENDED) {
30990c2143aSSeungwon Jeon 		stop->opcode = SD_IO_RW_DIRECT;
31090c2143aSSeungwon Jeon 		stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) |
31190c2143aSSeungwon Jeon 			     ((cmd->arg >> 28) & 0x7);
31290c2143aSSeungwon Jeon 		stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
31390c2143aSSeungwon Jeon 	} else {
31490c2143aSSeungwon Jeon 		return 0;
31590c2143aSSeungwon Jeon 	}
31690c2143aSSeungwon Jeon 
31790c2143aSSeungwon Jeon 	cmdr = stop->opcode | SDMMC_CMD_STOP |
31890c2143aSSeungwon Jeon 		SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP;
31990c2143aSSeungwon Jeon 
32090c2143aSSeungwon Jeon 	return cmdr;
32190c2143aSSeungwon Jeon }
32290c2143aSSeungwon Jeon 
323f95f3850SWill Newton static void dw_mci_start_command(struct dw_mci *host,
324f95f3850SWill Newton 				 struct mmc_command *cmd, u32 cmd_flags)
325f95f3850SWill Newton {
326f95f3850SWill Newton 	host->cmd = cmd;
3274a90920cSThomas Abraham 	dev_vdbg(host->dev,
328f95f3850SWill Newton 		 "start command: ARGR=0x%08x CMDR=0x%08x\n",
329f95f3850SWill Newton 		 cmd->arg, cmd_flags);
330f95f3850SWill Newton 
331f95f3850SWill Newton 	mci_writel(host, CMDARG, cmd->arg);
332f95f3850SWill Newton 	wmb();
333f95f3850SWill Newton 
334f95f3850SWill Newton 	mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
335f95f3850SWill Newton }
336f95f3850SWill Newton 
33790c2143aSSeungwon Jeon static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data)
338f95f3850SWill Newton {
33990c2143aSSeungwon Jeon 	struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort;
34090c2143aSSeungwon Jeon 	dw_mci_start_command(host, stop, host->stop_cmdr);
341f95f3850SWill Newton }
342f95f3850SWill Newton 
343f95f3850SWill Newton /* DMA interface functions */
344f95f3850SWill Newton static void dw_mci_stop_dma(struct dw_mci *host)
345f95f3850SWill Newton {
34603e8cb53SJames Hogan 	if (host->using_dma) {
347f95f3850SWill Newton 		host->dma_ops->stop(host);
348f95f3850SWill Newton 		host->dma_ops->cleanup(host);
349aa50f259SSeungwon Jeon 	}
350aa50f259SSeungwon Jeon 
351f95f3850SWill Newton 	/* Data transfer was stopped by the interrupt handler */
352f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
353f95f3850SWill Newton }
354f95f3850SWill Newton 
3559aa51408SSeungwon Jeon static int dw_mci_get_dma_dir(struct mmc_data *data)
3569aa51408SSeungwon Jeon {
3579aa51408SSeungwon Jeon 	if (data->flags & MMC_DATA_WRITE)
3589aa51408SSeungwon Jeon 		return DMA_TO_DEVICE;
3599aa51408SSeungwon Jeon 	else
3609aa51408SSeungwon Jeon 		return DMA_FROM_DEVICE;
3619aa51408SSeungwon Jeon }
3629aa51408SSeungwon Jeon 
3639beee912SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
364f95f3850SWill Newton static void dw_mci_dma_cleanup(struct dw_mci *host)
365f95f3850SWill Newton {
366f95f3850SWill Newton 	struct mmc_data *data = host->data;
367f95f3850SWill Newton 
368f95f3850SWill Newton 	if (data)
3699aa51408SSeungwon Jeon 		if (!data->host_cookie)
3704a90920cSThomas Abraham 			dma_unmap_sg(host->dev,
3719aa51408SSeungwon Jeon 				     data->sg,
3729aa51408SSeungwon Jeon 				     data->sg_len,
3739aa51408SSeungwon Jeon 				     dw_mci_get_dma_dir(data));
374f95f3850SWill Newton }
375f95f3850SWill Newton 
3765ce9d961SSeungwon Jeon static void dw_mci_idmac_reset(struct dw_mci *host)
3775ce9d961SSeungwon Jeon {
3785ce9d961SSeungwon Jeon 	u32 bmod = mci_readl(host, BMOD);
3795ce9d961SSeungwon Jeon 	/* Software reset of DMA */
3805ce9d961SSeungwon Jeon 	bmod |= SDMMC_IDMAC_SWRESET;
3815ce9d961SSeungwon Jeon 	mci_writel(host, BMOD, bmod);
3825ce9d961SSeungwon Jeon }
3835ce9d961SSeungwon Jeon 
384f95f3850SWill Newton static void dw_mci_idmac_stop_dma(struct dw_mci *host)
385f95f3850SWill Newton {
386f95f3850SWill Newton 	u32 temp;
387f95f3850SWill Newton 
388f95f3850SWill Newton 	/* Disable and reset the IDMAC interface */
389f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
390f95f3850SWill Newton 	temp &= ~SDMMC_CTRL_USE_IDMAC;
391f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_RESET;
392f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
393f95f3850SWill Newton 
394f95f3850SWill Newton 	/* Stop the IDMAC running */
395f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
396a5289a43SJaehoon Chung 	temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB);
3975ce9d961SSeungwon Jeon 	temp |= SDMMC_IDMAC_SWRESET;
398f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
399f95f3850SWill Newton }
400f95f3850SWill Newton 
401f95f3850SWill Newton static void dw_mci_idmac_complete_dma(struct dw_mci *host)
402f95f3850SWill Newton {
403f95f3850SWill Newton 	struct mmc_data *data = host->data;
404f95f3850SWill Newton 
4054a90920cSThomas Abraham 	dev_vdbg(host->dev, "DMA complete\n");
406f95f3850SWill Newton 
407f95f3850SWill Newton 	host->dma_ops->cleanup(host);
408f95f3850SWill Newton 
409f95f3850SWill Newton 	/*
410f95f3850SWill Newton 	 * If the card was removed, data will be NULL. No point in trying to
411f95f3850SWill Newton 	 * send the stop command or waiting for NBUSY in this case.
412f95f3850SWill Newton 	 */
413f95f3850SWill Newton 	if (data) {
414f95f3850SWill Newton 		set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
415f95f3850SWill Newton 		tasklet_schedule(&host->tasklet);
416f95f3850SWill Newton 	}
417f95f3850SWill Newton }
418f95f3850SWill Newton 
419f95f3850SWill Newton static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
420f95f3850SWill Newton 				    unsigned int sg_len)
421f95f3850SWill Newton {
422f95f3850SWill Newton 	int i;
423f95f3850SWill Newton 	struct idmac_desc *desc = host->sg_cpu;
424f95f3850SWill Newton 
425f95f3850SWill Newton 	for (i = 0; i < sg_len; i++, desc++) {
426f95f3850SWill Newton 		unsigned int length = sg_dma_len(&data->sg[i]);
427f95f3850SWill Newton 		u32 mem_addr = sg_dma_address(&data->sg[i]);
428f95f3850SWill Newton 
429f95f3850SWill Newton 		/* Set the OWN bit and disable interrupts for this descriptor */
430f95f3850SWill Newton 		desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH;
431f95f3850SWill Newton 
432f95f3850SWill Newton 		/* Buffer length */
433f95f3850SWill Newton 		IDMAC_SET_BUFFER1_SIZE(desc, length);
434f95f3850SWill Newton 
435f95f3850SWill Newton 		/* Physical address to DMA to/from */
436f95f3850SWill Newton 		desc->des2 = mem_addr;
437f95f3850SWill Newton 	}
438f95f3850SWill Newton 
439f95f3850SWill Newton 	/* Set first descriptor */
440f95f3850SWill Newton 	desc = host->sg_cpu;
441f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_FD;
442f95f3850SWill Newton 
443f95f3850SWill Newton 	/* Set last descriptor */
444f95f3850SWill Newton 	desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
445f95f3850SWill Newton 	desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
446f95f3850SWill Newton 	desc->des0 |= IDMAC_DES0_LD;
447f95f3850SWill Newton 
448f95f3850SWill Newton 	wmb();
449f95f3850SWill Newton }
450f95f3850SWill Newton 
451f95f3850SWill Newton static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
452f95f3850SWill Newton {
453f95f3850SWill Newton 	u32 temp;
454f95f3850SWill Newton 
455f95f3850SWill Newton 	dw_mci_translate_sglist(host, host->data, sg_len);
456f95f3850SWill Newton 
457f95f3850SWill Newton 	/* Select IDMAC interface */
458f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
459f95f3850SWill Newton 	temp |= SDMMC_CTRL_USE_IDMAC;
460f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
461f95f3850SWill Newton 
462f95f3850SWill Newton 	wmb();
463f95f3850SWill Newton 
464f95f3850SWill Newton 	/* Enable the IDMAC */
465f95f3850SWill Newton 	temp = mci_readl(host, BMOD);
466a5289a43SJaehoon Chung 	temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB;
467f95f3850SWill Newton 	mci_writel(host, BMOD, temp);
468f95f3850SWill Newton 
469f95f3850SWill Newton 	/* Start it running */
470f95f3850SWill Newton 	mci_writel(host, PLDMND, 1);
471f95f3850SWill Newton }
472f95f3850SWill Newton 
473f95f3850SWill Newton static int dw_mci_idmac_init(struct dw_mci *host)
474f95f3850SWill Newton {
475f95f3850SWill Newton 	struct idmac_desc *p;
476897b69e7SSeungwon Jeon 	int i;
477f95f3850SWill Newton 
478f95f3850SWill Newton 	/* Number of descriptors in the ring buffer */
479f95f3850SWill Newton 	host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
480f95f3850SWill Newton 
481f95f3850SWill Newton 	/* Forward link the descriptor list */
482f95f3850SWill Newton 	for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
483f95f3850SWill Newton 		p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
484f95f3850SWill Newton 
485f95f3850SWill Newton 	/* Set the last descriptor as the end-of-ring descriptor */
486f95f3850SWill Newton 	p->des3 = host->sg_dma;
487f95f3850SWill Newton 	p->des0 = IDMAC_DES0_ER;
488f95f3850SWill Newton 
4895ce9d961SSeungwon Jeon 	dw_mci_idmac_reset(host);
490141a712aSSeungwon Jeon 
491f95f3850SWill Newton 	/* Mask out interrupts - get Tx & Rx complete only */
492fc79a4d6SJoonyoung Shim 	mci_writel(host, IDSTS, IDMAC_INT_CLR);
493f95f3850SWill Newton 	mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
494f95f3850SWill Newton 		   SDMMC_IDMAC_INT_TI);
495f95f3850SWill Newton 
496f95f3850SWill Newton 	/* Set the descriptor base address */
497f95f3850SWill Newton 	mci_writel(host, DBADDR, host->sg_dma);
498f95f3850SWill Newton 	return 0;
499f95f3850SWill Newton }
500f95f3850SWill Newton 
5018e2b36eaSArnd Bergmann static const struct dw_mci_dma_ops dw_mci_idmac_ops = {
502885c3e80SSeungwon Jeon 	.init = dw_mci_idmac_init,
503885c3e80SSeungwon Jeon 	.start = dw_mci_idmac_start_dma,
504885c3e80SSeungwon Jeon 	.stop = dw_mci_idmac_stop_dma,
505885c3e80SSeungwon Jeon 	.complete = dw_mci_idmac_complete_dma,
506885c3e80SSeungwon Jeon 	.cleanup = dw_mci_dma_cleanup,
507885c3e80SSeungwon Jeon };
508885c3e80SSeungwon Jeon #endif /* CONFIG_MMC_DW_IDMAC */
509885c3e80SSeungwon Jeon 
5109aa51408SSeungwon Jeon static int dw_mci_pre_dma_transfer(struct dw_mci *host,
5119aa51408SSeungwon Jeon 				   struct mmc_data *data,
5129aa51408SSeungwon Jeon 				   bool next)
513f95f3850SWill Newton {
514f95f3850SWill Newton 	struct scatterlist *sg;
5159aa51408SSeungwon Jeon 	unsigned int i, sg_len;
516f95f3850SWill Newton 
5179aa51408SSeungwon Jeon 	if (!next && data->host_cookie)
5189aa51408SSeungwon Jeon 		return data->host_cookie;
519f95f3850SWill Newton 
520f95f3850SWill Newton 	/*
521f95f3850SWill Newton 	 * We don't do DMA on "complex" transfers, i.e. with
522f95f3850SWill Newton 	 * non-word-aligned buffers or lengths. Also, we don't bother
523f95f3850SWill Newton 	 * with all the DMA setup overhead for short transfers.
524f95f3850SWill Newton 	 */
525f95f3850SWill Newton 	if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD)
526f95f3850SWill Newton 		return -EINVAL;
5279aa51408SSeungwon Jeon 
528f95f3850SWill Newton 	if (data->blksz & 3)
529f95f3850SWill Newton 		return -EINVAL;
530f95f3850SWill Newton 
531f95f3850SWill Newton 	for_each_sg(data->sg, sg, data->sg_len, i) {
532f95f3850SWill Newton 		if (sg->offset & 3 || sg->length & 3)
533f95f3850SWill Newton 			return -EINVAL;
534f95f3850SWill Newton 	}
535f95f3850SWill Newton 
5364a90920cSThomas Abraham 	sg_len = dma_map_sg(host->dev,
5379aa51408SSeungwon Jeon 			    data->sg,
5389aa51408SSeungwon Jeon 			    data->sg_len,
5399aa51408SSeungwon Jeon 			    dw_mci_get_dma_dir(data));
5409aa51408SSeungwon Jeon 	if (sg_len == 0)
5419aa51408SSeungwon Jeon 		return -EINVAL;
5429aa51408SSeungwon Jeon 
5439aa51408SSeungwon Jeon 	if (next)
5449aa51408SSeungwon Jeon 		data->host_cookie = sg_len;
5459aa51408SSeungwon Jeon 
5469aa51408SSeungwon Jeon 	return sg_len;
5479aa51408SSeungwon Jeon }
5489aa51408SSeungwon Jeon 
5499aa51408SSeungwon Jeon static void dw_mci_pre_req(struct mmc_host *mmc,
5509aa51408SSeungwon Jeon 			   struct mmc_request *mrq,
5519aa51408SSeungwon Jeon 			   bool is_first_req)
5529aa51408SSeungwon Jeon {
5539aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
5549aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
5559aa51408SSeungwon Jeon 
5569aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
5579aa51408SSeungwon Jeon 		return;
5589aa51408SSeungwon Jeon 
5599aa51408SSeungwon Jeon 	if (data->host_cookie) {
5609aa51408SSeungwon Jeon 		data->host_cookie = 0;
5619aa51408SSeungwon Jeon 		return;
5629aa51408SSeungwon Jeon 	}
5639aa51408SSeungwon Jeon 
5649aa51408SSeungwon Jeon 	if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0)
5659aa51408SSeungwon Jeon 		data->host_cookie = 0;
5669aa51408SSeungwon Jeon }
5679aa51408SSeungwon Jeon 
5689aa51408SSeungwon Jeon static void dw_mci_post_req(struct mmc_host *mmc,
5699aa51408SSeungwon Jeon 			    struct mmc_request *mrq,
5709aa51408SSeungwon Jeon 			    int err)
5719aa51408SSeungwon Jeon {
5729aa51408SSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
5739aa51408SSeungwon Jeon 	struct mmc_data *data = mrq->data;
5749aa51408SSeungwon Jeon 
5759aa51408SSeungwon Jeon 	if (!slot->host->use_dma || !data)
5769aa51408SSeungwon Jeon 		return;
5779aa51408SSeungwon Jeon 
5789aa51408SSeungwon Jeon 	if (data->host_cookie)
5794a90920cSThomas Abraham 		dma_unmap_sg(slot->host->dev,
5809aa51408SSeungwon Jeon 			     data->sg,
5819aa51408SSeungwon Jeon 			     data->sg_len,
5829aa51408SSeungwon Jeon 			     dw_mci_get_dma_dir(data));
5839aa51408SSeungwon Jeon 	data->host_cookie = 0;
5849aa51408SSeungwon Jeon }
5859aa51408SSeungwon Jeon 
58652426899SSeungwon Jeon static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
58752426899SSeungwon Jeon {
58852426899SSeungwon Jeon #ifdef CONFIG_MMC_DW_IDMAC
58952426899SSeungwon Jeon 	unsigned int blksz = data->blksz;
59052426899SSeungwon Jeon 	const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
59152426899SSeungwon Jeon 	u32 fifo_width = 1 << host->data_shift;
59252426899SSeungwon Jeon 	u32 blksz_depth = blksz / fifo_width, fifoth_val;
59352426899SSeungwon Jeon 	u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers;
59452426899SSeungwon Jeon 	int idx = (sizeof(mszs) / sizeof(mszs[0])) - 1;
59552426899SSeungwon Jeon 
59652426899SSeungwon Jeon 	tx_wmark = (host->fifo_depth) / 2;
59752426899SSeungwon Jeon 	tx_wmark_invers = host->fifo_depth - tx_wmark;
59852426899SSeungwon Jeon 
59952426899SSeungwon Jeon 	/*
60052426899SSeungwon Jeon 	 * MSIZE is '1',
60152426899SSeungwon Jeon 	 * if blksz is not a multiple of the FIFO width
60252426899SSeungwon Jeon 	 */
60352426899SSeungwon Jeon 	if (blksz % fifo_width) {
60452426899SSeungwon Jeon 		msize = 0;
60552426899SSeungwon Jeon 		rx_wmark = 1;
60652426899SSeungwon Jeon 		goto done;
60752426899SSeungwon Jeon 	}
60852426899SSeungwon Jeon 
60952426899SSeungwon Jeon 	do {
61052426899SSeungwon Jeon 		if (!((blksz_depth % mszs[idx]) ||
61152426899SSeungwon Jeon 		     (tx_wmark_invers % mszs[idx]))) {
61252426899SSeungwon Jeon 			msize = idx;
61352426899SSeungwon Jeon 			rx_wmark = mszs[idx] - 1;
61452426899SSeungwon Jeon 			break;
61552426899SSeungwon Jeon 		}
61652426899SSeungwon Jeon 	} while (--idx > 0);
61752426899SSeungwon Jeon 	/*
61852426899SSeungwon Jeon 	 * If idx is '0', it won't be tried
61952426899SSeungwon Jeon 	 * Thus, initial values are uesed
62052426899SSeungwon Jeon 	 */
62152426899SSeungwon Jeon done:
62252426899SSeungwon Jeon 	fifoth_val = SDMMC_SET_FIFOTH(msize, rx_wmark, tx_wmark);
62352426899SSeungwon Jeon 	mci_writel(host, FIFOTH, fifoth_val);
62452426899SSeungwon Jeon #endif
62552426899SSeungwon Jeon }
62652426899SSeungwon Jeon 
627f1d2736cSSeungwon Jeon static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)
628f1d2736cSSeungwon Jeon {
629f1d2736cSSeungwon Jeon 	unsigned int blksz = data->blksz;
630f1d2736cSSeungwon Jeon 	u32 blksz_depth, fifo_depth;
631f1d2736cSSeungwon Jeon 	u16 thld_size;
632f1d2736cSSeungwon Jeon 
633f1d2736cSSeungwon Jeon 	WARN_ON(!(data->flags & MMC_DATA_READ));
634f1d2736cSSeungwon Jeon 
635f1d2736cSSeungwon Jeon 	if (host->timing != MMC_TIMING_MMC_HS200 &&
636f1d2736cSSeungwon Jeon 	    host->timing != MMC_TIMING_UHS_SDR104)
637f1d2736cSSeungwon Jeon 		goto disable;
638f1d2736cSSeungwon Jeon 
639f1d2736cSSeungwon Jeon 	blksz_depth = blksz / (1 << host->data_shift);
640f1d2736cSSeungwon Jeon 	fifo_depth = host->fifo_depth;
641f1d2736cSSeungwon Jeon 
642f1d2736cSSeungwon Jeon 	if (blksz_depth > fifo_depth)
643f1d2736cSSeungwon Jeon 		goto disable;
644f1d2736cSSeungwon Jeon 
645f1d2736cSSeungwon Jeon 	/*
646f1d2736cSSeungwon Jeon 	 * If (blksz_depth) >= (fifo_depth >> 1), should be 'thld_size <= blksz'
647f1d2736cSSeungwon Jeon 	 * If (blksz_depth) <  (fifo_depth >> 1), should be thld_size = blksz
648f1d2736cSSeungwon Jeon 	 * Currently just choose blksz.
649f1d2736cSSeungwon Jeon 	 */
650f1d2736cSSeungwon Jeon 	thld_size = blksz;
651f1d2736cSSeungwon Jeon 	mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(thld_size, 1));
652f1d2736cSSeungwon Jeon 	return;
653f1d2736cSSeungwon Jeon 
654f1d2736cSSeungwon Jeon disable:
655f1d2736cSSeungwon Jeon 	mci_writel(host, CDTHRCTL, SDMMC_SET_RD_THLD(0, 0));
656f1d2736cSSeungwon Jeon }
657f1d2736cSSeungwon Jeon 
6589aa51408SSeungwon Jeon static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
6599aa51408SSeungwon Jeon {
6609aa51408SSeungwon Jeon 	int sg_len;
6619aa51408SSeungwon Jeon 	u32 temp;
6629aa51408SSeungwon Jeon 
6639aa51408SSeungwon Jeon 	host->using_dma = 0;
6649aa51408SSeungwon Jeon 
6659aa51408SSeungwon Jeon 	/* If we don't have a channel, we can't do DMA */
6669aa51408SSeungwon Jeon 	if (!host->use_dma)
6679aa51408SSeungwon Jeon 		return -ENODEV;
6689aa51408SSeungwon Jeon 
6699aa51408SSeungwon Jeon 	sg_len = dw_mci_pre_dma_transfer(host, data, 0);
670a99aa9b9SSeungwon Jeon 	if (sg_len < 0) {
671a99aa9b9SSeungwon Jeon 		host->dma_ops->stop(host);
6729aa51408SSeungwon Jeon 		return sg_len;
673a99aa9b9SSeungwon Jeon 	}
6749aa51408SSeungwon Jeon 
67503e8cb53SJames Hogan 	host->using_dma = 1;
67603e8cb53SJames Hogan 
6774a90920cSThomas Abraham 	dev_vdbg(host->dev,
678f95f3850SWill Newton 		 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
679f95f3850SWill Newton 		 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
680f95f3850SWill Newton 		 sg_len);
681f95f3850SWill Newton 
68252426899SSeungwon Jeon 	/*
68352426899SSeungwon Jeon 	 * Decide the MSIZE and RX/TX Watermark.
68452426899SSeungwon Jeon 	 * If current block size is same with previous size,
68552426899SSeungwon Jeon 	 * no need to update fifoth.
68652426899SSeungwon Jeon 	 */
68752426899SSeungwon Jeon 	if (host->prev_blksz != data->blksz)
68852426899SSeungwon Jeon 		dw_mci_adjust_fifoth(host, data);
68952426899SSeungwon Jeon 
690f95f3850SWill Newton 	/* Enable the DMA interface */
691f95f3850SWill Newton 	temp = mci_readl(host, CTRL);
692f95f3850SWill Newton 	temp |= SDMMC_CTRL_DMA_ENABLE;
693f95f3850SWill Newton 	mci_writel(host, CTRL, temp);
694f95f3850SWill Newton 
695f95f3850SWill Newton 	/* Disable RX/TX IRQs, let DMA handle it */
696f95f3850SWill Newton 	temp = mci_readl(host, INTMASK);
697f95f3850SWill Newton 	temp  &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR);
698f95f3850SWill Newton 	mci_writel(host, INTMASK, temp);
699f95f3850SWill Newton 
700f95f3850SWill Newton 	host->dma_ops->start(host, sg_len);
701f95f3850SWill Newton 
702f95f3850SWill Newton 	return 0;
703f95f3850SWill Newton }
704f95f3850SWill Newton 
705f95f3850SWill Newton static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
706f95f3850SWill Newton {
707f95f3850SWill Newton 	u32 temp;
708f95f3850SWill Newton 
709f95f3850SWill Newton 	data->error = -EINPROGRESS;
710f95f3850SWill Newton 
711f95f3850SWill Newton 	WARN_ON(host->data);
712f95f3850SWill Newton 	host->sg = NULL;
713f95f3850SWill Newton 	host->data = data;
714f95f3850SWill Newton 
715f1d2736cSSeungwon Jeon 	if (data->flags & MMC_DATA_READ) {
71655c5efbcSJames Hogan 		host->dir_status = DW_MCI_RECV_STATUS;
717f1d2736cSSeungwon Jeon 		dw_mci_ctrl_rd_thld(host, data);
718f1d2736cSSeungwon Jeon 	} else {
71955c5efbcSJames Hogan 		host->dir_status = DW_MCI_SEND_STATUS;
720f1d2736cSSeungwon Jeon 	}
72155c5efbcSJames Hogan 
722f95f3850SWill Newton 	if (dw_mci_submit_data_dma(host, data)) {
723f9c2a0dcSSeungwon Jeon 		int flags = SG_MITER_ATOMIC;
724f9c2a0dcSSeungwon Jeon 		if (host->data->flags & MMC_DATA_READ)
725f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_TO_SG;
726f9c2a0dcSSeungwon Jeon 		else
727f9c2a0dcSSeungwon Jeon 			flags |= SG_MITER_FROM_SG;
728f9c2a0dcSSeungwon Jeon 
729f9c2a0dcSSeungwon Jeon 		sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
730f95f3850SWill Newton 		host->sg = data->sg;
73134b664a2SJames Hogan 		host->part_buf_start = 0;
73234b664a2SJames Hogan 		host->part_buf_count = 0;
733f95f3850SWill Newton 
734b40af3aaSJames Hogan 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR);
735f95f3850SWill Newton 		temp = mci_readl(host, INTMASK);
736f95f3850SWill Newton 		temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR;
737f95f3850SWill Newton 		mci_writel(host, INTMASK, temp);
738f95f3850SWill Newton 
739f95f3850SWill Newton 		temp = mci_readl(host, CTRL);
740f95f3850SWill Newton 		temp &= ~SDMMC_CTRL_DMA_ENABLE;
741f95f3850SWill Newton 		mci_writel(host, CTRL, temp);
74252426899SSeungwon Jeon 
74352426899SSeungwon Jeon 		/*
74452426899SSeungwon Jeon 		 * Use the initial fifoth_val for PIO mode.
74552426899SSeungwon Jeon 		 * If next issued data may be transfered by DMA mode,
74652426899SSeungwon Jeon 		 * prev_blksz should be invalidated.
74752426899SSeungwon Jeon 		 */
74852426899SSeungwon Jeon 		mci_writel(host, FIFOTH, host->fifoth_val);
74952426899SSeungwon Jeon 		host->prev_blksz = 0;
75052426899SSeungwon Jeon 	} else {
75152426899SSeungwon Jeon 		/*
75252426899SSeungwon Jeon 		 * Keep the current block size.
75352426899SSeungwon Jeon 		 * It will be used to decide whether to update
75452426899SSeungwon Jeon 		 * fifoth register next time.
75552426899SSeungwon Jeon 		 */
75652426899SSeungwon Jeon 		host->prev_blksz = data->blksz;
757f95f3850SWill Newton 	}
758f95f3850SWill Newton }
759f95f3850SWill Newton 
760f95f3850SWill Newton static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
761f95f3850SWill Newton {
762f95f3850SWill Newton 	struct dw_mci *host = slot->host;
763f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
764f95f3850SWill Newton 	unsigned int cmd_status = 0;
765f95f3850SWill Newton 
766f95f3850SWill Newton 	mci_writel(host, CMDARG, arg);
767f95f3850SWill Newton 	wmb();
768f95f3850SWill Newton 	mci_writel(host, CMD, SDMMC_CMD_START | cmd);
769f95f3850SWill Newton 
770f95f3850SWill Newton 	while (time_before(jiffies, timeout)) {
771f95f3850SWill Newton 		cmd_status = mci_readl(host, CMD);
772f95f3850SWill Newton 		if (!(cmd_status & SDMMC_CMD_START))
773f95f3850SWill Newton 			return;
774f95f3850SWill Newton 	}
775f95f3850SWill Newton 	dev_err(&slot->mmc->class_dev,
776f95f3850SWill Newton 		"Timeout sending command (cmd %#x arg %#x status %#x)\n",
777f95f3850SWill Newton 		cmd, arg, cmd_status);
778f95f3850SWill Newton }
779f95f3850SWill Newton 
780ab269128SAbhilash Kesavan static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
781f95f3850SWill Newton {
782f95f3850SWill Newton 	struct dw_mci *host = slot->host;
783fdf492a1SDoug Anderson 	unsigned int clock = slot->clock;
784f95f3850SWill Newton 	u32 div;
7859623b5b9SDoug Anderson 	u32 clk_en_a;
786f95f3850SWill Newton 
787fdf492a1SDoug Anderson 	if (!clock) {
788fdf492a1SDoug Anderson 		mci_writel(host, CLKENA, 0);
789fdf492a1SDoug Anderson 		mci_send_cmd(slot,
790fdf492a1SDoug Anderson 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
791fdf492a1SDoug Anderson 	} else if (clock != host->current_speed || force_clkinit) {
792fdf492a1SDoug Anderson 		div = host->bus_hz / clock;
793fdf492a1SDoug Anderson 		if (host->bus_hz % clock && host->bus_hz > clock)
794f95f3850SWill Newton 			/*
795f95f3850SWill Newton 			 * move the + 1 after the divide to prevent
796f95f3850SWill Newton 			 * over-clocking the card.
797f95f3850SWill Newton 			 */
798e419990bSSeungwon Jeon 			div += 1;
799e419990bSSeungwon Jeon 
800fdf492a1SDoug Anderson 		div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0;
801f95f3850SWill Newton 
802fdf492a1SDoug Anderson 		if ((clock << div) != slot->__clk_old || force_clkinit)
803f95f3850SWill Newton 			dev_info(&slot->mmc->class_dev,
804fdf492a1SDoug Anderson 				 "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
805fdf492a1SDoug Anderson 				 slot->id, host->bus_hz, clock,
806fdf492a1SDoug Anderson 				 div ? ((host->bus_hz / div) >> 1) :
807fdf492a1SDoug Anderson 				 host->bus_hz, div);
808f95f3850SWill Newton 
809f95f3850SWill Newton 		/* disable clock */
810f95f3850SWill Newton 		mci_writel(host, CLKENA, 0);
811f95f3850SWill Newton 		mci_writel(host, CLKSRC, 0);
812f95f3850SWill Newton 
813f95f3850SWill Newton 		/* inform CIU */
814f95f3850SWill Newton 		mci_send_cmd(slot,
815f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
816f95f3850SWill Newton 
817f95f3850SWill Newton 		/* set clock to desired speed */
818f95f3850SWill Newton 		mci_writel(host, CLKDIV, div);
819f95f3850SWill Newton 
820f95f3850SWill Newton 		/* inform CIU */
821f95f3850SWill Newton 		mci_send_cmd(slot,
822f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
823f95f3850SWill Newton 
8249623b5b9SDoug Anderson 		/* enable clock; only low power if no SDIO */
8259623b5b9SDoug Anderson 		clk_en_a = SDMMC_CLKEN_ENABLE << slot->id;
8269623b5b9SDoug Anderson 		if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id)))
8279623b5b9SDoug Anderson 			clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id;
8289623b5b9SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a);
829f95f3850SWill Newton 
830f95f3850SWill Newton 		/* inform CIU */
831f95f3850SWill Newton 		mci_send_cmd(slot,
832f95f3850SWill Newton 			     SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
833f95f3850SWill Newton 
834fdf492a1SDoug Anderson 		/* keep the clock with reflecting clock dividor */
835fdf492a1SDoug Anderson 		slot->__clk_old = clock << div;
836f95f3850SWill Newton 	}
837f95f3850SWill Newton 
838fdf492a1SDoug Anderson 	host->current_speed = clock;
839fdf492a1SDoug Anderson 
840f95f3850SWill Newton 	/* Set the current slot bus width */
8411d56c453SSeungwon Jeon 	mci_writel(host, CTYPE, (slot->ctype << slot->id));
842f95f3850SWill Newton }
843f95f3850SWill Newton 
844053b3ce6SSeungwon Jeon static void __dw_mci_start_request(struct dw_mci *host,
845053b3ce6SSeungwon Jeon 				   struct dw_mci_slot *slot,
846053b3ce6SSeungwon Jeon 				   struct mmc_command *cmd)
847f95f3850SWill Newton {
848f95f3850SWill Newton 	struct mmc_request *mrq;
849f95f3850SWill Newton 	struct mmc_data	*data;
850f95f3850SWill Newton 	u32 cmdflags;
851f95f3850SWill Newton 
852f95f3850SWill Newton 	mrq = slot->mrq;
853f95f3850SWill Newton 	if (host->pdata->select_slot)
854f95f3850SWill Newton 		host->pdata->select_slot(slot->id);
855f95f3850SWill Newton 
856f95f3850SWill Newton 	host->cur_slot = slot;
857f95f3850SWill Newton 	host->mrq = mrq;
858f95f3850SWill Newton 
859f95f3850SWill Newton 	host->pending_events = 0;
860f95f3850SWill Newton 	host->completed_events = 0;
861e352c813SSeungwon Jeon 	host->cmd_status = 0;
862f95f3850SWill Newton 	host->data_status = 0;
863e352c813SSeungwon Jeon 	host->dir_status = 0;
864f95f3850SWill Newton 
865053b3ce6SSeungwon Jeon 	data = cmd->data;
866f95f3850SWill Newton 	if (data) {
867f95f3850SWill Newton 		dw_mci_set_timeout(host);
868f95f3850SWill Newton 		mci_writel(host, BYTCNT, data->blksz*data->blocks);
869f95f3850SWill Newton 		mci_writel(host, BLKSIZ, data->blksz);
870f95f3850SWill Newton 	}
871f95f3850SWill Newton 
872f95f3850SWill Newton 	cmdflags = dw_mci_prepare_command(slot->mmc, cmd);
873f95f3850SWill Newton 
874f95f3850SWill Newton 	/* this is the first command, send the initialization clock */
875f95f3850SWill Newton 	if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags))
876f95f3850SWill Newton 		cmdflags |= SDMMC_CMD_INIT;
877f95f3850SWill Newton 
878f95f3850SWill Newton 	if (data) {
879f95f3850SWill Newton 		dw_mci_submit_data(host, data);
880f95f3850SWill Newton 		wmb();
881f95f3850SWill Newton 	}
882f95f3850SWill Newton 
883f95f3850SWill Newton 	dw_mci_start_command(host, cmd, cmdflags);
884f95f3850SWill Newton 
885f95f3850SWill Newton 	if (mrq->stop)
886f95f3850SWill Newton 		host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
88790c2143aSSeungwon Jeon 	else
88890c2143aSSeungwon Jeon 		host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd);
889f95f3850SWill Newton }
890f95f3850SWill Newton 
891053b3ce6SSeungwon Jeon static void dw_mci_start_request(struct dw_mci *host,
892053b3ce6SSeungwon Jeon 				 struct dw_mci_slot *slot)
893053b3ce6SSeungwon Jeon {
894053b3ce6SSeungwon Jeon 	struct mmc_request *mrq = slot->mrq;
895053b3ce6SSeungwon Jeon 	struct mmc_command *cmd;
896053b3ce6SSeungwon Jeon 
897053b3ce6SSeungwon Jeon 	cmd = mrq->sbc ? mrq->sbc : mrq->cmd;
898053b3ce6SSeungwon Jeon 	__dw_mci_start_request(host, slot, cmd);
899053b3ce6SSeungwon Jeon }
900053b3ce6SSeungwon Jeon 
9017456caaeSJames Hogan /* must be called with host->lock held */
902f95f3850SWill Newton static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot,
903f95f3850SWill Newton 				 struct mmc_request *mrq)
904f95f3850SWill Newton {
905f95f3850SWill Newton 	dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
906f95f3850SWill Newton 		 host->state);
907f95f3850SWill Newton 
908f95f3850SWill Newton 	slot->mrq = mrq;
909f95f3850SWill Newton 
910f95f3850SWill Newton 	if (host->state == STATE_IDLE) {
911f95f3850SWill Newton 		host->state = STATE_SENDING_CMD;
912f95f3850SWill Newton 		dw_mci_start_request(host, slot);
913f95f3850SWill Newton 	} else {
914f95f3850SWill Newton 		list_add_tail(&slot->queue_node, &host->queue);
915f95f3850SWill Newton 	}
916f95f3850SWill Newton }
917f95f3850SWill Newton 
918f95f3850SWill Newton static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
919f95f3850SWill Newton {
920f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
921f95f3850SWill Newton 	struct dw_mci *host = slot->host;
922f95f3850SWill Newton 
923f95f3850SWill Newton 	WARN_ON(slot->mrq);
924f95f3850SWill Newton 
9257456caaeSJames Hogan 	/*
9267456caaeSJames Hogan 	 * The check for card presence and queueing of the request must be
9277456caaeSJames Hogan 	 * atomic, otherwise the card could be removed in between and the
9287456caaeSJames Hogan 	 * request wouldn't fail until another card was inserted.
9297456caaeSJames Hogan 	 */
9307456caaeSJames Hogan 	spin_lock_bh(&host->lock);
9317456caaeSJames Hogan 
932f95f3850SWill Newton 	if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
9337456caaeSJames Hogan 		spin_unlock_bh(&host->lock);
934f95f3850SWill Newton 		mrq->cmd->error = -ENOMEDIUM;
935f95f3850SWill Newton 		mmc_request_done(mmc, mrq);
936f95f3850SWill Newton 		return;
937f95f3850SWill Newton 	}
938f95f3850SWill Newton 
939f95f3850SWill Newton 	dw_mci_queue_request(host, slot, mrq);
9407456caaeSJames Hogan 
9417456caaeSJames Hogan 	spin_unlock_bh(&host->lock);
942f95f3850SWill Newton }
943f95f3850SWill Newton 
944f95f3850SWill Newton static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
945f95f3850SWill Newton {
946f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
947e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
94841babf75SJaehoon Chung 	u32 regs;
949f95f3850SWill Newton 
950f95f3850SWill Newton 	switch (ios->bus_width) {
951f95f3850SWill Newton 	case MMC_BUS_WIDTH_4:
952f95f3850SWill Newton 		slot->ctype = SDMMC_CTYPE_4BIT;
953f95f3850SWill Newton 		break;
954c9b2a06fSJaehoon Chung 	case MMC_BUS_WIDTH_8:
955c9b2a06fSJaehoon Chung 		slot->ctype = SDMMC_CTYPE_8BIT;
956c9b2a06fSJaehoon Chung 		break;
957b2f7cb45SJaehoon Chung 	default:
958b2f7cb45SJaehoon Chung 		/* set default 1 bit mode */
959b2f7cb45SJaehoon Chung 		slot->ctype = SDMMC_CTYPE_1BIT;
960f95f3850SWill Newton 	}
961f95f3850SWill Newton 
96241babf75SJaehoon Chung 	regs = mci_readl(slot->host, UHS_REG);
9633f514291SSeungwon Jeon 
9643f514291SSeungwon Jeon 	/* DDR mode set */
9653f514291SSeungwon Jeon 	if (ios->timing == MMC_TIMING_UHS_DDR50)
966c69042a5SHyeonsu Kim 		regs |= ((0x1 << slot->id) << 16);
9673f514291SSeungwon Jeon 	else
968c69042a5SHyeonsu Kim 		regs &= ~((0x1 << slot->id) << 16);
9693f514291SSeungwon Jeon 
97041babf75SJaehoon Chung 	mci_writel(slot->host, UHS_REG, regs);
971f1d2736cSSeungwon Jeon 	slot->host->timing = ios->timing;
97241babf75SJaehoon Chung 
973f95f3850SWill Newton 	/*
974f95f3850SWill Newton 	 * Use mirror of ios->clock to prevent race with mmc
975f95f3850SWill Newton 	 * core ios update when finding the minimum.
976f95f3850SWill Newton 	 */
977f95f3850SWill Newton 	slot->clock = ios->clock;
978f95f3850SWill Newton 
979cb27a843SJames Hogan 	if (drv_data && drv_data->set_ios)
980cb27a843SJames Hogan 		drv_data->set_ios(slot->host, ios);
981800d78bfSThomas Abraham 
982bf7cb224SJaehoon Chung 	/* Slot specific timing and width adjustment */
983bf7cb224SJaehoon Chung 	dw_mci_setup_bus(slot, false);
984bf7cb224SJaehoon Chung 
985f95f3850SWill Newton 	switch (ios->power_mode) {
986f95f3850SWill Newton 	case MMC_POWER_UP:
987f95f3850SWill Newton 		set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
988e6f34e2fSJames Hogan 		/* Power up slot */
989e6f34e2fSJames Hogan 		if (slot->host->pdata->setpower)
990e6f34e2fSJames Hogan 			slot->host->pdata->setpower(slot->id, mmc->ocr_avail);
9914366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
9924366dcc5SJaehoon Chung 		regs |= (1 << slot->id);
9934366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
994e6f34e2fSJames Hogan 		break;
995e6f34e2fSJames Hogan 	case MMC_POWER_OFF:
996e6f34e2fSJames Hogan 		/* Power down slot */
997e6f34e2fSJames Hogan 		if (slot->host->pdata->setpower)
998e6f34e2fSJames Hogan 			slot->host->pdata->setpower(slot->id, 0);
9994366dcc5SJaehoon Chung 		regs = mci_readl(slot->host, PWREN);
10004366dcc5SJaehoon Chung 		regs &= ~(1 << slot->id);
10014366dcc5SJaehoon Chung 		mci_writel(slot->host, PWREN, regs);
1002f95f3850SWill Newton 		break;
1003f95f3850SWill Newton 	default:
1004f95f3850SWill Newton 		break;
1005f95f3850SWill Newton 	}
1006f95f3850SWill Newton }
1007f95f3850SWill Newton 
1008f95f3850SWill Newton static int dw_mci_get_ro(struct mmc_host *mmc)
1009f95f3850SWill Newton {
1010f95f3850SWill Newton 	int read_only;
1011f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
1012f95f3850SWill Newton 	struct dw_mci_board *brd = slot->host->pdata;
1013f95f3850SWill Newton 
1014f95f3850SWill Newton 	/* Use platform get_ro function, else try on board write protect */
10159640639bSDoug Anderson 	if (slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT)
1016b4967aa5SThomas Abraham 		read_only = 0;
1017b4967aa5SThomas Abraham 	else if (brd->get_ro)
1018f95f3850SWill Newton 		read_only = brd->get_ro(slot->id);
101955a6ceb2SDoug Anderson 	else if (gpio_is_valid(slot->wp_gpio))
102055a6ceb2SDoug Anderson 		read_only = gpio_get_value(slot->wp_gpio);
1021f95f3850SWill Newton 	else
1022f95f3850SWill Newton 		read_only =
1023f95f3850SWill Newton 			mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0;
1024f95f3850SWill Newton 
1025f95f3850SWill Newton 	dev_dbg(&mmc->class_dev, "card is %s\n",
1026f95f3850SWill Newton 		read_only ? "read-only" : "read-write");
1027f95f3850SWill Newton 
1028f95f3850SWill Newton 	return read_only;
1029f95f3850SWill Newton }
1030f95f3850SWill Newton 
1031f95f3850SWill Newton static int dw_mci_get_cd(struct mmc_host *mmc)
1032f95f3850SWill Newton {
1033f95f3850SWill Newton 	int present;
1034f95f3850SWill Newton 	struct dw_mci_slot *slot = mmc_priv(mmc);
1035f95f3850SWill Newton 	struct dw_mci_board *brd = slot->host->pdata;
1036*7cf347bdSZhangfei Gao 	struct dw_mci *host = slot->host;
1037*7cf347bdSZhangfei Gao 	int gpio_cd = mmc_gpio_get_cd(mmc);
1038f95f3850SWill Newton 
1039f95f3850SWill Newton 	/* Use platform get_cd function, else try onboard card detect */
1040fc3d7720SJaehoon Chung 	if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
1041fc3d7720SJaehoon Chung 		present = 1;
1042fc3d7720SJaehoon Chung 	else if (brd->get_cd)
1043f95f3850SWill Newton 		present = !brd->get_cd(slot->id);
1044bf626e55SZhangfei Gao 	else if (!IS_ERR_VALUE(gpio_cd))
1045*7cf347bdSZhangfei Gao 		present = gpio_cd;
1046f95f3850SWill Newton 	else
1047f95f3850SWill Newton 		present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
1048f95f3850SWill Newton 			== 0 ? 1 : 0;
1049f95f3850SWill Newton 
1050*7cf347bdSZhangfei Gao 	spin_lock_bh(&host->lock);
1051bf626e55SZhangfei Gao 	if (present) {
1052bf626e55SZhangfei Gao 		set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
1053f95f3850SWill Newton 		dev_dbg(&mmc->class_dev, "card is present\n");
1054bf626e55SZhangfei Gao 	} else {
1055bf626e55SZhangfei Gao 		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
1056f95f3850SWill Newton 		dev_dbg(&mmc->class_dev, "card is not present\n");
1057bf626e55SZhangfei Gao 	}
1058*7cf347bdSZhangfei Gao 	spin_unlock_bh(&host->lock);
1059f95f3850SWill Newton 
1060f95f3850SWill Newton 	return present;
1061f95f3850SWill Newton }
1062f95f3850SWill Newton 
10639623b5b9SDoug Anderson /*
10649623b5b9SDoug Anderson  * Disable lower power mode.
10659623b5b9SDoug Anderson  *
10669623b5b9SDoug Anderson  * Low power mode will stop the card clock when idle.  According to the
10679623b5b9SDoug Anderson  * description of the CLKENA register we should disable low power mode
10689623b5b9SDoug Anderson  * for SDIO cards if we need SDIO interrupts to work.
10699623b5b9SDoug Anderson  *
10709623b5b9SDoug Anderson  * This function is fast if low power mode is already disabled.
10719623b5b9SDoug Anderson  */
10729623b5b9SDoug Anderson static void dw_mci_disable_low_power(struct dw_mci_slot *slot)
10739623b5b9SDoug Anderson {
10749623b5b9SDoug Anderson 	struct dw_mci *host = slot->host;
10759623b5b9SDoug Anderson 	u32 clk_en_a;
10769623b5b9SDoug Anderson 	const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id;
10779623b5b9SDoug Anderson 
10789623b5b9SDoug Anderson 	clk_en_a = mci_readl(host, CLKENA);
10799623b5b9SDoug Anderson 
10809623b5b9SDoug Anderson 	if (clk_en_a & clken_low_pwr) {
10819623b5b9SDoug Anderson 		mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr);
10829623b5b9SDoug Anderson 		mci_send_cmd(slot, SDMMC_CMD_UPD_CLK |
10839623b5b9SDoug Anderson 			     SDMMC_CMD_PRV_DAT_WAIT, 0);
10849623b5b9SDoug Anderson 	}
10859623b5b9SDoug Anderson }
10869623b5b9SDoug Anderson 
10871a5c8e1fSShashidhar Hiremath static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
10881a5c8e1fSShashidhar Hiremath {
10891a5c8e1fSShashidhar Hiremath 	struct dw_mci_slot *slot = mmc_priv(mmc);
10901a5c8e1fSShashidhar Hiremath 	struct dw_mci *host = slot->host;
10911a5c8e1fSShashidhar Hiremath 	u32 int_mask;
10921a5c8e1fSShashidhar Hiremath 
10931a5c8e1fSShashidhar Hiremath 	/* Enable/disable Slot Specific SDIO interrupt */
10941a5c8e1fSShashidhar Hiremath 	int_mask = mci_readl(host, INTMASK);
10951a5c8e1fSShashidhar Hiremath 	if (enb) {
10969623b5b9SDoug Anderson 		/*
10979623b5b9SDoug Anderson 		 * Turn off low power mode if it was enabled.  This is a bit of
10989623b5b9SDoug Anderson 		 * a heavy operation and we disable / enable IRQs a lot, so
10999623b5b9SDoug Anderson 		 * we'll leave low power mode disabled and it will get
11009623b5b9SDoug Anderson 		 * re-enabled again in dw_mci_setup_bus().
11019623b5b9SDoug Anderson 		 */
11029623b5b9SDoug Anderson 		dw_mci_disable_low_power(slot);
11039623b5b9SDoug Anderson 
11041a5c8e1fSShashidhar Hiremath 		mci_writel(host, INTMASK,
1105705ad047SKyoungil Kim 			   (int_mask | SDMMC_INT_SDIO(slot->id)));
11061a5c8e1fSShashidhar Hiremath 	} else {
11071a5c8e1fSShashidhar Hiremath 		mci_writel(host, INTMASK,
1108705ad047SKyoungil Kim 			   (int_mask & ~SDMMC_INT_SDIO(slot->id)));
11091a5c8e1fSShashidhar Hiremath 	}
11101a5c8e1fSShashidhar Hiremath }
11111a5c8e1fSShashidhar Hiremath 
11120976f16dSSeungwon Jeon static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
11130976f16dSSeungwon Jeon {
11140976f16dSSeungwon Jeon 	struct dw_mci_slot *slot = mmc_priv(mmc);
11150976f16dSSeungwon Jeon 	struct dw_mci *host = slot->host;
11160976f16dSSeungwon Jeon 	const struct dw_mci_drv_data *drv_data = host->drv_data;
11170976f16dSSeungwon Jeon 	struct dw_mci_tuning_data tuning_data;
11180976f16dSSeungwon Jeon 	int err = -ENOSYS;
11190976f16dSSeungwon Jeon 
11200976f16dSSeungwon Jeon 	if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
11210976f16dSSeungwon Jeon 		if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
11220976f16dSSeungwon Jeon 			tuning_data.blk_pattern = tuning_blk_pattern_8bit;
11230976f16dSSeungwon Jeon 			tuning_data.blksz = sizeof(tuning_blk_pattern_8bit);
11240976f16dSSeungwon Jeon 		} else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
11250976f16dSSeungwon Jeon 			tuning_data.blk_pattern = tuning_blk_pattern_4bit;
11260976f16dSSeungwon Jeon 			tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
11270976f16dSSeungwon Jeon 		} else {
11280976f16dSSeungwon Jeon 			return -EINVAL;
11290976f16dSSeungwon Jeon 		}
11300976f16dSSeungwon Jeon 	} else if (opcode == MMC_SEND_TUNING_BLOCK) {
11310976f16dSSeungwon Jeon 		tuning_data.blk_pattern = tuning_blk_pattern_4bit;
11320976f16dSSeungwon Jeon 		tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
11330976f16dSSeungwon Jeon 	} else {
11340976f16dSSeungwon Jeon 		dev_err(host->dev,
11350976f16dSSeungwon Jeon 			"Undefined command(%d) for tuning\n", opcode);
11360976f16dSSeungwon Jeon 		return -EINVAL;
11370976f16dSSeungwon Jeon 	}
11380976f16dSSeungwon Jeon 
11390976f16dSSeungwon Jeon 	if (drv_data && drv_data->execute_tuning)
11400976f16dSSeungwon Jeon 		err = drv_data->execute_tuning(slot, opcode, &tuning_data);
11410976f16dSSeungwon Jeon 	return err;
11420976f16dSSeungwon Jeon }
11430976f16dSSeungwon Jeon 
1144f95f3850SWill Newton static const struct mmc_host_ops dw_mci_ops = {
1145f95f3850SWill Newton 	.request		= dw_mci_request,
11469aa51408SSeungwon Jeon 	.pre_req		= dw_mci_pre_req,
11479aa51408SSeungwon Jeon 	.post_req		= dw_mci_post_req,
1148f95f3850SWill Newton 	.set_ios		= dw_mci_set_ios,
1149f95f3850SWill Newton 	.get_ro			= dw_mci_get_ro,
1150f95f3850SWill Newton 	.get_cd			= dw_mci_get_cd,
11511a5c8e1fSShashidhar Hiremath 	.enable_sdio_irq	= dw_mci_enable_sdio_irq,
11520976f16dSSeungwon Jeon 	.execute_tuning		= dw_mci_execute_tuning,
1153f95f3850SWill Newton };
1154f95f3850SWill Newton 
1155f95f3850SWill Newton static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
1156f95f3850SWill Newton 	__releases(&host->lock)
1157f95f3850SWill Newton 	__acquires(&host->lock)
1158f95f3850SWill Newton {
1159f95f3850SWill Newton 	struct dw_mci_slot *slot;
1160f95f3850SWill Newton 	struct mmc_host	*prev_mmc = host->cur_slot->mmc;
1161f95f3850SWill Newton 
1162f95f3850SWill Newton 	WARN_ON(host->cmd || host->data);
1163f95f3850SWill Newton 
1164f95f3850SWill Newton 	host->cur_slot->mrq = NULL;
1165f95f3850SWill Newton 	host->mrq = NULL;
1166f95f3850SWill Newton 	if (!list_empty(&host->queue)) {
1167f95f3850SWill Newton 		slot = list_entry(host->queue.next,
1168f95f3850SWill Newton 				  struct dw_mci_slot, queue_node);
1169f95f3850SWill Newton 		list_del(&slot->queue_node);
11704a90920cSThomas Abraham 		dev_vdbg(host->dev, "list not empty: %s is next\n",
1171f95f3850SWill Newton 			 mmc_hostname(slot->mmc));
1172f95f3850SWill Newton 		host->state = STATE_SENDING_CMD;
1173f95f3850SWill Newton 		dw_mci_start_request(host, slot);
1174f95f3850SWill Newton 	} else {
11754a90920cSThomas Abraham 		dev_vdbg(host->dev, "list empty\n");
1176f95f3850SWill Newton 		host->state = STATE_IDLE;
1177f95f3850SWill Newton 	}
1178f95f3850SWill Newton 
1179f95f3850SWill Newton 	spin_unlock(&host->lock);
1180f95f3850SWill Newton 	mmc_request_done(prev_mmc, mrq);
1181f95f3850SWill Newton 	spin_lock(&host->lock);
1182f95f3850SWill Newton }
1183f95f3850SWill Newton 
1184e352c813SSeungwon Jeon static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
1185f95f3850SWill Newton {
1186f95f3850SWill Newton 	u32 status = host->cmd_status;
1187f95f3850SWill Newton 
1188f95f3850SWill Newton 	host->cmd_status = 0;
1189f95f3850SWill Newton 
1190f95f3850SWill Newton 	/* Read the response from the card (up to 16 bytes) */
1191f95f3850SWill Newton 	if (cmd->flags & MMC_RSP_PRESENT) {
1192f95f3850SWill Newton 		if (cmd->flags & MMC_RSP_136) {
1193f95f3850SWill Newton 			cmd->resp[3] = mci_readl(host, RESP0);
1194f95f3850SWill Newton 			cmd->resp[2] = mci_readl(host, RESP1);
1195f95f3850SWill Newton 			cmd->resp[1] = mci_readl(host, RESP2);
1196f95f3850SWill Newton 			cmd->resp[0] = mci_readl(host, RESP3);
1197f95f3850SWill Newton 		} else {
1198f95f3850SWill Newton 			cmd->resp[0] = mci_readl(host, RESP0);
1199f95f3850SWill Newton 			cmd->resp[1] = 0;
1200f95f3850SWill Newton 			cmd->resp[2] = 0;
1201f95f3850SWill Newton 			cmd->resp[3] = 0;
1202f95f3850SWill Newton 		}
1203f95f3850SWill Newton 	}
1204f95f3850SWill Newton 
1205f95f3850SWill Newton 	if (status & SDMMC_INT_RTO)
1206f95f3850SWill Newton 		cmd->error = -ETIMEDOUT;
1207f95f3850SWill Newton 	else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC))
1208f95f3850SWill Newton 		cmd->error = -EILSEQ;
1209f95f3850SWill Newton 	else if (status & SDMMC_INT_RESP_ERR)
1210f95f3850SWill Newton 		cmd->error = -EIO;
1211f95f3850SWill Newton 	else
1212f95f3850SWill Newton 		cmd->error = 0;
1213f95f3850SWill Newton 
1214f95f3850SWill Newton 	if (cmd->error) {
1215f95f3850SWill Newton 		/* newer ip versions need a delay between retries */
1216f95f3850SWill Newton 		if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY)
1217f95f3850SWill Newton 			mdelay(20);
1218f95f3850SWill Newton 	}
1219e352c813SSeungwon Jeon 
1220e352c813SSeungwon Jeon 	return cmd->error;
1221e352c813SSeungwon Jeon }
1222e352c813SSeungwon Jeon 
1223e352c813SSeungwon Jeon static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data)
1224e352c813SSeungwon Jeon {
122531bff450SSeungwon Jeon 	u32 status = host->data_status;
1226e352c813SSeungwon Jeon 
1227e352c813SSeungwon Jeon 	if (status & DW_MCI_DATA_ERROR_FLAGS) {
1228e352c813SSeungwon Jeon 		if (status & SDMMC_INT_DRTO) {
1229e352c813SSeungwon Jeon 			data->error = -ETIMEDOUT;
1230e352c813SSeungwon Jeon 		} else if (status & SDMMC_INT_DCRC) {
1231e352c813SSeungwon Jeon 			data->error = -EILSEQ;
1232e352c813SSeungwon Jeon 		} else if (status & SDMMC_INT_EBE) {
1233e352c813SSeungwon Jeon 			if (host->dir_status ==
1234e352c813SSeungwon Jeon 				DW_MCI_SEND_STATUS) {
1235e352c813SSeungwon Jeon 				/*
1236e352c813SSeungwon Jeon 				 * No data CRC status was returned.
1237e352c813SSeungwon Jeon 				 * The number of bytes transferred
1238e352c813SSeungwon Jeon 				 * will be exaggerated in PIO mode.
1239e352c813SSeungwon Jeon 				 */
1240e352c813SSeungwon Jeon 				data->bytes_xfered = 0;
1241e352c813SSeungwon Jeon 				data->error = -ETIMEDOUT;
1242e352c813SSeungwon Jeon 			} else if (host->dir_status ==
1243e352c813SSeungwon Jeon 					DW_MCI_RECV_STATUS) {
1244e352c813SSeungwon Jeon 				data->error = -EIO;
1245e352c813SSeungwon Jeon 			}
1246e352c813SSeungwon Jeon 		} else {
1247e352c813SSeungwon Jeon 			/* SDMMC_INT_SBE is included */
1248e352c813SSeungwon Jeon 			data->error = -EIO;
1249e352c813SSeungwon Jeon 		}
1250e352c813SSeungwon Jeon 
1251e352c813SSeungwon Jeon 		dev_err(host->dev, "data error, status 0x%08x\n", status);
1252e352c813SSeungwon Jeon 
1253e352c813SSeungwon Jeon 		/*
1254e352c813SSeungwon Jeon 		 * After an error, there may be data lingering
125531bff450SSeungwon Jeon 		 * in the FIFO
1256e352c813SSeungwon Jeon 		 */
125731bff450SSeungwon Jeon 		dw_mci_fifo_reset(host);
1258e352c813SSeungwon Jeon 	} else {
1259e352c813SSeungwon Jeon 		data->bytes_xfered = data->blocks * data->blksz;
1260e352c813SSeungwon Jeon 		data->error = 0;
1261e352c813SSeungwon Jeon 	}
1262e352c813SSeungwon Jeon 
1263e352c813SSeungwon Jeon 	return data->error;
1264f95f3850SWill Newton }
1265f95f3850SWill Newton 
1266f95f3850SWill Newton static void dw_mci_tasklet_func(unsigned long priv)
1267f95f3850SWill Newton {
1268f95f3850SWill Newton 	struct dw_mci *host = (struct dw_mci *)priv;
1269f95f3850SWill Newton 	struct mmc_data	*data;
1270f95f3850SWill Newton 	struct mmc_command *cmd;
1271e352c813SSeungwon Jeon 	struct mmc_request *mrq;
1272f95f3850SWill Newton 	enum dw_mci_state state;
1273f95f3850SWill Newton 	enum dw_mci_state prev_state;
1274e352c813SSeungwon Jeon 	unsigned int err;
1275f95f3850SWill Newton 
1276f95f3850SWill Newton 	spin_lock(&host->lock);
1277f95f3850SWill Newton 
1278f95f3850SWill Newton 	state = host->state;
1279f95f3850SWill Newton 	data = host->data;
1280e352c813SSeungwon Jeon 	mrq = host->mrq;
1281f95f3850SWill Newton 
1282f95f3850SWill Newton 	do {
1283f95f3850SWill Newton 		prev_state = state;
1284f95f3850SWill Newton 
1285f95f3850SWill Newton 		switch (state) {
1286f95f3850SWill Newton 		case STATE_IDLE:
1287f95f3850SWill Newton 			break;
1288f95f3850SWill Newton 
1289f95f3850SWill Newton 		case STATE_SENDING_CMD:
1290f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1291f95f3850SWill Newton 						&host->pending_events))
1292f95f3850SWill Newton 				break;
1293f95f3850SWill Newton 
1294f95f3850SWill Newton 			cmd = host->cmd;
1295f95f3850SWill Newton 			host->cmd = NULL;
1296f95f3850SWill Newton 			set_bit(EVENT_CMD_COMPLETE, &host->completed_events);
1297e352c813SSeungwon Jeon 			err = dw_mci_command_complete(host, cmd);
1298e352c813SSeungwon Jeon 			if (cmd == mrq->sbc && !err) {
1299053b3ce6SSeungwon Jeon 				prev_state = state = STATE_SENDING_CMD;
1300053b3ce6SSeungwon Jeon 				__dw_mci_start_request(host, host->cur_slot,
1301e352c813SSeungwon Jeon 						       mrq->cmd);
1302053b3ce6SSeungwon Jeon 				goto unlock;
1303053b3ce6SSeungwon Jeon 			}
1304053b3ce6SSeungwon Jeon 
1305e352c813SSeungwon Jeon 			if (cmd->data && err) {
130671abb133SSeungwon Jeon 				dw_mci_stop_dma(host);
130790c2143aSSeungwon Jeon 				send_stop_abort(host, data);
130871abb133SSeungwon Jeon 				state = STATE_SENDING_STOP;
130971abb133SSeungwon Jeon 				break;
131071abb133SSeungwon Jeon 			}
131171abb133SSeungwon Jeon 
1312e352c813SSeungwon Jeon 			if (!cmd->data || err) {
1313e352c813SSeungwon Jeon 				dw_mci_request_end(host, mrq);
1314f95f3850SWill Newton 				goto unlock;
1315f95f3850SWill Newton 			}
1316f95f3850SWill Newton 
1317f95f3850SWill Newton 			prev_state = state = STATE_SENDING_DATA;
1318f95f3850SWill Newton 			/* fall through */
1319f95f3850SWill Newton 
1320f95f3850SWill Newton 		case STATE_SENDING_DATA:
1321f95f3850SWill Newton 			if (test_and_clear_bit(EVENT_DATA_ERROR,
1322f95f3850SWill Newton 					       &host->pending_events)) {
1323f95f3850SWill Newton 				dw_mci_stop_dma(host);
132490c2143aSSeungwon Jeon 				send_stop_abort(host, data);
1325f95f3850SWill Newton 				state = STATE_DATA_ERROR;
1326f95f3850SWill Newton 				break;
1327f95f3850SWill Newton 			}
1328f95f3850SWill Newton 
1329f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1330f95f3850SWill Newton 						&host->pending_events))
1331f95f3850SWill Newton 				break;
1332f95f3850SWill Newton 
1333f95f3850SWill Newton 			set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
1334f95f3850SWill Newton 			prev_state = state = STATE_DATA_BUSY;
1335f95f3850SWill Newton 			/* fall through */
1336f95f3850SWill Newton 
1337f95f3850SWill Newton 		case STATE_DATA_BUSY:
1338f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
1339f95f3850SWill Newton 						&host->pending_events))
1340f95f3850SWill Newton 				break;
1341f95f3850SWill Newton 
1342f95f3850SWill Newton 			host->data = NULL;
1343f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
1344e352c813SSeungwon Jeon 			err = dw_mci_data_complete(host, data);
1345f95f3850SWill Newton 
1346e352c813SSeungwon Jeon 			if (!err) {
1347e352c813SSeungwon Jeon 				if (!data->stop || mrq->sbc) {
1348e352c813SSeungwon Jeon 					if (mrq->sbc)
1349053b3ce6SSeungwon Jeon 						data->stop->error = 0;
1350e352c813SSeungwon Jeon 					dw_mci_request_end(host, mrq);
1351053b3ce6SSeungwon Jeon 					goto unlock;
1352053b3ce6SSeungwon Jeon 				}
1353053b3ce6SSeungwon Jeon 
135490c2143aSSeungwon Jeon 				/* stop command for open-ended transfer*/
1355e352c813SSeungwon Jeon 				if (data->stop)
135690c2143aSSeungwon Jeon 					send_stop_abort(host, data);
135790c2143aSSeungwon Jeon 			}
1358e352c813SSeungwon Jeon 
1359e352c813SSeungwon Jeon 			/*
1360e352c813SSeungwon Jeon 			 * If err has non-zero,
1361e352c813SSeungwon Jeon 			 * stop-abort command has been already issued.
1362e352c813SSeungwon Jeon 			 */
1363e352c813SSeungwon Jeon 			prev_state = state = STATE_SENDING_STOP;
1364e352c813SSeungwon Jeon 
1365f95f3850SWill Newton 			/* fall through */
1366f95f3850SWill Newton 
1367f95f3850SWill Newton 		case STATE_SENDING_STOP:
1368f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1369f95f3850SWill Newton 						&host->pending_events))
1370f95f3850SWill Newton 				break;
1371f95f3850SWill Newton 
137271abb133SSeungwon Jeon 			/* CMD error in data command */
137331bff450SSeungwon Jeon 			if (mrq->cmd->error && mrq->data)
137431bff450SSeungwon Jeon 				dw_mci_fifo_reset(host);
137571abb133SSeungwon Jeon 
1376f95f3850SWill Newton 			host->cmd = NULL;
137771abb133SSeungwon Jeon 			host->data = NULL;
137890c2143aSSeungwon Jeon 
1379e352c813SSeungwon Jeon 			if (mrq->stop)
1380e352c813SSeungwon Jeon 				dw_mci_command_complete(host, mrq->stop);
138190c2143aSSeungwon Jeon 			else
138290c2143aSSeungwon Jeon 				host->cmd_status = 0;
138390c2143aSSeungwon Jeon 
1384e352c813SSeungwon Jeon 			dw_mci_request_end(host, mrq);
1385f95f3850SWill Newton 			goto unlock;
1386f95f3850SWill Newton 
1387f95f3850SWill Newton 		case STATE_DATA_ERROR:
1388f95f3850SWill Newton 			if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
1389f95f3850SWill Newton 						&host->pending_events))
1390f95f3850SWill Newton 				break;
1391f95f3850SWill Newton 
1392f95f3850SWill Newton 			state = STATE_DATA_BUSY;
1393f95f3850SWill Newton 			break;
1394f95f3850SWill Newton 		}
1395f95f3850SWill Newton 	} while (state != prev_state);
1396f95f3850SWill Newton 
1397f95f3850SWill Newton 	host->state = state;
1398f95f3850SWill Newton unlock:
1399f95f3850SWill Newton 	spin_unlock(&host->lock);
1400f95f3850SWill Newton 
1401f95f3850SWill Newton }
1402f95f3850SWill Newton 
140334b664a2SJames Hogan /* push final bytes to part_buf, only use during push */
140434b664a2SJames Hogan static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt)
140534b664a2SJames Hogan {
140634b664a2SJames Hogan 	memcpy((void *)&host->part_buf, buf, cnt);
140734b664a2SJames Hogan 	host->part_buf_count = cnt;
140834b664a2SJames Hogan }
140934b664a2SJames Hogan 
141034b664a2SJames Hogan /* append bytes to part_buf, only use during push */
141134b664a2SJames Hogan static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt)
141234b664a2SJames Hogan {
141334b664a2SJames Hogan 	cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count);
141434b664a2SJames Hogan 	memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt);
141534b664a2SJames Hogan 	host->part_buf_count += cnt;
141634b664a2SJames Hogan 	return cnt;
141734b664a2SJames Hogan }
141834b664a2SJames Hogan 
141934b664a2SJames Hogan /* pull first bytes from part_buf, only use during pull */
142034b664a2SJames Hogan static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt)
142134b664a2SJames Hogan {
142234b664a2SJames Hogan 	cnt = min(cnt, (int)host->part_buf_count);
142334b664a2SJames Hogan 	if (cnt) {
142434b664a2SJames Hogan 		memcpy(buf, (void *)&host->part_buf + host->part_buf_start,
142534b664a2SJames Hogan 		       cnt);
142634b664a2SJames Hogan 		host->part_buf_count -= cnt;
142734b664a2SJames Hogan 		host->part_buf_start += cnt;
142834b664a2SJames Hogan 	}
142934b664a2SJames Hogan 	return cnt;
143034b664a2SJames Hogan }
143134b664a2SJames Hogan 
143234b664a2SJames Hogan /* pull final bytes from the part_buf, assuming it's just been filled */
143334b664a2SJames Hogan static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt)
143434b664a2SJames Hogan {
143534b664a2SJames Hogan 	memcpy(buf, &host->part_buf, cnt);
143634b664a2SJames Hogan 	host->part_buf_start = cnt;
143734b664a2SJames Hogan 	host->part_buf_count = (1 << host->data_shift) - cnt;
143834b664a2SJames Hogan }
143934b664a2SJames Hogan 
1440f95f3850SWill Newton static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
1441f95f3850SWill Newton {
1442cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1443cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1444cfbeb59cSMarkos Chandras 
144534b664a2SJames Hogan 	/* try and push anything in the part_buf */
144634b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
144734b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
144834b664a2SJames Hogan 		buf += len;
144934b664a2SJames Hogan 		cnt -= len;
1450cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 2) {
14514e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
14524e0a5adfSJaehoon Chung 					host->part_buf16);
145334b664a2SJames Hogan 			host->part_buf_count = 0;
145434b664a2SJames Hogan 		}
145534b664a2SJames Hogan 	}
145634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
145734b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
145834b664a2SJames Hogan 		while (cnt >= 2) {
145934b664a2SJames Hogan 			u16 aligned_buf[64];
146034b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
146134b664a2SJames Hogan 			int items = len >> 1;
146234b664a2SJames Hogan 			int i;
146334b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
146434b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
146534b664a2SJames Hogan 			buf += len;
146634b664a2SJames Hogan 			cnt -= len;
146734b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
146834b664a2SJames Hogan 			for (i = 0; i < items; ++i)
14694e0a5adfSJaehoon Chung 				mci_writew(host, DATA(host->data_offset),
14704e0a5adfSJaehoon Chung 						aligned_buf[i]);
147134b664a2SJames Hogan 		}
147234b664a2SJames Hogan 	} else
147334b664a2SJames Hogan #endif
147434b664a2SJames Hogan 	{
147534b664a2SJames Hogan 		u16 *pdata = buf;
147634b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
14774e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset), *pdata++);
147834b664a2SJames Hogan 		buf = pdata;
147934b664a2SJames Hogan 	}
148034b664a2SJames Hogan 	/* put anything remaining in the part_buf */
148134b664a2SJames Hogan 	if (cnt) {
148234b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1483cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1484cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1485cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
14864e0a5adfSJaehoon Chung 			mci_writew(host, DATA(host->data_offset),
14874e0a5adfSJaehoon Chung 				   host->part_buf16);
1488f95f3850SWill Newton 	}
1489f95f3850SWill Newton }
1490f95f3850SWill Newton 
1491f95f3850SWill Newton static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
1492f95f3850SWill Newton {
149334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
149434b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x1)) {
149534b664a2SJames Hogan 		while (cnt >= 2) {
149634b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
149734b664a2SJames Hogan 			u16 aligned_buf[64];
149834b664a2SJames Hogan 			int len = min(cnt & -2, (int)sizeof(aligned_buf));
149934b664a2SJames Hogan 			int items = len >> 1;
150034b664a2SJames Hogan 			int i;
150134b664a2SJames Hogan 			for (i = 0; i < items; ++i)
15024e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readw(host,
15034e0a5adfSJaehoon Chung 						DATA(host->data_offset));
150434b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
150534b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
150634b664a2SJames Hogan 			buf += len;
150734b664a2SJames Hogan 			cnt -= len;
150834b664a2SJames Hogan 		}
150934b664a2SJames Hogan 	} else
151034b664a2SJames Hogan #endif
151134b664a2SJames Hogan 	{
151234b664a2SJames Hogan 		u16 *pdata = buf;
151334b664a2SJames Hogan 		for (; cnt >= 2; cnt -= 2)
15144e0a5adfSJaehoon Chung 			*pdata++ = mci_readw(host, DATA(host->data_offset));
151534b664a2SJames Hogan 		buf = pdata;
151634b664a2SJames Hogan 	}
151734b664a2SJames Hogan 	if (cnt) {
15184e0a5adfSJaehoon Chung 		host->part_buf16 = mci_readw(host, DATA(host->data_offset));
151934b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1520f95f3850SWill Newton 	}
1521f95f3850SWill Newton }
1522f95f3850SWill Newton 
1523f95f3850SWill Newton static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
1524f95f3850SWill Newton {
1525cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1526cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1527cfbeb59cSMarkos Chandras 
152834b664a2SJames Hogan 	/* try and push anything in the part_buf */
152934b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
153034b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
153134b664a2SJames Hogan 		buf += len;
153234b664a2SJames Hogan 		cnt -= len;
1533cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 4) {
15344e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
15354e0a5adfSJaehoon Chung 					host->part_buf32);
153634b664a2SJames Hogan 			host->part_buf_count = 0;
153734b664a2SJames Hogan 		}
153834b664a2SJames Hogan 	}
153934b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
154034b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
154134b664a2SJames Hogan 		while (cnt >= 4) {
154234b664a2SJames Hogan 			u32 aligned_buf[32];
154334b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
154434b664a2SJames Hogan 			int items = len >> 2;
154534b664a2SJames Hogan 			int i;
154634b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
154734b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
154834b664a2SJames Hogan 			buf += len;
154934b664a2SJames Hogan 			cnt -= len;
155034b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
155134b664a2SJames Hogan 			for (i = 0; i < items; ++i)
15524e0a5adfSJaehoon Chung 				mci_writel(host, DATA(host->data_offset),
15534e0a5adfSJaehoon Chung 						aligned_buf[i]);
155434b664a2SJames Hogan 		}
155534b664a2SJames Hogan 	} else
155634b664a2SJames Hogan #endif
155734b664a2SJames Hogan 	{
155834b664a2SJames Hogan 		u32 *pdata = buf;
155934b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
15604e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset), *pdata++);
156134b664a2SJames Hogan 		buf = pdata;
156234b664a2SJames Hogan 	}
156334b664a2SJames Hogan 	/* put anything remaining in the part_buf */
156434b664a2SJames Hogan 	if (cnt) {
156534b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1566cfbeb59cSMarkos Chandras 		 /* Push data if we have reached the expected data length */
1567cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1568cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
15694e0a5adfSJaehoon Chung 			mci_writel(host, DATA(host->data_offset),
15704e0a5adfSJaehoon Chung 				   host->part_buf32);
1571f95f3850SWill Newton 	}
1572f95f3850SWill Newton }
1573f95f3850SWill Newton 
1574f95f3850SWill Newton static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
1575f95f3850SWill Newton {
157634b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
157734b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x3)) {
157834b664a2SJames Hogan 		while (cnt >= 4) {
157934b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
158034b664a2SJames Hogan 			u32 aligned_buf[32];
158134b664a2SJames Hogan 			int len = min(cnt & -4, (int)sizeof(aligned_buf));
158234b664a2SJames Hogan 			int items = len >> 2;
158334b664a2SJames Hogan 			int i;
158434b664a2SJames Hogan 			for (i = 0; i < items; ++i)
15854e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readl(host,
15864e0a5adfSJaehoon Chung 						DATA(host->data_offset));
158734b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
158834b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
158934b664a2SJames Hogan 			buf += len;
159034b664a2SJames Hogan 			cnt -= len;
159134b664a2SJames Hogan 		}
159234b664a2SJames Hogan 	} else
159334b664a2SJames Hogan #endif
159434b664a2SJames Hogan 	{
159534b664a2SJames Hogan 		u32 *pdata = buf;
159634b664a2SJames Hogan 		for (; cnt >= 4; cnt -= 4)
15974e0a5adfSJaehoon Chung 			*pdata++ = mci_readl(host, DATA(host->data_offset));
159834b664a2SJames Hogan 		buf = pdata;
159934b664a2SJames Hogan 	}
160034b664a2SJames Hogan 	if (cnt) {
16014e0a5adfSJaehoon Chung 		host->part_buf32 = mci_readl(host, DATA(host->data_offset));
160234b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
1603f95f3850SWill Newton 	}
1604f95f3850SWill Newton }
1605f95f3850SWill Newton 
1606f95f3850SWill Newton static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
1607f95f3850SWill Newton {
1608cfbeb59cSMarkos Chandras 	struct mmc_data *data = host->data;
1609cfbeb59cSMarkos Chandras 	int init_cnt = cnt;
1610cfbeb59cSMarkos Chandras 
161134b664a2SJames Hogan 	/* try and push anything in the part_buf */
161234b664a2SJames Hogan 	if (unlikely(host->part_buf_count)) {
161334b664a2SJames Hogan 		int len = dw_mci_push_part_bytes(host, buf, cnt);
161434b664a2SJames Hogan 		buf += len;
161534b664a2SJames Hogan 		cnt -= len;
1616c09fbd74SSeungwon Jeon 
1617cfbeb59cSMarkos Chandras 		if (host->part_buf_count == 8) {
1618c09fbd74SSeungwon Jeon 			mci_writeq(host, DATA(host->data_offset),
16194e0a5adfSJaehoon Chung 					host->part_buf);
162034b664a2SJames Hogan 			host->part_buf_count = 0;
162134b664a2SJames Hogan 		}
162234b664a2SJames Hogan 	}
162334b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
162434b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
162534b664a2SJames Hogan 		while (cnt >= 8) {
162634b664a2SJames Hogan 			u64 aligned_buf[16];
162734b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
162834b664a2SJames Hogan 			int items = len >> 3;
162934b664a2SJames Hogan 			int i;
163034b664a2SJames Hogan 			/* memcpy from input buffer into aligned buffer */
163134b664a2SJames Hogan 			memcpy(aligned_buf, buf, len);
163234b664a2SJames Hogan 			buf += len;
163334b664a2SJames Hogan 			cnt -= len;
163434b664a2SJames Hogan 			/* push data from aligned buffer into fifo */
163534b664a2SJames Hogan 			for (i = 0; i < items; ++i)
16364e0a5adfSJaehoon Chung 				mci_writeq(host, DATA(host->data_offset),
16374e0a5adfSJaehoon Chung 						aligned_buf[i]);
163834b664a2SJames Hogan 		}
163934b664a2SJames Hogan 	} else
164034b664a2SJames Hogan #endif
164134b664a2SJames Hogan 	{
164234b664a2SJames Hogan 		u64 *pdata = buf;
164334b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
16444e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset), *pdata++);
164534b664a2SJames Hogan 		buf = pdata;
164634b664a2SJames Hogan 	}
164734b664a2SJames Hogan 	/* put anything remaining in the part_buf */
164834b664a2SJames Hogan 	if (cnt) {
164934b664a2SJames Hogan 		dw_mci_set_part_bytes(host, buf, cnt);
1650cfbeb59cSMarkos Chandras 		/* Push data if we have reached the expected data length */
1651cfbeb59cSMarkos Chandras 		if ((data->bytes_xfered + init_cnt) ==
1652cfbeb59cSMarkos Chandras 		    (data->blksz * data->blocks))
16534e0a5adfSJaehoon Chung 			mci_writeq(host, DATA(host->data_offset),
16544e0a5adfSJaehoon Chung 				   host->part_buf);
1655f95f3850SWill Newton 	}
1656f95f3850SWill Newton }
1657f95f3850SWill Newton 
1658f95f3850SWill Newton static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
1659f95f3850SWill Newton {
166034b664a2SJames Hogan #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
166134b664a2SJames Hogan 	if (unlikely((unsigned long)buf & 0x7)) {
166234b664a2SJames Hogan 		while (cnt >= 8) {
166334b664a2SJames Hogan 			/* pull data from fifo into aligned buffer */
166434b664a2SJames Hogan 			u64 aligned_buf[16];
166534b664a2SJames Hogan 			int len = min(cnt & -8, (int)sizeof(aligned_buf));
166634b664a2SJames Hogan 			int items = len >> 3;
166734b664a2SJames Hogan 			int i;
166834b664a2SJames Hogan 			for (i = 0; i < items; ++i)
16694e0a5adfSJaehoon Chung 				aligned_buf[i] = mci_readq(host,
16704e0a5adfSJaehoon Chung 						DATA(host->data_offset));
167134b664a2SJames Hogan 			/* memcpy from aligned buffer into output buffer */
167234b664a2SJames Hogan 			memcpy(buf, aligned_buf, len);
167334b664a2SJames Hogan 			buf += len;
167434b664a2SJames Hogan 			cnt -= len;
1675f95f3850SWill Newton 		}
167634b664a2SJames Hogan 	} else
167734b664a2SJames Hogan #endif
167834b664a2SJames Hogan 	{
167934b664a2SJames Hogan 		u64 *pdata = buf;
168034b664a2SJames Hogan 		for (; cnt >= 8; cnt -= 8)
16814e0a5adfSJaehoon Chung 			*pdata++ = mci_readq(host, DATA(host->data_offset));
168234b664a2SJames Hogan 		buf = pdata;
168334b664a2SJames Hogan 	}
168434b664a2SJames Hogan 	if (cnt) {
16854e0a5adfSJaehoon Chung 		host->part_buf = mci_readq(host, DATA(host->data_offset));
168634b664a2SJames Hogan 		dw_mci_pull_final_bytes(host, buf, cnt);
168734b664a2SJames Hogan 	}
168834b664a2SJames Hogan }
168934b664a2SJames Hogan 
169034b664a2SJames Hogan static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
169134b664a2SJames Hogan {
169234b664a2SJames Hogan 	int len;
169334b664a2SJames Hogan 
169434b664a2SJames Hogan 	/* get remaining partial bytes */
169534b664a2SJames Hogan 	len = dw_mci_pull_part_bytes(host, buf, cnt);
169634b664a2SJames Hogan 	if (unlikely(len == cnt))
169734b664a2SJames Hogan 		return;
169834b664a2SJames Hogan 	buf += len;
169934b664a2SJames Hogan 	cnt -= len;
170034b664a2SJames Hogan 
170134b664a2SJames Hogan 	/* get the rest of the data */
170234b664a2SJames Hogan 	host->pull_data(host, buf, cnt);
1703f95f3850SWill Newton }
1704f95f3850SWill Newton 
170587a74d39SKyoungil Kim static void dw_mci_read_data_pio(struct dw_mci *host, bool dto)
1706f95f3850SWill Newton {
1707f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1708f9c2a0dcSSeungwon Jeon 	void *buf;
1709f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1710f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1711f95f3850SWill Newton 	int shift = host->data_shift;
1712f95f3850SWill Newton 	u32 status;
17133e4b0d8bSMarkos Chandras 	unsigned int len;
1714f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1715f95f3850SWill Newton 
1716f95f3850SWill Newton 	do {
1717f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1718f9c2a0dcSSeungwon Jeon 			goto done;
1719f95f3850SWill Newton 
17204225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1721f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1722f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1723f9c2a0dcSSeungwon Jeon 		offset = 0;
1724f9c2a0dcSSeungwon Jeon 
1725f9c2a0dcSSeungwon Jeon 		do {
1726f9c2a0dcSSeungwon Jeon 			fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS))
1727f9c2a0dcSSeungwon Jeon 					<< shift) + host->part_buf_count;
1728f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1729f9c2a0dcSSeungwon Jeon 			if (!len)
1730f9c2a0dcSSeungwon Jeon 				break;
1731f9c2a0dcSSeungwon Jeon 			dw_mci_pull_data(host, (void *)(buf + offset), len);
17323e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1733f95f3850SWill Newton 			offset += len;
1734f9c2a0dcSSeungwon Jeon 			remain -= len;
1735f9c2a0dcSSeungwon Jeon 		} while (remain);
1736f95f3850SWill Newton 
1737e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1738f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1739f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
174087a74d39SKyoungil Kim 	/* if the RXDR is ready read again */
174187a74d39SKyoungil Kim 	} while ((status & SDMMC_INT_RXDR) ||
174287a74d39SKyoungil Kim 		 (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS))));
1743f9c2a0dcSSeungwon Jeon 
1744f9c2a0dcSSeungwon Jeon 	if (!remain) {
1745f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1746f9c2a0dcSSeungwon Jeon 			goto done;
1747f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1748f9c2a0dcSSeungwon Jeon 	}
1749f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1750f95f3850SWill Newton 	return;
1751f95f3850SWill Newton 
1752f95f3850SWill Newton done:
1753f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1754f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1755f95f3850SWill Newton 	smp_wmb();
1756f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1757f95f3850SWill Newton }
1758f95f3850SWill Newton 
1759f95f3850SWill Newton static void dw_mci_write_data_pio(struct dw_mci *host)
1760f95f3850SWill Newton {
1761f9c2a0dcSSeungwon Jeon 	struct sg_mapping_iter *sg_miter = &host->sg_miter;
1762f9c2a0dcSSeungwon Jeon 	void *buf;
1763f9c2a0dcSSeungwon Jeon 	unsigned int offset;
1764f95f3850SWill Newton 	struct mmc_data	*data = host->data;
1765f95f3850SWill Newton 	int shift = host->data_shift;
1766f95f3850SWill Newton 	u32 status;
17673e4b0d8bSMarkos Chandras 	unsigned int len;
1768f9c2a0dcSSeungwon Jeon 	unsigned int fifo_depth = host->fifo_depth;
1769f9c2a0dcSSeungwon Jeon 	unsigned int remain, fcnt;
1770f95f3850SWill Newton 
1771f95f3850SWill Newton 	do {
1772f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1773f9c2a0dcSSeungwon Jeon 			goto done;
1774f95f3850SWill Newton 
17754225fc85SImre Deak 		host->sg = sg_miter->piter.sg;
1776f9c2a0dcSSeungwon Jeon 		buf = sg_miter->addr;
1777f9c2a0dcSSeungwon Jeon 		remain = sg_miter->length;
1778f9c2a0dcSSeungwon Jeon 		offset = 0;
1779f9c2a0dcSSeungwon Jeon 
1780f9c2a0dcSSeungwon Jeon 		do {
1781f9c2a0dcSSeungwon Jeon 			fcnt = ((fifo_depth -
1782f9c2a0dcSSeungwon Jeon 				 SDMMC_GET_FCNT(mci_readl(host, STATUS)))
1783f9c2a0dcSSeungwon Jeon 					<< shift) - host->part_buf_count;
1784f9c2a0dcSSeungwon Jeon 			len = min(remain, fcnt);
1785f9c2a0dcSSeungwon Jeon 			if (!len)
1786f9c2a0dcSSeungwon Jeon 				break;
1787f9c2a0dcSSeungwon Jeon 			host->push_data(host, (void *)(buf + offset), len);
17883e4b0d8bSMarkos Chandras 			data->bytes_xfered += len;
1789f95f3850SWill Newton 			offset += len;
1790f9c2a0dcSSeungwon Jeon 			remain -= len;
1791f9c2a0dcSSeungwon Jeon 		} while (remain);
1792f95f3850SWill Newton 
1793e74f3a9cSSeungwon Jeon 		sg_miter->consumed = offset;
1794f95f3850SWill Newton 		status = mci_readl(host, MINTSTS);
1795f95f3850SWill Newton 		mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1796f95f3850SWill Newton 	} while (status & SDMMC_INT_TXDR); /* if TXDR write again */
1797f9c2a0dcSSeungwon Jeon 
1798f9c2a0dcSSeungwon Jeon 	if (!remain) {
1799f9c2a0dcSSeungwon Jeon 		if (!sg_miter_next(sg_miter))
1800f9c2a0dcSSeungwon Jeon 			goto done;
1801f9c2a0dcSSeungwon Jeon 		sg_miter->consumed = 0;
1802f9c2a0dcSSeungwon Jeon 	}
1803f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1804f95f3850SWill Newton 	return;
1805f95f3850SWill Newton 
1806f95f3850SWill Newton done:
1807f9c2a0dcSSeungwon Jeon 	sg_miter_stop(sg_miter);
1808f9c2a0dcSSeungwon Jeon 	host->sg = NULL;
1809f95f3850SWill Newton 	smp_wmb();
1810f95f3850SWill Newton 	set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1811f95f3850SWill Newton }
1812f95f3850SWill Newton 
1813f95f3850SWill Newton static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
1814f95f3850SWill Newton {
1815f95f3850SWill Newton 	if (!host->cmd_status)
1816f95f3850SWill Newton 		host->cmd_status = status;
1817f95f3850SWill Newton 
1818f95f3850SWill Newton 	smp_wmb();
1819f95f3850SWill Newton 
1820f95f3850SWill Newton 	set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1821f95f3850SWill Newton 	tasklet_schedule(&host->tasklet);
1822f95f3850SWill Newton }
1823f95f3850SWill Newton 
1824f95f3850SWill Newton static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
1825f95f3850SWill Newton {
1826f95f3850SWill Newton 	struct dw_mci *host = dev_id;
1827182c9081SSeungwon Jeon 	u32 pending;
18281a5c8e1fSShashidhar Hiremath 	int i;
1829f95f3850SWill Newton 
1830f95f3850SWill Newton 	pending = mci_readl(host, MINTSTS); /* read-only mask reg */
1831f95f3850SWill Newton 
1832f95f3850SWill Newton 	/*
1833f95f3850SWill Newton 	 * DTO fix - version 2.10a and below, and only if internal DMA
1834f95f3850SWill Newton 	 * is configured.
1835f95f3850SWill Newton 	 */
1836f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
1837f95f3850SWill Newton 		if (!pending &&
1838f95f3850SWill Newton 		    ((mci_readl(host, STATUS) >> 17) & 0x1fff))
1839f95f3850SWill Newton 			pending |= SDMMC_INT_DATA_OVER;
1840f95f3850SWill Newton 	}
1841f95f3850SWill Newton 
1842476d79f1SDoug Anderson 	if (pending) {
1843f95f3850SWill Newton 		if (pending & DW_MCI_CMD_ERROR_FLAGS) {
1844f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
1845182c9081SSeungwon Jeon 			host->cmd_status = pending;
1846f95f3850SWill Newton 			smp_wmb();
1847f95f3850SWill Newton 			set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1848f95f3850SWill Newton 		}
1849f95f3850SWill Newton 
1850f95f3850SWill Newton 		if (pending & DW_MCI_DATA_ERROR_FLAGS) {
1851f95f3850SWill Newton 			/* if there is an error report DATA_ERROR */
1852f95f3850SWill Newton 			mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
1853182c9081SSeungwon Jeon 			host->data_status = pending;
1854f95f3850SWill Newton 			smp_wmb();
1855f95f3850SWill Newton 			set_bit(EVENT_DATA_ERROR, &host->pending_events);
1856f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
1857f95f3850SWill Newton 		}
1858f95f3850SWill Newton 
1859f95f3850SWill Newton 		if (pending & SDMMC_INT_DATA_OVER) {
1860f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
1861f95f3850SWill Newton 			if (!host->data_status)
1862182c9081SSeungwon Jeon 				host->data_status = pending;
1863f95f3850SWill Newton 			smp_wmb();
1864f95f3850SWill Newton 			if (host->dir_status == DW_MCI_RECV_STATUS) {
1865f95f3850SWill Newton 				if (host->sg != NULL)
186687a74d39SKyoungil Kim 					dw_mci_read_data_pio(host, true);
1867f95f3850SWill Newton 			}
1868f95f3850SWill Newton 			set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
1869f95f3850SWill Newton 			tasklet_schedule(&host->tasklet);
1870f95f3850SWill Newton 		}
1871f95f3850SWill Newton 
1872f95f3850SWill Newton 		if (pending & SDMMC_INT_RXDR) {
1873f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
1874b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_RECV_STATUS && host->sg)
187587a74d39SKyoungil Kim 				dw_mci_read_data_pio(host, false);
1876f95f3850SWill Newton 		}
1877f95f3850SWill Newton 
1878f95f3850SWill Newton 		if (pending & SDMMC_INT_TXDR) {
1879f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1880b40af3aaSJames Hogan 			if (host->dir_status == DW_MCI_SEND_STATUS && host->sg)
1881f95f3850SWill Newton 				dw_mci_write_data_pio(host);
1882f95f3850SWill Newton 		}
1883f95f3850SWill Newton 
1884f95f3850SWill Newton 		if (pending & SDMMC_INT_CMD_DONE) {
1885f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
1886182c9081SSeungwon Jeon 			dw_mci_cmd_interrupt(host, pending);
1887f95f3850SWill Newton 		}
1888f95f3850SWill Newton 
1889f95f3850SWill Newton 		if (pending & SDMMC_INT_CD) {
1890f95f3850SWill Newton 			mci_writel(host, RINTSTS, SDMMC_INT_CD);
189195dcc2cbSThomas Abraham 			queue_work(host->card_workqueue, &host->card_work);
1892f95f3850SWill Newton 		}
1893f95f3850SWill Newton 
18941a5c8e1fSShashidhar Hiremath 		/* Handle SDIO Interrupts */
18951a5c8e1fSShashidhar Hiremath 		for (i = 0; i < host->num_slots; i++) {
18961a5c8e1fSShashidhar Hiremath 			struct dw_mci_slot *slot = host->slot[i];
18971a5c8e1fSShashidhar Hiremath 			if (pending & SDMMC_INT_SDIO(i)) {
18981a5c8e1fSShashidhar Hiremath 				mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
18991a5c8e1fSShashidhar Hiremath 				mmc_signal_sdio_irq(slot->mmc);
19001a5c8e1fSShashidhar Hiremath 			}
19011a5c8e1fSShashidhar Hiremath 		}
19021a5c8e1fSShashidhar Hiremath 
19031fb5f68aSMarkos Chandras 	}
1904f95f3850SWill Newton 
1905f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
1906f95f3850SWill Newton 	/* Handle DMA interrupts */
1907f95f3850SWill Newton 	pending = mci_readl(host, IDSTS);
1908f95f3850SWill Newton 	if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
1909f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
1910f95f3850SWill Newton 		mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
1911f95f3850SWill Newton 		host->dma_ops->complete(host);
1912f95f3850SWill Newton 	}
1913f95f3850SWill Newton #endif
1914f95f3850SWill Newton 
1915f95f3850SWill Newton 	return IRQ_HANDLED;
1916f95f3850SWill Newton }
1917f95f3850SWill Newton 
19181791b13eSJames Hogan static void dw_mci_work_routine_card(struct work_struct *work)
1919f95f3850SWill Newton {
19201791b13eSJames Hogan 	struct dw_mci *host = container_of(work, struct dw_mci, card_work);
1921f95f3850SWill Newton 	int i;
1922f95f3850SWill Newton 
1923f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
1924f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
1925f95f3850SWill Newton 		struct mmc_host *mmc = slot->mmc;
1926f95f3850SWill Newton 		struct mmc_request *mrq;
1927f95f3850SWill Newton 		int present;
1928f95f3850SWill Newton 
1929f95f3850SWill Newton 		present = dw_mci_get_cd(mmc);
1930f95f3850SWill Newton 		while (present != slot->last_detect_state) {
1931f95f3850SWill Newton 			dev_dbg(&slot->mmc->class_dev, "card %s\n",
1932f95f3850SWill Newton 				present ? "inserted" : "removed");
1933f95f3850SWill Newton 
19341791b13eSJames Hogan 			spin_lock_bh(&host->lock);
19351791b13eSJames Hogan 
1936f95f3850SWill Newton 			/* Card change detected */
1937f95f3850SWill Newton 			slot->last_detect_state = present;
1938f95f3850SWill Newton 
1939f95f3850SWill Newton 			/* Clean up queue if present */
1940f95f3850SWill Newton 			mrq = slot->mrq;
1941f95f3850SWill Newton 			if (mrq) {
1942f95f3850SWill Newton 				if (mrq == host->mrq) {
1943f95f3850SWill Newton 					host->data = NULL;
1944f95f3850SWill Newton 					host->cmd = NULL;
1945f95f3850SWill Newton 
1946f95f3850SWill Newton 					switch (host->state) {
1947f95f3850SWill Newton 					case STATE_IDLE:
1948f95f3850SWill Newton 						break;
1949f95f3850SWill Newton 					case STATE_SENDING_CMD:
1950f95f3850SWill Newton 						mrq->cmd->error = -ENOMEDIUM;
1951f95f3850SWill Newton 						if (!mrq->data)
1952f95f3850SWill Newton 							break;
1953f95f3850SWill Newton 						/* fall through */
1954f95f3850SWill Newton 					case STATE_SENDING_DATA:
1955f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
1956f95f3850SWill Newton 						dw_mci_stop_dma(host);
1957f95f3850SWill Newton 						break;
1958f95f3850SWill Newton 					case STATE_DATA_BUSY:
1959f95f3850SWill Newton 					case STATE_DATA_ERROR:
1960f95f3850SWill Newton 						if (mrq->data->error == -EINPROGRESS)
1961f95f3850SWill Newton 							mrq->data->error = -ENOMEDIUM;
1962f95f3850SWill Newton 						/* fall through */
1963f95f3850SWill Newton 					case STATE_SENDING_STOP:
196490c2143aSSeungwon Jeon 						if (mrq->stop)
1965f95f3850SWill Newton 							mrq->stop->error = -ENOMEDIUM;
1966f95f3850SWill Newton 						break;
1967f95f3850SWill Newton 					}
1968f95f3850SWill Newton 
1969f95f3850SWill Newton 					dw_mci_request_end(host, mrq);
1970f95f3850SWill Newton 				} else {
1971f95f3850SWill Newton 					list_del(&slot->queue_node);
1972f95f3850SWill Newton 					mrq->cmd->error = -ENOMEDIUM;
1973f95f3850SWill Newton 					if (mrq->data)
1974f95f3850SWill Newton 						mrq->data->error = -ENOMEDIUM;
1975f95f3850SWill Newton 					if (mrq->stop)
1976f95f3850SWill Newton 						mrq->stop->error = -ENOMEDIUM;
1977f95f3850SWill Newton 
1978f95f3850SWill Newton 					spin_unlock(&host->lock);
1979f95f3850SWill Newton 					mmc_request_done(slot->mmc, mrq);
1980f95f3850SWill Newton 					spin_lock(&host->lock);
1981f95f3850SWill Newton 				}
1982f95f3850SWill Newton 			}
1983f95f3850SWill Newton 
1984f95f3850SWill Newton 			/* Power down slot */
1985f95f3850SWill Newton 			if (present == 0) {
198631bff450SSeungwon Jeon 				/* Clear down the FIFO */
198731bff450SSeungwon Jeon 				dw_mci_fifo_reset(host);
1988f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
19895ce9d961SSeungwon Jeon 				dw_mci_idmac_reset(host);
1990f95f3850SWill Newton #endif
1991f95f3850SWill Newton 
1992f95f3850SWill Newton 			}
1993f95f3850SWill Newton 
19941791b13eSJames Hogan 			spin_unlock_bh(&host->lock);
19951791b13eSJames Hogan 
1996f95f3850SWill Newton 			present = dw_mci_get_cd(mmc);
1997f95f3850SWill Newton 		}
1998f95f3850SWill Newton 
1999f95f3850SWill Newton 		mmc_detect_change(slot->mmc,
2000f95f3850SWill Newton 			msecs_to_jiffies(host->pdata->detect_delay_ms));
2001f95f3850SWill Newton 	}
2002f95f3850SWill Newton }
2003f95f3850SWill Newton 
2004c91eab4bSThomas Abraham #ifdef CONFIG_OF
2005c91eab4bSThomas Abraham /* given a slot id, find out the device node representing that slot */
2006c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
2007c91eab4bSThomas Abraham {
2008c91eab4bSThomas Abraham 	struct device_node *np;
2009c91eab4bSThomas Abraham 	const __be32 *addr;
2010c91eab4bSThomas Abraham 	int len;
2011c91eab4bSThomas Abraham 
2012c91eab4bSThomas Abraham 	if (!dev || !dev->of_node)
2013c91eab4bSThomas Abraham 		return NULL;
2014c91eab4bSThomas Abraham 
2015c91eab4bSThomas Abraham 	for_each_child_of_node(dev->of_node, np) {
2016c91eab4bSThomas Abraham 		addr = of_get_property(np, "reg", &len);
2017c91eab4bSThomas Abraham 		if (!addr || (len < sizeof(int)))
2018c91eab4bSThomas Abraham 			continue;
2019c91eab4bSThomas Abraham 		if (be32_to_cpup(addr) == slot)
2020c91eab4bSThomas Abraham 			return np;
2021c91eab4bSThomas Abraham 	}
2022c91eab4bSThomas Abraham 	return NULL;
2023c91eab4bSThomas Abraham }
2024c91eab4bSThomas Abraham 
2025a70aaa64SDoug Anderson static struct dw_mci_of_slot_quirks {
2026a70aaa64SDoug Anderson 	char *quirk;
2027a70aaa64SDoug Anderson 	int id;
2028a70aaa64SDoug Anderson } of_slot_quirks[] = {
2029a70aaa64SDoug Anderson 	{
2030a70aaa64SDoug Anderson 		.quirk	= "disable-wp",
2031a70aaa64SDoug Anderson 		.id	= DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT,
2032a70aaa64SDoug Anderson 	},
2033a70aaa64SDoug Anderson };
2034a70aaa64SDoug Anderson 
2035a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
2036a70aaa64SDoug Anderson {
2037a70aaa64SDoug Anderson 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
2038a70aaa64SDoug Anderson 	int quirks = 0;
2039a70aaa64SDoug Anderson 	int idx;
2040a70aaa64SDoug Anderson 
2041a70aaa64SDoug Anderson 	/* get quirks */
2042a70aaa64SDoug Anderson 	for (idx = 0; idx < ARRAY_SIZE(of_slot_quirks); idx++)
2043a70aaa64SDoug Anderson 		if (of_get_property(np, of_slot_quirks[idx].quirk, NULL))
2044a70aaa64SDoug Anderson 			quirks |= of_slot_quirks[idx].id;
2045a70aaa64SDoug Anderson 
2046a70aaa64SDoug Anderson 	return quirks;
2047a70aaa64SDoug Anderson }
2048a70aaa64SDoug Anderson 
2049c91eab4bSThomas Abraham /* find out bus-width for a given slot */
2050c91eab4bSThomas Abraham static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
2051c91eab4bSThomas Abraham {
2052c91eab4bSThomas Abraham 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
2053c91eab4bSThomas Abraham 	u32 bus_wd = 1;
2054c91eab4bSThomas Abraham 
2055c91eab4bSThomas Abraham 	if (!np)
2056c91eab4bSThomas Abraham 		return 1;
2057c91eab4bSThomas Abraham 
2058c91eab4bSThomas Abraham 	if (of_property_read_u32(np, "bus-width", &bus_wd))
2059c91eab4bSThomas Abraham 		dev_err(dev, "bus-width property not found, assuming width"
2060c91eab4bSThomas Abraham 			       " as 1\n");
2061c91eab4bSThomas Abraham 	return bus_wd;
2062c91eab4bSThomas Abraham }
206355a6ceb2SDoug Anderson 
206455a6ceb2SDoug Anderson /* find the write protect gpio for a given slot; or -1 if none specified */
206555a6ceb2SDoug Anderson static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
206655a6ceb2SDoug Anderson {
206755a6ceb2SDoug Anderson 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
206855a6ceb2SDoug Anderson 	int gpio;
206955a6ceb2SDoug Anderson 
207055a6ceb2SDoug Anderson 	if (!np)
207155a6ceb2SDoug Anderson 		return -EINVAL;
207255a6ceb2SDoug Anderson 
207355a6ceb2SDoug Anderson 	gpio = of_get_named_gpio(np, "wp-gpios", 0);
207455a6ceb2SDoug Anderson 
207555a6ceb2SDoug Anderson 	/* Having a missing entry is valid; return silently */
207655a6ceb2SDoug Anderson 	if (!gpio_is_valid(gpio))
207755a6ceb2SDoug Anderson 		return -EINVAL;
207855a6ceb2SDoug Anderson 
207955a6ceb2SDoug Anderson 	if (devm_gpio_request(dev, gpio, "dw-mci-wp")) {
208055a6ceb2SDoug Anderson 		dev_warn(dev, "gpio [%d] request failed\n", gpio);
208155a6ceb2SDoug Anderson 		return -EINVAL;
208255a6ceb2SDoug Anderson 	}
208355a6ceb2SDoug Anderson 
208455a6ceb2SDoug Anderson 	return gpio;
208555a6ceb2SDoug Anderson }
2086bf626e55SZhangfei Gao 
2087*7cf347bdSZhangfei Gao /* find the cd gpio for a given slot */
2088bf626e55SZhangfei Gao static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
2089bf626e55SZhangfei Gao 					struct mmc_host *mmc)
2090bf626e55SZhangfei Gao {
2091bf626e55SZhangfei Gao 	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
2092bf626e55SZhangfei Gao 	int gpio;
2093bf626e55SZhangfei Gao 
2094bf626e55SZhangfei Gao 	if (!np)
2095bf626e55SZhangfei Gao 		return;
2096bf626e55SZhangfei Gao 
2097bf626e55SZhangfei Gao 	gpio = of_get_named_gpio(np, "cd-gpios", 0);
2098bf626e55SZhangfei Gao 
2099bf626e55SZhangfei Gao 	/* Having a missing entry is valid; return silently */
2100bf626e55SZhangfei Gao 	if (!gpio_is_valid(gpio))
2101bf626e55SZhangfei Gao 		return;
2102bf626e55SZhangfei Gao 
2103bf626e55SZhangfei Gao 	if (mmc_gpio_request_cd(mmc, gpio, 0))
2104bf626e55SZhangfei Gao 		dev_warn(dev, "gpio [%d] request failed\n", gpio);
2105bf626e55SZhangfei Gao }
2106c91eab4bSThomas Abraham #else /* CONFIG_OF */
2107a70aaa64SDoug Anderson static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
2108a70aaa64SDoug Anderson {
2109a70aaa64SDoug Anderson 	return 0;
2110a70aaa64SDoug Anderson }
2111c91eab4bSThomas Abraham static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
2112c91eab4bSThomas Abraham {
2113c91eab4bSThomas Abraham 	return 1;
2114c91eab4bSThomas Abraham }
2115c91eab4bSThomas Abraham static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
2116c91eab4bSThomas Abraham {
2117c91eab4bSThomas Abraham 	return NULL;
2118c91eab4bSThomas Abraham }
211955a6ceb2SDoug Anderson static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
212055a6ceb2SDoug Anderson {
212155a6ceb2SDoug Anderson 	return -EINVAL;
212255a6ceb2SDoug Anderson }
2123bf626e55SZhangfei Gao static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
2124bf626e55SZhangfei Gao 					struct mmc_host *mmc)
2125bf626e55SZhangfei Gao {
2126bf626e55SZhangfei Gao 	return;
2127bf626e55SZhangfei Gao }
2128c91eab4bSThomas Abraham #endif /* CONFIG_OF */
2129c91eab4bSThomas Abraham 
213036c179a9SJaehoon Chung static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
2131f95f3850SWill Newton {
2132f95f3850SWill Newton 	struct mmc_host *mmc;
2133f95f3850SWill Newton 	struct dw_mci_slot *slot;
2134e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
2135800d78bfSThomas Abraham 	int ctrl_id, ret;
21361f44a2a5SSeungwon Jeon 	u32 freq[2];
2137c91eab4bSThomas Abraham 	u8 bus_width;
2138f95f3850SWill Newton 
21394a90920cSThomas Abraham 	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
2140f95f3850SWill Newton 	if (!mmc)
2141f95f3850SWill Newton 		return -ENOMEM;
2142f95f3850SWill Newton 
2143f95f3850SWill Newton 	slot = mmc_priv(mmc);
2144f95f3850SWill Newton 	slot->id = id;
2145f95f3850SWill Newton 	slot->mmc = mmc;
2146f95f3850SWill Newton 	slot->host = host;
2147c91eab4bSThomas Abraham 	host->slot[id] = slot;
2148f95f3850SWill Newton 
2149a70aaa64SDoug Anderson 	slot->quirks = dw_mci_of_get_slot_quirks(host->dev, slot->id);
2150a70aaa64SDoug Anderson 
2151f95f3850SWill Newton 	mmc->ops = &dw_mci_ops;
21521f44a2a5SSeungwon Jeon 	if (of_property_read_u32_array(host->dev->of_node,
21531f44a2a5SSeungwon Jeon 				       "clock-freq-min-max", freq, 2)) {
21541f44a2a5SSeungwon Jeon 		mmc->f_min = DW_MCI_FREQ_MIN;
21551f44a2a5SSeungwon Jeon 		mmc->f_max = DW_MCI_FREQ_MAX;
21561f44a2a5SSeungwon Jeon 	} else {
21571f44a2a5SSeungwon Jeon 		mmc->f_min = freq[0];
21581f44a2a5SSeungwon Jeon 		mmc->f_max = freq[1];
21591f44a2a5SSeungwon Jeon 	}
2160f95f3850SWill Newton 
2161f95f3850SWill Newton 	if (host->pdata->get_ocr)
2162f95f3850SWill Newton 		mmc->ocr_avail = host->pdata->get_ocr(id);
2163f95f3850SWill Newton 	else
2164f95f3850SWill Newton 		mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
2165f95f3850SWill Newton 
2166f95f3850SWill Newton 	/*
2167f95f3850SWill Newton 	 * Start with slot power disabled, it will be enabled when a card
2168f95f3850SWill Newton 	 * is detected.
2169f95f3850SWill Newton 	 */
2170f95f3850SWill Newton 	if (host->pdata->setpower)
2171f95f3850SWill Newton 		host->pdata->setpower(id, 0);
2172f95f3850SWill Newton 
2173fc3d7720SJaehoon Chung 	if (host->pdata->caps)
2174fc3d7720SJaehoon Chung 		mmc->caps = host->pdata->caps;
2175fc3d7720SJaehoon Chung 
2176ab269128SAbhilash Kesavan 	if (host->pdata->pm_caps)
2177ab269128SAbhilash Kesavan 		mmc->pm_caps = host->pdata->pm_caps;
2178ab269128SAbhilash Kesavan 
2179800d78bfSThomas Abraham 	if (host->dev->of_node) {
2180800d78bfSThomas Abraham 		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
2181800d78bfSThomas Abraham 		if (ctrl_id < 0)
2182800d78bfSThomas Abraham 			ctrl_id = 0;
2183800d78bfSThomas Abraham 	} else {
2184800d78bfSThomas Abraham 		ctrl_id = to_platform_device(host->dev)->id;
2185800d78bfSThomas Abraham 	}
2186cb27a843SJames Hogan 	if (drv_data && drv_data->caps)
2187cb27a843SJames Hogan 		mmc->caps |= drv_data->caps[ctrl_id];
2188800d78bfSThomas Abraham 
21894f408cc6SSeungwon Jeon 	if (host->pdata->caps2)
21904f408cc6SSeungwon Jeon 		mmc->caps2 = host->pdata->caps2;
21914f408cc6SSeungwon Jeon 
2192f95f3850SWill Newton 	if (host->pdata->get_bus_wd)
2193c91eab4bSThomas Abraham 		bus_width = host->pdata->get_bus_wd(slot->id);
2194c91eab4bSThomas Abraham 	else if (host->dev->of_node)
2195c91eab4bSThomas Abraham 		bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
2196c91eab4bSThomas Abraham 	else
2197c91eab4bSThomas Abraham 		bus_width = 1;
2198c91eab4bSThomas Abraham 
2199c91eab4bSThomas Abraham 	switch (bus_width) {
2200c91eab4bSThomas Abraham 	case 8:
2201c91eab4bSThomas Abraham 		mmc->caps |= MMC_CAP_8_BIT_DATA;
2202c91eab4bSThomas Abraham 	case 4:
2203f95f3850SWill Newton 		mmc->caps |= MMC_CAP_4_BIT_DATA;
2204c91eab4bSThomas Abraham 	}
2205f95f3850SWill Newton 
2206f95f3850SWill Newton 	if (host->pdata->blk_settings) {
2207f95f3850SWill Newton 		mmc->max_segs = host->pdata->blk_settings->max_segs;
2208f95f3850SWill Newton 		mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
2209f95f3850SWill Newton 		mmc->max_blk_count = host->pdata->blk_settings->max_blk_count;
2210f95f3850SWill Newton 		mmc->max_req_size = host->pdata->blk_settings->max_req_size;
2211f95f3850SWill Newton 		mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
2212f95f3850SWill Newton 	} else {
2213f95f3850SWill Newton 		/* Useful defaults if platform data is unset. */
2214a39e5746SJaehoon Chung #ifdef CONFIG_MMC_DW_IDMAC
2215a39e5746SJaehoon Chung 		mmc->max_segs = host->ring_size;
2216a39e5746SJaehoon Chung 		mmc->max_blk_size = 65536;
2217a39e5746SJaehoon Chung 		mmc->max_blk_count = host->ring_size;
2218a39e5746SJaehoon Chung 		mmc->max_seg_size = 0x1000;
2219a39e5746SJaehoon Chung 		mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
2220a39e5746SJaehoon Chung #else
2221f95f3850SWill Newton 		mmc->max_segs = 64;
2222f95f3850SWill Newton 		mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
2223f95f3850SWill Newton 		mmc->max_blk_count = 512;
2224f95f3850SWill Newton 		mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
2225f95f3850SWill Newton 		mmc->max_seg_size = mmc->max_req_size;
2226f95f3850SWill Newton #endif /* CONFIG_MMC_DW_IDMAC */
2227a39e5746SJaehoon Chung 	}
2228f95f3850SWill Newton 
222955a6ceb2SDoug Anderson 	slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id);
2230bf626e55SZhangfei Gao 	dw_mci_of_get_cd_gpio(host->dev, slot->id, mmc);
223155a6ceb2SDoug Anderson 
22320cea529dSJaehoon Chung 	ret = mmc_add_host(mmc);
22330cea529dSJaehoon Chung 	if (ret)
22340cea529dSJaehoon Chung 		goto err_setup_bus;
2235f95f3850SWill Newton 
2236f95f3850SWill Newton #if defined(CONFIG_DEBUG_FS)
2237f95f3850SWill Newton 	dw_mci_init_debugfs(slot);
2238f95f3850SWill Newton #endif
2239f95f3850SWill Newton 
2240f95f3850SWill Newton 	/* Card initially undetected */
2241f95f3850SWill Newton 	slot->last_detect_state = 0;
2242f95f3850SWill Newton 
2243f95f3850SWill Newton 	return 0;
2244800d78bfSThomas Abraham 
2245800d78bfSThomas Abraham err_setup_bus:
2246800d78bfSThomas Abraham 	mmc_free_host(mmc);
2247800d78bfSThomas Abraham 	return -EINVAL;
2248f95f3850SWill Newton }
2249f95f3850SWill Newton 
2250f95f3850SWill Newton static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
2251f95f3850SWill Newton {
2252f95f3850SWill Newton 	/* Shutdown detect IRQ */
2253f95f3850SWill Newton 	if (slot->host->pdata->exit)
2254f95f3850SWill Newton 		slot->host->pdata->exit(id);
2255f95f3850SWill Newton 
2256f95f3850SWill Newton 	/* Debugfs stuff is cleaned up by mmc core */
2257f95f3850SWill Newton 	mmc_remove_host(slot->mmc);
2258f95f3850SWill Newton 	slot->host->slot[id] = NULL;
2259f95f3850SWill Newton 	mmc_free_host(slot->mmc);
2260f95f3850SWill Newton }
2261f95f3850SWill Newton 
2262f95f3850SWill Newton static void dw_mci_init_dma(struct dw_mci *host)
2263f95f3850SWill Newton {
2264f95f3850SWill Newton 	/* Alloc memory for sg translation */
2265780f22afSSeungwon Jeon 	host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
2266f95f3850SWill Newton 					  &host->sg_dma, GFP_KERNEL);
2267f95f3850SWill Newton 	if (!host->sg_cpu) {
22684a90920cSThomas Abraham 		dev_err(host->dev, "%s: could not alloc DMA memory\n",
2269f95f3850SWill Newton 			__func__);
2270f95f3850SWill Newton 		goto no_dma;
2271f95f3850SWill Newton 	}
2272f95f3850SWill Newton 
2273f95f3850SWill Newton 	/* Determine which DMA interface to use */
2274f95f3850SWill Newton #ifdef CONFIG_MMC_DW_IDMAC
2275f95f3850SWill Newton 	host->dma_ops = &dw_mci_idmac_ops;
227600956ea3SSeungwon Jeon 	dev_info(host->dev, "Using internal DMA controller.\n");
2277f95f3850SWill Newton #endif
2278f95f3850SWill Newton 
2279f95f3850SWill Newton 	if (!host->dma_ops)
2280f95f3850SWill Newton 		goto no_dma;
2281f95f3850SWill Newton 
2282e1631f98SJaehoon Chung 	if (host->dma_ops->init && host->dma_ops->start &&
2283e1631f98SJaehoon Chung 	    host->dma_ops->stop && host->dma_ops->cleanup) {
2284f95f3850SWill Newton 		if (host->dma_ops->init(host)) {
22854a90920cSThomas Abraham 			dev_err(host->dev, "%s: Unable to initialize "
2286f95f3850SWill Newton 				"DMA Controller.\n", __func__);
2287f95f3850SWill Newton 			goto no_dma;
2288f95f3850SWill Newton 		}
2289f95f3850SWill Newton 	} else {
22904a90920cSThomas Abraham 		dev_err(host->dev, "DMA initialization not found.\n");
2291f95f3850SWill Newton 		goto no_dma;
2292f95f3850SWill Newton 	}
2293f95f3850SWill Newton 
2294f95f3850SWill Newton 	host->use_dma = 1;
2295f95f3850SWill Newton 	return;
2296f95f3850SWill Newton 
2297f95f3850SWill Newton no_dma:
22984a90920cSThomas Abraham 	dev_info(host->dev, "Using PIO mode.\n");
2299f95f3850SWill Newton 	host->use_dma = 0;
2300f95f3850SWill Newton 	return;
2301f95f3850SWill Newton }
2302f95f3850SWill Newton 
230331bff450SSeungwon Jeon static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset)
2304f95f3850SWill Newton {
2305f95f3850SWill Newton 	unsigned long timeout = jiffies + msecs_to_jiffies(500);
230631bff450SSeungwon Jeon 	u32 ctrl;
2307f95f3850SWill Newton 
230831bff450SSeungwon Jeon 	ctrl = mci_readl(host, CTRL);
230931bff450SSeungwon Jeon 	ctrl |= reset;
231031bff450SSeungwon Jeon 	mci_writel(host, CTRL, ctrl);
2311f95f3850SWill Newton 
2312f95f3850SWill Newton 	/* wait till resets clear */
2313f95f3850SWill Newton 	do {
2314f95f3850SWill Newton 		ctrl = mci_readl(host, CTRL);
231531bff450SSeungwon Jeon 		if (!(ctrl & reset))
2316f95f3850SWill Newton 			return true;
2317f95f3850SWill Newton 	} while (time_before(jiffies, timeout));
2318f95f3850SWill Newton 
231931bff450SSeungwon Jeon 	dev_err(host->dev,
232031bff450SSeungwon Jeon 		"Timeout resetting block (ctrl reset %#x)\n",
232131bff450SSeungwon Jeon 		ctrl & reset);
2322f95f3850SWill Newton 
2323f95f3850SWill Newton 	return false;
2324f95f3850SWill Newton }
2325f95f3850SWill Newton 
232631bff450SSeungwon Jeon static inline bool dw_mci_fifo_reset(struct dw_mci *host)
232731bff450SSeungwon Jeon {
232831bff450SSeungwon Jeon 	/*
232931bff450SSeungwon Jeon 	 * Reseting generates a block interrupt, hence setting
233031bff450SSeungwon Jeon 	 * the scatter-gather pointer to NULL.
233131bff450SSeungwon Jeon 	 */
233231bff450SSeungwon Jeon 	if (host->sg) {
233331bff450SSeungwon Jeon 		sg_miter_stop(&host->sg_miter);
233431bff450SSeungwon Jeon 		host->sg = NULL;
233531bff450SSeungwon Jeon 	}
233631bff450SSeungwon Jeon 
233731bff450SSeungwon Jeon 	return dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET);
233831bff450SSeungwon Jeon }
233931bff450SSeungwon Jeon 
234031bff450SSeungwon Jeon static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host)
234131bff450SSeungwon Jeon {
234231bff450SSeungwon Jeon 	return dw_mci_ctrl_reset(host,
234331bff450SSeungwon Jeon 				 SDMMC_CTRL_FIFO_RESET |
234431bff450SSeungwon Jeon 				 SDMMC_CTRL_RESET |
234531bff450SSeungwon Jeon 				 SDMMC_CTRL_DMA_RESET);
234631bff450SSeungwon Jeon }
234731bff450SSeungwon Jeon 
2348c91eab4bSThomas Abraham #ifdef CONFIG_OF
2349c91eab4bSThomas Abraham static struct dw_mci_of_quirks {
2350c91eab4bSThomas Abraham 	char *quirk;
2351c91eab4bSThomas Abraham 	int id;
2352c91eab4bSThomas Abraham } of_quirks[] = {
2353c91eab4bSThomas Abraham 	{
2354c91eab4bSThomas Abraham 		.quirk	= "broken-cd",
2355c91eab4bSThomas Abraham 		.id	= DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
2356c91eab4bSThomas Abraham 	},
2357c91eab4bSThomas Abraham };
2358c91eab4bSThomas Abraham 
2359c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2360c91eab4bSThomas Abraham {
2361c91eab4bSThomas Abraham 	struct dw_mci_board *pdata;
2362c91eab4bSThomas Abraham 	struct device *dev = host->dev;
2363c91eab4bSThomas Abraham 	struct device_node *np = dev->of_node;
2364e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
2365800d78bfSThomas Abraham 	int idx, ret;
23663c6d89eaSDoug Anderson 	u32 clock_frequency;
2367c91eab4bSThomas Abraham 
2368c91eab4bSThomas Abraham 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
2369c91eab4bSThomas Abraham 	if (!pdata) {
2370c91eab4bSThomas Abraham 		dev_err(dev, "could not allocate memory for pdata\n");
2371c91eab4bSThomas Abraham 		return ERR_PTR(-ENOMEM);
2372c91eab4bSThomas Abraham 	}
2373c91eab4bSThomas Abraham 
2374c91eab4bSThomas Abraham 	/* find out number of slots supported */
2375c91eab4bSThomas Abraham 	if (of_property_read_u32(dev->of_node, "num-slots",
2376c91eab4bSThomas Abraham 				&pdata->num_slots)) {
2377c91eab4bSThomas Abraham 		dev_info(dev, "num-slots property not found, "
2378c91eab4bSThomas Abraham 				"assuming 1 slot is available\n");
2379c91eab4bSThomas Abraham 		pdata->num_slots = 1;
2380c91eab4bSThomas Abraham 	}
2381c91eab4bSThomas Abraham 
2382c91eab4bSThomas Abraham 	/* get quirks */
2383c91eab4bSThomas Abraham 	for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++)
2384c91eab4bSThomas Abraham 		if (of_get_property(np, of_quirks[idx].quirk, NULL))
2385c91eab4bSThomas Abraham 			pdata->quirks |= of_quirks[idx].id;
2386c91eab4bSThomas Abraham 
2387c91eab4bSThomas Abraham 	if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
2388c91eab4bSThomas Abraham 		dev_info(dev, "fifo-depth property not found, using "
2389c91eab4bSThomas Abraham 				"value of FIFOTH register as default\n");
2390c91eab4bSThomas Abraham 
2391c91eab4bSThomas Abraham 	of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
2392c91eab4bSThomas Abraham 
23933c6d89eaSDoug Anderson 	if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
23943c6d89eaSDoug Anderson 		pdata->bus_hz = clock_frequency;
23953c6d89eaSDoug Anderson 
2396cb27a843SJames Hogan 	if (drv_data && drv_data->parse_dt) {
2397cb27a843SJames Hogan 		ret = drv_data->parse_dt(host);
2398800d78bfSThomas Abraham 		if (ret)
2399800d78bfSThomas Abraham 			return ERR_PTR(ret);
2400800d78bfSThomas Abraham 	}
2401800d78bfSThomas Abraham 
2402ab269128SAbhilash Kesavan 	if (of_find_property(np, "keep-power-in-suspend", NULL))
2403ab269128SAbhilash Kesavan 		pdata->pm_caps |= MMC_PM_KEEP_POWER;
2404ab269128SAbhilash Kesavan 
2405ab269128SAbhilash Kesavan 	if (of_find_property(np, "enable-sdio-wakeup", NULL))
2406ab269128SAbhilash Kesavan 		pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
2407ab269128SAbhilash Kesavan 
240810b49841SSeungwon Jeon 	if (of_find_property(np, "supports-highspeed", NULL))
240910b49841SSeungwon Jeon 		pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
241010b49841SSeungwon Jeon 
24115dd63f52SSeungwon Jeon 	if (of_find_property(np, "caps2-mmc-hs200-1_8v", NULL))
24125dd63f52SSeungwon Jeon 		pdata->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
24135dd63f52SSeungwon Jeon 
24145dd63f52SSeungwon Jeon 	if (of_find_property(np, "caps2-mmc-hs200-1_2v", NULL))
24155dd63f52SSeungwon Jeon 		pdata->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
24165dd63f52SSeungwon Jeon 
2417*7cf347bdSZhangfei Gao 	if (of_get_property(np, "cd-inverted", NULL))
2418*7cf347bdSZhangfei Gao 		pdata->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
2419*7cf347bdSZhangfei Gao 
2420c91eab4bSThomas Abraham 	return pdata;
2421c91eab4bSThomas Abraham }
2422c91eab4bSThomas Abraham 
2423c91eab4bSThomas Abraham #else /* CONFIG_OF */
2424c91eab4bSThomas Abraham static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
2425c91eab4bSThomas Abraham {
2426c91eab4bSThomas Abraham 	return ERR_PTR(-EINVAL);
2427c91eab4bSThomas Abraham }
2428c91eab4bSThomas Abraham #endif /* CONFIG_OF */
2429c91eab4bSThomas Abraham 
243062ca8034SShashidhar Hiremath int dw_mci_probe(struct dw_mci *host)
2431f95f3850SWill Newton {
2432e95baf13SArnd Bergmann 	const struct dw_mci_drv_data *drv_data = host->drv_data;
243362ca8034SShashidhar Hiremath 	int width, i, ret = 0;
2434f95f3850SWill Newton 	u32 fifo_size;
24351c2215b7SThomas Abraham 	int init_slots = 0;
2436f95f3850SWill Newton 
2437c91eab4bSThomas Abraham 	if (!host->pdata) {
2438c91eab4bSThomas Abraham 		host->pdata = dw_mci_parse_dt(host);
2439c91eab4bSThomas Abraham 		if (IS_ERR(host->pdata)) {
2440c91eab4bSThomas Abraham 			dev_err(host->dev, "platform data not available\n");
2441c91eab4bSThomas Abraham 			return -EINVAL;
2442c91eab4bSThomas Abraham 		}
2443f95f3850SWill Newton 	}
2444f95f3850SWill Newton 
244562ca8034SShashidhar Hiremath 	if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
24464a90920cSThomas Abraham 		dev_err(host->dev,
2447f95f3850SWill Newton 			"Platform data must supply select_slot function\n");
244862ca8034SShashidhar Hiremath 		return -ENODEV;
2449f95f3850SWill Newton 	}
2450f95f3850SWill Newton 
2451780f22afSSeungwon Jeon 	host->biu_clk = devm_clk_get(host->dev, "biu");
2452f90a0612SThomas Abraham 	if (IS_ERR(host->biu_clk)) {
2453f90a0612SThomas Abraham 		dev_dbg(host->dev, "biu clock not available\n");
2454f90a0612SThomas Abraham 	} else {
2455f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->biu_clk);
2456f90a0612SThomas Abraham 		if (ret) {
2457f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable biu clock\n");
2458f90a0612SThomas Abraham 			return ret;
2459f90a0612SThomas Abraham 		}
2460f95f3850SWill Newton 	}
2461f95f3850SWill Newton 
2462780f22afSSeungwon Jeon 	host->ciu_clk = devm_clk_get(host->dev, "ciu");
2463f90a0612SThomas Abraham 	if (IS_ERR(host->ciu_clk)) {
2464f90a0612SThomas Abraham 		dev_dbg(host->dev, "ciu clock not available\n");
24653c6d89eaSDoug Anderson 		host->bus_hz = host->pdata->bus_hz;
2466f90a0612SThomas Abraham 	} else {
2467f90a0612SThomas Abraham 		ret = clk_prepare_enable(host->ciu_clk);
2468f90a0612SThomas Abraham 		if (ret) {
2469f90a0612SThomas Abraham 			dev_err(host->dev, "failed to enable ciu clock\n");
2470f90a0612SThomas Abraham 			goto err_clk_biu;
2471f90a0612SThomas Abraham 		}
2472f90a0612SThomas Abraham 
24733c6d89eaSDoug Anderson 		if (host->pdata->bus_hz) {
24743c6d89eaSDoug Anderson 			ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz);
24753c6d89eaSDoug Anderson 			if (ret)
24763c6d89eaSDoug Anderson 				dev_warn(host->dev,
24773c6d89eaSDoug Anderson 					 "Unable to set bus rate to %ul\n",
24783c6d89eaSDoug Anderson 					 host->pdata->bus_hz);
24793c6d89eaSDoug Anderson 		}
2480f90a0612SThomas Abraham 		host->bus_hz = clk_get_rate(host->ciu_clk);
24813c6d89eaSDoug Anderson 	}
2482f90a0612SThomas Abraham 
2483002f0d5cSYuvaraj Kumar C D 	if (drv_data && drv_data->init) {
2484002f0d5cSYuvaraj Kumar C D 		ret = drv_data->init(host);
2485002f0d5cSYuvaraj Kumar C D 		if (ret) {
2486002f0d5cSYuvaraj Kumar C D 			dev_err(host->dev,
2487002f0d5cSYuvaraj Kumar C D 				"implementation specific init failed\n");
2488002f0d5cSYuvaraj Kumar C D 			goto err_clk_ciu;
2489002f0d5cSYuvaraj Kumar C D 		}
2490002f0d5cSYuvaraj Kumar C D 	}
2491002f0d5cSYuvaraj Kumar C D 
2492cb27a843SJames Hogan 	if (drv_data && drv_data->setup_clock) {
2493cb27a843SJames Hogan 		ret = drv_data->setup_clock(host);
2494800d78bfSThomas Abraham 		if (ret) {
2495800d78bfSThomas Abraham 			dev_err(host->dev,
2496800d78bfSThomas Abraham 				"implementation specific clock setup failed\n");
2497800d78bfSThomas Abraham 			goto err_clk_ciu;
2498800d78bfSThomas Abraham 		}
2499800d78bfSThomas Abraham 	}
2500800d78bfSThomas Abraham 
2501a55d6ff0SMark Brown 	host->vmmc = devm_regulator_get_optional(host->dev, "vmmc");
2502870556a3SDoug Anderson 	if (IS_ERR(host->vmmc)) {
2503870556a3SDoug Anderson 		ret = PTR_ERR(host->vmmc);
2504870556a3SDoug Anderson 		if (ret == -EPROBE_DEFER)
2505870556a3SDoug Anderson 			goto err_clk_ciu;
2506870556a3SDoug Anderson 
2507870556a3SDoug Anderson 		dev_info(host->dev, "no vmmc regulator found: %d\n", ret);
2508870556a3SDoug Anderson 		host->vmmc = NULL;
2509870556a3SDoug Anderson 	} else {
2510870556a3SDoug Anderson 		ret = regulator_enable(host->vmmc);
2511870556a3SDoug Anderson 		if (ret) {
2512870556a3SDoug Anderson 			if (ret != -EPROBE_DEFER)
2513870556a3SDoug Anderson 				dev_err(host->dev,
2514870556a3SDoug Anderson 					"regulator_enable fail: %d\n", ret);
2515870556a3SDoug Anderson 			goto err_clk_ciu;
2516870556a3SDoug Anderson 		}
2517870556a3SDoug Anderson 	}
2518870556a3SDoug Anderson 
2519f90a0612SThomas Abraham 	if (!host->bus_hz) {
2520f90a0612SThomas Abraham 		dev_err(host->dev,
2521f90a0612SThomas Abraham 			"Platform data must supply bus speed\n");
2522f90a0612SThomas Abraham 		ret = -ENODEV;
2523870556a3SDoug Anderson 		goto err_regulator;
2524f90a0612SThomas Abraham 	}
2525f90a0612SThomas Abraham 
252662ca8034SShashidhar Hiremath 	host->quirks = host->pdata->quirks;
2527f95f3850SWill Newton 
2528f95f3850SWill Newton 	spin_lock_init(&host->lock);
2529f95f3850SWill Newton 	INIT_LIST_HEAD(&host->queue);
2530f95f3850SWill Newton 
2531f95f3850SWill Newton 	/*
2532f95f3850SWill Newton 	 * Get the host data width - this assumes that HCON has been set with
2533f95f3850SWill Newton 	 * the correct values.
2534f95f3850SWill Newton 	 */
2535f95f3850SWill Newton 	i = (mci_readl(host, HCON) >> 7) & 0x7;
2536f95f3850SWill Newton 	if (!i) {
2537f95f3850SWill Newton 		host->push_data = dw_mci_push_data16;
2538f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data16;
2539f95f3850SWill Newton 		width = 16;
2540f95f3850SWill Newton 		host->data_shift = 1;
2541f95f3850SWill Newton 	} else if (i == 2) {
2542f95f3850SWill Newton 		host->push_data = dw_mci_push_data64;
2543f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data64;
2544f95f3850SWill Newton 		width = 64;
2545f95f3850SWill Newton 		host->data_shift = 3;
2546f95f3850SWill Newton 	} else {
2547f95f3850SWill Newton 		/* Check for a reserved value, and warn if it is */
2548f95f3850SWill Newton 		WARN((i != 1),
2549f95f3850SWill Newton 		     "HCON reports a reserved host data width!\n"
2550f95f3850SWill Newton 		     "Defaulting to 32-bit access.\n");
2551f95f3850SWill Newton 		host->push_data = dw_mci_push_data32;
2552f95f3850SWill Newton 		host->pull_data = dw_mci_pull_data32;
2553f95f3850SWill Newton 		width = 32;
2554f95f3850SWill Newton 		host->data_shift = 2;
2555f95f3850SWill Newton 	}
2556f95f3850SWill Newton 
2557f95f3850SWill Newton 	/* Reset all blocks */
255831bff450SSeungwon Jeon 	if (!dw_mci_ctrl_all_reset(host))
2559141a712aSSeungwon Jeon 		return -ENODEV;
2560141a712aSSeungwon Jeon 
2561141a712aSSeungwon Jeon 	host->dma_ops = host->pdata->dma_ops;
2562141a712aSSeungwon Jeon 	dw_mci_init_dma(host);
2563f95f3850SWill Newton 
2564f95f3850SWill Newton 	/* Clear the interrupts for the host controller */
2565f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2566f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2567f95f3850SWill Newton 
2568f95f3850SWill Newton 	/* Put in max timeout */
2569f95f3850SWill Newton 	mci_writel(host, TMOUT, 0xFFFFFFFF);
2570f95f3850SWill Newton 
2571f95f3850SWill Newton 	/*
2572f95f3850SWill Newton 	 * FIFO threshold settings  RxMark  = fifo_size / 2 - 1,
2573f95f3850SWill Newton 	 *                          Tx Mark = fifo_size / 2 DMA Size = 8
2574f95f3850SWill Newton 	 */
2575b86d8253SJames Hogan 	if (!host->pdata->fifo_depth) {
2576b86d8253SJames Hogan 		/*
2577b86d8253SJames Hogan 		 * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may
2578b86d8253SJames Hogan 		 * have been overwritten by the bootloader, just like we're
2579b86d8253SJames Hogan 		 * about to do, so if you know the value for your hardware, you
2580b86d8253SJames Hogan 		 * should put it in the platform data.
2581b86d8253SJames Hogan 		 */
2582f95f3850SWill Newton 		fifo_size = mci_readl(host, FIFOTH);
25838234e869SJaehoon Chung 		fifo_size = 1 + ((fifo_size >> 16) & 0xfff);
2584b86d8253SJames Hogan 	} else {
2585b86d8253SJames Hogan 		fifo_size = host->pdata->fifo_depth;
2586b86d8253SJames Hogan 	}
2587b86d8253SJames Hogan 	host->fifo_depth = fifo_size;
258852426899SSeungwon Jeon 	host->fifoth_val =
258952426899SSeungwon Jeon 		SDMMC_SET_FIFOTH(0x2, fifo_size / 2 - 1, fifo_size / 2);
2590e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
2591f95f3850SWill Newton 
2592f95f3850SWill Newton 	/* disable clock to CIU */
2593f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2594f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2595f95f3850SWill Newton 
259663008768SJames Hogan 	/*
259763008768SJames Hogan 	 * In 2.40a spec, Data offset is changed.
259863008768SJames Hogan 	 * Need to check the version-id and set data-offset for DATA register.
259963008768SJames Hogan 	 */
260063008768SJames Hogan 	host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
260163008768SJames Hogan 	dev_info(host->dev, "Version ID is %04x\n", host->verid);
260263008768SJames Hogan 
260363008768SJames Hogan 	if (host->verid < DW_MMC_240A)
260463008768SJames Hogan 		host->data_offset = DATA_OFFSET;
260563008768SJames Hogan 	else
260663008768SJames Hogan 		host->data_offset = DATA_240A_OFFSET;
260763008768SJames Hogan 
2608f95f3850SWill Newton 	tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
260995dcc2cbSThomas Abraham 	host->card_workqueue = alloc_workqueue("dw-mci-card",
26101791b13eSJames Hogan 			WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1);
2611ef7aef9aSWei Yongjun 	if (!host->card_workqueue) {
2612ef7aef9aSWei Yongjun 		ret = -ENOMEM;
26131791b13eSJames Hogan 		goto err_dmaunmap;
2614ef7aef9aSWei Yongjun 	}
26151791b13eSJames Hogan 	INIT_WORK(&host->card_work, dw_mci_work_routine_card);
2616780f22afSSeungwon Jeon 	ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
2617780f22afSSeungwon Jeon 			       host->irq_flags, "dw-mci", host);
2618f95f3850SWill Newton 	if (ret)
26191791b13eSJames Hogan 		goto err_workqueue;
2620f95f3850SWill Newton 
2621f95f3850SWill Newton 	if (host->pdata->num_slots)
2622f95f3850SWill Newton 		host->num_slots = host->pdata->num_slots;
2623f95f3850SWill Newton 	else
2624f95f3850SWill Newton 		host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1;
2625f95f3850SWill Newton 
26262da1d7f2SYuvaraj CD 	/*
26272da1d7f2SYuvaraj CD 	 * Enable interrupts for command done, data over, data empty, card det,
26282da1d7f2SYuvaraj CD 	 * receive ready and error such as transmit, receive timeout, crc error
26292da1d7f2SYuvaraj CD 	 */
26302da1d7f2SYuvaraj CD 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
26312da1d7f2SYuvaraj CD 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
26322da1d7f2SYuvaraj CD 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
26332da1d7f2SYuvaraj CD 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
26342da1d7f2SYuvaraj CD 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
26352da1d7f2SYuvaraj CD 
26362da1d7f2SYuvaraj CD 	dev_info(host->dev, "DW MMC controller at irq %d, "
26372da1d7f2SYuvaraj CD 		 "%d bit host data width, "
26382da1d7f2SYuvaraj CD 		 "%u deep fifo\n",
26392da1d7f2SYuvaraj CD 		 host->irq, width, fifo_size);
26402da1d7f2SYuvaraj CD 
2641f95f3850SWill Newton 	/* We need at least one slot to succeed */
2642f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2643f95f3850SWill Newton 		ret = dw_mci_init_slot(host, i);
26441c2215b7SThomas Abraham 		if (ret)
26451c2215b7SThomas Abraham 			dev_dbg(host->dev, "slot %d init failed\n", i);
26461c2215b7SThomas Abraham 		else
26471c2215b7SThomas Abraham 			init_slots++;
2648f95f3850SWill Newton 	}
26491c2215b7SThomas Abraham 
26501c2215b7SThomas Abraham 	if (init_slots) {
26511c2215b7SThomas Abraham 		dev_info(host->dev, "%d slots initialized\n", init_slots);
26521c2215b7SThomas Abraham 	} else {
26531c2215b7SThomas Abraham 		dev_dbg(host->dev, "attempted to initialize %d slots, "
26541c2215b7SThomas Abraham 					"but failed on all\n", host->num_slots);
2655780f22afSSeungwon Jeon 		goto err_workqueue;
2656f95f3850SWill Newton 	}
2657f95f3850SWill Newton 
2658f95f3850SWill Newton 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
26594a90920cSThomas Abraham 		dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
2660f95f3850SWill Newton 
2661f95f3850SWill Newton 	return 0;
2662f95f3850SWill Newton 
26631791b13eSJames Hogan err_workqueue:
266495dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
26651791b13eSJames Hogan 
2666f95f3850SWill Newton err_dmaunmap:
2667f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2668f95f3850SWill Newton 		host->dma_ops->exit(host);
2669f95f3850SWill Newton 
2670870556a3SDoug Anderson err_regulator:
2671780f22afSSeungwon Jeon 	if (host->vmmc)
2672c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2673f90a0612SThomas Abraham 
2674f90a0612SThomas Abraham err_clk_ciu:
2675780f22afSSeungwon Jeon 	if (!IS_ERR(host->ciu_clk))
2676f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2677780f22afSSeungwon Jeon 
2678f90a0612SThomas Abraham err_clk_biu:
2679780f22afSSeungwon Jeon 	if (!IS_ERR(host->biu_clk))
2680f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2681780f22afSSeungwon Jeon 
2682f95f3850SWill Newton 	return ret;
2683f95f3850SWill Newton }
268462ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_probe);
2685f95f3850SWill Newton 
268662ca8034SShashidhar Hiremath void dw_mci_remove(struct dw_mci *host)
2687f95f3850SWill Newton {
2688f95f3850SWill Newton 	int i;
2689f95f3850SWill Newton 
2690f95f3850SWill Newton 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2691f95f3850SWill Newton 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
2692f95f3850SWill Newton 
2693f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
26944a90920cSThomas Abraham 		dev_dbg(host->dev, "remove slot %d\n", i);
2695f95f3850SWill Newton 		if (host->slot[i])
2696f95f3850SWill Newton 			dw_mci_cleanup_slot(host->slot[i], i);
2697f95f3850SWill Newton 	}
2698f95f3850SWill Newton 
2699f95f3850SWill Newton 	/* disable clock to CIU */
2700f95f3850SWill Newton 	mci_writel(host, CLKENA, 0);
2701f95f3850SWill Newton 	mci_writel(host, CLKSRC, 0);
2702f95f3850SWill Newton 
270395dcc2cbSThomas Abraham 	destroy_workqueue(host->card_workqueue);
2704f95f3850SWill Newton 
2705f95f3850SWill Newton 	if (host->use_dma && host->dma_ops->exit)
2706f95f3850SWill Newton 		host->dma_ops->exit(host);
2707f95f3850SWill Newton 
2708780f22afSSeungwon Jeon 	if (host->vmmc)
2709c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2710c07946a3SJaehoon Chung 
2711f90a0612SThomas Abraham 	if (!IS_ERR(host->ciu_clk))
2712f90a0612SThomas Abraham 		clk_disable_unprepare(host->ciu_clk);
2713780f22afSSeungwon Jeon 
2714f90a0612SThomas Abraham 	if (!IS_ERR(host->biu_clk))
2715f90a0612SThomas Abraham 		clk_disable_unprepare(host->biu_clk);
2716f95f3850SWill Newton }
271762ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_remove);
271862ca8034SShashidhar Hiremath 
271962ca8034SShashidhar Hiremath 
2720f95f3850SWill Newton 
27216fe8890dSJaehoon Chung #ifdef CONFIG_PM_SLEEP
2722f95f3850SWill Newton /*
2723f95f3850SWill Newton  * TODO: we should probably disable the clock to the card in the suspend path.
2724f95f3850SWill Newton  */
272562ca8034SShashidhar Hiremath int dw_mci_suspend(struct dw_mci *host)
2726f95f3850SWill Newton {
2727c07946a3SJaehoon Chung 	if (host->vmmc)
2728c07946a3SJaehoon Chung 		regulator_disable(host->vmmc);
2729c07946a3SJaehoon Chung 
2730f95f3850SWill Newton 	return 0;
2731f95f3850SWill Newton }
273262ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_suspend);
2733f95f3850SWill Newton 
273462ca8034SShashidhar Hiremath int dw_mci_resume(struct dw_mci *host)
2735f95f3850SWill Newton {
2736f95f3850SWill Newton 	int i, ret;
2737f95f3850SWill Newton 
2738f2f942ceSSachin Kamat 	if (host->vmmc) {
2739f2f942ceSSachin Kamat 		ret = regulator_enable(host->vmmc);
2740f2f942ceSSachin Kamat 		if (ret) {
2741f2f942ceSSachin Kamat 			dev_err(host->dev,
2742f2f942ceSSachin Kamat 				"failed to enable regulator: %d\n", ret);
2743f2f942ceSSachin Kamat 			return ret;
2744f2f942ceSSachin Kamat 		}
2745f2f942ceSSachin Kamat 	}
27461d6c4e0aSJaehoon Chung 
274731bff450SSeungwon Jeon 	if (!dw_mci_ctrl_all_reset(host)) {
2748e61cf118SJaehoon Chung 		ret = -ENODEV;
2749e61cf118SJaehoon Chung 		return ret;
2750e61cf118SJaehoon Chung 	}
2751e61cf118SJaehoon Chung 
27523bfe619dSJonathan Kliegman 	if (host->use_dma && host->dma_ops->init)
2753141a712aSSeungwon Jeon 		host->dma_ops->init(host);
2754141a712aSSeungwon Jeon 
275552426899SSeungwon Jeon 	/*
275652426899SSeungwon Jeon 	 * Restore the initial value at FIFOTH register
275752426899SSeungwon Jeon 	 * And Invalidate the prev_blksz with zero
275852426899SSeungwon Jeon 	 */
2759e61cf118SJaehoon Chung 	mci_writel(host, FIFOTH, host->fifoth_val);
276052426899SSeungwon Jeon 	host->prev_blksz = 0;
2761e61cf118SJaehoon Chung 
27622eb2944fSDoug Anderson 	/* Put in max timeout */
27632eb2944fSDoug Anderson 	mci_writel(host, TMOUT, 0xFFFFFFFF);
27642eb2944fSDoug Anderson 
2765e61cf118SJaehoon Chung 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
2766e61cf118SJaehoon Chung 	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
2767e61cf118SJaehoon Chung 		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
2768e61cf118SJaehoon Chung 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
2769e61cf118SJaehoon Chung 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
2770e61cf118SJaehoon Chung 
2771f95f3850SWill Newton 	for (i = 0; i < host->num_slots; i++) {
2772f95f3850SWill Newton 		struct dw_mci_slot *slot = host->slot[i];
2773f95f3850SWill Newton 		if (!slot)
2774f95f3850SWill Newton 			continue;
2775ab269128SAbhilash Kesavan 		if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
2776ab269128SAbhilash Kesavan 			dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
2777ab269128SAbhilash Kesavan 			dw_mci_setup_bus(slot, true);
2778ab269128SAbhilash Kesavan 		}
2779f95f3850SWill Newton 	}
2780f95f3850SWill Newton 	return 0;
2781f95f3850SWill Newton }
278262ca8034SShashidhar Hiremath EXPORT_SYMBOL(dw_mci_resume);
27836fe8890dSJaehoon Chung #endif /* CONFIG_PM_SLEEP */
27846fe8890dSJaehoon Chung 
2785f95f3850SWill Newton static int __init dw_mci_init(void)
2786f95f3850SWill Newton {
27878e1c4e4dSSachin Kamat 	pr_info("Synopsys Designware Multimedia Card Interface Driver\n");
278862ca8034SShashidhar Hiremath 	return 0;
2789f95f3850SWill Newton }
2790f95f3850SWill Newton 
2791f95f3850SWill Newton static void __exit dw_mci_exit(void)
2792f95f3850SWill Newton {
2793f95f3850SWill Newton }
2794f95f3850SWill Newton 
2795f95f3850SWill Newton module_init(dw_mci_init);
2796f95f3850SWill Newton module_exit(dw_mci_exit);
2797f95f3850SWill Newton 
2798f95f3850SWill Newton MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
2799f95f3850SWill Newton MODULE_AUTHOR("NXP Semiconductor VietNam");
2800f95f3850SWill Newton MODULE_AUTHOR("Imagination Technologies Ltd");
2801f95f3850SWill Newton MODULE_LICENSE("GPL v2");
2802