Index: include/urjtag/bus_driver.h
===================================================================
--- include/urjtag/bus_driver.h	(revision 1966)
+++ include/urjtag/bus_driver.h	(working copy)
@@ -81,6 +81,9 @@
     URJ_BUS_PARAM_KEY_DBGaDDR,  /* bool                         mpc824 */
     URJ_BUS_PARAM_KEY_DBGdATA,  /* bool                         mpc824 */
     URJ_BUS_PARAM_KEY_HWAIT,    /* string (= signal name)       blackfin */
+    URJ_BUS_PARAM_KEY_SCK,      /* string (= signal name)       spi */
+    URJ_BUS_PARAM_KEY_MOSI,     /* string (= signal name)       spi */
+    URJ_BUS_PARAM_KEY_MISO,     /* string (= signal name)       spi */
 }
 urj_bus_param_key_t;
 
Index: src/bus/spi.c
===================================================================
--- src/bus/spi.c	(revision 0)
+++ src/bus/spi.c	(revision 0)
@@ -0,0 +1,468 @@
+/*
+ * $Id: spi.c 1729 2010-01-24 11:31:51Z jgstroud $
+ *
+ * Copyright (C) 2002, 2003 ETC s.r.o.
+ *
+ * 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.
+ *
+ * Written by Jon Stroud <jstroud@breakingpoint.com>, 2010.
+ */
+
+#include "sysdep.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "part.h"
+#include "bus.h"
+#include "chain.h"
+#include "bssignal.h"
+#include "jtag.h"
+#include "buses.h"
+#include "generic_bus.h"
+
+typedef struct {
+    urj_part_signal_t *cs;
+    urj_part_signal_t *sck;
+    urj_part_signal_t *mosi;
+    urj_part_signal_t *miso;
+    int csa;
+    int ashift;
+    int dshift;
+} bus_params_t;
+
+#define CS      ((bus_params_t *) bus->params)->cs
+#define SCK     ((bus_params_t *) bus->params)->sck
+#define MOSI    ((bus_params_t *) bus->params)->mosi
+#define MISO    ((bus_params_t *) bus->params)->miso
+
+#define CSA     ((bus_params_t *) bus->params)->csa
+#define ASHIFT  ((bus_params_t *) bus->params)->ashift
+#define DSHIFT  ((bus_params_t *) bus->params)->dshift
+
+
+static urj_bus_t *
+spi_bus_new (urj_chain_t *chain, const urj_bus_driver_t *driver,
+                   const urj_param_t *cmd_params[])
+{
+    urj_bus_t *bus;
+    urj_part_signal_t *sig;
+    int i;
+    int failed = 0;
+    const char *value;
+
+    bus = urj_bus_generic_new (chain, driver, sizeof (bus_params_t));
+    if (bus == NULL)
+        return NULL;
+
+    CS = SCK = MOSI = MISO = NULL;
+    ASHIFT = 1;
+    DSHIFT = 0;
+    for (i = 0; cmd_params[i] != NULL; i++)
+    {
+        if (cmd_params[i]->key == URJ_BUS_PARAM_KEY_AMODE)
+        {
+            switch (cmd_params[i]->value.lu)
+            {
+            case 8:
+                ASHIFT = 0;
+                break;
+            case 16:
+                ASHIFT = 1;
+                break;
+            case 32:
+                ASHIFT = 3;
+                break;
+            case 0:
+                ASHIFT = 1;
+                break;
+
+            default:
+                urj_error_set (URJ_ERROR_INVALID,
+                        _("value %lu not defined for parameter %s"),
+                        cmd_params[i]->value.lu,
+                        urj_param_string(&urj_bus_param_list,
+                        cmd_params[i]));
+                failed = 1;     // @@@@ RFHH
+                break;
+            }
+
+        }
+        else if (cmd_params[i]->key == URJ_BUS_PARAM_KEY_WIDTH)
+        {
+            switch (cmd_params[i]->value.lu)
+            {
+            case 8:
+                DSHIFT = 0;
+                break;
+            case 16:
+                DSHIFT = 1;
+                break;
+            case 32:
+                DSHIFT = 3;
+                break;
+            case 0: 
+                DSHIFT = 0;
+                break;
+
+            default:
+                urj_error_set (URJ_ERROR_INVALID,
+                        _("value %lu not defined for parameter %s"),
+                        cmd_params[i]->value.lu,
+                        urj_param_string(&urj_bus_param_list,
+                        cmd_params[i]));
+                failed = 1;     // @@@@ RFHH
+                break;
+            }
+        }
+        else
+        {
+            if (cmd_params[i]->type != URJ_PARAM_TYPE_STRING)
+            {
+                urj_error_set (URJ_ERROR_SYNTAX,
+                               "parameter must be of type string");
+                failed = 1;
+                continue;
+            }
+
+            value = cmd_params[i]->value.string;
+
+            sig = urj_part_find_signal (bus->part, value);
+            if (!sig)
+            {
+                urj_error_set (URJ_ERROR_NOTFOUND, _("signal '%s' not found"),
+                               value);
+                failed = 1;
+                continue;
+            }
+
+            switch (cmd_params[i]->key)
+            {
+            case URJ_BUS_PARAM_KEY_SCK:
+                SCK = sig;
+                break;
+            case URJ_BUS_PARAM_KEY_CS:
+            case URJ_BUS_PARAM_KEY_NCS:
+                CS = sig;
+                CSA = (cmd_params[i]->key == URJ_BUS_PARAM_KEY_CS);
+                break;
+            case URJ_BUS_PARAM_KEY_MOSI:
+                MOSI = sig;
+                break;
+            case URJ_BUS_PARAM_KEY_MISO:
+                MISO = sig;
+                break;
+            default:
+                urj_error_set (URJ_ERROR_INVALID, _("parameter %s is unknown"),
+                               urj_param_string(&urj_bus_param_list,
+                               cmd_params[i]));
+                failed = 1;
+                break;
+            }
+        }
+    }
+
+    if (!CS) 
+    {
+        CS = urj_part_find_signal (bus->part, "CSN");
+        if (!CS) 
+        {
+            urj_error_set (URJ_ERROR_INVALID, _("signal '%s' not found\n"), "NCS");
+            failed = 1;
+        }
+    }
+    if (!SCK) 
+    {
+        SCK = urj_part_find_signal (bus->part, "SCK");
+        if (!SCK) 
+        {
+            urj_error_set (URJ_ERROR_INVALID, _("signal '%s' not found\n"), "SCK");
+            failed = 1;
+        }
+    }
+    if (!MOSI) 
+    {
+        MOSI = urj_part_find_signal (bus->part, "MOSI");
+        if (!MOSI) 
+        {
+            urj_error_set (URJ_ERROR_INVALID, _("signal '%s' not found\n"), "MOSI");
+            failed = 1;
+        }
+    }
+    if (!MISO) 
+    {
+        MISO = urj_part_find_signal (bus->part, "MISO");
+        if (!MISO) 
+        {
+            urj_error_set (URJ_ERROR_INVALID, _("signal '%s' not found\n"), "MISO");
+            failed = 1;
+        }
+    }
+    if (failed)
+    {
+        urj_bus_generic_free (bus);
+        return NULL;
+    }
+
+    return bus;
+}
+
+
+/**
+ * bus->driver->(*printinfo)
+ *
+ */
+static void
+spi_bus_printinfo (urj_log_level_t ll, urj_bus_t *bus)
+{
+    int i;
+
+    for (i = 0; i < bus->chain->parts->len; i++)
+        if (bus->part == bus->chain->parts->parts[i])
+            break;
+    urj_log (ll, _("SPI Flash bus driver via BSR (JTAG part No. %d)\n"), i);
+}
+
+/**
+ * bus->driver->(*area)
+ *
+ */
+static int
+spi_bus_area (urj_bus_t *bus, uint32_t adr, urj_bus_area_t *area)
+{
+    uint64_t asize = (uint64_t)((ASHIFT + 1) * 8);
+    asize = (uint64_t)1 << asize;
+    if (adr < asize) 
+    {
+        area->description = "SPI_FLASH";
+        area->start = UINT32_C (0x00000000);
+        area->length = (uint64_t)asize;
+        area->width = (DSHIFT + 1) * 8;
+    } 
+    else 
+    {
+        area->description = "NONE";
+        area->start = asize;
+        area->length = (uint64_t)(0x100000000 - asize);
+        area->width = 0;
+    }
+    return URJ_STATUS_OK;
+}
+
+static void
+spi_write_byte (urj_bus_t *bus, uint8_t data)
+{
+    urj_part_t *p = bus->part;
+    urj_chain_t *chain = bus->chain;
+    int32_t i;
+    for (i = 7; i >= 0; i--) 
+    {
+        urj_part_set_signal (p, MOSI, 1, (data & (1 << i) ? 1 : 0));
+        urj_part_set_signal (p, SCK, 1, 0);
+        urj_tap_chain_shift_data_registers (chain, 0);
+        urj_part_set_signal (p, SCK, 1, 1);
+        urj_tap_chain_shift_data_registers (chain, 0);
+    }
+}
+
+static uint8_t
+spi_read_byte (urj_bus_t *bus)
+{
+    urj_part_t *p = bus->part;
+    urj_chain_t *chain = bus->chain;
+    uint8_t data = 0;
+
+    int8_t i;
+    for (i = 7; i >= 0; i--) 
+    {
+        urj_part_set_signal (p, MOSI, 1, 0);
+        urj_part_set_signal (p, SCK, 1, 0);
+        urj_tap_chain_shift_data_registers (chain, 0);
+        urj_part_set_signal (p, SCK, 1, 1);
+        urj_tap_chain_shift_data_registers (chain, 1);
+        data <<= 1;
+        data |= (uint32_t)urj_part_get_signal (p, MISO);
+    }
+    return data;
+}
+
+/**
+ * bus->driver->(*write_start)
+ *
+ */
+static int
+spi_bus_write_start (urj_bus_t *bus, uint32_t adr)
+{
+    int i;
+    urj_part_t *p = bus->part;
+    urj_chain_t *chain = bus->chain;
+
+    urj_part_set_signal (p, CS, 1, CSA);
+    urj_part_set_signal (p, MOSI, 1, 0);
+    urj_part_set_signal (p, SCK, 1, 0);
+    urj_part_set_signal (p, MISO, 0, 0);
+    urj_tap_chain_shift_data_registers (chain, 0);
+
+    spi_write_byte (bus, 0x02); //write command
+    for (i = ASHIFT; i >= 0; i--) {
+        spi_write_byte(bus, (uint8_t)(adr >> (i * 8)));
+    }
+
+    return URJ_STATUS_OK;
+}
+
+/**
+ * bus->driver->(*read_start)
+ *
+ */
+static int
+spi_bus_read_start (urj_bus_t *bus, uint32_t adr)
+{
+    int i;
+    urj_part_t *p = bus->part;
+    urj_chain_t *chain = bus->chain;
+
+    urj_part_set_signal (p, CS, 1, CSA);
+    urj_part_set_signal (p, MOSI, 1, 0);
+    urj_part_set_signal (p, SCK, 1, 0);
+    urj_part_set_signal (p, MISO, 0, 0);
+    urj_tap_chain_shift_data_registers (chain, 0);
+
+    spi_write_byte (bus, 0x03); //read command
+    for (i = ASHIFT; i >= 0; i--) 
+    {
+        spi_write_byte (bus, (uint8_t)(adr >> (i * 8)));
+    }
+
+    return URJ_STATUS_OK;
+}
+
+/**
+ * bus->driver->(*read_next)
+ *
+ */
+static uint32_t
+spi_bus_read_next (urj_bus_t *bus, uint32_t adr)
+{
+    uint32_t data = 0;
+    uint8_t temp;
+    int i;
+
+    for (i = 0; i <= DSHIFT; i++) 
+    {
+        temp = spi_read_byte (bus);
+        data |= (temp << (i * 8));
+    }
+    return data;
+
+}
+
+/**
+ * bus->driver->(*read_end)
+ *
+ */
+static uint32_t
+spi_bus_read_end (urj_bus_t *bus)
+{
+    urj_part_t *p = bus->part;
+    urj_chain_t *chain = bus->chain;
+
+    uint32_t d = 0;
+    d = spi_bus_read_next (bus, 0);
+    urj_part_set_signal (p, CS, 1, !CSA);
+    urj_tap_chain_shift_data_registers (chain, 0);
+    return d;
+}
+
+/**
+ * bus->driver->(*write)
+ *
+ */
+static void
+spi_bus_write (urj_bus_t *bus, uint32_t adr, uint32_t data)
+{
+    int i;
+    for (i = 0; i <= DSHIFT; i++) 
+    {
+        spi_write_byte (bus, data);
+        data >>= 8;
+    }
+}
+
+/**
+ * bus->driver->(*enable)
+ *
+ */
+static int
+spi_bus_enable (urj_bus_t *bus)
+{
+    urj_part_t *p = bus->part;
+
+    urj_part_set_signal (p, CS, 1, CSA);
+    bus->enabled = 1;
+    return URJ_STATUS_OK;
+}
+
+/**
+ * bus->driver->(*disable)
+ *
+ */
+static int
+spi_bus_disable (urj_bus_t *bus)
+{
+    urj_part_t *p = bus->part;
+    urj_chain_t *chain = bus->chain;
+
+    urj_part_set_signal (p, CS, 1, !CSA);
+    urj_tap_chain_shift_data_registers (chain, 0);
+    bus->enabled = 0;
+    return URJ_STATUS_OK;
+}
+
+/**
+ * bus->driver->(*free)
+ *
+ */
+static void
+spi_bus_free (urj_bus_t *bus)
+{
+    urj_part_set_instruction (bus->part, "BYPASS");
+    urj_tap_chain_shift_instructions (bus->chain);
+
+    urj_bus_generic_free (bus);
+}
+
+const urj_bus_driver_t urj_bus_spi_bus = {
+    "spi",
+    N_("SPI FLASH driver via BSR, requires parameters:\n"
+       "           NCS=<CS#>|CS=<CS> SCK=<SCK> MISO=<MISO> MOSI=<MOSI> [AMODE=8|16|32] [WIDTH=8|16|32]"),
+    spi_bus_new,
+    spi_bus_free,
+    spi_bus_printinfo,
+    urj_bus_generic_prepare_extest,
+    spi_bus_area,
+    spi_bus_read_start,
+    spi_bus_read_next,
+    spi_bus_read_end,
+    urj_bus_generic_read,
+    spi_bus_write_start,
+    spi_bus_write,
+    urj_bus_generic_no_init,
+    spi_bus_enable,
+    spi_bus_disable,
+    URJ_BUS_TYPE_SPI,
+};
Index: src/bus/buses.c
===================================================================
--- src/bus/buses.c	(revision 1966)
+++ src/bus/buses.c	(working copy)
@@ -247,6 +247,9 @@
     { URJ_BUS_PARAM_KEY_DBGaDDR,    URJ_PARAM_TYPE_BOOL,    "DBGaDDR", },
     { URJ_BUS_PARAM_KEY_DBGdATA,    URJ_PARAM_TYPE_BOOL,    "DBGdATA", },
     { URJ_BUS_PARAM_KEY_HWAIT,      URJ_PARAM_TYPE_STRING,  "HWAIT", },
