usb: dwc3: Set DMA and coherent masks early
authorJonathan Bell <jonathan@raspberrypi.com>
Mon, 13 Sep 2021 10:14:32 +0000 (11:14 +0100)
committerDom Cobley <popcornmix@gmail.com>
Mon, 19 Feb 2024 11:34:41 +0000 (11:34 +0000)
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 <jonathan@raspberrypi.com>
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 <jonathan@raspberrypi.com>
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 <jonathan@raspberrypi.com>
drivers: usb: dwc3: remove downstream quirk dis-in-autoretry

Upstream have unilaterally disabled the feature.

Partially reverts 6e9142a26ee0fdc3a5adc49ed6cedc0b16ec2ed1 (downstream)

Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
drivers/phy/broadcom/Kconfig
drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c
drivers/phy/broadcom/phy-brcm-usb-init.h
drivers/phy/broadcom/phy-brcm-usb.c
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/host.c

index 1d89a2f..a67ac49 100644 (file)
@@ -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
index 4c10caf..8d9e91c 100644 (file)
@@ -335,6 +335,36 @@ static void usb_init_common_7216(struct brcm_usb_init_params *params)
        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->supported_port_modes != 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__);
@@ -380,6 +410,18 @@ static void usb_uninit_common_7211b0(struct brcm_usb_init_params *params)
 
 }
 
+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)
 {
 
@@ -434,6 +476,16 @@ static const struct brcm_usb_init_ops bcm7211b0_ops = {
        .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)
 {
 
@@ -451,3 +503,10 @@ void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params)
        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;
+}
index c1a88f5..6708347 100644 (file)
@@ -70,12 +70,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)
 {
index a16f0b5..edac75f 100644 (file)
@@ -75,7 +75,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_info_7211b0 = {
        .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_usb_dt_ids[] = {
                .data = &chip_info_7211b0,
        },
        {
+               .compatible = "brcm,bcm2712-usb-phy",
+               .data = &chip_info_2712,
+       },
+       {
                .compatible = "brcm,brcmstb-usb-phy",
                .data = &chip_info_7445,
        },
index b73b79f..27c5d7e 100644 (file)
@@ -1162,6 +1162,24 @@ static void dwc3_config_threshold(struct dwc3 *dwc)
        }
 }
 
+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
@@ -1242,6 +1260,8 @@ static int dwc3_core_init(struct dwc3 *dwc)
 
        dwc3_set_incr_burst_type(dwc);
 
+       dwc3_set_axi_pipe_limit(dwc);
+
        ret = dwc3_phy_power_on(dwc);
        if (ret)
                goto err_exit_phy;
@@ -1316,6 +1336,24 @@ static int dwc3_core_init(struct dwc3 *dwc)
 
        dwc3_config_threshold(dwc);
 
+       if (DWC3_IP_IS(DWC3) && dwc->dr_mode == USB_DR_MODE_HOST) {
+               u8 tx_thr_num = dwc->tx_thr_num_pkt_prd;
+               u8 tx_maxburst = dwc->tx_max_burst_prd;
+
+               if (tx_thr_num && tx_maxburst) {
+                       reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG);
+                       reg |= DWC3_GTXTHRCFG_PKTCNTSEL;
+
+                       reg &= ~DWC3_GTXTHRCFG_TXPKTCNT(~0);
+                       reg |= DWC3_GTXTHRCFG_TXPKTCNT(tx_thr_num);
+
+                       reg &= ~DWC3_GTXTHRCFG_MAXTXBURSTSIZE(~0);
+                       reg |= DWC3_GTXTHRCFG_MAXTXBURSTSIZE(tx_maxburst);
+
+                       dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg);
+               }
+       }
+
        return 0;
 
 err_power_off_phy:
@@ -1459,6 +1497,7 @@ static void dwc3_get_properties(struct dwc3 *dwc)
        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;
 
@@ -1481,6 +1520,9 @@ static void dwc3_get_properties(struct dwc3 *dwc)
         */
        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);
@@ -1600,6 +1642,9 @@ static void dwc3_get_properties(struct dwc3 *dwc)
        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;
 
@@ -1617,6 +1662,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)
        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;
@@ -1892,6 +1939,12 @@ static int dwc3_probe(struct platform_device *pdev)
 
        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);
index 6782ec8..a773197 100644 (file)
 #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)
@@ -1060,6 +1063,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
@@ -1292,6 +1296,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;
 
index 4323091..7b33f22 100644 (file)
@@ -61,16 +61,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;