linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/4] dt-bindings: spi: sun6i: add DT bindings for Allwinner R329 SPI
       [not found] <20220422155639.1071645-1-icenowy@outlook.com>
@ 2022-04-22 15:56 ` icenowy
  2022-04-22 23:49   ` Samuel Holland
  2022-04-22 15:56 ` [PATCH 2/4] spi: sun6i: change OF match data to a struct icenowy
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 12+ messages in thread
From: icenowy @ 2022-04-22 15:56 UTC (permalink / raw)
  To: Mark Brown, Chen-Yu Tsai, Jernej Skrabec, Samuel Holland, Maxime Ripard
  Cc: linux-spi, devicetree, linux-arm-kernel, linux-sunxi,
	linux-kernel, Icenowy Zheng

From: Icenowy Zheng <icenowy@aosc.io>

Allwinner R329 SPI has two controllers, and the second one has helper
functions for MIPI-DBI Type C.

Add compatible strings for these controllers

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 .../devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml        | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
index ca4c95345a49..6354635241fc 100644
--- a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
+++ b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
@@ -21,6 +21,8 @@ properties:
     oneOf:
       - const: allwinner,sun6i-a31-spi
       - const: allwinner,sun8i-h3-spi
+      - const: allwinner,sun50i-r329-spi
+      - const: allwinner,sun50i-r329-spi-dbi
       - items:
           - enum:
               - allwinner,sun8i-r40-spi
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/4] spi: sun6i: change OF match data to a struct
       [not found] <20220422155639.1071645-1-icenowy@outlook.com>
  2022-04-22 15:56 ` [PATCH 1/4] dt-bindings: spi: sun6i: add DT bindings for Allwinner R329 SPI icenowy
@ 2022-04-22 15:56 ` icenowy
  2022-04-22 23:50   ` Samuel Holland
  2022-04-22 15:56 ` [PATCH 3/4] spi: sun6i: add quirk for in-controller clock divider icenowy
  2022-04-22 15:56 ` [PATCH 4/4] spi: sun6i: add support for R329 SPI controllers icenowy
  3 siblings, 1 reply; 12+ messages in thread
From: icenowy @ 2022-04-22 15:56 UTC (permalink / raw)
  To: Mark Brown, Chen-Yu Tsai, Jernej Skrabec, Samuel Holland, Maxime Ripard
  Cc: linux-spi, devicetree, linux-arm-kernel, linux-sunxi,
	linux-kernel, Icenowy Zheng

From: Icenowy Zheng <icenowy@aosc.io>

As we're adding more properties to the OF match data, convert it to a
struct now.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 drivers/spi/spi-sun6i.c | 32 ++++++++++++++++++++++----------
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 23ad052528db..84c525b08ad0 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -85,6 +85,10 @@
 #define SUN6I_TXDATA_REG		0x200
 #define SUN6I_RXDATA_REG		0x300
 
+struct sun6i_spi_cfg {
+	unsigned long		fifo_depth;
+};
+
 struct sun6i_spi {
 	struct spi_master	*master;
 	void __iomem		*base_addr;
@@ -99,7 +103,7 @@ struct sun6i_spi {
 	const u8		*tx_buf;
 	u8			*rx_buf;
 	int			len;
-	unsigned long		fifo_depth;
+	const struct sun6i_spi_cfg *cfg;
 };
 
 static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg)
@@ -156,7 +160,7 @@ static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi)
 	u8 byte;
 
 	/* See how much data we can fit */
-	cnt = sspi->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi);
+	cnt = sspi->cfg->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi);
 
 	len = min((int)cnt, sspi->len);
 
@@ -289,14 +293,14 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
 		 * the hardcoded value used in old generation of Allwinner
 		 * SPI controller. (See spi-sun4i.c)
 		 */
-		trig_level = sspi->fifo_depth / 4 * 3;
+		trig_level = sspi->cfg->fifo_depth / 4 * 3;
 	} else {
 		/*
 		 * Setup FIFO DMA request trigger level
 		 * We choose 1/2 of the full fifo depth, that value will
 		 * be used as DMA burst length.
 		 */
-		trig_level = sspi->fifo_depth / 2;
+		trig_level = sspi->cfg->fifo_depth / 2;
 
 		if (tfr->tx_buf)
 			reg |= SUN6I_FIFO_CTL_TF_DRQ_EN;
@@ -410,9 +414,9 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
 	reg = SUN6I_INT_CTL_TC;
 
 	if (!use_dma) {
-		if (rx_len > sspi->fifo_depth)
+		if (rx_len > sspi->cfg->fifo_depth)
 			reg |= SUN6I_INT_CTL_RF_RDY;
-		if (tx_len > sspi->fifo_depth)
+		if (tx_len > sspi->cfg->fifo_depth)
 			reg |= SUN6I_INT_CTL_TF_ERQ;
 	}
 
@@ -543,7 +547,7 @@ static bool sun6i_spi_can_dma(struct spi_master *master,
 	 * the fifo length we can just fill the fifo and wait for a single
 	 * irq, so don't bother setting up dma
 	 */
-	return xfer->len > sspi->fifo_depth;
+	return xfer->len > sspi->cfg->fifo_depth;
 }
 
 static int sun6i_spi_probe(struct platform_device *pdev)
@@ -582,7 +586,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
 	}
 
 	sspi->master = master;
