From 676a2b59f13d3b0996586667d777e9a1630d94e9 Mon Sep 17 00:00:00 2001 From: kettenis Date: Mon, 8 Aug 2016 10:10:56 +0000 Subject: [PATCH] Implement mmc power sequencing; makes the sdo interface on the cubox-i work and see the BCM4330 wireless (for which we don't have a driver yet). ok jsg@ --- sys/arch/armv7/imx/imxesdhc.c | 152 ++++++++++++++++++++++++++++++++-- 1 file changed, 146 insertions(+), 6 deletions(-) diff --git a/sys/arch/armv7/imx/imxesdhc.c b/sys/arch/armv7/imx/imxesdhc.c index 5d58dd5b6a5..a50ab69547c 100644 --- a/sys/arch/armv7/imx/imxesdhc.c +++ b/sys/arch/armv7/imx/imxesdhc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: imxesdhc.c,v 1.28 2016/08/06 17:18:38 kettenis Exp $ */ +/* $OpenBSD: imxesdhc.c,v 1.29 2016/08/08 10:10:56 kettenis Exp $ */ /* * Copyright (c) 2009 Dale Rahn * Copyright (c) 2006 Uwe Stuehler @@ -180,6 +180,9 @@ struct imxesdhc_softc { void *sc_ih; /* Interrupt handler */ int sc_node; uint32_t sc_gpio[3]; + uint32_t sc_vmmc; + uint32_t sc_pwrseq; + uint32_t sc_vdd; u_int sc_flags; int unit; /* unit id */ @@ -201,10 +204,14 @@ struct imxesdhc_softc { /* Host controller functions called by the attachment driver. */ int imxesdhc_host_found(struct imxesdhc_softc *, bus_space_tag_t, bus_space_handle_t, bus_size_t, int); -void imxesdhc_power(int, void *); void imxesdhc_shutdown(void *); int imxesdhc_intr(void *); +void imxesdhc_enable_vbus(uint32_t); +void imxesdhc_clock_enable(uint32_t); +void imxesdhc_pwrseq_pre(uint32_t); +void imxesdhc_pwrseq_post(uint32_t); + /* RESET MODES */ #define MMC_RESET_DAT 1 #define MMC_RESET_CMD 2 @@ -318,6 +325,9 @@ imxesdhc_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); + /* * Reset the host controller and enable interrupts. */ @@ -448,13 +458,121 @@ err: return; } +void +imxesdhc_enable_vbus(uint32_t phandle) +{ + uint32_t gpio[3]; + int active; + int node; + + node = OF_getnodebyphandle(phandle); + if (node == 0) + return; + + if (!OF_is_compatible(node, "regulator-fixed")) + return; + + pinctrl_byname(node, "default"); + + if (OF_getproplen(node, "enable-active-high") == 0) + active = 1; + else + active = 0; + + if (OF_getpropintarray(node, "gpio", gpio, + sizeof(gpio)) != sizeof(gpio)) + return; + + gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT); + gpio_controller_set_pin(gpio, active); +} -/* - * Power hook established by or called from attachment driver. - */ void -imxesdhc_power(int why, void *arg) +imxesdhc_clock_enable(uint32_t phandle) { + uint32_t gpios[3]; + int node; + + node = OF_getnodebyphandle(phandle); + if (node == 0) + return; + + if (!OF_is_compatible(node, "gpio-gate-clock")) + return; + + pinctrl_byname(node, "default"); + + OF_getpropintarray(node, "enable-gpios", gpios, sizeof(gpios)); + gpio_controller_config_pin(&gpios[0], GPIO_CONFIG_OUTPUT); + gpio_controller_set_pin(&gpios[0], 1); +} + +void +imxesdhc_pwrseq_pre(uint32_t phandle) +{ + uint32_t *gpios, *gpio; + uint32_t clocks; + 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"); + + clocks = OF_getpropint(node, "clocks", 0); + if (clocks) + imxesdhc_clock_enable(clocks); + + 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 +imxesdhc_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); } /* @@ -564,6 +682,28 @@ imxesdhc_card_detect(sdmmc_chipset_handle_t sch) int imxesdhc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) { + struct imxesdhc_softc *sc = sch; + uint32_t vdd; + + ocr &= sc->ocr; + if (ISSET(ocr, MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V)) + vdd = 3300000; + else if (ISSET(ocr, MMC_OCR_2_9V_3_0V|MMC_OCR_3_0V_3_1V)) + vdd = 3000000; + else if (ISSET(ocr, MMC_OCR_1_65V_1_95V)) + vdd = 1800000; + + if (sc->sc_vdd == 0 && vdd > 0) + imxesdhc_pwrseq_pre(sc->sc_pwrseq); + + /* enable mmc power */ + if (sc->sc_vmmc && vdd > 0) + imxesdhc_enable_vbus(sc->sc_vmmc); + + if (sc->sc_vdd == 0 && vdd > 0) + imxesdhc_pwrseq_post(sc->sc_pwrseq); + + sc->sc_vdd = vdd; return 0; } -- 2.20.1