Diff below makes sximmc(4) play nice with our SDIO code.  The
Cubieboard4 (Allwinner A80) isn't entirely happy with this in
combination with bwfm(4).  But as long as you don't bring the
interface that doesn't cause any problems.  There is a power
sequencing glitch that prevents bwfm(4) from attaching anyway.

It seems to work fine on the Banana Pi M2 Berry (Allwinner R40).

The changes are:

- Add SDIO interrupt handling.

- Set a bit to let the CPU access the FIFO.  We inherited this bit
  from U-Boot on the SD/MMC controllers that it brings up, but U-Boot
  doesn't touch the SDIO controllers.

- Fix PIO transfers that are not a multiple of 4 bytes.

- Handle vqmmc-supply.

ok?


Index: dev/fdt/sximmc.c
===================================================================
RCS file: /cvs/src/sys/dev/fdt/sximmc.c,v
retrieving revision 1.3
diff -u -p -r1.3 sximmc.c
--- dev/fdt/sximmc.c    13 Aug 2017 00:13:07 -0000      1.3
+++ dev/fdt/sximmc.c    27 May 2018 15:00:06 -0000
@@ -219,6 +219,8 @@ int sximmc_bus_power(sdmmc_chipset_handl
 int    sximmc_bus_clock(sdmmc_chipset_handle_t, int, int);
 int    sximmc_bus_width(sdmmc_chipset_handle_t, int);
 void   sximmc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
+void   sximmc_card_intr_mask(sdmmc_chipset_handle_t, int);
+void   sximmc_card_intr_ack(sdmmc_chipset_handle_t);
 
 void   sximmc_pwrseq_pre(uint32_t);
 void   sximmc_pwrseq_post(uint32_t);
@@ -232,6 +234,8 @@ struct sdmmc_chip_functions sximmc_chip_
        .bus_clock = sximmc_bus_clock,
        .bus_width = sximmc_bus_width,
        .exec_command = sximmc_exec_command,
+       .card_intr_mask = sximmc_card_intr_mask,
+       .card_intr_ack = sximmc_card_intr_ack,
 };
 
 struct sximmc_softc {
@@ -265,6 +269,7 @@ struct sximmc_softc {
 
        uint32_t sc_gpio[4];
        uint32_t sc_vmmc;
+       uint32_t sc_vqmmc;
        uint32_t sc_pwrseq;
        uint32_t sc_vdd;
 };
@@ -407,6 +412,7 @@ sximmc_attach(struct device *parent, str
        gpio_controller_config_pin(sc->sc_gpio, GPIO_CONFIG_INPUT);
 
        sc->sc_vmmc = OF_getpropint(sc->sc_node, "vmmc-supply", 0);
+       sc->sc_vqmmc = OF_getpropint(sc->sc_node, "vqmmc-supply", 0);
        sc->sc_pwrseq = OF_getpropint(sc->sc_node, "mmc-pwrseq", 0);
 
        sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO,
@@ -489,11 +495,46 @@ sximmc_intr(void *priv)
        if (rint) {
                sc->sc_intr_rint |= rint;
                wakeup(&sc->sc_intr_rint);
+
+               if (rint & SXIMMC_INT_SDIO_INT) {
+                       uint32_t imask;
+
+                       imask = MMC_READ(sc, SXIMMC_IMASK);
+                       imask &= ~SXIMMC_INT_SDIO_INT;
+                       MMC_WRITE(sc, SXIMMC_IMASK, imask);
+                       sdmmc_card_intr(sc->sc_sdmmc_dev);
+               }
        }
 
        return 1;
 }
 
+void
+sximmc_card_intr_mask(sdmmc_chipset_handle_t sch, int enable)
+{
+       struct sximmc_softc *sc = sch;
+       uint32_t imask;
+
+       imask = MMC_READ(sc, SXIMMC_IMASK);
+       if (enable)
+               imask |= SXIMMC_INT_SDIO_INT;
+       else
+               imask &= ~SXIMMC_INT_SDIO_INT;
+       MMC_WRITE(sc, SXIMMC_IMASK, imask);
+}
+
+void
+sximmc_card_intr_ack(sdmmc_chipset_handle_t sch)
+{
+       struct sximmc_softc *sc = sch;
+       uint32_t imask;
+
+       MMC_WRITE(sc, SXIMMC_RINT, SXIMMC_INT_SDIO_INT);
+       imask = MMC_READ(sc, SXIMMC_IMASK);
+       imask |= SXIMMC_INT_SDIO_INT;
+       MMC_WRITE(sc, SXIMMC_IMASK, imask);
+}
+
 int
 sximmc_wait_rint(struct sximmc_softc *sc, uint32_t mask, int timeout)
 {
@@ -562,6 +603,10 @@ sximmc_host_reset(sdmmc_chipset_handle_t
                printf("%s: host reset succeeded\n", sc->sc_dev.dv_xname);
 #endif
 
+       /* Allow access to the FIFO by the CPU. */
+       MMC_WRITE(sc, SXIMMC_GCTRL,
+           MMC_READ(sc, SXIMMC_GCTRL) | SXIMMC_GCTRL_ACCESS_BY_AHB);
+
        MMC_WRITE(sc, SXIMMC_TIMEOUT, 0xffffffff);
 
        MMC_WRITE(sc, SXIMMC_IMASK,
@@ -625,6 +670,11 @@ sximmc_bus_power(sdmmc_chipset_handle_t 
        if (sc->sc_vmmc && vdd > 0)
                regulator_enable(sc->sc_vmmc);
 
+       if (sc->sc_vqmmc && vdd > 0)
+               regulator_enable(sc->sc_vqmmc);
+
+       delay(10000);
+
        if (sc->sc_vdd == 0 && vdd > 0)
                sximmc_pwrseq_post(sc->sc_pwrseq);
 
@@ -655,7 +705,7 @@ sximmc_update_clock(struct sximmc_softc 
 
        if (retry == 0) {
                printf("%s: timeout updating clock\n", sc->sc_dev.dv_xname);
-#ifdef SXIMMC_DEBUG
+#ifndef SXIMMC_DEBUG
                printf("GCTRL: 0x%08x\n", MMC_READ(sc, SXIMMC_GCTRL));
                printf("CLKCR: 0x%08x\n", MMC_READ(sc, SXIMMC_CLKCR));
                printf("TIMEOUT: 0x%08x\n", MMC_READ(sc, SXIMMC_TIMEOUT));
@@ -749,17 +799,34 @@ sximmc_pio_wait(struct sximmc_softc *sc,
 int
 sximmc_pio_transfer(struct sximmc_softc *sc, struct sdmmc_command *cmd)
 {
-       uint32_t *datap = (uint32_t *)cmd->c_data;
-       int i;
+       u_char *datap = cmd->c_data;
+       int datalen = cmd->c_resid;
 
-       for (i = 0; i < (cmd->c_resid >> 2); i++) {
+       while (datalen > 3) {
                if (sximmc_pio_wait(sc, cmd))
                        return ETIMEDOUT;
                if (cmd->c_flags & SCF_CMD_READ) {
-                       datap[i] = MMC_READ(sc, sc->sc_fifo_reg);
+                       *(uint32_t *)datap = MMC_READ(sc, sc->sc_fifo_reg);
                } else {
-                       MMC_WRITE(sc, sc->sc_fifo_reg, datap[i]);
+                       MMC_WRITE(sc, sc->sc_fifo_reg, *(uint32_t *)datap);
                }
+               datap += 4;
+               datalen -= 4;
+       }
+
+       if (datalen > 0 && cmd->c_flags & SCF_CMD_READ) {
+               uint32_t rv = MMC_READ(sc, sc->sc_fifo_reg);
+               do {
+                       *datap++ = rv & 0xff;
+                       rv = rv >> 8;
+               } while(--datalen > 0);
+       } else if (datalen > 0) {
+               uint32_t rv = *datap++;
+               if (datalen > 1)
+                       rv |= *datap++ << 8;
+               if (datalen > 2)
+                       rv |= *datap++ << 16;
+               MMC_WRITE(sc, sc->sc_fifo_reg, rv);
        }
 
        return 0;
@@ -887,7 +954,7 @@ sximmc_exec_command(sdmmc_chipset_handle
 
                blksize = MIN(cmd->c_datalen, cmd->c_blklen);
                blkcount = cmd->c_datalen / blksize;
-               if (blkcount > 1) {
+               if (blkcount > 1 && cmd->c_opcode != SD_IO_RW_EXTENDED) {
                        cmdval |= SXIMMC_CMD_SEND_AUTO_STOP;
                }
 

Reply via email to