Merge branch 'u-boot/master' into 'u-boot-arm/master'
authorAlbert ARIBAUD <albert.u.boot@aribaud.net>
Thu, 28 Mar 2013 17:50:01 +0000 (18:50 +0100)
committerAlbert ARIBAUD <albert.u.boot@aribaud.net>
Thu, 28 Mar 2013 17:50:01 +0000 (18:50 +0100)
Conflicts:
drivers/spi/tegra20_sflash.c
include/fdtdec.h
lib/fdtdec.c

55 files changed:
.checkpatch.conf
MAINTAINERS
MAKEALL
arch/x86/lib/board.c
board/chromebook-x86/dts/link.dts
common/cmd_bootm.c
common/cmd_ext4.c
common/cmd_sf.c
common/env_callback.c
common/image.c
drivers/mtd/spi/atmel.c
drivers/mtd/spi/eon.c
drivers/mtd/spi/macronix.c
drivers/mtd/spi/ramtron.c
drivers/mtd/spi/spansion.c
drivers/mtd/spi/spi_flash.c
drivers/mtd/spi/sst.c
drivers/mtd/spi/stmicro.c
drivers/mtd/spi/winbond.c
drivers/spi/Makefile
drivers/spi/altera_spi.c
drivers/spi/andes_spi.c
drivers/spi/armada100_spi.c
drivers/spi/atmel_spi.c
drivers/spi/bfin_spi.c
drivers/spi/bfin_spi6xx.c
drivers/spi/cf_qspi.c
drivers/spi/cf_spi.c
drivers/spi/davinci_spi.c
drivers/spi/exynos_spi.c
drivers/spi/fsl_espi.c
drivers/spi/ich.c [new file with mode: 0644]
drivers/spi/ich.h [new file with mode: 0644]
drivers/spi/kirkwood_spi.c
drivers/spi/mpc52xx_spi.c
drivers/spi/mpc8xxx_spi.c
drivers/spi/mxc_spi.c
drivers/spi/mxs_spi.c
drivers/spi/oc_tiny_spi.c
drivers/spi/omap3_spi.c
drivers/spi/sh_spi.c
drivers/spi/soft_spi.c
drivers/spi/spi.c [new file with mode: 0644]
drivers/spi/tegra20_sflash.c
drivers/spi/tegra20_slink.c
drivers/spi/xilinx_spi.c
include/config_defaults.h
include/configs/coreboot.h
include/env_callback.h
include/fdtdec.h
include/image.h
include/spi.h
include/spi_flash.h
lib/fdtdec.c
tools/checkpatch.pl

index 38386b354dadd99596a4b3efcb9d97d24508412c..d88af57129a82cf1b8cf772e9ca02d7c7a20efbb 100644 (file)
@@ -15,3 +15,6 @@
 
 # enable more tests
 --strict
+
+# Not Linux, so we don't recommend usleep_range() over udelay()
+--ignore USLEEP_RANGE
index 646997327e24f6f0d3a8f7554415718d1cb5ebaa..1614b913bdfe709925e853445139bc08b1f123be 100644 (file)
@@ -688,6 +688,10 @@ Stefan Herbrechtsmeier <stefan@code.herbrechtsmeier.net>
 
        dns325          ARM926EJS (Kirkwood SoC)
 
+Lauri Hintsala <lauri.hintsala@bluegiga.com>
+
+       apx4devkit      i.MX28
+
 Vaibhav Hiremath <hvaibhav@ti.com>
 
        am3517_evm      ARM ARMV7 (AM35x SoC)
@@ -806,10 +810,6 @@ Linus Walleij <linus.walleij@linaro.org>
        integratorap    various
        integratorcp    various
 
-Veli-Pekka Peltola <veli-pekka.peltola@bluegiga.com>
-
-       apx4devkit      i.MX28
-
 Luka Perkov <luka@openwrt.org>
 
        ib62x0          ARM926EJS
diff --git a/MAKEALL b/MAKEALL
index c1d895725643f41ae7a0cbaffbe693033bc9f472..91fa495ea7f43ce2b7edb6ca6ca5b8d0d8ebd643 100755 (executable)
--- a/MAKEALL
+++ b/MAKEALL
@@ -104,9 +104,9 @@ while true ; do
        -s|--soc)
                # echo "Option SoC: argument \`$2'"
                if [ "$opt_s" ] ; then
