| From 9d5f51dcdb646c2ed21649d379fbb703994f1ec9 Mon Sep 17 00:00:00 2001 |
| From: Al Cooper <alcooperx@gmail.com> |
| Date: Fri, 3 Jan 2020 13:18:06 -0500 |
| Subject: [PATCH] phy: usb: Add support for new Synopsys USB controller on the |
| 7211b0 |
| |
| The 7211b0 has added the STB XHCI Synopsys controller and it |
| will be used instead of the RPi based DWC USB controller. The new |
| Synopsys XHCI controller core is the same one that is used on the |
| 7216, but because of the way the STB USB PHY is used on both the A0 |
| and B0, some of the PHY control is different. |
| |
| Signed-off-by: Al Cooper <alcooperx@gmail.com> |
| Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> |
| Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com> |
| --- |
| .../phy/broadcom/phy-brcm-usb-init-synopsys.c | 163 +++++++++++++++++- |
| drivers/phy/broadcom/phy-brcm-usb-init.c | 31 ++-- |
| drivers/phy/broadcom/phy-brcm-usb-init.h | 17 +- |
| drivers/phy/broadcom/phy-brcm-usb.c | 162 +++++++++++------ |
| 4 files changed, 295 insertions(+), 78 deletions(-) |
| |
| --- a/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c |
| +++ b/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c |
| @@ -12,10 +12,33 @@ |
| #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_USB_M_ASB_CTRL 0x10 |
| + |
| +#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 |
| @@ -29,11 +52,73 @@ |
| #define USB_CTRL_USB_DEVICE_CTL1 0x10 |
| #define USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK 0x00000003 |
| |
| +/* Register definitions for the USB_PHY block in 7211b0 */ |
| +#define USB_PHY_PLL_LDO_CTL 0x08 |
| +#define USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK 0x00000004 |
| +#define USB_PHY_UTMI_CTL_1 0x04 |
| +#define USB_PHY_UTMI_CTL_1_PHY_MODE_MASK 0x0000000c |
| +#define USB_PHY_UTMI_CTL_1_PHY_MODE_SHIFT 2 |
| +#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 |
| + |
| + |
| +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->ctrl_regs; |
| + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; |
| |
| /* Assert reset */ |
| if (on_off) |
| @@ -45,7 +130,7 @@ static void xhci_soft_reset(struct brcm_ |
| |
| static void usb_init_ipp(struct brcm_usb_init_params *params) |
| { |
| - void __iomem *ctrl = params->ctrl_regs; |
| + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; |
| u32 reg; |
| u32 orig_reg; |
| |
| @@ -72,10 +157,18 @@ static void usb_init_ipp(struct brcm_usb |
| 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->ctrl_regs; |
| + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; |
| |
| pr_debug("%s\n", __func__); |
| |
| @@ -100,6 +193,45 @@ static void usb_init_common(struct brcm_ |
| } |
| } |
| |
| +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]; |
| + int timeout_ms = PHY_LOCK_TIMEOUT_MS; |
| + u32 reg; |
| + |
| + if (params->syscon_piarbctl) |
| + syscon_piarbctl_init(params->syscon_piarbctl); |
| + |
| + /* Init the PHY */ |
| + reg = brcm_usb_readl(usb_phy + USB_PHY_PLL_LDO_CTL); |
| + reg |= USB_PHY_PLL_LDO_CTL_AFE_CORERDY_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); |
| + |
| + /* Fix the incorrect default */ |
| + reg = brcm_usb_readl(ctrl + USB_CTRL_SETUP); |
| + reg &= ~USB_CTRL_SETUP_tca_drv_sel_MASK; |
| + brcm_usb_writel(reg, ctrl + USB_CTRL_SETUP); |
| + |
| + usb_init_common(params); |
| + |
| + usb2_eye_fix_7211b0(params); |
| +} |
| + |
| static void usb_init_xhci(struct brcm_usb_init_params *params) |
| { |
| pr_debug("%s\n", __func__); |
| @@ -109,7 +241,7 @@ static void usb_init_xhci(struct brcm_us |
| |
| static void usb_uninit_common(struct brcm_usb_init_params *params) |
| { |
| - void __iomem *ctrl = params->ctrl_regs; |
| + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; |
| |
| pr_debug("%s\n", __func__); |
| |
| @@ -127,7 +259,7 @@ static void usb_uninit_xhci(struct brcm_ |
| |
| static int usb_get_dual_select(struct brcm_usb_init_params *params) |
| { |
| - void __iomem *ctrl = params->ctrl_regs; |
| + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; |
| u32 reg = 0; |
| |
| pr_debug("%s\n", __func__); |
| @@ -139,7 +271,7 @@ static int usb_get_dual_select(struct br |
| |
| static void usb_set_dual_select(struct brcm_usb_init_params *params, int mode) |
| { |
| - void __iomem *ctrl = params->ctrl_regs; |
| + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; |
| u32 reg; |
| |
| pr_debug("%s\n", __func__); |
| @@ -161,6 +293,16 @@ static const struct brcm_usb_init_ops bc |
| .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, |
| + .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) |
| { |
| |
| @@ -169,3 +311,12 @@ void brcm_usb_dvr_init_7216(struct brcm_ |
| 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; |
| +} |
| --- a/drivers/phy/broadcom/phy-brcm-usb-init.c |
| +++ b/drivers/phy/broadcom/phy-brcm-usb-init.c |
| @@ -401,7 +401,7 @@ void usb_ctrl_unset_family(struct brcm_u |
| u32 mask; |
| |
| mask = params->usb_reg_bits_map[field]; |
| - brcm_usb_ctrl_unset(params->ctrl_regs + reg_offset, mask); |
| + brcm_usb_ctrl_unset(params->regs[BRCM_REGS_CTRL] + reg_offset, mask); |
| }; |
| |
| static inline |
| @@ -411,7 +411,7 @@ void usb_ctrl_set_family(struct brcm_usb |
| u32 mask; |
| |
| mask = params->usb_reg_bits_map[field]; |
| - brcm_usb_ctrl_set(params->ctrl_regs + reg_offset, mask); |
| + brcm_usb_ctrl_set(params->regs[BRCM_REGS_CTRL] + reg_offset, mask); |
| }; |
| |
| static u32 brcmusb_usb_mdio_read(void __iomem *ctrl_base, u32 reg, int mode) |
| @@ -544,7 +544,7 @@ static void brcmusb_usb3_pll_54mhz(struc |
| { |
| u32 ofs; |
| int ii; |
| - void __iomem *ctrl_base = params->ctrl_regs; |
| + void __iomem *ctrl_base = params->regs[BRCM_REGS_CTRL]; |
| |
| /* |
| * On newer B53 based SoC's, the reference clock for the |
| @@ -625,7 +625,7 @@ static void brcmusb_usb3_ssc_enable(void |
| |
| static void brcmusb_usb3_phy_workarounds(struct brcm_usb_init_params *params) |
| { |
| - void __iomem *ctrl_base = params->ctrl_regs; |
| + void __iomem *ctrl_base = params->regs[BRCM_REGS_CTRL]; |
| |
| brcmusb_usb3_pll_fix(ctrl_base); |
| brcmusb_usb3_pll_54mhz(params); |
| @@ -667,7 +667,7 @@ static void brcmusb_memc_fix(struct brcm |
| |
| static void brcmusb_usb3_otp_fix(struct brcm_usb_init_params *params) |
| { |
| - void __iomem *xhci_ec_base = params->xhci_ec_regs; |
| + void __iomem *xhci_ec_base = params->regs[BRCM_REGS_XHCI_EC]; |
| u32 val; |
| |
| if (params->family_id != 0x74371000 || !xhci_ec_base) |
| @@ -680,8 +680,8 @@ static void brcmusb_usb3_otp_fix(struct |
| brcm_usb_writel(val, USB_XHCI_EC_REG(xhci_ec_base, IRADAT)); |
| |
| /* Reset USB 3.0 PHY for workaround to take effect */ |
| - USB_CTRL_UNSET(params->ctrl_regs, USB30_CTL1, PHY3_RESETB); |
| - USB_CTRL_SET(params->ctrl_regs, USB30_CTL1, PHY3_RESETB); |
| + USB_CTRL_UNSET(params->regs[BRCM_REGS_CTRL], USB30_CTL1, PHY3_RESETB); |
| + USB_CTRL_SET(params->regs[BRCM_REGS_CTRL], USB30_CTL1, PHY3_RESETB); |
| } |
| |
| static void brcmusb_xhci_soft_reset(struct brcm_usb_init_params *params, |
| @@ -740,7 +740,7 @@ static enum brcm_family_type get_family_ |
| |
| static void usb_init_ipp(struct brcm_usb_init_params *params) |
| { |
| - void __iomem *ctrl = params->ctrl_regs; |
| + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; |
| u32 reg; |
| u32 orig_reg; |
| |
| @@ -786,7 +786,7 @@ static void usb_init_ipp(struct brcm_usb |
| static void usb_init_common(struct brcm_usb_init_params *params) |
| { |
| u32 reg; |
| - void __iomem *ctrl = params->ctrl_regs; |
| + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; |
| |
| /* Clear any pending wake conditions */ |
| reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_PM_STATUS)); |
| @@ -866,7 +866,7 @@ static void usb_init_common(struct brcm_ |
| static void usb_init_eohci(struct brcm_usb_init_params *params) |
| { |
| u32 reg; |
| - void __iomem *ctrl = params->ctrl_regs; |
| + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; |
| |
| if (USB_CTRL_MASK_FAMILY(params, USB_PM, USB20_HC_RESETB)) |
| USB_CTRL_SET_FAMILY(params, USB_PM, USB20_HC_RESETB); |
| @@ -902,7 +902,7 @@ static void usb_init_eohci(struct brcm_u |
| |
| static void usb_init_xhci(struct brcm_usb_init_params *params) |
| { |
| - void __iomem *ctrl = params->ctrl_regs; |
| + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; |
| |
| USB_CTRL_UNSET(ctrl, USB30_PCTL, PHY3_IDDQ_OVERRIDE); |
| /* 1 millisecond - for USB clocks to settle down */ |
| @@ -944,12 +944,13 @@ static void usb_uninit_eohci(struct brcm |
| static void usb_uninit_xhci(struct brcm_usb_init_params *params) |
| { |
| brcmusb_xhci_soft_reset(params, 1); |
| - USB_CTRL_SET(params->ctrl_regs, USB30_PCTL, PHY3_IDDQ_OVERRIDE); |
| + USB_CTRL_SET(params->regs[BRCM_REGS_CTRL], USB30_PCTL, |
| + PHY3_IDDQ_OVERRIDE); |
| } |
| |
| static int usb_get_dual_select(struct brcm_usb_init_params *params) |
| { |
| - void __iomem *ctrl = params->ctrl_regs; |
| + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; |
| u32 reg = 0; |
| |
| pr_debug("%s\n", __func__); |
| @@ -963,7 +964,7 @@ static int usb_get_dual_select(struct br |
| |
| static void usb_set_dual_select(struct brcm_usb_init_params *params, int mode) |
| { |
| - void __iomem *ctrl = params->ctrl_regs; |
| + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; |
| u32 reg; |
| |
| pr_debug("%s\n", __func__); |
| @@ -980,7 +981,7 @@ static void usb_set_dual_select(struct b |
| static void usb_wake_enable(struct brcm_usb_init_params *params, |
| int enable) |
| { |
| - void __iomem *ctrl = params->ctrl_regs; |
| + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; |
| |
| if (enable) |
| USB_CTRL_SET(ctrl, USB_PM, RMTWKUP_EN); |
| --- a/drivers/phy/broadcom/phy-brcm-usb-init.h |
| +++ b/drivers/phy/broadcom/phy-brcm-usb-init.h |
| @@ -6,12 +6,21 @@ |
| #ifndef _USB_BRCM_COMMON_INIT_H |
| #define _USB_BRCM_COMMON_INIT_H |
| |
| +#include <linux/regmap.h> |
| + |
| #define USB_CTLR_MODE_HOST 0 |
| #define USB_CTLR_MODE_DEVICE 1 |
| #define USB_CTLR_MODE_DRD 2 |
| #define USB_CTLR_MODE_TYPEC_PD 3 |
| |
| -struct brcm_usb_init_params; |
| +enum brcmusb_reg_sel { |
| + BRCM_REGS_CTRL = 0, |
| + BRCM_REGS_XHCI_EC, |
| + BRCM_REGS_XHCI_GBL, |
| + BRCM_REGS_USB_PHY, |
| + BRCM_REGS_USB_MDIO, |
| + BRCM_REGS_MAX |
| +}; |
| |
| #define USB_CTRL_REG(base, reg) ((void __iomem *)base + USB_CTRL_##reg) |
| #define USB_XHCI_EC_REG(base, reg) ((void __iomem *)base + USB_XHCI_EC_##reg) |
| @@ -41,9 +50,7 @@ struct brcm_usb_init_ops { |
| }; |
| |
| struct brcm_usb_init_params { |
| - void __iomem *ctrl_regs; |
| - void __iomem *xhci_ec_regs; |
| - void __iomem *xhci_gbl_regs; |
| + void __iomem *regs[BRCM_REGS_MAX]; |
| int ioc; |
| int ipp; |
| int mode; |
| @@ -53,10 +60,12 @@ struct brcm_usb_init_params { |
| const char *family_name; |
| const u32 *usb_reg_bits_map; |
| const struct brcm_usb_init_ops *ops; |
| + struct regmap *syscon_piarbctl; |
| }; |
| |
| void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params); |
| void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params); |
| +void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params); |
| |
| static inline u32 brcm_usb_readl(void __iomem *addr) |
| { |
| --- a/drivers/phy/broadcom/phy-brcm-usb.c |
| +++ b/drivers/phy/broadcom/phy-brcm-usb.c |
| @@ -16,6 +16,7 @@ |
| #include <linux/interrupt.h> |
| #include <linux/soc/brcmstb/brcmstb.h> |
| #include <dt-bindings/phy/phy.h> |
| +#include <linux/mfd/syscon.h> |
| |
| #include "phy-brcm-usb-init.h" |
| |
| @@ -32,6 +33,11 @@ struct value_to_name_map { |
| const char *name; |
| }; |
| |
| +struct match_chip_info { |
| + void *init_func; |
| + u8 required_regs[BRCM_REGS_MAX + 1]; |
| +}; |
| + |
| static struct value_to_name_map brcm_dr_mode_to_name[] = { |
| { USB_CTLR_MODE_HOST, "host" }, |
| { USB_CTLR_MODE_DEVICE, "peripheral" }, |
| @@ -64,6 +70,10 @@ struct brcm_usb_phy_data { |
| struct brcm_usb_phy phys[BRCM_USB_PHY_ID_MAX]; |
| }; |
| |
| +static s8 *node_reg_names[BRCM_REGS_MAX] = { |
| + "crtl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio" |
| +}; |
| + |
| static irqreturn_t brcm_usb_phy_wake_isr(int irq, void *dev_id) |
| { |
| struct phy *gphy = dev_id; |
| @@ -241,15 +251,86 @@ static const struct attribute_group brcm |
| .attrs = brcm_usb_phy_attrs, |
| }; |
| |
| +static struct match_chip_info chip_info_7216 = { |
| + .init_func = &brcm_usb_dvr_init_7216, |
| + .required_regs = { |
| + BRCM_REGS_CTRL, |
| + BRCM_REGS_XHCI_EC, |
| + BRCM_REGS_XHCI_GBL, |
| + -1, |
| + }, |
| +}; |
| + |
| +static struct match_chip_info chip_info_7211b0 = { |
| + .init_func = &brcm_usb_dvr_init_7211b0, |
| + .required_regs = { |
| + BRCM_REGS_CTRL, |
| + BRCM_REGS_XHCI_EC, |
| + BRCM_REGS_XHCI_GBL, |
| + BRCM_REGS_USB_PHY, |
| + BRCM_REGS_USB_MDIO, |
| + -1, |
| + }, |
| +}; |
| + |
| +static struct match_chip_info chip_info_7445 = { |
| + .init_func = &brcm_usb_dvr_init_7445, |
| + .required_regs = { |
| + BRCM_REGS_CTRL, |
| + BRCM_REGS_XHCI_EC, |
| + -1, |
| + }, |
| +}; |
| + |
| static const struct of_device_id brcm_usb_dt_ids[] = { |
| { |
| .compatible = "brcm,bcm7216-usb-phy", |
| - .data = &brcm_usb_dvr_init_7216, |
| + .data = &chip_info_7216, |
| + }, |
| + { |
| + .compatible = "brcm,bcm7211-usb-phy", |
| + .data = &chip_info_7211b0, |
| + }, |
| + { |
| + .compatible = "brcm,brcmstb-usb-phy", |
| + .data = &chip_info_7445, |
| }, |
| - { .compatible = "brcm,brcmstb-usb-phy" }, |
| { /* sentinel */ } |
| }; |
| |
| +static int brcm_usb_get_regs(struct platform_device *pdev, |
| + enum brcmusb_reg_sel regs, |
| + struct brcm_usb_init_params *ini) |
| +{ |
| + struct resource *res; |
| + |
| + /* Older DT nodes have ctrl and optional xhci_ec by index only */ |
| + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
| + node_reg_names[regs]); |
| + if (res == NULL) { |
| + if (regs == BRCM_REGS_CTRL) { |
| + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| + } else if (regs == BRCM_REGS_XHCI_EC) { |
| + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
| + /* XHCI_EC registers are optional */ |
| + if (res == NULL) |
| + return 0; |
| + } |
| + if (res == NULL) { |
| + dev_err(&pdev->dev, "can't get %s base address\n", |
| + node_reg_names[regs]); |
| + return 1; |
| + } |
| + } |
| + ini->regs[regs] = devm_ioremap_resource(&pdev->dev, res); |
| + if (IS_ERR(ini->regs[regs])) { |
| + dev_err(&pdev->dev, "can't map %s register space\n", |
| + node_reg_names[regs]); |
| + return 1; |
| + } |
| + return 0; |
| +} |
| + |
| static int brcm_usb_phy_dvr_init(struct platform_device *pdev, |
| struct brcm_usb_phy_data *priv, |
| struct device_node *dn) |
| @@ -325,9 +406,6 @@ static int brcm_usb_phy_dvr_init(struct |
| |
| static int brcm_usb_phy_probe(struct platform_device *pdev) |
| { |
| - struct resource *res_ctrl; |
| - struct resource *res_xhciec = NULL; |
| - struct resource *res_xhcigbl = NULL; |
| struct device *dev = &pdev->dev; |
| struct brcm_usb_phy_data *priv; |
| struct phy_provider *phy_provider; |
| @@ -335,6 +413,10 @@ static int brcm_usb_phy_probe(struct pla |
| int err; |
| const char *mode; |
| const struct of_device_id *match; |
| + void (*dvr_init)(struct brcm_usb_init_params *params); |
| + const struct match_chip_info *info; |
| + struct regmap *rmap; |
| + int x; |
| |
| priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
| if (!priv) |
| @@ -345,58 +427,13 @@ static int brcm_usb_phy_probe(struct pla |
| priv->ini.product_id = brcmstb_get_product_id(); |
| |
| match = of_match_node(brcm_usb_dt_ids, dev->of_node); |
| - if (match && match->data) { |
| - void (*dvr_init)(struct brcm_usb_init_params *params); |
| - |
| - dvr_init = match->data; |
| - (*dvr_init)(&priv->ini); |
| - } else { |
| - brcm_usb_dvr_init_7445(&priv->ini); |
| - } |
| + info = match->data; |
| + dvr_init = info->init_func; |
| + (*dvr_init)(&priv->ini); |
| |
| dev_dbg(dev, "Best mapping table is for %s\n", |
| priv->ini.family_name); |
| |
| - /* Newer DT node has reg-names. xhci_ec and xhci_gbl are optional. */ |
| - res_ctrl = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl"); |
| - if (res_ctrl != NULL) { |
| - res_xhciec = platform_get_resource_byname(pdev, |
| - IORESOURCE_MEM, |
| - "xhci_ec"); |
| - res_xhcigbl = platform_get_resource_byname(pdev, |
| - IORESOURCE_MEM, |
| - "xhci_gbl"); |
| - } else { |
| - /* Older DT node without reg-names, use index */ |
| - res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| - if (res_ctrl == NULL) { |
| - dev_err(dev, "can't get CTRL base address\n"); |
| - return -EINVAL; |
| - } |
| - res_xhciec = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
| - } |
| - priv->ini.ctrl_regs = devm_ioremap_resource(dev, res_ctrl); |
| - if (IS_ERR(priv->ini.ctrl_regs)) { |
| - dev_err(dev, "can't map CTRL register space\n"); |
| - return -EINVAL; |
| - } |
| - if (res_xhciec) { |
| - priv->ini.xhci_ec_regs = |
| - devm_ioremap_resource(dev, res_xhciec); |
| - if (IS_ERR(priv->ini.xhci_ec_regs)) { |
| - dev_err(dev, "can't map XHCI EC register space\n"); |
| - return -EINVAL; |
| - } |
| - } |
| - if (res_xhcigbl) { |
| - priv->ini.xhci_gbl_regs = |
| - devm_ioremap_resource(dev, res_xhcigbl); |
| - if (IS_ERR(priv->ini.xhci_gbl_regs)) { |
| - dev_err(dev, "can't map XHCI Global register space\n"); |
| - return -EINVAL; |
| - } |
| - } |
| - |
| of_property_read_u32(dn, "brcm,ipp", &priv->ini.ipp); |
| of_property_read_u32(dn, "brcm,ioc", &priv->ini.ioc); |
| |
| @@ -412,6 +449,16 @@ static int brcm_usb_phy_probe(struct pla |
| if (of_property_read_bool(dn, "brcm,has-eohci")) |
| priv->has_eohci = true; |
| |
| + for (x = 0; x < BRCM_REGS_MAX; x++) { |
| + if (info->required_regs[x] >= BRCM_REGS_MAX) |
| + break; |
| + |
| + err = brcm_usb_get_regs(pdev, info->required_regs[x], |
| + &priv->ini); |
| + if (err) |
| + return -EINVAL; |
| + } |
| + |
| err = brcm_usb_phy_dvr_init(pdev, priv, dn); |
| if (err) |
| return err; |
| @@ -431,6 +478,15 @@ static int brcm_usb_phy_probe(struct pla |
| if (err) |
| dev_warn(dev, "Error creating sysfs attributes\n"); |
| |
| + /* Get piarbctl syscon if it exists */ |
| + rmap = syscon_regmap_lookup_by_phandle(dev->of_node, |
| + "syscon-piarbctl"); |
| + if (IS_ERR(rmap)) |
| + rmap = syscon_regmap_lookup_by_phandle(dev->of_node, |
| + "brcm,syscon-piarbctl"); |
| + if (!IS_ERR(rmap)) |
| + priv->ini.syscon_piarbctl = rmap; |
| + |
| /* start with everything off */ |
| if (priv->has_xhci) |
| brcm_usb_uninit_xhci(&priv->ini); |