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