This patch adds ATI/AMD SB600 SPI interface, it also adds generic spi mmio functions for use else where (as suggested by Jordan Crouse). Detection code for the sb600 spi interface is in chipset_enable.c

Thanks to Jordan Crouse, Carl-Daniel Hailfinger, Corey Osgood, and Peter Stuge for all their help.

Signed-off-by: Sean Nelson <snelson@nmt.edu>
---

Index: flash.h
===================================================================
--- flash.h	(revision 3659)
+++ flash.h	(working copy)
@@ -380,11 +380,13 @@
 	BUS_TYPE_ICH7_SPI,
 	BUS_TYPE_ICH9_SPI,
 	BUS_TYPE_IT87XX_SPI,
+	BUS_TYPE_SB600_SPI,
 	BUS_TYPE_VIA_SPI
 } flashbus_t;
 
 extern flashbus_t flashbus;
 extern void *spibar;
+extern void *spi_mmio_baseaddr;
 
 /* Physical memory mapping device */
 #if defined (__sun) && (defined(__i386) || defined(__amd64))
@@ -413,6 +415,12 @@
 extern char *lb_part, *lb_vendor;
 
 /* spi.c */
+uint8_t spi_read8(uint8_t reg);
+uint16_t spi_read16(uint8_t reg);
+uint32_t spi_read32(uint8_t reg);
+void spi_write8(uint8_t reg, uint8_t val);
+void spi_write16(uint8_t reg, uint16_t val);
+void spi_write32(uint8_t reg, uint32_t val);
 int probe_spi_rdid(struct flashchip *flash);
 int probe_spi_rdid4(struct flashchip *flash);
 int probe_spi_res(struct flashchip *flash);
@@ -454,6 +462,11 @@
 int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf);
 int it8716f_spi_chip_write(struct flashchip *flash, uint8_t *buf);
 
+/* sb600spi.c */
+int sb600_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr);
+int sb600_spi_chip_read(struct flashchip *flash, uint8_t *buf);
+int sb600_spi_chip_write(struct flashchip *flash, uint8_t *buf);
+
 /* jedec.c */
 uint8_t oddparity(uint8_t val);
 void toggle_ready_jedec(volatile uint8_t *dst);
Index: spi.c
===================================================================
--- spi.c	(revision 3659)
+++ spi.c	(working copy)
@@ -29,7 +29,42 @@
 #include "flash.h"
 #include "spi.h"
 
+static uint8_t spi_read8(uint8_t reg)
+{
+	volatile uint8_t regval;
+	regval = *(volatile uint8_t *) ((uint8_t *) spi_mmio_baseaddr + reg);
+	return regval;
+}
 
+static uint16_t spi_read16(uint8_t reg)
+{
+	volatile uint16_t regval;
+	regval = *(volatile uint16_t *) ((uint8_t *) spi_mmio_baseaddr + reg);
+	return regval;
+}
+
+static uint32_t spi_read32(uint8_t reg)
+{
+	volatile uint32_t regval;
+	regval = *(volatile uint32_t *) ((uint8_t *) spi_mmio_baseaddr + reg);
+	return regval;
+}
+
+static void spi_write8(uint8_t reg, uint8_t val)
+{
+	(*(uint8_t *)((uint8_t *) spi_mmio_baseaddr + reg) = val);
+}
+
+static void spi_write16(uint8_t reg, uint16_t val)
+{
+	(*(uint16_t *)((uint8_t *) spi_mmio_baseaddr + reg) = val);
+}
+
+static void spi_write32(uint8_t reg, uint32_t val);
+{
+	(*(uint32_t *)((uint8_t *) spi_mmio_baseaddr + reg) = val);
+}
+
 void spi_prettyprint_status_register(struct flashchip *flash);
 
 int spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr)
