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