~ubuntu-branches/ubuntu/karmic/xserver-xorg-video-nouveau/karmic

« back to all changes in this revision

Viewing changes to src/nv50_crtc.c

  • Committer: Bazaar Package Importer
  • Author(s): Chris Lamb
  • Date: 2008-07-06 20:26:53 UTC
  • Revision ID: james.westby@ubuntu.com-20080706202653-e99oiii765j3a0qn
Tags: upstream-0.0.10~git+20080706+b1f3169
ImportĀ upstreamĀ versionĀ 0.0.10~git+20080706+b1f3169

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2007 NVIDIA, Corporation
 
3
 * Copyright 2008 Maarten Maathuis
 
4
 *
 
5
 * Permission is hereby granted, free of charge, to any person obtaining a
 
6
 * copy of this software and associated documentation files (the "Software"),
 
7
 * to deal in the Software without restriction, including without limitation
 
8
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
9
 * and/or sell copies of the Software, and to permit persons to whom the
 
10
 * Software is furnished to do so, subject to the following conditions:
 
11
 *
 
12
 * The above copyright notice and this permission notice shall be included in
 
13
 * all copies or substantial portions of the Software.
 
14
 *
 
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
16
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
17
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
18
 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 
19
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
 
20
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
21
 * SOFTWARE.
 
22
 */
 
23
 
 
24
#include "nouveau_modeset.h"
 
25
#include "nouveau_crtc.h"
 
26
#include "nouveau_output.h"
 
27
#include "nouveau_connector.h"
 
28
 
 
29
/* Don't call the directly, only load state should do this on the long run*/
 
30
static void 
 
31
NV50CheckWriteVClk(ScrnInfoPtr pScrn)
 
32
{
 
33
        NVPtr pNv = NVPTR(pScrn);
 
34
        int t_start = GetTimeInMillis();
 
35
 
 
36
        while (NVRead(pNv, NV50_DISPLAY_CTRL_STATE) & NV50_DISPLAY_CTRL_STATE_PENDING) {
 
37
                /* An educated guess. */
 
38
                const uint32_t supervisor = NVRead(pNv, NV50_DISPLAY_SUPERVISOR);
 
39
 
 
40
                /* Just in case something goes bad, at least you can blindly restart your machine. */
 
41
                if ((GetTimeInMillis() - t_start) > 5000) {
 
42
                        xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "NV50CheckWriteVClk() timed out.\n");
 
43
                        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "A reboot is probably required now.\n");
 
44
                        break;
 
45
                }
 
46
 
 
47
                /* Simply acknowledge it, maybe we should do more? */
 
48
                if (supervisor & NV50_DISPLAY_SUPERVISOR_CRTCn) {
 
49
                        NVWrite(pNv, NV50_DISPLAY_SUPERVISOR, supervisor & NV50_DISPLAY_SUPERVISOR_CRTCn);
 
50
                }
 