-                       opt_s="${opt_s%)} || \$6 == \"$2\")"
+                       opt_s="${opt_s%)} || \$6 == \"$2\" || \$6 ~ /$2/)"
                else
-                       opt_s="(\$6 == \"$2\")"
+                       opt_s="(\$6 == \"$2\" || \$6 ~ /$2/)"
                fi
                SELECTED='y'
                shift 2 ;;
index 452e5d8262b3e803b2950f07ecf8df45dae4d954..f372898f61276ea0dced65499d613797c9283f27 100644 (file)
@@ -164,13 +164,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,
index ae8217d02e538a6ebb1d1d79882d8fb6045078f3..d0738cbf46cd9f2f1d5ce5fbdc492817305a50de 100644 (file)
 
         chosen { };
         memory { device_type = "memory"; reg = <0 0>; };
+
+       spi {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "intel,ich9";
+               spi-flash@0 {
+                       reg = <0>;
+                       compatible = "winbond,w25q64", "spi-flash";
+                       memory-map = <0xff800000 0x00800000>;
+               };
+       };
 };
index 5d2ce0015ac3f30f1efa4901d9dfef20425ddec7..7438469d091721a6dcba15ec2263ef7b086dc743 100644 (file)
@@ -128,6 +128,9 @@ static boot_os_fn do_bootm_rtems;
 #if defined(CONFIG_BOOTM_OSE)
 static boot_os_fn do_bootm_ose;
 #endif
+#if defined(CONFIG_BOOTM_PLAN9)
+static boot_os_fn do_bootm_plan9;
+#endif
 #if defined(CONFIG_CMD_ELF)
 static boot_os_fn do_bootm_vxworks;
 static boot_os_fn do_bootm_qnxelf;
