diff mbox series

[4/6] spi: spi-geni-qcom: Add interconnect support

Message ID 1581946205-27189-5-git-send-email-akashast@codeaurora.org
State New
Headers show
Series Add interconnect support to UART, I2C, SPI and QSPI | expand

Commit Message

Akash Asthana Feb. 17, 2020, 1:30 p.m. UTC
Get the interconnect paths for SPI based Serial Engine device
and vote according to the current bus speed of the driver.

Signed-off-by: Akash Asthana <akashast@codeaurora.org>
---
 drivers/spi/spi-geni-qcom.c | 65 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 62 insertions(+), 3 deletions(-)

Comments

Matthias Kaehlcke Feb. 21, 2020, 6:55 p.m. UTC | #1
On Wed, Feb 19, 2020 at 10:09:50AM -0800, Matthias Kaehlcke wrote:
> On Mon, Feb 17, 2020 at 07:00:03PM +0530, Akash Asthana wrote:
> > Get the interconnect paths for SPI based Serial Engine device
> > and vote according to the current bus speed of the driver.
> > 
> > Signed-off-by: Akash Asthana <akashast@codeaurora.org>
> > ---
> >  drivers/spi/spi-geni-qcom.c | 65 ++++++++++++++++++++++++++++++++++++++++++---
> >  1 file changed, 62 insertions(+), 3 deletions(-)
> > 
> > diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
> > index c397242..a066ef26 100644
> > --- a/drivers/spi/spi-geni-qcom.c
> > +++ b/drivers/spi/spi-geni-qcom.c
> > @@ -608,16 +653,25 @@ static int spi_geni_remove(struct platform_device *pdev)
> >  	spi_unregister_master(spi);
> >  
> >  	free_irq(mas->irq, spi);
> > +	geni_spi_icc_put(&mas->se);
> >  	pm_runtime_disable(&pdev->dev);
> >  	return 0;
> >  }
> >  
> >  static int __maybe_unused spi_geni_runtime_suspend(struct device *dev)
> >  {
> > +	int ret;
> >  	struct spi_master *spi = dev_get_drvdata(dev);
> >  	struct spi_geni_master *mas = spi_master_get_devdata(spi);
> >  
> > -	return geni_se_resources_off(&mas->se);
> > +	ret = geni_se_resources_off(&mas->se);
> > +	if (ret)
> > +		return ret;
> > +
> > +	icc_set_bw(mas->se.icc_path[GENI_TO_CORE], 0, 0);
> 
> This causes my SC7180 system to reset at boot time:
> 
> [    3.509652] qcom-qmp-phy 88e9000.phy-wrapper: Registered Qcom-QMP phy
> [    3.516956] qcom-qusb2-phy 88e3000.phy: Registered Qcom-QUSB2 phy
> [    3.524450] geni_se_qup 8c0000.geniqup: Adding to iommu group 4
> [    3.533896] spi_master spi0: will run message pump with realtime priority
> <reset>
> 
> The system does not reset when passing 'Bps_to_icc(1000)' (=> 1) instead of 0.

I found this is related with the use of 'earlycon'.

There is a short window where the early console and the 'real' console coexist:

[    3.858122] printk: console [ttyMSM0] enabled
[    3.875692] printk: bootconsole [qcom_geni0] disabled

The reset probably occurs when the early console tries to write, but the ICC is
effectively disabled because ttyMSM0 and the other geni ports are runtime
suspended.

In any case that's not an issue of the SPI driver, but needs to be addressed
somewhere in the console/UART code.
diff mbox series

Patch

diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index c397242..a066ef26 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -118,6 +118,35 @@  static int get_spi_clk_cfg(unsigned int speed_hz,
 	return ret;
 }
 
+static int geni_spi_icc_get(struct geni_se *se)
+{
+	if (!se)
+		return -EINVAL;
+
+	se->icc_path[GENI_TO_CORE] = of_icc_get(se->dev, "qup-core");
+	if (IS_ERR(se->icc_path[GENI_TO_CORE]))
+		return PTR_ERR(se->icc_path[GENI_TO_CORE]);
+
+	se->icc_path[CPU_TO_GENI] = of_icc_get(se->dev, "qup-config");
+	if (IS_ERR(se->icc_path[CPU_TO_GENI])) {
+		icc_put(se->icc_path[GENI_TO_CORE]);
+		se->icc_path[GENI_TO_CORE] = NULL;
+		return PTR_ERR(se->icc_path[CPU_TO_GENI]);
+	}
+
+	return 0;
+}
+
+void geni_spi_icc_put(struct geni_se *se)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(se->icc_path); i++) {
+		icc_put(se->icc_path[i]);
+		se->icc_path[i] = NULL;
+	}
+}
+
 static void handle_fifo_timeout(struct spi_master *spi,
 				struct spi_message *msg)
 {
@@ -234,6 +263,11 @@  static int setup_fifo_params(struct spi_device *spi_slv,
 		return ret;
 	}
 
+	/* Set BW quota for CPU as driver supports FIFO mode only */
+	se->avg_bw_cpu = Bps_to_icc(mas->cur_speed_hz);
+	se->peak_bw_cpu = Bps_to_icc(2 * mas->cur_speed_hz);
+	icc_set_bw(se->icc_path[CPU_TO_GENI], se->avg_bw_cpu, se->peak_bw_cpu);
+
 	clk_sel = idx & CLK_SEL_MSK;
 	m_clk_cfg = (div << CLK_DIV_SHFT) | SER_CLK_EN;
 	spi_setup_word_len(mas, spi_slv->mode, spi_slv->bits_per_word);
@@ -578,13 +612,22 @@  static int spi_geni_probe(struct platform_device *pdev)
 	spin_lock_init(&mas->lock);
 	pm_runtime_enable(dev);
 
-	ret = spi_geni_init(mas);
+	ret = geni_spi_icc_get(&mas->se);
 	if (ret)
 		goto spi_geni_probe_runtime_disable;
+	/* Set the bus quota to a reasonable value */
+	mas->se.avg_bw_core = Bps_to_icc(CORE_2X_50_MHZ);
+	mas->se.peak_bw_core = Bps_to_icc(CORE_2X_100_MHZ);
+	mas->se.avg_bw_cpu = Bps_to_icc(1000);
+	mas->se.peak_bw_cpu = Bps_to_icc(1000);
+
+	ret = spi_geni_init(mas);
+	if (ret)
+		goto spi_geni_icc_put;
 
 	ret = request_irq(mas->irq, geni_spi_isr, 0, dev_name(dev), spi);
 	if (ret)
-		goto spi_geni_probe_runtime_disable;
+		goto spi_geni_icc_put;
 
 	ret = spi_register_master(spi);
 	if (ret)
@@ -593,6 +636,8 @@  static int spi_geni_probe(struct platform_device *pdev)
 	return 0;
 spi_geni_probe_free_irq:
 	free_irq(mas->irq, spi);
+spi_geni_icc_put:
+	geni_spi_icc_put(&mas->se);
 spi_geni_probe_runtime_disable:
 	pm_runtime_disable(dev);
 	spi_master_put(spi);
@@ -608,16 +653,25 @@  static int spi_geni_remove(struct platform_device *pdev)
 	spi_unregister_master(spi);
 
 	free_irq(mas->irq, spi);
+	geni_spi_icc_put(&mas->se);
 	pm_runtime_disable(&pdev->dev);
 	return 0;
 }
 
 static int __maybe_unused spi_geni_runtime_suspend(struct device *dev)
 {
+	int ret;
 	struct spi_master *spi = dev_get_drvdata(dev);
 	struct spi_geni_master *mas = spi_master_get_devdata(spi);
 
-	return geni_se_resources_off(&mas->se);
+	ret = geni_se_resources_off(&mas->se);
+	if (ret)
+		return ret;
+
+	icc_set_bw(mas->se.icc_path[GENI_TO_CORE], 0, 0);
+	icc_set_bw(mas->se.icc_path[CPU_TO_GENI], 0, 0);
+
+	return 0;
 }
 
 static int __maybe_unused spi_geni_runtime_resume(struct device *dev)
@@ -625,6 +679,11 @@  static int __maybe_unused spi_geni_runtime_resume(struct device *dev)
 	struct spi_master *spi = dev_get_drvdata(dev);
 	struct spi_geni_master *mas = spi_master_get_devdata(spi);
 
+	icc_set_bw(mas->se.icc_path[GENI_TO_CORE], mas->se.avg_bw_core,
+		mas->se.peak_bw_core);
+	icc_set_bw(mas->se.icc_path[CPU_TO_GENI], mas->se.avg_bw_cpu,
+		mas->se.peak_bw_cpu);
+
 	return geni_se_resources_on(&mas->se);
 }