14e5b9c9aSAl Cooper // SPDX-License-Identifier: GPL-2.0 24e5b9c9aSAl Cooper /* Copyright (c) 2018, Broadcom */ 34e5b9c9aSAl Cooper 44e5b9c9aSAl Cooper /* 54e5b9c9aSAl Cooper * This module contains USB PHY initialization for power up and S3 resume 64e5b9c9aSAl Cooper * for newer Synopsys based USB hardware first used on the bcm7216. 74e5b9c9aSAl Cooper */ 84e5b9c9aSAl Cooper 94e5b9c9aSAl Cooper #include <linux/delay.h> 104e5b9c9aSAl Cooper #include <linux/io.h> 114e5b9c9aSAl Cooper 124e5b9c9aSAl Cooper #include <linux/soc/brcmstb/brcmstb.h> 134e5b9c9aSAl Cooper #include "phy-brcm-usb-init.h" 144e5b9c9aSAl Cooper 159d5f51dcSAl Cooper #define PHY_LOCK_TIMEOUT_MS 200 169d5f51dcSAl Cooper 179d5f51dcSAl Cooper /* Register definitions for syscon piarbctl registers */ 189d5f51dcSAl Cooper #define PIARBCTL_CAM 0x00 199d5f51dcSAl Cooper #define PIARBCTL_SPLITTER 0x04 209d5f51dcSAl Cooper #define PIARBCTL_MISC 0x08 217e81153dSJustin Chen #define PIARBCTL_MISC_SATA_PRIORITY_MASK GENMASK(3, 0) 227e81153dSJustin Chen #define PIARBCTL_MISC_CAM0_MEM_PAGE_MASK GENMASK(7, 4) 237e81153dSJustin Chen #define PIARBCTL_MISC_CAM1_MEM_PAGE_MASK GENMASK(11, 8) 247e81153dSJustin Chen #define PIARBCTL_MISC_USB_MEM_PAGE_MASK GENMASK(15, 12) 257e81153dSJustin Chen #define PIARBCTL_MISC_USB_PRIORITY_MASK GENMASK(19, 16) 267e81153dSJustin Chen #define PIARBCTL_MISC_USB_4G_SDRAM_MASK BIT(29) 277e81153dSJustin Chen #define PIARBCTL_MISC_USB_SELECT_MASK BIT(30) 287e81153dSJustin Chen #define PIARBCTL_MISC_SECURE_MASK BIT(31) 299d5f51dcSAl Cooper 309d5f51dcSAl Cooper #define PIARBCTL_MISC_USB_ONLY_MASK \ 319d5f51dcSAl Cooper (PIARBCTL_MISC_USB_SELECT_MASK | \ 329d5f51dcSAl Cooper PIARBCTL_MISC_USB_4G_SDRAM_MASK | \ 339d5f51dcSAl Cooper PIARBCTL_MISC_USB_PRIORITY_MASK | \ 349d5f51dcSAl Cooper PIARBCTL_MISC_USB_MEM_PAGE_MASK) 359d5f51dcSAl Cooper 364e5b9c9aSAl Cooper /* Register definitions for the USB CTRL block */ 374e5b9c9aSAl Cooper #define USB_CTRL_SETUP 0x00 387e81153dSJustin Chen #define USB_CTRL_SETUP_IOC_MASK BIT(4) 397e81153dSJustin Chen #define USB_CTRL_SETUP_IPP_MASK BIT(5) 407e81153dSJustin Chen #define USB_CTRL_SETUP_SOFT_SHUTDOWN_MASK BIT(9) 417e81153dSJustin Chen #define USB_CTRL_SETUP_SCB1_EN_MASK BIT(14) 427e81153dSJustin Chen #define USB_CTRL_SETUP_SCB2_EN_MASK BIT(15) 437e81153dSJustin Chen #define USB_CTRL_SETUP_tca_drv_sel_MASK BIT(24) 447e81153dSJustin Chen #define USB_CTRL_SETUP_STRAP_IPP_SEL_MASK BIT(25) 454e5b9c9aSAl Cooper #define USB_CTRL_USB_PM 0x04 467e81153dSJustin Chen #define USB_CTRL_USB_PM_XHC_S2_CLK_SWITCH_EN_MASK BIT(3) 477e81153dSJustin Chen #define USB_CTRL_USB_PM_XHC_PME_EN_MASK BIT(4) 487e81153dSJustin Chen #define USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK BIT(22) 497e81153dSJustin Chen #define USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK BIT(23) 507e81153dSJustin Chen #define USB_CTRL_USB_PM_SOFT_RESET_MASK BIT(30) 517e81153dSJustin Chen #define USB_CTRL_USB_PM_USB_PWRDN_MASK BIT(31) 524e5b9c9aSAl Cooper #define USB_CTRL_USB_PM_STATUS 0x08 534e5b9c9aSAl Cooper #define USB_CTRL_USB_DEVICE_CTL1 0x10 547e81153dSJustin Chen #define USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK GENMASK(1, 0) 55b0c0b66cSAl Cooper #define USB_CTRL_TEST_PORT_CTL 0x30 567e81153dSJustin Chen #define USB_CTRL_TEST_PORT_CTL_TPOUT_SEL_MASK GENMASK(7, 0) 57b0c0b66cSAl Cooper #define USB_CTRL_TEST_PORT_CTL_TPOUT_SEL_PME_GEN_MASK 0x0000002e 58b0c0b66cSAl Cooper #define USB_CTRL_TP_DIAG1 0x34 597e81153dSJustin Chen #define USB_CTLR_TP_DIAG1_wake_MASK BIT(1) 60b0c0b66cSAl Cooper #define USB_CTRL_CTLR_CSHCR 0x50 617e81153dSJustin Chen #define USB_CTRL_CTLR_CSHCR_ctl_pme_en_MASK BIT(18) 624e5b9c9aSAl Cooper 639d5f51dcSAl Cooper /* Register definitions for the USB_PHY block in 7211b0 */ 64b0c0b66cSAl Cooper #define USB_PHY_PLL_CTL 0x00 65833c173eSJustin Chen #define USB_PHY_PLL_CTL_PLL_SUSPEND_MASK BIT(27) 667e81153dSJustin Chen #define USB_PHY_PLL_CTL_PLL_RESETB_MASK BIT(30) 679d5f51dcSAl Cooper #define USB_PHY_PLL_LDO_CTL 0x08 687e81153dSJustin Chen #define USB_PHY_PLL_LDO_CTL_AFE_BG_PWRDWNB_MASK BIT(0) 697e81153dSJustin Chen #define USB_PHY_PLL_LDO_CTL_AFE_LDO_PWRDWNB_MASK BIT(1) 707e81153dSJustin Chen #define USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK BIT(2) 719d5f51dcSAl Cooper #define USB_PHY_UTMI_CTL_1 0x04 727e81153dSJustin Chen #define USB_PHY_UTMI_CTL_1_PHY_MODE_MASK GENMASK(3, 2) 739d5f51dcSAl Cooper #define USB_PHY_UTMI_CTL_1_PHY_MODE_SHIFT 2 747e81153dSJustin Chen #define USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK BIT(11) 75b0c0b66cSAl Cooper #define USB_PHY_IDDQ 0x1c 767e81153dSJustin Chen #define USB_PHY_IDDQ_phy_iddq_MASK BIT(0) 779d5f51dcSAl Cooper #define USB_PHY_STATUS 0x20 787e81153dSJustin Chen #define USB_PHY_STATUS_pll_lock_MASK BIT(0) 799d5f51dcSAl Cooper 809d5f51dcSAl Cooper /* Register definitions for the MDIO registers in the DWC2 block of 819d5f51dcSAl Cooper * the 7211b0. 829d5f51dcSAl Cooper * NOTE: The PHY's MDIO registers are only accessible through the 839d5f51dcSAl Cooper * legacy DesignWare USB controller even though it's not being used. 849d5f51dcSAl Cooper */ 859d5f51dcSAl Cooper #define USB_GMDIOCSR 0 869d5f51dcSAl Cooper #define USB_GMDIOGEN 4 879d5f51dcSAl Cooper 88bed63b63SAl Cooper /* Register definitions for the BDC EC block in 7211b0 */ 89bed63b63SAl Cooper #define BDC_EC_AXIRDA 0x0c 907e81153dSJustin Chen #define BDC_EC_AXIRDA_RTS_MASK GENMASK(31, 28) 91bed63b63SAl Cooper #define BDC_EC_AXIRDA_RTS_SHIFT 28 92bed63b63SAl Cooper 939d5f51dcSAl Cooper 949d5f51dcSAl Cooper static void usb_mdio_write_7211b0(struct brcm_usb_init_params *params, 959d5f51dcSAl Cooper uint8_t addr, uint16_t data) 969d5f51dcSAl Cooper { 979d5f51dcSAl Cooper void __iomem *usb_mdio = params->regs[BRCM_REGS_USB_MDIO]; 989d5f51dcSAl Cooper 999d5f51dcSAl Cooper addr &= 0x1f; /* 5-bit address */ 1009d5f51dcSAl Cooper brcm_usb_writel(0xffffffff, usb_mdio + USB_GMDIOGEN); 1019d5f51dcSAl Cooper while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31)) 1029d5f51dcSAl Cooper ; 1039d5f51dcSAl Cooper brcm_usb_writel(0x59020000 | (addr << 18) | data, 1049d5f51dcSAl Cooper usb_mdio + USB_GMDIOGEN); 1059d5f51dcSAl Cooper while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31)) 1069d5f51dcSAl Cooper ; 1079d5f51dcSAl Cooper brcm_usb_writel(0x00000000, usb_mdio + USB_GMDIOGEN); 1089d5f51dcSAl Cooper while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31)) 1099d5f51dcSAl Cooper ; 1109d5f51dcSAl Cooper } 1119d5f51dcSAl Cooper 1129d5f51dcSAl Cooper static uint16_t __maybe_unused usb_mdio_read_7211b0( 1139d5f51dcSAl Cooper struct brcm_usb_init_params *params, uint8_t addr) 1149d5f51dcSAl Cooper { 1159d5f51dcSAl Cooper void __iomem *usb_mdio = params->regs[BRCM_REGS_USB_MDIO]; 1169d5f51dcSAl Cooper 1179d5f51dcSAl Cooper addr &= 0x1f; /* 5-bit address */ 1189d5f51dcSAl Cooper brcm_usb_writel(0xffffffff, usb_mdio + USB_GMDIOGEN); 1199d5f51dcSAl Cooper while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31)) 1209d5f51dcSAl Cooper ; 1219d5f51dcSAl Cooper brcm_usb_writel(0x69020000 | (addr << 18), usb_mdio + USB_GMDIOGEN); 1229d5f51dcSAl Cooper while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31)) 1239d5f51dcSAl Cooper ; 1249d5f51dcSAl Cooper brcm_usb_writel(0x00000000, usb_mdio + USB_GMDIOGEN); 1259d5f51dcSAl Cooper while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31)) 1269d5f51dcSAl Cooper ; 1279d5f51dcSAl Cooper return brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & 0xffff; 1289d5f51dcSAl Cooper } 1299d5f51dcSAl Cooper 1309d5f51dcSAl Cooper static void usb2_eye_fix_7211b0(struct brcm_usb_init_params *params) 1319d5f51dcSAl Cooper { 1329d5f51dcSAl Cooper /* select bank */ 1339d5f51dcSAl Cooper usb_mdio_write_7211b0(params, 0x1f, 0x80a0); 1349d5f51dcSAl Cooper 1359d5f51dcSAl Cooper /* Set the eye */ 1369d5f51dcSAl Cooper usb_mdio_write_7211b0(params, 0x0a, 0xc6a0); 1379d5f51dcSAl Cooper } 1384e5b9c9aSAl Cooper 1394e5b9c9aSAl Cooper static void xhci_soft_reset(struct brcm_usb_init_params *params, 1404e5b9c9aSAl Cooper int on_off) 1414e5b9c9aSAl Cooper { 1429d5f51dcSAl Cooper void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; 1434e5b9c9aSAl Cooper 1444e5b9c9aSAl Cooper /* Assert reset */ 1454e5b9c9aSAl Cooper if (on_off) 1464e5b9c9aSAl Cooper USB_CTRL_UNSET(ctrl, USB_PM, XHC_SOFT_RESETB); 1474e5b9c9aSAl Cooper /* De-assert reset */ 1484e5b9c9aSAl Cooper else 1494e5b9c9aSAl Cooper USB_CTRL_SET(ctrl, USB_PM, XHC_SOFT_RESETB); 1504e5b9c9aSAl Cooper } 1514e5b9c9aSAl Cooper 1524e5b9c9aSAl Cooper static void usb_init_ipp(struct brcm_usb_init_params *params) 1534e5b9c9aSAl Cooper { 1549d5f51dcSAl Cooper void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; 1554e5b9c9aSAl Cooper u32 reg; 1564e5b9c9aSAl Cooper u32 orig_reg; 1574e5b9c9aSAl Cooper 1584e5b9c9aSAl Cooper pr_debug("%s\n", __func__); 1594e5b9c9aSAl Cooper 1604e5b9c9aSAl Cooper orig_reg = reg = brcm_usb_readl(USB_CTRL_REG(ctrl, SETUP)); 1614e5b9c9aSAl Cooper if (params->ipp != 2) 1624e5b9c9aSAl Cooper /* override ipp strap pin (if it exits) */ 1634e5b9c9aSAl Cooper reg &= ~(USB_CTRL_MASK(SETUP, STRAP_IPP_SEL)); 1644e5b9c9aSAl Cooper 1654e5b9c9aSAl Cooper /* Override the default OC and PP polarity */ 1664e5b9c9aSAl Cooper reg &= ~(USB_CTRL_MASK(SETUP, IPP) | USB_CTRL_MASK(SETUP, IOC)); 1674e5b9c9aSAl Cooper if (params->ioc) 1684e5b9c9aSAl Cooper reg |= USB_CTRL_MASK(SETUP, IOC); 1694e5b9c9aSAl Cooper if (params->ipp == 1) 1704e5b9c9aSAl Cooper reg |= USB_CTRL_MASK(SETUP, IPP); 1714e5b9c9aSAl Cooper brcm_usb_writel(reg, USB_CTRL_REG(ctrl, SETUP)); 1724e5b9c9aSAl Cooper 1734e5b9c9aSAl Cooper /* 1744e5b9c9aSAl Cooper * If we're changing IPP, make sure power is off long enough 1754e5b9c9aSAl Cooper * to turn off any connected devices. 1764e5b9c9aSAl Cooper */ 1774e5b9c9aSAl Cooper if ((reg ^ orig_reg) & USB_CTRL_MASK(SETUP, IPP)) 1784e5b9c9aSAl Cooper msleep(50); 1794e5b9c9aSAl Cooper } 1804e5b9c9aSAl Cooper 1819d5f51dcSAl Cooper static void syscon_piarbctl_init(struct regmap *rmap) 1829d5f51dcSAl Cooper { 1839d5f51dcSAl Cooper /* Switch from legacy USB OTG controller to new STB USB controller */ 1849d5f51dcSAl Cooper regmap_update_bits(rmap, PIARBCTL_MISC, PIARBCTL_MISC_USB_ONLY_MASK, 1859d5f51dcSAl Cooper PIARBCTL_MISC_USB_SELECT_MASK | 1869d5f51dcSAl Cooper PIARBCTL_MISC_USB_4G_SDRAM_MASK); 1879d5f51dcSAl Cooper } 1889d5f51dcSAl Cooper 1894e5b9c9aSAl Cooper static void usb_init_common(struct brcm_usb_init_params *params) 1904e5b9c9aSAl Cooper { 1914e5b9c9aSAl Cooper u32 reg; 1929d5f51dcSAl Cooper void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; 1934e5b9c9aSAl Cooper 1944e5b9c9aSAl Cooper pr_debug("%s\n", __func__); 1954e5b9c9aSAl Cooper 1964e5b9c9aSAl Cooper if (USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE)) { 1974e5b9c9aSAl Cooper reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1)); 1984e5b9c9aSAl Cooper reg &= ~USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE); 19932fb07f3SJustin Chen reg |= params->port_mode; 2004e5b9c9aSAl Cooper brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1)); 2014e5b9c9aSAl Cooper } 20232fb07f3SJustin Chen switch (params->supported_port_modes) { 2034e5b9c9aSAl Cooper case USB_CTLR_MODE_HOST: 2044e5b9c9aSAl Cooper USB_CTRL_UNSET(ctrl, USB_PM, BDC_SOFT_RESETB); 2054e5b9c9aSAl Cooper break; 2064e5b9c9aSAl Cooper default: 2074e5b9c9aSAl Cooper USB_CTRL_UNSET(ctrl, USB_PM, BDC_SOFT_RESETB); 2084e5b9c9aSAl Cooper USB_CTRL_SET(ctrl, USB_PM, BDC_SOFT_RESETB); 2094e5b9c9aSAl Cooper break; 2104e5b9c9aSAl Cooper } 2114e5b9c9aSAl Cooper } 2124e5b9c9aSAl Cooper 213b0c0b66cSAl Cooper static void usb_wake_enable_7211b0(struct brcm_usb_init_params *params, 214b0c0b66cSAl Cooper bool enable) 215b0c0b66cSAl Cooper { 216b0c0b66cSAl Cooper void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; 217b0c0b66cSAl Cooper 218b0c0b66cSAl Cooper if (enable) 219b0c0b66cSAl Cooper USB_CTRL_SET(ctrl, CTLR_CSHCR, ctl_pme_en); 220b0c0b66cSAl Cooper else 221b0c0b66cSAl Cooper USB_CTRL_UNSET(ctrl, CTLR_CSHCR, ctl_pme_en); 222b0c0b66cSAl Cooper } 223b0c0b66cSAl Cooper 224ae532b2bSAl Cooper static void usb_wake_enable_7216(struct brcm_usb_init_params *params, 225ae532b2bSAl Cooper bool enable) 226ae532b2bSAl Cooper { 227ae532b2bSAl Cooper void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; 228ae532b2bSAl Cooper 229ae532b2bSAl Cooper if (enable) 230ae532b2bSAl Cooper USB_CTRL_SET(ctrl, USB_PM, XHC_PME_EN); 231ae532b2bSAl Cooper else 232ae532b2bSAl Cooper USB_CTRL_UNSET(ctrl, USB_PM, XHC_PME_EN); 233ae532b2bSAl Cooper } 234ae532b2bSAl Cooper 2359d5f51dcSAl Cooper static void usb_init_common_7211b0(struct brcm_usb_init_params *params) 2369d5f51dcSAl Cooper { 2379d5f51dcSAl Cooper void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; 2389d5f51dcSAl Cooper void __iomem *usb_phy = params->regs[BRCM_REGS_USB_PHY]; 239bed63b63SAl Cooper void __iomem *bdc_ec = params->regs[BRCM_REGS_BDC_EC]; 2409d5f51dcSAl Cooper int timeout_ms = PHY_LOCK_TIMEOUT_MS; 2419d5f51dcSAl Cooper u32 reg; 2429d5f51dcSAl Cooper 2439d5f51dcSAl Cooper if (params->syscon_piarbctl) 2449d5f51dcSAl Cooper syscon_piarbctl_init(params->syscon_piarbctl); 2459d5f51dcSAl Cooper 246b0c0b66cSAl Cooper USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN); 247b0c0b66cSAl Cooper 248b0c0b66cSAl Cooper usb_wake_enable_7211b0(params, false); 249b0c0b66cSAl Cooper if (!params->wake_enabled) { 250b0c0b66cSAl Cooper 251b0c0b66cSAl Cooper /* undo possible suspend settings */ 252b0c0b66cSAl Cooper brcm_usb_writel(0, usb_phy + USB_PHY_IDDQ); 253b0c0b66cSAl Cooper reg = brcm_usb_readl(usb_phy + USB_PHY_PLL_CTL); 254b0c0b66cSAl Cooper reg |= USB_PHY_PLL_CTL_PLL_RESETB_MASK; 255b0c0b66cSAl Cooper brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_CTL); 256b0c0b66cSAl Cooper 257b0c0b66cSAl Cooper /* temporarily enable FSM so PHY comes up properly */ 258b0c0b66cSAl Cooper reg = brcm_usb_readl(usb_phy + USB_PHY_UTMI_CTL_1); 259b0c0b66cSAl Cooper reg |= USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK; 260b0c0b66cSAl Cooper brcm_usb_writel(reg, usb_phy + USB_PHY_UTMI_CTL_1); 261b0c0b66cSAl Cooper } 262b0c0b66cSAl Cooper 263833c173eSJustin Chen /* Disable PLL auto suspend */ 264833c173eSJustin Chen reg = brcm_usb_readl(usb_phy + USB_PHY_PLL_CTL); 265833c173eSJustin Chen reg |= USB_PHY_PLL_CTL_PLL_SUSPEND_MASK; 266833c173eSJustin Chen brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_CTL); 267833c173eSJustin Chen 2689d5f51dcSAl Cooper /* Init the PHY */ 269b0c0b66cSAl Cooper reg = USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK | 270b0c0b66cSAl Cooper USB_PHY_PLL_LDO_CTL_AFE_LDO_PWRDWNB_MASK | 271b0c0b66cSAl Cooper USB_PHY_PLL_LDO_CTL_AFE_BG_PWRDWNB_MASK; 2729d5f51dcSAl Cooper brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_LDO_CTL); 2739d5f51dcSAl Cooper 2749d5f51dcSAl Cooper /* wait for lock */ 2759d5f51dcSAl Cooper while (timeout_ms-- > 0) { 2769d5f51dcSAl Cooper reg = brcm_usb_readl(usb_phy + USB_PHY_STATUS); 2779d5f51dcSAl Cooper if (reg & USB_PHY_STATUS_pll_lock_MASK) 2789d5f51dcSAl Cooper break; 2799d5f51dcSAl Cooper usleep_range(1000, 2000); 2809d5f51dcSAl Cooper } 2819d5f51dcSAl Cooper 2829d5f51dcSAl Cooper /* Set the PHY_MODE */ 2839d5f51dcSAl Cooper reg = brcm_usb_readl(usb_phy + USB_PHY_UTMI_CTL_1); 2849d5f51dcSAl Cooper reg &= ~USB_PHY_UTMI_CTL_1_PHY_MODE_MASK; 28532fb07f3SJustin Chen reg |= params->supported_port_modes << USB_PHY_UTMI_CTL_1_PHY_MODE_SHIFT; 2869d5f51dcSAl Cooper brcm_usb_writel(reg, usb_phy + USB_PHY_UTMI_CTL_1); 2879d5f51dcSAl Cooper 2889d5f51dcSAl Cooper usb_init_common(params); 2899d5f51dcSAl Cooper 290fc430aeaSAl Cooper /* 291bed63b63SAl Cooper * The BDC controller will get occasional failures with 292bed63b63SAl Cooper * the default "Read Transaction Size" of 6 (1024 bytes). 293bed63b63SAl Cooper * Set it to 4 (256 bytes). 294bed63b63SAl Cooper */ 29532fb07f3SJustin Chen if ((params->supported_port_modes != USB_CTLR_MODE_HOST) && bdc_ec) { 296bed63b63SAl Cooper reg = brcm_usb_readl(bdc_ec + BDC_EC_AXIRDA); 297bed63b63SAl Cooper reg &= ~BDC_EC_AXIRDA_RTS_MASK; 298bed63b63SAl Cooper reg |= (0x4 << BDC_EC_AXIRDA_RTS_SHIFT); 299bed63b63SAl Cooper brcm_usb_writel(reg, bdc_ec + BDC_EC_AXIRDA); 300bed63b63SAl Cooper } 301bed63b63SAl Cooper 302bed63b63SAl Cooper /* 303fc430aeaSAl Cooper * Disable FSM, otherwise the PHY will auto suspend when no 304fc430aeaSAl Cooper * device is connected and will be reset on resume. 305fc430aeaSAl Cooper */ 306fc430aeaSAl Cooper reg = brcm_usb_readl(usb_phy + USB_PHY_UTMI_CTL_1); 307fc430aeaSAl Cooper reg &= ~USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK; 308fc430aeaSAl Cooper brcm_usb_writel(reg, usb_phy + USB_PHY_UTMI_CTL_1); 309fc430aeaSAl Cooper 3109d5f51dcSAl Cooper usb2_eye_fix_7211b0(params); 3119d5f51dcSAl Cooper } 3129d5f51dcSAl Cooper 313ae532b2bSAl Cooper static void usb_init_common_7216(struct brcm_usb_init_params *params) 314ae532b2bSAl Cooper { 315ae532b2bSAl Cooper void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; 316ae532b2bSAl Cooper 317ae532b2bSAl Cooper USB_CTRL_UNSET(ctrl, USB_PM, XHC_S2_CLK_SWITCH_EN); 318ae532b2bSAl Cooper USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN); 319ae532b2bSAl Cooper 320ae532b2bSAl Cooper /* 1 millisecond - for USB clocks to settle down */ 321ae532b2bSAl Cooper usleep_range(1000, 2000); 322ae532b2bSAl Cooper 323ae532b2bSAl Cooper usb_wake_enable_7216(params, false); 324ae532b2bSAl Cooper usb_init_common(params); 325ae532b2bSAl Cooper } 326ae532b2bSAl Cooper 3274e5b9c9aSAl Cooper static void usb_init_xhci(struct brcm_usb_init_params *params) 3284e5b9c9aSAl Cooper { 3294e5b9c9aSAl Cooper pr_debug("%s\n", __func__); 3304e5b9c9aSAl Cooper 3314e5b9c9aSAl Cooper xhci_soft_reset(params, 0); 3324e5b9c9aSAl Cooper } 3334e5b9c9aSAl Cooper 334ae532b2bSAl Cooper static void usb_uninit_common_7216(struct brcm_usb_init_params *params) 3354e5b9c9aSAl Cooper { 3369d5f51dcSAl Cooper void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; 3374e5b9c9aSAl Cooper 3384e5b9c9aSAl Cooper pr_debug("%s\n", __func__); 3394e5b9c9aSAl Cooper 340*700c44b5SJustin Chen if (params->wake_enabled) { 341ae532b2bSAl Cooper /* Switch to using slower clock during suspend to save power */ 342ae532b2bSAl Cooper USB_CTRL_SET(ctrl, USB_PM, XHC_S2_CLK_SWITCH_EN); 343ae532b2bSAl Cooper usb_wake_enable_7216(params, true); 344*700c44b5SJustin Chen } else { 345*700c44b5SJustin Chen USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN); 346ae532b2bSAl Cooper } 3474e5b9c9aSAl Cooper } 3484e5b9c9aSAl Cooper 349b0c0b66cSAl Cooper static void usb_uninit_common_7211b0(struct brcm_usb_init_params *params) 350b0c0b66cSAl Cooper { 351b0c0b66cSAl Cooper void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; 352b0c0b66cSAl Cooper void __iomem *usb_phy = params->regs[BRCM_REGS_USB_PHY]; 353b0c0b66cSAl Cooper u32 reg; 354b0c0b66cSAl Cooper 355b0c0b66cSAl Cooper pr_debug("%s\n", __func__); 356b0c0b66cSAl Cooper 357b0c0b66cSAl Cooper if (params->wake_enabled) { 358b0c0b66cSAl Cooper USB_CTRL_SET(ctrl, TEST_PORT_CTL, TPOUT_SEL_PME_GEN); 359b0c0b66cSAl Cooper usb_wake_enable_7211b0(params, true); 360b0c0b66cSAl Cooper } else { 361b0c0b66cSAl Cooper USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN); 362b0c0b66cSAl Cooper brcm_usb_writel(0, usb_phy + USB_PHY_PLL_LDO_CTL); 363b0c0b66cSAl Cooper reg = brcm_usb_readl(usb_phy + USB_PHY_PLL_CTL); 364b0c0b66cSAl Cooper reg &= ~USB_PHY_PLL_CTL_PLL_RESETB_MASK; 365b0c0b66cSAl Cooper brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_CTL); 366b0c0b66cSAl Cooper brcm_usb_writel(USB_PHY_IDDQ_phy_iddq_MASK, 367b0c0b66cSAl Cooper usb_phy + USB_PHY_IDDQ); 368b0c0b66cSAl Cooper } 369b0c0b66cSAl Cooper 370b0c0b66cSAl Cooper } 371b0c0b66cSAl Cooper 3724e5b9c9aSAl Cooper static void usb_uninit_xhci(struct brcm_usb_init_params *params) 3734e5b9c9aSAl Cooper { 3744e5b9c9aSAl Cooper 3754e5b9c9aSAl Cooper pr_debug("%s\n", __func__); 3764e5b9c9aSAl Cooper 377b0c0b66cSAl Cooper if (!params->wake_enabled) 3784e5b9c9aSAl Cooper xhci_soft_reset(params, 1); 3794e5b9c9aSAl Cooper } 3804e5b9c9aSAl Cooper 3814e5b9c9aSAl Cooper static int usb_get_dual_select(struct brcm_usb_init_params *params) 3824e5b9c9aSAl Cooper { 3839d5f51dcSAl Cooper void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; 3844e5b9c9aSAl Cooper u32 reg = 0; 3854e5b9c9aSAl Cooper 3864e5b9c9aSAl Cooper pr_debug("%s\n", __func__); 3874e5b9c9aSAl Cooper 3884e5b9c9aSAl Cooper reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1)); 3894e5b9c9aSAl Cooper reg &= USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE); 3904e5b9c9aSAl Cooper return reg; 3914e5b9c9aSAl Cooper } 3924e5b9c9aSAl Cooper 39332fb07f3SJustin Chen static void usb_set_dual_select(struct brcm_usb_init_params *params) 3944e5b9c9aSAl Cooper { 3959d5f51dcSAl Cooper void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; 3964e5b9c9aSAl Cooper u32 reg; 3974e5b9c9aSAl Cooper 3984e5b9c9aSAl Cooper pr_debug("%s\n", __func__); 3994e5b9c9aSAl Cooper 4004e5b9c9aSAl Cooper reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1)); 4014e5b9c9aSAl Cooper reg &= ~USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE); 40232fb07f3SJustin Chen reg |= params->port_mode; 4034e5b9c9aSAl Cooper brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1)); 4044e5b9c9aSAl Cooper } 4054e5b9c9aSAl Cooper 4064e5b9c9aSAl Cooper static const struct brcm_usb_init_ops bcm7216_ops = { 4074e5b9c9aSAl Cooper .init_ipp = usb_init_ipp, 408ae532b2bSAl Cooper .init_common = usb_init_common_7216, 4094e5b9c9aSAl Cooper .init_xhci = usb_init_xhci, 410ae532b2bSAl Cooper .uninit_common = usb_uninit_common_7216, 4114e5b9c9aSAl Cooper .uninit_xhci = usb_uninit_xhci, 4124e5b9c9aSAl Cooper .get_dual_select = usb_get_dual_select, 4134e5b9c9aSAl Cooper .set_dual_select = usb_set_dual_select, 4144e5b9c9aSAl Cooper }; 4154e5b9c9aSAl Cooper 4169d5f51dcSAl Cooper static const struct brcm_usb_init_ops bcm7211b0_ops = { 4179d5f51dcSAl Cooper .init_ipp = usb_init_ipp, 4189d5f51dcSAl Cooper .init_common = usb_init_common_7211b0, 4199d5f51dcSAl Cooper .init_xhci = usb_init_xhci, 420b0c0b66cSAl Cooper .uninit_common = usb_uninit_common_7211b0, 4219d5f51dcSAl Cooper .uninit_xhci = usb_uninit_xhci, 4229d5f51dcSAl Cooper .get_dual_select = usb_get_dual_select, 4239d5f51dcSAl Cooper .set_dual_select = usb_set_dual_select, 4249d5f51dcSAl Cooper }; 4259d5f51dcSAl Cooper 4264e5b9c9aSAl Cooper void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params) 4274e5b9c9aSAl Cooper { 4284e5b9c9aSAl Cooper 4294e5b9c9aSAl Cooper pr_debug("%s\n", __func__); 4304e5b9c9aSAl Cooper 4314e5b9c9aSAl Cooper params->family_name = "7216"; 4324e5b9c9aSAl Cooper params->ops = &bcm7216_ops; 433ae532b2bSAl Cooper params->suspend_with_clocks = true; 4344e5b9c9aSAl Cooper } 4359d5f51dcSAl Cooper 4369d5f51dcSAl Cooper void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params) 4379d5f51dcSAl Cooper { 4389d5f51dcSAl Cooper 4399d5f51dcSAl Cooper pr_debug("%s\n", __func__); 4409d5f51dcSAl Cooper 4419d5f51dcSAl Cooper params->family_name = "7211"; 4429d5f51dcSAl Cooper params->ops = &bcm7211b0_ops; 443b0c0b66cSAl Cooper params->suspend_with_clocks = true; 4449d5f51dcSAl Cooper } 445