public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller
@ 2012-12-26 22:28 Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 01/15] fdt: Use sed instead of cpp to pre-process the dtc Simon Glass
                   ` (15 more replies)
  0 siblings, 16 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

Adding new fields to struct spi_slave and struct spi_flash is painful,
because most drivers don't zero the fields they don't use. Anyway it
seems better to have the SPI/SPI flash infrastructure provide a simple
way of doing this that all drivers can use.

So the first part of this series adds spi_alloc_slave(), for SPI, and
spi_flash_alloc() for SPI flash.

Support is added for the Intel ICH SPI controller, possibly the oddest
SPI controller in U-Boot. It is designed for use with SPI flash only,
and has a number of high-level features which are dedicated to flash.
As such it is a bit of a challenge to get it to behave just like a
normal U-Boot SPI device.

The ICH driver has two interesting features. Firstly it is impossible
to read or write more than 64 bytes at a time! For SPI reading it is
possible to hide this within the SPI driver. For SPI writing it
unfortunately isn't, since the spi_flash layer has to send an unlock
command and a new address for every write. It would be an egregious
hack to try to fake this in the driver. So a new property is added
to spi_flash to allow the maximum transfer size to be set.

Secondly, the ICH SPI flash can be memory mapped. On a lot of x86
devices this improves performance significantly. For example, the standard
driver gets maybe 12Mbps throughput from a 33Mbps dual interface, roughly
20% utilisation. With memory mapping, many platforms can achieve about
40Mbps. To implement memory mapping, a new property is provided in the
device tree to set the memory map address, which varies by platform. Some
x86 platforms will see a speed increase with memory mapping, some won't.
The memory mapping feature only works for reading. When in use, the
spi_flash layer bypasses the SPI driver completely, and just copies the
flash data from the correct place in the memory map.


Simon Glass (15):
  fdt: Use sed instead of cpp to pre-process the dtc
  fdt: Add fdtdec_get_addr_size() to read reg properties
  spi: Add function to allocate a new SPI slave
  spi: Use spi_alloc_slave() in each SPI driver
  sf: Add spi_flash_alloc() to create a new SPI flash struct
  sf: Use spi_flash_alloc() in each SPI flash driver
  x86: spi: Add Intel ICH driver
  spi: Add parameter for maximum write size
  sf: Respect maximum SPI write size
  x86: spi: Set maximum write size for ICH
  sf: Enable FDT-based configuration and memory mapping
  x86: Move PCI init before SPI init
  x86: Add FDT SPI node for link
  x86: Enable SPI flash support for coreboot
  x86: Enable time command for coreboot

 arch/x86/lib/board.c              |    8 +-
 board/chromebook-x86/dts/link.dts |   11 +
 drivers/mtd/spi/atmel.c           |    8 +-
 drivers/mtd/spi/eon.c             |    8 +-
 drivers/mtd/spi/macronix.c        |    8 +-
 drivers/mtd/spi/ramtron.c         |    4 +-
 drivers/mtd/spi/spansion.c        |    8 +-
 drivers/mtd/spi/spi_flash.c       |   81 ++++-
 drivers/mtd/spi/sst.c             |    8 +-
 drivers/mtd/spi/stmicro.c         |    8 +-
 drivers/mtd/spi/winbond.c         |    8 +-
 drivers/spi/Makefile              |    4 +
 drivers/spi/altera_spi.c          |    4 +-
 drivers/spi/andes_spi.c           |    4 +-
 drivers/spi/armada100_spi.c       |    4 +-
 drivers/spi/atmel_spi.c           |    4 +-
 drivers/spi/bfin_spi.c            |    4 +-
 drivers/spi/cf_qspi.c             |    4 +-
 drivers/spi/cf_spi.c              |    4 +-
 drivers/spi/davinci_spi.c         |    4 +-
 drivers/spi/fsl_espi.c            |    4 +-
 drivers/spi/ich.c                 |  752 +++++++++++++++++++++++++++++++++++++
 drivers/spi/ich.h                 |  144 +++++++
 drivers/spi/kirkwood_spi.c        |    5 +-
 drivers/spi/mpc52xx_spi.c         |    5 +-
 drivers/spi/mpc8xxx_spi.c         |    5 +-
 drivers/spi/mxc_spi.c             |    4 +-
 drivers/spi/mxs_spi.c             |    4 +-
 drivers/spi/oc_tiny_spi.c         |    5 +-
 drivers/spi/omap3_spi.c           |   27 +-
 drivers/spi/sh_spi.c              |    4 +-
 drivers/spi/soft_spi.c            |    4 +-
 drivers/spi/spi.c                 |   39 ++
 drivers/spi/tegra_spi.c           |    4 +-
 drivers/spi/xilinx_spi.c          |    4 +-
 dts/Makefile                      |   10 +-
 include/configs/coreboot.h        |   13 +-
 include/fdtdec.h                  |   16 +
 include/spi.h                     |   44 +++
 include/spi_flash.h               |   39 ++
 lib/fdtdec.c                      |   27 ++-
 41 files changed, 1208 insertions(+), 147 deletions(-)
 create mode 100644 drivers/spi/ich.c
 create mode 100644 drivers/spi/ich.h
 create mode 100644 drivers/spi/spi.c

-- 
1.7.7.3

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

* [U-Boot] [PATCH 01/15] fdt: Use sed instead of cpp to pre-process the dtc
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
@ 2012-12-26 22:28 ` Simon Glass
  2012-12-28  0:03   ` Stephen Warren
  2012-12-26 22:28 ` [U-Boot] [PATCH 02/15] fdt: Add fdtdec_get_addr_size() to read reg properties Simon Glass
                   ` (14 subsequent siblings)
  15 siblings, 1 reply; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

Include file support in dtc is still not available in common distributions
so we need to keep our preprocessing arrangement around for a little
longer.

But # is commonly used in FDT files, so use sed instead of cpp for this
preprocessing.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 dts/Makefile |   10 ++++------
 1 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/dts/Makefile b/dts/Makefile
index 785104e..76f1461 100644
--- a/dts/Makefile
+++ b/dts/Makefile
@@ -35,11 +35,6 @@ $(if $(CONFIG_ARCH_DEVICE_TREE),,\
 $(error Your architecture does not have device tree support enabled. \
 Please define CONFIG_ARCH_DEVICE_TREE))
 
-# We preprocess the device tree file provide a useful define
-DTS_CPPFLAGS := -ansi \
-		-DARCH_CPU_DTS=\"$(SRCTREE)/arch/$(ARCH)/dts/$(CONFIG_ARCH_DEVICE_TREE).dtsi\" \
-		-DBOARD_DTS=\"$(SRCTREE)/board/$(VENDOR)/$(BOARD)/dts/$(DEVICE_TREE).dts\"
-
 all:	$(obj).depend $(LIB)
 
 # Use a constant name for this so we can access it from C code.
@@ -49,7 +44,10 @@ DT_BIN	:= $(obj)dt.dtb
 
 $(DT_BIN): $(TOPDIR)/board/$(VENDOR)/dts/$(DEVICE_TREE).dts
 	rc=$$( \
-		cat $< | $(CPP) -P $(DTS_CPPFLAGS) - | \
+		cat $< \
+		| sed '{s#ARCH_CPU_DTS#"$(SRCTREE)/arch/$(ARCH)/dts/$(CONFIG_ARCH_DEVICE_TREE).dtsi"#; \
+			s#BOARD_DTS#$(SRCTREE)/board/$(VENDOR)/$(BOARD)/dts/$(DEVICE_TREE).dts#}' | \
+		tee dts.tmp | \
 		{ { $(DTC) -R 4 -p 0x1000 -O dtb -o ${DT_BIN} - 2>&1 ; \
 		    echo $$? >&3 ; } | \
 		  grep -v '^DTC: dts->dtb  on file' ; \
-- 
1.7.7.3

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

* [U-Boot] [PATCH 02/15] fdt: Add fdtdec_get_addr_size() to read reg properties
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 01/15] fdt: Use sed instead of cpp to pre-process the dtc Simon Glass
@ 2012-12-26 22:28 ` Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 03/15] spi: Add function to allocate a new SPI slave Simon Glass
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

It is common to have a "reg = <address size>" property in the FDT.
Add a function to handle this, similar to the existing
fdtdec_get_addr();

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 include/fdtdec.h |   15 +++++++++++++++
 lib/fdtdec.c     |   26 +++++++++++++++++++++-----
 2 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/include/fdtdec.h b/include/fdtdec.h
index 70d0e97..570d3ac 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -38,11 +38,13 @@
  */
 #ifdef CONFIG_PHYS_64BIT
 typedef u64 fdt_addr_t;
+typedef u64 fdt_size_t;
 #define FDT_ADDR_T_NONE (-1ULL)
 #define fdt_addr_to_cpu(reg) be64_to_cpu(reg)
 #define fdt_size_to_cpu(reg) be64_to_cpu(reg)
 #else
 typedef u32 fdt_addr_t;
+typedef u32 fdt_size_t;
 #define FDT_ADDR_T_NONE (-1U)
 #define fdt_addr_to_cpu(reg) be32_to_cpu(reg)
 #define fdt_size_to_cpu(reg) be32_to_cpu(reg)
@@ -186,6 +188,19 @@ fdt_addr_t fdtdec_get_addr(const void *blob, int node,
 		const char *prop_name);
 
 /**
+ * Look up an address property in a node and return it as an address.
+ * The property must hold one address with a length. This is only tested
+ * on 32-bit machines.
+ *
+ * @param blob	FDT blob
+ * @param node	node to examine
+ * @param prop_name	name of property to find
+ * @return address, if found, or FDT_ADDR_T_NONE if not
+ */
+fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
+		const char *prop_name, fdt_size_t *sizep);
+
+/**
  * Look up a 32-bit integer property in a node and return it. The property
  * must have at least 4 bytes of data. The value of the first cell is
  * returned.
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 6dba438..d0bc848 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -54,25 +54,41 @@ const char *fdtdec_get_compatible(enum fdt_compat_id id)
 	return compat_names[id];
 }
 
-fdt_addr_t fdtdec_get_addr(const void *blob, int node,
-		const char *prop_name)
+fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
+		const char *prop_name, fdt_size_t *sizep)
 {
 	const fdt_addr_t *cell;
 	int len;
 
 	debug("%s: %s: ", __func__, prop_name);
 	cell = fdt_getprop(blob, node, prop_name, &len);
-	if (cell && (len == sizeof(fdt_addr_t) ||
+	if (cell && ((!sizep && len == sizeof(fdt_addr_t)) ||
 			len == sizeof(fdt_addr_t) * 2)) {
-		fdt_addr_t addr = fdt_addr_to_cpu(*cell);
 
-		debug("%p\n", (void *)addr);
+		fdt_addr_t addr = fdt_addr_to_cpu(*cell);
+		if (sizep) {
+			const fdt_size_t *size;
+
+			size = (fdt_size_t *)((char *)cell +
+					sizeof(fdt_addr_t));
+			*sizep = fdt_size_to_cpu(*size);
+			debug("addr=%p, size=%p\n", (void *)addr,
+			      (void *)*sizep);
+		} else {
+			debug("%p\n", (void *)addr);
+		}
 		return addr;
 	}
 	debug("(not found)\n");
 	return FDT_ADDR_T_NONE;
 }
 
+fdt_addr_t fdtdec_get_addr(const void *blob, int node,
+		const char *prop_name)
+{
+	return fdtdec_get_addr_size(blob, node, prop_name, NULL);
+}
+
 s32 fdtdec_get_int(const void *blob, int node, const char *prop_name,
 		s32 default_val)
 {
-- 
1.7.7.3

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

* [U-Boot] [PATCH 03/15] spi: Add function to allocate a new SPI slave
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 01/15] fdt: Use sed instead of cpp to pre-process the dtc Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 02/15] fdt: Add fdtdec_get_addr_size() to read reg properties Simon Glass
@ 2012-12-26 22:28 ` Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 04/15] spi: Use spi_alloc_slave() in each SPI driver Simon Glass
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

At present it is difficult to extend the SPI structure since all
drivers allocate it themselves, and few of them zero all fields. Add
a new function spi_alloc_slave() which can be used by SPI drivers
to perform this allocation, and thus ensure that all drivers can
better cope with SPI structure changes.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 drivers/spi/Makefile |    3 +++
 drivers/spi/spi.c    |   39 +++++++++++++++++++++++++++++++++++++++
 include/spi.h        |   41 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 83 insertions(+), 0 deletions(-)
 create mode 100644 drivers/spi/spi.c

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 824d357..4e8de5d 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -25,6 +25,9 @@ include $(TOPDIR)/config.mk
 
 LIB	:= $(obj)libspi.o
 
+# There are many options which enable SPI, so make this library available
+COBJS-y += spi.o
+
 COBJS-$(CONFIG_ALTERA_SPI) += altera_spi.o
 COBJS-$(CONFIG_ANDES_SPI) += andes_spi.o
 COBJS-$(CONFIG_ARMADA100_SPI) += armada100_spi.o
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
new file mode 100644
index 0000000..cb36c5e
--- /dev/null
+++ b/drivers/spi/spi.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but without any warranty; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <spi.h>
+
+void *spi_do_alloc_slave(int offset, int size, unsigned int bus,
+			 unsigned int cs)
+{
+	struct spi_slave *slave;
+	void *ptr;
+
+	ptr = malloc(size);
+	if (ptr) {
+		memset(ptr, '\0', size);
+		slave = (struct spi_slave *)(ptr + offset);
+		slave->bus = bus;
+		slave->cs = cs;
+	}
+
+	return ptr;
+}
diff --git a/include/spi.h b/include/spi.h
index 60e85db..ebc9652 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -62,6 +62,47 @@ struct spi_slave {
  */
 void spi_init(void);
 
