1 /* 2 * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Support for i915 chipset and up based on the X driver, 6 * Copyright 2006-2007 Intel Corporation. 7 * 8 * Authors: 9 * Axel Dörfler, axeld@pinc-software.de 10 */ 11 12 13 #include "accelerant_protos.h" 14 #include "accelerant.h" 15 #include "utility.h" 16 17 #include <stdio.h> 18 #include <string.h> 19 #include <math.h> 20 21 #include <create_display_modes.h> 22 #include <ddc.h> 23 #include <edid.h> 24 25 26 #define TRACE_MODE 27 #ifdef TRACE_MODE 28 extern "C" void _sPrintf(const char *format, ...); 29 # define TRACE(x) _sPrintf x 30 #else 31 # define TRACE(x) ; 32 #endif 33 34 35 static display_mode gDisplayMode; 36 37 38 status_t 39 create_mode_list(void) 40 { 41 // TODO : Read active monitor EDID 42 43 /* Populate modeline with temporary example */ 44 gDisplayMode.timing.pixel_clock = 71500; 45 gDisplayMode.timing.h_display = 1366; // In Pixels 46 gDisplayMode.timing.h_sync_start = 1406; 47 gDisplayMode.timing.h_sync_end = 1438; 48 gDisplayMode.timing.h_total = 1510; 49 gDisplayMode.timing.v_display = 768; // In Pixels 50 gDisplayMode.timing.v_sync_start = 771; 51 gDisplayMode.timing.v_sync_end = 777; 52 gDisplayMode.timing.v_total = 789; 53 gDisplayMode.timing.flags = 0; // Polarity, ex: B_POSITIVE_HSYNC 54 55 gDisplayMode.space = B_RGB32_LITTLE; // Pixel configuration 56 gDisplayMode.virtual_width = 1366; // In Pixels 57 gDisplayMode.virtual_height = 768; // In Pixels 58 gDisplayMode.h_display_start = 0; 59 gDisplayMode.v_display_start = 0; 60 gDisplayMode.flags = 0; // Mode flags (Some drivers use this 61 62 gInfo->mode_list = &gDisplayMode; 63 gInfo->shared_info->mode_count = 1; 64 return B_OK; 65 } 66 67 68 // #pragma mark - 69 70 71 uint32 72 radeon_accelerant_mode_count(void) 73 { 74 TRACE(("radeon_accelerant_mode_count()\n")); 75 76 return gInfo->shared_info->mode_count; 77 } 78 79 80 status_t 81 radeon_get_mode_list(display_mode *modeList) 82 { 83 TRACE(("radeon_get_mode_info()\n")); 84 memcpy(modeList, gInfo->mode_list, 85 gInfo->shared_info->mode_count * sizeof(display_mode)); 86 return B_OK; 87 } 88 89 90 inline void 91 write32AtMask(uint32 adress, uint32 value, uint32 mask) 92 { 93 uint32 temp; 94 temp = read32(adress); 95 temp &= ~mask; 96 temp |= value & mask; 97 write32(adress, temp); 98 } 99 100 101 enum { 102 /* CRTC1 registers */ 103 D1CRTC_H_TOTAL = 0x6000, 104 D1CRTC_H_BLANK_START_END = 0x6004, 105 D1CRTC_H_SYNC_A = 0x6008, 106 D1CRTC_H_SYNC_A_CNTL = 0x600C, 107 D1CRTC_H_SYNC_B = 0x6010, 108 D1CRTC_H_SYNC_B_CNTL = 0x6014, 109 110 D1CRTC_V_TOTAL = 0x6020, 111 D1CRTC_V_BLANK_START_END = 0x6024, 112 D1CRTC_V_SYNC_A = 0x6028, 113 D1CRTC_V_SYNC_A_CNTL = 0x602C, 114 D1CRTC_V_SYNC_B = 0x6030, 115 D1CRTC_V_SYNC_B_CNTL = 0x6034, 116 117 D1CRTC_CONTROL = 0x6080, 118 D1CRTC_BLANK_CONTROL = 0x6084, 119 D1CRTC_INTERLACE_CONTROL = 0x6088, 120 D1CRTC_BLACK_COLOR = 0x6098, 121 D1CRTC_STATUS = 0x609C, 122 D1CRTC_COUNT_CONTROL = 0x60B4, 123 124 /* D1GRPH registers */ 125 D1GRPH_ENABLE = 0x6100, 126 D1GRPH_CONTROL = 0x6104, 127 D1GRPH_LUT_SEL = 0x6108, 128 D1GRPH_SWAP_CNTL = 0x610C, 129 D1GRPH_PRIMARY_SURFACE_ADDRESS = 0x6110, 130 D1GRPH_SECONDARY_SURFACE_ADDRESS = 0x6118, 131 D1GRPH_PITCH = 0x6120, 132 D1GRPH_SURFACE_OFFSET_X = 0x6124, 133 D1GRPH_SURFACE_OFFSET_Y = 0x6128, 134 D1GRPH_X_START = 0x612C, 135 D1GRPH_Y_START = 0x6130, 136 D1GRPH_X_END = 0x6134, 137 D1GRPH_Y_END = 0x6138, 138 D1GRPH_UPDATE = 0x6144, 139 140 /* D1MODE */ 141 D1MODE_DESKTOP_HEIGHT = 0x652C, 142 D1MODE_VLINE_START_END = 0x6538, 143 D1MODE_VLINE_STATUS = 0x653C, 144 D1MODE_VIEWPORT_START = 0x6580, 145 D1MODE_VIEWPORT_SIZE = 0x6584, 146 D1MODE_EXT_OVERSCAN_LEFT_RIGHT = 0x6588, 147 D1MODE_EXT_OVERSCAN_TOP_BOTTOM = 0x658C, 148 D1MODE_DATA_FORMAT = 0x6528, 149 150 /* D1SCL */ 151 D1SCL_ENABLE = 0x6590, 152 D1SCL_TAP_CONTROL = 0x6594, 153 D1MODE_CENTER = 0x659C, /* guess */ 154 D1SCL_HVSCALE = 0x65A4, /* guess */ 155 D1SCL_HFILTER = 0x65B0, /* guess */ 156 D1SCL_VFILTER = 0x65C0, /* guess */ 157 D1SCL_UPDATE = 0x65CC, 158 D1SCL_DITHER = 0x65D4, /* guess */ 159 D1SCL_FLIP_CONTROL = 0x65D8 /* guess */ 160 161 }; 162 163 164 static void 165 get_color_space_format(const display_mode &mode, uint32 &colorMode, 166 uint32 &bytesPerRow, uint32 &bitsPerPixel) 167 { 168 uint32 bytesPerPixel; 169 170 switch (mode.space) { 171 case B_RGB32_LITTLE: 172 colorMode = DISPLAY_CONTROL_RGB32; 173 bytesPerPixel = 4; 174 bitsPerPixel = 32; 175 break; 176 case B_RGB16_LITTLE: 177 colorMode = DISPLAY_CONTROL_RGB16; 178 bytesPerPixel = 2; 179 bitsPerPixel = 16; 180 break; 181 case B_RGB15_LITTLE: 182 colorMode = DISPLAY_CONTROL_RGB15; 183 bytesPerPixel = 2; 184 bitsPerPixel = 15; 185 break; 186 case B_CMAP8: 187 default: 188 colorMode = DISPLAY_CONTROL_CMAP8; 189 bytesPerPixel = 1; 190 bitsPerPixel = 8; 191 break; 192 } 193 194 bytesPerRow = mode.virtual_width * bytesPerPixel; 195 196 // Make sure bytesPerRow is a multiple of 64 197 // TODO: check if the older chips have the same restriction! 198 if ((bytesPerRow & 63) != 0) 199 bytesPerRow = (bytesPerRow + 63) & ~63; 200 } 201 202 203 #define D1_REG_OFFSET 0x0000 204 #define D2_REG_OFFSET 0x0800 205 206 207 static void 208 DxModeSet(display_mode *mode) 209 { 210 uint32 regOffset = D1_REG_OFFSET; 211 212 display_timing& displayTiming = mode->timing; 213 214 215 /* enable read requests */ 216 write32AtMask(regOffset + D1CRTC_CONTROL, 0, 0x01000000); 217 218 /* Horizontal */ 219 write32(regOffset + D1CRTC_H_TOTAL, displayTiming.h_total - 1); 220 221 uint16 blankStart = displayTiming.h_display; // displayTiming.h_sync_end; 222 uint16 blankEnd = displayTiming.h_sync_start; // displayTiming.h_total; 223 // write32(regOffset + D1CRTC_H_BLANK_START_END, 224 // blankStart | (blankEnd << 16)); 225 226 write32(regOffset + D1CRTC_H_SYNC_A, 227 (displayTiming.h_sync_end - displayTiming.h_sync_start) << 16); 228 // write32(regOffset + D1CRTC_H_SYNC_A_CNTL, Mode->Flags & V_NHSYNC); 229 //! write32(regOffset + D1CRTC_H_SYNC_A_CNTL, V_NHSYNC); 230 231 /* Vertical */ 232 write32(regOffset + D1CRTC_V_TOTAL, displayTiming.v_total - 1); 233 234 blankStart = displayTiming.v_display; // displayTiming.v_sync_end; 235 blankEnd = displayTiming.v_sync_start; // displayTiming.v_total; 236 // write32(regOffset + D1CRTC_V_BLANK_START_END, 237 // blankStart | (blankEnd << 16)); 238 239 /* set interlaced */ 240 // if (Mode->Flags & V_INTERLACE) { 241 if (0) { 242 write32(regOffset + D1CRTC_INTERLACE_CONTROL, 0x1); 243 write32(regOffset + D1MODE_DATA_FORMAT, 0x1); 244 } else { 245 write32(regOffset + D1CRTC_INTERLACE_CONTROL, 0x0); 246 write32(regOffset + D1MODE_DATA_FORMAT, 0x0); 247 } 248 249 write32(regOffset + D1CRTC_V_SYNC_A, 250 (displayTiming.v_sync_end - displayTiming.v_sync_start) << 16); 251 // write32(regOffset + D1CRTC_V_SYNC_A_CNTL, Mode->Flags & V_NVSYNC); 252 //! write32(regOffset + D1CRTC_V_SYNC_A_CNTL, V_NVSYNC); 253 254 /* set D1CRTC_HORZ_COUNT_BY2_EN to 0; 255 should only be set to 1 on 30bpp DVI modes 256 */ 257 write32AtMask(regOffset + D1CRTC_COUNT_CONTROL, 0x0, 0x1); 258 259 } 260 261 262 static void 263 DxModeScale(display_mode *mode) 264 { 265 uint32 regOffset = D1_REG_OFFSET; 266 267 /* D1Mode registers */ 268 write32(regOffset + D1MODE_VIEWPORT_SIZE, 269 mode->timing.v_display | (mode->timing.h_display << 16)); 270 write32(regOffset + D1MODE_VIEWPORT_START, 0); 271 272 /* write32(regOffset + D1MODE_EXT_OVERSCAN_LEFT_RIGHT, 273 (Overscan.OverscanLeft << 16) | Overscan.OverscanRight); 274 write32(regOffset + D1MODE_EXT_OVERSCAN_TOP_BOTTOM, 275 (Overscan.OverscanTop << 16) | Overscan.OverscanBottom); 276 */ 277 write32(regOffset + D1SCL_ENABLE, 0); 278 write32(regOffset + D1SCL_TAP_CONTROL, 0); 279 write32(regOffset + D1MODE_CENTER, 0); 280 } 281 282 283 status_t 284 radeon_set_display_mode(display_mode *mode) 285 { 286 DxModeSet(mode); 287 288 DxModeScale(mode); 289 290 uint32 colorMode, bytesPerRow, bitsPerPixel; 291 get_color_space_format(*mode, colorMode, bytesPerRow, bitsPerPixel); 292 293 uint32 regOffset = D1_REG_OFFSET; 294 295 write32AtMask(regOffset + D1GRPH_ENABLE, 1, 0x00000001); 296 297 /* disable R/B swap, disable tiling, disable 16bit alpha, etc. */ 298 write32(regOffset + D1GRPH_CONTROL, 0); 299 300 switch (mode->space) { 301 case B_CMAP8: 302 write32AtMask(regOffset + D1GRPH_CONTROL, 0, 0x00000703); 303 break; 304 case B_RGB15_LITTLE: 305 write32AtMask(regOffset + D1GRPH_CONTROL, 0x000001, 0x00000703); 306 break; 307 case B_RGB16_LITTLE: 308 write32AtMask(regOffset + D1GRPH_CONTROL, 0x000101, 0x00000703); 309 break; 310 case B_RGB24_LITTLE: 311 case B_RGB32_LITTLE: 312 default: 313 write32AtMask(regOffset + D1GRPH_CONTROL, 0x000002, 0x00000703); 314 break; 315 /* TODO: 64bpp ;p */ 316 } 317 318 /* Make sure that we are not swapping colours around */ 319 // if (rhdPtr->ChipSet > RHD_R600) 320 write32(regOffset + D1GRPH_SWAP_CNTL, 0); 321 /* R5xx - RS690 case is GRPH_CONTROL bit 16 */ 322 323 #define R6XX_CONFIG_FB_BASE 0x542C /* AKA CONFIG_F0_BASE */ 324 325 uint32 fbIntAddress = read32(R6XX_CONFIG_FB_BASE); 326 327 uint32 offset = gInfo->shared_info->frame_buffer_offset; 328 write32(regOffset + D1GRPH_PRIMARY_SURFACE_ADDRESS, 329 fbIntAddress + offset); 330 write32(regOffset + D1GRPH_PITCH, bytesPerRow / 4); 331 write32(regOffset + D1GRPH_SURFACE_OFFSET_X, 0); 332 write32(regOffset + D1GRPH_SURFACE_OFFSET_Y, 0); 333 write32(regOffset + D1GRPH_X_START, 0); 334 write32(regOffset + D1GRPH_Y_START, 0); 335 write32(regOffset + D1GRPH_X_END, mode->virtual_width); 336 write32(regOffset + D1GRPH_Y_END, mode->virtual_height); 337 338 /* D1Mode registers */ 339 write32(regOffset + D1MODE_DESKTOP_HEIGHT, mode->virtual_height); 340 341 // update shared info 342 gInfo->shared_info->bytes_per_row = bytesPerRow; 343 gInfo->shared_info->current_mode = *mode; 344 gInfo->shared_info->bits_per_pixel = bitsPerPixel; 345 346 return B_OK; 347 } 348 349 350 status_t 351 radeon_get_display_mode(display_mode *_currentMode) 352 { 353 TRACE(("radeon_get_display_mode()\n")); 354 355 *_currentMode = gDisplayMode; 356 return B_OK; 357 } 358 359 360 status_t 361 radeon_get_frame_buffer_config(frame_buffer_config *config) 362 { 363 TRACE(("radeon_get_frame_buffer_config()\n")); 364 365 uint32 offset = gInfo->shared_info->frame_buffer_offset; 366 367 config->frame_buffer = gInfo->shared_info->graphics_memory + offset; 368 config->frame_buffer_dma 369 = (uint8 *)gInfo->shared_info->physical_graphics_memory + offset; 370 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 371 372 return B_OK; 373 } 374 375 376 status_t 377 radeon_get_pixel_clock_limits(display_mode *mode, uint32 *_low, uint32 *_high) 378 { 379 TRACE(("radeon_get_pixel_clock_limits()\n")); 380 /* 381 if (_low != NULL) { 382 // lower limit of about 48Hz vertical refresh 383 uint32 totalClocks = (uint32)mode->timing.h_total * (uint32)mode->timing.v_total; 384 uint32 low = (totalClocks * 48L) / 1000L; 385 if (low < gInfo->shared_info->pll_info.min_frequency) 386 low = gInfo->shared_info->pll_info.min_frequency; 387 else if (low > gInfo->shared_info->pll_info.max_frequency) 388 return B_ERROR; 389 390 *_low = low; 391 } 392 393 if (_high != NULL) 394 *_high = gInfo->shared_info->pll_info.max_frequency; 395 */ 396 *_low = 48L; 397 *_high = 100 * 1000000L; 398 return B_OK; 399 } 400 401 402