1c51669eaSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2414c4531SDave Airlie /* 3414c4531SDave Airlie * Copyright 2010 Matt Turner. 4414c4531SDave Airlie * Copyright 2012 Red Hat 5414c4531SDave Airlie * 6414c4531SDave Airlie * Authors: Matthew Garrett 7414c4531SDave Airlie * Matt Turner 8414c4531SDave Airlie * Dave Airlie 9414c4531SDave Airlie */ 10414c4531SDave Airlie 11414c4531SDave Airlie #include <linux/delay.h> 1249a3f51dSThomas Zimmermann #include <linux/dma-buf-map.h> 13414c4531SDave Airlie 1488fabb75SThomas Zimmermann #include <drm/drm_atomic_helper.h> 1588fabb75SThomas Zimmermann #include <drm/drm_atomic_state_helper.h> 16760285e7SDavid Howells #include <drm/drm_crtc_helper.h> 17913ec479SThomas Zimmermann #include <drm/drm_damage_helper.h> 18913ec479SThomas Zimmermann #include <drm/drm_format_helper.h> 199f397801SSam Ravnborg #include <drm/drm_fourcc.h> 204862ffaeSThomas Zimmermann #include <drm/drm_gem_atomic_helper.h> 215635b7cfSThomas Zimmermann #include <drm/drm_gem_framebuffer_helper.h> 223cb9ae4fSDaniel Vetter #include <drm/drm_plane_helper.h> 2388fabb75SThomas Zimmermann #include <drm/drm_print.h> 24fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h> 2503e44ad1SThomas Zimmermann #include <drm/drm_simple_kms_helper.h> 26414c4531SDave Airlie 27414c4531SDave Airlie #include "mgag200_drv.h" 28414c4531SDave Airlie 29414c4531SDave Airlie #define MGAG200_LUT_SIZE 256 30414c4531SDave Airlie 31414c4531SDave Airlie /* 32414c4531SDave Airlie * This file contains setup code for the CRTC. 33414c4531SDave Airlie */ 34414c4531SDave Airlie 35414c4531SDave Airlie static void mga_crtc_load_lut(struct drm_crtc *crtc) 36414c4531SDave Airlie { 37414c4531SDave Airlie struct drm_device *dev = crtc->dev; 388d8ff2a9SThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 3988fabb75SThomas Zimmermann struct drm_framebuffer *fb; 409ed85e14SPeter Rosin u16 *r_ptr, *g_ptr, *b_ptr; 41414c4531SDave Airlie int i; 42414c4531SDave Airlie 43414c4531SDave Airlie if (!crtc->enabled) 44414c4531SDave Airlie return; 45414c4531SDave Airlie 4688fabb75SThomas Zimmermann if (!mdev->display_pipe.plane.state) 4788fabb75SThomas Zimmermann return; 4888fabb75SThomas Zimmermann 4988fabb75SThomas Zimmermann fb = mdev->display_pipe.plane.state->fb; 5088fabb75SThomas Zimmermann 519ed85e14SPeter Rosin r_ptr = crtc->gamma_store; 529ed85e14SPeter Rosin g_ptr = r_ptr + crtc->gamma_size; 539ed85e14SPeter Rosin b_ptr = g_ptr + crtc->gamma_size; 549ed85e14SPeter Rosin 55414c4531SDave Airlie WREG8(DAC_INDEX + MGA1064_INDEX, 0); 56414c4531SDave Airlie 57272725c7SVille Syrjälä if (fb && fb->format->cpp[0] * 8 == 16) { 58b00c600eSVille Syrjälä int inc = (fb->format->depth == 15) ? 8 : 4; 59de7500eaSEgbert Eich u8 r, b; 60de7500eaSEgbert Eich for (i = 0; i < MGAG200_LUT_SIZE; i += inc) { 61b00c600eSVille Syrjälä if (fb->format->depth == 16) { 62de7500eaSEgbert Eich if (i > (MGAG200_LUT_SIZE >> 1)) { 63de7500eaSEgbert Eich r = b = 0; 64de7500eaSEgbert Eich } else { 659ed85e14SPeter Rosin r = *r_ptr++ >> 8; 669ed85e14SPeter Rosin b = *b_ptr++ >> 8; 679ed85e14SPeter Rosin r_ptr++; 689ed85e14SPeter Rosin b_ptr++; 69de7500eaSEgbert Eich } 70de7500eaSEgbert Eich } else { 719ed85e14SPeter Rosin r = *r_ptr++ >> 8; 729ed85e14SPeter Rosin b = *b_ptr++ >> 8; 73de7500eaSEgbert Eich } 74de7500eaSEgbert Eich /* VGA registers */ 75de7500eaSEgbert Eich WREG8(DAC_INDEX + MGA1064_COL_PAL, r); 769ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8); 77de7500eaSEgbert Eich WREG8(DAC_INDEX + MGA1064_COL_PAL, b); 78de7500eaSEgbert Eich } 79de7500eaSEgbert Eich return; 80de7500eaSEgbert Eich } 81414c4531SDave Airlie for (i = 0; i < MGAG200_LUT_SIZE; i++) { 82414c4531SDave Airlie /* VGA registers */ 839ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *r_ptr++ >> 8); 849ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *g_ptr++ >> 8); 859ed85e14SPeter Rosin WREG8(DAC_INDEX + MGA1064_COL_PAL, *b_ptr++ >> 8); 86414c4531SDave Airlie } 87414c4531SDave Airlie } 88414c4531SDave Airlie 89414c4531SDave Airlie static inline void mga_wait_vsync(struct mga_device *mdev) 90414c4531SDave Airlie { 913cdc0e8dSChristopher Harvey unsigned long timeout = jiffies + HZ/10; 92414c4531SDave Airlie unsigned int status = 0; 93414c4531SDave Airlie 94414c4531SDave Airlie do { 95414c4531SDave Airlie status = RREG32(MGAREG_Status); 963cdc0e8dSChristopher Harvey } while ((status & 0x08) && time_before(jiffies, timeout)); 973cdc0e8dSChristopher Harvey timeout = jiffies + HZ/10; 98414c4531SDave Airlie status = 0; 99414c4531SDave Airlie do { 100414c4531SDave Airlie status = RREG32(MGAREG_Status); 1013cdc0e8dSChristopher Harvey } while (!(status & 0x08) && time_before(jiffies, timeout)); 102414c4531SDave Airlie } 103414c4531SDave Airlie 104414c4531SDave Airlie static inline void mga_wait_busy(struct mga_device *mdev) 105414c4531SDave Airlie { 1063cdc0e8dSChristopher Harvey unsigned long timeout = jiffies + HZ; 107414c4531SDave Airlie unsigned int status = 0; 108414c4531SDave Airlie do { 109414c4531SDave Airlie status = RREG8(MGAREG_Status + 2); 1103cdc0e8dSChristopher Harvey } while ((status & 0x01) && time_before(jiffies, timeout)); 111414c4531SDave Airlie } 112414c4531SDave Airlie 113904347fbSThomas Zimmermann static void mgag200_g200wb_hold_bmc(struct mga_device *mdev) 114414c4531SDave Airlie { 115414c4531SDave Airlie u8 tmp; 116414c4531SDave Airlie int iter_max; 117414c4531SDave Airlie 118414c4531SDave Airlie /* 1- The first step is to warn the BMC of an upcoming mode change. 119414c4531SDave Airlie * We are putting the misc<0> to output.*/ 120414c4531SDave Airlie 121414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL); 122414c4531SDave Airlie tmp = RREG8(DAC_DATA); 123414c4531SDave Airlie tmp |= 0x10; 124414c4531SDave Airlie WREG_DAC(MGA1064_GEN_IO_CTL, tmp); 125414c4531SDave Airlie 126414c4531SDave Airlie /* we are putting a 1 on the misc<0> line */ 127414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); 128414c4531SDave Airlie tmp = RREG8(DAC_DATA); 129414c4531SDave Airlie tmp |= 0x10; 130414c4531SDave Airlie WREG_DAC(MGA1064_GEN_IO_DATA, tmp); 131414c4531SDave Airlie 132414c4531SDave Airlie /* 2- Second step to mask and further scan request 133414c4531SDave Airlie * This will be done by asserting the remfreqmsk bit (XSPAREREG<7>) 134414c4531SDave Airlie */ 135414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 136414c4531SDave Airlie tmp = RREG8(DAC_DATA); 137414c4531SDave Airlie tmp |= 0x80; 138414c4531SDave Airlie WREG_DAC(MGA1064_SPAREREG, tmp); 139414c4531SDave Airlie 140414c4531SDave Airlie /* 3a- the third step is to verifu if there is an active scan 141414c4531SDave Airlie * We are searching for a 0 on remhsyncsts <XSPAREREG<0>) 142414c4531SDave Airlie */ 143414c4531SDave Airlie iter_max = 300; 144414c4531SDave Airlie while (!(tmp & 0x1) && iter_max) { 145414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 146414c4531SDave Airlie tmp = RREG8(DAC_DATA); 147414c4531SDave Airlie udelay(1000); 148414c4531SDave Airlie iter_max--; 149414c4531SDave Airlie } 150414c4531SDave Airlie 151414c4531SDave Airlie /* 3b- this step occurs only if the remove is actually scanning 152414c4531SDave Airlie * we are waiting for the end of the frame which is a 1 on 153414c4531SDave Airlie * remvsyncsts (XSPAREREG<1>) 154414c4531SDave Airlie */ 155414c4531SDave Airlie if (iter_max) { 156414c4531SDave Airlie iter_max = 300; 157414c4531SDave Airlie while ((tmp & 0x2) && iter_max) { 158414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 159414c4531SDave Airlie tmp = RREG8(DAC_DATA); 160414c4531SDave Airlie udelay(1000); 161414c4531SDave Airlie iter_max--; 162414c4531SDave Airlie } 163414c4531SDave Airlie } 164414c4531SDave Airlie } 165414c4531SDave Airlie 166904347fbSThomas Zimmermann static void mgag200_g200wb_release_bmc(struct mga_device *mdev) 167414c4531SDave Airlie { 168414c4531SDave Airlie u8 tmp; 169414c4531SDave Airlie 170414c4531SDave Airlie /* 1- The first step is to ensure that the vrsten and hrsten are set */ 171414c4531SDave Airlie WREG8(MGAREG_CRTCEXT_INDEX, 1); 172414c4531SDave Airlie tmp = RREG8(MGAREG_CRTCEXT_DATA); 173414c4531SDave Airlie WREG8(MGAREG_CRTCEXT_DATA, tmp | 0x88); 174414c4531SDave Airlie 175414c4531SDave Airlie /* 2- second step is to assert the rstlvl2 */ 176414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); 177414c4531SDave Airlie tmp = RREG8(DAC_DATA); 178414c4531SDave Airlie tmp |= 0x8; 179414c4531SDave Airlie WREG8(DAC_DATA, tmp); 180414c4531SDave Airlie 181414c4531SDave Airlie /* wait 10 us */ 182414c4531SDave Airlie udelay(10); 183414c4531SDave Airlie 184414c4531SDave Airlie /* 3- deassert rstlvl2 */ 185414c4531SDave Airlie tmp &= ~0x08; 186414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); 187414c4531SDave Airlie WREG8(DAC_DATA, tmp); 188414c4531SDave Airlie 189414c4531SDave Airlie /* 4- remove mask of scan request */ 190414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_SPAREREG); 191414c4531SDave Airlie tmp = RREG8(DAC_DATA); 192414c4531SDave Airlie tmp &= ~0x80; 193414c4531SDave Airlie WREG8(DAC_DATA, tmp); 194414c4531SDave Airlie 195414c4531SDave Airlie /* 5- put back a 0 on the misc<0> line */ 196414c4531SDave Airlie WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); 197414c4531SDave Airlie tmp = RREG8(DAC_DATA); 198414c4531SDave Airlie tmp &= ~0x10; 199414c4531SDave Airlie WREG_DAC(MGA1064_GEN_IO_DATA, tmp); 200414c4531SDave Airlie } 201414c4531SDave Airlie 2029f1d0366SChristopher Harvey /* 203d6237687SThomas Zimmermann * This is how the framebuffer base address is stored in g200 cards: 204d6237687SThomas Zimmermann * * Assume @offset is the gpu_addr variable of the framebuffer object 205d6237687SThomas Zimmermann * * Then addr is the number of _pixels_ (not bytes) from the start of 206d6237687SThomas Zimmermann * VRAM to the first pixel we want to display. (divided by 2 for 32bit 207d6237687SThomas Zimmermann * framebuffers) 208d6237687SThomas Zimmermann * * addr is stored in the CRTCEXT0, CRTCC and CRTCD registers 209d6237687SThomas Zimmermann * addr<20> -> CRTCEXT0<6> 210d6237687SThomas Zimmermann * addr<19-16> -> CRTCEXT0<3-0> 211d6237687SThomas Zimmermann * addr<15-8> -> CRTCC<7-0> 212d6237687SThomas Zimmermann * addr<7-0> -> CRTCD<7-0> 213d6237687SThomas Zimmermann * 214d6237687SThomas Zimmermann * CRTCEXT0 has to be programmed last to trigger an update and make the 215d6237687SThomas Zimmermann * new addr variable take effect. 2169f1d0366SChristopher Harvey */ 217d6237687SThomas Zimmermann static void mgag200_set_startadd(struct mga_device *mdev, 218d6237687SThomas Zimmermann unsigned long offset) 219414c4531SDave Airlie { 220832eddf5SThomas Zimmermann struct drm_device *dev = &mdev->base; 221d6237687SThomas Zimmermann u32 startadd; 222d6237687SThomas Zimmermann u8 crtcc, crtcd, crtcext0; 223414c4531SDave Airlie 224d6237687SThomas Zimmermann startadd = offset / 8; 225414c4531SDave Airlie 226d6237687SThomas Zimmermann /* 227d6237687SThomas Zimmermann * Can't store addresses any higher than that, but we also 228d6237687SThomas Zimmermann * don't have more than 16 MiB of memory, so it should be fine. 229d6237687SThomas Zimmermann */ 230d6237687SThomas Zimmermann drm_WARN_ON(dev, startadd > 0x1fffff); 231414c4531SDave Airlie 232d6237687SThomas Zimmermann RREG_ECRT(0x00, crtcext0); 233d6237687SThomas Zimmermann 234d6237687SThomas Zimmermann crtcc = (startadd >> 8) & 0xff; 235d6237687SThomas Zimmermann crtcd = startadd & 0xff; 236d6237687SThomas Zimmermann crtcext0 &= 0xb0; 237d6237687SThomas Zimmermann crtcext0 |= ((startadd >> 14) & BIT(6)) | 238d6237687SThomas Zimmermann ((startadd >> 16) & 0x0f); 239d6237687SThomas Zimmermann 240d6237687SThomas Zimmermann WREG_CRT(0x0c, crtcc); 241d6237687SThomas Zimmermann WREG_CRT(0x0d, crtcd); 242d6237687SThomas Zimmermann WREG_ECRT(0x00, crtcext0); 243414c4531SDave Airlie } 244414c4531SDave Airlie 2454f710d7cSThomas Zimmermann static void mgag200_set_dac_regs(struct mga_device *mdev) 2464f710d7cSThomas Zimmermann { 2474f710d7cSThomas Zimmermann size_t i; 2484f710d7cSThomas Zimmermann u8 dacvalue[] = { 2494f710d7cSThomas Zimmermann /* 0x00: */ 0, 0, 0, 0, 0, 0, 0x00, 0, 2504f710d7cSThomas Zimmermann /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0, 2514f710d7cSThomas Zimmermann /* 0x10: */ 0, 0, 0, 0, 0, 0, 0, 0, 2524f710d7cSThomas Zimmermann /* 0x18: */ 0x00, 0, 0xC9, 0xFF, 0xBF, 0x20, 0x1F, 0x20, 2534f710d7cSThomas Zimmermann /* 0x20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2544f710d7cSThomas Zimmermann /* 0x28: */ 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x40, 2554f710d7cSThomas Zimmermann /* 0x30: */ 0x00, 0xB0, 0x00, 0xC2, 0x34, 0x14, 0x02, 0x83, 2564f710d7cSThomas Zimmermann /* 0x38: */ 0x00, 0x93, 0x00, 0x77, 0x00, 0x00, 0x00, 0x3A, 2574f710d7cSThomas Zimmermann /* 0x40: */ 0, 0, 0, 0, 0, 0, 0, 0, 2584f710d7cSThomas Zimmermann /* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0 2594f710d7cSThomas Zimmermann }; 2604f710d7cSThomas Zimmermann 2614f710d7cSThomas Zimmermann switch (mdev->type) { 262e20dfd27SThomas Zimmermann case G200_PCI: 263e20dfd27SThomas Zimmermann case G200_AGP: 264e20dfd27SThomas Zimmermann dacvalue[MGA1064_SYS_PLL_M] = 0x04; 265e20dfd27SThomas Zimmermann dacvalue[MGA1064_SYS_PLL_N] = 0x2D; 266e20dfd27SThomas Zimmermann dacvalue[MGA1064_SYS_PLL_P] = 0x19; 267e20dfd27SThomas Zimmermann break; 2684f710d7cSThomas Zimmermann case G200_SE_A: 2694f710d7cSThomas Zimmermann case G200_SE_B: 2704f710d7cSThomas Zimmermann dacvalue[MGA1064_VREF_CTL] = 0x03; 2714f710d7cSThomas Zimmermann dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL; 2724f710d7cSThomas Zimmermann dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_DAC_EN | 2734f710d7cSThomas Zimmermann MGA1064_MISC_CTL_VGA8 | 2744f710d7cSThomas Zimmermann MGA1064_MISC_CTL_DAC_RAM_CS; 2754f710d7cSThomas Zimmermann break; 2764f710d7cSThomas Zimmermann case G200_WB: 2774f710d7cSThomas Zimmermann case G200_EW3: 2784f710d7cSThomas Zimmermann dacvalue[MGA1064_VREF_CTL] = 0x07; 2794f710d7cSThomas Zimmermann break; 2804f710d7cSThomas Zimmermann case G200_EV: 2814f710d7cSThomas Zimmermann dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL; 2824f710d7cSThomas Zimmermann dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 | 2834f710d7cSThomas Zimmermann MGA1064_MISC_CTL_DAC_RAM_CS; 2844f710d7cSThomas Zimmermann break; 2854f710d7cSThomas Zimmermann case G200_EH: 2864f710d7cSThomas Zimmermann case G200_EH3: 2874f710d7cSThomas Zimmermann dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 | 2884f710d7cSThomas Zimmermann MGA1064_MISC_CTL_DAC_RAM_CS; 2894f710d7cSThomas Zimmermann break; 2904f710d7cSThomas Zimmermann case G200_ER: 2914f710d7cSThomas Zimmermann break; 2924f710d7cSThomas Zimmermann } 2934f710d7cSThomas Zimmermann 2944f710d7cSThomas Zimmermann for (i = 0; i < ARRAY_SIZE(dacvalue); i++) { 2954f710d7cSThomas Zimmermann if ((i <= 0x17) || 2964f710d7cSThomas Zimmermann (i == 0x1b) || 2974f710d7cSThomas Zimmermann (i == 0x1c) || 2984f710d7cSThomas Zimmermann ((i >= 0x1f) && (i <= 0x29)) || 2994f710d7cSThomas Zimmermann ((i >= 0x30) && (i <= 0x37))) 3004f710d7cSThomas Zimmermann continue; 3014f710d7cSThomas Zimmermann if (IS_G200_SE(mdev) && 3024f710d7cSThomas Zimmermann ((i == 0x2c) || (i == 0x2d) || (i == 0x2e))) 3034f710d7cSThomas Zimmermann continue; 3044f710d7cSThomas Zimmermann if ((mdev->type == G200_EV || 3054f710d7cSThomas Zimmermann mdev->type == G200_WB || 3064f710d7cSThomas Zimmermann mdev->type == G200_EH || 3074f710d7cSThomas Zimmermann mdev->type == G200_EW3 || 3084f710d7cSThomas Zimmermann mdev->type == G200_EH3) && 3094f710d7cSThomas Zimmermann (i >= 0x44) && (i <= 0x4e)) 3104f710d7cSThomas Zimmermann continue; 3114f710d7cSThomas Zimmermann 3124f710d7cSThomas Zimmermann WREG_DAC(i, dacvalue[i]); 3134f710d7cSThomas Zimmermann } 3144f710d7cSThomas Zimmermann 3154f710d7cSThomas Zimmermann if (mdev->type == G200_ER) 3164f710d7cSThomas Zimmermann WREG_DAC(0x90, 0); 3174f710d7cSThomas Zimmermann } 3184f710d7cSThomas Zimmermann 3194f710d7cSThomas Zimmermann static void mgag200_init_regs(struct mga_device *mdev) 3204f710d7cSThomas Zimmermann { 3219053cad2SThomas Zimmermann u8 crtc11, misc; 3224f710d7cSThomas Zimmermann 3234f710d7cSThomas Zimmermann mgag200_set_dac_regs(mdev); 3244f710d7cSThomas Zimmermann 3254f710d7cSThomas Zimmermann WREG_SEQ(2, 0x0f); 3264f710d7cSThomas Zimmermann WREG_SEQ(3, 0x00); 3274f710d7cSThomas Zimmermann WREG_SEQ(4, 0x0e); 3284f710d7cSThomas Zimmermann 3294f710d7cSThomas Zimmermann WREG_CRT(10, 0); 3304f710d7cSThomas Zimmermann WREG_CRT(11, 0); 3314f710d7cSThomas Zimmermann WREG_CRT(12, 0); 3324f710d7cSThomas Zimmermann WREG_CRT(13, 0); 3334f710d7cSThomas Zimmermann WREG_CRT(14, 0); 3344f710d7cSThomas Zimmermann WREG_CRT(15, 0); 3354f710d7cSThomas Zimmermann 336da568d5eSThomas Zimmermann RREG_CRT(0x11, crtc11); 337da568d5eSThomas Zimmermann crtc11 &= ~(MGAREG_CRTC11_CRTCPROTECT | 338da568d5eSThomas Zimmermann MGAREG_CRTC11_VINTEN | 339da568d5eSThomas Zimmermann MGAREG_CRTC11_VINTCLR); 340da568d5eSThomas Zimmermann WREG_CRT(0x11, crtc11); 341da568d5eSThomas Zimmermann 3424f710d7cSThomas Zimmermann if (mdev->type == G200_ER) 3434f710d7cSThomas Zimmermann WREG_ECRT(0x24, 0x5); 3444f710d7cSThomas Zimmermann 3454f710d7cSThomas Zimmermann if (mdev->type == G200_EW3) 3464f710d7cSThomas Zimmermann WREG_ECRT(0x34, 0x5); 3474f710d7cSThomas Zimmermann 3484f710d7cSThomas Zimmermann misc = RREG8(MGA_MISC_IN); 349b9fa77ecSThomas Zimmermann misc |= MGAREG_MISC_IOADSEL; 3504f710d7cSThomas Zimmermann WREG8(MGA_MISC_OUT, misc); 3514f710d7cSThomas Zimmermann } 3524f710d7cSThomas Zimmermann 353a6edae07SThomas Zimmermann static void mgag200_set_mode_regs(struct mga_device *mdev, 354a6edae07SThomas Zimmermann const struct drm_display_mode *mode) 355a6edae07SThomas Zimmermann { 356a6edae07SThomas Zimmermann unsigned int hdisplay, hsyncstart, hsyncend, htotal; 357a6edae07SThomas Zimmermann unsigned int vdisplay, vsyncstart, vsyncend, vtotal; 358db05f8d3SThomas Zimmermann u8 misc, crtcext1, crtcext2, crtcext5; 359a6edae07SThomas Zimmermann 360a6edae07SThomas Zimmermann hdisplay = mode->hdisplay / 8 - 1; 361a6edae07SThomas Zimmermann hsyncstart = mode->hsync_start / 8 - 1; 362a6edae07SThomas Zimmermann hsyncend = mode->hsync_end / 8 - 1; 363a6edae07SThomas Zimmermann htotal = mode->htotal / 8 - 1; 364a6edae07SThomas Zimmermann 365a6edae07SThomas Zimmermann /* Work around hardware quirk */ 366a6edae07SThomas Zimmermann if ((htotal & 0x07) == 0x06 || (htotal & 0x07) == 0x04) 367a6edae07SThomas Zimmermann htotal++; 368a6edae07SThomas Zimmermann 369a6edae07SThomas Zimmermann vdisplay = mode->vdisplay - 1; 370a6edae07SThomas Zimmermann vsyncstart = mode->vsync_start - 1; 371a6edae07SThomas Zimmermann vsyncend = mode->vsync_end - 1; 372a6edae07SThomas Zimmermann vtotal = mode->vtotal - 2; 373a6edae07SThomas Zimmermann 374db05f8d3SThomas Zimmermann misc = RREG8(MGA_MISC_IN); 375db05f8d3SThomas Zimmermann 376a6edae07SThomas Zimmermann if (mode->flags & DRM_MODE_FLAG_NHSYNC) 377db05f8d3SThomas Zimmermann misc |= MGAREG_MISC_HSYNCPOL; 378db05f8d3SThomas Zimmermann else 379db05f8d3SThomas Zimmermann misc &= ~MGAREG_MISC_HSYNCPOL; 380db05f8d3SThomas Zimmermann 381a6edae07SThomas Zimmermann if (mode->flags & DRM_MODE_FLAG_NVSYNC) 382db05f8d3SThomas Zimmermann misc |= MGAREG_MISC_VSYNCPOL; 383db05f8d3SThomas Zimmermann else 384db05f8d3SThomas Zimmermann misc &= ~MGAREG_MISC_VSYNCPOL; 385a6edae07SThomas Zimmermann 386a6edae07SThomas Zimmermann crtcext1 = (((htotal - 4) & 0x100) >> 8) | 387a6edae07SThomas Zimmermann ((hdisplay & 0x100) >> 7) | 388a6edae07SThomas Zimmermann ((hsyncstart & 0x100) >> 6) | 389a6edae07SThomas Zimmermann (htotal & 0x40); 390a6edae07SThomas Zimmermann if (mdev->type == G200_WB || mdev->type == G200_EW3) 391a6edae07SThomas Zimmermann crtcext1 |= BIT(7) | /* vrsten */ 392a6edae07SThomas Zimmermann BIT(3); /* hrsten */ 393a6edae07SThomas Zimmermann 394a6edae07SThomas Zimmermann crtcext2 = ((vtotal & 0xc00) >> 10) | 395a6edae07SThomas Zimmermann ((vdisplay & 0x400) >> 8) | 396a6edae07SThomas Zimmermann ((vdisplay & 0xc00) >> 7) | 397a6edae07SThomas Zimmermann ((vsyncstart & 0xc00) >> 5) | 398a6edae07SThomas Zimmermann ((vdisplay & 0x400) >> 3); 399a6edae07SThomas Zimmermann crtcext5 = 0x00; 400a6edae07SThomas Zimmermann 401a6edae07SThomas Zimmermann WREG_CRT(0, htotal - 4); 402a6edae07SThomas Zimmermann WREG_CRT(1, hdisplay); 403a6edae07SThomas Zimmermann WREG_CRT(2, hdisplay); 404a6edae07SThomas Zimmermann WREG_CRT(3, (htotal & 0x1F) | 0x80); 405a6edae07SThomas Zimmermann WREG_CRT(4, hsyncstart); 406a6edae07SThomas Zimmermann WREG_CRT(5, ((htotal & 0x20) << 2) | (hsyncend & 0x1F)); 407a6edae07SThomas Zimmermann WREG_CRT(6, vtotal & 0xFF); 408a6edae07SThomas Zimmermann WREG_CRT(7, ((vtotal & 0x100) >> 8) | 409a6edae07SThomas Zimmermann ((vdisplay & 0x100) >> 7) | 410a6edae07SThomas Zimmermann ((vsyncstart & 0x100) >> 6) | 411a6edae07SThomas Zimmermann ((vdisplay & 0x100) >> 5) | 412a6edae07SThomas Zimmermann ((vdisplay & 0x100) >> 4) | /* linecomp */ 413a6edae07SThomas Zimmermann ((vtotal & 0x200) >> 4) | 414a6edae07SThomas Zimmermann ((vdisplay & 0x200) >> 3) | 415a6edae07SThomas Zimmermann ((vsyncstart & 0x200) >> 2)); 416a6edae07SThomas Zimmermann WREG_CRT(9, ((vdisplay & 0x200) >> 4) | 417a6edae07SThomas Zimmermann ((vdisplay & 0x200) >> 3)); 418a6edae07SThomas Zimmermann WREG_CRT(16, vsyncstart & 0xFF); 419a6edae07SThomas Zimmermann WREG_CRT(17, (vsyncend & 0x0F) | 0x20); 420a6edae07SThomas Zimmermann WREG_CRT(18, vdisplay & 0xFF); 421a6edae07SThomas Zimmermann WREG_CRT(20, 0); 422a6edae07SThomas Zimmermann WREG_CRT(21, vdisplay & 0xFF); 423a6edae07SThomas Zimmermann WREG_CRT(22, (vtotal + 1) & 0xFF); 424a6edae07SThomas Zimmermann WREG_CRT(23, 0xc3); 425a6edae07SThomas Zimmermann WREG_CRT(24, vdisplay & 0xFF); 426a6edae07SThomas Zimmermann 427a6edae07SThomas Zimmermann WREG_ECRT(0x01, crtcext1); 428a6edae07SThomas Zimmermann WREG_ECRT(0x02, crtcext2); 429a6edae07SThomas Zimmermann WREG_ECRT(0x05, crtcext5); 430db05f8d3SThomas Zimmermann 431db05f8d3SThomas Zimmermann WREG8(MGA_MISC_OUT, misc); 432a6edae07SThomas Zimmermann } 433a6edae07SThomas Zimmermann 434d9cc564bSThomas Zimmermann static u8 mgag200_get_bpp_shift(const struct drm_format_info *format) 43572a03a35SThomas Zimmermann { 436d9cc564bSThomas Zimmermann static const u8 bpp_shift[] = {0, 1, 0, 2}; 437d9cc564bSThomas Zimmermann 438d9cc564bSThomas Zimmermann return bpp_shift[format->cpp[0] - 1]; 43972a03a35SThomas Zimmermann } 44072a03a35SThomas Zimmermann 44172a03a35SThomas Zimmermann /* 44272a03a35SThomas Zimmermann * Calculates the HW offset value from the framebuffer's pitch. The 44372a03a35SThomas Zimmermann * offset is a multiple of the pixel size and depends on the display 44472a03a35SThomas Zimmermann * format. 44572a03a35SThomas Zimmermann */ 44672a03a35SThomas Zimmermann static u32 mgag200_calculate_offset(struct mga_device *mdev, 44772a03a35SThomas Zimmermann const struct drm_framebuffer *fb) 44872a03a35SThomas Zimmermann { 44972a03a35SThomas Zimmermann u32 offset = fb->pitches[0] / fb->format->cpp[0]; 450d9cc564bSThomas Zimmermann u8 bppshift = mgag200_get_bpp_shift(fb->format); 45172a03a35SThomas Zimmermann 45272a03a35SThomas Zimmermann if (fb->format->cpp[0] * 8 == 24) 45372a03a35SThomas Zimmermann offset = (offset * 3) >> (4 - bppshift); 45472a03a35SThomas Zimmermann else 45572a03a35SThomas Zimmermann offset = offset >> (4 - bppshift); 45672a03a35SThomas Zimmermann 45772a03a35SThomas Zimmermann return offset; 45872a03a35SThomas Zimmermann } 45972a03a35SThomas Zimmermann 46072a03a35SThomas Zimmermann static void mgag200_set_offset(struct mga_device *mdev, 46172a03a35SThomas Zimmermann const struct drm_framebuffer *fb) 46272a03a35SThomas Zimmermann { 46372a03a35SThomas Zimmermann u8 crtc13, crtcext0; 46472a03a35SThomas Zimmermann u32 offset = mgag200_calculate_offset(mdev, fb); 46572a03a35SThomas Zimmermann 46672a03a35SThomas Zimmermann RREG_ECRT(0, crtcext0); 46772a03a35SThomas Zimmermann 46872a03a35SThomas Zimmermann crtc13 = offset & 0xff; 46972a03a35SThomas Zimmermann 47072a03a35SThomas Zimmermann crtcext0 &= ~MGAREG_CRTCEXT0_OFFSET_MASK; 47172a03a35SThomas Zimmermann crtcext0 |= (offset >> 4) & MGAREG_CRTCEXT0_OFFSET_MASK; 47272a03a35SThomas Zimmermann 47372a03a35SThomas Zimmermann WREG_CRT(0x13, crtc13); 47472a03a35SThomas Zimmermann WREG_ECRT(0x00, crtcext0); 47572a03a35SThomas Zimmermann } 47672a03a35SThomas Zimmermann 477836d5368SThomas Zimmermann static void mgag200_set_format_regs(struct mga_device *mdev, 478836d5368SThomas Zimmermann const struct drm_framebuffer *fb) 479836d5368SThomas Zimmermann { 480832eddf5SThomas Zimmermann struct drm_device *dev = &mdev->base; 481836d5368SThomas Zimmermann const struct drm_format_info *format = fb->format; 482836d5368SThomas Zimmermann unsigned int bpp, bppshift, scale; 483836d5368SThomas Zimmermann u8 crtcext3, xmulctrl; 484836d5368SThomas Zimmermann 485836d5368SThomas Zimmermann bpp = format->cpp[0] * 8; 486836d5368SThomas Zimmermann 487d9cc564bSThomas Zimmermann bppshift = mgag200_get_bpp_shift(format); 488836d5368SThomas Zimmermann switch (bpp) { 489836d5368SThomas Zimmermann case 24: 490836d5368SThomas Zimmermann scale = ((1 << bppshift) * 3) - 1; 491836d5368SThomas Zimmermann break; 492836d5368SThomas Zimmermann default: 493836d5368SThomas Zimmermann scale = (1 << bppshift) - 1; 494836d5368SThomas Zimmermann break; 495836d5368SThomas Zimmermann } 496836d5368SThomas Zimmermann 497836d5368SThomas Zimmermann RREG_ECRT(3, crtcext3); 498836d5368SThomas Zimmermann 499836d5368SThomas Zimmermann switch (bpp) { 500836d5368SThomas Zimmermann case 8: 501836d5368SThomas Zimmermann xmulctrl = MGA1064_MUL_CTL_8bits; 502836d5368SThomas Zimmermann break; 503836d5368SThomas Zimmermann case 16: 504836d5368SThomas Zimmermann if (format->depth == 15) 505836d5368SThomas Zimmermann xmulctrl = MGA1064_MUL_CTL_15bits; 506836d5368SThomas Zimmermann else 507836d5368SThomas Zimmermann xmulctrl = MGA1064_MUL_CTL_16bits; 508836d5368SThomas Zimmermann break; 509836d5368SThomas Zimmermann case 24: 510836d5368SThomas Zimmermann xmulctrl = MGA1064_MUL_CTL_24bits; 511836d5368SThomas Zimmermann break; 512836d5368SThomas Zimmermann case 32: 513836d5368SThomas Zimmermann xmulctrl = MGA1064_MUL_CTL_32_24bits; 514836d5368SThomas Zimmermann break; 515836d5368SThomas Zimmermann default: 516836d5368SThomas Zimmermann /* BUG: We should have caught this problem already. */ 517836d5368SThomas Zimmermann drm_WARN_ON(dev, "invalid format depth\n"); 518836d5368SThomas Zimmermann return; 519836d5368SThomas Zimmermann } 520836d5368SThomas Zimmermann 521836d5368SThomas Zimmermann crtcext3 &= ~GENMASK(2, 0); 522836d5368SThomas Zimmermann crtcext3 |= scale; 523836d5368SThomas Zimmermann 524836d5368SThomas Zimmermann WREG_DAC(MGA1064_MUL_CTL, xmulctrl); 525836d5368SThomas Zimmermann 526836d5368SThomas Zimmermann WREG_GFX(0, 0x00); 527836d5368SThomas Zimmermann WREG_GFX(1, 0x00); 528836d5368SThomas Zimmermann WREG_GFX(2, 0x00); 529836d5368SThomas Zimmermann WREG_GFX(3, 0x00); 530836d5368SThomas Zimmermann WREG_GFX(4, 0x00); 531836d5368SThomas Zimmermann WREG_GFX(5, 0x40); 532836d5368SThomas Zimmermann WREG_GFX(6, 0x05); 533836d5368SThomas Zimmermann WREG_GFX(7, 0x0f); 534836d5368SThomas Zimmermann WREG_GFX(8, 0x0f); 535836d5368SThomas Zimmermann 536836d5368SThomas Zimmermann WREG_ECRT(3, crtcext3); 537836d5368SThomas Zimmermann } 538836d5368SThomas Zimmermann 5392e5ccbbaSThomas Zimmermann static void mgag200_g200er_reset_tagfifo(struct mga_device *mdev) 5402e5ccbbaSThomas Zimmermann { 5412e5ccbbaSThomas Zimmermann static uint32_t RESET_FLAG = 0x00200000; /* undocumented magic value */ 5422e5ccbbaSThomas Zimmermann u32 memctl; 5432e5ccbbaSThomas Zimmermann 5442e5ccbbaSThomas Zimmermann memctl = RREG32(MGAREG_MEMCTL); 5452e5ccbbaSThomas Zimmermann 5462e5ccbbaSThomas Zimmermann memctl |= RESET_FLAG; 5472e5ccbbaSThomas Zimmermann WREG32(MGAREG_MEMCTL, memctl); 5482e5ccbbaSThomas Zimmermann 5492e5ccbbaSThomas Zimmermann udelay(1000); 5502e5ccbbaSThomas Zimmermann 5512e5ccbbaSThomas Zimmermann memctl &= ~RESET_FLAG; 5522e5ccbbaSThomas Zimmermann WREG32(MGAREG_MEMCTL, memctl); 5532e5ccbbaSThomas Zimmermann } 5542e5ccbbaSThomas Zimmermann 5557fc1ae56SThomas Zimmermann static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev, 5567fc1ae56SThomas Zimmermann const struct drm_display_mode *mode, 5577fc1ae56SThomas Zimmermann const struct drm_framebuffer *fb) 5587fc1ae56SThomas Zimmermann { 559fb18825fSThomas Zimmermann u32 unique_rev_id = mdev->model.g200se.unique_rev_id; 5607fc1ae56SThomas Zimmermann unsigned int hiprilvl; 5617fc1ae56SThomas Zimmermann u8 crtcext6; 5627fc1ae56SThomas Zimmermann 563fb18825fSThomas Zimmermann if (unique_rev_id >= 0x04) { 5647fc1ae56SThomas Zimmermann hiprilvl = 0; 565fb18825fSThomas Zimmermann } else if (unique_rev_id >= 0x02) { 5667fc1ae56SThomas Zimmermann unsigned int bpp; 5677fc1ae56SThomas Zimmermann unsigned long mb; 5687fc1ae56SThomas Zimmermann 5697fc1ae56SThomas Zimmermann if (fb->format->cpp[0] * 8 > 16) 5707fc1ae56SThomas Zimmermann bpp = 32; 5717fc1ae56SThomas Zimmermann else if (fb->format->cpp[0] * 8 > 8) 5727fc1ae56SThomas Zimmermann bpp = 16; 5737fc1ae56SThomas Zimmermann else 5747fc1ae56SThomas Zimmermann bpp = 8; 5757fc1ae56SThomas Zimmermann 5767fc1ae56SThomas Zimmermann mb = (mode->clock * bpp) / 1000; 5777fc1ae56SThomas Zimmermann if (mb > 3100) 5787fc1ae56SThomas Zimmermann hiprilvl = 0; 5797fc1ae56SThomas Zimmermann else if (mb > 2600) 5807fc1ae56SThomas Zimmermann hiprilvl = 1; 5817fc1ae56SThomas Zimmermann else if (mb > 1900) 5827fc1ae56SThomas Zimmermann hiprilvl = 2; 5837fc1ae56SThomas Zimmermann else if (mb > 1160) 5847fc1ae56SThomas Zimmermann hiprilvl = 3; 5857fc1ae56SThomas Zimmermann else if (mb > 440) 5867fc1ae56SThomas Zimmermann hiprilvl = 4; 5877fc1ae56SThomas Zimmermann else 5887fc1ae56SThomas Zimmermann hiprilvl = 5; 5897fc1ae56SThomas Zimmermann 590fb18825fSThomas Zimmermann } else if (unique_rev_id >= 0x01) { 5917fc1ae56SThomas Zimmermann hiprilvl = 3; 5927fc1ae56SThomas Zimmermann } else { 5937fc1ae56SThomas Zimmermann hiprilvl = 4; 5947fc1ae56SThomas Zimmermann } 5957fc1ae56SThomas Zimmermann 5967fc1ae56SThomas Zimmermann crtcext6 = hiprilvl; /* implicitly sets maxhipri to 0 */ 5977fc1ae56SThomas Zimmermann 5987fc1ae56SThomas Zimmermann WREG_ECRT(0x06, crtcext6); 5997fc1ae56SThomas Zimmermann } 6007fc1ae56SThomas Zimmermann 6017fc1ae56SThomas Zimmermann static void mgag200_g200ev_set_hiprilvl(struct mga_device *mdev) 6027fc1ae56SThomas Zimmermann { 6037fc1ae56SThomas Zimmermann WREG_ECRT(0x06, 0x00); 6047fc1ae56SThomas Zimmermann } 6057fc1ae56SThomas Zimmermann 606153fef41SThomas Zimmermann static void mgag200_enable_display(struct mga_device *mdev) 607414c4531SDave Airlie { 60870c3881eSThomas Zimmermann u8 seq0, seq1, crtcext1; 60970c3881eSThomas Zimmermann 61070c3881eSThomas Zimmermann RREG_SEQ(0x00, seq0); 61170c3881eSThomas Zimmermann seq0 |= MGAREG_SEQ0_SYNCRST | 61270c3881eSThomas Zimmermann MGAREG_SEQ0_ASYNCRST; 61370c3881eSThomas Zimmermann WREG_SEQ(0x00, seq0); 614414c4531SDave Airlie 615153fef41SThomas Zimmermann /* 616153fef41SThomas Zimmermann * TODO: replace busy waiting with vblank IRQ; put 617153fef41SThomas Zimmermann * msleep(50) before changing SCROFF 618153fef41SThomas Zimmermann */ 619414c4531SDave Airlie mga_wait_vsync(mdev); 620414c4531SDave Airlie mga_wait_busy(mdev); 621153fef41SThomas Zimmermann 622153fef41SThomas Zimmermann RREG_SEQ(0x01, seq1); 623153fef41SThomas Zimmermann seq1 &= ~MGAREG_SEQ1_SCROFF; 624153fef41SThomas Zimmermann WREG_SEQ(0x01, seq1); 625153fef41SThomas Zimmermann 626414c4531SDave Airlie msleep(20); 627153fef41SThomas Zimmermann 628153fef41SThomas Zimmermann RREG_ECRT(0x01, crtcext1); 629153fef41SThomas Zimmermann crtcext1 &= ~MGAREG_CRTCEXT1_VSYNCOFF; 630153fef41SThomas Zimmermann crtcext1 &= ~MGAREG_CRTCEXT1_HSYNCOFF; 631153fef41SThomas Zimmermann WREG_ECRT(0x01, crtcext1); 632153fef41SThomas Zimmermann } 633153fef41SThomas Zimmermann 634153fef41SThomas Zimmermann static void mgag200_disable_display(struct mga_device *mdev) 635153fef41SThomas Zimmermann { 63670c3881eSThomas Zimmermann u8 seq0, seq1, crtcext1; 63770c3881eSThomas Zimmermann 63870c3881eSThomas Zimmermann RREG_SEQ(0x00, seq0); 63970c3881eSThomas Zimmermann seq0 &= ~MGAREG_SEQ0_SYNCRST; 64070c3881eSThomas Zimmermann WREG_SEQ(0x00, seq0); 641153fef41SThomas Zimmermann 642153fef41SThomas Zimmermann /* 643153fef41SThomas Zimmermann * TODO: replace busy waiting with vblank IRQ; put 644153fef41SThomas Zimmermann * msleep(50) before changing SCROFF 645153fef41SThomas Zimmermann */ 646153fef41SThomas Zimmermann mga_wait_vsync(mdev); 647153fef41SThomas Zimmermann mga_wait_busy(mdev); 648153fef41SThomas Zimmermann 649153fef41SThomas Zimmermann RREG_SEQ(0x01, seq1); 650153fef41SThomas Zimmermann seq1 |= MGAREG_SEQ1_SCROFF; 651153fef41SThomas Zimmermann WREG_SEQ(0x01, seq1); 652153fef41SThomas Zimmermann 653153fef41SThomas Zimmermann msleep(20); 654153fef41SThomas Zimmermann 655153fef41SThomas Zimmermann RREG_ECRT(0x01, crtcext1); 656153fef41SThomas Zimmermann crtcext1 |= MGAREG_CRTCEXT1_VSYNCOFF | 657153fef41SThomas Zimmermann MGAREG_CRTCEXT1_HSYNCOFF; 658153fef41SThomas Zimmermann WREG_ECRT(0x01, crtcext1); 659414c4531SDave Airlie } 660414c4531SDave Airlie 661414c4531SDave Airlie /* 66281a15b9aSThomas Zimmermann * Connector 66381a15b9aSThomas Zimmermann */ 66481a15b9aSThomas Zimmermann 665414c4531SDave Airlie static int mga_vga_get_modes(struct drm_connector *connector) 666414c4531SDave Airlie { 667414c4531SDave Airlie struct mga_connector *mga_connector = to_mga_connector(connector); 668414c4531SDave Airlie struct edid *edid; 669414c4531SDave Airlie int ret = 0; 670414c4531SDave Airlie 671414c4531SDave Airlie edid = drm_get_edid(connector, &mga_connector->i2c->adapter); 672414c4531SDave Airlie if (edid) { 673c555f023SDaniel Vetter drm_connector_update_edid_property(connector, edid); 674414c4531SDave Airlie ret = drm_add_edid_modes(connector, edid); 675414c4531SDave Airlie kfree(edid); 676414c4531SDave Airlie } 677414c4531SDave Airlie return ret; 678414c4531SDave Airlie } 679414c4531SDave Airlie 680abbee623SJulia Lemire static uint32_t mga_vga_calculate_mode_bandwidth(struct drm_display_mode *mode, 681abbee623SJulia Lemire int bits_per_pixel) 682abbee623SJulia Lemire { 683abbee623SJulia Lemire uint32_t total_area, divisor; 684c24ca5beSNicolas Pitre uint64_t active_area, pixels_per_second, bandwidth; 685abbee623SJulia Lemire uint64_t bytes_per_pixel = (bits_per_pixel + 7) / 8; 686abbee623SJulia Lemire 687abbee623SJulia Lemire divisor = 1024; 688abbee623SJulia Lemire 689abbee623SJulia Lemire if (!mode->htotal || !mode->vtotal || !mode->clock) 690abbee623SJulia Lemire return 0; 691abbee623SJulia Lemire 692abbee623SJulia Lemire active_area = mode->hdisplay * mode->vdisplay; 693abbee623SJulia Lemire total_area = mode->htotal * mode->vtotal; 694abbee623SJulia Lemire 695abbee623SJulia Lemire pixels_per_second = active_area * mode->clock * 1000; 696abbee623SJulia Lemire do_div(pixels_per_second, total_area); 697abbee623SJulia Lemire 698abbee623SJulia Lemire bandwidth = pixels_per_second * bytes_per_pixel * 100; 699abbee623SJulia Lemire do_div(bandwidth, divisor); 700abbee623SJulia Lemire 701abbee623SJulia Lemire return (uint32_t)(bandwidth); 702abbee623SJulia Lemire } 703abbee623SJulia Lemire 704abbee623SJulia Lemire #define MODE_BANDWIDTH MODE_BAD 705abbee623SJulia Lemire 706c69e52deSLuc Van Oostenryck static enum drm_mode_status mga_vga_mode_valid(struct drm_connector *connector, 707414c4531SDave Airlie struct drm_display_mode *mode) 708414c4531SDave Airlie { 7090ba53171SChristopher Harvey struct drm_device *dev = connector->dev; 7108d8ff2a9SThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 7110ba53171SChristopher Harvey int bpp = 32; 7120ba53171SChristopher Harvey 713abbee623SJulia Lemire if (IS_G200_SE(mdev)) { 714fb18825fSThomas Zimmermann u32 unique_rev_id = mdev->model.g200se.unique_rev_id; 715fb18825fSThomas Zimmermann 716fb18825fSThomas Zimmermann if (unique_rev_id == 0x01) { 717abbee623SJulia Lemire if (mode->hdisplay > 1600) 718abbee623SJulia Lemire return MODE_VIRTUAL_X; 719abbee623SJulia Lemire if (mode->vdisplay > 1200) 720abbee623SJulia Lemire return MODE_VIRTUAL_Y; 721abbee623SJulia Lemire if (mga_vga_calculate_mode_bandwidth(mode, bpp) 722abbee623SJulia Lemire > (24400 * 1024)) 723abbee623SJulia Lemire return MODE_BANDWIDTH; 724fb18825fSThomas Zimmermann } else if (unique_rev_id == 0x02) { 725abbee623SJulia Lemire if (mode->hdisplay > 1920) 726abbee623SJulia Lemire return MODE_VIRTUAL_X; 727abbee623SJulia Lemire if (mode->vdisplay > 1200) 728abbee623SJulia Lemire return MODE_VIRTUAL_Y; 729abbee623SJulia Lemire if (mga_vga_calculate_mode_bandwidth(mode, bpp) 730abbee623SJulia Lemire > (30100 * 1024)) 731abbee623SJulia Lemire return MODE_BANDWIDTH; 7320cbb7381SMathieu Larouche } else { 7330cbb7381SMathieu Larouche if (mga_vga_calculate_mode_bandwidth(mode, bpp) 7340cbb7381SMathieu Larouche > (55000 * 1024)) 7350cbb7381SMathieu Larouche return MODE_BANDWIDTH; 736abbee623SJulia Lemire } 737abbee623SJulia Lemire } else if (mdev->type == G200_WB) { 738abbee623SJulia Lemire if (mode->hdisplay > 1280) 739abbee623SJulia Lemire return MODE_VIRTUAL_X; 740abbee623SJulia Lemire if (mode->vdisplay > 1024) 741abbee623SJulia Lemire return MODE_VIRTUAL_Y; 7429eb8d7a9SDan Carpenter if (mga_vga_calculate_mode_bandwidth(mode, bpp) > 7439eb8d7a9SDan Carpenter (31877 * 1024)) 744abbee623SJulia Lemire return MODE_BANDWIDTH; 745abbee623SJulia Lemire } else if (mdev->type == G200_EV && 746abbee623SJulia Lemire (mga_vga_calculate_mode_bandwidth(mode, bpp) 747abbee623SJulia Lemire > (32700 * 1024))) { 748abbee623SJulia Lemire return MODE_BANDWIDTH; 749ec22b4aaSDave Airlie } else if (mdev->type == G200_EH && 750abbee623SJulia Lemire (mga_vga_calculate_mode_bandwidth(mode, bpp) 751abbee623SJulia Lemire > (37500 * 1024))) { 752abbee623SJulia Lemire return MODE_BANDWIDTH; 753ec22b4aaSDave Airlie } else if (mdev->type == G200_ER && 754abbee623SJulia Lemire (mga_vga_calculate_mode_bandwidth(mode, 755abbee623SJulia Lemire bpp) > (55000 * 1024))) { 756abbee623SJulia Lemire return MODE_BANDWIDTH; 757abbee623SJulia Lemire } 758414c4531SDave Airlie 75925161084SAdam Jackson if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 || 76025161084SAdam Jackson (mode->hsync_end % 8) != 0 || (mode->htotal % 8) != 0) { 76125161084SAdam Jackson return MODE_H_ILLEGAL; 76225161084SAdam Jackson } 76325161084SAdam Jackson 764414c4531SDave Airlie if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 || 765414c4531SDave Airlie mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 || 766414c4531SDave Airlie mode->crtc_vdisplay > 2048 || mode->crtc_vsync_start > 4096 || 767414c4531SDave Airlie mode->crtc_vsync_end > 4096 || mode->crtc_vtotal > 4096) { 768414c4531SDave Airlie return MODE_BAD; 769414c4531SDave Airlie } 770414c4531SDave Airlie 7710ba53171SChristopher Harvey /* Validate the mode input by the user */ 772eaf99c74SChris Wilson if (connector->cmdline_mode.specified) { 773eaf99c74SChris Wilson if (connector->cmdline_mode.bpp_specified) 774eaf99c74SChris Wilson bpp = connector->cmdline_mode.bpp; 7750ba53171SChristopher Harvey } 7760ba53171SChristopher Harvey 7772c51a660SThomas Zimmermann if ((mode->hdisplay * mode->vdisplay * (bpp/8)) > mdev->vram_fb_available) { 778eaf99c74SChris Wilson if (connector->cmdline_mode.specified) 779eaf99c74SChris Wilson connector->cmdline_mode.specified = false; 7800ba53171SChristopher Harvey return MODE_BAD; 7810ba53171SChristopher Harvey } 7820ba53171SChristopher Harvey 783414c4531SDave Airlie return MODE_OK; 784414c4531SDave Airlie } 785414c4531SDave Airlie 786414c4531SDave Airlie static void mga_connector_destroy(struct drm_connector *connector) 787414c4531SDave Airlie { 788414c4531SDave Airlie struct mga_connector *mga_connector = to_mga_connector(connector); 789414c4531SDave Airlie mgag200_i2c_destroy(mga_connector->i2c); 790414c4531SDave Airlie drm_connector_cleanup(connector); 791414c4531SDave Airlie } 792414c4531SDave Airlie 79371cb7495SVille Syrjälä static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = { 794414c4531SDave Airlie .get_modes = mga_vga_get_modes, 795414c4531SDave Airlie .mode_valid = mga_vga_mode_valid, 796414c4531SDave Airlie }; 797414c4531SDave Airlie 79871cb7495SVille Syrjälä static const struct drm_connector_funcs mga_vga_connector_funcs = { 79988fabb75SThomas Zimmermann .reset = drm_atomic_helper_connector_reset, 800414c4531SDave Airlie .fill_modes = drm_helper_probe_single_connector_modes, 801414c4531SDave Airlie .destroy = mga_connector_destroy, 80288fabb75SThomas Zimmermann .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 80388fabb75SThomas Zimmermann .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 804414c4531SDave Airlie }; 805414c4531SDave Airlie 80681a15b9aSThomas Zimmermann static int mgag200_vga_connector_init(struct mga_device *mdev) 807414c4531SDave Airlie { 808832eddf5SThomas Zimmermann struct drm_device *dev = &mdev->base; 80981a15b9aSThomas Zimmermann struct mga_connector *mconnector = &mdev->connector; 81081a15b9aSThomas Zimmermann struct drm_connector *connector = &mconnector->base; 81181a15b9aSThomas Zimmermann struct mga_i2c_chan *i2c; 81281a15b9aSThomas Zimmermann int ret; 813414c4531SDave Airlie 81481a15b9aSThomas Zimmermann i2c = mgag200_i2c_create(dev); 81581a15b9aSThomas Zimmermann if (!i2c) 81681a15b9aSThomas Zimmermann drm_warn(dev, "failed to add DDC bus\n"); 817414c4531SDave Airlie 81881a15b9aSThomas Zimmermann ret = drm_connector_init_with_ddc(dev, connector, 8199572ae17SAndrzej Pietrasiewicz &mga_vga_connector_funcs, 8209572ae17SAndrzej Pietrasiewicz DRM_MODE_CONNECTOR_VGA, 82181a15b9aSThomas Zimmermann &i2c->adapter); 82281a15b9aSThomas Zimmermann if (ret) 82381a15b9aSThomas Zimmermann goto err_mgag200_i2c_destroy; 824414c4531SDave Airlie drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs); 825414c4531SDave Airlie 82681a15b9aSThomas Zimmermann mconnector->i2c = i2c; 8273d5a1c5eSEgbert Eich 82881a15b9aSThomas Zimmermann return 0; 82981a15b9aSThomas Zimmermann 83081a15b9aSThomas Zimmermann err_mgag200_i2c_destroy: 83181a15b9aSThomas Zimmermann mgag200_i2c_destroy(i2c); 83281a15b9aSThomas Zimmermann return ret; 833414c4531SDave Airlie } 834414c4531SDave Airlie 83588fabb75SThomas Zimmermann /* 83688fabb75SThomas Zimmermann * Simple Display Pipe 83788fabb75SThomas Zimmermann */ 83888fabb75SThomas Zimmermann 83988fabb75SThomas Zimmermann static enum drm_mode_status 84088fabb75SThomas Zimmermann mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, 84188fabb75SThomas Zimmermann const struct drm_display_mode *mode) 84288fabb75SThomas Zimmermann { 84388fabb75SThomas Zimmermann return MODE_OK; 84488fabb75SThomas Zimmermann } 84588fabb75SThomas Zimmermann 84688fabb75SThomas Zimmermann static void 847913ec479SThomas Zimmermann mgag200_handle_damage(struct mga_device *mdev, struct drm_framebuffer *fb, 8484862ffaeSThomas Zimmermann struct drm_rect *clip, const struct dma_buf_map *map) 849913ec479SThomas Zimmermann { 8504862ffaeSThomas Zimmermann void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */ 851913ec479SThomas Zimmermann 8525ab7af71SThomas Zimmermann drm_fb_memcpy_dstclip(mdev->vram, fb->pitches[0], vmap, fb, clip); 853913ec479SThomas Zimmermann 854913ec479SThomas Zimmermann /* Always scanout image at VRAM offset 0 */ 855913ec479SThomas Zimmermann mgag200_set_startadd(mdev, (u32)0); 856913ec479SThomas Zimmermann mgag200_set_offset(mdev, fb); 857913ec479SThomas Zimmermann } 858913ec479SThomas Zimmermann 859913ec479SThomas Zimmermann static void 86088fabb75SThomas Zimmermann mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, 86188fabb75SThomas Zimmermann struct drm_crtc_state *crtc_state, 86288fabb75SThomas Zimmermann struct drm_plane_state *plane_state) 86388fabb75SThomas Zimmermann { 86488fabb75SThomas Zimmermann struct drm_crtc *crtc = &pipe->crtc; 86588fabb75SThomas Zimmermann struct drm_device *dev = crtc->dev; 86688fabb75SThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 867*0a6dab7dSThomas Zimmermann struct mgag200_pll *pixpll = &mdev->pixpll; 86888fabb75SThomas Zimmermann struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; 869*0a6dab7dSThomas Zimmermann struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); 87088fabb75SThomas Zimmermann struct drm_framebuffer *fb = plane_state->fb; 8714862ffaeSThomas Zimmermann struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); 872913ec479SThomas Zimmermann struct drm_rect fullscreen = { 873913ec479SThomas Zimmermann .x1 = 0, 874913ec479SThomas Zimmermann .x2 = fb->width, 875913ec479SThomas Zimmermann .y1 = 0, 876913ec479SThomas Zimmermann .y2 = fb->height, 877913ec479SThomas Zimmermann }; 87888fabb75SThomas Zimmermann 879895a4790SThomas Zimmermann if (mdev->type == G200_WB || mdev->type == G200_EW3) 880895a4790SThomas Zimmermann mgag200_g200wb_hold_bmc(mdev); 88188fabb75SThomas Zimmermann 88288fabb75SThomas Zimmermann mgag200_set_format_regs(mdev, fb); 88388fabb75SThomas Zimmermann mgag200_set_mode_regs(mdev, adjusted_mode); 884*0a6dab7dSThomas Zimmermann 885*0a6dab7dSThomas Zimmermann pixpll->funcs->update(pixpll, &mgag200_crtc_state->pixpllc); 88688fabb75SThomas Zimmermann 88788fabb75SThomas Zimmermann if (mdev->type == G200_ER) 88888fabb75SThomas Zimmermann mgag200_g200er_reset_tagfifo(mdev); 88988fabb75SThomas Zimmermann 89088fabb75SThomas Zimmermann if (IS_G200_SE(mdev)) 89188fabb75SThomas Zimmermann mgag200_g200se_set_hiprilvl(mdev, adjusted_mode, fb); 89288fabb75SThomas Zimmermann else if (mdev->type == G200_EV) 89388fabb75SThomas Zimmermann mgag200_g200ev_set_hiprilvl(mdev); 89488fabb75SThomas Zimmermann 895895a4790SThomas Zimmermann if (mdev->type == G200_WB || mdev->type == G200_EW3) 896895a4790SThomas Zimmermann mgag200_g200wb_release_bmc(mdev); 897895a4790SThomas Zimmermann 898895a4790SThomas Zimmermann mga_crtc_load_lut(crtc); 899895a4790SThomas Zimmermann mgag200_enable_display(mdev); 900913ec479SThomas Zimmermann 9014862ffaeSThomas Zimmermann mgag200_handle_damage(mdev, fb, &fullscreen, &shadow_plane_state->map[0]); 90288fabb75SThomas Zimmermann } 90388fabb75SThomas Zimmermann 90488fabb75SThomas Zimmermann static void 90588fabb75SThomas Zimmermann mgag200_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) 90688fabb75SThomas Zimmermann { 90788fabb75SThomas Zimmermann struct drm_crtc *crtc = &pipe->crtc; 908153fef41SThomas Zimmermann struct mga_device *mdev = to_mga_device(crtc->dev); 90988fabb75SThomas Zimmermann 910153fef41SThomas Zimmermann mgag200_disable_display(mdev); 91188fabb75SThomas Zimmermann } 91288fabb75SThomas Zimmermann 91388fabb75SThomas Zimmermann static int 91488fabb75SThomas Zimmermann mgag200_simple_display_pipe_check(struct drm_simple_display_pipe *pipe, 91588fabb75SThomas Zimmermann struct drm_plane_state *plane_state, 91688fabb75SThomas Zimmermann struct drm_crtc_state *crtc_state) 91788fabb75SThomas Zimmermann { 91888fabb75SThomas Zimmermann struct drm_plane *plane = plane_state->plane; 919*0a6dab7dSThomas Zimmermann struct drm_device *dev = plane->dev; 920*0a6dab7dSThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 921*0a6dab7dSThomas Zimmermann struct mgag200_pll *pixpll = &mdev->pixpll; 922*0a6dab7dSThomas Zimmermann struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); 92388fabb75SThomas Zimmermann struct drm_framebuffer *new_fb = plane_state->fb; 92488fabb75SThomas Zimmermann struct drm_framebuffer *fb = NULL; 925*0a6dab7dSThomas Zimmermann int ret; 92688fabb75SThomas Zimmermann 92788fabb75SThomas Zimmermann if (!new_fb) 92888fabb75SThomas Zimmermann return 0; 92988fabb75SThomas Zimmermann 93088fabb75SThomas Zimmermann if (plane->state) 93188fabb75SThomas Zimmermann fb = plane->state->fb; 93288fabb75SThomas Zimmermann 93388fabb75SThomas Zimmermann if (!fb || (fb->format != new_fb->format)) 93488fabb75SThomas Zimmermann crtc_state->mode_changed = true; /* update PLL settings */ 93588fabb75SThomas Zimmermann 936*0a6dab7dSThomas Zimmermann if (crtc_state->mode_changed) { 937*0a6dab7dSThomas Zimmermann ret = pixpll->funcs->compute(pixpll, crtc_state->mode.clock, 938*0a6dab7dSThomas Zimmermann &mgag200_crtc_state->pixpllc); 939*0a6dab7dSThomas Zimmermann if (ret) 940*0a6dab7dSThomas Zimmermann return ret; 941*0a6dab7dSThomas Zimmermann } 942*0a6dab7dSThomas Zimmermann 94388fabb75SThomas Zimmermann return 0; 94488fabb75SThomas Zimmermann } 94588fabb75SThomas Zimmermann 94688fabb75SThomas Zimmermann static void 94788fabb75SThomas Zimmermann mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, 94888fabb75SThomas Zimmermann struct drm_plane_state *old_state) 94988fabb75SThomas Zimmermann { 95088fabb75SThomas Zimmermann struct drm_plane *plane = &pipe->plane; 95188fabb75SThomas Zimmermann struct drm_device *dev = plane->dev; 95288fabb75SThomas Zimmermann struct mga_device *mdev = to_mga_device(dev); 95388fabb75SThomas Zimmermann struct drm_plane_state *state = plane->state; 9544862ffaeSThomas Zimmermann struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); 95588fabb75SThomas Zimmermann struct drm_framebuffer *fb = state->fb; 956913ec479SThomas Zimmermann struct drm_rect damage; 95788fabb75SThomas Zimmermann 95888fabb75SThomas Zimmermann if (!fb) 95988fabb75SThomas Zimmermann return; 96088fabb75SThomas Zimmermann 961913ec479SThomas Zimmermann if (drm_atomic_helper_damage_merged(old_state, state, &damage)) 9624862ffaeSThomas Zimmermann mgag200_handle_damage(mdev, fb, &damage, &shadow_plane_state->map[0]); 96388fabb75SThomas Zimmermann } 96488fabb75SThomas Zimmermann 96551b56939SThomas Zimmermann static struct drm_crtc_state * 96651b56939SThomas Zimmermann mgag200_simple_display_pipe_duplicate_crtc_state(struct drm_simple_display_pipe *pipe) 96751b56939SThomas Zimmermann { 96851b56939SThomas Zimmermann struct drm_crtc *crtc = &pipe->crtc; 96951b56939SThomas Zimmermann struct drm_crtc_state *crtc_state = crtc->state; 970*0a6dab7dSThomas Zimmermann struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); 97151b56939SThomas Zimmermann struct mgag200_crtc_state *new_mgag200_crtc_state; 97251b56939SThomas Zimmermann 97351b56939SThomas Zimmermann if (!crtc_state) 97451b56939SThomas Zimmermann return NULL; 97551b56939SThomas Zimmermann 97651b56939SThomas Zimmermann new_mgag200_crtc_state = kzalloc(sizeof(*new_mgag200_crtc_state), GFP_KERNEL); 97751b56939SThomas Zimmermann if (!new_mgag200_crtc_state) 97851b56939SThomas Zimmermann return NULL; 97951b56939SThomas Zimmermann __drm_atomic_helper_crtc_duplicate_state(crtc, &new_mgag200_crtc_state->base); 98051b56939SThomas Zimmermann 981*0a6dab7dSThomas Zimmermann memcpy(&new_mgag200_crtc_state->pixpllc, &mgag200_crtc_state->pixpllc, 982*0a6dab7dSThomas Zimmermann sizeof(new_mgag200_crtc_state->pixpllc)); 983*0a6dab7dSThomas Zimmermann 98451b56939SThomas Zimmermann return &new_mgag200_crtc_state->base; 98551b56939SThomas Zimmermann } 98651b56939SThomas Zimmermann 98751b56939SThomas Zimmermann static void mgag200_simple_display_pipe_destroy_crtc_state(struct drm_simple_display_pipe *pipe, 98851b56939SThomas Zimmermann struct drm_crtc_state *crtc_state) 98951b56939SThomas Zimmermann { 99051b56939SThomas Zimmermann struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); 99151b56939SThomas Zimmermann 99251b56939SThomas Zimmermann __drm_atomic_helper_crtc_destroy_state(&mgag200_crtc_state->base); 99351b56939SThomas Zimmermann kfree(mgag200_crtc_state); 99451b56939SThomas Zimmermann } 99551b56939SThomas Zimmermann 99651b56939SThomas Zimmermann static void mgag200_simple_display_pipe_reset_crtc(struct drm_simple_display_pipe *pipe) 99751b56939SThomas Zimmermann { 99851b56939SThomas Zimmermann struct drm_crtc *crtc = &pipe->crtc; 99951b56939SThomas Zimmermann struct mgag200_crtc_state *mgag200_crtc_state; 100051b56939SThomas Zimmermann 100151b56939SThomas Zimmermann if (crtc->state) { 100251b56939SThomas Zimmermann mgag200_simple_display_pipe_destroy_crtc_state(pipe, crtc->state); 100351b56939SThomas Zimmermann crtc->state = NULL; /* must be set to NULL here */ 100451b56939SThomas Zimmermann } 100551b56939SThomas Zimmermann 100651b56939SThomas Zimmermann mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), GFP_KERNEL); 100751b56939SThomas Zimmermann if (!mgag200_crtc_state) 100851b56939SThomas Zimmermann return; 100951b56939SThomas Zimmermann __drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base); 101051b56939SThomas Zimmermann } 101151b56939SThomas Zimmermann 101288fabb75SThomas Zimmermann static const struct drm_simple_display_pipe_funcs 101388fabb75SThomas Zimmermann mgag200_simple_display_pipe_funcs = { 101488fabb75SThomas Zimmermann .mode_valid = mgag200_simple_display_pipe_mode_valid, 101588fabb75SThomas Zimmermann .enable = mgag200_simple_display_pipe_enable, 101688fabb75SThomas Zimmermann .disable = mgag200_simple_display_pipe_disable, 101788fabb75SThomas Zimmermann .check = mgag200_simple_display_pipe_check, 101888fabb75SThomas Zimmermann .update = mgag200_simple_display_pipe_update, 101951b56939SThomas Zimmermann .reset_crtc = mgag200_simple_display_pipe_reset_crtc, 102051b56939SThomas Zimmermann .duplicate_crtc_state = mgag200_simple_display_pipe_duplicate_crtc_state, 102151b56939SThomas Zimmermann .destroy_crtc_state = mgag200_simple_display_pipe_destroy_crtc_state, 10224862ffaeSThomas Zimmermann DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, 102388fabb75SThomas Zimmermann }; 102488fabb75SThomas Zimmermann 102588fabb75SThomas Zimmermann static const uint32_t mgag200_simple_display_pipe_formats[] = { 102688fabb75SThomas Zimmermann DRM_FORMAT_XRGB8888, 102788fabb75SThomas Zimmermann DRM_FORMAT_RGB565, 102888fabb75SThomas Zimmermann DRM_FORMAT_RGB888, 102988fabb75SThomas Zimmermann }; 103088fabb75SThomas Zimmermann 103188fabb75SThomas Zimmermann static const uint64_t mgag200_simple_display_pipe_fmtmods[] = { 103288fabb75SThomas Zimmermann DRM_FORMAT_MOD_LINEAR, 103388fabb75SThomas Zimmermann DRM_FORMAT_MOD_INVALID 103488fabb75SThomas Zimmermann }; 103588fabb75SThomas Zimmermann 103688fabb75SThomas Zimmermann /* 103788fabb75SThomas Zimmermann * Mode config 103888fabb75SThomas Zimmermann */ 103988fabb75SThomas Zimmermann 10405635b7cfSThomas Zimmermann static const struct drm_mode_config_funcs mgag200_mode_config_funcs = { 1041913ec479SThomas Zimmermann .fb_create = drm_gem_fb_create_with_dirty, 104288fabb75SThomas Zimmermann .atomic_check = drm_atomic_helper_check, 104388fabb75SThomas Zimmermann .atomic_commit = drm_atomic_helper_commit, 10445635b7cfSThomas Zimmermann }; 10455635b7cfSThomas Zimmermann 10465635b7cfSThomas Zimmermann static unsigned int mgag200_preferred_depth(struct mga_device *mdev) 10475635b7cfSThomas Zimmermann { 10485635b7cfSThomas Zimmermann if (IS_G200_SE(mdev) && mdev->vram_fb_available < (2048*1024)) 10495635b7cfSThomas Zimmermann return 16; 10505635b7cfSThomas Zimmermann else 10515635b7cfSThomas Zimmermann return 32; 10525635b7cfSThomas Zimmermann } 1053414c4531SDave Airlie 1054414c4531SDave Airlie int mgag200_modeset_init(struct mga_device *mdev) 1055414c4531SDave Airlie { 1056832eddf5SThomas Zimmermann struct drm_device *dev = &mdev->base; 105781a15b9aSThomas Zimmermann struct drm_connector *connector = &mdev->connector.base; 105888fabb75SThomas Zimmermann struct drm_simple_display_pipe *pipe = &mdev->display_pipe; 105988fabb75SThomas Zimmermann size_t format_count = ARRAY_SIZE(mgag200_simple_display_pipe_formats); 106003e44ad1SThomas Zimmermann int ret; 1061414c4531SDave Airlie 106288fabb75SThomas Zimmermann mgag200_init_regs(mdev); 106388fabb75SThomas Zimmermann 10645635b7cfSThomas Zimmermann ret = drmm_mode_config_init(dev); 10655635b7cfSThomas Zimmermann if (ret) { 10665635b7cfSThomas Zimmermann drm_err(dev, "drmm_mode_config_init() failed, error %d\n", 10675635b7cfSThomas Zimmermann ret); 10685635b7cfSThomas Zimmermann return ret; 10695635b7cfSThomas Zimmermann } 10705635b7cfSThomas Zimmermann 1071ed5877b6SThomas Zimmermann dev->mode_config.max_width = MGAG200_MAX_FB_WIDTH; 1072ed5877b6SThomas Zimmermann dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT; 1073414c4531SDave Airlie 10745635b7cfSThomas Zimmermann dev->mode_config.preferred_depth = mgag200_preferred_depth(mdev); 10755635b7cfSThomas Zimmermann 1076ed5877b6SThomas Zimmermann dev->mode_config.fb_base = mdev->mc.vram_base; 1077414c4531SDave Airlie 10785635b7cfSThomas Zimmermann dev->mode_config.funcs = &mgag200_mode_config_funcs; 10795635b7cfSThomas Zimmermann 108081a15b9aSThomas Zimmermann ret = mgag200_vga_connector_init(mdev); 108181a15b9aSThomas Zimmermann if (ret) { 108281a15b9aSThomas Zimmermann drm_err(dev, 108381a15b9aSThomas Zimmermann "mgag200_vga_connector_init() failed, error %d\n", 108481a15b9aSThomas Zimmermann ret); 108581a15b9aSThomas Zimmermann return ret; 1086414c4531SDave Airlie } 1087414c4531SDave Airlie 10882545ac96SThomas Zimmermann ret = mgag200_pixpll_init(&mdev->pixpll, mdev); 10892545ac96SThomas Zimmermann if (ret) 10902545ac96SThomas Zimmermann return ret; 10912545ac96SThomas Zimmermann 109288fabb75SThomas Zimmermann ret = drm_simple_display_pipe_init(dev, pipe, 109388fabb75SThomas Zimmermann &mgag200_simple_display_pipe_funcs, 109488fabb75SThomas Zimmermann mgag200_simple_display_pipe_formats, 109588fabb75SThomas Zimmermann format_count, 109688fabb75SThomas Zimmermann mgag200_simple_display_pipe_fmtmods, 109788fabb75SThomas Zimmermann connector); 109888fabb75SThomas Zimmermann if (ret) { 109988fabb75SThomas Zimmermann drm_err(dev, 110088fabb75SThomas Zimmermann "drm_simple_display_pipe_init() failed, error %d\n", 110188fabb75SThomas Zimmermann ret); 110288fabb75SThomas Zimmermann return ret; 110388fabb75SThomas Zimmermann } 110488fabb75SThomas Zimmermann 110588fabb75SThomas Zimmermann /* FIXME: legacy gamma tables; convert to CRTC state */ 110688fabb75SThomas Zimmermann drm_mode_crtc_set_gamma_size(&pipe->crtc, MGAG200_LUT_SIZE); 110788fabb75SThomas Zimmermann 110888fabb75SThomas Zimmermann drm_mode_config_reset(dev); 1109414c4531SDave Airlie 1110414c4531SDave Airlie return 0; 1111414c4531SDave Airlie } 1112