-	sspi->fifo_depth = (unsigned long)of_device_get_match_data(&pdev->dev);
+	sspi->cfg = of_device_get_match_data(&pdev->dev);
 
 	master->max_speed_hz = 100 * 1000 * 1000;
 	master->min_speed_hz = 3 * 1000;
@@ -696,9 +700,17 @@ static int sun6i_spi_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct sun6i_spi_cfg sun6i_a31_spi_cfg = {
+	.fifo_depth	= SUN6I_FIFO_DEPTH,
+};
+
+static const struct sun6i_spi_cfg sun8i_h3_spi_cfg = {
+	.fifo_depth	= SUN8I_FIFO_DEPTH,
+};
+
 static const struct of_device_id sun6i_spi_match[] = {
-	{ .compatible = "allwinner,sun6i-a31-spi", .data = (void *)SUN6I_FIFO_DEPTH },
-	{ .compatible = "allwinner,sun8i-h3-spi",  .data = (void *)SUN8I_FIFO_DEPTH },
+	{ .compatible = "allwinner,sun6i-a31-spi", .data = &sun6i_a31_spi_cfg },
+	{ .compatible = "allwinner,sun8i-h3-spi",  .data = &sun8i_h3_spi_cfg },
 	{}
 };
 MODULE_DEVICE_TABLE(of, sun6i_spi_match);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/4] spi: sun6i: add quirk for in-controller clock divider
       [not found] <20220422155639.1071645-1-icenowy@outlook.com>
  2022-04-22 15:56 ` [PATCH 1/4] dt-bindings: spi: sun6i: add DT bindings for Allwinner R329 SPI icenowy
  2022-04-22 15:56 ` [PATCH 2/4] spi: sun6i: change OF match data to a struct icenowy
