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)
62*5095d045SJustin Chen #define USB_CTRL_P0_U2PHY_CFG1		0x68
63*5095d045SJustin Chen #define   USB_CTRL_P0_U2PHY_CFG1_COMMONONN_MASK		BIT(10)
644e5b9c9aSAl Cooper 
659d5f51dcSAl Cooper /* Register definitions for the USB_PHY block in 7211b0 */
66b0c0b66cSAl Cooper #define USB_PHY_PLL_CTL			0x00
67833c173eSJustin Chen #define   USB_PHY_PLL_CTL_PLL_SUSPEND_MASK		BIT(27)
687e81153dSJustin Chen #define   USB_PHY_PLL_CTL_PLL_RESETB_MASK		BIT(30)
699d5f51dcSAl Cooper #define USB_PHY_PLL_LDO_CTL		0x08
707e81153dSJustin Chen #define   USB_PHY_PLL_LDO_CTL_AFE_BG_PWRDWNB_MASK	BIT(0)
717e81153dSJustin Chen #define   USB_PHY_PLL_LDO_CTL_AFE_LDO_PWRDWNB_MASK	BIT(1)
727e81153dSJustin Chen #define   USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK		BIT(2)
739d5f51dcSAl Cooper #define USB_PHY_UTMI_CTL_1		0x04
747e81153dSJustin Chen #define   USB_PHY_UTMI_CTL_1_PHY_MODE_MASK		GENMASK(3, 2)
759d5f51dcSAl Cooper #define   USB_PHY_UTMI_CTL_1_PHY_MODE_SHIFT		2
767e81153dSJustin Chen #define   USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK	BIT(11)
77b0c0b66cSAl Cooper #define USB_PHY_IDDQ			0x1c
787e81153dSJustin Chen #define   USB_PHY_IDDQ_phy_iddq_MASK			BIT(0)
799d5f51dcSAl Cooper #define USB_PHY_STATUS			0x20
807e81153dSJustin Chen #define   USB_PHY_STATUS_pll_lock_MASK			BIT(0)
819d5f51dcSAl Cooper 
829d5f51dcSAl Cooper /* Register definitions for the MDIO registers in the DWC2 block of
839d5f51dcSAl Cooper  * the 7211b0.
849d5f51dcSAl Cooper  * NOTE: The PHY's MDIO registers are only accessible through the
859d5f51dcSAl Cooper  * legacy DesignWare USB controller even though it's not being used.
869d5f51dcSAl Cooper  */
879d5f51dcSAl Cooper #define USB_GMDIOCSR	0
889d5f51dcSAl Cooper #define USB_GMDIOGEN	4
899d5f51dcSAl Cooper 
90bed63b63SAl Cooper /* Register definitions for the BDC EC block in 7211b0 */
91bed63b63SAl Cooper #define BDC_EC_AXIRDA			0x0c
927e81153dSJustin Chen #define   BDC_EC_AXIRDA_RTS_MASK			GENMASK(31, 28)
93bed63b63SAl Cooper #define   BDC_EC_AXIRDA_RTS_SHIFT			28
94bed63b63SAl Cooper 
95*5095d045SJustin Chen #define USB_XHCI_GBL_GUSB2PHYCFG	0x100
96*5095d045SJustin Chen #define   USB_XHCI_GBL_GUSB2PHYCFG_U2_FREECLK_EXISTS_MASK	BIT(30)
979d5f51dcSAl Cooper 
usb_mdio_write_7211b0(struct brcm_usb_init_params * params,uint8_t addr,uint16_t data)989d5f51dcSAl Cooper static void usb_mdio_write_7211b0(struct brcm_usb_init_params *params,
999d5f51dcSAl Cooper 				  uint8_t addr, uint16_t data)
1009d5f51dcSAl Cooper {
1019d5f51dcSAl Cooper 	void __iomem *usb_mdio = params->regs[BRCM_REGS_USB_MDIO];
1029d5f51dcSAl Cooper 
1039d5f51dcSAl Cooper 	addr &= 0x1f; /* 5-bit address */
1049d5f51dcSAl Cooper 	brcm_usb_writel(0xffffffff, usb_mdio + USB_GMDIOGEN);
1059d5f51dcSAl Cooper 	while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
1069d5f51dcSAl Cooper 		;
1079d5f51dcSAl Cooper 	brcm_usb_writel(0x59020000 | (addr << 18) | data,
1089d5f51dcSAl Cooper 			usb_mdio + USB_GMDIOGEN);
1099d5f51dcSAl Cooper 	while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
1109d5f51dcSAl Cooper 		;
1119d5f51dcSAl Cooper 	brcm_usb_writel(0x00000000, usb_mdio + USB_GMDIOGEN);
1129d5f51dcSAl Cooper 	while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
1139d5f51dcSAl Cooper 		;
1149d5f51dcSAl Cooper }
1159d5f51dcSAl Cooper 
usb_mdio_read_7211b0(struct brcm_usb_init_params * params,uint8_t addr)1169d5f51dcSAl Cooper static uint16_t __maybe_unused usb_mdio_read_7211b0(
1179d5f51dcSAl Cooper 	struct brcm_usb_init_params *params, uint8_t addr)
1189d5f51dcSAl Cooper {
1199d5f51dcSAl Cooper 	void __iomem *usb_mdio = params->regs[BRCM_REGS_USB_MDIO];
1209d5f51dcSAl Cooper 
1219d5f51dcSAl Cooper 	addr &= 0x1f; /* 5-bit address */
1229d5f51dcSAl Cooper 	brcm_usb_writel(0xffffffff, usb_mdio + USB_GMDIOGEN);
1239d5f51dcSAl Cooper 	while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
1249d5f51dcSAl Cooper 		;
1259d5f51dcSAl Cooper 	brcm_usb_writel(0x69020000 | (addr << 18), usb_mdio + USB_GMDIOGEN);
1269d5f51dcSAl Cooper 	while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
1279d5f51dcSAl Cooper 		;
1289d5f51dcSAl Cooper 	brcm_usb_writel(0x00000000, usb_mdio + USB_GMDIOGEN);
1299d5f51dcSAl Cooper 	while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
1309d5f51dcSAl Cooper 		;
1319d5f51dcSAl Cooper 	return brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & 0xffff;
1329d5f51dcSAl Cooper }
1339d5f51dcSAl Cooper 
usb2_eye_fix_7211b0(struct brcm_usb_init_params * params)1349d5f51dcSAl Cooper static void usb2_eye_fix_7211b0(struct brcm_usb_init_params *params)
1359d5f51dcSAl Cooper {
1369d5f51dcSAl Cooper 	/* select bank */
1379d5f51dcSAl Cooper 	usb_mdio_write_7211b0(params, 0x1f, 0x80a0);
1389d5f51dcSAl Cooper 
1399d5f51dcSAl Cooper 	/* Set the eye */
1409d5f51dcSAl Cooper 	usb_mdio_write_7211b0(params, 0x0a, 0xc6a0);
1419d5f51dcSAl Cooper }
1424e5b9c9aSAl Cooper 
xhci_soft_reset(struct brcm_usb_init_params * params,int on_off)1434e5b9c9aSAl Cooper static void xhci_soft_reset(struct brcm_usb_init_params *params,
1444e5b9c9aSAl Cooper 			int on_off)
1454e5b9c9aSAl Cooper {
1469d5f51dcSAl Cooper 	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
147*5095d045SJustin Chen 	void __iomem *xhci_gbl = params->regs[BRCM_REGS_XHCI_GBL];
1484e5b9c9aSAl Cooper 
1494e5b9c9aSAl Cooper 	/* Assert reset */
150*5095d045SJustin Chen 	if (on_off) {
1514e5b9c9aSAl Cooper 		USB_CTRL_UNSET(ctrl, USB_PM, XHC_SOFT_RESETB);
1524e5b9c9aSAl Cooper 	/* De-assert reset */
153*5095d045SJustin Chen 	} else {
1544e5b9c9aSAl Cooper 		USB_CTRL_SET(ctrl, USB_PM, XHC_SOFT_RESETB);
155*5095d045SJustin Chen 		/* Required for COMMONONN to be set */
156*5095d045SJustin Chen 		USB_XHCI_GBL_UNSET(xhci_gbl, GUSB2PHYCFG, U2_FREECLK_EXISTS);
157*5095d045SJustin Chen 	}
1584e5b9c9aSAl Cooper }
1594e5b9c9aSAl Cooper 
usb_init_ipp(struct brcm_usb_init_params * params)1604e5b9c9aSAl Cooper static void usb_init_ipp(struct brcm_usb_init_params *params)
1614e5b9c9aSAl Cooper {
1629d5f51dcSAl Cooper 	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
1634e5b9c9aSAl Cooper 	u32 reg;
1644e5b9c9aSAl Cooper 	u32 orig_reg;
1654e5b9c9aSAl Cooper 
1664e5b9c9aSAl Cooper 	pr_debug("%s\n", __func__);
1674e5b9c9aSAl Cooper 
1684e5b9c9aSAl Cooper 	orig_reg = reg = brcm_usb_readl(USB_CTRL_REG(ctrl, SETUP));
1694e5b9c9aSAl Cooper 	if (params->ipp != 2)
1704e5b9c9aSAl Cooper 		/* override ipp strap pin (if it exits) */
1714e5b9c9aSAl Cooper 		reg &= ~(USB_CTRL_MASK(SETUP, STRAP_IPP_SEL));
1724e5b9c9aSAl Cooper 
1734e5b9c9aSAl Cooper 	/* Override the default OC and PP polarity */
1744e5b9c9aSAl Cooper 	reg &= ~(USB_CTRL_MASK(SETUP, IPP) | USB_CTRL_MASK(SETUP, IOC));
1754e5b9c9aSAl Cooper 	if (params->ioc)
1764e5b9c9aSAl Cooper 		reg |= USB_CTRL_MASK(SETUP, IOC);
1774e5b9c9aSAl Cooper 	if (params->ipp == 1)
1784e5b9c9aSAl Cooper 		reg |= USB_CTRL_MASK(SETUP, IPP);
1794e5b9c9aSAl Cooper 	brcm_usb_writel(reg, USB_CTRL_REG(ctrl, SETUP));
1804e5b9c9aSAl Cooper 
1814e5b9c9aSAl Cooper 	/*
1824e5b9c9aSAl Cooper 	 * If we're changing IPP, make sure power is off long enough
1834e5b9c9aSAl Cooper 	 * to turn off any connected devices.
1844e5b9c9aSAl Cooper 	 */
1854e5b9c9aSAl Cooper 	if ((reg ^ orig_reg) & USB_CTRL_MASK(SETUP, IPP))
1864e5b9c9aSAl Cooper 		msleep(50);
1874e5b9c9aSAl Cooper }
1884e5b9c9aSAl Cooper 
syscon_piarbctl_init(struct regmap * rmap)1899d5f51dcSAl Cooper static void syscon_piarbctl_init(struct regmap *rmap)
1909d5f51dcSAl Cooper {
1919d5f51dcSAl Cooper 	/* Switch from legacy USB OTG controller to new STB USB controller */
1929d5f51dcSAl Cooper 	regmap_update_bits(rmap, PIARBCTL_MISC, PIARBCTL_MISC_USB_ONLY_MASK,
1939d5f51dcSAl Cooper 			   PIARBCTL_MISC_USB_SELECT_MASK |
1949d5f51dcSAl Cooper 			   PIARBCTL_MISC_USB_4G_SDRAM_MASK);
1959d5f51dcSAl Cooper }
1969d5f51dcSAl Cooper 
usb_init_common(struct brcm_usb_init_params * params)1974e5b9c9aSAl Cooper static void usb_init_common(struct brcm_usb_init_params *params)
1984e5b9c9aSAl Cooper {
1994e5b9c9aSAl Cooper 	u32 reg;
2009d5f51dcSAl Cooper 	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
2014e5b9c9aSAl Cooper 
2024e5b9c9aSAl Cooper 	pr_debug("%s\n", __func__);
2034e5b9c9aSAl Cooper 
2044e5b9c9aSAl Cooper 	if (USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE)) {
2054e5b9c9aSAl Cooper 		reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
2064e5b9c9aSAl Cooper 		reg &= ~USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
20732fb07f3SJustin Chen 		reg |= params->port_mode;
2084e5b9c9aSAl Cooper 		brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
2094e5b9c9aSAl Cooper 	}
21032fb07f3SJustin Chen 	switch (params->supported_port_modes) {
2114e5b9c9aSAl Cooper 	case USB_CTLR_MODE_HOST:
2124e5b9c9aSAl Cooper 		USB_CTRL_UNSET(ctrl, USB_PM, BDC_SOFT_RESETB);
2134e5b9c9aSAl Cooper 		break;
2144e5b9c9aSAl Cooper 	default:
2154e5b9c9aSAl Cooper 		USB_CTRL_UNSET(ctrl, USB_PM, BDC_SOFT_RESETB);
2164e5b9c9aSAl Cooper 		USB_CTRL_SET(ctrl, USB_PM, BDC_SOFT_RESETB);
2174e5b9c9aSAl Cooper 		break;
2184e5b9c9aSAl Cooper 	}
2194e5b9c9aSAl Cooper }
2204e5b9c9aSAl Cooper 
usb_wake_enable_7211b0(struct brcm_usb_init_params * params,bool enable)221b0c0b66cSAl Cooper static void usb_wake_enable_7211b0(struct brcm_usb_init_params *params,
222b0c0b66cSAl Cooper 				   bool enable)
223b0c0b66cSAl Cooper {
224b0c0b66cSAl Cooper 	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
225b0c0b66cSAl Cooper 
226b0c0b66cSAl Cooper 	if (enable)
227b0c0b66cSAl Cooper 		USB_CTRL_SET(ctrl, CTLR_CSHCR, ctl_pme_en);
228b0c0b66cSAl Cooper 	else
229b0c0b66cSAl Cooper 		USB_CTRL_UNSET(ctrl, CTLR_CSHCR, ctl_pme_en);
230b0c0b66cSAl Cooper }
231b0c0b66cSAl Cooper 
usb_wake_enable_7216(struct brcm_usb_init_params * params,bool enable)232ae532b2bSAl Cooper static void usb_wake_enable_7216(struct brcm_usb_init_params *params,
233ae532b2bSAl Cooper 				 bool enable)
234ae532b2bSAl Cooper {
235ae532b2bSAl Cooper 	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
236ae532b2bSAl Cooper 
237ae532b2bSAl Cooper 	if (enable)
238ae532b2bSAl Cooper 		USB_CTRL_SET(ctrl, USB_PM, XHC_PME_EN);
239ae532b2bSAl Cooper 	else
240ae532b2bSAl Cooper 		USB_CTRL_UNSET(ctrl, USB_PM, XHC_PME_EN);
241ae532b2bSAl Cooper }
242ae532b2bSAl Cooper 
usb_init_common_7211b0(struct brcm_usb_init_params * params)2439d5f51dcSAl Cooper static void usb_init_common_7211b0(struct brcm_usb_init_params *params)
2449d5f51dcSAl Cooper {
2459d5f51dcSAl Cooper 	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
2469d5f51dcSAl Cooper 	void __iomem *usb_phy = params->regs[BRCM_REGS_USB_PHY];
247bed63b63SAl Cooper 	void __iomem *bdc_ec = params->regs[BRCM_REGS_BDC_EC];
2489d5f51dcSAl Cooper 	int timeout_ms = PHY_LOCK_TIMEOUT_MS;
2499d5f51dcSAl Cooper 	u32 reg;
2509d5f51dcSAl Cooper 
2519d5f51dcSAl Cooper 	if (params->syscon_piarbctl)
2529d5f51dcSAl Cooper 		syscon_piarbctl_init(params->syscon_piarbctl);
2539d5f51dcSAl Cooper 
254b0c0b66cSAl Cooper 	USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN);
255b0c0b66cSAl Cooper 
256b0c0b66cSAl Cooper 	usb_wake_enable_7211b0(params, false);
257b0c0b66cSAl Cooper 	if (!params->wake_enabled) {
258b0c0b66cSAl Cooper 
259b0c0b66cSAl Cooper 		/* undo possible suspend settings */
260b0c0b66cSAl Cooper 		brcm_usb_writel(0, usb_phy + USB_PHY_IDDQ);
261b0c0b66cSAl Cooper 		reg = brcm_usb_readl(usb_phy + USB_PHY_PLL_CTL);
262b0c0b66cSAl Cooper 		reg |= USB_PHY_PLL_CTL_PLL_RESETB_MASK;
263b0c0b66cSAl Cooper 		brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_CTL);
264b0c0b66cSAl Cooper 
265b0c0b66cSAl Cooper 		/* temporarily enable FSM so PHY comes up properly */
266b0c0b66cSAl Cooper 		reg = brcm_usb_readl(usb_phy + USB_PHY_UTMI_CTL_1);
267b0c0b66cSAl Cooper 		reg |= USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK;
268b0c0b66cSAl Cooper 		brcm_usb_writel(reg, usb_phy + USB_PHY_UTMI_CTL_1);
269b0c0b66cSAl Cooper 	}
270b0c0b66cSAl Cooper 
271833c173eSJustin Chen 	/* Disable PLL auto suspend */
272833c173eSJustin Chen 	reg = brcm_usb_readl(usb_phy + USB_PHY_PLL_CTL);
273833c173eSJustin Chen 	reg |= USB_PHY_PLL_CTL_PLL_SUSPEND_MASK;
274833c173eSJustin Chen 	brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_CTL);
275833c173eSJustin Chen 
2769d5f51dcSAl Cooper 	/* Init the PHY */
277b0c0b66cSAl Cooper 	reg = USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK |
278b0c0b66cSAl Cooper 		USB_PHY_PLL_LDO_CTL_AFE_LDO_PWRDWNB_MASK |
279b0c0b66cSAl Cooper 		USB_PHY_PLL_LDO_CTL_AFE_BG_PWRDWNB_MASK;
2809d5f51dcSAl Cooper 	brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_LDO_CTL);
2819d5f51dcSAl Cooper 
2829d5f51dcSAl Cooper 	/* wait for lock */
2839d5f51dcSAl Cooper 	while (timeout_ms-- > 0) {
2849d5f51dcSAl Cooper 		reg = brcm_usb_readl(usb_phy + USB_PHY_STATUS);
2859d5f51dcSAl Cooper 		if (reg & USB_PHY_STATUS_pll_lock_MASK)
2869d5f51dcSAl Cooper 			break;
2879d5f51dcSAl Cooper 		usleep_range(1000, 2000);
2889d5f51dcSAl Cooper 	}
2899d5f51dcSAl Cooper 
2909d5f51dcSAl Cooper 	/* Set the PHY_MODE */
2919d5f51dcSAl Cooper 	reg = brcm_usb_readl(usb_phy + USB_PHY_UTMI_CTL_1);
2929d5f51dcSAl Cooper 	reg &= ~USB_PHY_UTMI_CTL_1_PHY_MODE_MASK;
29332fb07f3SJustin Chen 	reg |= params->supported_port_modes << USB_PHY_UTMI_CTL_1_PHY_MODE_SHIFT;
2949d5f51dcSAl Cooper 	brcm_usb_writel(reg, usb_phy + USB_PHY_UTMI_CTL_1);
2959d5f51dcSAl Cooper 
2969d5f51dcSAl Cooper 	usb_init_common(params);
2979d5f51dcSAl Cooper 
298fc430aeaSAl Cooper 	/*
299bed63b63SAl Cooper 	 * The BDC controller will get occasional failures with
300bed63b63SAl Cooper 	 * the default "Read Transaction Size" of 6 (1024 bytes).
301bed63b63SAl Cooper 	 * Set it to 4 (256 bytes).
302bed63b63SAl Cooper 	 */
30332fb07f3SJustin Chen 	if ((params->supported_port_modes != USB_CTLR_MODE_HOST) && bdc_ec) {
304bed63b63SAl Cooper 		reg = brcm_usb_readl(bdc_ec + BDC_EC_AXIRDA);
305bed63b63SAl Cooper 		reg &= ~BDC_EC_AXIRDA_RTS_MASK;
306bed63b63SAl Cooper 		reg |= (0x4 << BDC_EC_AXIRDA_RTS_SHIFT);
307bed63b63SAl Cooper 		brcm_usb_writel(reg, bdc_ec + BDC_EC_AXIRDA);
308bed63b63SAl Cooper 	}
309bed63b63SAl Cooper 
310bed63b63SAl Cooper 	/*
311fc430aeaSAl Cooper 	 * Disable FSM, otherwise the PHY will auto suspend when no
312fc430aeaSAl Cooper 	 * device is connected and will be reset on resume.
313fc430aeaSAl Cooper 	 */
314fc430aeaSAl Cooper 	reg = brcm_usb_readl(usb_phy + USB_PHY_UTMI_CTL_1);
315fc430aeaSAl Cooper 	reg &= ~USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK;
316fc430aeaSAl Cooper 	brcm_usb_writel(reg, usb_phy + USB_PHY_UTMI_CTL_1);
317fc430aeaSAl Cooper 
3189d5f51dcSAl Cooper 	usb2_eye_fix_7211b0(params);
3199d5f51dcSAl Cooper }
3209d5f51dcSAl Cooper 
usb_init_common_7216(struct brcm_usb_init_params * params)321ae532b2bSAl Cooper static void usb_init_common_7216(struct brcm_usb_init_params *params)
322ae532b2bSAl Cooper {
323ae532b2bSAl Cooper 	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
324ae532b2bSAl Cooper 
325ae532b2bSAl Cooper 	USB_CTRL_UNSET(ctrl, USB_PM, XHC_S2_CLK_SWITCH_EN);
326ae532b2bSAl Cooper 	USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN);
327ae532b2bSAl Cooper 
328ae532b2bSAl Cooper 	/* 1 millisecond - for USB clocks to settle down */
329ae532b2bSAl Cooper 	usleep_range(1000, 2000);
330ae532b2bSAl Cooper 
331*5095d045SJustin Chen 	/* Disable PHY when port is suspended */
332*5095d045SJustin Chen 	USB_CTRL_SET(ctrl, P0_U2PHY_CFG1, COMMONONN);
333*5095d045SJustin Chen 
334ae532b2bSAl Cooper 	usb_wake_enable_7216(params, false);
335ae532b2bSAl Cooper 	usb_init_common(params);
336ae532b2bSAl Cooper }
337ae532b2bSAl Cooper 
usb_init_xhci(struct brcm_usb_init_params * params)3384e5b9c9aSAl Cooper static void usb_init_xhci(struct brcm_usb_init_params *params)
3394e5b9c9aSAl Cooper {
3404e5b9c9aSAl Cooper 	pr_debug("%s\n", __func__);
3414e5b9c9aSAl Cooper 
3424e5b9c9aSAl Cooper 	xhci_soft_reset(params, 0);
3434e5b9c9aSAl Cooper }
3444e5b9c9aSAl Cooper 
usb_uninit_common_7216(struct brcm_usb_init_params * params)345ae532b2bSAl Cooper static void usb_uninit_common_7216(struct brcm_usb_init_params *params)
3464e5b9c9aSAl Cooper {
3479d5f51dcSAl Cooper 	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
3484e5b9c9aSAl Cooper 
3494e5b9c9aSAl Cooper 	pr_debug("%s\n", __func__);
3504e5b9c9aSAl Cooper 
351700c44b5SJustin Chen 	if (params->wake_enabled) {
352ae532b2bSAl Cooper 		/* Switch to using slower clock during suspend to save power */
353ae532b2bSAl Cooper 		USB_CTRL_SET(ctrl, USB_PM, XHC_S2_CLK_SWITCH_EN);
354ae532b2bSAl Cooper 		usb_wake_enable_7216(params, true);
355700c44b5SJustin Chen 	} else {
356700c44b5SJustin Chen 		USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
357ae532b2bSAl Cooper 	}
3584e5b9c9aSAl Cooper }
3594e5b9c9aSAl Cooper 
usb_uninit_common_7211b0(struct brcm_usb_init_params * params)360b0c0b66cSAl Cooper static void usb_uninit_common_7211b0(struct brcm_usb_init_params *params)
361b0c0b66cSAl Cooper {
362b0c0b66cSAl Cooper 	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
363b0c0b66cSAl Cooper 	void __iomem *usb_phy = params->regs[BRCM_REGS_USB_PHY];
364b0c0b66cSAl Cooper 	u32 reg;
365b0c0b66cSAl Cooper 
366b0c0b66cSAl Cooper 	pr_debug("%s\n", __func__);
367b0c0b66cSAl Cooper 
368b0c0b66cSAl Cooper 	if (params->wake_enabled) {
369b0c0b66cSAl Cooper 		USB_CTRL_SET(ctrl, TEST_PORT_CTL, TPOUT_SEL_PME_GEN);
370b0c0b66cSAl Cooper 		usb_wake_enable_7211b0(params, true);
371b0c0b66cSAl Cooper 	} else {
372b0c0b66cSAl Cooper 		USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
373b0c0b66cSAl Cooper 		brcm_usb_writel(0, usb_phy + USB_PHY_PLL_LDO_CTL);
374b0c0b66cSAl Cooper 		reg = brcm_usb_readl(usb_phy + USB_PHY_PLL_CTL);
375b0c0b66cSAl Cooper 		reg &= ~USB_PHY_PLL_CTL_PLL_RESETB_MASK;
376b0c0b66cSAl Cooper 		brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_CTL);
377b0c0b66cSAl Cooper 		brcm_usb_writel(USB_PHY_IDDQ_phy_iddq_MASK,
378b0c0b66cSAl Cooper 				usb_phy + USB_PHY_IDDQ);
379b0c0b66cSAl Cooper 	}
380b0c0b66cSAl Cooper 
381b0c0b66cSAl Cooper }
382b0c0b66cSAl Cooper 
usb_uninit_xhci(struct brcm_usb_init_params * params)3834e5b9c9aSAl Cooper static void usb_uninit_xhci(struct brcm_usb_init_params *params)
3844e5b9c9aSAl Cooper {
3854e5b9c9aSAl Cooper 
3864e5b9c9aSAl Cooper 	pr_debug("%s\n", __func__);
3874e5b9c9aSAl Cooper 
388b0c0b66cSAl Cooper 	if (!params->wake_enabled)
3894e5b9c9aSAl Cooper 		xhci_soft_reset(params, 1);
3904e5b9c9aSAl Cooper }
3914e5b9c9aSAl Cooper 
usb_get_dual_select(struct brcm_usb_init_params * params)3924e5b9c9aSAl Cooper static int usb_get_dual_select(struct brcm_usb_init_params *params)
3934e5b9c9aSAl Cooper {
3949d5f51dcSAl Cooper 	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
3954e5b9c9aSAl Cooper 	u32 reg = 0;
3964e5b9c9aSAl Cooper 
3974e5b9c9aSAl Cooper 	pr_debug("%s\n", __func__);
3984e5b9c9aSAl Cooper 
3994e5b9c9aSAl Cooper 	reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
4004e5b9c9aSAl Cooper 	reg &= USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
4014e5b9c9aSAl Cooper 	return reg;
4024e5b9c9aSAl Cooper }
4034e5b9c9aSAl Cooper 
usb_set_dual_select(struct brcm_usb_init_params * params)40432fb07f3SJustin Chen static void usb_set_dual_select(struct brcm_usb_init_params *params)
4054e5b9c9aSAl Cooper {
4069d5f51dcSAl Cooper 	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
4074e5b9c9aSAl Cooper 	u32 reg;
4084e5b9c9aSAl Cooper 
4094e5b9c9aSAl Cooper 	pr_debug("%s\n", __func__);
4104e5b9c9aSAl Cooper 
4114e5b9c9aSAl Cooper 	reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
4124e5b9c9aSAl Cooper 	reg &= ~USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
41332fb07f3SJustin Chen 	reg |= params->port_mode;
4144e5b9c9aSAl Cooper 	brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
4154e5b9c9aSAl Cooper }
4164e5b9c9aSAl Cooper 
4174e5b9c9aSAl Cooper static const struct brcm_usb_init_ops bcm7216_ops = {
4184e5b9c9aSAl Cooper 	.init_ipp = usb_init_ipp,
419ae532b2bSAl Cooper 	.init_common = usb_init_common_7216,
4204e5b9c9aSAl Cooper 	.init_xhci = usb_init_xhci,
421ae532b2bSAl Cooper 	.uninit_common = usb_uninit_common_7216,
4224e5b9c9aSAl Cooper 	.uninit_xhci = usb_uninit_xhci,
4234e5b9c9aSAl Cooper 	.get_dual_select = usb_get_dual_select,
4244e5b9c9aSAl Cooper 	.set_dual_select = usb_set_dual_select,
4254e5b9c9aSAl Cooper };
4264e5b9c9aSAl Cooper 
4279d5f51dcSAl Cooper static const struct brcm_usb_init_ops bcm7211b0_ops = {
4289d5f51dcSAl Cooper 	.init_ipp = usb_init_ipp,
4299d5f51dcSAl Cooper 	.init_common = usb_init_common_7211b0,
4309d5f51dcSAl Cooper 	.init_xhci = usb_init_xhci,
431b0c0b66cSAl Cooper 	.uninit_common = usb_uninit_common_7211b0,
4329d5f51dcSAl Cooper 	.uninit_xhci = usb_uninit_xhci,
4339d5f51dcSAl Cooper 	.get_dual_select = usb_get_dual_select,
4349d5f51dcSAl Cooper 	.set_dual_select = usb_set_dual_select,
4359d5f51dcSAl Cooper };
4369d5f51dcSAl Cooper 
brcm_usb_dvr_init_7216(struct brcm_usb_init_params * params)4374e5b9c9aSAl Cooper void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params)
4384e5b9c9aSAl Cooper {
4394e5b9c9aSAl Cooper 
4404e5b9c9aSAl Cooper 	pr_debug("%s\n", __func__);
4414e5b9c9aSAl Cooper 
4424e5b9c9aSAl Cooper 	params->family_name = "7216";
4434e5b9c9aSAl Cooper 	params->ops = &bcm7216_ops;
4444e5b9c9aSAl Cooper }
4459d5f51dcSAl Cooper 
brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params * params)4469d5f51dcSAl Cooper void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params)
4479d5f51dcSAl Cooper {
4489d5f51dcSAl Cooper 
4499d5f51dcSAl Cooper 	pr_debug("%s\n", __func__);
4509d5f51dcSAl Cooper 
4519d5f51dcSAl Cooper 	params->family_name = "7211";
4529d5f51dcSAl Cooper 	params->ops = &bcm7211b0_ops;
4539d5f51dcSAl Cooper }
454