diff options
Diffstat (limited to 'target/linux/bcm4908/patches-5.4/084-v5.6-0007-phy-usb-Add-support-for-new-Synopsys-USB-controller-.patch')
-rw-r--r-- | target/linux/bcm4908/patches-5.4/084-v5.6-0007-phy-usb-Add-support-for-new-Synopsys-USB-controller-.patch | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/target/linux/bcm4908/patches-5.4/084-v5.6-0007-phy-usb-Add-support-for-new-Synopsys-USB-controller-.patch b/target/linux/bcm4908/patches-5.4/084-v5.6-0007-phy-usb-Add-support-for-new-Synopsys-USB-controller-.patch new file mode 100644 index 0000000000..11cc080c23 --- /dev/null +++ b/target/linux/bcm4908/patches-5.4/084-v5.6-0007-phy-usb-Add-support-for-new-Synopsys-USB-controller-.patch @@ -0,0 +1,358 @@ +From 4e5b9c9a73b32d28759225a40d30848393a8f1fd Mon Sep 17 00:00:00 2001 +From: Al Cooper <alcooperx@gmail.com> +Date: Fri, 3 Jan 2020 13:18:05 -0500 +Subject: [PATCH] phy: usb: Add support for new Synopsys USB controller on the + 7216 + +The 7216 has the new USB XHCI controller from Synopsys. While +this new controller and the PHY are similar to the STB versions, +the major differences are: + +- Many of the registers and fields in the CTRL block have been + removed or changed. +- A new set of Synopsys control registers, BCHP_USB_XHCI_GBL, were + added. +- MDIO functionality has been replaced with direct access registers + in the BCHP_USB_XHCI_GBL block. +- Power up PHY defaults that had to be changed by MDIO in previous + chips will now power up with the correct defaults. + +A new init module was created for this new Synopsys USB controller. +A new compatible string was added and the driver will dispatch +into one of two init modules based on it. A "reg-names" field was +added so the driver can more easily get optional registers. +A DT bindings document was also added for this driver. + +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> +--- + drivers/phy/broadcom/Makefile | 2 +- + .../phy/broadcom/phy-brcm-usb-init-synopsys.c | 171 ++++++++++++++++++ + drivers/phy/broadcom/phy-brcm-usb-init.h | 2 + + drivers/phy/broadcom/phy-brcm-usb.c | 70 +++++-- + 4 files changed, 227 insertions(+), 18 deletions(-) + create mode 100644 drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c + +--- a/drivers/phy/broadcom/Makefile ++++ b/drivers/phy/broadcom/Makefile +@@ -8,7 +8,7 @@ obj-$(CONFIG_PHY_NS2_USB_DRD) += phy-bc + obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o + obj-$(CONFIG_PHY_BRCM_USB) += phy-brcm-usb-dvr.o + +-phy-brcm-usb-dvr-objs := phy-brcm-usb.o phy-brcm-usb-init.o ++phy-brcm-usb-dvr-objs := phy-brcm-usb.o phy-brcm-usb-init.o phy-brcm-usb-init-synopsys.o + + obj-$(CONFIG_PHY_BCM_SR_PCIE) += phy-bcm-sr-pcie.o + obj-$(CONFIG_PHY_BCM_SR_USB) += phy-bcm-sr-usb.o +--- /dev/null ++++ b/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c +@@ -0,0 +1,171 @@ ++// 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" ++ ++/* 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_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_STATUS 0x08 ++#define USB_CTRL_USB_DEVICE_CTL1 0x10 ++#define USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK 0x00000003 ++ ++ ++static void xhci_soft_reset(struct brcm_usb_init_params *params, ++ int on_off) ++{ ++ void __iomem *ctrl = params->ctrl_regs; ++ ++ /* 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->ctrl_regs; ++ 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 usb_init_common(struct brcm_usb_init_params *params) ++{ ++ u32 reg; ++ void __iomem *ctrl = params->ctrl_regs; ++ ++ pr_debug("%s\n", __func__); ++ ++ USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN); ++ /* 1 millisecond - for USB clocks to settle down */ ++ usleep_range(1000, 2000); ++ ++ 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_init_xhci(struct brcm_usb_init_params *params) ++{ ++ pr_debug("%s\n", __func__); ++ ++ xhci_soft_reset(params, 0); ++} ++ ++static void usb_uninit_common(struct brcm_usb_init_params *params) ++{ ++ void __iomem *ctrl = params->ctrl_regs; ++ ++ pr_debug("%s\n", __func__); ++ ++ USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN); ++ ++} ++ ++static void usb_uninit_xhci(struct brcm_usb_init_params *params) ++{ ++ ++ pr_debug("%s\n", __func__); ++ ++ xhci_soft_reset(params, 1); ++} ++ ++static int usb_get_dual_select(struct brcm_usb_init_params *params) ++{ ++ void __iomem *ctrl = params->ctrl_regs; ++ 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->ctrl_regs; ++ 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, ++ .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) ++{ ++ ++ pr_debug("%s\n", __func__); ++ ++ params->family_name = "7216"; ++ params->ops = &bcm7216_ops; ++} +--- a/drivers/phy/broadcom/phy-brcm-usb-init.h ++++ b/drivers/phy/broadcom/phy-brcm-usb-init.h +@@ -43,6 +43,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; + int ioc; + int ipp; + int mode; +@@ -55,6 +56,7 @@ struct brcm_usb_init_params { + }; + + void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params); ++void brcm_usb_dvr_init_7216(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 +@@ -241,6 +241,15 @@ static const struct attribute_group brcm + .attrs = brcm_usb_phy_attrs, + }; + ++static const struct of_device_id brcm_usb_dt_ids[] = { ++ { ++ .compatible = "brcm,bcm7216-usb-phy", ++ .data = &brcm_usb_dvr_init_7216, ++ }, ++ { .compatible = "brcm,brcmstb-usb-phy" }, ++ { /* sentinel */ } ++}; ++ + static int brcm_usb_phy_dvr_init(struct platform_device *pdev, + struct brcm_usb_phy_data *priv, + struct device_node *dn) +@@ -316,13 +325,16 @@ static int brcm_usb_phy_dvr_init(struct + + static int brcm_usb_phy_probe(struct platform_device *pdev) + { +- struct resource *res; ++ 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; + struct device_node *dn = pdev->dev.of_node; + int err; + const char *mode; ++ const struct of_device_id *match; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) +@@ -331,30 +343,59 @@ static int brcm_usb_phy_probe(struct pla + + priv->ini.family_id = brcmstb_get_family_id(); + priv->ini.product_id = brcmstb_get_product_id(); +- brcm_usb_dvr_init_7445(&priv->ini); ++ ++ 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); ++ } ++ + dev_dbg(dev, "Best mapping table is for %s\n", + priv->ini.family_name); +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!res) { +- dev_err(dev, "can't get USB_CTRL base address\n"); +- return -EINVAL; ++ ++ /* 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); ++ 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; + } +- +- /* The XHCI EC registers are optional */ +- res = platform_get_resource(pdev, IORESOURCE_MEM, 1); +- if (res) { ++ if (res_xhciec) { + priv->ini.xhci_ec_regs = +- devm_ioremap_resource(dev, res); ++ 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); +@@ -480,11 +521,6 @@ static const struct dev_pm_ops brcm_usb_ + SET_LATE_SYSTEM_SLEEP_PM_OPS(brcm_usb_phy_suspend, brcm_usb_phy_resume) + }; + +-static const struct of_device_id brcm_usb_dt_ids[] = { +- { .compatible = "brcm,brcmstb-usb-phy" }, +- { /* sentinel */ } +-}; +- + MODULE_DEVICE_TABLE(of, brcm_usb_dt_ids); + + static struct platform_driver brcm_usb_driver = { |