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