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[MAX_GPIO_PINS]; 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 gConnector[id]->encoder.pll.id = ATOM_PPLL_INVALID; 136 } 137 138 // malloc for card gpio pin information 139 for (uint32 id = 0; id < MAX_GPIO_PINS; id++) { 140 gGPIOInfo[id] = (gpio_info*)malloc(sizeof(gpio_info)); 141 142 if (gGPIOInfo[id] == NULL) 143 return B_NO_MEMORY; 144 memset(gGPIOInfo[id], 0, sizeof(gpio_info)); 145 } 146 147 gInfo->is_clone = isClone; 148 gInfo->device = device; 149 150 gInfo->dpms_mode = B_DPMS_ON; 151 // initial state 152 153 // get basic info from driver 154 155 radeon_get_private_data data; 156 data.magic = RADEON_PRIVATE_DATA_MAGIC; 157 158 if (ioctl(device, RADEON_GET_PRIVATE_DATA, &data, 159 sizeof(radeon_get_private_data)) != 0) { 160 free(gInfo); 161 return B_ERROR; 162 } 163 164 AreaCloner sharedCloner; 165 gInfo->shared_info_area = sharedCloner.Clone("radeon hd shared info", 166 (void**)&gInfo->shared_info, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 167 data.shared_info_area); 168 status_t status = sharedCloner.InitCheck(); 169 if (status < B_OK) { 170 free(gInfo); 171 TRACE("%s, failed to create shared area\n", __func__); 172 return status; 173 } 174 175 AreaCloner regsCloner; 176 gInfo->regs_area = regsCloner.Clone("radeon hd regs", 177 (void**)&gInfo->regs, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 178 gInfo->shared_info->registers_area); 179 status = regsCloner.InitCheck(); 180 if (status < B_OK) { 181 free(gInfo); 182 TRACE("%s, failed to create mmio area\n", __func__); 183 return status; 184 } 185 186 gInfo->rom_area = clone_area("radeon hd AtomBIOS", 187 (void**)&gInfo->rom, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 188 gInfo->shared_info->rom_area); 189 190 if (gInfo->rom_area < 0) { 191 TRACE("%s: Clone of AtomBIOS failed!\n", __func__); 192 gInfo->shared_info->has_rom = false; 193 } 194 195 if (gInfo->rom[0] != 0x55 || gInfo->rom[1] != 0xAA) 196 TRACE("%s: didn't find a VGA bios in cloned region!\n", __func__); 197 198 sharedCloner.Keep(); 199 regsCloner.Keep(); 200 201 return B_OK; 202 } 203 204 205 /*! Clean up data common to both primary and cloned accelerant */ 206 static void 207 uninit_common(void) 208 { 209 if (gInfo != NULL) { 210 delete_area(gInfo->regs_area); 211 delete_area(gInfo->shared_info_area); 212 delete_area(gInfo->rom_area); 213 214 gInfo->regs_area = gInfo->shared_info_area = -1; 215 216 // close the file handle ONLY if we're the clone 217 if (gInfo->is_clone) 218 close(gInfo->device); 219 220 free(gInfo); 221 } 222 223 for (uint32 id = 0; id < MAX_DISPLAY; id++) { 224 if (gDisplay[id] != NULL) { 225 free(gDisplay[id]->regs); 226 free(gDisplay[id]); 227 } 228 } 229 230 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) 231 free(gConnector[id]); 232 233 for (uint32 id = 0; id < MAX_GPIO_PINS; id++) 234 free(gGPIOInfo[id]); 235 } 236 237 238 // #pragma mark - public accelerant functions 239 240 241 /*! Init primary accelerant */ 242 status_t 243 radeon_init_accelerant(int device) 244 { 245 TRACE("%s enter\n", __func__); 246 247 status_t status = init_common(device, false); 248 if (status != B_OK) 249 return status; 250 251 radeon_shared_info &info = *gInfo->shared_info; 252 253 init_lock(&info.accelerant_lock, "radeon hd accelerant"); 254 init_lock(&info.engine_lock, "radeon hd engine"); 255 256 radeon_init_bios(gInfo->rom); 257 258 // probe firmware information 259 radeon_gpu_probe(); 260 261 // apply GPU quirks 262 radeon_gpu_quirks(); 263 264 // find GPIO pins from AtomBIOS 265 gpio_populate(); 266 267 // find physical card connectors from AtomBIOS 268 status = connector_probe(); 269 270 if (status != B_OK) { 271 TRACE("%s: falling back to legacy connector probe.\n", __func__); 272 status = connector_probe_legacy(); 273 } 274 275 if (status != B_OK) { 276 TRACE("%s: couldn't detect supported connectors!\n", __func__); 277 return status; 278 } 279 280 // print found connectors 281 debug_connectors(); 282 283 // setup encoders on each connector if needed 284 encoder_init(); 285 286 // program external pll clock 287 pll_external_init(); 288 289 // setup link on any DisplayPort connectors 290 dp_setup_connectors(); 291 292 // detect attached displays 293 status = detect_displays(); 294 //if (status != B_OK) 295 // return status; 296 297 // print found displays 298 debug_displays(); 299 300 // create initial list of video modes 301 status = create_mode_list(); 302 //if (status != B_OK) { 303 // radeon_uninit_accelerant(); 304 // return status; 305 //} 306 307 radeon_gpu_mc_setup(); 308 309 // Set up data crunching + irq rings 310 radeon_gpu_ring_setup(); 311 312 radeon_gpu_ring_boot(RADEON_QUEUE_TYPE_GFX_INDEX); 313 314 TRACE("%s done\n", __func__); 315 return B_OK; 316 } 317 318 319 /*! This function is called for both, the primary accelerant and all of 320 its clones. 321 */ 322 void 323 radeon_uninit_accelerant(void) 324 { 325 TRACE("%s enter\n", __func__); 326 327 gInfo->mode_list = NULL; 328 329 radeon_shared_info &info = *gInfo->shared_info; 330 331 uninit_lock(&info.accelerant_lock); 332 uninit_lock(&info.engine_lock); 333 334 uninit_common(); 335 TRACE("%s done\n", __func__); 336 } 337 338 339 status_t 340 radeon_get_accelerant_device_info(accelerant_device_info* di) 341 { 342 radeon_shared_info &info = *gInfo->shared_info; 343 344 di->version = B_ACCELERANT_VERSION; 345 strcpy(di->name, info.deviceName); 346 347 char chipset[32]; 348 sprintf(chipset, "%s", gInfo->shared_info->chipsetName); 349 strcpy(di->chipset, chipset); 350 351 // add flags onto chipset name 352 if ((info.chipsetFlags & CHIP_IGP) != 0) 353 strcat(di->chipset, " IGP"); 354 if ((info.chipsetFlags & CHIP_MOBILE) != 0) 355 strcat(di->chipset, " Mobile"); 356 if ((info.chipsetFlags & CHIP_APU) != 0) 357 strcat(di->chipset, " APU"); 358 359 strcpy(di->serial_no, "None" ); 360 361 di->memory = gInfo->shared_info->graphics_memory_size; 362 return B_OK; 363 } 364