11b4bd023SJared McNeill /*- 21b4bd023SJared McNeill * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca> 31b4bd023SJared McNeill * All rights reserved. 41b4bd023SJared McNeill * 51b4bd023SJared McNeill * Redistribution and use in source and binary forms, with or without 61b4bd023SJared McNeill * modification, are permitted provided that the following conditions 71b4bd023SJared McNeill * are met: 81b4bd023SJared McNeill * 1. Redistributions of source code must retain the above copyright 91b4bd023SJared McNeill * notice, this list of conditions and the following disclaimer. 101b4bd023SJared McNeill * 2. Redistributions in binary form must reproduce the above copyright 111b4bd023SJared McNeill * notice, this list of conditions and the following disclaimer in the 121b4bd023SJared McNeill * documentation and/or other materials provided with the distribution. 131b4bd023SJared McNeill * 141b4bd023SJared McNeill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 151b4bd023SJared McNeill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 161b4bd023SJared McNeill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 171b4bd023SJared McNeill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 181b4bd023SJared McNeill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 191b4bd023SJared McNeill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 201b4bd023SJared McNeill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 211b4bd023SJared McNeill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 221b4bd023SJared McNeill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231b4bd023SJared McNeill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241b4bd023SJared McNeill * SUCH DAMAGE. 251b4bd023SJared McNeill * 261b4bd023SJared McNeill * $FreeBSD$ 271b4bd023SJared McNeill */ 281b4bd023SJared McNeill 291b4bd023SJared McNeill /* 301b4bd023SJared McNeill * Allwinner USB PHY 311b4bd023SJared McNeill */ 321b4bd023SJared McNeill 331b4bd023SJared McNeill #include <sys/cdefs.h> 341b4bd023SJared McNeill __FBSDID("$FreeBSD$"); 351b4bd023SJared McNeill 361b4bd023SJared McNeill #include <sys/param.h> 371b4bd023SJared McNeill #include <sys/systm.h> 381b4bd023SJared McNeill #include <sys/bus.h> 391b4bd023SJared McNeill #include <sys/rman.h> 401b4bd023SJared McNeill #include <sys/kernel.h> 411b4bd023SJared McNeill #include <sys/module.h> 421b4bd023SJared McNeill #include <sys/gpio.h> 4363dc81d8SJared McNeill #include <machine/bus.h> 441b4bd023SJared McNeill 451b4bd023SJared McNeill #include <dev/ofw/ofw_bus.h> 461b4bd023SJared McNeill #include <dev/ofw/ofw_bus_subr.h> 47627c360fSJared McNeill #include <dev/gpio/gpiobusvar.h> 481b4bd023SJared McNeill 496a05f063SJared McNeill #include <dev/extres/clk/clk.h> 506a05f063SJared McNeill #include <dev/extres/hwreset/hwreset.h> 516a05f063SJared McNeill #include <dev/extres/regulator/regulator.h> 52*84ebe16aSEmmanuel Vadot #include <dev/extres/phy/phy_usb.h> 531b4bd023SJared McNeill 54f8759facSMichal Meloun #include "phynode_if.h" 55627c360fSJared McNeill 5663dc81d8SJared McNeill enum awusbphy_type { 5763dc81d8SJared McNeill AWUSBPHY_TYPE_A10 = 1, 5863dc81d8SJared McNeill AWUSBPHY_TYPE_A13, 5963dc81d8SJared McNeill AWUSBPHY_TYPE_A20, 6063dc81d8SJared McNeill AWUSBPHY_TYPE_A31, 6163dc81d8SJared McNeill AWUSBPHY_TYPE_H3, 625b48129eSKyle Evans AWUSBPHY_TYPE_A64, 635b48129eSKyle Evans AWUSBPHY_TYPE_A83T 6463dc81d8SJared McNeill }; 651b4bd023SJared McNeill 6636dcd6a4SEmmanuel Vadot struct aw_usbphy_conf { 6736dcd6a4SEmmanuel Vadot int num_phys; 6836dcd6a4SEmmanuel Vadot enum awusbphy_type phy_type; 6936dcd6a4SEmmanuel Vadot bool pmu_unk1; 7036dcd6a4SEmmanuel Vadot bool phy0_route; 7136dcd6a4SEmmanuel Vadot }; 7236dcd6a4SEmmanuel Vadot 7336dcd6a4SEmmanuel Vadot static const struct aw_usbphy_conf a10_usbphy_conf = { 7436dcd6a4SEmmanuel Vadot .num_phys = 3, 7536dcd6a4SEmmanuel Vadot .phy_type = AWUSBPHY_TYPE_A10, 7636dcd6a4SEmmanuel Vadot .pmu_unk1 = false, 7736dcd6a4SEmmanuel Vadot .phy0_route = false, 7836dcd6a4SEmmanuel Vadot }; 7936dcd6a4SEmmanuel Vadot 8036dcd6a4SEmmanuel Vadot static const struct aw_usbphy_conf a13_usbphy_conf = { 8136dcd6a4SEmmanuel Vadot .num_phys = 2, 8236dcd6a4SEmmanuel Vadot .phy_type = AWUSBPHY_TYPE_A13, 8336dcd6a4SEmmanuel Vadot .pmu_unk1 = false, 8436dcd6a4SEmmanuel Vadot .phy0_route = false, 8536dcd6a4SEmmanuel Vadot }; 8636dcd6a4SEmmanuel Vadot 8736dcd6a4SEmmanuel Vadot static const struct aw_usbphy_conf a20_usbphy_conf = { 8836dcd6a4SEmmanuel Vadot .num_phys = 3, 8936dcd6a4SEmmanuel Vadot .phy_type = AWUSBPHY_TYPE_A20, 9036dcd6a4SEmmanuel Vadot .pmu_unk1 = false, 9136dcd6a4SEmmanuel Vadot .phy0_route = false, 9236dcd6a4SEmmanuel Vadot }; 9336dcd6a4SEmmanuel Vadot 9436dcd6a4SEmmanuel Vadot static const struct aw_usbphy_conf a31_usbphy_conf = { 9536dcd6a4SEmmanuel Vadot .num_phys = 3, 9636dcd6a4SEmmanuel Vadot .phy_type = AWUSBPHY_TYPE_A31, 9736dcd6a4SEmmanuel Vadot .pmu_unk1 = false, 9836dcd6a4SEmmanuel Vadot .phy0_route = false, 9936dcd6a4SEmmanuel Vadot }; 10036dcd6a4SEmmanuel Vadot 10136dcd6a4SEmmanuel Vadot static const struct aw_usbphy_conf h3_usbphy_conf = { 10236dcd6a4SEmmanuel Vadot .num_phys = 4, 10336dcd6a4SEmmanuel Vadot .phy_type = AWUSBPHY_TYPE_H3, 10436dcd6a4SEmmanuel Vadot .pmu_unk1 = true, 10536dcd6a4SEmmanuel Vadot .phy0_route = false, 10636dcd6a4SEmmanuel Vadot }; 10736dcd6a4SEmmanuel Vadot 10836dcd6a4SEmmanuel Vadot static const struct aw_usbphy_conf a64_usbphy_conf = { 10936dcd6a4SEmmanuel Vadot .num_phys = 2, 11036dcd6a4SEmmanuel Vadot .phy_type = AWUSBPHY_TYPE_A64, 11136dcd6a4SEmmanuel Vadot .pmu_unk1 = true, 11236dcd6a4SEmmanuel Vadot .phy0_route = true, 11336dcd6a4SEmmanuel Vadot }; 11436dcd6a4SEmmanuel Vadot 1155b48129eSKyle Evans static const struct aw_usbphy_conf a83t_usbphy_conf = { 1165b48129eSKyle Evans .num_phys = 3, 1175b48129eSKyle Evans .phy_type = AWUSBPHY_TYPE_A83T, 1185b48129eSKyle Evans .pmu_unk1 = false, 1195b48129eSKyle Evans .phy0_route = false, 1205b48129eSKyle Evans }; 1215b48129eSKyle Evans 1221b4bd023SJared McNeill static struct ofw_compat_data compat_data[] = { 12336dcd6a4SEmmanuel Vadot { "allwinner,sun4i-a10-usb-phy", (uintptr_t)&a10_usbphy_conf }, 12436dcd6a4SEmmanuel Vadot { "allwinner,sun5i-a13-usb-phy", (uintptr_t)&a13_usbphy_conf }, 12536dcd6a4SEmmanuel Vadot { "allwinner,sun6i-a31-usb-phy", (uintptr_t)&a31_usbphy_conf }, 12636dcd6a4SEmmanuel Vadot { "allwinner,sun7i-a20-usb-phy", (uintptr_t)&a20_usbphy_conf }, 12736dcd6a4SEmmanuel Vadot { "allwinner,sun8i-h3-usb-phy", (uintptr_t)&h3_usbphy_conf }, 12836dcd6a4SEmmanuel Vadot { "allwinner,sun50i-a64-usb-phy", (uintptr_t)&a64_usbphy_conf }, 1295b48129eSKyle Evans { "allwinner,sun8i-a83t-usb-phy", (uintptr_t)&a83t_usbphy_conf }, 1301b4bd023SJared McNeill { NULL, 0 } 1311b4bd023SJared McNeill }; 1321b4bd023SJared McNeill 133627c360fSJared McNeill struct awusbphy_softc { 13436dcd6a4SEmmanuel Vadot struct resource * phy_ctrl; 13536dcd6a4SEmmanuel Vadot struct resource ** pmu; 13636dcd6a4SEmmanuel Vadot regulator_t * reg; 137627c360fSJared McNeill gpio_pin_t id_det_pin; 138627c360fSJared McNeill int id_det_valid; 139627c360fSJared McNeill gpio_pin_t vbus_det_pin; 140627c360fSJared McNeill int vbus_det_valid; 14136dcd6a4SEmmanuel Vadot struct aw_usbphy_conf *phy_conf; 142*84ebe16aSEmmanuel Vadot int mode; 143627c360fSJared McNeill }; 144627c360fSJared McNeill 145f8759facSMichal Meloun /* Phy class and methods. */ 146f8759facSMichal Meloun static int awusbphy_phy_enable(struct phynode *phy, bool enable); 147*84ebe16aSEmmanuel Vadot static int awusbphy_get_mode(struct phynode *phy, int *mode); 148*84ebe16aSEmmanuel Vadot static int awusbphy_set_mode(struct phynode *phy, int mode); 149*84ebe16aSEmmanuel Vadot static phynode_usb_method_t awusbphy_phynode_methods[] = { 150f8759facSMichal Meloun PHYNODEMETHOD(phynode_enable, awusbphy_phy_enable), 151*84ebe16aSEmmanuel Vadot PHYNODEMETHOD(phynode_usb_get_mode, awusbphy_get_mode), 152*84ebe16aSEmmanuel Vadot PHYNODEMETHOD(phynode_usb_set_mode, awusbphy_set_mode), 153f8759facSMichal Meloun 154f8759facSMichal Meloun PHYNODEMETHOD_END 155f8759facSMichal Meloun }; 156f8759facSMichal Meloun DEFINE_CLASS_1(awusbphy_phynode, awusbphy_phynode_class, awusbphy_phynode_methods, 157*84ebe16aSEmmanuel Vadot sizeof(struct phynode_usb_sc), phynode_usb_class); 158f8759facSMichal Meloun 15936dcd6a4SEmmanuel Vadot #define RD4(res, o) bus_read_4(res, (o)) 16036dcd6a4SEmmanuel Vadot #define WR4(res, o, v) bus_write_4(res, (o), (v)) 16136dcd6a4SEmmanuel Vadot #define CLR4(res, o, m) WR4(res, o, RD4(res, o) & ~(m)) 16236dcd6a4SEmmanuel Vadot #define SET4(res, o, m) WR4(res, o, RD4(res, o) | (m)) 16363dc81d8SJared McNeill 16463dc81d8SJared McNeill #define OTG_PHY_CFG 0x20 16563dc81d8SJared McNeill #define OTG_PHY_ROUTE_OTG (1 << 0) 16663dc81d8SJared McNeill #define PMU_IRQ_ENABLE 0x00 16763dc81d8SJared McNeill #define PMU_AHB_INCR8 (1 << 10) 16863dc81d8SJared McNeill #define PMU_AHB_INCR4 (1 << 9) 16963dc81d8SJared McNeill #define PMU_AHB_INCRX_ALIGN (1 << 8) 17063dc81d8SJared McNeill #define PMU_ULPI_BYPASS (1 << 0) 17163dc81d8SJared McNeill #define PMU_UNK_H3 0x10 17263dc81d8SJared McNeill #define PMU_UNK_H3_CLR 0x2 173*84ebe16aSEmmanuel Vadot #define PHY_CSR 0x00 174*84ebe16aSEmmanuel Vadot #define ID_PULLUP_EN (1 << 17) 175*84ebe16aSEmmanuel Vadot #define DPDM_PULLUP_EN (1 << 16) 176*84ebe16aSEmmanuel Vadot #define FORCE_ID (0x3 << 14) 177*84ebe16aSEmmanuel Vadot #define FORCE_ID_SHIFT 14 178*84ebe16aSEmmanuel Vadot #define FORCE_ID_LOW 2 179*84ebe16aSEmmanuel Vadot #define FORCE_VBUS_VALID (0x3 << 12) 180*84ebe16aSEmmanuel Vadot #define FORCE_VBUS_VALID_SHIFT 12 181*84ebe16aSEmmanuel Vadot #define FORCE_VBUS_VALID_HIGH 3 182*84ebe16aSEmmanuel Vadot #define VBUS_CHANGE_DET (1 << 6) 183*84ebe16aSEmmanuel Vadot #define ID_CHANGE_DET (1 << 5) 184*84ebe16aSEmmanuel Vadot #define DPDM_CHANGE_DET (1 << 4) 18563dc81d8SJared McNeill 18663dc81d8SJared McNeill static void 18763dc81d8SJared McNeill awusbphy_configure(device_t dev, int phyno) 18863dc81d8SJared McNeill { 18963dc81d8SJared McNeill struct awusbphy_softc *sc; 19063dc81d8SJared McNeill 19163dc81d8SJared McNeill sc = device_get_softc(dev); 19263dc81d8SJared McNeill 19336dcd6a4SEmmanuel Vadot if (sc->pmu[phyno] == NULL) 19463dc81d8SJared McNeill return; 19563dc81d8SJared McNeill 19636dcd6a4SEmmanuel Vadot if (sc->phy_conf->pmu_unk1 == true) 1971eca1d26SEmmanuel Vadot CLR4(sc->pmu[phyno], PMU_UNK_H3, PMU_UNK_H3_CLR); 19863dc81d8SJared McNeill 19936dcd6a4SEmmanuel Vadot SET4(sc->pmu[phyno], PMU_IRQ_ENABLE, PMU_ULPI_BYPASS | 20063dc81d8SJared McNeill PMU_AHB_INCR8 | PMU_AHB_INCR4 | PMU_AHB_INCRX_ALIGN); 20163dc81d8SJared McNeill } 20263dc81d8SJared McNeill 2031b4bd023SJared McNeill static int 2041b4bd023SJared McNeill awusbphy_init(device_t dev) 2051b4bd023SJared McNeill { 206627c360fSJared McNeill struct awusbphy_softc *sc; 207627c360fSJared McNeill phandle_t node; 2081b4bd023SJared McNeill char pname[20]; 20936dcd6a4SEmmanuel Vadot int error, off, rid; 2106a05f063SJared McNeill regulator_t reg; 2116a05f063SJared McNeill hwreset_t rst; 2126a05f063SJared McNeill clk_t clk; 2131b4bd023SJared McNeill 214627c360fSJared McNeill sc = device_get_softc(dev); 215627c360fSJared McNeill node = ofw_bus_get_node(dev); 216627c360fSJared McNeill 21736dcd6a4SEmmanuel Vadot sc->phy_conf = (struct aw_usbphy_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; 21836dcd6a4SEmmanuel Vadot 21936dcd6a4SEmmanuel Vadot /* Get phy_ctrl region */ 22036dcd6a4SEmmanuel Vadot if (ofw_bus_find_string_index(node, "reg-names", "phy_ctrl", &rid) != 0) { 22136dcd6a4SEmmanuel Vadot device_printf(dev, "Cannot locate phy control resource\n"); 22236dcd6a4SEmmanuel Vadot return (ENXIO); 22336dcd6a4SEmmanuel Vadot } 22436dcd6a4SEmmanuel Vadot sc->phy_ctrl = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 22536dcd6a4SEmmanuel Vadot RF_ACTIVE); 22636dcd6a4SEmmanuel Vadot if (sc->phy_ctrl == NULL) { 22736dcd6a4SEmmanuel Vadot device_printf(dev, "Cannot allocate resource\n"); 22836dcd6a4SEmmanuel Vadot return (ENXIO); 22936dcd6a4SEmmanuel Vadot } 23063dc81d8SJared McNeill 2316a05f063SJared McNeill /* Enable clocks */ 232dac93553SMichal Meloun for (off = 0; clk_get_by_ofw_index(dev, 0, off, &clk) == 0; off++) { 2336a05f063SJared McNeill error = clk_enable(clk); 2346a05f063SJared McNeill if (error != 0) { 2356a05f063SJared McNeill device_printf(dev, "couldn't enable clock %s\n", 2366a05f063SJared McNeill clk_get_name(clk)); 2376a05f063SJared McNeill return (error); 2386a05f063SJared McNeill } 2396a05f063SJared McNeill } 2401b4bd023SJared McNeill 2416a05f063SJared McNeill /* De-assert resets */ 242dac93553SMichal Meloun for (off = 0; hwreset_get_by_ofw_idx(dev, 0, off, &rst) == 0; off++) { 2436a05f063SJared McNeill error = hwreset_deassert(rst); 2446a05f063SJared McNeill if (error != 0) { 2456a05f063SJared McNeill device_printf(dev, "couldn't de-assert reset %d\n", 2466a05f063SJared McNeill off); 2476a05f063SJared McNeill return (error); 2486a05f063SJared McNeill } 2496a05f063SJared McNeill } 2506a05f063SJared McNeill 251627c360fSJared McNeill /* Get GPIOs */ 252627c360fSJared McNeill error = gpio_pin_get_by_ofw_property(dev, node, "usb0_id_det-gpios", 253627c360fSJared McNeill &sc->id_det_pin); 254627c360fSJared McNeill if (error == 0) 255627c360fSJared McNeill sc->id_det_valid = 1; 256627c360fSJared McNeill error = gpio_pin_get_by_ofw_property(dev, node, "usb0_vbus_det-gpios", 257627c360fSJared McNeill &sc->vbus_det_pin); 258627c360fSJared McNeill if (error == 0) 259627c360fSJared McNeill sc->vbus_det_valid = 1; 260627c360fSJared McNeill 26136dcd6a4SEmmanuel Vadot sc->reg = malloc(sizeof(*(sc->reg)) * sc->phy_conf->num_phys, M_DEVBUF, 26236dcd6a4SEmmanuel Vadot M_WAITOK | M_ZERO); 26336dcd6a4SEmmanuel Vadot sc->pmu = malloc(sizeof(*(sc->pmu)) * sc->phy_conf->num_phys, M_DEVBUF, 26436dcd6a4SEmmanuel Vadot M_WAITOK | M_ZERO); 26536dcd6a4SEmmanuel Vadot /* Get regulators */ 26636dcd6a4SEmmanuel Vadot for (off = 0; off < sc->phy_conf->num_phys; off++) { 26736dcd6a4SEmmanuel Vadot snprintf(pname, sizeof(pname), "usb%d_vbus-supply", off); 26836dcd6a4SEmmanuel Vadot if (regulator_get_by_ofw_property(dev, 0, pname, ®) == 0) 26936dcd6a4SEmmanuel Vadot sc->reg[off] = reg; 27036dcd6a4SEmmanuel Vadot 27136dcd6a4SEmmanuel Vadot snprintf(pname, sizeof(pname), "pmu%d", off); 27236dcd6a4SEmmanuel Vadot if (ofw_bus_find_string_index(node, "reg-names", 27336dcd6a4SEmmanuel Vadot pname, &rid) != 0) 27436dcd6a4SEmmanuel Vadot continue; 27536dcd6a4SEmmanuel Vadot 27636dcd6a4SEmmanuel Vadot sc->pmu[off] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 27736dcd6a4SEmmanuel Vadot RF_ACTIVE); 27836dcd6a4SEmmanuel Vadot if (sc->pmu[off] == NULL) { 27936dcd6a4SEmmanuel Vadot device_printf(dev, "Cannot allocate resource\n"); 28036dcd6a4SEmmanuel Vadot return (ENXIO); 28136dcd6a4SEmmanuel Vadot } 28236dcd6a4SEmmanuel Vadot } 28363dc81d8SJared McNeill 284627c360fSJared McNeill return (0); 285627c360fSJared McNeill } 286627c360fSJared McNeill 287627c360fSJared McNeill static int 288627c360fSJared McNeill awusbphy_vbus_detect(device_t dev, int *val) 289627c360fSJared McNeill { 290627c360fSJared McNeill struct awusbphy_softc *sc; 291627c360fSJared McNeill bool active; 292627c360fSJared McNeill int error; 293627c360fSJared McNeill 294627c360fSJared McNeill sc = device_get_softc(dev); 295627c360fSJared McNeill 296627c360fSJared McNeill if (sc->vbus_det_valid) { 297627c360fSJared McNeill error = gpio_pin_is_active(sc->vbus_det_pin, &active); 298de355beaSEmmanuel Vadot if (error != 0) { 299de355beaSEmmanuel Vadot device_printf(dev, "Cannot get status of id pin %d\n", 300de355beaSEmmanuel Vadot error); 301627c360fSJared McNeill return (error); 302de355beaSEmmanuel Vadot } 303627c360fSJared McNeill *val = active; 304627c360fSJared McNeill return (0); 305627c360fSJared McNeill } 306627c360fSJared McNeill 307*84ebe16aSEmmanuel Vadot *val = 0; 308627c360fSJared McNeill return (0); 309627c360fSJared McNeill } 310627c360fSJared McNeill 311627c360fSJared McNeill static int 312f8759facSMichal Meloun awusbphy_phy_enable(struct phynode *phynode, bool enable) 313627c360fSJared McNeill { 314f8759facSMichal Meloun device_t dev; 315f8759facSMichal Meloun intptr_t phy; 316627c360fSJared McNeill struct awusbphy_softc *sc; 317627c360fSJared McNeill regulator_t reg; 318627c360fSJared McNeill int error, vbus_det; 319627c360fSJared McNeill 320f8759facSMichal Meloun dev = phynode_get_device(phynode); 321f8759facSMichal Meloun phy = phynode_get_id(phynode); 322627c360fSJared McNeill sc = device_get_softc(dev); 323627c360fSJared McNeill 32436dcd6a4SEmmanuel Vadot if (phy < 0 || phy >= sc->phy_conf->num_phys) 32536dcd6a4SEmmanuel Vadot return (ERANGE); 32636dcd6a4SEmmanuel Vadot 32763dc81d8SJared McNeill /* Configure PHY */ 32863dc81d8SJared McNeill awusbphy_configure(dev, phy); 32963dc81d8SJared McNeill 330627c360fSJared McNeill /* Regulators are optional. If not found, return success. */ 331627c360fSJared McNeill reg = sc->reg[phy]; 332627c360fSJared McNeill if (reg == NULL) 333627c360fSJared McNeill return (0); 334627c360fSJared McNeill 335627c360fSJared McNeill if (phy == 0) { 336*84ebe16aSEmmanuel Vadot /* If an external vbus is detected, do not enable phy 0 */ 337627c360fSJared McNeill error = awusbphy_vbus_detect(dev, &vbus_det); 338de355beaSEmmanuel Vadot if (error) 339de355beaSEmmanuel Vadot goto out; 340de355beaSEmmanuel Vadot 341*84ebe16aSEmmanuel Vadot if (vbus_det == 1) { 342*84ebe16aSEmmanuel Vadot if (bootverbose) 343*84ebe16aSEmmanuel Vadot device_printf(dev, "External VBUS detected, not enabling the regulator\n"); 344*84ebe16aSEmmanuel Vadot 345627c360fSJared McNeill return (0); 346*84ebe16aSEmmanuel Vadot } 347*84ebe16aSEmmanuel Vadot } 348*84ebe16aSEmmanuel Vadot if (enable) { 349*84ebe16aSEmmanuel Vadot /* Depending on the PHY we need to route OTG to OHCI/EHCI */ 350627c360fSJared McNeill error = regulator_enable(reg); 351627c360fSJared McNeill } else 352627c360fSJared McNeill error = regulator_disable(reg); 353de355beaSEmmanuel Vadot 354de355beaSEmmanuel Vadot out: 355627c360fSJared McNeill if (error != 0) { 3567dd62272SJared McNeill device_printf(dev, 3577dd62272SJared McNeill "couldn't %s regulator for phy %jd\n", 3587dd62272SJared McNeill enable ? "enable" : "disable", (intmax_t)phy); 359627c360fSJared McNeill return (error); 3606a05f063SJared McNeill } 3611b4bd023SJared McNeill 3621b4bd023SJared McNeill return (0); 3631b4bd023SJared McNeill } 3641b4bd023SJared McNeill 3651b4bd023SJared McNeill static int 366*84ebe16aSEmmanuel Vadot awusbphy_get_mode(struct phynode *phynode, int *mode) 367*84ebe16aSEmmanuel Vadot { 368*84ebe16aSEmmanuel Vadot struct awusbphy_softc *sc; 369*84ebe16aSEmmanuel Vadot device_t dev; 370*84ebe16aSEmmanuel Vadot 371*84ebe16aSEmmanuel Vadot dev = phynode_get_device(phynode); 372*84ebe16aSEmmanuel Vadot sc = device_get_softc(dev); 373*84ebe16aSEmmanuel Vadot 374*84ebe16aSEmmanuel Vadot *mode = sc->mode; 375*84ebe16aSEmmanuel Vadot 376*84ebe16aSEmmanuel Vadot return (0); 377*84ebe16aSEmmanuel Vadot } 378*84ebe16aSEmmanuel Vadot 379*84ebe16aSEmmanuel Vadot static int 380*84ebe16aSEmmanuel Vadot awusbphy_set_mode(struct phynode *phynode, int mode) 381*84ebe16aSEmmanuel Vadot { 382*84ebe16aSEmmanuel Vadot device_t dev; 383*84ebe16aSEmmanuel Vadot intptr_t phy; 384*84ebe16aSEmmanuel Vadot struct awusbphy_softc *sc; 385*84ebe16aSEmmanuel Vadot uint32_t val; 386*84ebe16aSEmmanuel Vadot int error, vbus_det; 387*84ebe16aSEmmanuel Vadot 388*84ebe16aSEmmanuel Vadot dev = phynode_get_device(phynode); 389*84ebe16aSEmmanuel Vadot phy = phynode_get_id(phynode); 390*84ebe16aSEmmanuel Vadot sc = device_get_softc(dev); 391*84ebe16aSEmmanuel Vadot 392*84ebe16aSEmmanuel Vadot if (phy != 0) 393*84ebe16aSEmmanuel Vadot return (EINVAL); 394*84ebe16aSEmmanuel Vadot 395*84ebe16aSEmmanuel Vadot switch (mode) { 396*84ebe16aSEmmanuel Vadot case PHY_USB_MODE_HOST: 397*84ebe16aSEmmanuel Vadot val = bus_read_4(sc->phy_ctrl, PHY_CSR); 398*84ebe16aSEmmanuel Vadot val &= ~(VBUS_CHANGE_DET | ID_CHANGE_DET | DPDM_CHANGE_DET); 399*84ebe16aSEmmanuel Vadot val |= (ID_PULLUP_EN | DPDM_PULLUP_EN); 400*84ebe16aSEmmanuel Vadot val &= ~FORCE_ID; 401*84ebe16aSEmmanuel Vadot val |= (FORCE_ID_LOW << FORCE_ID_SHIFT); 402*84ebe16aSEmmanuel Vadot val &= ~FORCE_VBUS_VALID; 403*84ebe16aSEmmanuel Vadot val |= (FORCE_VBUS_VALID_HIGH << FORCE_VBUS_VALID_SHIFT); 404*84ebe16aSEmmanuel Vadot bus_write_4(sc->phy_ctrl, PHY_CSR, val); 405*84ebe16aSEmmanuel Vadot if (sc->phy_conf->phy0_route == true) { 406*84ebe16aSEmmanuel Vadot error = awusbphy_vbus_detect(dev, &vbus_det); 407*84ebe16aSEmmanuel Vadot if (error) 408*84ebe16aSEmmanuel Vadot goto out; 409*84ebe16aSEmmanuel Vadot if (vbus_det == 0) 410*84ebe16aSEmmanuel Vadot CLR4(sc->phy_ctrl, OTG_PHY_CFG, 411*84ebe16aSEmmanuel Vadot OTG_PHY_ROUTE_OTG); 412*84ebe16aSEmmanuel Vadot else 413*84ebe16aSEmmanuel Vadot SET4(sc->phy_ctrl, OTG_PHY_CFG, 414*84ebe16aSEmmanuel Vadot OTG_PHY_ROUTE_OTG); 415*84ebe16aSEmmanuel Vadot } 416*84ebe16aSEmmanuel Vadot break; 417*84ebe16aSEmmanuel Vadot case PHY_USB_MODE_OTG: 418*84ebe16aSEmmanuel Vadot /* TODO */ 419*84ebe16aSEmmanuel Vadot break; 420*84ebe16aSEmmanuel Vadot } 421*84ebe16aSEmmanuel Vadot 422*84ebe16aSEmmanuel Vadot sc->mode = mode; 423*84ebe16aSEmmanuel Vadot 424*84ebe16aSEmmanuel Vadot 425*84ebe16aSEmmanuel Vadot out: 426*84ebe16aSEmmanuel Vadot return (0); 427*84ebe16aSEmmanuel Vadot } 428*84ebe16aSEmmanuel Vadot 429*84ebe16aSEmmanuel Vadot static int 4301b4bd023SJared McNeill awusbphy_probe(device_t dev) 4311b4bd023SJared McNeill { 4321b4bd023SJared McNeill if (!ofw_bus_status_okay(dev)) 4331b4bd023SJared McNeill return (ENXIO); 4341b4bd023SJared McNeill 4351b4bd023SJared McNeill if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 4361b4bd023SJared McNeill return (ENXIO); 4371b4bd023SJared McNeill 4381b4bd023SJared McNeill device_set_desc(dev, "Allwinner USB PHY"); 4391b4bd023SJared McNeill return (BUS_PROBE_DEFAULT); 4401b4bd023SJared McNeill } 4411b4bd023SJared McNeill 4421b4bd023SJared McNeill static int 4431b4bd023SJared McNeill awusbphy_attach(device_t dev) 4441b4bd023SJared McNeill { 4451b4bd023SJared McNeill int error; 446f8759facSMichal Meloun struct phynode *phynode; 447f8759facSMichal Meloun struct phynode_init_def phy_init; 448f8759facSMichal Meloun struct awusbphy_softc *sc; 449f8759facSMichal Meloun int i; 4501b4bd023SJared McNeill 451f8759facSMichal Meloun sc = device_get_softc(dev); 4521b4bd023SJared McNeill error = awusbphy_init(dev); 453627c360fSJared McNeill if (error) { 4541b4bd023SJared McNeill device_printf(dev, "failed to initialize USB PHY, error %d\n", 4551b4bd023SJared McNeill error); 456627c360fSJared McNeill return (error); 457627c360fSJared McNeill } 458627c360fSJared McNeill 459f8759facSMichal Meloun /* Create and register phys. */ 460f8759facSMichal Meloun for (i = 0; i < sc->phy_conf->num_phys; i++) { 461f8759facSMichal Meloun bzero(&phy_init, sizeof(phy_init)); 462f8759facSMichal Meloun phy_init.id = i; 463f8759facSMichal Meloun phy_init.ofw_node = ofw_bus_get_node(dev); 464f8759facSMichal Meloun phynode = phynode_create(dev, &awusbphy_phynode_class, 465f8759facSMichal Meloun &phy_init); 466f8759facSMichal Meloun if (phynode == NULL) { 467f8759facSMichal Meloun device_printf(dev, "failed to create USB PHY\n"); 468f8759facSMichal Meloun return (ENXIO); 469f8759facSMichal Meloun } 470f8759facSMichal Meloun if (phynode_register(phynode) == NULL) { 471f8759facSMichal Meloun device_printf(dev, "failed to create USB PHY\n"); 472f8759facSMichal Meloun return (ENXIO); 473f8759facSMichal Meloun } 474f8759facSMichal Meloun } 4751b4bd023SJared McNeill 4761b4bd023SJared McNeill return (error); 4771b4bd023SJared McNeill } 4781b4bd023SJared McNeill 4791b4bd023SJared McNeill static device_method_t awusbphy_methods[] = { 4801b4bd023SJared McNeill /* Device interface */ 4811b4bd023SJared McNeill DEVMETHOD(device_probe, awusbphy_probe), 4821b4bd023SJared McNeill DEVMETHOD(device_attach, awusbphy_attach), 4831b4bd023SJared McNeill 4841b4bd023SJared McNeill DEVMETHOD_END 4851b4bd023SJared McNeill }; 4861b4bd023SJared McNeill 4871b4bd023SJared McNeill static driver_t awusbphy_driver = { 4881b4bd023SJared McNeill "awusbphy", 4891b4bd023SJared McNeill awusbphy_methods, 490627c360fSJared McNeill sizeof(struct awusbphy_softc) 4911b4bd023SJared McNeill }; 4921b4bd023SJared McNeill 4931b4bd023SJared McNeill static devclass_t awusbphy_devclass; 4949f3b3133SKyle Evans /* aw_usbphy needs to come up after regulators/gpio/etc, but before ehci/ohci */ 495627c360fSJared McNeill EARLY_DRIVER_MODULE(awusbphy, simplebus, awusbphy_driver, awusbphy_devclass, 4969f3b3133SKyle Evans 0, 0, BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); 4971b4bd023SJared McNeill MODULE_VERSION(awusbphy, 1); 498