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