User:Greasemonkey/Intel GenX: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
Content added Content deleted
(→‎Somewhat complex version: added a note on VGA/DVI/HDMI)
(references are safer than replicating the manuals. also, updated VGA disabling method.)
Line 9: Line 9:
==Systems tested==
==Systems tested==
* Compaq CQ60-210TU: GM45 DevCTG (GMA 4500MHD; Cantiga) with 1366x768 LVDS panel
* Compaq CQ60-210TU: GM45 DevCTG (GMA 4500MHD; Cantiga) with 1366x768 LVDS panel
* HP Pavilion dv6-6c35tx: i5-2450M DevSNB (HD 3000) with 1366x768 LVDS panel


Anything that doesn't exactly match the specs listed here may differ. Approach at your own risk.
Anything that doesn't exactly match the specs listed here may differ. Approach at your own risk.


==Finding the GPU==
==Finding the GPU==
Tested on: GM45 1366x768 CQ60-210TU.
Tested on:
* GM45 1366x768 CQ60-210TU
* HD3000 1366x768 dv6-6c35tx


Probe the [[PCI]] bus. It should be located at Bus 0, Device 2, Function 0.
Probe the [[PCI]] bus. It should be located at Bus 0, Device 2, Function 0.
Line 30: Line 33:


==Getting a display==
==Getting a display==
Tested on: GM45 1366x768 CQ60-210TU.
Tested on:
* GM45 1366x768 CQ60-210TU


===Proper mode switch methodology===
===Somewhat complex version===
Consult the appropriate section of your manual. It tends to be in Volume 3 at the start of one of the parts.
This code assumes that you have a 1366x768 LVDS panel on Display B. In other words, you have a laptop. However, it's probably where you want to start if you want to get this GPU working over VGA, DVI and/or HDMI.


* G45: Vol3, pg 28
Valid monitor timings are a must.
* SNB: Vol3.2, pg 8