+/**
+ * spi_do_alloc_slave - Allocate a new SPI slave (internal)
+ *
+ * Allocate and zero all fields in the spi slave, and set the bus/chip
+ * select. Use the helper macro spi_alloc_slave() to call this.
+ *
+ * @offset: Offset of struct spi_slave within slave structure
+ * @size: Size of slave structure
+ * @bus: Bus ID of the slave chip.
+ * @cs: Chip select ID of the slave chip on the specified bus.
+ */
+void *spi_do_alloc_slave(int offset, int size, unsigned int bus,
+			 unsigned int cs);
+
+/**
+ * spi_alloc_slave - Allocate a new SPI slave
+ *
+ * Allocate and zero all fields in the spi slave, and set the bus/chip
+ * select.
+ *
+ * @_struct: Name of structure to allocate (e.g. struct tegra_spi). This
+ *	structure must contain a member 'struct spi_slave *slave'.
+ * @bus: Bus ID of the slave chip.
+ * @cs: Chip select ID of the slave chip on the specified bus.
+ */
+#define spi_alloc_slave(_struct, bus, cs) \
+	spi_do_alloc_slave(offsetof(_struct, slave), \
+			    sizeof(_struct), bus, cs)
+
+/**
+ * spi_alloc_slave_base - Allocate a new SPI slave with no private data
+ *
+ * Allocate and zero all fields in the spi slave, and set the bus/chip
+ * select.
+ *
+ * @bus: Bus ID of the slave chip.
+ * @cs: Chip select ID of the slave chip on the specified bus.
+ */
+#define spi_alloc_slave_base(bus, cs) \
+	spi_do_alloc_slave(0, sizeof(struct spi_slave), bus, cs)
+
 /*-----------------------------------------------------------------------
  * Set up communications parameters for a SPI slave.
  *
-- 
1.7.7.3

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

* [U-Boot] [PATCH 04/15] spi: Use spi_alloc_slave() in each SPI driver
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
                   ` (2 preceding siblings ...)
  2012-12-26 22:28 ` [U-Boot] [PATCH 03/15] spi: Add function to allocate a new SPI slave Simon Glass
@ 2012-12-26 22:28 ` Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 05/15] sf: Add spi_flash_alloc() to create a new SPI flash struct Simon Glass
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

Rather than each driver having its own way to allocate a SPI slave,
use the new allocation function everywhere. This will make it easier
to extend the interface without breaking drivers.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 drivers/spi/altera_spi.c    |    4 +---
 drivers/spi/andes_spi.c     |    4 +---
 drivers/spi/armada100_spi.c |    4 +---
 drivers/spi/atmel_spi.c     |    4 +---
 drivers/spi/bfin_spi.c      |    4 +---
 drivers/spi/cf_qspi.c       |    4 +---
 drivers/spi/cf_spi.c        |    4 +---
 drivers/spi/davinci_spi.c   |    4 +---
 drivers/spi/fsl_espi.c      |    4 +---
 drivers/spi/kirkwood_spi.c  |    5 +----
 drivers/spi/mpc52xx_spi.c   |    5 +----
 drivers/spi/mpc8xxx_spi.c   |    5 +----
 drivers/spi/mxc_spi.c       |    4 +---
 drivers/spi/mxs_spi.c       |    4 +---
 drivers/spi/oc_tiny_spi.c   |    5 +----
 drivers/spi/omap3_spi.c     |   27 ++++++++++++++-------------
 drivers/spi/sh_spi.c        |    4 +---
 drivers/spi/soft_spi.c      |    4 +---
 drivers/spi/tegra_spi.c     |    4 +---
 drivers/spi/xilinx_spi.c    |    4 +---
 20 files changed, 33 insertions(+), 74 deletions(-)

diff --git a/drivers/spi/altera_spi.c b/drivers/spi/altera_spi.c
index 138d6f4..b53607a 100644
--- a/drivers/spi/altera_spi.c
+++ b/drivers/spi/altera_spi.c
@@ -83,12 +83,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	if (!spi_cs_is_valid(bus, cs))
 		return NULL;
 
-	altspi = malloc(sizeof(*altspi));
+	altspi = spi_alloc_slave(struct altera_spi_slave, bus, cs);
 	if (!altspi)
 		return NULL;
 
-	altspi->slave.bus = bus;
-	altspi->slave.cs = cs;
 	altspi->base = altera_spi_base_list[bus];
 	debug("%s: bus:%i cs:%i base:%lx\n", __func__,
 		bus, cs, altspi->base);
diff --git a/drivers/spi/andes_spi.c b/drivers/spi/andes_spi.c
index fdde139..c56377b 100644
--- a/drivers/spi/andes_spi.c
+++ b/drivers/spi/andes_spi.c
@@ -53,12 +53,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	if (!spi_cs_is_valid(bus, cs))
 		return NULL;
 
-	ds = malloc(sizeof(*ds));
+	ds = spi_alloc_slave(struct andes_spi_slave, bus, cs);
 	if (!ds)
 		return NULL;
 
-	ds->slave.bus = bus;
-	ds->slave.cs = cs;
 	ds->regs = (struct andes_spi_regs *)CONFIG_SYS_SPI_BASE;
 
 	/*
diff --git a/drivers/spi/armada100_spi.c b/drivers/spi/armada100_spi.c
index 7384c9c..afdbe05 100644
--- a/drivers/spi/armada100_spi.c
+++ b/drivers/spi/armada100_spi.c
@@ -120,12 +120,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 {
 	struct armd_spi_slave *pss;
 
-	pss = malloc(sizeof(*pss));
+	pss = spi_alloc_slave(struct armd_spi_slave, bus, cs);
 	if (!pss)
 		return NULL;
 
-	pss->slave.bus = bus;
-	pss->slave.cs = cs;
 	pss->spi_reg = (struct ssp_reg *)SSP_REG_BASE(CONFIG_SYS_SSP_PORT);
 
 	pss->cr0 = SSCR0_MOTO | SSCR0_DATASIZE(DEFAULT_WORD_LEN) | SSCR0_SSE;
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index c7a51f7..0bca22f 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -84,12 +84,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	if (mode & SPI_CPOL)
 		csrx |= ATMEL_SPI_CSRx_CPOL;
 
-	as = malloc(sizeof(struct atmel_spi_slave));
+	as = spi_alloc_slave(struct atmel_spi_slave, bus, cs);
 	if (!as)
 		return NULL;
 
-	as->slave.bus = bus;
-	as->slave.cs = cs;
 	as->regs = regs;
 	as->mr = ATMEL_SPI_MR_MSTR | ATMEL_SPI_MR_MODFDIS
 #if defined(CONFIG_AT91SAM9X5)
diff --git a/drivers/spi/bfin_spi.c b/drivers/spi/bfin_spi.c
index e080bec..ab2e8b9 100644
--- a/drivers/spi/bfin_spi.c
+++ b/drivers/spi/bfin_spi.c
@@ -182,12 +182,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 		default: return NULL;
 	}
 
-	bss = malloc(sizeof(*bss));
+	bss = spi_alloc_slave(struct bfin_spi_slave, bus, cs);
 	if (!bss)
 		return NULL;
 
-	bss->slave.bus = bus;
-	bss->slave.cs = cs;
 	bss->mmr_base = (void *)mmr_base;
 	bss->ctl = SPE | MSTR | TDBR_CORE;
 	if (mode & SPI_CPHA) bss->ctl |= CPHA;
diff --git a/drivers/spi/cf_qspi.c b/drivers/spi/cf_qspi.c
index 72dd1a5..a37ac4e 100644
--- a/drivers/spi/cf_qspi.c
+++ b/drivers/spi/cf_qspi.c
@@ -120,13 +120,11 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	if (!spi_cs_is_valid(bus, cs))
 		return NULL;
 
-	dev = malloc(sizeof(struct cf_qspi_slave));
+	dev = spi_alloc_slave(struct cf_qspi_slave, bus, cs);
 	if (!dev)
 		return NULL;
 
 	/* Initialize to known value */
-	dev->slave.bus = bus;
-	dev->slave.cs  = cs;
 	dev->regs      = (qspi_t *)MMAP_QSPI;
 	dev->qmr       = 0;
 	dev->qwr       = 0;
diff --git a/drivers/spi/cf_spi.c b/drivers/spi/cf_spi.c
index a883da9..afe7917 100644
--- a/drivers/spi/cf_spi.c
+++ b/drivers/spi/cf_spi.c
@@ -330,12 +330,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	if (!spi_cs_is_valid(bus, cs))
 		return NULL;
 
-	cfslave = malloc(sizeof(struct cf_spi_slave));
+	cfslave = spi_alloc_slave(struct cf_spi_slave, bus, cs);
 	if (!cfslave)
 		return NULL;
 
-	cfslave->slave.bus = bus;
-	cfslave->slave.cs = cs;
 	cfslave->baudrate = max_hz;
 
 	/* specific setup */
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
index 13aca52..74792af 100644
--- a/drivers/spi/davinci_spi.c
+++ b/drivers/spi/davinci_spi.c
@@ -44,12 +44,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	if (!spi_cs_is_valid(bus, cs))
 		return NULL;
 
-	ds = malloc(sizeof(*ds));
+	ds = spi_alloc_slave(struct davinci_spi_slave, bus, cs);
 	if (!ds)
 		return NULL;
 
-	ds->slave.bus = bus;
-	ds->slave.cs = cs;
 	ds->regs = (struct davinci_spi_regs *)CONFIG_SYS_SPI_BASE;
 	ds->freq = max_hz;
 
diff --git a/drivers/spi/fsl_espi.c b/drivers/spi/fsl_espi.c
index eb99e90..28609ee 100644
--- a/drivers/spi/fsl_espi.c
+++ b/drivers/spi/fsl_espi.c
@@ -79,12 +79,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	if (!spi_cs_is_valid(bus, cs))
 		return NULL;
 
-	fsl = malloc(sizeof(struct fsl_spi_slave));
+	fsl = spi_alloc_slave(struct fsl_spi_slave, bus, cs);
 	if (!fsl)
 		return NULL;
 
-	fsl->slave.bus = bus;
-	fsl->slave.cs = cs;
 	fsl->mode = mode;
 	fsl->max_transfer_length = ESPI_MAX_DATA_TRANSFER_LEN;
 
diff --git a/drivers/spi/kirkwood_spi.c b/drivers/spi/kirkwood_spi.c
index a7cda75..5a226e3 100644
--- a/drivers/spi/kirkwood_spi.c
+++ b/drivers/spi/kirkwood_spi.c
@@ -46,13 +46,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	if (!spi_cs_is_valid(bus, cs))
 		return NULL;
 
-	slave = malloc(sizeof(struct spi_slave));
+	slave = spi_alloc_slave_base(bus, cs);
 	if (!slave)
 		return NULL;
 
-	slave->bus = bus;
-	slave->cs = cs;
-
 	writel(~KWSPI_CSN_ACT | KWSPI_SMEMRDY, &spireg->ctrl);
 
 	/* calculate spi clock prescaller using max_hz */
diff --git a/drivers/spi/mpc52xx_spi.c b/drivers/spi/mpc52xx_spi.c
index 3e96b3f..4b50bca 100644
--- a/drivers/spi/mpc52xx_spi.c
+++ b/drivers/spi/mpc52xx_spi.c
@@ -48,13 +48,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 {
 	struct spi_slave *slave;
 
-	slave = malloc(sizeof(struct spi_slave));
+	slave = spi_alloc_slave_base(bus, cs);
 	if (!slave)
 		return NULL;
 
-	slave->bus = bus;
-	slave->cs = cs;
-
 	return slave;
 }
 
diff --git a/drivers/spi/mpc8xxx_spi.c b/drivers/spi/mpc8xxx_spi.c
index 4e46041..6b0e3b4 100644
--- a/drivers/spi/mpc8xxx_spi.c
+++ b/drivers/spi/mpc8xxx_spi.c
@@ -45,13 +45,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	if (!spi_cs_is_valid(bus, cs))
 		return NULL;
 
-	slave = malloc(sizeof(struct spi_slave));
+	slave = spi_alloc_slave_base(bus, cs);
 	if (!slave)
 		return NULL;
 
