Enhance SPI/SPI flash probing, add support for Intel ICH controller
Subsystems (9)
cover Enhance SPI/SPI flash probing, add support for Intel ICH controller
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
Signature · 1 line
1.7.7.3
PATCH 1/15 fdt: Use sed instead of cpp to pre-process the dtc
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.
--- dts/Makefile | 10 ++++------ 1 files changed, 4 insertions(+), 6 deletions(-)
dts/Makefile +4 -6
@@ -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' ; \
Signature · 1 line
1.7.7.3
PATCH 1/15 fdt: Use sed instead of cpp to pre-process the dtc
Quoted 6 lines · Simon Glass
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:
Quoted 2 lines
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.
PATCH 1/15 fdt: Use sed instead of cpp to pre-process the dtc
Hi Stephen,
Quoted 8 lines · Stephen Warren
Quoted 6 lines · Simon Glass
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.
Quoted 7 lines
This sounds like the wrong approach to me. I'd suggest using what I proposed for the kernel:
Quoted 2 lines
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
PATCH 1/15 fdt: Use sed instead of cpp to pre-process the dtc
Quoted 18 lines · On Friday 28 December 2012 09:55:52 Simon Glass wrote:
Quoted 17 lines · Stephen Warren
Quoted 6 lines · Simon Glass
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:
Quoted 5 lines
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)
Quoted 7 lines
Quoted 1 line
The "-x assembler-with-cpp" is what solves the # problem IIRC.
I originally used CPP as an expedient means of converting the
ARCH_CPU_DTSsymbol 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>
PATCH 1/15 fdt: Use sed instead of cpp to pre-process the dtc
Hi,
Quoted 21 lines · Mike Frysinger
Quoted 20 lines · On Friday 28 December 2012 09:55:52 Simon Glass wrote:
Quoted 18 lines · Stephen Warren
Quoted 6 lines · Simon Glass
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:
Quoted 5 lines
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.
Quoted 8 lines
Quoted 5 lines
I originally used CPP as an expedient means of converting the
ARCH_CPU_DTSsymbol 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
Quoted 1 line
-mike
PATCH 1/15 fdt: Use sed instead of cpp to pre-process the dtc
Quoted 29 lines · Simon Glass
Hi,
Quoted 26 lines · Mike Frysinger
Quoted 25 lines · On Friday 28 December 2012 09:55:52 Simon Glass wrote:
Quoted 10 lines · Stephen Warren
Quoted 6 lines · Simon Glass
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
Quoted 8 lines
proposed for the kernel:
Quoted 5 lines
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_DTSsymbol 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.
Quoted 6 lines
Quoted 2 lines
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.
PATCH 1/15 fdt: Use sed instead of cpp to pre-process the dtc
Hi Stephen,
Quoted 41 lines · Stephen Warren
Quoted 29 lines · Simon Glass
Hi,
Quoted 26 lines · Mike Frysinger
Quoted 25 lines · On Friday 28 December 2012 09:55:52 Simon Glass wrote:
Quoted 10 lines · Stephen Warren
Quoted 6 lines · Simon Glass
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
Quoted 8 lines
proposed for the kernel:
Quoted 5 lines
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_DTSsymbol 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.
Quoted 6 lines
Quoted 2 lines
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?
Quoted 5 lines
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
PATCH 2/15 fdt: Add fdtdec_get_addr_size() to read reg properties
In reply to Simon GlassIt 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();
--- include/fdtdec.h | 15 +++++++++++++++ lib/fdtdec.c | 26 +++++++++++++++++++++----- 2 files changed, 36 insertions(+), 5 deletions(-)
include/fdtdec.h +15 -0
@@ -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.
lib/fdtdec.c +21 -5
@@ -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) {
Signature · 1 line
1.7.7.3
PATCH 3/15 spi: Add function to allocate a new SPI slave
In reply to Simon GlassAt 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.
--- 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
drivers/spi/Makefile +3 -0
@@ -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
drivers/spi/spi.c new file +39 -0
@@ -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; +}
include/spi.h +41 -0
47 lines not on this page · raw message
Signature · 1 line
1.7.7.3
PATCH 4/15 spi: Use spi_alloc_slave() in each SPI driver
In reply to Simon GlassRather 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.
--- 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(-)
drivers/spi/altera_spi.c +1 -3
@@ -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);
drivers/spi/andes_spi.c +1 -3
@@ -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 ;/*
drivers/spi/armada100_spi.c +1 -3
@@ -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 ;
drivers/spi/atmel_spi.c +1 -3
@@ -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 )
drivers/spi/bfin_spi.c +1 -3
@@ -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 ;
drivers/spi/cf_qspi.c +1 -3
@@ -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 ;
drivers/spi/cf_spi.c +1 -3
@@ -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 */
drivers/spi/davinci_spi.c +1 -3
@@ -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;
drivers/spi/fsl_espi.c +1 -3
@@ -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 ;
drivers/spi/kirkwood_spi.c +1 -4
@@ -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 */
drivers/spi/mpc52xx_spi.c +1 -4
@@ -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; }
drivers/spi/mpc8xxx_spi.c +1 -4
@@ -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.
drivers/spi/mxc_spi.c +1 -3
@@ -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);
drivers/spi/mxs_spi.c +1 -3
@@ -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;
drivers/spi/oc_tiny_spi.c +1 -4
@@ -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 ;
drivers/spi/omap3_spi.c +14 -13
@@ -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;
drivers/spi/sh_spi.c +1 -3
@@ -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 */
drivers/spi/soft_spi.c +1 -3
@@ -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 */
drivers/spi/tegra_spi.c +1 -3
@@ -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;
drivers/spi/xilinx_spi.c +1 -3
@@ -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;
Signature · 1 line
1.7.7.3
PATCH 5/15 sf: Add spi_flash_alloc() to create a new SPI flash struct
In reply to Simon GlassAt 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.
--- drivers/mtd/spi/spi_flash.c | 25 +++++++++++++++++++++++++ include/spi_flash.h | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 0 deletions(-)
drivers/mtd/spi/spi_flash.c +25 -0
@@ -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);
include/spi_flash.h +38 -0
@@ -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);
Signature · 1 line
1.7.7.3
PATCH 6/15 sf: Use spi_flash_alloc() in each SPI flash driver
In reply to Simon GlassRather 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.
--- 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(-)
drivers/mtd/spi/atmel.c +1 -7
@@ -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 */
drivers/mtd/spi/eon.c +1 -7
@@ -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
drivers/mtd/spi/macronix.c +1 -7
@@ -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;
drivers/mtd/spi/ramtron.c +1 -3
@@ -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;
drivers/mtd/spi/spansion.c +1 -7
@@ -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;
drivers/mtd/spi/sst.c +1 -7
@@ -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;
drivers/mtd/spi/stmicro.c +1 -7
@@ -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;
drivers/mtd/spi/winbond.c +1 -7
@@ -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;
Signature · 1 line
1.7.7.3
PATCH 7/15 x86: spi: Add Intel ICH driver
In reply to Simon GlassThis 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.
--- 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
drivers/spi/Makefile +1 -0
@@ -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
drivers/spi/ich.c new file +747 -0
747 lines not on this page · raw message
drivers/spi/ich.h new file +144 -0
144 lines not on this page · raw message
Signature · 1 line
1.7.7.3
PATCH 8/15 spi: Add parameter for maximum write size
In reply to Simon GlassSome 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.
--- include/spi.h | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
include/spi.h +3 -0
@@ -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; };/*-----------------------------------------------------------------------
Signature · 1 line
1.7.7.3
PATCH 9/15 sf: Respect maximum SPI write size
In reply to Simon GlassSome 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.
--- drivers/mtd/spi/spi_flash.c | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-)
drivers/mtd/spi/spi_flash.c +8 -2
@@ -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",
Signature · 1 line
1.7.7.3
PATCH 10/15 x86: spi: Set maximum write size for ICH
In reply to Simon GlassThis 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.
--- drivers/spi/ich.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)
drivers/spi/ich.c +5 -0
@@ -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;
Signature · 1 line
1.7.7.3
PATCH 11/15 sf: Enable FDT-based configuration and memory mapping
In reply to Simon GlassEnable device tree control of SPI flash, and use this to implement memory-mapped SPI flash, which is supported on Intel chips.
--- 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(-)
drivers/mtd/spi/spi_flash.c +45 -1
@@ -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);
include/fdtdec.h +1 -0
@@ -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, };
include/spi_flash.h +1 -0
@@ -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,
lib/fdtdec.c +1 -0
@@ -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)
Signature · 1 line
1.7.7.3
PATCH 12/15 x86: Move PCI init before SPI init
In reply to Simon GlassIt is possible that our PCI bus will provide the SPI controller, so change the init order to make this work.
--- arch/x86/lib/board.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)
arch/x86/lib/board.c +4 -4
@@ -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,
Signature · 1 line
1.7.7.3
PATCH 13/15 x86: Add FDT SPI node for link
In reply to Simon GlassAdd a memory-mapped 8GB SPI chip.
--- board/chromebook-x86/dts/link.dts | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-)
board/chromebook-x86/dts/link.dts +11 -0
@@ -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>; + }; + }; };
Signature · 1 line
1.7.7.3
PATCH 14/15 x86: Enable SPI flash support for coreboot
In reply to Simon GlassTurn on SPI flash support and related commands.
--- include/configs/coreboot.h | 12 +++++++++--- 1 files changed, 9 insertions(+), 3 deletions(-)
include/configs/coreboot.h +9 -3
@@ -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
Signature · 1 line
1.7.7.3
PATCH 15/15 x86: Enable time command for coreboot
In reply to Simon GlassThis command is useful for measuring SPI flash load times and the like.
--- include/configs/coreboot.h | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
include/configs/coreboot.h +1 -0
@@ -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
Signature · 1 line
1.7.7.3
cover Enhance SPI/SPI flash probing, add support for Intel ICH controller
In reply to Simon GlassHi,
Quoted 22 lines · Simon Glass
Adding new fields to struct
spi_slaveand structspi_flashis 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, andspi_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_flashlayer 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 tospi_flashto allow the maximum transfer size to be set.
Quoted 10 lines
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_flashlayer 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.
Quoted 65 lines
Simon Glass (15):
fdt: Use sed instead of cpp to pre-process the dtc
fdt: Addfdtdec_get_addr_size()to read reg properties
spi: Add function to allocate a new SPI slave
spi: Usespi_alloc_slave()in each SPI driver
sf: Addspi_flash_alloc()to create a new SPI flash struct
sf: Usespi_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 corebootarch/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
Quoted 3 lines
--
1.7.7.3
Regards,
Simon