Re: [PATCH v10 06/11] usb: dwc3: qcom: Refactor IRQ handling in QCOM Glue driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Jul 28, 2023 at 04:03:02AM +0530, Krishna Kurapati wrote:
> Refactor setup_irq call to facilitate reading multiport IRQ's along
> with non mulitport ones. For SA8295, there are 4-DP/4-DM and 2-SS
> IRQ's. Check whether device is multiport capable or not and read all
> interrupts for DP/DM/SS on each port accordingly.
> 
> Signed-off-by: Krishna Kurapati <quic_kriskura@xxxxxxxxxxx>
> ---
>  drivers/usb/dwc3/dwc3-qcom.c | 277 ++++++++++++++++++++++++-----------
>  1 file changed, 190 insertions(+), 87 deletions(-)
> 
> diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
> index 3de43df6bbe8..ad89ded116d3 100644
> --- a/drivers/usb/dwc3/dwc3-qcom.c
> +++ b/drivers/usb/dwc3/dwc3-qcom.c
> @@ -64,33 +64,61 @@ struct dwc3_acpi_pdata {
>  	bool			is_urs;
>  };
>  
> +struct dwc3_qcom_of_match_data {
> +	u8	num_ports;
> +};
> +
>  struct dwc3_qcom {
> -	struct device		*dev;
> -	void __iomem		*qscratch_base;
> -	struct platform_device	*dwc3;
> -	struct platform_device	*urs_usb;
> -	struct clk		**clks;
> -	int			num_clocks;
> -	struct reset_control	*resets;
> -
> -	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;
> -	struct extcon_dev	*host_edev;
> -	struct notifier_block	vbus_nb;
> -	struct notifier_block	host_nb;
> +	struct device				*dev;
> +	void __iomem				*qscratch_base;
> +	struct platform_device			*dwc3;
> +	struct platform_device			*urs_usb;
> +	struct clk				**clks;
> +	int					num_clocks;
> +	struct reset_control			*resets;
> +
> +	int					hs_phy_irq;
> +	int					dp_hs_phy_irq[DWC3_MAX_PORTS];
> +	int					dm_hs_phy_irq[DWC3_MAX_PORTS];
> +	int					ss_phy_irq[DWC3_MAX_PORTS];
> +	enum usb_device_speed			usb2_speed;
> +
> +	struct extcon_dev			*edev;
> +	struct extcon_dev			*host_edev;
> +	struct notifier_block			vbus_nb;
> +	struct notifier_block			host_nb;
> +
> +	const struct dwc3_acpi_pdata		*acpi_pdata;
> +
> +	enum usb_dr_mode			mode;
> +	bool					is_suspended;
> +	bool					pm_suspended;
> +	struct icc_path				*icc_path_ddr;
> +	struct icc_path				*icc_path_apps;
> +	const struct dwc3_qcom_of_match_data	*data;

Please don't adjust indentation of unrelated code, it makes it hard to
see what actually changed.

> +};
> +
> +static const struct dwc3_qcom_of_match_data qcom_dwc3  = {
> +	.num_ports = 1,
> +};
>  
> -	const struct dwc3_acpi_pdata *acpi_pdata;
> +static const struct dwc3_qcom_of_match_data sx8280xp_qcom_dwc3 = {
> +	.num_ports = 4,
> +};
>  
> -	enum usb_dr_mode	mode;
> -	bool			is_suspended;
> -	bool			pm_suspended;
> -	struct icc_path		*icc_path_ddr;
> -	struct icc_path		*icc_path_apps;
> +/*
> + * Driver needs to read HS/DP_HS/DM_HS/SS IRQ's. Currently, for
> + * SA8295 which supports mutliport, thre are 4 DP/ 4 DM/ 2 SS IRQ's
> + * and 1 HS IRQ present. So avoid trying to read HS_PHY_IRQ for 4
> + * ports of SA8295.
> + */

The last part here is relevant information, but it doesn't seem to
relate to this define.

Also, does all platforms have this configuration of interrupts?

> +#define MAX_PHY_IRQ	4
> +
> +enum dwc3_qcom_phy_irq_identifier {
> +	HS_PHY_IRQ = 0,
> +	DP_HS_PHY_IRQ,
> +	DM_HS_PHY_IRQ,
> +	SS_PHY_IRQ,
>  };

This enum is unused.

>  
[..]
> +static int dwc3_get_acpi_index(const struct dwc3_acpi_pdata *pdata, int irq_index)
> +{
> +	int acpi_index = -1;
> +
> +	if (!pdata)
> +		return -1;
> +
> +	if (irq_index == DP_HS_PHY_IRQ)
> +		acpi_index = pdata->dp_hs_phy_irq_index;
> +	else if (irq_index == DM_HS_PHY_IRQ)
> +		acpi_index = pdata->dm_hs_phy_irq_index;
> +	else if (irq_index == SS_PHY_IRQ)
> +		acpi_index = pdata->ss_phy_irq_index;

It looks favourable to put these in an array, instead of having to pull
them out of 4 different variables conditionally.

> +
> +	return acpi_index;
> +}
> +
> +static int dwc3_get_port_irq(struct platform_device *pdev, u8 port_index)
> +{
> +	struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
> +	bool is_mp_supported = (qcom->data->num_ports > 1) ? true : false;
> +	const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata;
> +	char *disp_name;
> +	int acpi_index;
> +	char *dt_name;
> +	int ret;
> +	int irq;
> +	int i;
> +
> +	/*
> +	 * We need to read only DP/DM/SS IRQ's here.
> +	 * So loop over from 1->3 and accordingly modify respective phy_irq[].
> +	 */
> +	for (i = 1; i < MAX_PHY_IRQ; i++) {
> +
> +		if (!is_mp_supported && (port_index == 0)) {
> +			if (i == DP_HS_PHY_IRQ) {
> +				dt_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
> +					"dp_hs_phy_irq");
> +				disp_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
> +					"qcom_dwc3 DP_HS");
> +			} else if (i == DM_HS_PHY_IRQ) {
> +				dt_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
> +					"dm_hs_phy_irq");
> +				disp_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
> +					"qcom_dwc3 DM_HS");
> +			} else if (i == SS_PHY_IRQ) {
> +				dt_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
> +					"ss_phy_irq");
> +				disp_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
> +					"qcom_dwc3 SS");
> +			}
> +		} else {
> +			if (i == DP_HS_PHY_IRQ) {
> +				dt_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
> +					"dp_hs_phy_%d", port_index + 1);
> +				disp_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
> +					"qcom_dwc3 DP_HS%d", port_index + 1);
> +			} else if (i == DM_HS_PHY_IRQ) {
> +				dt_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
> +					"dm_hs_phy_%d", port_index + 1);
> +				disp_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
> +					"qcom_dwc3 DM_HS%d", port_index + 1);
> +			} else if (i == SS_PHY_IRQ) {
> +				dt_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
> +					"ss_phy_%d", port_index + 1);
> +				disp_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
> +					"qcom_dwc3 SS%d", port_index + 1);
> +			}