@ 2022-04-22 15:56 ` icenowy
  2022-04-22 23:54   ` Samuel Holland
  2022-04-22 15:56 ` [PATCH 4/4] spi: sun6i: add support for R329 SPI controllers icenowy
  3 siblings, 1 reply; 12+ messages in thread
From: icenowy @ 2022-04-22 15:56 UTC (permalink / raw)
  To: Mark Brown, Chen-Yu Tsai, Jernej Skrabec, Samuel Holland, Maxime Ripard
  Cc: linux-spi, devicetree, linux-arm-kernel, linux-sunxi,
	linux-kernel, Icenowy Zheng

From: Icenowy Zheng <icenowy@aosc.io>

Previously SPI controllers in Allwinner SoCs has a clock divider inside.
However now the clock divider is removed and to set the transfer clock
rate it's only needed to set the SPI module clock to the target value.

Add a quirk for this kind of SPI controllers.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 drivers/spi/spi-sun6i.c | 68 +++++++++++++++++++++++------------------
 1 file changed, 38 insertions(+), 30 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 84c525b08ad0..fc81afc3a963 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -87,6 +87,7 @@
 
 struct sun6i_spi_cfg {
 	unsigned long		fifo_depth;
+	bool			has_clk_ctl;
 };
 
 struct sun6i_spi {
@@ -260,7 +261,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
 				  struct spi_transfer *tfr)
 {
 	struct sun6i_spi *sspi = spi_master_get_devdata(master);
-	unsigned int mclk_rate, div, div_cdr1, div_cdr2, timeout;
+	unsigned int div, div_cdr1, div_cdr2, timeout;
 	unsigned int start, end, tx_time;
 	unsigned int trig_level;
 	unsigned int tx_len = 0, rx_len = 0;
@@ -350,39 +351,44 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
 
 	sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
 
-	/* Ensure that we have a parent clock fast enough */
-	mclk_rate = clk_get_rate(sspi->mclk);
-	if (mclk_rate < (2 * tfr->speed_hz)) {
-		clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
-		mclk_rate = clk_get_rate(sspi->mclk);
-	}
+	if (sspi->cfg->has_clk_ctl) {
+		unsigned int mclk_rate = clk_get_rate(sspi->mclk);
+		/* Ensure that we have a parent clock fast enough */
+		if (mclk_rate < (2 * tfr->speed_hz)) {
+			clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
+			mclk_rate = clk_get_rate(sspi->mclk);
+		}
 
-	/*
-	 * Setup clock divider.
-	 *
-	 * We have two choices there. Either we can use the clock
-	 * divide rate 1, which is calculated thanks to this formula:
-	 * SPI_CLK = MOD_CLK / (2 ^ cdr)
-	 * Or we can use CDR2, which is calculated with the formula:
-	 * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
-	 * Wether we use the former or the latter is set through the
-	 * DRS bit.
-	 *
-	 * First try CDR2, and if we can't reach the expected
-	 * frequency, fall back to CDR1.
-	 */
-	div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
-	div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
-	if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
-		reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
-		tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
+		/*
+		 * Setup clock divider.
+		 *
+		 * We have two choices there. Either we can use the clock
+		 * divide rate 1, which is calculated thanks to this formula:
+		 * SPI_CLK = MOD_CLK / (2 ^ cdr)
+		 * Or we can use CDR2, which is calculated with the formula:
+		 * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
+		 * Wether we use the former or the latter is set through the
+		 * DRS bit.
+		 *
+		 * First try CDR2, and if we can't reach the expected
+		 * frequency, fall back to CDR1.
+		 */
+		div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
+		div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
+		if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
+			reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
+			tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
+		} else {
+			div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
+			reg = SUN6I_CLK_CTL_CDR1(div);
+			tfr->effective_speed_hz = mclk_rate / (1 << div);
+		}
+
+		sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
 	} else {
-		div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
-		reg = SUN6I_CLK_CTL_CDR1(div);
-		tfr->effective_speed_hz = mclk_rate / (1 << div);
+		clk_set_rate(sspi->mclk, tfr->speed_hz);
 	}
 
-	sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
 	/* Finally enable the bus - doing so before might raise SCK to HIGH */
 	reg = sun6i_spi_read(sspi, SUN6I_GBL_CTL_REG);
 	reg |= SUN6I_GBL_CTL_BUS_ENABLE;
@@ -702,10 +708,12 @@ static int sun6i_spi_remove(struct platform_device *pdev)
 
 static const struct sun6i_spi_cfg sun6i_a31_spi_cfg = {
 	.fifo_depth	= SUN6I_FIFO_DEPTH,
+	.has_clk_ctl	= true,
 };
 
 static const struct sun6i_spi_cfg sun8i_h3_spi_cfg = {
 	.fifo_depth	= SUN8I_FIFO_DEPTH,
+	.has_clk_ctl	= true,
 };
 
 static const struct of_device_id sun6i_spi_match[] = {
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/4] spi: sun6i: add support for R329 SPI controllers
       [not found] <20220422155639.1071645-1-icenowy@outlook.com>
                   ` (2 preceding siblings ...)
  2022-04-22 15:56 ` [PATCH 3/4] spi: sun6i: add quirk for in-controller clock divider icenowy
@ 2022-04-22 15:56 ` icenowy
  2022-04-22 23:59   ` Samuel Holland
  3 siblings, 1 reply; 12+ messages in thread
From: icenowy @ 2022-04-22 15:56 UTC (permalink / raw)
  To: Mark Brown, Chen-Yu Tsai, Jernej Skrabec, Samuel Holland, Maxime Ripard
  Cc: linux-spi, devicetree, linux-arm-kernel, linux-sunxi,
	linux-kernel, Icenowy Zheng

From: Icenowy Zheng <icenowy@aosc.io>

R329 has two SPI controllers. One of it is quite similar to previous
ones, but with internal clock divider removed; the other added MIPI DBI
Type-C offload based on the first one.

Add basical support for these controllers. As we're not going to
support the DBI functionality now, just implement the two kinds of
controllers as the same.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 drivers/spi/spi-sun6i.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index fc81afc3a963..c4bd8ea31b43 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -716,9 +716,21 @@ static const struct sun6i_spi_cfg sun8i_h3_spi_cfg = {
 	.has_clk_ctl	= true,
 };
 
+static const struct sun6i_spi_cfg sun50i_r329_spi_cfg = {
+	.fifo_depth	= SUN8I_FIFO_DEPTH,
+};
+
 static const struct of_device_id sun6i_spi_match[] = {
 	{ .compatible = "allwinner,sun6i-a31-spi", .data = &sun6i_a31_spi_cfg },
 	{ .compatible = "allwinner,sun8i-h3-spi",  .data = &sun8i_h3_spi_cfg },
+	{
+		.compatible = "allwinner,sun50i-r329-spi",
+		.data = &sun50i_r329_spi_cfg
+	},
+	{
+		.compatible = "allwinner,sun50i-r329-spi-dbi",
+		.data = &sun50i_r329_spi_cfg
+	},
 	{}
 };
 MODULE_DEVICE_TABLE(of, sun6i_spi_match);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/4] dt-bindings: spi: sun6i: add DT bindings for Allwinner R329 SPI
  2022-04-22 15:56 ` [PATCH 1/4] dt-bindings: spi: sun6i: add DT bindings for Allwinner R329 SPI icenowy
