2 * Copyright (c) 2007 NVIDIA, Corporation
3 * Copyright (c) 2008 Maarten Maathuis
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 #include "nv_include.h"
27 /* Don't call the directly, only load state should do this on the long run*/
28 void NV50CheckWriteVClk(ScrnInfoPtr pScrn)
30 NVPtr pNv = NVPTR(pScrn);
31 int t_start = GetTimeInMillis();
33 while (NVRead(pNv, NV50_DISPLAY_CTRL_STATE) & NV50_DISPLAY_CTRL_STATE_PENDING) {
34 /* An educated guess. */
35 const uint32_t supervisor = NVRead(pNv, NV50_DISPLAY_SUPERVISOR);
37 /* Just in case something goes bad, at least you can blindly restart your machine. */
38 if ((GetTimeInMillis() - t_start) > 5000) {
39 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "NV50CheckWriteVClk() timed out.\n");
40 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "A reboot is probably required now.\n");
44 /* Simply acknowledge it, maybe we should do more? */
45 if (supervisor & NV50_DISPLAY_SUPERVISOR_CRTCn) {
46 NVWrite(pNv, NV50_DISPLAY_SUPERVISOR, supervisor & NV50_DISPLAY_SUPERVISOR_CRTCn);
49 if (supervisor & NV50_DISPLAY_SUPERVISOR_CLK_MASK) {
50 if (supervisor & NV50_DISPLAY_SUPERVISOR_CLK_UPDATE) {
51 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
52 const uint32_t clockvar = NVRead(pNv, NV50_DISPLAY_UNK30_CTRL);
55 for(i = 0; i < xf86_config->num_crtc; i++) {
56 xf86CrtcPtr crtc = xf86_config->crtc[i];
57 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
60 if (nv_crtc->head == 1)
61 mask = NV50_DISPLAY_UNK30_CTRL_UPDATE_VCLK1;
63 mask = NV50_DISPLAY_UNK30_CTRL_UPDATE_VCLK0;
65 /* Always do something if the supervisor wants a clock change. */
66 /* This is needed because you get a deadlock if you don't kick the NV50_CRTC0_CLK_CTRL2 register. */
67 if (nv_crtc->modeset_lock || (clockvar & mask))
68 NV50CrtcSetPClk(crtc, !!(clockvar & mask));
72 NVWrite(pNv, NV50_DISPLAY_SUPERVISOR, 1 << (ffs(supervisor & NV50_DISPLAY_SUPERVISOR_CLK_MASK) - 1));
73 NVWrite(pNv, NV50_DISPLAY_UNK30_CTRL, NV50_DISPLAY_UNK30_CTRL_PENDING);
78 void NV50DisplayCommand(ScrnInfoPtr pScrn, CARD32 addr, CARD32 value)
80 DDXMMIOH("NV50DisplayCommand: head %d addr 0x%X value 0x%X\n", 0, addr, value);
81 NVPtr pNv = NVPTR(pScrn);
82 NVWrite(pNv, NV50_DISPLAY_CTRL_VAL, value);
83 NVWrite(pNv, NV50_DISPLAY_CTRL_STATE, addr | 0x10000 | NV50_DISPLAY_CTRL_STATE_ENABLE | NV50_DISPLAY_CTRL_STATE_PENDING);
84 NV50CheckWriteVClk(pScrn);
87 void NV50CrtcCommand(xf86CrtcPtr crtc, CARD32 addr, CARD32 value)
89 ScrnInfoPtr pScrn = crtc->scrn;
90 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
92 /* This head dependent offset may not be true everywere */
93 NV50DisplayCommand(pScrn, addr + 0x400 * nv_crtc->head, value);
96 void NV50CrtcSetPClk(xf86CrtcPtr crtc, Bool update)
98 ScrnInfoPtr pScrn = crtc->scrn;
99 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetPClk is called (%s).\n", update ? "update" : "no update");
101 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
102 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
103 NVPtr pNv = NVPTR(pScrn);
106 /* Sometimes NV50_CRTC0_CLK_CTRL2 needs a kick, but the clock needs no update. */
108 /* I don't know why exactly, but these were in my table. */
109 uint32_t pll_reg = nv_crtc->head ? NV50_CRTC1_CLK_CTRL1 : NV50_CRTC0_CLK_CTRL1;
111 int NM1 = 0xbeef, NM2 = 0xdead, log2P;
112 struct pll_lims pll_lim;
113 get_pll_limits(pScrn, pll_reg, &pll_lim);
114 /* NV5x hardware doesn't seem to support a single vco mode, otherwise the blob is hiding it well. */
115 getMNP_double(pScrn, &pll_lim, nv_crtc->pclk, &NM1, &NM2, &log2P);
117 uint32_t reg1 = NVRead(pNv, pll_reg + 4);
118 uint32_t reg2 = NVRead(pNv, pll_reg + 8);
120 /* bit0: The blob (and bios) seem to have this on (almost) always.
121 * I'm hoping this (experiment) will fix my image stability issues.
123 NVWrite(pNv, NV50_CRTC0_CLK_CTRL1 + nv_crtc->head * 0x800, NV50_CRTC_CLK_CTRL1_CONNECTED | 0x10000011);
125 /* Eventually we should learn ourselves what all the bits should be. */
129 uint8_t N1 = (NM1 >> 8) & 0xFF;
130 uint8_t M1 = NM1 & 0xFF;
131 uint8_t N2 = (NM2 >> 8) & 0xFF;
132 uint8_t M2 = NM2 & 0xFF;
134 reg1 |= (M1 << 16) | N1;
135 reg2 |= (log2P << 28) | (M2 << 16) | N2;
137 NVWrite(pNv, pll_reg + 4, reg1);
138 NVWrite(pNv, pll_reg + 8, reg2);
141 /* There seem to be a few indicator bits, which are similar to the SOR_CTRL bits. */
142 NVWrite(pNv, NV50_CRTC0_CLK_CTRL2 + nv_crtc->head * 0x800, 0);
144 for(i = 0; i < xf86_config->num_output; i++) {
145 xf86OutputPtr output = xf86_config->output[i];
147 if(output->crtc != crtc)
149 NV50OutputSetPClk(output, nv_crtc->pclk);
154 NV50CrtcSetDither(xf86CrtcPtr crtc, Bool update)
156 ScrnInfoPtr pScrn = crtc->scrn;
157 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetDither is called (%s).\n", update ? "update" : "no update");
159 xf86OutputPtr output = NULL;
160 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
163 for (i = 0; i < xf86_config->num_output; i++) {
164 if (xf86_config->output[i]->crtc == crtc) {
165 output = xf86_config->output[i];
173 NVOutputPrivatePtr nv_output = output->driver_private;
175 NV50CrtcCommand(crtc, NV50_CRTC0_DITHERING_CTRL, nv_output->dithering ?
176 NV50_CRTC0_DITHERING_CTRL_ON : NV50_CRTC0_DITHERING_CTRL_OFF);
178 NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
182 nv50_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode, int x, int y)
184 ScrnInfoPtr pScrn = crtc->scrn;
185 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
186 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_mode_set is called for %s with position (%d, %d).\n", nv_crtc->head ? "CRTC1" : "CRTC0", x, y);
188 nv_crtc->pclk = adjusted_mode->Clock;
190 uint32_t hsync_dur = adjusted_mode->CrtcHSyncEnd - adjusted_mode->CrtcHSyncStart;
191 uint32_t vsync_dur = adjusted_mode->CrtcVSyncEnd - adjusted_mode->CrtcVSyncStart;
192 uint32_t hsync_start_to_end = adjusted_mode->CrtcHBlankEnd - adjusted_mode->CrtcHSyncStart;
193 uint32_t vsync_start_to_end = adjusted_mode->CrtcVBlankEnd - adjusted_mode->CrtcVSyncStart;
194 /* I can't give this a proper name, anyone else can? */
195 uint32_t hunk1 = adjusted_mode->CrtcHTotal - adjusted_mode->CrtcHSyncStart + adjusted_mode->CrtcHBlankStart;
196 uint32_t vunk1 = adjusted_mode->CrtcVTotal - adjusted_mode->CrtcVSyncStart + adjusted_mode->CrtcVBlankStart;
197 /* Another strange value, this time only for interlaced modes. */
198 uint32_t vunk2a = 2*adjusted_mode->CrtcVTotal - adjusted_mode->CrtcVSyncStart + adjusted_mode->CrtcVBlankStart;
199 uint32_t vunk2b = adjusted_mode->CrtcVTotal - adjusted_mode->CrtcVSyncStart + adjusted_mode->CrtcVBlankEnd;
201 if (adjusted_mode->Flags & V_INTERLACE) {
203 vsync_start_to_end /= 2;
208 if (adjusted_mode->Flags & V_DBLSCAN) {
209 vsync_start_to_end -= 1;
216 /* NV50CrtcCommand includes head offset */
217 /* This is the native mode when DFP && !SCALE_PANEL */
218 NV50CrtcCommand(crtc, NV50_CRTC0_CLOCK, adjusted_mode->Clock | 0x800000);
219 NV50CrtcCommand(crtc, NV50_CRTC0_INTERLACE, (adjusted_mode->Flags & V_INTERLACE) ? 2 : 0);
220 NV50CrtcCommand(crtc, NV50_CRTC0_DISPLAY_START, 0);
221 NV50CrtcCommand(crtc, NV50_CRTC0_UNK82C, 0);
222 NV50CrtcCommand(crtc, NV50_CRTC0_DISPLAY_TOTAL, adjusted_mode->CrtcVTotal << 16 | adjusted_mode->CrtcHTotal);
223 NV50CrtcCommand(crtc, NV50_CRTC0_SYNC_DURATION, (vsync_dur - 1) << 16 | (hsync_dur - 1));
224 NV50CrtcCommand(crtc, NV50_CRTC0_SYNC_START_TO_BLANK_END, (vsync_start_to_end - 1) << 16 | (hsync_start_to_end - 1));
225 NV50CrtcCommand(crtc, NV50_CRTC0_MODE_UNK1, (vunk1 - 1) << 16 | (hunk1 - 1));
226 if (adjusted_mode->Flags & V_INTERLACE) {
227 NV50CrtcCommand(crtc, NV50_CRTC0_MODE_UNK2, (vunk2b - 1) << 16 | (vunk2a - 1));
229 NV50CrtcCommand(crtc, NV50_CRTC0_FB_SIZE, pScrn->virtualY << 16 | pScrn->virtualX);
230 NV50CrtcCommand(crtc, NV50_CRTC0_PITCH, pScrn->displayWidth * (pScrn->bitsPerPixel / 8) | 0x100000);
231 switch (pScrn->depth) {
233 NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_8BPP);
236 NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_15BPP);
239 NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_16BPP);
242 NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_24BPP);
245 NV50CrtcSetDither(crtc, FALSE);
246 NV50CrtcCommand(crtc, NV50_CRTC0_UNK_8A8, 0x40000);
247 NV50CrtcCommand(crtc, NV50_CRTC0_FB_POS, y << 16 | x);
248 /* This is the actual resolution of the mode. */
249 NV50CrtcCommand(crtc, NV50_CRTC0_SCRN_SIZE, (mode->VDisplay << 16) | mode->HDisplay);
250 NV50CrtcCommand(crtc, 0x8d4, 0);
252 NV50CrtcBlankScreen(crtc, FALSE);
256 NV50CrtcBlankScreen(xf86CrtcPtr crtc, Bool blank)
258 ScrnInfoPtr pScrn = crtc->scrn;
259 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcBlankScreen is called (%s).\n", blank ? "blanked" : "unblanked");
261 NVPtr pNv = NVPTR(pScrn);
262 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
265 NV50CrtcShowHideCursor(crtc, FALSE, FALSE);
267 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_MODE, NV50_CRTC0_CLUT_MODE_BLANK);
268 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, 0);
269 if(pNv->NVArch != 0x50)
270 NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK1, NV84_CRTC0_BLANK_UNK1_BLANK);
271 NV50CrtcCommand(crtc, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_BLANK);
272 if(pNv->NVArch != 0x50)
273 NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK2, NV84_CRTC0_BLANK_UNK2_BLANK);
275 NV50CrtcCommand(crtc, NV50_CRTC0_FB_OFFSET, pNv->FB->offset >> 8);
276 NV50CrtcCommand(crtc, 0x864, 0);
277 NVWrite(pNv, NV50_DISPLAY_UNK_380, 0);
278 /* RAM is clamped to 256 MiB. */
279 NVWrite(pNv, NV50_DISPLAY_RAM_AMOUNT, pNv->RamAmountKBytes * 1024 - 1);
280 NVWrite(pNv, NV50_DISPLAY_UNK_388, 0x150000);
281 NVWrite(pNv, NV50_DISPLAY_UNK_38C, 0);
282 if (nv_crtc->head == 1)
283 NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_OFFSET, pNv->Cursor2->offset >> 8);
285 NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_OFFSET, pNv->Cursor->offset >> 8);
286 if(pNv->NVArch != 0x50)
287 NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK2, NV84_CRTC0_BLANK_UNK2_UNBLANK);
288 if(nv_crtc->cursorVisible)
289 NV50CrtcShowHideCursor(crtc, TRUE, FALSE);
290 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_MODE,
291 pScrn->depth == 8 ? NV50_CRTC0_CLUT_MODE_OFF : NV50_CRTC0_CLUT_MODE_ON);
292 /* Each CRTC has it's own CLUT. */
293 if (nv_crtc->head == 1)
294 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, pNv->CLUT1->offset >> 8);
296 NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, pNv->CLUT0->offset >> 8);
297 if(pNv->NVArch != 0x50)
298 NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK1, NV84_CRTC0_BLANK_UNK1_UNBLANK);
299 NV50CrtcCommand(crtc, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_UNBLANK);
304 nv50_crtc_prepare(xf86CrtcPtr crtc)
306 ScrnInfoPtr pScrn = crtc->scrn;
307 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_prepare is called.\n");
309 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
310 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
313 nv_crtc->modeset_lock = TRUE;
315 for(i = 0; i < xf86_config->num_output; i++) {
316 xf86OutputPtr output = xf86_config->output[i];
319 output->funcs->mode_set(output, NULL, NULL);
323 static void ComputeAspectScale(DisplayModePtr mode, DisplayModePtr adjusted_mode, int *outX, int *outY)
325 float scaleX, scaleY, scale;
327 scaleX = adjusted_mode->HDisplay / (float)mode->HDisplay;
328 scaleY = adjusted_mode->VDisplay / (float)mode->VDisplay;
335 *outX = mode->HDisplay * scale;
336 *outY = mode->VDisplay * scale;
339 void NV50CrtcSetScale(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode, enum scaling_modes scale)
341 ScrnInfoPtr pScrn = crtc->scrn;
342 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetScale is called.\n");
344 int outX = 0, outY = 0;
348 ComputeAspectScale(mode, adjusted_mode, &outX, &outY);
351 case SCALE_FULLSCREEN:
352 outX = adjusted_mode->HDisplay;
353 outY = adjusted_mode->VDisplay;
357 outX = mode->HDisplay;
358 outY = mode->VDisplay;
362 /* What kind of mode is this precisely? */
363 if ((mode->Flags & V_DBLSCAN) || (mode->Flags & V_INTERLACE) ||
364 mode->HDisplay != outX || mode->VDisplay != outY) {
365 NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_CTRL, 9);
367 NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_CTRL, 0);
369 NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_REG1, outY << 16 | outX);
370 NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_REG2, outY << 16 | outX);
374 nv50_crtc_commit(xf86CrtcPtr crtc)
376 ScrnInfoPtr pScrn = crtc->scrn;
377 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_commit is called.\n");
379 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
380 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
381 int i, crtc_mask = 0;
383 /* If any heads are unused, blank them */
384 for (i = 0; i < xf86_config->num_output; i++) {
385 xf86OutputPtr output = xf86_config->output[i];
388 NVCrtcPrivatePtr nv_crtc = output->crtc->driver_private;
389 crtc_mask |= (1 << nv_crtc->head);
393 for (i = 0; i < xf86_config->num_crtc; i++) {
394 if(!((1 << i) & crtc_mask)) {
395 NV50CrtcBlankScreen(xf86_config->crtc[i], TRUE);
399 xf86_reload_cursors (pScrn->pScreen);
401 NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
403 nv_crtc->modeset_lock = FALSE;
406 static Bool nv50_crtc_lock(xf86CrtcPtr crtc)
412 * The indices are a bit strange, but i'll assume it's correct (taken from nv).
413 * The LUT resolution seems to be 14 bits on NV50 as opposed to the 8 bits of previous hardware.
415 #define NV50_LUT_INDEX(val, w) ((val << (8 - w)) | (val >> ((w << 1) - 8)))
417 nv50_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
420 ScrnInfoPtr pScrn = crtc->scrn;
421 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv50_crtc_gamma_set is called.\n");
423 NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
424 NVPtr pNv = NVPTR(pScrn);
428 /* Each CRTC has it's own CLUT. */
429 if (nv_crtc->head == 1)
430 CLUT = pNv->CLUT1->map;
432 CLUT = pNv->CLUT0->map;
435 unsigned short red, green, blue, unused;
436 } *lut = (void *) CLUT;
438 switch (pScrn->depth) {
441 for (i = 0; i < 32; i++) {
442 index = NV50_LUT_INDEX(i, 5);
443 lut[index].red = red[i] >> 2;
444 lut[index].green = green[i] >> 2;
445 lut[index].blue = blue[i] >> 2;
450 for (i = 0; i < 32; i++) {
451 index = NV50_LUT_INDEX(i, 5);
452 lut[index].red = red[i] >> 2;
453 lut[index].blue = blue[i] >> 2;
456 /* Green has an extra bit. */
457 for (i = 0; i < 64; i++) {
458 index = NV50_LUT_INDEX(i, 6);
459 lut[index].green = green[i] >> 2;
464 for (i = 0; i < 256; i++) {
465 lut[i].red = red[i] >> 2;
466 lut[i].green = green[i] >> 2;
467 lut[i].blue = blue[i] >> 2;
474 nv50_crtc_dpms_set(xf86CrtcPtr crtc, int mode)
479 nv50_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
480 DisplayModePtr adjusted_mode)
485 static const xf86CrtcFuncsRec nv50_crtc_funcs = {
486 .dpms = nv50_crtc_dpms_set,
489 .lock = nv50_crtc_lock,
491 .mode_fixup = nv50_crtc_mode_fixup,
492 .prepare = nv50_crtc_prepare,
493 .mode_set = nv50_crtc_mode_set,
494 .gamma_set = nv50_crtc_gamma_set,
495 .commit = nv50_crtc_commit,
496 .shadow_create = NULL,
497 .shadow_destroy = NULL,
498 .set_cursor_position = nv50_crtc_set_cursor_position,
499 .show_cursor = nv50_crtc_show_cursor,
500 .hide_cursor = nv50_crtc_hide_cursor,
501 .load_cursor_argb = nv50_crtc_load_cursor_argb,
505 const xf86CrtcFuncsRec * nv50_get_crtc_funcs()
507 return &nv50_crtc_funcs;