There is too much repetition in this for my liking.

>  		}
> -		qcom->hs_phy_irq = irq;
> -	}
>  
> -	irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq",
> -				pdata ? pdata->dp_hs_phy_irq_index : -1);
> -	if (irq > 0) {
> -		irq_set_status_flags(irq, IRQ_NOAUTOEN);
> -		ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
> -					qcom_dwc3_resume_irq,
> -					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
> -					"qcom_dwc3 DP_HS", qcom);
> -		if (ret) {
> -			dev_err(qcom->dev, "dp_hs_phy_irq failed: %d\n", ret);
> -			return ret;
> +		if (!dt_name || !disp_name)
> +			return -ENOMEM;
> +
> +		acpi_index = !is_mp_supported ? dwc3_get_acpi_index(pdata, i) : -1;
> +
> +		irq = dwc3_qcom_get_irq(pdev, dt_name, acpi_index);
> +		if (irq > 0) {
> +			ret = dwc3_qcom_prep_irq(qcom, dt_name, disp_name, irq);
> +			if (ret)
> +				return ret;
> +
> +			if (i == DP_HS_PHY_IRQ)
> +				qcom->dp_hs_phy_irq[port_index] = irq;
> +			else if (i == DM_HS_PHY_IRQ)
> +				qcom->dm_hs_phy_irq[port_index] = irq;
> +			else if (i == SS_PHY_IRQ)
> +				qcom->ss_phy_irq[port_index] = irq;
>  		}
> -		qcom->dp_hs_phy_irq = irq;
>  	}
>  
> -	irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq",
> -				pdata ? pdata->dm_hs_phy_irq_index : -1);
> +	return 0;
> +}
> +
> +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;
> +	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) {
> -		irq_set_status_flags(irq, IRQ_NOAUTOEN);
> -		ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
> -					qcom_dwc3_resume_irq,
> -					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
> -					"qcom_dwc3 DM_HS", qcom);
> -		if (ret) {
> -			dev_err(qcom->dev, "dm_hs_phy_irq failed: %d\n", ret);
> +		ret = dwc3_qcom_prep_irq(qcom, "hs_phy_irq", "qcom_dwc3 HS",irq);
> +		if (ret)

It would be nice to have this refactored out in a separate commit.

>  			return ret;
> -		}
> -		qcom->dm_hs_phy_irq = irq;
> +		qcom->hs_phy_irq = irq;
>  	}
>  
> -	irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq",
> -				pdata ? pdata->ss_phy_irq_index : -1);
> -	if (irq > 0) {
> -		irq_set_status_flags(irq, IRQ_NOAUTOEN);
> -		ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
> -					qcom_dwc3_resume_irq,
> -					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
> -					"qcom_dwc3 SS", qcom);
> -		if (ret) {
> -			dev_err(qcom->dev, "ss_phy_irq failed: %d\n", ret);
> +	for (i = 0; i < qcom->data->num_ports; i++) {
> +		ret = dwc3_get_port_irq(pdev, i);
> +		if (ret)
>  			return ret;
> -		}
> -		qcom->ss_phy_irq = irq;
>  	}
>  
>  	return 0;
> @@ -811,6 +905,8 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
>  	platform_set_drvdata(pdev, qcom);
>  	qcom->dev = &pdev->dev;
>  
> +	qcom->data = of_device_get_match_data(qcom->dev);
> +
>  	if (has_acpi_companion(dev)) {
>  		qcom->acpi_pdata = acpi_device_get_match_data(dev);
>  		if (!qcom->acpi_pdata) {
> @@ -1023,8 +1119,15 @@ static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = {
>  };
>  
>  static const struct of_device_id dwc3_qcom_of_match[] = {
> -	{ .compatible = "qcom,dwc3" },
> -	{ }
> +	{
> +		.compatible = "qcom,dwc3",
> +		.data = &qcom_dwc3,
> +	},
> +	{
> +		.compatible = "qcom,sc8280xp-dwc3-mp",
> +		.data = &sx8280xp_qcom_dwc3,
> +	},

I would prefer that we don't add a separate compatible, but rather just
try to parse the interrupts for multiport and fall back to single port.

If/when we figure out how to peak into the dwc3 core, we could
potentially introduce a check to aid the developer.

Regards,
Bjorn

> +	{ },
>  };
>  MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
>  
> -- 
> 2.40.0
> 



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux