/* * Copyright 2003 NVIDIA, Corporation * Copyright 2006 Dave Airlie * Copyright 2007 Maarten Maathuis * Copyright 2007-2009 Stuart Bennett * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE.
*/
int nv04_dac_output_offset(struct drm_encoder *encoder)
{ struct dcb_output *dcb = nouveau_encoder(encoder)->dcb; int offset = 0;
if (dcb->or & (8 | DCB_OUTPUT_C))
offset += 0x68; if (dcb->or & (8 | DCB_OUTPUT_B))
offset += 0x2000;
return offset;
}
/* * arbitrary limit to number of sense oscillations tolerated in one sample * period (observed to be at least 13 in "nvidia")
*/ #define MAX_HBLANK_OSC 20
/* * arbitrary limit to number of conflicting sample pairs to tolerate at a * voltage step (observed to be at least 5 in "nvidia")
*/ #define MAX_SAMPLE_PAIRS 10
for (i = 0; i < 2; i++) { bool sense_a, sense_b, sense_b_prime; int j = 0;
/* * wait for bit 0 clear -- out of hblank -- (say reg value 0x4), * then wait for transition 0x4->0x5->0x4: enter hblank, leave * hblank again * use a 10ms timeout (guards against crtc being inactive, in * which case blank state would never change)
*/ if (nvif_msec(&drm->client.device, 10, if (!(nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 1)) break;
) < 0) return -EBUSY;
if (nvif_msec(&drm->client.device, 10, if ( (nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 1)) break;
) < 0) return -EBUSY;
if (nvif_msec(&drm->client.device, 10, if (!(nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 1)) break;
) < 0) return -EBUSY;
udelay(100); /* when level triggers, sense is _LO_ */
sense_a = nvif_rd08(device, NV_PRMCIO_INP0) & 0x10;
/* take another reading until it agrees with sense_a... */ do {
udelay(100);
sense_b = nvif_rd08(device, NV_PRMCIO_INP0) & 0x10; if (sense_a != sense_b) {
sense_b_prime =
nvif_rd08(device, NV_PRMCIO_INP0) & 0x10; if (sense_b == sense_b_prime) { /* ... unless two consecutive subsequent
* samples agree; sense_a is replaced */
sense_a = sense_b; /* force mis-match so we loop */
sense_b = !sense_a;
}
}
} while ((sense_a != sense_b) && ++j < MAX_HBLANK_OSC);
if (j == MAX_HBLANK_OSC) /* with so much oscillation, default to sense:LO */
sense[i] = false; else
sense[i] = sense_a;
}
nvif_wr08(device, NV_PRMDIO_WRITE_MODE_ADDRESS, 0);
nvif_wr08(device, NV_PRMDIO_PALETTE_DATA, 0);
nvif_wr08(device, NV_PRMDIO_PALETTE_DATA, 0); /* testing blue won't find monochrome monitors. I don't care */
nvif_wr08(device, NV_PRMDIO_PALETTE_DATA, blue);
i = 0; /* take sample pairs until both samples in the pair agree */ do { if (sample_load_twice(dev, sense_pair)) goto out;
} while ((sense_pair[0] != sense_pair[1]) &&
++i < MAX_SAMPLE_PAIRS);
if (i == MAX_SAMPLE_PAIRS) /* too much oscillation defaults to LO */
sense = false; else
sense = sense_pair[0];
/* * if sense goes LO before blue ramps to 0x18, monitor is not connected. * ergo, if blue gets to 0x18, monitor must be connected
*/
} while (++blue < 0x18 && sense);
sample = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset); /* do it again just in case it's a residual current */
sample &= NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);
/* bios does something more complex for restoring, but I think this is good enough */
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, saved_routput);
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, saved_rtest_ctrl); if (regoffset == 0x68)
nvif_wr32(device, NV_PBUS_POWERCTRL_4, saved_powerctrl_4);
nvif_wr32(device, NV_PBUS_POWERCTRL_2, saved_powerctrl_2);
/* bit 16-19 are bits that are set on some G70 cards,
* but don't seem to have much effect */
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + dac_offset,
head << 8 | NV_PRAMDAC_DACCLK_SEL_DACCLK); /* force any other vga encoders to bind to the other crtc */
list_for_each_entry(rebind, &dev->mode_config.encoder_list, head) { if (rebind == encoder
|| nouveau_encoder(rebind)->dcb->type != DCB_OUTPUT_ANALOG) continue;
/* This could use refinement for flatpanels, but it should work this way */ if (drm->client.device.info.chipset < 0x44)
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0xf0000000); else
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000);
}
/* Check if the DAC corresponding to 'encoder' is being used by
* someone else. */ bool nv04_dac_in_use(struct drm_encoder *encoder)
{ struct drm_device *dev = encoder->dev; struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.