1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * ARM PrimeCell MultiMedia Card Interface - PL180
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) ST-Ericsson SA 2010
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Author: Ulf Hansson <ulf.hansson@stericsson.com>
7*4882a593Smuzhiyun * Author: Martin Lundholm <martin.xa.lundholm@stericsson.com>
8*4882a593Smuzhiyun * Ported to drivers/mmc/ by: Matt Waddel <matt.waddel@linaro.org>
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun /* #define DEBUG */
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <asm/io.h>
16*4882a593Smuzhiyun #include "common.h"
17*4882a593Smuzhiyun #include <errno.h>
18*4882a593Smuzhiyun #include <mmc.h>
19*4882a593Smuzhiyun #include "arm_pl180_mmci.h"
20*4882a593Smuzhiyun #include <malloc.h>
21*4882a593Smuzhiyun
wait_for_command_end(struct mmc * dev,struct mmc_cmd * cmd)22*4882a593Smuzhiyun static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun u32 hoststatus, statusmask;
25*4882a593Smuzhiyun struct pl180_mmc_host *host = dev->priv;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun statusmask = SDI_STA_CTIMEOUT | SDI_STA_CCRCFAIL;
28*4882a593Smuzhiyun if ((cmd->resp_type & MMC_RSP_PRESENT))
29*4882a593Smuzhiyun statusmask |= SDI_STA_CMDREND;
30*4882a593Smuzhiyun else
31*4882a593Smuzhiyun statusmask |= SDI_STA_CMDSENT;
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun do
34*4882a593Smuzhiyun hoststatus = readl(&host->base->status) & statusmask;
35*4882a593Smuzhiyun while (!hoststatus);
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun writel(statusmask, &host->base->status_clear);
38*4882a593Smuzhiyun if (hoststatus & SDI_STA_CTIMEOUT) {
39*4882a593Smuzhiyun debug("CMD%d time out\n", cmd->cmdidx);
40*4882a593Smuzhiyun return -ETIMEDOUT;
41*4882a593Smuzhiyun } else if ((hoststatus & SDI_STA_CCRCFAIL) &&
42*4882a593Smuzhiyun (cmd->resp_type & MMC_RSP_CRC)) {
43*4882a593Smuzhiyun printf("CMD%d CRC error\n", cmd->cmdidx);
44*4882a593Smuzhiyun return -EILSEQ;
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun if (cmd->resp_type & MMC_RSP_PRESENT) {
48*4882a593Smuzhiyun cmd->response[0] = readl(&host->base->response0);
49*4882a593Smuzhiyun cmd->response[1] = readl(&host->base->response1);
50*4882a593Smuzhiyun cmd->response[2] = readl(&host->base->response2);
51*4882a593Smuzhiyun cmd->response[3] = readl(&host->base->response3);
52*4882a593Smuzhiyun debug("CMD%d response[0]:0x%08X, response[1]:0x%08X, "
53*4882a593Smuzhiyun "response[2]:0x%08X, response[3]:0x%08X\n",
54*4882a593Smuzhiyun cmd->cmdidx, cmd->response[0], cmd->response[1],
55*4882a593Smuzhiyun cmd->response[2], cmd->response[3]);
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun return 0;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* send command to the mmc card and wait for results */
do_command(struct mmc * dev,struct mmc_cmd * cmd)62*4882a593Smuzhiyun static int do_command(struct mmc *dev, struct mmc_cmd *cmd)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun int result;
65*4882a593Smuzhiyun u32 sdi_cmd = 0;
66*4882a593Smuzhiyun struct pl180_mmc_host *host = dev->priv;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun sdi_cmd = ((cmd->cmdidx & SDI_CMD_CMDINDEX_MASK) | SDI_CMD_CPSMEN);
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun if (cmd->resp_type) {
71*4882a593Smuzhiyun sdi_cmd |= SDI_CMD_WAITRESP;
72*4882a593Smuzhiyun if (cmd->resp_type & MMC_RSP_136)
73*4882a593Smuzhiyun sdi_cmd |= SDI_CMD_LONGRESP;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun writel((u32)cmd->cmdarg, &host->base->argument);
77*4882a593Smuzhiyun udelay(COMMAND_REG_DELAY);
78*4882a593Smuzhiyun writel(sdi_cmd, &host->base->command);
79*4882a593Smuzhiyun result = wait_for_command_end(dev, cmd);
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun /* After CMD2 set RCA to a none zero value. */
82*4882a593Smuzhiyun if ((result == 0) && (cmd->cmdidx == MMC_CMD_ALL_SEND_CID))
83*4882a593Smuzhiyun dev->rca = 10;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /* After CMD3 open drain is switched off and push pull is used. */
86*4882a593Smuzhiyun if ((result == 0) && (cmd->cmdidx == MMC_CMD_SET_RELATIVE_ADDR)) {
87*4882a593Smuzhiyun u32 sdi_pwr = readl(&host->base->power) & ~SDI_PWR_OPD;
88*4882a593Smuzhiyun writel(sdi_pwr, &host->base->power);
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun return result;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
read_bytes(struct mmc * dev,u32 * dest,u32 blkcount,u32 blksize)94*4882a593Smuzhiyun static int read_bytes(struct mmc *dev, u32 *dest, u32 blkcount, u32 blksize)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun u32 *tempbuff = dest;
97*4882a593Smuzhiyun u64 xfercount = blkcount * blksize;
98*4882a593Smuzhiyun struct pl180_mmc_host *host = dev->priv;
99*4882a593Smuzhiyun u32 status, status_err;
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun debug("read_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun status = readl(&host->base->status);
104*4882a593Smuzhiyun status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT |
105*4882a593Smuzhiyun SDI_STA_RXOVERR);
106*4882a593Smuzhiyun while ((!status_err) && (xfercount >= sizeof(u32))) {
107*4882a593Smuzhiyun if (status & SDI_STA_RXDAVL) {
108*4882a593Smuzhiyun *(tempbuff) = readl(&host->base->fifo);
109*4882a593Smuzhiyun tempbuff++;
110*4882a593Smuzhiyun xfercount -= sizeof(u32);
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun status = readl(&host->base->status);
113*4882a593Smuzhiyun status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT |
114*4882a593Smuzhiyun SDI_STA_RXOVERR);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun status_err = status &
118*4882a593Smuzhiyun (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND |
119*4882a593Smuzhiyun SDI_STA_RXOVERR);
120*4882a593Smuzhiyun while (!status_err) {
121*4882a593Smuzhiyun status = readl(&host->base->status);
122*4882a593Smuzhiyun status_err = status &
123*4882a593Smuzhiyun (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND |
124*4882a593Smuzhiyun SDI_STA_RXOVERR);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun if (status & SDI_STA_DTIMEOUT) {
128*4882a593Smuzhiyun printf("Read data timed out, xfercount: %llu, status: 0x%08X\n",
129*4882a593Smuzhiyun xfercount, status);
130*4882a593Smuzhiyun return -ETIMEDOUT;
131*4882a593Smuzhiyun } else if (status & SDI_STA_DCRCFAIL) {
132*4882a593Smuzhiyun printf("Read data bytes CRC error: 0x%x\n", status);
133*4882a593Smuzhiyun return -EILSEQ;
134*4882a593Smuzhiyun } else if (status & SDI_STA_RXOVERR) {
135*4882a593Smuzhiyun printf("Read data RX overflow error\n");
136*4882a593Smuzhiyun return -EIO;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun writel(SDI_ICR_MASK, &host->base->status_clear);
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun if (xfercount) {
142*4882a593Smuzhiyun printf("Read data error, xfercount: %llu\n", xfercount);
143*4882a593Smuzhiyun return -ENOBUFS;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun return 0;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
write_bytes(struct mmc * dev,u32 * src,u32 blkcount,u32 blksize)149*4882a593Smuzhiyun static int write_bytes(struct mmc *dev, u32 *src, u32 blkcount, u32 blksize)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun u32 *tempbuff = src;
152*4882a593Smuzhiyun int i;
153*4882a593Smuzhiyun u64 xfercount = blkcount * blksize;
154*4882a593Smuzhiyun struct pl180_mmc_host *host = dev->priv;
155*4882a593Smuzhiyun u32 status, status_err;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun debug("write_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun status = readl(&host->base->status);
160*4882a593Smuzhiyun status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
161*4882a593Smuzhiyun while (!status_err && xfercount) {
162*4882a593Smuzhiyun if (status & SDI_STA_TXFIFOBW) {
163*4882a593Smuzhiyun if (xfercount >= SDI_FIFO_BURST_SIZE * sizeof(u32)) {
164*4882a593Smuzhiyun for (i = 0; i < SDI_FIFO_BURST_SIZE; i++)
165*4882a593Smuzhiyun writel(*(tempbuff + i),
166*4882a593Smuzhiyun &host->base->fifo);
167*4882a593Smuzhiyun tempbuff += SDI_FIFO_BURST_SIZE;
168*4882a593Smuzhiyun xfercount -= SDI_FIFO_BURST_SIZE * sizeof(u32);
169*4882a593Smuzhiyun } else {
170*4882a593Smuzhiyun while (xfercount >= sizeof(u32)) {
171*4882a593Smuzhiyun writel(*(tempbuff), &host->base->fifo);
172*4882a593Smuzhiyun tempbuff++;
173*4882a593Smuzhiyun xfercount -= sizeof(u32);
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun status = readl(&host->base->status);
178*4882a593Smuzhiyun status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun status_err = status &
182*4882a593Smuzhiyun (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND);
183*4882a593Smuzhiyun while (!status_err) {
184*4882a593Smuzhiyun status = readl(&host->base->status);
185*4882a593Smuzhiyun status_err = status &
186*4882a593Smuzhiyun (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun if (status & SDI_STA_DTIMEOUT) {
190*4882a593Smuzhiyun printf("Write data timed out, xfercount:%llu,status:0x%08X\n",
191*4882a593Smuzhiyun xfercount, status);
192*4882a593Smuzhiyun return -ETIMEDOUT;
193*4882a593Smuzhiyun } else if (status & SDI_STA_DCRCFAIL) {
194*4882a593Smuzhiyun printf("Write data CRC error\n");
195*4882a593Smuzhiyun return -EILSEQ;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun writel(SDI_ICR_MASK, &host->base->status_clear);
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun if (xfercount) {
201*4882a593Smuzhiyun printf("Write data error, xfercount:%llu", xfercount);
202*4882a593Smuzhiyun return -ENOBUFS;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun return 0;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
do_data_transfer(struct mmc * dev,struct mmc_cmd * cmd,struct mmc_data * data)208*4882a593Smuzhiyun static int do_data_transfer(struct mmc *dev,
209*4882a593Smuzhiyun struct mmc_cmd *cmd,
210*4882a593Smuzhiyun struct mmc_data *data)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun int error = -ETIMEDOUT;
213*4882a593Smuzhiyun struct pl180_mmc_host *host = dev->priv;
214*4882a593Smuzhiyun u32 blksz = 0;
215*4882a593Smuzhiyun u32 data_ctrl = 0;
216*4882a593Smuzhiyun u32 data_len = (u32) (data->blocks * data->blocksize);
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun if (!host->version2) {
219*4882a593Smuzhiyun blksz = (ffs(data->blocksize) - 1);
220*4882a593Smuzhiyun data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK);
221*4882a593Smuzhiyun } else {
222*4882a593Smuzhiyun blksz = data->blocksize;
223*4882a593Smuzhiyun data_ctrl |= (blksz << SDI_DCTRL_DBLOCKSIZE_V2_SHIFT);
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun data_ctrl |= SDI_DCTRL_DTEN | SDI_DCTRL_BUSYMODE;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun writel(SDI_DTIMER_DEFAULT, &host->base->datatimer);
228*4882a593Smuzhiyun writel(data_len, &host->base->datalength);
229*4882a593Smuzhiyun udelay(DATA_REG_DELAY);
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun if (data->flags & MMC_DATA_READ) {
232*4882a593Smuzhiyun data_ctrl |= SDI_DCTRL_DTDIR_IN;
233*4882a593Smuzhiyun writel(data_ctrl, &host->base->datactrl);
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun error = do_command(dev, cmd);
236*4882a593Smuzhiyun if (error)
237*4882a593Smuzhiyun return error;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun error = read_bytes(dev, (u32 *)data->dest, (u32)data->blocks,
240*4882a593Smuzhiyun (u32)data->blocksize);
241*4882a593Smuzhiyun } else if (data->flags & MMC_DATA_WRITE) {
242*4882a593Smuzhiyun error = do_command(dev, cmd);
243*4882a593Smuzhiyun if (error)
244*4882a593Smuzhiyun return error;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun writel(data_ctrl, &host->base->datactrl);
247*4882a593Smuzhiyun error = write_bytes(dev, (u32 *)data->src, (u32)data->blocks,
248*4882a593Smuzhiyun (u32)data->blocksize);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun return error;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
host_request(struct mmc * dev,struct mmc_cmd * cmd,struct mmc_data * data)254*4882a593Smuzhiyun static int host_request(struct mmc *dev,
255*4882a593Smuzhiyun struct mmc_cmd *cmd,
256*4882a593Smuzhiyun struct mmc_data *data)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun int result;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if (data)
261*4882a593Smuzhiyun result = do_data_transfer(dev, cmd, data);
262*4882a593Smuzhiyun else
263*4882a593Smuzhiyun result = do_command(dev, cmd);
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun return result;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /* MMC uses open drain drivers in the enumeration phase */
mmc_host_reset(struct mmc * dev)269*4882a593Smuzhiyun static int mmc_host_reset(struct mmc *dev)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun struct pl180_mmc_host *host = dev->priv;
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun writel(host->pwr_init, &host->base->power);
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun return 0;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun
host_set_ios(struct mmc * dev)278*4882a593Smuzhiyun static int host_set_ios(struct mmc *dev)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun struct pl180_mmc_host *host = dev->priv;
281*4882a593Smuzhiyun u32 sdi_clkcr;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun sdi_clkcr = readl(&host->base->clock);
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun /* Ramp up the clock rate */
286*4882a593Smuzhiyun if (dev->clock) {
287*4882a593Smuzhiyun u32 clkdiv = 0;
288*4882a593Smuzhiyun u32 tmp_clock;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun if (dev->clock >= dev->cfg->f_max) {
291*4882a593Smuzhiyun clkdiv = 0;
292*4882a593Smuzhiyun dev->clock = dev->cfg->f_max;
293*4882a593Smuzhiyun } else {
294*4882a593Smuzhiyun clkdiv = (host->clock_in / dev->clock) - 2;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun tmp_clock = host->clock_in / (clkdiv + 2);
298*4882a593Smuzhiyun while (tmp_clock > dev->clock) {
299*4882a593Smuzhiyun clkdiv++;
300*4882a593Smuzhiyun tmp_clock = host->clock_in / (clkdiv + 2);
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun if (clkdiv > SDI_CLKCR_CLKDIV_MASK)
304*4882a593Smuzhiyun clkdiv = SDI_CLKCR_CLKDIV_MASK;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun tmp_clock = host->clock_in / (clkdiv + 2);
307*4882a593Smuzhiyun dev->clock = tmp_clock;
308*4882a593Smuzhiyun sdi_clkcr &= ~(SDI_CLKCR_CLKDIV_MASK);
309*4882a593Smuzhiyun sdi_clkcr |= clkdiv;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun /* Set the bus width */
313*4882a593Smuzhiyun if (dev->bus_width) {
314*4882a593Smuzhiyun u32 buswidth = 0;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun switch (dev->bus_width) {
317*4882a593Smuzhiyun case 1:
318*4882a593Smuzhiyun buswidth |= SDI_CLKCR_WIDBUS_1;
319*4882a593Smuzhiyun break;
320*4882a593Smuzhiyun case 4:
321*4882a593Smuzhiyun buswidth |= SDI_CLKCR_WIDBUS_4;
322*4882a593Smuzhiyun break;
323*4882a593Smuzhiyun case 8:
324*4882a593Smuzhiyun buswidth |= SDI_CLKCR_WIDBUS_8;
325*4882a593Smuzhiyun break;
326*4882a593Smuzhiyun default:
327*4882a593Smuzhiyun printf("Invalid bus width: %d\n", dev->bus_width);
328*4882a593Smuzhiyun break;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun sdi_clkcr &= ~(SDI_CLKCR_WIDBUS_MASK);
331*4882a593Smuzhiyun sdi_clkcr |= buswidth;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun writel(sdi_clkcr, &host->base->clock);
335*4882a593Smuzhiyun udelay(CLK_CHANGE_DELAY);
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun return 0;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun static const struct mmc_ops arm_pl180_mmci_ops = {
341*4882a593Smuzhiyun .send_cmd = host_request,
342*4882a593Smuzhiyun .set_ios = host_set_ios,
343*4882a593Smuzhiyun .init = mmc_host_reset,
344*4882a593Smuzhiyun };
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun /*
347*4882a593Smuzhiyun * mmc_host_init - initialize the mmc controller.
348*4882a593Smuzhiyun * Set initial clock and power for mmc slot.
349*4882a593Smuzhiyun * Initialize mmc struct and register with mmc framework.
350*4882a593Smuzhiyun */
arm_pl180_mmci_init(struct pl180_mmc_host * host)351*4882a593Smuzhiyun int arm_pl180_mmci_init(struct pl180_mmc_host *host)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun struct mmc *mmc;
354*4882a593Smuzhiyun u32 sdi_u32;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun writel(host->pwr_init, &host->base->power);
357*4882a593Smuzhiyun writel(host->clkdiv_init, &host->base->clock);
358*4882a593Smuzhiyun udelay(CLK_CHANGE_DELAY);
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun /* Disable mmc interrupts */
361*4882a593Smuzhiyun sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK;
362*4882a593Smuzhiyun writel(sdi_u32, &host->base->mask0);
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun host->cfg.name = host->name;
365*4882a593Smuzhiyun host->cfg.ops = &arm_pl180_mmci_ops;
366*4882a593Smuzhiyun /* TODO remove the duplicates */
367*4882a593Smuzhiyun host->cfg.host_caps = host->caps;
368*4882a593Smuzhiyun host->cfg.voltages = host->voltages;
369*4882a593Smuzhiyun host->cfg.f_min = host->clock_min;
370*4882a593Smuzhiyun host->cfg.f_max = host->clock_max;
371*4882a593Smuzhiyun if (host->b_max != 0)
372*4882a593Smuzhiyun host->cfg.b_max = host->b_max;
373*4882a593Smuzhiyun else
374*4882a593Smuzhiyun host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun mmc = mmc_create(&host->cfg, host);
377*4882a593Smuzhiyun if (mmc == NULL)
378*4882a593Smuzhiyun return -1;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun debug("registered mmc interface number is:%d\n", mmc->block_dev.devnum);
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun return 0;
383*4882a593Smuzhiyun }
384