-	slave->bus = bus;
-	slave->cs = cs;
-
 	/*
 	 * TODO: Some of the code in spi_init() should probably move
 	 * here, or into spi_claim_bus() below.
diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c
index 859c43f..d792d8d 100644
--- a/drivers/spi/mxc_spi.c
+++ b/drivers/spi/mxc_spi.c
@@ -408,7 +408,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	if (bus >= ARRAY_SIZE(spi_bases))
 		return NULL;
 
-	mxcs = calloc(sizeof(struct mxc_spi_slave), 1);
+	mxcs = spi_alloc_slave(struct mxc_spi_slave, bus, cs);
 	if (!mxcs) {
 		puts("mxc_spi: SPI Slave not allocated !\n");
 		return NULL;
@@ -424,8 +424,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 
 	cs = ret;
 
-	mxcs->slave.bus = bus;
-	mxcs->slave.cs = cs;
 	mxcs->base = spi_bases[bus];
 
 	ret = spi_cfg_mxc(mxcs, cs, max_hz, mode);
diff --git a/drivers/spi/mxs_spi.c b/drivers/spi/mxs_spi.c
index 42e4c99..fb8aa08 100644
--- a/drivers/spi/mxs_spi.c
+++ b/drivers/spi/mxs_spi.c
@@ -89,7 +89,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 		return NULL;
 	}
 
-	mxs_slave = calloc(sizeof(struct mxs_spi_slave), 1);
+	mxs_slave = spi_alloc_slave(struct mxs_spi_slave, bus, cs);
 	if (!mxs_slave)
 		return NULL;
 
@@ -98,8 +98,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 
 	addr = MXS_SSP0_BASE + (bus * MXS_SPI_PORT_OFFSET);
 
-	mxs_slave->slave.bus = bus;
-	mxs_slave->slave.cs = cs;
 	mxs_slave->max_khz = max_hz / 1000;
 	mxs_slave->mode = mode;
 	mxs_slave->regs = (struct mxs_ssp_regs *)addr;
diff --git a/drivers/spi/oc_tiny_spi.c b/drivers/spi/oc_tiny_spi.c
index fc01fb8..6f7b1ed 100644
--- a/drivers/spi/oc_tiny_spi.c
+++ b/drivers/spi/oc_tiny_spi.c
@@ -90,13 +90,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	if (!spi_cs_is_valid(bus, cs) || gpio_request(cs, "tiny_spi"))
 		return NULL;
 
-	tiny_spi = malloc(sizeof(*tiny_spi));
+	tiny_spi = spi_alloc_slave(struct tiny_spi_slave, bus, cs);
 	if (!tiny_spi)
 		return NULL;
-	memset(tiny_spi, 0, sizeof(*tiny_spi));
 
-	tiny_spi->slave.bus = bus;
-	tiny_spi->slave.cs = cs;
 	tiny_spi->host = &tiny_spi_host_list[bus];
 	tiny_spi->mode = mode & (SPI_CPOL | SPI_CPHA);
 	tiny_spi->flg = mode & SPI_CS_HIGH ? 1 : 0;
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c
index 6791a7e..cb6be44 100644
--- a/drivers/spi/omap3_spi.c
+++ b/drivers/spi/omap3_spi.c
@@ -66,12 +66,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 				  unsigned int max_hz, unsigned int mode)
 {
 	struct omap3_spi_slave	*ds;
-
-	ds = malloc(sizeof(struct omap3_spi_slave));
-	if (!ds) {
-		printf("SPI error: malloc of SPI structure failed\n");
-		return NULL;
-	}
+	struct mcspi *regs;
 
 	/*
 	 * OMAP3 McSPI (MultiChannel SPI) has 4 busses (modules)
@@ -84,21 +79,21 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 
 	switch (bus) {
 	case 0:
-		ds->regs = (struct mcspi *)OMAP3_MCSPI1_BASE;
+		regs = (struct mcspi *)OMAP3_MCSPI1_BASE;
 		break;
 #ifdef OMAP3_MCSPI2_BASE
 	case 1:
-		ds->regs = (struct mcspi *)OMAP3_MCSPI2_BASE;
+		regs = (struct mcspi *)OMAP3_MCSPI2_BASE;
 		break;
 #endif
 #ifdef OMAP3_MCSPI3_BASE 
 	case 2:
-		ds->regs = (struct mcspi *)OMAP3_MCSPI3_BASE;
+		regs = (struct mcspi *)OMAP3_MCSPI3_BASE;
 		break;
 #endif
 #ifdef OMAP3_MCSPI4_BASE
 	case 3:
-		ds->regs = (struct mcspi *)OMAP3_MCSPI4_BASE;
+		regs = (struct mcspi *)OMAP3_MCSPI4_BASE;
 		break;
 #endif
 	default:
@@ -106,7 +101,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 			Supported busses 0 - 3\n", bus);
 		return NULL;
 	}
-	ds->slave.bus = bus;
 
 	if (((bus == 0) && (cs > 3)) ||
 			((bus == 1) && (cs > 1)) ||
@@ -116,19 +110,26 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 			on bus %i\n", cs, bus);
 		return NULL;
 	}
-	ds->slave.cs = cs;
 
 	if (max_hz > OMAP3_MCSPI_MAX_FREQ) {
 		printf("SPI error: unsupported frequency %i Hz. \
 			Max frequency is 48 Mhz\n", max_hz);
 		return NULL;
 	}
-	ds->freq = max_hz;
 
 	if (mode > SPI_MODE_3) {
 		printf("SPI error: unsupported SPI mode %i\n", mode);
 		return NULL;
 	}
+
+	ds = spi_alloc_slave(struct omap3_spi_slave, bus, cs);
+	if (!ds) {
+		printf("SPI error: malloc of SPI structure failed\n");
+		return NULL;
+	}
+
+	ds->regs = regs;
+	ds->freq = max_hz;
 	ds->mode = mode;
 
 	return &ds->slave;
diff --git a/drivers/spi/sh_spi.c b/drivers/spi/sh_spi.c
index e944b23..744afe3 100644
--- a/drivers/spi/sh_spi.c
+++ b/drivers/spi/sh_spi.c
@@ -103,12 +103,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	if (!spi_cs_is_valid(bus, cs))
 		return NULL;
 
-	ss = malloc(sizeof(struct spi_slave));
+	ss = spi_alloc_slave(struct sh_spi, bus, cs);
 	if (!ss)
 		return NULL;
 
-	ss->slave.bus = bus;
-	ss->slave.cs = cs;
 	ss->regs = (struct sh_spi_regs *)CONFIG_SH_SPI_BASE;
 
 	/* SPI sycle stop */
diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi.c
index 13df8cb..a1b84b6 100644
--- a/drivers/spi/soft_spi.c
+++ b/drivers/spi/soft_spi.c
@@ -73,12 +73,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	if (!spi_cs_is_valid(bus, cs))
 		return NULL;
 
-	ss = malloc(sizeof(struct soft_spi_slave));
+	ss = spi_alloc_slave(struct soft_spi_slave, bus, cs);
 	if (!ss)
 		return NULL;
 
-	ss->slave.bus = bus;
-	ss->slave.cs = cs;
 	ss->mode = mode;
 
 	/* TODO: Use max_hz to limit the SCK rate */
diff --git a/drivers/spi/tegra_spi.c b/drivers/spi/tegra_spi.c
index 9bb34e2..3b9f293 100644
--- a/drivers/spi/tegra_spi.c
+++ b/drivers/spi/tegra_spi.c
@@ -77,13 +77,11 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 		return NULL;
 	}
 
-	spi = malloc(sizeof(struct tegra_spi_slave));
+	spi = spi_alloc_slave(struct tegra_spi_slave, bus, cs);
 	if (!spi) {
 		printf("SPI error: malloc of SPI structure failed\n");
 		return NULL;
 	}
-	spi->slave.bus = bus;
-	spi->slave.cs = cs;
 	spi->freq = max_hz;
 	spi->regs = (struct spi_tegra *)NV_PA_SPI_BASE;
 	spi->mode = mode;
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index 52a4134..9798831 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -85,14 +85,12 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 		return NULL;
 	}
 
-	xilspi = malloc(sizeof(*xilspi));
+	xilspi = spi_alloc_slave(struct xilinx_spi_slave, bus, cs);
 	if (!xilspi) {
 		printf("XILSPI error: %s: malloc of SPI structure failed\n",
 				__func__);
 		return NULL;
 	}
-	xilspi->slave.bus = bus;
-	xilspi->slave.cs = cs;
 	xilspi->regs = (struct xilinx_spi_reg *)xilinx_spi_base_list[bus];
 	xilspi->freq = max_hz;
 	xilspi->mode = mode;
-- 
1.7.7.3

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

* [U-Boot] [PATCH 05/15] sf: Add spi_flash_alloc() to create a new SPI flash struct
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
                   ` (3 preceding siblings ...)
  2012-12-26 22:28 ` [U-Boot] [PATCH 04/15] spi: Use spi_alloc_slave() in each SPI driver Simon Glass
@ 2012-12-26 22:28 ` Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 06/15] sf: Use spi_flash_alloc() in each SPI flash driver Simon Glass
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

At present it is difficult to extend the SPI flash structure since
all devices allocate it themselves, and few of them zero all fields.
Add a new function spi_flash_alloc() which can be used by SPI devices
to perform this allocation, and thus ensure that all devices can
better cope with SPI structure changes.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 drivers/mtd/spi/spi_flash.c |   25 +++++++++++++++++++++++++
 include/spi_flash.h         |   38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 00aece9..17f3d3c 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -401,6 +401,31 @@ err_claim_bus:
 	return NULL;
 }
 
+void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi,
+			 const char *name)
+{
+	struct spi_flash *flash;
+	void *ptr;
+
+	ptr = malloc(size);
+	if (!ptr) {
+		debug("SF: Failed to allocate memory\n");
+		return NULL;
+	}
+	memset(ptr, '\0', size);
+	flash = (struct spi_flash *)(ptr + offset);
+
+	/* Set up some basic fields - caller will sort out sizes */
+	flash->spi = spi;
+	flash->name = name;
+
+	flash->read = spi_flash_cmd_read_fast;
+	flash->write = spi_flash_cmd_write_multi;
+	flash->erase = spi_flash_cmd_erase;
+
+	return flash;
+}
+
 void spi_flash_free(struct spi_flash *flash)
 {
 	spi_free_slave(flash->spi);
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 9da9062..030d49c 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -47,6 +47,44 @@ struct spi_flash {
 				size_t len);
 };
 
+/**
+ * spi_flash_do_alloc - Allocate a new spi flash structure
+ *
+ * The structure is allocated and cleared with default values for
+ * read, write and erase, which the caller can modify. The caller must set
+ * up size, page_size and sector_size.
+ *
+ * Use the helper macro spi_flash_alloc() to call this.
+ *
+ * @offset: Offset of struct spi_slave within slave structure
+ * @size: Size of slave structure
+ * @spi: SPI slave
+ * @name: Name of SPI flash device
+ */
+void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi,
+			 const char *name);
+
+/**
+ * spi_flash_alloc - Allocate a new SPI flash structure
+ *
+ * @_struct: Name of structure to allocate (e.g. struct ramtron_spi_fram). This
+ *	structure must contain a member 'struct spi_flash *flash'.
+ * @spi: SPI slave
+ * @name: Name of SPI flash device
+ */
+#define spi_flash_alloc(_struct, spi, name) \
+	spi_flash_do_alloc(offsetof(_struct, flash), sizeof(_struct), \
+				spi, name)
+
+/**
+ * spi_flash_alloc_base - Allocate a new SPI flash structure with no private data
+ *
+ * @spi: SPI slave
+ * @name: Name of SPI flash device
+ */
+#define spi_flash_alloc_base(spi, name) \
+	spi_flash_do_alloc(0, sizeof(struct spi_flash), spi, name)
+
 struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
 		unsigned int max_hz, unsigned int spi_mode);
 void spi_flash_free(struct spi_flash *flash);
-- 
1.7.7.3

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

* [U-Boot] [PATCH 06/15] sf: Use spi_flash_alloc() in each SPI flash driver
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
                   ` (4 preceding siblings ...)
  2012-12-26 22:28 ` [U-Boot] [PATCH 05/15] sf: Add spi_flash_alloc() to create a new SPI flash struct Simon Glass
@ 2012-12-26 22:28 ` Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 07/15] x86: spi: Add Intel ICH driver Simon Glass
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

Rather than each device having its own way to allocate a SPI flash
structure, use the new allocation function everywhere. This will make it
easier to extend the interface without breaking devices.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 drivers/mtd/spi/atmel.c    |    8 +-------
 drivers/mtd/spi/eon.c      |    8 +-------
 drivers/mtd/spi/macronix.c |    8 +-------
 drivers/mtd/spi/ramtron.c  |    4 +---
 drivers/mtd/spi/spansion.c |    8 +-------
 drivers/mtd/spi/sst.c      |    8 +-------
 drivers/mtd/spi/stmicro.c  |    8 +-------
 drivers/mtd/spi/winbond.c  |    8 +-------
 8 files changed, 8 insertions(+), 52 deletions(-)

diff --git a/drivers/mtd/spi/atmel.c b/drivers/mtd/spi/atmel.c
index 006f6d5..6a92c4b 100644
--- a/drivers/mtd/spi/atmel.c
+++ b/drivers/mtd/spi/atmel.c
@@ -480,15 +480,13 @@ struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode)
 		return NULL;
 	}
 
-	asf = malloc(sizeof(struct atmel_spi_flash));
+	asf = spi_flash_alloc(struct atmel_spi_flash, spi, params->name);
 	if (!asf) {
 		debug("SF: Failed to allocate memory\n");
 		return NULL;
 	}
 
 	asf->params = params;
-	asf->flash.spi = spi;
-	asf->flash.name = params->name;
 
 	/* Assuming power-of-two page size initially. */
 	page_size = 1 << params->l2_page_size;
@@ -513,7 +511,6 @@ struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode)
 			asf->flash.erase = dataflash_erase_at45;
 			page_size += 1 << (params->l2_page_size - 5);
 		} else {
-			asf->flash.read = spi_flash_cmd_read_fast;
 			asf->flash.write = dataflash_write_p2;
 			asf->flash.erase = dataflash_erase_p2;
 		}
@@ -524,9 +521,6 @@ struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode)
 
 	case DF_FAMILY_AT26F:
 	case DF_FAMILY_AT26DF:
-		asf->flash.read = spi_flash_cmd_read_fast;
-		asf->flash.write = spi_flash_cmd_write_multi;
-		asf->flash.erase = spi_flash_cmd_erase;
 		asf->flash.page_size = page_size;
 		asf->flash.sector_size = 4096;
 		/* clear SPRL# bit for locked flash */
diff --git a/drivers/mtd/spi/eon.c b/drivers/mtd/spi/eon.c
index 691ed4e..b16e7ab 100644
--- a/drivers/mtd/spi/eon.c
+++ b/drivers/mtd/spi/eon.c
@@ -46,18 +46,12 @@ struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode)
 		return NULL;
 	}
 
-	flash = malloc(sizeof(*flash));
+	flash = spi_flash_alloc_base(spi, params->name);
 	if (!flash) {
 		debug("SF: Failed to allocate memory\n");
 		return NULL;
 	}
 
