[PATCH v11 08/13] usb: dwc3: qcom: Refactor IRQ handling in QCOM Glue driver

From: Krishna Kurapati
Date: Mon Aug 28 2023 - 09:32:57 EST


Refactor setup_irq call to facilitate reading multiport IRQ's along
with non mulitport ones. Read through the interrupt-names property
to figure out, the type of interrupt (DP/DM/HS/SS) and to which port
it belongs. Also keep track of port index to calculate port count
based on interrupts provided as input in DT.

Signed-off-by: Krishna Kurapati <quic_kriskura@xxxxxxxxxxx>
---
drivers/usb/dwc3/dwc3-qcom.c | 215 +++++++++++++++++++++++++----------
1 file changed, 155 insertions(+), 60 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
index f14ddc9c541d..05990142cbc8 100644
--- a/drivers/usb/dwc3/dwc3-qcom.c
+++ b/drivers/usb/dwc3/dwc3-qcom.c
@@ -53,14 +53,24 @@
#define APPS_USB_AVG_BW 0
#define APPS_USB_PEAK_BW MBps_to_icc(40)

+#define NUM_PHY_IRQ 4
+
+#define DP_HS_PHY_IRQ_INDEX 0
+#define DM_HS_PHY_IRQ_INDEX 1
+#define SS_PHY_IRQ_INDEX 2
+#define HS_PHY_IRQ_INDEX 3
+
struct dwc3_acpi_pdata {
u32 qscratch_base_offset;
u32 qscratch_base_size;
u32 dwc3_core_base_size;
+
+ /*
+ * The phy_irq_index corresponds to ACPI indexes of (in order) DP/DM/SS
+ * IRQ's respectively.
+ */
+ int phy_irq_index[NUM_PHY_IRQ - 1];
int hs_phy_irq_index;
- int dp_hs_phy_irq_index;
- int dm_hs_phy_irq_index;
- int ss_phy_irq_index;
bool is_urs;
};

@@ -73,10 +83,12 @@ struct dwc3_qcom {
int num_clocks;
struct reset_control *resets;

+ /*
+ * The phy_irq corresponds to IRQ's registered for (in order) DP/DM/SS
+ * respectively.
+ */
+ int phy_irq[NUM_PHY_IRQ - 1][DWC3_MAX_PORTS];
int hs_phy_irq;
- int dp_hs_phy_irq;
- int dm_hs_phy_irq;
- int ss_phy_irq;
enum usb_device_speed usb2_speed;

struct extcon_dev *edev;
@@ -91,6 +103,8 @@ struct dwc3_qcom {
bool pm_suspended;
struct icc_path *icc_path_ddr;
struct icc_path *icc_path_apps;
+
+ int num_ports;
};

static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val)
@@ -375,16 +389,16 @@ static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
dwc3_qcom_disable_wakeup_irq(qcom->hs_phy_irq);

if (qcom->usb2_speed == USB_SPEED_LOW) {
- dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq);
+ dwc3_qcom_disable_wakeup_irq(qcom->phy_irq[DP_HS_PHY_IRQ_INDEX][0]);
} else if ((qcom->usb2_speed == USB_SPEED_HIGH) ||
(qcom->usb2_speed == USB_SPEED_FULL)) {
- dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq);
+ dwc3_qcom_disable_wakeup_irq(qcom->phy_irq[DM_HS_PHY_IRQ_INDEX][0]);
} else {
- dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq);
- dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq);
+ dwc3_qcom_disable_wakeup_irq(qcom->phy_irq[DP_HS_PHY_IRQ_INDEX][0]);
+ dwc3_qcom_disable_wakeup_irq(qcom->phy_irq[DM_HS_PHY_IRQ_INDEX][0]);
}

- dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq);
+ dwc3_qcom_disable_wakeup_irq(qcom->phy_irq[SS_PHY_IRQ_INDEX][0]);
}

static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
@@ -401,20 +415,20 @@ static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
*/

