OSDN Git Service

radeon: Fix type in check for tmds type.
[android-x86/external-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->requested_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_NON_GPU:
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         /* processed */
287         crtc->scaling_mode = crtc->requested_scaling_mode;
288
289         return 0;
290 }
291
292 static int nv50_crtc_calc_clock(struct nv50_crtc *crtc, 
293         uint32_t *bestN1, uint32_t *bestN2, uint32_t *bestM1, uint32_t *bestM2, uint32_t *bestlog2P)
294 {
295         struct nouveau_hw_mode *hw_mode;
296         struct pll_lims limits;
297         int clk, vco2, crystal;
298         int minvco1, minvco2, minU1, maxU1, minU2, maxU2, minM1, maxM1;
299         int maxvco1, maxvco2, minN1, maxN1, minM2, maxM2, minN2, maxN2;
300         bool fixedgain2;
301         int M1, N1, M2, N2, log2P;
302         int clkP, calcclk1, calcclk2, calcclkout;
303         int delta, bestdelta = INT_MAX;
304         int bestclk = 0;
305
306         NV50_DEBUG("\n");
307
308         if (crtc->use_native_mode)
309                 hw_mode = crtc->native_mode;
310         else
311                 hw_mode = crtc->mode;
312
313         clk = hw_mode->clock;
314
315         /* These are in the g80 bios tables, at least in mine. */
316         if (!get_pll_limits(crtc->dev, NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(crtc->index), &limits))
317                 return -EINVAL;
318
319         minvco1 = limits.vco1.minfreq, maxvco1 = limits.vco1.maxfreq;
320         minvco2 = limits.vco2.minfreq, maxvco2 = limits.vco2.maxfreq;
321         minU1 = limits.vco1.min_inputfreq, minU2 = limits.vco2.min_inputfreq;
322         maxU1 = limits.vco1.max_inputfreq, maxU2 = limits.vco2.max_inputfreq;
323         minM1 = limits.vco1.min_m, maxM1 = limits.vco1.max_m;
324         minN1 = limits.vco1.min_n, maxN1 = limits.vco1.max_n;
325         minM2 = limits.vco2.min_m, maxM2 = limits.vco2.max_m;
326         minN2 = limits.vco2.min_n, maxN2 = limits.vco2.max_n;
327         crystal = limits.refclk;
328         fixedgain2 = (minM2 == maxM2 && minN2 == maxN2);
329
330         vco2 = (maxvco2 - maxvco2/200) / 2;
331         for (log2P = 0; clk && log2P < 6 && clk <= (vco2 >> log2P); log2P++) /* log2P is maximum of 6 */
332                 ;
333         clkP = clk << log2P;
334
335         if (maxvco2 < clk + clk/200)    /* +0.5% */
336                 maxvco2 = clk + clk/200;
337
338         for (M1 = minM1; M1 <= maxM1; M1++) {
339                 if (crystal/M1 < minU1)
340                         return bestclk;
341                 if (crystal/M1 > maxU1)
342                         continue;
343
344                 for (N1 = minN1; N1 <= maxN1; N1++) {
345                         calcclk1 = crystal * N1 / M1;
346                         if (calcclk1 < minvco1)
347                                 continue;
348                         if (calcclk1 > maxvco1)
349                                 break;
350
351                         for (M2 = minM2; M2 <= maxM2; M2++) {
352                                 if (calcclk1/M2 < minU2)
353                                         break;
354                                 if (calcclk1/M2 > maxU2)
355                                         continue;
356
357                                 /* add calcclk1/2 to round better */
358                                 N2 = (clkP * M2 + calcclk1/2) / calcclk1;
359                                 if (N2 < minN2)
360                                         continue;
361                                 if (N2 > maxN2)
362                                         break;
363
364                                 if (!fixedgain2) {
365                                         calcclk2 = calcclk1 * N2 / M2;
366                                         if (calcclk2 < minvco2)
367                                                 break;
368                                         if (calcclk2 > maxvco2)
369                                                 continue;
370                                 } else
371                                         calcclk2 = calcclk1;
372
373                                 calcclkout = calcclk2 >> log2P;
374                                 delta = abs(calcclkout - clk);
375                                 /* we do an exhaustive search rather than terminating
376                                  * on an optimality condition...
377                                  */
378                                 if (delta < bestdelta) {
379                                         bestdelta = delta;
380                                         bestclk = calcclkout;
381                                         *bestN1 = N1;
382                                         *bestN2 = N2;
383                                         *bestM1 = M1;
384                                         *bestM2 = M2;
385                                         *bestlog2P = log2P;
386                                         if (delta == 0) /* except this one */
387                                                 return bestclk;
388                                 }
389                         }
390                 }
391         }
392
393         return bestclk;
394 }
395
396 static int nv50_crtc_set_clock(struct nv50_crtc *crtc)
397 {
398         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
399
400         uint32_t pll_reg = NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(crtc->index);
401
402         uint32_t N1 = 0, N2 = 0, M1 = 0, M2 = 0, log2P = 0;
403
404         uint32_t reg1 = NV_READ(pll_reg + 4);
405         uint32_t reg2 = NV_READ(pll_reg + 8);
406
407         NV50_DEBUG("\n");
408
409         NV_WRITE(pll_reg, NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1_CONNECTED | 0x10000011);
410
411         /* The other bits are typically empty, but let's be on the safe side. */
412         reg1 &= 0xff00ff00;
413         reg2 &= 0x8000ff00;
414
415         if (!nv50_crtc_calc_clock(crtc, &N1, &N2, &M1, &M2, &log2P))
416                 return -EINVAL;
417
418         NV50_DEBUG("N1 %d N2 %d M1 %d M2 %d log2P %d\n", N1, N2, M1, M2, log2P);
419
420         reg1 |= (M1 << 16) | N1;
421         reg2 |= (log2P << 28) | (M2 << 16) | N2;
422
423         NV_WRITE(pll_reg + 4, reg1);
424         NV_WRITE(pll_reg + 8, reg2);
425
426         return 0;
427 }
428
429 static int nv50_crtc_set_clock_mode(struct nv50_crtc *crtc)
430 {
431         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
432
433         NV50_DEBUG("\n");
434
435         /* This acknowledges a clock request. */
436         NV_WRITE(NV50_PDISPLAY_CRTC_CLK_CLK_CTRL2(crtc->index), 0);
437
438         return 0;
439 }
440
441 static int nv50_crtc_destroy(struct nv50_crtc *crtc)
442 {
443         struct drm_device *dev = crtc->dev;
444         struct drm_nouveau_private *dev_priv = dev->dev_private;
445         struct nv50_display *display = nv50_get_display(dev);
446
447         NV50_DEBUG("\n");
448
449         if (!display || !crtc)
450                 return -EINVAL;
451
452         list_del(&crtc->item);
453
454         nv50_fb_destroy(crtc);
455         nv50_lut_destroy(crtc);
456         nv50_cursor_destroy(crtc);
457
458         kfree(crtc->mode);
459         kfree(crtc->native_mode);
460
461         if (dev_priv->free_crtc)
462                 dev_priv->free_crtc(crtc);
463
464         return 0;
465 }
466
467 int nv50_crtc_create(struct drm_device *dev, int index)
468 {
469         struct drm_nouveau_private *dev_priv = dev->dev_private;
470         struct nv50_crtc *crtc = NULL;
471         struct nv50_display *display = NULL;
472         int rval = 0;
473
474         NV50_DEBUG("\n");
475
476         /* This allows the public layer to do it's thing. */
477         if (dev_priv->alloc_crtc)
478                 crtc = dev_priv->alloc_crtc(dev);
479
480         if (!crtc)
481                 return -ENOMEM;
482
483         crtc->dev = dev;
484
485         display = nv50_get_display(dev);
486         if (!display) {
487                 rval = -EINVAL;
488                 goto out;
489         }
490
491         list_add_tail(&crtc->item, &display->crtcs);
492
493         crtc->index = index;
494
495         crtc->mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL);
496         crtc->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL);
497
498         crtc->requested_scaling_mode = SCALE_INVALID;
499         crtc->scaling_mode = SCALE_INVALID;
500
501         if (!crtc->mode || !crtc->native_mode) {
502                 rval = -ENOMEM;
503                 goto out;
504         }
505
506         nv50_fb_create(crtc);
507         nv50_lut_create(crtc);
508         nv50_cursor_create(crtc);
509
510         /* set function pointers */
511         crtc->validate_mode = nv50_crtc_validate_mode;
512         crtc->set_mode = nv50_crtc_set_mode;
513         crtc->execute_mode = nv50_crtc_execute_mode;
514         crtc->set_fb = nv50_crtc_set_fb;
515         crtc->blank = nv50_crtc_blank;
516         crtc->set_dither = nv50_crtc_set_dither;
517         crtc->set_scale = nv50_crtc_set_scale;
518         crtc->set_clock = nv50_crtc_set_clock;
519         crtc->set_clock_mode = nv50_crtc_set_clock_mode;
520         crtc->destroy = nv50_crtc_destroy;
521
522         return 0;
523
524 out:
525         if (crtc->mode)
526                 kfree(crtc->mode);
527         if (crtc->native_mode)
528                 kfree(crtc->native_mode);
529         if (dev_priv->free_crtc)
530                 dev_priv->free_crtc(crtc);
531
532         return rval;
533 }