/* * 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_dfp_get_bound_head(struct drm_device *dev, struct dcb_output *dcbent)
{ /* special case of nv_read_tmds to find crtc associated with an output. * this does not give a correct answer for off-chip dvi, but there's no * use for such an answer anyway
*/ int ramdac = (dcbent->or & DCB_OUTPUT_C) >> 2;
void nv04_dfp_bind_head(struct drm_device *dev, struct dcb_output *dcbent, int head, bool dl)
{ /* The BIOS scripts don't do this for us, sadly * Luckily we do know the values ;-) * * head < 0 indicates we wish to force a setting with the overrideval * (for VT restore etc.)
*/
if (NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL) &
FP_TG_CONTROL_ON) { /* digital remnants must be cleaned before new crtc * values programmed. delay is time for the vga stuff * to realise it's in control again
*/
NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL,
FP_TG_CONTROL_OFF);
msleep(50);
} /* don't inadvertently turn it on when state written later */
crtcstate[head].fp_control = FP_TG_CONTROL_OFF;
crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] &=
~NV_CIO_CRE_LCD_ROUTE_MASK;
}
if (is_fpc_off(*fpc)) { /* using saved value is ok, as (is_digital && dpms_on && * fp_control==OFF) is (at present) *only* true when * fpc's most recent change was by below "off" code
*/
*fpc = nv_crtc->dpms_saved_fp_control;
}
if (dcb->type != DCB_OUTPUT_TMDS || dcb->location == DCB_LOC_ON_CHIP) return NULL;
/* Some BIOSes (e.g. the one in a Quadro FX1000) report several * TMDS transmitters at the same I2C address, in the same I2C * bus. This can still work because in that case one of them is * always hard-wired to a reasonable configuration using straps, * and the other one needs to be programmed. * * I don't think there's a way to know which is which, even the * blob programs the one exposed via I2C for *both* heads, so * let's do the same.
*/
list_for_each_entry(slave, &dev->mode_config.encoder_list, head) { struct dcb_output *slave_dcb = nouveau_encoder(slave)->dcb;
if (nv_encoder->dcb->location != DCB_LOC_ON_CHIP) return;
/* SEL_CLK is only used on the primary ramdac * It toggles spread spectrum PLL output and sets the bindings of PLLs * to heads on digital outputs
*/ if (head)
state->sel_clk |= bits1618; else
state->sel_clk &= ~bits1618;
/* nv30: * bit 0 NVClk spread spectrum on/off * bit 2 MemClk spread spectrum on/off * bit 4 PixClk1 spread spectrum on/off toggle * bit 6 PixClk2 spread spectrum on/off toggle * * nv40 (observations from bios behaviour and mmio traces): * bits 4&6 as for nv30 * bits 5&7 head dependent as for bits 4&6, but do not appear with 4&6; * maybe a different spread mode * bits 8&10 seen on dual-link dvi outputs, purpose unknown (set by POST scripts) * The logic behind turning spread spectrum on/off in the first place, * and which bit-pair to use, is unclear on nv40 (for earlier cards, the fp table * entry has the necessary info)
*/ if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS && nv04_display(dev)->saved_reg.sel_clk & 0xf0) { int shift = (nv04_display(dev)->saved_reg.sel_clk & 0x50) ? 0 : 1;
/* We want automatic scaling */
regp->fp_debug_1 = 0; /* This can override HTOTAL and VTOTAL */
regp->fp_debug_2 = 0;
/* Use 20.12 fixed point format to avoid floats */
mode_ratio = (1 << 12) * adjusted_mode->hdisplay / adjusted_mode->vdisplay;
panel_ratio = (1 << 12) * output_mode->hdisplay / output_mode->vdisplay; /* if ratios are equal, SCALE_ASPECT will automatically (and correctly)
* get treated the same as SCALE_FULLSCREEN */ if (nv_connector->scaling_mode == DRM_MODE_SCALE_ASPECT &&
mode_ratio != panel_ratio) {
uint32_t diff, scale; bool divide_by_2 = nv_gf4_disp_arch(dev);
if (mode_ratio < panel_ratio) { /* vertical needs to expand to glass size (automatic) * horizontal needs to be scaled at vertical scale factor
* to maintain aspect */
if (mode_ratio > panel_ratio) { /* horizontal needs to expand to glass size (automatic) * vertical needs to be scaled at horizontal scale factor
* to maintain aspect */
/* update fp_control state for any changes made by scripts,
* so correct value is written at DPMS on */
nv04_display(dev)->mode_reg.crtc_reg[head].fp_control =
NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_TG_CONTROL);
/* 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);
if (was_powersaving && is_powersaving_dpms(mode)) return;
if (nv_encoder->dcb->lvdsconf.use_power_scripts) { /* when removing an output, crtc may not be set, but PANEL_OFF * must still be run
*/ int head = crtc ? nouveau_crtc(crtc)->index :
nv04_dfp_get_bound_head(dev, nv_encoder->dcb);
if (mode == DRM_MODE_DPMS_ON) {
call_lvds_script(dev, nv_encoder->dcb, head,
LVDS_PANEL_ON, nv_encoder->mode.clock);
} else /* pxclk of 0 is fine for PANEL_OFF, and for a * disconnected LVDS encoder there is no native_mode
*/
call_lvds_script(dev, nv_encoder->dcb, head,
LVDS_PANEL_OFF, 0);
}
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.