@ 2022-04-22 23:49   ` Samuel Holland
  2022-04-23  0:10     ` Icenowy Zheng
  0 siblings, 1 reply; 12+ messages in thread
From: Samuel Holland @ 2022-04-22 23:49 UTC (permalink / raw)
  To: Icenowy Zheng, Mark Brown, Chen-Yu Tsai, Jernej Skrabec, Maxime Ripard
  Cc: linux-spi, devicetree, linux-arm-kernel, linux-sunxi,
	linux-kernel, Icenowy Zheng

On 4/22/22 10:56 AM, icenowy@outlook.com wrote:
> From: Icenowy Zheng <icenowy@aosc.io>
> 
> Allwinner R329 SPI has two controllers, and the second one has helper
> functions for MIPI-DBI Type C.
> 
> Add compatible strings for these controllers
> 
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
>  .../devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml        | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
> index ca4c95345a49..6354635241fc 100644
> --- a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
> +++ b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
> @@ -21,6 +21,8 @@ properties:
>      oneOf:
>        - const: allwinner,sun6i-a31-spi
>        - const: allwinner,sun8i-h3-spi
> +      - const: allwinner,sun50i-r329-spi
> +      - const: allwinner,sun50i-r329-spi-dbi

As far as I'm aware, the SPI portion of the DBI controller is
register-compatible with the regular SPI controller. So I would expect using
that as a fallback compatible for the DBI variant.

Regards,
Samuel

>        - items:
>            - enum:
>                - allwinner,sun8i-r40-spi
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/4] spi: sun6i: change OF match data to a struct
  2022-04-22 15:56 ` [PATCH 2/4] spi: sun6i: change OF match data to a struct icenowy
@ 2022-04-22 23:50   ` Samuel Holland
  0 siblings, 0 replies; 12+ messages in thread
From: Samuel Holland @ 2022-04-22 23:50 UTC (permalink / raw)
  To: Icenowy Zheng, Mark Brown, Chen-Yu Tsai, Jernej Skrabec, Maxime Ripard
  Cc: linux-spi, devicetree, linux-arm-kernel, linux-sunxi,
	linux-kernel, Icenowy Zheng

On 4/22/22 10:56 AM, icenowy@outlook.com wrote:
> From: Icenowy Zheng <icenowy@aosc.io>
> 
> As we're adding more properties to the OF match data, convert it to a
> struct now.
> 
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>