if (qcom->usb2_speed == USB_SPEED_LOW) {
- dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq,
+ dwc3_qcom_enable_wakeup_irq(qcom->phy_irq[DP_HS_PHY_IRQ_INDEX][0],
IRQ_TYPE_EDGE_FALLING);
} else if ((qcom->usb2_speed == USB_SPEED_HIGH) ||
(qcom->usb2_speed == USB_SPEED_FULL)) {
- dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq,
+ dwc3_qcom_enable_wakeup_irq(qcom->phy_irq[DM_HS_PHY_IRQ_INDEX][0],
IRQ_TYPE_EDGE_FALLING);
} else {
- dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq,
+ dwc3_qcom_enable_wakeup_irq(qcom->phy_irq[DP_HS_PHY_IRQ_INDEX][0],
IRQ_TYPE_EDGE_RISING);
- dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq,
+ dwc3_qcom_enable_wakeup_irq(qcom->phy_irq[DM_HS_PHY_IRQ_INDEX][0],
IRQ_TYPE_EDGE_RISING);
}

- dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0);
+ dwc3_qcom_enable_wakeup_irq(qcom->phy_irq[SS_PHY_IRQ_INDEX][0], 0);
}

static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup)
@@ -535,8 +549,8 @@ static int dwc3_qcom_get_irq(struct platform_device *pdev,
return ret;
}