+    { URJ_BUS_PARAM_KEY_SCK,        URJ_PARAM_TYPE_STRING,  "SCK", },
+    { URJ_BUS_PARAM_KEY_MOSI,       URJ_PARAM_TYPE_STRING,  "MOSI", },
+    { URJ_BUS_PARAM_KEY_MISO,       URJ_PARAM_TYPE_STRING,  "MISO", },
 };
 
 const urj_param_list_t urj_bus_param_list =
Index: src/bus/buses_list.h
===================================================================
--- src/bus/buses_list.h	(revision 1966)
+++ src/bus/buses_list.h	(working copy)
@@ -130,6 +130,9 @@
 #ifdef ENABLE_BUS_SLSUP3
 _URJ_BUS(slsup3)
 #endif
+#ifdef ENABLE_BUS_SPI
+_URJ_BUS(spi)
+#endif
 #ifdef ENABLE_BUS_TX4925
 _URJ_BUS(tx4925)
 #endif
Index: src/bus/Makefile.am
===================================================================
--- src/bus/Makefile.am	(revision 1966)
+++ src/bus/Makefile.am	(working copy)
@@ -166,6 +166,10 @@
 libbus_la_SOURCES += slsup3.c
 endif
 
+if ENABLE_BUS_SPI
+libbus_la_SOURCES += spi.c
+endif
+
 if ENABLE_BUS_TX4925
 libbus_la_SOURCES += tx4925.c
 endif
