Patchwork [U-Boot,2/7] tegra: spi: add fdt support to tegra SPI SFLASH driver

login
register
mail settings
Submitter Allen Martin
Date Jan. 11, 2013, 6:44 p.m.
Message ID <1357929877-18671-3-git-send-email-amartin@nvidia.com>
Download mbox | patch
Permalink /patch/211407/
State Superseded
Headers show

Comments

Allen Martin - Jan. 11, 2013, 6:44 p.m.
Add support for configuring tegra SPI driver from devicetree.
Support is keyed off CONFIG_OF_CONTROL.  Add entry in seaboard dts
file for spi controller to describe seaboard spi.

Signed-off-by: Allen Martin <amartin@nvidia.com>
---
 arch/arm/dts/tegra20.dtsi |   13 +++++++++++++
 drivers/spi/tegra_spi.c   |   42 +++++++++++++++++++++++++++++++++++++++++-
 include/fdtdec.h          |    1 +
 lib/fdtdec.c              |    1 +
 4 files changed, 56 insertions(+), 1 deletion(-)
Stephen Warren - Jan. 12, 2013, 12:13 a.m.
On 01/11/2013 11:44 AM, Allen Martin wrote:
> Add support for configuring tegra SPI driver from devicetree.
> Support is keyed off CONFIG_OF_CONTROL.  Add entry in seaboard dts
> file for spi controller to describe seaboard spi.

> diff --git a/arch/arm/dts/tegra20.dtsi b/arch/arm/dts/tegra20.dtsi

.dtsi changes would typically be in a separate patch.

> +	spi@7000c380 {
> +		compatible = "nvidia,tegra20-sflash";
> +		reg = <0x7000c380 0x80>;
> +		interrupts = <0 39 0x04>;
> +		nvidia,dma-request-selector = <&apbdma 11>;

> +		spi-max-frequency = <25000000>;

spi-max-frequency is board-specific; it should appear in the board .dts
file not the SoC .dtsi file.

> diff --git a/drivers/spi/tegra_spi.c b/drivers/spi/tegra_spi.c

> @@ -85,7 +91,41 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
>  	spi->slave.bus = bus;
>  	spi->slave.cs = cs;
>  	spi->freq = max_hz;
> +#ifdef CONFIG_OF_CONTROL
> +	int node = fdtdec_next_compatible(gd->fdt_blob, 0,
> +					  COMPAT_NVIDIA_TEGRA20_SFLASH);

I assume this function gets called once, and hence the line above simply
finds the first sflash node in the device tree. What if there's more
than one node? There certainly can be more than one SPI controller,
although perhaps the sflash controller only has one instance on any
current chip and it's the other IP block ("SPI") that has multiple
instances in practice.
Allen Martin - Jan. 12, 2013, 3:40 a.m.
On Fri, Jan 11, 2013 at 04:13:42PM -0800, Stephen Warren wrote:
> On 01/11/2013 11:44 AM, Allen Martin wrote:
> > Add support for configuring tegra SPI driver from devicetree.
> > Support is keyed off CONFIG_OF_CONTROL.  Add entry in seaboard dts
> > file for spi controller to describe seaboard spi.
> 
> > diff --git a/arch/arm/dts/tegra20.dtsi b/arch/arm/dts/tegra20.dtsi
> 
> .dtsi changes would typically be in a separate patch.

ok

> 
> > +	spi@7000c380 {
> > +		compatible = "nvidia,tegra20-sflash";
> > +		reg = <0x7000c380 0x80>;
> > +		interrupts = <0 39 0x04>;
> > +		nvidia,dma-request-selector = <&apbdma 11>;
> 
> > +		spi-max-frequency = <25000000>;
> 
> spi-max-frequency is board-specific; it should appear in the board .dts
> file not the SoC .dtsi file.

ok

> 
> > diff --git a/drivers/spi/tegra_spi.c b/drivers/spi/tegra_spi.c
> 
> > @@ -85,7 +91,41 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
> >  	spi->slave.bus = bus;
> >  	spi->slave.cs = cs;
> >  	spi->freq = max_hz;
> > +#ifdef CONFIG_OF_CONTROL
> > +	int node = fdtdec_next_compatible(gd->fdt_blob, 0,
> > +					  COMPAT_NVIDIA_TEGRA20_SFLASH);
> 
> I assume this function gets called once, and hence the line above simply
> finds the first sflash node in the device tree. What if there's more
> than one node? There certainly can be more than one SPI controller,
> although perhaps the sflash controller only has one instance on any
> current chip and it's the other IP block ("SPI") that has multiple
> instances in practice.

SFLASH only exists in tegra20, and there is only one.  This driver can
only handle a single controller anyway.  I highly doubt there will
ever be another chip with an SFLASH controller, never mind more than
one, but if there is, this driver will need lots of modification to
support multiple.  All newer chips have SLINK controllers only.

This function can be called more than once, like if you type "sf
probe" multiple times, but it passes in 0 as the initial node offset,
so it will always return the first compatible node.  So theoretically
if there ever is a tegra with more than one SFLASH controller, with
this patch the driver will operate like it did before this patch, it
will support the first controller only.

-Allen

Patch

diff --git a/arch/arm/dts/tegra20.dtsi b/arch/arm/dts/tegra20.dtsi
index 707975c..8d4c7ec 100644
--- a/arch/arm/dts/tegra20.dtsi
+++ b/arch/arm/dts/tegra20.dtsi
@@ -337,4 +337,17 @@ 
 		};
 	};
 
