static void init_egress(void) { u32 reg32; /* VC0: TC0 only */ EPBAR8(0x14) = 1; EPBAR8(0x4) = 1; switch (MCHBAR32(0xc00) & 0x7) { case 0x0: /* FSB 1066 */ EPBAR32(0x2c) = 0x0001a6db; break; case 0x2: /* FSB 800 */ EPBAR32(0x2c) = 0x00014514; break; default: case 0x4: /* FSB 1333 */ EPBAR32(0x2c) = 0x00022861; break; } EPBAR32(0x28) = 0x0a0a0a0a; EPBAR8(0xc) = (EPBAR8(0xc) & ~0xe) | 2; EPBAR32(0x1c) = (EPBAR32(0x1c) & ~0x7f0000) | 0x0a0000; MCHBAR8(0x3c) = MCHBAR8(0x3c) | 0x7; /* VC1: ID1, TC7 */ reg32 = (EPBAR32(0x20) & ~(7 << 24)) | (1 << 24); reg32 = (reg32 & ~0xfe) | (1 << 7); EPBAR32(0x20) = reg32; /* Init VC1 port arbitration table */ EPBAR32(0x100) = 0x001000001; EPBAR32(0x104) = 0x000040000; EPBAR32(0x108) = 0x000001000; EPBAR32(0x10c) = 0x000000040; EPBAR32(0x110) = 0x001000001; EPBAR32(0x114) = 0x000040000; EPBAR32(0x118) = 0x000001000; EPBAR32(0x11c) = 0x000000040; /* Load table */ reg32 = EPBAR32(0x20) | (1 << 16); EPBAR32(0x20) = reg32; asm("nop"); EPBAR32(0x20) = reg32; /* Wait for table load */ while ((EPBAR8(0x26) & (1 << 0)) != 0); /* VC1: enable */ EPBAR32(0x20) |= 1 << 31; /* Wait for VC1 */ while ((EPBAR8(0x26) & (1 << 1)) != 0); printk(BIOS_DEBUG, "Done Egress Port\n"); }
void init_iommu() { /* FIXME: proper test? */ int me_active = pci_read_config8(PCI_DEV(0, 3, 0), PCI_CLASS_REVISION) != 0xff; int stepping = pci_read_config8(PCI_DEV(0, 0, 0), PCI_CLASS_REVISION); MCHBAR32(0x28) = IOMMU_BASE1 | 1; /* HDA @ 0:1b.0 */ if (stepping != STEPPING_B2) { /* The official workaround is to run SMM every 64ms. The only winning move is not to play. */ MCHBAR32(0x18) = IOMMU_BASE2 | 1; /* IGD @ 0:2.0-1 */ } else { /* write-once, so lock it down */ MCHBAR32(0x18) = 0; /* disable IOMMU for IGD @ 0:2.0-1 */ } if (me_active) { MCHBAR32(0x10) = IOMMU_BASE3 | 1; /* ME @ 0:3.0-3 */ } MCHBAR32(0x20) = IOMMU_BASE4 | 1; /* all other DMA sources */ /* clear GTT */ u32 gtt = pci_read_config16(PCI_DEV(0, 0, 0), 0x52); if (gtt & 0x400) { /* VT mode */ device_t igd = PCI_DEV(0, 2, 0); /* setup somewhere */ u8 cmd = pci_read_config8(igd, PCI_COMMAND); cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; pci_write_config8(igd, PCI_COMMAND, cmd); void* bar = (void*)pci_read_config32(igd, PCI_BASE_ADDRESS_0); /* clear GTT, 2MB is enough (and should be safe) */ memset(bar, 0, 2<<20); /* and now disable again */ cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); pci_write_config8(igd, PCI_COMMAND, cmd); pci_write_config32(igd, PCI_BASE_ADDRESS_0, 0); } if (stepping == STEPPING_B3) { MCHBAR8(0xffc) |= 1 << 4; device_t peg = PCI_DEV(0, 1, 0); /* FIXME: proper test? */ if (pci_read_config8(peg, PCI_CLASS_REVISION) != 0xff) { int val = pci_read_config32(peg, 0xfc) | (1 << 15); pci_write_config32(peg, 0xfc, val); } } /* final */ MCHBAR8(0x94) |= 1 << 3; }
void intel_sandybridge_finalize_smm(void) { pcie_or_config16(PCI_DEV_SNB, 0x50, 1 << 0); /* GGC */ pcie_or_config32(PCI_DEV_SNB, 0x5c, 1 << 0); /* DPR */ pcie_or_config32(PCI_DEV_SNB, 0x78, 1 << 10); /* ME */ pcie_or_config32(PCI_DEV_SNB, 0x90, 1 << 0); /* REMAPBASE */ pcie_or_config32(PCI_DEV_SNB, 0x98, 1 << 0); /* REMAPLIMIT */ pcie_or_config32(PCI_DEV_SNB, 0xa0, 1 << 0); /* TOM */ pcie_or_config32(PCI_DEV_SNB, 0xa8, 1 << 0); /* TOUUD */ pcie_or_config32(PCI_DEV_SNB, 0xb0, 1 << 0); /* BDSM */ pcie_or_config32(PCI_DEV_SNB, 0xb4, 1 << 0); /* BGSM */ pcie_or_config32(PCI_DEV_SNB, 0xb8, 1 << 0); /* TSEGMB */ pcie_or_config32(PCI_DEV_SNB, 0xbc, 1 << 0); /* TOLUD */ MCHBAR32_OR(0x5500, 1 << 0); /* PAVP */ MCHBAR32_OR(0x5f00, 1 << 31); /* SA PM */ MCHBAR32_OR(0x6020, 1 << 0); /* UMA GFX */ MCHBAR32_OR(0x63fc, 1 << 0); /* VTDTRK */ MCHBAR32_OR(0x6800, 1 << 31); MCHBAR32_OR(0x7000, 1 << 31); MCHBAR32_OR(0x77fc, 1 << 0); /* Memory Controller Lockdown */ MCHBAR8(0x50fc) = 0x8f; /* Read+write the following */ MCHBAR32(0x6030) = MCHBAR32(0x6030); MCHBAR32(0x6034) = MCHBAR32(0x6034); MCHBAR32(0x6008) = MCHBAR32(0x6008); }
void intel_nehalem_finalize_smm(void) { MCHBAR32_OR(0x5500, 1 << 0); /* PAVP */ MCHBAR32_OR(0x5f00, 1 << 31); /* SA PM */ MCHBAR32_OR(0x6020, 1 << 0); /* UMA GFX */ MCHBAR32_OR(0x63fc, 1 << 0); /* VTDTRK */ MCHBAR32_OR(0x6800, 1 << 31); MCHBAR32_OR(0x7000, 1 << 31); MCHBAR32_OR(0x77fc, 1 << 0); /* Memory Controller Lockdown */ MCHBAR8(0x50fc) = 0x8f; /* Read+write the following */ MCHBAR32(0x6030) = MCHBAR32(0x6030); MCHBAR32(0x6034) = MCHBAR32(0x6034); MCHBAR32(0x6008) = MCHBAR32(0x6008); }
static void disable_igd(const sysinfo_t *const sysinfo) { const device_t mch_dev = PCI_DEV(0, 0, 0); printk(BIOS_DEBUG, "Disabling IGD.\n"); u16 reg16; reg16 = pci_read_config16(mch_dev, D0F0_GGC); reg16 &= 0xff0f; /* Disable Graphics Stolen Memory. */ reg16 |= 0x0002; /* Disable IGD. */ pci_write_config16(mch_dev, D0F0_GGC, reg16); MCHBAR8(0xf10) |= (1 << 0); if (!(pci_read_config8(mch_dev, D0F0_CAPID0 + 4) & (1 << (33 - 32)))) { MCHBAR16(0x1190) |= (1 << 14); MCHBAR16(0x119e) = (MCHBAR16(0x119e) & ~(7 << 13)) | (4 << 13); MCHBAR16(0x119e) |= (1 << 12); } }
static int normalize(int channel_offset, u8 * mediumcoarse, u8 * fine) { printk(BIOS_SPEW, " normalize()\n"); if (*fine < 0x80) return 0; *fine -= 0x80; *mediumcoarse += 1; if (*mediumcoarse >= 0x40) { printk(BIOS_DEBUG, "Normalize Error\n"); return -1; } set_receive_enable(channel_offset, *mediumcoarse & 3, *mediumcoarse >> 2); MCHBAR8(C0WL0REOST + channel_offset) = *fine; return 0; }
/** * sample the strobes signal */ static u32 sample_strobes(int channel_offset, struct sys_info *sysinfo) { u32 reg32, addr; int i; MCHBAR32(C0DRC1 + channel_offset) |= (1 << 6); MCHBAR32(C0DRC1 + channel_offset) &= ~(1 << 6); addr = 0; if (channel_offset != 0) { /* must be dual channel */ if (sysinfo->interleaved == 1) { addr |= (1 << 6); } else { addr = ((u32)MCHBAR8(C0DRB3)) << 25; } } for (i = 0; i < 28; i++) { read32((void *)addr); read32((void *)(addr + 0x80)); } reg32 = MCHBAR32(RCVENMT); if (channel_offset == 0) { reg32 = reg32 << 2; } /** * [19] = 1: all bits are high * [18] = 1: all bits are low * [19:18] = 00: bits are mixed high, low */ return reg32; }
static void pineview_setup_bars(void) { u8 reg8; u16 reg16; u32 reg32; /* Setting up Southbridge. In the northbridge code. */ printk(BIOS_DEBUG, "Setting up static southbridge registers..."); pci_write_config32(LPC, RCBA, (uintptr_t)DEFAULT_RCBA | 1); pci_write_config32(LPC, PMBASE, DEFAULT_PMBASE | 1); pci_write_config8(LPC, 0x44 /* ACPI_CNTL */ , 0x80); /* Enable ACPI */ pci_write_config32(LPC, GPIOBASE, DEFAULT_GPIOBASE | 1); pci_write_config8(LPC, 0x4c /* GC */ , 0x10); /* Enable GPIOs */ pci_write_config32(LPC, 0x88, 0x007c0291); pci_write_config32(PCI_DEV(0, 0x1e, 0), 0x1b, 0x20); printk(BIOS_DEBUG, " done.\n"); printk(BIOS_DEBUG, "Disabling Watchdog reboot..."); RCBA32(GCS) = RCBA32(GCS) | (1 << 5); /* No reset */ outw((1 << 11), DEFAULT_PMBASE | 0x60 | 0x08); /* halt timer */ printk(BIOS_DEBUG, " done.\n"); /* Enable upper 128bytes of CMOS */ RCBA32(0x3400) = (1 << 2); printk(BIOS_DEBUG, "Setting up static northbridge registers..."); pci_write_config8(D0F0, 0x8, 0x69); /* Set up all hardcoded northbridge BARs */ pci_write_config32(D0F0, EPBAR, DEFAULT_EPBAR | 1); pci_write_config32(D0F0, MCHBAR, (uintptr_t)DEFAULT_MCHBAR | 1); pci_write_config32(D0F0, DMIBAR, (uintptr_t)DEFAULT_DMIBAR | 1); pci_write_config32(D0F0, PMIOBAR, (uintptr_t)0x400 | 1); reg32 = MCHBAR32(0x30); MCHBAR32(0x30) = 0x21800; DMIBAR32(0x2c) = 0x86000040; pci_write_config8(D0F0, DEVEN, 0x09); pci_write_config32(PCI_DEV(0, 0x1e, 0), 0x18, 0x00020200); pci_write_config32(PCI_DEV(0, 0x1e, 0), 0x18, 0x00000000); reg8 = pci_read_config8(D0F0, 0xe5); // 0x10 reg16 = pci_read_config16(PCI_DEV(0, 0x02, 0), 0x0); // 0x8086 reg16 = pci_read_config16(D0F0, GGC); pci_write_config16(D0F0, GGC, 0x130); reg16 = pci_read_config16(D0F0, GGC); pci_write_config16(D0F0, GGC, 0x130); MCHBAR8(0xb08) = 0x20; reg8 = pci_read_config8(D0F0, 0xe6); // 0x11 reg16 = MCHBAR16(0xc8c); MCHBAR16(0xc8c) = reg16 | 0x0200; reg8 = MCHBAR8(0xc8c); MCHBAR8(0xc8c) = reg8; MCHBAR8(0xc8c) = 0x12; pci_write_config8(PCI_DEV(0, 0x02, 0), 0x62, 0x02); pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe8, 0x8000); MCHBAR32(0x3004) = 0x48000000; MCHBAR32(0x3008) = 0xfffffe00; MCHBAR32(0xb08) = 0x06028220; MCHBAR32(0xff4) = 0xc6db8b5f; MCHBAR16(0xff8) = 0x024f; // PLL Voltage controlled oscillator //MCHBAR8(0xc38) = 0x04; pci_write_config16(PCI_DEV(0, 0x02, 0), 0xcc, 0x014d); reg32 = MCHBAR32(0x40); MCHBAR32(0x40) = 0x0; reg32 = MCHBAR32(0x40); MCHBAR32(0x40) = 0x8; pci_write_config8(LPC, 0x8, 0x1d); pci_write_config8(LPC, 0x8, 0x0); RCBA32(0x3410) = 0x00020465; RCBA32(0x88) = 0x0011d000; RCBA32(0x1fc) = 0x60f; RCBA32(0x1f4) = 0x86000040; RCBA32(0x214) = 0x10030509; RCBA32(0x218) = 0x00020504; RCBA32(0x220) = 0xc5; RCBA32(0x3430) = 0x1; RCBA32(0x2027) = 0x38f6a70d; RCBA16(0x3e08) = 0x0080; RCBA16(0x3e48) = 0x0080; RCBA32(0x3e0e) = 0x00000080; RCBA32(0x3e4e) = 0x00000080; RCBA32(0x2034) = 0xb24577cc; RCBA32(0x1c) = 0x03128010; RCBA32(0x2010) = 0x400; RCBA32(0x3400) = 0x4; RCBA32(0x2080) = 0x18006007; RCBA32(0x20a0) = 0x18006007; RCBA32(0x20c0) = 0x18006007; RCBA32(0x20e0) = 0x18006007; pci_write_config32(PCI_DEV(0, 0x1d, 0), 0xca, 0x1); pci_write_config32(PCI_DEV(0, 0x1d, 1), 0xca, 0x1); pci_write_config32(PCI_DEV(0, 0x1d, 2), 0xca, 0x1); pci_write_config32(PCI_DEV(0, 0x1d, 3), 0xca, 0x1); RCBA32(0x3100) = 0x42210; RCBA32(0x3108) = 0x10004321; RCBA32(0x310c) = 0x00214321; RCBA32(0x3110) = 0x1; RCBA32(0x3140) = 0x01460132; RCBA32(0x3142) = 0x02370146; RCBA32(0x3144) = 0x32010237; RCBA32(0x3146) = 0x01463201; RCBA32(0x3148) = 0x146; /* Set C0000-FFFFF to access RAM on both reads and writes */ pci_write_config8(D0F0, PAM0, 0x30); pci_write_config8(D0F0, PAM1, 0x33); pci_write_config8(D0F0, PAM2, 0x33); pci_write_config8(D0F0, PAM3, 0x33); pci_write_config8(D0F0, PAM4, 0x33); pci_write_config8(D0F0, PAM5, 0x33); pci_write_config8(D0F0, PAM6, 0x33); pci_write_config32(D0F0, SKPAD, SKPAD_NORMAL_BOOT_MAGIC); printk(BIOS_DEBUG, " done.\n"); }
static void init_freq_scaling(const gmch_gfx_t sku, const int low_power_mode) { int i; MCHBAR32(0x11cc) = (MCHBAR32(0x11cc) & ~(0x1f)) | 0x17; switch (sku) { case GMCH_GM45: case GMCH_GE45: case GMCH_GS45: case GMCH_GM47: case GMCH_GM49: break; default: /* No more to be done for the others. */ return; } static const u32 voltage_mask = (0x1f << 24) | (0x1f << 16) | (0x1f << 8) | 0x1f; MCHBAR32(0x1120) = (MCHBAR32(0x1120) & ~voltage_mask) | 0x10111213; MCHBAR32(0x1124) = (MCHBAR32(0x1124) & ~voltage_mask) | 0x14151617; MCHBAR32(0x1128) = (MCHBAR32(0x1128) & ~voltage_mask) | 0x18191a1b; MCHBAR32(0x112c) = (MCHBAR32(0x112c) & ~voltage_mask) | 0x1c1d1e1f; MCHBAR32(0x1130) = (MCHBAR32(0x1130) & ~voltage_mask) | 0x00010203; MCHBAR32(0x1134) = (MCHBAR32(0x1134) & ~voltage_mask) | 0x04050607; MCHBAR32(0x1138) = (MCHBAR32(0x1138) & ~voltage_mask) | 0x08090a0b; MCHBAR32(0x113c) = (MCHBAR32(0x113c) & ~voltage_mask) | 0x0c0d0e0f; /* Program frequencies. */ static const u32 frequencies_from_sku_vco[][4][8] = { /* GM45/GE45/GS45_perf */ { /* VCO 2666 */ { 0xcd, 0xbc, 0x9b, 0x8a, 0x79, 0x78, 0x67, 0x56 }, /* VCO 3200 */ { 0xcd, 0xac, 0x9b, 0x8a, 0x89, 0x78, 0x67, 0x56 }, /* VCO 4000 */ { 0xac, 0x9b, 0x9a, 0x89, 0x89, 0x68, 0x56, 0x45 }, /* VCO 5333 */ { 0xab, 0x9a, 0x79, 0x68, 0x57, 0x56, 0x45, 0x34 }, }, /* GS45_low_power */ { /* VCO 2666 */ { 0xcd, 0x8a }, /* VCO 3200 */ { 0xcd, 0x89 }, /* VCO 4000 */ { 0xac, 0x89 }, /* VCO 5333 */ { 0xab, 0x68 }, }, /* GM47 */ { /* VCO 2666 */ { 0xcd, 0xcd, 0xbc, 0x9b, 0x79, 0x78, 0x67, 0x56 }, /* VCO 3200 */ { 0xde, 0xcd, 0xac, 0x9b, 0x89, 0x78, 0x67, 0x56 }, /* VCO 4000 */ { 0xcd, 0xac, 0x9b, 0x9a, 0x89, 0x68, 0x56, 0x45 }, /* VCO 5333 */ { 0xac, 0xab, 0x9a, 0x79, 0x68, 0x56, 0x45, 0x34 }, }, /* GM49 */ { /* VCO 2666 */ { }, /* VCO 3200 */ { 0xef, 0xde, 0xcd, 0xac, 0x89, 0x78, 0x67, 0x56 }, /* VCO 4000 */ { 0xef, 0xde, 0xac, 0x9b, 0x89, 0x68, 0x56, 0x45 }, /* VCO 5333 */ { 0xce, 0xbd, 0xab, 0x9a, 0x68, 0x57, 0x45, 0x34 }, }}; const int sku_index = sku_freq_index(sku, low_power_mode); const int vco_index = raminit_read_vco_index(); const int reg_limit = low_power_mode ? 1 : 4; if (sku == GMCH_GM49) MCHBAR8(0x1110+3) = 0x1b; else MCHBAR8(0x1110+3) = 0x17; MCHBAR8(0x1110+1) = 0x17; if (!low_power_mode) { MCHBAR8(0x1114+3) = 0x17; MCHBAR8(0x1114+1) = 0x17; MCHBAR8(0x1118+3) = 0x17; MCHBAR8(0x1118+1) = 0x17; MCHBAR8(0x111c+3) = 0x17; MCHBAR8(0x111c+1) = 0x17; } for (i = 0; i < reg_limit; ++i) { const int mchbar = 0x1110 + (i * 4); MCHBAR8(mchbar + 2) = frequencies_from_sku_vco [sku_index][vco_index][i * 2 + 0]; MCHBAR8(mchbar + 0) = frequencies_from_sku_vco [sku_index][vco_index][i * 2 + 1]; } if (low_power_mode) { MCHBAR16(0x1190) = (MCHBAR16(0x1190) & ~((7 << 8) | (7 << 4) | 7)) | (1 << 8) | (1 << 4) | 1; } else { MCHBAR16(0x1190) = (MCHBAR16(0x1190) & ~((7 << 8) | (7 << 4))) | 7; if (sku == GMCH_GS45) /* performance mode */ MCHBAR32(0x0ffc) &= ~(1 << 31); } MCHBAR16(0x0fc0) |= (1 << 11); MCHBAR16(0x11b8) = 0x333c; MCHBAR16(0x11c0 + 2) = 0x0303; MCHBAR32(0x11c4) = 0x0a030a03; MCHBAR16(0x1100) = (MCHBAR16(0x1100) & ~(0x1f << 8)) | (3 << 8); MCHBAR16(0x11b8 + 2) = 0x4000; }
void init_pm(const sysinfo_t *const sysinfo) { const stepping_t stepping = sysinfo->stepping; const fsb_clock_t fsb = sysinfo->selected_timings.fsb_clock; const mem_clock_t memclk = sysinfo->selected_timings.mem_clock; MCHBAR16(0xc14) = 0; MCHBAR16(0xc20) = 0; MCHBAR32(0xfc0) = 0x001f00fd; MCHBAR32(0xfc0) |= 3 << 25; MCHBAR32(0xfc0) |= 1 << 11; MCHBAR8(0xfb0) = 3; MCHBAR8(0xf10) |= 1 << 1; if (fsb == FSB_CLOCK_667MHz) { MCHBAR16(0xc3a) = 0xea6; MCHBAR8(0xc16) = (MCHBAR8(0xc16) & 0x80) | 0x0e; } else if (fsb == FSB_CLOCK_800MHz) { MCHBAR16(0xc3a) = 0x1194; MCHBAR8(0xc16) = (MCHBAR8(0xc16) & 0x80) | 0x10; } else if (fsb == FSB_CLOCK_1067MHz) { MCHBAR16(0xc3a) = 0x1777; MCHBAR8(0xc16) = (MCHBAR8(0xc16) & 0x80) | 0x15; } MCHBAR8(0xfb8) = 3; if (fsb == FSB_CLOCK_667MHz) MCHBAR16(0xc38) = 0x0ea6; else if (fsb == FSB_CLOCK_800MHz) MCHBAR16(0xc38) = 0x1194; else if (fsb == FSB_CLOCK_1067MHz) MCHBAR16(0xc38) = 0x1777; MCHBAR8(0xf10) |= 1 << 5; MCHBAR16(0xc16) |= 3 << 12; MCHBAR32(0xf60) = 0x01030419; if (fsb == FSB_CLOCK_667MHz) { MCHBAR32(0xf00) = 0x00000600; MCHBAR32(0xf04) = 0x00001d80; } else if (fsb == FSB_CLOCK_800MHz) { MCHBAR32(0xf00) = 0x00000700; MCHBAR32(0xf04) = 0x00002380; } else if (fsb == FSB_CLOCK_1067MHz) { MCHBAR32(0xf00) = 0x00000900; MCHBAR32(0xf04) = 0x00002e80; } MCHBAR16(0xf08) = 0x730f; if (fsb == FSB_CLOCK_667MHz) MCHBAR16(0xf0c) = 0x0b96; else if (fsb == FSB_CLOCK_800MHz) MCHBAR16(0xf0c) = 0x0c99; else if (fsb == FSB_CLOCK_1067MHz) MCHBAR16(0xf0c) = 0x10a4; MCHBAR32(0xf80) |= 1 << 31; MCHBAR32(0x40) = (MCHBAR32(0x40) & ~(0x3f << 24)) | (sysinfo->cores == 4) ? (1 << 24) : 0; MCHBAR32(0x40) &= ~(1 << 19); MCHBAR32(0x40) |= 1 << 13; MCHBAR32(0x40) |= 1 << 21; MCHBAR32(0x40) |= 1 << 9; if (stepping > STEPPING_B1) { if (fsb != FSB_CLOCK_1067MHz) { MCHBAR32(0x70) |= 1 << 30; } else { MCHBAR32(0x70) &= ~(1 << 30); } } if (stepping < STEPPING_B1) MCHBAR32(0x70) |= 1 << 29; else MCHBAR32(0x70) &= ~(1 << 29); if (stepping > STEPPING_B1) { MCHBAR32(0x70) |= 1 << 28; MCHBAR32(0x70) |= 1 << 25; } if (stepping > STEPPING_B0) { if (fsb != FSB_CLOCK_667MHz) MCHBAR32(0x70) = (MCHBAR32(0x70) & ~(3<<21)) | (1 << 21); else MCHBAR32(0x70) = (MCHBAR32(0x70) & ~(3<<21)); } if (stepping > STEPPING_B2) MCHBAR32(0x44) |= 1 << 30; MCHBAR32(0x44) |= 1 << 31; if (sysinfo->cores == 2) MCHBAR32(0x44) |= 1 << 26; MCHBAR32(0x44) |= 1 << 21; MCHBAR32(0x44) = (MCHBAR32(0x44) & ~(3 << 24)) | (2 << 24); MCHBAR32(0x44) |= 1 << 5; MCHBAR32(0x44) |= 1 << 4; MCHBAR32(0x90) = (MCHBAR32(0x90) & ~7) | 4; MCHBAR32(0x94) |= 1 << 29; MCHBAR32(0x94) |= 1 << 11; if (stepping < STEPPING_B0) MCHBAR32(0x94) = (MCHBAR32(0x94) & ~(3 << 19)) | (2 << 19); if (stepping > STEPPING_B2) MCHBAR32(0x94) |= 1 << 21; MCHBAR8(0xb00) &= ~1; MCHBAR8(0xb00) |= 1 << 7; if (fsb != FSB_CLOCK_1067MHz) MCHBAR8(0x75) |= 1 << 6; else MCHBAR8(0x75) &= 1 << 1; MCHBAR8(0x77) |= 3; if (stepping >= STEPPING_B1) MCHBAR8(0x77) |= 1 << 2; if (stepping > STEPPING_B2) MCHBAR8(0x77) |= 1 << 4; if (MCHBAR16(0x90) & 0x100) MCHBAR8(0x90) &= ~(7 << 4); if (stepping >= STEPPING_B0) MCHBAR8(0xd0) |= 1 << 1; MCHBAR8(0xbd8) |= 3 << 2; if (stepping >= STEPPING_B3) MCHBAR32(0x70) |= 1 << 0; MCHBAR32(0x70) |= 1 << 3; if (stepping >= STEPPING_B0) MCHBAR32(0x70) &= ~(1 << 16); else MCHBAR32(0x70) |= 1 << 16; if (stepping >= STEPPING_B3) MCHBAR8(0xc14) |= 1 << 1; if (stepping >= STEPPING_B1) MCHBAR16(0xffc) = (MCHBAR16(0xffc) & ~0x7ff) | 0x7c0; MCHBAR16(0x48) = (MCHBAR16(0x48) & ~(0xff << 2)) | (0xaa << 2); if (stepping == STEPPING_CONVERSION_A1) { MCHBAR16(0x40) |= 1 << 12; MCHBAR32(0x94) |= 3 << 22; } const int cpu_supports_super_lfm = rdmsr(0xee).lo & (1 << 27); if ((stepping >= STEPPING_B0) && cpu_supports_super_lfm) { MCHBAR16(CLKCFG_MCHBAR) &= ~(1 << 7); MCHBAR16(CLKCFG_MCHBAR) |= 1 << 14; } else { MCHBAR16(CLKCFG_MCHBAR) &= ~(1 << 14); MCHBAR16(CLKCFG_MCHBAR) |= 1 << 7; MCHBAR32(0x44) &= ~(1 << 31); /* Was set above. */ } if ((sysinfo->gfx_type != GMCH_PM45) && (sysinfo->gfx_type != GMCH_UNKNOWN)) init_freq_scaling(sysinfo->gfx_type, sysinfo->gs45_low_power_mode); /* This has to be the last write to CLKCFG. */ if ((fsb == FSB_CLOCK_1067MHz) && (memclk == MEM_CLOCK_667MT)) MCHBAR32(CLKCFG_MCHBAR) &= ~(1 << 17); }
/* The PEG settings have to be set before ASPM is setup on DMI. */ static void enable_igd(const sysinfo_t *const sysinfo, const int no_peg) { const device_t mch_dev = PCI_DEV(0, 0, 0); const device_t peg_dev = PCI_DEV(0, 1, 0); const device_t igd_dev = PCI_DEV(0, 2, 0); u16 reg16; u32 reg32; printk(BIOS_DEBUG, "Enabling IGD.\n"); /* HSync/VSync */ MCHBAR8(0xbd0 + 3) = 0x5a; MCHBAR8(0xbd0 + 4) = 0x5a; static const u16 display_clock_from_f0_and_vco[][4] = { /* VCO 2666 VCO 3200 VCO 4000 VCO 5333 */ { 222, 228, 222, 222, }, { 333, 320, 333, 333, }, }; const int f0_12 = (pci_read_config16(igd_dev, 0xf0) >> 12) & 1; const int vco = raminit_read_vco_index(); reg16 = pci_read_config16(igd_dev, 0xcc); reg16 &= 0xfc00; reg16 |= display_clock_from_f0_and_vco[f0_12][vco]; pci_write_config16(igd_dev, 0xcc, reg16); /* Graphics Stolen Memory: 2MB GTT (0x0300) when VT-d disabled, 2MB GTT + 2MB shadow GTT (0x0b00) else. */ /* Graphics Mode Select: 32MB framebuffer (0x0050) */ /* TODO: We could switch to 64MB (0x0070), config flag? */ const u32 capid = pci_read_config32(mch_dev, D0F0_CAPID0 + 4); reg16 = pci_read_config16(mch_dev, D0F0_GGC); reg16 &= 0xf00f; reg16 |= 0x0350; if (capid & (1 << (48 - 32))) reg16 |= 0x0800; pci_write_config16(mch_dev, D0F0_GGC, reg16); if ((sysinfo->gfx_type != GMCH_GL40) && (sysinfo->gfx_type != GMCH_GS40) && (sysinfo->gfx_type != GMCH_GL43)) { const u32 deven = pci_read_config32(mch_dev, D0F0_DEVEN); if (!(deven & 2)) /* Enable PEG temporarily to access D1:F0. */ pci_write_config32(mch_dev, D0F0_DEVEN, deven | 2); /* Some IGD related settings on D1:F0. */ reg16 = pci_read_config16(peg_dev, 0xa08); reg16 &= ~(1 << 15); pci_write_config16(peg_dev, 0xa08, reg16); reg16 = pci_read_config16(peg_dev, 0xa84); reg16 |= (1 << 8); pci_write_config16(peg_dev, 0xa84, reg16); reg16 = pci_read_config16(peg_dev, 0xb00); reg16 |= (3 << 8) | (7 << 3); pci_write_config16(peg_dev, 0xb00, reg16); reg32 = pci_read_config32(peg_dev, 0xb14); reg32 &= ~(1 << 17); pci_write_config32(peg_dev, 0xb14, reg32); if (!(deven & 2) || no_peg) { /* Disable PEG finally. */ printk(BIOS_DEBUG, "Finally disabling " "PEG in favor of IGD.\n"); MCHBAR8(0xc14) |= (1 << 5) | (1 << 0); reg32 = pci_read_config32(peg_dev, 0x200); reg32 |= (1 << 18); pci_write_config32(peg_dev, 0x200, reg32); reg16 = pci_read_config16(peg_dev, 0x224); reg16 |= (1 << 8); pci_write_config16(peg_dev, 0x224, reg16); reg32 = pci_read_config32(peg_dev, 0x200); reg32 &= ~(1 << 18); pci_write_config32(peg_dev, 0x200, reg32); while (pci_read_config32(peg_dev, 0x214) & 0x000f0000); pci_write_config32(mch_dev, D0F0_DEVEN, deven & ~2); MCHBAR8(0xc14) &= ~((1 << 5) | (1 << 0)); } } }
/* The PEG settings have to be set before ASPM is setup on DMI. */ static void enable_igd(const sysinfo_t *const sysinfo, const int no_peg) { const pci_devfn_t mch_dev = PCI_DEV(0, 0, 0); const pci_devfn_t peg_dev = PCI_DEV(0, 1, 0); const pci_devfn_t igd_dev = PCI_DEV(0, 2, 0); u16 reg16; u32 reg32; printk(BIOS_DEBUG, "Enabling IGD.\n"); /* HSync/VSync */ MCHBAR8(0xbd0 + 3) = 0x5a; MCHBAR8(0xbd0 + 4) = 0x5a; static const u16 display_clock_from_f0_and_vco[][4] = { /* VCO 2666 VCO 3200 VCO 4000 VCO 5333 */ { 222, 228, 222, 222, }, { 333, 320, 333, 333, }, }; const int f0_12 = (pci_read_config16(igd_dev, 0xf0) >> 12) & 1; const int vco = raminit_read_vco_index(); reg16 = pci_read_config16(igd_dev, 0xcc); reg16 &= 0xfc00; reg16 |= display_clock_from_f0_and_vco[f0_12][vco]; pci_write_config16(igd_dev, 0xcc, reg16); reg16 = pci_read_config16(mch_dev, D0F0_GGC); reg16 &= 0xf00f; reg16 |= sysinfo->ggc; pci_write_config16(mch_dev, D0F0_GGC, reg16); if ((sysinfo->gfx_type != GMCH_GL40) && (sysinfo->gfx_type != GMCH_GS40) && (sysinfo->gfx_type != GMCH_GL43)) { const u32 deven = pci_read_config32(mch_dev, D0F0_DEVEN); if (!(deven & 2)) /* Enable PEG temporarily to access D1:F0. */ pci_write_config32(mch_dev, D0F0_DEVEN, deven | 2); /* Some IGD related settings on D1:F0. */ reg16 = pci_read_config16(peg_dev, 0xa08); reg16 &= ~(1 << 15); pci_write_config16(peg_dev, 0xa08, reg16); reg16 = pci_read_config16(peg_dev, 0xa84); reg16 |= (1 << 8); pci_write_config16(peg_dev, 0xa84, reg16); reg16 = pci_read_config16(peg_dev, 0xb00); reg16 |= (3 << 8) | (7 << 3); pci_write_config16(peg_dev, 0xb00, reg16); reg32 = pci_read_config32(peg_dev, 0xb14); reg32 &= ~(1 << 17); pci_write_config32(peg_dev, 0xb14, reg32); if (!(deven & 2) || no_peg) { /* Disable PEG finally. */ printk(BIOS_DEBUG, "Finally disabling " "PEG in favor of IGD.\n"); MCHBAR8(0xc14) |= (1 << 5) | (1 << 0); reg32 = pci_read_config32(peg_dev, 0x200); reg32 |= (1 << 18); pci_write_config32(peg_dev, 0x200, reg32); reg16 = pci_read_config16(peg_dev, 0x224); reg16 |= (1 << 8); pci_write_config16(peg_dev, 0x224, reg16); reg32 = pci_read_config32(peg_dev, 0x200); reg32 &= ~(1 << 18); pci_write_config32(peg_dev, 0x200, reg32); while (pci_read_config32(peg_dev, 0x214) & 0x000f0000); pci_write_config32(mch_dev, D0F0_DEVEN, deven & ~2); MCHBAR8(0xc14) &= ~((1 << 5) | (1 << 0)); } } }