@@ -154,6 +157,9 @@ static boot_os_fn *boot_os[] = {
 #if defined(CONFIG_BOOTM_OSE)
        [IH_OS_OSE] = do_bootm_ose,
 #endif
+#if defined(CONFIG_BOOTM_PLAN9)
+       [IH_OS_PLAN9] = do_bootm_plan9,
+#endif
 #if defined(CONFIG_CMD_ELF)
        [IH_OS_VXWORKS] = do_bootm_vxworks,
        [IH_OS_QNX] = do_bootm_qnxelf,
@@ -1628,6 +1634,39 @@ static int do_bootm_ose(int flag, int argc, char * const argv[],
 }
 #endif /* CONFIG_BOOTM_OSE */
 
+#if defined(CONFIG_BOOTM_PLAN9)
+static int do_bootm_plan9(int flag, int argc, char * const argv[],
+                          bootm_headers_t *images)
+{
+       void (*entry_point)(void);
+
+       if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+               return 1;
+
+#if defined(CONFIG_FIT)
+       if (!images->legacy_hdr_valid) {
+               fit_unsupported_reset("Plan 9");
+               return 1;
+       }
+#endif
+
+       entry_point = (void (*)(void))images->ep;
+
+       printf("## Transferring control to Plan 9 (at address %08lx) ...\n",
+               (ulong)entry_point);
+
+       bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+       /*
+        * Plan 9 Parameters:
+        *   None
+        */
+       (*entry_point)();
+
+       return 1;
+}
+#endif /* CONFIG_BOOTM_PLAN9 */
+
 #if defined(CONFIG_CMD_ELF)
 static int do_bootm_vxworks(int flag, int argc, char * const argv[],
                             bootm_headers_t *images)
index dcf76a50cde54d103419b0533146dd3f8f96592f..706fd54a553b9fc394a18c3f4add6027838967c0 100644 (file)
@@ -88,10 +88,10 @@ int do_ext4_write(cmd_tbl_t *cmdtp, int flag, int argc,
        dev = dev_desc->dev;
 
        /* get the filename */
-       filename = argv[3];
+       filename = argv[4];
 
        /* get the address in hexadecimal format (string to int) */
-       ram_address = simple_strtoul(argv[4], NULL, 16);
+       ram_address = simple_strtoul(argv[3], NULL, 16);
 
        /* get the filesize in base 10 format */
        file_size = simple_strtoul(argv[5], NULL, 10);
@@ -122,7 +122,7 @@ fail:
 
 U_BOOT_CMD(ext4write, 6, 1, do_ext4_write,
        "create a file in the root directory",
-       "<interface> <dev[:part]> [Absolute filename path] [Address] [sizebytes]\n"
+       "<interface> <dev[:part]> <addr> <absolute filename path> [sizebytes]\n"
        "    - create a file in / directory");
 
 #endif
index b1753587d3c92f1273e66acab040bad9efca5761..3f0d414954c3e317507b899ec61391d07b38a77b 100644 (file)
@@ -369,8 +369,8 @@ static void spi_test_next_stage(struct test_info *test)
  * @param vbuf         Verification buffer
  * @return 0 if ok, -1 on error
  */
-static int spi_flash_test(struct spi_flash *flash, char *buf, ulong len,
-                          ulong offset, char *vbuf)
+static int spi_flash_test(struct spi_flash *flash, uint8_t *buf, ulong len,
+                          ulong offset, uint8_t *vbuf)
 {
        struct test_info test;
        int i;
@@ -431,9 +431,9 @@ static int do_spi_flash_test(int argc, char * const argv[])
 {
        unsigned long offset;
        unsigned long len;
-       char *buf = (char *)CONFIG_SYS_TEXT_BASE;
+       uint8_t *buf = (uint8_t *)CONFIG_SYS_TEXT_BASE;
        char *endp;
-       char *vbuf;
+       uint8_t *vbuf;
        int ret;
 
        offset = simple_strtoul(argv[1], &endp, 16);
index 78ca3674f09a85d5834bae0e2bb4d3a1427b07d3..78aafb4f2c224ad6fa4665424f36bd158b7d67bb 100644 (file)
@@ -31,7 +31,7 @@ DECLARE_GLOBAL_DATA_PTR;
 /*
  * Look up a callback function pointer by name
  */
-struct env_clbk_tbl *find_env_callback(const char *name)
+static struct env_clbk_tbl *find_env_callback(const char *name)
 {
        struct env_clbk_tbl *clbkp;
        int i;
index 6afbb40a9871078abe99d48deba8a2b54b16dbc5..60c21270398e649c7bb77a8bd04445769e22d127 100644 (file)
@@ -108,6 +108,7 @@ static const table_entry_t uimage_os[] = {
 #endif
        {       IH_OS_NETBSD,   "netbsd",       "NetBSD",               },
        {       IH_OS_OSE,      "ose",          "Enea OSE",             },
+       {       IH_OS_PLAN9,    "plan9",        "Plan 9",               },
        {       IH_OS_RTEMS,    "rtems",        "RTEMS",                },
        {       IH_OS_U_BOOT,   "u-boot",       "U-Boot",               },
 #if defined(CONFIG_CMD_ELF) || defined(USE_HOSTCC)
index 006f6d5d04fcb2258b3014fa41a32bdbadd8fb56..6a92c4b774b41ff85dbb834ccc206e12b8a7017d 100644 (file)
@@ -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 */
index 691ed4efc4f61096da88314dc202f9c6b9a3f82f..b16e7ab098ea36b7d1146ad7028fe3ec910e2e85 100644 (file)
@@ -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
index c97a39d49981201aa66178716b1cd457b55b7edc..036c30d3beee54488de1b20b4cedd8b93b2a7d75 100644 (file)
@@ -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;
index 099978149696968452e2851530687f6b358d2c4f..5299a6dbde09882e1e76ca232442d68dba698237 100644 (file)
@@ -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;
index 9288672c84cfbfb1ba8b076a03b2c58e54d63ffe..bc558c4c96ba317bffac1a66730bc28c2f49be32 100644 (file)
@@ -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;
index 00aece9291c398f44ec4db007d7048ac8727b5a3..111185af17586900b7ff447ead1e0ea9d131ecc4 100644 (file)
@@ -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 */
@@ -87,6 +90,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 +117,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",
@@ -140,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;
@@ -269,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
  *
@@ -385,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);
 
@@ -401,6 +451,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);
index ced4f2473f47189c45169638df6b20cb5a500485..95f5490c350ac0f85287b518f1b2427286c30ee3 100644 (file)
@@ -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;
index 8a193449d0cda34b983feed97b4fa4b481321569..2a9972bd4ee519f97c67c7df3e6c0c4ac49fa49d 100644 (file)
@@ -176,18 +176,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;
index 3560fcb6ba9a0e776af208caa8fb79920105768a..27162091c5ac69e4cfe8af4fc7d4f4944391c0a5 100644 (file)
@@ -97,18 +97,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;
index 46e8fa3bef7e5153f360f66415517084f6999320..d08609effe1ace437a87c06a9dd66744d7a3a642 100644 (file)
@@ -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
@@ -36,6 +39,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
index 138d6f4b45c523e239d57c62638110ae6fa08e11..b53607a4ec0264b654d93d52cee9e2fea48dad50 100644 (file)
@@ -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);
index fdde13954b18a0aac466f5e9852637fa65e4c033..c56377b63501ecf6e7a75f84b0c3c2db47082fc1 100644 (file)
@@ -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;
 
        /*
index 7384c9cd2c14671231e80f41ba889ec3b3736cdd..afdbe0508ca1c0db7cc88237e45288c626f8e304 100644 (file)
@@ -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;
index ce7d46085543330cf1721b7585557e5a797af2fe..f4b1bad22e85f787212194ff265908139946254e 100644 (file)
@@ -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) || defined(CONFIG_AT91SAM9M10G45)
index e080bec7052e523fd7c72dccfda5d5ec97ebb9bb..ab2e8b998bbf0ff1e089abf6e4f5aa740fa39593 100644 (file)
@@ -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;
index fde3447426770eb78f549d3d5484e1c2f04fbd92..c25c4a9aeab5550d34b9b544a22b9d64bfc185ad 100644 (file)
@@ -178,12 +178,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
                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->regs = (struct bfin_spi_regs *)reg_base;
        bss->control = SPI_CTL_EN | SPI_CTL_MSTR;
        if (mode & SPI_CPHA)
index 72dd1a520db822ca7a936e111fe4e84311d75dd1..a37ac4e5264b04db3dd3a558f82c428f1de88b6a 100644 (file)
@@ -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;
index a883da93688a1bc056b569ab859bdb6dae263dfa..afe791737c81ec5e35e5437240acbb09e4979dfc 100644 (file)
@@ -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 */
index 13aca52c7e2add329fb2c4334f9d3bb4d1752684..74792af0359b90bc25e602d69eda0aedcc52f258 100644 (file)
@@ -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;
 
index be60ada2ba43a17ecda4a8b968b08b791f0af73f..51b3d30538aefccda2860ec92f49beb45b3e864d 100644 (file)
@@ -89,15 +89,13 @@ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
                return NULL;
        }
 
-       spi_slave = malloc(sizeof(*spi_slave));
+       spi_slave = spi_alloc_slave(struct exynos_spi_slave, busnum, cs);
        if (!spi_slave) {
                debug("%s: Could not allocate spi_slave\n", __func__);
                return NULL;
        }
 
        bus = &spi_bus[busnum];
-       spi_slave->slave.bus = busnum;
-       spi_slave->slave.cs = cs;
        spi_slave->regs = bus->regs;
        spi_slave->mode = mode;
        spi_slave->periph_id = bus->periph_id;
index eb99e90becc9e27eb140e5b6f2ab9841ec63377b..28609eefebfde2ffe2b00a1fcbee08a9c28a63cc 100644 (file)
@@ -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/ich.c b/drivers/spi/ich.c
new file mode 100644 (file)
index 0000000..8865df5
--- /dev/null
@@ -0,0 +1,754 @@
+/*
+ * 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 */
+       ulong max_speed;        /* Maximum bus speed in MHz */
+};
+
+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)
+{
+       memcpy_toio(dest, value, size);
+}
+
+static void read_reg(const void *src, void *value, uint32_t size)
+{
+       memcpy_fromio(value, src, 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;
+       }
+
+       /*
+        * 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;
+}
+
+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;
+}
+
+/* @return 1 if the SPI flash supports the 33MHz speed */
+static int ich9_can_do_33mhz(pci_dev_t dev)
+{
+       u32 fdod, speed;
+
+       /* Observe SPI Descriptor Component Section 0 */
+       pci_write_config_dword(dev, 0xb0, 0x1000);
+
+       /* Extract the Write/Erase SPI Frequency from descriptor */
+       pci_read_config_dword(dev, 0xb4, &fdod);
+
+       /* Bits 23:21 have the fast read clock frequency, 0=20MHz, 1=33MHz */
+       speed = (fdod >> 21) & 7;
+
+       return speed == 1;
+}
+
+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);
+
+       /* Work out the maximum speed we can support */
+       ctlr->max_speed = 20000000;
+       if (ctlr->ich_version == 9 && ich9_can_do_33mhz(ctlr->dev))
+               ctlr->max_speed = 33000000;
+
+       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 && ctlr.max_speed >= 33000000) {
+               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 (file)
index 0000000..bd7bc12
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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 */
+};
index de81064b9defbff63f15b2975f5271d976e2a1ee..caa91e3e81718c8c4626fbb819a121f14e28e3e8 100644 (file)
@@ -49,13 +49,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 */
index 3e96b3f9f3b88fa997667a931650d76d8bdf9667..4b50bca880a8bdc9420d4163b0913bfe9f1a019d 100644 (file)
@@ -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;
 }
 