Reviewed-by: Samuel Holland <samuel@sholland.org>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/4] spi: sun6i: add quirk for in-controller clock divider
  2022-04-22 15:56 ` [PATCH 3/4] spi: sun6i: add quirk for in-controller clock divider icenowy
@ 2022-04-22 23:54   ` Samuel Holland
  2022-04-22 23:57     ` Icenowy Zheng
  0 siblings, 1 reply; 12+ messages in thread
From: Samuel Holland @ 2022-04-22 23:54 UTC (permalink / raw)
  To: Icenowy Zheng, Mark Brown, Chen-Yu Tsai, Jernej Skrabec, Maxime Ripard
  Cc: linux-spi, devicetree, linux-arm-kernel, linux-sunxi,
	linux-kernel, Icenowy Zheng

On 4/22/22 10:56 AM, icenowy@outlook.com wrote:
> From: Icenowy Zheng <icenowy@aosc.io>
> 
> Previously SPI controllers in Allwinner SoCs has a clock divider inside.
> However now the clock divider is removed and to set the transfer clock
> rate it's only needed to set the SPI module clock to the target value.
> 
> Add a quirk for this kind of SPI controllers.
> 
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
>  drivers/spi/spi-sun6i.c | 68 +++++++++++++++++++++++------------------
>  1 file changed, 38 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
> index 84c525b08ad0..fc81afc3a963 100644
> --- a/drivers/spi/spi-sun6i.c
> +++ b/drivers/spi/spi-sun6i.c
> @@ -87,6 +87,7 @@
>  
>  struct sun6i_spi_cfg {
>  	unsigned long		fifo_depth;
> +	bool			has_clk_ctl;
>  };
>  
>  struct sun6i_spi {
> @@ -260,7 +261,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
>  				  struct spi_transfer *tfr)
>  {
>  	struct sun6i_spi *sspi = spi_master_get_devdata(master);
> -	unsigned int mclk_rate, div, div_cdr1, div_cdr2, timeout;
> +	unsigned int div, div_cdr1, div_cdr2, timeout;
>  	unsigned int start, end, tx_time;
>  	unsigned int trig_level;
>  	unsigned int tx_len = 0, rx_len = 0;
> @@ -350,39 +351,44 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
>  
>  	sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
>  
> -	/* Ensure that we have a parent clock fast enough */
> -	mclk_rate = clk_get_rate(sspi->mclk);
> -	if (mclk_rate < (2 * tfr->speed_hz)) {
> -		clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
> -		mclk_rate = clk_get_rate(sspi->mclk);
> -	}
> +	if (sspi->cfg->has_clk_ctl) {
> +		unsigned int mclk_rate = clk_get_rate(sspi->mclk);
> +		/* Ensure that we have a parent clock fast enough */
> +		if (mclk_rate < (2 * tfr->speed_hz)) {
> +			clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
> +			mclk_rate = clk_get_rate(sspi->mclk);
> +		}
>  
> -	/*
> -	 * Setup clock divider.
> -	 *
> -	 * We have two choices there. Either we can use the clock
> -	 * divide rate 1, which is calculated thanks to this formula:
> -	 * SPI_CLK = MOD_CLK / (2 ^ cdr)
> -	 * Or we can use CDR2, which is calculated with the formula:
> -	 * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
> -	 * Wether we use the former or the latter is set through the
> -	 * DRS bit.
> -	 *
> -	 * First try CDR2, and if we can't reach the expected
> -	 * frequency, fall back to CDR1.
> -	 */
> -	div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
> -	div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
> -	if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
> -		reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
> -		tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
> +		/*
> +		 * Setup clock divider.
> +		 *
> +		 * We have two choices there. Either we can use the clock
> +		 * divide rate 1, which is calculated thanks to this formula:
> +		 * SPI_CLK = MOD_CLK / (2 ^ cdr)
> +		 * Or we can use CDR2, which is calculated with the formula:
> +		 * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
> +		 * Wether we use the former or the latter is set through the
> +		 * DRS bit.
> +		 *
> +		 * First try CDR2, and if we can't reach the expected
> +		 * frequency, fall back to CDR1.
> +		 */
> +		div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
> +		div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
> +		if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
> +			reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
> +			tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
> +		} else {
> +			div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
> +			reg = SUN6I_CLK_CTL_CDR1(div);
> +			tfr->effective_speed_hz = mclk_rate / (1 << div);
> +		}
> +
> +		sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
>  	} else {
> -		div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
> -		reg = SUN6I_CLK_CTL_CDR1(div);
> -		tfr->effective_speed_hz = mclk_rate / (1 << div);
> +		clk_set_rate(sspi->mclk, tfr->speed_hz);

clk_set_rate() may not set the exact requested rate. Should we set
tfr->effective_speed_hz based on clk_get_rate() afterward?

Regards,
Samuel

>  	}
>  
> -	sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
>  	/* Finally enable the bus - doing so before might raise SCK to HIGH */
>  	reg = sun6i_spi_read(sspi, SUN6I_GBL_CTL_REG);
>  	reg |= SUN6I_GBL_CTL_BUS_ENABLE;
> @@ -702,10 +708,12 @@ static int sun6i_spi_remove(struct platform_device *pdev)
>  
>  static const struct sun6i_spi_cfg sun6i_a31_spi_cfg = {
>  	.fifo_depth	= SUN6I_FIFO_DEPTH,
> +	.has_clk_ctl	= true,
>  };
>  
>  static const struct sun6i_spi_cfg sun8i_h3_spi_cfg = {
>  	.fifo_depth	= SUN8I_FIFO_DEPTH,
> +	.has_clk_ctl	= true,
>  };
>  
>  static const struct of_device_id sun6i_spi_match[] = {
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/4] spi: sun6i: add quirk for in-controller clock divider
  2022-04-22 23:54   ` Samuel Holland