51
 
 
52
                if (supervisor & NV50_DISPLAY_SUPERVISOR_CLK_MASK) {
 
53
                        if (supervisor & NV50_DISPLAY_SUPERVISOR_CLK_UPDATE) {
 
54
                                const uint32_t clockvar = NVRead(pNv, NV50_DISPLAY_UNK30_CTRL);
 
55
                                int i;
 
56
 
 
57
                                for(i = 0; i < 2; i++) {
 
58
                                        nouveauCrtcPtr crtc = pNv->crtc[i];
 
59
                                        uint32_t mask = 0;
 
60
 
 
61
                                        if (crtc->index == 1)
 
62
                                                mask = NV50_DISPLAY_UNK30_CTRL_UPDATE_VCLK1;
 
63
                                        else
 
64
                                                mask = NV50_DISPLAY_UNK30_CTRL_UPDATE_VCLK0;
 
65
 
 
66
                                        if (clockvar & mask)
 
67
                                                crtc->SetPixelClock(crtc, crtc->pixel_clock);
 
68
                                        /* Always do something if the supervisor wants a clock change. */
 
69
                                        /* This is needed because you get a deadlock if you don't kick the NV50_CRTC0_CLK_CTRL2 register. */
 
70
                                        if (crtc->modeset_lock) {
 
71
                                                crtc->SetClockMode(crtc, crtc->pixel_clock);
 
72
 
 
73
                                                nouveauOutputPtr output;
 
74
                                                for (output = pNv->output; output != NULL; output = output->next) {
 
75
                                                        if (output->crtc == crtc)
 
76
                                                                output->SetClockMode(output, crtc->pixel_clock);
 
77
                                                }
 
78
                                        }
 
79
                                }
 
80
                        }
 
81
 
 
82
                        NVWrite(pNv, NV50_DISPLAY_SUPERVISOR, 1 << (ffs(supervisor & NV50_DISPLAY_SUPERVISOR_CLK_MASK) - 1));
 
83
                        NVWrite(pNv, NV50_DISPLAY_UNK30_CTRL, NV50_DISPLAY_UNK30_CTRL_PENDING);
 
84
                }
 
85
        }
 
86
}
 
87
 
 
88
void NV50DisplayCommand(ScrnInfoPtr pScrn, uint32_t addr, uint32_t value)
 
89
{
 
90
        DDXMMIOH("NV50DisplayCommand: head %d addr 0x%X value 0x%X\n", 0, addr, value);
 
91
        NVPtr pNv = NVPTR(pScrn);
 
92
        NVWrite(pNv, NV50_DISPLAY_CTRL_VAL, value);
 
93
        NVWrite(pNv, NV50_DISPLAY_CTRL_STATE, addr | 0x10000 | NV50_DISPLAY_CTRL_STATE_ENABLE | NV50_DISPLAY_CTRL_STATE_PENDING);
 
94
        NV50CheckWriteVClk(pScrn);
 
95
}
 
96
 
 
97
void NV50CrtcCommand(nouveauCrtcPtr crtc, uint32_t addr, uint32_t value)
 
98
{
 
99
        ScrnInfoPtr pScrn = crtc->scrn;
 
100
 
 
101
        /* This head dependent offset is only for crtc commands. */
 
102
        NV50DisplayCommand(pScrn, addr + 0x400 * crtc->index, value);
 
103
}
 
104
 
 
105
static Bool
 
106
NV50CrtcModeValid(nouveauCrtcPtr crtc, DisplayModePtr mode)
 
107
{
 
108
        return TRUE;
 
109
}
 
110
 
 
111
static void
 
112
NV50CrtcModeSet(nouveauCrtcPtr crtc, DisplayModePtr mode)
 
