x86: spi: Support ValleyView in ICH SPI driver
authorSimon Glass <sjg@chromium.org>
Wed, 28 Jan 2015 05:13:43 +0000 (22:13 -0700)
committerSimon Glass <sjg@chromium.org>
Fri, 6 Feb 2015 19:07:38 +0000 (12:07 -0700)
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>
drivers/spi/ich.c
drivers/spi/ich.h

index fdff158637da063a9be9967c4ae13df5b5018e21..da857791e06ee53e18ffd110255c95f21e2f49e1 100644 (file)
@@ -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 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
         * 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 @@ static int get_ich_version(uint16_t device_id)
        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 @@ static int ich9_can_do_33mhz(pci_dev_t dev)
        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 @@ static int ich_find_spi_controller(pci_dev_t *devp, int *ich_versionp)
                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 @@ static int ich_init_controller(struct ich_ctlr *ctlr)
        } 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 @@ static int ich_init_controller(struct ich_ctlr *ctlr)
                      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 @@ void spi_init(void)
 {
        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 @@ void spi_init(void)
         * 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)
index d2e4b8523bf6d442fb5d27101a6c0c83d3bcb40c..1419b23e119a8868c9a2fcde7387c8bcc823b708 100644 (file)
@@ -37,18 +37,19 @@ struct ich9_spi_regs {
        uint8_t opmenu[8];              /* 0x98 */
        uint32_t bbar;
        uint8_t _reserved3[12];
-       uint32_t fdoc;
+       uint32_t fdoc;                  /* 0xb0 */
        uint32_t fdod;
        uint8_t _reserved4[8];
-       uint32_t afc;
+       uint32_t afc;                   /* 0xc0 */
        uint32_t lvscc;
        uint32_t uvscc;
        uint8_t _reserved5[4];
-       uint32_t fpb;
+       uint32_t fpb;                   /* 0xd0 */
        uint8_t _reserved6[28];
-       uint32_t srdl;
+       uint32_t srdl;                  /* 0xf0 */
        uint32_t srdc;
-       uint32_t srd;
+       uint32_t scs;
+       uint32_t bcr;
 } __packed;
 
 enum {