@ 2022-04-22 23:57     ` Icenowy Zheng
  0 siblings, 0 replies; 12+ messages in thread
From: Icenowy Zheng @ 2022-04-22 23:57 UTC (permalink / raw)
  To: Samuel Holland, Mark Brown, Chen-Yu Tsai, Jernej Skrabec, Maxime Ripard
  Cc: linux-spi, devicetree, linux-arm-kernel, linux-sunxi, linux-kernel

在 2022-04-22星期五的 18:54 -0500,Samuel Holland写道:
> On 4/22/22 10:56 AM, icenowy@outlook.com wrote:
> > From: Icenowy Zheng <icenowy@aosc.io>
> > 
> > Previously SPI controllers in Allwinner SoCs has a clock divider
> > inside.
> > However now the clock divider is removed and to set the transfer
> > clock
> > rate it's only needed to set the SPI module clock to the target
> > value.
> > 
> > Add a quirk for this kind of SPI controllers.
> > 
> > Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> > ---
> >  drivers/spi/spi-sun6i.c | 68 +++++++++++++++++++++++--------------
> > ----
> >  1 file changed, 38 insertions(+), 30 deletions(-)
> > 
> > diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
> > index 84c525b08ad0..fc81afc3a963 100644
> > --- a/drivers/spi/spi-sun6i.c
> > +++ b/drivers/spi/spi-sun6i.c
> > @@ -87,6 +87,7 @@
> >  
> >  struct sun6i_spi_cfg {
> >         unsigned long           fifo_depth;
> > +       bool                    has_clk_ctl;
> >  };
> >  
> >  struct sun6i_spi {
> > @@ -260,7 +261,7 @@ static int sun6i_spi_transfer_one(struct
> > spi_master *master,
> >                                   struct spi_transfer *tfr)
> >  {
> >         struct sun6i_spi *sspi = spi_master_get_devdata(master);
> > -       unsigned int mclk_rate, div, div_cdr1, div_cdr2, timeout;
> > +       unsigned int div, div_cdr1, div_cdr2, timeout;
> >         unsigned int start, end, tx_time;
> >         unsigned int trig_level;
> >         unsigned int tx_len = 0, rx_len = 0;
> > @@ -350,39 +351,44 @@ static int sun6i_spi_transfer_one(struct
> > spi_master *master,
> >  
> >         sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
> >  
> > -       /* Ensure that we have a parent clock fast enough */
> > -       mclk_rate = clk_get_rate(sspi->mclk);
> > -       if (mclk_rate < (2 * tfr->speed_hz)) {
> > -               clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
> > -               mclk_rate = clk_get_rate(sspi->mclk);
> > -       }
> > +       if (sspi->cfg->has_clk_ctl) {
> > +               unsigned int mclk_rate = clk_get_rate(sspi->mclk);
> > +               /* Ensure that we have a parent clock fast enough
> > */
> > +               if (mclk_rate < (2 * tfr->speed_hz)) {
> > +                       clk_set_rate(sspi->mclk, 2 * tfr-
> > >speed_hz);
> > +                       mclk_rate = clk_get_rate(sspi->mclk);
> > +               }
> >  
> > -       /*
> > -        * Setup clock divider.
> > -        *
> > -        * We have two choices there. Either we can use the clock
> > -        * divide rate 1, which is calculated thanks to this
> > formula:
> > -        * SPI_CLK = MOD_CLK / (2 ^ cdr)
> > -        * Or we can use CDR2, which is calculated with the
> > formula:
> > -        * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
> > -        * Wether we use the former or the latter is set through
> > the
> > -        * DRS bit.
> > -        *
> > -        * First try CDR2, and if we can't reach the expected
> > -        * frequency, fall back to CDR1.
> > -        */
> > -       div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
> > -       div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
> > -       if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
> > -               reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) |
> > SUN6I_CLK_CTL_DRS;
> > -               tfr->effective_speed_hz = mclk_rate / (2 *
> > div_cdr2);
> > +               /*
> > +                * Setup clock divider.
> > +                *
> > +                * We have two choices there. Either we can use the
> > clock
> > +                * divide rate 1, which is calculated thanks to
> > this formula:
> > +                * SPI_CLK = MOD_CLK / (2 ^ cdr)
> > +                * Or we can use CDR2, which is calculated with the
> > formula:
> > +                * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
> > +                * Wether we use the former or the latter is set
> > through the
> > +                * DRS bit.
> > +                *
> > +                * First try CDR2, and if we can't reach the
> > expected
> > +                * frequency, fall back to CDR1.
> > +                */
> > +               div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
> > +               div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
> > +               if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
> > +                       reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) |
> > SUN6I_CLK_CTL_DRS;
> > +                       tfr->effective_speed_hz = mclk_rate / (2 *
> > div_cdr2);
> > +               } else {
> > +                       div = min(SUN6I_CLK_CTL_CDR1_MASK,
> > order_base_2(div_cdr1));
> > +                       reg = SUN6I_CLK_CTL_CDR1(div);
> > +                       tfr->effective_speed_hz = mclk_rate / (1 <<
> > div);
> > +               }
> > +
> > +               sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
> >         } else {
> > -               div = min(SUN6I_CLK_CTL_CDR1_MASK,
> > order_base_2(div_cdr1));
> > -               reg = SUN6I_CLK_CTL_CDR1(div);
> > -               tfr->effective_speed_hz = mclk_rate / (1 << div);
> > +               clk_set_rate(sspi->mclk, tfr->speed_hz);
> 
> clk_set_rate() may not set the exact requested rate. Should we set
> tfr->effective_speed_hz based on clk_get_rate() afterward?

Sounds right. I should add this in the next revision.

> 
> Regards,
> Samuel
> 
> >         }
> >  
> > -       sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
> >         /* Finally enable the bus - doing so before might raise SCK
> > to HIGH */
> >         reg = sun6i_spi_read(sspi, SUN6I_GBL_CTL_REG);
> >         reg |= SUN6I_GBL_CTL_BUS_ENABLE;
> > @@ -702,10 +708,12 @@ static int sun6i_spi_remove(struct
> > platform_device *pdev)
> >  
> >  static const struct sun6i_spi_cfg sun6i_a31_spi_cfg = {
> >         .fifo_depth     = SUN6I_FIFO_DEPTH,
> > +       .has_clk_ctl    = true,
> >  };
> >  
> >  static const struct sun6i_spi_cfg sun8i_h3_spi_cfg = {
> >         .fifo_depth     = SUN8I_FIFO_DEPTH,
> > +       .has_clk_ctl    = true,
> >  };
> >  
> >  static const struct of_device_id sun6i_spi_match[] = {
> > 
> 



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 4/4] spi: sun6i: add support for R329 SPI controllers
  2022-04-22 15:56 ` [PATCH 4/4] spi: sun6i: add support for R329 SPI controllers icenowy
