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 gInfo->overlay_registers = (struct overlay_registers*) 145 (gInfo->shared_info->graphics_memory 146 + gInfo->shared_info->overlay_offset); 147 148 if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x)) { 149 // allocate some extra memory for the 3D context 150 if (intel_allocate_memory(INTEL_i965_3D_CONTEXT_SIZE, 151 B_APERTURE_NON_RESERVED, gInfo->context_base) == B_OK) { 152 gInfo->context_offset = gInfo->context_base 153 - (addr_t)gInfo->shared_info->graphics_memory; 154 } 155 } 156 157 return B_OK; 158 } 159 160 161 /*! Clean up data common to both primary and cloned accelerant */ 162 static void 163 uninit_common(void) 164 { 165 intel_free_memory(gInfo->context_base); 166 167 delete_area(gInfo->regs_area); 168 delete_area(gInfo->shared_info_area); 169 170 gInfo->regs_area = gInfo->shared_info_area = -1; 171 172 // close the file handle ONLY if we're the clone 173 if (gInfo->is_clone) 174 close(gInfo->device); 175 176 free(gInfo); 177 } 178 179 180 // #pragma mark - public accelerant functions 181 182 183 /*! Init primary accelerant */ 184 status_t 185 intel_init_accelerant(int device) 186 { 187 CALLED(); 188 189 status_t status = init_common(device, false); 190 if (status != B_OK) 191 return status; 192 193 intel_shared_info &info = *gInfo->shared_info; 194 195 init_lock(&info.accelerant_lock, "intel extreme accelerant"); 196 init_lock(&info.engine_lock, "intel extreme engine"); 197 198 setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer"); 199 200 // determine head depending on what's already enabled from the BIOS 201 // TODO: it would be nicer to retrieve this data via DDC - else the 202 // display is gone for good if the BIOS decides to only show the 203 // picture on the connected analog monitor! 204 gInfo->head_mode = 0; 205 if (read32(INTEL_DISPLAY_B_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED) 206 gInfo->head_mode |= HEAD_MODE_B_DIGITAL; 207 if (read32(INTEL_DISPLAY_A_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED) 208 gInfo->head_mode |= HEAD_MODE_A_ANALOG; 209 210 uint32 lvds = read32(INTEL_DISPLAY_LVDS_PORT); 211 212 // If we have an enabled display pipe we save the passed information and 213 // assume it is the valid panel size.. 214 // Later we query for proper EDID info if it exists, or figure something 215 // else out. (Default modes, etc.) 216 bool hasPCH = gInfo->shared_info->device_type.HasPlatformControlHub(); 217 if ((hasPCH && (lvds & PCH_LVDS_DETECTED) != 0) 218 || (!hasPCH && (lvds & DISPLAY_PIPE_ENABLED) != 0)) { 219 save_lvds_mode(); 220 gInfo->head_mode |= HEAD_MODE_LVDS_PANEL; 221 } 222 223 TRACE("head detected: %#x\n", gInfo->head_mode); 224 TRACE("adpa: %08lx, dova: %08lx, dovb: %08lx, lvds: %08lx\n", 225 read32(INTEL_DISPLAY_A_ANALOG_PORT), 226 read32(INTEL_DISPLAY_A_DIGITAL_PORT), 227 read32(INTEL_DISPLAY_B_DIGITAL_PORT), 228 read32(INTEL_DISPLAY_LVDS_PORT)); 229 230 status = create_mode_list(); 231 if (status != B_OK) { 232 uninit_common(); 233 return status; 234 } 235 236 return B_OK; 237 } 238 239 240 ssize_t 241 intel_accelerant_clone_info_size(void) 242 { 243 CALLED(); 244 // clone info is device name, so return its maximum size 245 return B_PATH_NAME_LENGTH; 246 } 247 248 249 void 250 intel_get_accelerant_clone_info(void* info) 251 { 252 CALLED(); 253 ioctl(gInfo->device, INTEL_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH); 254 } 255 256 257 status_t 258 intel_clone_accelerant(void* info) 259 { 260 CALLED(); 261 262 // create full device name 263 char path[B_PATH_NAME_LENGTH]; 264 strcpy(path, "/dev/"); 265 #ifdef __HAIKU__ 266 strlcat(path, (const char*)info, sizeof(path)); 267 #else 268 strcat(path, (const char*)info); 269 #endif 270 271 int fd = open(path, B_READ_WRITE); 272 if (fd < 0) 273 return errno; 274 275 status_t status = init_common(fd, true); 276 if (status != B_OK) 277 goto err1; 278 279 // get read-only clone of supported display modes 280 status = gInfo->mode_list_area = clone_area( 281 "intel extreme cloned modes", (void**)&gInfo->mode_list, 282 B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area); 283 if (status < B_OK) 284 goto err2; 285 286 return B_OK; 287 288 err2: 289 uninit_common(); 290 err1: 291 close(fd); 292 return status; 293 } 294 295 296 /*! This function is called for both, the primary accelerant and all of 297 its clones. 298 */ 299 void 300 intel_uninit_accelerant(void) 301 { 302 CALLED(); 303 304 // delete accelerant instance data 305 delete_area(gInfo->mode_list_area); 306 gInfo->mode_list = NULL; 307 308 intel_shared_info &info = *gInfo->shared_info; 309 310 uninit_lock(&info.accelerant_lock); 311 uninit_lock(&info.engine_lock); 312 313 uninit_ring_buffer(info.primary_ring_buffer); 314 315 uninit_common(); 316 } 317 318 319 status_t 320 intel_get_accelerant_device_info(accelerant_device_info* info) 321 { 322 CALLED(); 323 324 info->version = B_ACCELERANT_VERSION; 325 strcpy(info->name, gInfo->shared_info->device_type.InFamily(INTEL_TYPE_7xx) 326 ? "Intel Extreme Graphics 1" : "Intel Extreme Graphics 2"); 327 strcpy(info->chipset, gInfo->shared_info->device_identifier); 328 strcpy(info->serial_no, "None"); 329 330 info->memory = gInfo->shared_info->graphics_memory_size; 331 info->dac_speed = gInfo->shared_info->pll_info.max_frequency; 332 333 return B_OK; 334 } 335 336 337 sem_id 338 intel_accelerant_retrace_semaphore() 339 { 340 CALLED(); 341 return gInfo->shared_info->vblank_sem; 342 } 343 344