summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2018-05-27 18:03:22 +0000
committerkettenis <kettenis@openbsd.org>2018-05-27 18:03:22 +0000
commit541a0a51e95e099b564536be593df497f77a45d9 (patch)
tree382045a06481cff27c81d30cbbc709022346bbd9
parentBCM43430 SDIO works if we load the appropriate firmware. (diff)
downloadwireguard-openbsd-541a0a51e95e099b564536be593df497f77a45d9.tar.xz
wireguard-openbsd-541a0a51e95e099b564536be593df497f77a45d9.zip
Add SDIO support:
- Implement SDIO interrupt handling - Set control bit that allows CPU access to the FIFO - Fix PIO transfers that are not a multiple of 4 bytes - Handle vqmmc-supply ok patrick@
-rw-r--r--sys/dev/fdt/sximmc.c81
1 files changed, 74 insertions, 7 deletions
diff --git a/sys/dev/fdt/sximmc.c b/sys/dev/fdt/sximmc.c
index 7acb8f55d56..293db1af683 100644
--- a/sys/dev/fdt/sximmc.c
+++ b/sys/dev/fdt/sximmc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sximmc.c,v 1.3 2017/08/13 00:13:07 kettenis Exp $ */
+/* $OpenBSD: sximmc.c,v 1.4 2018/05/27 18:03:22 kettenis Exp $ */
/* $NetBSD: awin_mmc.c,v 1.23 2015/11/14 10:32:40 bouyer Exp $ */
/*-
@@ -219,6 +219,8 @@ int sximmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
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_functions = {
.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, struct device *self, void *aux)
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 sch)
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 sch, uint32_t ocr)
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);
@@ -749,17 +799,34 @@ sximmc_pio_wait(struct sximmc_softc *sc, struct sdmmc_command *cmd)
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_t sch, struct sdmmc_command *cmd)
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;
}