Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/ic Add support for SDIO interrupts.



details:   https://anonhg.NetBSD.org/src/rev/dbbee3b4704b
branches:  trunk
changeset: 464412:dbbee3b4704b
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sat Oct 05 12:27:14 2019 +0000

description:
Add support for SDIO interrupts.

diffstat:

 sys/dev/ic/dwc_mmc.c     |  459 ++++++++++++++++++++++++----------------------
 sys/dev/ic/dwc_mmc_var.h |   15 +-
 2 files changed, 250 insertions(+), 224 deletions(-)

diffs (truncated from 710 to 300 lines):

diff -r 63d46da8b869 -r dbbee3b4704b sys/dev/ic/dwc_mmc.c
--- a/sys/dev/ic/dwc_mmc.c      Sat Oct 05 12:09:01 2019 +0000
+++ b/sys/dev/ic/dwc_mmc.c      Sat Oct 05 12:27:14 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_mmc.c,v 1.17 2019/07/28 10:30:44 jmcneill Exp $ */
+/* $NetBSD: dwc_mmc.c,v 1.18 2019/10/05 12:27:14 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2014-2017 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc_mmc.c,v 1.17 2019/07/28 10:30:44 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc_mmc.c,v 1.18 2019/10/05 12:27:14 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -79,16 +79,40 @@
 #define MMC_READ(sc, reg) \
        bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
 
-static void
-dwc_mmc_dump_regs(struct dwc_mmc_softc *sc)
+static int
+dwc_mmc_dmabounce_setup(struct dwc_mmc_softc *sc)
 {
-       device_printf(sc->sc_dev, "device registers:\n");
-       for (u_int off = 0x00; off < 0x100; off += 16) {
-               device_printf(sc->sc_dev, "xxxxxx%02x: %08x %08x %08x %08x\n",
-                   off,
-                   MMC_READ(sc, off + 0), MMC_READ(sc, off + 4),
-                   MMC_READ(sc, off + 8), MMC_READ(sc, off + 12));
-       }
+       bus_dma_segment_t ds[1];
+       int error, rseg;
+
+       sc->sc_dmabounce_buflen = dwc_mmc_host_maxblklen(sc);
+       error = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dmabounce_buflen, 0,
+           sc->sc_dmabounce_buflen, ds, 1, &rseg, BUS_DMA_WAITOK);
+       if (error)
+               return error;
+       error = bus_dmamem_map(sc->sc_dmat, ds, 1, sc->sc_dmabounce_buflen,
+           &sc->sc_dmabounce_buf, BUS_DMA_WAITOK);
+       if (error)
+               goto free;
+       error = bus_dmamap_create(sc->sc_dmat, sc->sc_dmabounce_buflen, 1,
+           sc->sc_dmabounce_buflen, 0, BUS_DMA_WAITOK, &sc->sc_dmabounce_map);
+       if (error)
+               goto unmap;
+       error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmabounce_map,
+           sc->sc_dmabounce_buf, sc->sc_dmabounce_buflen, NULL,
+           BUS_DMA_WAITOK);
+       if (error)
+               goto destroy;
+       return 0;
+
+destroy:
+       bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmabounce_map);
+unmap:
+       bus_dmamem_unmap(sc->sc_dmat, sc->sc_dmabounce_buf,
+           sc->sc_dmabounce_buflen);
+free:
+       bus_dmamem_free(sc->sc_dmat, ds, rseg);
+       return error;
 }
 
 static int
@@ -145,55 +169,20 @@
        saa.saa_sch = sc;
        saa.saa_clkmin = 400;
        saa.saa_clkmax = sc->sc_clock_freq / 1000;
+       saa.saa_dmat = sc->sc_dmat;
        saa.saa_caps = SMC_CAPS_4BIT_MODE|
                       SMC_CAPS_8BIT_MODE|
                       SMC_CAPS_SD_HIGHSPEED|
                       SMC_CAPS_MMC_HIGHSPEED|
-                      SMC_CAPS_AUTO_STOP;
-       if (ISSET(sc->sc_flags, DWC_MMC_F_DMA)) {
-               saa.saa_dmat = sc->sc_dmat;
-               saa.saa_caps |= SMC_CAPS_DMA |
-                               SMC_CAPS_MULTI_SEG_DMA;
-       }
+                      SMC_CAPS_AUTO_STOP |
+                      SMC_CAPS_DMA |
+                      SMC_CAPS_MULTI_SEG_DMA;
        if (sc->sc_card_detect)
                saa.saa_caps |= SMC_CAPS_POLL_CARD_DET;
 
        sc->sc_sdmmc_dev = config_found(self, &saa, NULL);
 }
 
-static int
-dwc_mmc_wait_rint(struct dwc_mmc_softc *sc, uint32_t mask, int timeout)
-{
-       const bool use_dma = ISSET(sc->sc_flags, DWC_MMC_F_DMA);
-       int retry, error;
-
-       KASSERT(mutex_owned(&sc->sc_intr_lock));
-
-       if (sc->sc_intr_rint & mask)
-               return 0;
-
-       retry = timeout / hz;
-
-       while (retry > 0) {
-               if (use_dma) {
-                       error = cv_timedwait(&sc->sc_intr_cv,
-                           &sc->sc_intr_lock, hz);
-                       if (error && error != EWOULDBLOCK)
-                               return error;
-                       if (sc->sc_intr_rint & mask)
-                               return 0;
-               } else {
-                       sc->sc_intr_rint |= MMC_READ(sc, DWC_MMC_RINT);
-                       if (sc->sc_intr_rint & mask)
-                               return 0;
-                       delay(1000);
-               }
-               --retry;
-       }
-
-       return ETIMEDOUT;
-}
-
 static void
 dwc_mmc_led(struct dwc_mmc_softc *sc, int on)
 {
@@ -226,9 +215,9 @@
 
        MMC_WRITE(sc, DWC_MMC_TIMEOUT, 0xffffffff);
 
-       MMC_WRITE(sc, DWC_MMC_IMASK,
-           DWC_MMC_INT_CMD_DONE | DWC_MMC_INT_ERROR |
-           DWC_MMC_INT_DATA_OVER | DWC_MMC_INT_AUTO_CMD_DONE);
+       MMC_WRITE(sc, DWC_MMC_IMASK, 0);
+
+       MMC_WRITE(sc, DWC_MMC_RINT, 0xffffffff);
 
        const uint32_t rx_wmark = (sc->sc_fifo_depth / 2) - 1;
        const uint32_t tx_wmark = sc->sc_fifo_depth / 2;
@@ -421,56 +410,43 @@
        return -1;
 }
 
-
-static int
-dwc_mmc_pio_wait(struct dwc_mmc_softc *sc, struct sdmmc_command *cmd)
-{
-       int retry = 0xfffff;
-       uint32_t bit = (cmd->c_flags & SCF_CMD_READ) ?
-           DWC_MMC_STATUS_FIFO_EMPTY : DWC_MMC_STATUS_FIFO_FULL;
-
-       while (--retry > 0) {
-               uint32_t status = MMC_READ(sc, DWC_MMC_STATUS);
-               if (!(status & bit))
-                       return 0;
-               delay(10);
-       }
-
-       return ETIMEDOUT;
-}
-
-static int
-dwc_mmc_pio_transfer(struct dwc_mmc_softc *sc, struct sdmmc_command *cmd)
-{
-       uint32_t *datap = (uint32_t *)cmd->c_data;
-       int i;
-
-       for (i = 0; i < (cmd->c_resid >> 2); i++) {
-               if (dwc_mmc_pio_wait(sc, cmd))
-                       return ETIMEDOUT;
-               if (cmd->c_flags & SCF_CMD_READ) {
-                       datap[i] = MMC_READ(sc, sc->sc_fifo_reg);
-               } else {
-                       MMC_WRITE(sc, sc->sc_fifo_reg, datap[i]);
-               }
-       }
-
-       return 0;
-}
-
 static int
 dwc_mmc_dma_prepare(struct dwc_mmc_softc *sc, struct sdmmc_command *cmd)
 {
        struct dwc_mmc_idma_desc *dma = sc->sc_idma_desc;
        bus_addr_t desc_paddr = sc->sc_idma_map->dm_segs[0].ds_addr;
+       bus_dmamap_t map;
        bus_size_t off;
        int desc, resid, seg;
        uint32_t val;
 
+       /*
+        * If the command includs a dma map use it, otherwise we need to
+        * bounce. This can happen for SDIO IO_RW_EXTENDED (CMD53) commands.
+        */
+       if (cmd->c_dmamap) {
+               map = cmd->c_dmamap;
+       } else {
+               if (cmd->c_datalen > sc->sc_dmabounce_buflen)
+                       return E2BIG;
+               map = sc->sc_dmabounce_map;
+
+               if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
+                       memset(sc->sc_dmabounce_buf, 0, cmd->c_datalen);
+                       bus_dmamap_sync(sc->sc_dmat, sc->sc_dmabounce_map,
+                           0, cmd->c_datalen, BUS_DMASYNC_PREREAD);
+               } else {
+                       memcpy(sc->sc_dmabounce_buf, cmd->c_data,
+                           cmd->c_datalen);
+                       bus_dmamap_sync(sc->sc_dmat, sc->sc_dmabounce_map,
+                           0, cmd->c_datalen, BUS_DMASYNC_PREWRITE);
+               }
+       }
+
        desc = 0;
