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