/* 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)); } } }
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; }
/* 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)); } } }