113
{
 
114
        ScrnInfoPtr pScrn = crtc->scrn;
 
115
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcModeSet is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
 
116
 
 
117
        /* Anyone know a more appropriate name? */
 
118
        DisplayModePtr desired_mode = crtc->use_native_mode ? crtc->native_mode : mode;
 
119
 
 
120
        /* Save the pixel clock for posterity. */
 
121
        crtc->pixel_clock = desired_mode->Clock;
 
122
        crtc->cur_mode = mode;
 
123
 
 
124
        uint32_t hsync_dur = desired_mode->CrtcHSyncEnd - desired_mode->CrtcHSyncStart;
 
125
        uint32_t vsync_dur = desired_mode->CrtcVSyncEnd - desired_mode->CrtcVSyncStart;
 
126
        uint32_t hsync_start_to_end = desired_mode->CrtcHBlankEnd - desired_mode->CrtcHSyncStart;
 
127
        uint32_t vsync_start_to_end = desired_mode->CrtcVBlankEnd - desired_mode->CrtcVSyncStart;
 
128
        /* I can't give this a proper name, anyone else can? */
 
129
        uint32_t hunk1 = desired_mode->CrtcHTotal - desired_mode->CrtcHSyncStart + desired_mode->CrtcHBlankStart;
 
130
        uint32_t vunk1 = desired_mode->CrtcVTotal - desired_mode->CrtcVSyncStart + desired_mode->CrtcVBlankStart;
 
131
        /* Another strange value, this time only for interlaced modes. */
 
132
        uint32_t vunk2a = 2*desired_mode->CrtcVTotal - desired_mode->CrtcVSyncStart + desired_mode->CrtcVBlankStart;
 
133
        uint32_t vunk2b = desired_mode->CrtcVTotal - desired_mode->CrtcVSyncStart + desired_mode->CrtcVBlankEnd;
 
134
 
 
135
        if (desired_mode->Flags & V_INTERLACE) {
 
136
                vsync_dur /= 2;
 
137
                vsync_start_to_end  /= 2;
 
138
                vunk1 /= 2;
 
139
                vunk2a /= 2;
 
140
                vunk2b /= 2;
 
141
                /* magic */
 
142
                if (desired_mode->Flags & V_DBLSCAN) {
 
143
                        vsync_start_to_end -= 1;
 
144
                        vunk1 -= 1;
 
145
                        vunk2a -= 1;
 
146
                        vunk2b -= 1;
 
147
                }
 
148
        }
 
149
 
 
150
        /* NV50CrtcCommand includes head offset */
 
151
        /* This is the native mode when DFP && !SCALE_PANEL */
 
152
        NV50CrtcCommand(crtc, NV50_CRTC0_CLOCK, desired_mode->Clock | 0x800000);
 
153
        NV50CrtcCommand(crtc, NV50_CRTC0_INTERLACE, (desired_mode->Flags & V_INTERLACE) ? 2 : 0);
 
154
        NV50CrtcCommand(crtc, NV50_CRTC0_DISPLAY_START, 0);
 
155
        NV50CrtcCommand(crtc, NV50_CRTC0_UNK82C, 0);
 
156
        NV50CrtcCommand(crtc, NV50_CRTC0_DISPLAY_TOTAL, desired_mode->CrtcVTotal << 16 | desired_mode->CrtcHTotal);
 
157
        NV50CrtcCommand(crtc, NV50_CRTC0_SYNC_DURATION, (vsync_dur - 1) << 16 | (hsync_dur - 1));
 
158
        NV50CrtcCommand(crtc, NV50_CRTC0_SYNC_START_TO_BLANK_END, (vsync_start_to_end - 1) << 16 | (hsync_start_to_end - 1));
 
159
        NV50CrtcCommand(crtc, NV50_CRTC0_MODE_UNK1, (vunk1 - 1) << 16 | (hunk1 - 1));
 
160
        if (desired_mode->Flags & V_INTERLACE) {
 
161
                NV50CrtcCommand(crtc, NV50_CRTC0_MODE_UNK2, (vunk2b - 1) << 16 | (vunk2a - 1));
 
162
        }
 
163
        NV50CrtcCommand(crtc, NV50_CRTC0_FB_SIZE, pScrn->virtualY << 16 | pScrn->virtualX);
 
164
 
 
165
        /* Maybe move this calculation elsewhere? */
 
166
        crtc->fb_pitch = pScrn->displayWidth * (pScrn->bitsPerPixel / 8);
 
167
        NV50CrtcCommand(crtc, NV50_CRTC0_FB_PITCH, crtc->fb_pitch | 0x100000);
 
168
 
 
169
        switch (pScrn->depth) {
 
170
                case 8:
 
171
                        NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_8BPP); 
 
172
                        break;
 
173
                case 15:
 
174
                        NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_15BPP);
 
175
                        break;
 
176
                case 16:
 
177
                        NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_16BPP);
 
178
                        break;
 
179
                case 24:
 
180
                        NV50CrtcCommand(crtc, NV50_CRTC0_DEPTH, NV50_CRTC0_DEPTH_24BPP); 
 
