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 136 // malloc for card gpio pin information 137 for (uint32 id = 0; id < MAX_GPIO_PINS; 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 231 for (uint32 id = 0; id < MAX_GPIO_PINS; id++) 232 free(gGPIOInfo[id]); 233 } 234 235 236 // #pragma mark - public accelerant functions 237 238 239 /*! Init primary accelerant */ 240 status_t 241 radeon_init_accelerant(int device) 242 { 243 TRACE("%s enter\n", __func__); 244 245 status_t status = init_common(device, false); 246 if (status != B_OK) 247 return status; 248 249 radeon_shared_info &info = *gInfo->shared_info; 250 251 init_lock(&info.accelerant_lock, "radeon hd accelerant"); 252 init_lock(&info.engine_lock, "radeon hd engine"); 253 254 radeon_init_bios(gInfo->rom); 255 256 // probe firmware information 257 radeon_gpu_probe(); 258 259 // find GPIO pins from AtomBIOS 260 gpio_populate(); 261 262 // find physical card connectors from AtomBIOS 263 status = connector_probe(); 264 265 if (status != B_OK) { 266 TRACE("%s: falling back to legacy connector probe.\n", __func__); 267 status = connector_probe_legacy(); 268 } 269 270 if (status != B_OK) { 271 TRACE("%s: couldn't detect supported connectors!\n", __func__); 272 return status; 273 } 274 275 // print found connectors 276 debug_connectors(); 277 278 // setup encoders on each connector if needed 279 encoder_init(); 280 281 // program external pll clock 282 pll_external_init(); 283 284 // setup link on any DisplayPort connectors 285 dp_setup_connectors(); 286 287 // detect attached displays 288 status = detect_displays(); 289 //if (status != B_OK) 290 // return status; 291 292 // print found displays 293 debug_displays(); 294 295 // create initial list of video modes 296 status = create_mode_list(); 297 //if (status != B_OK) { 298 // radeon_uninit_accelerant(); 299 // return status; 300 //} 301 302 radeon_gpu_mc_setup(); 303 304 // Set up data crunching + irq rings 305 radeon_gpu_ring_setup(); 306 307 radeon_gpu_ring_boot(RADEON_QUEUE_TYPE_GFX_INDEX); 308 309 TRACE("%s done\n", __func__); 310 return B_OK; 311 } 312 313 314 /*! This function is called for both, the primary accelerant and all of 315 its clones. 316 */ 317 void 318 radeon_uninit_accelerant(void) 319 { 320 TRACE("%s enter\n", __func__); 321 322 gInfo->mode_list = NULL; 323 324 radeon_shared_info &info = *gInfo->shared_info; 325 326 uninit_lock(&info.accelerant_lock); 327 uninit_lock(&info.engine_lock); 328 329 uninit_common(); 330 TRACE("%s done\n", __func__); 331 } 332 333 334 status_t 335 radeon_get_accelerant_device_info(accelerant_device_info* di) 336 { 337 radeon_shared_info &info = *gInfo->shared_info; 338 339 di->version = B_ACCELERANT_VERSION; 340 strcpy(di->name, info.deviceName); 341 342 char chipset[32]; 343 sprintf(chipset, "%s", gInfo->shared_info->chipsetName); 344 strcpy(di->chipset, chipset); 345 346 // add flags onto chipset name 347 if ((info.chipsetFlags & CHIP_IGP) != 0) 348 strcat(di->chipset, " IGP"); 349 if ((info.chipsetFlags & CHIP_MOBILE) != 0) 350 strcat(di->chipset, " Mobile"); 351 if ((info.chipsetFlags & CHIP_APU) != 0) 352 strcat(di->chipset, " APU"); 353 354 strcpy(di->serial_no, "None" ); 355 356 di->memory = gInfo->shared_info->graphics_memory_size; 357 return B_OK; 358 } 359