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.h" 12 13 #include <AGP.h> 14 #include <Debug.h> 15 #include <errno.h> 16 #include <stdlib.h> 17 #include <stdio.h> 18 #include <string.h> 19 #include <syslog.h> 20 #include <unistd.h> 21 22 #include "accelerant_protos.h" 23 24 #include "bios.h" 25 #include "connector.h" 26 #include "display.h" 27 #include "displayport.h" 28 #include "gpu.h" 29 #include "pll.h" 30 #include "utility.h" 31 32 33 #undef TRACE 34 35 #define TRACE_ACCELERANT 36 #ifdef TRACE_ACCELERANT 37 # define TRACE(x...) _sPrintf("radeon_hd: " x) 38 #else 39 # define TRACE(x...) ; 40 #endif 41 42 43 struct accelerant_info* gInfo; 44 display_info* gDisplay[MAX_DISPLAY]; 45 connector_info* gConnector[ATOM_MAX_SUPPORTED_DEVICE]; 46 gpio_info* gGPIOInfo[ATOM_MAX_SUPPORTED_DEVICE]; 47 48 49 class AreaCloner { 50 public: 51 AreaCloner(); 52 ~AreaCloner(); 53 54 area_id Clone(const char* name, void** _address, 55 uint32 spec, uint32 protection, 56 area_id sourceArea); 57 status_t InitCheck() 58 {return fArea < 0 ? (status_t)fArea : B_OK;} 59 void Keep(); 60 61 private: 62 area_id fArea; 63 }; 64 65 66 AreaCloner::AreaCloner() 67 : 68 fArea(-1) 69 { 70 } 71 72 73 AreaCloner::~AreaCloner() 74 { 75 if (fArea >= 0) 76 delete_area(fArea); 77 } 78 79 80 area_id 81 AreaCloner::Clone(const char* name, void** _address, uint32 spec, 82 uint32 protection, area_id sourceArea) 83 { 84 fArea = clone_area(name, _address, spec, protection, sourceArea); 85 return fArea; 86 } 87 88 89 void 90 AreaCloner::Keep() 91 { 92 fArea = -1; 93 } 94 95 96 // #pragma mark - 97 98 99 /*! This is the common accelerant_info initializer. It is called by 100 both, the first accelerant and all clones. 101 */ 102 static status_t 103 init_common(int device, bool isClone) 104 { 105 // initialize global accelerant info structure 106 107 gInfo = (accelerant_info*)malloc(sizeof(accelerant_info)); 108 109 if (gInfo == NULL) 110 return B_NO_MEMORY; 111 112 memset(gInfo, 0, sizeof(accelerant_info)); 113 114 // malloc memory for active display information 115 for (uint32 id = 0; id < MAX_DISPLAY; id++) { 116 gDisplay[id] = (display_info*)malloc(sizeof(display_info)); 117 if (gDisplay[id] == NULL) 118 return B_NO_MEMORY; 119 memset(gDisplay[id], 0, sizeof(display_info)); 120 121 gDisplay[id]->regs = (register_info*)malloc(sizeof(register_info)); 122 if (gDisplay[id]->regs == NULL) 123 return B_NO_MEMORY; 124 memset(gDisplay[id]->regs, 0, sizeof(register_info)); 125 } 126 127 // malloc for possible physical card connectors 128 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { 129 gConnector[id] = (connector_info*)malloc(sizeof(connector_info)); 130 131 if (gConnector[id] == NULL) 132 return B_NO_MEMORY; 133 memset(gConnector[id], 0, sizeof(connector_info)); 134 } 135 136 // malloc for card gpio pin information 137 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { 138 gGPIOInfo[id] = (gpio_info*)malloc(sizeof(gpio_info)); 139 140 if (gGPIOInfo[id] == NULL) 141 return B_NO_MEMORY; 142 memset(gGPIOInfo[id], 0, sizeof(gpio_info)); 143 } 144 145 gInfo->is_clone = isClone; 146 gInfo->device = device; 147 148 gInfo->dpms_mode = B_DPMS_ON; 149 // initial state 150 151 // get basic info from driver 152 153 radeon_get_private_data data; 154 data.magic = RADEON_PRIVATE_DATA_MAGIC; 155 156 if (ioctl(device, RADEON_GET_PRIVATE_DATA, &data, 157 sizeof(radeon_get_private_data)) != 0) { 158 free(gInfo); 159 return B_ERROR; 160 } 161 162 AreaCloner sharedCloner; 163 gInfo->shared_info_area = sharedCloner.Clone("radeon hd shared info", 164 (void**)&gInfo->shared_info, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 165 data.shared_info_area); 166 status_t status = sharedCloner.InitCheck(); 167 if (status < B_OK) { 168 free(gInfo); 169 TRACE("%s, failed to create shared area\n", __func__); 170 return status; 171 } 172 173 AreaCloner regsCloner; 174 gInfo->regs_area = regsCloner.Clone("radeon hd regs", 175 (void**)&gInfo->regs, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 176 gInfo->shared_info->registers_area); 177 status = regsCloner.InitCheck(); 178 if (status < B_OK) { 179 free(gInfo); 180 TRACE("%s, failed to create mmio area\n", __func__); 181 return status; 182 } 183 184 gInfo->rom_area = clone_area("radeon hd AtomBIOS", 185 (void**)&gInfo->rom, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 186 gInfo->shared_info->rom_area); 187 188 if (gInfo->rom_area < 0) { 189 TRACE("%s: Clone of AtomBIOS failed!\n", __func__); 190 gInfo->shared_info->has_rom = false; 191 } 192 193 if (gInfo->rom[0] != 0x55 || gInfo->rom[1] != 0xAA) 194 TRACE("%s: didn't find a VGA bios in cloned region!\n", __func__); 195 196 sharedCloner.Keep(); 197 regsCloner.Keep(); 198 199 return B_OK; 200 } 201 202 203 /*! Clean up data common to both primary and cloned accelerant */ 204 static void 205 uninit_common(void) 206 { 207 if (gInfo != NULL) { 208 delete_area(gInfo->regs_area); 209 delete_area(gInfo->shared_info_area); 210 delete_area(gInfo->rom_area); 211 212 gInfo->regs_area = gInfo->shared_info_area = -1; 213 214 // close the file handle ONLY if we're the clone 215 if (gInfo->is_clone) 216 close(gInfo->device); 217 218 free(gInfo); 219 } 220 221 for (uint32 id = 0; id < MAX_DISPLAY; id++) { 222 if (gDisplay[id] != NULL) { 223 free(gDisplay[id]->regs); 224 free(gDisplay[id]); 225 } 226 } 227 228 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { 229 free(gConnector[id]); 230 free(gGPIOInfo[id]); 231 } 232 } 233 234 235 // #pragma mark - public accelerant functions 236 237 238 /*! Init primary accelerant */ 239 status_t 240 radeon_init_accelerant(int device) 241 { 242 TRACE("%s enter\n", __func__); 243 244 status_t status = init_common(device, false); 245 if (status != B_OK) 246 return status; 247 248 radeon_shared_info &info = *gInfo->shared_info; 249 250 init_lock(&info.accelerant_lock, "radeon hd accelerant"); 251 init_lock(&info.engine_lock, "radeon hd engine"); 252 253 radeon_init_bios(gInfo->rom); 254 255 // probe firmware information 256 radeon_gpu_probe(); 257 258 // find GPIO pins from AtomBIOS 259 gpio_probe(); 260 261 // find physical card connectors from AtomBIOS 262 status = connector_probe(); 263 264 if (status != B_OK) { 265 TRACE("%s: falling back to legacy connector probe.\n", __func__); 266 status = connector_probe_legacy(); 267 } 268 269 if (status != B_OK) { 270 TRACE("%s: couldn't detect supported connectors!\n", __func__); 271 return status; 272 } 273 274 // print found connectors 275 debug_connectors(); 276 277 // setup encoders on each connector if needed 278 encoder_init(); 279 280 // program external pll clock 281 pll_external_init(); 282 283 // setup link on any DisplayPort connectors 284 dp_setup_connectors(); 285 286 // detect attached displays 287 status = detect_displays(); 288 //if (status != B_OK) 289 // return status; 290 291 // print found displays 292 debug_displays(); 293 294 // create initial list of video modes 295 status = create_mode_list(); 296 //if (status != B_OK) { 297 // radeon_uninit_accelerant(); 298 // return status; 299 //} 300 301 radeon_gpu_mc_setup(); 302 303 // Set up data crunching + irq rings 304 radeon_gpu_ring_setup(); 305 306 radeon_gpu_ring_boot(RADEON_QUEUE_TYPE_GFX_INDEX); 307 308 TRACE("%s done\n", __func__); 309 return B_OK; 310 } 311 312 313 /*! This function is called for both, the primary accelerant and all of 314 its clones. 315 */ 316 void 317 radeon_uninit_accelerant(void) 318 { 319 TRACE("%s enter\n", __func__); 320 321 gInfo->mode_list = NULL; 322 323 radeon_shared_info &info = *gInfo->shared_info; 324 325 uninit_lock(&info.accelerant_lock); 326 uninit_lock(&info.engine_lock); 327 328 uninit_common(); 329 TRACE("%s done\n", __func__); 330 } 331 332 333 status_t 334 radeon_get_accelerant_device_info(accelerant_device_info* di) 335 { 336 radeon_shared_info &info = *gInfo->shared_info; 337 338 di->version = B_ACCELERANT_VERSION; 339 strcpy(di->name, info.deviceName); 340 341 char chipset[32]; 342 sprintf(chipset, "%s", gInfo->shared_info->chipsetName); 343 strcpy(di->chipset, chipset); 344 345 // add flags onto chipset name 346 if ((info.chipsetFlags & CHIP_IGP) != 0) 347 strcat(di->chipset, " IGP"); 348 if ((info.chipsetFlags & CHIP_MOBILE) != 0) 349 strcat(di->chipset, " Mobile"); 350 if ((info.chipsetFlags & CHIP_APU) != 0) 351 strcat(di->chipset, " APU"); 352 353 strcpy(di->serial_no, "None" ); 354 355 di->memory = gInfo->shared_info->graphics_memory_size; 356 return B_OK; 357 } 358