Index: head/sys/arm/nvidia/as3722_gpio.c =================================================================== --- head/sys/arm/nvidia/as3722_gpio.c (revision 299714) +++ head/sys/arm/nvidia/as3722_gpio.c (revision 299715) @@ -1,577 +1,577 @@ /*- * Copyright (c) 2016 Michal Meloun * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include "as3722.h" MALLOC_DEFINE(M_AS3722_GPIO, "AS3722 gpio", "AS3722 GPIO"); /* AS3722_GPIOx_CONTROL MODE and IOSF definition. */ #define AS3722_IOSF_GPIO 0x00 #define AS3722_IOSF_INTERRUPT_OUT 0x01 #define AS3722_IOSF_VSUP_VBAT_LOW_UNDEBOUNCE_OUT 0x02 #define AS3722_IOSF_GPIO_IN_INTERRUPT 0x03 #define AS3722_IOSF_PWM_IN 0x04 #define AS3722_IOSF_VOLTAGE_IN_STANDBY 0x05 #define AS3722_IOSF_OC_PG_SD0 0x06 #define AS3722_IOSF_POWERGOOD_OUT 0x07 #define AS3722_IOSF_CLK32K_OUT 0x08 #define AS3722_IOSF_WATCHDOG_IN 0x09 #define AS3722_IOSF_SOFT_RESET_IN 0x0b #define AS3722_IOSF_PWM_OUT 0x0c #define AS3722_IOSF_VSUP_VBAT_LOW_DEBOUNCE_OUT 0x0d #define AS3722_IOSF_OC_PG_SD6 0x0e #define AS3722_MODE_INPUT 0 #define AS3722_MODE_PUSH_PULL 1 #define AS3722_MODE_OPEN_DRAIN 2 #define AS3722_MODE_TRISTATE 3 #define AS3722_MODE_INPUT_PULL_UP_LV 4 #define AS3722_MODE_INPUT_PULL_DOWN 5 #define AS3722_MODE_OPEN_DRAIN_LV 6 #define AS3722_MODE_PUSH_PULL_LV 7 #define NGPIO 8 #define GPIO_LOCK(_sc) sx_slock(&(_sc)->gpio_lock) #define GPIO_UNLOCK(_sc) sx_unlock(&(_sc)->gpio_lock) #define GPIO_ASSERT(_sc) sx_assert(&(_sc)->gpio_lock, SA_LOCKED) #define AS3722_CFG_BIAS_DISABLE 0x0001 #define AS3722_CFG_BIAS_PULL_UP 0x0002 #define AS3722_CFG_BIAS_PULL_DOWN 0x0004 #define AS3722_CFG_BIAS_HIGH_IMPEDANCE 0x0008 #define AS3722_CFG_OPEN_DRAIN 0x0010 static const struct { const char *name; int config; /* AS3722_CFG_ */ } as3722_cfg_names[] = { {"bias-disable", AS3722_CFG_BIAS_DISABLE}, {"bias-pull-up", AS3722_CFG_BIAS_PULL_UP}, {"bias-pull-down", AS3722_CFG_BIAS_PULL_DOWN}, {"bias-high-impedance", AS3722_CFG_BIAS_HIGH_IMPEDANCE}, {"drive-open-drain", AS3722_CFG_OPEN_DRAIN}, }; static struct { const char *name; int fnc_val; } as3722_fnc_table[] = { {"gpio", AS3722_IOSF_GPIO}, {"interrupt-out", AS3722_IOSF_INTERRUPT_OUT}, {"vsup-vbat-low-undebounce-out", AS3722_IOSF_VSUP_VBAT_LOW_UNDEBOUNCE_OUT}, {"gpio-in-interrupt", AS3722_IOSF_GPIO_IN_INTERRUPT}, {"pwm-in", AS3722_IOSF_PWM_IN}, {"voltage-in-standby", AS3722_IOSF_VOLTAGE_IN_STANDBY}, {"oc-pg-sd0", AS3722_IOSF_OC_PG_SD0}, {"powergood-out", AS3722_IOSF_POWERGOOD_OUT}, {"clk32k-out", AS3722_IOSF_CLK32K_OUT}, {"watchdog-in", AS3722_IOSF_WATCHDOG_IN}, {"soft-reset-in", AS3722_IOSF_SOFT_RESET_IN}, {"pwm-out", AS3722_IOSF_PWM_OUT}, {"vsup-vbat-low-debounce-out", AS3722_IOSF_VSUP_VBAT_LOW_DEBOUNCE_OUT}, {"oc-pg-sd6", AS3722_IOSF_OC_PG_SD6}, }; struct as3722_pincfg { char *function; int flags; }; struct as3722_gpio_pin { int pin_caps; uint8_t pin_ctrl_reg; char pin_name[GPIOMAXNAME]; int pin_cfg_flags; }; /* -------------------------------------------------------------------------- * * Pinmux functions. */ static int as3722_pinmux_get_function(struct as3722_softc *sc, char *name) { int i; for (i = 0; i < nitems(as3722_fnc_table); i++) { if (strcmp(as3722_fnc_table[i].name, name) == 0) return (as3722_fnc_table[i].fnc_val); } return (-1); } static int as3722_pinmux_config_node(struct as3722_softc *sc, char *pin_name, struct as3722_pincfg *cfg) { uint8_t ctrl; int rv, fnc, pin; for (pin = 0; pin < sc->gpio_npins; pin++) { if (strcmp(sc->gpio_pins[pin]->pin_name, pin_name) == 0) break; } if (pin >= sc->gpio_npins) { device_printf(sc->dev, "Unknown pin: %s\n", pin_name); return (ENXIO); } ctrl = sc->gpio_pins[pin]->pin_ctrl_reg; sc->gpio_pins[pin]->pin_cfg_flags = cfg->flags; if (cfg->function != NULL) { fnc = as3722_pinmux_get_function(sc, cfg->function); if (fnc == -1) { device_printf(sc->dev, "Unknown function %s for pin %s\n", cfg->function, sc->gpio_pins[pin]->pin_name); return (ENXIO); } switch (fnc) { case AS3722_IOSF_INTERRUPT_OUT: case AS3722_IOSF_VSUP_VBAT_LOW_UNDEBOUNCE_OUT: case AS3722_IOSF_OC_PG_SD0: case AS3722_IOSF_POWERGOOD_OUT: case AS3722_IOSF_CLK32K_OUT: case AS3722_IOSF_PWM_OUT: case AS3722_IOSF_OC_PG_SD6: ctrl &= ~(AS3722_GPIO_MODE_MASK << AS3722_GPIO_MODE_SHIFT); ctrl |= AS3722_MODE_PUSH_PULL << AS3722_GPIO_MODE_SHIFT; /* XXX Handle flags (OC + pullup) */ break; case AS3722_IOSF_GPIO_IN_INTERRUPT: case AS3722_IOSF_PWM_IN: case AS3722_IOSF_VOLTAGE_IN_STANDBY: case AS3722_IOSF_WATCHDOG_IN: case AS3722_IOSF_SOFT_RESET_IN: ctrl &= ~(AS3722_GPIO_MODE_MASK << AS3722_GPIO_MODE_SHIFT); ctrl |= AS3722_MODE_INPUT << AS3722_GPIO_MODE_SHIFT; /* XXX Handle flags (pulldown + pullup) */ default: break; } ctrl &= ~(AS3722_GPIO_IOSF_MASK << AS3722_GPIO_IOSF_SHIFT); ctrl |= fnc << AS3722_GPIO_IOSF_SHIFT; } rv = 0; if (ctrl != sc->gpio_pins[pin]->pin_ctrl_reg) { rv = WR1(sc, AS3722_GPIO0_CONTROL + pin, ctrl); sc->gpio_pins[pin]->pin_ctrl_reg = ctrl; } return (rv); } static int as3722_pinmux_read_node(struct as3722_softc *sc, phandle_t node, struct as3722_pincfg *cfg, char **pins, int *lpins) { int rv, i; *lpins = OF_getprop_alloc(node, "pins", 1, (void **)pins); if (*lpins <= 0) return (ENOENT); /* Read function (mux) settings. */ rv = OF_getprop_alloc(node, "function", 1, (void **)&cfg->function); if (rv <= 0) cfg->function = NULL; /* Read boolean properties. */ for (i = 0; i < nitems(as3722_cfg_names); i++) { if (OF_hasprop(node, as3722_cfg_names[i].name)) cfg->flags |= as3722_cfg_names[i].config; } return (0); } static int as3722_pinmux_process_node(struct as3722_softc *sc, phandle_t node) { struct as3722_pincfg cfg; char *pins, *pname; int i, len, lpins, rv; rv = as3722_pinmux_read_node(sc, node, &cfg, &pins, &lpins); if (rv != 0) return (rv); len = 0; pname = pins; do { i = strlen(pname) + 1; rv = as3722_pinmux_config_node(sc, pname, &cfg); if (rv != 0) { device_printf(sc->dev, "Cannot configure pin: %s: %d\n", pname, rv); } len += i; pname += i; } while (len < lpins); if (pins != NULL) - free(pins, M_OFWPROP); + OF_prop_free(pins); if (cfg.function != NULL) - free(cfg.function, M_OFWPROP); + OF_prop_free(cfg.function); return (rv); } int as3722_pinmux_configure(device_t dev, phandle_t cfgxref) { struct as3722_softc *sc; phandle_t node, cfgnode; int rv; sc = device_get_softc(dev); cfgnode = OF_node_from_xref(cfgxref); for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) { if (!fdt_is_enabled(node)) continue; rv = as3722_pinmux_process_node(sc, node); if (rv != 0) device_printf(dev, "Failed to process pinmux"); } return (0); } /* -------------------------------------------------------------------------- * * GPIO */ device_t as3722_gpio_get_bus(device_t dev) { struct as3722_softc *sc; sc = device_get_softc(dev); return (sc->gpio_busdev); } int as3722_gpio_pin_max(device_t dev, int *maxpin) { *maxpin = NGPIO - 1; return (0); } int as3722_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) { struct as3722_softc *sc; sc = device_get_softc(dev); if (pin >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); *caps = sc->gpio_pins[pin]->pin_caps; GPIO_UNLOCK(sc); return (0); } int as3722_gpio_pin_getname(device_t dev, uint32_t pin, char *name) { struct as3722_softc *sc; sc = device_get_softc(dev); if (pin >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); memcpy(name, sc->gpio_pins[pin]->pin_name, GPIOMAXNAME); GPIO_UNLOCK(sc); return (0); } int as3722_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *out_flags) { struct as3722_softc *sc; uint8_t tmp, mode, iosf; uint32_t flags; bool inverted; sc = device_get_softc(dev); if (pin >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); tmp = sc->gpio_pins[pin]->pin_ctrl_reg; GPIO_UNLOCK(sc); iosf = (tmp >> AS3722_GPIO_IOSF_SHIFT) & AS3722_GPIO_IOSF_MASK; mode = (tmp >> AS3722_GPIO_MODE_SHIFT) & AS3722_GPIO_MODE_MASK; inverted = (tmp & AS3722_GPIO_INVERT) != 0; /* Is pin in GPIO mode ? */ if (iosf != AS3722_IOSF_GPIO) return (ENXIO); flags = 0; switch (mode) { case AS3722_MODE_INPUT: flags = GPIO_PIN_INPUT; break; case AS3722_MODE_PUSH_PULL: case AS3722_MODE_PUSH_PULL_LV: flags = GPIO_PIN_OUTPUT; break; case AS3722_MODE_OPEN_DRAIN: case AS3722_MODE_OPEN_DRAIN_LV: flags = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN; break; case AS3722_MODE_TRISTATE: flags = GPIO_PIN_TRISTATE; break; case AS3722_MODE_INPUT_PULL_UP_LV: flags = GPIO_PIN_INPUT | GPIO_PIN_PULLUP; break; case AS3722_MODE_INPUT_PULL_DOWN: flags = GPIO_PIN_OUTPUT | GPIO_PIN_PULLDOWN; break; } if (inverted) flags |= GPIO_PIN_INVIN | GPIO_PIN_INVOUT; *out_flags = flags; return (0); } static int as3722_gpio_get_mode(struct as3722_softc *sc, uint32_t pin, uint32_t gpio_flags) { uint8_t ctrl; int flags; ctrl = sc->gpio_pins[pin]->pin_ctrl_reg; flags = sc->gpio_pins[pin]->pin_cfg_flags; /* Tristate mode. */ if (flags & AS3722_CFG_BIAS_HIGH_IMPEDANCE || gpio_flags & GPIO_PIN_TRISTATE) return (AS3722_MODE_TRISTATE); /* Open drain modes. */ if (flags & AS3722_CFG_OPEN_DRAIN || gpio_flags & GPIO_PIN_OPENDRAIN) { /* Only pull up have effect */ if (flags & AS3722_CFG_BIAS_PULL_UP || gpio_flags & GPIO_PIN_PULLUP) return (AS3722_MODE_OPEN_DRAIN_LV); return (AS3722_MODE_OPEN_DRAIN); } /* Input modes. */ if (gpio_flags & GPIO_PIN_INPUT) { /* Accept pull up or pull down. */ if (flags & AS3722_CFG_BIAS_PULL_UP || gpio_flags & GPIO_PIN_PULLUP) return (AS3722_MODE_INPUT_PULL_UP_LV); if (flags & AS3722_CFG_BIAS_PULL_DOWN || gpio_flags & GPIO_PIN_PULLDOWN) return (AS3722_MODE_INPUT_PULL_DOWN); return (AS3722_MODE_INPUT); } /* * Output modes. * Pull down is used as indicator of low voltage output. */ if (flags & AS3722_CFG_BIAS_PULL_DOWN || gpio_flags & GPIO_PIN_PULLDOWN) return (AS3722_MODE_PUSH_PULL_LV); return (AS3722_MODE_PUSH_PULL); } int as3722_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { struct as3722_softc *sc; uint8_t ctrl, mode, iosf; int rv; sc = device_get_softc(dev); if (pin >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); ctrl = sc->gpio_pins[pin]->pin_ctrl_reg; iosf = (ctrl >> AS3722_GPIO_IOSF_SHIFT) & AS3722_GPIO_IOSF_MASK; /* Is pin in GPIO mode ? */ if (iosf != AS3722_IOSF_GPIO) { GPIO_UNLOCK(sc); return (ENXIO); } mode = as3722_gpio_get_mode(sc, pin, flags); ctrl &= ~(AS3722_GPIO_MODE_MASK << AS3722_GPIO_MODE_SHIFT); ctrl |= AS3722_MODE_PUSH_PULL << AS3722_GPIO_MODE_SHIFT; rv = 0; if (ctrl != sc->gpio_pins[pin]->pin_ctrl_reg) { rv = WR1(sc, AS3722_GPIO0_CONTROL + pin, ctrl); sc->gpio_pins[pin]->pin_ctrl_reg = ctrl; } GPIO_UNLOCK(sc); return (rv); } int as3722_gpio_pin_set(device_t dev, uint32_t pin, uint32_t val) { struct as3722_softc *sc; uint8_t tmp; int rv; sc = device_get_softc(dev); if (pin >= sc->gpio_npins) return (EINVAL); tmp = (val != 0) ? 1 : 0; if (sc->gpio_pins[pin]->pin_ctrl_reg & AS3722_GPIO_INVERT) tmp ^= 1; GPIO_LOCK(sc); rv = RM1(sc, AS3722_GPIO_SIGNAL_OUT, (1 << pin), (tmp << pin)); GPIO_UNLOCK(sc); return (rv); } int as3722_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *val) { struct as3722_softc *sc; uint8_t tmp, mode, ctrl; int rv; sc = device_get_softc(dev); if (pin >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); ctrl = sc->gpio_pins[pin]->pin_ctrl_reg; mode = (ctrl >> AS3722_GPIO_MODE_SHIFT) & AS3722_GPIO_MODE_MASK; if ((mode == AS3722_MODE_PUSH_PULL) || (mode == AS3722_MODE_PUSH_PULL_LV)) rv = RD1(sc, AS3722_GPIO_SIGNAL_OUT, &tmp); else rv = RD1(sc, AS3722_GPIO_SIGNAL_IN, &tmp); GPIO_UNLOCK(sc); if (rv != 0) return (rv); *val = tmp & (1 << pin) ? 1 : 0; if (ctrl & AS3722_GPIO_INVERT) *val ^= 1; return (0); } int as3722_gpio_pin_toggle(device_t dev, uint32_t pin) { struct as3722_softc *sc; uint8_t tmp; int rv; sc = device_get_softc(dev); if (pin >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); rv = RD1(sc, AS3722_GPIO_SIGNAL_OUT, &tmp); if (rv != 0) { GPIO_UNLOCK(sc); return (rv); } tmp ^= (1 <gpio_lock, "AS3722 GPIO lock"); sc->gpio_npins = NGPIO; sc->gpio_pins = malloc(sizeof(struct as3722_gpio_pin *) * sc->gpio_npins, M_AS3722_GPIO, M_WAITOK | M_ZERO); sc->gpio_busdev = gpiobus_attach_bus(sc->dev); if (sc->gpio_busdev == NULL) return (ENXIO); for (i = 0; i < sc->gpio_npins; i++) { sc->gpio_pins[i] = malloc(sizeof(struct as3722_gpio_pin), M_AS3722_GPIO, M_WAITOK | M_ZERO); pin = sc->gpio_pins[i]; sprintf(pin->pin_name, "gpio%d", i); pin->pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | GPIO_PIN_TRISTATE | GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | GPIO_PIN_INVIN | GPIO_PIN_INVOUT; rv = RD1(sc, AS3722_GPIO0_CONTROL + i, &pin->pin_ctrl_reg); if (rv != 0) { device_printf(sc->dev, "Cannot read configuration for pin %s\n", sc->gpio_pins[i]->pin_name); } } return (0); } Index: head/sys/arm/nvidia/tegra124/tegra124_coretemp.c =================================================================== --- head/sys/arm/nvidia/tegra124/tegra124_coretemp.c (revision 299714) +++ head/sys/arm/nvidia/tegra124/tegra124_coretemp.c (revision 299715) @@ -1,273 +1,273 @@ /*- * Copyright (c) 2016 Michal Meloun * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tegra_soctherm_if.h" enum therm_info { CORETEMP_TEMP, CORETEMP_DELTA, CORETEMP_RESOLUTION, CORETEMP_TJMAX, }; struct tegra124_coretemp_softc { device_t dev; int overheat_log; int core_max_temp; int cpu_id; device_t tsens_dev; intptr_t tsens_id; }; static int coretemp_get_val_sysctl(SYSCTL_HANDLER_ARGS) { device_t dev; int val, temp, rv; struct tegra124_coretemp_softc *sc; enum therm_info type; char stemp[16]; dev = (device_t) arg1; sc = device_get_softc(dev); type = arg2; rv = TEGRA_SOCTHERM_GET_TEMPERATURE(sc->tsens_dev, sc->dev, sc->tsens_id, &temp); if (rv != 0) { device_printf(sc->dev, "Cannot read temperature sensor %d: %d\n", sc->tsens_id, rv); return (rv); } switch (type) { case CORETEMP_TEMP: val = temp / 100; val += 2731; break; case CORETEMP_DELTA: val = (sc->core_max_temp - temp) / 1000; break; case CORETEMP_RESOLUTION: val = 1; break; case CORETEMP_TJMAX: val = sc->core_max_temp / 100; val += 2731; break; } if ((temp > sc->core_max_temp) && !sc->overheat_log) { sc->overheat_log = 1; /* * Check for Critical Temperature Status and Critical * Temperature Log. It doesn't really matter if the * current temperature is invalid because the "Critical * Temperature Log" bit will tell us if the Critical * Temperature has * been reached in past. It's not * directly related to the current temperature. * * If we reach a critical level, allow devctl(4) * to catch this and shutdown the system. */ device_printf(dev, "critical temperature detected, " "suggest system shutdown\n"); snprintf(stemp, sizeof(stemp), "%d", val); devctl_notify("coretemp", "Thermal", stemp, "notify=0xcc"); } else { sc->overheat_log = 0; } return (sysctl_handle_int(oidp, 0, val, req)); } static int tegra124_coretemp_ofw_parse(struct tegra124_coretemp_softc *sc) { int rv, ncells; phandle_t node, xnode; pcell_t *cells; node = OF_peer(0); node = ofw_bus_find_child(node, "thermal-zones"); if (node <= 0) { device_printf(sc->dev, "Cannot find 'thermal-zones'.\n"); return (ENXIO); } node = ofw_bus_find_child(node, "cpu"); if (node <= 0) { device_printf(sc->dev, "Cannot find 'cpu'\n"); return (ENXIO); } rv = ofw_bus_parse_xref_list_alloc(node, "thermal-sensors", "#thermal-sensor-cells", 0, &xnode, &ncells, &cells); if (rv != 0) { device_printf(sc->dev, "Cannot parse 'thermal-sensors' property.\n"); return (ENXIO); } if (ncells != 1) { device_printf(sc->dev, "Invalid format of 'thermal-sensors' property(%d).\n", ncells); return (ENXIO); } sc->tsens_id = 0x100 + sc->cpu_id; //cells[0]; - free(cells, M_OFWPROP); + OF_prop_free(cells); sc->tsens_dev = OF_device_from_xref(xnode); if (sc->tsens_dev == NULL) { device_printf(sc->dev, "Cannot find thermal sensors device."); return (ENXIO); } return (0); } static void tegra124_coretemp_identify(driver_t *driver, device_t parent) { if (device_find_child(parent, "tegra124_coretemp", -1) != NULL) return; if (BUS_ADD_CHILD(parent, 0, "tegra124_coretemp", -1) == NULL) device_printf(parent, "add child failed\n"); } static int tegra124_coretemp_probe(device_t dev) { device_set_desc(dev, "CPU Frequency Control"); return (0); } static int tegra124_coretemp_attach(device_t dev) { struct tegra124_coretemp_softc *sc; device_t pdev; struct sysctl_oid *oid; struct sysctl_ctx_list *ctx; int rv; sc = device_get_softc(dev); sc->dev = dev; sc->cpu_id = device_get_unit(dev); sc->core_max_temp = 102000; pdev = device_get_parent(dev); rv = tegra124_coretemp_ofw_parse(sc); if (rv != 0) return (rv); ctx = device_get_sysctl_ctx(dev); oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(pdev)), OID_AUTO, "coretemp", CTLFLAG_RD, NULL, "Per-CPU thermal information"); /* * Add the MIBs to dev.cpu.N and dev.cpu.N.coretemp. */ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(pdev)), OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, CORETEMP_TEMP, coretemp_get_val_sysctl, "IK", "Current temperature"); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "delta", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, CORETEMP_DELTA, coretemp_get_val_sysctl, "I", "Delta between TCC activation and current temperature"); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "resolution", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, CORETEMP_RESOLUTION, coretemp_get_val_sysctl, "I", "Resolution of CPU thermal sensor"); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "tjmax", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, CORETEMP_TJMAX, coretemp_get_val_sysctl, "IK", "TCC activation temperature"); return (0); } static int tegra124_coretemp_detach(device_t dev) { struct tegra124_coretemp_softc *sc; sc = device_get_softc(dev); return (0); } static device_method_t tegra124_coretemp_methods[] = { /* Device interface */ DEVMETHOD(device_identify, tegra124_coretemp_identify), DEVMETHOD(device_probe, tegra124_coretemp_probe), DEVMETHOD(device_attach, tegra124_coretemp_attach), DEVMETHOD(device_detach, tegra124_coretemp_detach), DEVMETHOD_END }; static devclass_t tegra124_coretemp_devclass; static driver_t tegra124_coretemp_driver = { "tegra124_coretemp", tegra124_coretemp_methods, sizeof(struct tegra124_coretemp_softc), }; DRIVER_MODULE(tegra124_coretemp, cpu, tegra124_coretemp_driver, tegra124_coretemp_devclass, 0, 0); Index: head/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c =================================================================== --- head/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c (revision 299714) +++ head/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c (revision 299715) @@ -1,603 +1,603 @@ /*- * Copyright (c) 2016 Michal Meloun * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "phy_if.h" #define XUSB_PADCTL_USB2_PAD_MUX 0x004 #define XUSB_PADCTL_ELPG_PROGRAM 0x01C #define ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26) #define ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25) #define ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24) #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040 #define IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19) #define IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK (0xf<< 12) #define IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1) #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044 #define IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6) #define IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5) #define IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4) #define XUSB_PADCTL_USB3_PAD_MUX 0x134 #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138 #define IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27) #define IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24) #define IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3) #define IOPHY_PLL_S0_CTL1_PLL_RST_L (1 << 1) #define IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0) #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2 0x13C #define XUSB_PADCTL_IOPHY_PLL_S0_CTL3 0x140 #define XUSB_PADCTL_IOPHY_PLL_S0_CTL4 0x144 #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148 #define IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1) #define IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0) #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 0x14C #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL3 0x150 #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL4 0x154 #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 0x158 #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 0x15C struct lane_cfg { char *function; char **lanes; int iddq; }; struct xusbpadctl_softc { device_t dev; struct resource *mem_res; hwreset_t rst; int phy_ena_cnt; }; static struct ofw_compat_data compat_data[] = { {"nvidia,tegra124-xusb-padctl", 1}, {NULL, 0}, }; struct padctl_lane { const char *name; bus_size_t reg; uint32_t shift; uint32_t mask; int iddq; char **mux; int nmux; }; static char *otg_mux[] = {"snps", "xusb", "uart", "rsvd"}; static char *usb_mux[] = {"snps", "xusb"}; static char *pci_mux[] = {"pcie", "usb3", "sata", "rsvd"}; #define LANE(n, r, s, m, i, mx) \ { \ .name = n, \ .reg = r, \ .shift = s, \ .mask = m, \ .iddq = i, \ .mux = mx, \ .nmux = nitems(mx), \ } static const struct padctl_lane lanes_tbl[] = { LANE("otg-0", XUSB_PADCTL_USB2_PAD_MUX, 0, 0x3, -1, otg_mux), LANE("otg-1", XUSB_PADCTL_USB2_PAD_MUX, 2, 0x3, -1, otg_mux), LANE("otg-2", XUSB_PADCTL_USB2_PAD_MUX, 4, 0x3, -1, otg_mux), LANE("ulpi-0", XUSB_PADCTL_USB2_PAD_MUX, 12, 0x1, -1, usb_mux), LANE("hsic-0", XUSB_PADCTL_USB2_PAD_MUX, 14, 0x1, -1, usb_mux), LANE("hsic-1", XUSB_PADCTL_USB2_PAD_MUX, 15, 0x1, -1, usb_mux), LANE("pcie-0", XUSB_PADCTL_USB3_PAD_MUX, 16, 0x3, 1, pci_mux), LANE("pcie-1", XUSB_PADCTL_USB3_PAD_MUX, 18, 0x3, 2, pci_mux), LANE("pcie-2", XUSB_PADCTL_USB3_PAD_MUX, 20, 0x3, 3, pci_mux), LANE("pcie-3", XUSB_PADCTL_USB3_PAD_MUX, 22, 0x3, 4, pci_mux), LANE("pcie-4", XUSB_PADCTL_USB3_PAD_MUX, 24, 0x3, 5, pci_mux), LANE("sata-0", XUSB_PADCTL_USB3_PAD_MUX, 26, 0x3, 6, pci_mux), }; static int xusbpadctl_mux_function(const struct padctl_lane *lane, char *fnc_name) { int i; for (i = 0; i < lane->nmux; i++) { if (strcmp(fnc_name, lane->mux[i]) == 0) return (i); } return (-1); } static int xusbpadctl_config_lane(struct xusbpadctl_softc *sc, char *lane_name, const struct padctl_lane *lane, struct lane_cfg *cfg) { int tmp; uint32_t reg; reg = bus_read_4(sc->mem_res, lane->reg); if (cfg->function != NULL) { tmp = xusbpadctl_mux_function(lane, cfg->function); if (tmp == -1) { device_printf(sc->dev, "Unknown function %s for lane %s\n", cfg->function, lane_name); return (EINVAL); } reg &= ~(lane->mask << lane->shift); reg |= (tmp & lane->mask) << lane->shift; } if (cfg->iddq != -1) { if (lane->iddq == -1) { device_printf(sc->dev, "Invalid IDDQ for lane %s\n", lane_name); return (EINVAL); } if (cfg->iddq != 0) reg &= ~(1 << lane->iddq); else reg |= 1 << lane->iddq; } bus_write_4(sc->mem_res, lane->reg, reg); return (0); } static const struct padctl_lane * xusbpadctl_search_lane(char *lane_name) { int i; for (i = 0; i < nitems(lanes_tbl); i++) { if (strcmp(lane_name, lanes_tbl[i].name) == 0) return (&lanes_tbl[i]); } return (NULL); } static int xusbpadctl_config_node(struct xusbpadctl_softc *sc, char *lane_name, struct lane_cfg *cfg) { const struct padctl_lane *lane; int rv; lane = xusbpadctl_search_lane(lane_name); if (lane == NULL) { device_printf(sc->dev, "Unknown lane: %s\n", lane_name); return (ENXIO); } rv = xusbpadctl_config_lane(sc, lane_name, lane, cfg); return (rv); } static int xusbpadctl_read_node(struct xusbpadctl_softc *sc, phandle_t node, struct lane_cfg *cfg, char **lanes, int *llanes) { int rv; *llanes = OF_getprop_alloc(node, "nvidia,lanes", 1, (void **)lanes); if (*llanes <= 0) return (ENOENT); /* Read function (mux) settings. */ rv = OF_getprop_alloc(node, "nvidia,function", 1, (void **)&cfg->function); if (rv <= 0) cfg->function = NULL; /* Read numeric properties. */ rv = OF_getencprop(node, "nvidia,iddq", &cfg->iddq, sizeof(cfg->iddq)); if (rv <= 0) cfg->iddq = -1; return (0); } static int xusbpadctl_process_node(struct xusbpadctl_softc *sc, phandle_t node) { struct lane_cfg cfg; char *lanes, *lname; int i, len, llanes, rv; rv = xusbpadctl_read_node(sc, node, &cfg, &lanes, &llanes); if (rv != 0) return (rv); len = 0; lname = lanes; do { i = strlen(lname) + 1; rv = xusbpadctl_config_node(sc, lname, &cfg); if (rv != 0) device_printf(sc->dev, "Cannot configure lane: %s: %d\n", lname, rv); len += i; lname += i; } while (len < llanes); if (lanes != NULL) - free(lanes, M_OFWPROP); + OF_prop_free(lanes); if (cfg.function != NULL) - free(cfg.function, M_OFWPROP); + OF_prop_free(cfg.function); return (rv); } static int xusbpadctl_pinctrl_cfg(device_t dev, phandle_t cfgxref) { struct xusbpadctl_softc *sc; phandle_t node, cfgnode; int rv; sc = device_get_softc(dev); cfgnode = OF_node_from_xref(cfgxref); rv = 0; for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) { if (!fdt_is_enabled(node)) continue; rv = xusbpadctl_process_node(sc, node); if (rv != 0) return (rv); } return (rv); } static int xusbpadctl_phy_pcie_powerup(struct xusbpadctl_softc *sc) { uint32_t reg; int i; reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); reg &= ~IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK; bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg); DELAY(100); reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL2); reg |= IOPHY_PLL_P0_CTL2_REFCLKBUF_EN; reg |= IOPHY_PLL_P0_CTL2_TXCLKREF_EN; reg |= IOPHY_PLL_P0_CTL2_TXCLKREF_SEL; bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL2, reg); DELAY(100); reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); reg |= IOPHY_PLL_P0_CTL1_PLL_RST; bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg); DELAY(100); for (i = 0; i < 100; i++) { reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); if (reg & IOPHY_PLL_P0_CTL1_PLL0_LOCKDET) return (0); DELAY(10); } return (ETIMEDOUT); } static int xusbpadctl_phy_pcie_powerdown(struct xusbpadctl_softc *sc) { uint32_t reg; reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); reg &= ~IOPHY_PLL_P0_CTL1_PLL_RST; bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg); DELAY(100); return (0); } static int xusbpadctl_phy_sata_powerup(struct xusbpadctl_softc *sc) { uint32_t reg; int i; reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); reg &= ~IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; reg &= ~IOPHY_MISC_PAD_S0_CTL1_IDDQ; bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg); reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); reg &= ~IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; reg &= ~IOPHY_PLL_S0_CTL1_PLL_IDDQ; bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); reg |= IOPHY_PLL_S0_CTL1_PLL1_MODE; bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); reg |= IOPHY_PLL_S0_CTL1_PLL_RST_L; bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); for (i = 100; i >= 0; i--) { reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); if (reg & IOPHY_PLL_S0_CTL1_PLL1_LOCKDET) break; DELAY(100); } if (i <= 0) { device_printf(sc->dev, "Failed to power up SATA phy\n"); return (ETIMEDOUT); } return (0); } static int xusbpadctl_phy_sata_powerdown(struct xusbpadctl_softc *sc) { uint32_t reg; reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); reg &= ~IOPHY_PLL_S0_CTL1_PLL_RST_L; bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); DELAY(100); reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); reg &= ~IOPHY_PLL_S0_CTL1_PLL1_MODE; bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); DELAY(100); reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); reg |= IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; reg |= IOPHY_PLL_S0_CTL1_PLL_IDDQ; bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); DELAY(100); reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); reg |= IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; reg |= IOPHY_MISC_PAD_S0_CTL1_IDDQ; bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg); DELAY(100); return (0); } static int xusbpadctl_phy_powerup(struct xusbpadctl_softc *sc) { uint32_t reg; reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM); reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg); DELAY(100); reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM); reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg); DELAY(100); reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM); reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg); DELAY(100); return (0); } static int xusbpadctl_phy_powerdown(struct xusbpadctl_softc *sc) { uint32_t reg; reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM); reg |= ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg); DELAY(100); reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM); reg |= ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg); DELAY(100); reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM); reg |= ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg); DELAY(100); return (0); } static int xusbpadctl_phy_enable(device_t dev, intptr_t id, bool enable) { struct xusbpadctl_softc *sc; int rv; sc = device_get_softc(dev); if ((id != TEGRA_XUSB_PADCTL_PCIE) && (id != TEGRA_XUSB_PADCTL_SATA)) { device_printf(dev, "Unknown phy: %d\n", id); return (ENXIO); } rv = 0; if (enable) { if (sc->phy_ena_cnt == 0) { rv = xusbpadctl_phy_powerup(sc); if (rv != 0) return (rv); } sc->phy_ena_cnt++; } if (id == TEGRA_XUSB_PADCTL_PCIE) { if (enable) rv = xusbpadctl_phy_pcie_powerup(sc); else rv = xusbpadctl_phy_pcie_powerdown(sc); if (rv != 0) return (rv); } else if (id == TEGRA_XUSB_PADCTL_SATA) { if (enable) rv = xusbpadctl_phy_sata_powerup(sc); else rv = xusbpadctl_phy_sata_powerdown(sc); if (rv != 0) return (rv); } if (!enable) { if (sc->phy_ena_cnt == 1) { rv = xusbpadctl_phy_powerdown(sc); if (rv != 0) return (rv); } sc->phy_ena_cnt--; } return (0); } static int xusbpadctl_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "Tegra XUSB phy"); return (BUS_PROBE_DEFAULT); } static int xusbpadctl_detach(device_t dev) { /* This device is always present. */ return (EBUSY); } static int xusbpadctl_attach(device_t dev) { struct xusbpadctl_softc * sc; int rid, rv; phandle_t node; sc = device_get_softc(dev); sc->dev = dev; rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) { device_printf(dev, "Cannot allocate memory resources\n"); return (ENXIO); } node = ofw_bus_get_node(dev); rv = hwreset_get_by_ofw_name(dev, "padctl", &sc->rst); if (rv != 0) { device_printf(dev, "Cannot get 'padctl' reset: %d\n", rv); return (rv); } rv = hwreset_deassert(sc->rst); if (rv != 0) { device_printf(dev, "Cannot unreset 'padctl' reset: %d\n", rv); return (rv); } /* Register as a pinctrl device and use default configuration */ fdt_pinctrl_register(dev, NULL); fdt_pinctrl_configure_by_name(dev, "default"); phy_register_provider(dev); return (0); } static device_method_t tegra_xusbpadctl_methods[] = { /* Device interface */ DEVMETHOD(device_probe, xusbpadctl_probe), DEVMETHOD(device_attach, xusbpadctl_attach), DEVMETHOD(device_detach, xusbpadctl_detach), /* fdt_pinctrl interface */ DEVMETHOD(fdt_pinctrl_configure, xusbpadctl_pinctrl_cfg), /* phy interface */ DEVMETHOD(phy_enable, xusbpadctl_phy_enable), DEVMETHOD_END }; static driver_t tegra_xusbpadctl_driver = { "tegra_xusbpadctl", tegra_xusbpadctl_methods, sizeof(struct xusbpadctl_softc), }; static devclass_t tegra_xusbpadctl_devclass; EARLY_DRIVER_MODULE(tegra_xusbpadctl, simplebus, tegra_xusbpadctl_driver, tegra_xusbpadctl_devclass, 0, 0, 73); Index: head/sys/arm/nvidia/tegra_pinmux.c =================================================================== --- head/sys/arm/nvidia/tegra_pinmux.c (revision 299714) +++ head/sys/arm/nvidia/tegra_pinmux.c (revision 299715) @@ -1,804 +1,804 @@ /*- * Copyright (c) 2016 Michal Meloun * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Pin multiplexer driver for Tegra SoCs. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Pin multipexor register. */ #define TEGRA_MUX_FUNCTION_MASK 0x03 #define TEGRA_MUX_FUNCTION_SHIFT 0 #define TEGRA_MUX_PUPD_MASK 0x03 #define TEGRA_MUX_PUPD_SHIFT 2 #define TEGRA_MUX_TRISTATE_SHIFT 4 #define TEGRA_MUX_ENABLE_INPUT_SHIFT 5 #define TEGRA_MUX_OPEN_DRAIN_SHIFT 6 #define TEGRA_MUX_LOCK_SHIFT 7 #define TEGRA_MUX_IORESET_SHIFT 8 #define TEGRA_MUX_RCV_SEL_SHIFT 9 /* Pin goup register. */ #define TEGRA_GRP_HSM_SHIFT 2 #define TEGRA_GRP_SCHMT_SHIFT 3 #define TEGRA_GRP_DRV_TYPE_SHIFT 6 #define TEGRA_GRP_DRV_TYPE_MASK 0x03 #define TEGRA_GRP_DRV_DRVDN_SLWR_SHIFT 28 #define TEGRA_GRP_DRV_DRVDN_SLWR_MASK 0x03 #define TEGRA_GRP_DRV_DRVUP_SLWF_SHIFT 30 #define TEGRA_GRP_DRV_DRVUP_SLWF_MASK 0x03 struct pinmux_softc { device_t dev; struct resource *pad_mem_res; struct resource *mux_mem_res; struct resource *mipi_mem_res; }; static struct ofw_compat_data compat_data[] = { {"nvidia,tegra124-pinmux", 1}, {NULL, 0}, }; enum prop_id { PROP_ID_PULL, PROP_ID_TRISTATE, PROP_ID_ENABLE_INPUT, PROP_ID_OPEN_DRAIN, PROP_ID_LOCK, PROP_ID_IORESET, PROP_ID_RCV_SEL, PROP_ID_HIGH_SPEED_MODE, PROP_ID_SCHMITT, PROP_ID_LOW_POWER_MODE, PROP_ID_DRIVE_DOWN_STRENGTH, PROP_ID_DRIVE_UP_STRENGTH, PROP_ID_SLEW_RATE_FALLING, PROP_ID_SLEW_RATE_RISING, PROP_ID_DRIVE_TYPE, PROP_ID_MAX_ID }; /* Numeric based parameters. */ static const struct prop_name { const char *name; enum prop_id id; } prop_names[] = { {"nvidia,pull", PROP_ID_PULL}, {"nvidia,tristate", PROP_ID_TRISTATE}, {"nvidia,enable-input", PROP_ID_ENABLE_INPUT}, {"nvidia,open-drain", PROP_ID_OPEN_DRAIN}, {"nvidia,lock", PROP_ID_LOCK}, {"nvidia,io-reset", PROP_ID_IORESET}, {"nvidia,rcv-sel", PROP_ID_RCV_SEL}, {"nvidia,high-speed-mode", PROP_ID_HIGH_SPEED_MODE}, {"nvidia,schmitt", PROP_ID_SCHMITT}, {"nvidia,low-power-mode", PROP_ID_LOW_POWER_MODE}, {"nvidia,pull-down-strength", PROP_ID_DRIVE_DOWN_STRENGTH}, {"nvidia,pull-up-strength", PROP_ID_DRIVE_UP_STRENGTH}, {"nvidia,slew-rate-falling", PROP_ID_SLEW_RATE_FALLING}, {"nvidia,slew-rate-rising", PROP_ID_SLEW_RATE_RISING}, {"nvidia,drive-type", PROP_ID_DRIVE_TYPE}, }; /* * configuration for one pin group. */ struct pincfg { char *function; int params[PROP_ID_MAX_ID]; }; #define GPIO_BANK_A 0 #define GPIO_BANK_B 1 #define GPIO_BANK_C 2 #define GPIO_BANK_D 3 #define GPIO_BANK_E 4 #define GPIO_BANK_F 5 #define GPIO_BANK_G 6 #define GPIO_BANK_H 7 #define GPIO_BANK_I 8 #define GPIO_BANK_J 9 #define GPIO_BANK_K 10 #define GPIO_BANK_L 11 #define GPIO_BANK_M 12 #define GPIO_BANK_N 13 #define GPIO_BANK_O 14 #define GPIO_BANK_P 15 #define GPIO_BANK_Q 16 #define GPIO_BANK_R 17 #define GPIO_BANK_S 18 #define GPIO_BANK_T 19 #define GPIO_BANK_U 20 #define GPIO_BANK_V 21 #define GPIO_BANK_W 22 #define GPIO_BANK_X 23 #define GPIO_BANK_Y 24 #define GPIO_BANK_Z 25 #define GPIO_BANK_AA 26 #define GPIO_BANK_BB 27 #define GPIO_BANK_CC 28 #define GPIO_BANK_DD 29 #define GPIO_BANK_EE 30 #define GPIO_BANK_FF 31 #define GPIO_NUM(b, p) (8 * (b) + (p)) struct tegra_mux { char *name; bus_size_t reg; char *functions[4]; int gpio_num; }; #define GMUX(r, gb, gi, nm, f1, f2, f3, f4) \ { \ .name = #nm, \ .reg = r, \ .gpio_num = GPIO_NUM(GPIO_BANK_##gb, gi), \ .functions = {#f1, #f2, #f3, #f4}, \ } #define FMUX(r, nm, f1, f2, f3, f4) \ { \ .name = #nm, \ .reg = r, \ .gpio_num = -1, \ .functions = {#f1, #f2, #f3, #f4}, \ } static const struct tegra_mux pin_mux_tbl[] = { GMUX(0x000, O, 1, ulpi_data0_po1, spi3, hsi, uarta, ulpi), GMUX(0x004, O, 2, ulpi_data1_po2, spi3, hsi, uarta, ulpi), GMUX(0x008, O, 3, ulpi_data2_po3, spi3, hsi, uarta, ulpi), GMUX(0x00C, O, 4, ulpi_data3_po4, spi3, hsi, uarta, ulpi), GMUX(0x010, O, 5, ulpi_data4_po5, spi2, hsi, uarta, ulpi), GMUX(0x014, O, 6, ulpi_data5_po6, spi2, hsi, uarta, ulpi), GMUX(0x018, O, 7, ulpi_data6_po7, spi2, hsi, uarta, ulpi), GMUX(0x01C, O, 0, ulpi_data7_po0, spi2, hsi, uarta, ulpi), GMUX(0x020, P, 9, ulpi_clk_py0, spi1, spi5, uartd, ulpi), GMUX(0x024, P, 1, ulpi_dir_py1, spi1, spi5, uartd, ulpi), GMUX(0x028, P, 2, ulpi_nxt_py2, spi1, spi5, uartd, ulpi), GMUX(0x02C, P, 3, ulpi_stp_py3, spi1, spi5, uartd, ulpi), GMUX(0x030, P, 0, dap3_fs_pp0, i2s2, spi5, displaya, displayb), GMUX(0x034, P, 1, dap3_din_pp1, i2s2, spi5, displaya, displayb), GMUX(0x038, P, 2, dap3_dout_pp2, i2s2, spi5, displaya, rsvd4), GMUX(0x03C, P, 3, dap3_sclk_pp3, i2s2, spi5, rsvd3, displayb), GMUX(0x040, V, 0, pv0, rsvd1, rsvd2, rsvd3, rsvd4), GMUX(0x044, V, 1, pv1, rsvd1, rsvd2, rsvd3, rsvd4), GMUX(0x048, Z, 0, sdmmc1_clk_pz0, sdmmc1, clk12, rsvd3, rsvd4), GMUX(0x04C, Z, 1, sdmmc1_cmd_pz1, sdmmc1, spdif, spi4, uarta), GMUX(0x050, Y, 4, sdmmc1_dat3_py4, sdmmc1, spdif, spi4, uarta), GMUX(0x054, Y, 5, sdmmc1_dat2_py5, sdmmc1, pwm0, spi4, uarta), GMUX(0x058, Y, 6, sdmmc1_dat1_py6, sdmmc1, pwm1, spi4, uarta), GMUX(0x05C, Y, 7, sdmmc1_dat0_py7, sdmmc1, rsvd2, spi4, uarta), GMUX(0x068, W, 5, clk2_out_pw5, extperiph2, rsvd2, rsvd3, rsvd4), GMUX(0x06C, CC, 5, clk2_req_pcc5, dap, rsvd2, rsvd3, rsvd4), GMUX(0x110, N, 7, hdmi_int_pn7, rsvd1, rsvd2, rsvd3, rsvd4), GMUX(0x114, V, 4, ddc_scl_pv4, i2c4, rsvd2, rsvd3, rsvd4), GMUX(0x118, V, 5, ddc_sda_pv5, i2c4, rsvd2, rsvd3, rsvd4), GMUX(0x164, V, 3, uart2_rxd_pc3, irda, spdif, uarta, spi4), GMUX(0x168, C, 2, uart2_txd_pc2, irda, spdif, uarta, spi4), GMUX(0x16C, J, 6, uart2_rts_n_pj6, uarta, uartb, gmi, spi4), GMUX(0x170, J, 5, uart2_cts_n_pj5, uarta, uartb, gmi, spi4), GMUX(0x174, W, 6, uart3_txd_pw6, uartc, rsvd2, gmi, spi4), GMUX(0x178, W, 7, uart3_rxd_pw7, uartc, rsvd2, gmi, spi4), GMUX(0x17C, S, 1, uart3_cts_n_pa1, uartc, sdmmc1, dtv, gmi), GMUX(0x180, C, 0, uart3_rts_n_pc0, uartc, pwm0, dtv, gmi), GMUX(0x184, U, 0, pu0, owr, uarta, gmi, rsvd4), GMUX(0x188, U, 1, pu1, rsvd1, uarta, gmi, rsvd4), GMUX(0x18C, U, 2, pu2, rsvd1, uarta, gmi, rsvd4), GMUX(0x190, U, 3, pu3, pwm0, uarta, gmi, displayb), GMUX(0x194, U, 4, pu4, pwm1, uarta, gmi, displayb), GMUX(0x198, U, 5, pu5, pwm2, uarta, gmi, displayb), GMUX(0x19C, U, 6, pu6, pwm3, uarta, rsvd3, gmi), GMUX(0x1A0, C, 5, gen1_i2c_sda_pc5, i2c1, rsvd2, rsvd3, rsvd4), GMUX(0x1A4, C, 4, gen1_i2c_scl_pc4, i2c1, rsvd2, rsvd3, rsvd4), GMUX(0x1A8, P, 3, dap4_fs_pp4, i2s3, gmi, dtv, rsvd4), GMUX(0x1AC, P, 4, dap4_din_pp5, i2s3, gmi, rsvd3, rsvd4), GMUX(0x1B0, P, 5, dap4_dout_pp6, i2s3, gmi, dtv, rsvd4), GMUX(0x1B4, P, 7, dap4_sclk_pp7, i2s3, gmi, rsvd3, rsvd4), GMUX(0x1B8, P, 0, clk3_out_pee0, extperiph3, rsvd2, rsvd3, rsvd4), GMUX(0x1BC, EE, 1, clk3_req_pee1, dev3, rsvd2, rsvd3, rsvd4), GMUX(0x1C0, C, 7, pc7, rsvd1, rsvd2, gmi, gmi_alt), GMUX(0x1C4, I, 5, pi5, sdmmc2, rsvd2, gmi, rsvd4), GMUX(0x1C8, I, 7, pi7, rsvd1, trace, gmi, dtv), GMUX(0x1CC, K, 0, pk0, rsvd1, sdmmc3, gmi, soc), GMUX(0x1D0, K, 1, pk1, sdmmc2, trace, gmi, rsvd4), GMUX(0x1D4, J, 0, pj0, rsvd1, rsvd2, gmi, usb), GMUX(0x1D8, J, 2, pj2, rsvd1, rsvd2, gmi, soc), GMUX(0x1DC, K, 3, pk3, sdmmc2, trace, gmi, ccla), GMUX(0x1E0, K, 4, pk4, sdmmc2, rsvd2, gmi, gmi_alt), GMUX(0x1E4, K, 2, pk2, rsvd1, rsvd2, gmi, rsvd4), GMUX(0x1E8, I, 3, pi3, rsvd1, rsvd2, gmi, spi4), GMUX(0x1EC, I, 6, pi6, rsvd1, rsvd2, gmi, sdmmc2), GMUX(0x1F0, G, 0, pg0, rsvd1, rsvd2, gmi, rsvd4), GMUX(0x1F4, G, 1, pg1, rsvd1, rsvd2, gmi, rsvd4), GMUX(0x1F8, G, 2, pg2, rsvd1, trace, gmi, rsvd4), GMUX(0x1FC, G, 3, pg3, rsvd1, trace, gmi, rsvd4), GMUX(0x200, G, 4, pg4, rsvd1, tmds, gmi, spi4), GMUX(0x204, G, 5, pg5, rsvd1, rsvd2, gmi, spi4), GMUX(0x208, G, 6, pg6, rsvd1, rsvd2, gmi, spi4), GMUX(0x20C, G, 7, pg7, rsvd1, rsvd2, gmi, spi4), GMUX(0x210, H, 0, ph0, pwm0, trace, gmi, dtv), GMUX(0x214, H, 1, ph1, pwm1, tmds, gmi, displaya), GMUX(0x218, H, 2, ph2, pwm2, tmds, gmi, cldvfs), GMUX(0x21C, H, 3, ph3, pwm3, spi4, gmi, cldvfs), GMUX(0x220, H, 4, ph4, sdmmc2, rsvd2, gmi, rsvd4), GMUX(0x224, H, 5, ph5, sdmmc2, rsvd2, gmi, rsvd4), GMUX(0x228, H, 6, ph6, sdmmc2, trace, gmi, dtv), GMUX(0x22C, H, 7, ph7, sdmmc2, trace, gmi, dtv), GMUX(0x230, J, 7, pj7, uartd, rsvd2, gmi, gmi_alt), GMUX(0x234, B, 0, pb0, uartd, rsvd2, gmi, rsvd4), GMUX(0x238, B, 1, pb1, uartd, rsvd2, gmi, rsvd4), GMUX(0x23C, K, 7, pk7, uartd, rsvd2, gmi, rsvd4), GMUX(0x240, I, 0, pi0, rsvd1, rsvd2, gmi, rsvd4), GMUX(0x244, I, 1, pi1, rsvd1, rsvd2, gmi, rsvd4), GMUX(0x248, I, 2, pi2, sdmmc2, trace, gmi, rsvd4), GMUX(0x24C, I, 4, pi4, spi4, trace, gmi, displaya), GMUX(0x250, T, 5, gen2_i2c_scl_pt5, i2c2, rsvd2, gmi, rsvd4), GMUX(0x254, T, 6, gen2_i2c_sda_pt6, i2c2, rsvd2, gmi, rsvd4), GMUX(0x258, CC, 4, sdmmc4_clk_pcc4, sdmmc4, rsvd2, gmi, rsvd4), GMUX(0x25C, T, 7, sdmmc4_cmd_pt7, sdmmc4, rsvd2, gmi, rsvd4), GMUX(0x260, AA, 0, sdmmc4_dat0_paa0, sdmmc4, spi3, gmi, rsvd4), GMUX(0x264, AA, 1, sdmmc4_dat1_paa1, sdmmc4, spi3, gmi, rsvd4), GMUX(0x268, AA, 2, sdmmc4_dat2_paa2, sdmmc4, spi3, gmi, rsvd4), GMUX(0x26C, AA, 3, sdmmc4_dat3_paa3, sdmmc4, spi3, gmi, rsvd4), GMUX(0x270, AA, 4, sdmmc4_dat4_paa4, sdmmc4, spi3, gmi, rsvd4), GMUX(0x274, AA, 5, sdmmc4_dat5_paa5, sdmmc4, spi3, rsvd3, rsvd4), GMUX(0x278, AA, 6, sdmmc4_dat6_paa6, sdmmc4, spi3, gmi, rsvd4), GMUX(0x27C, AA, 7, sdmmc4_dat7_paa7, sdmmc4, rsvd2, gmi, rsvd4), GMUX(0x284, CC, 0, cam_mclk_pcc0, vi, vi_alt1, vi_alt3, sdmmc2), GMUX(0x288, CC, 1, pcc1, i2s4, rsvd2, rsvd3, sdmmc2), GMUX(0x28C, BB, 0, pbb0, vgp6, vimclk2, sdmmc2, vimclk2_alt), GMUX(0x290, BB, 1, cam_i2c_scl_pbb1, vgp1, i2c3, rsvd3, sdmmc2), GMUX(0x294, BB, 2, cam_i2c_sda_pbb2, vgp2, i2c3, rsvd3, sdmmc2), GMUX(0x298, BB, 3, pbb3, vgp3, displaya, displayb, sdmmc2), GMUX(0x29C, BB, 4, pbb4, vgp4, displaya, displayb, sdmmc2), GMUX(0x2A0, BB, 5, pbb5, vgp5, displaya, rsvd3, sdmmc2), GMUX(0x2A4, BB, 6, pbb6, i2s4, rsvd2, displayb, sdmmc2), GMUX(0x2A8, BB, 7, pbb7, i2s4, rsvd2, rsvd3, sdmmc2), GMUX(0x2AC, CC, 2, pcc2, i2s4, rsvd2, sdmmc3, sdmmc2), FMUX(0x2B0, jtag_rtck, rtck, rsvd2, rsvd3, rsvd4), GMUX(0x2B4, Z, 6, pwr_i2c_scl_pz6, i2cpwr, rsvd2, rsvd3, rsvd4), GMUX(0x2B8, Z, 7, pwr_i2c_sda_pz7, i2cpwr, rsvd2, rsvd3, rsvd4), GMUX(0x2BC, R, 0, kb_row0_pr0, kbc, rsvd2, rsvd3, rsvd4), GMUX(0x2C0, R, 1, kb_row1_pr1, kbc, rsvd2, rsvd3, rsvd4), GMUX(0x2C4, R, 2, kb_row2_pr2, kbc, rsvd2, rsvd3, rsvd4), GMUX(0x2C8, R, 3, kb_row3_pr3, kbc, displaya, sys, displayb), GMUX(0x2CC, R, 4, kb_row4_pr4, kbc, displaya, rsvd3, displayb), GMUX(0x2D0, R, 5, kb_row5_pr5, kbc, displaya, rsvd3, displayb), GMUX(0x2D4, R, 6, kb_row6_pr6, kbc, displaya, displaya_alt, displayb), GMUX(0x2D8, R, 7, kb_row7_pr7, kbc, rsvd2, cldvfs, uarta), GMUX(0x2DC, S, 0, kb_row8_ps0, kbc, rsvd2, cldvfs, uarta), GMUX(0x2E0, S, 1, kb_row9_ps1, kbc, rsvd2, rsvd3, uarta), GMUX(0x2E4, S, 2, kb_row10_ps2, kbc, rsvd2, rsvd3, uarta), GMUX(0x2E8, S, 3, kb_row11_ps3, kbc, rsvd2, rsvd3, irda), GMUX(0x2EC, S, 4, kb_row12_ps4, kbc, rsvd2, rsvd3, irda), GMUX(0x2F0, S, 5, kb_row13_ps5, kbc, rsvd2, spi2, rsvd4), GMUX(0x2F4, S, 6, kb_row14_ps6, kbc, rsvd2, spi2, rsvd4), GMUX(0x2F8, S, 7, kb_row15_ps7, kbc, soc, rsvd3, rsvd4), GMUX(0x2FC, Q, 0, kb_col0_pq0, kbc, rsvd2, spi2, rsvd4), GMUX(0x300, Q, 1, kb_col1_pq1, kbc, rsvd2, spi2, rsvd4), GMUX(0x304, Q, 2, kb_col2_pq2, kbc, rsvd2, spi2, rsvd4), GMUX(0x308, Q, 3, kb_col3_pq3, kbc, displaya, pwm2, uarta), GMUX(0x30C, Q, 4, kb_col4_pq4, kbc, owr, sdmmc3, uarta), GMUX(0x310, Q, 5, kb_col5_pq5, kbc, rsvd2, sdmmc3, rsvd4), GMUX(0x314, Q, 6, kb_col6_pq6, kbc, rsvd2, spi2, uartd), GMUX(0x318, Q, 7, kb_col7_pq7, kbc, rsvd2, spi2, uartd), GMUX(0x31C, A, 0, clk_32k_out_pa0, blink, soc, rsvd3, rsvd4), FMUX(0x324, core_pwr_req, pwron, rsvd2, rsvd3, rsvd4), FMUX(0x328, cpu_pwr_req, cpu, rsvd2, rsvd3, rsvd4), FMUX(0x32C, pwr_int_n, pmi, rsvd2, rsvd3, rsvd4), FMUX(0x330, clk_32k_in, clk, rsvd2, rsvd3, rsvd4), FMUX(0x334, owr, owr, rsvd2, rsvd3, rsvd4), GMUX(0x338, N, 0, dap1_fs_pn0, i2s0, hda, gmi, rsvd4), GMUX(0x33C, N, 1, dap1_din_pn1, i2s0, hda, gmi, rsvd4), GMUX(0x340, N, 2, dap1_dout_pn2, i2s0, hda, gmi, sata), GMUX(0x344, N, 3, dap1_sclk_pn3, i2s0, hda, gmi, rsvd4), GMUX(0x348, EE, 2, dap_mclk1_req_pee2, dap, dap1, sata, rsvd4), GMUX(0x34C, W, 4, dap_mclk1_pw4, extperiph1, dap2, rsvd3, rsvd4), GMUX(0x350, K, 6, spdif_in_pk6, spdif, rsvd2, rsvd3, i2c3), GMUX(0x354, K, 5, spdif_out_pk5, spdif, rsvd2, rsvd3, i2c3), GMUX(0x358, A, 2, dap2_fs_pa2, i2s1, hda, gmi, rsvd4), GMUX(0x35C, A, 4, dap2_din_pa4, i2s1, hda, gmi, rsvd4), GMUX(0x360, A, 5, dap2_dout_pa5, i2s1, hda, gmi, rsvd4), GMUX(0x364, A, 3, dap2_sclk_pa3, i2s1, hda, gmi, rsvd4), GMUX(0x368, X, 0, dvfs_pwm_px0, spi6, cldvfs, gmi, rsvd4), GMUX(0x36C, X, 1, gpio_x1_aud_px1, spi6, rsvd2, gmi, rsvd4), GMUX(0x370, X, 3, gpio_x3_aud_px3, spi6, spi1, gmi, rsvd4), GMUX(0x374, X, 2, dvfs_clk_px2, spi6, cldvfs, gmi, rsvd4), GMUX(0x378, X, 4, gpio_x4_aud_px4, gmi, spi1, spi2, dap2), GMUX(0x37C, X, 5, gpio_x5_aud_px5, gmi, spi1, spi2, rsvd4), GMUX(0x380, X, 6, gpio_x6_aud_px6, spi6, spi1, spi2, gmi), GMUX(0x384, X, 7, gpio_x7_aud_px7, rsvd1, spi1, spi2, rsvd4), GMUX(0x390, A, 6, sdmmc3_clk_pa6, sdmmc3, rsvd2, rsvd3, spi3), GMUX(0x394, A, 7, sdmmc3_cmd_pa7, sdmmc3, pwm3, uarta, spi3), GMUX(0x398, B, 7, sdmmc3_dat0_pb7, sdmmc3, rsvd2, rsvd3, spi3), GMUX(0x39C, B, 6, sdmmc3_dat1_pb6, sdmmc3, pwm2, uarta, spi3), GMUX(0x3A0, B, 5, sdmmc3_dat2_pb5, sdmmc3, pwm1, displaya, spi3), GMUX(0x3A4, B, 4, sdmmc3_dat3_pb4, sdmmc3, pwm0, displayb, spi3), GMUX(0x3BC, DD, 1, pex_l0_rst_n_pdd1, pe0, rsvd2, rsvd3, rsvd4), GMUX(0x3C0, DD, 2, pex_l0_clkreq_n_pdd2, pe0, rsvd2, rsvd3, rsvd4), GMUX(0x3C4, DD, 3, pex_wake_n_pdd3, pe, rsvd2, rsvd3, rsvd4), GMUX(0x3CC, DD, 5, pex_l1_rst_n_pdd5, pe1, rsvd2, rsvd3, rsvd4), GMUX(0x3D0, DD, 6, pex_l1_clkreq_n_pdd6, pe1, rsvd2, rsvd3, rsvd4), GMUX(0x3E0, EE, 3, hdmi_cec_pee3, cec, rsvd2, rsvd3, rsvd4), GMUX(0x3E4, V, 3, sdmmc1_wp_n_pv3, sdmmc1, clk12, spi4, uarta), GMUX(0x3E8, V, 2, sdmmc3_cd_n_pv2, sdmmc3, owr, rsvd3, rsvd4), GMUX(0x3EC, W, 2, gpio_w2_aud_pw2, spi6, rsvd2, spi2, i2c1), GMUX(0x3F0, W, 3, gpio_w3_aud_pw3, spi6, spi1, spi2, i2c1), GMUX(0x3F4, N, 4, usb_vbus_en0_pn4, usb, rsvd2, rsvd3, rsvd4), GMUX(0x3F8, N, 5, usb_vbus_en1_pn5, usb, rsvd2, rsvd3, rsvd4), GMUX(0x3FC, EE, 5, sdmmc3_clk_lb_in_pee5, sdmmc3, rsvd2, rsvd3, rsvd4), GMUX(0x400, EE, 4, sdmmc3_clk_lb_out_pee4, sdmmc3, rsvd2, rsvd3, rsvd4), FMUX(0x404, gmi_clk_lb, sdmmc2, rsvd2, gmi, rsvd4), FMUX(0x408, reset_out_n, rsvd1, rsvd2, rsvd3, reset_out_n), GMUX(0x40C, T, 0, kb_row16_pt0, kbc, rsvd2, rsvd3, uartc), GMUX(0x410, T, 1, kb_row17_pt1, kbc, rsvd2, rsvd3, uartc), GMUX(0x414, FF, 1, usb_vbus_en2_pff1, usb, rsvd2, rsvd3, rsvd4), GMUX(0x418, FF, 2, pff2, sata, rsvd2, rsvd3, rsvd4), GMUX(0x430, FF, 0, dp_hpd_pff0, dp, rsvd2, rsvd3, rsvd4), }; struct tegra_grp { char *name; bus_size_t reg; int drvdn_shift; int drvdn_mask; int drvup_shift; int drvup_mask; }; #define GRP(r, nm, dn_s, dn_w, up_s, up_w) \ { \ .name = #nm, \ .reg = r - 0x868, \ .drvdn_shift = dn_s, \ .drvdn_mask = (1 << dn_w) - 1, \ .drvup_shift = up_s, \ .drvup_mask = (1 << dn_w) - 1, \ } /* Use register offsets from TRM */ static const struct tegra_grp pin_grp_tbl[] = { GRP(0x868, ao1, 12, 5, 20, 5), GRP(0x86C, ao2, 12, 5, 20, 5), GRP(0x870, at1, 12, 7, 20, 7), GRP(0x874, at2, 12, 7, 20, 7), GRP(0x878, at3, 12, 7, 20, 7), GRP(0x87C, at4, 12, 7, 20, 7), GRP(0x880, at5, 14, 5, 19, 5), GRP(0x884, cdev1, 12, 5, 20, 5), GRP(0x888, cdev2, 12, 5, 20, 5), GRP(0x890, dap1, 12, 5, 20, 5), GRP(0x894, dap2, 12, 5, 20, 5), GRP(0x898, dap3, 12, 5, 20, 5), GRP(0x89C, dap4, 12, 5, 20, 5), GRP(0x8A0, dbg, 12, 5, 20, 5), GRP(0x8B0, sdio3, 12, 7, 20, 7), GRP(0x8B4, spi, 12, 5, 20, 5), GRP(0x8B8, uaa, 12, 5, 20, 5), GRP(0x8BC, uab, 12, 5, 20, 5), GRP(0x8C0, uart2, 12, 5, 20, 5), GRP(0x8C4, uart3, 12, 5, 20, 5), GRP(0x8EC, sdio1, 12, 7, 20, 7), GRP(0x8FC, ddc, 12, 5, 20, 5), GRP(0x900, gma, 14, 5, 20, 5), GRP(0x910, gme, 14, 5, 19, 5), GRP(0x914, gmf, 14, 5, 19, 5), GRP(0x918, gmg, 14, 5, 19, 5), GRP(0x91C, gmh, 14, 5, 19, 5), GRP(0x920, owr, 12, 5, 20, 5), GRP(0x924, uda, 12, 5, 20, 5), GRP(0x928, gpv, 12, 5, 20, 5), GRP(0x92C, dev3, 12, 5, 20, 5), GRP(0x938, cec, 12, 5, 20, 5), GRP(0x994, at6, 12, 7, 20, 7), GRP(0x998, dap5, 12, 5, 20, 5), GRP(0x99C, usb_vbus_en, 12, 5, 20, 5), GRP(0x9A8, ao3, 12, 5, -1, 0), GRP(0x9B0, ao0, 12, 5, 20, 5), GRP(0x9B4, hv0, 12, 5, -1, 0), GRP(0x9C4, sdio4, 12, 5, 20, 5), GRP(0x9C8, ao4, 12, 7, 20, 7), }; static const struct tegra_grp * pinmux_search_grp(char *grp_name) { int i; for (i = 0; i < nitems(pin_grp_tbl); i++) { if (strcmp(grp_name, pin_grp_tbl[i].name) == 0) return (&pin_grp_tbl[i]); } return (NULL); } static const struct tegra_mux * pinmux_search_mux(char *pin_name) { int i; for (i = 0; i < nitems(pin_mux_tbl); i++) { if (strcmp(pin_name, pin_mux_tbl[i].name) == 0) return (&pin_mux_tbl[i]); } return (NULL); } static int pinmux_mux_function(const struct tegra_mux *mux, char *fnc_name) { int i; for (i = 0; i < 4; i++) { if (strcmp(fnc_name, mux->functions[i]) == 0) return (i); } return (-1); } static int pinmux_config_mux(struct pinmux_softc *sc, char *pin_name, const struct tegra_mux *mux, struct pincfg *cfg) { int tmp; uint32_t reg; reg = bus_read_4(sc->mux_mem_res, mux->reg); if (cfg->function != NULL) { tmp = pinmux_mux_function(mux, cfg->function); if (tmp == -1) { device_printf(sc->dev, "Unknown function %s for pin %s\n", cfg->function, pin_name); return (ENXIO); } reg &= ~(TEGRA_MUX_FUNCTION_MASK << TEGRA_MUX_FUNCTION_SHIFT); reg |= (tmp & TEGRA_MUX_FUNCTION_MASK) << TEGRA_MUX_FUNCTION_SHIFT; } if (cfg->params[PROP_ID_PULL] != -1) { reg &= ~(TEGRA_MUX_PUPD_MASK << TEGRA_MUX_PUPD_SHIFT); reg |= (cfg->params[PROP_ID_PULL] & TEGRA_MUX_PUPD_MASK) << TEGRA_MUX_PUPD_SHIFT; } if (cfg->params[PROP_ID_TRISTATE] != -1) { reg &= ~(1 << TEGRA_MUX_TRISTATE_SHIFT); reg |= (cfg->params[PROP_ID_TRISTATE] & 1) << TEGRA_MUX_TRISTATE_SHIFT; } if (cfg->params[TEGRA_MUX_ENABLE_INPUT_SHIFT] != -1) { reg &= ~(1 << TEGRA_MUX_ENABLE_INPUT_SHIFT); reg |= (cfg->params[TEGRA_MUX_ENABLE_INPUT_SHIFT] & 1) << TEGRA_MUX_ENABLE_INPUT_SHIFT; } if (cfg->params[PROP_ID_ENABLE_INPUT] != -1) { reg &= ~(1 << TEGRA_MUX_ENABLE_INPUT_SHIFT); reg |= (cfg->params[PROP_ID_ENABLE_INPUT] & 1) << TEGRA_MUX_ENABLE_INPUT_SHIFT; } if (cfg->params[PROP_ID_ENABLE_INPUT] != -1) { reg &= ~(1 << TEGRA_MUX_ENABLE_INPUT_SHIFT); reg |= (cfg->params[PROP_ID_OPEN_DRAIN] & 1) << TEGRA_MUX_ENABLE_INPUT_SHIFT; } if (cfg->params[PROP_ID_LOCK] != -1) { reg &= ~(1 << TEGRA_MUX_LOCK_SHIFT); reg |= (cfg->params[PROP_ID_LOCK] & 1) << TEGRA_MUX_LOCK_SHIFT; } if (cfg->params[PROP_ID_IORESET] != -1) { reg &= ~(1 << TEGRA_MUX_IORESET_SHIFT); reg |= (cfg->params[PROP_ID_IORESET] & 1) << TEGRA_MUX_IORESET_SHIFT; } if (cfg->params[PROP_ID_RCV_SEL] != -1) { reg &= ~(1 << TEGRA_MUX_RCV_SEL_SHIFT); reg |= (cfg->params[PROP_ID_RCV_SEL] & 1) << TEGRA_MUX_RCV_SEL_SHIFT; } bus_write_4(sc->mux_mem_res, mux->reg, reg); return (0); } static int pinmux_config_grp(struct pinmux_softc *sc, char *grp_name, const struct tegra_grp *grp, struct pincfg *cfg) { uint32_t reg; reg = bus_read_4(sc->pad_mem_res, grp->reg); if (cfg->params[PROP_ID_HIGH_SPEED_MODE] != -1) { reg &= ~(1 << TEGRA_GRP_HSM_SHIFT); reg |= (cfg->params[PROP_ID_HIGH_SPEED_MODE] & 1) << TEGRA_GRP_HSM_SHIFT; } if (cfg->params[PROP_ID_SCHMITT] != -1) { reg &= ~(1 << TEGRA_GRP_SCHMT_SHIFT); reg |= (cfg->params[PROP_ID_SCHMITT] & 1) << TEGRA_GRP_SCHMT_SHIFT; } if (cfg->params[PROP_ID_DRIVE_TYPE] != -1) { reg &= ~(TEGRA_GRP_DRV_TYPE_MASK << TEGRA_GRP_DRV_TYPE_SHIFT); reg |= (cfg->params[PROP_ID_DRIVE_TYPE] & TEGRA_GRP_DRV_TYPE_MASK) << TEGRA_GRP_DRV_TYPE_SHIFT; } if (cfg->params[PROP_ID_SLEW_RATE_RISING] != -1) { reg &= ~(TEGRA_GRP_DRV_DRVDN_SLWR_MASK << TEGRA_GRP_DRV_DRVDN_SLWR_SHIFT); reg |= (cfg->params[PROP_ID_SLEW_RATE_RISING] & TEGRA_GRP_DRV_DRVDN_SLWR_MASK) << TEGRA_GRP_DRV_DRVDN_SLWR_SHIFT; } if (cfg->params[PROP_ID_SLEW_RATE_FALLING] != -1) { reg &= ~(TEGRA_GRP_DRV_DRVUP_SLWF_MASK << TEGRA_GRP_DRV_DRVUP_SLWF_SHIFT); reg |= (cfg->params[PROP_ID_SLEW_RATE_FALLING] & TEGRA_GRP_DRV_DRVUP_SLWF_MASK) << TEGRA_GRP_DRV_DRVUP_SLWF_SHIFT; } if ((cfg->params[PROP_ID_DRIVE_DOWN_STRENGTH] != -1) && (grp->drvdn_mask != -1)) { reg &= ~(grp->drvdn_shift << grp->drvdn_mask); reg |= (cfg->params[PROP_ID_DRIVE_DOWN_STRENGTH] & grp->drvdn_mask) << grp->drvdn_shift; } if ((cfg->params[PROP_ID_DRIVE_UP_STRENGTH] != -1) && (grp->drvup_mask != -1)) { reg &= ~(grp->drvup_shift << grp->drvup_mask); reg |= (cfg->params[PROP_ID_DRIVE_UP_STRENGTH] & grp->drvup_mask) << grp->drvup_shift; } bus_write_4(sc->pad_mem_res, grp->reg, reg); return (0); } static int pinmux_config_node(struct pinmux_softc *sc, char *pin_name, struct pincfg *cfg) { const struct tegra_mux *mux; const struct tegra_grp *grp; uint32_t reg; int rv; /* Handle MIPI special case first */ if (strcmp(pin_name, "dsi_b") == 0) { if (cfg->function == NULL) { /* nothing to set */ return (0); } reg = bus_read_4(sc->mipi_mem_res, 0); /* register 0x820 */ if (strcmp(cfg->function, "csi") == 0) reg &= ~(1 << 1); else if (strcmp(cfg->function, "dsi_b") == 0) reg |= (1 << 1); bus_write_4(sc->mipi_mem_res, 0, reg); /* register 0x820 */ } /* Handle pin muxes */ mux = pinmux_search_mux(pin_name); if (mux != NULL) { if (mux->gpio_num != -1) { /* XXXX TODO: Reserve gpio here */ } rv = pinmux_config_mux(sc, pin_name, mux, cfg); return (rv); } /* Handle pin groups */ grp = pinmux_search_grp(pin_name); if (grp != NULL) { rv = pinmux_config_grp(sc, pin_name, grp, cfg); return (rv); } device_printf(sc->dev, "Unknown pin: %s\n", pin_name); return (ENXIO); } static int pinmux_read_node(struct pinmux_softc *sc, phandle_t node, struct pincfg *cfg, char **pins, int *lpins) { int rv, i; *lpins = OF_getprop_alloc(node, "nvidia,pins", 1, (void **)pins); if (*lpins <= 0) return (ENOENT); /* Read function (mux) settings. */ rv = OF_getprop_alloc(node, "nvidia,function", 1, (void **)&cfg->function); if (rv <= 0) cfg->function = NULL; /* Read numeric properties. */ for (i = 0; i < PROP_ID_MAX_ID; i++) { rv = OF_getencprop(node, prop_names[i].name, &cfg->params[i], sizeof(cfg->params[i])); if (rv <= 0) cfg->params[i] = -1; } return (0); } static int pinmux_process_node(struct pinmux_softc *sc, phandle_t node) { struct pincfg cfg; char *pins, *pname; int i, len, lpins, rv; rv = pinmux_read_node(sc, node, &cfg, &pins, &lpins); if (rv != 0) return (rv); len = 0; pname = pins; do { i = strlen(pname) + 1; rv = pinmux_config_node(sc, pname, &cfg); if (rv != 0) device_printf(sc->dev, "Cannot configure pin: %s: %d\n", pname, rv); len += i; pname += i; } while (len < lpins); if (pins != NULL) - free(pins, M_OFWPROP); + OF_prop_free(pins); if (cfg.function != NULL) - free(cfg.function, M_OFWPROP); + OF_prop_free(cfg.function); return (rv); } static int pinmux_configure(device_t dev, phandle_t cfgxref) { struct pinmux_softc *sc; phandle_t node, cfgnode; int rv; sc = device_get_softc(dev); cfgnode = OF_node_from_xref(cfgxref); for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) { if (!fdt_is_enabled(node)) continue; rv = pinmux_process_node(sc, node); } return (0); } static int pinmux_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "Tegra pin configuration"); return (BUS_PROBE_DEFAULT); } static int pinmux_detach(device_t dev) { /* This device is always present. */ return (EBUSY); } static int pinmux_attach(device_t dev) { struct pinmux_softc * sc; int rid; sc = device_get_softc(dev); sc->dev = dev; rid = 0; sc->pad_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->pad_mem_res == NULL) { device_printf(dev, "Cannot allocate memory resources\n"); return (ENXIO); } rid = 1; sc->mux_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mux_mem_res == NULL) { device_printf(dev, "Cannot allocate memory resources\n"); return (ENXIO); } rid = 2; sc->mipi_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mipi_mem_res == NULL) { device_printf(dev, "Cannot allocate memory resources\n"); return (ENXIO); } /* Register as a pinctrl device and process default configuration */ fdt_pinctrl_register(dev, NULL); fdt_pinctrl_configure_by_name(dev, "boot"); return (0); } static device_method_t tegra_pinmux_methods[] = { /* Device interface */ DEVMETHOD(device_probe, pinmux_probe), DEVMETHOD(device_attach, pinmux_attach), DEVMETHOD(device_detach, pinmux_detach), /* fdt_pinctrl interface */ DEVMETHOD(fdt_pinctrl_configure,pinmux_configure), DEVMETHOD_END }; static driver_t tegra_pinmux_driver = { "tegra_pinmux", tegra_pinmux_methods, sizeof(struct pinmux_softc), }; static devclass_t tegra_pinmux_devclass; EARLY_DRIVER_MODULE(tegra_pinmux, simplebus, tegra_pinmux_driver, tegra_pinmux_devclass, 0, 0, 71); Index: head/sys/arm/nvidia/tegra_usbphy.c =================================================================== --- head/sys/arm/nvidia/tegra_usbphy.c (revision 299714) +++ head/sys/arm/nvidia/tegra_usbphy.c (revision 299715) @@ -1,839 +1,839 @@ /*- * Copyright (c) 2016 Michal Meloun * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * USB phy driver for Tegra SoCs. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "phy_if.h" #define CTRL_ICUSB_CTRL 0x15c #define ICUSB_CTR_IC_ENB1 (1 << 3) #define CTRL_USB_USBMODE 0x1f8 #define USB_USBMODE_MASK (3 << 0) #define USB_USBMODE_HOST (3 << 0) #define USB_USBMODE_DEVICE (2 << 0) #define CTRL_USB_HOSTPC1_DEVLC 0x1b4 #define USB_HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29) #define USB_HOSTPC1_DEVLC_STS (1 << 28) #define USB_HOSTPC1_DEVLC_PHCD (1 << 22) #define IF_USB_SUSP_CTRL 0x400 #define FAST_WAKEUP_RESP (1 << 26) #define UTMIP_SUSPL1_SET (1 << 25) #define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16) #define USB_SUSP_SET (1 << 14) #define UTMIP_PHY_ENB (1 << 12) #define UTMIP_RESET (1 << 11) #define USB_SUSP_POL (1 << 10) #define USB_PHY_CLK_VALID_INT_ENB (1 << 9) #define USB_PHY_CLK_VALID_INT_STS (1 << 8) #define USB_PHY_CLK_VALID (1 << 7) #define USB_CLKEN (1 << 6) #define USB_SUSP_CLR (1 << 5) #define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) #define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) #define USB_WAKE_ON_RESUME_EN (1 << 2) #define USB_WAKEUP_INT_ENB (1 << 1) #define USB_WAKEUP_INT_STS (1 << 0) #define IF_USB_PHY_VBUS_SENSORS 0x404 #define B_SESS_END_SW_VALUE (1 << 4) #define B_SESS_END_SW_EN (1 << 3) #define UTMIP_XCVR_CFG0 0x808 #define UTMIP_XCVR_HSSLEW_MSB(x) ((((x) & 0x1fc) >> 2) << 25) #define UTMIP_XCVR_SETUP_MSB(x) ((((x) & 0x70) >> 4) << 22) #define UTMIP_XCVR_LSBIAS_SEL (1 << 21) #define UTMIP_XCVR_DISCON_METHOD (1 << 20) #define UTMIP_FORCE_PDZI_POWERUP (1 << 19) #define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18) #define UTMIP_FORCE_PD2_POWERUP (1 << 17) #define UTMIP_FORCE_PD2_POWERDOWN (1 << 16) #define UTMIP_FORCE_PD_POWERUP (1 << 15) #define UTMIP_FORCE_PD_POWERDOWN (1 << 14) #define UTMIP_XCVR_TERMEN (1 << 13) #define UTMIP_XCVR_HSLOOPBACK (1 << 12) #define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10) #define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8) #define UTMIP_XCVR_FSSLEW(x) (((x) & 0x3) << 6) #define UTMIP_XCVR_HSSLEW(x) (((x) & 0x3) << 4) #define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0) #define UTMIP_BIAS_CFG0 0x80C #define UTMIP_IDDIG_C_VAL (1 << 30) #define UTMIP_IDDIG_C_SEL (1 << 29) #define UTMIP_IDDIG_B_VAL (1 << 28) #define UTMIP_IDDIG_B_SEL (1 << 27) #define UTMIP_IDDIG_A_VAL (1 << 26) #define UTMIP_IDDIG_A_SEL (1 << 25) #define UTMIP_HSDISCON_LEVEL_MSB(x) ((((x) & 0x4) >> 2) << 24) #define UTMIP_IDPD_VAL (1 << 23) #define UTMIP_IDPD_SEL (1 << 22) #define UTMIP_IDDIG_VAL (1 << 21) #define UTMIP_IDDIG_SEL (1 << 20) #define UTMIP_GPI_VAL (1 << 19) #define UTMIP_GPI_SEL (1 << 18) #define UTMIP_ACTIVE_TERM_OFFSET(x) (((x) & 0x7) << 15) #define UTMIP_ACTIVE_PULLUP_OFFSET(x) (((x) & 0x7) << 12) #define UTMIP_OTGPD (1 << 11) #define UTMIP_BIASPD (1 << 10) #define UTMIP_VBUS_LEVEL_LEVEL(x) (((x) & 0x3) << 8) #define UTMIP_SESS_LEVEL_LEVEL(x) (((x) & 0x3) << 6) #define UTMIP_HSCHIRP_LEVEL(x) (((x) & 0x3) << 4) #define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2) #define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0) #define UTMIP_HSRX_CFG0 0x810 #define UTMIP_KEEP_PATT_ON_ACTIVE(x) (((x) & 0x3) << 30) #define UTMIP_ALLOW_CONSEC_UPDN (1 << 29) #define UTMIP_REALIGN_ON_NEW_PKT (1 << 28) #define UTMIP_PCOUNT_UPDN_DIV(x) (((x) & 0xf) << 24) #define UTMIP_SQUELCH_EOP_DLY(x) (((x) & 0x7) << 21) #define UTMIP_NO_STRIPPING (1 << 20) #define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15) #define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10) #define UTMIP_ELASTIC_OVERRUN_DISABLE (1 << 9) #define UTMIP_ELASTIC_UNDERRUN_DISABLE (1 << 8) #define UTMIP_PASS_CHIRP (1 << 7) #define UTMIP_PASS_FEEDBACK (1 << 6) #define UTMIP_PCOUNT_INERTIA(x) (((x) & 0x3) << 4) #define UTMIP_PHASE_ADJUST(x) (((x) & 0x3) << 2) #define UTMIP_THREE_SYNCBITS (1 << 1) #define UTMIP_USE4SYNC_TRAN (1 << 0) #define UTMIP_HSRX_CFG1 0x814 #define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1F) << 1) #define UTMIP_HS_ALLOW_KEEP_ALIVE (1 << 0) #define UTMIP_TX_CFG0 0x820 #define UTMIP_FS_PREAMBLE_J (1 << 19) #define UTMIP_FS_POSTAMBLE_OUTPUT_ENABLE (1 << 18) #define UTMIP_FS_PREAMBLE_OUTPUT_ENABLE (1 << 17) #define UTMIP_FSLS_ALLOW_SOP_TX_STUFF_ERR (1 << 16) #define UTMIP_HS_READY_WAIT_FOR_VALID (1 << 15) #define UTMIP_HS_TX_IPG_DLY(x) (((x) & 0x1f) << 10) #define UTMIP_HS_DISCON_EOP_ONLY (1 << 9) #define UTMIP_HS_DISCON_DISABLE (1 << 8) #define UTMIP_HS_POSTAMBLE_OUTPUT_ENABLE (1 << 7) #define UTMIP_HS_PREAMBLE_OUTPUT_ENABLE (1 << 6) #define UTMIP_SIE_RESUME_ON_LINESTATE (1 << 5) #define UTMIP_SOF_ON_NO_STUFF (1 << 4) #define UTMIP_SOF_ON_NO_ENCODE (1 << 3) #define UTMIP_NO_STUFFING (1 << 2) #define UTMIP_NO_ENCODING (1 << 1) #define UTMIP_NO_SYNC_NO_EOP (1 << 0) #define UTMIP_MISC_CFG0 0x824 #define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27) #define UTMIP_DPDM_OBSERVE (1 << 26) #define UTMIP_KEEP_XCVR_PD_ON_SOFT_DISCON (1 << 25) #define UTMIP_ALLOW_LS_ON_SOFT_DISCON (1 << 24) #define UTMIP_FORCE_FS_DISABLE_ON_DEV_CHIRP (1 << 23) #define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22) #define UTMIP_LS_TO_FS_SKIP_4MS (1 << 21) #define UTMIP_INJECT_ERROR_TYPE(x) (((x) & 0x3) << 19) #define UTMIP_FORCE_HS_CLOCK_ON (1 << 18) #define UTMIP_DISABLE_HS_TERM (1 << 17) #define UTMIP_FORCE_HS_TERM (1 << 16) #define UTMIP_DISABLE_PULLUP_DP (1 << 15) #define UTMIP_DISABLE_PULLUP_DM (1 << 14) #define UTMIP_DISABLE_PULLDN_DP (1 << 13) #define UTMIP_DISABLE_PULLDN_DM (1 << 12) #define UTMIP_FORCE_PULLUP_DP (1 << 11) #define UTMIP_FORCE_PULLUP_DM (1 << 10) #define UTMIP_FORCE_PULLDN_DP (1 << 9) #define UTMIP_FORCE_PULLDN_DM (1 << 8) #define UTMIP_STABLE_COUNT(x) (((x) & 0x7) << 5) #define UTMIP_STABLE_ALL (1 << 4) #define UTMIP_NO_FREE_ON_SUSPEND (1 << 3) #define UTMIP_NEVER_FREE_RUNNING_TERMS (1 << 2) #define UTMIP_ALWAYS_FREE_RUNNING_TERMS (1 << 1) #define UTMIP_COMB_TERMS (1 << 0) #define UTMIP_MISC_CFG1 0x828 #define UTMIP_PHY_XTAL_CLOCKEN (1 << 30) #define UTMIP_DEBOUNCE_CFG0 0x82C #define UTMIP_BIAS_DEBOUNCE_B(x) (((x) & 0xffff) << 16) #define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0) #define UTMIP_BAT_CHRG_CFG0 0x830 #define UTMIP_CHRG_DEBOUNCE_TIMESCALE(x) (((x) & 0x1f) << 8) #define UTMIP_OP_I_SRC_ENG (1 << 5) #define UTMIP_ON_SRC_ENG (1 << 4) #define UTMIP_OP_SRC_ENG (1 << 3) #define UTMIP_ON_SINK_ENG (1 << 2) #define UTMIP_OP_SINK_ENG (1 << 1) #define UTMIP_PD_CHRG (1 << 0) #define UTMIP_SPARE_CFG0 0x834 #define FUSE_HS_IREF_CAP_CFG (1 << 7) #define FUSE_HS_SQUELCH_LEVEL (1 << 6) #define FUSE_SPARE (1 << 5) #define FUSE_TERM_RANGE_ADJ_SEL (1 << 4) #define FUSE_SETUP_SEL (1 << 3) #define HS_RX_LATE_SQUELCH (1 << 2) #define HS_RX_FLUSH_ALAP (1 << 1) #define HS_RX_IPG_ERROR_ENABLE (1 << 0) #define UTMIP_XCVR_CFG1 0x838 #define UTMIP_XCVR_RPU_RANGE_ADJ(x) (((x) & 0x3) << 26) #define UTMIP_XCVR_HS_IREF_CAP(x) (((x) & 0x3) << 24) #define UTMIP_XCVR_SPARE(x) (((x) & 0x3) << 22) #define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18) #define UTMIP_RCTRL_SW_SET (1 << 17) #define UTMIP_RCTRL_SW_VAL(x) (((x) & 0x1f) << 12) #define UTMIP_TCTRL_SW_SET (1 << 11) #define UTMIP_TCTRL_SW_VAL(x) (((x) & 0x1f) << 6) #define UTMIP_FORCE_PDDR_POWERUP (1 << 5) #define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4) #define UTMIP_FORCE_PDCHRP_POWERUP (1 << 3) #define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2) #define UTMIP_FORCE_PDDISC_POWERUP (1 << 1) #define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0) #define UTMIP_BIAS_CFG1 0x83c #define UTMIP_BIAS_DEBOUNCE_TIMESCALE(x) (((x) & 0x3f) << 8) #define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3) #define UTMIP_VBUS_WAKEUP_POWERDOWN (1 << 2) #define UTMIP_FORCE_PDTRK_POWERUP (1 << 1) #define UTMIP_FORCE_PDTRK_POWERDOWN (1 << 0) static int usbpby_enable_cnt; enum usb_ifc_type { USB_IFC_TYPE_UNKNOWN = 0, USB_IFC_TYPE_UTMI, USB_IFC_TYPE_ULPI }; enum usb_dr_mode { USB_DR_MODE_UNKNOWN = 0, USB_DR_MODE_DEVICE, USB_DR_MODE_HOST, USB_DR_MODE_OTG }; struct usbphy_softc { device_t dev; struct resource *mem_res; struct resource *pads_res; clk_t clk_reg; clk_t clk_pads; clk_t clk_pllu; regulator_t supply_vbus; hwreset_t reset_usb; hwreset_t reset_pads; enum usb_ifc_type ifc_type; enum usb_dr_mode dr_mode; bool have_utmi_regs; /* UTMI params */ int hssync_start_delay; int elastic_limit; int idle_wait_delay; int term_range_adj; int xcvr_lsfslew; int xcvr_lsrslew; int xcvr_hsslew; int hssquelch_level; int hsdiscon_level; int xcvr_setup; int xcvr_setup_use_fuses; }; static struct ofw_compat_data compat_data[] = { {"nvidia,tegra30-usb-phy", 1}, {NULL, 0}, }; #define RD4(sc, offs) \ bus_read_4(sc->mem_res, offs) #define WR4(sc, offs, val) \ bus_write_4(sc->mem_res, offs, val) static int reg_wait(struct usbphy_softc *sc, uint32_t reg, uint32_t mask, uint32_t val) { int i; for (i = 0; i < 1000; i++) { if ((RD4(sc, reg) & mask) == val) return (0); DELAY(10); } return (ETIMEDOUT); } static int usbphy_utmi_phy_clk(struct usbphy_softc *sc, bool enable) { uint32_t val; int rv; val = RD4(sc, CTRL_USB_HOSTPC1_DEVLC); if (enable) val &= ~USB_HOSTPC1_DEVLC_PHCD; else val |= USB_HOSTPC1_DEVLC_PHCD; WR4(sc, CTRL_USB_HOSTPC1_DEVLC, val); rv = reg_wait(sc, IF_USB_SUSP_CTRL, USB_PHY_CLK_VALID, enable ? USB_PHY_CLK_VALID: 0); if (rv != 0) { device_printf(sc->dev, "USB phy clock timeout.\n"); return (ETIMEDOUT); } return (0); } static int usbphy_utmi_enable(struct usbphy_softc *sc) { int rv; uint32_t val; /* Reset phy */ val = RD4(sc, IF_USB_SUSP_CTRL); val |= UTMIP_RESET; WR4(sc, IF_USB_SUSP_CTRL, val); val = RD4(sc, UTMIP_TX_CFG0); val |= UTMIP_FS_PREAMBLE_J; WR4(sc, UTMIP_TX_CFG0, val); val = RD4(sc, UTMIP_HSRX_CFG0); val &= ~UTMIP_IDLE_WAIT(~0); val &= ~UTMIP_ELASTIC_LIMIT(~0); val |= UTMIP_IDLE_WAIT(sc->idle_wait_delay); val |= UTMIP_ELASTIC_LIMIT(sc->elastic_limit); WR4(sc, UTMIP_HSRX_CFG0, val); val = RD4(sc, UTMIP_HSRX_CFG1); val &= ~UTMIP_HS_SYNC_START_DLY(~0); val |= UTMIP_HS_SYNC_START_DLY(sc->hssync_start_delay); WR4(sc, UTMIP_HSRX_CFG1, val); val = RD4(sc, UTMIP_DEBOUNCE_CFG0); val &= ~UTMIP_BIAS_DEBOUNCE_A(~0); val |= UTMIP_BIAS_DEBOUNCE_A(0x7530); /* For 12MHz */ WR4(sc, UTMIP_DEBOUNCE_CFG0, val); val = RD4(sc, UTMIP_MISC_CFG0); val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE; WR4(sc, UTMIP_MISC_CFG0, val); if (sc->dr_mode == USB_DR_MODE_DEVICE) { val = RD4(sc,IF_USB_SUSP_CTRL); val &= ~USB_WAKE_ON_CNNT_EN_DEV; val &= ~USB_WAKE_ON_DISCON_EN_DEV; WR4(sc, IF_USB_SUSP_CTRL, val); val = RD4(sc, UTMIP_BAT_CHRG_CFG0); val &= ~UTMIP_PD_CHRG; WR4(sc, UTMIP_BAT_CHRG_CFG0, val); } else { val = RD4(sc, UTMIP_BAT_CHRG_CFG0); val |= UTMIP_PD_CHRG; WR4(sc, UTMIP_BAT_CHRG_CFG0, val); } usbpby_enable_cnt++; if (usbpby_enable_cnt == 1) { rv = hwreset_deassert(sc->reset_pads); if (rv != 0) { device_printf(sc->dev, "Cannot unreset 'utmi-pads' reset\n"); return (rv); } rv = clk_enable(sc->clk_pads); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'utmi-pads' clock\n"); return (rv); } val = bus_read_4(sc->pads_res, UTMIP_BIAS_CFG0); val &= ~UTMIP_OTGPD; val &= ~UTMIP_BIASPD; val &= ~UTMIP_HSSQUELCH_LEVEL(~0); val &= ~UTMIP_HSDISCON_LEVEL(~0); val &= ~UTMIP_HSDISCON_LEVEL_MSB(~0); val |= UTMIP_HSSQUELCH_LEVEL(sc->hssquelch_level); val |= UTMIP_HSDISCON_LEVEL(sc->hsdiscon_level); val |= UTMIP_HSDISCON_LEVEL_MSB(sc->hsdiscon_level); bus_write_4(sc->pads_res, UTMIP_BIAS_CFG0, val); rv = clk_disable(sc->clk_pads); if (rv != 0) { device_printf(sc->dev, "Cannot disable 'utmi-pads' clock\n"); return (rv); } } val = RD4(sc, UTMIP_XCVR_CFG0); val &= ~UTMIP_FORCE_PD_POWERDOWN; val &= ~UTMIP_FORCE_PD2_POWERDOWN ; val &= ~UTMIP_FORCE_PDZI_POWERDOWN; val &= ~UTMIP_XCVR_LSBIAS_SEL; val &= ~UTMIP_XCVR_LSFSLEW(~0); val &= ~UTMIP_XCVR_LSRSLEW(~0); val &= ~UTMIP_XCVR_HSSLEW(~0); val &= ~UTMIP_XCVR_HSSLEW_MSB(~0); val |= UTMIP_XCVR_LSFSLEW(sc->xcvr_lsfslew); val |= UTMIP_XCVR_LSRSLEW(sc->xcvr_lsrslew); val |= UTMIP_XCVR_HSSLEW(sc->xcvr_hsslew); val |= UTMIP_XCVR_HSSLEW_MSB(sc->xcvr_hsslew); if (!sc->xcvr_setup_use_fuses) { val &= ~UTMIP_XCVR_SETUP(~0); val &= ~UTMIP_XCVR_SETUP_MSB(~0); val |= UTMIP_XCVR_SETUP(sc->xcvr_setup); val |= UTMIP_XCVR_SETUP_MSB(sc->xcvr_setup); } WR4(sc, UTMIP_XCVR_CFG0, val); val = RD4(sc, UTMIP_XCVR_CFG1); val &= ~UTMIP_FORCE_PDDISC_POWERDOWN; val &= ~UTMIP_FORCE_PDCHRP_POWERDOWN; val &= ~UTMIP_FORCE_PDDR_POWERDOWN; val &= ~UTMIP_XCVR_TERM_RANGE_ADJ(~0); val |= UTMIP_XCVR_TERM_RANGE_ADJ(sc->term_range_adj); WR4(sc, UTMIP_XCVR_CFG1, val); val = RD4(sc, UTMIP_BIAS_CFG1); val &= ~UTMIP_BIAS_PDTRK_COUNT(~0); val |= UTMIP_BIAS_PDTRK_COUNT(0x5); WR4(sc, UTMIP_BIAS_CFG1, val); val = RD4(sc, UTMIP_SPARE_CFG0); if (sc->xcvr_setup_use_fuses) val |= FUSE_SETUP_SEL; else val &= ~FUSE_SETUP_SEL; WR4(sc, UTMIP_SPARE_CFG0, val); val = RD4(sc, IF_USB_SUSP_CTRL); val |= UTMIP_PHY_ENB; WR4(sc, IF_USB_SUSP_CTRL, val); val = RD4(sc, IF_USB_SUSP_CTRL); val &= ~UTMIP_RESET; WR4(sc, IF_USB_SUSP_CTRL, val); usbphy_utmi_phy_clk(sc, true); val = RD4(sc, CTRL_USB_USBMODE); val &= ~USB_USBMODE_MASK; if (sc->dr_mode == USB_DR_MODE_HOST) val |= USB_USBMODE_HOST; else val |= USB_USBMODE_DEVICE; WR4(sc, CTRL_USB_USBMODE, val); val = RD4(sc, CTRL_USB_HOSTPC1_DEVLC); val &= ~USB_HOSTPC1_DEVLC_PTS(~0); val |= USB_HOSTPC1_DEVLC_PTS(0); WR4(sc, CTRL_USB_HOSTPC1_DEVLC, val); return (0); } static int usbphy_utmi_disable(struct usbphy_softc *sc) { int rv; uint32_t val; usbphy_utmi_phy_clk(sc, false); if (sc->dr_mode == USB_DR_MODE_DEVICE) { val = RD4(sc, IF_USB_SUSP_CTRL); val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); val |= USB_WAKE_ON_CNNT_EN_DEV; val |= USB_WAKEUP_DEBOUNCE_COUNT(5); WR4(sc, IF_USB_SUSP_CTRL, val); } val = RD4(sc, IF_USB_SUSP_CTRL); val |= UTMIP_RESET; WR4(sc, IF_USB_SUSP_CTRL, val); val = RD4(sc, UTMIP_BAT_CHRG_CFG0); val |= UTMIP_PD_CHRG; WR4(sc, UTMIP_BAT_CHRG_CFG0, val); val = RD4(sc, UTMIP_XCVR_CFG0); val |= UTMIP_FORCE_PD_POWERDOWN; val |= UTMIP_FORCE_PD2_POWERDOWN; val |= UTMIP_FORCE_PDZI_POWERDOWN; WR4(sc, UTMIP_XCVR_CFG0, val); val = RD4(sc, UTMIP_XCVR_CFG1); val |= UTMIP_FORCE_PDDISC_POWERDOWN; val |= UTMIP_FORCE_PDCHRP_POWERDOWN; val |= UTMIP_FORCE_PDDR_POWERDOWN; WR4(sc, UTMIP_XCVR_CFG1, val); usbpby_enable_cnt--; if (usbpby_enable_cnt <= 0) { rv = clk_enable(sc->clk_pads); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'utmi-pads' clock\n"); return (rv); } val =bus_read_4(sc->pads_res, UTMIP_BIAS_CFG0); val |= UTMIP_OTGPD; val |= UTMIP_BIASPD; bus_write_4(sc->pads_res, UTMIP_BIAS_CFG0, val); rv = clk_disable(sc->clk_pads); if (rv != 0) { device_printf(sc->dev, "Cannot disable 'utmi-pads' clock\n"); return (rv); } } return (0); } static int usbphy_phy_enable(device_t dev, int id, bool enable) { struct usbphy_softc *sc; int rv = 0; sc = device_get_softc(dev); if (sc->ifc_type != USB_IFC_TYPE_UTMI) { device_printf(sc->dev, "Only UTMI interface is supported.\n"); return (ENXIO); } if (enable) rv = usbphy_utmi_enable(sc); else rv = usbphy_utmi_disable(sc); return (rv); } static enum usb_ifc_type usb_get_ifc_mode(device_t dev, phandle_t node, char *name) { char *tmpstr; int rv; enum usb_ifc_type ret; rv = OF_getprop_alloc(node, name, 1, (void **)&tmpstr); if (rv <= 0) return (USB_IFC_TYPE_UNKNOWN); ret = USB_IFC_TYPE_UNKNOWN; if (strcmp(tmpstr, "utmi") == 0) ret = USB_IFC_TYPE_UTMI; else if (strcmp(tmpstr, "ulpi") == 0) ret = USB_IFC_TYPE_ULPI; else device_printf(dev, "Unsupported phy type: %s\n", tmpstr); - free(tmpstr, M_OFWPROP); + OF_prop_free(tmpstr); return (ret); } static enum usb_dr_mode usb_get_dr_mode(device_t dev, phandle_t node, char *name) { char *tmpstr; int rv; enum usb_dr_mode ret; rv = OF_getprop_alloc(node, name, 1, (void **)&tmpstr); if (rv <= 0) return (USB_DR_MODE_UNKNOWN); ret = USB_DR_MODE_UNKNOWN; if (strcmp(tmpstr, "device") == 0) ret = USB_DR_MODE_DEVICE; else if (strcmp(tmpstr, "host") == 0) ret = USB_DR_MODE_HOST; else if (strcmp(tmpstr, "otg") == 0) ret = USB_DR_MODE_OTG; else device_printf(dev, "Unknown dr mode: %s\n", tmpstr); - free(tmpstr, M_OFWPROP); + OF_prop_free(tmpstr); return (ret); } static int usbphy_utmi_read_params(struct usbphy_softc *sc, phandle_t node) { int rv; rv = OF_getencprop(node, "nvidia,hssync-start-delay", &sc->hssync_start_delay, sizeof (sc->hssync_start_delay)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,elastic-limit", &sc->elastic_limit, sizeof (sc->elastic_limit)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,idle-wait-delay", &sc->idle_wait_delay, sizeof (sc->idle_wait_delay)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,term-range-adj", &sc->term_range_adj, sizeof (sc->term_range_adj)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,xcvr-lsfslew", &sc->xcvr_lsfslew, sizeof (sc->xcvr_lsfslew)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,xcvr-lsrslew", &sc->xcvr_lsrslew, sizeof (sc->xcvr_lsrslew)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,xcvr-hsslew", &sc->xcvr_hsslew, sizeof (sc->xcvr_hsslew)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,hssquelch-level", &sc->hssquelch_level, sizeof (sc->hssquelch_level)); if (rv <= 0) return (ENXIO); rv = OF_getencprop(node, "nvidia,hsdiscon-level", &sc->hsdiscon_level, sizeof (sc->hsdiscon_level)); if (rv <= 0) return (ENXIO); rv = OF_getproplen(node, "nvidia,xcvr-setup-use-fuses"); if (rv >= 1) { sc->xcvr_setup_use_fuses = 1; } else { rv = OF_getencprop(node, "nvidia,xcvr-setup", &sc->xcvr_setup, sizeof (sc->xcvr_setup)); if (rv <= 0) return (ENXIO); } return (0); } static int usbphy_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "Tegra USB phy"); return (BUS_PROBE_DEFAULT); } static int usbphy_attach(device_t dev) { struct usbphy_softc * sc; int rid, rv; phandle_t node; sc = device_get_softc(dev); sc->dev = dev; rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE | RF_SHAREABLE); if (sc->mem_res == NULL) { device_printf(dev, "Cannot allocate memory resources\n"); return (ENXIO); } rid = 1; sc->pads_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE | RF_SHAREABLE); if (sc->mem_res == NULL) { device_printf(dev, "Cannot allocate memory resources\n"); return (ENXIO); } node = ofw_bus_get_node(dev); rv = hwreset_get_by_ofw_name(sc->dev, "usb", &sc->reset_usb); if (rv != 0) { device_printf(dev, "Cannot get 'usb' reset\n"); return (ENXIO); } rv = hwreset_get_by_ofw_name(sc->dev, "utmi-pads", &sc->reset_pads); if (rv != 0) { device_printf(dev, "Cannot get 'utmi-pads' reset\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, "reg", &sc->clk_reg); if (rv != 0) { device_printf(sc->dev, "Cannot get 'reg' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, "pll_u", &sc->clk_pllu); if (rv != 0) { device_printf(sc->dev, "Cannot get 'pll_u' clock\n"); return (ENXIO); } rv = clk_get_by_ofw_name(sc->dev, "utmi-pads", &sc->clk_pads); if (rv != 0) { device_printf(sc->dev, "Cannot get 'utmi-pads' clock\n"); return (ENXIO); } rv = hwreset_deassert(sc->reset_usb); if (rv != 0) { device_printf(dev, "Cannot unreset 'usb' reset\n"); return (ENXIO); } rv = clk_enable(sc->clk_pllu); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'pllu' clock\n"); return (ENXIO); } rv = clk_enable(sc->clk_reg); if (rv != 0) { device_printf(sc->dev, "Cannot enable 'reg' clock\n"); return (ENXIO); } if (OF_hasprop(node, "nvidia,has-utmi-pad-registers")) sc->have_utmi_regs = true; sc->dr_mode = usb_get_dr_mode(dev, node, "dr_mode"); if (sc->dr_mode == USB_DR_MODE_UNKNOWN) sc->dr_mode = USB_DR_MODE_HOST; sc->ifc_type = usb_get_ifc_mode(dev, node, "phy_type"); /* We supports only utmi phy mode for now .... */ if (sc->ifc_type != USB_IFC_TYPE_UTMI) { device_printf(dev, "Unsupported phy type\n"); return (ENXIO); } rv = usbphy_utmi_read_params(sc, node); if (rv < 0) return rv; if (OF_hasprop(node, "vbus-supply")) { rv = regulator_get_by_ofw_property(sc->dev, "vbus-supply", &sc->supply_vbus); if (rv != 0) { device_printf(sc->dev, "Cannot get \"vbus\" regulator\n"); return (ENXIO); } rv = regulator_enable(sc->supply_vbus); if (rv != 0) { device_printf(sc->dev, "Cannot enable \"vbus\" regulator\n"); return (rv); } } phy_register_provider(dev); return (0); } static int usbphy_detach(device_t dev) { /* This device is always present. */ return (EBUSY); } static device_method_t tegra_usbphy_methods[] = { /* Device interface */ DEVMETHOD(device_probe, usbphy_probe), DEVMETHOD(device_attach, usbphy_attach), DEVMETHOD(device_detach, usbphy_detach), /* phy interface */ DEVMETHOD(phy_enable, usbphy_phy_enable), DEVMETHOD_END }; static driver_t tegra_usbphy_driver = { "tegra_usbphy", tegra_usbphy_methods, sizeof(struct usbphy_softc), }; static devclass_t tegra_usbphy_devclass; EARLY_DRIVER_MODULE(tegra_usbphy, simplebus, tegra_usbphy_driver, tegra_usbphy_devclass, 0, 0, 79);