modesetting-101: rename modeflags, as to avoid conflicts with the xorg definitions
[platform/upstream/libdrm.git] / linux-core / nv50_crtc.c
1 /*
2  * Copyright (C) 2008 Maarten Maathuis.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a 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:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  */
26
27 #include "nv50_crtc.h"
28 #include "nv50_cursor.h"
29 #include "nv50_lut.h"
30 #include "nv50_fb.h"
31
32 static int nv50_crtc_validate_mode(struct nv50_crtc *crtc, struct nouveau_hw_mode *mode)
33 {
34         NV50_DEBUG("\n");
35
36         if (mode->clock > 400000)
37                 return MODE_CLOCK_HIGH;
38
39         if (mode->clock < 25000)
40                 return MODE_CLOCK_LOW;
41
42         return MODE_OK;
43 }
44
45 static int nv50_crtc_set_mode(struct nv50_crtc *crtc, struct nouveau_hw_mode *mode)
46 {
47         struct nouveau_hw_mode *hw_mode = crtc->mode;
48         uint8_t rval;
49
50         NV50_DEBUG("index %d\n", crtc->index);
51
52         if (!mode) {
53                 DRM_ERROR("No mode\n");
54                 return MODE_NOMODE;
55         }
56
57         if ((rval = crtc->validate_mode(crtc, mode))) {
58                 DRM_ERROR("Mode invalid\n");
59                 return rval;
60         }
61
62         /* copy values to mode */
63         *hw_mode = *mode;
64
65         return 0;
66 }
67
68 static int nv50_crtc_execute_mode(struct nv50_crtc *crtc)
69 {
70         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
71         struct nouveau_hw_mode *hw_mode;
72         uint32_t hsync_dur,  vsync_dur, hsync_start_to_end, vsync_start_to_end;
73         uint32_t hunk1, vunk1, vunk2a, vunk2b;
74         uint32_t offset = crtc->index * 0x400;
75
76         NV50_DEBUG("index %d\n", crtc->index);
77         NV50_DEBUG("%s native mode\n", crtc->use_native_mode ? "using" : "not using");
78
79         if (crtc->use_native_mode)
80                 hw_mode = crtc->native_mode;
81         else
82                 hw_mode = crtc->mode;
83
84         hsync_dur = hw_mode->hsync_end - hw_mode->hsync_start;
85         vsync_dur = hw_mode->vsync_end - hw_mode->vsync_start;
86         hsync_start_to_end = hw_mode->hblank_end - hw_mode->hsync_start;
87         vsync_start_to_end = hw_mode->vblank_end - hw_mode->vsync_start;
88         /* I can't give this a proper name, anyone else can? */
89         hunk1 = hw_mode->htotal - hw_mode->hsync_start + hw_mode->hblank_start;
90         vunk1 = hw_mode->vtotal - hw_mode->vsync_start + hw_mode->vblank_start;
91         /* Another strange value, this time only for interlaced modes. */
92         vunk2a = 2*hw_mode->vtotal - hw_mode->vsync_start + hw_mode->vblank_start;
93         vunk2b = hw_mode->vtotal - hw_mode->vsync_start + hw_mode->vblank_end;
94
95         if (hw_mode->flags & DRM_MODE_FLAG_INTERLACE) {
96                 vsync_dur /= 2;
97                 vsync_start_to_end  /= 2;
98                 vunk1 /= 2;
99                 vunk2a /= 2;
100                 vunk2b /= 2;
101                 /* magic */
102                 if (hw_mode->flags & DRM_MODE_FLAG_DBLSCAN) {
103                         vsync_start_to_end -= 1;
104                         vunk1 -= 1;
105                         vunk2a -= 1;
106                         vunk2b -= 1;
107                 }
108         }
109
110         OUT_MODE(NV50_CRTC0_CLOCK + offset, hw_mode->clock | 0x800000);
111         OUT_MODE(NV50_CRTC0_INTERLACE + offset, (hw_mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 0);
112         OUT_MODE(NV50_CRTC0_DISPLAY_START + offset, 0);
113         OUT_MODE(NV50_CRTC0_UNK82C + offset, 0);
114         OUT_MODE(NV50_CRTC0_DISPLAY_TOTAL + offset, hw_mode->vtotal << 16 | hw_mode->htotal);
115         OUT_MODE(NV50_CRTC0_SYNC_DURATION + offset, (vsync_dur - 1) << 16 | (hsync_dur - 1));
116         OUT_MODE(NV50_CRTC0_SYNC_START_TO_BLANK_END + offset, (vsync_start_to_end - 1) << 16 | (hsync_start_to_end - 1));
117         OUT_MODE(NV50_CRTC0_MODE_UNK1 + offset, (vunk1 - 1) << 16 | (hunk1 - 1));
118         if (hw_mode->flags & DRM_MODE_FLAG_INTERLACE) {
119                 OUT_MODE(NV50_CRTC0_MODE_UNK2 + offset, (vunk2b - 1) << 16 | (vunk2a - 1));
120         }
121
122         crtc->set_fb(crtc);
123         crtc->set_dither(crtc);
124
125         /* This is the actual resolution of the mode. */
126         OUT_MODE(NV50_CRTC0_REAL_RES + offset, (crtc->mode->vdisplay << 16) | crtc->mode->hdisplay);
127         OUT_MODE(NV50_CRTC0_SCALE_CENTER_OFFSET + offset, NV50_CRTC_SCALE_CENTER_OFFSET_VAL(0,0));
128
129         /* Maybe move this as well? */
130         crtc->blank(crtc, FALSE);
131
132         return 0;
133 }
134
135 static int nv50_crtc_set_fb(struct nv50_crtc *crtc)
136 {
137         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
138         uint32_t offset = crtc->index * 0x400;
139
140         NV50_DEBUG("\n");
141
142         OUT_MODE(NV50_CRTC0_FB_SIZE + offset, crtc->fb->height << 16 | crtc->fb->width);
143
144         /* I suspect this flag indicates a linear fb. */
145         OUT_MODE(NV50_CRTC0_FB_PITCH + offset, crtc->fb->pitch | 0x100000);
146
147         switch (crtc->fb->depth) {
148                 case 8:
149                         OUT_MODE(NV50_CRTC0_DEPTH + offset, NV50_CRTC0_DEPTH_8BPP); 
150                         break;
151                 case 15:
152                         OUT_MODE(NV50_CRTC0_DEPTH + offset, NV50_CRTC0_DEPTH_15BPP);
153                         break;
154                 case 16:
155                         OUT_MODE(NV50_CRTC0_DEPTH + offset, NV50_CRTC0_DEPTH_16BPP);
156                         break;
157                 case 24:
158                         OUT_MODE(NV50_CRTC0_DEPTH + offset, NV50_CRTC0_DEPTH_24BPP); 
159                         break;
160         }
161
162         OUT_MODE(NV50_CRTC0_COLOR_CTRL + offset, NV50_CRTC_COLOR_CTRL_MODE_COLOR);
163         OUT_MODE(NV50_CRTC0_FB_POS + offset, (crtc->fb->y << 16) | (crtc->fb->x));
164
165         return 0;
166 }
167
168 static int nv50_crtc_blank(struct nv50_crtc *crtc, bool blanked)
169 {
170         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
171         uint32_t offset = crtc->index * 0x400;
172
173         NV50_DEBUG("index %d\n", crtc->index);
174         NV50_DEBUG("%s\n", blanked ? "blanked" : "unblanked");
175
176         /* We really need a framebuffer. */
177         if (!crtc->fb->block && !blanked) {
178                 DRM_ERROR("No framebuffer available on crtc %d\n", crtc->index);
179                 return -EINVAL;
180         }
181
182         if (blanked) {
183                 crtc->cursor->hide(crtc);
184
185                 OUT_MODE(NV50_CRTC0_CLUT_MODE + offset, NV50_CRTC0_CLUT_MODE_BLANK);
186                 OUT_MODE(NV50_CRTC0_CLUT_OFFSET + offset, 0);
187                 if (dev_priv->chipset != 0x50)
188                         OUT_MODE(NV84_CRTC0_BLANK_UNK1 + offset, NV84_CRTC0_BLANK_UNK1_BLANK);
189                 OUT_MODE(NV50_CRTC0_BLANK_CTRL + offset, NV50_CRTC0_BLANK_CTRL_BLANK);
190                 if (dev_priv->chipset != 0x50)
191                         OUT_MODE(NV84_CRTC0_BLANK_UNK2 + offset, NV84_CRTC0_BLANK_UNK2_BLANK);
192         } else {
193                 OUT_MODE(NV50_CRTC0_FB_OFFSET + offset, crtc->fb->block->start >> 8);
194                 OUT_MODE(0x864 + offset, 0);
195
196                 crtc->cursor->set_offset(crtc);
197
198                 if (dev_priv->chipset != 0x50)
199                         OUT_MODE(NV84_CRTC0_BLANK_UNK2 + offset, NV84_CRTC0_BLANK_UNK2_UNBLANK);
200
201                 if (crtc->cursor->visible)
202                         crtc->cursor->show(crtc);
203                 else
204                         crtc->cursor->hide(crtc);
205
206                 OUT_MODE(NV50_CRTC0_CLUT_MODE + offset, 
207                         crtc->fb->depth == 8 ? NV50_CRTC0_CLUT_MODE_OFF : NV50_CRTC0_CLUT_MODE_ON);
208                 OUT_MODE(NV50_CRTC0_CLUT_OFFSET + offset, crtc->lut->block->start >> 8);
209                 if (dev_priv->chipset != 0x50)
210                         OUT_MODE(NV84_CRTC0_BLANK_UNK1 + offset, NV84_CRTC0_BLANK_UNK1_UNBLANK);
211                 OUT_MODE(NV50_CRTC0_BLANK_CTRL + offset, NV50_CRTC0_BLANK_CTRL_UNBLANK);
212         }
213
214         /* sometimes you need to know if a screen is already blanked. */
215         crtc->blanked = blanked;
216
217         return 0;
218 }
219
220 static int nv50_crtc_set_dither(struct nv50_crtc *crtc)
221 {
222         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
223         uint32_t offset = crtc->index * 0x400;
224
225         NV50_DEBUG("\n");
226
227         OUT_MODE(NV50_CRTC0_DITHERING_CTRL + offset, crtc->use_dithering ? 
228                         NV50_CRTC0_DITHERING_CTRL_ON : NV50_CRTC0_DITHERING_CTRL_OFF);
229
230         return 0;
231 }
232
233 static void nv50_crtc_calc_scale(struct nv50_crtc *crtc, uint32_t *outX, uint32_t *outY)
234 {
235         uint32_t hor_scale, ver_scale;
236
237         /* max res is 8192, which is 2^13, which leaves 19 bits */
238         hor_scale = (crtc->native_mode->hdisplay << 19)/crtc->mode->hdisplay;
239         ver_scale = (crtc->native_mode->vdisplay << 19)/crtc->mode->vdisplay;
240
241         if (ver_scale > hor_scale) {
242                 *outX = (crtc->mode->hdisplay * hor_scale) >> 19;
243                 *outY = (crtc->mode->vdisplay * hor_scale) >> 19;
244         } else {
245                 *outX = (crtc->mode->hdisplay * ver_scale) >> 19;
246                 *outY = (crtc->mode->vdisplay * ver_scale) >> 19;
247         }
248 }
249
250 static int nv50_crtc_set_scale(struct nv50_crtc *crtc)
251 {
252         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
253         uint32_t offset = crtc->index * 0x400;
254         uint32_t outX, outY;
255
256         NV50_DEBUG("\n");
257
258         switch (crtc->scaling_mode) {
259                 case SCALE_ASPECT:
260                         nv50_crtc_calc_scale(crtc, &outX, &outY);
261                         break;
262                 case SCALE_FULLSCREEN:
263                         outX = crtc->native_mode->hdisplay;
264                         outY = crtc->native_mode->vdisplay;
265                         break;
266                 case SCALE_NOSCALE:
267                 case SCALE_PANEL:
268                 default:
269                         outX = crtc->mode->hdisplay;
270                         outY = crtc->mode->vdisplay;
271                         break;
272         }
273
274         /* Got a better name for SCALER_ACTIVE? */
275         /* One day i've got to really figure out why this is needed. */
276         if ((crtc->mode->flags & DRM_MODE_FLAG_DBLSCAN) || (crtc->mode->flags & DRM_MODE_FLAG_INTERLACE) ||
277                 crtc->mode->hdisplay != outX || crtc->mode->vdisplay != outY) {
278                 OUT_MODE(NV50_CRTC0_SCALE_CTRL + offset, NV50_CRTC0_SCALE_CTRL_SCALER_ACTIVE);
279         } else {
280                 OUT_MODE(NV50_CRTC0_SCALE_CTRL + offset, NV50_CRTC0_SCALE_CTRL_SCALER_INACTIVE);
281         }
282
283         OUT_MODE(NV50_CRTC0_SCALE_RES1 + offset, outY << 16 | outX);
284         OUT_MODE(NV50_CRTC0_SCALE_RES2 + offset, outY << 16 | outX);
285
286         return 0;
287 }
288
289 static int nv50_crtc_calc_clock(struct nv50_crtc *crtc, 
290         uint32_t *bestN1, uint32_t *bestN2, uint32_t *bestM1, uint32_t *bestM2, uint32_t *bestlog2P)
291 {
292         struct nouveau_hw_mode *hw_mode;
293         struct pll_lims limits;
294         int clk, vco2, crystal;
295         int minvco1, minvco2, minU1, maxU1, minU2, maxU2, minM1, maxM1;
296         int maxvco1, maxvco2, minN1, maxN1, minM2, maxM2, minN2, maxN2;
297         bool fixedgain2;
298         int M1, N1, M2, N2, log2P;
299         int clkP, calcclk1, calcclk2, calcclkout;
300         int delta, bestdelta = INT_MAX;
301         int bestclk = 0;
302
303         NV50_DEBUG("\n");
304
305         if (crtc->use_native_mode)
306                 hw_mode = crtc->native_mode;
307         else
308                 hw_mode = crtc->mode;
309
310         clk = hw_mode->clock;
311
312         /* These are in the g80 bios tables, at least in mine. */
313         if (!get_pll_limits(crtc->dev, NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(crtc->index), &limits))
314                 return -EINVAL;
315
316         minvco1 = limits.vco1.minfreq, maxvco1 = limits.vco1.maxfreq;
317         minvco2 = limits.vco2.minfreq, maxvco2 = limits.vco2.maxfreq;
318         minU1 = limits.vco1.min_inputfreq, minU2 = limits.vco2.min_inputfreq;
319         maxU1 = limits.vco1.max_inputfreq, maxU2 = limits.vco2.max_inputfreq;
320         minM1 = limits.vco1.min_m, maxM1 = limits.vco1.max_m;
321         minN1 = limits.vco1.min_n, maxN1 = limits.vco1.max_n;
322         minM2 = limits.vco2.min_m, maxM2 = limits.vco2.max_m;
323         minN2 = limits.vco2.min_n, maxN2 = limits.vco2.max_n;
324         crystal = limits.refclk;
325         fixedgain2 = (minM2 == maxM2 && minN2 == maxN2);
326
327         vco2 = (maxvco2 - maxvco2/200) / 2;
328         for (log2P = 0; clk && log2P < 6 && clk <= (vco2 >> log2P); log2P++) /* log2P is maximum of 6 */
329                 ;
330         clkP = clk << log2P;
331
332         if (maxvco2 < clk + clk/200)    /* +0.5% */
333                 maxvco2 = clk + clk/200;
334
335         for (M1 = minM1; M1 <= maxM1; M1++) {
336                 if (crystal/M1 < minU1)
337                         return bestclk;
338                 if (crystal/M1 > maxU1)
339                         continue;
340
341                 for (N1 = minN1; N1 <= maxN1; N1++) {
342                         calcclk1 = crystal * N1 / M1;
343                         if (calcclk1 < minvco1)
344                                 continue;
345                         if (calcclk1 > maxvco1)
346                                 break;
347
348                         for (M2 = minM2; M2 <= maxM2; M2++) {
349                                 if (calcclk1/M2 < minU2)
350                                         break;
351                                 if (calcclk1/M2 > maxU2)
352                                         continue;
353
354                                 /* add calcclk1/2 to round better */
355                                 N2 = (clkP * M2 + calcclk1/2) / calcclk1;
356                                 if (N2 < minN2)
357                                         continue;
358                                 if (N2 > maxN2)
359                                         break;
360
361                                 if (!fixedgain2) {
362                                         calcclk2 = calcclk1 * N2 / M2;
363                                         if (calcclk2 < minvco2)
364                                                 break;
365                                         if (calcclk2 > maxvco2)
366                                                 continue;
367                                 } else
368                                         calcclk2 = calcclk1;
369
370                                 calcclkout = calcclk2 >> log2P;
371                                 delta = abs(calcclkout - clk);
372                                 /* we do an exhaustive search rather than terminating
373                                  * on an optimality condition...
374                                  */
375                                 if (delta < bestdelta) {
376                                         bestdelta = delta;
377                                         bestclk = calcclkout;
378                                         *bestN1 = N1;
379                                         *bestN2 = N2;
380                                         *bestM1 = M1;
381                                         *bestM2 = M2;
382                                         *bestlog2P = log2P;
383                                         if (delta == 0) /* except this one */
384                                                 return bestclk;
385                                 }
386                         }
387                 }
388         }
389
390         return bestclk;
391 }
392
393 static int nv50_crtc_set_clock(struct nv50_crtc *crtc)
394 {
395         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
396
397         uint32_t pll_reg = NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(crtc->index);
398
399         uint32_t N1 = 0, N2 = 0, M1 = 0, M2 = 0, log2P = 0;
400
401         uint32_t reg1 = NV_READ(pll_reg + 4);
402         uint32_t reg2 = NV_READ(pll_reg + 8);
403
404         NV50_DEBUG("\n");
405
406         NV_WRITE(pll_reg, NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1_CONNECTED | 0x10000011);
407
408         /* The other bits are typically empty, but let's be on the safe side. */
409         reg1 &= 0xff00ff00;
410         reg2 &= 0x8000ff00;
411
412         if (!nv50_crtc_calc_clock(crtc, &N1, &N2, &M1, &M2, &log2P))
413                 return -EINVAL;
414
415         NV50_DEBUG("N1 %d N2 %d M1 %d M2 %d log2P %d\n", N1, N2, M1, M2, log2P);
416
417         reg1 |= (M1 << 16) | N1;
418         reg2 |= (log2P << 28) | (M2 << 16) | N2;
419
420         NV_WRITE(pll_reg + 4, reg1);
421         NV_WRITE(pll_reg + 8, reg2);
422
423         return 0;
424 }
425
426 static int nv50_crtc_set_clock_mode(struct nv50_crtc *crtc)
427 {
428         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
429
430         NV50_DEBUG("\n");
431
432         /* This acknowledges a clock request. */
433         NV_WRITE(NV50_PDISPLAY_CRTC_CLK_CLK_CTRL2(crtc->index), 0);
434
435         return 0;
436 }
437
438 static int nv50_crtc_destroy(struct nv50_crtc *crtc)
439 {
440         struct drm_device *dev = crtc->dev;
441         struct drm_nouveau_private *dev_priv = dev->dev_private;
442         struct nv50_display *display = nv50_get_display(dev);
443
444         NV50_DEBUG("\n");
445
446         if (!display || !crtc)
447                 return -EINVAL;
448
449         list_del(&crtc->item);
450
451         nv50_fb_destroy(crtc);
452         nv50_lut_destroy(crtc);
453         nv50_cursor_destroy(crtc);
454
455         kfree(crtc->mode);
456         kfree(crtc->native_mode);
457
458         if (dev_priv->free_crtc)
459                 dev_priv->free_crtc(crtc);
460
461         return 0;
462 }
463
464 int nv50_crtc_create(struct drm_device *dev, int index)
465 {
466         struct drm_nouveau_private *dev_priv = dev->dev_private;
467         struct nv50_crtc *crtc = NULL;
468         struct nv50_display *display = NULL;
469         int rval = 0;
470
471         NV50_DEBUG("\n");
472
473         /* This allows the public layer to do it's thing. */
474         if (dev_priv->alloc_crtc)
475                 crtc = dev_priv->alloc_crtc(dev);
476
477         if (!crtc)
478                 return -ENOMEM;
479
480         crtc->dev = dev;
481
482         display = nv50_get_display(dev);
483         if (!display) {
484                 rval = -EINVAL;
485                 goto out;
486         }
487
488         list_add_tail(&crtc->item, &display->crtcs);
489
490         crtc->index = index;
491
492         crtc->mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL);
493         crtc->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL);
494
495         if (!crtc->mode || !crtc->native_mode) {
496                 rval = -ENOMEM;
497                 goto out;
498         }
499
500         nv50_fb_create(crtc);
501         nv50_lut_create(crtc);
502         nv50_cursor_create(crtc);
503
504         /* set function pointers */
505         crtc->validate_mode = nv50_crtc_validate_mode;
506         crtc->set_mode = nv50_crtc_set_mode;
507         crtc->execute_mode = nv50_crtc_execute_mode;
508         crtc->set_fb = nv50_crtc_set_fb;
509         crtc->blank = nv50_crtc_blank;
510         crtc->set_dither = nv50_crtc_set_dither;
511         crtc->set_scale = nv50_crtc_set_scale;
512         crtc->set_clock = nv50_crtc_set_clock;
513         crtc->set_clock_mode = nv50_crtc_set_clock_mode;
514         crtc->destroy = nv50_crtc_destroy;
515
516         return 0;
517
518 out:
519         if (crtc->mode)
520                 kfree(crtc->mode);
521         if (crtc->native_mode)
522                 kfree(crtc->native_mode);
523         if (dev_priv->free_crtc)
524                 dev_priv->free_crtc(crtc);
525
526         return rval;
527 }