What is Load Detection and why it is useful
Load detection is a mechanism used to detect connected displays. Basically, when you connect something to the video outputs that thing loads the output (draws current from it), hence the name.
Current displays have a mechanism called DDC, Display Data Channel, which allows the graphics card to retrieve information from it (the EDID, Extended Display Identification Data). Among the information retrieved from the display there is the display model name, manufacturer, the list of supported video modes, the size of the display area. As a "bonus", the DDC allows the graphics card to probe for a connected display.
So apparently there is currently no use for load detection, so why bother? Well, the DDC mechanism is fairly recent, so old (ancient?) displays were not built with DDC support. So if we only relied on DDC, it would be impossible to use these displays today. Moreover, the S-Video or Composite connectors you see on some graphics cards are not supposed to have DDC support.
To sum up, if you want your card to output to an old display or a TV, you need to either manually enable the output or rely on load detection.
{i} Disclaimer: From now on the information is based on observation and source code | rather than from true knowledge of how it works | because nvidia does not provide documentation for the hardware. The information is supposed to be true for the NV46 generation | because that's the hardware I have | but it's probably true for other generations. Feel free to edit if you believe something is wrong or missing. |
Output signal loops
As far as load detection is concerned, we are only interested in analog outputs. This is mainly because modern digital video interfaces have some form DDC support, so there's no need for the archaic methods.
From the electric perspective, all currently used analog signal paths appear to the card as 75 Ohm loads. These loads appear across two terminals, the signal terminal and the ground or return terminal. So we have one current loop for each signal.
So for the normal VESA RGB connector we have three signal loops, one for each color (there are actually more loops for auxiliary signals). For the S-Video connector we have two signal loops, one for luma (luminance information) and another for chroma (color information). The Composite connector only has one loop, which carries all the signals, hence the name.
Simulating a display
When doing load detection tests it is often more convenient to use "simulated displays" rather than real ones. Using our knowledge on how displays look like from the card's point of view, it's easy to see that we can simulate an output loop with a 75 Ohm resistor. Simply connecting it across the loop terminals is enough. You'll obviously need one resistor per output loop :-?
During my tests I've been using 100 Ohm resistors instead. This is mainly because they were easier to find. It seems that the detection still works up to 300 Ohms, but it's better to use a value close to the specification.
The test points
The nvidia engineers included a testing facility in each set of output resources (most modern cards have two). As far as I know, this testing mechanism is only used for output detection, but it is possible that it has some other unknown uses.
Each testing facility can be used to do tests on the corresponding output. The corresponding output is reported by the manufacturer on the BIOS Dcb Table. On my card, for instance, the VGA output corresponds to output 0 and S-Video corresponds to output 1.
The associated registers
Each testing facility has a set of associated registers, included in the corresponding PRAMDAC register set. Aparently only three registers are relevant per PRAMDAC:
- NV_TEST_DATA
- NV_TEST_CONTROL
- NV_OUTPUT. From what I've seen the different register sets are not independent as far as testing is concerned. Changing PRAMDAC0->NV_TEST_CONTROL can mess with PRAMDAC1->NV_TEST_CONTROL and both PRAMDACx->NV_OUTPUT.
NV_TEST_DATA
The layout of this register is somewhat documented on rivatv rules.xml (thanks to malc0 for pointing me to it), but not what it actually does. It is called "testpoint data" on the rivatv doc.
The two MSB's are documented as binary data, and the other 30 are divided in sets of 10 bit data, one for each test channel (documented on rivatv docs as RGB, but should also apply to luma/chroma for S-Video). So the magic 0x94050140 value set by the nv driver when detecting a CRT is divided as:
( 1 << 31 | 0x140 << 20 | 0x140 << 10 | 0x140 << 0 )
The actual meaning of the RGB values is unknown, but tests suggest it may be a threshold value or something like that.
NV_TEST_CONTROL
Like NV_TEST_DATA, the layout of this register is also documented on rivatv docs. It is divided in two parts, the test bits and the result bits.
NV_TEST_CONTROL Test bits
The test bits are used to retrieve the result from the testing mechanism. They are the 4 MSB's from the NV_TEST_CONTROL registers.
As far as normal load detection is concerned, the 3 MSB's (bits 29, 30, 31) represent one output loop each, being on when the loop is closed, and off when it is open.
The other bit (bit 28) is the result of bitwise AND of the 3 MSB's, meaning it will be on if all three loops are closed, and off otherwise.
NOTE: For VGA the nv driver requires bit 28 to be on (meaning it will require the 3 RGB loops to be closed). On the other hand, the nvidia blob only requires a single loop connected, which means detection will be tolerant to faulty displays. For S-Video testing of individual loops is required, as there are only two (or a single loop for Composite output).
NV_TEST_CONTROL Control bits
The bits bits from 0 to 27 seem to be used for control. Rivatv documents their names, but their actual use is still unknown to me.
NV_OUTPUT
These registers control the outputs. Only a few of their bits are used, and even fewer are known. I found out that some bits of these registers pay an important part in TV output load detection. On the other hand they seem to have no effect on VGA load detection.
The bits in question belong to the nibble number 4 (0xf << 4). The bios sets them to the value 3 or 7 when in the text console. Under X, while performing load detection, the blob first tests with value 3 and then re-tests with value 7. On both tests my "simulated S-Video TV" is properly detected.
These are the test results for different values on this NV_OUTPUT register nibble, for my S-Video output:
Value | All disconnected | 100 Ohms on Luma | 100 Ohms on Chroma | 100 Ohms on Both |
0x0 | 0x6 | 0x6 | 0xf | ? |
0x3 | 0x0 | 0x4 | 0x8 | 0xc |