-	flash->spi = spi;
-	flash->name = params->name;
-
-	flash->write = spi_flash_cmd_write_multi;
-	flash->erase = spi_flash_cmd_erase;
-	flash->read = spi_flash_cmd_read_fast;
 	flash->page_size = 256;
 	flash->sector_size = 256 * 16 * 16;
 	flash->size = 256 * 16
diff --git a/drivers/mtd/spi/macronix.c b/drivers/mtd/spi/macronix.c
index c97a39d..036c30d 100644
--- a/drivers/mtd/spi/macronix.c
+++ b/drivers/mtd/spi/macronix.c
@@ -97,18 +97,12 @@ struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode)
 		return NULL;
 	}
 
-	flash = malloc(sizeof(*flash));
+	flash = spi_flash_alloc_base(spi, params->name);
 	if (!flash) {
 		debug("SF: Failed to allocate memory\n");
 		return NULL;
 	}
 
-	flash->spi = spi;
-	flash->name = params->name;
-
-	flash->write = spi_flash_cmd_write_multi;
-	flash->erase = spi_flash_cmd_erase;
-	flash->read = spi_flash_cmd_read_fast;
 	flash->page_size = 256;
 	flash->sector_size = 256 * 16 * 16;
 	flash->size = flash->sector_size * params->nr_blocks;
diff --git a/drivers/mtd/spi/ramtron.c b/drivers/mtd/spi/ramtron.c
index 0999781..5299a6d 100644
--- a/drivers/mtd/spi/ramtron.c
+++ b/drivers/mtd/spi/ramtron.c
@@ -284,15 +284,13 @@ struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode)
 	return NULL;
 
 found:
-	sn = malloc(sizeof(*sn));
+	sn = spi_flash_alloc(struct ramtron_spi_fram, spi, params->name);
 	if (!sn) {
 		debug("SF: Failed to allocate memory\n");
 		return NULL;
 	}
 
 	sn->params = params;
-	sn->flash.spi = spi;
-	sn->flash.name = params->name;
 
 	sn->flash.write = ramtron_write;
 	sn->flash.read = ramtron_read;
diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c
index 32b76e0..afd6a8c 100644
--- a/drivers/mtd/spi/spansion.c
+++ b/drivers/mtd/spi/spansion.c
@@ -128,18 +128,12 @@ struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode)
 		return NULL;
 	}
 
-	flash = malloc(sizeof(*flash));
+	flash = spi_flash_alloc_base(spi, params->name);
 	if (!flash) {
 		debug("SF: Failed to allocate memory\n");
 		return NULL;
 	}
 
-	flash->spi = spi;
-	flash->name = params->name;
-
-	flash->write = spi_flash_cmd_write_multi;
-	flash->erase = spi_flash_cmd_erase;
-	flash->read = spi_flash_cmd_read_fast;
 	flash->page_size = 256;
 	flash->sector_size = 256 * params->pages_per_sector;
 	flash->size = flash->sector_size * params->nr_sectors;
diff --git a/drivers/mtd/spi/sst.c b/drivers/mtd/spi/sst.c
index ced4f24..95f5490 100644
--- a/drivers/mtd/spi/sst.c
+++ b/drivers/mtd/spi/sst.c
@@ -203,22 +203,16 @@ spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode)
 		return NULL;
 	}
 
-	stm = malloc(sizeof(*stm));
+	stm = spi_flash_alloc(struct sst_spi_flash, spi, params->name);
 	if (!stm) {
 		debug("SF: Failed to allocate memory\n");
 		return NULL;
 	}
 
 	stm->params = params;
-	stm->flash.spi = spi;
-	stm->flash.name = params->name;
 
 	if (stm->params->flags & SST_FEAT_WP)
 		stm->flash.write = sst_write_wp;
-	else
-		stm->flash.write = spi_flash_cmd_write_multi;
-	stm->flash.erase = spi_flash_cmd_erase;
-	stm->flash.read = spi_flash_cmd_read_fast;
 	stm->flash.page_size = 256;
 	stm->flash.sector_size = 4096;
 	stm->flash.size = stm->flash.sector_size * params->nr_sectors;
diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c
index 30b626a..44fc8aa 100644
--- a/drivers/mtd/spi/stmicro.c
+++ b/drivers/mtd/spi/stmicro.c
@@ -146,18 +146,12 @@ struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode)
 		return NULL;
 	}
 
-	flash = malloc(sizeof(*flash));
+	flash = spi_flash_alloc_base(spi, params->name);
 	if (!flash) {
 		debug("SF: Failed to allocate memory\n");
 		return NULL;
 	}
 
-	flash->spi = spi;
-	flash->name = params->name;
-
-	flash->write = spi_flash_cmd_write_multi;
-	flash->erase = spi_flash_cmd_erase;
-	flash->read = spi_flash_cmd_read_fast;
 	flash->page_size = 256;
 	flash->sector_size = 256 * params->pages_per_sector;
 	flash->size = flash->sector_size * params->nr_sectors;
diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c
index f6aab3d..f112ae1 100644
--- a/drivers/mtd/spi/winbond.c
+++ b/drivers/mtd/spi/winbond.c
@@ -87,18 +87,12 @@ struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode)
 		return NULL;
 	}
 
-	flash = malloc(sizeof(*flash));
+	flash = spi_flash_alloc_base(spi, params->name);
 	if (!flash) {
 		debug("SF: Failed to allocate memory\n");
 		return NULL;
 	}
 
-	flash->spi = spi;
-	flash->name = params->name;
-
-	flash->write = spi_flash_cmd_write_multi;
-	flash->erase = spi_flash_cmd_erase;
-	flash->read = spi_flash_cmd_read_fast;
 	flash->page_size = 256;
 	flash->sector_size = 4096;
 	flash->size = 4096 * 16 * params->nr_blocks;
-- 
1.7.7.3

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

* [U-Boot] [PATCH 07/15] x86: spi: Add Intel ICH driver
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
                   ` (5 preceding siblings ...)
  2012-12-26 22:28 ` [U-Boot] [PATCH 06/15] sf: Use spi_flash_alloc() in each SPI flash driver Simon Glass