+	spi@7000c380 {
+		compatible = "nvidia,tegra20-sflash";
+		reg = <0x7000c380 0x80>;
+		interrupts = <0 39 0x04>;
+		nvidia,dma-request-selector = <&apbdma 11>;
+		spi-max-frequency = <25000000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+		/* PERIPH_ID_SPI1, PLLP_OUT0 */
+		clocks = <&tegra_car 43>;
+	};
+
 };
diff --git a/drivers/spi/tegra_spi.c b/drivers/spi/tegra_spi.c
index 9bb34e2..36b0cd0 100644
--- a/drivers/spi/tegra_spi.c
+++ b/drivers/spi/tegra_spi.c
@@ -32,6 +32,11 @@ 
 #include <asm/arch-tegra/clk_rst.h>
 #include <asm/arch-tegra/tegra_spi.h>
 #include <spi.h>
+#ifdef CONFIG_OF_CONTROL
+#include <fdtdec.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
 
 #if defined(CONFIG_SPI_CORRUPTS_UART)
  #define corrupt_delay()	udelay(CONFIG_SPI_CORRUPTS_UART_DLY);
@@ -44,6 +49,7 @@  struct tegra_spi_slave {
 	struct spi_tegra *regs;
 	unsigned int freq;
 	unsigned int mode;
+	int periph_id;
 };
 
 static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave)
@@ -85,7 +91,41 @@  struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	spi->slave.bus = bus;
 	spi->slave.cs = cs;
 	spi->freq = max_hz;
+#ifdef CONFIG_OF_CONTROL
+	int node = fdtdec_next_compatible(gd->fdt_blob, 0,
+					  COMPAT_NVIDIA_TEGRA20_SFLASH);
+	if (node < 0) {
+		debug("%s: cannot locate sflash node\n", __func__);
+		return NULL;
+	}
+	spi->regs = (struct spi_tegra *)fdtdec_get_addr(gd->fdt_blob,
+							node, "reg");
+	if ((fdt_addr_t)spi->regs == FDT_ADDR_T_NONE) {
+		debug("%s: no sflash register found\n", __func__);
+		return NULL;
+	}
+	spi->freq = fdtdec_get_int(gd->fdt_blob, node, "spi-max-frequency", 0);
+	if (!spi->freq) {
+		debug("%s: no sflash max frequency found\n", __func__);
+		return NULL;
+	}
+	spi->periph_id = clock_decode_periph_id(gd->fdt_blob, node);
+	if (spi->periph_id == PERIPH_ID_NONE) {
+		debug("%s: could not decode periph id\n", __func__);
+		return NULL;
+	}
+#else
 	spi->regs = (struct spi_tegra *)NV_PA_SPI_BASE;
+	spi->freq = TEGRA_SPI_MAX_FREQ;
+	spi->periph_id = PERIPH_ID_SPI1;
+#endif
+	if (max_hz < spi->freq) {
+		debug("%s: limiting frequency from %u to %u\n", __func__,
+		      spi->freq, max_hz);
+		spi->freq = max_hz;
+	}
+	debug("%s: controller initialized at %p, freq = %u, periph_id = %d\n",
+	      __func__, spi->regs, spi->freq, spi->periph_id);
 	spi->mode = mode;
 
 	return &spi->slave;
@@ -110,7 +150,7 @@  int spi_claim_bus(struct spi_slave *slave)
 	u32 reg;
 
 	/* Change SPI clock to correct frequency, PLLP_OUT0 source */
-	clock_start_periph_pll(PERIPH_ID_SPI1, CLOCK_ID_PERIPH, spi->freq);
+	clock_start_periph_pll(spi->periph_id, CLOCK_ID_PERIPH, spi->freq);
 
 	/* Clear stale status here */
 	reg = SPI_STAT_RDY | SPI_STAT_RXF_FLUSH | SPI_STAT_TXF_FLUSH | \
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 70d0e97..1504336 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -70,6 +70,7 @@  enum fdt_compat_id {
 	COMPAT_NVIDIA_TEGRA20_NAND,	/* Tegra2 NAND controller */
 	COMPAT_NVIDIA_TEGRA20_PWM,	/* Tegra 2 PWM controller */
 	COMPAT_NVIDIA_TEGRA20_DC,	/* Tegra 2 Display controller */
+	COMPAT_NVIDIA_TEGRA20_SFLASH,	/* Tegra 2 SPI flash controller */
 
 	COMPAT_COUNT,
 };
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 6dba438..6779278 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -45,6 +45,7 @@  static const char * const compat_names[COMPAT_COUNT] = {
 	COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"),
 	COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"),
 	COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"),
+	COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"),
 };
 
 const char *fdtdec_get_compatible(enum fdt_compat_id id)