181
                        break;
 
182
        }
 
183
        crtc->SetDither(crtc);
 
184
        NV50CrtcCommand(crtc, NV50_CRTC0_COLOR_CTRL, NV50_CRTC_COLOR_CTRL_MODE_COLOR);
 
185
        NV50CrtcCommand(crtc, NV50_CRTC0_FB_POS, (crtc->y << 16) | (crtc->x));
 
186
        /* This is the actual resolution of the mode. */
 
187
        NV50CrtcCommand(crtc, NV50_CRTC0_REAL_RES, (mode->VDisplay << 16) | mode->HDisplay);
 
188
        NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_CENTER_OFFSET, NV50_CRTC_SCALE_CENTER_OFFSET_VAL(0,0));
 
189
 
 
190
        /* Maybe move this as well? */
 
191
        crtc->Blank(crtc, FALSE);
 
192
}
 
193
 
 
194
static void
 
195
NV50CrtcSetPixelClock(nouveauCrtcPtr crtc, int clock)
 
196
{
 
197
        ScrnInfoPtr pScrn = crtc->scrn;
 
198
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetPixelClock is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
 
199
 
 
200
        NVPtr pNv = NVPTR(pScrn);
 
201
 
 
202
        /* I don't know why exactly, but these were in my table. */
 
203
        uint32_t pll_reg = crtc->index ? NV50_CRTC1_CLK_CTRL1 : NV50_CRTC0_CLK_CTRL1;
 
204
 
 
205
        int NM1 = 0xbeef, NM2 = 0xdead, log2P;
 
206
        struct pll_lims pll_lim;
 
207
        get_pll_limits(pScrn, pll_reg, &pll_lim);
 
208
        /* NV5x hardware doesn't seem to support a single vco mode, otherwise the blob is hiding it well. */
 
209
        getMNP_double(pScrn, &pll_lim, clock, &NM1, &NM2, &log2P);
 
210
 
 
211
        uint32_t reg1 = NVRead(pNv, pll_reg + 4);
 
212
        uint32_t reg2 = NVRead(pNv, pll_reg + 8);
 
213
 
 
214
        /* bit0: The blob (and bios) seem to have this on (almost) always.
 
215
         *          I'm hoping this (experiment) will fix my image stability issues.
 
216
         */
 
217
        NVWrite(pNv, NV50_CRTC0_CLK_CTRL1 + crtc->index * 0x800, NV50_CRTC_CLK_CTRL1_CONNECTED | 0x10000011);
 
218
 
 
219
        /* Eventually we should learn ourselves what all the bits should be. */
 
220
        reg1 &= 0xff00ff00;
 
221
        reg2 &= 0x8000ff00;
 
222
 
 
223
        uint8_t N1 = (NM1 >> 8) & 0xFF;
 
224
        uint8_t M1 = NM1 & 0xFF;
 
225
        uint8_t N2 = (NM2 >> 8) & 0xFF;
 
226
        uint8_t M2 = NM2 & 0xFF;
 
227
 
 
228
        reg1 |= (M1 << 16) | N1;
 
229
        reg2 |= (log2P << 28) | (M2 << 16) | N2;
 
230
 
 
231
        NVWrite(pNv, pll_reg + 4, reg1);
 
232
        NVWrite(pNv, pll_reg + 8, reg2);
 
233
}
 
234
 
 
235
static void
 
236
NV50CrtcSetClockMode(nouveauCrtcPtr crtc, int clock)
 
237
{
 
238
        ScrnInfoPtr pScrn = crtc->scrn;
 
239
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetClockMode is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
 
240
 
 
241
        NVPtr pNv = NVPTR(pScrn);
 
242
 
 
243
        /* There seem to be a few indicator bits, which are similar to the SOR_CTRL bits. */
 
244
        NVWrite(pNv, NV50_CRTC0_CLK_CTRL2 + crtc->index * 0x800, 0);
 
245
}
 