@ 2012-12-26 22:28 ` Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 08/15] spi: Add parameter for maximum write size Simon Glass
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

This supports Intel ICH7/9. The Intel controller is a little unusual in
that it is mostly intended for use with SPI flash, and has some
optimisations and features specifically for that application. In
particular it is not possible to support ongoing transactions that
continue over many calls with SPI_XFER_BEGIN and SPI_XFER_END.

This driver supports writes of up to 64 bytes at a time, the limit
for the controller. Future work will improve this.

Signed-off-by: Bernie Thompson <bhthompson@chromium.org>
Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Signed-off-by: Gabe Black <gabeblack@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
---
 drivers/spi/Makefile |    1 +
 drivers/spi/ich.c    |  747 ++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/spi/ich.h    |  144 ++++++++++
 3 files changed, 892 insertions(+), 0 deletions(-)
 create mode 100644 drivers/spi/ich.c
 create mode 100644 drivers/spi/ich.h

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 4e8de5d..cfdc5d3 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -38,6 +38,7 @@ COBJS-$(CONFIG_CF_SPI) += cf_spi.o
 COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o
 COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
 COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
+COBJS-$(CONFIG_ICH_SPI) +=  ich.o
 COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
 COBJS-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
 COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c
new file mode 100644
index 0000000..31f9482
--- /dev/null
+++ b/drivers/spi/ich.c
@@ -0,0 +1,747 @@
+/*
+ * Copyright (c) 2011-12 The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but without any warranty; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * This file is derived from the flashrom project.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <spi.h>
+#include <pci.h>
+#include <pci_ids.h>
+#include <asm/io.h>
+
+#include "ich.h"
+
+#define SPI_OPCODE_WREN      0x06
+#define SPI_OPCODE_FAST_READ 0x0b
+
+struct ich_ctlr {
+	pci_dev_t dev;		/* PCI device number */
+	int ich_version;	/* Controller version, 7 or 9 */
+	int ichspi_lock;
+	int locked;
+	uint8_t *opmenu;
+	int menubytes;
+	void *base;		/* Base of register set */
+	uint16_t *preop;
+	uint16_t *optype;
+	uint32_t *addr;
+	uint8_t *data;
+	unsigned databytes;
+	uint8_t *status;
+	uint16_t *control;
+	uint32_t *bbar;
+	uint32_t *pr;		/* only for ich9 */
+	uint8_t *speed;		/* pointer to speed control */
+};
+
+struct ich_ctlr ctlr;
+
+static inline struct ich_spi_slave *to_ich_spi(struct spi_slave *slave)
+{
+	return container_of(slave, struct ich_spi_slave, slave);
+}
+
+static unsigned int ich_reg(const void *addr)
+{
+	return (unsigned)(addr - ctlr.base) & 0xffff;
+}
+
+static u8 ich_readb(const void *addr)
+{
+	u8 value = readb(addr);
+
+	debug("read %2.2x from %4.4x\n", value, ich_reg(addr));
+
+	return value;
+}
+
+static u16 ich_readw(const void *addr)
+{
+	u16 value = readw(addr);
+
+	debug("read %4.4x from %4.4x\n", value, ich_reg(addr));
+
+	return value;
+}
+
+static u32 ich_readl(const void *addr)
+{
+	u32 value = readl(addr);
+
+	debug("read %8.8x from %4.4x\n", value, ich_reg(addr));
+
+	return value;
+}
+
+static void ich_writeb(u8 value, void *addr)
+{
+	writeb(value, addr);
+	debug("wrote %2.2x to %4.4x\n", value, ich_reg(addr));
+}
+
+static void ich_writew(u16 value, void *addr)
+{
+	writew(value, addr);
+	debug("wrote %4.4x to %4.4x\n", value, ich_reg(addr));
+}
+
+static void ich_writel(u32 value, void *addr)
+{
+	writel(value, addr);
+	debug("wrote %8.8x to %4.4x\n", value, ich_reg(addr));
+}
+
+static void write_reg(const void *value, void *dest, uint32_t size)
+{
+	const uint8_t *bvalue = value;
+	uint8_t *bdest = dest;
+
+	while (size >= 4) {
+		ich_writel(*(const uint32_t *)bvalue, bdest);
+		bdest += 4; bvalue += 4; size -= 4;
+	}
+	while (size) {
+		ich_writeb(*bvalue, bdest);
+		bdest++; bvalue++; size--;
+	}
+}
+
+static void read_reg(const void *src, void *value, uint32_t size)
+{
+	const uint8_t *bsrc = src;
+	uint8_t *bvalue = value;
+
+	while (size >= 4) {
+		*(uint32_t *)bvalue = ich_readl(bsrc);
+		bsrc += 4; bvalue += 4; size -= 4;
+	}
+	while (size) {
+		*bvalue = ich_readb(bsrc);
+		bsrc++; bvalue++; size--;
+	}
+}
+
+static void ich_set_bbar(struct ich_ctlr *ctlr, uint32_t minaddr)
+{
+	const uint32_t bbar_mask = 0x00ffff00;
+	uint32_t ichspi_bbar;
+
+	minaddr &= bbar_mask;
+	ichspi_bbar = ich_readl(ctlr->bbar) & ~bbar_mask;
+	ichspi_bbar |= minaddr;
+	ich_writel(ichspi_bbar, ctlr->bbar);
+}
+
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+	puts("spi_cs_is_valid used but not implemented\n");
+	return 0;
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+		unsigned int max_hz, unsigned int mode)
+{
+	struct ich_spi_slave *ich;
+
+	ich = spi_alloc_slave(struct ich_spi_slave, bus, cs);
+	if (!ich) {
+		puts("ICH SPI: Out of memory\n");
+		return NULL;
+	}
+
+	ich->speed = max_hz;
+
+	return &ich->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+	struct ich_spi_slave *ich = to_ich_spi(slave);
+
+	free(ich);
+}
+
+/*
+ * Check if this device ID matches one of supported Intel PCH devices.
+ *
+ * Return the ICH version if there is a match, or zero otherwise.
+ */
+static int get_ich_version(uint16_t device_id)
+{
+	if (device_id == PCI_DEVICE_ID_INTEL_TGP_LPC)
+		return 7;
+
+	if ((device_id >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN &&
+	     device_id <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX) ||
+	    (device_id >= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN &&
+	     device_id <= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX))
+		return 9;
+
+	return 0;
+}
+
+static int ich_find_spi_controller(pci_dev_t *devp, int *ich_versionp)
+{
+	int last_bus = pci_last_busno();
+	int bus;
+
+	if (last_bus == -1) {
+		debug("No PCI busses?\n");
+		return -1;
+	}
+
+	for (bus = 0; bus <= last_bus; bus++) {
+		uint16_t vendor_id, device_id;
+		uint32_t ids;
+		pci_dev_t dev;
+
+		dev = PCI_BDF(bus, 31, 0);
+		pci_read_config_dword(dev, 0, &ids);
+		vendor_id = ids;
+		device_id = ids >> 16;
+
+		if (vendor_id == PCI_VENDOR_ID_INTEL) {
+			*devp = dev;
+			*ich_versionp = get_ich_version(device_id);
+			return 0;
+		}
+	}
+
+	debug("ICH SPI: No ICH found.\n");
+	return -1;
+}
+
+static int ich_init_controller(struct ich_ctlr *ctlr)
+{
+	uint8_t *rcrb; /* Root Complex Register Block */
+	uint32_t rcba; /* Root Complex Base Address */
+
+	pci_read_config_dword(ctlr->dev, 0xf0, &rcba);
+	/* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable. */
+	rcrb = (uint8_t *)(rcba & 0xffffc000);
+	if (ctlr->ich_version == 7) {
+		struct ich7_spi_regs *ich7_spi;
+
+		ich7_spi = (struct ich7_spi_regs *)(rcrb + 0x3020);
+		ctlr->ichspi_lock = ich_readw(&ich7_spi->spis) & SPIS_LOCK;
+		ctlr->opmenu = ich7_spi->opmenu;
+		ctlr->menubytes = sizeof(ich7_spi->opmenu);
+		ctlr->optype = &ich7_spi->optype;
+		ctlr->addr = &ich7_spi->spia;
+		ctlr->data = (uint8_t *)ich7_spi->spid;
+		ctlr->databytes = sizeof(ich7_spi->spid);
+		ctlr->status = (uint8_t *)&ich7_spi->spis;
+		ctlr->control = &ich7_spi->spic;
+		ctlr->bbar = &ich7_spi->bbar;
+		ctlr->preop = &ich7_spi->preop;
+		ctlr->base = ich7_spi;
+	} else if (ctlr->ich_version == 9) {
+		struct ich9_spi_regs *ich9_spi;
+
+		ich9_spi = (struct ich9_spi_regs *)(rcrb + 0x3800);
+		ctlr->ichspi_lock = ich_readw(&ich9_spi->hsfs) & HSFS_FLOCKDN;
+		ctlr->opmenu = ich9_spi->opmenu;
+		ctlr->menubytes = sizeof(ich9_spi->opmenu);
+		ctlr->optype = &ich9_spi->optype;
+		ctlr->addr = &ich9_spi->faddr;
+		ctlr->data = (uint8_t *)ich9_spi->fdata;
+		ctlr->databytes = sizeof(ich9_spi->fdata);
+		ctlr->status = &ich9_spi->ssfs;
+		ctlr->control = (uint16_t *)ich9_spi->ssfc;
+		ctlr->speed = ich9_spi->ssfc + 2;
+		ctlr->bbar = &ich9_spi->bbar;
+		ctlr->preop = &ich9_spi->preop;
+		ctlr->pr = &ich9_spi->pr[0];
+		ctlr->base = ich9_spi;
+	} else {
+		debug("ICH SPI: Unrecognized ICH version %d.\n",
+		      ctlr->ich_version);
+		return -1;
+	}
+	debug("ICH SPI: Version %d detected\n", ctlr->ich_version);
+
+	ich_set_bbar(ctlr, 0);
+
+	return 0;
+}
+
+void spi_init(void)
+{
+	uint8_t bios_cntl;
+
+	if (ich_find_spi_controller(&ctlr.dev, &ctlr.ich_version)) {
+		printf("ICH SPI: Cannot find device\n");
+		return;
+	}
+
+	if (ich_init_controller(&ctlr)) {
+		printf("ICH SPI: Cannot setup controller\n");
+		return;
+	}
+
+	/*
+	 * Disable the BIOS write protect so write commands are allowed.  On
+	 * v9, deassert SMM BIOS Write Protect Disable.
+	 */
+	pci_read_config_byte(ctlr.dev, 0xdc, &bios_cntl);
+	if (ctlr.ich_version == 9)
+		bios_cntl &= ~(1 << 5);
+	pci_write_config_byte(ctlr.dev, 0xdc, bios_cntl | 0x1);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	/* Handled by ICH automatically. */
+	return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+	/* Handled by ICH automatically. */
+}
+
+void spi_cs_activate(struct spi_slave *slave)
+{
+	/* Handled by ICH automatically. */
+}
+
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+	/* Handled by ICH automatically. */
+}
+
+static inline void spi_use_out(struct spi_trans *trans, unsigned bytes)
+{
+	trans->out += bytes;
+	trans->bytesout -= bytes;
+}
+
+static inline void spi_use_in(struct spi_trans *trans, unsigned bytes)
+{
+	trans->in += bytes;
+	trans->bytesin -= bytes;
+}
+
+static void spi_setup_type(struct spi_trans *trans, int data_bytes)
+{
+	trans->type = 0xFF;
+
+	/* Try to guess spi type from read/write sizes. */
+	if (trans->bytesin == 0) {
+		if (trans->bytesout + data_bytes > 4)
+			/*
+			 * If bytesin = 0 and bytesout > 4, we presume this is
+			 * a write data operation, which is accompanied by an
+			 * address.
+			 */
+			trans->type = SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS;
+		else
+			trans->type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
+		return;
+	}
+
+	if (trans->bytesout == 1) {	/* and bytesin is > 0 */
+		trans->type = SPI_OPCODE_TYPE_READ_NO_ADDRESS;
+		return;
+	}
+
+	if (trans->bytesout == 4)	/* and bytesin is > 0 */
+		trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
+
+	/* Fast read command is called with 5 bytes instead of 4 */
+	if (trans->out[0] == SPI_OPCODE_FAST_READ && trans->bytesout == 5) {
+		trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
+		--trans->bytesout;
+	}
+}
+
+static int spi_setup_opcode(struct spi_trans *trans)
+{
+	uint16_t optypes;
+	uint8_t opmenu[ctlr.menubytes];
+
+	trans->opcode = trans->out[0];
+	spi_use_out(trans, 1);
+	if (!ctlr.ichspi_lock) {
+		/* The lock is off, so just use index 0. */
+		ich_writeb(trans->opcode, ctlr.opmenu);
+		optypes = ich_readw(ctlr.optype);
+		optypes = (optypes & 0xfffc) | (trans->type & 0x3);
+		ich_writew(optypes, ctlr.optype);
+		return 0;
+	} else {
+		/* The lock is on. See if what we need is on the menu. */
+		uint8_t optype;
+		uint16_t opcode_index;
+
+		/* Write Enable is handled as atomic prefix */
+		if (trans->opcode == SPI_OPCODE_WREN)
+			return 0;
+
+		read_reg(ctlr.opmenu, opmenu, sizeof(opmenu));
+		for (opcode_index = 0; opcode_index < ctlr.menubytes;
+				opcode_index++) {
+			if (opmenu[opcode_index] == trans->opcode)
+				break;
+		}
+
+		if (opcode_index == ctlr.menubytes) {
+			printf("ICH SPI: Opcode %x not found\n",
+				trans->opcode);
+			return -1;
+		}
+
+		optypes = ich_readw(ctlr.optype);
+		optype = (optypes >> (opcode_index * 2)) & 0x3;
+		if (trans->type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS &&
+				optype == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS &&
+				trans->bytesout >= 3) {
+			/* We guessed wrong earlier. Fix it up. */
+			trans->type = optype;
+		}
+		if (optype != trans->type) {
+			printf("ICH SPI: Transaction doesn't fit type %d\n",
+				optype);
+			return -1;
+		}
+		return opcode_index;
+	}
+}
+
+static int spi_setup_offset(struct spi_trans *trans)
+{
+	/* Separate the SPI address and data. */
+	switch (trans->type) {
+	case SPI_OPCODE_TYPE_READ_NO_ADDRESS:
+	case SPI_OPCODE_TYPE_WRITE_NO_ADDRESS:
+		return 0;
+	case SPI_OPCODE_TYPE_READ_WITH_ADDRESS:
+	case SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS:
+		trans->offset = ((uint32_t)trans->out[0] << 16) |
+				((uint32_t)trans->out[1] << 8) |
+				((uint32_t)trans->out[2] << 0);
+		spi_use_out(trans, 3);
+		return 1;
+	default:
+		printf("Unrecognized SPI transaction type %#x\n", trans->type);
+		return -1;
+	}
+}
+
+/*
+ * Wait for up to 6s til status register bit(s) turn 1 (in case wait_til_set
+ * below is True) or 0. In case the wait was for the bit(s) to set - write
+ * those bits back, which would cause resetting them.
+ *
+ * Return the last read status value on success or -1 on failure.
+ */
+static int ich_status_poll(u16 bitmask, int wait_til_set)
+{
+	int timeout = 600000; /* This will result in 6s */
+	u16 status = 0;
+
+	while (timeout--) {
+		status = ich_readw(ctlr.status);
+		if (wait_til_set ^ ((status & bitmask) == 0)) {
+			if (wait_til_set)
+				ich_writew((status & bitmask), ctlr.status);
+			return status;
+		}
+		udelay(10);
+	}
+
+	printf("ICH SPI: SCIP timeout, read %x, expected %x\n",
+		status, bitmask);
+	return -1;
+}
+
+/*
+int spi_xfer(struct spi_slave *slave, const void *dout,
+		unsigned int bitsout, void *din, unsigned int bitsin)
+*/
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+		void *din, unsigned long flags)
+{
+	struct ich_spi_slave *ich = to_ich_spi(slave);
+	uint16_t control;
+	int16_t opcode_index;
+	int with_address;
+	int status;
+	int bytes = bitlen / 8;
+	struct spi_trans *trans = &ich->trans;
+	unsigned type = flags & (SPI_XFER_BEGIN | SPI_XFER_END);
+	int using_cmd = 0;
+	/* Align read transactions to 64-byte boundaries */
+	char buff[ctlr.databytes];
+
+	/* Ee don't support writing partial bytes. */
+	if (bitlen % 8) {
+		debug("ICH SPI: Accessing partial bytes not supported\n");
+		return -1;
+	}
+
+	/* An empty end transaction can be ignored */
+	if (type == SPI_XFER_END && !dout && !din)
+		return 0;
+
+	if (type & SPI_XFER_BEGIN)
+		memset(trans, '\0', sizeof(*trans));
+
+	/* Dp we need to come back later to finish it? */
+	if (dout && type == SPI_XFER_BEGIN) {
+		if (bytes > ICH_MAX_CMD_LEN) {
+			debug("ICH SPI: Command length limit exceeded\n");
+			return -1;
+		}
+		memcpy(trans->cmd, dout, bytes);
+		trans->cmd_len = bytes;
+		debug("ICH SPI: Saved %d bytes\n", bytes);
+		return 0;
+	}
+
+	/*
+	 * We process a 'middle' spi_xfer() call, which has no
+	 * SPI_XFER_BEGIN/END, as an independent transaction as if it had
+	 * an end. We therefore repeat the command. This is because ICH
+	 * seems to have no support for this, or because interest (in digging
+	 * out the details and creating a special case in the code) is low.
+	 */
+	if (trans->cmd_len) {
+		trans->out = trans->cmd;
+		trans->bytesout = trans->cmd_len;
+		using_cmd = 1;
+		debug("ICH SPI: Using %d bytes\n", trans->cmd_len);
+	} else {
+		trans->out = dout;
+		trans->bytesout = dout ? bytes : 0;
+	}
+
+	trans->in = din;
+	trans->bytesin = din ? bytes : 0;
+
+	/* There has to always at least be an opcode. */
+	if (!trans->bytesout) {
+		debug("ICH SPI: No opcode for transfer\n");
+		return -1;
+	}
+
+	if (ich_status_poll(SPIS_SCIP, 0) == -1)
+		return -1;
+
+	ich_writew(SPIS_CDS | SPIS_FCERR, ctlr.status);
+
+	spi_setup_type(trans, using_cmd ? bytes : 0);
+	opcode_index = spi_setup_opcode(trans);
+	if (opcode_index < 0)
+		return -1;
+	with_address = spi_setup_offset(trans);
+	if (with_address < 0)
+		return -1;
+
+	if (trans->opcode == SPI_OPCODE_WREN) {
+		/*
+		 * Treat Write Enable as Atomic Pre-Op if possible
+		 * in order to prevent the Management Engine from
+		 * issuing a transaction between WREN and DATA.
+		 */
+		if (!ctlr.ichspi_lock)
+			ich_writew(trans->opcode, ctlr.preop);
+		return 0;
+	}
+
+	if (ctlr.speed) {
+		int byte;
+
+		byte = ich_readb(ctlr.speed);
+		if (ich->speed >= 33000000)
+			byte |= SSFC_SCF_33MHZ;
+		else
+			byte &= ~SSFC_SCF_33MHZ;
+		ich_writeb(byte, ctlr.speed);
+	}
+
+	/* See if we have used up the command data */
+	if (using_cmd && dout && bytes) {
+		trans->out = dout;
+		trans->bytesout = bytes;
+		debug("ICH SPI: Moving to data, %d bytes\n", bytes);
+	}
+
+	/* Preset control fields */
+	control = ich_readw(ctlr.control);
+	control &= ~SSFC_RESERVED;
+	control = SPIC_SCGO | ((opcode_index & 0x07) << 4);
+
+	/* Issue atomic preop cycle if needed */
+	if (ich_readw(ctlr.preop))
+		control |= SPIC_ACS;
+
+	if (!trans->bytesout && !trans->bytesin) {
+		/* SPI addresses are 24 bit only */
+		if (with_address)
+			ich_writel(trans->offset & 0x00FFFFFF, ctlr.addr);
+
+		/*
+		 * This is a 'no data' command (like Write Enable), its
+		 * bitesout size was 1, decremented to zero while executing
+		 * spi_setup_opcode() above. Tell the chip to send the
+		 * command.
+		 */
+		ich_writew(control, ctlr.control);
+
+		/* wait for the result */
+		status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1);
+		if (status == -1)
+			return -1;
+
+		if (status & SPIS_FCERR) {
+			debug("ICH SPI: Command transaction error\n");
+			return -1;
+		}
+
+		return 0;
+	}
+
+	/*
+	 * Check if this is a write command atempting to transfer more bytes
+	 * than the controller can handle. Iterations for writes are not
+	 * supported here because each SPI write command needs to be preceded
+	 * and followed by other SPI commands, and this sequence is controlled
+	 * by the SPI chip driver.
+	 */
+	if (trans->bytesout > ctlr.databytes) {
+		debug("ICH SPI: Too much to write. This should be prevented"
+		     " by the driver's max_write_size?\n");
+		return -1;
+	}
+
+	/*
+	 * Read or write up to databytes bytes at a time until everything has
+	 * been sent.
+	 */
+	while (trans->bytesout || trans->bytesin) {
+		uint32_t data_length;
+		uint32_t aligned_offset;
+		uint32_t diff;
+
+		aligned_offset = trans->offset & ~(ctlr.databytes - 1);
+		diff = trans->offset - aligned_offset;
+
+		/* SPI addresses are 24 bit only */
+		ich_writel(aligned_offset & 0x00FFFFFF, ctlr.addr);
+
+		if (trans->bytesout)
+			data_length = min(trans->bytesout, ctlr.databytes);
+		else
+			data_length = min(trans->bytesin, ctlr.databytes);
+
+		/* Program data into FDATA0 to N */
+		if (trans->bytesout) {
+			write_reg(trans->out, ctlr.data, data_length);
+			spi_use_out(trans, data_length);
+			if (with_address)
+				trans->offset += data_length;
+		}
+
+		/* Add proper control fields' values */
+		control &= ~((ctlr.databytes - 1) << 8);
+		control |= SPIC_DS;
+		control |= (data_length - 1) << 8;
+
+		/* write it */
+		ich_writew(control, ctlr.control);
+
+		/* Wait for Cycle Done Status or Flash Cycle Error. */
+		status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1);
+		if (status == -1)
+			return -1;
+
+		if (status & SPIS_FCERR) {
+			debug("ICH SPI: Data transaction error\n");
+			return -1;
+		}
+
+		if (trans->bytesin) {
+			if (diff) {
+				data_length -= diff;
+				read_reg(ctlr.data, buff, ctlr.databytes);
+				memcpy(trans->in, buff + diff, data_length);
+			} else {
+				read_reg(ctlr.data, trans->in, data_length);
+			}
+			spi_use_in(trans, data_length);
+			if (with_address)
+				trans->offset += data_length;
+		}
+	}
+
+	/* Clear atomic preop now that xfer is done */
+	ich_writew(0, ctlr.preop);
+
+	return 0;
+}
+
+
+/*
+ * This uses the SPI controller from the Intel Cougar Point and Panther Point
+ * PCH to write-protect portions of the SPI flash until reboot. The changes
+ * don't actually take effect until the HSFS[FLOCKDN] bit is set, but that's
+ * done elsewhere.
+ */
+int spi_write_protect_region(uint32_t lower_limit, uint32_t length, int hint)
+{
+	uint32_t tmplong;
+	uint32_t upper_limit;
+
+	if (!ctlr.pr) {
+		printf("%s: operation not supported on this chipset\n",
+		       __func__);
+		return -1;
+	}
+
+	if (length == 0 ||
+	    lower_limit > (0xFFFFFFFFUL - length) + 1 ||
+	    hint < 0 || hint > 4) {
+		printf("%s(0x%x, 0x%x, %d): invalid args\n", __func__,
+		     lower_limit, length, hint);
+		return -1;
+	}
+
+	upper_limit = lower_limit + length - 1;
+
+	/*
+	 * Determine bits to write, as follows:
+	 *  31     Write-protection enable (includes erase operation)
+	 *  30:29  reserved
+	 *  28:16  Upper Limit (FLA address bits 24:12, with 11:0 == 0xfff)
+	 *  15     Read-protection enable
+	 *  14:13  reserved
+	 *  12:0   Lower Limit (FLA address bits 24:12, with 11:0 == 0x000)
+	 */
+	tmplong = 0x80000000 |
+		((upper_limit & 0x01fff000) << 4) |
+		((lower_limit & 0x01fff000) >> 12);
+
+	printf("%s: writing 0x%08x to %p\n", __func__, tmplong,
+	       &ctlr.pr[hint]);
+	ctlr.pr[hint] = tmplong;
+
+	return 0;
+}
diff --git a/drivers/spi/ich.h b/drivers/spi/ich.h
new file mode 100644
index 0000000..f90d859
--- /dev/null
+++ b/drivers/spi/ich.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but without any warranty; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * This file is derived from the flashrom project.
+ */
+
+struct ich7_spi_regs {
+	uint16_t spis;
+	uint16_t spic;
+	uint32_t spia;
+	uint64_t spid[8];
+	uint64_t _pad;
+	uint32_t bbar;
+	uint16_t preop;
+	uint16_t optype;
+	uint8_t opmenu[8];
+} __packed;
+
+struct ich9_spi_regs {
+	uint32_t bfpr;			/* 0x00 */
+	uint16_t hsfs;
+	uint16_t hsfc;
+	uint32_t faddr;
+	uint32_t _reserved0;
+	uint32_t fdata[16];		/* 0x10 */
+	uint32_t frap;			/* 0x50 */
+	uint32_t freg[5];
+	uint32_t _reserved1[3];
+	uint32_t pr[5];			/* 0x74 */
+	uint32_t _reserved2[2];
+	uint8_t ssfs;			/* 0x90 */
+	uint8_t ssfc[3];
+	uint16_t preop;			/* 0x94 */
+	uint16_t optype;
+	uint8_t opmenu[8];		/* 0x98 */
+	uint32_t bbar;
+	uint8_t _reserved3[12];
+	uint32_t fdoc;
+	uint32_t fdod;
+	uint8_t _reserved4[8];
+	uint32_t afc;
+	uint32_t lvscc;
+	uint32_t uvscc;
+	uint8_t _reserved5[4];
+	uint32_t fpb;
+	uint8_t _reserved6[28];
+	uint32_t srdl;
+	uint32_t srdc;
+	uint32_t srd;
+} __packed;
+
+enum {
+	SPIS_SCIP =		0x0001,
+	SPIS_GRANT =		0x0002,
+	SPIS_CDS =		0x0004,
+	SPIS_FCERR =		0x0008,
+	SSFS_AEL =		0x0010,
+	SPIS_LOCK =		0x8000,
+	SPIS_RESERVED_MASK =	0x7ff0,
+	SSFS_RESERVED_MASK =	0x7fe2
+};
+
+enum {
+	SPIC_SCGO =		0x000002,
+	SPIC_ACS =		0x000004,
+	SPIC_SPOP =		0x000008,
+	SPIC_DBC =		0x003f00,
+	SPIC_DS =		0x004000,
+	SPIC_SME =		0x008000,
+	SSFC_SCF_MASK =		0x070000,
+	SSFC_RESERVED =		0xf80000,
+
+	/* Mask for speed byte, biuts 23:16 of SSFC */
+	SSFC_SCF_33MHZ	=	0x01,
+};
+
+enum {
+	HSFS_FDONE =		0x0001,
+	HSFS_FCERR =		0x0002,
+	HSFS_AEL =		0x0004,
+	HSFS_BERASE_MASK =	0x0018,
+	HSFS_BERASE_SHIFT =	3,
+	HSFS_SCIP =		0x0020,
+	HSFS_FDOPSS =		0x2000,
+	HSFS_FDV =		0x4000,
+	HSFS_FLOCKDN =		0x8000
+};
+
+enum {
+	HSFC_FGO =		0x0001,
+	HSFC_FCYCLE_MASK =	0x0006,
+	HSFC_FCYCLE_SHIFT =	1,
+	HSFC_FDBC_MASK =	0x3f00,
+	HSFC_FDBC_SHIFT =	8,
+	HSFC_FSMIE =		0x8000
+};
+
+enum {
+	SPI_OPCODE_TYPE_READ_NO_ADDRESS =	0,
+	SPI_OPCODE_TYPE_WRITE_NO_ADDRESS =	1,
+	SPI_OPCODE_TYPE_READ_WITH_ADDRESS =	2,
+	SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS =	3
+};
+
+enum {
+	ICH_MAX_CMD_LEN		= 5,
+};
+
+struct spi_trans {
+	uint8_t cmd[ICH_MAX_CMD_LEN];
+	int cmd_len;
+	const uint8_t *out;
+	uint32_t bytesout;
+	uint8_t *in;
+	uint32_t bytesin;
+	uint8_t type;
+	uint8_t opcode;
+	uint32_t offset;
+};
+
+struct ich_spi_slave {
+	struct spi_slave slave;
+	struct spi_trans trans;	/* current transaction in progress */
+	int speed;		/* SPI speed in Hz */
+};
+
-- 
1.7.7.3

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

* [U-Boot] [PATCH 08/15] spi: Add parameter for maximum write size
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
                   ` (6 preceding siblings ...)
  2012-12-26 22:28 ` [U-Boot] [PATCH 07/15] x86: spi: Add Intel ICH driver Simon Glass
@ 2012-12-26 22:28 ` Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 09/15] sf: Respect maximum SPI " Simon Glass
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