@@ -37,6 +72,8 @@
 	switch (flashbus) {
 	case BUS_TYPE_IT87XX_SPI:
 		return it8716f_spi_command(writecnt, readcnt, writearr, readarr);
+	case BUS_TYPE_SB600_SPI:
+		return sb600_spi_command(writecnt, readcnt, writearr, readarr);
 	case BUS_TYPE_ICH7_SPI:
 	case BUS_TYPE_ICH9_SPI:
 	case BUS_TYPE_VIA_SPI:
@@ -139,6 +176,7 @@
 
 	/* only some SPI chipsets support 4 bytes commands */
 	switch (flashbus) {
+	case BUS_TYPE_SB600_SPI:
 	case BUS_TYPE_ICH7_SPI:
 	case BUS_TYPE_ICH9_SPI:
 	case BUS_TYPE_VIA_SPI:
@@ -378,6 +416,8 @@
 {
 
 	switch (flashbus) {
+	case BUS_TYPE_SB600_SPI:
+		return sb600_spi_chip_read(flash, buf);
 	case BUS_TYPE_IT87XX_SPI:
 		return it8716f_spi_chip_read(flash, buf);
 	case BUS_TYPE_ICH7_SPI:
@@ -394,6 +434,8 @@
 int spi_chip_write(struct flashchip *flash, uint8_t *buf)
 {
 	switch (flashbus) {
+	case BUS_TYPE_SB600_SPI:
+		return sb600_spi_chip_write(flash, buf);
 	case BUS_TYPE_IT87XX_SPI:
 		return it8716f_spi_chip_write(flash, buf);
 	case BUS_TYPE_ICH7_SPI:
Index: Makefile
===================================================================
--- Makefile	(revision 3659)
+++ Makefile	(working copy)
@@ -29,7 +29,7 @@
 	w49f002u.o 82802ab.o pm49fl00x.o sst49lf040.o en29f002a.o \
 	sst49lfxxxc.o sst_fwhub.o layout.o cbtable.o flashchips.o \
 	flashrom.o w39v080fa.o sharplhf00l04.o w29ee011.o spi.o it87spi.o \
-	ichspi.o w39v040c.o
+	ichspi.o w39v040c.o sb600spi.o
 
 all: pciutils dep $(PROGRAM)
 
Index: chipset_enable.c
===================================================================
--- chipset_enable.c	(revision 3659)
+++ chipset_enable.c	(working copy)
@@ -44,6 +44,7 @@
 
 flashbus_t flashbus = BUS_TYPE_LPC;
 void *spibar = NULL;
+void *spi_mmio_baseaddr = NULL;
 
 
 static int enable_flash_ali_m1533(struct pci_dev *dev, const char *name)
@@ -221,6 +222,29 @@
 	return 0;
 }
 
+static int enable_flash_sb600_spi(struct pci_dev *dev, const char *name)
+{
+	uint32_t flashspi_base;
+
+	/* SPI Base Address (A0h) */
+	flashspi_base = pci_read_word(dev, 0xa0);
+	printf_debug("MMIO base at = 0x%x\n", flashspi_base);
+	
+	sb600_spibase = mmap(NULL, 0x20, PROT_WRITE | PROT_READ, MAP_SHARED,
+	 			fd_mem, flashspi_base);
+	
+	if (sb600_spibase == MAP_FAILED)
+	{
+		perror("Can't mmpa memory using " MEM_DEV);
+		exit(1);
+	}
+	
+	flashbus = BUS_TYPE_SB600_SPI;
+
+	return 0;
+}
+
+
 static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name, int ich_generation)
 {
 	int ret, i;
Index: sb600spi.c
===================================================================
--- sb600spi.c	(revision 0)
+++ sb600spi.c	(revision 0)
@@ -0,0 +1,151 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2008 Sean Nelson <snelson@nmt.edu>
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * SPI interface for SB600
+ * Note for the SB600 in Sharing Mode (BIOS and MAC):
+ * This driver must also be careful to properly synchronize when 
+ * NOTE: This SPI is memory mapped not IO mapped, so no INB/OUTB
+ */
+
+#include <stdio.h>
+#include <pci/pci.h>
+#include <stdint.h>
+#include <string.h>
+#include "flash.h"
+#include "spi.h"
+
+/* use fast 33MHz SPI (<>0) or slow 16MHz (0) */
+int fast_spi = 1;
+
+int sb600_spi_command(unsigned int writecnt, unsigned int readcnt,
+	const unsigned char *writearr, unsigned char *readarr)
+{
+	uint8_t busy, speed, cmd_exec, FifoPtr,
+		FifoPtrClr, FifoPtrInc, sendbits;
+	int i;
+
+	/* Make sure we have the SPI's MMIO BaseAddr set for use */
+	if (spi_mmio_baseaddr != 0)
+	{
+		printf("spi_mmio_baseaddr needs to be set to use sb600 SPI\n");
+		return 1;
+	}
+	
+	/* the sb600 fifo can only handle 8 bytes for reading
+	 * and 8 bytes for writing
+	 */
+	if (readcnt > 8) {
+		printf("%s called with unsupported readcnt %i.\n",
+			__func__, readcnt);
+		return 1;
+	}
+	
+	/* the write count for the sb600 is the number of bytes being sent 
+	 * through the FIFO which doesn't include the cmd byte that we count
+	 * as part of the write count
+	 */
+	if ((writecnt-1) > 8) {
+		printf("%s called with unsupported writecnt %i.\n",
+			__func__, (writecnt-1));
+		return 1;
+	}
+
+	/* check what the fifo ptr is (bits 2-0) */
+	FifoPtr = spi_read8(0x0d) & 0x7;
+	/* clear fifo ptr (bit 4) */
+	if(FifoPtr != 0)
+	{
+		FifoPtrClr = spi_read8(0x03);
+		spi_write8(0x03, FifoPtrClr|(1<<4));
+	}
+	spi_write(0x00, writearr[0]);
+	for(i=1; i < writecnt; i++)
+	{
+		/* write fifo byte */
+		spi_write8(0x0c, writearr[i]);
+		/* increment fifo ptr; to get next byte (bit 5) */
+		FifoPtrInc = spi_read8(0x03);
+		spi_write8(0x03, FifoPtrInc|(1<<5));
+	}
+
+	/*
+	 * set the SPI clock speed (0x0D)
+	 * NormSpeed: bit 5 & 4
+	 * FastSpeed: bit 7 & 6
+	 *
+	 * 33MHz - 0x1
+	 * 22MHz - 0x2
+	 * 16.5MHz - 0x3
+	 */
+	speed = spi_read8(0x0d);
+	spi_write8(0x0d, speed | ((fast_spi ? 1 : 3)<<6) | ((fast_spi ? 1 : 3)<<4) );
+	
+	/*
+	 * set the TxByte and RxBytes (0x01)
+	 * TxByteCount: bit 3-0
+	 * RxByteCount: bit 7-4
+	 */
+	sendbits = spi_read8(0x01);
+	spi_write8(0x01, sendbits | ((writecnt-1)<<4) | (readcnt) );
+
+	/*
+	 * start the command execution (0x02)
+	 * ExecuteOpCode: bit 0; start off the SPI command
+	 * Reserved: bit 1&2
+	 * SpiArbEnable: bit 3; 0 to speed up SPI ROM Access, if only BIOS
+	 */
+	cmd_exec = spi_read8(0x02);
+	spi_write8(0x02 ,cmd_exec|(1<<0));
+
+	/* check what the fifo ptr is (bits 2-0) */
+	FifoPtr = spi_read8(0x0d) & 0x7;
+	/* clear fifo ptr (bit 4) */
+	if(FifoPtr != 0)
+	{
+		FifoPtrClr = spi_read8(0x03);
+		spi_write8(0x03, FifoPtrClr|(1<<4));
+	}
+	if (readcnt > 0) {
+		for (i = 0; i < readcnt; i++) {
+			/* read fifo byte */
+			readarr[i] = spi_read8(0x0c);
+			/* increment fifo ptr; to get next byte (bit 5) */
+			FifoPtrInc = spi_read8(0x03);
+			spi_write8(0x03, FifoPtrInc|(1<<5));
+		}
+	}
+
+	return 0;
+}
+
+int sb600_spi_chip_read(struct flashchip *flash, uint8_t *buf)
+{
+	int total_size = 1024 * flash->total_size;
+	memcpy(buf, (const char *)flash->virtual_memory, total_size);
+	return 0;
+}
+
+int sb600_spi_chip_write(struct flashchip *flash, uint8_t *buf)
+{
+	int total_size = 1024 * flash->total_size;
+	memcpy((const char*)flash->virtual_memory, buf, total_size);
+	return 0;
+}
+
