static void pch_lock_smm(pci_dev_t dev) { #if TEST_SMM_FLASH_LOCKDOWN u8 reg8; #endif if (acpi_slp_type != 3) { #if ENABLE_ACPI_MODE_IN_COREBOOT debug("Enabling ACPI via APMC:\n"); outb(0xe1, 0xb2); /* Enable ACPI mode */ debug("done.\n"); #else debug("Disabling ACPI via APMC:\n"); outb(0x1e, 0xb2); /* Disable ACPI mode */ debug("done.\n"); #endif } /* Don't allow evil boot loaders, kernels, or * userspace applications to deceive us: */ smm_lock(); #if TEST_SMM_FLASH_LOCKDOWN /* Now try this: */ debug("Locking BIOS to RO... "); reg8 = x86_pci_read_config8(dev, 0xdc); /* BIOS_CNTL */ debug(" BLE: %s; BWE: %s\n", (reg8 & 2) ? "on" : "off", (reg8 & 1) ? "rw" : "ro"); reg8 &= ~(1 << 0); /* clear BIOSWE */ x86_pci_write_config8(dev, 0xdc, reg8); reg8 |= (1 << 1); /* set BLE */ x86_pci_write_config8(dev, 0xdc, reg8); debug("ok.\n"); reg8 = x86_pci_read_config8(dev, 0xdc); /* BIOS_CNTL */ debug(" BLE: %s; BWE: %s\n", (reg8 & 2) ? "on" : "off", (reg8 & 1) ? "rw" : "ro"); debug("Writing:\n"); writeb(0, 0xfff00000); debug("Testing:\n"); reg8 |= (1 << 0); /* set BIOSWE */ x86_pci_write_config8(dev, 0xdc, reg8); reg8 = x86_pci_read_config8(dev, 0xdc); /* BIOS_CNTL */ debug(" BLE: %s; BWE: %s\n", (reg8 & 2) ? "on" : "off", (reg8 & 1) ? "rw" : "ro"); debug("Done.\n"); #endif }
static void pch_rtc_init(pci_dev_t dev) { int rtc_failed; u8 reg8; reg8 = x86_pci_read_config8(dev, GEN_PMCON_3); rtc_failed = reg8 & RTC_BATTERY_DEAD; if (rtc_failed) { reg8 &= ~RTC_BATTERY_DEAD; x86_pci_write_config8(dev, GEN_PMCON_3, reg8); } debug("rtc_failed = 0x%x\n", rtc_failed); #if CONFIG_HAVE_ACPI_RESUME /* Avoid clearing pending interrupts and resetting the RTC control * register in the resume path because the Linux kernel relies on * this to know if it should restart the RTC timerqueue if the wake * was due to the RTC alarm. */ if (acpi_get_slp_type() == 3) return; #endif /* TODO: Handle power failure */ if (rtc_failed) printf("RTC power failed\n"); rtc_init(); }
void pci_assign_irqs(int bus, int device, u8 irq[4]) { pci_dev_t bdf; int func; u16 vendor; u8 pin, line; for (func = 0; func < 8; func++) { bdf = PCI_BDF(bus, device, func); vendor = x86_pci_read_config16(bdf, PCI_VENDOR_ID); if (vendor == 0xffff || vendor == 0x0000) continue; pin = x86_pci_read_config8(bdf, PCI_INTERRUPT_PIN); /* PCI spec says all values except 1..4 are reserved */ if ((pin < 1) || (pin > 4)) continue; line = irq[pin - 1]; if (!line) continue; debug("Assigning IRQ %d to PCI device %d.%x.%d (INT%c)\n", line, bus, device, func, 'A' + pin - 1); x86_pci_write_config8(bdf, PCI_INTERRUPT_LINE, line); } }
static void pch_disable_smm_only_flashing(pci_dev_t dev) { u8 reg8; debug("Enabling BIOS updates outside of SMM... "); reg8 = x86_pci_read_config8(dev, 0xdc); /* BIOS_CNTL */ reg8 &= ~(1 << 5); x86_pci_write_config8(dev, 0xdc, reg8); }
static void pch_fixups(pci_dev_t dev) { u8 gen_pmcon_2; /* Indicate DRAM init done for MRC S3 to know it can resume */ gen_pmcon_2 = x86_pci_read_config8(dev, GEN_PMCON_2); gen_pmcon_2 |= (1 << 7); x86_pci_write_config8(dev, GEN_PMCON_2, gen_pmcon_2); /* Enable DMI ASPM in the PCH */ clrbits_le32(RCB_REG(0x2304), 1 << 10); setbits_le32(RCB_REG(0x21a4), (1 << 11) | (1 << 10)); setbits_le32(RCB_REG(0x21a8), 0x3); }
static void pch_rtc_init(pci_dev_t dev) { int rtc_failed; u8 reg8; reg8 = x86_pci_read_config8(dev, GEN_PMCON_3); rtc_failed = reg8 & RTC_BATTERY_DEAD; if (rtc_failed) { reg8 &= ~RTC_BATTERY_DEAD; x86_pci_write_config8(dev, GEN_PMCON_3, reg8); } debug("rtc_failed = 0x%x\n", rtc_failed); /* TODO: Handle power failure */ if (rtc_failed) printf("RTC power failed\n"); }
static void enable_pm_piix(void) { u8 en; u16 cmd; /* Set the PM I/O base */ x86_pci_write_config32(PIIX_PM, PMBA, CONFIG_ACPI_PM1_BASE | 1); /* Enable access to the PM I/O space */ cmd = x86_pci_read_config16(PIIX_PM, PCI_COMMAND); cmd |= PCI_COMMAND_IO; x86_pci_write_config16(PIIX_PM, PCI_COMMAND, cmd); /* PM I/O Space Enable (PMIOSE) */ en = x86_pci_read_config8(PIIX_PM, PMREGMISC); en |= PMIOSE; x86_pci_write_config8(PIIX_PM, PMREGMISC, en); }
bool pirq_check_irq_routed(int link, u8 irq) { u8 pirq; int base = irq_router.link_base; if (irq_router.config == PIRQ_VIA_PCI) pirq = x86_pci_read_config8(irq_router.bdf, LINK_N2V(link, base)); else pirq = readb(irq_router.ibase + LINK_N2V(link, base)); pirq &= 0xf; /* IRQ# 0/1/2/8/13 are reserved */ if (pirq < 3 || pirq == 8 || pirq == 13) return false; return pirq == irq ? true : false; }
int mp_determine_pci_dstirq(int bus, int dev, int func, int pirq) { u8 irq; if (i440fx) { /* * Not like most x86 platforms, the PIRQ[A-D] on PIIX3 are not * connected to I/O APIC INTPIN#16-19. Instead they are routed * to an irq number controled by the PIRQ routing register. */ irq = x86_pci_read_config8(PCI_BDF(bus, dev, func), PCI_INTERRUPT_LINE); } else { /* * ICH9's PIRQ[A-H] are not consecutive numbers from 0 to 7. * PIRQ[A-D] still maps to [0-3] but PIRQ[E-H] maps to [8-11]. */ irq = pirq < 8 ? pirq + 16 : pirq + 12; } return irq; }
static int gpio_ich6_get_base(unsigned long base) { pci_dev_t pci_dev; /* handle for 0:1f:0 */ u8 tmpbyte; u16 tmpword; u32 tmplong; /* Where should it be? */ pci_dev = PCI_BDF(0, 0x1f, 0); /* Is the device present? */ tmpword = x86_pci_read_config16(pci_dev, PCI_VENDOR_ID); if (tmpword != PCI_VENDOR_ID_INTEL) { debug("%s: wrong VendorID %x\n", __func__, tmpword); return -ENODEV; } tmpword = x86_pci_read_config16(pci_dev, PCI_DEVICE_ID); debug("Found %04x:%04x\n", PCI_VENDOR_ID_INTEL, tmpword); /* * We'd like to validate the Device ID too, but pretty much any * value is either a) correct with slight differences, or b) * correct but undocumented. We'll have to check a bunch of other * things instead... */ /* I/O should already be enabled (it's a RO bit). */ tmpword = x86_pci_read_config16(pci_dev, PCI_COMMAND); if (!(tmpword & PCI_COMMAND_IO)) { debug("%s: device IO not enabled\n", __func__); return -ENODEV; } /* Header Type must be normal (bits 6-0 only; see spec.) */ tmpbyte = x86_pci_read_config8(pci_dev, PCI_HEADER_TYPE); if ((tmpbyte & 0x7f) != PCI_HEADER_TYPE_NORMAL) { debug("%s: invalid Header type\n", __func__); return -ENODEV; } /* Base Class must be a bridge device */ tmpbyte = x86_pci_read_config8(pci_dev, PCI_CLASS_CODE); if (tmpbyte != PCI_CLASS_CODE_BRIDGE) { debug("%s: invalid class\n", __func__); return -ENODEV; } /* Sub Class must be ISA */ tmpbyte = x86_pci_read_config8(pci_dev, PCI_CLASS_SUB_CODE); if (tmpbyte != PCI_CLASS_SUB_CODE_BRIDGE_ISA) { debug("%s: invalid subclass\n", __func__); return -ENODEV; } /* Programming Interface must be 0x00 (no others exist) */ tmpbyte = x86_pci_read_config8(pci_dev, PCI_CLASS_PROG); if (tmpbyte != 0x00) { debug("%s: invalid interface type\n", __func__); return -ENODEV; } /* * GPIOBASE moved to its current offset with ICH6, but prior to * that it was unused (or undocumented). Check that it looks * okay: not all ones or zeros. * * Note we don't need check bit0 here, because the Tunnel Creek * GPIO base address register bit0 is reserved (read returns 0), * while on the Ivybridge the bit0 is used to indicate it is an * I/O space. */ tmplong = x86_pci_read_config32(pci_dev, base); if (tmplong == 0x00000000 || tmplong == 0xffffffff) { debug("%s: unexpected BASE value\n", __func__); return -ENODEV; } /* * Okay, I guess we're looking at the right device. The actual * GPIO registers are in the PCI device's I/O space, starting * at the offset that we just read. Bit 0 indicates that it's * an I/O address, not a memory address, so mask that off. */ return tmplong & 1 ? tmplong & ~3 : tmplong & ~15; }