Index: src/flash/spi_flash.c
===================================================================
--- src/flash/spi_flash.c	(revision 0)
+++ src/flash/spi_flash.c	(revision 0)
@@ -0,0 +1,243 @@
+/*
+ * $Id: spi_flash.c 1729 2010-01-24 11:31:51Z jgstroud $
+ *
+ * Copyright (C) 2002, 2003 ETC s.r.o.
+ *
+ * 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.
+ *
+ * Written by Jon Stroud <jstroud@breakingpoint.com>, 2010.
+ */
+
+#include <sysdep.h>
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>     /* usleep */
+
+#include <urjtag/log.h>
+#include <urjtag/error.h>
+#include <urjtag/flash.h>
+#include <urjtag/bus.h>
+
+#include "flash.h"
+#include "spi_flash.h"
+#include "cfi.h"
+#include "amd.h"
+
+
+inline void spi_flash_set_csn (urj_flash_cfi_array_t *cfi_array, uint8_t csn);
+inline uint8_t spi_flash_rdsr (urj_flash_cfi_array_t *cfi_array);
+inline void spi_flash_wait_wr_done (urj_flash_cfi_array_t *cfi_array);
+inline void spi_flash_wren (urj_flash_cfi_array_t *cfi_array);
+inline void spi_flash_wrdi (urj_flash_cfi_array_t *cfi_array);
+
+int
+urj_flash_spi_detect (urj_bus_t *bus, uint32_t adr, urj_flash_cfi_array_t **cfi_array)
+{
+    urj_bus_area_t area;
+    urj_flash_cfi_query_structure_t *cfi;
+
+    if (!cfi_array || !bus)
+        return -1;        /* invalid parameters */
+
+    *cfi_array = calloc ( 1, sizeof (urj_flash_cfi_array_t) );
+    if (!*cfi_array)
+        return -2;        /* out of memory */
+
+    (*cfi_array)->bus = bus;
+    (*cfi_array)->address = 0;
+    if (URJ_BUS_AREA(bus, adr + 0, &area) != URJ_STATUS_OK)
+        return -8;              /* bus width detection failed */
+    if (URJ_BUS_TYPE (bus) != URJ_BUS_TYPE_SPI)
+        return URJ_STATUS_FAIL;
+
+    urj_log (URJ_LOG_LEVEL_NORMAL, "SPI Flash\n");
+
+    unsigned int bw = area.width;
+    int ba,i;
+    if (bw != 8)
+        return -3;              /* invalid bus width */
+    (*cfi_array)->bus_width = ba = bw / 8;
+    (*cfi_array)->cfi_chips = calloc (ba, sizeof (urj_flash_cfi_chip_t *));
+    if (!(*cfi_array)->cfi_chips)
+        return -2;
+
+    for ( i=0; i<ba; i++ )
+    {
+        (*cfi_array)->cfi_chips[i] = calloc (1, sizeof (urj_flash_cfi_chip_t));
+        if (!(*cfi_array)->cfi_chips[i])
+            return -2;    /* out of memory */
+        (*cfi_array)->cfi_chips[i]->width = 1;        //ba;
+        cfi = &(*cfi_array)->cfi_chips[i]->cfi;
+
+        cfi->identification_string.pri_id_code = CFI_VENDOR_NULL;
+        cfi->identification_string.pri_vendor_tbl = NULL;
+        cfi->identification_string.alt_id_code = 0;
+        cfi->identification_string.alt_vendor_tbl = NULL;
+
+        cfi->device_geometry.device_size = 512*1024;
+        cfi->device_geometry.device_interface = 0;    // x 8
+        cfi->device_geometry.max_bytes_write = 128;
+        cfi->device_geometry.number_of_erase_regions = 0;
+        cfi->device_geometry.erase_block_regions =
+        malloc (cfi->device_geometry.number_of_erase_regions * sizeof
+            (urj_flash_cfi_erase_block_region_t));
+        if (!cfi->device_geometry.erase_block_regions)
+            return -2;    /* out of memory */
+
+        cfi->device_geometry.erase_block_regions[i].erase_block_size = 64 * 1024;
+        cfi->device_geometry.erase_block_regions[i].number_of_erase_blocks = 0;
+        //Add other details for info
+    }
+    return 0;
+}
+
+static void
+spi_flash_print_info (urj_log_level_t ll, urj_flash_cfi_array_t *cfi_array)
+{
+    urj_log (ll, _("Chip: SPI Flash\n"));
+    urj_log (ll, _("Page Size = 128 bytes\n"));
+}
+
+static int
+spi_flash_erase_block (urj_flash_cfi_array_t *cfi_array, uint32_t adr)
+{
+    // we dont need to erase blocks with the spi flash
+    return 0;
+}
+
+static int
+spi_flash_unlock_block (urj_flash_cfi_array_t *cfi_array, uint32_t adr)
+{
+    // we dont need to unlock blocks with the spi flash
+    return 0;
+}
+
+inline void spi_flash_set_csn (urj_flash_cfi_array_t *cfi_array, uint8_t csn)
+{
+    if (csn)
+        URJ_BUS_DISABLE (cfi_array->bus);
+    else
+        URJ_BUS_ENABLE (cfi_array->bus);
+}
+
+
+inline uint8_t spi_flash_rdsr (urj_flash_cfi_array_t *cfi_array)
+{
+    uint8_t reg;
+    urj_bus_t *bus = cfi_array->bus;
+    spi_flash_set_csn (cfi_array, 0);
+    URJ_BUS_WRITE (bus, 0, CMD_SPI_RDSR);
+    reg = URJ_BUS_READ_NEXT (bus, 0);
+    spi_flash_set_csn (cfi_array, 1);
+    return reg;
+}
+
+inline void spi_flash_wait_wr_done (urj_flash_cfi_array_t *cfi_array)
+{
+    uint8_t reg;
+    urj_bus_t *bus = cfi_array->bus;
+    spi_flash_set_csn (cfi_array, 0);
+    URJ_BUS_WRITE (bus, 0, CMD_SPI_RDSR);
+    reg = URJ_BUS_READ_NEXT (bus, 0);
+    while (reg & SPI_WIP)
+        reg = URJ_BUS_READ_NEXT (bus, 0);
+    spi_flash_set_csn (cfi_array, 1);
+}
+
+inline void spi_flash_wren (urj_flash_cfi_array_t *cfi_array)
+{
+    urj_bus_t *bus = cfi_array->bus;
+    spi_flash_set_csn (cfi_array, 0);
+    URJ_BUS_WRITE (bus, 0, CMD_SPI_WREN);
+    spi_flash_set_csn (cfi_array, 1);
+}
+
+inline void spi_flash_wrdi (urj_flash_cfi_array_t *cfi_array)
+{
+    urj_bus_t *bus = cfi_array->bus;
+    spi_flash_set_csn (cfi_array, 0);
+    URJ_BUS_WRITE (bus, 0, CMD_SPI_WRDI);
+    spi_flash_set_csn (cfi_array, 1);
+}
+
+static int
+spi_flash_write_page (urj_flash_cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count)
+{
+    uint32_t i;
+    urj_bus_t *bus = cfi_array->bus;
+
+    if (count > 128) count = 128;
+    spi_flash_wren (cfi_array);
+    spi_flash_set_csn (cfi_array, 0);
+    URJ_BUS_WRITE_START (bus, adr);
+    for (i = 0; i < count; i++) {
+        URJ_BUS_WRITE (bus, 0, buffer[i]);
+    }
+    spi_flash_set_csn (cfi_array, 1);
+    spi_flash_wrdi (cfi_array);
+    return count;
+}
+
+static int
+spi_flash_program (urj_flash_cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count)
+{
+    uint32_t i;
+    uint32_t num_bytes;
+
+    for (i = 0; i < count; )
+    {
+        num_bytes = spi_flash_write_page (cfi_array, adr + i, &buffer[i], count - i);
+        i += num_bytes;
+        spi_flash_wait_wr_done (cfi_array);
+    }
+    return 0;
+}
+
+static int
+spi_flash_autodetect (urj_flash_cfi_array_t *cfi_array)
+{
+    // cant really autodetect the spi flash because it does not usually contain
+    // an identification page
+    urj_bus_area_t area;
+
+    if (URJ_BUS_AREA (cfi_array->bus, cfi_array->address, &area) != URJ_STATUS_OK)
+        return 0;
+
+    return (area.width == 8);
+}
+
+static void
+spi_flash_readarray (urj_flash_cfi_array_t *cfi_array)
+{
+    /* Read Array */
+}
+
+
+const urj_flash_driver_t urj_spi_flash_driver = {
+    N_("SPI Flash"),
+    N_("supported: Standard SPI flash, 1 x 8 bit"),
+    1, /* buswidth */
+    spi_flash_autodetect,
+    spi_flash_print_info,
+    spi_flash_erase_block,
+    spi_flash_unlock_block,
+    spi_flash_program,
+    spi_flash_readarray,
+};
+
Index: src/flash/spi_flash.h
===================================================================
--- src/flash/spi_flash.h	(revision 0)
+++ src/flash/spi_flash.h	(revision 0)
@@ -0,0 +1,20 @@
+#ifndef URJ_SRC_SPI_FLASH_H
+#define URJ_SRC_SPI_FLASH_H
+
+#include <urjtag/types.h>
+#include <urjtag/flash.h>
+
+
+#define CMD_SPI_WREN    0x06
+#define CMD_SPI_WRDI    0x04
+#define CMD_SPI_RDSR    0x05
+#define CMD_SPI_WRSR    0x01
+#define CMD_SPI_READ    0x03
+#define CMD_SPI_WRITE   0x02
+#define SPI_WIP         0x01
+
+int urj_flash_spi_detect (urj_bus_t *bus, uint32_t adr, urj_flash_cfi_array_t **cfi_array);
+
+extern const urj_flash_driver_t urj_spi_flash_driver;
+
+#endif
Index: src/flash/detectflash.c
===================================================================
--- src/flash/detectflash.c	(revision 1966)
+++ src/flash/detectflash.c	(working copy)
@@ -44,12 +44,14 @@
 #include "amd.h"
 #include "cfi.h"
 #include "intel.h"
