1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2020/12/31 Bernard Add license info
9 */
10 #include <rthw.h>
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include <drivers/dev_mmcsd_core.h>
14
15 #include <stdint.h>
16 #include <stdio.h>
17
18 #include "board.h"
19 #include "drv_sdio.h"
20
21 #ifdef RT_USING_SDIO
22
23 #define MMC_BASE_ADDR (0x10005000)
24
25 #define PL180_POWER (0x00)
26 #define PL180_CLOCK (0x04)
27 #define PL180_ARGUMENT (0x08)
28 #define PL180_COMMAND (0x0c)
29 #define PL180_RESPCMD (0x10)
30 #define PL180_RESP0 (0x14)
31 #define PL180_RESP1 (0x18)
32 #define PL180_RESP2 (0x1c)
33 #define PL180_RESP3 (0x20)
34 #define PL180_DATA_TIMER (0x24)
35 #define PL180_DATA_LENGTH (0x28)
36 #define PL180_DATA_CTRL (0x2c)
37 #define PL180_DATA_CNT (0x30)
38 #define PL180_STATUS (0x34)
39 #define PL180_CLEAR (0x38)
40 #define PL180_MASK0 (0x3c)
41 #define PL180_MASK1 (0x40)
42 #define PL180_SELECT (0x44)
43 #define PL180_FIFO_CNT (0x48)
44 #define PL180_FIFO (0x80)
45
46 #define PL180_RSP_NONE (0 << 0)
47 #define PL180_RSP_PRESENT (1 << 0)
48 #define PL180_RSP_136BIT (1 << 1)
49 #define PL180_RSP_CRC (1 << 2)
50
51 #define PL180_CMD_WAITRESP (1 << 6)
52 #define PL180_CMD_LONGRSP (1 << 7)
53 #define PL180_CMD_WAITINT (1 << 8)
54 #define PL180_CMD_WAITPEND (1 << 9)
55 #define PL180_CMD_ENABLE (1 << 10)
56
57 #define PL180_STAT_CMD_CRC_FAIL (1 << 0)
58 #define PL180_STAT_DAT_CRC_FAIL (1 << 1)
59 #define PL180_STAT_CMD_TIME_OUT (1 << 2)
60 #define PL180_STAT_DAT_TIME_OUT (1 << 3)
61 #define PL180_STAT_TX_UNDERRUN (1 << 4)
62 #define PL180_STAT_RX_OVERRUN (1 << 5)
63 #define PL180_STAT_CMD_RESP_END (1 << 6)
64 #define PL180_STAT_CMD_SENT (1 << 7)
65 #define PL180_STAT_DAT_END (1 << 8)
66 #define PL180_STAT_DAT_BLK_END (1 << 10)
67 #define PL180_STAT_CMD_ACT (1 << 11)
68 #define PL180_STAT_TX_ACT (1 << 12)
69 #define PL180_STAT_RX_ACT (1 << 13)
70 #define PL180_STAT_TX_FIFO_HALF (1 << 14)
71 #define PL180_STAT_RX_FIFO_HALF (1 << 15)
72 #define PL180_STAT_TX_FIFO_FULL (1 << 16)
73 #define PL180_STAT_RX_FIFO_FULL (1 << 17)
74 #define PL180_STAT_TX_FIFO_ZERO (1 << 18)
75 #define PL180_STAT_RX_DAT_ZERO (1 << 19)
76 #define PL180_STAT_TX_DAT_AVL (1 << 20)
77 #define PL180_STAT_RX_FIFO_AVL (1 << 21)
78
79 #define PL180_CLR_CMD_CRC_FAIL (1 << 0)
80 #define PL180_CLR_DAT_CRC_FAIL (1 << 1)
81 #define PL180_CLR_CMD_TIMEOUT (1 << 2)
82 #define PL180_CLR_DAT_TIMEOUT (1 << 3)
83 #define PL180_CLR_TX_UNDERRUN (1 << 4)
84 #define PL180_CLR_RX_OVERRUN (1 << 5)
85 #define PL180_CLR_CMD_RESP_END (1 << 6)
86 #define PL180_CLR_CMD_SENT (1 << 7)
87 #define PL180_CLR_DAT_END (1 << 8)
88 #define PL180_CLR_DAT_BLK_END (1 << 10)
89
90 #define DBG_TAG "drv.sdio"
91 #define DBG_LVL DBG_INFO
92 #include "rtdbg.h"
93
94 struct sdhci_pl180_pdata_t
95 {
96 rt_uint32_t virt;
97 };
98
read32(uint32_t addr)99 static inline rt_uint32_t read32(uint32_t addr)
100 {
101 return( *((volatile rt_uint32_t *)(addr)) );
102 }
103
write32(uint32_t addr,rt_uint32_t value)104 static inline void write32(uint32_t addr, rt_uint32_t value)
105 {
106 *((volatile rt_uint32_t *)(addr)) = value;
107 }
108
pl180_transfer_command(struct sdhci_pl180_pdata_t * pdat,struct sdhci_cmd_t * cmd)109 static rt_err_t pl180_transfer_command(struct sdhci_pl180_pdata_t * pdat, struct sdhci_cmd_t * cmd)
110 {
111 rt_uint32_t cmdidx;
112 rt_uint32_t status;
113 rt_err_t ret = RT_EOK;
114
115 if(read32(pdat->virt + PL180_COMMAND) & PL180_CMD_ENABLE)
116 write32(pdat->virt + PL180_COMMAND, 0x0);
117
118 cmdidx = (cmd->cmdidx & 0xff) | PL180_CMD_ENABLE;
119 if(cmd->resptype)
120 {
121 cmdidx |= PL180_CMD_WAITRESP;
122 if(cmd->resptype & PL180_RSP_136BIT)
123 cmdidx |= PL180_CMD_LONGRSP;
124 }
125
126 write32(pdat->virt + PL180_ARGUMENT, cmd->cmdarg);
127 write32(pdat->virt + PL180_COMMAND, cmdidx);
128
129 do {
130 status = read32(pdat->virt + PL180_STATUS);
131 } while(!(status & (PL180_STAT_CMD_SENT | PL180_STAT_CMD_RESP_END | PL180_STAT_CMD_TIME_OUT | PL180_STAT_CMD_CRC_FAIL)));
132 LOG_D("mmc status done!");
133
134 if(cmd->resptype & PL180_RSP_PRESENT)
135 {
136 cmd->response[0] = read32(pdat->virt + PL180_RESP0);
137 if(cmd->resptype & PL180_RSP_136BIT)
138 {
139 LOG_D("136bit response");
140 cmd->response[1] = read32(pdat->virt + PL180_RESP1);
141 cmd->response[2] = read32(pdat->virt + PL180_RESP2);
142 cmd->response[3] = read32(pdat->virt + PL180_RESP3);
143 }
144 }
145
146 if(status & PL180_STAT_CMD_TIME_OUT)
147 {
148 ret = -RT_ETIMEOUT;
149 }
150 else if ((status & PL180_STAT_CMD_CRC_FAIL) && (cmd->resptype & PL180_RSP_CRC))
151 {
152 ret = -RT_ERROR;
153 }
154
155 write32(pdat->virt + PL180_CLEAR, (PL180_CLR_CMD_SENT | PL180_CLR_CMD_RESP_END | PL180_CLR_CMD_TIMEOUT | PL180_CLR_CMD_CRC_FAIL));
156 return ret;
157 }
158
read_bytes(struct sdhci_pl180_pdata_t * pdat,rt_uint32_t * buf,rt_uint32_t blkcount,rt_uint32_t blksize)159 static rt_err_t read_bytes(struct sdhci_pl180_pdata_t * pdat, rt_uint32_t * buf, rt_uint32_t blkcount, rt_uint32_t blksize)
160 {
161 rt_uint32_t * tmp = buf;
162 rt_uint32_t count = blkcount * blksize;
163 rt_uint32_t status, err;
164
165 status = read32(pdat->virt + PL180_STATUS);
166 err = status & (PL180_STAT_DAT_CRC_FAIL | PL180_STAT_DAT_TIME_OUT | PL180_STAT_RX_OVERRUN);
167 while((!err) && (count >= sizeof(rt_uint32_t)))
168 {
169 if(status & PL180_STAT_RX_FIFO_AVL)
170 {
171 *(tmp) = read32(pdat->virt + PL180_FIFO);
172 tmp++;
173 count -= sizeof(rt_uint32_t);
174 }
175 status = read32(pdat->virt + PL180_STATUS);
176 err = status & (PL180_STAT_DAT_CRC_FAIL | PL180_STAT_DAT_TIME_OUT | PL180_STAT_RX_OVERRUN);
177 }
178
179 err = status & (PL180_STAT_DAT_CRC_FAIL | PL180_STAT_DAT_TIME_OUT | PL180_STAT_DAT_BLK_END | PL180_STAT_RX_OVERRUN);
180 while(!err)
181 {
182 status = read32(pdat->virt + PL180_STATUS);
183 err = status & (PL180_STAT_DAT_CRC_FAIL | PL180_STAT_DAT_TIME_OUT | PL180_STAT_DAT_BLK_END | PL180_STAT_RX_OVERRUN);
184 }
185
186 if(status & PL180_STAT_DAT_TIME_OUT)
187 return -RT_ERROR;
188 else if (status & PL180_STAT_DAT_CRC_FAIL)
189 return -RT_ERROR;
190 else if (status & PL180_STAT_RX_OVERRUN)
191 return -RT_ERROR;
192 write32(pdat->virt + PL180_CLEAR, 0x1DC007FF);
193
194 if(count)
195 return -RT_ERROR;
196
197 return RT_EOK;
198 }
199
write_bytes(struct sdhci_pl180_pdata_t * pdat,rt_uint32_t * buf,rt_uint32_t blkcount,rt_uint32_t blksize)200 static rt_err_t write_bytes(struct sdhci_pl180_pdata_t * pdat, rt_uint32_t * buf, rt_uint32_t blkcount, rt_uint32_t blksize)
201 {
202 rt_uint32_t * tmp = buf;
203 rt_uint32_t count = blkcount * blksize;
204 rt_uint32_t status, err;
205 int i;
206
207 status = read32(pdat->virt + PL180_STATUS);
208 err = status & (PL180_STAT_DAT_CRC_FAIL | PL180_STAT_DAT_TIME_OUT);
209 while(!err && count)
210 {
211 if(status & PL180_STAT_TX_FIFO_HALF)
212 {
213 if(count >= 8 * sizeof(rt_uint32_t))
214 {
215 for(i = 0; i < 8; i++)
216 write32(pdat->virt + PL180_FIFO, *(tmp + i));
217 tmp += 8;
218 count -= 8 * sizeof(rt_uint32_t);
219 }
220 else
221 {
222 while(count >= sizeof(rt_uint32_t))
223 {
224 write32(pdat->virt + PL180_FIFO, *tmp);
225 tmp++;
226 count -= sizeof(rt_uint32_t);
227 }
228 }
229 }
230 status = read32(pdat->virt + PL180_STATUS);
231 err = status & (PL180_STAT_DAT_CRC_FAIL | PL180_STAT_DAT_TIME_OUT);
232 }
233
234 err = status & (PL180_STAT_DAT_CRC_FAIL | PL180_STAT_DAT_TIME_OUT | PL180_STAT_DAT_BLK_END);
235 while(!err)
236 {
237 status = read32(pdat->virt + PL180_STATUS);
238 err = status & (PL180_STAT_DAT_CRC_FAIL | PL180_STAT_DAT_TIME_OUT | PL180_STAT_DAT_BLK_END);
239 }
240
241 if(status & PL180_STAT_DAT_TIME_OUT)
242 return -RT_ERROR;
243 else if (status & PL180_STAT_DAT_CRC_FAIL)
244 return -RT_ERROR;
245 write32(pdat->virt + PL180_CLEAR, 0x1DC007FF);
246
247 if(count)
248 return -RT_ERROR;
249 return RT_EOK;
250 }
251
pl180_transfer_data(struct sdhci_pl180_pdata_t * pdat,struct sdhci_cmd_t * cmd,struct sdhci_data_t * dat)252 static rt_err_t pl180_transfer_data(struct sdhci_pl180_pdata_t * pdat, struct sdhci_cmd_t * cmd, struct sdhci_data_t * dat)
253 {
254 rt_uint32_t dlen = (rt_uint32_t)(dat->blkcnt * dat->blksz);
255 rt_uint32_t blksz_bits = dat->blksz - 1;
256 rt_uint32_t dctrl = (blksz_bits << 4) | (0x1 << 0) | (0x1 << 14);
257 rt_err_t ret = -RT_ERROR;
258
259 write32(pdat->virt + PL180_DATA_TIMER, 0xffff);
260 write32(pdat->virt + PL180_DATA_LENGTH, dlen);
261
262 if(dat->flag & DATA_DIR_READ)
263 {
264 dctrl |= (0x1 << 1);
265 write32(pdat->virt + PL180_DATA_CTRL, dctrl);
266 ret = pl180_transfer_command(pdat, cmd);
267 if (ret < 0) return ret;
268 ret = read_bytes(pdat, (rt_uint32_t *)dat->buf, dat->blkcnt, dat->blksz);
269 }
270 else if(dat->flag & DATA_DIR_WRITE)
271 {
272 ret = pl180_transfer_command(pdat, cmd);
273 if (ret < 0) return ret;
274 write32(pdat->virt + PL180_DATA_CTRL, dctrl);
275 ret = write_bytes(pdat, (rt_uint32_t *)dat->buf, dat->blkcnt, dat->blksz);
276 }
277
278 return ret;
279 }
280
sdhci_pl180_detect(struct sdhci_t * sdhci)281 static rt_err_t sdhci_pl180_detect(struct sdhci_t * sdhci)
282 {
283 return RT_EOK;
284 }
285
sdhci_pl180_setwidth(struct sdhci_t * sdhci,rt_uint32_t width)286 static rt_err_t sdhci_pl180_setwidth(struct sdhci_t * sdhci, rt_uint32_t width)
287 {
288 return RT_EOK;
289 }
290
sdhci_pl180_setclock(struct sdhci_t * sdhci,rt_uint32_t clock)291 static rt_err_t sdhci_pl180_setclock(struct sdhci_t * sdhci, rt_uint32_t clock)
292 {
293 rt_uint32_t temp = 0;
294 struct sdhci_pl180_pdata_t * pdat = (struct sdhci_pl180_pdata_t *)sdhci->priv;
295
296 if(clock)
297 {
298 temp = read32(pdat->virt + PL180_CLOCK) | (0x1 << 8);
299 (void)temp; // skip warning
300 write32(pdat->virt + PL180_CLOCK, 0x100);
301 }
302 else
303 {
304 //write32(pdat->virt + PL180_CLOCK, read32(pdat->virt + PL180_CLOCK) & (~(0x1<<8)));
305 }
306 return RT_EOK;
307 }
308
sdhci_pl180_transfer(struct sdhci_t * sdhci,struct sdhci_cmd_t * cmd,struct sdhci_data_t * dat)309 static rt_err_t sdhci_pl180_transfer(struct sdhci_t * sdhci, struct sdhci_cmd_t * cmd, struct sdhci_data_t * dat)
310 {
311 struct sdhci_pl180_pdata_t * pdat = (struct sdhci_pl180_pdata_t *)sdhci->priv;
312
313 if(!dat)
314 return pl180_transfer_command(pdat, cmd);
315
316 return pl180_transfer_data(pdat, cmd, dat);
317 }
318
mmc_request_send(struct rt_mmcsd_host * host,struct rt_mmcsd_req * req)319 static void mmc_request_send(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
320 {
321 struct sdhci_t *sdhci = (struct sdhci_t *)host->private_data;
322 struct sdhci_cmd_t cmd;
323 struct sdhci_cmd_t stop;
324 struct sdhci_data_t dat;
325
326 rt_memset(&cmd, 0, sizeof(struct sdhci_cmd_t));
327 rt_memset(&stop, 0, sizeof(struct sdhci_cmd_t));
328 rt_memset(&dat, 0, sizeof(struct sdhci_data_t));
329
330 cmd.cmdidx = req->cmd->cmd_code;
331 cmd.cmdarg = req->cmd->arg;
332 if (req->cmd->flags & RESP_MASK)
333 {
334 cmd.resptype = PL180_RSP_PRESENT;
335 if (resp_type(req->cmd) == RESP_R2)
336 cmd.resptype |= PL180_RSP_136BIT;
337 }
338 else
339 cmd.resptype = 0;
340
341 if(req->data)
342 {
343 dat.buf = (rt_uint8_t *)req->data->buf;
344 dat.flag = req->data->flags;
345 dat.blksz = req->data->blksize;
346 dat.blkcnt = req->data->blks;
347
348 req->cmd->err = sdhci_pl180_transfer(sdhci, &cmd, &dat);
349 }
350 else
351 {
352 req->cmd->err = sdhci_pl180_transfer(sdhci, &cmd, RT_NULL);
353 }
354
355 LOG_D("cmdarg:%d", cmd.cmdarg);
356 LOG_D("cmdidx:%d", cmd.cmdidx);
357
358 LOG_D("[0]:0x%08x [1]:0x%08x [2]:0x%08x [3]:0x%08x", cmd.response[0], cmd.response[1], cmd.response[2], cmd.response[3]);
359 req->cmd->resp[3] = cmd.response[3];
360 req->cmd->resp[2] = cmd.response[2];
361 req->cmd->resp[1] = cmd.response[1];
362 req->cmd->resp[0] = cmd.response[0];
363
364 if (req->stop)
365 {
366 stop.cmdidx = req->stop->cmd_code;
367 stop.cmdarg = req->stop->arg;
368 if (req->stop->flags & RESP_MASK)
369 {
370 stop.resptype = PL180_RSP_PRESENT;
371 if (resp_type(req->stop) == RESP_R2)
372 stop.resptype |= PL180_RSP_136BIT;
373 }
374 else
375 stop.resptype = 0;
376
377 req->stop->err = sdhci_pl180_transfer(sdhci, &stop, RT_NULL);
378 }
379
380 mmcsd_req_complete(host);
381 }
382
mmc_set_iocfg(struct rt_mmcsd_host * host,struct rt_mmcsd_io_cfg * io_cfg)383 static void mmc_set_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
384 {
385 struct sdhci_t * sdhci = (struct sdhci_t *)host->private_data;
386
387 sdhci_pl180_setclock(sdhci, io_cfg->clock);
388 sdhci_pl180_setwidth(sdhci, io_cfg->bus_width);
389 LOG_D("clock:%d bus_width:%d", io_cfg->clock, io_cfg->bus_width);
390 }
391
392 static const struct rt_mmcsd_host_ops ops =
393 {
394 mmc_request_send,
395 mmc_set_iocfg,
396 RT_NULL,
397 RT_NULL,
398 };
399
pl180_init(void)400 int pl180_init(void)
401 {
402 rt_uint32_t virt;
403 rt_uint32_t id;
404 struct rt_mmcsd_host * host = RT_NULL;
405 struct sdhci_pl180_pdata_t * pdat = RT_NULL;
406 struct sdhci_t * sdhci = RT_NULL;
407
408 host = mmcsd_alloc_host();
409 if (!host)
410 {
411 LOG_E("alloc host failed");
412 goto err;
413 }
414
415 sdhci = rt_malloc(sizeof(struct sdhci_t));
416 if (!sdhci)
417 {
418 LOG_E("alloc sdhci failed");
419 goto err;
420 }
421 rt_memset(sdhci, 0, sizeof(struct sdhci_t));
422
423 #ifdef RT_USING_SMART
424 virt = (rt_uint32_t)rt_ioremap((void*)MMC_BASE_ADDR, 0x1000);
425 #else
426 virt = MMC_BASE_ADDR;
427 #endif
428
429 id = (((read32((virt + 0xfec)) & 0xff) << 24) |
430 ((read32((virt + 0xfe8)) & 0xff) << 16) |
431 ((read32((virt + 0xfe4)) & 0xff) << 8) |
432 ((read32((virt + 0xfe0)) & 0xff) << 0));
433
434 LOG_D("id=0x%08x", id);
435 if(((id >> 12) & 0xff) != 0x41 || (id & 0xfff) != 0x181)
436 {
437 LOG_E("check id failed");
438 goto err;
439 }
440
441 pdat = (struct sdhci_pl180_pdata_t *)rt_malloc(sizeof(struct sdhci_pl180_pdata_t));
442 RT_ASSERT(pdat != RT_NULL);
443
444 pdat->virt = (uint32_t)virt;
445
446 sdhci->name = "sd0";
447 sdhci->voltages = VDD_33_34;
448 sdhci->width = MMCSD_BUSWIDTH_4;
449 sdhci->clock = 26 * 1000 * 1000;
450 sdhci->removeable = RT_TRUE;
451 sdhci->detect = sdhci_pl180_detect;
452 sdhci->setwidth = sdhci_pl180_setwidth;
453 sdhci->setclock = sdhci_pl180_setclock;
454 sdhci->transfer = sdhci_pl180_transfer;
455 sdhci->priv = pdat;
456 write32(pdat->virt + PL180_POWER, 0xbf);
457
458 host->ops = &ops;
459 host->freq_min = 400000;
460 host->freq_max = 50000000;
461 host->valid_ocr = VDD_32_33 | VDD_33_34;
462 host->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_HIGHSPEED | MMCSD_SUP_SDIO_IRQ | MMCSD_BUSWIDTH_4;
463 host->max_seg_size = 2048;
464 host->max_dma_segs = 10;
465 host->max_blk_size = 512;
466 host->max_blk_count = 4096;
467
468 host->private_data = sdhci;
469
470 mmcsd_change(host);
471
472 return RT_EOK;
473
474 err:
475 if(host) rt_free(host);
476 if(sdhci) rt_free(sdhci);
477
478 return -RT_EIO;
479 }
480 INIT_DEVICE_EXPORT(pl180_init);
481
482 #endif
483