cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mgag200_mode.c (29421B)


      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_helper.h>
     15#include <drm/drm_atomic_state_helper.h>
     16#include <drm/drm_crtc_helper.h>
     17#include <drm/drm_damage_helper.h>
     18#include <drm/drm_format_helper.h>
     19#include <drm/drm_fourcc.h>
     20#include <drm/drm_gem_atomic_helper.h>
     21#include <drm/drm_gem_framebuffer_helper.h>
     22#include <drm/drm_plane_helper.h>
     23#include <drm/drm_print.h>
     24#include <drm/drm_probe_helper.h>
     25#include <drm/drm_simple_kms_helper.h>
     26
     27#include "mgag200_drv.h"
     28
     29#define MGAG200_LUT_SIZE 256
     30
     31/*
     32 * This file contains setup code for the CRTC.
     33 */
     34
     35static void mga_crtc_load_lut(struct drm_crtc *crtc)
     36{
     37	struct drm_device *dev = crtc->dev;
     38	struct mga_device *mdev = to_mga_device(dev);
     39	struct drm_framebuffer *fb;
     40	u16 *r_ptr, *g_ptr, *b_ptr;
     41	int i;
     42
     43	if (!crtc->enabled)
     44		return;
     45
     46	if (!mdev->display_pipe.plane.state)
     47		return;
     48
     49	fb = mdev->display_pipe.plane.state->fb;
     50
     51	r_ptr = crtc->gamma_store;
     52	g_ptr = r_ptr + crtc->gamma_size;
     53	b_ptr = g_ptr + crtc->gamma_size;
     54
     55	WREG8(DAC_INDEX + MGA1064_INDEX, 0);
     56
     57	if (fb && fb->format->cpp[0] * 8 == 16) {
     58		int inc = (fb->format->depth == 15) ? 8 : 4;
     59		u8 r, b;
     60		for (i = 0; i < MGAG200_LUT_SIZE; i += inc) {
     61			if (fb->format->depth == 16) {
     62				if (i > (MGAG200_LUT_SIZE >> 1)) {
     63					r = b = 0;
     64				} else {
     65					r = *r_ptr++ >> 8;
     66					b = *b_ptr++ >> 8;
     67					r_ptr++;
     68					b_ptr++;
     69				}
     70			} else {
     71				r = *r_ptr++ >> 8;
     72				b = *b_ptr++ >> 8;
     73			}
     74			/* VGA registers */
     75			WREG8(DAC_INDEX + MGA1064_COL_PAL, r);
     76			WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8);
     77			WREG8(DAC_INDEX + MGA1064_COL_PAL, b);
     78		}
     79		return;
     80	}
     81	for (i = 0; i < MGAG200_LUT_SIZE; i++) {
     82		/* VGA registers */
     83		WREG8(DAC_INDEX + MGA1064_COL_PAL, *r_ptr++ >> 8);
     84		WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8);
     85		WREG8(DAC_INDEX + MGA1064_COL_PAL, *b_ptr++ >> 8);
     86	}
     87}
     88
     89static inline void mga_wait_vsync(struct mga_device *mdev)
     90{
     91	unsigned long timeout = jiffies + HZ/10;
     92	unsigned int status = 0;
     93
     94	do {
     95		status = RREG32(MGAREG_Status);
     96	} while ((status & 0x08) && time_before(jiffies, timeout));
     97	timeout = jiffies + HZ/10;
     98	status = 0;
     99	do {
    100		status = RREG32(MGAREG_Status);
    101	} while (!(status & 0x08) && time_before(jiffies, timeout));
    102}
    103
    104static inline void mga_wait_busy(struct mga_device *mdev)
    105{
    106	unsigned long timeout = jiffies + HZ;
    107	unsigned int status = 0;
    108	do {
    109		status = RREG8(MGAREG_Status + 2);
    110	} while ((status & 0x01) && time_before(jiffies, timeout));
    111}
    112
    113static void mgag200_g200wb_hold_bmc(struct mga_device *mdev)
    114{
    115	u8 tmp;
    116	int iter_max;
    117
    118	/* 1- The first step is to warn the BMC of an upcoming mode change.
    119	 * We are putting the misc<0> to output.*/
    120
    121	WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL);
    122	tmp = RREG8(DAC_DATA);
    123	tmp |= 0x10;
    124	WREG_DAC(MGA1064_GEN_IO_CTL, tmp);
    125
    126	/* we are putting a 1 on the misc<0> line */
    127	WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA);
    128	tmp = RREG8(DAC_DATA);
    129	tmp |= 0x10;
    130	WREG_DAC(MGA1064_GEN_IO_DATA, tmp);
    131
    132	/* 2- Second step to mask and further scan request
    133	 * This will be done by asserting the remfreqmsk bit (XSPAREREG<7>)
    134	 */
    135	WREG8(DAC_INDEX, MGA1064_SPAREREG);
    136	tmp = RREG8(DAC_DATA);
    137	tmp |= 0x80;
    138	WREG_DAC(MGA1064_SPAREREG, tmp);
    139
    140	/* 3a- the third step is to verifu if there is an active scan
    141	 * We are searching for a 0 on remhsyncsts <XSPAREREG<0>)
    142	 */
    143	iter_max = 300;
    144	while (!(tmp & 0x1) && iter_max) {
    145		WREG8(DAC_INDEX, MGA1064_SPAREREG);
    146		tmp = RREG8(DAC_DATA);
    147		udelay(1000);
    148		iter_max--;
    149	}
    150
    151	/* 3b- this step occurs only if the remove is actually scanning
    152	 * we are waiting for the end of the frame which is a 1 on
    153	 * remvsyncsts (XSPAREREG<1>)
    154	 */
    155	if (iter_max) {
    156		iter_max = 300;
    157		while ((tmp & 0x2) && iter_max) {
    158			WREG8(DAC_INDEX, MGA1064_SPAREREG);
    159			tmp = RREG8(DAC_DATA);
    160			udelay(1000);
    161			iter_max--;
    162		}
    163	}
    164}
    165
    166static void mgag200_g200wb_release_bmc(struct mga_device *mdev)
    167{
    168	u8 tmp;
    169
    170	/* 1- The first step is to ensure that the vrsten and hrsten are set */
    171	WREG8(MGAREG_CRTCEXT_INDEX, 1);
    172	tmp = RREG8(MGAREG_CRTCEXT_DATA);
    173	WREG8(MGAREG_CRTCEXT_DATA, tmp | 0x88);
    174
    175	/* 2- second step is to assert the rstlvl2 */
    176	WREG8(DAC_INDEX, MGA1064_REMHEADCTL2);
    177	tmp = RREG8(DAC_DATA);
    178	tmp |= 0x8;
    179	WREG8(DAC_DATA, tmp);
    180
    181	/* wait 10 us */
    182	udelay(10);
    183
    184	/* 3- deassert rstlvl2 */
    185	tmp &= ~0x08;
    186	WREG8(DAC_INDEX, MGA1064_REMHEADCTL2);
    187	WREG8(DAC_DATA, tmp);
    188
    189	/* 4- remove mask of scan request */
    190	WREG8(DAC_INDEX, MGA1064_SPAREREG);
    191	tmp = RREG8(DAC_DATA);
    192	tmp &= ~0x80;
    193	WREG8(DAC_DATA, tmp);
    194
    195	/* 5- put back a 0 on the misc<0> line */
    196	WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA);
    197	tmp = RREG8(DAC_DATA);
    198	tmp &= ~0x10;
    199	WREG_DAC(MGA1064_GEN_IO_DATA, tmp);
    200}
    201
    202/*
    203 * This is how the framebuffer base address is stored in g200 cards:
    204 *   * Assume @offset is the gpu_addr variable of the framebuffer object
    205 *   * Then addr is the number of _pixels_ (not bytes) from the start of
    206 *     VRAM to the first pixel we want to display. (divided by 2 for 32bit
    207 *     framebuffers)
    208 *   * addr is stored in the CRTCEXT0, CRTCC and CRTCD registers
    209 *      addr<20> -> CRTCEXT0<6>
    210 *      addr<19-16> -> CRTCEXT0<3-0>
    211 *      addr<15-8> -> CRTCC<7-0>
    212 *      addr<7-0> -> CRTCD<7-0>
    213 *
    214 *  CRTCEXT0 has to be programmed last to trigger an update and make the
    215 *  new addr variable take effect.
    216 */
    217static void mgag200_set_startadd(struct mga_device *mdev,
    218				 unsigned long offset)
    219{
    220	struct drm_device *dev = &mdev->base;
    221	u32 startadd;
    222	u8 crtcc, crtcd, crtcext0;
    223
    224	startadd = offset / 8;
    225
    226	/*
    227	 * Can't store addresses any higher than that, but we also
    228	 * don't have more than 16 MiB of memory, so it should be fine.
    229	 */
    230	drm_WARN_ON(dev, startadd > 0x1fffff);
    231
    232	RREG_ECRT(0x00, crtcext0);
    233
    234	crtcc = (startadd >> 8) & 0xff;
    235	crtcd = startadd & 0xff;
    236	crtcext0 &= 0xb0;
    237	crtcext0 |= ((startadd >> 14) & BIT(6)) |
    238		    ((startadd >> 16) & 0x0f);
    239
    240	WREG_CRT(0x0c, crtcc);
    241	WREG_CRT(0x0d, crtcd);
    242	WREG_ECRT(0x00, crtcext0);
    243}
    244
    245static void mgag200_set_dac_regs(struct mga_device *mdev)
    246{
    247	size_t i;
    248	u8 dacvalue[] = {
    249		/* 0x00: */        0,    0,    0,    0,    0,    0, 0x00,    0,
    250		/* 0x08: */        0,    0,    0,    0,    0,    0,    0,    0,
    251		/* 0x10: */        0,    0,    0,    0,    0,    0,    0,    0,
    252		/* 0x18: */     0x00,    0, 0xC9, 0xFF, 0xBF, 0x20, 0x1F, 0x20,
    253		/* 0x20: */     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    254		/* 0x28: */     0x00, 0x00, 0x00, 0x00,    0,    0,    0, 0x40,
    255		/* 0x30: */     0x00, 0xB0, 0x00, 0xC2, 0x34, 0x14, 0x02, 0x83,
    256		/* 0x38: */     0x00, 0x93, 0x00, 0x77, 0x00, 0x00, 0x00, 0x3A,
    257		/* 0x40: */        0,    0,    0,    0,    0,    0,    0,    0,
    258		/* 0x48: */        0,    0,    0,    0,    0,    0,    0,    0
    259	};
    260
    261	switch (mdev->type) {
    262	case G200_PCI:
    263	case G200_AGP:
    264		dacvalue[MGA1064_SYS_PLL_M] = 0x04;
    265		dacvalue[MGA1064_SYS_PLL_N] = 0x2D;
    266		dacvalue[MGA1064_SYS_PLL_P] = 0x19;
    267		break;
    268	case G200_SE_A:
    269	case G200_SE_B:
    270		dacvalue[MGA1064_VREF_CTL] = 0x03;
    271		dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL;
    272		dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_DAC_EN |
    273					     MGA1064_MISC_CTL_VGA8 |
    274					     MGA1064_MISC_CTL_DAC_RAM_CS;
    275		break;
    276	case G200_WB:
    277	case G200_EW3:
    278		dacvalue[MGA1064_VREF_CTL] = 0x07;
    279		break;
    280	case G200_EV:
    281		dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL;
    282		dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 |
    283					     MGA1064_MISC_CTL_DAC_RAM_CS;
    284		break;
    285	case G200_EH:
    286	case G200_EH3:
    287		dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 |
    288					     MGA1064_MISC_CTL_DAC_RAM_CS;
    289		break;
    290	case G200_ER:
    291		break;
    292	}
    293
    294	for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
    295		if ((i <= 0x17) ||
    296		    (i == 0x1b) ||
    297		    (i == 0x1c) ||
    298		    ((i >= 0x1f) && (i <= 0x29)) ||
    299		    ((i >= 0x30) && (i <= 0x37)))
    300			continue;
    301		if (IS_G200_SE(mdev) &&
    302		    ((i == 0x2c) || (i == 0x2d) || (i == 0x2e)))
    303			continue;
    304		if ((mdev->type == G200_EV ||
    305		    mdev->type == G200_WB ||
    306		    mdev->type == G200_EH ||
    307		    mdev->type == G200_EW3 ||
    308		    mdev->type == G200_EH3) &&
    309		    (i >= 0x44) && (i <= 0x4e))
    310			continue;
    311
    312		WREG_DAC(i, dacvalue[i]);
    313	}
    314
    315	if (mdev->type == G200_ER)
    316		WREG_DAC(0x90, 0);
    317}
    318
    319static void mgag200_init_regs(struct mga_device *mdev)
    320{
    321	u8 crtc11, misc;
    322
    323	mgag200_set_dac_regs(mdev);
    324
    325	WREG_SEQ(2, 0x0f);
    326	WREG_SEQ(3, 0x00);
    327	WREG_SEQ(4, 0x0e);
    328
    329	WREG_CRT(10, 0);
    330	WREG_CRT(11, 0);
    331	WREG_CRT(12, 0);
    332	WREG_CRT(13, 0);
    333	WREG_CRT(14, 0);
    334	WREG_CRT(15, 0);
    335
    336	RREG_CRT(0x11, crtc11);
    337	crtc11 &= ~(MGAREG_CRTC11_CRTCPROTECT |
    338		    MGAREG_CRTC11_VINTEN |
    339		    MGAREG_CRTC11_VINTCLR);
    340	WREG_CRT(0x11, crtc11);
    341
    342	if (mdev->type == G200_ER)
    343		WREG_ECRT(0x24, 0x5);
    344
    345	if (mdev->type == G200_EW3)
    346		WREG_ECRT(0x34, 0x5);
    347
    348	misc = RREG8(MGA_MISC_IN);
    349	misc |= MGAREG_MISC_IOADSEL;
    350	WREG8(MGA_MISC_OUT, misc);
    351}
    352
    353static void mgag200_set_mode_regs(struct mga_device *mdev,
    354				  const struct drm_display_mode *mode)
    355{
    356	unsigned int hdisplay, hsyncstart, hsyncend, htotal;
    357	unsigned int vdisplay, vsyncstart, vsyncend, vtotal;
    358	u8 misc, crtcext1, crtcext2, crtcext5;
    359
    360	hdisplay = mode->hdisplay / 8 - 1;
    361	hsyncstart = mode->hsync_start / 8 - 1;
    362	hsyncend = mode->hsync_end / 8 - 1;
    363	htotal = mode->htotal / 8 - 1;
    364
    365	/* Work around hardware quirk */
    366	if ((htotal & 0x07) == 0x06 || (htotal & 0x07) == 0x04)
    367		htotal++;
    368
    369	vdisplay = mode->vdisplay - 1;
    370	vsyncstart = mode->vsync_start - 1;
    371	vsyncend = mode->vsync_end - 1;
    372	vtotal = mode->vtotal - 2;
    373
    374	misc = RREG8(MGA_MISC_IN);
    375
    376	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
    377		misc |= MGAREG_MISC_HSYNCPOL;
    378	else
    379		misc &= ~MGAREG_MISC_HSYNCPOL;
    380
    381	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
    382		misc |= MGAREG_MISC_VSYNCPOL;
    383	else
    384		misc &= ~MGAREG_MISC_VSYNCPOL;
    385
    386	crtcext1 = (((htotal - 4) & 0x100) >> 8) |
    387		   ((hdisplay & 0x100) >> 7) |
    388		   ((hsyncstart & 0x100) >> 6) |
    389		    (htotal & 0x40);
    390	if (mdev->type == G200_WB || mdev->type == G200_EW3)
    391		crtcext1 |= BIT(7) | /* vrsten */
    392			    BIT(3); /* hrsten */
    393
    394	crtcext2 = ((vtotal & 0xc00) >> 10) |
    395		   ((vdisplay & 0x400) >> 8) |
    396		   ((vdisplay & 0xc00) >> 7) |
    397		   ((vsyncstart & 0xc00) >> 5) |
    398		   ((vdisplay & 0x400) >> 3);
    399	crtcext5 = 0x00;
    400
    401	WREG_CRT(0, htotal - 4);
    402	WREG_CRT(1, hdisplay);
    403	WREG_CRT(2, hdisplay);
    404	WREG_CRT(3, (htotal & 0x1F) | 0x80);
    405	WREG_CRT(4, hsyncstart);
    406	WREG_CRT(5, ((htotal & 0x20) << 2) | (hsyncend & 0x1F));
    407	WREG_CRT(6, vtotal & 0xFF);
    408	WREG_CRT(7, ((vtotal & 0x100) >> 8) |
    409		 ((vdisplay & 0x100) >> 7) |
    410		 ((vsyncstart & 0x100) >> 6) |
    411		 ((vdisplay & 0x100) >> 5) |
    412		 ((vdisplay & 0x100) >> 4) | /* linecomp */
    413		 ((vtotal & 0x200) >> 4) |
    414		 ((vdisplay & 0x200) >> 3) |
    415		 ((vsyncstart & 0x200) >> 2));
    416	WREG_CRT(9, ((vdisplay & 0x200) >> 4) |
    417		 ((vdisplay & 0x200) >> 3));
    418	WREG_CRT(16, vsyncstart & 0xFF);
    419	WREG_CRT(17, (vsyncend & 0x0F) | 0x20);
    420	WREG_CRT(18, vdisplay & 0xFF);
    421	WREG_CRT(20, 0);
    422	WREG_CRT(21, vdisplay & 0xFF);
    423	WREG_CRT(22, (vtotal + 1) & 0xFF);
    424	WREG_CRT(23, 0xc3);
    425	WREG_CRT(24, vdisplay & 0xFF);
    426
    427	WREG_ECRT(0x01, crtcext1);
    428	WREG_ECRT(0x02, crtcext2);
    429	WREG_ECRT(0x05, crtcext5);
    430
    431	WREG8(MGA_MISC_OUT, misc);
    432}
    433
    434static u8 mgag200_get_bpp_shift(const struct drm_format_info *format)
    435{
    436	static const u8 bpp_shift[] = {0, 1, 0, 2};
    437
    438	return bpp_shift[format->cpp[0] - 1];
    439}
    440
    441/*
    442 * Calculates the HW offset value from the framebuffer's pitch. The
    443 * offset is a multiple of the pixel size and depends on the display
    444 * format.
    445 */
    446static u32 mgag200_calculate_offset(struct mga_device *mdev,
    447				    const struct drm_framebuffer *fb)
    448{
    449	u32 offset = fb->pitches[0] / fb->format->cpp[0];
    450	u8 bppshift = mgag200_get_bpp_shift(fb->format);
    451
    452	if (fb->format->cpp[0] * 8 == 24)
    453		offset = (offset * 3) >> (4 - bppshift);
    454	else
    455		offset = offset >> (4 - bppshift);
    456
    457	return offset;
    458}
    459
    460static void mgag200_set_offset(struct mga_device *mdev,
    461			       const struct drm_framebuffer *fb)
    462{
    463	u8 crtc13, crtcext0;
    464	u32 offset = mgag200_calculate_offset(mdev, fb);
    465
    466	RREG_ECRT(0, crtcext0);
    467
    468	crtc13 = offset & 0xff;
    469
    470	crtcext0 &= ~MGAREG_CRTCEXT0_OFFSET_MASK;
    471	crtcext0 |= (offset >> 4) & MGAREG_CRTCEXT0_OFFSET_MASK;
    472
    473	WREG_CRT(0x13, crtc13);
    474	WREG_ECRT(0x00, crtcext0);
    475}
    476
    477static void mgag200_set_format_regs(struct mga_device *mdev,
    478				    const struct drm_framebuffer *fb)
    479{
    480	struct drm_device *dev = &mdev->base;
    481	const struct drm_format_info *format = fb->format;
    482	unsigned int bpp, bppshift, scale;
    483	u8 crtcext3, xmulctrl;
    484
    485	bpp = format->cpp[0] * 8;
    486
    487	bppshift = mgag200_get_bpp_shift(format);
    488	switch (bpp) {
    489	case 24:
    490		scale = ((1 << bppshift) * 3) - 1;
    491		break;
    492	default:
    493		scale = (1 << bppshift) - 1;
    494		break;
    495	}
    496
    497	RREG_ECRT(3, crtcext3);
    498
    499	switch (bpp) {
    500	case 8:
    501		xmulctrl = MGA1064_MUL_CTL_8bits;
    502		break;
    503	case 16:
    504		if (format->depth == 15)
    505			xmulctrl = MGA1064_MUL_CTL_15bits;
    506		else
    507			xmulctrl = MGA1064_MUL_CTL_16bits;
    508		break;
    509	case 24:
    510		xmulctrl = MGA1064_MUL_CTL_24bits;
    511		break;
    512	case 32:
    513		xmulctrl = MGA1064_MUL_CTL_32_24bits;
    514		break;
    515	default:
    516		/* BUG: We should have caught this problem already. */
    517		drm_WARN_ON(dev, "invalid format depth\n");
    518		return;
    519	}
    520
    521	crtcext3 &= ~GENMASK(2, 0);
    522	crtcext3 |= scale;
    523
    524	WREG_DAC(MGA1064_MUL_CTL, xmulctrl);
    525
    526	WREG_GFX(0, 0x00);
    527	WREG_GFX(1, 0x00);
    528	WREG_GFX(2, 0x00);
    529	WREG_GFX(3, 0x00);
    530	WREG_GFX(4, 0x00);
    531	WREG_GFX(5, 0x40);
    532	/* GCTL6 should be 0x05, but we configure memmapsl to 0xb8000 (text mode),
    533	 * so that it doesn't hang when running kexec/kdump on G200_SE rev42.
    534	 */
    535	WREG_GFX(6, 0x0d);
    536	WREG_GFX(7, 0x0f);
    537	WREG_GFX(8, 0x0f);
    538
    539	WREG_ECRT(3, crtcext3);
    540}
    541
    542static void mgag200_g200er_reset_tagfifo(struct mga_device *mdev)
    543{
    544	static uint32_t RESET_FLAG = 0x00200000; /* undocumented magic value */
    545	u32 memctl;
    546
    547	memctl = RREG32(MGAREG_MEMCTL);
    548
    549	memctl |= RESET_FLAG;
    550	WREG32(MGAREG_MEMCTL, memctl);
    551
    552	udelay(1000);
    553
    554	memctl &= ~RESET_FLAG;
    555	WREG32(MGAREG_MEMCTL, memctl);
    556}
    557
    558static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev,
    559					const struct drm_display_mode *mode,
    560					const struct drm_framebuffer *fb)
    561{
    562	u32 unique_rev_id = mdev->model.g200se.unique_rev_id;
    563	unsigned int hiprilvl;
    564	u8 crtcext6;
    565
    566	if  (unique_rev_id >= 0x04) {
    567		hiprilvl = 0;
    568	} else if (unique_rev_id >= 0x02) {
    569		unsigned int bpp;
    570		unsigned long mb;
    571
    572		if (fb->format->cpp[0] * 8 > 16)
    573			bpp = 32;
    574		else if (fb->format->cpp[0] * 8 > 8)
    575			bpp = 16;
    576		else
    577			bpp = 8;
    578
    579		mb = (mode->clock * bpp) / 1000;
    580		if (mb > 3100)
    581			hiprilvl = 0;
    582		else if (mb > 2600)
    583			hiprilvl = 1;
    584		else if (mb > 1900)
    585			hiprilvl = 2;
    586		else if (mb > 1160)
    587			hiprilvl = 3;
    588		else if (mb > 440)
    589			hiprilvl = 4;
    590		else
    591			hiprilvl = 5;
    592
    593	} else if (unique_rev_id >= 0x01) {
    594		hiprilvl = 3;
    595	} else {
    596		hiprilvl = 4;
    597	}
    598
    599	crtcext6 = hiprilvl; /* implicitly sets maxhipri to 0 */
    600
    601	WREG_ECRT(0x06, crtcext6);
    602}
    603
    604static void mgag200_g200ev_set_hiprilvl(struct mga_device *mdev)
    605{
    606	WREG_ECRT(0x06, 0x00);
    607}
    608
    609static void mgag200_enable_display(struct mga_device *mdev)
    610{
    611	u8 seq0, seq1, crtcext1;
    612
    613	RREG_SEQ(0x00, seq0);
    614	seq0 |= MGAREG_SEQ0_SYNCRST |
    615		MGAREG_SEQ0_ASYNCRST;
    616	WREG_SEQ(0x00, seq0);
    617
    618	/*
    619	 * TODO: replace busy waiting with vblank IRQ; put
    620	 *       msleep(50) before changing SCROFF
    621	 */
    622	mga_wait_vsync(mdev);
    623	mga_wait_busy(mdev);
    624
    625	RREG_SEQ(0x01, seq1);
    626	seq1 &= ~MGAREG_SEQ1_SCROFF;
    627	WREG_SEQ(0x01, seq1);
    628
    629	msleep(20);
    630
    631	RREG_ECRT(0x01, crtcext1);
    632	crtcext1 &= ~MGAREG_CRTCEXT1_VSYNCOFF;
    633	crtcext1 &= ~MGAREG_CRTCEXT1_HSYNCOFF;
    634	WREG_ECRT(0x01, crtcext1);
    635}
    636
    637static void mgag200_disable_display(struct mga_device *mdev)
    638{
    639	u8 seq0, seq1, crtcext1;
    640
    641	RREG_SEQ(0x00, seq0);
    642	seq0 &= ~MGAREG_SEQ0_SYNCRST;
    643	WREG_SEQ(0x00, seq0);
    644
    645	/*
    646	 * TODO: replace busy waiting with vblank IRQ; put
    647	 *       msleep(50) before changing SCROFF
    648	 */
    649	mga_wait_vsync(mdev);
    650	mga_wait_busy(mdev);
    651
    652	RREG_SEQ(0x01, seq1);
    653	seq1 |= MGAREG_SEQ1_SCROFF;
    654	WREG_SEQ(0x01, seq1);
    655
    656	msleep(20);
    657
    658	RREG_ECRT(0x01, crtcext1);
    659	crtcext1 |= MGAREG_CRTCEXT1_VSYNCOFF |
    660		    MGAREG_CRTCEXT1_HSYNCOFF;
    661	WREG_ECRT(0x01, crtcext1);
    662}
    663
    664/*
    665 * Connector
    666 */
    667
    668static int mga_vga_get_modes(struct drm_connector *connector)
    669{
    670	struct mga_connector *mga_connector = to_mga_connector(connector);
    671	struct edid *edid;
    672	int ret = 0;
    673
    674	edid = drm_get_edid(connector, &mga_connector->i2c->adapter);
    675	if (edid) {
    676		drm_connector_update_edid_property(connector, edid);
    677		ret = drm_add_edid_modes(connector, edid);
    678		kfree(edid);
    679	}
    680	return ret;
    681}
    682
    683static uint32_t mga_vga_calculate_mode_bandwidth(struct drm_display_mode *mode,
    684							int bits_per_pixel)
    685{
    686	uint32_t total_area, divisor;
    687	uint64_t active_area, pixels_per_second, bandwidth;
    688	uint64_t bytes_per_pixel = (bits_per_pixel + 7) / 8;
    689
    690	divisor = 1024;
    691
    692	if (!mode->htotal || !mode->vtotal || !mode->clock)
    693		return 0;
    694
    695	active_area = mode->hdisplay * mode->vdisplay;
    696	total_area = mode->htotal * mode->vtotal;
    697
    698	pixels_per_second = active_area * mode->clock * 1000;
    699	do_div(pixels_per_second, total_area);
    700
    701	bandwidth = pixels_per_second * bytes_per_pixel * 100;
    702	do_div(bandwidth, divisor);
    703
    704	return (uint32_t)(bandwidth);
    705}
    706
    707#define MODE_BANDWIDTH	MODE_BAD
    708
    709static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector,
    710				 struct drm_display_mode *mode)
    711{
    712	struct drm_device *dev = connector->dev;
    713	struct mga_device *mdev = to_mga_device(dev);
    714	int bpp = 32;
    715
    716	if (IS_G200_SE(mdev)) {
    717		u32 unique_rev_id = mdev->model.g200se.unique_rev_id;
    718
    719		if (unique_rev_id == 0x01) {
    720			if (mode->hdisplay > 1600)
    721				return MODE_VIRTUAL_X;
    722			if (mode->vdisplay > 1200)
    723				return MODE_VIRTUAL_Y;
    724			if (mga_vga_calculate_mode_bandwidth(mode, bpp)
    725				> (24400 * 1024))
    726				return MODE_BANDWIDTH;
    727		} else if (unique_rev_id == 0x02) {
    728			if (mode->hdisplay > 1920)
    729				return MODE_VIRTUAL_X;
    730			if (mode->vdisplay > 1200)
    731				return MODE_VIRTUAL_Y;
    732			if (mga_vga_calculate_mode_bandwidth(mode, bpp)
    733				> (30100 * 1024))
    734				return MODE_BANDWIDTH;
    735		} else {
    736			if (mga_vga_calculate_mode_bandwidth(mode, bpp)
    737				> (55000 * 1024))
    738				return MODE_BANDWIDTH;
    739		}
    740	} else if (mdev->type == G200_WB) {
    741		if (mode->hdisplay > 1280)
    742			return MODE_VIRTUAL_X;
    743		if (mode->vdisplay > 1024)
    744			return MODE_VIRTUAL_Y;
    745		if (mga_vga_calculate_mode_bandwidth(mode, bpp) >
    746		    (31877 * 1024))
    747			return MODE_BANDWIDTH;
    748	} else if (mdev->type == G200_EV &&
    749		(mga_vga_calculate_mode_bandwidth(mode, bpp)
    750			> (32700 * 1024))) {
    751		return MODE_BANDWIDTH;
    752	} else if (mdev->type == G200_EH &&
    753		(mga_vga_calculate_mode_bandwidth(mode, bpp)
    754			> (37500 * 1024))) {
    755		return MODE_BANDWIDTH;
    756	} else if (mdev->type == G200_ER &&
    757		(mga_vga_calculate_mode_bandwidth(mode,
    758			bpp) > (55000 * 1024))) {
    759		return MODE_BANDWIDTH;
    760	}
    761
    762	if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 ||
    763	    (mode->hsync_end % 8) != 0 || (mode->htotal % 8) != 0) {
    764		return MODE_H_ILLEGAL;
    765	}
    766
    767	if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 ||
    768	    mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 ||
    769	    mode->crtc_vdisplay > 2048 || mode->crtc_vsync_start > 4096 ||
    770	    mode->crtc_vsync_end > 4096 || mode->crtc_vtotal > 4096) {
    771		return MODE_BAD;
    772	}
    773
    774	/* Validate the mode input by the user */
    775	if (connector->cmdline_mode.specified) {
    776		if (connector->cmdline_mode.bpp_specified)
    777			bpp = connector->cmdline_mode.bpp;
    778	}
    779
    780	if ((mode->hdisplay * mode->vdisplay * (bpp/8)) > mdev->vram_fb_available) {
    781		if (connector->cmdline_mode.specified)
    782			connector->cmdline_mode.specified = false;
    783		return MODE_BAD;
    784	}
    785
    786	return MODE_OK;
    787}
    788
    789static void mga_connector_destroy(struct drm_connector *connector)
    790{
    791	struct mga_connector *mga_connector = to_mga_connector(connector);
    792	mgag200_i2c_destroy(mga_connector->i2c);
    793	drm_connector_cleanup(connector);
    794}
    795
    796static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = {
    797	.get_modes  = mga_vga_get_modes,
    798	.mode_valid = mga_vga_mode_valid,
    799};
    800
    801static const struct drm_connector_funcs mga_vga_connector_funcs = {
    802	.reset                  = drm_atomic_helper_connector_reset,
    803	.fill_modes             = drm_helper_probe_single_connector_modes,
    804	.destroy                = mga_connector_destroy,
    805	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
    806	.atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
    807};
    808
    809static int mgag200_vga_connector_init(struct mga_device *mdev)
    810{
    811	struct drm_device *dev = &mdev->base;
    812	struct mga_connector *mconnector = &mdev->connector;
    813	struct drm_connector *connector = &mconnector->base;
    814	struct mga_i2c_chan *i2c;
    815	int ret;
    816
    817	i2c = mgag200_i2c_create(dev);
    818	if (!i2c)
    819		drm_warn(dev, "failed to add DDC bus\n");
    820
    821	ret = drm_connector_init_with_ddc(dev, connector,
    822					  &mga_vga_connector_funcs,
    823					  DRM_MODE_CONNECTOR_VGA,
    824					  &i2c->adapter);
    825	if (ret)
    826		goto err_mgag200_i2c_destroy;
    827	drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs);
    828
    829	mconnector->i2c = i2c;
    830
    831	return 0;
    832
    833err_mgag200_i2c_destroy:
    834	mgag200_i2c_destroy(i2c);
    835	return ret;
    836}
    837
    838/*
    839 * Simple Display Pipe
    840 */
    841
    842static enum drm_mode_status
    843mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
    844				       const struct drm_display_mode *mode)
    845{
    846	return MODE_OK;
    847}
    848
    849static void
    850mgag200_handle_damage(struct mga_device *mdev, struct drm_framebuffer *fb,
    851		      struct drm_rect *clip, const struct iosys_map *map)
    852{
    853	void __iomem *dst = mdev->vram;
    854	void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */
    855
    856	dst += drm_fb_clip_offset(fb->pitches[0], fb->format, clip);
    857	drm_fb_memcpy_toio(dst, fb->pitches[0], vmap, fb, clip);
    858
    859	/* Always scanout image at VRAM offset 0 */
    860	mgag200_set_startadd(mdev, (u32)0);
    861	mgag200_set_offset(mdev, fb);
    862}
    863
    864static void
    865mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
    866				   struct drm_crtc_state *crtc_state,
    867				   struct drm_plane_state *plane_state)
    868{
    869	struct drm_crtc *crtc = &pipe->crtc;
    870	struct drm_device *dev = crtc->dev;
    871	struct mga_device *mdev = to_mga_device(dev);
    872	struct mgag200_pll *pixpll = &mdev->pixpll;
    873	struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
    874	struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
    875	struct drm_framebuffer *fb = plane_state->fb;
    876	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
    877	struct drm_rect fullscreen = {
    878		.x1 = 0,
    879		.x2 = fb->width,
    880		.y1 = 0,
    881		.y2 = fb->height,
    882	};
    883
    884	/*
    885	 * Concurrent operations could possibly trigger a call to
    886	 * drm_connector_helper_funcs.get_modes by trying to read the
    887	 * display modes. Protect access to I/O registers by acquiring
    888	 * the I/O-register lock.
    889	 */
    890	mutex_lock(&mdev->rmmio_lock);
    891
    892	if (mdev->type == G200_WB || mdev->type == G200_EW3)
    893		mgag200_g200wb_hold_bmc(mdev);
    894
    895	mgag200_set_format_regs(mdev, fb);
    896	mgag200_set_mode_regs(mdev, adjusted_mode);
    897
    898	pixpll->funcs->update(pixpll, &mgag200_crtc_state->pixpllc);
    899
    900	if (mdev->type == G200_ER)
    901		mgag200_g200er_reset_tagfifo(mdev);
    902
    903	if (IS_G200_SE(mdev))
    904		mgag200_g200se_set_hiprilvl(mdev, adjusted_mode, fb);
    905	else if (mdev->type == G200_EV)
    906		mgag200_g200ev_set_hiprilvl(mdev);
    907
    908	if (mdev->type == G200_WB || mdev->type == G200_EW3)
    909		mgag200_g200wb_release_bmc(mdev);
    910
    911	mga_crtc_load_lut(crtc);
    912	mgag200_enable_display(mdev);
    913
    914	mgag200_handle_damage(mdev, fb, &fullscreen, &shadow_plane_state->data[0]);
    915
    916	mutex_unlock(&mdev->rmmio_lock);
    917}
    918
    919static void
    920mgag200_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
    921{
    922	struct drm_crtc *crtc = &pipe->crtc;
    923	struct mga_device *mdev = to_mga_device(crtc->dev);
    924
    925	mgag200_disable_display(mdev);
    926}
    927
    928static int
    929mgag200_simple_display_pipe_check(struct drm_simple_display_pipe *pipe,
    930				  struct drm_plane_state *plane_state,
    931				  struct drm_crtc_state *crtc_state)
    932{
    933	struct drm_plane *plane = plane_state->plane;
    934	struct drm_device *dev = plane->dev;
    935	struct mga_device *mdev = to_mga_device(dev);
    936	struct mgag200_pll *pixpll = &mdev->pixpll;
    937	struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
    938	struct drm_framebuffer *new_fb = plane_state->fb;
    939	struct drm_framebuffer *fb = NULL;
    940	int ret;
    941
    942	if (!new_fb)
    943		return 0;
    944
    945	if (plane->state)
    946		fb = plane->state->fb;
    947
    948	if (!fb || (fb->format != new_fb->format))
    949		crtc_state->mode_changed = true; /* update PLL settings */
    950
    951	if (crtc_state->mode_changed) {
    952		ret = pixpll->funcs->compute(pixpll, crtc_state->mode.clock,
    953					     &mgag200_crtc_state->pixpllc);
    954		if (ret)
    955			return ret;
    956	}
    957
    958	return 0;
    959}
    960
    961static void
    962mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
    963				   struct drm_plane_state *old_state)
    964{
    965	struct drm_plane *plane = &pipe->plane;
    966	struct drm_device *dev = plane->dev;
    967	struct mga_device *mdev = to_mga_device(dev);
    968	struct drm_plane_state *state = plane->state;
    969	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
    970	struct drm_framebuffer *fb = state->fb;
    971	struct drm_rect damage;
    972
    973	if (!fb)
    974		return;
    975
    976	mutex_lock(&mdev->rmmio_lock);
    977
    978	if (drm_atomic_helper_damage_merged(old_state, state, &damage))
    979		mgag200_handle_damage(mdev, fb, &damage, &shadow_plane_state->data[0]);
    980
    981	mutex_unlock(&mdev->rmmio_lock);
    982}
    983
    984static struct drm_crtc_state *
    985mgag200_simple_display_pipe_duplicate_crtc_state(struct drm_simple_display_pipe *pipe)
    986{
    987	struct drm_crtc *crtc = &pipe->crtc;
    988	struct drm_crtc_state *crtc_state = crtc->state;
    989	struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
    990	struct mgag200_crtc_state *new_mgag200_crtc_state;
    991
    992	if (!crtc_state)
    993		return NULL;
    994
    995	new_mgag200_crtc_state = kzalloc(sizeof(*new_mgag200_crtc_state), GFP_KERNEL);
    996	if (!new_mgag200_crtc_state)
    997		return NULL;
    998	__drm_atomic_helper_crtc_duplicate_state(crtc, &new_mgag200_crtc_state->base);
    999
   1000	memcpy(&new_mgag200_crtc_state->pixpllc, &mgag200_crtc_state->pixpllc,
   1001	       sizeof(new_mgag200_crtc_state->pixpllc));
   1002
   1003	return &new_mgag200_crtc_state->base;
   1004}
   1005
   1006static void mgag200_simple_display_pipe_destroy_crtc_state(struct drm_simple_display_pipe *pipe,
   1007							   struct drm_crtc_state *crtc_state)
   1008{
   1009	struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
   1010
   1011	__drm_atomic_helper_crtc_destroy_state(&mgag200_crtc_state->base);
   1012	kfree(mgag200_crtc_state);
   1013}
   1014
   1015static void mgag200_simple_display_pipe_reset_crtc(struct drm_simple_display_pipe *pipe)
   1016{
   1017	struct drm_crtc *crtc = &pipe->crtc;
   1018	struct mgag200_crtc_state *mgag200_crtc_state;
   1019
   1020	if (crtc->state) {
   1021		mgag200_simple_display_pipe_destroy_crtc_state(pipe, crtc->state);
   1022		crtc->state = NULL; /* must be set to NULL here */
   1023	}
   1024
   1025	mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), GFP_KERNEL);
   1026	if (!mgag200_crtc_state)
   1027		return;
   1028	__drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base);
   1029}
   1030
   1031static const struct drm_simple_display_pipe_funcs
   1032mgag200_simple_display_pipe_funcs = {
   1033	.mode_valid = mgag200_simple_display_pipe_mode_valid,
   1034	.enable	    = mgag200_simple_display_pipe_enable,
   1035	.disable    = mgag200_simple_display_pipe_disable,
   1036	.check	    = mgag200_simple_display_pipe_check,
   1037	.update	    = mgag200_simple_display_pipe_update,
   1038	.reset_crtc = mgag200_simple_display_pipe_reset_crtc,
   1039	.duplicate_crtc_state = mgag200_simple_display_pipe_duplicate_crtc_state,
   1040	.destroy_crtc_state = mgag200_simple_display_pipe_destroy_crtc_state,
   1041	DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
   1042};
   1043
   1044static const uint32_t mgag200_simple_display_pipe_formats[] = {
   1045	DRM_FORMAT_XRGB8888,
   1046	DRM_FORMAT_RGB565,
   1047	DRM_FORMAT_RGB888,
   1048};
   1049
   1050static const uint64_t mgag200_simple_display_pipe_fmtmods[] = {
   1051	DRM_FORMAT_MOD_LINEAR,
   1052	DRM_FORMAT_MOD_INVALID
   1053};
   1054
   1055/*
   1056 * Mode config
   1057 */
   1058
   1059static const struct drm_mode_config_funcs mgag200_mode_config_funcs = {
   1060	.fb_create     = drm_gem_fb_create_with_dirty,
   1061	.atomic_check  = drm_atomic_helper_check,
   1062	.atomic_commit = drm_atomic_helper_commit,
   1063};
   1064
   1065static unsigned int mgag200_preferred_depth(struct mga_device *mdev)
   1066{
   1067	if (IS_G200_SE(mdev) && mdev->vram_fb_available < (2048*1024))
   1068		return 16;
   1069	else
   1070		return 32;
   1071}
   1072
   1073int mgag200_modeset_init(struct mga_device *mdev)
   1074{
   1075	struct drm_device *dev = &mdev->base;
   1076	struct drm_connector *connector = &mdev->connector.base;
   1077	struct drm_simple_display_pipe *pipe = &mdev->display_pipe;
   1078	size_t format_count = ARRAY_SIZE(mgag200_simple_display_pipe_formats);
   1079	int ret;
   1080
   1081	mgag200_init_regs(mdev);
   1082
   1083	ret = drmm_mode_config_init(dev);
   1084	if (ret) {
   1085		drm_err(dev, "drmm_mode_config_init() failed, error %d\n",
   1086			ret);
   1087		return ret;
   1088	}
   1089
   1090	dev->mode_config.max_width = MGAG200_MAX_FB_WIDTH;
   1091	dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT;
   1092
   1093	dev->mode_config.preferred_depth = mgag200_preferred_depth(mdev);
   1094
   1095	dev->mode_config.fb_base = mdev->mc.vram_base;
   1096
   1097	dev->mode_config.funcs = &mgag200_mode_config_funcs;
   1098
   1099	ret = mgag200_vga_connector_init(mdev);
   1100	if (ret) {
   1101		drm_err(dev,
   1102			"mgag200_vga_connector_init() failed, error %d\n",
   1103			ret);
   1104		return ret;
   1105	}
   1106
   1107	ret = mgag200_pixpll_init(&mdev->pixpll, mdev);
   1108	if (ret)
   1109		return ret;
   1110
   1111	ret = drm_simple_display_pipe_init(dev, pipe,
   1112					   &mgag200_simple_display_pipe_funcs,
   1113					   mgag200_simple_display_pipe_formats,
   1114					   format_count,
   1115					   mgag200_simple_display_pipe_fmtmods,
   1116					   connector);
   1117	if (ret) {
   1118		drm_err(dev,
   1119			"drm_simple_display_pipe_init() failed, error %d\n",
   1120			ret);
   1121		return ret;
   1122	}
   1123
   1124	/* FIXME: legacy gamma tables; convert to CRTC state */
   1125	drm_mode_crtc_set_gamma_size(&pipe->crtc, MGAG200_LUT_SIZE);
   1126
   1127	drm_mode_config_reset(dev);
   1128
   1129	return 0;
   1130}