@ 2022-04-22 23:59   ` Samuel Holland
  2022-04-23  0:01     ` Icenowy Zheng
  2022-04-23  0:07     ` Icenowy Zheng
  0 siblings, 2 replies; 12+ messages in thread
From: Samuel Holland @ 2022-04-22 23:59 UTC (permalink / raw)
  To: Icenowy Zheng, Mark Brown, Chen-Yu Tsai, Jernej Skrabec, Maxime Ripard
  Cc: linux-spi, devicetree, linux-arm-kernel, linux-sunxi,
	linux-kernel, Icenowy Zheng

On 4/22/22 10:56 AM, icenowy@outlook.com wrote:
> From: Icenowy Zheng <icenowy@aosc.io>
> 
> R329 has two SPI controllers. One of it is quite similar to previous
> ones, but with internal clock divider removed; the other added MIPI DBI
> Type-C offload based on the first one.
> 
> Add basical support for these controllers. As we're not going to
> support the DBI functionality now, just implement the two kinds of
> controllers as the same.

I'm curious what speeds you were able to use SPI at. On D1, with effectively
these same changes, I would always get corrupted data when reading from the
onboard SPI NAND on the Nezha board. However, if I enabled the "new mode of
sample timing" (bit 2 in GBL_CTL_REG), I got the correct data.

Regards,
Samuel

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 4/4] spi: sun6i: add support for R329 SPI controllers
  2022-04-22 23:59   ` Samuel Holland
@ 2022-04-23  0:01     ` Icenowy Zheng
  2022-04-23  0:07     ` Icenowy Zheng
  1 sibling, 0 replies; 12+ messages in thread
From: Icenowy Zheng @ 2022-04-23  0:01 UTC (permalink / raw)
  To: Samuel Holland, Mark Brown, Chen-Yu Tsai, Jernej Skrabec, Maxime Ripard
  Cc: linux-spi, devicetree, linux-arm-kernel, linux-sunxi, linux-kernel

在 2022-04-22星期五的 18:59 -0500,Samuel Holland写道:
> On 4/22/22 10:56 AM, icenowy@outlook.com wrote:
> > From: Icenowy Zheng <icenowy@aosc.io>
> > 
> > R329 has two SPI controllers. One of it is quite similar to
> > previous
> > ones, but with internal clock divider removed; the other added MIPI
> > DBI
> > Type-C offload based on the first one.
> > 
> > Add basical support for these controllers. As we're not going to
> > support the DBI functionality now, just implement the two kinds of
> > controllers as the same.
> 
> I'm curious what speeds you were able to use SPI at. On D1, with
> effectively
> these same changes, I would always get corrupted data when reading
> from the
> onboard SPI NAND on the Nezha board. However, if I enabled the "new
> mode of
> sample timing" (bit 2 in GBL_CTL_REG), I got the correct data.

Oh my usage never read from device now, because it's a write-only MIPI
DBI panel.

> 
> Regards,
> Samuel



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 4/4] spi: sun6i: add support for R329 SPI controllers
  2022-04-22 23:59   ` Samuel Holland
  2022-04-23  0:01     ` Icenowy Zheng
