int lpc_early_init(const void *blob, int node, pci_dev_t dev) { struct reg_info { u32 base; u32 size; } values[4], *ptr; int count; int i; count = fdtdec_get_int_array_count(blob, node, "intel,gen-dec", (u32 *)values, sizeof(values) / sizeof(u32)); if (count < 0) return -EINVAL; /* Set COM1/COM2 decode range */ x86_pci_write_config16(dev, LPC_IO_DEC, 0x0010); /* Enable PS/2 Keyboard/Mouse, EC areas and COM1 */ x86_pci_write_config16(dev, LPC_EN, KBC_LPC_EN | MC_LPC_EN | GAMEL_LPC_EN | COMA_LPC_EN); /* Write all registers but use 0 if we run out of data */ count = count * sizeof(u32) / sizeof(values[0]); for (i = 0, ptr = values; i < ARRAY_SIZE(values); i++, ptr++) { u32 reg = 0; if (i < count) reg = ptr->base | PCI_COMMAND_IO | (ptr->size << 16); x86_pci_write_config32(dev, LPC_GENX_DEC(i), reg); } return 0; }
static void qemu_chipset_init(void) { u16 device, xbcs; int pam, i; /* * i440FX and Q35 chipset have different PAM register offset, but with * the same bitfield layout. Here we determine the offset based on its * PCI device ID. */ device = x86_pci_read_config16(PCI_BDF(0, 0, 0), PCI_DEVICE_ID); i440fx = (device == PCI_DEVICE_ID_INTEL_82441); pam = i440fx ? I440FX_PAM : Q35_PAM; /* * Initialize Programmable Attribute Map (PAM) Registers * * Configure legacy segments C/D/E/F to system RAM */ for (i = 0; i < PAM_NUM; i++) x86_pci_write_config8(PCI_BDF(0, 0, 0), pam + i, PAM_RW); if (i440fx) { /* * Enable legacy IDE I/O ports decode * * Note: QEMU always decode legacy IDE I/O port on PIIX chipset. * However Linux ata_piix driver does sanity check on these two * registers to see whether legacy ports decode is turned on. * This is to make Linux ata_piix driver happy. */ x86_pci_write_config16(PIIX_IDE, IDE0_TIM, IDE_DECODE_EN); x86_pci_write_config16(PIIX_IDE, IDE1_TIM, IDE_DECODE_EN); /* Enable I/O APIC */ xbcs = x86_pci_read_config16(PIIX_ISA, XBCS); xbcs |= APIC_EN; x86_pci_write_config16(PIIX_ISA, XBCS, xbcs); enable_pm_piix(); } else { /* Configure PCIe ECAM base address */ x86_pci_write_config32(PCI_BDF(0, 0, 0), PCIEX_BAR, CONFIG_PCIE_ECAM_BASE | BAR_EN); enable_pm_ich9(); } qemu_fwcfg_init(); }
static void enable_clock_gating(pci_dev_t dev) { u32 reg32; u16 reg16; setbits_le32(RCB_REG(0x2234), 0xf); reg16 = x86_pci_read_config16(dev, GEN_PMCON_1); reg16 |= (1 << 2) | (1 << 11); x86_pci_write_config16(dev, GEN_PMCON_1, reg16); pch_iobp_update(0xEB007F07, ~0UL, (1 << 31)); pch_iobp_update(0xEB004000, ~0UL, (1 << 7)); pch_iobp_update(0xEC007F07, ~0UL, (1 << 31)); pch_iobp_update(0xEC004000, ~0UL, (1 << 7)); reg32 = readl(RCB_REG(CG)); reg32 |= (1 << 31); reg32 |= (1 << 29) | (1 << 28); reg32 |= (1 << 27) | (1 << 26) | (1 << 25) | (1 << 24); reg32 |= (1 << 16); reg32 |= (1 << 17); reg32 |= (1 << 18); reg32 |= (1 << 22); reg32 |= (1 << 23); reg32 &= ~(1 << 20); reg32 |= (1 << 19); reg32 |= (1 << 0); reg32 |= (0xf << 1); writel(reg32, RCB_REG(CG)); setbits_le32(RCB_REG(0x38c0), 0x7); setbits_le32(RCB_REG(0x36d4), 0x6680c004); setbits_le32(RCB_REG(0x3564), 0x3); }
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); }
int board_pci_post_scan(struct pci_controller *hose) { int ret = 0; u16 device, xbcs; int pam, i; pci_dev_t vga; ulong start; /* * i440FX and Q35 chipset have different PAM register offset, but with * the same bitfield layout. Here we determine the offset based on its * PCI device ID. */ device = x86_pci_read_config16(PCI_BDF(0, 0, 0), PCI_DEVICE_ID); i440fx = (device == PCI_DEVICE_ID_INTEL_82441); pam = i440fx ? I440FX_PAM : Q35_PAM; /* * Initialize Programmable Attribute Map (PAM) Registers * * Configure legacy segments C/D/E/F to system RAM */ for (i = 0; i < PAM_NUM; i++) x86_pci_write_config8(PCI_BDF(0, 0, 0), pam + i, PAM_RW); if (i440fx) { /* * Enable legacy IDE I/O ports decode * * Note: QEMU always decode legacy IDE I/O port on PIIX chipset. * However Linux ata_piix driver does sanity check on these two * registers to see whether legacy ports decode is turned on. * This is to make Linux ata_piix driver happy. */ x86_pci_write_config16(PIIX_IDE, IDE0_TIM, IDE_DECODE_EN); x86_pci_write_config16(PIIX_IDE, IDE1_TIM, IDE_DECODE_EN); /* Enable I/O APIC */ xbcs = x86_pci_read_config16(PIIX_ISA, XBCS); xbcs |= APIC_EN; x86_pci_write_config16(PIIX_ISA, XBCS, xbcs); } else { /* Configure PCIe ECAM base address */ x86_pci_write_config32(PCI_BDF(0, 0, 0), PCIEX_BAR, CONFIG_PCIE_ECAM_BASE | BAR_EN); } /* * QEMU emulated graphic card shows in the PCI configuration space with * PCI vendor id and device id as an artificial pair 0x1234:0x1111. * It is on PCI bus 0, function 0, but device number is not consistent * for the two x86 targets it supports. For i440FX and PIIX chipset * board, it shows as device 2, while for Q35 and ICH9 chipset board, * it shows as device 1. */ vga = i440fx ? I440FX_VGA : Q35_VGA; start = get_timer(0); ret = pci_run_vga_bios(vga, NULL, PCI_ROM_USE_NATIVE); debug("BIOS ran in %lums\n", get_timer(start)); return ret; }
int lpc_init(struct pci_controller *hose, pci_dev_t dev) { const void *blob = gd->fdt_blob; int node; debug("pch: lpc_init\n"); pci_write_bar32(hose, dev, 0, 0); pci_write_bar32(hose, dev, 1, 0xff800000); pci_write_bar32(hose, dev, 2, 0xfec00000); pci_write_bar32(hose, dev, 3, 0x800); pci_write_bar32(hose, dev, 4, 0x900); node = fdtdec_next_compatible(blob, 0, COMPAT_INTEL_PCH); if (node < 0) return -ENOENT; /* Set the value for PCI command register. */ x86_pci_write_config16(dev, PCI_COMMAND, 0x000f); /* IO APIC initialization. */ pch_enable_apic(dev); pch_enable_serial_irqs(dev); /* Setup the PIRQ. */ pch_pirq_init(blob, node, dev); /* Setup power options. */ pch_power_options(blob, node, dev); /* Initialize power management */ switch (pch_silicon_type()) { case PCH_TYPE_CPT: /* CougarPoint */ cpt_pm_init(dev); break; case PCH_TYPE_PPT: /* PantherPoint */ ppt_pm_init(dev); break; default: printf("Unknown Chipset: %#02x.%dx\n", PCI_DEV(dev), PCI_FUNC(dev)); return -ENOSYS; } /* Initialize the real time clock. */ pch_rtc_init(dev); /* Initialize the High Precision Event Timers, if present. */ enable_hpet(); /* Initialize Clock Gating */ enable_clock_gating(dev); pch_disable_smm_only_flashing(dev); #if CONFIG_HAVE_SMI_HANDLER pch_lock_smm(dev); #endif pch_fixups(dev); return 0; }
static int pch_power_options(const void *blob, int node, pci_dev_t dev) { u8 reg8; u16 reg16, pmbase; u32 reg32; const char *state; int pwr_on; int nmi_option; int ret; /* * Which state do we want to goto after g3 (power restored)? * 0 == S0 Full On * 1 == S5 Soft Off * * If the option is not existent (Laptops), use Kconfig setting. * TODO([email protected]): Make this configurable */ pwr_on = MAINBOARD_POWER_ON; reg16 = x86_pci_read_config16(dev, GEN_PMCON_3); reg16 &= 0xfffe; switch (pwr_on) { case MAINBOARD_POWER_OFF: reg16 |= 1; state = "off"; break; case MAINBOARD_POWER_ON: reg16 &= ~1; state = "on"; break; case MAINBOARD_POWER_KEEP: reg16 &= ~1; state = "state keep"; break; default: state = "undefined"; } reg16 &= ~(3 << 4); /* SLP_S4# Assertion Stretch 4s */ reg16 |= (1 << 3); /* SLP_S4# Assertion Stretch Enable */ reg16 &= ~(1 << 10); reg16 |= (1 << 11); /* SLP_S3# Min Assertion Width 50ms */ reg16 |= (1 << 12); /* Disable SLP stretch after SUS well */ x86_pci_write_config16(dev, GEN_PMCON_3, reg16); debug("Set power %s after power failure.\n", state); /* Set up NMI on errors. */ reg8 = inb(0x61); reg8 &= 0x0f; /* Higher Nibble must be 0 */ reg8 &= ~(1 << 3); /* IOCHK# NMI Enable */ reg8 |= (1 << 2); /* PCI SERR# Disable for now */ outb(reg8, 0x61); reg8 = inb(0x70); /* TODO([email protected]): Make this configurable */ nmi_option = NMI_OFF; if (nmi_option) { debug("NMI sources enabled.\n"); reg8 &= ~(1 << 7); /* Set NMI. */ } else { debug("NMI sources disabled.\n"); /* Can't mask NMI from PCI-E and NMI_NOW */ reg8 |= (1 << 7); } outb(reg8, 0x70); /* Enable CPU_SLP# and Intel Speedstep, set SMI# rate down */ reg16 = x86_pci_read_config16(dev, GEN_PMCON_1); reg16 &= ~(3 << 0); /* SMI# rate 1 minute */ reg16 &= ~(1 << 10); /* Disable BIOS_PCI_EXP_EN for native PME */ #if DEBUG_PERIODIC_SMIS /* Set DEBUG_PERIODIC_SMIS in pch.h to debug using periodic SMIs */ reg16 |= (3 << 0); /* Periodic SMI every 8s */ #endif x86_pci_write_config16(dev, GEN_PMCON_1, reg16); /* Set the board's GPI routing. */ ret = pch_gpi_routing(blob, node, dev); if (ret) return ret; pmbase = x86_pci_read_config16(dev, 0x40) & 0xfffe; writel(pmbase + GPE0_EN, fdtdec_get_int(blob, node, "intel,gpe0-enable", 0)); writew(pmbase + ALT_GP_SMI_EN, fdtdec_get_int(blob, node, "intel,alt-gp-smi-enable", 0)); /* Set up power management block and determine sleep mode */ reg32 = inl(pmbase + 0x04); /* PM1_CNT */ reg32 &= ~(7 << 10); /* SLP_TYP */ reg32 |= (1 << 0); /* SCI_EN */ outl(reg32, pmbase + 0x04); /* Clear magic status bits to prevent unexpected wake */ setbits_le32(RCB_REG(0x3310), (1 << 4) | (1 << 5) | (1 << 0)); clrbits_le32(RCB_REG(0x3f02), 0xf); return 0; }