xref: /openbmc/linux/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c (revision 700c44b508020a3ea29d297c677f8d4ab14b7e6a)
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