===Simplified version===
* Disable VGA compatibility mode by setting bit 31 of VGACNTR.
This assumes that the BIOS configured the LVDS panel properly and/or in a way that we can just take its values and run with them. If it does, you can avoid an awful lot of pain. It also assumes that it's on the default setup of Pipe B, Display B.
* Disable Display A and B by clearing bit 31 of DSPACNTR and DSPBCNTR.
* Disable Pipe A and B by clearing bit 31 of PIPEACONF and PIPEBCONF. (Don't forget to applaud Intel for their naming consistency!)
* Wait for Pipe A and B to stop by reading bit 30 of PIPEACONF and PIPEBCONF and ensuring that they are both 0.
* There's a few steps explained in the G45 manual, Vol 3, pg29...


This code works on a GM45. It does not quite work on an HD3000, although the VGA compatibility mode is successfully disabled.
Basically, you disable the cursor and overlay planes, force the display on and off while triggering display flips, then restore the cursor and overlay planes to what they were before you messed with them.


This also assumes that your panel is less than 2048 pixels wide, but that can be fixed by adding a few "if" statements. However, the 1366x768 assumption is dropped from this version.
Here's the C code for it (XXX: confirm - the manual says to use display/pipe A, are we supposed to use that for display B?):

If you want a non-native resolution, enable the panelfitter and adjust PIPEBSRC to suit. Note, the panelfitter does love to blur everything.

Here's how you get from VGA text mode to native 32bpp full-res BGRX mode the easy way, and by easy we mean this is very much empirical, about as risky, and assumes the BIOS doesn't have stupid bugs in it - but may be more reliable than the version above:


<pre>
<pre>
// Set VGA screen off
uint32_t pbconf_tmp = genx_reg32[PIPEBCONF] & ~(3<<18);
outportb(0x3C4, 0x01);
genx_reg32[PIPEBCONF] &= ~(3<<18);
outportb(0x3C5, inportb(0x3C5)|(1<<5));
genx_reg32[DSPBCNTR] |= (1<<31);

genx_reg32[DSPBSURF] = 0;
// Wait at least 100us (Gen4.5 only needs 20us, but Gen6 needs 100us)
genx_reg32[DSPBCNTR] &= ~(1<<31);
wait_us(100);
genx_reg32[DSPBSURF] = 0;

genx_reg32[PIPEBCONF] = (genx_reg32[PIPEBCONF] & ~(3<<18)) | pbconf_tmp;
// Disable VGA
// WARNING: Gen5 changes the location of this register!
// If you intend to support pre-Gen5 and Gen5+,
// select the right location for the architecture version.
genx_reg32[VGACNTRL] |= (1<<31);

genx_reg32[DSPBCNTR] &= ~(1<<31); // Disable Display B
genx_reg32[PIPEBCONF] &= ~(1<<31); // Disable Pipe B
while((genx_reg32[PIPEBCONF] & (1<<30))) {} // Wait for Pipe B to stop

// Set PIPEBSRC to screen resolution
uint32_t vis_w = (genx_reg32[HTOTAL_B] & 0xFFFF)+1;
uint32_t vis_h = (genx_reg32[VTOTAL_B] & 0xFFFF)+1;
genx_reg32[PIPEBSRC] = ((vis_w-1)<<16)|(vis_h-1);

// XXX: Panelfitter location unknown for DevSNB.
// It mentions a spreadsheet which appears to be publically unavailable.
genx_reg32[PFIT_CONTROL] &= ~(1<<31); // Disable panelfitter
genx_reg32[PIPEBCONF] |= (1<<31); // Enable Pipe B

// Set up Display B and enable
genx_reg32[DSPBLINOFF] = 0x00000000; // linear offset
genx_reg32[DSPBSTRIDE] = 2048*4; // scanline pitch
genx_reg32[DSPBSURF] = 0x00000000; // surface base
genx_reg32[DSPBCNTR] = (genx_reg32[DSPBCNTR] & ~(15<<26)) | (6<<26); // bit depth select, 6 = 32bpp BGRX
genx_reg32[DSPBCNTR] = (genx_reg32[DSPBCNTR] & ~(3<<20)) | (0<<20); // pixel multiply
genx_reg32[DSPBCNTR] = (genx_reg32[DSPBCNTR] & ~(1<<10)) | (0<<10); // tiling flag
genx_reg32[DSPBCNTR] |= (1<<31); // enable
</pre>
</pre>


With the above config, your framebuffer should be located at the start of the AGP aperture, and be 2048 32bpp BGRX pixels wide internally.
* Disable write protection by setting the upper 16 bits of PP_CONTROL to 0xABCD.

* If you need to program the DPLL, now would be a good time. You probably don't need (or even want) to, but here's the steps:
===Setting monitor timings===
** Disable the DPLL by clearing DPLLB_CTRL bit 31.
** Program the DPLL.
** Enable the DPLL by setting DPLLB_CTRL bit 31.
** Wait at least 150us via some method.
* Set the monitor timings via the (H|V)(TOTAL|BLANK|SYNC)_B and PIPEBSRC registers...


These timings work on the CQ60-210TU:
If you need to set the monitor timings, this code should be useful for a start. These timings work on the CQ60-210TU's surprisingly tolerant LVDS panel:


<pre>
<pre>
Line 89: Line 119:
genx_reg32[VSYNC_B] = ((vis_h+vis_sblank_h+vis_sync_h-1)<<16) | (vis_h+vis_sblank_h-1);
genx_reg32[VSYNC_B] = ((vis_h+vis_sblank_h+vis_sync_h-1)<<16) | (vis_h+vis_sblank_h-1);
genx_reg32[PIPEBSRC] = ((vis_stretch_w-1)<<16)|(vis_stretch_h-1);
genx_reg32[PIPEBSRC] = ((vis_stretch_w-1)<<16)|(vis_stretch_h-1);
</pre>

It should still work if you only set PIPEBSRC, but if that's all you're setting, you should probably read the low 16 bits of HTOTAL_B and VTOTAL_B and add 1 to get the "native" resolution, assuming the BIOS sets that up correctly.

* Disable the panelfitter by clearing bit 31 of PFIT_CONTROL. This step is important, unless of course you like blurry images!
* Enable write protection by setting the upper 16 bits of PP_CONTROL to 0x0000.
* Enable Pipe B by setting bit 31 of PIPEBCONF.
* Set up Display B and enable it...

This works well for 1366x768, but should also work just as well for 1920x1080 if you have one of those monitors (but you should look for proper 1920x1080 timing):

<pre>
genx_reg32[DSPBLINOFF] = 0x00000000; // linear offset
genx_reg32[DSPBSTRIDE] = 2048*4; // scanline pitch
genx_reg32[DSPBSURF] = 0x00000000; // surface base
genx_reg32[DSPBCNTR] = (genx_reg32[DSPBCNTR] & ~(15<<26)) | (6<<26); // bit depth select, 6 = 32bpp BGRX
genx_reg32[DSPBCNTR] = (genx_reg32[DSPBCNTR] & ~(3<<20)) | (0<<20); // pixel multiply
genx_reg32[DSPBCNTR] = (genx_reg32[DSPBCNTR] & ~(1<<10)) | (0<<10); // tiling flag
genx_reg32[DSPBCNTR] |= (1<<31); // enable
</pre>

And that's it.

With the above config, your framebuffer should be located at the start of the AGP aperture, and be 2048 32bpp BGRX pixels wide internally.

===Simplified version===
This assumes that the BIOS configured the LVDS panel properly and/or in a way that we can just take its values and run with them. If it does, you can avoid an awful lot of pain.

This also assumes that your panel is less than 2048 pixels wide, but that can be fixed by adding a few "if" statements. However, the 1366x768 assumption is dropped from this version.

If you want a non-native resolution, enable the panelfitter and adjust PIPEBSRC to suit. Note, the panelfitter does love to blur everything.

Here's how you get from VGA text mode to native 32bpp full-res BGRX mode the easy way, and by easy we mean this is very much empirical, about as risky, and assumes the BIOS doesn't have stupid bugs in it - but may be more reliable than the version above:

<pre>
genx_reg32[VGACNTR] |= (1<<31); // Disable VGA
genx_reg32[DSPBCNTR] &= ~(1<<31); // Disable Display B
genx_reg32[PIPEBCONF] &= ~(1<<31); // Disable Pipe B
while((genx_reg32[PIPEBCONF] & (1<<30))) {} // Wait for Pipe B to stop

// Set PIPEBSRC to screen resolution
uint32_t vis_w = (genx_reg32[HTOTAL_B] & 0xFFFF)+1;
uint32_t vis_h = (genx_reg32[VTOTAL_B] & 0xFFFF)+1;
genx_reg32[PIPEBSRC] = ((vis_w-1)<<16)|(vis_h-1);

genx_reg32[PFIT_CONTROL] &= ~(1<<31); // Disable panelfitter
genx_reg32[PIPEBCONF] |= (1<<31); // Enable Pipe B

// Set up Display B and enable
genx_reg32[DSPBLINOFF] = 0x00000000; // linear offset
genx_reg32[DSPBSTRIDE] = 2048*4; // scanline pitch
genx_reg32[DSPBSURF] = 0x00000000; // surface base
genx_reg32[DSPBCNTR] = (genx_reg32[DSPBCNTR] & ~(15<<26)) | (6<<26); // bit depth select, 6 = 32bpp BGRX
genx_reg32[DSPBCNTR] = (genx_reg32[DSPBCNTR] & ~(3<<20)) | (0<<20); // pixel multiply
genx_reg32[DSPBCNTR] = (genx_reg32[DSPBCNTR] & ~(1<<10)) | (0<<10); // tiling flag
genx_reg32[DSPBCNTR] |= (1<<31); // enable
</pre>
</pre>



Revision as of 03:44, 28 May 2015

The Intel GenX GPU architecture (probably) covers the Intel HD and the later Intel GMA series of GPUs, starting with the Intel 965. Later revisions tend to add and remove and readd features and instructions over time, but otherwise remain fairly similar.

This will cover Gen4 (963, 965, G35) and later. Earlier GPUs do not have open documentation and are apparently very different.

As there is an awful lot to document, this is probably a better place for tutorials.

This page is a stub.
You can help the wiki by accurately adding more contents to it.

Systems tested

  • Compaq CQ60-210TU: GM45 DevCTG (GMA 4500MHD; Cantiga) with 1366x768 LVDS panel
  • HP Pavilion dv6-6c35tx: i5-2450M DevSNB (HD 3000) with 1366x768 LVDS panel

Anything that doesn't exactly match the specs listed here may differ. Approach at your own risk.

Finding the GPU

Tested on:

  • GM45 1366x768 CQ60-210TU
  • HD3000 1366x768 dv6-6c35tx

Probe the PCI bus. It should be located at Bus 0, Device 2, Function 0.

GMAs tend to be advertised as at least two functions, so you may wish to check Function 1 as well. HDs tend to be advertised as just one.

Either way, there appears to be no difference between using BAR0 of Function 0 and BAR0 of Function 1, and only Function 0 gives the initial AGP aperture space information, so you might be able to get away with just using Function 0.

With that said, make sure you check the IDs to ensure that they match hardware that you've actually tested. Different GPUs have different bugs and thus require different workarounds - even when they're within the same family.

Here's the information, assuming you are accessing everything through Function 0:

  • uint64_t @ PCI 0x10: Location of MMIO registers. (XXX: for devices with a Function 1, this appears to do more than just MMIO registers - Function 1 should be able to provide a space with "just" MMIO registers.)
  • uint64_t @ PCI 0x18: Location of AGP stolen memory location.

The 64-bit pointers have the lower 4 bits set to 0x4, so remember to mask it out before you use it, and remember to maintain that mask before writing back.

Getting a display

Tested on:

  • GM45 1366x768 CQ60-210TU

Proper mode switch methodology

Consult the appropriate section of your manual. It tends to be in Volume 3 at the start of one of the parts.

  • G45: Vol3, pg 28
  • SNB: Vol3.2, pg 8

Simplified version

This assumes that the BIOS configured the LVDS panel properly and/or in a way that we can just take its values and run with them. If it does, you can avoid an awful lot of pain. It also assumes that it's on the default setup of Pipe B, Display B.

This code works on a GM45. It does not quite work on an HD3000, although the VGA compatibility mode is successfully disabled.

This also assumes that your panel is less than 2048 pixels wide, but that can be fixed by adding a few "if" statements. However, the 1366x768 assumption is dropped from this version.

If you want a non-native resolution, enable the panelfitter and adjust PIPEBSRC to suit. Note, the panelfitter does love to blur everything.

Here's how you get from VGA text mode to native 32bpp full-res BGRX mode the easy way, and by easy we mean this is very much empirical, about as risky, and assumes the BIOS doesn't have stupid bugs in it - but may be more reliable than the version above:

	// Set VGA screen off
	outportb(0x3C4, 0x01);
	outportb(0x3C5, inportb(0x3C5)|(1<<5));

	// Wait at least 100us (Gen4.5 only needs 20us, but Gen6 needs 100us)
	wait_us(100);

	// Disable VGA
	// WARNING: Gen5 changes the location of this register!
	// If you intend to support pre-Gen5 and Gen5+,
	// select the right location for the architecture version.
	genx_reg32[VGACNTRL] |= (1<<31);

	genx_reg32[DSPBCNTR] &= ~(1<<31); // Disable Display B
	genx_reg32[PIPEBCONF] &= ~(1<<31); // Disable Pipe B
	while((genx_reg32[PIPEBCONF] & (1<<30))) {} // Wait for Pipe B to stop

	// Set PIPEBSRC to screen resolution
	uint32_t vis_w = (genx_reg32[HTOTAL_B] & 0xFFFF)+1;
	uint32_t vis_h = (genx_reg32[VTOTAL_B] & 0xFFFF)+1;
	genx_reg32[PIPEBSRC] = ((vis_w-1)<<16)|(vis_h-1);

	// XXX: Panelfitter location unknown for DevSNB.
	// It mentions a spreadsheet which appears to be publically unavailable.
	genx_reg32[PFIT_CONTROL] &= ~(1<<31); // Disable panelfitter
	genx_reg32[PIPEBCONF] |= (1<<31); // Enable Pipe B

	// Set up Display B and enable
	genx_reg32[DSPBLINOFF] = 0x00000000; // linear offset
	genx_reg32[DSPBSTRIDE] = 2048*4; // scanline pitch
	genx_reg32[DSPBSURF] = 0x00000000; // surface base
	genx_reg32[DSPBCNTR] = (genx_reg32[DSPBCNTR] & ~(15<<26)) | (6<<26); // bit depth select, 6 = 32bpp BGRX
	genx_reg32[DSPBCNTR] = (genx_reg32[DSPBCNTR] & ~(3<<20)) | (0<<20); // pixel multiply
	genx_reg32[DSPBCNTR] = (genx_reg32[DSPBCNTR] & ~(1<<10)) | (0<<10); // tiling flag
	genx_reg32[DSPBCNTR] |= (1<<31); // enable

With the above config, your framebuffer should be located at the start of the AGP aperture, and be 2048 32bpp BGRX pixels wide internally.

Setting monitor timings

If you need to set the monitor timings, this code should be useful for a start. These timings work on the CQ60-210TU's surprisingly tolerant LVDS panel:

	uint32_t vis_w = 1366;
	uint32_t vis_stretch_w = vis_w;
	uint32_t vis_sblank_w = 80;
	uint32_t vis_sync_w = 128;
	uint32_t vis_eblank_w = 200;

	uint32_t vis_h = 768;
	uint32_t vis_stretch_h = vis_h;
	uint32_t vis_sblank_h = 3;
	uint32_t vis_sync_h = 5;
	uint32_t vis_eblank_h = 22;

	uint32_t vis_blank_w = vis_sblank_w + vis_sync_w + vis_eblank_w;
	uint32_t vis_blank_h = vis_sblank_h + vis_sync_h + vis_eblank_h;
	genx_reg32[HTOTAL_B] = ((vis_w+vis_blank_w-1)<<16) | (vis_w-1);
	genx_reg32[HBLANK_B] = ((vis_w+vis_blank_w-1)<<16) | (vis_w-1);
	genx_reg32[HSYNC_B] = ((vis_w+vis_sblank_w+vis_sync_w-1)<<16) | (vis_w+vis_sblank_w-1);
	genx_reg32[VTOTAL_B] = ((vis_h+vis_blank_h-1)<<16) | (vis_h-1);
	genx_reg32[VBLANK_B] = ((vis_h+vis_blank_h-1)<<16) | (vis_h-1);
	genx_reg32[VSYNC_B] = ((vis_h+vis_sblank_h+vis_sync_h-1)<<16) | (vis_h+vis_sblank_h-1);
	genx_reg32[PIPEBSRC] = ((vis_stretch_w-1)<<16)|(vis_stretch_h-1);

See Also

Articles

External Links