246
 
 
247
static void
 
248
NV50CrtcSetFB(nouveauCrtcPtr crtc, struct nouveau_bo * buffer)
 
249
{
 
250
        /* For the moment the actual hardware settings stays in ModeSet(). */
 
251
        crtc->front_buffer = buffer;
 
252
}
 
253
 
 
254
static void 
 
255
NV50CrtcSetFBOffset(nouveauCrtcPtr crtc, uint32_t x, uint32_t y)
 
256
{
 
257
        /* For the moment the actual hardware settings stays in ModeSet(). */
 
258
        crtc->x = x;
 
259
        crtc->y = y;
 
260
}
 
261
 
 
262
static void 
 
263
NV50CrtcBlank(nouveauCrtcPtr crtc, Bool blanked)
 
264
{
 
265
        ScrnInfoPtr pScrn = crtc->scrn;
 
266
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcBlank is called (%s) for %s.\n", blanked ? "blanked" : "unblanked", crtc->index ? "CRTC1" : "CRTC0");
 
267
 
 
268
        NVPtr pNv = NVPTR(pScrn);
 
269
 
 
270
        if (blanked) {
 
271
                crtc->HideCursor(crtc, TRUE);
 
272
 
 
273
                NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_MODE, NV50_CRTC0_CLUT_MODE_BLANK);
 
274
                NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, 0);
 
275
                if (pNv->NVArch != 0x50)
 
276
                        NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK1, NV84_CRTC0_BLANK_UNK1_BLANK);
 
277
                NV50CrtcCommand(crtc, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_BLANK);
 
278
                if (pNv->NVArch != 0x50)
 
279
                        NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK2, NV84_CRTC0_BLANK_UNK2_BLANK);
 
280
        } else {
 
281
                NV50CrtcCommand(crtc, NV50_CRTC0_FB_OFFSET, crtc->front_buffer->offset >> 8);
 
282
                NV50CrtcCommand(crtc, 0x864, 0);
 
283
                NVWrite(pNv, NV50_DISPLAY_UNK_380, 0);
 
284
                /* RAM is clamped to 256 MiB. */
 
285
                NVWrite(pNv, NV50_DISPLAY_RAM_AMOUNT, pNv->RamAmountKBytes * 1024 - 1);
 
286
                NVWrite(pNv, NV50_DISPLAY_UNK_388, 0x150000);
 
287
                NVWrite(pNv, NV50_DISPLAY_UNK_38C, 0);
 
288
                if (crtc->index == 1)
 
289
                        NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_OFFSET, pNv->Cursor2->offset >> 8);
 
290
                else
 
291
                        NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_OFFSET, pNv->Cursor->offset >> 8);
 
292
                if(pNv->NVArch != 0x50)
 
293
                        NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK2, NV84_CRTC0_BLANK_UNK2_UNBLANK);
 
294
 
 
295
                if (crtc->cursor_visible)
 
296
                        crtc->ShowCursor(crtc, TRUE);
 
297
 
 
298
                NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_MODE, 
 
299
                        pScrn->depth == 8 ? NV50_CRTC0_CLUT_MODE_OFF : NV50_CRTC0_CLUT_MODE_ON);
 
300
                /* Each CRTC has it's own CLUT. */
 
301
                if (crtc->index == 1)
 
302
                        NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, pNv->CLUT1->offset >> 8);
 
303
                else
 
304
                        NV50CrtcCommand(crtc, NV50_CRTC0_CLUT_OFFSET, pNv->CLUT0->offset >> 8);
 
305
                if (pNv->NVArch != 0x50)
 
306
                        NV50CrtcCommand(crtc, NV84_CRTC0_BLANK_UNK1, NV84_CRTC0_BLANK_UNK1_UNBLANK);
 
307
                NV50CrtcCommand(crtc, NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_UNBLANK);
 
