[modesetting-101] update mode count after fill_modes.
[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 & V_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 & V_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 & V_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 & V_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                 if (crtc->cursor->block)
196                         OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + offset, crtc->cursor->block->start >> 8);
197                 else
198                         OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + offset, 0);
199                 if (dev_priv->chipset != 0x50)
200                         OUT_MODE(NV84_CRTC0_BLANK_UNK2 + offset, NV84_CRTC0_BLANK_UNK2_UNBLANK);
201
202                 if (crtc->cursor->visible)
203                         crtc->cursor->show(crtc);
204                 else
205                         crtc->cursor->hide(crtc);
206
207                 OUT_MODE(NV50_CRTC0_CLUT_MODE + offset, 
208                         crtc->fb->depth == 8 ? NV50_CRTC0_CLUT_MODE_OFF : NV50_CRTC0_CLUT_MODE_ON);
209                 OUT_MODE(NV50_CRTC0_CLUT_OFFSET + offset, crtc->lut->block->start >> 8);
210                 if (dev_priv->chipset != 0x50)
211                         OUT_MODE(NV84_CRTC0_BLANK_UNK1 + offset, NV84_CRTC0_BLANK_UNK1_UNBLANK);
212                 OUT_MODE(NV50_CRTC0_BLANK_CTRL + offset, NV50_CRTC0_BLANK_CTRL_UNBLANK);
213         }
214
215         return 0;
216 }
217
218 static int nv50_crtc_set_dither(struct nv50_crtc *crtc)
219 {
220         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
221         uint32_t offset = crtc->index * 0x400;
222
223         NV50_DEBUG("\n");
224
225         OUT_MODE(NV50_CRTC0_DITHERING_CTRL + offset, crtc->use_dithering ? 
226                         NV50_CRTC0_DITHERING_CTRL_ON : NV50_CRTC0_DITHERING_CTRL_OFF);
227
228         return 0;
229 }
230
231 static void nv50_crtc_calc_scale(struct nv50_crtc *crtc, uint32_t *outX, uint32_t *outY)
232 {
233         float hor_scale, ver_scale;
234
235         hor_scale = (float)crtc->native_mode->hdisplay/(float)crtc->mode->hdisplay;
236         ver_scale = (float)crtc->native_mode->vdisplay/(float)crtc->mode->vdisplay;
237
238         if (ver_scale > hor_scale) {
239                 *outX = crtc->mode->hdisplay * hor_scale;
240                 *outY = crtc->mode->vdisplay * hor_scale;
241         } else {
242                 *outX = crtc->mode->hdisplay * ver_scale;
243                 *outY = crtc->mode->vdisplay * ver_scale;
244         }
245 }
246
247 static int nv50_crtc_set_scale(struct nv50_crtc *crtc)
248 {
249         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
250         uint32_t offset = crtc->index * 0x400;
251         uint32_t outX, outY;
252
253         NV50_DEBUG("\n");
254
255         switch (crtc->scaling_mode) {
256                 case SCALE_ASPECT:
257                         nv50_crtc_calc_scale(crtc, &outX, &outY);
258                         break;
259                 case SCALE_FULLSCREEN:
260                         outX = crtc->native_mode->hdisplay;
261                         outY = crtc->native_mode->vdisplay;
262                         break;
263                 case SCALE_NOSCALE:
264                 case SCALE_PANEL:
265                 default:
266                         outX = crtc->mode->hdisplay;
267                         outY = crtc->mode->vdisplay;
268                         break;
269         }
270
271         /* Got a better name for SCALER_ACTIVE? */
272         /* One day i've got to really figure out why this is needed. */
273         if ((crtc->mode->flags & V_DBLSCAN) || (crtc->mode->flags & V_INTERLACE) ||
274                 crtc->mode->hdisplay != outX || crtc->mode->vdisplay != outY) {
275                 OUT_MODE(NV50_CRTC0_SCALE_CTRL + offset, NV50_CRTC0_SCALE_CTRL_SCALER_ACTIVE);
276         } else {
277                 OUT_MODE(NV50_CRTC0_SCALE_CTRL + offset, NV50_CRTC0_SCALE_CTRL_SCALER_INACTIVE);
278         }
279
280         OUT_MODE(NV50_CRTC0_SCALE_RES1 + offset, outY << 16 | outX);
281         OUT_MODE(NV50_CRTC0_SCALE_RES2 + offset, outY << 16 | outX);
282
283         return 0;
284 }
285
286 static int nv50_crtc_calc_clock(struct nv50_crtc *crtc, 
287         uint32_t *bestN1, uint32_t *bestN2, uint32_t *bestM1, uint32_t *bestM2, uint32_t *bestlog2P)
288 {
289         struct nouveau_hw_mode *hw_mode;
290         struct pll_lims limits;
291         int clk, vco2, crystal;
292         int minvco1, minvco2, minU1, maxU1, minU2, maxU2, minM1, maxM1;
293         int maxvco1, maxvco2, minN1, maxN1, minM2, maxM2, minN2, maxN2;
294         bool fixedgain2;
295         int M1, N1, M2, N2, log2P;
296         int clkP, calcclk1, calcclk2, calcclkout;
297         int delta, bestdelta = INT_MAX;
298         int bestclk = 0;
299
300         NV50_DEBUG("\n");
301
302         if (crtc->use_native_mode)
303                 hw_mode = crtc->native_mode;
304         else
305                 hw_mode = crtc->mode;
306
307         clk = hw_mode->clock;
308
309         /* These are in the g80 bios tables, at least in mine. */
310         if (!get_pll_limits(crtc->dev, NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(crtc->index), &limits))
311                 return -EINVAL;
312
313         minvco1 = limits.vco1.minfreq, maxvco1 = limits.vco1.maxfreq;
314         minvco2 = limits.vco2.minfreq, maxvco2 = limits.vco2.maxfreq;
315         minU1 = limits.vco1.min_inputfreq, minU2 = limits.vco2.min_inputfreq;
316         maxU1 = limits.vco1.max_inputfreq, maxU2 = limits.vco2.max_inputfreq;
317         minM1 = limits.vco1.min_m, maxM1 = limits.vco1.max_m;
318         minN1 = limits.vco1.min_n, maxN1 = limits.vco1.max_n;
319         minM2 = limits.vco2.min_m, maxM2 = limits.vco2.max_m;
320         minN2 = limits.vco2.min_n, maxN2 = limits.vco2.max_n;
321         crystal = limits.refclk;
322         fixedgain2 = (minM2 == maxM2 && minN2 == maxN2);
323
324         vco2 = (maxvco2 - maxvco2/200) / 2;
325         for (log2P = 0; clk && log2P < 6 && clk <= (vco2 >> log2P); log2P++) /* log2P is maximum of 6 */
326                 ;
327         clkP = clk << log2P;
328
329         if (maxvco2 < clk + clk/200)    /* +0.5% */
330                 maxvco2 = clk + clk/200;
331
332         for (M1 = minM1; M1 <= maxM1; M1++) {
333                 if (crystal/M1 < minU1)
334                         return bestclk;
335                 if (crystal/M1 > maxU1)
336                         continue;
337
338                 for (N1 = minN1; N1 <= maxN1; N1++) {
339                         calcclk1 = crystal * N1 / M1;
340                         if (calcclk1 < minvco1)
341                                 continue;
342                         if (calcclk1 > maxvco1)
343                                 break;
344
345                         for (M2 = minM2; M2 <= maxM2; M2++) {
346                                 if (calcclk1/M2 < minU2)
347                                         break;
348                                 if (calcclk1/M2 > maxU2)
349                                         continue;
350
351                                 /* add calcclk1/2 to round better */
352                                 N2 = (clkP * M2 + calcclk1/2) / calcclk1;
353                                 if (N2 < minN2)
354                                         continue;
355                                 if (N2 > maxN2)
356                                         break;
357
358                                 if (!fixedgain2) {
359                                         calcclk2 = calcclk1 * N2 / M2;
360                                         if (calcclk2 < minvco2)
361                                                 break;
362                                         if (calcclk2 > maxvco2)
363                                                 continue;
364                                 } else
365                                         calcclk2 = calcclk1;
366
367                                 calcclkout = calcclk2 >> log2P;
368                                 delta = abs(calcclkout - clk);
369                                 /* we do an exhaustive search rather than terminating
370                                  * on an optimality condition...
371                                  */
372                                 if (delta < bestdelta) {
373                                         bestdelta = delta;
374                                         bestclk = calcclkout;
375                                         *bestN1 = N1;
376                                         *bestN2 = N2;
377                                         *bestM1 = M1;
378                                         *bestM2 = M2;
379                                         *bestlog2P = log2P;
380                                         if (delta == 0) /* except this one */
381                                                 return bestclk;
382                                 }
383                         }
384                 }
385         }
386
387         return bestclk;
388 }
389
390 static int nv50_crtc_set_clock(struct nv50_crtc *crtc)
391 {
392         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
393
394         uint32_t pll_reg = NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(crtc->index);
395
396         uint32_t N1 = 0, N2 = 0, M1 = 0, M2 = 0, log2P = 0;
397
398         uint32_t reg1 = NV_READ(pll_reg + 4);
399         uint32_t reg2 = NV_READ(pll_reg + 8);
400
401         NV50_DEBUG("\n");
402
403         NV_WRITE(pll_reg, NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1_CONNECTED | 0x10000011);
404
405         /* The other bits are typically empty, but let's be on the safe side. */
406         reg1 &= 0xff00ff00;
407         reg2 &= 0x8000ff00;
408
409         if (!nv50_crtc_calc_clock(crtc, &N1, &N2, &M1, &M2, &log2P))
410                 return -EINVAL;
411
412         NV50_DEBUG("N1 %d N2 %d M1 %d M2 %d log2P %d\n", N1, N2, M1, M2, log2P);
413
414         reg1 |= (M1 << 16) | N1;
415         reg2 |= (log2P << 28) | (M2 << 16) | N2;
416
417         NV_WRITE(pll_reg + 4, reg1);
418         NV_WRITE(pll_reg + 8, reg2);
419
420         return 0;
421 }
422
423 static int nv50_crtc_set_clock_mode(struct nv50_crtc *crtc)
424 {
425         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
426
427         NV50_DEBUG("\n");
428
429         /* This acknowledges a clock request. */
430         NV_WRITE(NV50_PDISPLAY_CRTC_CLK_CLK_CTRL2(crtc->index), 0);
431
432         return 0;
433 }
434
435 static int nv50_crtc_destroy(struct nv50_crtc *crtc)
436 {
437         struct drm_device *dev = crtc->dev;
438         struct drm_nouveau_private *dev_priv = dev->dev_private;
439         struct nv50_display *display = nv50_get_display(dev);
440
441         NV50_DEBUG("\n");
442
443         if (!display || !crtc)
444                 return -EINVAL;
445
446         list_del(&crtc->head);
447
448         nv50_fb_destroy(crtc);
449         nv50_lut_destroy(crtc);
450         nv50_cursor_destroy(crtc);
451
452         kfree(crtc->mode);
453         kfree(crtc->native_mode);
454
455         if (dev_priv->free_crtc)
456                 dev_priv->free_crtc(crtc);
457
458         return 0;
459 }
460
461 int nv50_crtc_create(struct drm_device *dev, int index)
462 {
463         struct drm_nouveau_private *dev_priv = dev->dev_private;
464         struct nv50_crtc *crtc = NULL;
465         struct nv50_display *display = NULL;
466         int rval = 0;
467
468         NV50_DEBUG("\n");
469
470         /* This allows the public layer to do it's thing. */
471         if (dev_priv->alloc_crtc)
472                 crtc = dev_priv->alloc_crtc(dev);
473
474         if (!crtc)
475                 return -ENOMEM;
476
477         crtc->dev = dev;
478
479         display = nv50_get_display(dev);
480         if (!display) {
481                 rval = -EINVAL;
482                 goto out;
483         }
484
485         list_add_tail(&crtc->head, &display->crtcs);
486
487         crtc->index = index;
488
489         crtc->mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL);
490         crtc->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL);
491
492         if (!crtc->mode || !crtc->native_mode) {
493                 rval = -ENOMEM;
494                 goto out;
495         }
496
497         nv50_fb_create(crtc);
498         nv50_lut_create(crtc);
499         nv50_cursor_create(crtc);
500
501         /* set function pointers */
502         crtc->validate_mode = nv50_crtc_validate_mode;
503         crtc->set_mode = nv50_crtc_set_mode;
504         crtc->execute_mode = nv50_crtc_execute_mode;
505         crtc->set_fb = nv50_crtc_set_fb;
506         crtc->blank = nv50_crtc_blank;
507         crtc->set_dither = nv50_crtc_set_dither;
508         crtc->set_scale = nv50_crtc_set_scale;
509         crtc->set_clock = nv50_crtc_set_clock;
510         crtc->set_clock_mode = nv50_crtc_set_clock_mode;
511         crtc->destroy = nv50_crtc_destroy;
512
513         return 0;
514
515 out:
516         if (crtc->mode)
517                 kfree(crtc->mode);
518         if (crtc->native_mode)
519                 kfree(crtc->native_mode);
520         if (dev_priv->free_crtc)
521                 dev_priv->free_crtc(crtc);
522
523         return rval;
524 }