diff options
author | Simon Glass <sjg@chromium.org> | 2015-01-27 22:13:43 -0700 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2015-02-06 12:07:38 -0700 |
commit | 5093badbb59e83b42b8f9e5579e07e3916271207 (patch) | |
tree | 91ddc9365a2a161a4d69d9e21e9b49b488af2252 /drivers/spi | |
parent | 447f8b018e5e5bc5b6958ce6ed8f79e8c35c30af (diff) |
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>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/ich.c | 56 | ||||
-rw-r--r-- | drivers/spi/ich.h | 11 |
2 files changed, 47 insertions, 20 deletions
diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index fdff158637..da857791e0 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 @@ 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) diff --git a/drivers/spi/ich.h b/drivers/spi/ich.h index d2e4b8523b..1419b23e11 100644 --- a/drivers/spi/ich.h +++ b/drivers/spi/ich.h @@ -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 { |