diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-08-27 18:12:17 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-08-27 18:12:17 +0000 |
commit | 17ac3b3a3f214e3820023a9678d34a09dacd079b (patch) | |
tree | 1288d1d5e39b106603f65e022c754ba71d08aadd | |
parent | e4c834527a6daf90de1a40eec6aa4f4cef7419c6 (diff) |
Deassert reset signals if there is a "resets" property. Implement mmc power
sequencing like we have for imxesdhc(4). Unfortunately that doesn't seem to
be enough to be able to see the onboard sdio wireless on my Banana Pi 2+.
-rw-r--r-- | sys/arch/armv7/sunxi/sximmc.c | 128 |
1 files changed, 95 insertions, 33 deletions
diff --git a/sys/arch/armv7/sunxi/sximmc.c b/sys/arch/armv7/sunxi/sximmc.c index 93ae4072aac..c138e0b155d 100644 --- a/sys/arch/armv7/sunxi/sximmc.c +++ b/sys/arch/armv7/sunxi/sximmc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sximmc.c,v 1.5 2016/08/27 16:41:52 kettenis Exp $ */ +/* $OpenBSD: sximmc.c,v 1.6 2016/08/27 18:12:16 kettenis Exp $ */ /* $NetBSD: awin_mmc.c,v 1.23 2015/11/14 10:32:40 bouyer Exp $ */ /*- @@ -31,6 +31,7 @@ #include <sys/systm.h> #include <sys/device.h> #include <sys/kernel.h> +#include <sys/malloc.h> #include <machine/intr.h> #include <machine/bus.h> @@ -44,6 +45,7 @@ #include <dev/ofw/ofw_clock.h> #include <dev/ofw/ofw_gpio.h> #include <dev/ofw/ofw_pinctrl.h> +#include <dev/ofw/ofw_regulator.h> #include <dev/ofw/fdt.h> //#define SXIMMC_DEBUG @@ -218,6 +220,9 @@ 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_pwrseq_pre(uint32_t); +void sximmc_pwrseq_post(uint32_t); + struct sdmmc_chip_functions sximmc_chip_functions = { .host_reset = sximmc_host_reset, .host_ocr = sximmc_host_ocr, @@ -259,6 +264,9 @@ struct sximmc_softc { uint32_t sc_idma_idst; uint32_t sc_gpio[4]; + uint32_t sc_vmmc; + uint32_t sc_pwrseq; + uint32_t sc_vdd; }; struct cfdriver sximmc_cd = { @@ -365,38 +373,7 @@ sximmc_attach(struct device *parent, struct device *self, void *aux) clock_enable(faa->fa_node, NULL); delay(5000); -#if 0 - if (awin_chip_id() == AWIN_CHIP_ID_A80) { - bus_space_subregion(sc->sc_bst, aio->aio_ccm_bsh, - AWIN_A80_CCU_SCLK_SDMMC0_CLK_REG + (loc->loc_port * 4), 4, - &sc->sc_clk_bsh); - awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, - AWIN_A80_CCU_SCLK_BUS_CLK_GATING0_REG, - AWIN_A80_CCU_SCLK_BUS_CLK_GATING0_SD, 0); - awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, - AWIN_A80_CCU_SCLK_BUS_SOFT_RST0_REG, - AWIN_A80_CCU_SCLK_BUS_SOFT_RST0_SD, 0); - awin_reg_set_clear(aio->aio_core_bst, aio->aio_core_bsh, - AWIN_A80_SDMMC_COMM_OFFSET + (loc->loc_port * 4), - AWIN_A80_SDMMC_COMM_SDC_RESET_SW | - AWIN_A80_SDMMC_COMM_SDC_CLOCK_SW, 0); - delay(1000); - } else { - bus_space_subregion(sc->sc_bst, aio->aio_ccm_bsh, - AWIN_SD0_CLK_REG + (loc->loc_port * 4), 4, &sc->sc_clk_bsh); - - awin_pll6_enable(); - - awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, - AWIN_AHB_GATING0_REG, - AWIN_AHB_GATING0_SDMMC0 << loc->loc_port, 0); - if (awin_chip_id() == AWIN_CHIP_ID_A31) { - awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, - AWIN_A31_AHB_RESET0_REG, - AWIN_A31_AHB_RESET0_SD0_RST << loc->loc_port, 0); - } - } -#endif + reset_deassert_all(faa->fa_node); /* * The FIFO register is in a different location on the @@ -432,6 +409,9 @@ sximmc_attach(struct device *parent, struct device *self, void *aux) sizeof(sc->sc_gpio)); gpio_controller_config_pin(sc->sc_gpio, GPIO_CONFIG_INPUT); + sc->sc_vmmc = OF_getpropint(sc->sc_node, "vmmc-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, sximmc_intr, sc, sc->sc_dev.dv_xname); if (sc->sc_ih == NULL) { @@ -693,6 +673,23 @@ sximmc_card_detect(sdmmc_chipset_handle_t sch) int sximmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) { + struct sximmc_softc *sc = sch; + uint32_t vdd = 0; + + if (ISSET(ocr, MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V)) + vdd = 3300000; + + if (sc->sc_vdd == 0 && vdd > 0) + sximmc_pwrseq_pre(sc->sc_pwrseq); + + /* enable mmc power */ + if (sc->sc_vmmc && vdd > 0) + regulator_enable(sc->sc_vmmc); + + if (sc->sc_vdd == 0 && vdd > 0) + sximmc_pwrseq_post(sc->sc_pwrseq); + + sc->sc_vdd = vdd; return 0; } @@ -1090,3 +1087,68 @@ done: MMC_READ(sc, SXIMMC_GCTRL) | SXIMMC_GCTRL_FIFORESET); } } + +void +sximmc_pwrseq_pre(uint32_t phandle) +{ + uint32_t *gpios, *gpio; + int node; + int len; + + node = OF_getnodebyphandle(phandle); + if (node == 0) + return; + + if (!OF_is_compatible(node, "mmc-pwrseq-simple")) + return; + + pinctrl_byname(node, "default"); + + clock_enable(node, "ext_clock"); + + len = OF_getproplen(node, "reset-gpios"); + if (len <= 0) + return; + + gpios = malloc(len, M_TEMP, M_WAITOK); + OF_getpropintarray(node, "reset-gpios", gpios, len); + + gpio = gpios; + while (gpio && gpio < gpios + (len / sizeof(uint32_t))) { + gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT); + gpio_controller_set_pin(gpio, 1); + gpio = gpio_controller_next_pin(gpio); + } + + free(gpios, M_TEMP, len); +} + +void +sximmc_pwrseq_post(uint32_t phandle) +{ + uint32_t *gpios, *gpio; + int node; + int len; + + node = OF_getnodebyphandle(phandle); + if (node == 0) + return; + + if (!OF_is_compatible(node, "mmc-pwrseq-simple")) + return; + + len = OF_getproplen(node, "reset-gpios"); + if (len <= 0) + return; + + gpios = malloc(len, M_TEMP, M_WAITOK); + OF_getpropintarray(node, "reset-gpios", gpios, len); + + gpio = gpios; + while (gpio && gpio < gpios + (len / sizeof(uint32_t))) { + gpio_controller_set_pin(gpio, 0); + gpio = gpio_controller_next_pin(gpio); + } + + free(gpios, M_TEMP, len); +} |