From 4ffa5f2c5fc7854683964bb2f2bf23907c18213f Mon Sep 17 00:00:00 2001 From: Jonathan Bell Date: Mon, 13 Sep 2021 11:14:32 +0100 Subject: [PATCH] usb: dwc3: Set DMA and coherent masks early dwc3 allocates scratch and event buffers in the top-level driver. Hack the probe function to set the DMA mask before trying to allocate these. I think the event buffers are only used in device mode, but the scratch buffers may be used if core hibernation is enabled. usb: dwc3: add support for new DT quirks Apply the optional axi-pipe-limit and dis-in-autoretry-quirk properties during driver probe. Signed-off-by: Jonathan Bell phy: phy-brcm-usb: Add 2712 support usb: dwc3: if the host controller instance number is present in DT, use it If two instances of a dwc3 host controller are specified in devicetree, then the probe order may be arbitrary which results in the device names swapping on a per-boot basis. If a "usb" alias with the instance number is specified, then use that to construct the device name instead of autogenerating one. Signed-off-by: Jonathan Bell rp1 dwc3 changes drivers: usb: dwc3: allow setting GTXTHRCFG on dwc_usb3.0 hardware Equivalent register fields exist in the SuperSpeed Host version of the hardware, so allow the use of TX thresholds if specified in devicetree. Signed-off-by: Jonathan Bell drivers: usb: dwc3: remove downstream quirk dis-in-autoretry Upstream have unilaterally disabled the feature. Partially reverts 6e9142a26ee0fdc3a5adc49ed6cedc0b16ec2ed1 (downstream) Signed-off-by: Jonathan Bell --- drivers/phy/broadcom/Kconfig | 2 +- .../phy/broadcom/phy-brcm-usb-init-synopsys.c | 59 +++++++++++++++++++ drivers/phy/broadcom/phy-brcm-usb-init.h | 2 + drivers/phy/broadcom/phy-brcm-usb.c | 18 +++++- drivers/usb/dwc3/core.c | 52 ++++++++++++++++ drivers/usb/dwc3/core.h | 10 ++++ drivers/usb/dwc3/host.c | 17 ++++-- 7 files changed, 153 insertions(+), 7 deletions(-) --- a/drivers/phy/broadcom/Kconfig +++ b/drivers/phy/broadcom/Kconfig @@ -93,7 +93,7 @@ config PHY_BRCM_SATA config PHY_BRCM_USB tristate "Broadcom STB USB PHY driver" - depends on ARCH_BCMBCA || ARCH_BRCMSTB || COMPILE_TEST + depends on ARCH_BCMBCA || ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST depends on OF select GENERIC_PHY select SOC_BRCMSTB if ARCH_BRCMSTB --- a/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c +++ b/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c @@ -318,6 +318,36 @@ static void usb_init_common_7216(struct usb_init_common(params); } +static void usb_init_common_2712(struct brcm_usb_init_params *params) +{ + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; + void __iomem *bdc_ec = params->regs[BRCM_REGS_BDC_EC]; + 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); + + 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); + } + + usb2_eye_fix_7211b0(params); +} + static void usb_init_xhci(struct brcm_usb_init_params *params) { pr_debug("%s\n", __func__); @@ -363,6 +393,18 @@ static void usb_uninit_common_7211b0(str } +static void usb_uninit_common_2712(struct brcm_usb_init_params *params) +{ + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; + + 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); + } +} + static void usb_uninit_xhci(struct brcm_usb_init_params *params) { @@ -417,6 +459,16 @@ static const struct brcm_usb_init_ops bc .set_dual_select = usb_set_dual_select, }; +static const struct brcm_usb_init_ops bcm2712_ops = { + .init_ipp = usb_init_ipp, + .init_common = usb_init_common_2712, + .init_xhci = usb_init_xhci, + .uninit_common = usb_uninit_common_2712, + .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) { @@ -434,3 +486,10 @@ void brcm_usb_dvr_init_7211b0(struct brc params->family_name = "7211"; params->ops = &bcm7211b0_ops; } + +void brcm_usb_dvr_init_2712(struct brcm_usb_init_params *params) +{ + params->family_name = "2712"; + params->ops = &bcm2712_ops; + params->suspend_with_clocks = true; +} --- a/drivers/phy/broadcom/phy-brcm-usb-init.h +++ b/drivers/phy/broadcom/phy-brcm-usb-init.h @@ -61,12 +61,14 @@ struct brcm_usb_init_params { const struct brcm_usb_init_ops *ops; struct regmap *syscon_piarbctl; bool wake_enabled; + bool suspend_with_clocks; }; void brcm_usb_dvr_init_4908(struct brcm_usb_init_params *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); void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params); +void brcm_usb_dvr_init_2712(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 @@ -76,7 +76,7 @@ struct brcm_usb_phy_data { }; static s8 *node_reg_names[BRCM_REGS_MAX] = { - "crtl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec" + "ctrl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec" }; static int brcm_pm_notifier(struct notifier_block *notifier, @@ -315,6 +315,18 @@ static const struct match_chip_info chip .optional_reg = BRCM_REGS_BDC_EC, }; +static const struct match_chip_info chip_info_2712 = { + .init_func = &brcm_usb_dvr_init_2712, + .required_regs = { + BRCM_REGS_CTRL, + BRCM_REGS_XHCI_EC, + BRCM_REGS_XHCI_GBL, + BRCM_REGS_USB_MDIO, + -1, + }, + .optional_reg = BRCM_REGS_BDC_EC, +}; + static const struct match_chip_info chip_info_7445 = { .init_func = &brcm_usb_dvr_init_7445, .required_regs = { @@ -338,6 +350,10 @@ static const struct of_device_id brcm_us .data = &chip_info_7211b0, }, { + .compatible = "brcm,bcm2712-usb-phy", + .data = &chip_info_2712, + }, + { .compatible = "brcm,brcmstb-usb-phy", .data = &chip_info_7445, }, --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1180,6 +1180,24 @@ static void dwc3_config_threshold(struct } } +static void dwc3_set_axi_pipe_limit(struct dwc3 *dwc) +{ + struct device *dev = dwc->dev; + u32 cfg; + + if (!dwc->axi_pipe_limit) + return; + if (dwc->axi_pipe_limit > 16) { + dev_err(dev, "Invalid axi_pipe_limit property\n"); + return; + } + cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG1); + cfg &= ~DWC3_GSBUSCFG1_PIPETRANSLIMIT(15); + cfg |= DWC3_GSBUSCFG1_PIPETRANSLIMIT(dwc->axi_pipe_limit - 1); + + dwc3_writel(dwc->regs, DWC3_GSBUSCFG1, cfg); +} + /** * dwc3_core_init - Low-level initialization of DWC3 Core * @dwc: Pointer to our controller context structure @@ -1257,6 +1275,8 @@ static int dwc3_core_init(struct dwc3 *d dwc3_set_incr_burst_type(dwc); + dwc3_set_axi_pipe_limit(dwc); + usb_phy_set_suspend(dwc->usb2_phy, 0); usb_phy_set_suspend(dwc->usb3_phy, 0); ret = phy_power_on(dwc->usb2_generic_phy); @@ -1490,6 +1510,7 @@ static void dwc3_get_properties(struct d u8 tx_thr_num_pkt_prd = 0; u8 tx_max_burst_prd = 0; u8 tx_fifo_resize_max_num; + u8 axi_pipe_limit; const char *usb_psy_name; int ret; @@ -1512,6 +1533,9 @@ static void dwc3_get_properties(struct d */ tx_fifo_resize_max_num = 6; + /* Default to 0 (don't override hardware defaults) */ + axi_pipe_limit = 0; + dwc->maximum_speed = usb_get_maximum_speed(dev); dwc->max_ssp_rate = usb_get_maximum_ssp_rate(dev); dwc->dr_mode = usb_get_dr_mode(dev); @@ -1627,6 +1651,9 @@ static void dwc3_get_properties(struct d dwc->dis_split_quirk = device_property_read_bool(dev, "snps,dis-split-quirk"); + device_property_read_u8(dev, "snps,axi-pipe-limit", + &axi_pipe_limit); + dwc->lpm_nyet_threshold = lpm_nyet_threshold; dwc->tx_de_emphasis = tx_de_emphasis; @@ -1644,6 +1671,8 @@ static void dwc3_get_properties(struct d dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd; dwc->tx_max_burst_prd = tx_max_burst_prd; + dwc->axi_pipe_limit = axi_pipe_limit; + dwc->imod_interval = 0; dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num; @@ -1852,6 +1881,12 @@ static int dwc3_probe(struct platform_de dwc3_get_properties(dwc); + if (!dwc->sysdev_is_parent) { + ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64)); + if (ret) + return ret; + } + dwc->reset = devm_reset_control_array_get_optional_shared(dev); if (IS_ERR(dwc->reset)) { ret = PTR_ERR(dwc->reset); --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -183,6 +183,9 @@ #define DWC3_GSBUSCFG0_INCRBRSTENA (1 << 0) /* undefined length enable */ #define DWC3_GSBUSCFG0_INCRBRST_MASK 0xff +/* Global SoC Bus Configuration Register 1 */ +#define DWC3_GSBUSCFG1_PIPETRANSLIMIT(n) (((n) & 0xf) << 8) + /* Global Debug LSP MUX Select */ #define DWC3_GDBGLSPMUX_ENDBC BIT(15) /* Host only */ #define DWC3_GDBGLSPMUX_HOSTSELECT(n) ((n) & 0x3fff) @@ -1056,6 +1059,7 @@ struct dwc3_scratchpad_array { * @tx_max_burst_prd: max periodic ESS transmit burst size * @tx_fifo_resize_max_num: max number of fifos allocated during txfifo resize * @clear_stall_protocol: endpoint number that requires a delayed status phase + * @axi_max_pipe: set to override the maximum number of pipelined AXI transfers * @hsphy_interface: "utmi" or "ulpi" * @connected: true when we're connected to a host, false otherwise * @softconnect: true when gadget connect is called, false when disconnect runs @@ -1287,6 +1291,7 @@ struct dwc3 { u8 tx_max_burst_prd; u8 tx_fifo_resize_max_num; u8 clear_stall_protocol; + u8 axi_pipe_limit; const char *hsphy_interface; --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -51,10 +51,10 @@ static void dwc3_host_fill_xhci_irq_res( static int dwc3_host_get_irq(struct dwc3 *dwc) { - struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); + struct platform_device *pdev = to_platform_device(dwc->dev); int irq; - irq = platform_get_irq_byname_optional(dwc3_pdev, "host"); + irq = platform_get_irq_byname_optional(pdev, "host"); if (irq > 0) { dwc3_host_fill_xhci_irq_res(dwc, irq, "host"); goto out; @@ -63,7 +63,7 @@ static int dwc3_host_get_irq(struct dwc3 if (irq == -EPROBE_DEFER) goto out; - irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3"); + irq = platform_get_irq_byname_optional(pdev, "dwc_usb3"); if (irq > 0) { dwc3_host_fill_xhci_irq_res(dwc, irq, "dwc_usb3"); goto out; @@ -72,7 +72,7 @@ static int dwc3_host_get_irq(struct dwc3 if (irq == -EPROBE_DEFER) goto out; - irq = platform_get_irq(dwc3_pdev, 0); + irq = platform_get_irq(pdev, 0); if (irq > 0) { dwc3_host_fill_xhci_irq_res(dwc, irq, NULL); goto out; @@ -87,16 +87,23 @@ out: int dwc3_host_init(struct dwc3 *dwc) { + struct platform_device *pdev = to_platform_device(dwc->dev); struct property_entry props[5]; struct platform_device *xhci; int ret, irq; int prop_idx = 0; + int id; irq = dwc3_host_get_irq(dwc); if (irq < 0) return irq; - xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); + id = of_alias_get_id(pdev->dev.of_node, "usb"); + if (id >= 0) + xhci = platform_device_alloc("xhci-hcd", id); + else + xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); + if (!xhci) { dev_err(dwc->dev, "couldn't allocate xHCI device\n"); return -ENOMEM;