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