]> Git Repo - linux.git/blob - drivers/gpu/drm/mgag200/mgag200_mode.c
crypto: akcipher - Drop sign/verify operations
[linux.git] / drivers / gpu / drm / mgag200 / mgag200_mode.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright 2010 Matt Turner.
4  * Copyright 2012 Red Hat
5  *
6  * Authors: Matthew Garrett
7  *          Matt Turner
8  *          Dave Airlie
9  */
10
11 #include <linux/delay.h>
12 #include <linux/iosys-map.h>
13
14 #include <drm/drm_atomic.h>
15 #include <drm/drm_atomic_helper.h>
16 #include <drm/drm_damage_helper.h>
17 #include <drm/drm_edid.h>
18 #include <drm/drm_format_helper.h>
19 #include <drm/drm_fourcc.h>
20 #include <drm/drm_framebuffer.h>
21 #include <drm/drm_gem_atomic_helper.h>
22 #include <drm/drm_gem_framebuffer_helper.h>
23 #include <drm/drm_panic.h>
24 #include <drm/drm_print.h>
25 #include <drm/drm_vblank.h>
26
27 #include "mgag200_ddc.h"
28 #include "mgag200_drv.h"
29
30 /*
31  * This file contains setup code for the CRTC.
32  */
33
34 void mgag200_crtc_set_gamma_linear(struct mga_device *mdev,
35                                    const struct drm_format_info *format)
36 {
37         int i;
38
39         WREG8(DAC_INDEX + MGA1064_INDEX, 0);
40
41         switch (format->format) {
42         case DRM_FORMAT_RGB565:
43                 /* Use better interpolation, to take 32 values from 0 to 255 */
44                 for (i = 0; i < MGAG200_LUT_SIZE / 8; i++) {
45                         WREG8(DAC_INDEX + MGA1064_COL_PAL, i * 8 + i / 4);
46                         WREG8(DAC_INDEX + MGA1064_COL_PAL, i * 4 + i / 16);
47                         WREG8(DAC_INDEX + MGA1064_COL_PAL, i * 8 + i / 4);
48                 }
49                 /* Green has one more bit, so add padding with 0 for red and blue. */
50                 for (i = MGAG200_LUT_SIZE / 8; i < MGAG200_LUT_SIZE / 4; i++) {
51                         WREG8(DAC_INDEX + MGA1064_COL_PAL, 0);
52                         WREG8(DAC_INDEX + MGA1064_COL_PAL, i * 4 + i / 16);
53                         WREG8(DAC_INDEX + MGA1064_COL_PAL, 0);
54                 }
55                 break;
56         case DRM_FORMAT_RGB888:
57         case DRM_FORMAT_XRGB8888:
58                 for (i = 0; i < MGAG200_LUT_SIZE; i++) {
59                         WREG8(DAC_INDEX + MGA1064_COL_PAL, i);
60                         WREG8(DAC_INDEX + MGA1064_COL_PAL, i);
61                         WREG8(DAC_INDEX + MGA1064_COL_PAL, i);
62                 }
63                 break;
64         default:
65                 drm_warn_once(&mdev->base, "Unsupported format %p4cc for gamma correction\n",
66                               &format->format);
67                 break;
68         }
69 }
70
71 void mgag200_crtc_set_gamma(struct mga_device *mdev,
72                             const struct drm_format_info *format,
73                             struct drm_color_lut *lut)
74 {
75         int i;
76
77         WREG8(DAC_INDEX + MGA1064_INDEX, 0);
78
79         switch (format->format) {
80         case DRM_FORMAT_RGB565:
81                 /* Use better interpolation, to take 32 values from lut[0] to lut[255] */
82                 for (i = 0; i < MGAG200_LUT_SIZE / 8; i++) {
83                         WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i * 8 + i / 4].red >> 8);
84                         WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i * 4 + i / 16].green >> 8);
85                         WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i * 8 + i / 4].blue >> 8);
86                 }
87                 /* Green has one more bit, so add padding with 0 for red and blue. */
88                 for (i = MGAG200_LUT_SIZE / 8; i < MGAG200_LUT_SIZE / 4; i++) {
89                         WREG8(DAC_INDEX + MGA1064_COL_PAL, 0);
90                         WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i * 4 + i / 16].green >> 8);
91                         WREG8(DAC_INDEX + MGA1064_COL_PAL, 0);
92                 }
93                 break;
94         case DRM_FORMAT_RGB888:
95         case DRM_FORMAT_XRGB8888:
96                 for (i = 0; i < MGAG200_LUT_SIZE; i++) {
97                         WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i].red >> 8);
98                         WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i].green >> 8);
99                         WREG8(DAC_INDEX + MGA1064_COL_PAL, lut[i].blue >> 8);
100                 }
101                 break;
102         default:
103                 drm_warn_once(&mdev->base, "Unsupported format %p4cc for gamma correction\n",
104                               &format->format);
105                 break;
106         }
107 }
108
109 static inline void mga_wait_vsync(struct mga_device *mdev)
110 {
111         unsigned long timeout = jiffies + HZ/10;
112         unsigned int status = 0;
113
114         do {
115                 status = RREG32(MGAREG_STATUS);
116         } while ((status & 0x08) && time_before(jiffies, timeout));
117         timeout = jiffies + HZ/10;
118         status = 0;
119         do {
120                 status = RREG32(MGAREG_STATUS);
121         } while (!(status & 0x08) && time_before(jiffies, timeout));
122 }
123
124 static inline void mga_wait_busy(struct mga_device *mdev)
125 {
126         unsigned long timeout = jiffies + HZ;
127         unsigned int status = 0;
128         do {
129                 status = RREG8(MGAREG_STATUS + 2);
130         } while ((status & 0x01) && time_before(jiffies, timeout));
131 }
132
133 /*
134  * This is how the framebuffer base address is stored in g200 cards:
135  *   * Assume @offset is the gpu_addr variable of the framebuffer object
136  *   * Then addr is the number of _pixels_ (not bytes) from the start of
137  *     VRAM to the first pixel we want to display. (divided by 2 for 32bit
138  *     framebuffers)
139  *   * addr is stored in the CRTCEXT0, CRTCC and CRTCD registers
140  *      addr<20> -> CRTCEXT0<6>
141  *      addr<19-16> -> CRTCEXT0<3-0>
142  *      addr<15-8> -> CRTCC<7-0>
143  *      addr<7-0> -> CRTCD<7-0>
144  *
145  *  CRTCEXT0 has to be programmed last to trigger an update and make the
146  *  new addr variable take effect.
147  */
148 static void mgag200_set_startadd(struct mga_device *mdev,
149                                  unsigned long offset)
150 {
151         struct drm_device *dev = &mdev->base;
152         u32 startadd;
153         u8 crtcc, crtcd, crtcext0;
154
155         startadd = offset / 8;
156
157         if (startadd > 0)
158                 drm_WARN_ON_ONCE(dev, mdev->info->bug_no_startadd);
159
160         /*
161          * Can't store addresses any higher than that, but we also
162          * don't have more than 16 MiB of memory, so it should be fine.
163          */
164         drm_WARN_ON(dev, startadd > 0x1fffff);
165
166         RREG_ECRT(0x00, crtcext0);
167
168         crtcc = (startadd >> 8) & 0xff;
169         crtcd = startadd & 0xff;
170         crtcext0 &= 0xb0;
171         crtcext0 |= ((startadd >> 14) & BIT(6)) |
172                     ((startadd >> 16) & 0x0f);
173
174         WREG_CRT(0x0c, crtcc);
175         WREG_CRT(0x0d, crtcd);
176         WREG_ECRT(0x00, crtcext0);
177 }
178
179 void mgag200_init_registers(struct mga_device *mdev)
180 {
181         u8 crtc11, misc;
182
183         WREG_SEQ(2, 0x0f);
184         WREG_SEQ(3, 0x00);
185         WREG_SEQ(4, 0x0e);
186
187         WREG_CRT(10, 0);
188         WREG_CRT(11, 0);
189         WREG_CRT(12, 0);
190         WREG_CRT(13, 0);
191         WREG_CRT(14, 0);
192         WREG_CRT(15, 0);
193
194         RREG_CRT(0x11, crtc11);
195         crtc11 &= ~(MGAREG_CRTC11_CRTCPROTECT |
196                     MGAREG_CRTC11_VINTEN |
197                     MGAREG_CRTC11_VINTCLR);
198         WREG_CRT(0x11, crtc11);
199
200         misc = RREG8(MGA_MISC_IN);
201         misc |= MGAREG_MISC_IOADSEL;
202         WREG8(MGA_MISC_OUT, misc);
203 }
204
205 void mgag200_set_mode_regs(struct mga_device *mdev, const struct drm_display_mode *mode,
206                            bool set_vidrst)
207 {
208         unsigned int hdispend, hsyncstr, hsyncend, htotal, hblkstr, hblkend;
209         unsigned int vdispend, vsyncstr, vsyncend, vtotal, vblkstr, vblkend;
210         unsigned int linecomp;
211         u8 misc, crtcext1, crtcext2, crtcext5;
212
213         hdispend = mode->crtc_hdisplay / 8 - 1;
214         hsyncstr = mode->crtc_hsync_start / 8 - 1;
215         hsyncend = mode->crtc_hsync_end / 8 - 1;
216         htotal = mode->crtc_htotal / 8 - 1;
217         /* Work around hardware quirk */
218         if ((htotal & 0x07) == 0x06 || (htotal & 0x07) == 0x04)
219                 htotal++;
220         hblkstr = mode->crtc_hblank_start / 8 - 1;
221         hblkend = htotal;
222
223         vdispend = mode->crtc_vdisplay - 1;
224         vsyncstr = mode->crtc_vsync_start - 1;
225         vsyncend = mode->crtc_vsync_end - 1;
226         vtotal = mode->crtc_vtotal - 2;
227         vblkstr = mode->crtc_vblank_start;
228         vblkend = vtotal + 1;
229
230         /*
231          * There's no VBLANK interrupt on Matrox chipsets, so we use
232          * the VLINE interrupt instead. It triggers when the current
233          * <linecomp> has been reached. For VBLANK, this is the first
234          * non-visible line at the bottom of the screen. Therefore,
235          * keep <linecomp> in sync with <vblkstr>.
236          */
237         linecomp = vblkstr;
238
239         misc = RREG8(MGA_MISC_IN);
240
241         if (mode->flags & DRM_MODE_FLAG_NHSYNC)
242                 misc |= MGAREG_MISC_HSYNCPOL;
243         else
244                 misc &= ~MGAREG_MISC_HSYNCPOL;
245
246         if (mode->flags & DRM_MODE_FLAG_NVSYNC)
247                 misc |= MGAREG_MISC_VSYNCPOL;
248         else
249                 misc &= ~MGAREG_MISC_VSYNCPOL;
250
251         crtcext1 = (((htotal - 4) & 0x100) >> 8) |
252                    ((hblkstr & 0x100) >> 7) |
253                    ((hsyncstr & 0x100) >> 6) |
254                     (hblkend & 0x40);
255         if (set_vidrst)
256                 crtcext1 |= MGAREG_CRTCEXT1_VRSTEN |
257                             MGAREG_CRTCEXT1_HRSTEN;
258
259         crtcext2 = ((vtotal & 0xc00) >> 10) |
260                    ((vdispend & 0x400) >> 8) |
261                    ((vblkstr & 0xc00) >> 7) |
262                    ((vsyncstr & 0xc00) >> 5) |
263                    ((linecomp & 0x400) >> 3);
264         crtcext5 = 0x00;
265
266         WREG_CRT(0x00, htotal - 4);
267         WREG_CRT(0x01, hdispend);
268         WREG_CRT(0x02, hblkstr);
269         WREG_CRT(0x03, (hblkend & 0x1f) | 0x80);
270         WREG_CRT(0x04, hsyncstr);
271         WREG_CRT(0x05, ((hblkend & 0x20) << 2) | (hsyncend & 0x1f));
272         WREG_CRT(0x06, vtotal & 0xff);
273         WREG_CRT(0x07, ((vtotal & 0x100) >> 8) |
274                        ((vdispend & 0x100) >> 7) |
275                        ((vsyncstr & 0x100) >> 6) |
276                        ((vblkstr & 0x100) >> 5) |
277                        ((linecomp & 0x100) >> 4) |
278                        ((vtotal & 0x200) >> 4) |
279                        ((vdispend & 0x200) >> 3) |
280                        ((vsyncstr & 0x200) >> 2));
281         WREG_CRT(0x09, ((vblkstr & 0x200) >> 4) |
282                        ((linecomp & 0x200) >> 3));
283         WREG_CRT(0x10, vsyncstr & 0xff);
284         WREG_CRT(0x11, (vsyncend & 0x0f) | 0x20);
285         WREG_CRT(0x12, vdispend & 0xff);
286         WREG_CRT(0x14, 0);
287         WREG_CRT(0x15, vblkstr & 0xff);
288         WREG_CRT(0x16, vblkend & 0xff);
289         WREG_CRT(0x17, 0xc3);
290         WREG_CRT(0x18, linecomp & 0xff);
291
292         WREG_ECRT(0x01, crtcext1);
293         WREG_ECRT(0x02, crtcext2);
294         WREG_ECRT(0x05, crtcext5);
295
296         WREG8(MGA_MISC_OUT, misc);
297 }
298
299 static u8 mgag200_get_bpp_shift(const struct drm_format_info *format)
300 {
301         static const u8 bpp_shift[] = {0, 1, 0, 2};
302
303         return bpp_shift[format->cpp[0] - 1];
304 }
305
306 /*
307  * Calculates the HW offset value from the framebuffer's pitch. The
308  * offset is a multiple of the pixel size and depends on the display
309  * format.
310  */
311 static u32 mgag200_calculate_offset(struct mga_device *mdev,
312                                     const struct drm_framebuffer *fb)
313 {
314         u32 offset = fb->pitches[0] / fb->format->cpp[0];
315         u8 bppshift = mgag200_get_bpp_shift(fb->format);
316
317         if (fb->format->cpp[0] * 8 == 24)
318                 offset = (offset * 3) >> (4 - bppshift);
319         else
320                 offset = offset >> (4 - bppshift);
321
322         return offset;
323 }
324
325 static void mgag200_set_offset(struct mga_device *mdev,
326                                const struct drm_framebuffer *fb)
327 {
328         u8 crtc13, crtcext0;
329         u32 offset = mgag200_calculate_offset(mdev, fb);
330
331         RREG_ECRT(0, crtcext0);
332
333         crtc13 = offset & 0xff;
334
335         crtcext0 &= ~MGAREG_CRTCEXT0_OFFSET_MASK;
336         crtcext0 |= (offset >> 4) & MGAREG_CRTCEXT0_OFFSET_MASK;
337
338         WREG_CRT(0x13, crtc13);
339         WREG_ECRT(0x00, crtcext0);
340 }
341
342 void mgag200_set_format_regs(struct mga_device *mdev, const struct drm_format_info *format)
343 {
344         struct drm_device *dev = &mdev->base;
345         unsigned int bpp, bppshift, scale;
346         u8 crtcext3, xmulctrl;
347
348         bpp = format->cpp[0] * 8;
349
350         bppshift = mgag200_get_bpp_shift(format);
351         switch (bpp) {
352         case 24:
353                 scale = ((1 << bppshift) * 3) - 1;
354                 break;
355         default:
356                 scale = (1 << bppshift) - 1;
357                 break;
358         }
359
360         RREG_ECRT(3, crtcext3);
361
362         switch (bpp) {
363         case 8:
364                 xmulctrl = MGA1064_MUL_CTL_8bits;
365                 break;
366         case 16:
367                 if (format->depth == 15)
368                         xmulctrl = MGA1064_MUL_CTL_15bits;
369                 else
370                         xmulctrl = MGA1064_MUL_CTL_16bits;
371                 break;
372         case 24:
373                 xmulctrl = MGA1064_MUL_CTL_24bits;
374                 break;
375         case 32:
376                 xmulctrl = MGA1064_MUL_CTL_32_24bits;
377                 break;
378         default:
379                 /* BUG: We should have caught this problem already. */
380                 drm_WARN_ON(dev, "invalid format depth\n");
381                 return;
382         }
383
384         crtcext3 &= ~GENMASK(2, 0);
385         crtcext3 |= scale;
386
387         WREG_DAC(MGA1064_MUL_CTL, xmulctrl);
388
389         WREG_GFX(0, 0x00);
390         WREG_GFX(1, 0x00);
391         WREG_GFX(2, 0x00);
392         WREG_GFX(3, 0x00);
393         WREG_GFX(4, 0x00);
394         WREG_GFX(5, 0x40);
395         /* GCTL6 should be 0x05, but we configure memmapsl to 0xb8000 (text mode),
396          * so that it doesn't hang when running kexec/kdump on G200_SE rev42.
397          */
398         WREG_GFX(6, 0x0d);
399         WREG_GFX(7, 0x0f);
400         WREG_GFX(8, 0x0f);
401
402         WREG_ECRT(3, crtcext3);
403 }
404
405 void mgag200_enable_display(struct mga_device *mdev)
406 {
407         u8 seq0, crtcext1;
408
409         RREG_SEQ(0x00, seq0);
410         seq0 |= MGAREG_SEQ0_SYNCRST |
411                 MGAREG_SEQ0_ASYNCRST;
412         WREG_SEQ(0x00, seq0);
413
414         /*
415          * TODO: replace busy waiting with vblank IRQ; put
416          *       msleep(50) before changing SCROFF
417          */
418         mga_wait_vsync(mdev);
419         mga_wait_busy(mdev);
420
421         RREG_ECRT(0x01, crtcext1);
422         crtcext1 &= ~MGAREG_CRTCEXT1_VSYNCOFF;
423         crtcext1 &= ~MGAREG_CRTCEXT1_HSYNCOFF;
424         WREG_ECRT(0x01, crtcext1);
425 }
426
427 static void mgag200_disable_display(struct mga_device *mdev)
428 {
429         u8 seq0, crtcext1;
430
431         RREG_SEQ(0x00, seq0);
432         seq0 &= ~MGAREG_SEQ0_SYNCRST;
433         WREG_SEQ(0x00, seq0);
434
435         /*
436          * TODO: replace busy waiting with vblank IRQ; put
437          *       msleep(50) before changing SCROFF
438          */
439         mga_wait_vsync(mdev);
440         mga_wait_busy(mdev);
441
442         RREG_ECRT(0x01, crtcext1);
443         crtcext1 |= MGAREG_CRTCEXT1_VSYNCOFF |
444                     MGAREG_CRTCEXT1_HSYNCOFF;
445         WREG_ECRT(0x01, crtcext1);
446 }
447
448 static void mgag200_handle_damage(struct mga_device *mdev, const struct iosys_map *vmap,
449                                   struct drm_framebuffer *fb, struct drm_rect *clip)
450 {
451         struct iosys_map dst = IOSYS_MAP_INIT_VADDR_IOMEM(mdev->vram);
452
453         iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, clip));
454         drm_fb_memcpy(&dst, fb->pitches, vmap, fb, clip);
455 }
456
457 /*
458  * Primary plane
459  */
460
461 const uint32_t mgag200_primary_plane_formats[] = {
462         DRM_FORMAT_XRGB8888,
463         DRM_FORMAT_RGB565,
464         DRM_FORMAT_RGB888,
465 };
466
467 const size_t mgag200_primary_plane_formats_size = ARRAY_SIZE(mgag200_primary_plane_formats);
468
469 const uint64_t mgag200_primary_plane_fmtmods[] = {
470         DRM_FORMAT_MOD_LINEAR,
471         DRM_FORMAT_MOD_INVALID
472 };
473
474 int mgag200_primary_plane_helper_atomic_check(struct drm_plane *plane,
475                                               struct drm_atomic_state *new_state)
476 {
477         struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane);
478         struct drm_framebuffer *new_fb = new_plane_state->fb;
479         struct drm_framebuffer *fb = NULL;
480         struct drm_crtc *new_crtc = new_plane_state->crtc;
481         struct drm_crtc_state *new_crtc_state = NULL;
482         struct mgag200_crtc_state *new_mgag200_crtc_state;
483         int ret;
484
485         if (new_crtc)
486                 new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_crtc);
487
488         ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
489                                                   DRM_PLANE_NO_SCALING,
490                                                   DRM_PLANE_NO_SCALING,
491                                                   false, true);
492         if (ret)
493                 return ret;
494         else if (!new_plane_state->visible)
495                 return 0;
496
497         if (plane->state)
498                 fb = plane->state->fb;
499
500         if (!fb || (fb->format != new_fb->format))
501                 new_crtc_state->mode_changed = true; /* update PLL settings */
502
503         new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
504         new_mgag200_crtc_state->format = new_fb->format;
505
506         return 0;
507 }
508
509 void mgag200_primary_plane_helper_atomic_update(struct drm_plane *plane,
510                                                 struct drm_atomic_state *old_state)
511 {
512         struct drm_device *dev = plane->dev;
513         struct mga_device *mdev = to_mga_device(dev);
514         struct drm_plane_state *plane_state = plane->state;
515         struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(old_state, plane);
516         struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
517         struct drm_framebuffer *fb = plane_state->fb;
518         struct drm_atomic_helper_damage_iter iter;
519         struct drm_rect damage;
520
521         drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
522         drm_atomic_for_each_plane_damage(&iter, &damage) {
523                 mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &damage);
524         }
525
526         /* Always scanout image at VRAM offset 0 */
527         mgag200_set_startadd(mdev, (u32)0);
528         mgag200_set_offset(mdev, fb);
529 }
530
531 void mgag200_primary_plane_helper_atomic_enable(struct drm_plane *plane,
532                                                 struct drm_atomic_state *state)
533 {
534         struct drm_device *dev = plane->dev;
535         struct mga_device *mdev = to_mga_device(dev);
536         u8 seq1;
537
538         RREG_SEQ(0x01, seq1);
539         seq1 &= ~MGAREG_SEQ1_SCROFF;
540         WREG_SEQ(0x01, seq1);
541         msleep(20);
542 }
543
544 void mgag200_primary_plane_helper_atomic_disable(struct drm_plane *plane,
545                                                  struct drm_atomic_state *old_state)
546 {
547         struct drm_device *dev = plane->dev;
548         struct mga_device *mdev = to_mga_device(dev);
549         u8 seq1;
550
551         RREG_SEQ(0x01, seq1);
552         seq1 |= MGAREG_SEQ1_SCROFF;
553         WREG_SEQ(0x01, seq1);
554         msleep(20);
555 }
556
557 int mgag200_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane,
558                                                     struct drm_scanout_buffer *sb)
559 {
560         struct mga_device *mdev = to_mga_device(plane->dev);
561         struct iosys_map map = IOSYS_MAP_INIT_VADDR_IOMEM(mdev->vram);
562
563         if (plane->state && plane->state->fb) {
564                 sb->format = plane->state->fb->format;
565                 sb->width = plane->state->fb->width;
566                 sb->height = plane->state->fb->height;
567                 sb->pitch[0] = plane->state->fb->pitches[0];
568                 sb->map[0] = map;
569                 return 0;
570         }
571         return -ENODEV;
572 }
573
574 /*
575  * CRTC
576  */
577
578 enum drm_mode_status mgag200_crtc_helper_mode_valid(struct drm_crtc *crtc,
579                                                     const struct drm_display_mode *mode)
580 {
581         struct mga_device *mdev = to_mga_device(crtc->dev);
582         const struct mgag200_device_info *info = mdev->info;
583
584         /*
585          * Some devices have additional limits on the size of the
586          * display mode.
587          */
588         if (mode->hdisplay > info->max_hdisplay)
589                 return MODE_VIRTUAL_X;
590         if (mode->vdisplay > info->max_vdisplay)
591                 return MODE_VIRTUAL_Y;
592
593         if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 ||
594             (mode->hsync_end % 8) != 0 || (mode->htotal % 8) != 0) {
595                 return MODE_H_ILLEGAL;
596         }
597
598         if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 ||
599             mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 ||
600             mode->crtc_vdisplay > 2048 || mode->crtc_vsync_start > 4096 ||
601             mode->crtc_vsync_end > 4096 || mode->crtc_vtotal > 4096) {
602                 return MODE_BAD;
603         }
604
605         return MODE_OK;
606 }
607
608 int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state)
609 {
610         struct drm_device *dev = crtc->dev;
611         struct mga_device *mdev = to_mga_device(dev);
612         const struct mgag200_device_funcs *funcs = mdev->funcs;
613         struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
614         struct drm_property_blob *new_gamma_lut = new_crtc_state->gamma_lut;
615         int ret;
616
617         if (!new_crtc_state->enable)
618                 return 0;
619
620         ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state);
621         if (ret)
622                 return ret;
623
624         if (new_crtc_state->mode_changed) {
625                 if (funcs->pixpllc_atomic_check) {
626                         ret = funcs->pixpllc_atomic_check(crtc, new_state);
627                         if (ret)
628                                 return ret;
629                 }
630         }
631
632         if (new_crtc_state->color_mgmt_changed && new_gamma_lut) {
633                 if (new_gamma_lut->length != MGAG200_LUT_SIZE * sizeof(struct drm_color_lut)) {
634                         drm_dbg(dev, "Wrong size for gamma_lut %zu\n", new_gamma_lut->length);
635                         return -EINVAL;
636                 }
637         }
638
639         return 0;
640 }
641
642 void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *old_state)
643 {
644         struct drm_crtc_state *crtc_state = crtc->state;
645         struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
646         struct drm_device *dev = crtc->dev;
647         struct mga_device *mdev = to_mga_device(dev);
648         struct drm_pending_vblank_event *event;
649         unsigned long flags;
650
651         if (crtc_state->enable && crtc_state->color_mgmt_changed) {
652                 const struct drm_format_info *format = mgag200_crtc_state->format;
653
654                 if (crtc_state->gamma_lut)
655                         mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data);
656                 else
657                         mgag200_crtc_set_gamma_linear(mdev, format);
658         }
659
660         event = crtc->state->event;
661         if (event) {
662                 crtc->state->event = NULL;
663
664                 spin_lock_irqsave(&dev->event_lock, flags);
665                 if (drm_crtc_vblank_get(crtc) != 0)
666                         drm_crtc_send_vblank_event(crtc, event);
667                 else
668                         drm_crtc_arm_vblank_event(crtc, event);
669                 spin_unlock_irqrestore(&dev->event_lock, flags);
670         }
671 }
672
673 void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *old_state)
674 {
675         struct drm_device *dev = crtc->dev;
676         struct mga_device *mdev = to_mga_device(dev);
677         const struct mgag200_device_funcs *funcs = mdev->funcs;
678         struct drm_crtc_state *crtc_state = crtc->state;
679         struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
680         struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
681         const struct drm_format_info *format = mgag200_crtc_state->format;
682
683         mgag200_set_format_regs(mdev, format);
684         mgag200_set_mode_regs(mdev, adjusted_mode, mgag200_crtc_state->set_vidrst);
685
686         if (funcs->pixpllc_atomic_update)
687                 funcs->pixpllc_atomic_update(crtc, old_state);
688
689         if (crtc_state->gamma_lut)
690                 mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data);
691         else
692                 mgag200_crtc_set_gamma_linear(mdev, format);
693
694         mgag200_enable_display(mdev);
695
696         drm_crtc_vblank_on(crtc);
697 }
698
699 void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *old_state)
700 {
701         struct mga_device *mdev = to_mga_device(crtc->dev);
702
703         drm_crtc_vblank_off(crtc);
704
705         mgag200_disable_display(mdev);
706 }
707
708 bool mgag200_crtc_helper_get_scanout_position(struct drm_crtc *crtc, bool in_vblank_irq,
709                                               int *vpos, int *hpos,
710                                               ktime_t *stime, ktime_t *etime,
711                                               const struct drm_display_mode *mode)
712 {
713         struct mga_device *mdev = to_mga_device(crtc->dev);
714         u32 vcount;
715
716         if (stime)
717                 *stime = ktime_get();
718
719         if (vpos) {
720                 vcount = RREG32(MGAREG_VCOUNT);
721                 *vpos = vcount & GENMASK(11, 0);
722         }
723
724         if (hpos)
725                 *hpos = mode->htotal >> 1; // near middle of scanline on average
726
727         if (etime)
728                 *etime = ktime_get();
729
730         return true;
731 }
732
733 void mgag200_crtc_reset(struct drm_crtc *crtc)
734 {
735         struct mgag200_crtc_state *mgag200_crtc_state;
736
737         if (crtc->state)
738                 crtc->funcs->atomic_destroy_state(crtc, crtc->state);
739
740         mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), GFP_KERNEL);
741         if (mgag200_crtc_state)
742                 __drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base);
743         else
744                 __drm_atomic_helper_crtc_reset(crtc, NULL);
745 }
746
747 struct drm_crtc_state *mgag200_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
748 {
749         struct drm_crtc_state *crtc_state = crtc->state;
750         struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
751         struct mgag200_crtc_state *new_mgag200_crtc_state;
752
753         if (!crtc_state)
754                 return NULL;
755
756         new_mgag200_crtc_state = kzalloc(sizeof(*new_mgag200_crtc_state), GFP_KERNEL);
757         if (!new_mgag200_crtc_state)
758                 return NULL;
759         __drm_atomic_helper_crtc_duplicate_state(crtc, &new_mgag200_crtc_state->base);
760
761         new_mgag200_crtc_state->format = mgag200_crtc_state->format;
762         memcpy(&new_mgag200_crtc_state->pixpllc, &mgag200_crtc_state->pixpllc,
763                sizeof(new_mgag200_crtc_state->pixpllc));
764         new_mgag200_crtc_state->set_vidrst = mgag200_crtc_state->set_vidrst;
765
766         return &new_mgag200_crtc_state->base;
767 }
768
769 void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
770 {
771         struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
772
773         __drm_atomic_helper_crtc_destroy_state(&mgag200_crtc_state->base);
774         kfree(mgag200_crtc_state);
775 }
776
777 int mgag200_crtc_enable_vblank(struct drm_crtc *crtc)
778 {
779         struct mga_device *mdev = to_mga_device(crtc->dev);
780         u32 ien;
781
782         WREG32(MGAREG_ICLEAR, MGAREG_ICLEAR_VLINEICLR);
783
784         ien = RREG32(MGAREG_IEN);
785         ien |= MGAREG_IEN_VLINEIEN;
786         WREG32(MGAREG_IEN, ien);
787
788         return 0;
789 }
790
791 void mgag200_crtc_disable_vblank(struct drm_crtc *crtc)
792 {
793         struct mga_device *mdev = to_mga_device(crtc->dev);
794         u32 ien;
795
796         ien = RREG32(MGAREG_IEN);
797         ien &= ~(MGAREG_IEN_VLINEIEN);
798         WREG32(MGAREG_IEN, ien);
799 }
800
801 /*
802  * Mode config
803  */
804
805 static void mgag200_mode_config_helper_atomic_commit_tail(struct drm_atomic_state *state)
806 {
807         struct mga_device *mdev = to_mga_device(state->dev);
808
809         /*
810          * Concurrent operations could possibly trigger a call to
811          * drm_connector_helper_funcs.get_modes by trying to read the
812          * display modes. Protect access to I/O registers by acquiring
813          * the I/O-register lock.
814          */
815         mutex_lock(&mdev->rmmio_lock);
816         drm_atomic_helper_commit_tail(state);
817         mutex_unlock(&mdev->rmmio_lock);
818 }
819
820 static const struct drm_mode_config_helper_funcs mgag200_mode_config_helper_funcs = {
821         .atomic_commit_tail = mgag200_mode_config_helper_atomic_commit_tail,
822 };
823
824 /* Calculates a mode's required memory bandwidth (in KiB/sec). */
825 static uint32_t mgag200_calculate_mode_bandwidth(const struct drm_display_mode *mode,
826                                                  unsigned int bits_per_pixel)
827 {
828         uint32_t total_area, divisor;
829         uint64_t active_area, pixels_per_second, bandwidth;
830         uint64_t bytes_per_pixel = (bits_per_pixel + 7) / 8;
831
832         divisor = 1024;
833
834         if (!mode->htotal || !mode->vtotal || !mode->clock)
835                 return 0;
836
837         active_area = mode->hdisplay * mode->vdisplay;
838         total_area = mode->htotal * mode->vtotal;
839
840         pixels_per_second = active_area * mode->clock * 1000;
841         do_div(pixels_per_second, total_area);
842
843         bandwidth = pixels_per_second * bytes_per_pixel * 100;
844         do_div(bandwidth, divisor);
845
846         return (uint32_t)bandwidth;
847 }
848
849 static enum drm_mode_status mgag200_mode_config_mode_valid(struct drm_device *dev,
850                                                            const struct drm_display_mode *mode)
851 {
852         static const unsigned int max_bpp = 4; // DRM_FORMAT_XRGB8888
853         struct mga_device *mdev = to_mga_device(dev);
854         unsigned long fbsize, fbpages, max_fbpages;
855         const struct mgag200_device_info *info = mdev->info;
856
857         max_fbpages = mdev->vram_available >> PAGE_SHIFT;
858
859         fbsize = mode->hdisplay * mode->vdisplay * max_bpp;
860         fbpages = DIV_ROUND_UP(fbsize, PAGE_SIZE);
861
862         if (fbpages > max_fbpages)
863                 return MODE_MEM;
864
865         /*
866          * Test the mode's required memory bandwidth if the device
867          * specifies a maximum. Not all devices do though.
868          */
869         if (info->max_mem_bandwidth) {
870                 uint32_t mode_bandwidth = mgag200_calculate_mode_bandwidth(mode, max_bpp * 8);
871
872                 if (mode_bandwidth > (info->max_mem_bandwidth * 1024))
873                         return MODE_BAD;
874         }
875
876         return MODE_OK;
877 }
878
879 static const struct drm_mode_config_funcs mgag200_mode_config_funcs = {
880         .fb_create = drm_gem_fb_create_with_dirty,
881         .mode_valid = mgag200_mode_config_mode_valid,
882         .atomic_check = drm_atomic_helper_check,
883         .atomic_commit = drm_atomic_helper_commit,
884 };
885
886 int mgag200_mode_config_init(struct mga_device *mdev, resource_size_t vram_available)
887 {
888         struct drm_device *dev = &mdev->base;
889         int ret;
890
891         mdev->vram_available = vram_available;
892
893         ret = drmm_mode_config_init(dev);
894         if (ret) {
895                 drm_err(dev, "drmm_mode_config_init() failed: %d\n", ret);
896                 return ret;
897         }
898
899         dev->mode_config.max_width = MGAG200_MAX_FB_WIDTH;
900         dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT;
901         dev->mode_config.preferred_depth = 24;
902         dev->mode_config.funcs = &mgag200_mode_config_funcs;
903         dev->mode_config.helper_private = &mgag200_mode_config_helper_funcs;
904
905         return 0;
906 }
This page took 0.085393 seconds and 4 git commands to generate.