1ef2ee5d0SMichal Meloun /*- 2ef2ee5d0SMichal Meloun * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org> 3ef2ee5d0SMichal Meloun * All rights reserved. 4ef2ee5d0SMichal Meloun * 5ef2ee5d0SMichal Meloun * Redistribution and use in source and binary forms, with or without 6ef2ee5d0SMichal Meloun * modification, are permitted provided that the following conditions 7ef2ee5d0SMichal Meloun * are met: 8ef2ee5d0SMichal Meloun * 1. Redistributions of source code must retain the above copyright 9ef2ee5d0SMichal Meloun * notice, this list of conditions and the following disclaimer. 10ef2ee5d0SMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright 11ef2ee5d0SMichal Meloun * notice, this list of conditions and the following disclaimer in the 12ef2ee5d0SMichal Meloun * documentation and/or other materials provided with the distribution. 13ef2ee5d0SMichal Meloun * 14ef2ee5d0SMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15ef2ee5d0SMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16ef2ee5d0SMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ef2ee5d0SMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18ef2ee5d0SMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19ef2ee5d0SMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20ef2ee5d0SMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21ef2ee5d0SMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22ef2ee5d0SMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23ef2ee5d0SMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24ef2ee5d0SMichal Meloun * SUCH DAMAGE. 25ef2ee5d0SMichal Meloun * 26ef2ee5d0SMichal Meloun * $FreeBSD$ 27ef2ee5d0SMichal Meloun */ 28ef2ee5d0SMichal Meloun 29ef2ee5d0SMichal Meloun #include <sys/param.h> 30ef2ee5d0SMichal Meloun #include <sys/systm.h> 31ef2ee5d0SMichal Meloun #include <sys/bus.h> 32ef2ee5d0SMichal Meloun #include <sys/kernel.h> 33ef2ee5d0SMichal Meloun #include <sys/module.h> 34ef2ee5d0SMichal Meloun #include <sys/malloc.h> 35ef2ee5d0SMichal Meloun #include <sys/rman.h> 36ef2ee5d0SMichal Meloun 37ef2ee5d0SMichal Meloun #include <machine/bus.h> 38ef2ee5d0SMichal Meloun #include <machine/fdt.h> 39ef2ee5d0SMichal Meloun 40ef2ee5d0SMichal Meloun #include <dev/extres/hwreset/hwreset.h> 41ef2ee5d0SMichal Meloun #include <dev/extres/phy/phy.h> 42ef2ee5d0SMichal Meloun #include <dev/fdt/fdt_common.h> 43ef2ee5d0SMichal Meloun #include <dev/fdt/fdt_pinctrl.h> 44ef2ee5d0SMichal Meloun #include <dev/ofw/openfirm.h> 45ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus.h> 46ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus_subr.h> 47ef2ee5d0SMichal Meloun 48ef2ee5d0SMichal Meloun #include <gnu/dts/include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h> 49ef2ee5d0SMichal Meloun 50ef2ee5d0SMichal Meloun #include "phy_if.h" 51ef2ee5d0SMichal Meloun 52ef2ee5d0SMichal Meloun #define XUSB_PADCTL_USB2_PAD_MUX 0x004 53ef2ee5d0SMichal Meloun 54ef2ee5d0SMichal Meloun #define XUSB_PADCTL_ELPG_PROGRAM 0x01C 55ef2ee5d0SMichal Meloun #define ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26) 56ef2ee5d0SMichal Meloun #define ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25) 57ef2ee5d0SMichal Meloun #define ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24) 58ef2ee5d0SMichal Meloun 59ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040 60ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19) 61ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK (0xf<< 12) 62ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1) 63ef2ee5d0SMichal Meloun 64ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044 65ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6) 66ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5) 67ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4) 68ef2ee5d0SMichal Meloun 69ef2ee5d0SMichal Meloun 70ef2ee5d0SMichal Meloun #define XUSB_PADCTL_USB3_PAD_MUX 0x134 71ef2ee5d0SMichal Meloun 72ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138 73ef2ee5d0SMichal Meloun #define IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27) 74ef2ee5d0SMichal Meloun #define IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24) 75ef2ee5d0SMichal Meloun #define IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3) 76ef2ee5d0SMichal Meloun #define IOPHY_PLL_S0_CTL1_PLL_RST_L (1 << 1) 77ef2ee5d0SMichal Meloun #define IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0) 78ef2ee5d0SMichal Meloun 79ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2 0x13C 80ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_S0_CTL3 0x140 81ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_S0_CTL4 0x144 82ef2ee5d0SMichal Meloun 83ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148 84ef2ee5d0SMichal Meloun #define IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1) 85ef2ee5d0SMichal Meloun #define IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0) 86ef2ee5d0SMichal Meloun 87ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 0x14C 88ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL3 0x150 89ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL4 0x154 90ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 0x158 91ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 0x15C 92ef2ee5d0SMichal Meloun 93ef2ee5d0SMichal Meloun struct lane_cfg { 94ef2ee5d0SMichal Meloun char *function; 95ef2ee5d0SMichal Meloun char **lanes; 96ef2ee5d0SMichal Meloun int iddq; 97ef2ee5d0SMichal Meloun }; 98ef2ee5d0SMichal Meloun 99ef2ee5d0SMichal Meloun struct xusbpadctl_softc { 100ef2ee5d0SMichal Meloun device_t dev; 101ef2ee5d0SMichal Meloun struct resource *mem_res; 102ef2ee5d0SMichal Meloun hwreset_t rst; 103ef2ee5d0SMichal Meloun int phy_ena_cnt; 104ef2ee5d0SMichal Meloun }; 105ef2ee5d0SMichal Meloun 106ef2ee5d0SMichal Meloun static struct ofw_compat_data compat_data[] = { 107ef2ee5d0SMichal Meloun {"nvidia,tegra124-xusb-padctl", 1}, 108ef2ee5d0SMichal Meloun {NULL, 0}, 109ef2ee5d0SMichal Meloun }; 110ef2ee5d0SMichal Meloun 111ef2ee5d0SMichal Meloun struct padctl_lane { 112ef2ee5d0SMichal Meloun const char *name; 113ef2ee5d0SMichal Meloun bus_size_t reg; 114ef2ee5d0SMichal Meloun uint32_t shift; 115ef2ee5d0SMichal Meloun uint32_t mask; 116ef2ee5d0SMichal Meloun int iddq; 117ef2ee5d0SMichal Meloun char **mux; 118ef2ee5d0SMichal Meloun int nmux; 119ef2ee5d0SMichal Meloun }; 120ef2ee5d0SMichal Meloun 121ef2ee5d0SMichal Meloun static char *otg_mux[] = {"snps", "xusb", "uart", "rsvd"}; 122ef2ee5d0SMichal Meloun static char *usb_mux[] = {"snps", "xusb"}; 123ef2ee5d0SMichal Meloun static char *pci_mux[] = {"pcie", "usb3", "sata", "rsvd"}; 124ef2ee5d0SMichal Meloun 125ef2ee5d0SMichal Meloun #define LANE(n, r, s, m, i, mx) \ 126ef2ee5d0SMichal Meloun { \ 127ef2ee5d0SMichal Meloun .name = n, \ 128ef2ee5d0SMichal Meloun .reg = r, \ 129ef2ee5d0SMichal Meloun .shift = s, \ 130ef2ee5d0SMichal Meloun .mask = m, \ 131ef2ee5d0SMichal Meloun .iddq = i, \ 132ef2ee5d0SMichal Meloun .mux = mx, \ 133ef2ee5d0SMichal Meloun .nmux = nitems(mx), \ 134ef2ee5d0SMichal Meloun } 135ef2ee5d0SMichal Meloun 136ef2ee5d0SMichal Meloun static const struct padctl_lane lanes_tbl[] = { 137ef2ee5d0SMichal Meloun LANE("otg-0", XUSB_PADCTL_USB2_PAD_MUX, 0, 0x3, -1, otg_mux), 138ef2ee5d0SMichal Meloun LANE("otg-1", XUSB_PADCTL_USB2_PAD_MUX, 2, 0x3, -1, otg_mux), 139ef2ee5d0SMichal Meloun LANE("otg-2", XUSB_PADCTL_USB2_PAD_MUX, 4, 0x3, -1, otg_mux), 140ef2ee5d0SMichal Meloun LANE("ulpi-0", XUSB_PADCTL_USB2_PAD_MUX, 12, 0x1, -1, usb_mux), 141ef2ee5d0SMichal Meloun LANE("hsic-0", XUSB_PADCTL_USB2_PAD_MUX, 14, 0x1, -1, usb_mux), 142ef2ee5d0SMichal Meloun LANE("hsic-1", XUSB_PADCTL_USB2_PAD_MUX, 15, 0x1, -1, usb_mux), 143ef2ee5d0SMichal Meloun LANE("pcie-0", XUSB_PADCTL_USB3_PAD_MUX, 16, 0x3, 1, pci_mux), 144ef2ee5d0SMichal Meloun LANE("pcie-1", XUSB_PADCTL_USB3_PAD_MUX, 18, 0x3, 2, pci_mux), 145ef2ee5d0SMichal Meloun LANE("pcie-2", XUSB_PADCTL_USB3_PAD_MUX, 20, 0x3, 3, pci_mux), 146ef2ee5d0SMichal Meloun LANE("pcie-3", XUSB_PADCTL_USB3_PAD_MUX, 22, 0x3, 4, pci_mux), 147ef2ee5d0SMichal Meloun LANE("pcie-4", XUSB_PADCTL_USB3_PAD_MUX, 24, 0x3, 5, pci_mux), 148ef2ee5d0SMichal Meloun LANE("sata-0", XUSB_PADCTL_USB3_PAD_MUX, 26, 0x3, 6, pci_mux), 149ef2ee5d0SMichal Meloun }; 150ef2ee5d0SMichal Meloun 151ef2ee5d0SMichal Meloun static int 152ef2ee5d0SMichal Meloun xusbpadctl_mux_function(const struct padctl_lane *lane, char *fnc_name) 153ef2ee5d0SMichal Meloun { 154ef2ee5d0SMichal Meloun int i; 155ef2ee5d0SMichal Meloun 156ef2ee5d0SMichal Meloun for (i = 0; i < lane->nmux; i++) { 157ef2ee5d0SMichal Meloun if (strcmp(fnc_name, lane->mux[i]) == 0) 158ef2ee5d0SMichal Meloun return (i); 159ef2ee5d0SMichal Meloun } 160ef2ee5d0SMichal Meloun 161ef2ee5d0SMichal Meloun return (-1); 162ef2ee5d0SMichal Meloun } 163ef2ee5d0SMichal Meloun 164ef2ee5d0SMichal Meloun static int 165ef2ee5d0SMichal Meloun xusbpadctl_config_lane(struct xusbpadctl_softc *sc, char *lane_name, 166ef2ee5d0SMichal Meloun const struct padctl_lane *lane, struct lane_cfg *cfg) 167ef2ee5d0SMichal Meloun { 168ef2ee5d0SMichal Meloun 169ef2ee5d0SMichal Meloun int tmp; 170ef2ee5d0SMichal Meloun uint32_t reg; 171ef2ee5d0SMichal Meloun 172ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, lane->reg); 173ef2ee5d0SMichal Meloun if (cfg->function != NULL) { 174ef2ee5d0SMichal Meloun tmp = xusbpadctl_mux_function(lane, cfg->function); 175ef2ee5d0SMichal Meloun if (tmp == -1) { 176ef2ee5d0SMichal Meloun device_printf(sc->dev, 177ef2ee5d0SMichal Meloun "Unknown function %s for lane %s\n", cfg->function, 178ef2ee5d0SMichal Meloun lane_name); 179ef2ee5d0SMichal Meloun return (EINVAL); 180ef2ee5d0SMichal Meloun } 181ef2ee5d0SMichal Meloun reg &= ~(lane->mask << lane->shift); 182ef2ee5d0SMichal Meloun reg |= (tmp & lane->mask) << lane->shift; 183ef2ee5d0SMichal Meloun } 184ef2ee5d0SMichal Meloun if (cfg->iddq != -1) { 185ef2ee5d0SMichal Meloun if (lane->iddq == -1) { 186ef2ee5d0SMichal Meloun device_printf(sc->dev, "Invalid IDDQ for lane %s\n", 187ef2ee5d0SMichal Meloun lane_name); 188ef2ee5d0SMichal Meloun return (EINVAL); 189ef2ee5d0SMichal Meloun } 190ef2ee5d0SMichal Meloun if (cfg->iddq != 0) 191ef2ee5d0SMichal Meloun reg &= ~(1 << lane->iddq); 192ef2ee5d0SMichal Meloun else 193ef2ee5d0SMichal Meloun reg |= 1 << lane->iddq; 194ef2ee5d0SMichal Meloun } 195ef2ee5d0SMichal Meloun 196ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, lane->reg, reg); 197ef2ee5d0SMichal Meloun return (0); 198ef2ee5d0SMichal Meloun } 199ef2ee5d0SMichal Meloun 200ef2ee5d0SMichal Meloun static const struct padctl_lane * 201ef2ee5d0SMichal Meloun xusbpadctl_search_lane(char *lane_name) 202ef2ee5d0SMichal Meloun { 203ef2ee5d0SMichal Meloun int i; 204ef2ee5d0SMichal Meloun 205ef2ee5d0SMichal Meloun for (i = 0; i < nitems(lanes_tbl); i++) { 206ef2ee5d0SMichal Meloun if (strcmp(lane_name, lanes_tbl[i].name) == 0) 207ef2ee5d0SMichal Meloun return (&lanes_tbl[i]); 208ef2ee5d0SMichal Meloun } 209ef2ee5d0SMichal Meloun 210ef2ee5d0SMichal Meloun return (NULL); 211ef2ee5d0SMichal Meloun } 212ef2ee5d0SMichal Meloun 213ef2ee5d0SMichal Meloun static int 214ef2ee5d0SMichal Meloun xusbpadctl_config_node(struct xusbpadctl_softc *sc, char *lane_name, 215ef2ee5d0SMichal Meloun struct lane_cfg *cfg) 216ef2ee5d0SMichal Meloun { 217ef2ee5d0SMichal Meloun const struct padctl_lane *lane; 218ef2ee5d0SMichal Meloun int rv; 219ef2ee5d0SMichal Meloun 220ef2ee5d0SMichal Meloun lane = xusbpadctl_search_lane(lane_name); 221ef2ee5d0SMichal Meloun if (lane == NULL) { 222ef2ee5d0SMichal Meloun device_printf(sc->dev, "Unknown lane: %s\n", lane_name); 223ef2ee5d0SMichal Meloun return (ENXIO); 224ef2ee5d0SMichal Meloun } 225ef2ee5d0SMichal Meloun rv = xusbpadctl_config_lane(sc, lane_name, lane, cfg); 226ef2ee5d0SMichal Meloun return (rv); 227ef2ee5d0SMichal Meloun } 228ef2ee5d0SMichal Meloun 229ef2ee5d0SMichal Meloun static int 230ef2ee5d0SMichal Meloun xusbpadctl_read_node(struct xusbpadctl_softc *sc, phandle_t node, 231ef2ee5d0SMichal Meloun struct lane_cfg *cfg, char **lanes, int *llanes) 232ef2ee5d0SMichal Meloun { 233ef2ee5d0SMichal Meloun int rv; 234ef2ee5d0SMichal Meloun 235ef2ee5d0SMichal Meloun *llanes = OF_getprop_alloc(node, "nvidia,lanes", 1, (void **)lanes); 236ef2ee5d0SMichal Meloun if (*llanes <= 0) 237ef2ee5d0SMichal Meloun return (ENOENT); 238ef2ee5d0SMichal Meloun 239ef2ee5d0SMichal Meloun /* Read function (mux) settings. */ 240ef2ee5d0SMichal Meloun rv = OF_getprop_alloc(node, "nvidia,function", 1, 241ef2ee5d0SMichal Meloun (void **)&cfg->function); 242ef2ee5d0SMichal Meloun if (rv <= 0) 243ef2ee5d0SMichal Meloun cfg->function = NULL; 244ef2ee5d0SMichal Meloun /* Read numeric properties. */ 245ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "nvidia,iddq", &cfg->iddq, 246ef2ee5d0SMichal Meloun sizeof(cfg->iddq)); 247ef2ee5d0SMichal Meloun if (rv <= 0) 248ef2ee5d0SMichal Meloun cfg->iddq = -1; 249ef2ee5d0SMichal Meloun return (0); 250ef2ee5d0SMichal Meloun } 251ef2ee5d0SMichal Meloun 252ef2ee5d0SMichal Meloun static int 253ef2ee5d0SMichal Meloun xusbpadctl_process_node(struct xusbpadctl_softc *sc, phandle_t node) 254ef2ee5d0SMichal Meloun { 255ef2ee5d0SMichal Meloun struct lane_cfg cfg; 256ef2ee5d0SMichal Meloun char *lanes, *lname; 257ef2ee5d0SMichal Meloun int i, len, llanes, rv; 258ef2ee5d0SMichal Meloun 259ef2ee5d0SMichal Meloun rv = xusbpadctl_read_node(sc, node, &cfg, &lanes, &llanes); 260ef2ee5d0SMichal Meloun if (rv != 0) 261ef2ee5d0SMichal Meloun return (rv); 262ef2ee5d0SMichal Meloun 263ef2ee5d0SMichal Meloun len = 0; 264ef2ee5d0SMichal Meloun lname = lanes; 265ef2ee5d0SMichal Meloun do { 266ef2ee5d0SMichal Meloun i = strlen(lname) + 1; 267ef2ee5d0SMichal Meloun rv = xusbpadctl_config_node(sc, lname, &cfg); 268ef2ee5d0SMichal Meloun if (rv != 0) 269ef2ee5d0SMichal Meloun device_printf(sc->dev, 270ef2ee5d0SMichal Meloun "Cannot configure lane: %s: %d\n", lname, rv); 271ef2ee5d0SMichal Meloun 272ef2ee5d0SMichal Meloun len += i; 273ef2ee5d0SMichal Meloun lname += i; 274ef2ee5d0SMichal Meloun } while (len < llanes); 275ef2ee5d0SMichal Meloun 276ef2ee5d0SMichal Meloun if (lanes != NULL) 277ef2ee5d0SMichal Meloun free(lanes, M_OFWPROP); 278ef2ee5d0SMichal Meloun if (cfg.function != NULL) 279ef2ee5d0SMichal Meloun free(cfg.function, M_OFWPROP); 280ef2ee5d0SMichal Meloun return (rv); 281ef2ee5d0SMichal Meloun } 282ef2ee5d0SMichal Meloun 283ef2ee5d0SMichal Meloun 284ef2ee5d0SMichal Meloun static int 285ef2ee5d0SMichal Meloun xusbpadctl_pinctrl_cfg(device_t dev, phandle_t cfgxref) 286ef2ee5d0SMichal Meloun { 287ef2ee5d0SMichal Meloun struct xusbpadctl_softc *sc; 288ef2ee5d0SMichal Meloun phandle_t node, cfgnode; 289ef2ee5d0SMichal Meloun int rv; 290ef2ee5d0SMichal Meloun 291ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 292ef2ee5d0SMichal Meloun cfgnode = OF_node_from_xref(cfgxref); 293ef2ee5d0SMichal Meloun 294ef2ee5d0SMichal Meloun rv = 0; 295ef2ee5d0SMichal Meloun for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) { 296ef2ee5d0SMichal Meloun if (!fdt_is_enabled(node)) 297ef2ee5d0SMichal Meloun continue; 298ef2ee5d0SMichal Meloun rv = xusbpadctl_process_node(sc, node); 299ef2ee5d0SMichal Meloun if (rv != 0) 300ef2ee5d0SMichal Meloun return (rv); 301ef2ee5d0SMichal Meloun } 302ef2ee5d0SMichal Meloun 303ef2ee5d0SMichal Meloun return (rv); 304ef2ee5d0SMichal Meloun } 305ef2ee5d0SMichal Meloun 306ef2ee5d0SMichal Meloun static int 307ef2ee5d0SMichal Meloun xusbpadctl_phy_pcie_powerup(struct xusbpadctl_softc *sc) 308ef2ee5d0SMichal Meloun { 309ef2ee5d0SMichal Meloun uint32_t reg; 310ef2ee5d0SMichal Meloun int i; 311ef2ee5d0SMichal Meloun 312ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); 313ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK; 314ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg); 315ef2ee5d0SMichal Meloun DELAY(100); 316ef2ee5d0SMichal Meloun 317ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL2); 318ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_P0_CTL2_REFCLKBUF_EN; 319ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_P0_CTL2_TXCLKREF_EN; 320ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_P0_CTL2_TXCLKREF_SEL; 321ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL2, reg); 322ef2ee5d0SMichal Meloun DELAY(100); 323ef2ee5d0SMichal Meloun 324ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); 325ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_P0_CTL1_PLL_RST; 326ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg); 327ef2ee5d0SMichal Meloun DELAY(100); 328ef2ee5d0SMichal Meloun 329ef2ee5d0SMichal Meloun for (i = 0; i < 100; i++) { 330ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); 331ef2ee5d0SMichal Meloun if (reg & IOPHY_PLL_P0_CTL1_PLL0_LOCKDET) 332ef2ee5d0SMichal Meloun return (0); 333ef2ee5d0SMichal Meloun DELAY(10); 334ef2ee5d0SMichal Meloun } 335ef2ee5d0SMichal Meloun 336ef2ee5d0SMichal Meloun return (ETIMEDOUT); 337ef2ee5d0SMichal Meloun } 338ef2ee5d0SMichal Meloun 339ef2ee5d0SMichal Meloun 340ef2ee5d0SMichal Meloun static int 341ef2ee5d0SMichal Meloun xusbpadctl_phy_pcie_powerdown(struct xusbpadctl_softc *sc) 342ef2ee5d0SMichal Meloun { 343ef2ee5d0SMichal Meloun uint32_t reg; 344ef2ee5d0SMichal Meloun 345ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); 346ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_P0_CTL1_PLL_RST; 347ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg); 348ef2ee5d0SMichal Meloun DELAY(100); 349ef2ee5d0SMichal Meloun return (0); 350ef2ee5d0SMichal Meloun 351ef2ee5d0SMichal Meloun } 352ef2ee5d0SMichal Meloun 353ef2ee5d0SMichal Meloun static int 354ef2ee5d0SMichal Meloun xusbpadctl_phy_sata_powerup(struct xusbpadctl_softc *sc) 355ef2ee5d0SMichal Meloun { 356ef2ee5d0SMichal Meloun uint32_t reg; 357ef2ee5d0SMichal Meloun int i; 358ef2ee5d0SMichal Meloun 359ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); 360ef2ee5d0SMichal Meloun reg &= ~IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; 361ef2ee5d0SMichal Meloun reg &= ~IOPHY_MISC_PAD_S0_CTL1_IDDQ; 362ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg); 363ef2ee5d0SMichal Meloun 364ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 365ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; 366ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_S0_CTL1_PLL_IDDQ; 367ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 368ef2ee5d0SMichal Meloun 369ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 370ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_S0_CTL1_PLL1_MODE; 371ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 372ef2ee5d0SMichal Meloun 373ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 374ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_S0_CTL1_PLL_RST_L; 375ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 376ef2ee5d0SMichal Meloun 377ef2ee5d0SMichal Meloun for (i = 100; i >= 0; i--) { 378ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 379ef2ee5d0SMichal Meloun if (reg & IOPHY_PLL_S0_CTL1_PLL1_LOCKDET) 380ef2ee5d0SMichal Meloun break; 381ef2ee5d0SMichal Meloun DELAY(100); 382ef2ee5d0SMichal Meloun } 383ef2ee5d0SMichal Meloun if (i <= 0) { 384ef2ee5d0SMichal Meloun device_printf(sc->dev, "Failed to power up SATA phy\n"); 385ef2ee5d0SMichal Meloun return (ETIMEDOUT); 386ef2ee5d0SMichal Meloun } 387ef2ee5d0SMichal Meloun 388ef2ee5d0SMichal Meloun return (0); 389ef2ee5d0SMichal Meloun } 390ef2ee5d0SMichal Meloun 391ef2ee5d0SMichal Meloun static int 392ef2ee5d0SMichal Meloun xusbpadctl_phy_sata_powerdown(struct xusbpadctl_softc *sc) 393ef2ee5d0SMichal Meloun { 394ef2ee5d0SMichal Meloun uint32_t reg; 395ef2ee5d0SMichal Meloun 396ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 397ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_S0_CTL1_PLL_RST_L; 398ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 399ef2ee5d0SMichal Meloun DELAY(100); 400ef2ee5d0SMichal Meloun 401ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 402ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_S0_CTL1_PLL1_MODE; 403ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 404ef2ee5d0SMichal Meloun DELAY(100); 405ef2ee5d0SMichal Meloun 406ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 407ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; 408ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_S0_CTL1_PLL_IDDQ; 409ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 410ef2ee5d0SMichal Meloun DELAY(100); 411ef2ee5d0SMichal Meloun 412ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); 413ef2ee5d0SMichal Meloun reg |= IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; 414ef2ee5d0SMichal Meloun reg |= IOPHY_MISC_PAD_S0_CTL1_IDDQ; 415ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg); 416ef2ee5d0SMichal Meloun DELAY(100); 417ef2ee5d0SMichal Meloun 418ef2ee5d0SMichal Meloun return (0); 419ef2ee5d0SMichal Meloun } 420ef2ee5d0SMichal Meloun 421ef2ee5d0SMichal Meloun static int 422ef2ee5d0SMichal Meloun xusbpadctl_phy_powerup(struct xusbpadctl_softc *sc) 423ef2ee5d0SMichal Meloun { 424ef2ee5d0SMichal Meloun uint32_t reg; 425ef2ee5d0SMichal Meloun 426ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM); 427ef2ee5d0SMichal Meloun reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; 428ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg); 429ef2ee5d0SMichal Meloun DELAY(100); 430ef2ee5d0SMichal Meloun 431ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM); 432ef2ee5d0SMichal Meloun reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; 433ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg); 434ef2ee5d0SMichal Meloun DELAY(100); 435ef2ee5d0SMichal Meloun 436ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM); 437ef2ee5d0SMichal Meloun reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; 438ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg); 439ef2ee5d0SMichal Meloun DELAY(100); 440ef2ee5d0SMichal Meloun 441ef2ee5d0SMichal Meloun return (0); 442ef2ee5d0SMichal Meloun } 443ef2ee5d0SMichal Meloun 444ef2ee5d0SMichal Meloun static int 445ef2ee5d0SMichal Meloun xusbpadctl_phy_powerdown(struct xusbpadctl_softc *sc) 446ef2ee5d0SMichal Meloun { 447ef2ee5d0SMichal Meloun uint32_t reg; 448ef2ee5d0SMichal Meloun 449ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM); 450ef2ee5d0SMichal Meloun reg |= ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; 451ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg); 452ef2ee5d0SMichal Meloun DELAY(100); 453ef2ee5d0SMichal Meloun 454ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM); 455ef2ee5d0SMichal Meloun reg |= ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; 456ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg); 457ef2ee5d0SMichal Meloun DELAY(100); 458ef2ee5d0SMichal Meloun 459ef2ee5d0SMichal Meloun reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM); 460ef2ee5d0SMichal Meloun reg |= ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; 461ef2ee5d0SMichal Meloun bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg); 462ef2ee5d0SMichal Meloun DELAY(100); 463ef2ee5d0SMichal Meloun 464ef2ee5d0SMichal Meloun return (0); 465ef2ee5d0SMichal Meloun } 466ef2ee5d0SMichal Meloun 467ef2ee5d0SMichal Meloun static int 468ef2ee5d0SMichal Meloun xusbpadctl_phy_enable(device_t dev, intptr_t id, bool enable) 469ef2ee5d0SMichal Meloun { 470ef2ee5d0SMichal Meloun struct xusbpadctl_softc *sc; 471ef2ee5d0SMichal Meloun int rv; 472ef2ee5d0SMichal Meloun 473ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 474ef2ee5d0SMichal Meloun 475ef2ee5d0SMichal Meloun if ((id != TEGRA_XUSB_PADCTL_PCIE) && 476ef2ee5d0SMichal Meloun (id != TEGRA_XUSB_PADCTL_SATA)) { 477ef2ee5d0SMichal Meloun device_printf(dev, "Unknown phy: %d\n", id); 478ef2ee5d0SMichal Meloun return (ENXIO); 479ef2ee5d0SMichal Meloun } 480ef2ee5d0SMichal Meloun 481ef2ee5d0SMichal Meloun rv = 0; 482ef2ee5d0SMichal Meloun if (enable) { 483ef2ee5d0SMichal Meloun if (sc->phy_ena_cnt == 0) { 484ef2ee5d0SMichal Meloun rv = xusbpadctl_phy_powerup(sc); 485ef2ee5d0SMichal Meloun if (rv != 0) 486ef2ee5d0SMichal Meloun return (rv); 487ef2ee5d0SMichal Meloun } 488ef2ee5d0SMichal Meloun sc->phy_ena_cnt++; 489ef2ee5d0SMichal Meloun } 490ef2ee5d0SMichal Meloun 491ef2ee5d0SMichal Meloun if (id == TEGRA_XUSB_PADCTL_PCIE) { 492ef2ee5d0SMichal Meloun if (enable) 493ef2ee5d0SMichal Meloun rv = xusbpadctl_phy_pcie_powerup(sc); 494ef2ee5d0SMichal Meloun else 495ef2ee5d0SMichal Meloun rv = xusbpadctl_phy_pcie_powerdown(sc); 496ef2ee5d0SMichal Meloun if (rv != 0) 497ef2ee5d0SMichal Meloun return (rv); 498ef2ee5d0SMichal Meloun } else if (id == TEGRA_XUSB_PADCTL_SATA) { 499ef2ee5d0SMichal Meloun if (enable) 500ef2ee5d0SMichal Meloun rv = xusbpadctl_phy_sata_powerup(sc); 501ef2ee5d0SMichal Meloun else 502ef2ee5d0SMichal Meloun rv = xusbpadctl_phy_sata_powerdown(sc); 503ef2ee5d0SMichal Meloun if (rv != 0) 504ef2ee5d0SMichal Meloun return (rv); 505ef2ee5d0SMichal Meloun } 506ef2ee5d0SMichal Meloun if (!enable) { 507ef2ee5d0SMichal Meloun if (sc->phy_ena_cnt == 1) { 508ef2ee5d0SMichal Meloun rv = xusbpadctl_phy_powerdown(sc); 509ef2ee5d0SMichal Meloun if (rv != 0) 510ef2ee5d0SMichal Meloun return (rv); 511ef2ee5d0SMichal Meloun } 512ef2ee5d0SMichal Meloun sc->phy_ena_cnt--; 513ef2ee5d0SMichal Meloun } 514ef2ee5d0SMichal Meloun 515ef2ee5d0SMichal Meloun return (0); 516ef2ee5d0SMichal Meloun } 517ef2ee5d0SMichal Meloun 518ef2ee5d0SMichal Meloun static int 519ef2ee5d0SMichal Meloun xusbpadctl_probe(device_t dev) 520ef2ee5d0SMichal Meloun { 521ef2ee5d0SMichal Meloun 522ef2ee5d0SMichal Meloun if (!ofw_bus_status_okay(dev)) 523ef2ee5d0SMichal Meloun return (ENXIO); 524ef2ee5d0SMichal Meloun 525ef2ee5d0SMichal Meloun if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 526ef2ee5d0SMichal Meloun return (ENXIO); 527ef2ee5d0SMichal Meloun 528ef2ee5d0SMichal Meloun device_set_desc(dev, "Tegra XUSB phy"); 529ef2ee5d0SMichal Meloun return (BUS_PROBE_DEFAULT); 530ef2ee5d0SMichal Meloun } 531ef2ee5d0SMichal Meloun 532ef2ee5d0SMichal Meloun static int 533ef2ee5d0SMichal Meloun xusbpadctl_detach(device_t dev) 534ef2ee5d0SMichal Meloun { 535ef2ee5d0SMichal Meloun 536ef2ee5d0SMichal Meloun /* This device is always present. */ 537ef2ee5d0SMichal Meloun return (EBUSY); 538ef2ee5d0SMichal Meloun } 539ef2ee5d0SMichal Meloun 540ef2ee5d0SMichal Meloun static int 541ef2ee5d0SMichal Meloun xusbpadctl_attach(device_t dev) 542ef2ee5d0SMichal Meloun { 543ef2ee5d0SMichal Meloun struct xusbpadctl_softc * sc; 544ef2ee5d0SMichal Meloun int rid, rv; 545ef2ee5d0SMichal Meloun phandle_t node; 546ef2ee5d0SMichal Meloun 547ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 548ef2ee5d0SMichal Meloun sc->dev = dev; 549ef2ee5d0SMichal Meloun 550ef2ee5d0SMichal Meloun rid = 0; 551ef2ee5d0SMichal Meloun sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 552ef2ee5d0SMichal Meloun RF_ACTIVE); 553ef2ee5d0SMichal Meloun if (sc->mem_res == NULL) { 554ef2ee5d0SMichal Meloun device_printf(dev, "Cannot allocate memory resources\n"); 555ef2ee5d0SMichal Meloun return (ENXIO); 556ef2ee5d0SMichal Meloun } 557ef2ee5d0SMichal Meloun 558ef2ee5d0SMichal Meloun node = ofw_bus_get_node(dev); 559ef2ee5d0SMichal Meloun rv = hwreset_get_by_ofw_name(dev, "padctl", &sc->rst); 560ef2ee5d0SMichal Meloun if (rv != 0) { 561ef2ee5d0SMichal Meloun device_printf(dev, "Cannot get 'padctl' reset: %d\n", rv); 562ef2ee5d0SMichal Meloun return (rv); 563ef2ee5d0SMichal Meloun } 564ef2ee5d0SMichal Meloun rv = hwreset_deassert(sc->rst); 565ef2ee5d0SMichal Meloun if (rv != 0) { 566ef2ee5d0SMichal Meloun device_printf(dev, "Cannot unreset 'padctl' reset: %d\n", rv); 567ef2ee5d0SMichal Meloun return (rv); 568ef2ee5d0SMichal Meloun } 569ef2ee5d0SMichal Meloun 570ef2ee5d0SMichal Meloun /* Register as a pinctrl device and use default configuration */ 571ef2ee5d0SMichal Meloun fdt_pinctrl_register(dev, NULL); 572ef2ee5d0SMichal Meloun fdt_pinctrl_configure_by_name(dev, "default"); 573ef2ee5d0SMichal Meloun phy_register_provider(dev); 574ef2ee5d0SMichal Meloun 575ef2ee5d0SMichal Meloun return (0); 576ef2ee5d0SMichal Meloun } 577ef2ee5d0SMichal Meloun 578ef2ee5d0SMichal Meloun 579ef2ee5d0SMichal Meloun static device_method_t tegra_xusbpadctl_methods[] = { 580ef2ee5d0SMichal Meloun /* Device interface */ 581ef2ee5d0SMichal Meloun DEVMETHOD(device_probe, xusbpadctl_probe), 582ef2ee5d0SMichal Meloun DEVMETHOD(device_attach, xusbpadctl_attach), 583ef2ee5d0SMichal Meloun DEVMETHOD(device_detach, xusbpadctl_detach), 584ef2ee5d0SMichal Meloun 585ef2ee5d0SMichal Meloun /* fdt_pinctrl interface */ 586ef2ee5d0SMichal Meloun DEVMETHOD(fdt_pinctrl_configure, xusbpadctl_pinctrl_cfg), 587ef2ee5d0SMichal Meloun 588ef2ee5d0SMichal Meloun /* phy interface */ 589ef2ee5d0SMichal Meloun DEVMETHOD(phy_enable, xusbpadctl_phy_enable), 590ef2ee5d0SMichal Meloun 591ef2ee5d0SMichal Meloun DEVMETHOD_END 592ef2ee5d0SMichal Meloun }; 593ef2ee5d0SMichal Meloun 594ef2ee5d0SMichal Meloun static driver_t tegra_xusbpadctl_driver = { 595ef2ee5d0SMichal Meloun "tegra_xusbpadctl", 596ef2ee5d0SMichal Meloun tegra_xusbpadctl_methods, 597ef2ee5d0SMichal Meloun sizeof(struct xusbpadctl_softc), 598ef2ee5d0SMichal Meloun }; 599ef2ee5d0SMichal Meloun 600ef2ee5d0SMichal Meloun static devclass_t tegra_xusbpadctl_devclass; 601ef2ee5d0SMichal Meloun 602ef2ee5d0SMichal Meloun EARLY_DRIVER_MODULE(tegra_xusbpadctl, simplebus, tegra_xusbpadctl_driver, 603ef2ee5d0SMichal Meloun tegra_xusbpadctl_devclass, 0, 0, 73); 604