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