Author: stepan Date: 2009-04-29 21:22:07 +0200 (Wed, 29 Apr 2009) New Revision: 94
Modified: trunk/filo/drivers/intel.c Log: fix poweroff command on intel platforms, and add bios flash locking example.
Modified: trunk/filo/drivers/intel.c =================================================================== --- trunk/filo/drivers/intel.c 2009-04-29 19:19:55 UTC (rev 93) +++ trunk/filo/drivers/intel.c 2009-04-29 19:22:07 UTC (rev 94) @@ -24,27 +24,141 @@ #define DEBUG_THIS CONFIG_DEBUG_INTEL #include <debug.h>
+#define DEFAULT_RCBA 0xfed1c000 + +#define PM1_STS 0x00 +#define PWRBTN_STS (1 << 8) +#define PM1_EN 0x02 +#define PM1_CNT 0x04 +#define SLP_EN (1 << 13) +#define SLP_TYP (7 << 10) +#define SLP_TYP_S0 (0 << 10) +#define SLP_TYP_S1 (1 << 10) +#define SLP_TYP_S3 (5 << 10) +#define SLP_TYP_S4 (6 << 10) +#define SLP_TYP_S5 (7 << 10) +#define GPE0_EN 0x2c + +#define RCBA8(x) *((volatile u8 *)(DEFAULT_RCBA + x)) +#define RCBA16(x) *((volatile u16 *)(DEFAULT_RCBA + x)) +#define RCBA32(x) *((volatile u32 *)(DEFAULT_RCBA + x)) + + +void intel_lockdown_flash(void) +{ + u8 reg8; + u32 reg32; + + reg32 = pci_read_config32(PCI_DEV(0,0x1f, 0), 0); + switch (reg32) { + case 0x27b08086: + case 0x27b88086: + case 0x27b98086: + case 0x27bd8086: + break; + default: + debug("Not an ICH7 southbridge\n"); + return; + } + + /* Now try this: */ + debug("Locking BIOS to read-only... "); + reg8 = pci_read_config8(PCI_DEV(0,0x1f,0), 0xdc); /* BIOS_CNTL */ + debug(" BIOS Lockdown Enable: %s; BIOS Write-Enable: %s\n", + (reg8&2)?"on":"off", (reg8&1)?"rw":"ro"); + + reg8 &= ~(1 << 0); /* clear BIOSWE */ + pci_write_config8(PCI_DEV(0,0x1f,0), 0xdc, reg8); + + reg8 |= (1 << 1); /* set BLE */ + pci_write_config8(PCI_DEV(0,0x1f,0), 0xdc, reg8); + + reg32 = RCBA32(0x3410); /* GCS - General Control and Status */ + reg32 |= 1; /* BILD - BIOS Interface Lockdown */ + RCBA32(0x3410) = reg32; /* Set BUC.TS and GCS.BBS to RO */ + + debug("BIOS hard locked until next full reset.\n"); + +} + + +/* We should add some "do this for each pci device" function to libpayload */ + +static void busmaster_disable_on_bus(int bus) +{ + int slot, func; + unsigned int val; + unsigned char hdr; + + for (slot = 0; slot < 0x20; slot++) { + for (func = 0; func < 8; func++) { + u32 reg32; + pcidev_t dev = PCI_DEV(bus, slot, func); + + val = pci_read_config32(dev, REG_VENDOR_ID); + + if (val == 0xffffffff || val == 0x00000000 || + val == 0x0000ffff || val == 0xffff0000) + continue; + + /* Disable Bus Mastering for this one device */ + reg32 = pci_read_config32(dev, REG_COMMAND); + reg32 &= ~REG_COMMAND_BM; + pci_write_config32(dev, REG_COMMAND, reg32); + + /* If this is a bridge, then follow it. */ + hdr = pci_read_config8(dev, REG_HEADER_TYPE); + hdr &= 0x7f; + if (hdr == HEADER_TYPE_BRIDGE || + hdr == HEADER_TYPE_CARDBUS) { + unsigned int buses; + buses = pci_read_config32(dev, REG_PRIMARY_BUS); + busmaster_disable_on_bus((buses >> 8) & 0xff); + } + } + } +} + +static void busmaster_disable(void) +{ + busmaster_disable_on_bus(0); +} + /** * Mostly for testing purposes without booting an OS */
void platform_poweroff(void) { - int pmbase; - + u16 pmbase; + u32 reg32; + pmbase = pci_read_config16(PCI_DEV(0,0x1f, 0), 0x40) & 0xfffe;
- /* XXX The sequence is correct; It works fine under Linux. - * Yet, it does not power off the system in FILO. - * Some initialization is missing - */ + /* Mask interrupts */ + asm("cli");
+ /* Turn off all bus master enable bits */ + busmaster_disable(); + + /* avoid any GPI waking the system from S5 */ + outl(0x00000000, pmbase + GPE0_EN); + + /* Clear Power Button Status */ + outw(PWRBTN_STS, pmbase + PM1_STS); + /* PMBASE + 4, Bit 10-12, Sleeping Type, * set to 110 -> S5, soft_off */
- outl((6 << 10), pmbase + 0x04); - outl((1 << 13) | (6 << 10), pmbase + 0x04); + reg32 = inl(pmbase + PM1_CNT);
+ reg32 &= ~(SLP_EN | SLP_TYP); + reg32 |= SLP_TYP_S5; + outl(reg32, pmbase + PM1_CNT); + + reg32 |= SLP_EN; + outl(reg32, pmbase + PM1_CNT); + for (;;) ; }