183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2f6c3b346SKuo-Jung Su /*
3f6c3b346SKuo-Jung Su * Faraday MMC/SD Host Controller
4f6c3b346SKuo-Jung Su *
5f6c3b346SKuo-Jung Su * (C) Copyright 2010 Faraday Technology
6f6c3b346SKuo-Jung Su * Dante Su <dantesu@faraday-tech.com>
7f6c3b346SKuo-Jung Su *
8bf9ba4dbSRick Chen * Copyright 2018 Andes Technology, Inc.
9bf9ba4dbSRick Chen * Author: Rick Chen (rick@andestech.com)
10f6c3b346SKuo-Jung Su */
11f6c3b346SKuo-Jung Su
12f6c3b346SKuo-Jung Su #include <common.h>
13bf9ba4dbSRick Chen #include <clk.h>
14f6c3b346SKuo-Jung Su #include <malloc.h>
15f6c3b346SKuo-Jung Su #include <part.h>
16f6c3b346SKuo-Jung Su #include <mmc.h>
17252185f2SRick Chen #include <linux/io.h>
181221ce45SMasahiro Yamada #include <linux/errno.h>
19f6c3b346SKuo-Jung Su #include <asm/byteorder.h>
20f6c3b346SKuo-Jung Su #include <faraday/ftsdc010.h>
21252185f2SRick Chen #include "ftsdc010_mci.h"
22bf9ba4dbSRick Chen #include <dm.h>
23bf9ba4dbSRick Chen #include <dt-structs.h>
24bf9ba4dbSRick Chen #include <errno.h>
25bf9ba4dbSRick Chen #include <mapmem.h>
26bf9ba4dbSRick Chen #include <pwrseq.h>
27bf9ba4dbSRick Chen #include <syscon.h>
28bf9ba4dbSRick Chen #include <linux/err.h>
29bf9ba4dbSRick Chen
30bf9ba4dbSRick Chen DECLARE_GLOBAL_DATA_PTR;
31f6c3b346SKuo-Jung Su
32f6c3b346SKuo-Jung Su #define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */
33f6c3b346SKuo-Jung Su #define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
34f6c3b346SKuo-Jung Su
35bf9ba4dbSRick Chen #if CONFIG_IS_ENABLED(OF_PLATDATA)
36bf9ba4dbSRick Chen struct ftsdc010 {
37bf9ba4dbSRick Chen fdt32_t bus_width;
38bf9ba4dbSRick Chen bool cap_mmc_highspeed;
39bf9ba4dbSRick Chen bool cap_sd_highspeed;
40bf9ba4dbSRick Chen fdt32_t clock_freq_min_max[2];
41bf9ba4dbSRick Chen struct phandle_2_cell clocks[4];
42bf9ba4dbSRick Chen fdt32_t fifo_depth;
43bf9ba4dbSRick Chen fdt32_t reg[2];
44bf9ba4dbSRick Chen };
45bf9ba4dbSRick Chen #endif
46bf9ba4dbSRick Chen
47bf9ba4dbSRick Chen struct ftsdc010_plat {
48bf9ba4dbSRick Chen #if CONFIG_IS_ENABLED(OF_PLATDATA)
49bf9ba4dbSRick Chen struct ftsdc010 dtplat;
50bf9ba4dbSRick Chen #endif
51bf9ba4dbSRick Chen struct mmc_config cfg;
52bf9ba4dbSRick Chen struct mmc mmc;
53bf9ba4dbSRick Chen };
54bf9ba4dbSRick Chen
55bf9ba4dbSRick Chen struct ftsdc_priv {
56bf9ba4dbSRick Chen struct clk clk;
57bf9ba4dbSRick Chen struct ftsdc010_chip chip;
58bf9ba4dbSRick Chen int fifo_depth;
59bf9ba4dbSRick Chen bool fifo_mode;
60bf9ba4dbSRick Chen u32 minmax[2];
61bf9ba4dbSRick Chen };
62bf9ba4dbSRick Chen
ftsdc010_send_cmd(struct mmc * mmc,struct mmc_cmd * mmc_cmd)63f6c3b346SKuo-Jung Su static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
64f6c3b346SKuo-Jung Su {
65f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv;
66f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs = chip->regs;
67915ffa52SJaehoon Chung int ret = -ETIMEDOUT;
68f6c3b346SKuo-Jung Su uint32_t ts, st;
69f6c3b346SKuo-Jung Su uint32_t cmd = FTSDC010_CMD_IDX(mmc_cmd->cmdidx);
70f6c3b346SKuo-Jung Su uint32_t arg = mmc_cmd->cmdarg;
71f6c3b346SKuo-Jung Su uint32_t flags = mmc_cmd->resp_type;
72f6c3b346SKuo-Jung Su
73f6c3b346SKuo-Jung Su cmd |= FTSDC010_CMD_CMD_EN;
74f6c3b346SKuo-Jung Su
75f6c3b346SKuo-Jung Su if (chip->acmd) {
76f6c3b346SKuo-Jung Su cmd |= FTSDC010_CMD_APP_CMD;
77f6c3b346SKuo-Jung Su chip->acmd = 0;
78f6c3b346SKuo-Jung Su }
79f6c3b346SKuo-Jung Su
80f6c3b346SKuo-Jung Su if (flags & MMC_RSP_PRESENT)
81f6c3b346SKuo-Jung Su cmd |= FTSDC010_CMD_NEED_RSP;
82f6c3b346SKuo-Jung Su
83f6c3b346SKuo-Jung Su if (flags & MMC_RSP_136)
84f6c3b346SKuo-Jung Su cmd |= FTSDC010_CMD_LONG_RSP;
85f6c3b346SKuo-Jung Su
86f6c3b346SKuo-Jung Su writel(FTSDC010_STATUS_RSP_MASK | FTSDC010_STATUS_CMD_SEND,
87f6c3b346SKuo-Jung Su ®s->clr);
88f6c3b346SKuo-Jung Su writel(arg, ®s->argu);
89f6c3b346SKuo-Jung Su writel(cmd, ®s->cmd);
90f6c3b346SKuo-Jung Su
91f6c3b346SKuo-Jung Su if (!(flags & (MMC_RSP_PRESENT | MMC_RSP_136))) {
92f6c3b346SKuo-Jung Su for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
93f6c3b346SKuo-Jung Su if (readl(®s->status) & FTSDC010_STATUS_CMD_SEND) {
94f6c3b346SKuo-Jung Su writel(FTSDC010_STATUS_CMD_SEND, ®s->clr);
95f6c3b346SKuo-Jung Su ret = 0;
96f6c3b346SKuo-Jung Su break;
97f6c3b346SKuo-Jung Su }
98f6c3b346SKuo-Jung Su }
99f6c3b346SKuo-Jung Su } else {
100f6c3b346SKuo-Jung Su st = 0;
101f6c3b346SKuo-Jung Su for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
102f6c3b346SKuo-Jung Su st = readl(®s->status);
103f6c3b346SKuo-Jung Su writel(st & FTSDC010_STATUS_RSP_MASK, ®s->clr);
104f6c3b346SKuo-Jung Su if (st & FTSDC010_STATUS_RSP_MASK)
105f6c3b346SKuo-Jung Su break;
106f6c3b346SKuo-Jung Su }
107f6c3b346SKuo-Jung Su if (st & FTSDC010_STATUS_RSP_CRC_OK) {
108f6c3b346SKuo-Jung Su if (flags & MMC_RSP_136) {
109f6c3b346SKuo-Jung Su mmc_cmd->response[0] = readl(®s->rsp3);
110f6c3b346SKuo-Jung Su mmc_cmd->response[1] = readl(®s->rsp2);
111f6c3b346SKuo-Jung Su mmc_cmd->response[2] = readl(®s->rsp1);
112f6c3b346SKuo-Jung Su mmc_cmd->response[3] = readl(®s->rsp0);
113f6c3b346SKuo-Jung Su } else {
114f6c3b346SKuo-Jung Su mmc_cmd->response[0] = readl(®s->rsp0);
115f6c3b346SKuo-Jung Su }
116f6c3b346SKuo-Jung Su ret = 0;
117f6c3b346SKuo-Jung Su } else {
118f6c3b346SKuo-Jung Su debug("ftsdc010: rsp err (cmd=%d, st=0x%x)\n",
119f6c3b346SKuo-Jung Su mmc_cmd->cmdidx, st);
120f6c3b346SKuo-Jung Su }
121f6c3b346SKuo-Jung Su }
122f6c3b346SKuo-Jung Su
123f6c3b346SKuo-Jung Su if (ret) {
124f6c3b346SKuo-Jung Su debug("ftsdc010: cmd timeout (op code=%d)\n",
125f6c3b346SKuo-Jung Su mmc_cmd->cmdidx);
126f6c3b346SKuo-Jung Su } else if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD) {
127f6c3b346SKuo-Jung Su chip->acmd = 1;
128f6c3b346SKuo-Jung Su }
129f6c3b346SKuo-Jung Su
130f6c3b346SKuo-Jung Su return ret;
131f6c3b346SKuo-Jung Su }
132f6c3b346SKuo-Jung Su
ftsdc010_clkset(struct mmc * mmc,uint32_t rate)133f6c3b346SKuo-Jung Su static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate)
134f6c3b346SKuo-Jung Su {
135f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv;
136f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs = chip->regs;
137f6c3b346SKuo-Jung Su uint32_t div;
138f6c3b346SKuo-Jung Su
139f6c3b346SKuo-Jung Su for (div = 0; div < 0x7f; ++div) {
140f6c3b346SKuo-Jung Su if (rate >= chip->sclk / (2 * (div + 1)))
141f6c3b346SKuo-Jung Su break;
142f6c3b346SKuo-Jung Su }
143f6c3b346SKuo-Jung Su chip->rate = chip->sclk / (2 * (div + 1));
144f6c3b346SKuo-Jung Su
145f6c3b346SKuo-Jung Su writel(FTSDC010_CCR_CLK_DIV(div), ®s->ccr);
146f6c3b346SKuo-Jung Su
147f6c3b346SKuo-Jung Su if (IS_SD(mmc)) {
148f6c3b346SKuo-Jung Su setbits_le32(®s->ccr, FTSDC010_CCR_CLK_SD);
149f6c3b346SKuo-Jung Su
150f6c3b346SKuo-Jung Su if (chip->rate > 25000000)
151f6c3b346SKuo-Jung Su setbits_le32(®s->ccr, FTSDC010_CCR_CLK_HISPD);
152f6c3b346SKuo-Jung Su else
153f6c3b346SKuo-Jung Su clrbits_le32(®s->ccr, FTSDC010_CCR_CLK_HISPD);
154f6c3b346SKuo-Jung Su }
155f6c3b346SKuo-Jung Su }
156f6c3b346SKuo-Jung Su
ftsdc010_wait(struct ftsdc010_mmc __iomem * regs,uint32_t mask)157f6c3b346SKuo-Jung Su static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
158f6c3b346SKuo-Jung Su {
159915ffa52SJaehoon Chung int ret = -ETIMEDOUT;
160252185f2SRick Chen uint32_t st, timeout = 10000000;
161252185f2SRick Chen while (timeout--) {
162f6c3b346SKuo-Jung Su st = readl(®s->status);
163f6c3b346SKuo-Jung Su if (!(st & mask))
164f6c3b346SKuo-Jung Su continue;
165f6c3b346SKuo-Jung Su writel(st & mask, ®s->clr);
166f6c3b346SKuo-Jung Su ret = 0;
167f6c3b346SKuo-Jung Su break;
168f6c3b346SKuo-Jung Su }
169f6c3b346SKuo-Jung Su
1701a9db640SRick Chen if (ret){
171f6c3b346SKuo-Jung Su debug("ftsdc010: wait st(0x%x) timeout\n", mask);
1721a9db640SRick Chen }
173f6c3b346SKuo-Jung Su
174f6c3b346SKuo-Jung Su return ret;
175f6c3b346SKuo-Jung Su }
176f6c3b346SKuo-Jung Su
177f6c3b346SKuo-Jung Su /*
178f6c3b346SKuo-Jung Su * u-boot mmc api
179f6c3b346SKuo-Jung Su */
ftsdc010_request(struct udevice * dev,struct mmc_cmd * cmd,struct mmc_data * data)180252185f2SRick Chen static int ftsdc010_request(struct udevice *dev, struct mmc_cmd *cmd,
181252185f2SRick Chen struct mmc_data *data)
182252185f2SRick Chen {
183252185f2SRick Chen struct mmc *mmc = mmc_get_mmc_dev(dev);
184915ffa52SJaehoon Chung int ret = -EOPNOTSUPP;
185f6c3b346SKuo-Jung Su uint32_t len = 0;
186f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv;
187f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs = chip->regs;
188f6c3b346SKuo-Jung Su
189f6c3b346SKuo-Jung Su if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) {
190f6c3b346SKuo-Jung Su printf("ftsdc010: the card is write protected!\n");
191f6c3b346SKuo-Jung Su return ret;
192f6c3b346SKuo-Jung Su }
193f6c3b346SKuo-Jung Su
194f6c3b346SKuo-Jung Su if (data) {
195f6c3b346SKuo-Jung Su uint32_t dcr;
196f6c3b346SKuo-Jung Su
197f6c3b346SKuo-Jung Su len = data->blocksize * data->blocks;
198f6c3b346SKuo-Jung Su
199f6c3b346SKuo-Jung Su /* 1. data disable + fifo reset */
200dbb713baSGabor Juhos dcr = 0;
201dbb713baSGabor Juhos #ifdef CONFIG_FTSDC010_SDIO
202dbb713baSGabor Juhos dcr |= FTSDC010_DCR_FIFO_RST;
203dbb713baSGabor Juhos #endif
204dbb713baSGabor Juhos writel(dcr, ®s->dcr);
205f6c3b346SKuo-Jung Su
206f6c3b346SKuo-Jung Su /* 2. clear status register */
207f6c3b346SKuo-Jung Su writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN
208f6c3b346SKuo-Jung Su | FTSDC010_STATUS_FIFO_ORUN, ®s->clr);
209f6c3b346SKuo-Jung Su
210f6c3b346SKuo-Jung Su /* 3. data timeout (1 sec) */
211f6c3b346SKuo-Jung Su writel(chip->rate, ®s->dtr);
212f6c3b346SKuo-Jung Su
213f6c3b346SKuo-Jung Su /* 4. data length (bytes) */
214f6c3b346SKuo-Jung Su writel(len, ®s->dlr);
215f6c3b346SKuo-Jung Su
216f6c3b346SKuo-Jung Su /* 5. data enable */
217f6c3b346SKuo-Jung Su dcr = (ffs(data->blocksize) - 1) | FTSDC010_DCR_DATA_EN;
218f6c3b346SKuo-Jung Su if (data->flags & MMC_DATA_WRITE)
219f6c3b346SKuo-Jung Su dcr |= FTSDC010_DCR_DATA_WRITE;
220f6c3b346SKuo-Jung Su writel(dcr, ®s->dcr);
221f6c3b346SKuo-Jung Su }
222f6c3b346SKuo-Jung Su
223f6c3b346SKuo-Jung Su ret = ftsdc010_send_cmd(mmc, cmd);
224f6c3b346SKuo-Jung Su if (ret) {
225f6c3b346SKuo-Jung Su printf("ftsdc010: CMD%d failed\n", cmd->cmdidx);
226f6c3b346SKuo-Jung Su return ret;
227f6c3b346SKuo-Jung Su }
228f6c3b346SKuo-Jung Su
229f6c3b346SKuo-Jung Su if (!data)
230f6c3b346SKuo-Jung Su return ret;
231f6c3b346SKuo-Jung Su
232f6c3b346SKuo-Jung Su if (data->flags & MMC_DATA_WRITE) {
233f6c3b346SKuo-Jung Su const uint8_t *buf = (const uint8_t *)data->src;
234f6c3b346SKuo-Jung Su
235f6c3b346SKuo-Jung Su while (len > 0) {
236f6c3b346SKuo-Jung Su int wlen;
237f6c3b346SKuo-Jung Su
238f6c3b346SKuo-Jung Su /* wait for tx ready */
239f6c3b346SKuo-Jung Su ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_URUN);
240f6c3b346SKuo-Jung Su if (ret)
241f6c3b346SKuo-Jung Su break;
242f6c3b346SKuo-Jung Su
243f6c3b346SKuo-Jung Su /* write bytes to ftsdc010 */
244f6c3b346SKuo-Jung Su for (wlen = 0; wlen < len && wlen < chip->fifo; ) {
245f6c3b346SKuo-Jung Su writel(*(uint32_t *)buf, ®s->dwr);
246f6c3b346SKuo-Jung Su buf += 4;
247f6c3b346SKuo-Jung Su wlen += 4;
248f6c3b346SKuo-Jung Su }
249f6c3b346SKuo-Jung Su
250f6c3b346SKuo-Jung Su len -= wlen;
251f6c3b346SKuo-Jung Su }
252f6c3b346SKuo-Jung Su
253f6c3b346SKuo-Jung Su } else {
254f6c3b346SKuo-Jung Su uint8_t *buf = (uint8_t *)data->dest;
255f6c3b346SKuo-Jung Su
256f6c3b346SKuo-Jung Su while (len > 0) {
257f6c3b346SKuo-Jung Su int rlen;
258f6c3b346SKuo-Jung Su
259f6c3b346SKuo-Jung Su /* wait for rx ready */
260f6c3b346SKuo-Jung Su ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_ORUN);
261f6c3b346SKuo-Jung Su if (ret)
262f6c3b346SKuo-Jung Su break;
263f6c3b346SKuo-Jung Su
264f6c3b346SKuo-Jung Su /* fetch bytes from ftsdc010 */
265f6c3b346SKuo-Jung Su for (rlen = 0; rlen < len && rlen < chip->fifo; ) {
266f6c3b346SKuo-Jung Su *(uint32_t *)buf = readl(®s->dwr);
267f6c3b346SKuo-Jung Su buf += 4;
268f6c3b346SKuo-Jung Su rlen += 4;
269f6c3b346SKuo-Jung Su }
270f6c3b346SKuo-Jung Su
271f6c3b346SKuo-Jung Su len -= rlen;
272f6c3b346SKuo-Jung Su }
273f6c3b346SKuo-Jung Su
274f6c3b346SKuo-Jung Su }
275f6c3b346SKuo-Jung Su
276f6c3b346SKuo-Jung Su if (!ret) {
277f6c3b346SKuo-Jung Su ret = ftsdc010_wait(regs,
2781a9db640SRick Chen FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_CRC_OK);
279f6c3b346SKuo-Jung Su }
280f6c3b346SKuo-Jung Su
281f6c3b346SKuo-Jung Su return ret;
282f6c3b346SKuo-Jung Su }
283f6c3b346SKuo-Jung Su
ftsdc010_set_ios(struct udevice * dev)284252185f2SRick Chen static int ftsdc010_set_ios(struct udevice *dev)
285252185f2SRick Chen {
286252185f2SRick Chen struct mmc *mmc = mmc_get_mmc_dev(dev);
287f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv;
288f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs = chip->regs;
289f6c3b346SKuo-Jung Su
290f6c3b346SKuo-Jung Su ftsdc010_clkset(mmc, mmc->clock);
291f6c3b346SKuo-Jung Su
292f6c3b346SKuo-Jung Su clrbits_le32(®s->bwr, FTSDC010_BWR_MODE_MASK);
293f6c3b346SKuo-Jung Su switch (mmc->bus_width) {
294f6c3b346SKuo-Jung Su case 4:
295f6c3b346SKuo-Jung Su setbits_le32(®s->bwr, FTSDC010_BWR_MODE_4BIT);
296f6c3b346SKuo-Jung Su break;
297f6c3b346SKuo-Jung Su case 8:
298f6c3b346SKuo-Jung Su setbits_le32(®s->bwr, FTSDC010_BWR_MODE_8BIT);
299f6c3b346SKuo-Jung Su break;
300f6c3b346SKuo-Jung Su default:
301f6c3b346SKuo-Jung Su setbits_le32(®s->bwr, FTSDC010_BWR_MODE_1BIT);
302f6c3b346SKuo-Jung Su break;
303f6c3b346SKuo-Jung Su }
30407b0b9c0SJaehoon Chung
30507b0b9c0SJaehoon Chung return 0;
306f6c3b346SKuo-Jung Su }
307f6c3b346SKuo-Jung Su
ftsdc010_get_cd(struct udevice * dev)308252185f2SRick Chen static int ftsdc010_get_cd(struct udevice *dev)
309252185f2SRick Chen {
310252185f2SRick Chen struct mmc *mmc = mmc_get_mmc_dev(dev);
311252185f2SRick Chen struct ftsdc010_chip *chip = mmc->priv;
312252185f2SRick Chen struct ftsdc010_mmc __iomem *regs = chip->regs;
313252185f2SRick Chen return !(readl(®s->status) & FTSDC010_STATUS_CARD_DETECT);
314252185f2SRick Chen }
315252185f2SRick Chen
ftsdc010_get_wp(struct udevice * dev)316252185f2SRick Chen static int ftsdc010_get_wp(struct udevice *dev)
317252185f2SRick Chen {
318252185f2SRick Chen struct mmc *mmc = mmc_get_mmc_dev(dev);
319252185f2SRick Chen struct ftsdc010_chip *chip = mmc->priv;
320252185f2SRick Chen struct ftsdc010_mmc __iomem *regs = chip->regs;
321252185f2SRick Chen if (readl(®s->status) & FTSDC010_STATUS_WRITE_PROT) {
322252185f2SRick Chen printf("ftsdc010: write protected\n");
323252185f2SRick Chen chip->wprot = 1;
324252185f2SRick Chen }
325252185f2SRick Chen
326252185f2SRick Chen return 0;
327252185f2SRick Chen }
328252185f2SRick Chen
ftsdc010_init(struct mmc * mmc)329f6c3b346SKuo-Jung Su static int ftsdc010_init(struct mmc *mmc)
330f6c3b346SKuo-Jung Su {
331f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv;
332f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs = chip->regs;
333f6c3b346SKuo-Jung Su uint32_t ts;
334f6c3b346SKuo-Jung Su
335f6c3b346SKuo-Jung Su chip->fifo = (readl(®s->feature) & 0xff) << 2;
336f6c3b346SKuo-Jung Su
337f6c3b346SKuo-Jung Su /* 1. chip reset */
338f6c3b346SKuo-Jung Su writel(FTSDC010_CMD_SDC_RST, ®s->cmd);
339f6c3b346SKuo-Jung Su for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
340f6c3b346SKuo-Jung Su if (readl(®s->cmd) & FTSDC010_CMD_SDC_RST)
341f6c3b346SKuo-Jung Su continue;
342f6c3b346SKuo-Jung Su break;
343f6c3b346SKuo-Jung Su }
344f6c3b346SKuo-Jung Su if (readl(®s->cmd) & FTSDC010_CMD_SDC_RST) {
345f6c3b346SKuo-Jung Su printf("ftsdc010: reset failed\n");
346915ffa52SJaehoon Chung return -EOPNOTSUPP;
347f6c3b346SKuo-Jung Su }
348f6c3b346SKuo-Jung Su
349f6c3b346SKuo-Jung Su /* 2. enter low speed mode (400k card detection) */
350f6c3b346SKuo-Jung Su ftsdc010_clkset(mmc, 400000);
351f6c3b346SKuo-Jung Su
352f6c3b346SKuo-Jung Su /* 3. interrupt disabled */
353f6c3b346SKuo-Jung Su writel(0, ®s->int_mask);
354f6c3b346SKuo-Jung Su
355f6c3b346SKuo-Jung Su return 0;
356f6c3b346SKuo-Jung Su }
357f6c3b346SKuo-Jung Su
ftsdc010_probe(struct udevice * dev)358bf9ba4dbSRick Chen static int ftsdc010_probe(struct udevice *dev)
359252185f2SRick Chen {
360252185f2SRick Chen struct mmc *mmc = mmc_get_mmc_dev(dev);
361252185f2SRick Chen return ftsdc010_init(mmc);
362252185f2SRick Chen }
363252185f2SRick Chen
364bf9ba4dbSRick Chen const struct dm_mmc_ops dm_ftsdc010_mmc_ops = {
365252185f2SRick Chen .send_cmd = ftsdc010_request,
366252185f2SRick Chen .set_ios = ftsdc010_set_ios,
367252185f2SRick Chen .get_cd = ftsdc010_get_cd,
368252185f2SRick Chen .get_wp = ftsdc010_get_wp,
369252185f2SRick Chen };
370252185f2SRick Chen
ftsdc_setup_cfg(struct mmc_config * cfg,const char * name,int buswidth,uint caps,u32 max_clk,u32 min_clk)371bf9ba4dbSRick Chen static void ftsdc_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth,
372252185f2SRick Chen uint caps, u32 max_clk, u32 min_clk)
373252185f2SRick Chen {
374252185f2SRick Chen cfg->name = name;
375252185f2SRick Chen cfg->f_min = min_clk;
376252185f2SRick Chen cfg->f_max = max_clk;
377252185f2SRick Chen cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
378252185f2SRick Chen cfg->host_caps = caps;
379252185f2SRick Chen if (buswidth == 8) {
380252185f2SRick Chen cfg->host_caps |= MMC_MODE_8BIT;
381252185f2SRick Chen cfg->host_caps &= ~MMC_MODE_4BIT;
382252185f2SRick Chen } else {
383252185f2SRick Chen cfg->host_caps |= MMC_MODE_4BIT;
384252185f2SRick Chen cfg->host_caps &= ~MMC_MODE_8BIT;
385252185f2SRick Chen }
386252185f2SRick Chen cfg->part_type = PART_TYPE_DOS;
387252185f2SRick Chen cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
388252185f2SRick Chen }
389252185f2SRick Chen
ftsdc010_mmc_ofdata_to_platdata(struct udevice * dev)390bf9ba4dbSRick Chen static int ftsdc010_mmc_ofdata_to_platdata(struct udevice *dev)
391252185f2SRick Chen {
392bf9ba4dbSRick Chen #if !CONFIG_IS_ENABLED(OF_PLATDATA)
393bf9ba4dbSRick Chen struct ftsdc_priv *priv = dev_get_priv(dev);
394bf9ba4dbSRick Chen struct ftsdc010_chip *chip = &priv->chip;
395bf9ba4dbSRick Chen chip->name = dev->name;
396bf9ba4dbSRick Chen chip->ioaddr = (void *)devfdt_get_addr(dev);
397bf9ba4dbSRick Chen chip->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
398bf9ba4dbSRick Chen "bus-width", 4);
399bf9ba4dbSRick Chen chip->priv = dev;
400bf9ba4dbSRick Chen priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
401bf9ba4dbSRick Chen "fifo-depth", 0);
402bf9ba4dbSRick Chen priv->fifo_mode = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
403bf9ba4dbSRick Chen "fifo-mode");
404bf9ba4dbSRick Chen if (fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev),
405bf9ba4dbSRick Chen "clock-freq-min-max", priv->minmax, 2)) {
406bf9ba4dbSRick Chen int val = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
407bf9ba4dbSRick Chen "max-frequency", -EINVAL);
408bf9ba4dbSRick Chen if (val < 0)
409bf9ba4dbSRick Chen return val;
410bf9ba4dbSRick Chen
411bf9ba4dbSRick Chen priv->minmax[0] = 400000; /* 400 kHz */
412bf9ba4dbSRick Chen priv->minmax[1] = val;
413bf9ba4dbSRick Chen } else {
414bf9ba4dbSRick Chen debug("%s: 'clock-freq-min-max' property was deprecated.\n",
415bf9ba4dbSRick Chen __func__);
416252185f2SRick Chen }
417bf9ba4dbSRick Chen #endif
418bf9ba4dbSRick Chen chip->sclk = priv->minmax[1];
419bf9ba4dbSRick Chen chip->regs = chip->ioaddr;
420bf9ba4dbSRick Chen return 0;
421bf9ba4dbSRick Chen }
422bf9ba4dbSRick Chen
ftsdc010_mmc_probe(struct udevice * dev)423bf9ba4dbSRick Chen static int ftsdc010_mmc_probe(struct udevice *dev)
424bf9ba4dbSRick Chen {
425bf9ba4dbSRick Chen struct ftsdc010_plat *plat = dev_get_platdata(dev);
426bf9ba4dbSRick Chen struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
427bf9ba4dbSRick Chen struct ftsdc_priv *priv = dev_get_priv(dev);
428bf9ba4dbSRick Chen struct ftsdc010_chip *chip = &priv->chip;
429bf9ba4dbSRick Chen struct udevice *pwr_dev __maybe_unused;
430bf9ba4dbSRick Chen
431bf9ba4dbSRick Chen #if CONFIG_IS_ENABLED(OF_PLATDATA)
432bf9ba4dbSRick Chen int ret;
433bf9ba4dbSRick Chen struct ftsdc010 *dtplat = &plat->dtplat;
434bf9ba4dbSRick Chen chip->name = dev->name;
435bf9ba4dbSRick Chen chip->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
436bf9ba4dbSRick Chen chip->buswidth = dtplat->bus_width;
437bf9ba4dbSRick Chen chip->priv = dev;
438bf9ba4dbSRick Chen chip->dev_index = 1;
439bf9ba4dbSRick Chen memcpy(priv->minmax, dtplat->clock_freq_min_max, sizeof(priv->minmax));
440bf9ba4dbSRick Chen ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk);
441bf9ba4dbSRick Chen if (ret < 0)
442bf9ba4dbSRick Chen return ret;
443bf9ba4dbSRick Chen #endif
444bf9ba4dbSRick Chen
445bf9ba4dbSRick Chen if (dev_read_bool(dev, "cap-mmc-highspeed") || \
446bf9ba4dbSRick Chen dev_read_bool(dev, "cap-sd-highspeed"))
447bf9ba4dbSRick Chen chip->caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
448bf9ba4dbSRick Chen
449bf9ba4dbSRick Chen ftsdc_setup_cfg(&plat->cfg, dev->name, chip->buswidth, chip->caps,
450bf9ba4dbSRick Chen priv->minmax[1] , priv->minmax[0]);
451bf9ba4dbSRick Chen chip->mmc = &plat->mmc;
452bf9ba4dbSRick Chen chip->mmc->priv = &priv->chip;
453bf9ba4dbSRick Chen chip->mmc->dev = dev;
454bf9ba4dbSRick Chen upriv->mmc = chip->mmc;
455bf9ba4dbSRick Chen return ftsdc010_probe(dev);
456bf9ba4dbSRick Chen }
457bf9ba4dbSRick Chen
ftsdc010_mmc_bind(struct udevice * dev)458bf9ba4dbSRick Chen int ftsdc010_mmc_bind(struct udevice *dev)
459bf9ba4dbSRick Chen {
460bf9ba4dbSRick Chen struct ftsdc010_plat *plat = dev_get_platdata(dev);
461bf9ba4dbSRick Chen
462bf9ba4dbSRick Chen return mmc_bind(dev, &plat->mmc, &plat->cfg);
463bf9ba4dbSRick Chen }
464bf9ba4dbSRick Chen
465bf9ba4dbSRick Chen static const struct udevice_id ftsdc010_mmc_ids[] = {
466*cf3922ddSRick Chen { .compatible = "andestech,atfsdc010" },
467bf9ba4dbSRick Chen { }
468bf9ba4dbSRick Chen };
469bf9ba4dbSRick Chen
470bf9ba4dbSRick Chen U_BOOT_DRIVER(ftsdc010_mmc) = {
471bf9ba4dbSRick Chen .name = "ftsdc010_mmc",
472bf9ba4dbSRick Chen .id = UCLASS_MMC,
473bf9ba4dbSRick Chen .of_match = ftsdc010_mmc_ids,
474bf9ba4dbSRick Chen .ofdata_to_platdata = ftsdc010_mmc_ofdata_to_platdata,
475bf9ba4dbSRick Chen .ops = &dm_ftsdc010_mmc_ops,
476bf9ba4dbSRick Chen .bind = ftsdc010_mmc_bind,
477bf9ba4dbSRick Chen .probe = ftsdc010_mmc_probe,
478bf9ba4dbSRick Chen .priv_auto_alloc_size = sizeof(struct ftsdc_priv),
479bf9ba4dbSRick Chen .platdata_auto_alloc_size = sizeof(struct ftsdc010_plat),
480bf9ba4dbSRick Chen };
481