Some SPI controllers (e.g. Intel ICH) have a limit on the number of SPI
bytes that can be written at a time. Add this as a parameter so that
clients of the SPI interface can respect this value.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 include/spi.h |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/include/spi.h b/include/spi.h
index ebc9652..3fe2e1e 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -49,10 +49,13 @@
  *
  *   bus:	ID of the bus that the slave is attached to.
  *   cs:	ID of the chip select connected to the slave.
+ *   max_write_size:	If non-zero, the maximum number of bytes which can
+ *		be written at once, excluding command bytes.
  */
 struct spi_slave {
 	unsigned int	bus;
 	unsigned int	cs;
+	unsigned int max_write_size;
 };
 
 /*-----------------------------------------------------------------------
-- 
1.7.7.3

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

* [U-Boot] [PATCH 09/15] sf: Respect maximum SPI write size
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
                   ` (7 preceding siblings ...)
  2012-12-26 22:28 ` [U-Boot] [PATCH 08/15] spi: Add parameter for maximum write size Simon Glass
@ 2012-12-26 22:28 ` Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 10/15] x86: spi: Set maximum write size for ICH Simon Glass
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

Some SPI flash controllers (e.g. Intel ICH) have a limit on the number of
bytes that can be in a write transaction. Support this by breaking the
writes into multiple transactions.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 drivers/mtd/spi/spi_flash.c |   10 ++++++++--
 1 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 17f3d3c..b82011d 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -87,6 +87,9 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset,
 	for (actual = 0; actual < len; actual += chunk_len) {
 		chunk_len = min(len - actual, page_size - byte_addr);
 
+		if (flash->spi->max_write_size)
+			chunk_len = min(chunk_len, flash->spi->max_write_size);
+
 		cmd[1] = page_addr >> 8;
 		cmd[2] = page_addr;
 		cmd[3] = byte_addr;
@@ -111,8 +114,11 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset,
 		if (ret)
 			break;
 
-		page_addr++;
-		byte_addr = 0;
+		byte_addr += chunk_len;
+		if (byte_addr == page_size) {
+			page_addr++;
+			byte_addr = 0;
+		}
 	}
 
 	debug("SF: program %s %zu bytes @ %#x\n",
-- 
1.7.7.3

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

* [U-Boot] [PATCH 10/15] x86: spi: Set maximum write size for ICH
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
                   ` (8 preceding siblings ...)
  2012-12-26 22:28 ` [U-Boot] [PATCH 09/15] sf: Respect maximum SPI " Simon Glass
@ 2012-12-26 22:28 ` Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 11/15] sf: Enable FDT-based configuration and memory mapping Simon Glass
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

This SPI controller can only write 64 bytes at a time. Add this restriction
in so that 'sf write' works correct for blocks larger than 64 bytes.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 drivers/spi/ich.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c
index 31f9482..17defa4 100644
--- a/drivers/spi/ich.c
+++ b/drivers/spi/ich.c
@@ -166,6 +166,11 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 		return NULL;
 	}
 
+	/*
+	 * Yes this controller can only write a small number of bytes at
+	 * once! The limit is typically 64 bytes.
+	 */
+	ich->slave.max_write_size = ctlr.databytes;
 	ich->speed = max_hz;
 
 	return &ich->slave;
-- 
1.7.7.3

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

* [U-Boot] [PATCH 11/15] sf: Enable FDT-based configuration and memory mapping
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
                   ` (9 preceding siblings ...)
  2012-12-26 22:28 ` [U-Boot] [PATCH 10/15] x86: spi: Set maximum write size for ICH Simon Glass