+#include "spi_flash.h"
 
 urj_flash_cfi_array_t *urj_flash_cfi_array = NULL;
 
 static const urj_flash_detect_func_t urj_flash_detect_funcs[] = {
     &urj_flash_cfi_detect,
     &urj_flash_jedec_detect,
+    &urj_flash_spi_detect,
     &urj_flash_amd_detect,
 #ifdef JEDEC_EXP
     &urj_flash_jedec_exp_detect,
Index: src/flash/Makefile.am
===================================================================
--- src/flash/Makefile.am	(revision 1966)
+++ src/flash/Makefile.am	(working copy)
@@ -38,6 +38,8 @@
 	intel.h \
 	jedec.c \
 	jedec.h \
+	spi_flash.c \
+	spi_flash.h \
 	mic.h
 
 if JEDEC_EXP
Index: src/flash/flash.c
===================================================================
--- src/flash/flash.c	(revision 1966)
+++ src/flash/flash.c	(working copy)
@@ -50,6 +50,7 @@
 #include "cfi.h"
 #include "intel.h"
 #include "amd.h"
+#include "spi_flash.h"
 
 const urj_flash_driver_t * const urj_flash_flash_drivers[] = {
     &urj_flash_amd_32_flash_driver,
@@ -59,6 +60,7 @@
     &urj_flash_intel_16_flash_driver,
     &urj_flash_intel_8_flash_driver,
     &urj_flash_amd_29xx040_flash_driver,        //20/09/2006
+    &urj_spi_flash_driver,
     NULL
 };
 
Index: configure.ac
===================================================================
--- configure.ac	(revision 1966)
+++ configure.ac	(working copy)
@@ -602,6 +602,7 @@
 	sharc_21065L
 	sharc_21369_ezkit
 	slsup3
+	spi
 	tx4925
 	zefant_xs3
 ])
