Message ID | 20240206051825.1038685-8-quic_kriskura@quicinc.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | Add multiport support for DWC3 controllers | expand |
On Tue, Feb 06, 2024 at 10:48:23AM +0530, Krishna Kurapati wrote: > On multiport supported controllers, each port has its own DP/DM > and SS (if super speed capable) interrupts. As per the bindings, > their interrupt names differ from standard ones having "_x" added > as suffix (x indicates port number). Refactor dwc3_qcom_setup_irq() > call to parse multiport interrupts along with non-multiport ones. > > Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com> Reviewed-by: Bjorn Andersson <andersson@kernel.org> Regards, Bjorn > --- > drivers/usb/dwc3/dwc3-qcom.c | 222 +++++++++++++++++++++++++---------- > 1 file changed, 161 insertions(+), 61 deletions(-) > > diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c > index 08df29584366..a20d63a791bd 100644 > --- a/drivers/usb/dwc3/dwc3-qcom.c > +++ b/drivers/usb/dwc3/dwc3-qcom.c > @@ -53,17 +53,33 @@ > #define APPS_USB_AVG_BW 0 > #define APPS_USB_PEAK_BW MBps_to_icc(40) > > +#define NUM_PHY_IRQ 4 > + > +enum dwc3_qcom_phy_index { > + DP_HS_PHY_IRQ_INDEX, > + DM_HS_PHY_IRQ_INDEX, > + SS_PHY_IRQ_INDEX, > + QUSB2_PHY_IRQ_INDEX, > +}; > + > struct dwc3_acpi_pdata { > u32 qscratch_base_offset; > u32 qscratch_base_size; > u32 dwc3_core_base_size; > - int qusb2_phy_irq_index; > - int dp_hs_phy_irq_index; > - int dm_hs_phy_irq_index; > - int ss_phy_irq_index; > + /* > + * The phy_irq_index corresponds to ACPI indexes of (in order) > + * DP/DM/SS/QUSB2 IRQ's respectively. > + */ > + int phy_irq_index[NUM_PHY_IRQ]; > bool is_urs; > }; > > +struct dwc3_qcom_port { > + int dp_hs_phy_irq; > + int dm_hs_phy_irq; > + int ss_phy_irq; > +}; > + > struct dwc3_qcom { > struct device *dev; > void __iomem *qscratch_base; > @@ -74,9 +90,7 @@ struct dwc3_qcom { > struct reset_control *resets; > > int qusb2_phy_irq; > - int dp_hs_phy_irq; > - int dm_hs_phy_irq; > - int ss_phy_irq; > + struct dwc3_qcom_port port_info[DWC3_MAX_PORTS]; > enum usb_device_speed usb2_speed; > > struct extcon_dev *edev; > @@ -91,6 +105,7 @@ struct dwc3_qcom { > bool pm_suspended; > struct icc_path *icc_path_ddr; > struct icc_path *icc_path_apps; > + u8 num_ports; > }; > > static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val) > @@ -375,16 +390,16 @@ static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) > dwc3_qcom_disable_wakeup_irq(qcom->qusb2_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->port_info[0].dm_hs_phy_irq); > } 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->port_info[0].dp_hs_phy_irq); > } 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->port_info[0].dp_hs_phy_irq); > + dwc3_qcom_disable_wakeup_irq(qcom->port_info[0].dm_hs_phy_irq); > } > > - dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq); > + dwc3_qcom_disable_wakeup_irq(qcom->port_info[0].ss_phy_irq); > } > > static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) > @@ -401,20 +416,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, > - IRQ_TYPE_EDGE_FALLING); > + dwc3_qcom_enable_wakeup_irq(qcom->port_info[0].dm_hs_phy_irq, > + 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, > - IRQ_TYPE_EDGE_FALLING); > + dwc3_qcom_enable_wakeup_irq(qcom->port_info[0].dp_hs_phy_irq, > + IRQ_TYPE_EDGE_FALLING); > } else { > - dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq, > - IRQ_TYPE_EDGE_RISING); > - dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq, > - IRQ_TYPE_EDGE_RISING); > + dwc3_qcom_enable_wakeup_irq(qcom->port_info[0].dp_hs_phy_irq, > + IRQ_TYPE_EDGE_RISING); > + dwc3_qcom_enable_wakeup_irq(qcom->port_info[0].dm_hs_phy_irq, > + IRQ_TYPE_EDGE_RISING); > } > > - dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0); > + dwc3_qcom_enable_wakeup_irq(qcom->port_info[0].ss_phy_irq, 0); > } > > static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup) > @@ -535,6 +550,74 @@ static int dwc3_qcom_get_irq(struct platform_device *pdev, > return ret; > } > > +static int dwc3_qcom_get_irq_index(const char *irq_name) > +{ > + /* > + * Parse IRQ index based on prefixes from interrupt name. > + * Return -1 incase of an invalid interrupt name. > + */ > + 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, "qusb2_phy", strlen("qusb2_phy")) == 0) > + irq_index = QUSB2_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 QUSB2_PHY_IRQ_INDEX: > + port_index = 1; > + break; > + } > + > + if (port_index <= 0 || 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; > + > + /* > + * 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 || port_index != 1) > + return -1; > + > + return pdata->phy_irq_index[irq_index]; > +} > + > static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq, > const char *name) > { > @@ -554,44 +637,67 @@ static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq, > 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, "qusb2_phy", > - pdata ? pdata->qusb2_phy_irq_index : -1); > - if (irq > 0) { > - ret = dwc3_qcom_request_irq(qcom, irq, "hs_phy_irq"); > - if (ret) > - return ret; > - qcom->qusb2_phy_irq = irq; > - } > + irq_count = of_property_count_strings(np, "interrupt-names"); > + if (irq_count < 0) > + return -EINVAL; > > - irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq", > - pdata ? pdata->dp_hs_phy_irq_index : -1); > - if (irq > 0) { > - ret = dwc3_qcom_request_irq(qcom, irq, "dp_hs_phy_irq"); > - if (ret) > - return ret; > - qcom->dp_hs_phy_irq = irq; > - } > + irq_names = devm_kcalloc(&pdev->dev, irq_count, sizeof(*irq_names), GFP_KERNEL); > + if (!irq_names) > + return -ENOMEM; > > - irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq", > - pdata ? pdata->dm_hs_phy_irq_index : -1); > - if (irq > 0) { > - ret = dwc3_qcom_request_irq(qcom, irq, "dm_hs_phy_irq"); > - if (ret) > - return ret; > - qcom->dm_hs_phy_irq = irq; > - } > + ret = of_property_read_string_array(np, "interrupt-names", > + irq_names, irq_count); > + if (!ret) > + return ret; > > - irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq", > - pdata ? pdata->ss_phy_irq_index : -1); > - if (irq > 0) { > - ret = dwc3_qcom_request_irq(qcom, irq, "ss_phy_irq"); > - if (ret) > - return ret; > - qcom->ss_phy_irq = irq; > + for (i = 0; i < irq_count; i++) { > + irq_index = dwc3_qcom_get_irq_index(irq_names[i]); > + if (irq_index == -1) { > + dev_err(&pdev->dev, "Unknown interrupt-name \"%s\" found\n", irq_names[i]); > + continue; > + } > + port_index = dwc3_qcom_get_port_index(irq_names[i], irq_index); > + if (port_index == -1) { > + dev_err(&pdev->dev, "Invalid interrupt-name suffix \"%s\"\n", irq_names[i]); > + continue; > + } > + > + 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_request_irq(qcom, irq, irq_names[i]); > + if (ret) > + return ret; > + > + switch (irq_index) { > + case DP_HS_PHY_IRQ_INDEX: > + qcom->port_info[port_index - 1].dp_hs_phy_irq = irq; > + break; > + case DM_HS_PHY_IRQ_INDEX: > + qcom->port_info[port_index - 1].dm_hs_phy_irq = irq; > + break; > + case SS_PHY_IRQ_INDEX: > + qcom->port_info[port_index - 1].ss_phy_irq = irq; > + break; > + case QUSB2_PHY_IRQ_INDEX: > + qcom->qusb2_phy_irq = irq; > + break; > + } > + > + if (qcom->num_ports < port_index) > + qcom->num_ports = port_index; > + } > } > > return 0; > @@ -1053,20 +1159,14 @@ 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, > - .qusb2_phy_irq_index = 1, > - .dp_hs_phy_irq_index = 4, > - .dm_hs_phy_irq_index = 3, > - .ss_phy_irq_index = 2 > + .phy_irq_index = {4, 3, 2, 1}, > }; > > 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, > - .qusb2_phy_irq_index = 1, > - .dp_hs_phy_irq_index = 4, > - .dm_hs_phy_irq_index = 3, > - .ss_phy_irq_index = 2, > + .phy_irq_index = {4, 3, 2, 1}, > .is_urs = true, > }; > > -- > 2.34.1 >
On Tue, Feb 06, 2024, Krishna Kurapati wrote: > On multiport supported controllers, each port has its own DP/DM > and SS (if super speed capable) interrupts. As per the bindings, > their interrupt names differ from standard ones having "_x" added > as suffix (x indicates port number). Refactor dwc3_qcom_setup_irq() > call to parse multiport interrupts along with non-multiport ones. > > Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com> > --- > drivers/usb/dwc3/dwc3-qcom.c | 222 +++++++++++++++++++++++++---------- > 1 file changed, 161 insertions(+), 61 deletions(-) > > diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c > index 08df29584366..a20d63a791bd 100644 > --- a/drivers/usb/dwc3/dwc3-qcom.c > +++ b/drivers/usb/dwc3/dwc3-qcom.c > @@ -53,17 +53,33 @@ > #define APPS_USB_AVG_BW 0 > #define APPS_USB_PEAK_BW MBps_to_icc(40) > > +#define NUM_PHY_IRQ 4 > + > +enum dwc3_qcom_phy_index { > + DP_HS_PHY_IRQ_INDEX, > + DM_HS_PHY_IRQ_INDEX, > + SS_PHY_IRQ_INDEX, > + QUSB2_PHY_IRQ_INDEX, > +}; > + > struct dwc3_acpi_pdata { > u32 qscratch_base_offset; > u32 qscratch_base_size; > u32 dwc3_core_base_size; > - int qusb2_phy_irq_index; > - int dp_hs_phy_irq_index; > - int dm_hs_phy_irq_index; > - int ss_phy_irq_index; > + /* > + * The phy_irq_index corresponds to ACPI indexes of (in order) > + * DP/DM/SS/QUSB2 IRQ's respectively. > + */ > + int phy_irq_index[NUM_PHY_IRQ]; > bool is_urs; > }; > > +struct dwc3_qcom_port { > + int dp_hs_phy_irq; > + int dm_hs_phy_irq; > + int ss_phy_irq; > +}; > + > struct dwc3_qcom { > struct device *dev; > void __iomem *qscratch_base; > @@ -74,9 +90,7 @@ struct dwc3_qcom { > struct reset_control *resets; > > int qusb2_phy_irq; > - int dp_hs_phy_irq; > - int dm_hs_phy_irq; > - int ss_phy_irq; > + struct dwc3_qcom_port port_info[DWC3_MAX_PORTS]; > enum usb_device_speed usb2_speed; > > struct extcon_dev *edev; > @@ -91,6 +105,7 @@ struct dwc3_qcom { > bool pm_suspended; > struct icc_path *icc_path_ddr; > struct icc_path *icc_path_apps; > + u8 num_ports; > }; > > static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val) > @@ -375,16 +390,16 @@ static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) > dwc3_qcom_disable_wakeup_irq(qcom->qusb2_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->port_info[0].dm_hs_phy_irq); > } 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->port_info[0].dp_hs_phy_irq); > } 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->port_info[0].dp_hs_phy_irq); > + dwc3_qcom_disable_wakeup_irq(qcom->port_info[0].dm_hs_phy_irq); > } > > - dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq); > + dwc3_qcom_disable_wakeup_irq(qcom->port_info[0].ss_phy_irq); > } > > static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) > @@ -401,20 +416,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, > - IRQ_TYPE_EDGE_FALLING); > + dwc3_qcom_enable_wakeup_irq(qcom->port_info[0].dm_hs_phy_irq, > + 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, > - IRQ_TYPE_EDGE_FALLING); > + dwc3_qcom_enable_wakeup_irq(qcom->port_info[0].dp_hs_phy_irq, > + IRQ_TYPE_EDGE_FALLING); > } else { > - dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq, > - IRQ_TYPE_EDGE_RISING); > - dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq, > - IRQ_TYPE_EDGE_RISING); > + dwc3_qcom_enable_wakeup_irq(qcom->port_info[0].dp_hs_phy_irq, > + IRQ_TYPE_EDGE_RISING); > + dwc3_qcom_enable_wakeup_irq(qcom->port_info[0].dm_hs_phy_irq, > + IRQ_TYPE_EDGE_RISING); > } > > - dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0); > + dwc3_qcom_enable_wakeup_irq(qcom->port_info[0].ss_phy_irq, 0); > } > > static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup) > @@ -535,6 +550,74 @@ static int dwc3_qcom_get_irq(struct platform_device *pdev, > return ret; > } > > +static int dwc3_qcom_get_irq_index(const char *irq_name) > +{ > + /* > + * Parse IRQ index based on prefixes from interrupt name. > + * Return -1 incase of an invalid interrupt name. > + */ > + 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, "qusb2_phy", strlen("qusb2_phy")) == 0) > + irq_index = QUSB2_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 QUSB2_PHY_IRQ_INDEX: > + port_index = 1; > + break; > + } > + > + if (port_index <= 0 || 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; > + > + /* > + * 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 || port_index != 1) > + return -1; > + > + return pdata->phy_irq_index[irq_index]; > +} > + > static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq, > const char *name) > { > @@ -554,44 +637,67 @@ static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq, > 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, "qusb2_phy", > - pdata ? pdata->qusb2_phy_irq_index : -1); > - if (irq > 0) { > - ret = dwc3_qcom_request_irq(qcom, irq, "hs_phy_irq"); > - if (ret) > - return ret; > - qcom->qusb2_phy_irq = irq; > - } > + irq_count = of_property_count_strings(np, "interrupt-names"); > + if (irq_count < 0) > + return -EINVAL; > > - irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq", > - pdata ? pdata->dp_hs_phy_irq_index : -1); > - if (irq > 0) { > - ret = dwc3_qcom_request_irq(qcom, irq, "dp_hs_phy_irq"); > - if (ret) > - return ret; > - qcom->dp_hs_phy_irq = irq; > - } > + irq_names = devm_kcalloc(&pdev->dev, irq_count, sizeof(*irq_names), GFP_KERNEL); > + if (!irq_names) > + return -ENOMEM; > > - irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq", > - pdata ? pdata->dm_hs_phy_irq_index : -1); > - if (irq > 0) { > - ret = dwc3_qcom_request_irq(qcom, irq, "dm_hs_phy_irq"); > - if (ret) > - return ret; > - qcom->dm_hs_phy_irq = irq; > - } > + ret = of_property_read_string_array(np, "interrupt-names", > + irq_names, irq_count); > + if (!ret) > + return ret; > > - irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq", > - pdata ? pdata->ss_phy_irq_index : -1); > - if (irq > 0) { > - ret = dwc3_qcom_request_irq(qcom, irq, "ss_phy_irq"); > - if (ret) > - return ret; > - qcom->ss_phy_irq = irq; > + for (i = 0; i < irq_count; i++) { > + irq_index = dwc3_qcom_get_irq_index(irq_names[i]); > + if (irq_index == -1) { > + dev_err(&pdev->dev, "Unknown interrupt-name \"%s\" found\n", irq_names[i]); > + continue; > + } > + port_index = dwc3_qcom_get_port_index(irq_names[i], irq_index); > + if (port_index == -1) { > + dev_err(&pdev->dev, "Invalid interrupt-name suffix \"%s\"\n", irq_names[i]); > + continue; > + } > + > + 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_request_irq(qcom, irq, irq_names[i]); > + if (ret) > + return ret; > + > + switch (irq_index) { > + case DP_HS_PHY_IRQ_INDEX: > + qcom->port_info[port_index - 1].dp_hs_phy_irq = irq; > + break; > + case DM_HS_PHY_IRQ_INDEX: > + qcom->port_info[port_index - 1].dm_hs_phy_irq = irq; > + break; > + case SS_PHY_IRQ_INDEX: > + qcom->port_info[port_index - 1].ss_phy_irq = irq; > + break; > + case QUSB2_PHY_IRQ_INDEX: > + qcom->qusb2_phy_irq = irq; > + break; > + } > + > + if (qcom->num_ports < port_index) > + qcom->num_ports = port_index; > + } > } > > return 0; > @@ -1053,20 +1159,14 @@ 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, > - .qusb2_phy_irq_index = 1, > - .dp_hs_phy_irq_index = 4, > - .dm_hs_phy_irq_index = 3, > - .ss_phy_irq_index = 2 > + .phy_irq_index = {4, 3, 2, 1}, > }; > > 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, > - .qusb2_phy_irq_index = 1, > - .dp_hs_phy_irq_index = 4, > - .dm_hs_phy_irq_index = 3, > - .ss_phy_irq_index = 2, > + .phy_irq_index = {4, 3, 2, 1}, > .is_urs = true, > }; > > -- > 2.34.1 > Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> BR, Thinh
diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 08df29584366..a20d63a791bd 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -53,17 +53,33 @@ #define APPS_USB_AVG_BW 0 #define APPS_USB_PEAK_BW MBps_to_icc(40) +#define NUM_PHY_IRQ 4 + +enum dwc3_qcom_phy_index { + DP_HS_PHY_IRQ_INDEX, + DM_HS_PHY_IRQ_INDEX, + SS_PHY_IRQ_INDEX, + QUSB2_PHY_IRQ_INDEX, +}; + struct dwc3_acpi_pdata { u32 qscratch_base_offset; u32 qscratch_base_size; u32 dwc3_core_base_size; - int qusb2_phy_irq_index; - int dp_hs_phy_irq_index; - int dm_hs_phy_irq_index; - int ss_phy_irq_index; + /* + * The phy_irq_index corresponds to ACPI indexes of (in order) + * DP/DM/SS/QUSB2 IRQ's respectively. + */ + int phy_irq_index[NUM_PHY_IRQ]; bool is_urs; }; +struct dwc3_qcom_port { + int dp_hs_phy_irq; + int dm_hs_phy_irq; + int ss_phy_irq; +}; + struct dwc3_qcom { struct device *dev; void __iomem *qscratch_base; @@ -74,9 +90,7 @@ struct dwc3_qcom { struct reset_control *resets; int qusb2_phy_irq; - int dp_hs_phy_irq; - int dm_hs_phy_irq; - int ss_phy_irq; + struct dwc3_qcom_port port_info[DWC3_MAX_PORTS]; enum usb_device_speed usb2_speed; struct extcon_dev *edev; @@ -91,6 +105,7 @@ struct dwc3_qcom { bool pm_suspended; struct icc_path *icc_path_ddr; struct icc_path *icc_path_apps; + u8 num_ports; }; static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val) @@ -375,16 +390,16 @@ static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) dwc3_qcom_disable_wakeup_irq(qcom->qusb2_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->port_info[0].dm_hs_phy_irq); } 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->port_info[0].dp_hs_phy_irq); } 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->port_info[0].dp_hs_phy_irq); + dwc3_qcom_disable_wakeup_irq(qcom->port_info[0].dm_hs_phy_irq); } - dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq); + dwc3_qcom_disable_wakeup_irq(qcom->port_info[0].ss_phy_irq); } static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) @@ -401,20 +416,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, - IRQ_TYPE_EDGE_FALLING); + dwc3_qcom_enable_wakeup_irq(qcom->port_info[0].dm_hs_phy_irq, + 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, - IRQ_TYPE_EDGE_FALLING); + dwc3_qcom_enable_wakeup_irq(qcom->port_info[0].dp_hs_phy_irq, + IRQ_TYPE_EDGE_FALLING); } else { - dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq, - IRQ_TYPE_EDGE_RISING); - dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq, - IRQ_TYPE_EDGE_RISING); + dwc3_qcom_enable_wakeup_irq(qcom->port_info[0].dp_hs_phy_irq, + IRQ_TYPE_EDGE_RISING); + dwc3_qcom_enable_wakeup_irq(qcom->port_info[0].dm_hs_phy_irq, + IRQ_TYPE_EDGE_RISING); } - dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0); + dwc3_qcom_enable_wakeup_irq(qcom->port_info[0].ss_phy_irq, 0); } static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup) @@ -535,6 +550,74 @@ static int dwc3_qcom_get_irq(struct platform_device *pdev, return ret; } +static int dwc3_qcom_get_irq_index(const char *irq_name) +{ + /* + * Parse IRQ index based on prefixes from interrupt name. + * Return -1 incase of an invalid interrupt name. + */ + 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, "qusb2_phy", strlen("qusb2_phy")) == 0) + irq_index = QUSB2_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 QUSB2_PHY_IRQ_INDEX: + port_index = 1; + break; + } + + if (port_index <= 0 || 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; + + /* + * 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 || port_index != 1) + return -1; + + return pdata->phy_irq_index[irq_index]; +} + static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq, const char *name) { @@ -554,44 +637,67 @@ static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq, 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, "qusb2_phy", - pdata ? pdata->qusb2_phy_irq_index : -1); - if (irq > 0) { - ret = dwc3_qcom_request_irq(qcom, irq, "hs_phy_irq"); - if (ret) - return ret; - qcom->qusb2_phy_irq = irq; - } + irq_count = of_property_count_strings(np, "interrupt-names"); + if (irq_count < 0) + return -EINVAL; - irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq", - pdata ? pdata->dp_hs_phy_irq_index : -1); - if (irq > 0) { - ret = dwc3_qcom_request_irq(qcom, irq, "dp_hs_phy_irq"); - if (ret) - return ret; - qcom->dp_hs_phy_irq = irq; - } + irq_names = devm_kcalloc(&pdev->dev, irq_count, sizeof(*irq_names), GFP_KERNEL); + if (!irq_names) + return -ENOMEM; - irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq", - pdata ? pdata->dm_hs_phy_irq_index : -1); - if (irq > 0) { - ret = dwc3_qcom_request_irq(qcom, irq, "dm_hs_phy_irq"); - if (ret) - return ret; - qcom->dm_hs_phy_irq = irq; - } + ret = of_property_read_string_array(np, "interrupt-names", + irq_names, irq_count); + if (!ret) + return ret; - irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq", - pdata ? pdata->ss_phy_irq_index : -1); - if (irq > 0) { - ret = dwc3_qcom_request_irq(qcom, irq, "ss_phy_irq"); - if (ret) - return ret; - qcom->ss_phy_irq = irq; + for (i = 0; i < irq_count; i++) { + irq_index = dwc3_qcom_get_irq_index(irq_names[i]); + if (irq_index == -1) { + dev_err(&pdev->dev, "Unknown interrupt-name \"%s\" found\n", irq_names[i]); + continue; + } + port_index = dwc3_qcom_get_port_index(irq_names[i], irq_index); + if (port_index == -1) { + dev_err(&pdev->dev, "Invalid interrupt-name suffix \"%s\"\n", irq_names[i]); + continue; + } + + 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_request_irq(qcom, irq, irq_names[i]); + if (ret) + return ret; + + switch (irq_index) { + case DP_HS_PHY_IRQ_INDEX: + qcom->port_info[port_index - 1].dp_hs_phy_irq = irq; + break; + case DM_HS_PHY_IRQ_INDEX: + qcom->port_info[port_index - 1].dm_hs_phy_irq = irq; + break; + case SS_PHY_IRQ_INDEX: + qcom->port_info[port_index - 1].ss_phy_irq = irq; + break; + case QUSB2_PHY_IRQ_INDEX: + qcom->qusb2_phy_irq = irq; + break; + } + + if (qcom->num_ports < port_index) + qcom->num_ports = port_index; + } } return 0; @@ -1053,20 +1159,14 @@ 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, - .qusb2_phy_irq_index = 1, - .dp_hs_phy_irq_index = 4, - .dm_hs_phy_irq_index = 3, - .ss_phy_irq_index = 2 + .phy_irq_index = {4, 3, 2, 1}, }; 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, - .qusb2_phy_irq_index = 1, - .dp_hs_phy_irq_index = 4, - .dm_hs_phy_irq_index = 3, - .ss_phy_irq_index = 2, + .phy_irq_index = {4, 3, 2, 1}, .is_urs = true, };
On multiport supported controllers, each port has its own DP/DM and SS (if super speed capable) interrupts. As per the bindings, their interrupt names differ from standard ones having "_x" added as suffix (x indicates port number). Refactor dwc3_qcom_setup_irq() call to parse multiport interrupts along with non-multiport ones. Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com> --- drivers/usb/dwc3/dwc3-qcom.c | 222 +++++++++++++++++++++++++---------- 1 file changed, 161 insertions(+), 61 deletions(-)