@ 2012-12-26 22:28 ` Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 12/15] x86: Move PCI init before SPI init Simon Glass
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

Enable device tree control of SPI flash, and use this to implement
memory-mapped SPI flash, which is supported on Intel chips.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 drivers/mtd/spi/spi_flash.c |   46 ++++++++++++++++++++++++++++++++++++++++++-
 include/fdtdec.h            |    1 +
 include/spi_flash.h         |    1 +
 lib/fdtdec.c                |    1 +
 4 files changed, 48 insertions(+), 1 deletions(-)

diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index b82011d..111185a 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -8,6 +8,7 @@
  */
 
 #include <common.h>
+#include <fdtdec.h>
 #include <malloc.h>
 #include <spi.h>
 #include <spi_flash.h>
@@ -15,6 +16,8 @@
 
 #include "spi_flash_internal.h"
 
+DECLARE_GLOBAL_DATA_PTR;
+
 static void spi_flash_addr(u32 addr, u8 *cmd)
 {
 	/* cmd[0] is actual command */
@@ -146,6 +149,10 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
 {
 	u8 cmd[5];
 
+	/* Handle memory-mapped SPI */
+	if (flash->memory_map)
+		memcpy(data, flash->memory_map + offset, len);
+
 	cmd[0] = CMD_READ_ARRAY_FAST;
 	spi_flash_addr(offset, cmd);
 	cmd[4] = 0x00;
@@ -275,6 +282,34 @@ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr)
 	return 0;
 }
 
+#ifdef CONFIG_OF_CONTROL
+int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash)
+{
+	fdt_addr_t addr;
+	fdt_size_t size;
+	int node;
+
+	/* If there is no node, do nothing */
+	node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
+	if (node < 0)
+		return 0;
+
+	addr = fdtdec_get_addr_size(blob, node, "memory-map", &size);
+	if (addr == FDT_ADDR_T_NONE) {
+		debug("%s: Cannot decode address\n", __func__);
+		return 0;
+	}
+
+	if (flash->size != size) {
+		debug("%s: Memory map must cover entire device\n", __func__);
+		return -1;
+	}
+	flash->memory_map = (void *)addr;
+
+	return 0;
+}
+#endif /* CONFIG_OF_CONTROL */
+
 /*
  * The following table holds all device probe functions
  *
@@ -391,9 +426,18 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
 		goto err_manufacturer_probe;
 	}
 
+#ifdef CONFIG_OF_CONTROL
+	if (spi_flash_decode_fdt(gd->fdt_blob, flash)) {
+		debug("SF: FDT decode error\n");
+		goto err_manufacturer_probe;
+	}
+#endif
 	printf("SF: Detected %s with page size ", flash->name);
 	print_size(flash->sector_size, ", total ");
-	print_size(flash->size, "\n");
+	print_size(flash->size, "");
+	if (flash->memory_map)
+		printf(", mapped at %p", flash->memory_map);
+	puts("\n");
 
 	spi_release_bus(spi);
 
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 570d3ac..bfd1dda 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -72,6 +72,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_GENERIC_SPI_FLASH,	/* Generic SPI Flash chip */
 
 	COMPAT_COUNT,
 };
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 030d49c..3b6a44e 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -39,6 +39,7 @@ struct spi_flash {
 	/* Erase (sector) size */
 	u32		sector_size;
 
+	void *memory_map;	/* Address of read-only SPI flash access */
 	int		(*read)(struct spi_flash *flash, u32 offset,
 				size_t len, void *buf);
 	int		(*write)(struct spi_flash *flash, u32 offset,
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index d0bc848..55305b4 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(GENERIC_SPI_FLASH, "spi-flash"),
 };
 
 const char *fdtdec_get_compatible(enum fdt_compat_id id)
-- 
1.7.7.3

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

* [U-Boot] [PATCH 12/15] x86: Move PCI init before SPI init
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
                   ` (10 preceding siblings ...)
  2012-12-26 22:28 ` [U-Boot] [PATCH 11/15] sf: Enable FDT-based configuration and memory mapping Simon Glass
@ 2012-12-26 22:28 ` Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 13/15] x86: Add FDT SPI node for link Simon Glass
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