-       for (seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) {
-               bus_addr_t paddr = cmd->c_dmamap->dm_segs[seg].ds_addr;
-               bus_size_t len = cmd->c_dmamap->dm_segs[seg].ds_len;
+       for (seg = 0; seg < map->dm_nsegs; seg++) {
+               bus_addr_t paddr = map->dm_segs[seg].ds_addr;
+               bus_size_t len = map->dm_segs[seg].ds_len;
                resid = uimin(len, cmd->c_resid);
                off = 0;
                while (resid > 0) {
@@ -480,13 +456,11 @@
                        dma[desc].dma_buf_size = htole32(len);
                        dma[desc].dma_buf_addr = htole32(paddr + off);
                        dma[desc].dma_config = htole32(
+                           DWC_MMC_IDMA_CONFIG_CH |
                            DWC_MMC_IDMA_CONFIG_OWN);
                        cmd->c_resid -= len;
                        resid -= len;
                        off += len;
-                       dma[desc].dma_next = htole32(
-                           desc_paddr + ((desc+1) *
-                           sizeof(struct dwc_mmc_idma_desc)));
                        if (desc == 0) {
                                dma[desc].dma_config |= htole32(
                                    DWC_MMC_IDMA_CONFIG_FD);
@@ -494,10 +468,15 @@
                        if (cmd->c_resid == 0) {
                                dma[desc].dma_config |= htole32(
                                    DWC_MMC_IDMA_CONFIG_LD);
+                               dma[desc].dma_config |= htole32(
+                                   DWC_MMC_IDMA_CONFIG_ER);
+                               dma[desc].dma_next = 0;
                        } else {
                                dma[desc].dma_config |=
-                                   htole32(DWC_MMC_IDMA_CONFIG_CH|
-                                           DWC_MMC_IDMA_CONFIG_DIC);
+                                   htole32(DWC_MMC_IDMA_CONFIG_DIC);
+                               dma[desc].dma_next = htole32(
+                                   desc_paddr + ((desc+1) *
+                                   sizeof(struct dwc_mmc_idma_desc)));
                        }
                        ++desc;
                }
@@ -512,34 +491,46 @@
        bus_dmamap_sync(sc->sc_dmat, sc->sc_idma_map, 0,
            sc->sc_idma_size, BUS_DMASYNC_PREWRITE);
 
-       sc->sc_idma_idst = 0;
+       MMC_WRITE(sc, DWC_MMC_DLBA, desc_paddr);
 
        val = MMC_READ(sc, DWC_MMC_GCTRL);
        val |= DWC_MMC_GCTRL_DMAEN;
-       val |= DWC_MMC_GCTRL_INTEN;
        MMC_WRITE(sc, DWC_MMC_GCTRL, val);
        val |= DWC_MMC_GCTRL_DMARESET;
        MMC_WRITE(sc, DWC_MMC_GCTRL, val);
+
        MMC_WRITE(sc, DWC_MMC_DMAC, DWC_MMC_DMAC_SOFTRESET);
+       if (cmd->c_flags & SCF_CMD_READ)
+               val = DWC_MMC_IDST_RECEIVE_INT;
+       else
+               val = 0;
+       MMC_WRITE(sc, DWC_MMC_IDIE, val);
        MMC_WRITE(sc, DWC_MMC_DMAC,
            DWC_MMC_DMAC_IDMA_ON|DWC_MMC_DMAC_FIX_BURST);
-       val = MMC_READ(sc, DWC_MMC_IDIE);
-       val &= ~(DWC_MMC_IDST_RECEIVE_INT|DWC_MMC_IDST_TRANSMIT_INT);
-       if (cmd->c_flags & SCF_CMD_READ)
-               val |= DWC_MMC_IDST_RECEIVE_INT;
-       else
-               val |= DWC_MMC_IDST_TRANSMIT_INT;
-       MMC_WRITE(sc, DWC_MMC_IDIE, val);
-       MMC_WRITE(sc, DWC_MMC_DLBA, desc_paddr);
 
        return 0;
 }
 
 static void
-dwc_mmc_dma_complete(struct dwc_mmc_softc *sc)
+dwc_mmc_dma_complete(struct dwc_mmc_softc *sc, struct sdmmc_command *cmd)
 {
+       MMC_WRITE(sc, DWC_MMC_DMAC, 0);
+       MMC_WRITE(sc, DWC_MMC_IDIE, 0);
+
        bus_dmamap_sync(sc->sc_dmat, sc->sc_idma_map, 0,



Home | Main Index | Thread Index | Old Index