308
        }
 
309
}
 
310
 
 
311
static void
 
312
NV50CrtcSetDither(nouveauCrtcPtr crtc)
 
313
{
 
314
        ScrnInfoPtr pScrn = crtc->scrn;
 
315
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetDither is called (%s).\n", !crtc->modeset_lock ? "update" : "no update");
 
316
 
 
317
        NV50CrtcCommand(crtc, NV50_CRTC0_DITHERING_CTRL, crtc->dithering ? 
 
318
                        NV50_CRTC0_DITHERING_CTRL_ON : NV50_CRTC0_DITHERING_CTRL_OFF);
 
319
 
 
320
        if (!crtc->modeset_lock)
 
321
                NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
 
322
}
 
323
 
 
324
static void
 
325
ComputeAspectScale(DisplayModePtr mode, DisplayModePtr adjusted_mode, int *outX, int *outY)
 
326
{
 
327
        float scaleX, scaleY, scale;
 
328
 
 
329
        scaleX = adjusted_mode->HDisplay / (float)mode->HDisplay;
 
330
        scaleY = adjusted_mode->VDisplay / (float)mode->VDisplay;
 
331
 
 
332
        if (scaleX > scaleY)
 
333
                scale = scaleY;
 
334
        else
 
335
                scale = scaleX;
 
336
 
 
337
        *outX = mode->HDisplay * scale;
 
338
        *outY = mode->VDisplay * scale;
 
339
}
 
340
 
 
341
static void
 
342
NV50CrtcSetScaleMode(nouveauCrtcPtr crtc, int scale)
 
343
{
 
344
        ScrnInfoPtr pScrn = crtc->scrn;
 
345
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcSetScale is called with mode %d for %s.\n", scale, crtc->index ? "CRTC1" : "CRTC0");
 
346
 
 
347
        uint32_t scale_val = 0;
 
348
        int outX = 0, outY = 0;
 
349
 
 
350
        switch(scale) {
 
351
                case SCALE_ASPECT:
 
352
                        ComputeAspectScale(crtc->cur_mode, crtc->native_mode, &outX, &outY);
 
353
                        break;
 
354
                case SCALE_FULLSCREEN:
 
355
                        outX = crtc->native_mode->HDisplay;
 
356
                        outY = crtc->native_mode->VDisplay;
 
357
                        break;
 
358
                case SCALE_NOSCALE:
 
359
                case SCALE_PANEL:
 
360
                default:
 
361
                        outX = crtc->cur_mode->HDisplay;
 
362
                        outY = crtc->cur_mode->VDisplay;
 
363
                        break;
 
364
        }
 
365
 
 
366
        /* Got a better name for SCALER_ACTIVE? */
 
367
        if ((crtc->cur_mode->Flags & V_DBLSCAN) || (crtc->cur_mode->Flags & V_INTERLACE) ||
 
368
                crtc->cur_mode->HDisplay != outX || crtc->cur_mode->VDisplay != outY) {
 
369
                scale_val = NV50_CRTC0_SCALE_CTRL_SCALER_ACTIVE;
 
370
        } else {
 
371
                scale_val = NV50_CRTC0_SCALE_CTRL_SCALER_INACTIVE;
 
372
        }
 
373
 
 
374
        NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_CTRL, scale_val);
 
375
        NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_RES1, outY << 16 | outX);
 
376
        NV50CrtcCommand(crtc, NV50_CRTC0_SCALE_RES2, outY << 16 | outX);
 
377
}
 
378
 
 
379
/*
 
380
 * Cursor stuff.
 
381
 */
 
382
 
 
383
static void
 
384
NV50CrtcShowCursor(nouveauCrtcPtr crtc, Bool forced_lock)
 
385
{
 
386
        ScrnInfoPtr pScrn = crtc->scrn;
 
387
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcShowCursor is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
 
388
 
 
389
        if (!crtc->modeset_lock)
 
390
                crtc->cursor_visible = TRUE;
 
391
 
 
392
        NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_CTRL, NV50_CRTC0_CURSOR_CTRL_SHOW);
 
