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 27f8759facSMichal Meloun #include <sys/cdefs.h> 28f8759facSMichal Meloun __FBSDID("$FreeBSD$"); 29f8759facSMichal Meloun 30ef2ee5d0SMichal Meloun #include <sys/param.h> 31ef2ee5d0SMichal Meloun #include <sys/systm.h> 32ef2ee5d0SMichal Meloun #include <sys/bus.h> 33ef2ee5d0SMichal Meloun #include <sys/kernel.h> 34ef2ee5d0SMichal Meloun #include <sys/module.h> 35ef2ee5d0SMichal Meloun #include <sys/malloc.h> 36ef2ee5d0SMichal Meloun #include <sys/rman.h> 37ef2ee5d0SMichal Meloun 38ef2ee5d0SMichal Meloun #include <machine/bus.h> 39ef2ee5d0SMichal Meloun #include <machine/fdt.h> 40ef2ee5d0SMichal Meloun 41ef2ee5d0SMichal Meloun #include <dev/extres/hwreset/hwreset.h> 42ef2ee5d0SMichal Meloun #include <dev/extres/phy/phy.h> 4359b591b1SMichal Meloun #include <dev/extres/regulator/regulator.h> 44ef2ee5d0SMichal Meloun #include <dev/fdt/fdt_common.h> 45ef2ee5d0SMichal Meloun #include <dev/fdt/fdt_pinctrl.h> 46ef2ee5d0SMichal Meloun #include <dev/ofw/openfirm.h> 47ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus.h> 48ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus_subr.h> 49ef2ee5d0SMichal Meloun 5059b591b1SMichal Meloun #include <arm/nvidia/tegra_efuse.h> 5159b591b1SMichal Meloun 528a7a4683SEmmanuel Vadot #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> 53ef2ee5d0SMichal Meloun 54f8759facSMichal Meloun #include "phydev_if.h" 55ef2ee5d0SMichal Meloun 5659b591b1SMichal Meloun /* FUSE calibration data. */ 5759b591b1SMichal Meloun #define FUSE_XUSB_CALIB 0x0F0 5859b591b1SMichal Meloun #define FUSE_XUSB_CALIB_HS_CURR_LEVEL_123(x) (((x) >> 15) & 0x3F); 5959b591b1SMichal Meloun #define FUSE_XUSB_CALIB_HS_IREF_CAP(x) (((x) >> 13) & 0x03); 6059b591b1SMichal Meloun #define FUSE_XUSB_CALIB_HS_SQUELCH_LEVEL(x) (((x) >> 11) & 0x03); 6159b591b1SMichal Meloun #define FUSE_XUSB_CALIB_HS_TERM_RANGE_ADJ(x) (((x) >> 7) & 0x0F); 6259b591b1SMichal Meloun #define FUSE_XUSB_CALIB_HS_CURR_LEVEL_0(x) (((x) >> 0) & 0x3F); 6359b591b1SMichal Meloun 6459b591b1SMichal Meloun /* Registers. */ 65ef2ee5d0SMichal Meloun #define XUSB_PADCTL_USB2_PAD_MUX 0x004 66ef2ee5d0SMichal Meloun 6759b591b1SMichal Meloun #define XUSB_PADCTL_USB2_PORT_CAP 0x008 6859b591b1SMichal Meloun #define USB2_PORT_CAP_ULPI_PORT_INTERNAL (1 << 25) 6959b591b1SMichal Meloun #define USB2_PORT_CAP_ULPI_PORT_CAP (1 << 24) 7059b591b1SMichal Meloun #define USB2_PORT_CAP_PORT_REVERSE_ID(p) (1 << (3 + (p) * 4)) 7159b591b1SMichal Meloun #define USB2_PORT_CAP_PORT_INTERNAL(p) (1 << (2 + (p) * 4)) 7259b591b1SMichal Meloun #define USB2_PORT_CAP_PORT_CAP(p, x) (((x) & 3) << ((p) * 4)) 7359b591b1SMichal Meloun #define USB2_PORT_CAP_PORT_CAP_OTG 0x3 7459b591b1SMichal Meloun #define USB2_PORT_CAP_PORT_CAP_DEVICE 0x2 7559b591b1SMichal Meloun #define USB2_PORT_CAP_PORT_CAP_HOST 0x1 7659b591b1SMichal Meloun #define USB2_PORT_CAP_PORT_CAP_DISABLED 0x0 7759b591b1SMichal Meloun 7859b591b1SMichal Meloun #define XUSB_PADCTL_SS_PORT_MAP 0x014 7959b591b1SMichal Meloun #define SS_PORT_MAP_PORT_INTERNAL(p) (1 << (3 + (p) * 4)) 8059b591b1SMichal Meloun #define SS_PORT_MAP_PORT_MAP(p, x) (((x) & 7) << ((p) * 4)) 8159b591b1SMichal Meloun 82ef2ee5d0SMichal Meloun #define XUSB_PADCTL_ELPG_PROGRAM 0x01C 83ef2ee5d0SMichal Meloun #define ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26) 84ef2ee5d0SMichal Meloun #define ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25) 85ef2ee5d0SMichal Meloun #define ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24) 8659b591b1SMichal Meloun #define ELPG_PROGRAM_SSP_ELPG_VCORE_DOWN(x) (1 << (18 + (x) * 4)) 8759b591b1SMichal Meloun #define ELPG_PROGRAM_SSP_ELPG_CLAMP_EN_EARLY(x) (1 << (17 + (x) * 4)) 8859b591b1SMichal Meloun #define ELPG_PROGRAM_SSP_ELPG_CLAMP_EN(x) (1 << (16 + (x) * 4)) 89ef2ee5d0SMichal Meloun 90ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040 91ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19) 9259b591b1SMichal Meloun #define IOPHY_PLL_P0_CTL1_REFCLK_SEL(x) (((x) & 0xF) << 12) 93ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1) 94ef2ee5d0SMichal Meloun 95ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044 96ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6) 97ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5) 98ef2ee5d0SMichal Meloun #define IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4) 99ef2ee5d0SMichal Meloun 10059b591b1SMichal Meloun #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2(x) (0x058 + (x) * 4) 10159b591b1SMichal Meloun #define IOPHY_USB3_PAD_CTL2_CDR_CNTL(x) (((x) & 0x00FF) << 4) 10259b591b1SMichal Meloun #define IOPHY_USB3_PAD_CTL2_RX_EQ(x) (((x) & 0xFFFF) << 8) 10359b591b1SMichal Meloun #define IOPHY_USB3_PAD_CTL2_RX_WANDER(x) (((x) & 0x000F) << 4) 10459b591b1SMichal Meloun #define IOPHY_USB3_PAD_CTL2_RX_TERM_CNTL(x) (((x) & 0x0003) << 2) 10559b591b1SMichal Meloun #define IOPHY_USB3_PAD_CTL2_TX_TERM_CNTL(x) (((x) & 0x0003) << 0) 10659b591b1SMichal Meloun 10759b591b1SMichal Meloun #define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4(x) (0x068 + (x) * 4) 10859b591b1SMichal Meloun 10959b591b1SMichal Meloun #define XUSB_PADCTL_USB2_OTG_PAD_CTL0(x) (0x0A0 + (x) * 4) 11059b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_LSBIAS_SEL (1 << 23) 11159b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_DISCON_DETECT_METHOD (1 << 22) 11259b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_PD_ZI (1 << 21) 11359b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_PD2 (1 << 20) 11459b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_PD (1 << 19) 11559b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_TERM_EN (1 << 18) 11659b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_LS_LS_FSLEW(x) (((x) & 0x03) << 16) 11759b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_LS_RSLEW(x) (((x) & 0x03) << 14) 11859b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_FS_SLEW(x) (((x) & 0x03) << 12) 11959b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_HS_SLEW(x) (((x) & 0x3F) << 6) 12059b591b1SMichal Meloun #define USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(x) (((x) & 0x3F) << 0) 12159b591b1SMichal Meloun 12259b591b1SMichal Meloun #define XUSB_PADCTL_USB2_OTG_PAD_CTL1(x) (0x0AC + (x) * 4) 12359b591b1SMichal Meloun #define USB2_OTG_PAD_CTL1_RPU_RANGE_ADJ(x) (((x) & 0x3) << 11) 12459b591b1SMichal Meloun #define USB2_OTG_PAD_CTL1_HS_IREF_CAP(x) (((x) & 0x3) << 9) 12559b591b1SMichal Meloun #define USB2_OTG_PAD_CTL1_SPARE(x) (((x) & 0x3) << 7) 12659b591b1SMichal Meloun #define USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ(x) (((x) & 0xF) << 3) 12759b591b1SMichal Meloun #define USB2_OTG_PAD_CTL1_PD_DR (1 << 2) 12859b591b1SMichal Meloun #define USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP (1 << 1) 12959b591b1SMichal Meloun #define USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP (1 << 0) 13059b591b1SMichal Meloun 13159b591b1SMichal Meloun #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x0B8 13259b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_ADJRPU(x) (((x) & 0x7) << 14) 13359b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_PD_TRK (1 << 13) 13459b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_PD (1 << 12) 13559b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_TERM_OFFSETL(x) (((x) & 0x3) << 9) 13659b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_VBUS_LEVEL(x) (((x) & 0x3) << 7) 13759b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_HS_CHIRP_LEVEL(x) (((x) & 0x3) << 5) 13859b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL(x) (((x) & 0x7) << 2) 13959b591b1SMichal Meloun #define USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL(x) (((x) & 0x3) << 0) 14059b591b1SMichal Meloun 14159b591b1SMichal Meloun #define XUSB_PADCTL_HSIC_PAD0_CTL0 0x0C8 14259b591b1SMichal Meloun #define HSIC_PAD0_CTL0_HSIC_OPT(x) (((x) & 0xF) << 16) 14359b591b1SMichal Meloun #define HSIC_PAD0_CTL0_TX_SLEWN(x) (((x) & 0xF) << 12) 14459b591b1SMichal Meloun #define HSIC_PAD0_CTL0_TX_SLEWP(x) (((x) & 0xF) << 8) 14559b591b1SMichal Meloun #define HSIC_PAD0_CTL0_TX_RTUNEN(x) (((x) & 0xF) << 4) 14659b591b1SMichal Meloun #define HSIC_PAD0_CTL0_TX_RTUNEP(x) (((x) & 0xF) << 0) 147ef2ee5d0SMichal Meloun 148ef2ee5d0SMichal Meloun #define XUSB_PADCTL_USB3_PAD_MUX 0x134 14959b591b1SMichal Meloun #define USB3_PAD_MUX_PCIE_IDDQ_DISABLE(x) (1 << (1 + (x))) 15059b591b1SMichal Meloun #define USB3_PAD_MUX_SATA_IDDQ_DISABLE (1 << 6) 15159b591b1SMichal Meloun 152ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138 153ef2ee5d0SMichal Meloun #define IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27) 154ef2ee5d0SMichal Meloun #define IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24) 155ef2ee5d0SMichal Meloun #define IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3) 156ef2ee5d0SMichal Meloun #define IOPHY_PLL_S0_CTL1_PLL_RST_L (1 << 1) 157ef2ee5d0SMichal Meloun #define IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0) 158ef2ee5d0SMichal Meloun 159ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_S0_CTL2 0x13C 160ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_S0_CTL3 0x140 161ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_PLL_S0_CTL4 0x144 162ef2ee5d0SMichal Meloun 163ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148 164ef2ee5d0SMichal Meloun #define IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1) 165ef2ee5d0SMichal Meloun #define IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0) 166ef2ee5d0SMichal Meloun 167ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 0x14C 168ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL3 0x150 169ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL4 0x154 170ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 0x158 171ef2ee5d0SMichal Meloun #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 0x15C 172ef2ee5d0SMichal Meloun 17359b591b1SMichal Meloun #define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v)) 17459b591b1SMichal Meloun #define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r)) 17559b591b1SMichal Meloun 17659b591b1SMichal Meloun struct padctl_softc { 177ef2ee5d0SMichal Meloun device_t dev; 178ef2ee5d0SMichal Meloun struct resource *mem_res; 179ef2ee5d0SMichal Meloun hwreset_t rst; 180ef2ee5d0SMichal Meloun int phy_ena_cnt; 18159b591b1SMichal Meloun 18259b591b1SMichal Meloun /* Fuses calibration data */ 18359b591b1SMichal Meloun uint32_t hs_curr_level_0; 18459b591b1SMichal Meloun uint32_t hs_curr_level_123; 18559b591b1SMichal Meloun uint32_t hs_iref_cap; 18659b591b1SMichal Meloun uint32_t hs_term_range_adj; 18759b591b1SMichal Meloun uint32_t hs_squelch_level; 18859b591b1SMichal Meloun 18959b591b1SMichal Meloun uint32_t hs_curr_level_offset; 190ef2ee5d0SMichal Meloun }; 191ef2ee5d0SMichal Meloun 192ef2ee5d0SMichal Meloun static struct ofw_compat_data compat_data[] = { 193ef2ee5d0SMichal Meloun {"nvidia,tegra124-xusb-padctl", 1}, 194ef2ee5d0SMichal Meloun {NULL, 0}, 195ef2ee5d0SMichal Meloun }; 196ef2ee5d0SMichal Meloun 19759b591b1SMichal Meloun /* Ports. */ 19859b591b1SMichal Meloun enum padctl_port_type { 19959b591b1SMichal Meloun PADCTL_PORT_USB2, 20059b591b1SMichal Meloun PADCTL_PORT_ULPI, 20159b591b1SMichal Meloun PADCTL_PORT_HSIC, 20259b591b1SMichal Meloun PADCTL_PORT_USB3, 20359b591b1SMichal Meloun }; 20459b591b1SMichal Meloun 20559b591b1SMichal Meloun struct padctl_lane; 20659b591b1SMichal Meloun struct padctl_port { 20759b591b1SMichal Meloun enum padctl_port_type type; 20859b591b1SMichal Meloun const char *name; 20959b591b1SMichal Meloun const char *base_name; 21059b591b1SMichal Meloun int idx; 21159b591b1SMichal Meloun int (*init)(struct padctl_softc *sc, 21259b591b1SMichal Meloun struct padctl_port *port); 21359b591b1SMichal Meloun 21459b591b1SMichal Meloun /* Runtime data. */ 21559b591b1SMichal Meloun bool enabled; 21659b591b1SMichal Meloun regulator_t supply_vbus; /* USB2, USB3 */ 21759b591b1SMichal Meloun bool internal; /* ULPI, USB2, USB3 */ 21859b591b1SMichal Meloun uint32_t companion; /* USB3 */ 21959b591b1SMichal Meloun struct padctl_lane *lane; 22059b591b1SMichal Meloun }; 22159b591b1SMichal Meloun 22259b591b1SMichal Meloun static int usb3_port_init(struct padctl_softc *sc, struct padctl_port *port); 22359b591b1SMichal Meloun 22459b591b1SMichal Meloun #define PORT(t, n, p, i) { \ 22559b591b1SMichal Meloun .type = t, \ 22659b591b1SMichal Meloun .name = n "-" #p, \ 22759b591b1SMichal Meloun .base_name = n, \ 22859b591b1SMichal Meloun .idx = p, \ 22959b591b1SMichal Meloun .init = i, \ 23059b591b1SMichal Meloun } 23159b591b1SMichal Meloun static struct padctl_port ports_tbl[] = { 23259b591b1SMichal Meloun PORT(PADCTL_PORT_USB2, "usb2", 0, NULL), 23359b591b1SMichal Meloun PORT(PADCTL_PORT_USB2, "usb2", 1, NULL), 23459b591b1SMichal Meloun PORT(PADCTL_PORT_USB2, "usb2", 2, NULL), 23559b591b1SMichal Meloun PORT(PADCTL_PORT_ULPI, "ulpi", 0, NULL), 23659b591b1SMichal Meloun PORT(PADCTL_PORT_HSIC, "hsic", 0, NULL), 23759b591b1SMichal Meloun PORT(PADCTL_PORT_HSIC, "hsic", 1, NULL), 23859b591b1SMichal Meloun PORT(PADCTL_PORT_USB3, "usb3", 0, usb3_port_init), 23959b591b1SMichal Meloun PORT(PADCTL_PORT_USB3, "usb3", 1, usb3_port_init), 24059b591b1SMichal Meloun }; 24159b591b1SMichal Meloun 24259b591b1SMichal Meloun /* Pads - a group of lannes. */ 24359b591b1SMichal Meloun enum padctl_pad_type { 24459b591b1SMichal Meloun PADCTL_PAD_USB2, 24559b591b1SMichal Meloun PADCTL_PAD_ULPI, 24659b591b1SMichal Meloun PADCTL_PAD_HSIC, 24759b591b1SMichal Meloun PADCTL_PAD_PCIE, 24859b591b1SMichal Meloun PADCTL_PAD_SATA, 24959b591b1SMichal Meloun }; 25059b591b1SMichal Meloun 25159b591b1SMichal Meloun struct padctl_lane; 25259b591b1SMichal Meloun struct padctl_pad { 25359b591b1SMichal Meloun const char *name; 25459b591b1SMichal Meloun enum padctl_pad_type type; 25559b591b1SMichal Meloun int (*powerup)(struct padctl_softc *sc, 25659b591b1SMichal Meloun struct padctl_lane *lane); 25759b591b1SMichal Meloun int (*powerdown)(struct padctl_softc *sc, 25859b591b1SMichal Meloun struct padctl_lane *lane); 25959b591b1SMichal Meloun /* Runtime data. */ 26059b591b1SMichal Meloun bool enabled; 26159b591b1SMichal Meloun struct padctl_lane *lanes[8]; /* Safe maximum value. */ 26259b591b1SMichal Meloun int nlanes; 26359b591b1SMichal Meloun }; 26459b591b1SMichal Meloun 26559b591b1SMichal Meloun static int usb2_powerup(struct padctl_softc *sc, struct padctl_lane *lane); 26659b591b1SMichal Meloun static int usb2_powerdown(struct padctl_softc *sc, struct padctl_lane *lane); 26759b591b1SMichal Meloun static int pcie_powerup(struct padctl_softc *sc, struct padctl_lane *lane); 26859b591b1SMichal Meloun static int pcie_powerdown(struct padctl_softc *sc, struct padctl_lane *lane); 26959b591b1SMichal Meloun static int sata_powerup(struct padctl_softc *sc, struct padctl_lane *lane); 27059b591b1SMichal Meloun static int sata_powerdown(struct padctl_softc *sc, struct padctl_lane *lane); 27159b591b1SMichal Meloun 27259b591b1SMichal Meloun #define PAD(n, t, u, d) { \ 27359b591b1SMichal Meloun .name = n, \ 27459b591b1SMichal Meloun .type = t, \ 27559b591b1SMichal Meloun .powerup = u, \ 27659b591b1SMichal Meloun .powerdown = d, \ 27759b591b1SMichal Meloun } 27859b591b1SMichal Meloun static struct padctl_pad pads_tbl[] = { 27959b591b1SMichal Meloun PAD("usb2", PADCTL_PAD_USB2, usb2_powerup, usb2_powerdown), 28059b591b1SMichal Meloun PAD("ulpi", PADCTL_PAD_ULPI, NULL, NULL), 28159b591b1SMichal Meloun PAD("hsic", PADCTL_PAD_HSIC, NULL, NULL), 28259b591b1SMichal Meloun PAD("pcie", PADCTL_PAD_PCIE, pcie_powerup, pcie_powerdown), 28359b591b1SMichal Meloun PAD("sata", PADCTL_PAD_SATA, sata_powerup, sata_powerdown), 28459b591b1SMichal Meloun }; 28559b591b1SMichal Meloun 28659b591b1SMichal Meloun /* Lanes. */ 28759b591b1SMichal Meloun static char *otg_mux[] = {"snps", "xusb", "uart", "rsvd"}; 28859b591b1SMichal Meloun static char *usb_mux[] = {"snps", "xusb"}; 28959b591b1SMichal Meloun static char *pci_mux[] = {"pcie", "usb3-ss", "sata", "rsvd"}; 29059b591b1SMichal Meloun 291ef2ee5d0SMichal Meloun struct padctl_lane { 292ef2ee5d0SMichal Meloun const char *name; 29359b591b1SMichal Meloun int idx; 294ef2ee5d0SMichal Meloun bus_size_t reg; 295ef2ee5d0SMichal Meloun uint32_t shift; 296ef2ee5d0SMichal Meloun uint32_t mask; 297ef2ee5d0SMichal Meloun char **mux; 298ef2ee5d0SMichal Meloun int nmux; 29959b591b1SMichal Meloun /* Runtime data. */ 30059b591b1SMichal Meloun bool enabled; 30159b591b1SMichal Meloun struct padctl_pad *pad; 30259b591b1SMichal Meloun struct padctl_port *port; 30359b591b1SMichal Meloun int mux_idx; 30459b591b1SMichal Meloun 305ef2ee5d0SMichal Meloun }; 306ef2ee5d0SMichal Meloun 30759b591b1SMichal Meloun #define LANE(n, p, r, s, m, mx) { \ 30859b591b1SMichal Meloun .name = n "-" #p, \ 30959b591b1SMichal Meloun .idx = p, \ 310ef2ee5d0SMichal Meloun .reg = r, \ 311ef2ee5d0SMichal Meloun .shift = s, \ 312ef2ee5d0SMichal Meloun .mask = m, \ 313ef2ee5d0SMichal Meloun .mux = mx, \ 314ef2ee5d0SMichal Meloun .nmux = nitems(mx), \ 315ef2ee5d0SMichal Meloun } 31659b591b1SMichal Meloun static struct padctl_lane lanes_tbl[] = { 31759b591b1SMichal Meloun LANE("usb2", 0, XUSB_PADCTL_USB2_PAD_MUX, 0, 0x3, otg_mux), 31859b591b1SMichal Meloun LANE("usb2", 1, XUSB_PADCTL_USB2_PAD_MUX, 2, 0x3, otg_mux), 31959b591b1SMichal Meloun LANE("usb2", 2, XUSB_PADCTL_USB2_PAD_MUX, 4, 0x3, otg_mux), 32059b591b1SMichal Meloun LANE("ulpi", 0, XUSB_PADCTL_USB2_PAD_MUX, 12, 0x1, usb_mux), 32159b591b1SMichal Meloun LANE("hsic", 0, XUSB_PADCTL_USB2_PAD_MUX, 14, 0x1, usb_mux), 32259b591b1SMichal Meloun LANE("hsic", 1, XUSB_PADCTL_USB2_PAD_MUX, 15, 0x1, usb_mux), 32359b591b1SMichal Meloun LANE("pcie", 0, XUSB_PADCTL_USB3_PAD_MUX, 16, 0x3, pci_mux), 32459b591b1SMichal Meloun LANE("pcie", 1, XUSB_PADCTL_USB3_PAD_MUX, 18, 0x3, pci_mux), 32559b591b1SMichal Meloun LANE("pcie", 2, XUSB_PADCTL_USB3_PAD_MUX, 20, 0x3, pci_mux), 32659b591b1SMichal Meloun LANE("pcie", 3, XUSB_PADCTL_USB3_PAD_MUX, 22, 0x3, pci_mux), 32759b591b1SMichal Meloun LANE("pcie", 4, XUSB_PADCTL_USB3_PAD_MUX, 24, 0x3, pci_mux), 32859b591b1SMichal Meloun LANE("sata", 0, XUSB_PADCTL_USB3_PAD_MUX, 26, 0x3, pci_mux), 329ef2ee5d0SMichal Meloun }; 330ef2ee5d0SMichal Meloun 33159b591b1SMichal Meloun /* Define all possible mappings for USB3 port lanes */ 33259b591b1SMichal Meloun struct padctl_lane_map { 33359b591b1SMichal Meloun int port_idx; 33459b591b1SMichal Meloun enum padctl_pad_type pad_type; 33559b591b1SMichal Meloun int lane_idx; 33659b591b1SMichal Meloun }; 337ef2ee5d0SMichal Meloun 33859b591b1SMichal Meloun #define LANE_MAP(pi, pt, li) { \ 33959b591b1SMichal Meloun .port_idx = pi, \ 34059b591b1SMichal Meloun .pad_type = pt, \ 34159b591b1SMichal Meloun .lane_idx = li, \ 342ef2ee5d0SMichal Meloun } 34359b591b1SMichal Meloun static struct padctl_lane_map lane_map_tbl[] = { 34459b591b1SMichal Meloun LANE_MAP(0, PADCTL_PAD_PCIE, 0), /* port USB3-0 -> lane PCIE-0 */ 34559b591b1SMichal Meloun LANE_MAP(1, PADCTL_PAD_PCIE, 1), /* port USB3-1 -> lane PCIE-1 */ 34659b591b1SMichal Meloun /* -- or -- */ 34759b591b1SMichal Meloun LANE_MAP(1, PADCTL_PAD_SATA, 0), /* port USB3-1 -> lane SATA-0 */ 34859b591b1SMichal Meloun }; 349ef2ee5d0SMichal Meloun 350f8759facSMichal Meloun /* Phy class and methods. */ 351f8759facSMichal Meloun static int xusbpadctl_phy_enable(struct phynode *phy, bool enable); 352f8759facSMichal Meloun static phynode_method_t xusbpadctl_phynode_methods[] = { 353f8759facSMichal Meloun PHYNODEMETHOD(phynode_enable, xusbpadctl_phy_enable), 354f8759facSMichal Meloun PHYNODEMETHOD_END 355f8759facSMichal Meloun 356f8759facSMichal Meloun }; 357f8759facSMichal Meloun DEFINE_CLASS_1(xusbpadctl_phynode, xusbpadctl_phynode_class, 358f8759facSMichal Meloun xusbpadctl_phynode_methods, 0, phynode_class); 359f8759facSMichal Meloun 36059b591b1SMichal Meloun static struct padctl_port *search_lane_port(struct padctl_softc *sc, 36159b591b1SMichal Meloun struct padctl_lane *lane); 36259b591b1SMichal Meloun /* ------------------------------------------------------------------------- 36359b591b1SMichal Meloun * 36459b591b1SMichal Meloun * PHY functions 36559b591b1SMichal Meloun */ 366ef2ee5d0SMichal Meloun static int 36759b591b1SMichal Meloun usb3_port_init(struct padctl_softc *sc, struct padctl_port *port) 368ef2ee5d0SMichal Meloun { 369ef2ee5d0SMichal Meloun uint32_t reg; 370ef2ee5d0SMichal Meloun 37159b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_SS_PORT_MAP); 37259b591b1SMichal Meloun if (port->internal) 37359b591b1SMichal Meloun reg &= ~SS_PORT_MAP_PORT_INTERNAL(port->idx); 374ef2ee5d0SMichal Meloun else 37559b591b1SMichal Meloun reg |= SS_PORT_MAP_PORT_INTERNAL(port->idx); 37659b591b1SMichal Meloun reg &= ~SS_PORT_MAP_PORT_MAP(port->idx, ~0); 37759b591b1SMichal Meloun reg |= SS_PORT_MAP_PORT_MAP(port->idx, port->companion); 37859b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_SS_PORT_MAP, reg); 379ef2ee5d0SMichal Meloun 38059b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_USB3_PAD_CTL2(port->idx)); 38159b591b1SMichal Meloun reg &= ~IOPHY_USB3_PAD_CTL2_CDR_CNTL(~0); 38259b591b1SMichal Meloun reg &= ~IOPHY_USB3_PAD_CTL2_RX_EQ(~0); 38359b591b1SMichal Meloun reg &= ~IOPHY_USB3_PAD_CTL2_RX_WANDER(~0); 38459b591b1SMichal Meloun reg |= IOPHY_USB3_PAD_CTL2_CDR_CNTL(0x24); 38559b591b1SMichal Meloun reg |= IOPHY_USB3_PAD_CTL2_RX_EQ(0xF070); 38659b591b1SMichal Meloun reg |= IOPHY_USB3_PAD_CTL2_RX_WANDER(0xF); 38759b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_USB3_PAD_CTL2(port->idx), reg); 388ef2ee5d0SMichal Meloun 38959b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_USB3_PAD_CTL4(port->idx), 39059b591b1SMichal Meloun 0x002008EE); 391ef2ee5d0SMichal Meloun 39259b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 39359b591b1SMichal Meloun reg &= ~ELPG_PROGRAM_SSP_ELPG_VCORE_DOWN(port->idx); 39459b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 395ef2ee5d0SMichal Meloun DELAY(100); 396ef2ee5d0SMichal Meloun 39759b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 39859b591b1SMichal Meloun reg &= ~ELPG_PROGRAM_SSP_ELPG_CLAMP_EN_EARLY(port->idx); 39959b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 40059b591b1SMichal Meloun DELAY(100); 40159b591b1SMichal Meloun 40259b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 40359b591b1SMichal Meloun reg &= ~ELPG_PROGRAM_SSP_ELPG_CLAMP_EN(port->idx); 40459b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 40559b591b1SMichal Meloun DELAY(100); 40659b591b1SMichal Meloun 40759b591b1SMichal Meloun return (0); 40859b591b1SMichal Meloun } 40959b591b1SMichal Meloun 41059b591b1SMichal Meloun static int 41159b591b1SMichal Meloun pcie_powerup(struct padctl_softc *sc, struct padctl_lane *lane) 41259b591b1SMichal Meloun { 41359b591b1SMichal Meloun uint32_t reg; 41459b591b1SMichal Meloun int i; 41559b591b1SMichal Meloun 41659b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); 41759b591b1SMichal Meloun reg &= ~IOPHY_PLL_P0_CTL1_REFCLK_SEL(~0); 41859b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg); 41959b591b1SMichal Meloun DELAY(100); 42059b591b1SMichal Meloun 42159b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL2); 422ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_P0_CTL2_REFCLKBUF_EN; 423ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_P0_CTL2_TXCLKREF_EN; 424ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_P0_CTL2_TXCLKREF_SEL; 42559b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL2, reg); 426ef2ee5d0SMichal Meloun DELAY(100); 427ef2ee5d0SMichal Meloun 42859b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); 429ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_P0_CTL1_PLL_RST; 43059b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg); 431ef2ee5d0SMichal Meloun DELAY(100); 432ef2ee5d0SMichal Meloun 43359b591b1SMichal Meloun for (i = 100; i > 0; i--) { 43459b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); 435ef2ee5d0SMichal Meloun if (reg & IOPHY_PLL_P0_CTL1_PLL0_LOCKDET) 43659b591b1SMichal Meloun break; 437ef2ee5d0SMichal Meloun DELAY(10); 438ef2ee5d0SMichal Meloun } 43959b591b1SMichal Meloun if (i <= 0) { 44059b591b1SMichal Meloun device_printf(sc->dev, "Failed to power up PCIe phy\n"); 441ef2ee5d0SMichal Meloun return (ETIMEDOUT); 442ef2ee5d0SMichal Meloun } 44359b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); 44459b591b1SMichal Meloun reg |= USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->idx); 44559b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); 446ef2ee5d0SMichal Meloun 44759b591b1SMichal Meloun return (0); 44859b591b1SMichal Meloun } 449ef2ee5d0SMichal Meloun 450ef2ee5d0SMichal Meloun static int 45159b591b1SMichal Meloun pcie_powerdown(struct padctl_softc *sc, struct padctl_lane *lane) 452ef2ee5d0SMichal Meloun { 453ef2ee5d0SMichal Meloun uint32_t reg; 454ef2ee5d0SMichal Meloun 45559b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); 45659b591b1SMichal Meloun reg &= ~USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->idx); 45759b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); 45859b591b1SMichal Meloun 45959b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1); 460ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_P0_CTL1_PLL_RST; 46159b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg); 462ef2ee5d0SMichal Meloun DELAY(100); 46359b591b1SMichal Meloun 464ef2ee5d0SMichal Meloun return (0); 465ef2ee5d0SMichal Meloun 466ef2ee5d0SMichal Meloun } 467ef2ee5d0SMichal Meloun 468ef2ee5d0SMichal Meloun static int 46959b591b1SMichal Meloun sata_powerup(struct padctl_softc *sc, struct padctl_lane *lane) 470ef2ee5d0SMichal Meloun { 471ef2ee5d0SMichal Meloun uint32_t reg; 472ef2ee5d0SMichal Meloun int i; 473ef2ee5d0SMichal Meloun 47459b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); 475ef2ee5d0SMichal Meloun reg &= ~IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; 476ef2ee5d0SMichal Meloun reg &= ~IOPHY_MISC_PAD_S0_CTL1_IDDQ; 47759b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg); 478ef2ee5d0SMichal Meloun 47959b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 480ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; 481ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_S0_CTL1_PLL_IDDQ; 48259b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 483ef2ee5d0SMichal Meloun 48459b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 485ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_S0_CTL1_PLL1_MODE; 48659b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 487ef2ee5d0SMichal Meloun 48859b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 489ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_S0_CTL1_PLL_RST_L; 49059b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 491ef2ee5d0SMichal Meloun 492ef2ee5d0SMichal Meloun for (i = 100; i >= 0; i--) { 49359b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 494ef2ee5d0SMichal Meloun if (reg & IOPHY_PLL_S0_CTL1_PLL1_LOCKDET) 495ef2ee5d0SMichal Meloun break; 496ef2ee5d0SMichal Meloun DELAY(100); 497ef2ee5d0SMichal Meloun } 498ef2ee5d0SMichal Meloun if (i <= 0) { 499ef2ee5d0SMichal Meloun device_printf(sc->dev, "Failed to power up SATA phy\n"); 500ef2ee5d0SMichal Meloun return (ETIMEDOUT); 501ef2ee5d0SMichal Meloun } 50259b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); 50359b591b1SMichal Meloun reg |= IOPHY_PLL_S0_CTL1_PLL_RST_L; 50459b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); 50559b591b1SMichal Meloun 50659b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); 50759b591b1SMichal Meloun reg |= USB3_PAD_MUX_SATA_IDDQ_DISABLE; 50859b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); 509ef2ee5d0SMichal Meloun 510ef2ee5d0SMichal Meloun return (0); 511ef2ee5d0SMichal Meloun } 512ef2ee5d0SMichal Meloun 513ef2ee5d0SMichal Meloun static int 51459b591b1SMichal Meloun sata_powerdown(struct padctl_softc *sc, struct padctl_lane *lane) 515ef2ee5d0SMichal Meloun { 516ef2ee5d0SMichal Meloun uint32_t reg; 517ef2ee5d0SMichal Meloun 51859b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX); 51959b591b1SMichal Meloun reg &= ~USB3_PAD_MUX_SATA_IDDQ_DISABLE; 52059b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg); 52159b591b1SMichal Meloun 52259b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 523ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_S0_CTL1_PLL_RST_L; 52459b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 525ef2ee5d0SMichal Meloun DELAY(100); 526ef2ee5d0SMichal Meloun 52759b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 528ef2ee5d0SMichal Meloun reg &= ~IOPHY_PLL_S0_CTL1_PLL1_MODE; 52959b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 530ef2ee5d0SMichal Meloun DELAY(100); 531ef2ee5d0SMichal Meloun 53259b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1); 533ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD; 534ef2ee5d0SMichal Meloun reg |= IOPHY_PLL_S0_CTL1_PLL_IDDQ; 53559b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg); 536ef2ee5d0SMichal Meloun DELAY(100); 537ef2ee5d0SMichal Meloun 53859b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1); 539ef2ee5d0SMichal Meloun reg |= IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD; 540ef2ee5d0SMichal Meloun reg |= IOPHY_MISC_PAD_S0_CTL1_IDDQ; 54159b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg); 542ef2ee5d0SMichal Meloun DELAY(100); 543ef2ee5d0SMichal Meloun 544ef2ee5d0SMichal Meloun return (0); 545ef2ee5d0SMichal Meloun } 546ef2ee5d0SMichal Meloun 547ef2ee5d0SMichal Meloun static int 54859b591b1SMichal Meloun usb2_powerup(struct padctl_softc *sc, struct padctl_lane *lane) 54959b591b1SMichal Meloun { 55059b591b1SMichal Meloun uint32_t reg; 55159b591b1SMichal Meloun struct padctl_port *port; 55259b591b1SMichal Meloun int rv; 55359b591b1SMichal Meloun 55459b591b1SMichal Meloun port = search_lane_port(sc, lane); 55559b591b1SMichal Meloun if (port == NULL) { 55659b591b1SMichal Meloun device_printf(sc->dev, "Cannot find port for lane: %s\n", 55759b591b1SMichal Meloun lane->name); 55859b591b1SMichal Meloun } 55959b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 56059b591b1SMichal Meloun reg &= ~USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL(~0); 56159b591b1SMichal Meloun reg &= ~USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL(~0); 56259b591b1SMichal Meloun reg |= USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL(sc->hs_squelch_level); 56359b591b1SMichal Meloun reg |= USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL(5); 56459b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0, reg); 56559b591b1SMichal Meloun 56659b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB2_PORT_CAP); 56759b591b1SMichal Meloun reg &= ~USB2_PORT_CAP_PORT_CAP(lane->idx, ~0); 56859b591b1SMichal Meloun reg |= USB2_PORT_CAP_PORT_CAP(lane->idx, USB2_PORT_CAP_PORT_CAP_HOST); 56959b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB2_PORT_CAP, reg); 57059b591b1SMichal Meloun 57159b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL0(lane->idx)); 57259b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(~0); 57359b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL0_HS_SLEW(~0); 57459b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL0_LS_RSLEW(~0); 57559b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL0_PD; 57659b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL0_PD2; 57759b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL0_PD_ZI; 57859b591b1SMichal Meloun 57959b591b1SMichal Meloun reg |= USB2_OTG_PAD_CTL0_HS_SLEW(14); 58059b591b1SMichal Meloun if (lane->idx == 0) { 58159b591b1SMichal Meloun reg |= USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(sc->hs_curr_level_0); 58259b591b1SMichal Meloun reg |= USB2_OTG_PAD_CTL0_LS_RSLEW(3); 58359b591b1SMichal Meloun } else { 58459b591b1SMichal Meloun reg |= USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(sc->hs_curr_level_123); 58559b591b1SMichal Meloun reg |= USB2_OTG_PAD_CTL0_LS_RSLEW(0); 58659b591b1SMichal Meloun } 58759b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL0(lane->idx), reg); 58859b591b1SMichal Meloun 58959b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL1(lane->idx)); 59059b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ(~0); 59159b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL1_HS_IREF_CAP(~0); 59259b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL1_PD_DR; 59359b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP; 59459b591b1SMichal Meloun reg &= ~USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP; 59559b591b1SMichal Meloun 59659b591b1SMichal Meloun reg |= USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ(sc->hs_term_range_adj); 59759b591b1SMichal Meloun reg |= USB2_OTG_PAD_CTL1_HS_IREF_CAP(sc->hs_iref_cap); 59859b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL1(lane->idx), reg); 59959b591b1SMichal Meloun 60059b591b1SMichal Meloun if (port != NULL && port->supply_vbus != NULL) { 60159b591b1SMichal Meloun rv = regulator_enable(port->supply_vbus); 60259b591b1SMichal Meloun if (rv != 0) { 60359b591b1SMichal Meloun device_printf(sc->dev, 60459b591b1SMichal Meloun "Cannot enable vbus regulator\n"); 60559b591b1SMichal Meloun return (rv); 60659b591b1SMichal Meloun } 60759b591b1SMichal Meloun } 60859b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 60959b591b1SMichal Meloun reg &= ~USB2_BIAS_PAD_CTL0_PD; 61059b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0, reg); 61159b591b1SMichal Meloun 61259b591b1SMichal Meloun return (0); 61359b591b1SMichal Meloun } 61459b591b1SMichal Meloun 61559b591b1SMichal Meloun static int 61659b591b1SMichal Meloun usb2_powerdown(struct padctl_softc *sc, struct padctl_lane *lane) 61759b591b1SMichal Meloun { 61859b591b1SMichal Meloun uint32_t reg; 61959b591b1SMichal Meloun struct padctl_port *port; 62059b591b1SMichal Meloun int rv; 62159b591b1SMichal Meloun 62259b591b1SMichal Meloun port = search_lane_port(sc, lane); 62359b591b1SMichal Meloun if (port == NULL) { 62459b591b1SMichal Meloun device_printf(sc->dev, "Cannot find port for lane: %s\n", 62559b591b1SMichal Meloun lane->name); 62659b591b1SMichal Meloun } 62759b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); 62859b591b1SMichal Meloun reg |= USB2_BIAS_PAD_CTL0_PD; 62959b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0, reg); 63059b591b1SMichal Meloun 63159b591b1SMichal Meloun if (port != NULL && port->supply_vbus != NULL) { 63259b591b1SMichal Meloun rv = regulator_enable(port->supply_vbus); 63359b591b1SMichal Meloun if (rv != 0) { 63459b591b1SMichal Meloun device_printf(sc->dev, 63559b591b1SMichal Meloun "Cannot disable vbus regulator\n"); 63659b591b1SMichal Meloun return (rv); 63759b591b1SMichal Meloun } 63859b591b1SMichal Meloun } 63959b591b1SMichal Meloun return (0); 64059b591b1SMichal Meloun } 64159b591b1SMichal Meloun 64259b591b1SMichal Meloun static int 64359b591b1SMichal Meloun phy_powerup(struct padctl_softc *sc) 644ef2ee5d0SMichal Meloun { 645ef2ee5d0SMichal Meloun uint32_t reg; 646ef2ee5d0SMichal Meloun 64759b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 648ef2ee5d0SMichal Meloun reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; 64959b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 65059b591b1SMichal Meloun DELAY(100); 65159b591b1SMichal Meloun 65259b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 65359b591b1SMichal Meloun reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; 65459b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 65559b591b1SMichal Meloun DELAY(100); 65659b591b1SMichal Meloun 65759b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 65859b591b1SMichal Meloun reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; 65959b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 660ef2ee5d0SMichal Meloun DELAY(100); 661ef2ee5d0SMichal Meloun 662ef2ee5d0SMichal Meloun return (0); 663ef2ee5d0SMichal Meloun } 664ef2ee5d0SMichal Meloun 665ef2ee5d0SMichal Meloun static int 66659b591b1SMichal Meloun phy_powerdown(struct padctl_softc *sc) 667ef2ee5d0SMichal Meloun { 668ef2ee5d0SMichal Meloun uint32_t reg; 669ef2ee5d0SMichal Meloun 67059b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 671ef2ee5d0SMichal Meloun reg |= ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY; 67259b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 673ef2ee5d0SMichal Meloun DELAY(100); 674ef2ee5d0SMichal Meloun 67559b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 676ef2ee5d0SMichal Meloun reg |= ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN; 67759b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 67859b591b1SMichal Meloun DELAY(100); 67959b591b1SMichal Meloun 68059b591b1SMichal Meloun reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM); 68159b591b1SMichal Meloun reg |= ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN; 68259b591b1SMichal Meloun WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg); 683ef2ee5d0SMichal Meloun DELAY(100); 684ef2ee5d0SMichal Meloun 685ef2ee5d0SMichal Meloun return (0); 686ef2ee5d0SMichal Meloun } 687ef2ee5d0SMichal Meloun 688ef2ee5d0SMichal Meloun static int 689f8759facSMichal Meloun xusbpadctl_phy_enable(struct phynode *phy, bool enable) 690ef2ee5d0SMichal Meloun { 691f8759facSMichal Meloun device_t dev; 692f8759facSMichal Meloun intptr_t id; 69359b591b1SMichal Meloun struct padctl_softc *sc; 69459b591b1SMichal Meloun struct padctl_lane *lane; 69559b591b1SMichal Meloun struct padctl_pad *pad; 696ef2ee5d0SMichal Meloun int rv; 697ef2ee5d0SMichal Meloun 698f8759facSMichal Meloun dev = phynode_get_device(phy); 699f8759facSMichal Meloun id = phynode_get_id(phy); 700ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 701ef2ee5d0SMichal Meloun 70259b591b1SMichal Meloun if (id < 0 || id >= nitems(lanes_tbl)) { 703ef2ee5d0SMichal Meloun device_printf(dev, "Unknown phy: %d\n", id); 704ef2ee5d0SMichal Meloun return (ENXIO); 705ef2ee5d0SMichal Meloun } 70659b591b1SMichal Meloun lane = lanes_tbl + id; 70759b591b1SMichal Meloun if (!lane->enabled) { 70859b591b1SMichal Meloun device_printf(dev, "Lane is not enabled/configured: %s\n", 70959b591b1SMichal Meloun lane->name); 71059b591b1SMichal Meloun return (ENXIO); 71159b591b1SMichal Meloun } 71259b591b1SMichal Meloun pad = lane->pad; 713ef2ee5d0SMichal Meloun if (enable) { 714ef2ee5d0SMichal Meloun if (sc->phy_ena_cnt == 0) { 71559b591b1SMichal Meloun rv = phy_powerup(sc); 716ef2ee5d0SMichal Meloun if (rv != 0) 717ef2ee5d0SMichal Meloun return (rv); 718ef2ee5d0SMichal Meloun } 719ef2ee5d0SMichal Meloun sc->phy_ena_cnt++; 720ef2ee5d0SMichal Meloun } 721ef2ee5d0SMichal Meloun 722ef2ee5d0SMichal Meloun if (enable) 72359b591b1SMichal Meloun rv = pad->powerup(sc, lane); 724ef2ee5d0SMichal Meloun else 72559b591b1SMichal Meloun rv = pad->powerdown(sc, lane); 726ef2ee5d0SMichal Meloun if (rv != 0) 727ef2ee5d0SMichal Meloun return (rv); 72859b591b1SMichal Meloun 729ef2ee5d0SMichal Meloun if (!enable) { 730ef2ee5d0SMichal Meloun if (sc->phy_ena_cnt == 1) { 73159b591b1SMichal Meloun rv = phy_powerdown(sc); 732ef2ee5d0SMichal Meloun if (rv != 0) 733ef2ee5d0SMichal Meloun return (rv); 734ef2ee5d0SMichal Meloun } 735ef2ee5d0SMichal Meloun sc->phy_ena_cnt--; 736ef2ee5d0SMichal Meloun } 737ef2ee5d0SMichal Meloun 738ef2ee5d0SMichal Meloun return (0); 739ef2ee5d0SMichal Meloun } 740ef2ee5d0SMichal Meloun 74159b591b1SMichal Meloun /* ------------------------------------------------------------------------- 74259b591b1SMichal Meloun * 74359b591b1SMichal Meloun * FDT processing 74459b591b1SMichal Meloun */ 74559b591b1SMichal Meloun static struct padctl_port * 74659b591b1SMichal Meloun search_port(struct padctl_softc *sc, char *port_name) 74759b591b1SMichal Meloun { 74859b591b1SMichal Meloun int i; 74959b591b1SMichal Meloun 75059b591b1SMichal Meloun for (i = 0; i < nitems(ports_tbl); i++) { 75159b591b1SMichal Meloun if (strcmp(port_name, ports_tbl[i].name) == 0) 75259b591b1SMichal Meloun return (&ports_tbl[i]); 75359b591b1SMichal Meloun } 75459b591b1SMichal Meloun return (NULL); 75559b591b1SMichal Meloun } 75659b591b1SMichal Meloun 75759b591b1SMichal Meloun static struct padctl_port * 75859b591b1SMichal Meloun search_lane_port(struct padctl_softc *sc, struct padctl_lane *lane) 75959b591b1SMichal Meloun { 76059b591b1SMichal Meloun int i; 76159b591b1SMichal Meloun 76259b591b1SMichal Meloun for (i = 0; i < nitems(ports_tbl); i++) { 76359b591b1SMichal Meloun if (!ports_tbl[i].enabled) 76459b591b1SMichal Meloun continue; 76559b591b1SMichal Meloun if (ports_tbl[i].lane == lane) 76659b591b1SMichal Meloun return (ports_tbl + i); 76759b591b1SMichal Meloun } 76859b591b1SMichal Meloun return (NULL); 76959b591b1SMichal Meloun } 77059b591b1SMichal Meloun 77159b591b1SMichal Meloun static struct padctl_lane * 77259b591b1SMichal Meloun search_lane(struct padctl_softc *sc, char *lane_name) 77359b591b1SMichal Meloun { 77459b591b1SMichal Meloun int i; 77559b591b1SMichal Meloun 77659b591b1SMichal Meloun for (i = 0; i < nitems(lanes_tbl); i++) { 77759b591b1SMichal Meloun if (strcmp(lane_name, lanes_tbl[i].name) == 0) 77859b591b1SMichal Meloun return (lanes_tbl + i); 77959b591b1SMichal Meloun } 78059b591b1SMichal Meloun return (NULL); 78159b591b1SMichal Meloun } 78259b591b1SMichal Meloun 78359b591b1SMichal Meloun static struct padctl_lane * 78459b591b1SMichal Meloun search_pad_lane(struct padctl_softc *sc, enum padctl_pad_type type, int idx) 78559b591b1SMichal Meloun { 78659b591b1SMichal Meloun int i; 78759b591b1SMichal Meloun 78859b591b1SMichal Meloun for (i = 0; i < nitems(lanes_tbl); i++) { 78959b591b1SMichal Meloun if (!lanes_tbl[i].enabled) 79059b591b1SMichal Meloun continue; 79159b591b1SMichal Meloun if (type == lanes_tbl[i].pad->type && idx == lanes_tbl[i].idx) 79259b591b1SMichal Meloun return (lanes_tbl + i); 79359b591b1SMichal Meloun } 79459b591b1SMichal Meloun return (NULL); 79559b591b1SMichal Meloun } 79659b591b1SMichal Meloun 79759b591b1SMichal Meloun static struct padctl_lane * 79859b591b1SMichal Meloun search_usb3_pad_lane(struct padctl_softc *sc, int idx) 79959b591b1SMichal Meloun { 80059b591b1SMichal Meloun int i; 80159b591b1SMichal Meloun struct padctl_lane *lane, *tmp; 80259b591b1SMichal Meloun 80359b591b1SMichal Meloun lane = NULL; 80459b591b1SMichal Meloun for (i = 0; i < nitems(lane_map_tbl); i++) { 80559b591b1SMichal Meloun if (idx != lane_map_tbl[i].port_idx) 80659b591b1SMichal Meloun continue; 80759b591b1SMichal Meloun tmp = search_pad_lane(sc, lane_map_tbl[i].pad_type, 80859b591b1SMichal Meloun lane_map_tbl[i].lane_idx); 80959b591b1SMichal Meloun if (tmp == NULL) 81059b591b1SMichal Meloun continue; 81159b591b1SMichal Meloun if (strcmp(tmp->mux[tmp->mux_idx], "usb3-ss") != 0) 81259b591b1SMichal Meloun continue; 81359b591b1SMichal Meloun if (lane != NULL) { 81459b591b1SMichal Meloun device_printf(sc->dev, "Duplicated mappings found for" 81559b591b1SMichal Meloun " lanes: %s and %s\n", lane->name, tmp->name); 81659b591b1SMichal Meloun return (NULL); 81759b591b1SMichal Meloun } 81859b591b1SMichal Meloun lane = tmp; 81959b591b1SMichal Meloun } 82059b591b1SMichal Meloun return (lane); 82159b591b1SMichal Meloun } 82259b591b1SMichal Meloun 82359b591b1SMichal Meloun static struct padctl_pad * 82459b591b1SMichal Meloun search_pad(struct padctl_softc *sc, char *pad_name) 82559b591b1SMichal Meloun { 82659b591b1SMichal Meloun int i; 82759b591b1SMichal Meloun 82859b591b1SMichal Meloun for (i = 0; i < nitems(pads_tbl); i++) { 82959b591b1SMichal Meloun if (strcmp(pad_name, pads_tbl[i].name) == 0) 83059b591b1SMichal Meloun return (pads_tbl + i); 83159b591b1SMichal Meloun } 83259b591b1SMichal Meloun return (NULL); 83359b591b1SMichal Meloun } 83459b591b1SMichal Meloun 83559b591b1SMichal Meloun static int 83659b591b1SMichal Meloun search_mux(struct padctl_softc *sc, struct padctl_lane *lane, char *fnc_name) 83759b591b1SMichal Meloun { 83859b591b1SMichal Meloun int i; 83959b591b1SMichal Meloun 84059b591b1SMichal Meloun for (i = 0; i < lane->nmux; i++) { 84159b591b1SMichal Meloun if (strcmp(fnc_name, lane->mux[i]) == 0) 84259b591b1SMichal Meloun return (i); 84359b591b1SMichal Meloun } 84459b591b1SMichal Meloun return (-1); 84559b591b1SMichal Meloun } 84659b591b1SMichal Meloun 84759b591b1SMichal Meloun static int 84859b591b1SMichal Meloun config_lane(struct padctl_softc *sc, struct padctl_lane *lane) 84959b591b1SMichal Meloun { 85059b591b1SMichal Meloun uint32_t reg; 85159b591b1SMichal Meloun 85259b591b1SMichal Meloun reg = RD4(sc, lane->reg); 85359b591b1SMichal Meloun reg &= ~(lane->mask << lane->shift); 85459b591b1SMichal Meloun reg |= (lane->mux_idx & lane->mask) << lane->shift; 85559b591b1SMichal Meloun WR4(sc, lane->reg, reg); 85659b591b1SMichal Meloun return (0); 85759b591b1SMichal Meloun } 85859b591b1SMichal Meloun 85959b591b1SMichal Meloun static int 86059b591b1SMichal Meloun process_lane(struct padctl_softc *sc, phandle_t node, struct padctl_pad *pad) 86159b591b1SMichal Meloun { 86259b591b1SMichal Meloun struct padctl_lane *lane; 863f8759facSMichal Meloun struct phynode *phynode; 864f8759facSMichal Meloun struct phynode_init_def phy_init; 86559b591b1SMichal Meloun char *name; 86659b591b1SMichal Meloun char *function; 86759b591b1SMichal Meloun int rv; 86859b591b1SMichal Meloun 86959b591b1SMichal Meloun name = NULL; 87059b591b1SMichal Meloun function = NULL; 871217d17bcSOleksandr Tymoshenko rv = OF_getprop_alloc(node, "name", (void **)&name); 87259b591b1SMichal Meloun if (rv <= 0) { 87359b591b1SMichal Meloun device_printf(sc->dev, "Cannot read lane name.\n"); 87459b591b1SMichal Meloun return (ENXIO); 87559b591b1SMichal Meloun } 87659b591b1SMichal Meloun 87759b591b1SMichal Meloun lane = search_lane(sc, name); 87859b591b1SMichal Meloun if (lane == NULL) { 87959b591b1SMichal Meloun device_printf(sc->dev, "Unknown lane: %s\n", name); 88059b591b1SMichal Meloun rv = ENXIO; 88159b591b1SMichal Meloun goto end; 88259b591b1SMichal Meloun } 88359b591b1SMichal Meloun 88459b591b1SMichal Meloun /* Read function (mux) settings. */ 885217d17bcSOleksandr Tymoshenko rv = OF_getprop_alloc(node, "nvidia,function", (void **)&function); 88659b591b1SMichal Meloun if (rv <= 0) { 88759b591b1SMichal Meloun device_printf(sc->dev, "Cannot read lane function.\n"); 88859b591b1SMichal Meloun rv = ENXIO; 88959b591b1SMichal Meloun goto end; 89059b591b1SMichal Meloun } 89159b591b1SMichal Meloun 89259b591b1SMichal Meloun lane->mux_idx = search_mux(sc, lane, function); 89359b591b1SMichal Meloun if (lane->mux_idx == ~0) { 89459b591b1SMichal Meloun device_printf(sc->dev, "Unknown function %s for lane %s\n", 89559b591b1SMichal Meloun function, name); 89659b591b1SMichal Meloun rv = ENXIO; 89759b591b1SMichal Meloun goto end; 89859b591b1SMichal Meloun } 89959b591b1SMichal Meloun 90059b591b1SMichal Meloun rv = config_lane(sc, lane); 90159b591b1SMichal Meloun if (rv != 0) { 90259b591b1SMichal Meloun device_printf(sc->dev, "Cannot configure lane: %s: %d\n", 90359b591b1SMichal Meloun name, rv); 90459b591b1SMichal Meloun rv = ENXIO; 90559b591b1SMichal Meloun goto end; 90659b591b1SMichal Meloun } 90759b591b1SMichal Meloun lane->pad = pad; 90859b591b1SMichal Meloun lane->enabled = true; 90959b591b1SMichal Meloun pad->lanes[pad->nlanes++] = lane; 910f8759facSMichal Meloun 911f8759facSMichal Meloun /* Create and register phy. */ 912f8759facSMichal Meloun bzero(&phy_init, sizeof(phy_init)); 913f8759facSMichal Meloun phy_init.id = lane - lanes_tbl; 914f8759facSMichal Meloun phy_init.ofw_node = node; 915f8759facSMichal Meloun phynode = phynode_create(sc->dev, &xusbpadctl_phynode_class, &phy_init); 916f8759facSMichal Meloun if (phynode == NULL) { 917f8759facSMichal Meloun device_printf(sc->dev, "Cannot create phy\n"); 918f8759facSMichal Meloun rv = ENXIO; 919f8759facSMichal Meloun goto end; 920f8759facSMichal Meloun } 921f8759facSMichal Meloun if (phynode_register(phynode) == NULL) { 922f8759facSMichal Meloun device_printf(sc->dev, "Cannot create phy\n"); 923f8759facSMichal Meloun return (ENXIO); 924f8759facSMichal Meloun } 925f8759facSMichal Meloun 92659b591b1SMichal Meloun rv = 0; 92759b591b1SMichal Meloun 92859b591b1SMichal Meloun end: 92959b591b1SMichal Meloun if (name != NULL) 93059b591b1SMichal Meloun OF_prop_free(name); 93159b591b1SMichal Meloun if (function != NULL) 93259b591b1SMichal Meloun OF_prop_free(function); 93359b591b1SMichal Meloun return (rv); 93459b591b1SMichal Meloun } 93559b591b1SMichal Meloun 93659b591b1SMichal Meloun static int 93759b591b1SMichal Meloun process_pad(struct padctl_softc *sc, phandle_t node) 93859b591b1SMichal Meloun { 93959b591b1SMichal Meloun struct padctl_pad *pad; 94059b591b1SMichal Meloun char *name; 94159b591b1SMichal Meloun int rv; 94259b591b1SMichal Meloun 94359b591b1SMichal Meloun name = NULL; 944217d17bcSOleksandr Tymoshenko rv = OF_getprop_alloc(node, "name", (void **)&name); 94559b591b1SMichal Meloun if (rv <= 0) { 94659b591b1SMichal Meloun device_printf(sc->dev, "Cannot read pad name.\n"); 94759b591b1SMichal Meloun return (ENXIO); 94859b591b1SMichal Meloun } 94959b591b1SMichal Meloun pad = search_pad(sc, name); 95059b591b1SMichal Meloun if (pad == NULL) { 95159b591b1SMichal Meloun device_printf(sc->dev, "Unknown pad: %s\n", name); 95259b591b1SMichal Meloun rv = ENXIO; 95359b591b1SMichal Meloun goto end; 95459b591b1SMichal Meloun } 95559b591b1SMichal Meloun 95659b591b1SMichal Meloun /* Read and process associated lanes. */ 95759b591b1SMichal Meloun node = ofw_bus_find_child(node, "lanes"); 95859b591b1SMichal Meloun if (node <= 0) { 95959b591b1SMichal Meloun device_printf(sc->dev, "Cannot find regulators subnode\n"); 96059b591b1SMichal Meloun rv = ENXIO; 96159b591b1SMichal Meloun goto end; 96259b591b1SMichal Meloun } 96359b591b1SMichal Meloun 96459b591b1SMichal Meloun for (node = OF_child(node); node != 0; node = OF_peer(node)) { 9657bc28467SAndrew Turner if (!ofw_bus_node_status_okay(node)) 96659b591b1SMichal Meloun continue; 96759b591b1SMichal Meloun 96859b591b1SMichal Meloun rv = process_lane(sc, node, pad); 96959b591b1SMichal Meloun if (rv != 0) 97059b591b1SMichal Meloun goto end; 97159b591b1SMichal Meloun } 97259b591b1SMichal Meloun pad->enabled = true; 97359b591b1SMichal Meloun rv = 0; 97459b591b1SMichal Meloun end: 97559b591b1SMichal Meloun if (name != NULL) 97659b591b1SMichal Meloun OF_prop_free(name); 97759b591b1SMichal Meloun return (rv); 97859b591b1SMichal Meloun } 97959b591b1SMichal Meloun 98059b591b1SMichal Meloun static int 98159b591b1SMichal Meloun process_port(struct padctl_softc *sc, phandle_t node) 98259b591b1SMichal Meloun { 98359b591b1SMichal Meloun 98459b591b1SMichal Meloun struct padctl_port *port; 98559b591b1SMichal Meloun char *name; 98659b591b1SMichal Meloun int rv; 98759b591b1SMichal Meloun 98859b591b1SMichal Meloun name = NULL; 989217d17bcSOleksandr Tymoshenko rv = OF_getprop_alloc(node, "name", (void **)&name); 99059b591b1SMichal Meloun if (rv <= 0) { 99159b591b1SMichal Meloun device_printf(sc->dev, "Cannot read port name.\n"); 99259b591b1SMichal Meloun return (ENXIO); 99359b591b1SMichal Meloun } 99459b591b1SMichal Meloun 99559b591b1SMichal Meloun port = search_port(sc, name); 99659b591b1SMichal Meloun if (port == NULL) { 99759b591b1SMichal Meloun device_printf(sc->dev, "Unknown port: %s\n", name); 99859b591b1SMichal Meloun rv = ENXIO; 99959b591b1SMichal Meloun goto end; 100059b591b1SMichal Meloun } 100159b591b1SMichal Meloun 100259b591b1SMichal Meloun if (port->type == PADCTL_PORT_USB3) { 100359b591b1SMichal Meloun rv = OF_getencprop(node, "nvidia,usb2-companion", 100459b591b1SMichal Meloun &(port->companion), sizeof(port->companion)); 100559b591b1SMichal Meloun if (rv <= 0) { 100659b591b1SMichal Meloun device_printf(sc->dev, 100759b591b1SMichal Meloun "Missing 'nvidia,usb2-companion' property " 100859b591b1SMichal Meloun "for port: %s\n", name); 100959b591b1SMichal Meloun rv = ENXIO; 101059b591b1SMichal Meloun goto end; 101159b591b1SMichal Meloun } 101259b591b1SMichal Meloun } 101359b591b1SMichal Meloun 101459b591b1SMichal Meloun if (OF_hasprop(node, "vbus-supply")) { 101559b591b1SMichal Meloun rv = regulator_get_by_ofw_property(sc->dev, 0, 101659b591b1SMichal Meloun "vbus-supply", &port->supply_vbus); 101759b591b1SMichal Meloun if (rv <= 0) { 101859b591b1SMichal Meloun device_printf(sc->dev, 101959b591b1SMichal Meloun "Cannot get 'vbus-supply' regulator " 102059b591b1SMichal Meloun "for port: %s\n", name); 102159b591b1SMichal Meloun rv = ENXIO; 102259b591b1SMichal Meloun goto end; 102359b591b1SMichal Meloun } 102459b591b1SMichal Meloun } 102559b591b1SMichal Meloun 102659b591b1SMichal Meloun if (OF_hasprop(node, "nvidia,internal")) 102759b591b1SMichal Meloun port->internal = true; 102859b591b1SMichal Meloun /* Find assigned lane */ 102959b591b1SMichal Meloun if (port->lane == NULL) { 103059b591b1SMichal Meloun switch(port->type) { 103159b591b1SMichal Meloun /* Routing is fixed for USB2, ULPI AND HSIC. */ 103259b591b1SMichal Meloun case PADCTL_PORT_USB2: 103359b591b1SMichal Meloun port->lane = search_pad_lane(sc, PADCTL_PAD_USB2, 103459b591b1SMichal Meloun port->idx); 103559b591b1SMichal Meloun break; 103659b591b1SMichal Meloun case PADCTL_PORT_ULPI: 103759b591b1SMichal Meloun port->lane = search_pad_lane(sc, PADCTL_PAD_ULPI, 103859b591b1SMichal Meloun port->idx); 103959b591b1SMichal Meloun break; 104059b591b1SMichal Meloun case PADCTL_PORT_HSIC: 104159b591b1SMichal Meloun port->lane = search_pad_lane(sc, PADCTL_PAD_HSIC, 104259b591b1SMichal Meloun port->idx); 104359b591b1SMichal Meloun break; 104459b591b1SMichal Meloun case PADCTL_PORT_USB3: 104559b591b1SMichal Meloun port->lane = search_usb3_pad_lane(sc, port->idx); 104659b591b1SMichal Meloun break; 104759b591b1SMichal Meloun } 104859b591b1SMichal Meloun } 104959b591b1SMichal Meloun if (port->lane == NULL) { 105059b591b1SMichal Meloun device_printf(sc->dev, "Cannot find lane for port: %s\n", name); 105159b591b1SMichal Meloun rv = ENXIO; 105259b591b1SMichal Meloun goto end; 105359b591b1SMichal Meloun } 105459b591b1SMichal Meloun port->enabled = true; 105559b591b1SMichal Meloun rv = 0; 105659b591b1SMichal Meloun end: 105759b591b1SMichal Meloun if (name != NULL) 105859b591b1SMichal Meloun OF_prop_free(name); 105959b591b1SMichal Meloun return (rv); 106059b591b1SMichal Meloun } 106159b591b1SMichal Meloun 106259b591b1SMichal Meloun static int 106359b591b1SMichal Meloun parse_fdt(struct padctl_softc *sc, phandle_t base_node) 106459b591b1SMichal Meloun { 106559b591b1SMichal Meloun phandle_t node; 106659b591b1SMichal Meloun int rv; 106759b591b1SMichal Meloun 106859b591b1SMichal Meloun rv = 0; 106959b591b1SMichal Meloun node = ofw_bus_find_child(base_node, "pads"); 107059b591b1SMichal Meloun 107159b591b1SMichal Meloun if (node <= 0) { 107259b591b1SMichal Meloun device_printf(sc->dev, "Cannot find pads subnode.\n"); 107359b591b1SMichal Meloun return (ENXIO); 107459b591b1SMichal Meloun } 107559b591b1SMichal Meloun for (node = OF_child(node); node != 0; node = OF_peer(node)) { 10767bc28467SAndrew Turner if (!ofw_bus_node_status_okay(node)) 107759b591b1SMichal Meloun continue; 107859b591b1SMichal Meloun rv = process_pad(sc, node); 107959b591b1SMichal Meloun if (rv != 0) 108059b591b1SMichal Meloun return (rv); 108159b591b1SMichal Meloun } 108259b591b1SMichal Meloun 108359b591b1SMichal Meloun node = ofw_bus_find_child(base_node, "ports"); 108459b591b1SMichal Meloun if (node <= 0) { 108559b591b1SMichal Meloun device_printf(sc->dev, "Cannot find ports subnode.\n"); 108659b591b1SMichal Meloun return (ENXIO); 108759b591b1SMichal Meloun } 108859b591b1SMichal Meloun for (node = OF_child(node); node != 0; node = OF_peer(node)) { 10897bc28467SAndrew Turner if (!ofw_bus_node_status_okay(node)) 109059b591b1SMichal Meloun continue; 109159b591b1SMichal Meloun rv = process_port(sc, node); 109259b591b1SMichal Meloun if (rv != 0) 109359b591b1SMichal Meloun return (rv); 109459b591b1SMichal Meloun } 109559b591b1SMichal Meloun 109659b591b1SMichal Meloun return (0); 109759b591b1SMichal Meloun } 109859b591b1SMichal Meloun 109959b591b1SMichal Meloun static void 110059b591b1SMichal Meloun load_calibration(struct padctl_softc *sc) 110159b591b1SMichal Meloun { 110259b591b1SMichal Meloun uint32_t reg; 110359b591b1SMichal Meloun 110459b591b1SMichal Meloun /* All XUSB pad calibrations are packed into single dword.*/ 110559b591b1SMichal Meloun reg = tegra_fuse_read_4(FUSE_XUSB_CALIB); 110659b591b1SMichal Meloun sc->hs_curr_level_0 = FUSE_XUSB_CALIB_HS_CURR_LEVEL_0(reg); 110759b591b1SMichal Meloun sc->hs_curr_level_123 = FUSE_XUSB_CALIB_HS_CURR_LEVEL_123(reg); 110859b591b1SMichal Meloun sc->hs_iref_cap = FUSE_XUSB_CALIB_HS_IREF_CAP(reg); 110959b591b1SMichal Meloun sc->hs_squelch_level = FUSE_XUSB_CALIB_HS_SQUELCH_LEVEL(reg); 111059b591b1SMichal Meloun sc->hs_term_range_adj = FUSE_XUSB_CALIB_HS_TERM_RANGE_ADJ(reg); 111159b591b1SMichal Meloun } 111259b591b1SMichal Meloun 111359b591b1SMichal Meloun /* ------------------------------------------------------------------------- 111459b591b1SMichal Meloun * 111559b591b1SMichal Meloun * BUS functions 111659b591b1SMichal Meloun */ 111759b591b1SMichal Meloun static int 1118ef2ee5d0SMichal Meloun xusbpadctl_probe(device_t dev) 1119ef2ee5d0SMichal Meloun { 1120ef2ee5d0SMichal Meloun 1121ef2ee5d0SMichal Meloun if (!ofw_bus_status_okay(dev)) 1122ef2ee5d0SMichal Meloun return (ENXIO); 1123ef2ee5d0SMichal Meloun 1124ef2ee5d0SMichal Meloun if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 1125ef2ee5d0SMichal Meloun return (ENXIO); 1126ef2ee5d0SMichal Meloun 1127ef2ee5d0SMichal Meloun device_set_desc(dev, "Tegra XUSB phy"); 1128ef2ee5d0SMichal Meloun return (BUS_PROBE_DEFAULT); 1129ef2ee5d0SMichal Meloun } 1130ef2ee5d0SMichal Meloun 1131ef2ee5d0SMichal Meloun static int 1132ef2ee5d0SMichal Meloun xusbpadctl_detach(device_t dev) 1133ef2ee5d0SMichal Meloun { 1134ef2ee5d0SMichal Meloun 1135ef2ee5d0SMichal Meloun /* This device is always present. */ 1136ef2ee5d0SMichal Meloun return (EBUSY); 1137ef2ee5d0SMichal Meloun } 1138ef2ee5d0SMichal Meloun 1139ef2ee5d0SMichal Meloun static int 1140ef2ee5d0SMichal Meloun xusbpadctl_attach(device_t dev) 1141ef2ee5d0SMichal Meloun { 114259b591b1SMichal Meloun struct padctl_softc * sc; 114359b591b1SMichal Meloun int i, rid, rv; 114459b591b1SMichal Meloun struct padctl_port *port; 1145ef2ee5d0SMichal Meloun phandle_t node; 1146ef2ee5d0SMichal Meloun 1147ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 1148ef2ee5d0SMichal Meloun sc->dev = dev; 114959b591b1SMichal Meloun node = ofw_bus_get_node(dev); 1150ef2ee5d0SMichal Meloun 1151ef2ee5d0SMichal Meloun rid = 0; 1152ef2ee5d0SMichal Meloun sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 1153ef2ee5d0SMichal Meloun RF_ACTIVE); 1154ef2ee5d0SMichal Meloun if (sc->mem_res == NULL) { 1155ef2ee5d0SMichal Meloun device_printf(dev, "Cannot allocate memory resources\n"); 1156ef2ee5d0SMichal Meloun return (ENXIO); 1157ef2ee5d0SMichal Meloun } 1158ef2ee5d0SMichal Meloun 1159dac93553SMichal Meloun rv = hwreset_get_by_ofw_name(dev, 0, "padctl", &sc->rst); 1160ef2ee5d0SMichal Meloun if (rv != 0) { 1161ef2ee5d0SMichal Meloun device_printf(dev, "Cannot get 'padctl' reset: %d\n", rv); 1162ef2ee5d0SMichal Meloun return (rv); 1163ef2ee5d0SMichal Meloun } 1164ef2ee5d0SMichal Meloun rv = hwreset_deassert(sc->rst); 1165ef2ee5d0SMichal Meloun if (rv != 0) { 1166ef2ee5d0SMichal Meloun device_printf(dev, "Cannot unreset 'padctl' reset: %d\n", rv); 1167ef2ee5d0SMichal Meloun return (rv); 1168ef2ee5d0SMichal Meloun } 1169ef2ee5d0SMichal Meloun 117059b591b1SMichal Meloun load_calibration(sc); 1171ef2ee5d0SMichal Meloun 117259b591b1SMichal Meloun rv = parse_fdt(sc, node); 117359b591b1SMichal Meloun if (rv != 0) { 117459b591b1SMichal Meloun device_printf(dev, "Cannot parse fdt configuration: %d\n", rv); 117559b591b1SMichal Meloun return (rv); 117659b591b1SMichal Meloun } 117759b591b1SMichal Meloun for (i = 0; i < nitems(ports_tbl); i++) { 117859b591b1SMichal Meloun port = ports_tbl + i; 117959b591b1SMichal Meloun if (!port->enabled) 118059b591b1SMichal Meloun continue; 118159b591b1SMichal Meloun if (port->init == NULL) 118259b591b1SMichal Meloun continue; 118359b591b1SMichal Meloun rv = port->init(sc, port); 118459b591b1SMichal Meloun if (rv != 0) { 118559b591b1SMichal Meloun device_printf(dev, "Cannot init port '%s'\n", 118659b591b1SMichal Meloun port->name); 118759b591b1SMichal Meloun return (rv); 118859b591b1SMichal Meloun } 118959b591b1SMichal Meloun } 1190ef2ee5d0SMichal Meloun return (0); 1191ef2ee5d0SMichal Meloun } 1192ef2ee5d0SMichal Meloun 1193ef2ee5d0SMichal Meloun static device_method_t tegra_xusbpadctl_methods[] = { 1194ef2ee5d0SMichal Meloun /* Device interface */ 1195ef2ee5d0SMichal Meloun DEVMETHOD(device_probe, xusbpadctl_probe), 1196ef2ee5d0SMichal Meloun DEVMETHOD(device_attach, xusbpadctl_attach), 1197ef2ee5d0SMichal Meloun DEVMETHOD(device_detach, xusbpadctl_detach), 1198ef2ee5d0SMichal Meloun 1199ef2ee5d0SMichal Meloun DEVMETHOD_END 1200ef2ee5d0SMichal Meloun }; 1201ef2ee5d0SMichal Meloun 12024bda238aSMichal Meloun static DEFINE_CLASS_0(xusbpadctl, tegra_xusbpadctl_driver, 120359b591b1SMichal Meloun tegra_xusbpadctl_methods, sizeof(struct padctl_softc)); 1204ef2ee5d0SMichal Meloun EARLY_DRIVER_MODULE(tegra_xusbpadctl, simplebus, tegra_xusbpadctl_driver, 1205289f133bSJohn Baldwin NULL, NULL, 73); 1206