18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (c) 2018, Broadcom */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci/*
58c2ecf20Sopenharmony_ci * This module contains USB PHY initialization for power up and S3 resume
68c2ecf20Sopenharmony_ci * for newer Synopsys based USB hardware first used on the bcm7216.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/delay.h>
108c2ecf20Sopenharmony_ci#include <linux/io.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/soc/brcmstb/brcmstb.h>
138c2ecf20Sopenharmony_ci#include "phy-brcm-usb-init.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define PHY_LOCK_TIMEOUT_MS 200
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/* Register definitions for syscon piarbctl registers */
188c2ecf20Sopenharmony_ci#define PIARBCTL_CAM			0x00
198c2ecf20Sopenharmony_ci#define PIARBCTL_SPLITTER		0x04
208c2ecf20Sopenharmony_ci#define PIARBCTL_MISC			0x08
218c2ecf20Sopenharmony_ci#define   PIARBCTL_MISC_SECURE_MASK			0x80000000
228c2ecf20Sopenharmony_ci#define   PIARBCTL_MISC_USB_SELECT_MASK			0x40000000
238c2ecf20Sopenharmony_ci#define   PIARBCTL_MISC_USB_4G_SDRAM_MASK		0x20000000
248c2ecf20Sopenharmony_ci#define   PIARBCTL_MISC_USB_PRIORITY_MASK		0x000f0000
258c2ecf20Sopenharmony_ci#define   PIARBCTL_MISC_USB_MEM_PAGE_MASK		0x0000f000
268c2ecf20Sopenharmony_ci#define   PIARBCTL_MISC_CAM1_MEM_PAGE_MASK		0x00000f00
278c2ecf20Sopenharmony_ci#define   PIARBCTL_MISC_CAM0_MEM_PAGE_MASK		0x000000f0
288c2ecf20Sopenharmony_ci#define   PIARBCTL_MISC_SATA_PRIORITY_MASK		0x0000000f
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define PIARBCTL_MISC_USB_ONLY_MASK		\
318c2ecf20Sopenharmony_ci	(PIARBCTL_MISC_USB_SELECT_MASK |	\
328c2ecf20Sopenharmony_ci	 PIARBCTL_MISC_USB_4G_SDRAM_MASK |	\
338c2ecf20Sopenharmony_ci	 PIARBCTL_MISC_USB_PRIORITY_MASK |	\
348c2ecf20Sopenharmony_ci	 PIARBCTL_MISC_USB_MEM_PAGE_MASK)
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* Register definitions for the USB CTRL block */
378c2ecf20Sopenharmony_ci#define USB_CTRL_SETUP			0x00
388c2ecf20Sopenharmony_ci#define   USB_CTRL_SETUP_STRAP_IPP_SEL_MASK		0x02000000
398c2ecf20Sopenharmony_ci#define   USB_CTRL_SETUP_SCB2_EN_MASK			0x00008000
408c2ecf20Sopenharmony_ci#define   USB_CTRL_SETUP_tca_drv_sel_MASK		0x01000000
418c2ecf20Sopenharmony_ci#define   USB_CTRL_SETUP_SCB1_EN_MASK			0x00004000
428c2ecf20Sopenharmony_ci#define   USB_CTRL_SETUP_SOFT_SHUTDOWN_MASK		0x00000200
438c2ecf20Sopenharmony_ci#define   USB_CTRL_SETUP_IPP_MASK			0x00000020
448c2ecf20Sopenharmony_ci#define   USB_CTRL_SETUP_IOC_MASK			0x00000010
458c2ecf20Sopenharmony_ci#define USB_CTRL_USB_PM			0x04
468c2ecf20Sopenharmony_ci#define   USB_CTRL_USB_PM_USB_PWRDN_MASK		0x80000000
478c2ecf20Sopenharmony_ci#define   USB_CTRL_USB_PM_SOFT_RESET_MASK		0x40000000
488c2ecf20Sopenharmony_ci#define   USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK		0x00800000
498c2ecf20Sopenharmony_ci#define   USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK		0x00400000
508c2ecf20Sopenharmony_ci#define USB_CTRL_USB_PM_STATUS		0x08
518c2ecf20Sopenharmony_ci#define USB_CTRL_USB_DEVICE_CTL1	0x10
528c2ecf20Sopenharmony_ci#define   USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK	0x00000003
538c2ecf20Sopenharmony_ci#define USB_CTRL_TEST_PORT_CTL		0x30
548c2ecf20Sopenharmony_ci#define   USB_CTRL_TEST_PORT_CTL_TPOUT_SEL_MASK	0x000000ff
558c2ecf20Sopenharmony_ci#define   USB_CTRL_TEST_PORT_CTL_TPOUT_SEL_PME_GEN_MASK	0x0000002e
568c2ecf20Sopenharmony_ci#define USB_CTRL_TP_DIAG1		0x34
578c2ecf20Sopenharmony_ci#define   USB_CTLR_TP_DIAG1_wake_MASK	0x00000002
588c2ecf20Sopenharmony_ci#define USB_CTRL_CTLR_CSHCR		0x50
598c2ecf20Sopenharmony_ci#define   USB_CTRL_CTLR_CSHCR_ctl_pme_en_MASK	0x00040000
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/* Register definitions for the USB_PHY block in 7211b0 */
628c2ecf20Sopenharmony_ci#define USB_PHY_PLL_CTL			0x00
638c2ecf20Sopenharmony_ci#define   USB_PHY_PLL_CTL_PLL_RESETB_MASK		0x40000000
648c2ecf20Sopenharmony_ci#define USB_PHY_PLL_LDO_CTL		0x08
658c2ecf20Sopenharmony_ci#define   USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK		0x00000004
668c2ecf20Sopenharmony_ci#define   USB_PHY_PLL_LDO_CTL_AFE_LDO_PWRDWNB_MASK	0x00000002
678c2ecf20Sopenharmony_ci#define   USB_PHY_PLL_LDO_CTL_AFE_BG_PWRDWNB_MASK	0x00000001
688c2ecf20Sopenharmony_ci#define USB_PHY_UTMI_CTL_1		0x04
698c2ecf20Sopenharmony_ci#define   USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK	0x00000800
708c2ecf20Sopenharmony_ci#define   USB_PHY_UTMI_CTL_1_PHY_MODE_MASK		0x0000000c
718c2ecf20Sopenharmony_ci#define   USB_PHY_UTMI_CTL_1_PHY_MODE_SHIFT		2
728c2ecf20Sopenharmony_ci#define USB_PHY_IDDQ			0x1c
738c2ecf20Sopenharmony_ci#define   USB_PHY_IDDQ_phy_iddq_MASK			0x00000001
748c2ecf20Sopenharmony_ci#define USB_PHY_STATUS			0x20
758c2ecf20Sopenharmony_ci#define   USB_PHY_STATUS_pll_lock_MASK			0x00000001
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/* Register definitions for the MDIO registers in the DWC2 block of
788c2ecf20Sopenharmony_ci * the 7211b0.
798c2ecf20Sopenharmony_ci * NOTE: The PHY's MDIO registers are only accessible through the
808c2ecf20Sopenharmony_ci * legacy DesignWare USB controller even though it's not being used.
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_ci#define USB_GMDIOCSR	0
838c2ecf20Sopenharmony_ci#define USB_GMDIOGEN	4
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/* Register definitions for the BDC EC block in 7211b0 */
868c2ecf20Sopenharmony_ci#define BDC_EC_AXIRDA			0x0c
878c2ecf20Sopenharmony_ci#define   BDC_EC_AXIRDA_RTS_MASK			0xf0000000
888c2ecf20Sopenharmony_ci#define   BDC_EC_AXIRDA_RTS_SHIFT			28
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic void usb_mdio_write_7211b0(struct brcm_usb_init_params *params,
928c2ecf20Sopenharmony_ci				  uint8_t addr, uint16_t data)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	void __iomem *usb_mdio = params->regs[BRCM_REGS_USB_MDIO];
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	addr &= 0x1f; /* 5-bit address */
978c2ecf20Sopenharmony_ci	brcm_usb_writel(0xffffffff, usb_mdio + USB_GMDIOGEN);
988c2ecf20Sopenharmony_ci	while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
998c2ecf20Sopenharmony_ci		;
1008c2ecf20Sopenharmony_ci	brcm_usb_writel(0x59020000 | (addr << 18) | data,
1018c2ecf20Sopenharmony_ci			usb_mdio + USB_GMDIOGEN);
1028c2ecf20Sopenharmony_ci	while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
1038c2ecf20Sopenharmony_ci		;
1048c2ecf20Sopenharmony_ci	brcm_usb_writel(0x00000000, usb_mdio + USB_GMDIOGEN);
1058c2ecf20Sopenharmony_ci	while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
1068c2ecf20Sopenharmony_ci		;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic uint16_t __maybe_unused usb_mdio_read_7211b0(
1108c2ecf20Sopenharmony_ci	struct brcm_usb_init_params *params, uint8_t addr)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	void __iomem *usb_mdio = params->regs[BRCM_REGS_USB_MDIO];
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	addr &= 0x1f; /* 5-bit address */
1158c2ecf20Sopenharmony_ci	brcm_usb_writel(0xffffffff, usb_mdio + USB_GMDIOGEN);
1168c2ecf20Sopenharmony_ci	while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
1178c2ecf20Sopenharmony_ci		;
1188c2ecf20Sopenharmony_ci	brcm_usb_writel(0x69020000 | (addr << 18), usb_mdio + USB_GMDIOGEN);
1198c2ecf20Sopenharmony_ci	while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
1208c2ecf20Sopenharmony_ci		;
1218c2ecf20Sopenharmony_ci	brcm_usb_writel(0x00000000, usb_mdio + USB_GMDIOGEN);
1228c2ecf20Sopenharmony_ci	while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
1238c2ecf20Sopenharmony_ci		;
1248c2ecf20Sopenharmony_ci	return brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & 0xffff;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic void usb2_eye_fix_7211b0(struct brcm_usb_init_params *params)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	/* select bank */
1308c2ecf20Sopenharmony_ci	usb_mdio_write_7211b0(params, 0x1f, 0x80a0);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	/* Set the eye */
1338c2ecf20Sopenharmony_ci	usb_mdio_write_7211b0(params, 0x0a, 0xc6a0);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic void xhci_soft_reset(struct brcm_usb_init_params *params,
1378c2ecf20Sopenharmony_ci			int on_off)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	/* Assert reset */
1428c2ecf20Sopenharmony_ci	if (on_off)
1438c2ecf20Sopenharmony_ci		USB_CTRL_UNSET(ctrl, USB_PM, XHC_SOFT_RESETB);
1448c2ecf20Sopenharmony_ci	/* De-assert reset */
1458c2ecf20Sopenharmony_ci	else
1468c2ecf20Sopenharmony_ci		USB_CTRL_SET(ctrl, USB_PM, XHC_SOFT_RESETB);
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic void usb_init_ipp(struct brcm_usb_init_params *params)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
1528c2ecf20Sopenharmony_ci	u32 reg;
1538c2ecf20Sopenharmony_ci	u32 orig_reg;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	orig_reg = reg = brcm_usb_readl(USB_CTRL_REG(ctrl, SETUP));
1588c2ecf20Sopenharmony_ci	if (params->ipp != 2)
1598c2ecf20Sopenharmony_ci		/* override ipp strap pin (if it exits) */
1608c2ecf20Sopenharmony_ci		reg &= ~(USB_CTRL_MASK(SETUP, STRAP_IPP_SEL));
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	/* Override the default OC and PP polarity */
1638c2ecf20Sopenharmony_ci	reg &= ~(USB_CTRL_MASK(SETUP, IPP) | USB_CTRL_MASK(SETUP, IOC));
1648c2ecf20Sopenharmony_ci	if (params->ioc)
1658c2ecf20Sopenharmony_ci		reg |= USB_CTRL_MASK(SETUP, IOC);
1668c2ecf20Sopenharmony_ci	if (params->ipp == 1)
1678c2ecf20Sopenharmony_ci		reg |= USB_CTRL_MASK(SETUP, IPP);
1688c2ecf20Sopenharmony_ci	brcm_usb_writel(reg, USB_CTRL_REG(ctrl, SETUP));
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	/*
1718c2ecf20Sopenharmony_ci	 * If we're changing IPP, make sure power is off long enough
1728c2ecf20Sopenharmony_ci	 * to turn off any connected devices.
1738c2ecf20Sopenharmony_ci	 */
1748c2ecf20Sopenharmony_ci	if ((reg ^ orig_reg) & USB_CTRL_MASK(SETUP, IPP))
1758c2ecf20Sopenharmony_ci		msleep(50);
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic void syscon_piarbctl_init(struct regmap *rmap)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	/* Switch from legacy USB OTG controller to new STB USB controller */
1818c2ecf20Sopenharmony_ci	regmap_update_bits(rmap, PIARBCTL_MISC, PIARBCTL_MISC_USB_ONLY_MASK,
1828c2ecf20Sopenharmony_ci			   PIARBCTL_MISC_USB_SELECT_MASK |
1838c2ecf20Sopenharmony_ci			   PIARBCTL_MISC_USB_4G_SDRAM_MASK);
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic void usb_init_common(struct brcm_usb_init_params *params)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	u32 reg;
1898c2ecf20Sopenharmony_ci	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN);
1948c2ecf20Sopenharmony_ci	/* 1 millisecond - for USB clocks to settle down */
1958c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE)) {
1988c2ecf20Sopenharmony_ci		reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
1998c2ecf20Sopenharmony_ci		reg &= ~USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
2008c2ecf20Sopenharmony_ci		reg |= params->mode;
2018c2ecf20Sopenharmony_ci		brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci	switch (params->mode) {
2048c2ecf20Sopenharmony_ci	case USB_CTLR_MODE_HOST:
2058c2ecf20Sopenharmony_ci		USB_CTRL_UNSET(ctrl, USB_PM, BDC_SOFT_RESETB);
2068c2ecf20Sopenharmony_ci		break;
2078c2ecf20Sopenharmony_ci	default:
2088c2ecf20Sopenharmony_ci		USB_CTRL_UNSET(ctrl, USB_PM, BDC_SOFT_RESETB);
2098c2ecf20Sopenharmony_ci		USB_CTRL_SET(ctrl, USB_PM, BDC_SOFT_RESETB);
2108c2ecf20Sopenharmony_ci		break;
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic void usb_wake_enable_7211b0(struct brcm_usb_init_params *params,
2158c2ecf20Sopenharmony_ci				   bool enable)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	if (enable)
2208c2ecf20Sopenharmony_ci		USB_CTRL_SET(ctrl, CTLR_CSHCR, ctl_pme_en);
2218c2ecf20Sopenharmony_ci	else
2228c2ecf20Sopenharmony_ci		USB_CTRL_UNSET(ctrl, CTLR_CSHCR, ctl_pme_en);
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic void usb_init_common_7211b0(struct brcm_usb_init_params *params)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
2288c2ecf20Sopenharmony_ci	void __iomem *usb_phy = params->regs[BRCM_REGS_USB_PHY];
2298c2ecf20Sopenharmony_ci	void __iomem *bdc_ec = params->regs[BRCM_REGS_BDC_EC];
2308c2ecf20Sopenharmony_ci	int timeout_ms = PHY_LOCK_TIMEOUT_MS;
2318c2ecf20Sopenharmony_ci	u32 reg;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	if (params->syscon_piarbctl)
2348c2ecf20Sopenharmony_ci		syscon_piarbctl_init(params->syscon_piarbctl);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	usb_wake_enable_7211b0(params, false);
2398c2ecf20Sopenharmony_ci	if (!params->wake_enabled) {
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci		/* undo possible suspend settings */
2428c2ecf20Sopenharmony_ci		brcm_usb_writel(0, usb_phy + USB_PHY_IDDQ);
2438c2ecf20Sopenharmony_ci		reg = brcm_usb_readl(usb_phy + USB_PHY_PLL_CTL);
2448c2ecf20Sopenharmony_ci		reg |= USB_PHY_PLL_CTL_PLL_RESETB_MASK;
2458c2ecf20Sopenharmony_ci		brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_CTL);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci		/* temporarily enable FSM so PHY comes up properly */
2488c2ecf20Sopenharmony_ci		reg = brcm_usb_readl(usb_phy + USB_PHY_UTMI_CTL_1);
2498c2ecf20Sopenharmony_ci		reg |= USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK;
2508c2ecf20Sopenharmony_ci		brcm_usb_writel(reg, usb_phy + USB_PHY_UTMI_CTL_1);
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/* Init the PHY */
2548c2ecf20Sopenharmony_ci	reg = USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK |
2558c2ecf20Sopenharmony_ci		USB_PHY_PLL_LDO_CTL_AFE_LDO_PWRDWNB_MASK |
2568c2ecf20Sopenharmony_ci		USB_PHY_PLL_LDO_CTL_AFE_BG_PWRDWNB_MASK;
2578c2ecf20Sopenharmony_ci	brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_LDO_CTL);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/* wait for lock */
2608c2ecf20Sopenharmony_ci	while (timeout_ms-- > 0) {
2618c2ecf20Sopenharmony_ci		reg = brcm_usb_readl(usb_phy + USB_PHY_STATUS);
2628c2ecf20Sopenharmony_ci		if (reg & USB_PHY_STATUS_pll_lock_MASK)
2638c2ecf20Sopenharmony_ci			break;
2648c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/* Set the PHY_MODE */
2688c2ecf20Sopenharmony_ci	reg = brcm_usb_readl(usb_phy + USB_PHY_UTMI_CTL_1);
2698c2ecf20Sopenharmony_ci	reg &= ~USB_PHY_UTMI_CTL_1_PHY_MODE_MASK;
2708c2ecf20Sopenharmony_ci	reg |= params->mode << USB_PHY_UTMI_CTL_1_PHY_MODE_SHIFT;
2718c2ecf20Sopenharmony_ci	brcm_usb_writel(reg, usb_phy + USB_PHY_UTMI_CTL_1);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	usb_init_common(params);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/*
2768c2ecf20Sopenharmony_ci	 * The BDC controller will get occasional failures with
2778c2ecf20Sopenharmony_ci	 * the default "Read Transaction Size" of 6 (1024 bytes).
2788c2ecf20Sopenharmony_ci	 * Set it to 4 (256 bytes).
2798c2ecf20Sopenharmony_ci	 */
2808c2ecf20Sopenharmony_ci	if ((params->mode != USB_CTLR_MODE_HOST) && bdc_ec) {
2818c2ecf20Sopenharmony_ci		reg = brcm_usb_readl(bdc_ec + BDC_EC_AXIRDA);
2828c2ecf20Sopenharmony_ci		reg &= ~BDC_EC_AXIRDA_RTS_MASK;
2838c2ecf20Sopenharmony_ci		reg |= (0x4 << BDC_EC_AXIRDA_RTS_SHIFT);
2848c2ecf20Sopenharmony_ci		brcm_usb_writel(reg, bdc_ec + BDC_EC_AXIRDA);
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	/*
2888c2ecf20Sopenharmony_ci	 * Disable FSM, otherwise the PHY will auto suspend when no
2898c2ecf20Sopenharmony_ci	 * device is connected and will be reset on resume.
2908c2ecf20Sopenharmony_ci	 */
2918c2ecf20Sopenharmony_ci	reg = brcm_usb_readl(usb_phy + USB_PHY_UTMI_CTL_1);
2928c2ecf20Sopenharmony_ci	reg &= ~USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK;
2938c2ecf20Sopenharmony_ci	brcm_usb_writel(reg, usb_phy + USB_PHY_UTMI_CTL_1);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	usb2_eye_fix_7211b0(params);
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic void usb_init_xhci(struct brcm_usb_init_params *params)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	xhci_soft_reset(params, 0);
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic void usb_uninit_common(struct brcm_usb_init_params *params)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic void usb_uninit_common_7211b0(struct brcm_usb_init_params *params)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
3188c2ecf20Sopenharmony_ci	void __iomem *usb_phy = params->regs[BRCM_REGS_USB_PHY];
3198c2ecf20Sopenharmony_ci	u32 reg;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	if (params->wake_enabled) {
3248c2ecf20Sopenharmony_ci		USB_CTRL_SET(ctrl, TEST_PORT_CTL, TPOUT_SEL_PME_GEN);
3258c2ecf20Sopenharmony_ci		usb_wake_enable_7211b0(params, true);
3268c2ecf20Sopenharmony_ci	} else {
3278c2ecf20Sopenharmony_ci		USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
3288c2ecf20Sopenharmony_ci		brcm_usb_writel(0, usb_phy + USB_PHY_PLL_LDO_CTL);
3298c2ecf20Sopenharmony_ci		reg = brcm_usb_readl(usb_phy + USB_PHY_PLL_CTL);
3308c2ecf20Sopenharmony_ci		reg &= ~USB_PHY_PLL_CTL_PLL_RESETB_MASK;
3318c2ecf20Sopenharmony_ci		brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_CTL);
3328c2ecf20Sopenharmony_ci		brcm_usb_writel(USB_PHY_IDDQ_phy_iddq_MASK,
3338c2ecf20Sopenharmony_ci				usb_phy + USB_PHY_IDDQ);
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic void usb_uninit_xhci(struct brcm_usb_init_params *params)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (!params->wake_enabled)
3448c2ecf20Sopenharmony_ci		xhci_soft_reset(params, 1);
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_cistatic int usb_get_dual_select(struct brcm_usb_init_params *params)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
3508c2ecf20Sopenharmony_ci	u32 reg = 0;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
3558c2ecf20Sopenharmony_ci	reg &= USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
3568c2ecf20Sopenharmony_ci	return reg;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic void usb_set_dual_select(struct brcm_usb_init_params *params, int mode)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
3628c2ecf20Sopenharmony_ci	u32 reg;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
3678c2ecf20Sopenharmony_ci	reg &= ~USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
3688c2ecf20Sopenharmony_ci	reg |= mode;
3698c2ecf20Sopenharmony_ci	brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic const struct brcm_usb_init_ops bcm7216_ops = {
3738c2ecf20Sopenharmony_ci	.init_ipp = usb_init_ipp,
3748c2ecf20Sopenharmony_ci	.init_common = usb_init_common,
3758c2ecf20Sopenharmony_ci	.init_xhci = usb_init_xhci,
3768c2ecf20Sopenharmony_ci	.uninit_common = usb_uninit_common,
3778c2ecf20Sopenharmony_ci	.uninit_xhci = usb_uninit_xhci,
3788c2ecf20Sopenharmony_ci	.get_dual_select = usb_get_dual_select,
3798c2ecf20Sopenharmony_ci	.set_dual_select = usb_set_dual_select,
3808c2ecf20Sopenharmony_ci};
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic const struct brcm_usb_init_ops bcm7211b0_ops = {
3838c2ecf20Sopenharmony_ci	.init_ipp = usb_init_ipp,
3848c2ecf20Sopenharmony_ci	.init_common = usb_init_common_7211b0,
3858c2ecf20Sopenharmony_ci	.init_xhci = usb_init_xhci,
3868c2ecf20Sopenharmony_ci	.uninit_common = usb_uninit_common_7211b0,
3878c2ecf20Sopenharmony_ci	.uninit_xhci = usb_uninit_xhci,
3888c2ecf20Sopenharmony_ci	.get_dual_select = usb_get_dual_select,
3898c2ecf20Sopenharmony_ci	.set_dual_select = usb_set_dual_select,
3908c2ecf20Sopenharmony_ci};
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_civoid brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	params->family_name = "7216";
3988c2ecf20Sopenharmony_ci	params->ops = &bcm7216_ops;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_civoid brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	params->family_name = "7211";
4078c2ecf20Sopenharmony_ci	params->ops = &bcm7211b0_ops;
4088c2ecf20Sopenharmony_ci	params->suspend_with_clocks = true;
4098c2ecf20Sopenharmony_ci}
410