393
 
 
394
        /* Calling this during modeset will lock things up. */
 
395
        if (!crtc->modeset_lock && !forced_lock)
 
396
                NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
 
397
}
 
398
 
 
399
static void
 
400
NV50CrtcHideCursor(nouveauCrtcPtr crtc, Bool forced_lock)
 
401
{
 
402
        ScrnInfoPtr pScrn = crtc->scrn;
 
403
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcHideCursor is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
 
404
 
 
405
        if (!crtc->modeset_lock)
 
406
                crtc->cursor_visible = FALSE;
 
407
 
 
408
        NV50CrtcCommand(crtc, NV50_CRTC0_CURSOR_CTRL, NV50_CRTC0_CURSOR_CTRL_HIDE);
 
409
 
 
410
        /* Calling this during modeset will lock things up. */
 
411
        if (!crtc->modeset_lock && !forced_lock)
 
412
                NV50DisplayCommand(pScrn, NV50_UPDATE_DISPLAY, 0);
 
413
}
 
414
 
 
415
static void
 
416
NV50CrtcSetCursorPosition(nouveauCrtcPtr crtc, int x, int y)
 
417
{
 
418
        ScrnInfoPtr pScrn = crtc->scrn;
 
419
        NVPtr pNv = NVPTR(pScrn);
 
420
        NVWrite(pNv, NV50_CRTC0_CURSOR_POS + crtc->index * 0x1000, (y & 0xFFFF) << 16 | (x & 0xFFFF));
 
421
 
 
422
        /* This is needed to allow the cursor to move. */
 
423
        NVWrite(pNv, NV50_CRTC0_CURSOR_POS_CTRL + crtc->index * 0x1000, 0);
 
424
}
 
425
 
 
426
static void
 
427
NV50CrtcLoadCursor(nouveauCrtcPtr crtc, Bool argb, uint32_t *src)
 
428
{
 
429
        if (!argb) /* FIXME */
 
430
                return;
 
431
 
 
432
        NVPtr pNv = NVPTR(crtc->scrn);
 
433
        uint32_t *dst = NULL;
 
434
 
 
435
        if (crtc->index == 1)
 
436
                dst = (uint32_t *) pNv->Cursor2->map;
 
437
        else
 
438
                dst = (uint32_t *) pNv->Cursor->map;
 
439
 
 
440
        /* Assume cursor is 64x64 */
 
441
        memcpy(dst, src, 64 * 64 * 4);
 
442
}
 
443
 
 
444
/*
 
445
 * Gamma stuff.
 
446
 */
 
447
 
 
448
/*
 
449
 * The indices are a bit strange, but i'll assume it's correct (taken from nv).
 
450
 * The LUT resolution seems to be 14 bits on NV50 as opposed to the 8 bits of previous hardware.
 
451
 */
 
452
#define NV50_LUT_INDEX(val, w) ((val << (8 - w)) | (val >> ((w << 1) - 8)))
 
453
static void
 
454
NV50CrtcGammaSet(nouveauCrtcPtr crtc, uint16_t *red, uint16_t *green, uint16_t *blue, int size)
 
