x86: spi: Support ValleyView in ICH SPI driver

The base address is found in a different way and the protection bit is also
in a different place. Otherwise it is very similar.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c
index fdff158..da85779 100644
--- a/drivers/spi/ich.c
+++ b/drivers/spi/ich.c
@@ -7,6 +7,7 @@
  */
 
 #include <common.h>
+#include <errno.h>
 #include <malloc.h>
 #include <spi.h>
 #include <pci.h>
@@ -21,6 +22,7 @@
 struct ich_ctlr {
 	pci_dev_t dev;		/* PCI device number */
 	int ich_version;	/* Controller version, 7 or 9 */
+	bool use_sbase;		/* Use SBASE instead of RCB */
 	int ichspi_lock;
 	int locked;
 	uint8_t *opmenu;
@@ -145,7 +147,7 @@
 	 * ICH 7 SPI controller only supports array read command
 	 * and byte program command for SST flash
 	 */
-	if (ctlr.ich_version == 7) {
+	if (ctlr.ich_version == 7 || ctlr.use_sbase) {
 		ich->slave.op_mode_rx = SPI_OPM_RX_AS;
 		ich->slave.op_mode_tx = SPI_OPM_TX_BP;
 	}
@@ -181,7 +183,8 @@
 	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))
+	     device_id <= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX) ||
+	    device_id == PCI_DEVICE_ID_INTEL_VALLEYVIEW_LPC)
 		return 9;
 
 	return 0;
@@ -204,14 +207,14 @@
 	return speed == 1;
 }
 
-static int ich_find_spi_controller(pci_dev_t *devp, int *ich_versionp)
+static int ich_find_spi_controller(struct ich_ctlr *ich)
 {
 	int last_bus = pci_last_busno();
 	int bus;
 
 	if (last_bus == -1) {
 		debug("No PCI busses?\n");
-		return -1;
+		return -ENODEV;
 	}
 
 	for (bus = 0; bus <= last_bus; bus++) {
@@ -225,24 +228,33 @@
 		device_id = ids >> 16;
 
 		if (vendor_id == PCI_VENDOR_ID_INTEL) {
-			*devp = dev;
-			*ich_versionp = get_ich_version(device_id);
-			return 0;
+			ich->dev = dev;
+			ich->ich_version = get_ich_version(device_id);
+			if (device_id == PCI_DEVICE_ID_INTEL_VALLEYVIEW_LPC)
+				ich->use_sbase = true;
+			return ich->ich_version == 0 ? -ENODEV : 0;
 		}
 	}
 
 	debug("ICH SPI: No ICH found.\n");
-	return -1;
+	return -ENODEV;
 }
 
 static int ich_init_controller(struct ich_ctlr *ctlr)
 {
 	uint8_t *rcrb; /* Root Complex Register Block */
 	uint32_t rcba; /* Root Complex Base Address */
+	uint32_t sbase_addr;
+	uint8_t *sbase;
 
 	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);
+
+	/* SBASE is similar */
+	pci_read_config_dword(ctlr->dev, 0x54, &sbase_addr);
+	sbase = (uint8_t *)(sbase_addr & 0xfffffe00);
+
 	if (ctlr->ich_version == 7) {
 		struct ich7_spi_regs *ich7_spi;
 
@@ -262,7 +274,10 @@
 	} else if (ctlr->ich_version == 9) {
 		struct ich9_spi_regs *ich9_spi;
 
-		ich9_spi = (struct ich9_spi_regs *)(rcrb + 0x3800);
+		if (ctlr->use_sbase)
+			ich9_spi = (struct ich9_spi_regs *)sbase;
+		else
+			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);
@@ -282,12 +297,13 @@
 		      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;
+	debug("ICH SPI: Version %d detected at %p, speed %ld\n",
+	      ctlr->ich_version, ctlr->base, ctlr->max_speed);
 
 	ich_set_bbar(ctlr, 0);
 
@@ -298,7 +314,7 @@
 {
 	uint8_t bios_cntl;
 
-	if (ich_find_spi_controller(&ctlr.dev, &ctlr.ich_version)) {
+	if (ich_find_spi_controller(&ctlr)) {
 		printf("ICH SPI: Cannot find device\n");
 		return;
 	}
@@ -312,10 +328,20 @@
 	 * 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);
+	if (ctlr.use_sbase) {
+		struct ich9_spi_regs *ich9_spi;
+
+		ich9_spi = (struct ich9_spi_regs *)ctlr.base;
+		bios_cntl = ich_readb(&ich9_spi->bcr);
+		bios_cntl &= ~(1 << 5);	/* clear Enable InSMM_STS (EISS) */
+		bios_cntl |= 1;		/* Write Protect Disable (WPD) */
+		ich_writeb(bios_cntl, &ich9_spi->bcr);
+	} else {
+		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)