xref: /OK3568_Linux_fs/u-boot/drivers/mmc/arm_pl180_mmci.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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