455
{
 
456
        ScrnInfoPtr pScrn = crtc->scrn;
 
457
        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV50CrtcGammaSet is called for %s.\n", crtc->index ? "CRTC1" : "CRTC0");
 
458
 
 
459
        NVPtr pNv = NVPTR(pScrn);
 
460
        uint32_t index, i;
 
461
        void * CLUT = NULL;
 
462
 
 
463
        /* Each CRTC has it's own CLUT. */
 
464
        if (crtc->index == 1)
 
465
                CLUT = pNv->CLUT1->map;
 
466
        else
 
467
                CLUT = pNv->CLUT0->map;
 
468
 
 
469
        volatile struct {
 
470
                unsigned short red, green, blue, unused;
 
471
        } *lut = (void *) CLUT;
 
472
 
 
473
        switch (pScrn->depth) {
 
474
        case 15:
 
475
                /* R5G5B5 */
 
476
                for (i = 0; i < 32; i++) {
 
477
                        index = NV50_LUT_INDEX(i, 5);
 
478
                        lut[index].red = red[i] >> 2;
 
479
                        lut[index].green = green[i] >> 2;
 
480
                        lut[index].blue = blue[i] >> 2;
 
481
                }
 
482
                break;
 
483
        case 16:
 
484
                /* R5G6B5 */
 
485
                for (i = 0; i < 32; i++) {
 
486
                        index = NV50_LUT_INDEX(i, 5);
 
487
                        lut[index].red = red[i] >> 2;
 
488
                        lut[index].blue = blue[i] >> 2;
 
489
                }
 
490
 
 
491
                /* Green has an extra bit. */
 
492
                for (i = 0; i < 64; i++) {
 
493
                        index = NV50_LUT_INDEX(i, 6);
 
494
                        lut[index].green = green[i] >> 2;
 
495
                }
 
496
                break;
 
497
        default:
 
498
                /* R8G8B8 */
 
499
                for (i = 0; i < 256; i++) {
 
500
                        lut[i].red = red[i] >> 2;
 
501
                        lut[i].green = green[i] >> 2;
 
502
                        lut[i].blue = blue[i] >> 2;
 
503
                }
 
504
                break;
 
505
        }
 
506
}
 
507
 
 
508
void
 
509
NV50CrtcInit(ScrnInfoPtr pScrn)
 
510
{
 
511
        int i;
 
512
        NVPtr pNv = NVPTR(pScrn);
 
513
 
 
514
        for (i=0; i < 2; i++) {
 
515
                nouveauCrtcPtr crtc = xnfcalloc(sizeof(nouveauCrtcRec), 1);
 
516
                crtc->scrn = pScrn;
 
517
                crtc->index = i;
 
518
 
 
519
                /* Function pointers. */
 
520
                crtc->ModeValid = NV50CrtcModeValid;
 
521
                crtc->ModeSet = NV50CrtcModeSet;
 
522
                crtc->SetPixelClock = NV50CrtcSetPixelClock;
 
523
                crtc->SetClockMode = NV50CrtcSetClockMode;
 
524
 
 
525
                crtc->SetFB = NV50CrtcSetFB;
 
526
                crtc->SetFBOffset = NV50CrtcSetFBOffset;
 
527
 
 
528
                crtc->Blank = NV50CrtcBlank;
 
529
                crtc->SetDither = NV50CrtcSetDither;
 
530
 
 
531
                crtc->SetScaleMode = NV50CrtcSetScaleMode;
 
532
 
 
533
                crtc->ShowCursor = NV50CrtcShowCursor;
 
534
                crtc->HideCursor = NV50CrtcHideCursor;
 
535
                crtc->SetCursorPosition = NV50CrtcSetCursorPosition;
 
536
                crtc->LoadCursor = NV50CrtcLoadCursor;
 
537
 
 
538
                crtc->GammaSet = NV50CrtcGammaSet;
 
539
 
 
540
                pNv->crtc[i] = crtc;
 
541
        }
 
542
}
 
543
 
 
544
void
 
545
NV50CrtcDestroy(ScrnInfoPtr pScrn)
 
546
{
 
547
        int i;
 
548
        NVPtr pNv = NVPTR(pScrn);
 
549
 
 
550
        for (i=0; i < 2; i++) {
 
551
                nouveauCrtcPtr crtc = pNv->crtc[i];
 
552
 
 
553
                xfree(crtc->name);
 
554
                xfree(crtc);
 
555
                pNv->crtc[i] = NULL;
 
556
        }
 
557
}