source: rtems-libbsd/rtemsbsd/sys/dev/dw_mmc/dw_mmc.c @ c30fa94

5-freebsd-12
Last change on this file since c30fa94 was c30fa94, checked in by Sebastian Huber <sebastian.huber@…>, on Feb 5, 2018 at 12:57:11 PM

Add device tree support for Altera/Intel? Cyclone V

Close #3290.

  • Property mode set to 100644
File size: 24.2 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*-
4 * Copyright (c) 2006 Bernd Walter.  All rights reserved.
5 * Copyright (c) 2006 M. Warner Losh.  All rights reserved.
6 * Copyright (c) 2010 Greg Ansley.  All rights reserved.
7 * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/bio.h>
34#include <sys/bus.h>
35#include <sys/conf.h>
36#include <sys/endian.h>
37#include <sys/kernel.h>
38#include <sys/kthread.h>
39#include <sys/lock.h>
40#include <sys/malloc.h>
41#include <sys/module.h>
42#include <sys/mutex.h>
43#include <sys/queue.h>
44#include <sys/resource.h>
45#include <sys/rman.h>
46#include <sys/sysctl.h>
47#include <sys/time.h>
48
49#include <machine/bus.h>
50#include <machine/cpu.h>
51#include <machine/cpufunc.h>
52#include <machine/resource.h>
53
54#include <dev/ofw/openfirm.h>
55#include <dev/ofw/ofw_bus.h>
56#include <dev/ofw/ofw_bus_subr.h>
57
58#include <dev/dw_mmc/dw_mmcreg.h>
59
60#include <dev/mmc/bridge.h>
61#include <dev/mmc/mmcreg.h>
62#include <dev/mmc/mmcbrvar.h>
63
64#include <rtems/bsd/local/mmcbr_if.h>
65
66#include <rtems/irq-extension.h>
67
68#include <bsp.h>
69
70#ifdef LIBBSP_ARM_ALTERA_CYCLONE_V_BSP_H
71
72#define DW_MMC_ALTERA_CYCLONE_V
73
74#include <bsp/socal/hps.h>
75#include <bsp/socal/socal.h>
76#include <bsp/socal/alt_sysmgr.h>
77#include <bsp/alt_clock_manager.h>
78#include <bsp/irq.h>
79
80#endif /* DW_MMC_ALTERA_CYCLONE_V */
81
82struct dw_mmc_softc {
83        device_t dev;
84        struct mtx sc_mtx;
85        struct mtx bus_mtx;
86        bus_space_handle_t bushandle;
87        int bus_busy;
88        uint32_t biu_clock;
89        uint32_t ciu_clock;
90        uint32_t card_clock;
91        struct mmc_host host;
92        uint32_t cmdr_flags;
93        volatile struct dw_mmc_des *des;
94        rtems_id task_id;
95};
96
97#define DW_MMC_MAX_DES_COUNT 32
98
99#define DW_MMC_MAX_DMA_TRANSFER_BYTES \
100    (DW_MMC_MAX_DES_COUNT * 2 * DW_MMC_DES1_MAX_BS)
101
102static inline uint32_t
103RD4(struct dw_mmc_softc *sc, bus_size_t off)
104{
105        return (bus_space_read_4(0, sc->bushandle, off));
106}
107
108static inline void
109WR4(struct dw_mmc_softc *sc, bus_size_t off, uint32_t val)
110{
111        bus_space_write_4(0, sc->bushandle, off, val);
112}
113
114/* bus entry points */
115static int dw_mmc_probe(device_t dev);
116static int dw_mmc_attach(device_t dev);
117static int dw_mmc_detach(device_t dev);
118static void dw_mmc_intr(void *);
119
120static void
121DW_MMC_LOCK(struct dw_mmc_softc *sc)
122{
123        mtx_lock(&sc->sc_mtx);
124        sc->task_id = rtems_task_self();
125}
126
127#define DW_MMC_UNLOCK(_sc)              mtx_unlock(&(_sc)->sc_mtx)
128#define DW_MMC_LOCK_INIT(_sc) \
129        mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
130            "dw_mmc", MTX_DEF)
131
132static int
133dw_mmc_poll_reset_completion(struct dw_mmc_softc *sc, uint32_t ctrl_resets)
134{
135        rtems_interval timeout = rtems_clock_tick_later_usec(250000);
136
137        do {
138                if ((RD4(sc, DW_MMC_CTRL) & ctrl_resets) == 0) {
139                        return 0;
140                }
141        } while (rtems_clock_tick_before(timeout));
142
143        return EBUSY;
144}
145
146static uint32_t
147dw_mmc_poll_intsts(struct dw_mmc_softc *sc, uint32_t mask)
148{
149        uint32_t ret_intsts = 0;
150
151        while (1) {
152                uint32_t intsts = RD4(sc, DW_MMC_RINTSTS);
153
154                if ((intsts & DW_MMC_INT_ERROR) != 0) {
155                        WR4(sc, DW_MMC_RINTSTS, intsts);
156                        ret_intsts = intsts;
157                        break;
158                }
159
160                if ((intsts & mask) != 0) {
161                        WR4(sc, DW_MMC_RINTSTS, intsts & mask);
162                        break;
163                }
164        }
165
166        return ret_intsts;
167}
168
169static void
170dw_mmc_wait_for_interrupt(struct dw_mmc_softc *sc, uint32_t intmask)
171{
172        rtems_status_code rs;
173
174        WR4(sc, DW_MMC_INTMASK, intmask);
175
176        rs = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
177        BSD_ASSERT(rs == RTEMS_SUCCESSFUL);
178}
179
180static int
181dw_mmc_init(struct dw_mmc_softc *sc)
182{
183        uint32_t ctrl;
184        uint32_t fifoth;
185        int err;
186
187        err = dw_mmc_poll_reset_completion(sc, DW_MMC_CTRL_RESET);
188        if (err != 0) {
189                return err;
190        }
191
192        sc->card_clock = UINT32_MAX;
193
194        /* Clear interrupt status */
195        WR4(sc, DW_MMC_RINTSTS, 0xffffffff);
196
197        /* Disable all interrupts */
198        WR4(sc, DW_MMC_INTMASK, 0x0);
199
200        /* Enable interrupts in general */
201        ctrl = RD4(sc, DW_MMC_CTRL);
202        ctrl |= DW_MMC_CTRL_INT_ENABLE;
203        WR4(sc, DW_MMC_CTRL, ctrl);
204
205        /* Set data and response timeout to maximum values */
206        WR4(sc, DW_MMC_TMOUT, 0xffffffff);
207
208        /* Set debounce value to 25ms */
209        WR4(sc, DW_MMC_DEBNCE, (sc->biu_clock / 1000) * 25);
210
211        /* Set FIFO watermarks */
212        fifoth = RD4(sc, DW_MMC_FIFOTH);
213        fifoth &= ~(DW_MMC_FIFOTH_RX_WMARK_MSK | DW_MMC_FIFOTH_TX_WMARK_MSK);
214        fifoth |= DW_MMC_FIFOTH_RX_WMARK(511) | DW_MMC_FIFOTH_TX_WMARK(512);
215        WR4(sc, DW_MMC_FIFOTH, fifoth);
216
217        /* Set DMA descriptor */
218        WR4(sc, DW_MMC_DBADDR, (uint32_t) sc->des);
219
220        return 0;
221}
222
223static void
224dw_mmc_fini(struct dw_mmc_softc *sc)
225{
226        WR4(sc, DW_MMC_CTRL, DW_MMC_CTRL_FIFO_RESET | DW_MMC_CTRL_RESET);
227}
228
229static struct ofw_compat_data compat_data[] = {
230        {"altr,socfpga-dw-mshc",        1},
231        {NULL,                          0},
232};
233
234static int
235dw_mmc_probe(device_t dev)
236{
237
238        if (!ofw_bus_status_okay(dev))
239                return (ENXIO);
240
241        if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
242                return (ENXIO);
243
244        device_set_desc(dev, "DesignWare Mobile Storage Host");
245        return (0);
246}
247
248static int
249dw_mmc_platform_init(struct dw_mmc_softc *sc)
250{
251#ifdef DW_MMC_ALTERA_CYCLONE_V
252        size_t des_size = DW_MMC_MAX_DES_COUNT * sizeof(*sc->des);
253        ALT_STATUS_CODE as;
254
255        /* Module base address */
256        sc->bushandle = (bus_space_handle_t) ALT_SDMMC_ADDR;
257
258        /* BIU clock */
259        as = alt_clk_freq_get(ALT_CLK_L4_MP, &sc->biu_clock);
260        BSD_ASSERT(as == ALT_E_SUCCESS);
261
262        /* CIU clock */
263        as = alt_clk_clock_enable(ALT_CLK_SDMMC);
264        BSD_ASSERT(as == ALT_E_SUCCESS);
265        as = alt_clk_freq_get(ALT_CLK_SDMMC, &sc->ciu_clock);
266        BSD_ASSERT(as == ALT_E_SUCCESS);
267        sc->ciu_clock /= 4;
268
269        sc->des = rtems_cache_coherent_allocate(des_size, 0, 0);
270        if (sc->des == NULL) {
271                return (ENOMEM);
272        }
273        memset(__DEVOLATILE(void *, sc->des), 0, des_size);
274#endif
275
276        return (0);
277}
278
279static void
280dw_mmc_platform_install_intr(struct dw_mmc_softc *sc)
281{
282        rtems_vector_number irq =
283#ifdef DW_MMC_ALTERA_CYCLONE_V
284            ALT_INT_INTERRUPT_SDMMC_IRQ;
285#else
286            UINT32_MAX;
287#endif
288        rtems_status_code rs;
289
290        /*
291         * Activate the interrupt
292         */
293        rs = rtems_interrupt_handler_install(irq, "DW MMC",
294            RTEMS_INTERRUPT_SHARED, dw_mmc_intr, sc);
295        BSD_ASSERT(rs == RTEMS_SUCCESSFUL);
296}
297
298static bool
299dw_mmc_platform_set_clock(struct dw_mmc_softc *sc, uint32_t card_clock)
300{
301        bool use_hold_reg;
302
303#ifdef DW_MMC_ALTERA_CYCLONE_V
304        uint32_t drvsel;
305        uint32_t smplsel;
306        uint32_t ctl;
307        ALT_STATUS_CODE as;
308
309        /* FIXME: Values taken from U-Boot, not clear how they are determined */
310        if (card_clock > 25000000) {
311                drvsel = 3;
312                smplsel = 7;
313        } else {
314                drvsel = 3;
315                smplsel = 0;
316        }
317
318        use_hold_reg = drvsel != 0;
319
320        as = alt_clk_clock_disable(ALT_CLK_SDMMC);
321        BSD_ASSERT(as == ALT_E_SUCCESS);
322
323        ctl = alt_read_word(ALT_SYSMGR_SDMMC_CTL_ADDR);
324        ctl &= ALT_SYSMGR_SDMMC_CTL_DRVSEL_CLR_MSK
325            & ALT_SYSMGR_SDMMC_CTL_SMPLSEL_CLR_MSK;
326        ctl |= ALT_SYSMGR_SDMMC_CTL_DRVSEL_SET(drvsel)
327            | ALT_SYSMGR_SDMMC_CTL_SMPLSEL_SET(smplsel);
328        alt_write_word(ALT_SYSMGR_SDMMC_CTL_ADDR, ctl);
329
330        as = alt_clk_clock_enable(ALT_CLK_SDMMC);
331        BSD_ASSERT(as == ALT_E_SUCCESS);
332#else
333        use_hold_reg = false;
334#endif
335
336        return use_hold_reg;
337}
338
339static void
340dw_mmc_platform_fini(struct dw_mmc_softc *sc)
341{
342#ifdef DW_MMC_ALTERA_CYCLONE_V
343        rtems_cache_coherent_free(__DEVOLATILE(void *, sc->des));
344#endif
345}
346
347static int
348dw_mmc_attach(device_t dev)
349{
350        struct dw_mmc_softc *sc = device_get_softc(dev);
351        int err;
352
353        sc->dev = dev;
354
355        err = dw_mmc_platform_init(sc);
356        if (err != 0) {
357                return (err);
358        }
359
360        dw_mmc_fini(sc);
361        err = dw_mmc_init(sc);
362        if (err != 0) {
363                dw_mmc_platform_fini(sc);
364
365                return (err);
366        }
367
368        DW_MMC_LOCK_INIT(sc);
369
370        dw_mmc_platform_install_intr(sc);
371
372        sc->host.f_min = 400000;
373        sc->host.f_max = (int) sc->ciu_clock;
374        if (sc->host.f_max > 50000000)
375                sc->host.f_max = 50000000;      /* Limit to 50MHz */
376
377        sc->host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340;
378
379        /* FIXME: MMC_CAP_8_BIT_DATA for eSDIO? */
380        sc->host.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_HSPEED;
381
382        device_add_child(dev, "mmc", 0);
383        device_set_ivars(dev, &sc->host);
384        err = bus_generic_attach(dev);
385
386        return (err);
387}
388
389static int
390dw_mmc_detach(device_t dev)
391{
392        struct dw_mmc_softc *sc = device_get_softc(dev);
393
394        dw_mmc_fini(sc);
395
396        /* FIXME: Implement */
397        BSD_ASSERT(0);
398
399        return (EBUSY);
400}
401
402static int
403dw_mmc_cmd_wait(struct dw_mmc_softc *sc)
404{
405        rtems_interval timeout = rtems_clock_tick_later_usec(250000);
406
407        do {
408                if ((RD4(sc, DW_MMC_CMD) & DW_MMC_CMD_START) == 0) {
409                        return 0;
410                }
411        } while (rtems_clock_tick_before(timeout));
412
413        return EBUSY;
414}
415
416static void
417dw_mmc_cmd_start(struct dw_mmc_softc *sc, uint32_t cmd, uint32_t cmdarg)
418{
419        WR4(sc, DW_MMC_CMDARG, cmdarg);
420        cmd |= DW_MMC_CMD_START;
421        WR4(sc, DW_MMC_CMD, cmd);
422}
423
424static int
425dw_mmc_cmd_update_clock(struct dw_mmc_softc *sc)
426{
427        dw_mmc_cmd_start(sc,
428            DW_MMC_CMD_UPDATE_CLK | DW_MMC_CMD_PRV_DATA_WAIT, 0);
429
430        return dw_mmc_cmd_wait(sc);
431}
432
433static int
434dw_mmc_set_clock(struct dw_mmc_softc *sc, uint32_t card_clock)
435{
436        uint32_t clkdiv;
437        int err;
438
439        if (sc->card_clock == card_clock) {
440                return 0;
441        }
442
443        sc->card_clock = card_clock;
444
445        /* Disable card clock */
446        WR4(sc, DW_MMC_CLKENA, 0);
447
448        err = dw_mmc_cmd_update_clock(sc);
449        if (err != 0) {
450                return err;
451        }
452
453        if (card_clock == 0) {
454                return 0;
455        }
456
457        if (dw_mmc_platform_set_clock(sc, card_clock)) {
458                sc->cmdr_flags |= DW_MMC_CMD_USE_HOLD_REG;
459        } else {
460                sc->cmdr_flags &= ~DW_MMC_CMD_USE_HOLD_REG;
461        }
462
463        if (card_clock == sc->ciu_clock) {
464                clkdiv = 0;
465        } else {
466                uint32_t s = 2 * card_clock;
467
468                clkdiv = (sc->ciu_clock + s - 1) / s;
469        }
470
471        WR4(sc, DW_MMC_CLKDIV, clkdiv);
472        WR4(sc, DW_MMC_CLKSRC, 0);
473
474        err = dw_mmc_cmd_update_clock(sc);
475        if (err != 0) {
476                return err;
477        }
478
479        /* Enable card clock */
480        WR4(sc, DW_MMC_CLKENA, DW_MMC_CLKEN_ENABLE);
481
482        return dw_mmc_cmd_update_clock(sc);
483}
484
485static int
486dw_mmc_update_ios(device_t brdev, device_t reqdev)
487{
488        struct dw_mmc_softc *sc = device_get_softc(brdev);
489        struct mmc_host *host;
490        struct mmc_ios *ios;
491        uint32_t ctype;
492        int err;
493
494        DW_MMC_LOCK(sc);
495
496        host = &sc->host;
497        ios = &host->ios;
498
499        err = dw_mmc_set_clock(sc, (uint32_t) ios->clock);
500        if (err != 0) {
501                return (err);
502        }
503
504        if (ios->power_mode == power_off) {
505                WR4(sc, DW_MMC_PWREN, 0);
506        } else {
507                sc->cmdr_flags |= DW_MMC_CMD_SEND_INIT;
508                WR4(sc, DW_MMC_PWREN, DW_MMC_PWREN_ENABLE);
509        }
510
511        switch (ios->bus_width) {
512        default:
513                BSD_ASSERT(ios->bus_width == bus_width_1);
514                ctype = DW_MMC_CTYPE_1BIT;
515                break;
516        case bus_width_4:
517                ctype = DW_MMC_CTYPE_4BIT;
518                break;
519        case bus_width_8:
520                ctype = DW_MMC_CTYPE_8BIT;
521                break;
522        }
523
524        WR4(sc, DW_MMC_CTYPE, ctype);
525
526        DW_MMC_UNLOCK(sc);
527
528        return (0);
529}
530
531static int
532dw_mmc_fifo_and_dma_reset(struct dw_mmc_softc *sc)
533{
534        uint32_t ctrl_resets = DW_MMC_CTRL_FIFO_RESET | DW_MMC_CTRL_DMA_RESET;
535        uint32_t ctrl = RD4(sc, DW_MMC_CTRL);
536
537        ctrl |= ctrl_resets;
538
539        WR4(sc, DW_MMC_CTRL, ctrl);
540
541        return dw_mmc_poll_reset_completion(sc, ctrl_resets);
542}
543
544static int
545dw_mmc_cmd_read_response(struct dw_mmc_softc *sc, struct mmc_command *cmd,
546    uint32_t intsts)
547{
548        if ((intsts & DW_MMC_INT_RTO) != 0) {
549                return MMC_ERR_TIMEOUT;
550        } else if ((intsts & DW_MMC_INT_RCRC) != 0
551            && (cmd->flags & MMC_RSP_CRC) != 0) {
552                return MMC_ERR_BADCRC;
553        } else if ((intsts & DW_MMC_INT_RE) != 0) {
554                return MMC_ERR_FAILED;
555        }
556
557        if ((cmd->flags & MMC_RSP_PRESENT) != 0) {
558                uint32_t *resp = &cmd->resp[0];
559
560                if ((cmd->flags & MMC_RSP_136) != 0) {
561                        resp[3] = RD4(sc, DW_MMC_RESP0);
562                        resp[2] = RD4(sc, DW_MMC_RESP1);
563                        resp[1] = RD4(sc, DW_MMC_RESP2);
564                        resp[0] = RD4(sc, DW_MMC_RESP3);
565                } else {
566                        resp[0] = RD4(sc, DW_MMC_RESP0);
567                }
568        }
569
570        return MMC_ERR_NONE;
571}
572
573static uint32_t
574dw_mmc_cmd_data_read(struct dw_mmc_softc *sc, struct mmc_data *data,
575    uint32_t *data32, size_t count_bytes)
576{
577        uint32_t intsts = 0;
578
579        while (count_bytes > 0) {
580                uint32_t status;
581                size_t available_words;
582                size_t dangling_bytes = 0;
583                size_t i;
584
585                intsts = dw_mmc_poll_intsts(sc, DW_MMC_INT_RXDR
586                    | DW_MMC_INT_DTO | DW_MMC_INT_HTO);
587
588                if (intsts != 0) {
589                        return intsts;
590                }
591
592                status = RD4(sc, DW_MMC_STATUS);
593                available_words = DW_MMC_STATUS_GET_FIFO_CNT(status);
594
595                if (available_words * DW_MMC_FIFO_WIDTH > count_bytes) {
596                        dangling_bytes = count_bytes % DW_MMC_FIFO_WIDTH;
597                        --available_words;
598                }
599
600                for (i = 0; i < available_words; i++) {
601                        data32[i] = RD4(sc, DW_MMC_DATA);
602                }
603
604                data32 += available_words;
605                count_bytes -= available_words * DW_MMC_FIFO_WIDTH;
606
607                if (dangling_bytes != 0) {
608                        uint32_t tmp = RD4(sc, DW_MMC_DATA);
609
610                        memcpy(data32, &tmp, dangling_bytes);
611                        BSD_ASSERT(count_bytes == dangling_bytes);
612                        count_bytes = 0;
613                }
614        }
615
616        if ((data->flags & MMC_DATA_MULTI) != 0) {
617                intsts = dw_mmc_poll_intsts(sc, DW_MMC_INT_ACD);
618        }
619
620        return intsts;
621}
622
623static uint32_t
624dw_mmc_cmd_data_write(struct dw_mmc_softc *sc, struct mmc_data *data,
625    uint32_t *data32, size_t count_bytes)
626{
627        uint32_t intsts;
628
629        while (count_bytes > 0) {
630                uint32_t status;
631                size_t pending_words = count_bytes / DW_MMC_FIFO_WIDTH;
632                size_t free_words;
633                size_t dangling_bytes;
634                size_t words_to_write;
635                size_t i;
636
637                intsts = dw_mmc_poll_intsts(sc, DW_MMC_INT_TXDR
638                    | DW_MMC_INT_HTO);
639
640                if (intsts != 0) {
641                        return intsts;
642                }
643
644                status = RD4(sc, DW_MMC_STATUS);
645                free_words = DW_MMC_FIFO_DEPTH - DW_MMC_STATUS_GET_FIFO_CNT(status);
646
647                if (pending_words >= free_words) {
648                        words_to_write = free_words;
649                        dangling_bytes = 0;
650                } else {
651                        words_to_write = pending_words;
652                        dangling_bytes = count_bytes % DW_MMC_FIFO_WIDTH;
653                }
654
655                for (i = 0; i < words_to_write; i++) {
656                        WR4(sc, DW_MMC_DATA, data32[i]);
657                }
658
659                data32 += words_to_write;
660                count_bytes -= words_to_write * DW_MMC_FIFO_WIDTH;
661
662                if (dangling_bytes != 0) {
663                        uint32_t tmp = 0;
664
665                        memcpy(&tmp, &data32[0], dangling_bytes);
666                        WR4(sc, DW_MMC_DATA, tmp);
667                        BSD_ASSERT(count_bytes == dangling_bytes);
668                        count_bytes = 0;
669                }
670        }
671
672        intsts = dw_mmc_poll_intsts(sc, DW_MMC_INT_DTO);
673
674        if ((data->flags & MMC_DATA_MULTI) != 0 && intsts == 0) {
675                dw_mmc_poll_intsts(sc, DW_MMC_INT_ACD);
676        }
677
678        return intsts;
679}
680
681static uint32_t
682dw_mmc_cmd_data_transfer(struct dw_mmc_softc *sc, struct mmc_data *data,
683    size_t done_bytes, bool use_dma)
684{
685        uint32_t *data32 = (uint32_t *) ((char *) data->data + done_bytes);
686        bool do_write = (data->flags & MMC_DATA_WRITE) != 0;
687        uint32_t intsts;
688
689        if (use_dma) {
690                dw_mmc_wait_for_interrupt(sc, DW_MMC_INT_DTO);
691                intsts = dw_mmc_poll_intsts(sc, DW_MMC_INT_DTO);
692
693                if ((data->flags & MMC_DATA_MULTI) != 0 && intsts == 0) {
694                        dw_mmc_poll_intsts(sc, DW_MMC_INT_ACD);
695                }
696
697                if (!do_write) {
698                        rtems_cache_invalidate_multiple_data_lines(data->data,
699                            data->len);
700                }
701        } else {
702                size_t count_bytes = data->len - done_bytes;
703
704                if (do_write) {
705                        intsts = dw_mmc_cmd_data_write(sc, data, data32, count_bytes);
706                } else {
707                        intsts = dw_mmc_cmd_data_read(sc, data, data32, count_bytes);
708                }
709        }
710
711        return intsts;
712}
713
714static int
715dw_mmc_cmd_data_finish(struct dw_mmc_softc *sc, uint32_t intsts)
716{
717        int mmc_err = MMC_ERR_NONE;
718
719        if ((intsts & DW_MMC_INT_ERROR) != 0) {
720                if ((intsts & DW_MMC_INT_DCRC) != 0) {
721                        mmc_err = MMC_ERR_BADCRC;
722                } else if ((intsts & DW_MMC_INT_EBE) != 0) {
723                        mmc_err = MMC_ERR_FAILED;
724                } else if ((intsts & DW_MMC_INT_DRTO) != 0) {
725                        mmc_err = MMC_ERR_TIMEOUT;
726                } else {
727                        mmc_err = MMC_ERR_FAILED;
728                }
729        }
730
731        return mmc_err;
732}
733
734static int
735dw_mmc_cmd_done(struct dw_mmc_softc *sc, struct mmc_command *cmd,
736    struct mmc_data *data, size_t done_bytes, bool use_dma)
737{
738        uint32_t intsts;
739        int mmc_err;
740
741        dw_mmc_wait_for_interrupt(sc, DW_MMC_INT_CMD_DONE);
742
743        intsts = RD4(sc, DW_MMC_RINTSTS);
744        WR4(sc, DW_MMC_RINTSTS,
745            intsts & (DW_MMC_INT_ERROR | DW_MMC_INT_CMD_DONE));
746
747        mmc_err = dw_mmc_cmd_read_response(sc, cmd, intsts);
748        if (mmc_err != 0) {
749                return mmc_err;
750        }
751
752        if (data != NULL) {
753                intsts = dw_mmc_cmd_data_transfer(sc, data, done_bytes, use_dma);
754                mmc_err = dw_mmc_cmd_data_finish(sc, intsts);
755        }
756
757        return mmc_err;
758}
759
760static size_t
761dw_mmc_fill_fifo(struct dw_mmc_softc *sc, struct mmc_data *data)
762{
763        uint32_t *data32 = data->data;
764        size_t count_bytes = data->len;
765        size_t count_words = 0;
766        size_t dangling_bytes;
767        size_t i;
768
769        if (count_bytes >= DW_MMC_FIFO_DEPTH * DW_MMC_FIFO_WIDTH) {
770                count_words = DW_MMC_FIFO_DEPTH;
771                dangling_bytes = 0;
772        } else {
773                count_words = count_bytes / DW_MMC_FIFO_WIDTH;
774                dangling_bytes = count_bytes % DW_MMC_FIFO_WIDTH;
775        }
776
777        for (i = 0; i < count_words; ++i) {
778                WR4(sc, DW_MMC_DATA, data32[i]);
779        }
780
781        if (dangling_bytes) {
782                uint32_t tmp = 0;
783
784                memcpy(&tmp, &data32[i], dangling_bytes);
785                WR4(sc, DW_MMC_DATA, tmp);
786        }
787
788        return count_words * DW_MMC_FIFO_WIDTH + dangling_bytes;
789}
790
791static bool dw_mmc_dma_can_use(const struct mmc_data *data)
792{
793        uintptr_t cache_line = 32;
794
795        return data->len >= cache_line
796            && ((data->len | (uintptr_t) data->data) & (cache_line - 1)) == 0;
797}
798
799static void
800dw_mmc_dma_setup(struct dw_mmc_softc *sc, struct mmc_data *data)
801{
802        volatile struct dw_mmc_des *des = sc->des;
803        uint32_t buf = (uint32_t) data->data;
804        size_t count_bytes = data->len;
805        uint32_t fs = DW_MMC_DES0_FS;
806        size_t s = 2 * DW_MMC_DES1_MAX_BS;
807        size_t n = (count_bytes + s - 1) / s;
808        size_t m = count_bytes % s;
809        size_t i;
810
811        for (i = 0; i < n - 1; ++i) {
812                des[i].des1 = DW_MMC_DES1_BS1(DW_MMC_DES1_MAX_BS)
813                    | DW_MMC_DES1_BS2(DW_MMC_DES1_MAX_BS);
814                des[i].des2 = buf;
815                buf += DW_MMC_DES1_MAX_BS;
816                des[i].des3 = buf;
817                buf += DW_MMC_DES1_MAX_BS;
818                des[i].des0 = DW_MMC_DES0_OWN | fs;
819                fs = 0;
820        }
821
822        if (m > DW_MMC_DES1_MAX_BS) {
823                des[i].des1 = DW_MMC_DES1_BS1(DW_MMC_DES1_MAX_BS)
824                    | DW_MMC_DES1_BS2(m - DW_MMC_DES1_MAX_BS);
825                des[i].des2 = buf;
826                buf += DW_MMC_DES1_MAX_BS;
827                des[i].des3 = buf;
828        } else {
829                des[i].des1 = DW_MMC_DES1_BS1(m);
830                des[i].des2 = buf;
831                des[i].des3 = 0;
832        }
833
834        des[i].des0 = DW_MMC_DES0_OWN | DW_MMC_DES0_ER | fs | DW_MMC_DES0_LD;
835
836#ifdef __arm__
837        _ARM_Data_synchronization_barrier();
838#else
839        /* TODO */
840#endif
841}
842
843
844static void
845dw_mmc_cmd_do(struct dw_mmc_softc *sc, struct mmc_request *req,
846    struct mmc_command *cmd)
847{
848        size_t done_bytes = 0;
849        bool use_dma = false;
850        struct mmc_data *data;
851        uint32_t cmdr;
852
853        data = cmd->data;
854        cmdr = cmd->opcode;
855
856        if (cmd->opcode == MMC_STOP_TRANSMISSION) {
857                cmdr |= DW_MMC_CMD_SEND_STOP;
858        } else {
859                cmdr |= DW_MMC_CMD_PRV_DATA_WAIT;
860        }
861
862        cmdr |= sc->cmdr_flags;
863        sc->cmdr_flags &= ~DW_MMC_CMD_SEND_INIT;
864
865        if (MMC_RSP(cmd->flags) != MMC_RSP_NONE) {
866                cmdr |= DW_MMC_CMD_RESP_EXP;
867
868                if ((cmd->flags & MMC_RSP_136) != 0) {
869                        cmdr |= DW_MMC_CMD_RESP_LONG;
870                }
871        }
872
873        if ((cmd->flags & MMC_RSP_CRC) != 0) {
874                cmdr |= DW_MMC_CMD_RESP_CRC;
875        }
876
877        if (data != NULL) {
878                size_t count_bytes = data->len;
879                uint32_t ctrl;
880                int mmc_err;
881
882                cmdr |= DW_MMC_CMD_DATA_EXP;
883
884                if ((data->flags & MMC_DATA_MULTI) != 0) {
885                        cmdr |= DW_MMC_CMD_SEND_STOP;
886                }
887
888                mmc_err = dw_mmc_fifo_and_dma_reset(sc);
889                if (mmc_err != 0) {
890                        cmd->error = mmc_err;
891                        return;
892                }
893
894                use_dma = dw_mmc_dma_can_use(data);
895
896                ctrl = RD4(sc, DW_MMC_CTRL);
897
898                if (use_dma) {
899                        ctrl |= DW_MMC_CTRL_DMA_ENABLE;
900                } else {
901                        ctrl &= ~DW_MMC_CTRL_DMA_ENABLE;
902                }
903
904                WR4(sc, DW_MMC_CTRL, ctrl);
905                WR4(sc, DW_MMC_BLKSIZ, MIN(count_bytes, MMC_SECTOR_SIZE));
906                WR4(sc, DW_MMC_BYTCNT, count_bytes);
907
908                if ((data->flags & MMC_DATA_WRITE) != 0) {
909                        cmdr |= DW_MMC_CMD_DATA_WR;
910
911                        if (use_dma) {
912                                rtems_cache_flush_multiple_data_lines(data->data,
913                                    count_bytes);
914                        } else {
915                                done_bytes = dw_mmc_fill_fifo(sc, data);
916                        }
917                } else if (use_dma) {
918                        rtems_cache_invalidate_multiple_data_lines(data->data,
919                            count_bytes);
920                }
921
922                if (use_dma) {
923                        if (count_bytes > DW_MMC_MAX_DMA_TRANSFER_BYTES) {
924                                cmd->error = MMC_ERR_INVALID;
925                                return;
926                        }
927
928                        dw_mmc_dma_setup(sc, data);
929                }
930        }
931
932        dw_mmc_cmd_start(sc, cmdr, cmd->arg);
933
934        if (use_dma) {
935                WR4(sc, DW_MMC_PLDMND, 0);
936        }
937
938        cmd->error = dw_mmc_cmd_done(sc, cmd, data, done_bytes, use_dma);
939}
940
941static int
942dw_mmc_request(device_t brdev, device_t reqdev, struct mmc_request *req)
943{
944        struct dw_mmc_softc *sc = device_get_softc(brdev);
945
946        DW_MMC_LOCK(sc);
947        dw_mmc_cmd_do(sc, req, req->cmd);
948        DW_MMC_UNLOCK(sc);
949
950        (*req->done)(req);
951
952        return (0);
953}
954
955static int
956dw_mmc_get_ro(device_t brdev, device_t reqdev)
957{
958        return (0);
959}
960
961static int
962dw_mmc_acquire_host(device_t brdev, device_t reqdev)
963{
964        struct dw_mmc_softc *sc = device_get_softc(brdev);
965
966        DW_MMC_LOCK(sc);
967        while (sc->bus_busy)
968                msleep(sc, &sc->sc_mtx, PZERO, "dw_mmc: acquire host", 0);
969        sc->bus_busy = 1;
970        DW_MMC_UNLOCK(sc);
971        return (0);
972}
973
974static int
975dw_mmc_release_host(device_t brdev, device_t reqdev)
976{
977        struct dw_mmc_softc *sc = device_get_softc(brdev);
978
979        DW_MMC_LOCK(sc);
980        sc->bus_busy = 0;
981        wakeup(sc);
982        DW_MMC_UNLOCK(sc);
983        return (0);
984}
985
986static void
987dw_mmc_intr(void *arg)
988{
989        struct dw_mmc_softc *sc = (struct dw_mmc_softc *) arg;
990        rtems_status_code rs;
991
992        WR4(sc, DW_MMC_INTMASK, 0);
993
994        rs = rtems_event_transient_send(sc->task_id);
995        BSD_ASSERT(rs == RTEMS_SUCCESSFUL);
996}
997
998static int
999dw_mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
1000{
1001        struct dw_mmc_softc *sc = device_get_softc(bus);
1002
1003        switch (which) {
1004        default:
1005                return (EINVAL);
1006        case MMCBR_IVAR_BUS_MODE:
1007                *(int *)result = sc->host.ios.bus_mode;
1008                break;
1009        case MMCBR_IVAR_BUS_WIDTH:
1010                *(int *)result = sc->host.ios.bus_width;
1011                break;
1012        case MMCBR_IVAR_CHIP_SELECT:
1013                *(int *)result = sc->host.ios.chip_select;
1014                break;
1015        case MMCBR_IVAR_CLOCK:
1016                *(int *)result = sc->host.ios.clock;
1017                break;
1018        case MMCBR_IVAR_F_MIN:
1019                *(int *)result = sc->host.f_min;
1020                break;
1021        case MMCBR_IVAR_F_MAX:
1022                *(int *)result = sc->host.f_max;
1023                break;
1024        case MMCBR_IVAR_HOST_OCR:
1025                *(int *)result = sc->host.host_ocr;
1026                break;
1027        case MMCBR_IVAR_MODE:
1028                *(int *)result = sc->host.mode;
1029                break;
1030        case MMCBR_IVAR_OCR:
1031                *(int *)result = sc->host.ocr;
1032                break;
1033        case MMCBR_IVAR_POWER_MODE:
1034                *(int *)result = sc->host.ios.power_mode;
1035                break;
1036        case MMCBR_IVAR_VDD:
1037                *(int *)result = sc->host.ios.vdd;
1038                break;
1039        case MMCBR_IVAR_CAPS:
1040                *(int *)result = sc->host.caps;
1041                break;
1042        case MMCBR_IVAR_MAX_DATA:
1043                *(int *)result = 1;
1044                break;
1045        }
1046        return (0);
1047}
1048
1049static int
1050dw_mmc_write_ivar(device_t bus, device_t child, int which, uintptr_t value)
1051{
1052        struct dw_mmc_softc *sc = device_get_softc(bus);
1053
1054        switch (which) {
1055        default:
1056                return (EINVAL);
1057        case MMCBR_IVAR_BUS_MODE:
1058                sc->host.ios.bus_mode = value;
1059                break;
1060        case MMCBR_IVAR_BUS_WIDTH:
1061                sc->host.ios.bus_width = value;
1062                break;
1063        case MMCBR_IVAR_CHIP_SELECT:
1064                sc->host.ios.chip_select = value;
1065                break;
1066        case MMCBR_IVAR_CLOCK:
1067                sc->host.ios.clock = value;
1068                break;
1069        case MMCBR_IVAR_MODE:
1070                sc->host.mode = value;
1071                break;
1072        case MMCBR_IVAR_OCR:
1073                sc->host.ocr = value;
1074                break;
1075        case MMCBR_IVAR_POWER_MODE:
1076                sc->host.ios.power_mode = value;
1077                break;
1078        case MMCBR_IVAR_VDD:
1079                sc->host.ios.vdd = value;
1080                break;
1081        /* These are read-only */
1082        case MMCBR_IVAR_CAPS:
1083        case MMCBR_IVAR_HOST_OCR:
1084        case MMCBR_IVAR_F_MIN:
1085        case MMCBR_IVAR_F_MAX:
1086        case MMCBR_IVAR_MAX_DATA:
1087                return (EINVAL);
1088        }
1089        return (0);
1090}
1091
1092static device_method_t dw_mmc_methods[] = {
1093        /* device_if */
1094        DEVMETHOD(device_probe, dw_mmc_probe),
1095        DEVMETHOD(device_attach, dw_mmc_attach),
1096        DEVMETHOD(device_detach, dw_mmc_detach),
1097
1098        /* Bus interface */
1099        DEVMETHOD(bus_read_ivar, dw_mmc_read_ivar),
1100        DEVMETHOD(bus_write_ivar, dw_mmc_write_ivar),
1101
1102        /* mmcbr_if */
1103        DEVMETHOD(mmcbr_update_ios, dw_mmc_update_ios),
1104        DEVMETHOD(mmcbr_request, dw_mmc_request),
1105        DEVMETHOD(mmcbr_get_ro, dw_mmc_get_ro),
1106        DEVMETHOD(mmcbr_acquire_host, dw_mmc_acquire_host),
1107        DEVMETHOD(mmcbr_release_host, dw_mmc_release_host),
1108
1109        DEVMETHOD_END
1110};
1111
1112static driver_t dw_mmc_driver = {
1113        "dw_mmc",
1114        dw_mmc_methods,
1115        sizeof(struct dw_mmc_softc)
1116};
1117
1118static devclass_t dw_mmc_devclass;
1119
1120DRIVER_MODULE(dw_mmc, simplebus, dw_mmc_driver, dw_mmc_devclass, NULL, NULL);
1121DRIVER_MODULE(mmc, dw_mmc, mmc_driver, mmc_devclass, NULL, NULL);
1122MODULE_DEPEND(dw_mmc, mmc, 1, 1, 1);
Note: See TracBrowser for help on using the repository browser.