1 /* 2 * Copyright 2006-2010, 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 */ 8 9 10 #include "accelerant_protos.h" 11 #include "accelerant.h" 12 13 #include "utility.h" 14 15 #include <Debug.h> 16 #include <errno.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <unistd.h> 20 #include <syslog.h> 21 22 #include <AGP.h> 23 24 25 #undef TRACE 26 #define TRACE_ACCELERANT 27 #ifdef TRACE_ACCELERANT 28 # define TRACE(x...) _sPrintf("intel_extreme accelerant:" x) 29 #else 30 # define TRACE(x...) 31 #endif 32 33 #define ERROR(x...) _sPrintf("intel_extreme accelerant: " x) 34 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) 35 36 37 struct accelerant_info* gInfo; 38 39 40 class AreaCloner { 41 public: 42 AreaCloner(); 43 ~AreaCloner(); 44 45 area_id Clone(const char* name, void** _address, 46 uint32 spec, uint32 protection, 47 area_id sourceArea); 48 status_t InitCheck() 49 { return fArea < 0 ? (status_t)fArea : B_OK; } 50 void Keep(); 51 52 private: 53 area_id fArea; 54 }; 55 56 57 AreaCloner::AreaCloner() 58 : 59 fArea(-1) 60 { 61 } 62 63 64 AreaCloner::~AreaCloner() 65 { 66 if (fArea >= 0) 67 delete_area(fArea); 68 } 69 70 71 area_id 72 AreaCloner::Clone(const char* name, void** _address, uint32 spec, 73 uint32 protection, area_id sourceArea) 74 { 75 fArea = clone_area(name, _address, spec, protection, sourceArea); 76 return fArea; 77 } 78 79 80 void 81 AreaCloner::Keep() 82 { 83 fArea = -1; 84 } 85 86 87 // #pragma mark - 88 89 90 /*! This is the common accelerant_info initializer. It is called by 91 both, the first accelerant and all clones. 92 */ 93 static status_t 94 init_common(int device, bool isClone) 95 { 96 // initialize global accelerant info structure 97 98 gInfo = (accelerant_info*)malloc(sizeof(accelerant_info)); 99 if (gInfo == NULL) 100 return B_NO_MEMORY; 101 102 memset(gInfo, 0, sizeof(accelerant_info)); 103 104 gInfo->is_clone = isClone; 105 gInfo->device = device; 106 107 // get basic info from driver 108 109 intel_get_private_data data; 110 data.magic = INTEL_PRIVATE_DATA_MAGIC; 111 112 if (ioctl(device, INTEL_GET_PRIVATE_DATA, &data, 113 sizeof(intel_get_private_data)) != 0) { 114 free(gInfo); 115 return B_ERROR; 116 } 117 118 AreaCloner sharedCloner; 119 gInfo->shared_info_area = sharedCloner.Clone("intel extreme shared info", 120 (void**)&gInfo->shared_info, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 121 data.shared_info_area); 122 status_t status = sharedCloner.InitCheck(); 123 if (status < B_OK) { 124 free(gInfo); 125 return status; 126 } 127 128 AreaCloner regsCloner; 129 gInfo->regs_area = regsCloner.Clone("intel extreme regs", 130 (void**)&gInfo->registers, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 131 gInfo->shared_info->registers_area); 132 status = regsCloner.InitCheck(); 133 if (status < B_OK) { 134 free(gInfo); 135 return status; 136 } 137 138 sharedCloner.Keep(); 139 regsCloner.Keep(); 140 141 // The overlay registers, hardware status, and cursor memory share 142 // a single area with the shared_info 143 144 if (gInfo->shared_info->overlay_offset != 0) { 145 gInfo->overlay_registers = (struct overlay_registers*) 146 (gInfo->shared_info->graphics_memory 147 + gInfo->shared_info->overlay_offset); 148 } 149 150 if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x)) { 151 // allocate some extra memory for the 3D context 152 if (intel_allocate_memory(INTEL_i965_3D_CONTEXT_SIZE, 153 B_APERTURE_NON_RESERVED, gInfo->context_base) == B_OK) { 154 gInfo->context_offset = gInfo->context_base 155 - (addr_t)gInfo->shared_info->graphics_memory; 156 } 157 } 158 159 return B_OK; 160 } 161 162 163 /*! Clean up data common to both primary and cloned accelerant */ 164 static void 165 uninit_common(void) 166 { 167 intel_free_memory(gInfo->context_base); 168 169 delete_area(gInfo->regs_area); 170 delete_area(gInfo->shared_info_area); 171 172 gInfo->regs_area = gInfo->shared_info_area = -1; 173 174 // close the file handle ONLY if we're the clone 175 if (gInfo->is_clone) 176 close(gInfo->device); 177 178 free(gInfo); 179 } 180 181 182 // #pragma mark - public accelerant functions 183 184 185 /*! Init primary accelerant */ 186 status_t 187 intel_init_accelerant(int device) 188 { 189 CALLED(); 190 191 status_t status = init_common(device, false); 192 if (status != B_OK) 193 return status; 194 195 intel_shared_info &info = *gInfo->shared_info; 196 197 init_lock(&info.accelerant_lock, "intel extreme accelerant"); 198 init_lock(&info.engine_lock, "intel extreme engine"); 199 200 setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer"); 201 202 // determine head depending on what's already enabled from the BIOS 203 // TODO: it would be nicer to retrieve this data via DDC - else the 204 // display is gone for good if the BIOS decides to only show the 205 // picture on the connected analog monitor! 206 gInfo->head_mode = 0; 207 if (read32(INTEL_DISPLAY_B_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED) 208 gInfo->head_mode |= HEAD_MODE_B_DIGITAL; 209 if (read32(INTEL_DISPLAY_A_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED) 210 gInfo->head_mode |= HEAD_MODE_A_ANALOG; 211 212 uint32 lvds = read32(INTEL_DISPLAY_LVDS_PORT); 213 214 // If we have an enabled display pipe we save the passed information and 215 // assume it is the valid panel size.. 216 // Later we query for proper EDID info if it exists, or figure something 217 // else out. (Default modes, etc.) 218 bool hasPCH = gInfo->shared_info->device_type.HasPlatformControlHub(); 219 if ((hasPCH && (lvds & PCH_LVDS_DETECTED) != 0) 220 || (!hasPCH && (lvds & DISPLAY_PIPE_ENABLED) != 0)) { 221 save_lvds_mode(); 222 gInfo->head_mode |= HEAD_MODE_LVDS_PANEL; 223 } 224 225 TRACE("head detected: %#x\n", gInfo->head_mode); 226 TRACE("adpa: %08lx, dova: %08lx, dovb: %08lx, lvds: %08lx\n", 227 read32(INTEL_DISPLAY_A_ANALOG_PORT), 228 read32(INTEL_DISPLAY_A_DIGITAL_PORT), 229 read32(INTEL_DISPLAY_B_DIGITAL_PORT), 230 read32(INTEL_DISPLAY_LVDS_PORT)); 231 232 status = create_mode_list(); 233 if (status != B_OK) { 234 uninit_common(); 235 return status; 236 } 237 238 return B_OK; 239 } 240 241 242 ssize_t 243 intel_accelerant_clone_info_size(void) 244 { 245 CALLED(); 246 // clone info is device name, so return its maximum size 247 return B_PATH_NAME_LENGTH; 248 } 249 250 251 void 252 intel_get_accelerant_clone_info(void* info) 253 { 254 CALLED(); 255 ioctl(gInfo->device, INTEL_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH); 256 } 257 258 259 status_t 260 intel_clone_accelerant(void* info) 261 { 262 CALLED(); 263 264 // create full device name 265 char path[B_PATH_NAME_LENGTH]; 266 strcpy(path, "/dev/"); 267 #ifdef __HAIKU__ 268 strlcat(path, (const char*)info, sizeof(path)); 269 #else 270 strcat(path, (const char*)info); 271 #endif 272 273 int fd = open(path, B_READ_WRITE); 274 if (fd < 0) 275 return errno; 276 277 status_t status = init_common(fd, true); 278 if (status != B_OK) 279 goto err1; 280 281 // get read-only clone of supported display modes 282 status = gInfo->mode_list_area = clone_area( 283 "intel extreme cloned modes", (void**)&gInfo->mode_list, 284 B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area); 285 if (status < B_OK) 286 goto err2; 287 288 return B_OK; 289 290 err2: 291 uninit_common(); 292 err1: 293 close(fd); 294 return status; 295 } 296 297 298 /*! This function is called for both, the primary accelerant and all of 299 its clones. 300 */ 301 void 302 intel_uninit_accelerant(void) 303 { 304 CALLED(); 305 306 // delete accelerant instance data 307 delete_area(gInfo->mode_list_area); 308 gInfo->mode_list = NULL; 309 310 intel_shared_info &info = *gInfo->shared_info; 311 312 uninit_lock(&info.accelerant_lock); 313 uninit_lock(&info.engine_lock); 314 315 uninit_ring_buffer(info.primary_ring_buffer); 316 317 uninit_common(); 318 } 319 320 321 status_t 322 intel_get_accelerant_device_info(accelerant_device_info* info) 323 { 324 CALLED(); 325 326 info->version = B_ACCELERANT_VERSION; 327 strcpy(info->name, gInfo->shared_info->device_type.InFamily(INTEL_TYPE_7xx) 328 ? "Intel Extreme Graphics 1" : "Intel Extreme Graphics 2"); 329 strcpy(info->chipset, gInfo->shared_info->device_identifier); 330 strcpy(info->serial_no, "None"); 331 332 info->memory = gInfo->shared_info->graphics_memory_size; 333 info->dac_speed = gInfo->shared_info->pll_info.max_frequency; 334 335 return B_OK; 336 } 337 338 339 sem_id 340 intel_accelerant_retrace_semaphore() 341 { 342 CALLED(); 343 return gInfo->shared_info->vblank_sem; 344 } 345 346