[PATCH v3] usb: dwc3: enable CCI support for AMD-xilinx DWC3 controller

From: Radhey Shyam Pandey
Date: Thu Jun 06 2024 - 03:01:59 EST


The GSBUSCFG0 register bits [31:16] are used to configure the cache type
settings of the descriptor and data write/read transfers (Cacheable,
Bufferable/Posted). When CCI is enabled in the design, DWC3 core GSBUSCFG0
cache bits must be updated to support CCI enabled transfers in USB.

To program GSBUSCFG0 cache bits create a software node property
in AMD-xilinx dwc3 glue driver and pass it to dwc3 core. The core
then reads this property value and configures it in dwc3_core_init()
sequence.

Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@xxxxxxx>
---
Changes for v3:
In v2 review as suggested by Thinh Nguyen, switch to swnode implementation
for passing GSBUSCFG0 cache bits from AMD-xilinx dwc3 glue driver to
core driver.

Changes for v2:
Make GSBUSCFG0 configuration specific to AMD-xilinx platform.
Taken reference from existing commit ec5eb43813a4 ("usb: dwc3: core:
add support for realtek SoCs custom's global register start address")

v1 link:
https://lore.kernel.org/all/20231013053448.11056-1-piyush.mehta@xxxxxxx
---
drivers/usb/dwc3/core.c | 24 ++++++++++++++++++++++++
drivers/usb/dwc3/core.h | 8 ++++++++
drivers/usb/dwc3/dwc3-xilinx.c | 18 +++++++++++++++++-
3 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 7ee61a89520b..159d21b25629 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_graph.h>
#include <linux/acpi.h>
#include <linux/pinctrl/consumer.h>
@@ -599,6 +600,19 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
parms->hwparams9 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS9);
}

+static void dwc3_config_soc_bus(struct dwc3 *dwc)
+{
+ if (of_dma_is_coherent(dwc->dev->of_node)) {
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0);
+ reg &= ~DWC3_GSBUSCFG0_DAT_DES_RD_WR_REQINFO_MASK;
+ reg |= (dwc->acache_data_rd_wr_info <<
+ DWC3_GSBUSCFG0_DAT_DES_RD_WR_REQINFO_SHIFT);
+ dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, reg);
+ }
+}
+
static int dwc3_core_ulpi_init(struct dwc3 *dwc)
{
int intf;
@@ -1320,6 +1334,8 @@ static int dwc3_core_init(struct dwc3 *dwc)

dwc3_set_incr_burst_type(dwc);

+ dwc3_config_soc_bus(dwc);
+
ret = dwc3_phy_power_on(dwc);
if (ret)
goto err_exit_phy;
@@ -1574,6 +1590,7 @@ static void dwc3_get_properties(struct dwc3 *dwc)
u8 tx_max_burst_prd = 0;
u8 tx_fifo_resize_max_num;
const char *usb_psy_name;
+ struct device *tmpdev;
int ret;

/* default to highest possible threshold */
@@ -1716,6 +1733,13 @@ static void dwc3_get_properties(struct dwc3 *dwc)
dwc->dis_split_quirk = device_property_read_bool(dev,
"snps,dis-split-quirk");

+ /* Iterate over all parent nodes for finding swnode properties */
+ for (tmpdev = dwc->dev; tmpdev; tmpdev = tmpdev->parent) {
+ device_property_read_u16(tmpdev,
+ "snps,acache-data-rd-wr-info",
+ &dwc->acache_data_rd_wr_info);
+ }
+
dwc->lpm_nyet_threshold = lpm_nyet_threshold;
dwc->tx_de_emphasis = tx_de_emphasis;

diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 3781c736c1a1..57b3cb739353 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -194,6 +194,10 @@
#define DWC3_GSBUSCFG0_INCRBRSTENA (1 << 0) /* undefined length enable */
#define DWC3_GSBUSCFG0_INCRBRST_MASK 0xff

+/* Global SoC Bus Configuration Register: AHB-prot/AXI-cache/OCP-ReqInfo */
+#define DWC3_GSBUSCFG0_DAT_DES_RD_WR_REQINFO_MASK GENMASK(31, 16)
+#define DWC3_GSBUSCFG0_DAT_DES_RD_WR_REQINFO_SHIFT 16
+
/* Global Debug LSP MUX Select */
#define DWC3_GDBGLSPMUX_ENDBC BIT(15) /* Host only */
#define DWC3_GDBGLSPMUX_HOSTSELECT(n) ((n) & 0x3fff)
@@ -1153,6 +1157,9 @@ struct dwc3_scratchpad_array {
* @num_ep_resized: carries the current number endpoints which have had its tx
* fifo resized.
* @debug_root: root debugfs directory for this device to put its files in.
+ * @acache_data_rd_wr_info: store GSBUSCFG0.DATRDREQINFO, DESRDREQINFO,
+ * DATWRREQINFO, and DESWRREQINFO value passed from
+ * glue driver.
*/
struct dwc3 {
struct work_struct drd_work;
@@ -1380,6 +1387,7 @@ struct dwc3 {
int last_fifo_depth;
int num_ep_resized;
struct dentry *debug_root;
+ u16 acache_data_rd_wr_info;
};

#define INCRX_BURST_MODE 0
diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c
index 6095f4dee6ce..f3757bfbd650 100644
--- a/drivers/usb/dwc3/dwc3-xilinx.c
+++ b/drivers/usb/dwc3/dwc3-xilinx.c
@@ -47,6 +47,15 @@ struct dwc3_xlnx {
struct phy *usb3_phy;
};

+static const struct property_entry dwc3_xilinx_properties[] = {
+ PROPERTY_ENTRY_U16("snps,acache-data-rd-wr-info", 0xffff),
+ {},
+};
+
+static const struct software_node dwc3_xilinx_swnode = {
+ .properties = dwc3_xilinx_properties,
+};
+
static void dwc3_xlnx_mask_phy_rst(struct dwc3_xlnx *priv_data, bool mask)
{
u32 reg;
@@ -288,10 +297,14 @@ static int dwc3_xlnx_probe(struct platform_device *pdev)
if (ret)
goto err_clk_put;

- ret = of_platform_populate(np, NULL, NULL, dev);
+ ret = device_add_software_node(dev, &dwc3_xilinx_swnode);
if (ret)
goto err_clk_put;

+ ret = of_platform_populate(np, NULL, NULL, dev);
+ if (ret)
+ goto err_remove_swnode;
+
pm_runtime_set_active(dev);
ret = devm_pm_runtime_enable(dev);
if (ret < 0)
@@ -303,6 +316,9 @@ static int dwc3_xlnx_probe(struct platform_device *pdev)
err_pm_set_suspended:
pm_runtime_set_suspended(dev);

+err_remove_swnode:
+ device_remove_software_node(dev);
+
err_clk_put:
clk_bulk_disable_unprepare(priv_data->num_clocks, priv_data->clks);

--
2.34.1