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