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 27ef2ee5d0SMichal Meloun #include <sys/param.h> 28ef2ee5d0SMichal Meloun #include <sys/systm.h> 29ef2ee5d0SMichal Meloun #include <sys/bus.h> 30ef2ee5d0SMichal Meloun #include <sys/kernel.h> 31ef2ee5d0SMichal Meloun #include <sys/module.h> 32ef2ee5d0SMichal Meloun #include <sys/malloc.h> 33ef2ee5d0SMichal Meloun #include <sys/rman.h> 34ef2ee5d0SMichal Meloun 35ef2ee5d0SMichal Meloun #include <machine/bus.h> 36ef2ee5d0SMichal Meloun #include <machine/fdt.h> 37ef2ee5d0SMichal Meloun 381f469a9fSEmmanuel Vadot #include <dev/hwreset/hwreset.h> 39ef2ee5d0SMichal Meloun #include <dev/extres/phy/phy.h> 4059b591b1SMichal Meloun #include <dev/extres/regulator/regulator.h> 41ef2ee5d0SMichal Meloun #include <dev/fdt/fdt_common.h> 42ef2ee5d0SMichal Meloun #include <dev/fdt/fdt_pinctrl.h> 43ef2ee5d0SMichal Meloun #include <dev/ofw/openfirm.h> 44ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus.h> 45ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus_subr.h> 46ef2ee5d0SMichal Meloun 4759b591b1SMichal Meloun #include <arm/nvidia/tegra_efuse.h> 4859b591b1SMichal Meloun 498a7a4683SEmmanuel Vadot #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> 50ef2ee5d0SMichal Meloun 51f8759facSMichal Meloun #include "phydev_if.h" 52ef2ee5d0SMichal Meloun 5359b591b1SMichal Meloun /* FUSE calibration data. */ 5459b591b1SMichal Meloun #define FUSE_XUSB_CALIB 0x0F0 5559b591b1SMichal Meloun #define FUSE_XUSB_CALIB_HS_CURR_LEVEL_123(x) (((x) >> 15) & 0x3F); 5659b591b1SMichal Meloun #define FUSE_XUSB_CALIB_HS_IREF_CAP(x) (((x) >> 13) & 0x03); 5759b591b1SMichal Meloun #define FUSE_XUSB_CALIB_HS_SQUELCH_LEVEL(x) (((x) >> 11) & 0x03); 5859b591b1SMichal Meloun #define FUSE_XUSB_CALIB_HS_TERM_RANGE_ADJ(x) (((x) >> 7) & 0x0F); 5959b591b1SMichal Meloun #define FUSE_XUSB_CALIB_HS_CURR_LEVEL_0(x) (((x) >> 0) & 0x3F); 6059b591b1SMichal Meloun 6159b591b1SMichal Meloun /* Registers. */ 62ef2ee5d0SMichal Meloun #define XUSB_PADCTL_USB2_PAD_MUX 0x004 63ef2ee5d0SMichal Meloun 6459b591b1SMichal Meloun #define XUSB_PADCTL_USB2_PORT_CAP 0x008 6559b591b1SMichal Meloun #define USB2_PORT_CAP_ULPI_PORT_INTERNAL (1 << 25) 6659b591b1SMichal Meloun #define USB2_PORT_CAP_ULPI_PORT_CAP (1 << 24) 6759b591b1SMichal Meloun #define USB2_PORT_CAP_PORT_REVERSE_ID(p) (1 << (3 + (p) * 4)) 6859b591b1SMichal Meloun #define USB2_PORT_CAP_PORT_INTERNAL(p) (1 << (2 + (p) * 4)) 6959b591b1SMichal Meloun #define USB2_PORT_CAP_PORT_CAP(p, x) (((x) & 3) << ((p) * 4)) 7059b591b1SMichal Meloun #define USB2_PORT_CAP_PORT_CAP_OTG 0x3 7159b591b1SMichal Meloun #define USB2_PORT_CAP_PORT_CAP_DEVICE 0x2 7259b591b1SMichal Meloun #define USB2_PORT_CAP_PORT_CAP_HOST 0x1 7359b591b1SMichal Meloun #define USB2_PORT_CAP_PORT_CAP_DISABLED 0x0 7459b591b1SMichal Meloun 7559b591b1SMichal Meloun #define XUSB_PADCTL_SS_PORT_MAP 0x014 7659b591b1SMichal Meloun #define SS_PORT_MAP_PORT_INTERNAL(p) (1 << (3 + (p) * 4)) 7759b591b1SMichal Meloun #define SS_PORT_MAP_PORT_MAP(p, x) (((x) & 7) << ((p) * 4)) 7859b591b1SMichal Meloun 79ef2ee5d0SMichal Meloun #define XUSB_PADCTL_ELPG_PROGRAM 0x01C 80ef2ee5d0SMichal Meloun #define ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26) 81ef2ee5d0SMichal Meloun #define ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25) 82ef2ee5d0SMichal Meloun #define ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24) 8359b591b1SMichal Meloun #define ELPG_PROGRAM_SSP_ELPG_VCORE_DOWN(x) (1 << (18 + (x) * 4)) 8459b591b1SMichal Meloun #define ELPG_PROGRAM_SSP_ELPG_CLAMP_EN_EARLY(x) (1 << (17 + (x) * 4)) 8559b591b1SMichal Meloun #define ELPG_PROGRAM_SSP_ELPG_CLAMP_EN(x) (1 << (16 + (x) * 4)) 86ef2ee5d0SMichal Meloun 87ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040 88ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19) 8959b591b1SMichal Meloun #define IOPHY_PLL_P0_CTL1_REFCLK_SEL(x) (((x) & 0xF) << 12) 90ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1) 91ef2ee5d0SMichal Meloun 92ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044 93ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6) 94ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5) 95ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4) 96ef2ee5d0SMichal Meloun 9759b591b1SMichal Meloun #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2(x) (0x058 + (x) * 4) 9859b591b1SMichal Meloun #define IOPHY_USB3_PAD_CTL2_CDR_CNTL(x) (((x) & 0x00FF) << 4) 9959b591b1SMichal Meloun #define IOPHY_USB3_PAD_CTL2_RX_EQ(x) (((x) & 0xFFFF) << 8) 10059b591b1SMichal Meloun #define IOPHY_USB3_PAD_CTL2_RX_WANDER(x) (((x) & 0x000F) << 4) 10159b591b1SMichal Meloun #define IOPHY_USB3_PAD_CTL2_RX_TERM_CNTL(x) (((x) & 0x0003) << 2) 10259b591b1SMichal Meloun #define IOPHY_USB3_PAD_CTL2_TX_TERM_CNTL(x) (((x) & 0x0003) << 0) 10359b591b1SMichal Meloun 10459b591b1SMichal Meloun #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4(x) (0x068 + (x) * 4) 10559b591b1SMichal Meloun 10659b591b1SMichal Meloun #define XUSB_PADCTL_USB2_OTG_PAD_CTL0(x) (0x0A0 + (x) * 4) 10759b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_LSBIAS_SEL (1 << 23) 10859b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_DISCON_DETECT_METHOD (1 << 22) 10959b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_PD_ZI (1 << 21) 11059b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_PD2 (1 << 20) 11159b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_PD (1 << 19) 11259b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_TERM_EN (1 << 18) 11359b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_LS_LS_FSLEW(x) (((x) & 0x03) << 16) 11459b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_LS_RSLEW(x) (((x) & 0x03) << 14) 11559b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_FS_SLEW(x) (((x) & 0x03) << 12) 11659b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_HS_SLEW(x) (((x) & 0x3F) << 6) 11759b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(x) (((x) & 0x3F) << 0) 11859b591b1SMichal Meloun 11959b591b1SMichal Meloun #define XUSB_PADCTL_USB2_OTG_PAD_CTL1(x) (0x0AC + (x) * 4) 12059b591b1SMichal Meloun #define USB2_OTG_PAD_CTL1_RPU_RANGE_ADJ(x) (((x) & 0x3) << 11) 12159b591b1SMichal Meloun #define USB2_OTG_PAD_CTL1_HS_IREF_CAP(x) (((x) & 0x3) << 9) 12259b591b1SMichal Meloun #define USB2_OTG_PAD_CTL1_SPARE(x) (((x) & 0x3) << 7) 12359b591b1SMichal Meloun #define USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ(x) (((x) & 0xF) << 3) 12459b591b1SMichal Meloun #define USB2_OTG_PAD_CTL1_PD_DR (1 << 2) 12559b591b1SMichal Meloun #define USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP (1 << 1) 12659b591b1SMichal Meloun #define USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP (1 << 0) 12759b591b1SMichal Meloun 12859b591b1SMichal Meloun #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x0B8 12959b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_ADJRPU(x) (((x) & 0x7) << 14) 13059b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_PD_TRK (1 << 13) 13159b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_PD (1 << 12) 13259b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_TERM_OFFSETL(x) (((x) & 0x3) << 9) 13359b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_VBUS_LEVEL(x) (((x) & 0x3) << 7) 13459b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_HS_CHIRP_LEVEL(x) (((x) & 0x3) << 5) 13559b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL(x) (((x) & 0x7) << 2) 13659b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL(x) (((x) & 0x3) << 0) 13759b591b1SMichal Meloun 13859b591b1SMichal Meloun #define XUSB_PADCTL_HSIC_PAD0_CTL0 0x0C8 13959b591b1SMichal Meloun #define HSIC_PAD0_CTL0_HSIC_OPT(x) (((x) & 0xF) << 16) 14059b591b1SMichal Meloun #define HSIC_PAD0_CTL0_TX_SLEWN(x) (((x) & 0xF) << 12) 14159b591b1SMichal Meloun #define HSIC_PAD0_CTL0_TX_SLEWP(x) (((x) & 0xF) << 8) 14259b591b1SMichal Meloun #define HSIC_PAD0_CTL0_TX_RTUNEN(x) (((x) & 0xF) << 4) 14359b591b1SMichal Meloun #define HSIC_PAD0_CTL0_TX_RTUNEP(x) (((x) & 0xF) << 0) 144ef2ee5d0SMichal Meloun 145ef2ee5d0SMichal Meloun #define XUSB_PADCTL_USB3_PAD_MUX 0x134 14659b591b1SMichal Meloun #define USB3_PAD_MUX_PCIE_IDDQ_DISABLE(x) (1 << (1 + (x))) 14759b591b1SMichal Meloun #define USB3_PAD_MUX_SATA_IDDQ_DISABLE (1 << 6) 14859b591b1SMichal Meloun 149ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138 150ef2ee5d0SMichal Meloun #define IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27) 151ef2ee5d0SMichal Meloun #define IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24) 152ef2ee5d0SMichal Meloun #define IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3) 153ef2ee5d0SMichal Meloun #define IOPHY_PLL_S0_CTL1_PLL_RST_L (1 << 1) 154ef2ee5d0SMichal Meloun #define IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0) 155ef2ee5d0SMichal Meloun 156ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2 0x13C 157ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_S0_CTL3 0x140 158ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_S0_CTL4 0x144 159ef2ee5d0SMichal Meloun 160ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148 161ef2ee5d0SMichal Meloun #define IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1) 162ef2ee5d0SMichal Meloun #define IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0) 163ef2ee5d0SMichal Meloun 164ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 0x14C 165ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL3 0x150 166ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL4 0x154 167ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 0x158 168ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 0x15C 169ef2ee5d0SMichal Meloun 17059b591b1SMichal Meloun #define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v)) 17159b591b1SMichal Meloun #define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r)) 17259b591b1SMichal Meloun 17359b591b1SMichal Meloun struct padctl_softc { 174ef2ee5d0SMichal Meloun device_t dev; 175ef2ee5d0SMichal Meloun struct resource *mem_res; 176ef2ee5d0SMichal Meloun hwreset_t rst; 177ef2ee5d0SMichal Meloun int phy_ena_cnt; 17859b591b1SMichal Meloun 17959b591b1SMichal Meloun /* Fuses calibration data */ 18059b591b1SMichal Meloun uint32_t hs_curr_level_0; 18159b591b1SMichal Meloun uint32_t hs_curr_level_123; 18259b591b1SMichal Meloun uint32_t hs_iref_cap; 18359b591b1SMichal Meloun uint32_t hs_term_range_adj; 18459b591b1SMichal Meloun uint32_t hs_squelch_level; 18559b591b1SMichal Meloun 18659b591b1SMichal Meloun uint32_t hs_curr_level_offset; 187ef2ee5d0SMichal Meloun }; 188ef2ee5d0SMichal Meloun 189ef2ee5d0SMichal Meloun static struct ofw_compat_data compat_data[] = { 190ef2ee5d0SMichal Meloun {"nvidia,tegra124-xusb-padctl", 1}, 191ef2ee5d0SMichal Meloun {NULL, 0}, 192ef2ee5d0SMichal Meloun }; 193ef2ee5d0SMichal Meloun 19459b591b1SMichal Meloun /* Ports. */ 19559b591b1SMichal Meloun enum padctl_port_type { 19659b591b1SMichal Meloun PADCTL_PORT_USB2, 19759b591b1SMichal Meloun PADCTL_PORT_ULPI, 19859b591b1SMichal Meloun PADCTL_PORT_HSIC, 19959b591b1SMichal Meloun PADCTL_PORT_USB3, 20059b591b1SMichal Meloun }; 20159b591b1SMichal Meloun 20259b591b1SMichal Meloun struct padctl_lane; 20359b591b1SMichal Meloun struct padctl_port { 20459b591b1SMichal Meloun enum padctl_port_type type; 20559b591b1SMichal Meloun const char *name; 20659b591b1SMichal Meloun const char *base_name; 20759b591b1SMichal Meloun int idx; 20859b591b1SMichal Meloun int (*init)(struct padctl_softc *sc, 20959b591b1SMichal Meloun struct padctl_port *port); 21059b591b1SMichal Meloun 21159b591b1SMichal Meloun /* Runtime data. */ 21259b591b1SMichal Meloun bool enabled; 21359b591b1SMichal Meloun regulator_t supply_vbus; /* USB2, USB3 */ 21459b591b1SMichal Meloun bool internal; /* ULPI, USB2, USB3 */ 21559b591b1SMichal Meloun uint32_t companion; /* USB3 */ 21659b591b1SMichal Meloun struct padctl_lane *lane; 21759b591b1SMichal Meloun }; 21859b591b1SMichal Meloun 21959b591b1SMichal Meloun static int usb3_port_init(struct padctl_softc *sc, struct padctl_port *port); 22059b591b1SMichal Meloun 22159b591b1SMichal Meloun #define PORT(t, n, p, i) { \ 22259b591b1SMichal Meloun .type = t, \ 22359b591b1SMichal Meloun .name = n "-" #p, \ 22459b591b1SMichal Meloun .base_name = n, \ 22559b591b1SMichal Meloun .idx = p, \ 22659b591b1SMichal Meloun .init = i, \ 22759b591b1SMichal Meloun } 22859b591b1SMichal Meloun static struct padctl_port ports_tbl[] = { 22959b591b1SMichal Meloun PORT(PADCTL_PORT_USB2, "usb2", 0, NULL), 23059b591b1SMichal Meloun PORT(PADCTL_PORT_USB2, "usb2", 1, NULL), 23159b591b1SMichal Meloun PORT(PADCTL_PORT_USB2, "usb2", 2, NULL), 23259b591b1SMichal Meloun PORT(PADCTL_PORT_ULPI, "ulpi", 0, NULL), 23359b591b1SMichal Meloun PORT(PADCTL_PORT_HSIC, "hsic", 0, NULL), 23459b591b1SMichal Meloun PORT(PADCTL_PORT_HSIC, "hsic", 1, NULL), 23559b591b1SMichal Meloun PORT(PADCTL_PORT_USB3, "usb3", 0, usb3_port_init), 23659b591b1SMichal Meloun PORT(PADCTL_PORT_USB3, "usb3", 1, usb3_port_init), 23759b591b1SMichal Meloun }; 23859b591b1SMichal Meloun 23959b591b1SMichal Meloun /* Pads - a group of lannes. */ 24059b591b1SMichal Meloun enum padctl_pad_type { 24159b591b1SMichal Meloun PADCTL_PAD_USB2, 24259b591b1SMichal Meloun PADCTL_PAD_ULPI, 24359b591b1SMichal Meloun PADCTL_PAD_HSIC, 24459b591b1SMichal Meloun PADCTL_PAD_PCIE, 24559b591b1SMichal Meloun PADCTL_PAD_SATA, 24659b591b1SMichal Meloun }; 24759b591b1SMichal Meloun 24859b591b1SMichal Meloun struct padctl_lane; 24959b591b1SMichal Meloun struct padctl_pad { 25059b591b1SMichal Meloun const char *name; 25159b591b1SMichal Meloun enum padctl_pad_type type; 25259b591b1SMichal Meloun int (*powerup)(struct padctl_softc *sc, 25359b591b1SMichal Meloun struct padctl_lane *lane); 25459b591b1SMichal Meloun int (*powerdown)(struct padctl_softc *sc, 25559b591b1SMichal Meloun struct padctl_lane *lane); 25659b591b1SMichal Meloun /* Runtime data. */ 25759b591b1SMichal Meloun bool enabled; 25859b591b1SMichal Meloun struct padctl_lane *lanes[8]; /* Safe maximum value. */ 25959b591b1SMichal Meloun int nlanes; 26059b591b1SMichal Meloun }; 26159b591b1SMichal Meloun 26259b591b1SMichal Meloun static int usb2_powerup(struct padctl_softc *sc, struct padctl_lane *lane); 26359b591b1SMichal Meloun static int usb2_powerdown(struct padctl_softc *sc, struct padctl_lane *lane); 26459b591b1SMichal Meloun static int pcie_powerup(struct padctl_softc *sc, struct padctl_lane *lane); 26559b591b1SMichal Meloun static int pcie_powerdown(struct padctl_softc *sc, struct padctl_lane *lane); 26659b591b1SMichal Meloun static int sata_powerup(struct padctl_softc *sc, struct padctl_lane *lane); 26759b591b1SMichal Meloun static int sata_powerdown(struct padctl_softc *sc, struct padctl_lane *lane); 26859b591b1SMichal Meloun 26959b591b1SMichal Meloun #define PAD(n, t, u, d) { \ 27059b591b1SMichal Meloun .name = n, \ 27159b591b1SMichal Meloun .type = t, \ 27259b591b1SMichal Meloun .powerup = u, \ 27359b591b1SMichal Meloun .powerdown = d, \ 27459b591b1SMichal Meloun } 27559b591b1SMichal Meloun static struct padctl_pad pads_tbl[] = { 27659b591b1SMichal Meloun PAD("usb2", PADCTL_PAD_USB2, usb2_powerup, usb2_powerdown), 27759b591b1SMichal Meloun PAD("ulpi", PADCTL_PAD_ULPI, NULL, NULL), 27859b591b1SMichal Meloun PAD("hsic", PADCTL_PAD_HSIC, NULL, NULL), 27959b591b1SMichal Meloun PAD("pcie", PADCTL_PAD_PCIE, pcie_powerup, pcie_powerdown), 28059b591b1SMichal Meloun PAD("sata", PADCTL_PAD_SATA, sata_powerup, sata_powerdown), 28159b591b1SMichal Meloun }; 28259b591b1SMichal Meloun 28359b591b1SMichal Meloun /* Lanes. */ 28459b591b1SMichal Meloun static char *otg_mux[] = {"snps", "xusb", "uart", "rsvd"}; 28559b591b1SMichal Meloun static char *usb_mux[] = {"snps", "xusb"}; 28659b591b1SMichal Meloun static char *pci_mux[] = {"pcie", "usb3-ss", "sata", "rsvd"}; 28759b591b1SMichal Meloun 288ef2ee5d0SMichal Meloun struct padctl_lane { 289ef2ee5d0SMichal Meloun const char *name; 29059b591b1SMichal Meloun int idx; 291ef2ee5d0SMichal Meloun bus_size_t reg; 292ef2ee5d0SMichal Meloun uint32_t shift; 293ef2ee5d0SMichal Meloun uint32_t mask; 294ef2ee5d0SMichal Meloun char **mux; 295ef2ee5d0SMichal Meloun int nmux; 29659b591b1SMichal Meloun /* Runtime data. */ 29759b591b1SMichal Meloun bool enabled; 29859b591b1SMichal Meloun struct padctl_pad *pad; 29959b591b1SMichal Meloun struct padctl_port *port; 30059b591b1SMichal Meloun int mux_idx; 30159b591b1SMichal Meloun 302ef2ee5d0SMichal Meloun }; 303ef2ee5d0SMichal Meloun 30459b591b1SMichal Meloun #define LANE(n, p, r, s, m, mx) { \ 30559b591b1SMichal Meloun .name = n "-" #p, \ 30659b591b1SMichal Meloun .idx = p, \ 307ef2ee5d0SMichal Meloun .reg = r, \ 308ef2ee5d0SMichal Meloun .shift = s, \ 309ef2ee5d0SMichal Meloun .mask = m, \ 310ef2ee5d0SMichal Meloun .mux = mx, \ 311ef2ee5d0SMichal Meloun .nmux = nitems(mx), \ 312ef2ee5d0SMichal Meloun } 31359b591b1SMichal Meloun static struct padctl_lane lanes_tbl[] = { 31459b591b1SMichal Meloun LANE("usb2", 0, XUSB_PADCTL_USB2_PAD_MUX, 0, 0x3, otg_mux), 31559b591b1SMichal Meloun LANE("usb2", 1, XUSB_PADCTL_USB2_PAD_MUX, 2, 0x3, otg_mux), 31659b591b1SMichal Meloun LANE("usb2", 2, XUSB_PADCTL_USB2_PAD_MUX, 4, 0x3, otg_mux), 31759b591b1SMichal Meloun LANE("ulpi", 0, XUSB_PADCTL_USB2_PAD_MUX, 12, 0x1, usb_mux), 31859b591b1SMichal Meloun LANE("hsic", 0, XUSB_PADCTL_USB2_PAD_MUX, 14, 0x1, usb_mux), 31959b591b1SMichal Meloun LANE("hsic", 1, XUSB_PADCTL_USB2_PAD_MUX, 15, 0x1, usb_mux), 32059b591b1SMichal Meloun LANE("pcie", 0, XUSB_PADCTL_USB3_PAD_MUX, 16, 0x3, pci_mux), 32159b591b1SMichal Meloun LANE("pcie", 1, XUSB_PADCTL_USB3_PAD_MUX, 18, 0x3, pci_mux), 32259b591b1SMichal Meloun LANE("pcie", 2, XUSB_PADCTL_USB3_PAD_MUX, 20, 0x3, pci_mux), 32359b591b1SMichal Meloun LANE("pcie", 3, XUSB_PADCTL_USB3_PAD_MUX, 22, 0x3, pci_mux), 32459b591b1SMichal Meloun LANE("pcie", 4, XUSB_PADCTL_USB3_PAD_MUX, 24, 0x3, pci_mux), 32559b591b1SMichal Meloun LANE("sata", 0, XUSB_PADCTL_USB3_PAD_MUX, 26, 0x3, pci_mux), 326ef2ee5d0SMichal Meloun }; 327ef2ee5d0SMichal Meloun 32859b591b1SMichal Meloun /* Define all possible mappings for USB3 port lanes */ 32959b591b1SMichal Meloun struct padctl_lane_map { 33059b591b1SMichal Meloun int port_idx; 33159b591b1SMichal Meloun enum padctl_pad_type pad_type; 33259b591b1SMichal Meloun int lane_idx; 33359b591b1SMichal Meloun }; 334ef2ee5d0SMichal Meloun 33559b591b1SMichal Meloun #define LANE_MAP(pi, pt, li) { \ 33659b591b1SMichal Meloun .port_idx = pi, \ 33759b591b1SMichal Meloun .pad_type = pt, \ 33859b591b1SMichal Meloun .lane_idx = li, \ 339ef2ee5d0SMichal Meloun } 34059b591b1SMichal Meloun static struct padctl_lane_map lane_map_tbl[] = { 34159b591b1SMichal Meloun LANE_MAP(0, PADCTL_PAD_PCIE, 0), /* port USB3-0 -> lane PCIE-0 */ 34259b591b1SMichal Meloun LANE_MAP(1, PADCTL_PAD_PCIE, 1), /* port USB3-1 -> lane PCIE-1 */ 34359b591b1SMichal Meloun /* -- or -- */ 34459b591b1SMichal Meloun LANE_MAP(1, PADCTL_PAD_SATA, 0), /* port USB3-1 -> lane SATA-0 */ 34559b591b1SMichal Meloun }; 346ef2ee5d0SMichal Meloun 347f8759facSMichal Meloun /* Phy class and methods. */ 348f8759facSMichal Meloun static int xusbpadctl_phy_enable(struct phynode *phy, bool enable); 349f8759facSMichal Meloun static phynode_method_t xusbpadctl_phynode_methods[] = { 350f8759facSMichal Meloun PHYNODEMETHOD(phynode_enable, xusbpadctl_phy_enable), 351f8759facSMichal Meloun PHYNODEMETHOD_END 352f8759facSMichal Meloun 353f8759facSMichal Meloun }; 354f8759facSMichal Meloun DEFINE_CLASS_1(xusbpadctl_phynode, xusbpadctl_phynode_class, 355f8759facSMichal Meloun xusbpadctl_phynode_methods, 0, phynode_class); 356f8759facSMichal Meloun 35759b591b1SMichal Meloun static struct padctl_port *search_lane_port(struct padctl_softc *sc, 35859b591b1SMichal Meloun struct padctl_lane *lane); 35959b591b1SMichal Meloun /* ------------------------------------------------------------------------- 36059b591b1SMichal Meloun * 36159b591b1SMichal Meloun * PHY functions 36259b591b1SMichal Meloun */ 363ef2ee5d0SMichal Meloun static int 36459b591b1SMichal Meloun usb3_port_init(struct padctl_softc *sc, struct padctl_port *port) 365ef2ee5d0SMichal Meloun { 366ef2ee5d0SMichal Meloun uint32_t reg; 367ef2ee5d0SMichal Meloun 36859b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_SS_PORT_MAP); 36959b591b1SMichal Meloun if (port->internal) 37059b591b1SMichal Meloun reg &= ~SS_PORT_MAP_PORT_INTERNAL(port->idx); 371ef2ee5d0SMichal Meloun else 37259b591b1SMichal Meloun reg |= SS_PORT_MAP_PORT_INTERNAL(port->idx); 37359b591b1SMichal Meloun reg &= ~SS_PORT_MAP_PORT_MAP(port->idx, ~0); 37459b591b1SMichal Meloun reg |= SS_PORT_MAP_PORT_MAP(port->idx, port->companion); 37559b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_SS_PORT_MAP, reg); 376ef2ee5d0SMichal Meloun 37759b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_USB3_PAD_CTL2(port->idx)); 37859b591b1SMichal Meloun reg &= ~IOPHY_USB3_PAD_CTL2_CDR_CNTL(~0); 37959b591b1SMichal Meloun reg &= ~IOPHY_USB3_PAD_CTL2_RX_EQ(~0); 38059b591b1SMichal Meloun reg &= ~IOPHY_USB3_PAD_CTL2_RX_WANDER(~0); 38159b591b1SMichal Meloun reg |= IOPHY_USB3_PAD_CTL2_CDR_CNTL(0x24); 38259b591b1SMichal Meloun reg |= IOPHY_USB3_PAD_CTL2_RX_EQ(0xF070); 38359b591b1SMichal Meloun reg |= IOPHY_USB3_PAD_CTL2_RX_WANDER(0xF); 38459b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_USB3_PAD_CTL2(port->idx), reg); 385ef2ee5d0SMichal Meloun 38659b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_USB3_PAD_CTL4(port->idx), 38759b591b1SMichal Meloun 0x002008EE); 388ef2ee5d0SMichal Meloun 38959b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 39059b591b1SMichal Meloun reg &= ~ELPG_PROGRAM_SSP_ELPG_VCORE_DOWN(port->idx); 39159b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 392ef2ee5d0SMichal Meloun DELAY(100); 393ef2ee5d0SMichal Meloun 39459b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 39559b591b1SMichal Meloun reg &= ~ELPG_PROGRAM_SSP_ELPG_CLAMP_EN_EARLY(port->idx); 39659b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 39759b591b1SMichal Meloun DELAY(100); 39859b591b1SMichal Meloun 39959b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 40059b591b1SMichal Meloun reg &= ~ELPG_PROGRAM_SSP_ELPG_CLAMP_EN(port->idx); 40159b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 40259b591b1SMichal Meloun DELAY(100); 40359b591b1SMichal Meloun 40459b591b1SMichal Meloun return (0); 40559b591b1SMichal Meloun } 40659b591b1SMichal Meloun 40759b591b1SMichal Meloun static int 40859b591b1SMichal Meloun pcie_powerup(struct padctl_softc *sc, struct padctl_lane *lane) 40959b591b1SMichal Meloun { 41059b591b1SMichal Meloun uint32_t reg; 41159b591b1SMichal Meloun int i; 41259b591b1SMichal Meloun 41359b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); 41459b591b1SMichal Meloun reg &= ~IOPHY_PLL_P0_CTL1_REFCLK_SEL(~0); 41559b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg); 41659b591b1SMichal Meloun DELAY(100); 41759b591b1SMichal Meloun 41859b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL2); 419ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_P0_CTL2_REFCLKBUF_EN; 420ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_P0_CTL2_TXCLKREF_EN; 421ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_P0_CTL2_TXCLKREF_SEL; 42259b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL2, reg); 423ef2ee5d0SMichal Meloun DELAY(100); 424ef2ee5d0SMichal Meloun 42559b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); 426ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_P0_CTL1_PLL_RST; 42759b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg); 428ef2ee5d0SMichal Meloun DELAY(100); 429ef2ee5d0SMichal Meloun 43059b591b1SMichal Meloun for (i = 100; i > 0; i--) { 43159b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); 432ef2ee5d0SMichal Meloun if (reg & IOPHY_PLL_P0_CTL1_PLL0_LOCKDET) 43359b591b1SMichal Meloun break; 434ef2ee5d0SMichal Meloun DELAY(10); 435ef2ee5d0SMichal Meloun } 43659b591b1SMichal Meloun if (i <= 0) { 43759b591b1SMichal Meloun device_printf(sc->dev, "Failed to power up PCIe phy\n"); 438ef2ee5d0SMichal Meloun return (ETIMEDOUT); 439ef2ee5d0SMichal Meloun } 44059b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); 44159b591b1SMichal Meloun reg |= USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->idx); 44259b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); 443ef2ee5d0SMichal Meloun 44459b591b1SMichal Meloun return (0); 44559b591b1SMichal Meloun } 446ef2ee5d0SMichal Meloun 447ef2ee5d0SMichal Meloun static int 44859b591b1SMichal Meloun pcie_powerdown(struct padctl_softc *sc, struct padctl_lane *lane) 449ef2ee5d0SMichal Meloun { 450ef2ee5d0SMichal Meloun uint32_t reg; 451ef2ee5d0SMichal Meloun 45259b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); 45359b591b1SMichal Meloun reg &= ~USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->idx); 45459b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); 45559b591b1SMichal Meloun 45659b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); 457ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_P0_CTL1_PLL_RST; 45859b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg); 459ef2ee5d0SMichal Meloun DELAY(100); 46059b591b1SMichal Meloun 461ef2ee5d0SMichal Meloun return (0); 462ef2ee5d0SMichal Meloun 463ef2ee5d0SMichal Meloun } 464ef2ee5d0SMichal Meloun 465ef2ee5d0SMichal Meloun static int 46659b591b1SMichal Meloun sata_powerup(struct padctl_softc *sc, struct padctl_lane *lane) 467ef2ee5d0SMichal Meloun { 468ef2ee5d0SMichal Meloun uint32_t reg; 469ef2ee5d0SMichal Meloun int i; 470ef2ee5d0SMichal Meloun 47159b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); 472ef2ee5d0SMichal Meloun reg &= ~IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; 473ef2ee5d0SMichal Meloun reg &= ~IOPHY_MISC_PAD_S0_CTL1_IDDQ; 47459b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg); 475ef2ee5d0SMichal Meloun 47659b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 477ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; 478ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_S0_CTL1_PLL_IDDQ; 47959b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 480ef2ee5d0SMichal Meloun 48159b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 482ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_S0_CTL1_PLL1_MODE; 48359b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 484ef2ee5d0SMichal Meloun 48559b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 486ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_S0_CTL1_PLL_RST_L; 48759b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 488ef2ee5d0SMichal Meloun 489ef2ee5d0SMichal Meloun for (i = 100; i >= 0; i--) { 49059b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 491ef2ee5d0SMichal Meloun if (reg & IOPHY_PLL_S0_CTL1_PLL1_LOCKDET) 492ef2ee5d0SMichal Meloun break; 493ef2ee5d0SMichal Meloun DELAY(100); 494ef2ee5d0SMichal Meloun } 495ef2ee5d0SMichal Meloun if (i <= 0) { 496ef2ee5d0SMichal Meloun device_printf(sc->dev, "Failed to power up SATA phy\n"); 497ef2ee5d0SMichal Meloun return (ETIMEDOUT); 498ef2ee5d0SMichal Meloun } 49959b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); 50059b591b1SMichal Meloun reg |= IOPHY_PLL_S0_CTL1_PLL_RST_L; 50159b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); 50259b591b1SMichal Meloun 50359b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); 50459b591b1SMichal Meloun reg |= USB3_PAD_MUX_SATA_IDDQ_DISABLE; 50559b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); 506ef2ee5d0SMichal Meloun 507ef2ee5d0SMichal Meloun return (0); 508ef2ee5d0SMichal Meloun } 509ef2ee5d0SMichal Meloun 510ef2ee5d0SMichal Meloun static int 51159b591b1SMichal Meloun sata_powerdown(struct padctl_softc *sc, struct padctl_lane *lane) 512ef2ee5d0SMichal Meloun { 513ef2ee5d0SMichal Meloun uint32_t reg; 514ef2ee5d0SMichal Meloun 51559b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); 51659b591b1SMichal Meloun reg &= ~USB3_PAD_MUX_SATA_IDDQ_DISABLE; 51759b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); 51859b591b1SMichal Meloun 51959b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 520ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_S0_CTL1_PLL_RST_L; 52159b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 522ef2ee5d0SMichal Meloun DELAY(100); 523ef2ee5d0SMichal Meloun 52459b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 525ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_S0_CTL1_PLL1_MODE; 52659b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 527ef2ee5d0SMichal Meloun DELAY(100); 528ef2ee5d0SMichal Meloun 52959b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 530ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; 531ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_S0_CTL1_PLL_IDDQ; 53259b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 533ef2ee5d0SMichal Meloun DELAY(100); 534ef2ee5d0SMichal Meloun 53559b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); 536ef2ee5d0SMichal Meloun reg |= IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; 537ef2ee5d0SMichal Meloun reg |= IOPHY_MISC_PAD_S0_CTL1_IDDQ; 53859b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg); 539ef2ee5d0SMichal Meloun DELAY(100); 540ef2ee5d0SMichal Meloun 541ef2ee5d0SMichal Meloun return (0); 542ef2ee5d0SMichal Meloun } 543ef2ee5d0SMichal Meloun 544ef2ee5d0SMichal Meloun static int 54559b591b1SMichal Meloun usb2_powerup(struct padctl_softc *sc, struct padctl_lane *lane) 54659b591b1SMichal Meloun { 54759b591b1SMichal Meloun uint32_t reg; 54859b591b1SMichal Meloun struct padctl_port *port; 54959b591b1SMichal Meloun int rv; 55059b591b1SMichal Meloun 55159b591b1SMichal Meloun port = search_lane_port(sc, lane); 55259b591b1SMichal Meloun if (port == NULL) { 55359b591b1SMichal Meloun device_printf(sc->dev, "Cannot find port for lane: %s\n", 55459b591b1SMichal Meloun lane->name); 55559b591b1SMichal Meloun } 55659b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 55759b591b1SMichal Meloun reg &= ~USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL(~0); 55859b591b1SMichal Meloun reg &= ~USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL(~0); 55959b591b1SMichal Meloun reg |= USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL(sc->hs_squelch_level); 56059b591b1SMichal Meloun reg |= USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL(5); 56159b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0, reg); 56259b591b1SMichal Meloun 56359b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB2_PORT_CAP); 56459b591b1SMichal Meloun reg &= ~USB2_PORT_CAP_PORT_CAP(lane->idx, ~0); 56559b591b1SMichal Meloun reg |= USB2_PORT_CAP_PORT_CAP(lane->idx, USB2_PORT_CAP_PORT_CAP_HOST); 56659b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB2_PORT_CAP, reg); 56759b591b1SMichal Meloun 56859b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL0(lane->idx)); 56959b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(~0); 57059b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL0_HS_SLEW(~0); 57159b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL0_LS_RSLEW(~0); 57259b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL0_PD; 57359b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL0_PD2; 57459b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL0_PD_ZI; 57559b591b1SMichal Meloun 57659b591b1SMichal Meloun reg |= USB2_OTG_PAD_CTL0_HS_SLEW(14); 57759b591b1SMichal Meloun if (lane->idx == 0) { 57859b591b1SMichal Meloun reg |= USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(sc->hs_curr_level_0); 57959b591b1SMichal Meloun reg |= USB2_OTG_PAD_CTL0_LS_RSLEW(3); 58059b591b1SMichal Meloun } else { 58159b591b1SMichal Meloun reg |= USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(sc->hs_curr_level_123); 58259b591b1SMichal Meloun reg |= USB2_OTG_PAD_CTL0_LS_RSLEW(0); 58359b591b1SMichal Meloun } 58459b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL0(lane->idx), reg); 58559b591b1SMichal Meloun 58659b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL1(lane->idx)); 58759b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ(~0); 58859b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL1_HS_IREF_CAP(~0); 58959b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL1_PD_DR; 59059b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP; 59159b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP; 59259b591b1SMichal Meloun 59359b591b1SMichal Meloun reg |= USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ(sc->hs_term_range_adj); 59459b591b1SMichal Meloun reg |= USB2_OTG_PAD_CTL1_HS_IREF_CAP(sc->hs_iref_cap); 59559b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL1(lane->idx), reg); 59659b591b1SMichal Meloun 59759b591b1SMichal Meloun if (port != NULL && port->supply_vbus != NULL) { 59859b591b1SMichal Meloun rv = regulator_enable(port->supply_vbus); 59959b591b1SMichal Meloun if (rv != 0) { 60059b591b1SMichal Meloun device_printf(sc->dev, 60159b591b1SMichal Meloun "Cannot enable vbus regulator\n"); 60259b591b1SMichal Meloun return (rv); 60359b591b1SMichal Meloun } 60459b591b1SMichal Meloun } 60559b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 60659b591b1SMichal Meloun reg &= ~USB2_BIAS_PAD_CTL0_PD; 60759b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0, reg); 60859b591b1SMichal Meloun 60959b591b1SMichal Meloun return (0); 61059b591b1SMichal Meloun } 61159b591b1SMichal Meloun 61259b591b1SMichal Meloun static int 61359b591b1SMichal Meloun usb2_powerdown(struct padctl_softc *sc, struct padctl_lane *lane) 61459b591b1SMichal Meloun { 61559b591b1SMichal Meloun uint32_t reg; 61659b591b1SMichal Meloun struct padctl_port *port; 61759b591b1SMichal Meloun int rv; 61859b591b1SMichal Meloun 61959b591b1SMichal Meloun port = search_lane_port(sc, lane); 62059b591b1SMichal Meloun if (port == NULL) { 62159b591b1SMichal Meloun device_printf(sc->dev, "Cannot find port for lane: %s\n", 62259b591b1SMichal Meloun lane->name); 62359b591b1SMichal Meloun } 62459b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 62559b591b1SMichal Meloun reg |= USB2_BIAS_PAD_CTL0_PD; 62659b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0, reg); 62759b591b1SMichal Meloun 62859b591b1SMichal Meloun if (port != NULL && port->supply_vbus != NULL) { 62959b591b1SMichal Meloun rv = regulator_enable(port->supply_vbus); 63059b591b1SMichal Meloun if (rv != 0) { 63159b591b1SMichal Meloun device_printf(sc->dev, 63259b591b1SMichal Meloun "Cannot disable vbus regulator\n"); 63359b591b1SMichal Meloun return (rv); 63459b591b1SMichal Meloun } 63559b591b1SMichal Meloun } 63659b591b1SMichal Meloun return (0); 63759b591b1SMichal Meloun } 63859b591b1SMichal Meloun 63959b591b1SMichal Meloun static int 64059b591b1SMichal Meloun phy_powerup(struct padctl_softc *sc) 641ef2ee5d0SMichal Meloun { 642ef2ee5d0SMichal Meloun uint32_t reg; 643ef2ee5d0SMichal Meloun 64459b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 645ef2ee5d0SMichal Meloun reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; 64659b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 64759b591b1SMichal Meloun DELAY(100); 64859b591b1SMichal Meloun 64959b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 65059b591b1SMichal Meloun reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; 65159b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 65259b591b1SMichal Meloun DELAY(100); 65359b591b1SMichal Meloun 65459b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 65559b591b1SMichal Meloun reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; 65659b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 657ef2ee5d0SMichal Meloun DELAY(100); 658ef2ee5d0SMichal Meloun 659ef2ee5d0SMichal Meloun return (0); 660ef2ee5d0SMichal Meloun } 661ef2ee5d0SMichal Meloun 662ef2ee5d0SMichal Meloun static int 66359b591b1SMichal Meloun phy_powerdown(struct padctl_softc *sc) 664ef2ee5d0SMichal Meloun { 665ef2ee5d0SMichal Meloun uint32_t reg; 666ef2ee5d0SMichal Meloun 66759b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 668ef2ee5d0SMichal Meloun reg |= ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; 66959b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 670ef2ee5d0SMichal Meloun DELAY(100); 671ef2ee5d0SMichal Meloun 67259b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 673ef2ee5d0SMichal Meloun reg |= ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; 67459b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 67559b591b1SMichal Meloun DELAY(100); 67659b591b1SMichal Meloun 67759b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 67859b591b1SMichal Meloun reg |= ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; 67959b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 680ef2ee5d0SMichal Meloun DELAY(100); 681ef2ee5d0SMichal Meloun 682ef2ee5d0SMichal Meloun return (0); 683ef2ee5d0SMichal Meloun } 684ef2ee5d0SMichal Meloun 685ef2ee5d0SMichal Meloun static int 686f8759facSMichal Meloun xusbpadctl_phy_enable(struct phynode *phy, bool enable) 687ef2ee5d0SMichal Meloun { 688f8759facSMichal Meloun device_t dev; 689f8759facSMichal Meloun intptr_t id; 69059b591b1SMichal Meloun struct padctl_softc *sc; 69159b591b1SMichal Meloun struct padctl_lane *lane; 69259b591b1SMichal Meloun struct padctl_pad *pad; 693ef2ee5d0SMichal Meloun int rv; 694ef2ee5d0SMichal Meloun 695f8759facSMichal Meloun dev = phynode_get_device(phy); 696f8759facSMichal Meloun id = phynode_get_id(phy); 697ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 698ef2ee5d0SMichal Meloun 69959b591b1SMichal Meloun if (id < 0 || id >= nitems(lanes_tbl)) { 700ef2ee5d0SMichal Meloun device_printf(dev, "Unknown phy: %d\n", id); 701ef2ee5d0SMichal Meloun return (ENXIO); 702ef2ee5d0SMichal Meloun } 70359b591b1SMichal Meloun lane = lanes_tbl + id; 70459b591b1SMichal Meloun if (!lane->enabled) { 70559b591b1SMichal Meloun device_printf(dev, "Lane is not enabled/configured: %s\n", 70659b591b1SMichal Meloun lane->name); 70759b591b1SMichal Meloun return (ENXIO); 70859b591b1SMichal Meloun } 70959b591b1SMichal Meloun pad = lane->pad; 710ef2ee5d0SMichal Meloun if (enable) { 711ef2ee5d0SMichal Meloun if (sc->phy_ena_cnt == 0) { 71259b591b1SMichal Meloun rv = phy_powerup(sc); 713ef2ee5d0SMichal Meloun if (rv != 0) 714ef2ee5d0SMichal Meloun return (rv); 715ef2ee5d0SMichal Meloun } 716ef2ee5d0SMichal Meloun sc->phy_ena_cnt++; 717ef2ee5d0SMichal Meloun } 718ef2ee5d0SMichal Meloun 719ef2ee5d0SMichal Meloun if (enable) 72059b591b1SMichal Meloun rv = pad->powerup(sc, lane); 721ef2ee5d0SMichal Meloun else 72259b591b1SMichal Meloun rv = pad->powerdown(sc, lane); 723ef2ee5d0SMichal Meloun if (rv != 0) 724ef2ee5d0SMichal Meloun return (rv); 72559b591b1SMichal Meloun 726ef2ee5d0SMichal Meloun if (!enable) { 727ef2ee5d0SMichal Meloun if (sc->phy_ena_cnt == 1) { 72859b591b1SMichal Meloun rv = phy_powerdown(sc); 729ef2ee5d0SMichal Meloun if (rv != 0) 730ef2ee5d0SMichal Meloun return (rv); 731ef2ee5d0SMichal Meloun } 732ef2ee5d0SMichal Meloun sc->phy_ena_cnt--; 733ef2ee5d0SMichal Meloun } 734ef2ee5d0SMichal Meloun 735ef2ee5d0SMichal Meloun return (0); 736ef2ee5d0SMichal Meloun } 737ef2ee5d0SMichal Meloun 73859b591b1SMichal Meloun /* ------------------------------------------------------------------------- 73959b591b1SMichal Meloun * 74059b591b1SMichal Meloun * FDT processing 74159b591b1SMichal Meloun */ 74259b591b1SMichal Meloun static struct padctl_port * 74359b591b1SMichal Meloun search_port(struct padctl_softc *sc, char *port_name) 74459b591b1SMichal Meloun { 74559b591b1SMichal Meloun int i; 74659b591b1SMichal Meloun 74759b591b1SMichal Meloun for (i = 0; i < nitems(ports_tbl); i++) { 74859b591b1SMichal Meloun if (strcmp(port_name, ports_tbl[i].name) == 0) 74959b591b1SMichal Meloun return (&ports_tbl[i]); 75059b591b1SMichal Meloun } 75159b591b1SMichal Meloun return (NULL); 75259b591b1SMichal Meloun } 75359b591b1SMichal Meloun 75459b591b1SMichal Meloun static struct padctl_port * 75559b591b1SMichal Meloun search_lane_port(struct padctl_softc *sc, struct padctl_lane *lane) 75659b591b1SMichal Meloun { 75759b591b1SMichal Meloun int i; 75859b591b1SMichal Meloun 75959b591b1SMichal Meloun for (i = 0; i < nitems(ports_tbl); i++) { 76059b591b1SMichal Meloun if (!ports_tbl[i].enabled) 76159b591b1SMichal Meloun continue; 76259b591b1SMichal Meloun if (ports_tbl[i].lane == lane) 76359b591b1SMichal Meloun return (ports_tbl + i); 76459b591b1SMichal Meloun } 76559b591b1SMichal Meloun return (NULL); 76659b591b1SMichal Meloun } 76759b591b1SMichal Meloun 76859b591b1SMichal Meloun static struct padctl_lane * 76959b591b1SMichal Meloun search_lane(struct padctl_softc *sc, char *lane_name) 77059b591b1SMichal Meloun { 77159b591b1SMichal Meloun int i; 77259b591b1SMichal Meloun 77359b591b1SMichal Meloun for (i = 0; i < nitems(lanes_tbl); i++) { 77459b591b1SMichal Meloun if (strcmp(lane_name, lanes_tbl[i].name) == 0) 77559b591b1SMichal Meloun return (lanes_tbl + i); 77659b591b1SMichal Meloun } 77759b591b1SMichal Meloun return (NULL); 77859b591b1SMichal Meloun } 77959b591b1SMichal Meloun 78059b591b1SMichal Meloun static struct padctl_lane * 78159b591b1SMichal Meloun search_pad_lane(struct padctl_softc *sc, enum padctl_pad_type type, int idx) 78259b591b1SMichal Meloun { 78359b591b1SMichal Meloun int i; 78459b591b1SMichal Meloun 78559b591b1SMichal Meloun for (i = 0; i < nitems(lanes_tbl); i++) { 78659b591b1SMichal Meloun if (!lanes_tbl[i].enabled) 78759b591b1SMichal Meloun continue; 78859b591b1SMichal Meloun if (type == lanes_tbl[i].pad->type && idx == lanes_tbl[i].idx) 78959b591b1SMichal Meloun return (lanes_tbl + i); 79059b591b1SMichal Meloun } 79159b591b1SMichal Meloun return (NULL); 79259b591b1SMichal Meloun } 79359b591b1SMichal Meloun 79459b591b1SMichal Meloun static struct padctl_lane * 79559b591b1SMichal Meloun search_usb3_pad_lane(struct padctl_softc *sc, int idx) 79659b591b1SMichal Meloun { 79759b591b1SMichal Meloun int i; 79859b591b1SMichal Meloun struct padctl_lane *lane, *tmp; 79959b591b1SMichal Meloun 80059b591b1SMichal Meloun lane = NULL; 80159b591b1SMichal Meloun for (i = 0; i < nitems(lane_map_tbl); i++) { 80259b591b1SMichal Meloun if (idx != lane_map_tbl[i].port_idx) 80359b591b1SMichal Meloun continue; 80459b591b1SMichal Meloun tmp = search_pad_lane(sc, lane_map_tbl[i].pad_type, 80559b591b1SMichal Meloun lane_map_tbl[i].lane_idx); 80659b591b1SMichal Meloun if (tmp == NULL) 80759b591b1SMichal Meloun continue; 80859b591b1SMichal Meloun if (strcmp(tmp->mux[tmp->mux_idx], "usb3-ss") != 0) 80959b591b1SMichal Meloun continue; 81059b591b1SMichal Meloun if (lane != NULL) { 81159b591b1SMichal Meloun device_printf(sc->dev, "Duplicated mappings found for" 81259b591b1SMichal Meloun " lanes: %s and %s\n", lane->name, tmp->name); 81359b591b1SMichal Meloun return (NULL); 81459b591b1SMichal Meloun } 81559b591b1SMichal Meloun lane = tmp; 81659b591b1SMichal Meloun } 81759b591b1SMichal Meloun return (lane); 81859b591b1SMichal Meloun } 81959b591b1SMichal Meloun 82059b591b1SMichal Meloun static struct padctl_pad * 82159b591b1SMichal Meloun search_pad(struct padctl_softc *sc, char *pad_name) 82259b591b1SMichal Meloun { 82359b591b1SMichal Meloun int i; 82459b591b1SMichal Meloun 82559b591b1SMichal Meloun for (i = 0; i < nitems(pads_tbl); i++) { 82659b591b1SMichal Meloun if (strcmp(pad_name, pads_tbl[i].name) == 0) 82759b591b1SMichal Meloun return (pads_tbl + i); 82859b591b1SMichal Meloun } 82959b591b1SMichal Meloun return (NULL); 83059b591b1SMichal Meloun } 83159b591b1SMichal Meloun 83259b591b1SMichal Meloun static int 83359b591b1SMichal Meloun search_mux(struct padctl_softc *sc, struct padctl_lane *lane, char *fnc_name) 83459b591b1SMichal Meloun { 83559b591b1SMichal Meloun int i; 83659b591b1SMichal Meloun 83759b591b1SMichal Meloun for (i = 0; i < lane->nmux; i++) { 83859b591b1SMichal Meloun if (strcmp(fnc_name, lane->mux[i]) == 0) 83959b591b1SMichal Meloun return (i); 84059b591b1SMichal Meloun } 84159b591b1SMichal Meloun return (-1); 84259b591b1SMichal Meloun } 84359b591b1SMichal Meloun 84459b591b1SMichal Meloun static int 84559b591b1SMichal Meloun config_lane(struct padctl_softc *sc, struct padctl_lane *lane) 84659b591b1SMichal Meloun { 84759b591b1SMichal Meloun uint32_t reg; 84859b591b1SMichal Meloun 84959b591b1SMichal Meloun reg = RD4(sc, lane->reg); 85059b591b1SMichal Meloun reg &= ~(lane->mask << lane->shift); 85159b591b1SMichal Meloun reg |= (lane->mux_idx & lane->mask) << lane->shift; 85259b591b1SMichal Meloun WR4(sc, lane->reg, reg); 85359b591b1SMichal Meloun return (0); 85459b591b1SMichal Meloun } 85559b591b1SMichal Meloun 85659b591b1SMichal Meloun static int 85759b591b1SMichal Meloun process_lane(struct padctl_softc *sc, phandle_t node, struct padctl_pad *pad) 85859b591b1SMichal Meloun { 85959b591b1SMichal Meloun struct padctl_lane *lane; 860f8759facSMichal Meloun struct phynode *phynode; 861f8759facSMichal Meloun struct phynode_init_def phy_init; 86259b591b1SMichal Meloun char *name; 86359b591b1SMichal Meloun char *function; 86459b591b1SMichal Meloun int rv; 86559b591b1SMichal Meloun 86659b591b1SMichal Meloun name = NULL; 86759b591b1SMichal Meloun function = NULL; 868217d17bcSOleksandr Tymoshenko rv = OF_getprop_alloc(node, "name", (void **)&name); 86959b591b1SMichal Meloun if (rv <= 0) { 87059b591b1SMichal Meloun device_printf(sc->dev, "Cannot read lane name.\n"); 87159b591b1SMichal Meloun return (ENXIO); 87259b591b1SMichal Meloun } 87359b591b1SMichal Meloun 87459b591b1SMichal Meloun lane = search_lane(sc, name); 87559b591b1SMichal Meloun if (lane == NULL) { 87659b591b1SMichal Meloun device_printf(sc->dev, "Unknown lane: %s\n", name); 87759b591b1SMichal Meloun rv = ENXIO; 87859b591b1SMichal Meloun goto end; 87959b591b1SMichal Meloun } 88059b591b1SMichal Meloun 88159b591b1SMichal Meloun /* Read function (mux) settings. */ 882217d17bcSOleksandr Tymoshenko rv = OF_getprop_alloc(node, "nvidia,function", (void **)&function); 88359b591b1SMichal Meloun if (rv <= 0) { 88459b591b1SMichal Meloun device_printf(sc->dev, "Cannot read lane function.\n"); 88559b591b1SMichal Meloun rv = ENXIO; 88659b591b1SMichal Meloun goto end; 88759b591b1SMichal Meloun } 88859b591b1SMichal Meloun 88959b591b1SMichal Meloun lane->mux_idx = search_mux(sc, lane, function); 89059b591b1SMichal Meloun if (lane->mux_idx == ~0) { 89159b591b1SMichal Meloun device_printf(sc->dev, "Unknown function %s for lane %s\n", 89259b591b1SMichal Meloun function, name); 89359b591b1SMichal Meloun rv = ENXIO; 89459b591b1SMichal Meloun goto end; 89559b591b1SMichal Meloun } 89659b591b1SMichal Meloun 89759b591b1SMichal Meloun rv = config_lane(sc, lane); 89859b591b1SMichal Meloun if (rv != 0) { 89959b591b1SMichal Meloun device_printf(sc->dev, "Cannot configure lane: %s: %d\n", 90059b591b1SMichal Meloun name, rv); 90159b591b1SMichal Meloun rv = ENXIO; 90259b591b1SMichal Meloun goto end; 90359b591b1SMichal Meloun } 90459b591b1SMichal Meloun lane->pad = pad; 90559b591b1SMichal Meloun lane->enabled = true; 90659b591b1SMichal Meloun pad->lanes[pad->nlanes++] = lane; 907f8759facSMichal Meloun 908f8759facSMichal Meloun /* Create and register phy. */ 909f8759facSMichal Meloun bzero(&phy_init, sizeof(phy_init)); 910f8759facSMichal Meloun phy_init.id = lane - lanes_tbl; 911f8759facSMichal Meloun phy_init.ofw_node = node; 912f8759facSMichal Meloun phynode = phynode_create(sc->dev, &xusbpadctl_phynode_class, &phy_init); 913f8759facSMichal Meloun if (phynode == NULL) { 914f8759facSMichal Meloun device_printf(sc->dev, "Cannot create phy\n"); 915f8759facSMichal Meloun rv = ENXIO; 916f8759facSMichal Meloun goto end; 917f8759facSMichal Meloun } 918f8759facSMichal Meloun if (phynode_register(phynode) == NULL) { 919f8759facSMichal Meloun device_printf(sc->dev, "Cannot create phy\n"); 920f8759facSMichal Meloun return (ENXIO); 921f8759facSMichal Meloun } 922f8759facSMichal Meloun 92359b591b1SMichal Meloun rv = 0; 92459b591b1SMichal Meloun 92559b591b1SMichal Meloun end: 92659b591b1SMichal Meloun if (name != NULL) 92759b591b1SMichal Meloun OF_prop_free(name); 92859b591b1SMichal Meloun if (function != NULL) 92959b591b1SMichal Meloun OF_prop_free(function); 93059b591b1SMichal Meloun return (rv); 93159b591b1SMichal Meloun } 93259b591b1SMichal Meloun 93359b591b1SMichal Meloun static int 93459b591b1SMichal Meloun process_pad(struct padctl_softc *sc, phandle_t node) 93559b591b1SMichal Meloun { 93659b591b1SMichal Meloun struct padctl_pad *pad; 93759b591b1SMichal Meloun char *name; 93859b591b1SMichal Meloun int rv; 93959b591b1SMichal Meloun 94059b591b1SMichal Meloun name = NULL; 941217d17bcSOleksandr Tymoshenko rv = OF_getprop_alloc(node, "name", (void **)&name); 94259b591b1SMichal Meloun if (rv <= 0) { 94359b591b1SMichal Meloun device_printf(sc->dev, "Cannot read pad name.\n"); 94459b591b1SMichal Meloun return (ENXIO); 94559b591b1SMichal Meloun } 94659b591b1SMichal Meloun pad = search_pad(sc, name); 94759b591b1SMichal Meloun if (pad == NULL) { 94859b591b1SMichal Meloun device_printf(sc->dev, "Unknown pad: %s\n", name); 94959b591b1SMichal Meloun rv = ENXIO; 95059b591b1SMichal Meloun goto end; 95159b591b1SMichal Meloun } 95259b591b1SMichal Meloun 95359b591b1SMichal Meloun /* Read and process associated lanes. */ 95459b591b1SMichal Meloun node = ofw_bus_find_child(node, "lanes"); 95559b591b1SMichal Meloun if (node <= 0) { 95659b591b1SMichal Meloun device_printf(sc->dev, "Cannot find regulators subnode\n"); 95759b591b1SMichal Meloun rv = ENXIO; 95859b591b1SMichal Meloun goto end; 95959b591b1SMichal Meloun } 96059b591b1SMichal Meloun 96159b591b1SMichal Meloun for (node = OF_child(node); node != 0; node = OF_peer(node)) { 9627bc28467SAndrew Turner if (!ofw_bus_node_status_okay(node)) 96359b591b1SMichal Meloun continue; 96459b591b1SMichal Meloun 96559b591b1SMichal Meloun rv = process_lane(sc, node, pad); 96659b591b1SMichal Meloun if (rv != 0) 96759b591b1SMichal Meloun goto end; 96859b591b1SMichal Meloun } 96959b591b1SMichal Meloun pad->enabled = true; 97059b591b1SMichal Meloun rv = 0; 97159b591b1SMichal Meloun end: 97259b591b1SMichal Meloun if (name != NULL) 97359b591b1SMichal Meloun OF_prop_free(name); 97459b591b1SMichal Meloun return (rv); 97559b591b1SMichal Meloun } 97659b591b1SMichal Meloun 97759b591b1SMichal Meloun static int 97859b591b1SMichal Meloun process_port(struct padctl_softc *sc, phandle_t node) 97959b591b1SMichal Meloun { 98059b591b1SMichal Meloun 98159b591b1SMichal Meloun struct padctl_port *port; 98259b591b1SMichal Meloun char *name; 98359b591b1SMichal Meloun int rv; 98459b591b1SMichal Meloun 98559b591b1SMichal Meloun name = NULL; 986217d17bcSOleksandr Tymoshenko rv = OF_getprop_alloc(node, "name", (void **)&name); 98759b591b1SMichal Meloun if (rv <= 0) { 98859b591b1SMichal Meloun device_printf(sc->dev, "Cannot read port name.\n"); 98959b591b1SMichal Meloun return (ENXIO); 99059b591b1SMichal Meloun } 99159b591b1SMichal Meloun 99259b591b1SMichal Meloun port = search_port(sc, name); 99359b591b1SMichal Meloun if (port == NULL) { 99459b591b1SMichal Meloun device_printf(sc->dev, "Unknown port: %s\n", name); 99559b591b1SMichal Meloun rv = ENXIO; 99659b591b1SMichal Meloun goto end; 99759b591b1SMichal Meloun } 99859b591b1SMichal Meloun 99959b591b1SMichal Meloun if (port->type == PADCTL_PORT_USB3) { 100059b591b1SMichal Meloun rv = OF_getencprop(node, "nvidia,usb2-companion", 100159b591b1SMichal Meloun &(port->companion), sizeof(port->companion)); 100259b591b1SMichal Meloun if (rv <= 0) { 100359b591b1SMichal Meloun device_printf(sc->dev, 100459b591b1SMichal Meloun "Missing 'nvidia,usb2-companion' property " 100559b591b1SMichal Meloun "for port: %s\n", name); 100659b591b1SMichal Meloun rv = ENXIO; 100759b591b1SMichal Meloun goto end; 100859b591b1SMichal Meloun } 100959b591b1SMichal Meloun } 101059b591b1SMichal Meloun 101159b591b1SMichal Meloun if (OF_hasprop(node, "vbus-supply")) { 101259b591b1SMichal Meloun rv = regulator_get_by_ofw_property(sc->dev, 0, 101359b591b1SMichal Meloun "vbus-supply", &port->supply_vbus); 101459b591b1SMichal Meloun if (rv <= 0) { 101559b591b1SMichal Meloun device_printf(sc->dev, 101659b591b1SMichal Meloun "Cannot get 'vbus-supply' regulator " 101759b591b1SMichal Meloun "for port: %s\n", name); 101859b591b1SMichal Meloun rv = ENXIO; 101959b591b1SMichal Meloun goto end; 102059b591b1SMichal Meloun } 102159b591b1SMichal Meloun } 102259b591b1SMichal Meloun 102359b591b1SMichal Meloun if (OF_hasprop(node, "nvidia,internal")) 102459b591b1SMichal Meloun port->internal = true; 102559b591b1SMichal Meloun /* Find assigned lane */ 102659b591b1SMichal Meloun if (port->lane == NULL) { 102759b591b1SMichal Meloun switch(port->type) { 102859b591b1SMichal Meloun /* Routing is fixed for USB2, ULPI AND HSIC. */ 102959b591b1SMichal Meloun case PADCTL_PORT_USB2: 103059b591b1SMichal Meloun port->lane = search_pad_lane(sc, PADCTL_PAD_USB2, 103159b591b1SMichal Meloun port->idx); 103259b591b1SMichal Meloun break; 103359b591b1SMichal Meloun case PADCTL_PORT_ULPI: 103459b591b1SMichal Meloun port->lane = search_pad_lane(sc, PADCTL_PAD_ULPI, 103559b591b1SMichal Meloun port->idx); 103659b591b1SMichal Meloun break; 103759b591b1SMichal Meloun case PADCTL_PORT_HSIC: 103859b591b1SMichal Meloun port->lane = search_pad_lane(sc, PADCTL_PAD_HSIC, 103959b591b1SMichal Meloun port->idx); 104059b591b1SMichal Meloun break; 104159b591b1SMichal Meloun case PADCTL_PORT_USB3: 104259b591b1SMichal Meloun port->lane = search_usb3_pad_lane(sc, port->idx); 104359b591b1SMichal Meloun break; 104459b591b1SMichal Meloun } 104559b591b1SMichal Meloun } 104659b591b1SMichal Meloun if (port->lane == NULL) { 104759b591b1SMichal Meloun device_printf(sc->dev, "Cannot find lane for port: %s\n", name); 104859b591b1SMichal Meloun rv = ENXIO; 104959b591b1SMichal Meloun goto end; 105059b591b1SMichal Meloun } 105159b591b1SMichal Meloun port->enabled = true; 105259b591b1SMichal Meloun rv = 0; 105359b591b1SMichal Meloun end: 105459b591b1SMichal Meloun if (name != NULL) 105559b591b1SMichal Meloun OF_prop_free(name); 105659b591b1SMichal Meloun return (rv); 105759b591b1SMichal Meloun } 105859b591b1SMichal Meloun 105959b591b1SMichal Meloun static int 106059b591b1SMichal Meloun parse_fdt(struct padctl_softc *sc, phandle_t base_node) 106159b591b1SMichal Meloun { 106259b591b1SMichal Meloun phandle_t node; 106359b591b1SMichal Meloun int rv; 106459b591b1SMichal Meloun 106559b591b1SMichal Meloun rv = 0; 106659b591b1SMichal Meloun node = ofw_bus_find_child(base_node, "pads"); 106759b591b1SMichal Meloun 106859b591b1SMichal Meloun if (node <= 0) { 106959b591b1SMichal Meloun device_printf(sc->dev, "Cannot find pads subnode.\n"); 107059b591b1SMichal Meloun return (ENXIO); 107159b591b1SMichal Meloun } 107259b591b1SMichal Meloun for (node = OF_child(node); node != 0; node = OF_peer(node)) { 10737bc28467SAndrew Turner if (!ofw_bus_node_status_okay(node)) 107459b591b1SMichal Meloun continue; 107559b591b1SMichal Meloun rv = process_pad(sc, node); 107659b591b1SMichal Meloun if (rv != 0) 107759b591b1SMichal Meloun return (rv); 107859b591b1SMichal Meloun } 107959b591b1SMichal Meloun 108059b591b1SMichal Meloun node = ofw_bus_find_child(base_node, "ports"); 108159b591b1SMichal Meloun if (node <= 0) { 108259b591b1SMichal Meloun device_printf(sc->dev, "Cannot find ports subnode.\n"); 108359b591b1SMichal Meloun return (ENXIO); 108459b591b1SMichal Meloun } 108559b591b1SMichal Meloun for (node = OF_child(node); node != 0; node = OF_peer(node)) { 10867bc28467SAndrew Turner if (!ofw_bus_node_status_okay(node)) 108759b591b1SMichal Meloun continue; 108859b591b1SMichal Meloun rv = process_port(sc, node); 108959b591b1SMichal Meloun if (rv != 0) 109059b591b1SMichal Meloun return (rv); 109159b591b1SMichal Meloun } 109259b591b1SMichal Meloun 109359b591b1SMichal Meloun return (0); 109459b591b1SMichal Meloun } 109559b591b1SMichal Meloun 109659b591b1SMichal Meloun static void 109759b591b1SMichal Meloun load_calibration(struct padctl_softc *sc) 109859b591b1SMichal Meloun { 109959b591b1SMichal Meloun uint32_t reg; 110059b591b1SMichal Meloun 110159b591b1SMichal Meloun /* All XUSB pad calibrations are packed into single dword.*/ 110259b591b1SMichal Meloun reg = tegra_fuse_read_4(FUSE_XUSB_CALIB); 110359b591b1SMichal Meloun sc->hs_curr_level_0 = FUSE_XUSB_CALIB_HS_CURR_LEVEL_0(reg); 110459b591b1SMichal Meloun sc->hs_curr_level_123 = FUSE_XUSB_CALIB_HS_CURR_LEVEL_123(reg); 110559b591b1SMichal Meloun sc->hs_iref_cap = FUSE_XUSB_CALIB_HS_IREF_CAP(reg); 110659b591b1SMichal Meloun sc->hs_squelch_level = FUSE_XUSB_CALIB_HS_SQUELCH_LEVEL(reg); 110759b591b1SMichal Meloun sc->hs_term_range_adj = FUSE_XUSB_CALIB_HS_TERM_RANGE_ADJ(reg); 110859b591b1SMichal Meloun } 110959b591b1SMichal Meloun 111059b591b1SMichal Meloun /* ------------------------------------------------------------------------- 111159b591b1SMichal Meloun * 111259b591b1SMichal Meloun * BUS functions 111359b591b1SMichal Meloun */ 111459b591b1SMichal Meloun static int 1115ef2ee5d0SMichal Meloun xusbpadctl_probe(device_t dev) 1116ef2ee5d0SMichal Meloun { 1117ef2ee5d0SMichal Meloun 1118ef2ee5d0SMichal Meloun if (!ofw_bus_status_okay(dev)) 1119ef2ee5d0SMichal Meloun return (ENXIO); 1120ef2ee5d0SMichal Meloun 1121ef2ee5d0SMichal Meloun if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 1122ef2ee5d0SMichal Meloun return (ENXIO); 1123ef2ee5d0SMichal Meloun 1124ef2ee5d0SMichal Meloun device_set_desc(dev, "Tegra XUSB phy"); 1125ef2ee5d0SMichal Meloun return (BUS_PROBE_DEFAULT); 1126ef2ee5d0SMichal Meloun } 1127ef2ee5d0SMichal Meloun 1128ef2ee5d0SMichal Meloun static int 1129ef2ee5d0SMichal Meloun xusbpadctl_detach(device_t dev) 1130ef2ee5d0SMichal Meloun { 1131ef2ee5d0SMichal Meloun 1132ef2ee5d0SMichal Meloun /* This device is always present. */ 1133ef2ee5d0SMichal Meloun return (EBUSY); 1134ef2ee5d0SMichal Meloun } 1135ef2ee5d0SMichal Meloun 1136ef2ee5d0SMichal Meloun static int 1137ef2ee5d0SMichal Meloun xusbpadctl_attach(device_t dev) 1138ef2ee5d0SMichal Meloun { 113959b591b1SMichal Meloun struct padctl_softc * sc; 114059b591b1SMichal Meloun int i, rid, rv; 114159b591b1SMichal Meloun struct padctl_port *port; 1142ef2ee5d0SMichal Meloun phandle_t node; 1143ef2ee5d0SMichal Meloun 1144ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 1145ef2ee5d0SMichal Meloun sc->dev = dev; 114659b591b1SMichal Meloun node = ofw_bus_get_node(dev); 1147ef2ee5d0SMichal Meloun 1148ef2ee5d0SMichal Meloun rid = 0; 1149ef2ee5d0SMichal Meloun sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 1150ef2ee5d0SMichal Meloun RF_ACTIVE); 1151ef2ee5d0SMichal Meloun if (sc->mem_res == NULL) { 1152ef2ee5d0SMichal Meloun device_printf(dev, "Cannot allocate memory resources\n"); 1153ef2ee5d0SMichal Meloun return (ENXIO); 1154ef2ee5d0SMichal Meloun } 1155ef2ee5d0SMichal Meloun 1156dac93553SMichal Meloun rv = hwreset_get_by_ofw_name(dev, 0, "padctl", &sc->rst); 1157ef2ee5d0SMichal Meloun if (rv != 0) { 1158ef2ee5d0SMichal Meloun device_printf(dev, "Cannot get 'padctl' reset: %d\n", rv); 1159ef2ee5d0SMichal Meloun return (rv); 1160ef2ee5d0SMichal Meloun } 1161ef2ee5d0SMichal Meloun rv = hwreset_deassert(sc->rst); 1162ef2ee5d0SMichal Meloun if (rv != 0) { 1163ef2ee5d0SMichal Meloun device_printf(dev, "Cannot unreset 'padctl' reset: %d\n", rv); 1164ef2ee5d0SMichal Meloun return (rv); 1165ef2ee5d0SMichal Meloun } 1166ef2ee5d0SMichal Meloun 116759b591b1SMichal Meloun load_calibration(sc); 1168ef2ee5d0SMichal Meloun 116959b591b1SMichal Meloun rv = parse_fdt(sc, node); 117059b591b1SMichal Meloun if (rv != 0) { 117159b591b1SMichal Meloun device_printf(dev, "Cannot parse fdt configuration: %d\n", rv); 117259b591b1SMichal Meloun return (rv); 117359b591b1SMichal Meloun } 117459b591b1SMichal Meloun for (i = 0; i < nitems(ports_tbl); i++) { 117559b591b1SMichal Meloun port = ports_tbl + i; 117659b591b1SMichal Meloun if (!port->enabled) 117759b591b1SMichal Meloun continue; 117859b591b1SMichal Meloun if (port->init == NULL) 117959b591b1SMichal Meloun continue; 118059b591b1SMichal Meloun rv = port->init(sc, port); 118159b591b1SMichal Meloun if (rv != 0) { 118259b591b1SMichal Meloun device_printf(dev, "Cannot init port '%s'\n", 118359b591b1SMichal Meloun port->name); 118459b591b1SMichal Meloun return (rv); 118559b591b1SMichal Meloun } 118659b591b1SMichal Meloun } 1187ef2ee5d0SMichal Meloun return (0); 1188ef2ee5d0SMichal Meloun } 1189ef2ee5d0SMichal Meloun 1190ef2ee5d0SMichal Meloun static device_method_t tegra_xusbpadctl_methods[] = { 1191ef2ee5d0SMichal Meloun /* Device interface */ 1192ef2ee5d0SMichal Meloun DEVMETHOD(device_probe, xusbpadctl_probe), 1193ef2ee5d0SMichal Meloun DEVMETHOD(device_attach, xusbpadctl_attach), 1194ef2ee5d0SMichal Meloun DEVMETHOD(device_detach, xusbpadctl_detach), 1195ef2ee5d0SMichal Meloun 1196ef2ee5d0SMichal Meloun DEVMETHOD_END 1197ef2ee5d0SMichal Meloun }; 1198ef2ee5d0SMichal Meloun 11994bda238aSMichal Meloun static DEFINE_CLASS_0(xusbpadctl, tegra_xusbpadctl_driver, 120059b591b1SMichal Meloun tegra_xusbpadctl_methods, sizeof(struct padctl_softc)); 1201ef2ee5d0SMichal Meloun EARLY_DRIVER_MODULE(tegra_xusbpadctl, simplebus, tegra_xusbpadctl_driver, 1202289f133bSJohn Baldwin NULL, NULL, 73); 1203