It is possible that our PCI bus will provide the SPI controller, so change
the init order to make this work.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 arch/x86/lib/board.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c
index 555301a..c2407e4 100644
--- a/arch/x86/lib/board.c
+++ b/arch/x86/lib/board.c
@@ -163,13 +163,13 @@ init_fnc_t *init_sequence_r[] = {
 #ifndef CONFIG_SYS_NO_FLASH
 	flash_init_r,
 #endif
-#ifdef CONFIG_SPI
-	init_func_spi;
-#endif
-	env_relocate_r,
 #ifdef CONFIG_PCI
 	pci_init_r,
 #endif
+#ifdef CONFIG_SPI
+	init_func_spi,
+#endif
+	env_relocate_r,
 	stdio_init,
 	jumptable_init_r,
 	console_init_r,
-- 
1.7.7.3

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

* [U-Boot] [PATCH 13/15] x86: Add FDT SPI node for link
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
                   ` (11 preceding siblings ...)
  2012-12-26 22:28 ` [U-Boot] [PATCH 12/15] x86: Move PCI init before SPI init Simon Glass
@ 2012-12-26 22:28 ` Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 14/15] x86: Enable SPI flash support for coreboot Simon Glass
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

Add a memory-mapped 8GB SPI chip.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 board/chromebook-x86/dts/link.dts |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/board/chromebook-x86/dts/link.dts b/board/chromebook-x86/dts/link.dts
index ae8217d..d0738cb 100644
--- a/board/chromebook-x86/dts/link.dts
+++ b/board/chromebook-x86/dts/link.dts
@@ -21,4 +21,15 @@
 
         chosen { };
         memory { device_type = "memory"; reg = <0 0>; };
+
+	spi {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "intel,ich9";
+		spi-flash at 0 {
+			reg = <0>;
+			compatible = "winbond,w25q64", "spi-flash";
+			memory-map = <0xff800000 0x00800000>;
+		};
+	};
 };
-- 
1.7.7.3

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

* [U-Boot] [PATCH 14/15] x86: Enable SPI flash support for coreboot
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
                   ` (12 preceding siblings ...)
  2012-12-26 22:28 ` [U-Boot] [PATCH 13/15] x86: Add FDT SPI node for link Simon Glass
@ 2012-12-26 22:28 ` Simon Glass
  2012-12-26 22:28 ` [U-Boot] [PATCH 15/15] x86: Enable time command " Simon Glass
  2013-03-08  4:30 ` [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
  15 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

Turn on SPI flash support and related commands.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 include/configs/coreboot.h |   12 +++++++++---
 1 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/include/configs/coreboot.h b/include/configs/coreboot.h
index fd383ff..ea92ffe 100644
--- a/include/configs/coreboot.h
+++ b/include/configs/coreboot.h
@@ -258,10 +258,16 @@
 /*-----------------------------------------------------------------------
  * FLASH configuration
  */
+#define CONFIG_ICH_SPI
+#define CONFIG_SPI_FLASH
+#define CONFIG_SPI_FLASH_MACRONIX
+#define CONFIG_SPI_FLASH_WINBOND
+#define CONFIG_SPI_FLASH_GIGADEVICE
 #define CONFIG_SYS_NO_FLASH
-#undef CONFIG_FLASH_CFI_DRIVER
-#define CONFIG_SYS_MAX_FLASH_SECT		1
-#define CONFIG_SYS_MAX_FLASH_BANKS		1
+#define CONFIG_CMD_SF
+#define CONFIG_CMD_SF_TEST
+#define CONFIG_CMD_SPI
+#define CONFIG_SPI
 
 /*-----------------------------------------------------------------------
  * Environment configuration
-- 
1.7.7.3

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

* [U-Boot] [PATCH 15/15] x86: Enable time command for coreboot
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
                   ` (13 preceding siblings ...)
  2012-12-26 22:28 ` [U-Boot] [PATCH 14/15] x86: Enable SPI flash support for coreboot Simon Glass
@ 2012-12-26 22:28 ` Simon Glass
  2013-03-08  4:30 ` [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
  15 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-26 22:28 UTC (permalink / raw)
  To: u-boot

This command is useful for measuring SPI flash load times and the like.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 include/configs/coreboot.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/include/configs/coreboot.h b/include/configs/coreboot.h
index ea92ffe..4b6eb73 100644
--- a/include/configs/coreboot.h
+++ b/include/configs/coreboot.h
@@ -180,6 +180,7 @@
 #define CONFIG_CMD_SAVEENV
 #define CONFIG_CMD_SETGETDCR
 #define CONFIG_CMD_SOURCE
+#define CONFIG_CMD_TIME
 #define CONFIG_CMD_XIMG
 #define CONFIG_CMD_SCSI
 
-- 
1.7.7.3

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

* [U-Boot] [PATCH 01/15] fdt: Use sed instead of cpp to pre-process the dtc
  2012-12-26 22:28 ` [U-Boot] [PATCH 01/15] fdt: Use sed instead of cpp to pre-process the dtc Simon Glass
@ 2012-12-28  0:03   ` Stephen Warren
  2012-12-28 14:55     ` Simon Glass
  0 siblings, 1 reply; 23+ messages in thread
From: Stephen Warren @ 2012-12-28  0:03 UTC (permalink / raw)
  To: u-boot

On 12/26/2012 03:28 PM, Simon Glass wrote:
> Include file support in dtc is still not available in common distributions
> so we need to keep our preprocessing arrangement around for a little
> longer.
> 
> But # is commonly used in FDT files, so use sed instead of cpp for this
> preprocessing.

This sounds like the wrong approach to me. I'd suggest using what I
proposed for the kernel:

> cmd_dtc_cpp = $(CPP) $(cpp_flags) -D__DTS__ -x assembler-with-cpp -o $(dtc-tmp) $< ; \
>         $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS) $(dtc-tmp)

The "-x assembler-with-cpp" is what solves the # problem IIRC.

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

* [U-Boot] [PATCH 01/15] fdt: Use sed instead of cpp to pre-process the dtc
  2012-12-28  0:03   ` Stephen Warren
@ 2012-12-28 14:55     ` Simon Glass
  2012-12-28 16:42       ` Mike Frysinger
  0 siblings, 1 reply; 23+ messages in thread
From: Simon Glass @ 2012-12-28 14:55 UTC (permalink / raw)
  To: u-boot

Hi Stephen,

On Thu, Dec 27, 2012 at 4:03 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 12/26/2012 03:28 PM, Simon Glass wrote:
>> Include file support in dtc is still not available in common distributions
>> so we need to keep our preprocessing arrangement around for a little
>> longer.
>>
>> But # is commonly used in FDT files, so use sed instead of cpp for this
>> preprocessing.
>
> This sounds like the wrong approach to me. I'd suggest using what I
> proposed for the kernel:
>
>> cmd_dtc_cpp = $(CPP) $(cpp_flags) -D__DTS__ -x assembler-with-cpp -o $(dtc-tmp) $< ; \
>>         $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS) $(dtc-tmp)
>
> The "-x assembler-with-cpp" is what solves the # problem IIRC.

I originally used CPP as an expedient means of converting the
ARCH_CPU_DTS symbol until we all have a dtc with include path support.

Are you saying that we want to actually use the CPP on tthe device
tree and (presumably) use U-Boot include files within the FDT?

Regards,
Simon

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

* [U-Boot] [PATCH 01/15] fdt: Use sed instead of cpp to pre-process the dtc
  2012-12-28 14:55     ` Simon Glass
@ 2012-12-28 16:42       ` Mike Frysinger
  2012-12-28 18:07         ` Simon Glass
  0 siblings, 1 reply; 23+ messages in thread
From: Mike Frysinger @ 2012-12-28 16:42 UTC (permalink / raw)
  To: u-boot

On Friday 28 December 2012 09:55:52 Simon Glass wrote:
> On Thu, Dec 27, 2012 at 4:03 PM, Stephen Warren wrote:
> > On 12/26/2012 03:28 PM, Simon Glass wrote:
> >> Include file support in dtc is still not available in common
> >> distributions so we need to keep our preprocessing arrangement around
> >> for a little longer.
> >> 
> >> But # is commonly used in FDT files, so use sed instead of cpp for this
> >> preprocessing.
> > 
> > This sounds like the wrong approach to me. I'd suggest using what I
> > 
> > proposed for the kernel:
> >> cmd_dtc_cpp = $(CPP) $(cpp_flags) -D__DTS__ -x assembler-with-cpp -o
> >> $(dtc-tmp) $< ; \
> >> 
> >>         $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS)
> >>         $(dtc-tmp)
> > 
> > The "-x assembler-with-cpp" is what solves the # problem IIRC.
> 
> I originally used CPP as an expedient means of converting the
> ARCH_CPU_DTS symbol until we all have a dtc with include path support.
> 
> Are you saying that we want to actually use the CPP on tthe device
> tree and (presumably) use U-Boot include files within the FDT?

sounds reasonable to me.  we already do it with linker scripts, and if the 
kernel is doing it, it means we can (possibly) share more.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20121228/25432cdf/attachment.pgp>

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

* [U-Boot] [PATCH 01/15] fdt: Use sed instead of cpp to pre-process the dtc
  2012-12-28 16:42       ` Mike Frysinger
@ 2012-12-28 18:07         ` Simon Glass
  2012-12-28 23:47           ` Stephen Warren
  0 siblings, 1 reply; 23+ messages in thread
From: Simon Glass @ 2012-12-28 18:07 UTC (permalink / raw)
  To: u-boot

Hi,

On Fri, Dec 28, 2012 at 8:42 AM, Mike Frysinger <vapier@gentoo.org> wrote:
> On Friday 28 December 2012 09:55:52 Simon Glass wrote:
>> On Thu, Dec 27, 2012 at 4:03 PM, Stephen Warren wrote:
>> > On 12/26/2012 03:28 PM, Simon Glass wrote:
>> >> Include file support in dtc is still not available in common
>> >> distributions so we need to keep our preprocessing arrangement around
>> >> for a little longer.
>> >>
>> >> But # is commonly used in FDT files, so use sed instead of cpp for this
>> >> preprocessing.
>> >
>> > This sounds like the wrong approach to me. I'd suggest using what I
>> >
>> > proposed for the kernel:
>> >> cmd_dtc_cpp = $(CPP) $(cpp_flags) -D__DTS__ -x assembler-with-cpp -o
>> >> $(dtc-tmp) $< ; \
>> >>
>> >>         $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS)
>> >>         $(dtc-tmp)
>> >
>> > The "-x assembler-with-cpp" is what solves the # problem IIRC.
>>
>> I originally used CPP as an expedient means of converting the
>> ARCH_CPU_DTS symbol until we all have a dtc with include path support.
>>
>> Are you saying that we want to actually use the CPP on tthe device
>> tree and (presumably) use U-Boot include files within the FDT?
>
> sounds reasonable to me.  we already do it with linker scripts, and if the
> kernel is doing it, it means we can (possibly) share more.

OK. Stephen, what is the kernel actually doing with the preprocessor?
Have you given up on the dtc symbol stuff for now and plan to use CPP
instead?

Regards,
Simon

> -mike

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

* [U-Boot] [PATCH 01/15] fdt: Use sed instead of cpp to pre-process the dtc
  2012-12-28 18:07         ` Simon Glass
@ 2012-12-28 23:47           ` Stephen Warren
  2012-12-29  0:34             ` Simon Glass
  0 siblings, 1 reply; 23+ messages in thread
From: Stephen Warren @ 2012-12-28 23:47 UTC (permalink / raw)
  To: u-boot

On 12/28/2012 11:07 AM, Simon Glass wrote:
> Hi,
> 
> On Fri, Dec 28, 2012 at 8:42 AM, Mike Frysinger <vapier@gentoo.org> wrote:
>> On Friday 28 December 2012 09:55:52 Simon Glass wrote:
>>> On Thu, Dec 27, 2012 at 4:03 PM, Stephen Warren wrote:
>>>> On 12/26/2012 03:28 PM, Simon Glass wrote:
>>>>> Include file support in dtc is still not available in common
>>>>> distributions so we need to keep our preprocessing arrangement around
>>>>> for a little longer.
>>>>>
>>>>> But # is commonly used in FDT files, so use sed instead of cpp for this
>>>>> preprocessing.
>>>>
>>>> This sounds like the wrong approach to me. I'd suggest using what I
>>>>
>>>> proposed for the kernel:
>>>>> cmd_dtc_cpp = $(CPP) $(cpp_flags) -D__DTS__ -x assembler-with-cpp -o
>>>>> $(dtc-tmp) $< ; \
>>>>>
>>>>>         $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS)
>>>>>         $(dtc-tmp)
>>>>
>>>> The "-x assembler-with-cpp" is what solves the # problem IIRC.
>>>
>>> I originally used CPP as an expedient means of converting the
>>> ARCH_CPU_DTS symbol until we all have a dtc with include path support.
>>>
>>> Are you saying that we want to actually use the CPP on tthe device
>>> tree and (presumably) use U-Boot include files within the FDT?

Yes, I'd explicitly like to be able to use C-style header files to
define named constants etc.

>> sounds reasonable to me.  we already do it with linker scripts, and if the
>> kernel is doing it, it means we can (possibly) share more.
> 
> OK. Stephen, what is the kernel actually doing with the preprocessor?
> Have you given up on the dtc symbol stuff for now and plan to use CPP
> instead?

Yes, I've given up on getting any kind of pre-processor or macro
language into dtc itself. I haven't managed to get the kernel to accept
the logic I quoted above either yet; this has all been a very long and
tortuous process. I hope to repost the patch that implements this in the
kernel within the next week or so.

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

* [U-Boot] [PATCH 01/15] fdt: Use sed instead of cpp to pre-process the dtc
  2012-12-28 23:47           ` Stephen Warren
@ 2012-12-29  0:34             ` Simon Glass
  0 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2012-12-29  0:34 UTC (permalink / raw)
  To: u-boot

Hi Stephen,

On Fri, Dec 28, 2012 at 3:47 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 12/28/2012 11:07 AM, Simon Glass wrote:
>> Hi,
>>
>> On Fri, Dec 28, 2012 at 8:42 AM, Mike Frysinger <vapier@gentoo.org> wrote:
>>> On Friday 28 December 2012 09:55:52 Simon Glass wrote:
>>>> On Thu, Dec 27, 2012 at 4:03 PM, Stephen Warren wrote:
>>>>> On 12/26/2012 03:28 PM, Simon Glass wrote:
>>>>>> Include file support in dtc is still not available in common
>>>>>> distributions so we need to keep our preprocessing arrangement around
>>>>>> for a little longer.
>>>>>>
>>>>>> But # is commonly used in FDT files, so use sed instead of cpp for this
>>>>>> preprocessing.
>>>>>
>>>>> This sounds like the wrong approach to me. I'd suggest using what I
>>>>>
>>>>> proposed for the kernel:
>>>>>> cmd_dtc_cpp = $(CPP) $(cpp_flags) -D__DTS__ -x assembler-with-cpp -o
>>>>>> $(dtc-tmp) $< ; \
>>>>>>
>>>>>>         $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS)
>>>>>>         $(dtc-tmp)
>>>>>
>>>>> The "-x assembler-with-cpp" is what solves the # problem IIRC.
>>>>
>>>> I originally used CPP as an expedient means of converting the
>>>> ARCH_CPU_DTS symbol until we all have a dtc with include path support.
>>>>
>>>> Are you saying that we want to actually use the CPP on tthe device
>>>> tree and (presumably) use U-Boot include files within the FDT?
>
> Yes, I'd explicitly like to be able to use C-style header files to
> define named constants etc.
>
>>> sounds reasonable to me.  we already do it with linker scripts, and if the
>>> kernel is doing it, it means we can (possibly) share more.
>>
>> OK. Stephen, what is the kernel actually doing with the preprocessor?
>> Have you given up on the dtc symbol stuff for now and plan to use CPP
>> instead?
>
> Yes, I've given up on getting any kind of pre-processor or macro
> language into dtc itself. I haven't managed to get the kernel to accept
> the logic I quoted above either yet; this has all been a very long and
> tortuous process. I hope to repost the patch that implements this in the
> kernel within the next week or so.

OK good luck with the cat-herding. I will update this patch along the
lines you describe above and resend. I hope we are not opening a can
of worms using the full power of the pre-processor, but clearly we are
not getting anywhere with dtc, so this is the only reasonable option.

Regards,
Simon

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

* [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller
  2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
                   ` (14 preceding siblings ...)
  2012-12-26 22:28 ` [U-Boot] [PATCH 15/15] x86: Enable time command " Simon Glass
@ 2013-03-08  4:30 ` Simon Glass
  15 siblings, 0 replies; 23+ messages in thread
From: Simon Glass @ 2013-03-08  4:30 UTC (permalink / raw)
  To: u-boot

Hi,

On Wed, Dec 26, 2012 at 2:28 PM, Simon Glass <sjg@chromium.org> wrote:
> Adding new fields to struct spi_slave and struct spi_flash is painful,
> because most drivers don't zero the fields they don't use. Anyway it
> seems better to have the SPI/SPI flash infrastructure provide a simple
> way of doing this that all drivers can use.
>
> So the first part of this series adds spi_alloc_slave(), for SPI, and
> spi_flash_alloc() for SPI flash.
>
> Support is added for the Intel ICH SPI controller, possibly the oddest
> SPI controller in U-Boot. It is designed for use with SPI flash only,
> and has a number of high-level features which are dedicated to flash.
> As such it is a bit of a challenge to get it to behave just like a
> normal U-Boot SPI device.
>
> The ICH driver has two interesting features. Firstly it is impossible
> to read or write more than 64 bytes at a time! For SPI reading it is
> possible to hide this within the SPI driver. For SPI writing it
> unfortunately isn't, since the spi_flash layer has to send an unlock
> command and a new address for every write. It would be an egregious
> hack to try to fake this in the driver. So a new property is added
> to spi_flash to allow the maximum transfer size to be set.
>
> Secondly, the ICH SPI flash can be memory mapped. On a lot of x86
> devices this improves performance significantly. For example, the standard
> driver gets maybe 12Mbps throughput from a 33Mbps dual interface, roughly
> 20% utilisation. With memory mapping, many platforms can achieve about
> 40Mbps. To implement memory mapping, a new property is provided in the
> device tree to set the memory map address, which varies by platform. Some
> x86 platforms will see a speed increase with memory mapping, some won't.
> The memory mapping feature only works for reading. When in use, the
> spi_flash layer bypasses the SPI driver completely, and just copies the
> flash data from the correct place in the memory map.

This series includes some generic changes to the SPI and SPI flash layers.

It also includes an x86 SPI driver for Intel.

Are there any comments, particularlly on the addition of
spi_alloc_aloc() and spi_flsah_alloc()? This affects all SPI flash
drivers.

The first patch needs to be dropped since it seems we are sticking with cpp.

>
>
> Simon Glass (15):
>   fdt: Use sed instead of cpp to pre-process the dtc
>   fdt: Add fdtdec_get_addr_size() to read reg properties
>   spi: Add function to allocate a new SPI slave
>   spi: Use spi_alloc_slave() in each SPI driver
>   sf: Add spi_flash_alloc() to create a new SPI flash struct
>   sf: Use spi_flash_alloc() in each SPI flash driver
>   x86: spi: Add Intel ICH driver
>   spi: Add parameter for maximum write size
>   sf: Respect maximum SPI write size
>   x86: spi: Set maximum write size for ICH
>   sf: Enable FDT-based configuration and memory mapping
>   x86: Move PCI init before SPI init
>   x86: Add FDT SPI node for link
>   x86: Enable SPI flash support for coreboot
>   x86: Enable time command for coreboot
>
>  arch/x86/lib/board.c              |    8 +-
>  board/chromebook-x86/dts/link.dts |   11 +
>  drivers/mtd/spi/atmel.c           |    8 +-
>  drivers/mtd/spi/eon.c             |    8 +-
>  drivers/mtd/spi/macronix.c        |    8 +-
>  drivers/mtd/spi/ramtron.c         |    4 +-
>  drivers/mtd/spi/spansion.c        |    8 +-
>  drivers/mtd/spi/spi_flash.c       |   81 ++++-
>  drivers/mtd/spi/sst.c             |    8 +-
>  drivers/mtd/spi/stmicro.c         |    8 +-
>  drivers/mtd/spi/winbond.c         |    8 +-
>  drivers/spi/Makefile              |    4 +
>  drivers/spi/altera_spi.c          |    4 +-
>  drivers/spi/andes_spi.c           |    4 +-
>  drivers/spi/armada100_spi.c       |    4 +-
>  drivers/spi/atmel_spi.c           |    4 +-
>  drivers/spi/bfin_spi.c            |    4 +-
>  drivers/spi/cf_qspi.c             |    4 +-
>  drivers/spi/cf_spi.c              |    4 +-
>  drivers/spi/davinci_spi.c         |    4 +-
>  drivers/spi/fsl_espi.c            |    4 +-
>  drivers/spi/ich.c                 |  752 +++++++++++++++++++++++++++++++++++++
>  drivers/spi/ich.h                 |  144 +++++++
>  drivers/spi/kirkwood_spi.c        |    5 +-
>  drivers/spi/mpc52xx_spi.c         |    5 +-
>  drivers/spi/mpc8xxx_spi.c         |    5 +-
>  drivers/spi/mxc_spi.c             |    4 +-
>  drivers/spi/mxs_spi.c             |    4 +-
>  drivers/spi/oc_tiny_spi.c         |    5 +-
>  drivers/spi/omap3_spi.c           |   27 +-
>  drivers/spi/sh_spi.c              |    4 +-
>  drivers/spi/soft_spi.c            |    4 +-
>  drivers/spi/spi.c                 |   39 ++
>  drivers/spi/tegra_spi.c           |    4 +-
>  drivers/spi/xilinx_spi.c          |    4 +-
>  dts/Makefile                      |   10 +-
>  include/configs/coreboot.h        |   13 +-
>  include/fdtdec.h                  |   16 +
>  include/spi.h                     |   44 +++
>  include/spi_flash.h               |   39 ++
>  lib/fdtdec.c                      |   27 ++-
>  41 files changed, 1208 insertions(+), 147 deletions(-)
>  create mode 100644 drivers/spi/ich.c
>  create mode 100644 drivers/spi/ich.h
>  create mode 100644 drivers/spi/spi.c
>
> --
> 1.7.7.3
>

Regards,
Simon

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

end of thread, other threads:[~2013-03-08  4:30 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-12-26 22:28 [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass
2012-12-26 22:28 ` [U-Boot] [PATCH 01/15] fdt: Use sed instead of cpp to pre-process the dtc Simon Glass
2012-12-28  0:03   ` Stephen Warren
2012-12-28 14:55     ` Simon Glass
2012-12-28 16:42       ` Mike Frysinger
2012-12-28 18:07         ` Simon Glass
2012-12-28 23:47           ` Stephen Warren
2012-12-29  0:34             ` Simon Glass
2012-12-26 22:28 ` [U-Boot] [PATCH 02/15] fdt: Add fdtdec_get_addr_size() to read reg properties Simon Glass
2012-12-26 22:28 ` [U-Boot] [PATCH 03/15] spi: Add function to allocate a new SPI slave Simon Glass
2012-12-26 22:28 ` [U-Boot] [PATCH 04/15] spi: Use spi_alloc_slave() in each SPI driver Simon Glass
2012-12-26 22:28 ` [U-Boot] [PATCH 05/15] sf: Add spi_flash_alloc() to create a new SPI flash struct Simon Glass
2012-12-26 22:28 ` [U-Boot] [PATCH 06/15] sf: Use spi_flash_alloc() in each SPI flash driver Simon Glass
2012-12-26 22:28 ` [U-Boot] [PATCH 07/15] x86: spi: Add Intel ICH driver Simon Glass
2012-12-26 22:28 ` [U-Boot] [PATCH 08/15] spi: Add parameter for maximum write size Simon Glass
2012-12-26 22:28 ` [U-Boot] [PATCH 09/15] sf: Respect maximum SPI " Simon Glass
2012-12-26 22:28 ` [U-Boot] [PATCH 10/15] x86: spi: Set maximum write size for ICH Simon Glass
2012-12-26 22:28 ` [U-Boot] [PATCH 11/15] sf: Enable FDT-based configuration and memory mapping Simon Glass
2012-12-26 22:28 ` [U-Boot] [PATCH 12/15] x86: Move PCI init before SPI init Simon Glass
2012-12-26 22:28 ` [U-Boot] [PATCH 13/15] x86: Add FDT SPI node for link Simon Glass
2012-12-26 22:28 ` [U-Boot] [PATCH 14/15] x86: Enable SPI flash support for coreboot Simon Glass
2012-12-26 22:28 ` [U-Boot] [PATCH 15/15] x86: Enable time command " Simon Glass
2013-03-08  4:30 ` [U-Boot] [PATCH 0/15] Enhance SPI/SPI flash probing, add support for Intel ICH controller Simon Glass

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox