6c90999e2e
This includes BCM4908 support Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
681 lines
21 KiB
Diff
681 lines
21 KiB
Diff
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);
|