1 /* 2 * Copyright 2012 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Gerald Zajac 7 */ 8 9 /*! 10 Haiku Intel-810 video driver was adapted from the X.org intel driver which 11 has the following copyright. 12 13 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. 14 All Rights Reserved. 15 */ 16 17 18 #include "accelerant.h" 19 #include "i810_regs.h" 20 21 #include <create_display_modes.h> // common accelerant header file 22 #include <math.h> 23 #include <unistd.h> 24 25 26 // I810_CalcVCLK -- Determine closest clock frequency to the one requested. 27 #define MAX_VCO_FREQ 600.0 28 #define TARGET_MAX_N 30 29 #define REF_FREQ 24.0 30 31 #define CALC_VCLK(m,n,p) (double)m / ((double)n * (1 << p)) * 4 * REF_FREQ 32 33 34 static void 35 CalcVCLK(double freq, uint16& clkM, uint16& clkN, uint16& clkP) { 36 int m, n, p; 37 double f_out, f_best; 38 double f_err; 39 double f_vco; 40 int m_best = 0, n_best = 0, p_best = 0; 41 double f_target = freq; 42 double errMax = 0.005; 43 double errTarget = 0.001; 44 double errBest = 999999.0; 45 46 p_best = p = int(log(MAX_VCO_FREQ / f_target) / log((double)2)); 47 // Make sure p is within range. 48 if (p_best > 5) { 49 p_best = p = 5; 50 } 51 52 f_vco = f_target * (1 << p); 53 54 n = 2; 55 do { 56 n++; 57 m = int(f_vco / (REF_FREQ / (double)n) / (double)4.0 + 0.5); 58 if (m < 3) 59 m = 3; 60 f_out = CALC_VCLK(m, n, p); 61 f_err = 1.0 - (f_target / f_out); 62 if (fabs(f_err) < errMax) { 63 m_best = m; 64 n_best = n; 65 f_best = f_out; 66 errBest = f_err; 67 } 68 } while ((fabs(f_err) >= errTarget) && ((n <= TARGET_MAX_N) 69 || (fabs(errBest) > errMax))); 70 71 if (fabs(f_err) < errTarget) { 72 m_best = m; 73 n_best = n; 74 } 75 76 clkM = (m_best - 2) & 0x3FF; 77 clkN = (n_best - 2) & 0x3FF; 78 clkP = (p_best << 4); 79 80 TRACE("Setting dot clock to %.1f MHz [ 0x%x 0x%x 0x%x ] [ %d %d %d ]\n", 81 CALC_VCLK(m_best, n_best, p_best), 82 clkM, clkN, clkP, m_best, n_best, p_best); 83 } 84 85 86 static void 87 SetCrtcTimingValues(const DisplayModeEx& mode) 88 { 89 // Set the timing values for CRTC registers cr00 to cr18, and some extended 90 // CRTC registers. 91 92 int hTotal = mode.timing.h_total / 8 - 5; 93 int hDisp_e = mode.timing.h_display / 8 - 1; 94 int hSync_s = mode.timing.h_sync_start / 8; 95 int hSync_e = mode.timing.h_sync_end / 8; 96 int hBlank_s = hDisp_e + 1; // start of horizontal blanking 97 int hBlank_e = hTotal; // end of horizontal blanking 98 99 int vTotal = mode.timing.v_total - 2; 100 int vDisp_e = mode.timing.v_display - 1; 101 int vSync_s = mode.timing.v_sync_start; 102 int vSync_e = mode.timing.v_sync_end; 103 int vBlank_s = vDisp_e; // start of vertical blanking 104 int vBlank_e = vTotal; // end of vertical blanking 105 106 uint16 offset = mode.bytesPerRow / 8; 107 108 // CRTC Controller values 109 110 uint8 crtc[25]; 111 crtc[0x00] = hTotal; 112 crtc[0x01] = hDisp_e; 113 crtc[0x02] = hBlank_s; 114 crtc[0x03] = (hBlank_e & 0x1f) | 0x80; 115 crtc[0x04] = hSync_s; 116 crtc[0x05] = ((hSync_e & 0x1f) | ((hBlank_e & 0x20) << 2)); 117 crtc[0x06] = vTotal; 118 crtc[0x07] = (((vTotal & 0x100) >> 8) 119 | ((vDisp_e & 0x100) >> 7) 120 | ((vSync_s & 0x100) >> 6) 121 | ((vBlank_s & 0x100) >> 5) 122 | 0x10 123 | ((vTotal & 0x200) >> 4) 124 | ((vDisp_e & 0x200) >> 3) 125 | ((vSync_s & 0x200) >> 2)); 126 127 crtc[0x08] = 0x00; 128 crtc[0x09] = ((vBlank_s & 0x200) >> 4) | 0x40; 129 crtc[0x0a] = 0x00; 130 crtc[0x0b] = 0x00; 131 crtc[0x0c] = 0x00; 132 crtc[0x0d] = 0x00; 133 crtc[0x0e] = 0x00; 134 crtc[0x0f] = 0x00; 135 crtc[0x10] = vSync_s; 136 crtc[0x11] = (vSync_e & 0x0f) | 0x20; 137 crtc[0x12] = vDisp_e; 138 crtc[0x13] = offset; 139 crtc[0x14] = 0x00; 140 crtc[0x15] = vBlank_s; 141 crtc[0x16] = vBlank_e; 142 crtc[0x17] = 0xc3; 143 crtc[0x18] = 0xff; 144 145 // Set the standard CRTC vga regs; however, before setting them, unlock 146 // CRTC reg's 0-7 by clearing bit 7 of cr11 147 148 WriteCrtcReg(0x11, crtc[0x11] & ~0x80); 149 150 for (uint8 j = 0; j <= 0x18; j++) 151 WriteCrtcReg(j, crtc[j]); 152 153 // Set the extended CRTC reg's. 154 155 WriteCrtcReg(EXT_VERT_TOTAL, vTotal >> 8); 156 WriteCrtcReg(EXT_VERT_DISPLAY, vDisp_e >> 8); 157 WriteCrtcReg(EXT_VERT_SYNC_START, vSync_s >> 8); 158 WriteCrtcReg(EXT_VERT_BLANK_START, vBlank_s >> 8); 159 WriteCrtcReg(EXT_HORIZ_TOTAL, hTotal >> 8); 160 WriteCrtcReg(EXT_HORIZ_BLANK, (hBlank_e & 0x40) >> 6); 161 WriteCrtcReg(EXT_OFFSET, offset >> 8); 162 163 WriteCrtcReg(INTERLACE_CNTL, INTERLACE_DISABLE); // turn off interlace 164 165 // Enable high resolution mode. 166 WriteCrtcReg(IO_CTNL, ReadCrtcReg(IO_CTNL) | EXTENDED_CRTC_CNTL); 167 } 168 169 170 status_t 171 I810_SetDisplayMode(const DisplayModeEx& mode) 172 { 173 if (mode.bitsPerPixel != 8 && mode.bitsPerPixel != 16) { 174 // Only 8 & 16 bits/pixel are suppoted. 175 TRACE("Unsupported color depth: %d bpp\n", mode.bitsPerPixel); 176 return B_ERROR; 177 } 178 179 snooze(50000); 180 181 // Turn off DRAM refresh. 182 uint8 temp = INREG8(DRAM_ROW_CNTL_HI) & ~DRAM_REFRESH_RATE; 183 OUTREG8(DRAM_ROW_CNTL_HI, temp | DRAM_REFRESH_DISABLE); 184 185 snooze(1000); // wait 1 ms 186 187 // Calculate the VCLK that most closely matches the requested pixel clock, 188 // and then set the M, N, and P values. 189 190 uint16 m, n, p; 191 CalcVCLK(mode.timing.pixel_clock / 1000.0, m, n, p); 192 193 OUTREG16(VCLK2_VCO_M, m); 194 OUTREG16(VCLK2_VCO_N, n); 195 OUTREG8(VCLK2_VCO_DIV_SEL, p); 196 197 // Setup HSYNC & VSYNC polarity and select clock source 2 (0x08) for 198 // programmable PLL. 199 200 uint8 miscOutReg = 0x08 | 0x01; 201 if (!(mode.timing.flags & B_POSITIVE_HSYNC)) 202 miscOutReg |= 0x40; 203 if (!(mode.timing.flags & B_POSITIVE_VSYNC)) 204 miscOutReg |= 0x80; 205 206 OUTREG8(MISC_OUT_W, miscOutReg); 207 208 SetCrtcTimingValues(mode); 209 210 OUTREG32(MEM_MODE, INREG32(MEM_MODE) | 4); 211 212 // Set the address mapping to use the frame buffer memory mapped via the 213 // GTT table instead of the VGA buffer. 214 215 uint8 addrMapping = ReadGraphReg(ADDRESS_MAPPING); 216 addrMapping &= 0xE0; // preserve reserved bits 7:5 217 addrMapping |= (GTT_MEM_MAP_ENABLE | LINEAR_MODE_ENABLE); 218 WriteGraphReg(ADDRESS_MAPPING, addrMapping); 219 220 // Turn on DRAM refresh. 221 temp = INREG8(DRAM_ROW_CNTL_HI) & ~DRAM_REFRESH_RATE; 222 OUTREG8(DRAM_ROW_CNTL_HI, temp | DRAM_REFRESH_60HZ); 223 224 temp = INREG8(BITBLT_CNTL) & ~COLEXP_MODE; 225 temp |= (mode.bitsPerPixel == 8 ? COLEXP_8BPP : COLEXP_16BPP); 226 OUTREG8(BITBLT_CNTL, temp); 227 228 // Turn on 8 bit dac mode so that the indexed colors are displayed properly, 229 // and put display in high resolution mode. 230 231 uint32 temp32 = INREG32(PIXPIPE_CONFIG) & 0xF3E062FC; 232 temp32 |= (DAC_8_BIT | HIRES_MODE | NO_BLANK_DELAY | 233 (mode.bitsPerPixel == 8 ? DISPLAY_8BPP_MODE : DISPLAY_16BPP_MODE)); 234 OUTREG32(PIXPIPE_CONFIG, temp32); 235 236 OUTREG16(EIR, 0); 237 238 temp32 = INREG32(FWATER_BLC); 239 temp32 &= ~(LM_BURST_LENGTH | LM_FIFO_WATERMARK 240 | MM_BURST_LENGTH | MM_FIFO_WATERMARK); 241 temp32 |= I810_GetWatermark(mode); 242 OUTREG32(FWATER_BLC, temp32); 243 244 // Enable high resolution mode. 245 WriteCrtcReg(IO_CTNL, ReadCrtcReg(IO_CTNL) | EXTENDED_CRTC_CNTL); 246 247 I810_AdjustFrame(mode); 248 return B_OK; 249 } 250 251 252 void 253 I810_AdjustFrame(const DisplayModeEx& mode) 254 { 255 // Adjust start address in frame buffer. 256 257 uint32 address = ((mode.v_display_start * mode.virtual_width 258 + mode.h_display_start) * mode.bytesPerPixel) >> 2; 259 260 WriteCrtcReg(START_ADDR_LO, address & 0xff); 261 WriteCrtcReg(START_ADDR_HI, (address >> 8) & 0xff); 262 WriteCrtcReg(EXT_START_ADDR_HI, (address >> 22) & 0xff); 263 WriteCrtcReg(EXT_START_ADDR, 264 ((address >> 16) & 0x3f) | EXT_START_ADDR_ENABLE); 265 } 266 267 268 void 269 I810_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags) 270 { 271 // Set the indexed color palette for 8-bit color depth mode. 272 273 (void)flags; // avoid compiler warning for unused arg 274 275 if (gInfo.sharedInfo->displayMode.space != B_CMAP8) 276 return ; 277 278 OUTREG8(DAC_MASK, 0xff); 279 OUTREG8(DAC_W_INDEX, first); // initial color index 280 281 while (count--) { 282 OUTREG8(DAC_DATA, colorData[0]); // red 283 OUTREG8(DAC_DATA, colorData[1]); // green 284 OUTREG8(DAC_DATA, colorData[2]); // blue 285 286 colorData += 3; 287 } 288 } 289