xref: /OK3568_Linux_fs/u-boot/drivers/mmc/mxsmmc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Freescale i.MX28 SSP MMC driver
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
5*4882a593Smuzhiyun  * on behalf of DENX Software Engineering GmbH
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Based on code from LTIB:
8*4882a593Smuzhiyun  * (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
9*4882a593Smuzhiyun  * Terry Lv
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * Copyright 2007, Freescale Semiconductor, Inc
12*4882a593Smuzhiyun  * Andy Fleming
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * Based vaguely on the pxa mmc code:
15*4882a593Smuzhiyun  * (C) Copyright 2003
16*4882a593Smuzhiyun  * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
19*4882a593Smuzhiyun  */
20*4882a593Smuzhiyun #include <common.h>
21*4882a593Smuzhiyun #include <malloc.h>
22*4882a593Smuzhiyun #include <mmc.h>
23*4882a593Smuzhiyun #include <linux/errno.h>
24*4882a593Smuzhiyun #include <asm/io.h>
25*4882a593Smuzhiyun #include <asm/arch/clock.h>
26*4882a593Smuzhiyun #include <asm/arch/imx-regs.h>
27*4882a593Smuzhiyun #include <asm/arch/sys_proto.h>
28*4882a593Smuzhiyun #include <asm/mach-imx/dma.h>
29*4882a593Smuzhiyun #include <bouncebuf.h>
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun struct mxsmmc_priv {
32*4882a593Smuzhiyun 	int			id;
33*4882a593Smuzhiyun 	struct mxs_ssp_regs	*regs;
34*4882a593Smuzhiyun 	uint32_t		buswidth;
35*4882a593Smuzhiyun 	int			(*mmc_is_wp)(int);
36*4882a593Smuzhiyun 	int			(*mmc_cd)(int);
37*4882a593Smuzhiyun 	struct mxs_dma_desc	*desc;
38*4882a593Smuzhiyun 	struct mmc_config	cfg;	/* mmc configuration */
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun #define	MXSMMC_MAX_TIMEOUT	10000
42*4882a593Smuzhiyun #define MXSMMC_SMALL_TRANSFER	512
43*4882a593Smuzhiyun 
mxsmmc_cd(struct mxsmmc_priv * priv)44*4882a593Smuzhiyun static int mxsmmc_cd(struct mxsmmc_priv *priv)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun 	struct mxs_ssp_regs *ssp_regs = priv->regs;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	if (priv->mmc_cd)
49*4882a593Smuzhiyun 		return priv->mmc_cd(priv->id);
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	return !(readl(&ssp_regs->hw_ssp_status) & SSP_STATUS_CARD_DETECT);
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun 
mxsmmc_send_cmd_pio(struct mxsmmc_priv * priv,struct mmc_data * data)54*4882a593Smuzhiyun static int mxsmmc_send_cmd_pio(struct mxsmmc_priv *priv, struct mmc_data *data)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	struct mxs_ssp_regs *ssp_regs = priv->regs;
57*4882a593Smuzhiyun 	uint32_t *data_ptr;
58*4882a593Smuzhiyun 	int timeout = MXSMMC_MAX_TIMEOUT;
59*4882a593Smuzhiyun 	uint32_t reg;
60*4882a593Smuzhiyun 	uint32_t data_count = data->blocksize * data->blocks;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	if (data->flags & MMC_DATA_READ) {
63*4882a593Smuzhiyun 		data_ptr = (uint32_t *)data->dest;
64*4882a593Smuzhiyun 		while (data_count && --timeout) {
65*4882a593Smuzhiyun 			reg = readl(&ssp_regs->hw_ssp_status);
66*4882a593Smuzhiyun 			if (!(reg & SSP_STATUS_FIFO_EMPTY)) {
67*4882a593Smuzhiyun 				*data_ptr++ = readl(&ssp_regs->hw_ssp_data);
68*4882a593Smuzhiyun 				data_count -= 4;
69*4882a593Smuzhiyun 				timeout = MXSMMC_MAX_TIMEOUT;
70*4882a593Smuzhiyun 			} else
71*4882a593Smuzhiyun 				udelay(1000);
72*4882a593Smuzhiyun 		}
73*4882a593Smuzhiyun 	} else {
74*4882a593Smuzhiyun 		data_ptr = (uint32_t *)data->src;
75*4882a593Smuzhiyun 		timeout *= 100;
76*4882a593Smuzhiyun 		while (data_count && --timeout) {
77*4882a593Smuzhiyun 			reg = readl(&ssp_regs->hw_ssp_status);
78*4882a593Smuzhiyun 			if (!(reg & SSP_STATUS_FIFO_FULL)) {
79*4882a593Smuzhiyun 				writel(*data_ptr++, &ssp_regs->hw_ssp_data);
80*4882a593Smuzhiyun 				data_count -= 4;
81*4882a593Smuzhiyun 				timeout = MXSMMC_MAX_TIMEOUT;
82*4882a593Smuzhiyun 			} else
83*4882a593Smuzhiyun 				udelay(1000);
84*4882a593Smuzhiyun 		}
85*4882a593Smuzhiyun 	}
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	return timeout ? 0 : -ECOMM;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
mxsmmc_send_cmd_dma(struct mxsmmc_priv * priv,struct mmc_data * data)90*4882a593Smuzhiyun static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	uint32_t data_count = data->blocksize * data->blocks;
93*4882a593Smuzhiyun 	int dmach;
94*4882a593Smuzhiyun 	struct mxs_dma_desc *desc = priv->desc;
95*4882a593Smuzhiyun 	void *addr;
96*4882a593Smuzhiyun 	unsigned int flags;
97*4882a593Smuzhiyun 	struct bounce_buffer bbstate;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	memset(desc, 0, sizeof(struct mxs_dma_desc));
100*4882a593Smuzhiyun 	desc->address = (dma_addr_t)desc;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	if (data->flags & MMC_DATA_READ) {
103*4882a593Smuzhiyun 		priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE;
104*4882a593Smuzhiyun 		addr = data->dest;
105*4882a593Smuzhiyun 		flags = GEN_BB_WRITE;
106*4882a593Smuzhiyun 	} else {
107*4882a593Smuzhiyun 		priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ;
108*4882a593Smuzhiyun 		addr = (void *)data->src;
109*4882a593Smuzhiyun 		flags = GEN_BB_READ;
110*4882a593Smuzhiyun 	}
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	bounce_buffer_start(&bbstate, addr, data_count, flags);
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	priv->desc->cmd.address = (dma_addr_t)bbstate.bounce_buffer;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	priv->desc->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM |
117*4882a593Smuzhiyun 				(data_count << MXS_DMA_DESC_BYTES_OFFSET);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + priv->id;
120*4882a593Smuzhiyun 	mxs_dma_desc_append(dmach, priv->desc);
121*4882a593Smuzhiyun 	if (mxs_dma_go(dmach)) {
122*4882a593Smuzhiyun 		bounce_buffer_stop(&bbstate);
123*4882a593Smuzhiyun 		return -ECOMM;
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	bounce_buffer_stop(&bbstate);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	return 0;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun /*
132*4882a593Smuzhiyun  * Sends a command out on the bus.  Takes the mmc pointer,
133*4882a593Smuzhiyun  * a command pointer, and an optional data pointer.
134*4882a593Smuzhiyun  */
135*4882a593Smuzhiyun static int
mxsmmc_send_cmd(struct mmc * mmc,struct mmc_cmd * cmd,struct mmc_data * data)136*4882a593Smuzhiyun mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	struct mxsmmc_priv *priv = mmc->priv;
139*4882a593Smuzhiyun 	struct mxs_ssp_regs *ssp_regs = priv->regs;
140*4882a593Smuzhiyun 	uint32_t reg;
141*4882a593Smuzhiyun 	int timeout;
142*4882a593Smuzhiyun 	uint32_t ctrl0;
143*4882a593Smuzhiyun 	int ret;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	debug("MMC%d: CMD%d\n", mmc->block_dev.devnum, cmd->cmdidx);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	/* Check bus busy */
148*4882a593Smuzhiyun 	timeout = MXSMMC_MAX_TIMEOUT;
149*4882a593Smuzhiyun 	while (--timeout) {
150*4882a593Smuzhiyun 		udelay(1000);
151*4882a593Smuzhiyun 		reg = readl(&ssp_regs->hw_ssp_status);
152*4882a593Smuzhiyun 		if (!(reg &
153*4882a593Smuzhiyun 			(SSP_STATUS_BUSY | SSP_STATUS_DATA_BUSY |
154*4882a593Smuzhiyun 			SSP_STATUS_CMD_BUSY))) {
155*4882a593Smuzhiyun 			break;
156*4882a593Smuzhiyun 		}
157*4882a593Smuzhiyun 	}
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	if (!timeout) {
160*4882a593Smuzhiyun 		printf("MMC%d: Bus busy timeout!\n", mmc->block_dev.devnum);
161*4882a593Smuzhiyun 		return -ETIMEDOUT;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	/* See if card is present */
165*4882a593Smuzhiyun 	if (!mxsmmc_cd(priv)) {
166*4882a593Smuzhiyun 		printf("MMC%d: No card detected!\n", mmc->block_dev.devnum);
167*4882a593Smuzhiyun 		return -ENOMEDIUM;
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	/* Start building CTRL0 contents */
171*4882a593Smuzhiyun 	ctrl0 = priv->buswidth;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	/* Set up command */
174*4882a593Smuzhiyun 	if (!(cmd->resp_type & MMC_RSP_CRC))
175*4882a593Smuzhiyun 		ctrl0 |= SSP_CTRL0_IGNORE_CRC;
176*4882a593Smuzhiyun 	if (cmd->resp_type & MMC_RSP_PRESENT)	/* Need to get response */
177*4882a593Smuzhiyun 		ctrl0 |= SSP_CTRL0_GET_RESP;
178*4882a593Smuzhiyun 	if (cmd->resp_type & MMC_RSP_136)	/* It's a 136 bits response */
179*4882a593Smuzhiyun 		ctrl0 |= SSP_CTRL0_LONG_RESP;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	if (data && (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER))
182*4882a593Smuzhiyun 		writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_clr);
183*4882a593Smuzhiyun 	else
184*4882a593Smuzhiyun 		writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_set);
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	/* Command index */
187*4882a593Smuzhiyun 	reg = readl(&ssp_regs->hw_ssp_cmd0);
188*4882a593Smuzhiyun 	reg &= ~(SSP_CMD0_CMD_MASK | SSP_CMD0_APPEND_8CYC);
189*4882a593Smuzhiyun 	reg |= cmd->cmdidx << SSP_CMD0_CMD_OFFSET;
190*4882a593Smuzhiyun 	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
191*4882a593Smuzhiyun 		reg |= SSP_CMD0_APPEND_8CYC;
192*4882a593Smuzhiyun 	writel(reg, &ssp_regs->hw_ssp_cmd0);
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	/* Command argument */
195*4882a593Smuzhiyun 	writel(cmd->cmdarg, &ssp_regs->hw_ssp_cmd1);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	/* Set up data */
198*4882a593Smuzhiyun 	if (data) {
199*4882a593Smuzhiyun 		/* READ or WRITE */
200*4882a593Smuzhiyun 		if (data->flags & MMC_DATA_READ) {
201*4882a593Smuzhiyun 			ctrl0 |= SSP_CTRL0_READ;
202*4882a593Smuzhiyun 		} else if (priv->mmc_is_wp &&
203*4882a593Smuzhiyun 			priv->mmc_is_wp(mmc->block_dev.devnum)) {
204*4882a593Smuzhiyun 			printf("MMC%d: Can not write a locked card!\n",
205*4882a593Smuzhiyun 				mmc->block_dev.devnum);
206*4882a593Smuzhiyun 			return -EOPNOTSUPP;
207*4882a593Smuzhiyun 		}
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 		ctrl0 |= SSP_CTRL0_DATA_XFER;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 		reg = data->blocksize * data->blocks;
212*4882a593Smuzhiyun #if defined(CONFIG_MX23)
213*4882a593Smuzhiyun 		ctrl0 |= reg & SSP_CTRL0_XFER_COUNT_MASK;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 		clrsetbits_le32(&ssp_regs->hw_ssp_cmd0,
216*4882a593Smuzhiyun 			SSP_CMD0_BLOCK_SIZE_MASK | SSP_CMD0_BLOCK_COUNT_MASK,
217*4882a593Smuzhiyun 			((data->blocks - 1) << SSP_CMD0_BLOCK_COUNT_OFFSET) |
218*4882a593Smuzhiyun 			((ffs(data->blocksize) - 1) <<
219*4882a593Smuzhiyun 				SSP_CMD0_BLOCK_SIZE_OFFSET));
220*4882a593Smuzhiyun #elif defined(CONFIG_MX28)
221*4882a593Smuzhiyun 		writel(reg, &ssp_regs->hw_ssp_xfer_size);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 		reg = ((data->blocks - 1) <<
224*4882a593Smuzhiyun 			SSP_BLOCK_SIZE_BLOCK_COUNT_OFFSET) |
225*4882a593Smuzhiyun 			((ffs(data->blocksize) - 1) <<
226*4882a593Smuzhiyun 			SSP_BLOCK_SIZE_BLOCK_SIZE_OFFSET);
227*4882a593Smuzhiyun 		writel(reg, &ssp_regs->hw_ssp_block_size);
228*4882a593Smuzhiyun #endif
229*4882a593Smuzhiyun 	}
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	/* Kick off the command */
232*4882a593Smuzhiyun 	ctrl0 |= SSP_CTRL0_WAIT_FOR_IRQ | SSP_CTRL0_ENABLE | SSP_CTRL0_RUN;
233*4882a593Smuzhiyun 	writel(ctrl0, &ssp_regs->hw_ssp_ctrl0);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	/* Wait for the command to complete */
236*4882a593Smuzhiyun 	timeout = MXSMMC_MAX_TIMEOUT;
237*4882a593Smuzhiyun 	while (--timeout) {
238*4882a593Smuzhiyun 		udelay(1000);
239*4882a593Smuzhiyun 		reg = readl(&ssp_regs->hw_ssp_status);
240*4882a593Smuzhiyun 		if (!(reg & SSP_STATUS_CMD_BUSY))
241*4882a593Smuzhiyun 			break;
242*4882a593Smuzhiyun 	}
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	if (!timeout) {
245*4882a593Smuzhiyun 		printf("MMC%d: Command %d busy\n",
246*4882a593Smuzhiyun 			mmc->block_dev.devnum, cmd->cmdidx);
247*4882a593Smuzhiyun 		return -ETIMEDOUT;
248*4882a593Smuzhiyun 	}
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	/* Check command timeout */
251*4882a593Smuzhiyun 	if (reg & SSP_STATUS_RESP_TIMEOUT) {
252*4882a593Smuzhiyun 		printf("MMC%d: Command %d timeout (status 0x%08x)\n",
253*4882a593Smuzhiyun 			mmc->block_dev.devnum, cmd->cmdidx, reg);
254*4882a593Smuzhiyun 		return -ETIMEDOUT;
255*4882a593Smuzhiyun 	}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	/* Check command errors */
258*4882a593Smuzhiyun 	if (reg & (SSP_STATUS_RESP_CRC_ERR | SSP_STATUS_RESP_ERR)) {
259*4882a593Smuzhiyun 		printf("MMC%d: Command %d error (status 0x%08x)!\n",
260*4882a593Smuzhiyun 			mmc->block_dev.devnum, cmd->cmdidx, reg);
261*4882a593Smuzhiyun 		return -ECOMM;
262*4882a593Smuzhiyun 	}
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	/* Copy response to response buffer */
265*4882a593Smuzhiyun 	if (cmd->resp_type & MMC_RSP_136) {
266*4882a593Smuzhiyun 		cmd->response[3] = readl(&ssp_regs->hw_ssp_sdresp0);
267*4882a593Smuzhiyun 		cmd->response[2] = readl(&ssp_regs->hw_ssp_sdresp1);
268*4882a593Smuzhiyun 		cmd->response[1] = readl(&ssp_regs->hw_ssp_sdresp2);
269*4882a593Smuzhiyun 		cmd->response[0] = readl(&ssp_regs->hw_ssp_sdresp3);
270*4882a593Smuzhiyun 	} else
271*4882a593Smuzhiyun 		cmd->response[0] = readl(&ssp_regs->hw_ssp_sdresp0);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	/* Return if no data to process */
274*4882a593Smuzhiyun 	if (!data)
275*4882a593Smuzhiyun 		return 0;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	if (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER) {
278*4882a593Smuzhiyun 		ret = mxsmmc_send_cmd_pio(priv, data);
279*4882a593Smuzhiyun 		if (ret) {
280*4882a593Smuzhiyun 			printf("MMC%d: Data timeout with command %d "
281*4882a593Smuzhiyun 				"(status 0x%08x)!\n",
282*4882a593Smuzhiyun 				mmc->block_dev.devnum, cmd->cmdidx, reg);
283*4882a593Smuzhiyun 			return ret;
284*4882a593Smuzhiyun 		}
285*4882a593Smuzhiyun 	} else {
286*4882a593Smuzhiyun 		ret = mxsmmc_send_cmd_dma(priv, data);
287*4882a593Smuzhiyun 		if (ret) {
288*4882a593Smuzhiyun 			printf("MMC%d: DMA transfer failed\n",
289*4882a593Smuzhiyun 				mmc->block_dev.devnum);
290*4882a593Smuzhiyun 			return ret;
291*4882a593Smuzhiyun 		}
292*4882a593Smuzhiyun 	}
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	/* Check data errors */
295*4882a593Smuzhiyun 	reg = readl(&ssp_regs->hw_ssp_status);
296*4882a593Smuzhiyun 	if (reg &
297*4882a593Smuzhiyun 		(SSP_STATUS_TIMEOUT | SSP_STATUS_DATA_CRC_ERR |
298*4882a593Smuzhiyun 		SSP_STATUS_FIFO_OVRFLW | SSP_STATUS_FIFO_UNDRFLW)) {
299*4882a593Smuzhiyun 		printf("MMC%d: Data error with command %d (status 0x%08x)!\n",
300*4882a593Smuzhiyun 			mmc->block_dev.devnum, cmd->cmdidx, reg);
301*4882a593Smuzhiyun 		return -ECOMM;
302*4882a593Smuzhiyun 	}
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	return 0;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
mxsmmc_set_ios(struct mmc * mmc)307*4882a593Smuzhiyun static int mxsmmc_set_ios(struct mmc *mmc)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun 	struct mxsmmc_priv *priv = mmc->priv;
310*4882a593Smuzhiyun 	struct mxs_ssp_regs *ssp_regs = priv->regs;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	/* Set the clock speed */
313*4882a593Smuzhiyun 	if (mmc->clock)
314*4882a593Smuzhiyun 		mxs_set_ssp_busclock(priv->id, mmc->clock / 1000);
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	switch (mmc->bus_width) {
317*4882a593Smuzhiyun 	case 1:
318*4882a593Smuzhiyun 		priv->buswidth = SSP_CTRL0_BUS_WIDTH_ONE_BIT;
319*4882a593Smuzhiyun 		break;
320*4882a593Smuzhiyun 	case 4:
321*4882a593Smuzhiyun 		priv->buswidth = SSP_CTRL0_BUS_WIDTH_FOUR_BIT;
322*4882a593Smuzhiyun 		break;
323*4882a593Smuzhiyun 	case 8:
324*4882a593Smuzhiyun 		priv->buswidth = SSP_CTRL0_BUS_WIDTH_EIGHT_BIT;
325*4882a593Smuzhiyun 		break;
326*4882a593Smuzhiyun 	}
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	/* Set the bus width */
329*4882a593Smuzhiyun 	clrsetbits_le32(&ssp_regs->hw_ssp_ctrl0,
330*4882a593Smuzhiyun 			SSP_CTRL0_BUS_WIDTH_MASK, priv->buswidth);
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	debug("MMC%d: Set %d bits bus width\n",
333*4882a593Smuzhiyun 		mmc->block_dev.devnum, mmc->bus_width);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	return 0;
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun 
mxsmmc_init(struct mmc * mmc)338*4882a593Smuzhiyun static int mxsmmc_init(struct mmc *mmc)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun 	struct mxsmmc_priv *priv = mmc->priv;
341*4882a593Smuzhiyun 	struct mxs_ssp_regs *ssp_regs = priv->regs;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	/* Reset SSP */
344*4882a593Smuzhiyun 	mxs_reset_block(&ssp_regs->hw_ssp_ctrl0_reg);
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	/* Reconfigure the SSP block for MMC operation */
347*4882a593Smuzhiyun 	writel(SSP_CTRL1_SSP_MODE_SD_MMC |
348*4882a593Smuzhiyun 		SSP_CTRL1_WORD_LENGTH_EIGHT_BITS |
349*4882a593Smuzhiyun 		SSP_CTRL1_DMA_ENABLE |
350*4882a593Smuzhiyun 		SSP_CTRL1_POLARITY |
351*4882a593Smuzhiyun 		SSP_CTRL1_RECV_TIMEOUT_IRQ_EN |
352*4882a593Smuzhiyun 		SSP_CTRL1_DATA_CRC_IRQ_EN |
353*4882a593Smuzhiyun 		SSP_CTRL1_DATA_TIMEOUT_IRQ_EN |
354*4882a593Smuzhiyun 		SSP_CTRL1_RESP_TIMEOUT_IRQ_EN |
355*4882a593Smuzhiyun 		SSP_CTRL1_RESP_ERR_IRQ_EN,
356*4882a593Smuzhiyun 		&ssp_regs->hw_ssp_ctrl1_set);
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	/* Set initial bit clock 400 KHz */
359*4882a593Smuzhiyun 	mxs_set_ssp_busclock(priv->id, 400);
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	/* Send initial 74 clock cycles (185 us @ 400 KHz)*/
362*4882a593Smuzhiyun 	writel(SSP_CMD0_CONT_CLKING_EN, &ssp_regs->hw_ssp_cmd0_set);
363*4882a593Smuzhiyun 	udelay(200);
364*4882a593Smuzhiyun 	writel(SSP_CMD0_CONT_CLKING_EN, &ssp_regs->hw_ssp_cmd0_clr);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	return 0;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun static const struct mmc_ops mxsmmc_ops = {
370*4882a593Smuzhiyun 	.send_cmd	= mxsmmc_send_cmd,
371*4882a593Smuzhiyun 	.set_ios	= mxsmmc_set_ios,
372*4882a593Smuzhiyun 	.init		= mxsmmc_init,
373*4882a593Smuzhiyun };
374*4882a593Smuzhiyun 
mxsmmc_initialize(bd_t * bis,int id,int (* wp)(int),int (* cd)(int))375*4882a593Smuzhiyun int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int), int (*cd)(int))
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun 	struct mmc *mmc = NULL;
378*4882a593Smuzhiyun 	struct mxsmmc_priv *priv = NULL;
379*4882a593Smuzhiyun 	int ret;
380*4882a593Smuzhiyun 	const unsigned int mxsmmc_clk_id = mxs_ssp_clock_by_bus(id);
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	if (!mxs_ssp_bus_id_valid(id))
383*4882a593Smuzhiyun 		return -ENODEV;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	priv = malloc(sizeof(struct mxsmmc_priv));
386*4882a593Smuzhiyun 	if (!priv)
387*4882a593Smuzhiyun 		return -ENOMEM;
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	priv->desc = mxs_dma_desc_alloc();
390*4882a593Smuzhiyun 	if (!priv->desc) {
391*4882a593Smuzhiyun 		free(priv);
392*4882a593Smuzhiyun 		return -ENOMEM;
393*4882a593Smuzhiyun 	}
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	ret = mxs_dma_init_channel(MXS_DMA_CHANNEL_AHB_APBH_SSP0 + id);
396*4882a593Smuzhiyun 	if (ret)
397*4882a593Smuzhiyun 		return ret;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	priv->mmc_is_wp = wp;
400*4882a593Smuzhiyun 	priv->mmc_cd = cd;
401*4882a593Smuzhiyun 	priv->id = id;
402*4882a593Smuzhiyun 	priv->regs = mxs_ssp_regs_by_bus(id);
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	priv->cfg.name = "MXS MMC";
405*4882a593Smuzhiyun 	priv->cfg.ops = &mxsmmc_ops;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	priv->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	priv->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT |
410*4882a593Smuzhiyun 			 MMC_MODE_HS_52MHz | MMC_MODE_HS;
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	/*
413*4882a593Smuzhiyun 	 * SSPCLK = 480 * 18 / 29 / 1 = 297.731 MHz
414*4882a593Smuzhiyun 	 * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
415*4882a593Smuzhiyun 	 * CLOCK_DIVIDE has to be an even value from 2 to 254, and
416*4882a593Smuzhiyun 	 * CLOCK_RATE could be any integer from 0 to 255.
417*4882a593Smuzhiyun 	 */
418*4882a593Smuzhiyun 	priv->cfg.f_min = 400000;
419*4882a593Smuzhiyun 	priv->cfg.f_max = mxc_get_clock(MXC_SSP0_CLK + mxsmmc_clk_id) * 1000 / 2;
420*4882a593Smuzhiyun 	priv->cfg.b_max = 0x20;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	mmc = mmc_create(&priv->cfg, priv);
423*4882a593Smuzhiyun 	if (mmc == NULL) {
424*4882a593Smuzhiyun 		mxs_dma_desc_free(priv->desc);
425*4882a593Smuzhiyun 		free(priv);
426*4882a593Smuzhiyun 		return -ENOMEM;
427*4882a593Smuzhiyun 	}
428*4882a593Smuzhiyun 	return 0;
429*4882a593Smuzhiyun }
430