xref: /OK3568_Linux_fs/u-boot/drivers/mmc/ftsdc010_mci.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Faraday MMC/SD Host Controller
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * (C) Copyright 2010 Faraday Technology
5*4882a593Smuzhiyun  * Dante Su <dantesu@faraday-tech.com>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <common.h>
11*4882a593Smuzhiyun #include <malloc.h>
12*4882a593Smuzhiyun #include <part.h>
13*4882a593Smuzhiyun #include <mmc.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <asm/io.h>
16*4882a593Smuzhiyun #include <linux/errno.h>
17*4882a593Smuzhiyun #include <asm/byteorder.h>
18*4882a593Smuzhiyun #include <faraday/ftsdc010.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */
21*4882a593Smuzhiyun #define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun struct ftsdc010_chip {
24*4882a593Smuzhiyun 	void __iomem *regs;
25*4882a593Smuzhiyun 	uint32_t wprot;   /* write protected (locked) */
26*4882a593Smuzhiyun 	uint32_t rate;    /* actual SD clock in Hz */
27*4882a593Smuzhiyun 	uint32_t sclk;    /* FTSDC010 source clock in Hz */
28*4882a593Smuzhiyun 	uint32_t fifo;    /* fifo depth in bytes */
29*4882a593Smuzhiyun 	uint32_t acmd;
30*4882a593Smuzhiyun 	struct mmc_config cfg;	/* mmc configuration */
31*4882a593Smuzhiyun };
32*4882a593Smuzhiyun 
ftsdc010_send_cmd(struct mmc * mmc,struct mmc_cmd * mmc_cmd)33*4882a593Smuzhiyun static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	struct ftsdc010_chip *chip = mmc->priv;
36*4882a593Smuzhiyun 	struct ftsdc010_mmc __iomem *regs = chip->regs;
37*4882a593Smuzhiyun 	int ret = -ETIMEDOUT;
38*4882a593Smuzhiyun 	uint32_t ts, st;
39*4882a593Smuzhiyun 	uint32_t cmd   = FTSDC010_CMD_IDX(mmc_cmd->cmdidx);
40*4882a593Smuzhiyun 	uint32_t arg   = mmc_cmd->cmdarg;
41*4882a593Smuzhiyun 	uint32_t flags = mmc_cmd->resp_type;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	cmd |= FTSDC010_CMD_CMD_EN;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	if (chip->acmd) {
46*4882a593Smuzhiyun 		cmd |= FTSDC010_CMD_APP_CMD;
47*4882a593Smuzhiyun 		chip->acmd = 0;
48*4882a593Smuzhiyun 	}
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	if (flags & MMC_RSP_PRESENT)
51*4882a593Smuzhiyun 		cmd |= FTSDC010_CMD_NEED_RSP;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	if (flags & MMC_RSP_136)
54*4882a593Smuzhiyun 		cmd |= FTSDC010_CMD_LONG_RSP;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	writel(FTSDC010_STATUS_RSP_MASK | FTSDC010_STATUS_CMD_SEND,
57*4882a593Smuzhiyun 		&regs->clr);
58*4882a593Smuzhiyun 	writel(arg, &regs->argu);
59*4882a593Smuzhiyun 	writel(cmd, &regs->cmd);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	if (!(flags & (MMC_RSP_PRESENT | MMC_RSP_136))) {
62*4882a593Smuzhiyun 		for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
63*4882a593Smuzhiyun 			if (readl(&regs->status) & FTSDC010_STATUS_CMD_SEND) {
64*4882a593Smuzhiyun 				writel(FTSDC010_STATUS_CMD_SEND, &regs->clr);
65*4882a593Smuzhiyun 				ret = 0;
66*4882a593Smuzhiyun 				break;
67*4882a593Smuzhiyun 			}
68*4882a593Smuzhiyun 		}
69*4882a593Smuzhiyun 	} else {
70*4882a593Smuzhiyun 		st = 0;
71*4882a593Smuzhiyun 		for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
72*4882a593Smuzhiyun 			st = readl(&regs->status);
73*4882a593Smuzhiyun 			writel(st & FTSDC010_STATUS_RSP_MASK, &regs->clr);
74*4882a593Smuzhiyun 			if (st & FTSDC010_STATUS_RSP_MASK)
75*4882a593Smuzhiyun 				break;
76*4882a593Smuzhiyun 		}
77*4882a593Smuzhiyun 		if (st & FTSDC010_STATUS_RSP_CRC_OK) {
78*4882a593Smuzhiyun 			if (flags & MMC_RSP_136) {
79*4882a593Smuzhiyun 				mmc_cmd->response[0] = readl(&regs->rsp3);
80*4882a593Smuzhiyun 				mmc_cmd->response[1] = readl(&regs->rsp2);
81*4882a593Smuzhiyun 				mmc_cmd->response[2] = readl(&regs->rsp1);
82*4882a593Smuzhiyun 				mmc_cmd->response[3] = readl(&regs->rsp0);
83*4882a593Smuzhiyun 			} else {
84*4882a593Smuzhiyun 				mmc_cmd->response[0] = readl(&regs->rsp0);
85*4882a593Smuzhiyun 			}
86*4882a593Smuzhiyun 			ret = 0;
87*4882a593Smuzhiyun 		} else {
88*4882a593Smuzhiyun 			debug("ftsdc010: rsp err (cmd=%d, st=0x%x)\n",
89*4882a593Smuzhiyun 				mmc_cmd->cmdidx, st);
90*4882a593Smuzhiyun 		}
91*4882a593Smuzhiyun 	}
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	if (ret) {
94*4882a593Smuzhiyun 		debug("ftsdc010: cmd timeout (op code=%d)\n",
95*4882a593Smuzhiyun 			mmc_cmd->cmdidx);
96*4882a593Smuzhiyun 	} else if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD) {
97*4882a593Smuzhiyun 		chip->acmd = 1;
98*4882a593Smuzhiyun 	}
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	return ret;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
ftsdc010_clkset(struct mmc * mmc,uint32_t rate)103*4882a593Smuzhiyun static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	struct ftsdc010_chip *chip = mmc->priv;
106*4882a593Smuzhiyun 	struct ftsdc010_mmc __iomem *regs = chip->regs;
107*4882a593Smuzhiyun 	uint32_t div;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	for (div = 0; div < 0x7f; ++div) {
110*4882a593Smuzhiyun 		if (rate >= chip->sclk / (2 * (div + 1)))
111*4882a593Smuzhiyun 			break;
112*4882a593Smuzhiyun 	}
113*4882a593Smuzhiyun 	chip->rate = chip->sclk / (2 * (div + 1));
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	writel(FTSDC010_CCR_CLK_DIV(div), &regs->ccr);
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	if (IS_SD(mmc)) {
118*4882a593Smuzhiyun 		setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_SD);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 		if (chip->rate > 25000000)
121*4882a593Smuzhiyun 			setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
122*4882a593Smuzhiyun 		else
123*4882a593Smuzhiyun 			clrbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
ftsdc010_wait(struct ftsdc010_mmc __iomem * regs,uint32_t mask)127*4882a593Smuzhiyun static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun 	int ret = -ETIMEDOUT;
130*4882a593Smuzhiyun 	uint32_t st, ts;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
133*4882a593Smuzhiyun 		st = readl(&regs->status);
134*4882a593Smuzhiyun 		if (!(st & mask))
135*4882a593Smuzhiyun 			continue;
136*4882a593Smuzhiyun 		writel(st & mask, &regs->clr);
137*4882a593Smuzhiyun 		ret = 0;
138*4882a593Smuzhiyun 		break;
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	if (ret)
142*4882a593Smuzhiyun 		debug("ftsdc010: wait st(0x%x) timeout\n", mask);
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	return ret;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun /*
148*4882a593Smuzhiyun  * u-boot mmc api
149*4882a593Smuzhiyun  */
150*4882a593Smuzhiyun 
ftsdc010_request(struct mmc * mmc,struct mmc_cmd * cmd,struct mmc_data * data)151*4882a593Smuzhiyun static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
152*4882a593Smuzhiyun 	struct mmc_data *data)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	int ret = -EOPNOTSUPP;
155*4882a593Smuzhiyun 	uint32_t len = 0;
156*4882a593Smuzhiyun 	struct ftsdc010_chip *chip = mmc->priv;
157*4882a593Smuzhiyun 	struct ftsdc010_mmc __iomem *regs = chip->regs;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) {
160*4882a593Smuzhiyun 		printf("ftsdc010: the card is write protected!\n");
161*4882a593Smuzhiyun 		return ret;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (data) {
165*4882a593Smuzhiyun 		uint32_t dcr;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 		len = data->blocksize * data->blocks;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 		/* 1. data disable + fifo reset */
170*4882a593Smuzhiyun 		dcr = 0;
171*4882a593Smuzhiyun #ifdef CONFIG_FTSDC010_SDIO
172*4882a593Smuzhiyun 		dcr |= FTSDC010_DCR_FIFO_RST;
173*4882a593Smuzhiyun #endif
174*4882a593Smuzhiyun 		writel(dcr, &regs->dcr);
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 		/* 2. clear status register */
177*4882a593Smuzhiyun 		writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN
178*4882a593Smuzhiyun 			| FTSDC010_STATUS_FIFO_ORUN, &regs->clr);
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 		/* 3. data timeout (1 sec) */
181*4882a593Smuzhiyun 		writel(chip->rate, &regs->dtr);
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 		/* 4. data length (bytes) */
184*4882a593Smuzhiyun 		writel(len, &regs->dlr);
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 		/* 5. data enable */
187*4882a593Smuzhiyun 		dcr = (ffs(data->blocksize) - 1) | FTSDC010_DCR_DATA_EN;
188*4882a593Smuzhiyun 		if (data->flags & MMC_DATA_WRITE)
189*4882a593Smuzhiyun 			dcr |= FTSDC010_DCR_DATA_WRITE;
190*4882a593Smuzhiyun 		writel(dcr, &regs->dcr);
191*4882a593Smuzhiyun 	}
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	ret = ftsdc010_send_cmd(mmc, cmd);
194*4882a593Smuzhiyun 	if (ret) {
195*4882a593Smuzhiyun 		printf("ftsdc010: CMD%d failed\n", cmd->cmdidx);
196*4882a593Smuzhiyun 		return ret;
197*4882a593Smuzhiyun 	}
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (!data)
200*4882a593Smuzhiyun 		return ret;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	if (data->flags & MMC_DATA_WRITE) {
203*4882a593Smuzhiyun 		const uint8_t *buf = (const uint8_t *)data->src;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 		while (len > 0) {
206*4882a593Smuzhiyun 			int wlen;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 			/* wait for tx ready */
209*4882a593Smuzhiyun 			ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_URUN);
210*4882a593Smuzhiyun 			if (ret)
211*4882a593Smuzhiyun 				break;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 			/* write bytes to ftsdc010 */
214*4882a593Smuzhiyun 			for (wlen = 0; wlen < len && wlen < chip->fifo; ) {
215*4882a593Smuzhiyun 				writel(*(uint32_t *)buf, &regs->dwr);
216*4882a593Smuzhiyun 				buf  += 4;
217*4882a593Smuzhiyun 				wlen += 4;
218*4882a593Smuzhiyun 			}
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 			len -= wlen;
221*4882a593Smuzhiyun 		}
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	} else {
224*4882a593Smuzhiyun 		uint8_t *buf = (uint8_t *)data->dest;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 		while (len > 0) {
227*4882a593Smuzhiyun 			int rlen;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 			/* wait for rx ready */
230*4882a593Smuzhiyun 			ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_ORUN);
231*4882a593Smuzhiyun 			if (ret)
232*4882a593Smuzhiyun 				break;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 			/* fetch bytes from ftsdc010 */
235*4882a593Smuzhiyun 			for (rlen = 0; rlen < len && rlen < chip->fifo; ) {
236*4882a593Smuzhiyun 				*(uint32_t *)buf = readl(&regs->dwr);
237*4882a593Smuzhiyun 				buf  += 4;
238*4882a593Smuzhiyun 				rlen += 4;
239*4882a593Smuzhiyun 			}
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 			len -= rlen;
242*4882a593Smuzhiyun 		}
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	if (!ret) {
247*4882a593Smuzhiyun 		ret = ftsdc010_wait(regs,
248*4882a593Smuzhiyun 			FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_ERROR);
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	return ret;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun 
ftsdc010_set_ios(struct mmc * mmc)254*4882a593Smuzhiyun static int ftsdc010_set_ios(struct mmc *mmc)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun 	struct ftsdc010_chip *chip = mmc->priv;
257*4882a593Smuzhiyun 	struct ftsdc010_mmc __iomem *regs = chip->regs;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	ftsdc010_clkset(mmc, mmc->clock);
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	clrbits_le32(&regs->bwr, FTSDC010_BWR_MODE_MASK);
262*4882a593Smuzhiyun 	switch (mmc->bus_width) {
263*4882a593Smuzhiyun 	case 4:
264*4882a593Smuzhiyun 		setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_4BIT);
265*4882a593Smuzhiyun 		break;
266*4882a593Smuzhiyun 	case 8:
267*4882a593Smuzhiyun 		setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_8BIT);
268*4882a593Smuzhiyun 		break;
269*4882a593Smuzhiyun 	default:
270*4882a593Smuzhiyun 		setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_1BIT);
271*4882a593Smuzhiyun 		break;
272*4882a593Smuzhiyun 	}
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	return 0;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
ftsdc010_init(struct mmc * mmc)277*4882a593Smuzhiyun static int ftsdc010_init(struct mmc *mmc)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun 	struct ftsdc010_chip *chip = mmc->priv;
280*4882a593Smuzhiyun 	struct ftsdc010_mmc __iomem *regs = chip->regs;
281*4882a593Smuzhiyun 	uint32_t ts;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	if (readl(&regs->status) & FTSDC010_STATUS_CARD_DETECT)
284*4882a593Smuzhiyun 		return -ENOMEDIUM;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	if (readl(&regs->status) & FTSDC010_STATUS_WRITE_PROT) {
287*4882a593Smuzhiyun 		printf("ftsdc010: write protected\n");
288*4882a593Smuzhiyun 		chip->wprot = 1;
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	chip->fifo = (readl(&regs->feature) & 0xff) << 2;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	/* 1. chip reset */
294*4882a593Smuzhiyun 	writel(FTSDC010_CMD_SDC_RST, &regs->cmd);
295*4882a593Smuzhiyun 	for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
296*4882a593Smuzhiyun 		if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST)
297*4882a593Smuzhiyun 			continue;
298*4882a593Smuzhiyun 		break;
299*4882a593Smuzhiyun 	}
300*4882a593Smuzhiyun 	if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST) {
301*4882a593Smuzhiyun 		printf("ftsdc010: reset failed\n");
302*4882a593Smuzhiyun 		return -EOPNOTSUPP;
303*4882a593Smuzhiyun 	}
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	/* 2. enter low speed mode (400k card detection) */
306*4882a593Smuzhiyun 	ftsdc010_clkset(mmc, 400000);
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	/* 3. interrupt disabled */
309*4882a593Smuzhiyun 	writel(0, &regs->int_mask);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	return 0;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun static const struct mmc_ops ftsdc010_ops = {
315*4882a593Smuzhiyun 	.send_cmd	= ftsdc010_request,
316*4882a593Smuzhiyun 	.set_ios	= ftsdc010_set_ios,
317*4882a593Smuzhiyun 	.init		= ftsdc010_init,
318*4882a593Smuzhiyun };
319*4882a593Smuzhiyun 
ftsdc010_mmc_init(int devid)320*4882a593Smuzhiyun int ftsdc010_mmc_init(int devid)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	struct mmc *mmc;
323*4882a593Smuzhiyun 	struct ftsdc010_chip *chip;
324*4882a593Smuzhiyun 	struct ftsdc010_mmc __iomem *regs;
325*4882a593Smuzhiyun #ifdef CONFIG_FTSDC010_BASE_LIST
326*4882a593Smuzhiyun 	uint32_t base_list[] = CONFIG_FTSDC010_BASE_LIST;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	if (devid < 0 || devid >= ARRAY_SIZE(base_list))
329*4882a593Smuzhiyun 		return -1;
330*4882a593Smuzhiyun 	regs = (void __iomem *)base_list[devid];
331*4882a593Smuzhiyun #else
332*4882a593Smuzhiyun 	regs = (void __iomem *)(CONFIG_FTSDC010_BASE + (devid << 20));
333*4882a593Smuzhiyun #endif
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	chip = malloc(sizeof(struct ftsdc010_chip));
336*4882a593Smuzhiyun 	if (!chip)
337*4882a593Smuzhiyun 		return -ENOMEM;
338*4882a593Smuzhiyun 	memset(chip, 0, sizeof(struct ftsdc010_chip));
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	chip->regs = regs;
341*4882a593Smuzhiyun #ifdef CONFIG_SYS_CLK_FREQ
342*4882a593Smuzhiyun 	chip->sclk = CONFIG_SYS_CLK_FREQ;
343*4882a593Smuzhiyun #else
344*4882a593Smuzhiyun 	chip->sclk = clk_get_rate("SDC");
345*4882a593Smuzhiyun #endif
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	chip->cfg.name = "ftsdc010";
348*4882a593Smuzhiyun 	chip->cfg.ops = &ftsdc010_ops;
349*4882a593Smuzhiyun 	chip->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
350*4882a593Smuzhiyun 	switch (readl(&regs->bwr) & FTSDC010_BWR_CAPS_MASK) {
351*4882a593Smuzhiyun 	case FTSDC010_BWR_CAPS_4BIT:
352*4882a593Smuzhiyun 		chip->cfg.host_caps |= MMC_MODE_4BIT;
353*4882a593Smuzhiyun 		break;
354*4882a593Smuzhiyun 	case FTSDC010_BWR_CAPS_8BIT:
355*4882a593Smuzhiyun 		chip->cfg.host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
356*4882a593Smuzhiyun 		break;
357*4882a593Smuzhiyun 	default:
358*4882a593Smuzhiyun 		break;
359*4882a593Smuzhiyun 	}
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	chip->cfg.voltages  = MMC_VDD_32_33 | MMC_VDD_33_34;
362*4882a593Smuzhiyun 	chip->cfg.f_max     = chip->sclk / 2;
363*4882a593Smuzhiyun 	chip->cfg.f_min     = chip->sclk / 0x100;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	chip->cfg.part_type = PART_TYPE_DOS;
366*4882a593Smuzhiyun 	chip->cfg.b_max	    = CONFIG_SYS_MMC_MAX_BLK_COUNT;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	mmc = mmc_create(&chip->cfg, chip);
369*4882a593Smuzhiyun 	if (mmc == NULL) {
370*4882a593Smuzhiyun 		free(chip);
371*4882a593Smuzhiyun 		return -ENOMEM;
372*4882a593Smuzhiyun 	}
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	return 0;
375*4882a593Smuzhiyun }
376