1 /* 2 * Copyright 2006-2011, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 * Alexander von Gluck, kallisti5@unixzen.com 8 */ 9 10 11 #include "accelerant_protos.h" 12 #include "accelerant.h" 13 14 #include "utility.h" 15 #include "pll.h" 16 #include "mc.h" 17 18 #include <errno.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <unistd.h> 22 #include <syslog.h> 23 24 #include <AGP.h> 25 26 27 #define TRACE_ACCELERANT 28 #ifdef TRACE_ACCELERANT 29 extern "C" void _sPrintf(const char *format, ...); 30 # define TRACE(x...) _sPrintf("radeon_hd: " x) 31 #else 32 # define TRACE(x...) ; 33 #endif 34 35 36 struct accelerant_info *gInfo; 37 struct register_info *gRegister; 38 crt_info *gCRT[MAX_CRT]; 39 40 41 class AreaCloner { 42 public: 43 AreaCloner(); 44 ~AreaCloner(); 45 46 area_id Clone(const char *name, void **_address, 47 uint32 spec, uint32 protection, 48 area_id sourceArea); 49 status_t InitCheck() 50 {return fArea < 0 ? (status_t)fArea : B_OK;} 51 void Keep(); 52 53 private: 54 area_id fArea; 55 }; 56 57 58 AreaCloner::AreaCloner() 59 : 60 fArea(-1) 61 { 62 } 63 64 65 AreaCloner::~AreaCloner() 66 { 67 if (fArea >= 0) 68 delete_area(fArea); 69 } 70 71 72 area_id 73 AreaCloner::Clone(const char *name, void **_address, uint32 spec, 74 uint32 protection, area_id sourceArea) 75 { 76 fArea = clone_area(name, _address, spec, protection, sourceArea); 77 return fArea; 78 } 79 80 81 void 82 AreaCloner::Keep() 83 { 84 fArea = -1; 85 } 86 87 88 // #pragma mark - 89 90 91 /*! This is the common accelerant_info initializer. It is called by 92 both, the first accelerant and all clones. 93 */ 94 static status_t 95 init_common(int device, bool isClone) 96 { 97 // initialize global accelerant info structure 98 99 gInfo = (accelerant_info *)malloc(sizeof(accelerant_info)); 100 gRegister = (register_info *)malloc(sizeof(register_info)); 101 102 if (gInfo == NULL || gRegister == NULL) 103 return B_NO_MEMORY; 104 105 for (uint32 id = 0; id < MAX_CRT; id++) { 106 gCRT[id] = (crt_info *)malloc(sizeof(crt_info)); 107 if (gCRT[id] == NULL) 108 return B_NO_MEMORY; 109 } 110 111 memset(gInfo, 0, sizeof(accelerant_info)); 112 memset(gRegister, 0, sizeof(register_info)); 113 114 for (uint32 id = 0; id < MAX_CRT; id++) 115 memset(gCRT[id], 0, sizeof(crt_info)); 116 117 gInfo->is_clone = isClone; 118 gInfo->device = device; 119 120 // get basic info from driver 121 122 radeon_get_private_data data; 123 data.magic = RADEON_PRIVATE_DATA_MAGIC; 124 125 if (ioctl(device, RADEON_GET_PRIVATE_DATA, &data, 126 sizeof(radeon_get_private_data)) != 0) { 127 free(gInfo); 128 return B_ERROR; 129 } 130 131 AreaCloner sharedCloner; 132 gInfo->shared_info_area = sharedCloner.Clone("radeon hd shared info", 133 (void **)&gInfo->shared_info, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 134 data.shared_info_area); 135 status_t status = sharedCloner.InitCheck(); 136 if (status < B_OK) { 137 free(gInfo); 138 TRACE("%s, failed shared area%i, %i\n", 139 __func__, data.shared_info_area, gInfo->shared_info_area); 140 return status; 141 } 142 143 AreaCloner regsCloner; 144 gInfo->regs_area = regsCloner.Clone("radeon hd regs", 145 (void **)&gInfo->regs, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 146 gInfo->shared_info->registers_area); 147 status = regsCloner.InitCheck(); 148 if (status < B_OK) { 149 free(gInfo); 150 return status; 151 } 152 153 sharedCloner.Keep(); 154 regsCloner.Keep(); 155 156 // Define Radeon PLL default ranges 157 gInfo->shared_info->pll_info.reference_frequency 158 = RHD_PLL_REFERENCE_DEFAULT; 159 gInfo->shared_info->pll_info.min_frequency = RHD_PLL_MIN_DEFAULT; 160 gInfo->shared_info->pll_info.max_frequency = RHD_PLL_MAX_DEFAULT; 161 162 return B_OK; 163 } 164 165 166 /*! Clean up data common to both primary and cloned accelerant */ 167 static void 168 uninit_common(void) 169 { 170 delete_area(gInfo->regs_area); 171 delete_area(gInfo->shared_info_area); 172 173 gInfo->regs_area = gInfo->shared_info_area = -1; 174 175 // close the file handle ONLY if we're the clone 176 if (gInfo->is_clone) 177 close(gInfo->device); 178 179 free(gInfo); 180 free(gRegister); 181 182 for (uint32 id = 0; id < MAX_CRT; id++) 183 free(gCRT[id]); 184 } 185 186 187 /*! Populate gRegister with device dependant register locations */ 188 status_t 189 init_registers(uint8 crtid) 190 { 191 radeon_shared_info &info = *gInfo->shared_info; 192 193 if (info.device_chipset >= RADEON_R800) { 194 uint32 offset = 0; 195 196 // AMD Eyefinity on Evergreen GPUs 197 if (crtid == 1) { 198 offset = EVERGREEN_CRTC1_REGISTER_OFFSET; 199 gRegister->vgaControl = D2VGA_CONTROL; 200 } else if (crtid == 2) { 201 offset = EVERGREEN_CRTC2_REGISTER_OFFSET; 202 gRegister->vgaControl = EVERGREEN_D3VGA_CONTROL; 203 } else if (crtid == 3) { 204 offset = EVERGREEN_CRTC3_REGISTER_OFFSET; 205 gRegister->vgaControl = EVERGREEN_D4VGA_CONTROL; 206 } else if (crtid == 4) { 207 offset = EVERGREEN_CRTC4_REGISTER_OFFSET; 208 gRegister->vgaControl = EVERGREEN_D5VGA_CONTROL; 209 } else if (crtid == 5) { 210 offset = EVERGREEN_CRTC5_REGISTER_OFFSET; 211 gRegister->vgaControl = EVERGREEN_D6VGA_CONTROL; 212 } else { 213 offset = EVERGREEN_CRTC0_REGISTER_OFFSET; 214 gRegister->vgaControl = D1VGA_CONTROL; 215 } 216 217 // Evergreen+ is crtoffset + register 218 gRegister->grphEnable = offset + EVERGREEN_GRPH_ENABLE; 219 gRegister->grphControl = offset + EVERGREEN_GRPH_CONTROL; 220 gRegister->grphSwapControl = offset + EVERGREEN_GRPH_SWAP_CONTROL; 221 gRegister->grphPrimarySurfaceAddr 222 = offset + EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS; 223 gRegister->grphSecondarySurfaceAddr 224 = offset + EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS; 225 226 gRegister->grphPrimarySurfaceAddrHigh 227 = offset + EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH; 228 gRegister->grphSecondarySurfaceAddrHigh 229 = offset + EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH; 230 231 gRegister->grphPitch = offset + EVERGREEN_GRPH_PITCH; 232 gRegister->grphSurfaceOffsetX 233 = offset + EVERGREEN_GRPH_SURFACE_OFFSET_X; 234 gRegister->grphSurfaceOffsetY 235 = offset + EVERGREEN_GRPH_SURFACE_OFFSET_Y; 236 gRegister->grphXStart = offset + EVERGREEN_GRPH_X_START; 237 gRegister->grphYStart = offset + EVERGREEN_GRPH_Y_START; 238 gRegister->grphXEnd = offset + EVERGREEN_GRPH_X_END; 239 gRegister->grphYEnd = offset + EVERGREEN_GRPH_Y_END; 240 gRegister->crtControl = offset + EVERGREEN_CRTC_CONTROL; 241 gRegister->modeDesktopHeight = offset + EVERGREEN_DESKTOP_HEIGHT; 242 gRegister->modeDataFormat = offset + EVERGREEN_DATA_FORMAT; 243 gRegister->viewportStart = offset + EVERGREEN_VIEWPORT_START; 244 gRegister->viewportSize = offset + EVERGREEN_VIEWPORT_SIZE; 245 246 } else if (info.device_chipset >= RADEON_R600 247 && info.device_chipset < RADEON_R800) { 248 249 // r600 - r700 are D1 or D2 based on primary / secondary crt 250 gRegister->vgaControl 251 = crtid == 1 ? D2VGA_CONTROL : D1VGA_CONTROL; 252 gRegister->grphEnable 253 = crtid == 1 ? D2GRPH_ENABLE : D1GRPH_ENABLE; 254 gRegister->grphControl 255 = crtid == 1 ? D2GRPH_CONTROL : D1GRPH_CONTROL; 256 gRegister->grphSwapControl 257 = crtid == 1 ? D2GRPH_SWAP_CNTL : D1GRPH_SWAP_CNTL; 258 gRegister->grphPrimarySurfaceAddr 259 = crtid == 1 ? D2GRPH_PRIMARY_SURFACE_ADDRESS 260 : D1GRPH_PRIMARY_SURFACE_ADDRESS; 261 gRegister->grphSecondarySurfaceAddr 262 = crtid == 1 ? D2GRPH_SECONDARY_SURFACE_ADDRESS 263 : D1GRPH_SECONDARY_SURFACE_ADDRESS; 264 265 // Surface Address high only used on r770+ 266 gRegister->grphPrimarySurfaceAddrHigh 267 = crtid == 1 ? R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 268 : R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH; 269 gRegister->grphSecondarySurfaceAddrHigh 270 = crtid == 1 ? R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 271 : R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH; 272 273 gRegister->grphPitch 274 = crtid == 1 ? D2GRPH_PITCH : D1GRPH_PITCH; 275 gRegister->grphSurfaceOffsetX 276 = crtid == 1 ? D2GRPH_SURFACE_OFFSET_X : D1GRPH_SURFACE_OFFSET_X; 277 gRegister->grphSurfaceOffsetY 278 = crtid == 1 ? D2GRPH_SURFACE_OFFSET_Y : D1GRPH_SURFACE_OFFSET_Y; 279 gRegister->grphXStart 280 = crtid == 1 ? D2GRPH_X_START : D1GRPH_X_START; 281 gRegister->grphYStart 282 = crtid == 1 ? D2GRPH_Y_START : D1GRPH_Y_START; 283 gRegister->grphXEnd 284 = crtid == 1 ? D2GRPH_X_END : D1GRPH_X_END; 285 gRegister->grphYEnd 286 = crtid == 1 ? D2GRPH_Y_END : D1GRPH_Y_END; 287 gRegister->crtControl 288 = crtid == 1 ? D2CRTC_CONTROL : D1CRTC_CONTROL; 289 gRegister->modeDesktopHeight 290 = crtid == 1 ? D2MODE_DESKTOP_HEIGHT : D1MODE_DESKTOP_HEIGHT; 291 gRegister->modeDataFormat 292 = crtid == 1 ? D2MODE_DATA_FORMAT : D1MODE_DATA_FORMAT; 293 gRegister->viewportStart 294 = crtid == 1 ? D2MODE_VIEWPORT_START : D1MODE_VIEWPORT_START; 295 gRegister->viewportSize 296 = crtid == 1 ? D2MODE_VIEWPORT_SIZE : D1MODE_VIEWPORT_SIZE; 297 } else { 298 // this really shouldn't happen unless a driver PCIID chipset is wrong 299 TRACE("%s, unknown Radeon chipset: r%X\n", __func__, 300 info.device_chipset); 301 return B_ERROR; 302 } 303 304 // Populate common registers 305 // TODO : Wait.. this doesn't work with Eyefinity > crt 1. 306 gRegister->crtid = crtid; 307 308 gRegister->modeCenter 309 = crtid == 1 ? D2MODE_CENTER : D1MODE_CENTER; 310 gRegister->grphUpdate 311 = crtid == 1 ? D2GRPH_UPDATE : D1GRPH_UPDATE; 312 gRegister->crtHPolarity 313 = crtid == 1 ? D2CRTC_H_SYNC_A_CNTL : D1CRTC_H_SYNC_A_CNTL; 314 gRegister->crtVPolarity 315 = crtid == 1 ? D2CRTC_V_SYNC_A_CNTL : D1CRTC_V_SYNC_A_CNTL; 316 gRegister->crtHTotal 317 = crtid == 1 ? D2CRTC_H_TOTAL : D1CRTC_H_TOTAL; 318 gRegister->crtVTotal 319 = crtid == 1 ? D2CRTC_V_TOTAL : D1CRTC_V_TOTAL; 320 gRegister->crtHSync 321 = crtid == 1 ? D2CRTC_H_SYNC_A : D1CRTC_H_SYNC_A; 322 gRegister->crtVSync 323 = crtid == 1 ? D2CRTC_V_SYNC_A : D1CRTC_V_SYNC_A; 324 gRegister->crtHBlank 325 = crtid == 1 ? D2CRTC_H_BLANK_START_END : D1CRTC_H_BLANK_START_END; 326 gRegister->crtVBlank 327 = crtid == 1 ? D2CRTC_V_BLANK_START_END : D1CRTC_V_BLANK_START_END; 328 gRegister->crtInterlace 329 = crtid == 1 ? D2CRTC_INTERLACE_CONTROL : D1CRTC_INTERLACE_CONTROL; 330 gRegister->crtCountControl 331 = crtid == 1 ? D2CRTC_COUNT_CONTROL : D1CRTC_COUNT_CONTROL; 332 gRegister->sclUpdate 333 = crtid == 1 ? D2SCL_UPDATE : D1SCL_UPDATE; 334 gRegister->sclEnable 335 = crtid == 1 ? D2SCL_ENABLE : D1SCL_ENABLE; 336 gRegister->sclTapControl 337 = crtid == 1 ? D2SCL_TAP_CONTROL : D1SCL_TAP_CONTROL; 338 339 TRACE("%s, registers for ATI chipset r%X crt #%d loaded\n", __func__, 340 info.device_chipset, crtid); 341 342 return B_OK; 343 } 344 345 346 // #pragma mark - public accelerant functions 347 348 349 /*! Init primary accelerant */ 350 status_t 351 radeon_init_accelerant(int device) 352 { 353 TRACE("%s enter\n", __func__); 354 355 status_t status = init_common(device, false); 356 if (status != B_OK) 357 return status; 358 359 radeon_shared_info &info = *gInfo->shared_info; 360 361 init_lock(&info.accelerant_lock, "radeon hd accelerant"); 362 init_lock(&info.engine_lock, "radeon hd engine"); 363 364 status = init_registers(0); 365 // Initilize registers for crt0 to begin 366 367 if (status != B_OK) 368 return status; 369 370 status = create_mode_list(); 371 if (status != B_OK) { 372 uninit_common(); 373 return status; 374 } 375 376 TRACE("%s done\n", __func__); 377 return B_OK; 378 } 379 380 381 /*! This function is called for both, the primary accelerant and all of 382 its clones. 383 */ 384 void 385 radeon_uninit_accelerant(void) 386 { 387 TRACE("%s enter\n", __func__); 388 389 gInfo->mode_list = NULL; 390 391 radeon_shared_info &info = *gInfo->shared_info; 392 393 uninit_lock(&info.accelerant_lock); 394 uninit_lock(&info.engine_lock); 395 396 uninit_common(); 397 TRACE("%s done\n", __func__); 398 } 399 400