123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436 |
- // SPDX-License-Identifier: GPL-2.0
- /* Copyright (c) 2018, Broadcom */
- /*
- * This module contains USB PHY initialization for power up and S3 resume
- * for newer Synopsys based USB hardware first used on the bcm7216.
- */
- #include <linux/delay.h>
- #include <linux/io.h>
- #include <linux/soc/brcmstb/brcmstb.h>
- #include "phy-brcm-usb-init.h"
- #define PHY_LOCK_TIMEOUT_MS 200
- /* Register definitions for syscon piarbctl registers */
- #define PIARBCTL_CAM 0x00
- #define PIARBCTL_SPLITTER 0x04
- #define PIARBCTL_MISC 0x08
- #define PIARBCTL_MISC_SECURE_MASK 0x80000000
- #define PIARBCTL_MISC_USB_SELECT_MASK 0x40000000
- #define PIARBCTL_MISC_USB_4G_SDRAM_MASK 0x20000000
- #define PIARBCTL_MISC_USB_PRIORITY_MASK 0x000f0000
- #define PIARBCTL_MISC_USB_MEM_PAGE_MASK 0x0000f000
- #define PIARBCTL_MISC_CAM1_MEM_PAGE_MASK 0x00000f00
- #define PIARBCTL_MISC_CAM0_MEM_PAGE_MASK 0x000000f0
- #define PIARBCTL_MISC_SATA_PRIORITY_MASK 0x0000000f
- #define PIARBCTL_MISC_USB_ONLY_MASK \
- (PIARBCTL_MISC_USB_SELECT_MASK | \
- PIARBCTL_MISC_USB_4G_SDRAM_MASK | \
- PIARBCTL_MISC_USB_PRIORITY_MASK | \
- PIARBCTL_MISC_USB_MEM_PAGE_MASK)
- /* Register definitions for the USB CTRL block */
- #define USB_CTRL_SETUP 0x00
- #define USB_CTRL_SETUP_STRAP_IPP_SEL_MASK 0x02000000
- #define USB_CTRL_SETUP_SCB2_EN_MASK 0x00008000
- #define USB_CTRL_SETUP_tca_drv_sel_MASK 0x01000000
- #define USB_CTRL_SETUP_SCB1_EN_MASK 0x00004000
- #define USB_CTRL_SETUP_SOFT_SHUTDOWN_MASK 0x00000200
- #define USB_CTRL_SETUP_IPP_MASK 0x00000020
- #define USB_CTRL_SETUP_IOC_MASK 0x00000010
- #define USB_CTRL_USB_PM 0x04
- #define USB_CTRL_USB_PM_USB_PWRDN_MASK 0x80000000
- #define USB_CTRL_USB_PM_SOFT_RESET_MASK 0x40000000
- #define USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK 0x00800000
- #define USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK 0x00400000
- #define USB_CTRL_USB_PM_XHC_PME_EN_MASK 0x00000010
- #define USB_CTRL_USB_PM_XHC_S2_CLK_SWITCH_EN_MASK 0x00000008
- #define USB_CTRL_USB_PM_STATUS 0x08
- #define USB_CTRL_USB_DEVICE_CTL1 0x10
- #define USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK 0x00000003
- #define USB_CTRL_TEST_PORT_CTL 0x30
- #define USB_CTRL_TEST_PORT_CTL_TPOUT_SEL_MASK 0x000000ff
- #define USB_CTRL_TEST_PORT_CTL_TPOUT_SEL_PME_GEN_MASK 0x0000002e
- #define USB_CTRL_TP_DIAG1 0x34
- #define USB_CTLR_TP_DIAG1_wake_MASK 0x00000002
- #define USB_CTRL_CTLR_CSHCR 0x50
- #define USB_CTRL_CTLR_CSHCR_ctl_pme_en_MASK 0x00040000
- /* Register definitions for the USB_PHY block in 7211b0 */
- #define USB_PHY_PLL_CTL 0x00
- #define USB_PHY_PLL_CTL_PLL_RESETB_MASK 0x40000000
- #define USB_PHY_PLL_LDO_CTL 0x08
- #define USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK 0x00000004
- #define USB_PHY_PLL_LDO_CTL_AFE_LDO_PWRDWNB_MASK 0x00000002
- #define USB_PHY_PLL_LDO_CTL_AFE_BG_PWRDWNB_MASK 0x00000001
- #define USB_PHY_UTMI_CTL_1 0x04
- #define USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK 0x00000800
- #define USB_PHY_UTMI_CTL_1_PHY_MODE_MASK 0x0000000c
- #define USB_PHY_UTMI_CTL_1_PHY_MODE_SHIFT 2
- #define USB_PHY_IDDQ 0x1c
- #define USB_PHY_IDDQ_phy_iddq_MASK 0x00000001
- #define USB_PHY_STATUS 0x20
- #define USB_PHY_STATUS_pll_lock_MASK 0x00000001
- /* Register definitions for the MDIO registers in the DWC2 block of
- * the 7211b0.
- * NOTE: The PHY's MDIO registers are only accessible through the
- * legacy DesignWare USB controller even though it's not being used.
- */
- #define USB_GMDIOCSR 0
- #define USB_GMDIOGEN 4
- /* Register definitions for the BDC EC block in 7211b0 */
- #define BDC_EC_AXIRDA 0x0c
- #define BDC_EC_AXIRDA_RTS_MASK 0xf0000000
- #define BDC_EC_AXIRDA_RTS_SHIFT 28
- static void usb_mdio_write_7211b0(struct brcm_usb_init_params *params,
- uint8_t addr, uint16_t data)
- {
- void __iomem *usb_mdio = params->regs[BRCM_REGS_USB_MDIO];
- addr &= 0x1f; /* 5-bit address */
- brcm_usb_writel(0xffffffff, usb_mdio + USB_GMDIOGEN);
- while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
- ;
- brcm_usb_writel(0x59020000 | (addr << 18) | data,
- usb_mdio + USB_GMDIOGEN);
- while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
- ;
- brcm_usb_writel(0x00000000, usb_mdio + USB_GMDIOGEN);
- while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
- ;
- }
- static uint16_t __maybe_unused usb_mdio_read_7211b0(
- struct brcm_usb_init_params *params, uint8_t addr)
- {
- void __iomem *usb_mdio = params->regs[BRCM_REGS_USB_MDIO];
- addr &= 0x1f; /* 5-bit address */
- brcm_usb_writel(0xffffffff, usb_mdio + USB_GMDIOGEN);
- while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
- ;
- brcm_usb_writel(0x69020000 | (addr << 18), usb_mdio + USB_GMDIOGEN);
- while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
- ;
- brcm_usb_writel(0x00000000, usb_mdio + USB_GMDIOGEN);
- while (brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & (1<<31))
- ;
- return brcm_usb_readl(usb_mdio + USB_GMDIOCSR) & 0xffff;
- }
- static void usb2_eye_fix_7211b0(struct brcm_usb_init_params *params)
- {
- /* select bank */
- usb_mdio_write_7211b0(params, 0x1f, 0x80a0);
- /* Set the eye */
- usb_mdio_write_7211b0(params, 0x0a, 0xc6a0);
- }
- static void xhci_soft_reset(struct brcm_usb_init_params *params,
- int on_off)
- {
- void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
- /* Assert reset */
- if (on_off)
- USB_CTRL_UNSET(ctrl, USB_PM, XHC_SOFT_RESETB);
- /* De-assert reset */
- else
- USB_CTRL_SET(ctrl, USB_PM, XHC_SOFT_RESETB);
- }
- static void usb_init_ipp(struct brcm_usb_init_params *params)
- {
- void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
- u32 reg;
- u32 orig_reg;
- pr_debug("%s\n", __func__);
- orig_reg = reg = brcm_usb_readl(USB_CTRL_REG(ctrl, SETUP));
- if (params->ipp != 2)
- /* override ipp strap pin (if it exits) */
- reg &= ~(USB_CTRL_MASK(SETUP, STRAP_IPP_SEL));
- /* Override the default OC and PP polarity */
- reg &= ~(USB_CTRL_MASK(SETUP, IPP) | USB_CTRL_MASK(SETUP, IOC));
- if (params->ioc)
- reg |= USB_CTRL_MASK(SETUP, IOC);
- if (params->ipp == 1)
- reg |= USB_CTRL_MASK(SETUP, IPP);
- brcm_usb_writel(reg, USB_CTRL_REG(ctrl, SETUP));
- /*
- * If we're changing IPP, make sure power is off long enough
- * to turn off any connected devices.
- */
- if ((reg ^ orig_reg) & USB_CTRL_MASK(SETUP, IPP))
- msleep(50);
- }
- static void syscon_piarbctl_init(struct regmap *rmap)
- {
- /* Switch from legacy USB OTG controller to new STB USB controller */
- regmap_update_bits(rmap, PIARBCTL_MISC, PIARBCTL_MISC_USB_ONLY_MASK,
- PIARBCTL_MISC_USB_SELECT_MASK |
- PIARBCTL_MISC_USB_4G_SDRAM_MASK);
- }
- static void usb_init_common(struct brcm_usb_init_params *params)
- {
- u32 reg;
- void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
- pr_debug("%s\n", __func__);
- if (USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE)) {
- reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
- reg &= ~USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
- reg |= params->mode;
- brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
- }
- switch (params->mode) {
- case USB_CTLR_MODE_HOST:
- USB_CTRL_UNSET(ctrl, USB_PM, BDC_SOFT_RESETB);
- break;
- default:
- USB_CTRL_UNSET(ctrl, USB_PM, BDC_SOFT_RESETB);
- USB_CTRL_SET(ctrl, USB_PM, BDC_SOFT_RESETB);
- break;
- }
- }
- static void usb_wake_enable_7211b0(struct brcm_usb_init_params *params,
- bool enable)
- {
- void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
- if (enable)
- USB_CTRL_SET(ctrl, CTLR_CSHCR, ctl_pme_en);
- else
- USB_CTRL_UNSET(ctrl, CTLR_CSHCR, ctl_pme_en);
- }
- static void usb_wake_enable_7216(struct brcm_usb_init_params *params,
- bool enable)
- {
- void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
- if (enable)
- USB_CTRL_SET(ctrl, USB_PM, XHC_PME_EN);
- else
- USB_CTRL_UNSET(ctrl, USB_PM, XHC_PME_EN);
- }
- static void usb_init_common_7211b0(struct brcm_usb_init_params *params)
- {
- void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
- void __iomem *usb_phy = params->regs[BRCM_REGS_USB_PHY];
- void __iomem *bdc_ec = params->regs[BRCM_REGS_BDC_EC];
- int timeout_ms = PHY_LOCK_TIMEOUT_MS;
- u32 reg;
- if (params->syscon_piarbctl)
- syscon_piarbctl_init(params->syscon_piarbctl);
- USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN);
- usb_wake_enable_7211b0(params, false);
- if (!params->wake_enabled) {
- /* undo possible suspend settings */
- brcm_usb_writel(0, usb_phy + USB_PHY_IDDQ);
- reg = brcm_usb_readl(usb_phy + USB_PHY_PLL_CTL);
- reg |= USB_PHY_PLL_CTL_PLL_RESETB_MASK;
- brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_CTL);
- /* temporarily enable FSM so PHY comes up properly */
- reg = brcm_usb_readl(usb_phy + USB_PHY_UTMI_CTL_1);
- reg |= USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK;
- brcm_usb_writel(reg, usb_phy + USB_PHY_UTMI_CTL_1);
- }
- /* Init the PHY */
- reg = USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK |
- USB_PHY_PLL_LDO_CTL_AFE_LDO_PWRDWNB_MASK |
- USB_PHY_PLL_LDO_CTL_AFE_BG_PWRDWNB_MASK;
- brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_LDO_CTL);
- /* wait for lock */
- while (timeout_ms-- > 0) {
- reg = brcm_usb_readl(usb_phy + USB_PHY_STATUS);
- if (reg & USB_PHY_STATUS_pll_lock_MASK)
- break;
- usleep_range(1000, 2000);
- }
- /* Set the PHY_MODE */
- reg = brcm_usb_readl(usb_phy + USB_PHY_UTMI_CTL_1);
- reg &= ~USB_PHY_UTMI_CTL_1_PHY_MODE_MASK;
- reg |= params->mode << USB_PHY_UTMI_CTL_1_PHY_MODE_SHIFT;
- brcm_usb_writel(reg, usb_phy + USB_PHY_UTMI_CTL_1);
- usb_init_common(params);
- /*
- * The BDC controller will get occasional failures with
- * the default "Read Transaction Size" of 6 (1024 bytes).
- * Set it to 4 (256 bytes).
- */
- if ((params->mode != USB_CTLR_MODE_HOST) && bdc_ec) {
- reg = brcm_usb_readl(bdc_ec + BDC_EC_AXIRDA);
- reg &= ~BDC_EC_AXIRDA_RTS_MASK;
- reg |= (0x4 << BDC_EC_AXIRDA_RTS_SHIFT);
- brcm_usb_writel(reg, bdc_ec + BDC_EC_AXIRDA);
- }
- /*
- * Disable FSM, otherwise the PHY will auto suspend when no
- * device is connected and will be reset on resume.
- */
- reg = brcm_usb_readl(usb_phy + USB_PHY_UTMI_CTL_1);
- reg &= ~USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK;
- brcm_usb_writel(reg, usb_phy + USB_PHY_UTMI_CTL_1);
- usb2_eye_fix_7211b0(params);
- }
- static void usb_init_common_7216(struct brcm_usb_init_params *params)
- {
- void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
- USB_CTRL_UNSET(ctrl, USB_PM, XHC_S2_CLK_SWITCH_EN);
- USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN);
- /* 1 millisecond - for USB clocks to settle down */
- usleep_range(1000, 2000);
- usb_wake_enable_7216(params, false);
- usb_init_common(params);
- }
- static void usb_init_xhci(struct brcm_usb_init_params *params)
- {
- pr_debug("%s\n", __func__);
- xhci_soft_reset(params, 0);
- }
- static void usb_uninit_common_7216(struct brcm_usb_init_params *params)
- {
- void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
- pr_debug("%s\n", __func__);
- if (params->wake_enabled) {
- /* Switch to using slower clock during suspend to save power */
- USB_CTRL_SET(ctrl, USB_PM, XHC_S2_CLK_SWITCH_EN);
- usb_wake_enable_7216(params, true);
- } else {
- USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
- }
- }
- static void usb_uninit_common_7211b0(struct brcm_usb_init_params *params)
- {
- void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
- void __iomem *usb_phy = params->regs[BRCM_REGS_USB_PHY];
- u32 reg;
- pr_debug("%s\n", __func__);
- if (params->wake_enabled) {
- USB_CTRL_SET(ctrl, TEST_PORT_CTL, TPOUT_SEL_PME_GEN);
- usb_wake_enable_7211b0(params, true);
- } else {
- USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
- brcm_usb_writel(0, usb_phy + USB_PHY_PLL_LDO_CTL);
- reg = brcm_usb_readl(usb_phy + USB_PHY_PLL_CTL);
- reg &= ~USB_PHY_PLL_CTL_PLL_RESETB_MASK;
- brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_CTL);
- brcm_usb_writel(USB_PHY_IDDQ_phy_iddq_MASK,
- usb_phy + USB_PHY_IDDQ);
- }
- }
- static void usb_uninit_xhci(struct brcm_usb_init_params *params)
- {
- pr_debug("%s\n", __func__);
- if (!params->wake_enabled)
- xhci_soft_reset(params, 1);
- }
- static int usb_get_dual_select(struct brcm_usb_init_params *params)
- {
- void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
- u32 reg = 0;
- pr_debug("%s\n", __func__);
- reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
- reg &= USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
- return reg;
- }
- static void usb_set_dual_select(struct brcm_usb_init_params *params, int mode)
- {
- void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
- u32 reg;
- pr_debug("%s\n", __func__);
- reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
- reg &= ~USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
- reg |= mode;
- brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
- }
- static const struct brcm_usb_init_ops bcm7216_ops = {
- .init_ipp = usb_init_ipp,
- .init_common = usb_init_common_7216,
- .init_xhci = usb_init_xhci,
- .uninit_common = usb_uninit_common_7216,
- .uninit_xhci = usb_uninit_xhci,
- .get_dual_select = usb_get_dual_select,
- .set_dual_select = usb_set_dual_select,
- };
- static const struct brcm_usb_init_ops bcm7211b0_ops = {
- .init_ipp = usb_init_ipp,
- .init_common = usb_init_common_7211b0,
- .init_xhci = usb_init_xhci,
- .uninit_common = usb_uninit_common_7211b0,
- .uninit_xhci = usb_uninit_xhci,
- .get_dual_select = usb_get_dual_select,
- .set_dual_select = usb_set_dual_select,
- };
- void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params)
- {
- pr_debug("%s\n", __func__);
- params->family_name = "7216";
- params->ops = &bcm7216_ops;
- }
- void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params)
- {
- pr_debug("%s\n", __func__);
- params->family_name = "7211";
- params->ops = &bcm7211b0_ops;
- }
|