index 4e46041dfff5df76c98561d161daa4a13790acd5..6b0e3b46ec8fead7db89daf64e67422dc9fe50bd 100644 (file)
@@ -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.
index 859c43fee2790de7c80335bb58a71b20934c49f9..d792d8d493c13c475ec8ca03694f4efd8fde0e7f 100644 (file)
@@ -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);
index ffa3c1d693bbab56381bd8789aafc6b53ff392f3..aa999f9a945583a740e75af2e831b56d7406dab4 100644 (file)
@@ -77,15 +77,13 @@ 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;
 
        if (mxs_dma_init_channel(MXS_DMA_CHANNEL_AHB_APBH_SSP0 + bus))
                goto err_init;
 
-       mxs_slave->slave.bus = bus;
-       mxs_slave->slave.cs = cs;
        mxs_slave->max_khz = max_hz / 1000;
        mxs_slave->mode = mode;
        mxs_slave->regs = mxs_ssp_regs_by_bus(bus);
index fc01fb83a21b64b9e06d2d77d5954e97414590a2..6f7b1edd602c7a145375b32a42158b861b691628 100644 (file)
@@ -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;
index 344d5b8a7e2dc5d9006793e00d40343dec18be44..80a4e4776c83d17314b54060e758d980d91975b8 100644 (file)
@@ -80,12 +80,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)
@@ -98,21 +93,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:
@@ -120,7 +115,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)) ||
@@ -130,19 +124,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;
index e944b23c2df355936e724d4013bb217f185ad13a..744afe3295aebeca01ad9e1921ce387c0c823dbb 100644 (file)
@@ -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 */
index 13df8cb7de167aece971549f0cddf5696cbb8c17..a1b84b6e37b921d39a68aac0d55bc28a60fde41c 100644 (file)
@@ -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/spi.c b/drivers/spi/spi.c
new file mode 100644 (file)
index 0000000..cb36c5e
--- /dev/null
@@ -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;
+}
index a4e6c9aa3f24485a91d07066b663a5f0969a3a13..9322ce7f64102b61100039feb071716f243ab65e 100644 (file)
@@ -127,7 +127,7 @@ struct spi_slave *tegra20_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;
index 2ef2eb8495e2d1a3a1264db49ec604db11fc74c6..664de6e916613f4571fadb9fbd46497a32131fce 100644 (file)
@@ -135,13 +135,11 @@ struct spi_slave *tegra30_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->ctrl = &spi_ctrls[bus];
        if (!spi->ctrl) {
                printf("SPI error: could not find controller for bus %d\n",
index db01cc25f71ae37a9ba54c10c87b019becfa885e..a82b056948a4cecd716a776f6d7eae1e63b89423 100644 (file)
@@ -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;
index d023c632d98288a777f119df0c84620be498f0dc..567b46c87a5a6fc7bf8451255eb9383da1de3016 100644 (file)
@@ -12,6 +12,7 @@
 /* Support bootm-ing different OSes */
 #define CONFIG_BOOTM_LINUX 1
 #define CONFIG_BOOTM_NETBSD 1
+#define CONFIG_BOOTM_PLAN9 1
 #define CONFIG_BOOTM_RTEMS 1
 
 #define CONFIG_GZIP 1
index 87daf62681c5967543b33259b39a47279e7b4ab6..a4aa8f74535e4d3f1d769e8b2c4e51759c2a840a 100644 (file)
 #define CONFIG_CMD_SAVEENV
 #define CONFIG_CMD_SETGETDCR
 #define CONFIG_CMD_SOURCE
+#define CONFIG_CMD_TIME
+#define CONFIG_CMD_GETTIME
 #define CONFIG_CMD_XIMG
 #define CONFIG_CMD_SCSI
 
 /*-----------------------------------------------------------------------
  * 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
index e89b6dadc9421f9bf9dc8435795f99d588283a1f..b8560006540041e43d36928f470e08f341dc0846 100644 (file)
@@ -67,7 +67,6 @@ struct env_clbk_tbl {
                int flags);
 };
 
-struct env_clbk_tbl *find_env_callback(const char *);
 void env_callback_init(ENTRY *var_entry);
 
 /*
index cb520a69187269d978f25c702a90345f952f430c..e7e3ff9e0384f10157a671ff36ee153654ae34bf 100644 (file)
  */
 #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)
@@ -86,6 +88,7 @@ enum fdt_compat_id {
        COMPAT_SAMSUNG_EXYNOS_USB_PHY,  /* Exynos phy controller for usb2.0 */
        COMPAT_SAMSUNG_EXYNOS_TMU,      /* Exynos TMU */
        COMPAT_MAXIM_MAX77686_PMIC,     /* MAX77686 PMIC */
+       COMPAT_GENERIC_SPI_FLASH,       /* Generic SPI Flash chip */
        COMPAT_MAXIM_98095_CODEC,       /* MAX98095 Codec */
 
        COMPAT_COUNT,
@@ -202,6 +205,19 @@ int fdtdec_next_compatible_subnode(const void *blob, int node,
 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
index 8e285f9b9ff963877bc954871473d6cdd70a3fd8..4ad0e6b21ac1e26839c0bfa8da54549386e6067c 100644 (file)
@@ -84,6 +84,7 @@
 #define IH_OS_UNITY            20      /* Unity OS     */
 #define IH_OS_INTEGRITY                21      /* INTEGRITY    */
 #define IH_OS_OSE              22      /* OSE          */
+#define IH_OS_PLAN9            23      /* Plan 9       */
 
 /*
  * CPU Architecture Codes (supported by Linux)
index 60e85db9a46e052c97b638c58bb93114a378e3b7..3fe2e1eab2defc568079cd8a035225bbf682b18d 100644 (file)
  *
  *   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;
 };
 
 /*-----------------------------------------------------------------------
@@ -62,6 +65,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.
  *
index 9da90624f23d665fc58c95e37da02096b1adde07..3b6a44edcef6a1e8707ecd20572f191c9f05da46 100644 (file)
@@ -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,
@@ -47,6 +48,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);
index d2166e66323cba31796387d1bd37c8198ecc05e0..e17dd001ca2a0c6b578c88ce76c90251e89ea0d3 100644 (file)
@@ -61,6 +61,7 @@ static const char * const compat_names[COMPAT_COUNT] = {
        COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
        COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),
        COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),
+       COMPAT(GENERIC_SPI_FLASH, "spi-flash"),
        COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"),
 };
 
@@ -71,25 +72,40 @@ 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) ||
-                       len == sizeof(fdt_addr_t) * 2)) {
+       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);
+               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)
 {
index 051ba0de376a42f39fdb931c95955ed7e70fcfc8..9f23901872c9b7aa85d5d993016ba7094b016401 100755 (executable)
@@ -272,6 +272,7 @@ our $logFunctions = qr{(?x:
        [a-z0-9]+_(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)|
        WARN(?:_RATELIMIT|_ONCE|)|
        panic|
+       debug|
        MODULE_[A-Z_]+
 )};