2 * Copyright 2006-2016, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Axel Dörfler, axeld@pinc-software.de
10 #include "accelerant_protos.h"
11 #include "accelerant.h"
28 #define TRACE_ACCELERANT
29 #ifdef TRACE_ACCELERANT
30 # define TRACE(x...) _sPrintf("intel_extreme: " x)
35 #define ERROR(x...) _sPrintf("intel_extreme: " x)
36 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
39 struct accelerant_info
* gInfo
;
48 area_id
Clone(const char* name
, void** _address
,
49 uint32 spec
, uint32 protection
,
52 { return fArea
< 0 ? (status_t
)fArea
: B_OK
; }
60 AreaCloner::AreaCloner()
67 AreaCloner::~AreaCloner()
75 AreaCloner::Clone(const char* name
, void** _address
, uint32 spec
,
76 uint32 protection
, area_id sourceArea
)
78 fArea
= clone_area(name
, _address
, spec
, protection
, sourceArea
);
93 // intel_reg --mmio=ie-0001.bin --devid=27a2 dump
99 sprintf(filename
, "/boot/system/cache/tmp/ie-%04" B_PRId32
".bin",
102 ERROR("%s: Taking register dump #%" B_PRId32
"\n", __func__
, gDumpCount
);
104 int fd
= open(filename
, O_CREAT
| O_WRONLY
, 0644);
107 for (int32 i
= 0; i
< 0x80000; i
+= sizeof(data
)) {
109 //int length = sprintf(line, "%05" B_PRIx32 ": "
110 // "%08" B_PRIx32 " %08" B_PRIx32 " %08" B_PRIx32 " %08" B_PRIx32 "\n",
111 // i, read32(i), read32(i + 4), read32(i + 8), read32(i + 12));
113 write(fd
, &data
, sizeof(data
));
123 /*! This is the common accelerant_info initializer. It is called by
124 both, the first accelerant and all clones.
127 init_common(int device
, bool isClone
)
129 // initialize global accelerant info structure
131 // Number of register dumps we have... taken.
134 gInfo
= (accelerant_info
*)malloc(sizeof(accelerant_info
));
138 memset(gInfo
, 0, sizeof(accelerant_info
));
140 gInfo
->is_clone
= isClone
;
141 gInfo
->device
= device
;
143 // get basic info from driver
145 intel_get_private_data data
;
146 data
.magic
= INTEL_PRIVATE_DATA_MAGIC
;
148 if (ioctl(device
, INTEL_GET_PRIVATE_DATA
, &data
,
149 sizeof(intel_get_private_data
)) != 0) {
154 AreaCloner sharedCloner
;
155 gInfo
->shared_info_area
= sharedCloner
.Clone("intel extreme shared info",
156 (void**)&gInfo
->shared_info
, B_ANY_ADDRESS
, B_READ_AREA
| B_WRITE_AREA
,
157 data
.shared_info_area
);
158 status_t status
= sharedCloner
.InitCheck();
164 AreaCloner regsCloner
;
165 gInfo
->regs_area
= regsCloner
.Clone("intel extreme regs",
166 (void**)&gInfo
->registers
, B_ANY_ADDRESS
, B_READ_AREA
| B_WRITE_AREA
,
167 gInfo
->shared_info
->registers_area
);
168 status
= regsCloner
.InitCheck();
177 // The overlay registers, hardware status, and cursor memory share
178 // a single area with the shared_info
180 if (gInfo
->shared_info
->overlay_offset
!= 0) {
181 gInfo
->overlay_registers
= (struct overlay_registers
*)
182 (gInfo
->shared_info
->graphics_memory
183 + gInfo
->shared_info
->overlay_offset
);
186 if (gInfo
->shared_info
->device_type
.InGroup(INTEL_GROUP_96x
)) {
187 // allocate some extra memory for the 3D context
188 if (intel_allocate_memory(INTEL_i965_3D_CONTEXT_SIZE
,
189 B_APERTURE_NON_RESERVED
, gInfo
->context_base
) == B_OK
) {
190 gInfo
->context_offset
= gInfo
->context_base
191 - (addr_t
)gInfo
->shared_info
->graphics_memory
;
195 gInfo
->pipe_count
= 0;
197 // Allocate all of our pipes
198 for (int i
= 0; i
< MAX_PIPES
; i
++) {
201 gInfo
->pipes
[i
] = new(std::nothrow
) Pipe(INTEL_PIPE_A
);
204 gInfo
->pipes
[i
] = new(std::nothrow
) Pipe(INTEL_PIPE_B
);
207 ERROR("%s: Unknown pipe %d\n", __func__
, i
);
209 if (gInfo
->pipes
[i
] == NULL
)
210 ERROR("%s: Error allocating pipe %d\n", __func__
, i
);
219 /*! Clean up data common to both primary and cloned accelerant */
223 intel_free_memory(gInfo
->context_base
);
225 delete_area(gInfo
->regs_area
);
226 delete_area(gInfo
->shared_info_area
);
228 gInfo
->regs_area
= gInfo
->shared_info_area
= -1;
230 // close the file handle ONLY if we're the clone
232 close(gInfo
->device
);
241 if (gInfo
->port_count
== 0) {
242 TRACE("%s: No ports connected\n", __func__
);
246 TRACE("%s: Connected ports: (port_count: %" B_PRIu32
")\n", __func__
,
249 for (uint32 i
= 0; i
< gInfo
->port_count
; i
++) {
250 Port
* port
= gInfo
->ports
[i
];
252 TRACE("port %" B_PRIu32
":: INVALID ALLOC!\n", i
);
255 TRACE("port %" B_PRIu32
": %s %s\n", i
, port
->PortName(),
256 port
->IsConnected() ? "connected" : "disconnected");
262 has_connected_port(port_index portIndex
, uint32 type
)
264 for (uint32 i
= 0; i
< gInfo
->port_count
; i
++) {
265 Port
* port
= gInfo
->ports
[i
];
266 if (type
!= INTEL_PORT_TYPE_ANY
&& port
->Type() != type
)
268 if (portIndex
!= INTEL_PORT_ANY
&& port
->PortIndex() != portIndex
)
281 // Try to determine what ports to use. We use the following heuristic:
282 // * Check for DisplayPort, these can be more or less detected reliably.
283 // * Check for HDMI, it'll fail on devices not having HDMI for us to fall
285 // * Assume DVI B if no HDMI and no DisplayPort is present, confirmed by
286 // reading EDID in the IsConnected() call.
287 // * Check for analog if possible (there's a detection bit on PCH),
288 // otherwise the assumed presence is confirmed by reading EDID in
291 TRACE("adpa: %08" B_PRIx32
"\n", read32(INTEL_ANALOG_PORT
));
292 TRACE("dova: %08" B_PRIx32
", dovb: %08" B_PRIx32
293 ", dovc: %08" B_PRIx32
"\n", read32(INTEL_DIGITAL_PORT_A
),
294 read32(INTEL_DIGITAL_PORT_B
), read32(INTEL_DIGITAL_PORT_C
));
295 TRACE("lvds: %08" B_PRIx32
"\n", read32(INTEL_DIGITAL_LVDS_PORT
));
297 bool foundLVDS
= false;
299 gInfo
->port_count
= 0;
300 for (int i
= INTEL_PORT_A
; i
<= INTEL_PORT_D
; i
++) {
301 Port
* displayPort
= new(std::nothrow
) DisplayPort((port_index
)i
);
302 if (displayPort
== NULL
)
305 if (displayPort
->IsConnected())
306 gInfo
->ports
[gInfo
->port_count
++] = displayPort
;
311 // Digital Display Interface
312 if (gInfo
->shared_info
->device_type
.HasDDI()) {
313 for (int i
= INTEL_PORT_A
; i
<= INTEL_PORT_E
; i
++) {
315 = new(std::nothrow
) DigitalDisplayInterface((port_index
)i
);
320 if (ddiPort
->IsConnected())
321 gInfo
->ports
[gInfo
->port_count
++] = ddiPort
;
327 // Ensure DP_A isn't already taken (or DDI)
328 if (!has_connected_port((port_index
)INTEL_PORT_A
, INTEL_PORT_TYPE_ANY
)) {
329 // also always try eDP, it'll also just fail if not applicable
330 Port
* eDPPort
= new(std::nothrow
) EmbeddedDisplayPort();
333 if (eDPPort
->IsConnected())
334 gInfo
->ports
[gInfo
->port_count
++] = eDPPort
;
339 for (int i
= INTEL_PORT_B
; i
<= INTEL_PORT_D
; i
++) {
340 if (has_connected_port((port_index
)i
, INTEL_PORT_TYPE_ANY
)) {
341 // Ensure port not already claimed by something like DDI
345 Port
* hdmiPort
= new(std::nothrow
) HDMIPort((port_index
)i
);
346 if (hdmiPort
== NULL
)
349 if (hdmiPort
->IsConnected())
350 gInfo
->ports
[gInfo
->port_count
++] = hdmiPort
;
355 if (!has_connected_port(INTEL_PORT_ANY
, INTEL_PORT_TYPE_ANY
)) {
356 // there's neither DisplayPort nor HDMI so far, assume DVI B
357 Port
* dviPort
= new(std::nothrow
) DigitalPort(INTEL_PORT_B
);
361 if (dviPort
->IsConnected()) {
362 gInfo
->ports
[gInfo
->port_count
++] = dviPort
;
363 gInfo
->head_mode
|= HEAD_MODE_B_DIGITAL
;
368 // always try the LVDS port, it'll simply fail if not applicable
369 Port
* lvdsPort
= new(std::nothrow
) LVDSPort();
370 if (lvdsPort
== NULL
)
372 if (lvdsPort
->IsConnected()) {
374 gInfo
->ports
[gInfo
->port_count
++] = lvdsPort
;
375 gInfo
->head_mode
|= HEAD_MODE_LVDS_PANEL
;
376 gInfo
->head_mode
|= HEAD_MODE_A_ANALOG
;
377 // FIXME this should not be set, but without it, LVDS modesetting
378 // doesn't work on SandyBridge. Find out why it makes a difference.
379 gInfo
->head_mode
|= HEAD_MODE_B_DIGITAL
;
383 // then finally always try the analog port
384 Port
* analogPort
= new(std::nothrow
) AnalogPort();
385 if (analogPort
== NULL
)
387 if (analogPort
->IsConnected()) {
388 gInfo
->ports
[gInfo
->port_count
++] = analogPort
;
389 gInfo
->head_mode
|= HEAD_MODE_A_ANALOG
;
393 if (gInfo
->port_count
== 0)
396 // Activate reference clocks if needed
397 if (gInfo
->shared_info
->pch_info
== INTEL_PCH_IBX
398 || gInfo
->shared_info
->pch_info
== INTEL_PCH_CPT
) {
399 // XXX: Is LVDS the same as Panel?
400 refclk_activate_ilk(foundLVDS
);
403 } else if (gInfo->shared_info->pch_info == INTEL_PCH_LPT) {
404 // TODO: Some kind of stepped bend thing?
405 // only needed for vga
406 refclk_activate_lpt(foundLVDS);
417 // TODO: At some point we should "group" ports to pipes with the same mode.
418 // You can drive multiple ports from a single pipe as long as the mode is
419 // the same. For the moment we could get displays with the wrong pipes
420 // assigned when the count is > 1;
423 for (uint32 i
= 0; i
< gInfo
->port_count
; i
++) {
424 if (gInfo
->ports
[i
] == NULL
)
427 pipe_index preference
= gInfo
->ports
[i
]->PipePreference();
428 if (preference
!= INTEL_PIPE_ANY
) {
429 // Some ports *really* need to be assigned a pipe due to
430 // implementation bugs.
431 int index
= (preference
== INTEL_PIPE_B
) ? 1 : 0;
432 gInfo
->ports
[i
]->SetPipe(gInfo
->pipes
[index
]);
436 if (gInfo
->ports
[i
]->IsConnected()) {
437 if (current
>= gInfo
->pipe_count
) {
438 ERROR("%s: No pipes left to assign to port %s!\n", __func__
,
439 gInfo
->ports
[i
]->PortName());
443 gInfo
->ports
[i
]->SetPipe(gInfo
->pipes
[current
]);
452 // #pragma mark - public accelerant functions
455 /*! Init primary accelerant */
457 intel_init_accelerant(int device
)
461 status_t status
= init_common(device
, false);
465 intel_shared_info
&info
= *gInfo
->shared_info
;
467 init_lock(&info
.accelerant_lock
, "intel extreme accelerant");
468 init_lock(&info
.engine_lock
, "intel extreme engine");
470 setup_ring_buffer(info
.primary_ring_buffer
, "intel primary ring buffer");
472 TRACE("pipe control for: 0x%" B_PRIx32
" 0x%" B_PRIx32
"\n",
473 read32(INTEL_PIPE_CONTROL
), read32(INTEL_PIPE_CONTROL
));
476 status
= probe_ports();
478 // On TRACE, dump ports and states
482 ERROR("Warning: zero active displays were found!\n");
484 status
= assign_pipes();
487 ERROR("Warning: error while assigning pipes!\n");
489 status
= create_mode_list();
490 if (status
!= B_OK
) {
500 intel_accelerant_clone_info_size(void)
503 // clone info is device name, so return its maximum size
504 return B_PATH_NAME_LENGTH
;
509 intel_get_accelerant_clone_info(void* info
)
512 ioctl(gInfo
->device
, INTEL_GET_DEVICE_NAME
, info
, B_PATH_NAME_LENGTH
);
517 intel_clone_accelerant(void* info
)
521 // create full device name
522 char path
[B_PATH_NAME_LENGTH
];
523 strcpy(path
, "/dev/");
525 strlcat(path
, (const char*)info
, sizeof(path
));
527 strcat(path
, (const char*)info
);
530 int fd
= open(path
, B_READ_WRITE
);
534 status_t status
= init_common(fd
, true);
538 // get read-only clone of supported display modes
539 status
= gInfo
->mode_list_area
= clone_area(
540 "intel extreme cloned modes", (void**)&gInfo
->mode_list
,
541 B_ANY_ADDRESS
, B_READ_AREA
, gInfo
->shared_info
->mode_list_area
);
555 /*! This function is called for both, the primary accelerant and all of
559 intel_uninit_accelerant(void)
563 // delete accelerant instance data
564 delete_area(gInfo
->mode_list_area
);
565 gInfo
->mode_list
= NULL
;
567 intel_shared_info
&info
= *gInfo
->shared_info
;
569 uninit_lock(&info
.accelerant_lock
);
570 uninit_lock(&info
.engine_lock
);
572 uninit_ring_buffer(info
.primary_ring_buffer
);
579 intel_get_accelerant_device_info(accelerant_device_info
* info
)
583 info
->version
= B_ACCELERANT_VERSION
;
585 DeviceType
* type
= &gInfo
->shared_info
->device_type
;
587 if (type
->InFamily(INTEL_FAMILY_7xx
) || type
->InFamily(INTEL_FAMILY_8xx
))
588 strcpy(info
->name
, "Intel Extreme");
589 else if (type
->InFamily(INTEL_FAMILY_9xx
))
590 strcpy(info
->name
, "Intel GMA");
591 else if (type
->InFamily(INTEL_FAMILY_POVR
))
592 strcpy(info
->name
, "Intel PowerVR");
593 else if (type
->InFamily(INTEL_FAMILY_SOC0
))
594 strcpy(info
->name
, "Intel Atom");
595 else if (type
->InFamily(INTEL_FAMILY_SER5
))
596 strcpy(info
->name
, "Intel HD/Iris");
598 strcpy(info
->name
, "Intel");
600 strcpy(info
->chipset
, gInfo
->shared_info
->device_identifier
);
601 strcpy(info
->serial_no
, "None");
603 info
->memory
= gInfo
->shared_info
->graphics_memory_size
;
604 info
->dac_speed
= gInfo
->shared_info
->pll_info
.max_frequency
;
611 intel_accelerant_retrace_semaphore()
614 return gInfo
->shared_info
->vblank_sem
;