2024-05-10 11:19:19 +00:00
|
|
|
From fa846f5991de6c37db1f40e26a39f52c130f2bc7 Mon Sep 17 00:00:00 2001
|
|
|
|
From: Jonathan Bell <jonathan@raspberrypi.com>
|
|
|
|
Date: Mon, 13 Sep 2021 11:14:32 +0100
|
|
|
|
Subject: [PATCH 0519/1085] 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 <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 | 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 | 53 +++++++++++++++++
|
|
|
|
drivers/usb/dwc3/core.h | 5 ++
|
|
|
|
drivers/usb/dwc3/host.c | 9 ++-
|
|
|
|
7 files changed, 145 insertions(+), 3 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
|
|
|
|
@@ -335,6 +335,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->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(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)
|
|
|
|
{
|
|
|
|
|
|
|
|
@@ -434,6 +476,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)
|
|
|
|
{
|
|
|
|
|
|
|
|
@@ -451,3 +503,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
|
|
|
|
@@ -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)
|
|
|
|
{
|
|
|
|
--- a/drivers/phy/broadcom/phy-brcm-usb.c
|
|
|
|
+++ b/drivers/phy/broadcom/phy-brcm-usb.c
|
|
|
|
@@ -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
|
|
|
|
.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
|
2024-09-04 19:32:54 +00:00
|
|
|
@@ -1202,6 +1202,24 @@ static void dwc3_config_threshold(struct
|
2024-05-10 11:19:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
+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
|
2024-09-04 19:32:54 +00:00
|
|
|
@@ -1267,6 +1285,8 @@ static int dwc3_core_init(struct dwc3 *d
|
2024-05-10 11:19:19 +00:00
|
|
|
|
|
|
|
dwc3_set_incr_burst_type(dwc);
|
|
|
|
|
|
|
|
+ dwc3_set_axi_pipe_limit(dwc);
|
|
|
|
+
|
|
|
|
ret = dwc3_phy_power_on(dwc);
|
|
|
|
if (ret)
|
|
|
|
goto err_exit_phy;
|
2024-09-12 11:14:13 +00:00
|
|
|
@@ -1356,6 +1376,24 @@ static int dwc3_core_init(struct dwc3 *d
|
2024-05-10 11:19:19 +00:00
|
|
|
|
|
|
|
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:
|
2024-09-12 11:14:13 +00:00
|
|
|
@@ -1499,6 +1537,7 @@ static void dwc3_get_properties(struct d
|
2024-05-10 11:19:19 +00:00
|
|
|
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;
|
|
|
|
|
2024-09-12 11:14:13 +00:00
|
|
|
@@ -1521,6 +1560,9 @@ static void dwc3_get_properties(struct d
|
2024-05-10 11:19:19 +00:00
|
|
|
*/
|
|
|
|
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);
|
2024-09-12 11:14:13 +00:00
|
|
|
@@ -1642,6 +1684,9 @@ static void dwc3_get_properties(struct d
|
2024-05-10 11:19:19 +00:00
|
|
|
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;
|
|
|
|
|
2024-09-12 11:14:13 +00:00
|
|
|
@@ -1659,6 +1704,8 @@ static void dwc3_get_properties(struct d
|
2024-05-10 11:19:19 +00:00
|
|
|
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;
|
2024-09-12 11:14:13 +00:00
|
|
|
@@ -1934,6 +1981,12 @@ static int dwc3_probe(struct platform_de
|
2024-05-10 11:19:19 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
@@ -185,6 +185,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)
|
2024-09-12 11:14:13 +00:00
|
|
|
@@ -1061,6 +1064,7 @@ struct dwc3_scratchpad_array {
|
2024-05-10 11:19:19 +00:00
|
|
|
* @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
|
2024-09-12 11:14:13 +00:00
|
|
|
@@ -1296,6 +1300,7 @@ struct dwc3 {
|
2024-05-10 11:19:19 +00:00
|
|
|
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
|
|
|
|
@@ -82,16 +82,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;
|