-static int dwc3_qcom_prep_irq(struct dwc3_qcom *qcom, char *irq_name,
- char *disp_name, int irq)
+static int dwc3_qcom_prep_irq(struct dwc3_qcom *qcom, const char *irq_name,
+ const char *disp_name, int irq)
{
int ret;

@@ -553,51 +567,136 @@ static int dwc3_qcom_prep_irq(struct dwc3_qcom *qcom, char *irq_name,
return ret;
}

+static int dwc3_qcom_get_irq_index(const char *irq_name)
+{
+ /*
+ * If we are reading IRQ not supported by the driver
+ * like pwr_event_irq, then return -1 indicating the next
+ * helper function to skip processing IRQ name further.
+ */
+ int irq_index = -1;
+
+ if (strncmp(irq_name, "dp_hs_phy", strlen("dp_hs_phy")) == 0)
+ irq_index = DP_HS_PHY_IRQ_INDEX;
+ else if (strncmp(irq_name, "dm_hs_phy", strlen("dm_hs_phy")) == 0)
+ irq_index = DM_HS_PHY_IRQ_INDEX;
+ else if (strncmp(irq_name, "ss_phy", strlen("ss_phy")) == 0)
+ irq_index = SS_PHY_IRQ_INDEX;
+ else if (strncmp(irq_name, "hs_phy", strlen("hs_phy")) == 0)
+ irq_index = HS_PHY_IRQ_INDEX;
+
+ return irq_index;
+}
+
+static int dwc3_qcom_get_port_index(const char *irq_name, int irq_index)
+{
+ int port_index = -1;
+
+ switch (irq_index) {
+ case DP_HS_PHY_IRQ_INDEX:
+ if (strcmp(irq_name, "dp_hs_phy_irq") == 0)
+ port_index = 1;
+ else
+ sscanf(irq_name, "dp_hs_phy_%d", &port_index);
+ break;
+
+ case DM_HS_PHY_IRQ_INDEX:
+ if (strcmp(irq_name, "dm_hs_phy_irq") == 0)
+ port_index = 1;
+ else
+ sscanf(irq_name, "dm_hs_phy_%d", &port_index);
+ break;
+
+ case SS_PHY_IRQ_INDEX:
+ if (strcmp(irq_name, "ss_phy_irq") == 0)
+ port_index = 1;
+ else
+ sscanf(irq_name, "ss_phy_%d", &port_index);
+ break;
+
+ case HS_PHY_IRQ_INDEX:
+ port_index = 1;
+ break;
+ }
+
+ if (port_index > DWC3_MAX_PORTS)
+ port_index = -1;
+
+ return port_index;
+}
+
+static int dwc3_qcom_get_acpi_index(struct dwc3_qcom *qcom, int irq_index,
+ int port_index)
+{
+ const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata;
+ int acpi_index = -1;
+
+ /*
+ * Currently multiport supported targets don't have an ACPI variant.
+ * So return -1 if we are not dealing with first port of the controller.
+ */
+ if ((pdata == NULL) || (port_index != 1))
+ goto done;
+
+ if (irq_index == HS_PHY_IRQ_INDEX)
+ acpi_index = pdata->hs_phy_irq_index;
+ else
+ acpi_index = pdata->phy_irq_index[irq_index];
+
+done:
+ return acpi_index;
+}
+
static int dwc3_qcom_setup_irq(struct platform_device *pdev)
{
struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
- const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata;
+ struct device_node *np = pdev->dev.of_node;
+ const char **irq_names;
+ int port_index;
+ int acpi_index;
+ int irq_count;
+ int irq_index;
int irq;
int ret;
+ int i;

- irq = dwc3_qcom_get_irq(pdev, "hs_phy_irq",
- pdata ? pdata->hs_phy_irq_index : -1);
- if (irq > 0) {
- ret = dwc3_qcom_prep_irq(qcom, "hs_phy_irq",
- "qcom_dwc3 HS", irq);
- if (ret)
- return ret;
- qcom->hs_phy_irq = irq;
- }
+ irq_count = of_property_count_strings(np, "interrupt-names");
+ irq_names = devm_kzalloc(&pdev->dev, sizeof(*irq_names) * irq_count, GFP_KERNEL);
+ if (!irq_names)
+ return -ENOMEM;

- irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq",
- pdata ? pdata->dp_hs_phy_irq_index : -1);
- if (irq > 0) {
- ret = dwc3_qcom_prep_irq(qcom, "dp_hs_phy_irq",
- "qcom_dwc3 DP_HS", irq);
- if (ret)
- return ret;
- qcom->dp_hs_phy_irq = irq;
- }
+ ret = of_property_read_string_array(np, "interrupt-names",
+ irq_names, irq_count);
+ for (i = 0; i < irq_count; i++) {
+ irq_index = dwc3_qcom_get_irq_index(irq_names[i]);
+ if (irq_index == -1) {
+ dev_dbg(&pdev->dev, "Invalid IRQ not handled");
+ continue;
+ }

- irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq",
- pdata ? pdata->dm_hs_phy_irq_index : -1);
- if (irq > 0) {
- ret = dwc3_qcom_prep_irq(qcom, "dm_hs_phy_irq",
- "qcom_dwc3 DM_HS", irq);
- if (ret)
- return ret;
- qcom->dm_hs_phy_irq = irq;
- }
+ port_index = dwc3_qcom_get_port_index(irq_names[i], irq_index);
+ if (port_index == -1) {
+ dev_dbg(&pdev->dev, "Port index invalid. IRQ not handled");
+ continue;
+ }

- irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq",
- pdata ? pdata->ss_phy_irq_index : -1);
- if (irq > 0) {
- ret = dwc3_qcom_prep_irq(qcom, "ss_phy_irq",
- "qcom_dwc3 SS", irq);
- if (ret)
- return ret;
- qcom->ss_phy_irq = irq;
+ acpi_index = dwc3_qcom_get_acpi_index(qcom, irq_index, port_index);
+
+ irq = dwc3_qcom_get_irq(pdev, irq_names[i], acpi_index);
+ if (irq > 0) {
+ ret = dwc3_qcom_prep_irq(qcom, irq_names[i],
+ irq_names[i], irq);
+ if (ret)
+ return ret;
+
+ if (irq_index == HS_PHY_IRQ_INDEX)
+ qcom->hs_phy_irq = irq;
+ else
+ qcom->phy_irq[irq_index][port_index-1] = irq;
+
+ if (qcom->num_ports < port_index)
+ qcom->num_ports = port_index;
+ }
}

return 0;
@@ -1030,20 +1129,16 @@ static const struct dwc3_acpi_pdata sdm845_acpi_pdata = {
.qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
.qscratch_base_size = SDM845_QSCRATCH_SIZE,
.dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
+ .phy_irq_index = {4, 3, 2},
.hs_phy_irq_index = 1,
- .dp_hs_phy_irq_index = 4,
- .dm_hs_phy_irq_index = 3,
- .ss_phy_irq_index = 2
};

static const struct dwc3_acpi_pdata sdm845_acpi_urs_pdata = {
.qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
.qscratch_base_size = SDM845_QSCRATCH_SIZE,
.dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
+ .phy_irq_index = {4, 3, 2},
.hs_phy_irq_index = 1,
- .dp_hs_phy_irq_index = 4,
- .dm_hs_phy_irq_index = 3,
- .ss_phy_irq_index = 2,
.is_urs = true,
};

--
2.40.0