@ 2022-04-23  0:07     ` Icenowy Zheng
  1 sibling, 0 replies; 12+ messages in thread
From: Icenowy Zheng @ 2022-04-23  0:07 UTC (permalink / raw)
  To: Samuel Holland, Mark Brown, Chen-Yu Tsai, Jernej Skrabec, Maxime Ripard
  Cc: linux-spi, devicetree, linux-arm-kernel, linux-sunxi, linux-kernel

在 2022-04-22星期五的 18:59 -0500,Samuel Holland写道:
> On 4/22/22 10:56 AM, icenowy@outlook.com wrote:
> > From: Icenowy Zheng <icenowy@aosc.io>
> > 
> > R329 has two SPI controllers. One of it is quite similar to
> > previous
> > ones, but with internal clock divider removed; the other added MIPI
> > DBI
> > Type-C offload based on the first one.
> > 
> > Add basical support for these controllers. As we're not going to
> > support the DBI functionality now, just implement the two kinds of
> > controllers as the same.
> 
> I'm curious what speeds you were able to use SPI at. On D1, with
> effectively
> these same changes, I would always get corrupted data when reading
> from the
> onboard SPI NAND on the Nezha board. However, if I enabled the "new
> mode of
> sample timing" (bit 2 in GBL_CTL_REG), I got the correct data.

See 7.3.3.10 of R329_User_Manual_v1.0.pdf ? (named SPI sample mode and
Run Clock configuration)

> 
> Regards,
> Samuel



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/4] dt-bindings: spi: sun6i: add DT bindings for Allwinner R329 SPI
  2022-04-22 23:49   ` Samuel Holland
@ 2022-04-23  0:10     ` Icenowy Zheng
  0 siblings, 0 replies; 12+ messages in thread
From: Icenowy Zheng @ 2022-04-23  0:10 UTC (permalink / raw)
  To: Samuel Holland, Mark Brown, Chen-Yu Tsai, Jernej Skrabec, Maxime Ripard
  Cc: linux-spi, devicetree, linux-arm-kernel, linux-sunxi, linux-kernel

在 2022-04-22星期五的 18:49 -0500,Samuel Holland写道:
> On 4/22/22 10:56 AM, icenowy@outlook.com wrote:
> > From: Icenowy Zheng <icenowy@aosc.io>
> > 
> > Allwinner R329 SPI has two controllers, and the second one has
> > helper
> > functions for MIPI-DBI Type C.
> > 
> > Add compatible strings for these controllers
> > 
> > Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> > ---
> >  .../devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml        |
> > 2 ++
> >  1 file changed, 2 insertions(+)
> > 
> > diff --git a/Documentation/devicetree/bindings/spi/allwinner,sun6i-
> > a31-spi.yaml
> > b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-
> > spi.yaml
> > index ca4c95345a49..6354635241fc 100644
> > --- a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-
> > spi.yaml
> > +++ b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-
> > spi.yaml
> > @@ -21,6 +21,8 @@ properties:
> >      oneOf:
> >        - const: allwinner,sun6i-a31-spi
> >        - const: allwinner,sun8i-h3-spi
> > +      - const: allwinner,sun50i-r329-spi
> > +      - const: allwinner,sun50i-r329-spi-dbi
> 
> As far as I'm aware, the SPI portion of the DBI controller is
> register-compatible with the regular SPI controller. So I would
> expect using
> that as a fallback compatible for the DBI variant.

This sounds reasonable.

> 
> Regards,
> Samuel
> 
> >        - items:
> >            - enum:
> >                - allwinner,sun8i-r40-spi
> > 
> 



^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2022-04-23  7:00 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20220422155639.1071645-1-icenowy@outlook.com>
2022-04-22 15:56 ` [PATCH 1/4] dt-bindings: spi: sun6i: add DT bindings for Allwinner R329 SPI icenowy
2022-04-22 23:49   ` Samuel Holland
2022-04-23  0:10     ` Icenowy Zheng
2022-04-22 15:56 ` [PATCH 2/4] spi: sun6i: change OF match data to a struct icenowy
2022-04-22 23:50   ` Samuel Holland
2022-04-22 15:56 ` [PATCH 3/4] spi: sun6i: add quirk for in-controller clock divider icenowy
2022-04-22 23:54   ` Samuel Holland
2022-04-22 23:57     ` Icenowy Zheng
2022-04-22 15:56 ` [PATCH 4/4] spi: sun6i: add support for R329 SPI controllers icenowy
2022-04-22 23:59   ` Samuel Holland
2022-04-23  0:01     ` Icenowy Zheng
2022-04-23  0:07     ` Icenowy Zheng

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).