/* * Copyright 1993-2003 NVIDIA, Corporation * Copyright 2006 Dave Airlie * Copyright 2007 Maarten Maathuis * * 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.
*/ #include <drm/drm_crtc_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_plane_helper.h> #include <drm/drm_vblank.h>
if (nvbios_pll_parse(bios, nv_crtc->index ? PLL_VPLL1 : PLL_VPLL0,
&pll_lim)) return;
/* NM2 == 0 is used to determine single stage mode on two stage plls */
pv->NM2 = 0;
/* for newer nv4x the blob uses only the first stage of the vpll below a * certain clock. for a certain nv4b this is 150MHz. since the max * output frequency of the first stage for this card is 300MHz, it is * assumed the threshold is given by vco1 maxfreq/2
*/ /* for early nv4x, specifically nv40 and *some* nv43 (devids 0 and 6, * not 8, others unknown), the blob always uses both plls. no problem * has yet been observed in allowing the use a single stage pll on all * nv43 however. the behaviour of single stage use is untested on nv40
*/ if (drm->client.device.info.chipset > 0x40 && dot_clock <= (pll_lim.vco1.max_freq / 2))
memset(&pll_lim.vco2, 0, sizeof(pll_lim.vco2));
if (!clk->pll_calc(clk, &pll_lim, dot_clock, pv)) return;
/* The blob uses this always, so let's do the same */ if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE)
state->pllsel |= NV_PRAMDAC_PLL_COEFF_SELECT_USE_VPLL2_TRUE; /* again nv40 and some nv43 act more like nv3x as described above */ if (drm->client.device.info.chipset < 0x41)
state->pllsel |= NV_PRAMDAC_PLL_COEFF_SELECT_SOURCE_PROG_MPLL |
NV_PRAMDAC_PLL_COEFF_SELECT_SOURCE_PROG_NVPLL;
state->pllsel |= nv_crtc->index ? PLLSEL_VPLL2_MASK : PLLSEL_VPLL1_MASK;
NV_DEBUG(drm, "Setting dpms mode %d on CRTC %d\n", mode,
nv_crtc->index);
if (nv_crtc->last_dpms == mode) /* Don't do unnecessary mode changes. */ return;
nv_crtc->last_dpms = mode;
if (nv_two_heads(dev))
NVSetOwner(dev, nv_crtc->index);
/* nv4ref indicates these two RPC1 bits inhibit h/v sync */
crtc1A = NVReadVgaCrtc(dev, nv_crtc->index,
NV_CIO_CRE_RPC1_INDEX) & ~0xC0; switch (mode) { case DRM_MODE_DPMS_STANDBY: /* Screen: Off; HSync: Off, VSync: On -- Not Supported */
seq1 = 0x20;
crtc17 = 0x80;
crtc1A |= 0x80; break; case DRM_MODE_DPMS_SUSPEND: /* Screen: Off; HSync: On, VSync: Off -- Not Supported */
seq1 = 0x20;
crtc17 = 0x80;
crtc1A |= 0x40; break; case DRM_MODE_DPMS_OFF: /* Screen: Off; HSync: Off, VSync: Off */
seq1 = 0x20;
crtc17 = 0x00;
crtc1A |= 0xC0; break; case DRM_MODE_DPMS_ON: default: /* Screen: On; HSync: On, VSync: On */
seq1 = 0x00;
crtc17 = 0x80; break;
}
NVVgaSeqReset(dev, nv_crtc->index, true); /* Each head has it's own sequencer, so we can turn it off when we want */
seq1 |= (NVReadVgaSeq(dev, nv_crtc->index, NV_VIO_SR_CLOCK_INDEX) & ~0x20);
NVWriteVgaSeq(dev, nv_crtc->index, NV_VIO_SR_CLOCK_INDEX, seq1);
crtc17 |= (NVReadVgaCrtc(dev, nv_crtc->index, NV_CIO_CR_MODE_INDEX) & ~0x80);
mdelay(10);
NVWriteVgaCrtc(dev, nv_crtc->index, NV_CIO_CR_MODE_INDEX, crtc17);
NVVgaSeqReset(dev, nv_crtc->index, false);
if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS)
digital = lvds_output = true; if (nv_encoder->dcb->type == DCB_OUTPUT_TV)
tv_output = true; if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS)
digital = tmds_output = true; if (nv_encoder->dcb->location != DCB_LOC_ON_CHIP && digital)
off_chip_digital = true;
}
/* Registers not directly related to the (s)vga mode */
/* What is the meaning of this register? */ /* A few popular values are 0x18, 0x1c, 0x38, 0x3c */
regp->CRTC[NV_CIO_CRE_ENH_INDEX] = savep->CRTC[NV_CIO_CRE_ENH_INDEX] & ~(1<<5);
regp->crtc_eng_ctrl = 0; /* Except for rare conditions I2C is enabled on the primary crtc */ if (nv_crtc->index == 0)
regp->crtc_eng_ctrl |= NV_CRTC_FSEL_I2C; #if 0 /* Set overlay to desired crtc. */ if (dev->overlayAdaptor) {
NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(dev); if (pPriv->overlayCRTC == nv_crtc->index)
regp->crtc_eng_ctrl |= NV_CRTC_FSEL_OVERLAY;
} #endif
/* ADDRESS_SPACE_PNVM is the same as setting HCUR_ASI */
regp->cursor_cfg = NV_PCRTC_CURSOR_CONFIG_CUR_LINES_64 |
NV_PCRTC_CURSOR_CONFIG_CUR_PIXELS_64 |
NV_PCRTC_CURSOR_CONFIG_ADDRESS_SPACE_PNVM; if (drm->client.device.info.chipset >= 0x11)
regp->cursor_cfg |= NV_PCRTC_CURSOR_CONFIG_CUR_BPP_32; if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
regp->cursor_cfg |= NV_PCRTC_CURSOR_CONFIG_DOUBLE_SCAN_ENABLE;
/* 0x00 is disabled, 0x11 is lvds, 0x22 crt and 0x88 tmds */ if (lvds_output)
regp->CRTC[NV_CIO_CRE_SCRATCH3__INDEX] = 0x11; elseif (tmds_output)
regp->CRTC[NV_CIO_CRE_SCRATCH3__INDEX] = 0x88; else
regp->CRTC[NV_CIO_CRE_SCRATCH3__INDEX] = 0x22;
/* These values seem to vary */ /* This register seems to be used by the bios to make certain decisions on some G70 cards? */
regp->CRTC[NV_CIO_CRE_SCRATCH4__INDEX] = savep->CRTC[NV_CIO_CRE_SCRATCH4__INDEX];
/* probably a scratch reg, but kept for cargo-cult purposes: * bit0: crtc0?, head A * bit6: lvds, head A * bit7: (only in X), head A
*/ if (nv_crtc->index == 0)
regp->CRTC[NV_CIO_CRE_4B] = savep->CRTC[NV_CIO_CRE_4B] | 0x80;
/* The blob seems to take the current value from crtc 0, add 4 to that
* and reuse the old value for crtc 1 */
regp->CRTC[NV_CIO_CRE_TVOUT_LATENCY] = nv04_display(dev)->saved_reg.crtc_reg[0].CRTC[NV_CIO_CRE_TVOUT_LATENCY]; if (!nv_crtc->index)
regp->CRTC[NV_CIO_CRE_TVOUT_LATENCY] += 4;
/* the blob sometimes sets |= 0x10 (which is the same as setting |=
* 1 << 30 on 0x60.830), for no apparent reason */
regp->CRTC[NV_CIO_CRE_59] = off_chip_digital;
/* * Sets up registers for the given mode/adjusted_mode pair. * * The clocks, CRTCs and outputs attached to this CRTC must be off. * * This shouldn't enable any clocks, CRTCs, or outputs, but they should * be easily turned on/off after this.
*/ staticint
nv_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *old_fb)
{ struct drm_device *dev = crtc->dev; struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_drm *drm = nouveau_drm(dev); int ret;
NV_DEBUG(drm, "CTRC mode on CRTC %d:\n", nv_crtc->index);
drm_mode_debug_printmodeline(adjusted_mode);
ret = nv_crtc_swap_fbs(crtc, old_fb); if (ret) return ret;
/* unlock must come after turning off FP_TG_CONTROL in output_prepare */
nv_lock_vga_crtc_shadow(dev, nv_crtc->index, -1);
nv_crtc_mode_set_vga(crtc, adjusted_mode); /* calculated in nv04_dfp_prepare, nv40 needs it written before calculating PLLs */ if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE)
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK, nv04_display(dev)->mode_reg.sel_clk);
nv_crtc_mode_set_regs(crtc, adjusted_mode);
nv_crtc_calc_state_ext(crtc, mode, adjusted_mode->clock); return 0;
}
rgbs = (struct rgb *)nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index].DAC;
r = crtc->gamma_store;
g = r + crtc->gamma_size;
b = g + crtc->gamma_size;
for (i = 0; i < 256; i++) {
rgbs[i].r = *r++ >> 8;
rgbs[i].g = *g++ >> 8;
rgbs[i].b = *b++ >> 8;
}
/* We need to know the depth before we upload, but it's possible to * get called before a framebuffer is bound. If this is the case, * mark the lut values as dirty by setting depth==0, and it'll be * uploaded on the first mode_set_base()
*/ if (!nv_crtc->base.primary->fb) {
nv_crtc->lut.depth = 0; return 0;
}
/* no fb bound */ if (!atomic && !crtc->primary->fb) {
NV_DEBUG(drm, "No FB bound\n"); return 0;
}
/* If atomic, we want to switch to the fb we were passed, so * now we update pointers to do that.
*/ if (atomic) {
drm_fb = passed_fb;
} else {
drm_fb = crtc->primary->fb;
}
staticint
nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb)
{ int ret = nv_crtc_swap_fbs(crtc, old_fb); if (ret) return ret; return nv04_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
}
staticint
nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y, enum mode_set_atomic state)
{ return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true);
}
staticvoid nv04_cursor_upload(struct drm_device *dev, struct nouveau_bo *src, struct nouveau_bo *dst)
{ int width = nv_cursor_width(dev);
uint32_t pixel; int i, j;
for (i = 0; i < width; i++) { for (j = 0; j < width; j++) {
pixel = nouveau_bo_rd32(src, i*64 + j);
/* nv11+ supports premultiplied (PM), or non-premultiplied (NPM) alpha * cursors (though NPM in combination with fp dithering may not work on * nv11, from "nv" driver history) * NPM mode needs NV_PCRTC_CURSOR_CONFIG_ALPHA_BLEND set and is what the * blob uses, however we get given PM cursors so we use PM mode
*/ for (i = 0; i < 64 * 64; i++) {
pixel = nouveau_bo_rd32(src, i);
/* hw gets unhappy if alpha <= rgb values. for a PM image "less * than" shouldn't happen; fix "equal to" case by adding one to * alpha channel (slightly inaccurate, but so is attempting to * get back to NPM images, due to limits of integer precision)
*/
alpha = pixel >> 24; if (alpha > 0 && alpha < 255)
pixel = (pixel & 0x00ffffff) | ((alpha + 1) << 24);
s = list_first_entry(&fctx->flip, struct nv04_page_flip_state, head); if (s->event) {
drm_crtc_arm_vblank_event(s->crtc, s->event);
} else { /* Give up ownership of vblank for page-flipped crtc */
drm_crtc_vblank_put(s->crtc);
}
/* Queue it to the pending list */
spin_lock_irqsave(&dev->event_lock, flags);
list_add_tail(&s->head, &fctx->flip);
spin_unlock_irqrestore(&dev->event_lock, flags);
/* Synchronize with the old framebuffer */
ret = nouveau_fence_sync(old_bo, chan, false, false); if (ret) goto fail;
/* Emit the pageflip */
ret = PUSH_WAIT(push, 2); if (ret) goto fail;
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.