1 /*
2 * Copyright 2006-2018, 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 IV, kallisti5@unixzen.com
8 * Adrien Destugues, pulkomandy@pulkomandy.tk
9 */
10
11
12 #include "intel_extreme.h"
13
14 #include <unistd.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <errno.h>
18
19 #include <AreaKeeper.h>
20 #include <boot_item.h>
21 #include <driver_settings.h>
22 #include <util/kernel_cpp.h>
23
24 #include <vesa_info.h>
25
26 #include "driver.h"
27 #include "power.h"
28 #include "utility.h"
29
30
31 #define TRACE_INTELEXTREME
32 #ifdef TRACE_INTELEXTREME
33 # define TRACE(x...) dprintf("intel_extreme: " x)
34 #else
35 # define TRACE(x) ;
36 #endif
37
38 #define ERROR(x...) dprintf("intel_extreme: " x)
39 #define CALLED(x...) TRACE("intel_extreme: CALLED %s\n", __PRETTY_FUNCTION__)
40
41
42 static void
init_overlay_registers(overlay_registers * _registers)43 init_overlay_registers(overlay_registers* _registers)
44 {
45 user_memset(_registers, 0, B_PAGE_SIZE);
46
47 overlay_registers registers;
48 memset(®isters, 0, sizeof(registers));
49 registers.contrast_correction = 0x48;
50 registers.saturation_cos_correction = 0x9a;
51 // this by-passes contrast and saturation correction
52
53 user_memcpy(_registers, ®isters, sizeof(overlay_registers));
54 }
55
56
57 static void
read_settings(bool & hardwareCursor)58 read_settings(bool &hardwareCursor)
59 {
60 hardwareCursor = false;
61
62 void* settings = load_driver_settings("intel_extreme");
63 if (settings != NULL) {
64 hardwareCursor = get_driver_boolean_parameter(settings,
65 "hardware_cursor", true, true);
66
67 unload_driver_settings(settings);
68 }
69 }
70
71
72 static int32
release_vblank_sem(intel_info & info)73 release_vblank_sem(intel_info &info)
74 {
75 int32 count;
76 if (get_sem_count(info.shared_info->vblank_sem, &count) == B_OK
77 && count < 0) {
78 release_sem_etc(info.shared_info->vblank_sem, -count,
79 B_DO_NOT_RESCHEDULE);
80 return B_INVOKE_SCHEDULER;
81 }
82
83 return B_HANDLED_INTERRUPT;
84 }
85
86
87 static void
gen8_enable_interrupts(intel_info & info,pipe_index pipe,bool enable)88 gen8_enable_interrupts(intel_info& info, pipe_index pipe, bool enable)
89 {
90 ASSERT(pipe != INTEL_PIPE_ANY);
91 ASSERT(info.device_type.Generation() >= 12 || pipe != INTEL_PIPE_D);
92
93 const uint32 regMask = PCH_INTERRUPT_PIPE_MASK_BDW(pipe);
94 const uint32 regEnabled = PCH_INTERRUPT_PIPE_ENABLED_BDW(pipe);
95 const uint32 regIdentity = PCH_INTERRUPT_PIPE_IDENTITY_BDW(pipe);
96 const uint32 value = enable ? PCH_INTERRUPT_VBLANK_BDW : 0;
97 write32(info, regIdentity, ~0);
98 write32(info, regEnabled, value);
99 write32(info, regMask, ~value);
100 }
101
102
103 static uint32
gen11_enable_global_interrupts(intel_info & info,bool enable)104 gen11_enable_global_interrupts(intel_info& info, bool enable)
105 {
106 write32(info, GEN11_GFX_MSTR_IRQ, enable ? GEN11_MASTER_IRQ : 0);
107 return enable ? 0 : read32(info, GEN11_GFX_MSTR_IRQ);
108 }
109
110
111 static uint32
gen8_enable_global_interrupts(intel_info & info,bool enable)112 gen8_enable_global_interrupts(intel_info& info, bool enable)
113 {
114 write32(info, PCH_MASTER_INT_CTL_BDW, enable ? PCH_MASTER_INT_CTL_GLOBAL_BDW : 0);
115 return enable ? 0 : read32(info, PCH_MASTER_INT_CTL_BDW);
116 }
117
118
119 /*!
120 Checks interrupt status with provided master interrupt control register.
121 For Gen8 to Gen11.
122 */
123 static int32
gen8_handle_interrupts(intel_info & info,uint32 interrupt)124 gen8_handle_interrupts(intel_info& info, uint32 interrupt)
125 {
126 int32 handled = B_HANDLED_INTERRUPT;
127 if ((interrupt & PCH_MASTER_INT_CTL_PIPE_PENDING_BDW(INTEL_PIPE_A)) != 0) {
128 const uint32 regIdentity = PCH_INTERRUPT_PIPE_IDENTITY_BDW(INTEL_PIPE_A);
129 uint32 identity = read32(info, regIdentity);
130 if ((identity & PCH_INTERRUPT_VBLANK_BDW) != 0) {
131 handled = release_vblank_sem(info);
132 write32(info, regIdentity, identity | PCH_INTERRUPT_VBLANK_BDW);
133 } else {
134 dprintf("gen8_handle_interrupts unhandled interrupt on pipe A\n");
135 }
136 interrupt &= ~PCH_MASTER_INT_CTL_PIPE_PENDING_BDW(INTEL_PIPE_A);
137 }
138 if ((interrupt & PCH_MASTER_INT_CTL_PIPE_PENDING_BDW(INTEL_PIPE_B)) != 0) {
139 const uint32 regIdentity = PCH_INTERRUPT_PIPE_IDENTITY_BDW(INTEL_PIPE_B);
140 uint32 identity = read32(info, regIdentity);
141 if ((identity & PCH_INTERRUPT_VBLANK_BDW) != 0) {
142 handled = release_vblank_sem(info);
143 write32(info, regIdentity, identity | PCH_INTERRUPT_VBLANK_BDW);
144 } else {
145 dprintf("gen8_handle_interrupts unhandled interrupt on pipe B\n");
146 }
147 interrupt &= ~PCH_MASTER_INT_CTL_PIPE_PENDING_BDW(INTEL_PIPE_B);
148 }
149 if ((interrupt & PCH_MASTER_INT_CTL_PIPE_PENDING_BDW(INTEL_PIPE_C)) != 0) {
150 const uint32 regIdentity = PCH_INTERRUPT_PIPE_IDENTITY_BDW(INTEL_PIPE_C);
151 uint32 identity = read32(info, regIdentity);
152 if ((identity & PCH_INTERRUPT_VBLANK_BDW) != 0) {
153 handled = release_vblank_sem(info);
154 write32(info, regIdentity, identity | PCH_INTERRUPT_VBLANK_BDW);
155 } else {
156 dprintf("gen8_handle_interrupts unhandled interrupt on pipe C\n");
157 }
158 interrupt &= ~PCH_MASTER_INT_CTL_PIPE_PENDING_BDW(INTEL_PIPE_C);
159 }
160
161 if ((interrupt & GEN8_DE_PORT_IRQ) != 0) {
162 uint32 iir = read32(info, GEN8_DE_PORT_IIR);
163 if (iir != 0) {
164 write32(info, GEN8_DE_PORT_IIR, iir);
165 }
166 interrupt &= ~GEN8_DE_PORT_IRQ;
167 }
168
169 if (info.device_type.Generation() >= 11 && (interrupt & GEN11_DE_HPD_IRQ) != 0) {
170 dprintf("gen8_handle_interrupts HPD\n");
171 uint32 iir = read32(info, GEN11_DE_HPD_IIR);
172 if (iir != 0) {
173 dprintf("gen8_handle_interrupts HPD_IIR %" B_PRIx32 "\n", iir);
174 write32(info, GEN11_DE_HPD_IIR, iir);
175 }
176 interrupt &= ~GEN11_DE_HPD_IRQ;
177 }
178
179 if ((interrupt & GEN8_DE_PCH_IRQ) != 0) {
180 dprintf("gen8_handle_interrupts PCH\n");
181 uint32 iir = read32(info, SDEIIR);
182 if (iir != 0) {
183 dprintf("gen8_handle_interrupts PCH_IIR %" B_PRIx32 "\n", iir);
184 write32(info, SDEIIR, iir);
185 if (info.shared_info->pch_info >= INTEL_PCH_ICP) {
186 uint32 ddiHotplug = read32(info, SHOTPLUG_CTL_DDI);
187 write32(info, SHOTPLUG_CTL_DDI, ddiHotplug);
188 dprintf("gen8_handle_interrupts PCH_IIR ddiHotplug %" B_PRIx32 "\n", ddiHotplug);
189
190 uint32 tcHotplug = read32(info, SHOTPLUG_CTL_TC);
191 write32(info, SHOTPLUG_CTL_TC, tcHotplug);
192 dprintf("gen8_handle_interrupts PCH_IIR tcHotplug %" B_PRIx32 "\n", tcHotplug);
193 }
194 }
195 interrupt &= ~GEN8_DE_PCH_IRQ;
196 }
197
198 interrupt &= ~PCH_MASTER_INT_CTL_GLOBAL_BDW;
199 if (interrupt != 0)
200 dprintf("gen8_handle_interrupts unhandled %" B_PRIx32 "\n", interrupt);
201 return handled;
202 }
203
204
205
206 /** Get the appropriate interrupt mask for enabling or testing interrupts on
207 * the given pipe.
208 *
209 * The bits to test or set are different depending on the hardware generation.
210 *
211 * \param info Intel_extreme driver information
212 * \param pipe pipe to use
213 * \param enable true to get the mask for enabling the interrupts, false to get
214 * the mask for testing them.
215 */
216 static uint32
intel_get_interrupt_mask(intel_info & info,pipe_index pipe,bool enable)217 intel_get_interrupt_mask(intel_info& info, pipe_index pipe, bool enable)
218 {
219 uint32 mask = 0;
220 bool hasPCH = info.pch_info != INTEL_PCH_NONE;
221
222 // Intel changed the PCH register mapping between Sandy Bridge and the
223 // later generations (Ivy Bridge and up).
224 // The PCH register itself does not exist in pre-PCH platforms, and the
225 // previous interrupt register of course also had a different mapping.
226
227 if (pipe == INTEL_PIPE_A) {
228 if (info.device_type.InGroup(INTEL_GROUP_SNB)
229 || info.device_type.InGroup(INTEL_GROUP_ILK))
230 mask |= PCH_INTERRUPT_VBLANK_PIPEA_SNB;
231 else if (hasPCH)
232 mask |= PCH_INTERRUPT_VBLANK_PIPEA;
233 else
234 mask |= INTERRUPT_VBLANK_PIPEA;
235 }
236
237 if (pipe == INTEL_PIPE_B) {
238 if (info.device_type.InGroup(INTEL_GROUP_SNB)
239 || info.device_type.InGroup(INTEL_GROUP_ILK))
240 mask |= PCH_INTERRUPT_VBLANK_PIPEB_SNB;
241 else if (hasPCH)
242 mask |= PCH_INTERRUPT_VBLANK_PIPEB;
243 else
244 mask |= INTERRUPT_VBLANK_PIPEB;
245 }
246
247 #if 0 // FIXME enable when we support the 3rd pipe
248 if (pipe == INTEL_PIPE_C) {
249 // Older generations only had two pipes
250 if (hasPCH && info.device_type.Generation() > 6)
251 mask |= PCH_INTERRUPT_VBLANK_PIPEC;
252 }
253 #endif
254
255 // On SandyBridge, there is an extra "global enable" flag, which must also
256 // be set when enabling the interrupts (but not when testing for them).
257 if (enable && info.device_type.InFamily(INTEL_FAMILY_SER5))
258 mask |= PCH_INTERRUPT_GLOBAL_SNB;
259
260 return mask;
261 }
262
263
264 static void
intel_enable_interrupts(intel_info & info,pipes which,bool enable)265 intel_enable_interrupts(intel_info& info, pipes which, bool enable)
266 {
267 uint32 finalMask = 0;
268 const uint32 pipeAMask = intel_get_interrupt_mask(info, INTEL_PIPE_A, true);
269 const uint32 pipeBMask = intel_get_interrupt_mask(info, INTEL_PIPE_B, true);
270 if (which.HasPipe(INTEL_PIPE_A))
271 finalMask |= pipeAMask;
272 if (which.HasPipe(INTEL_PIPE_B))
273 finalMask |= pipeBMask;
274
275 const uint32 value = enable ? finalMask : 0;
276
277 // Clear all the interrupts
278 write32(info, find_reg(info, INTEL_INTERRUPT_IDENTITY), ~0);
279
280 // enable interrupts - we only want VBLANK interrupts
281 write32(info, find_reg(info, INTEL_INTERRUPT_ENABLED), value);
282 write32(info, find_reg(info, INTEL_INTERRUPT_MASK), ~value);
283 }
284
285
286 static bool
intel_check_interrupt(intel_info & info,pipes & which)287 intel_check_interrupt(intel_info& info, pipes& which)
288 {
289 which.ClearPipe(INTEL_PIPE_ANY);
290 const uint32 pipeAMask = intel_get_interrupt_mask(info, INTEL_PIPE_A, false);
291 const uint32 pipeBMask = intel_get_interrupt_mask(info, INTEL_PIPE_B, false);
292 const uint32 regIdentity = find_reg(info, INTEL_INTERRUPT_IDENTITY);
293 const uint32 interrupt = read32(info, regIdentity);
294 if ((interrupt & pipeAMask) != 0)
295 which.SetPipe(INTEL_PIPE_A);
296 if ((interrupt & pipeBMask) != 0)
297 which.SetPipe(INTEL_PIPE_B);
298 return which.HasPipe(INTEL_PIPE_ANY);
299 }
300
301
302 static void
g35_clear_interrupt_status(intel_info & info,pipe_index pipe)303 g35_clear_interrupt_status(intel_info& info, pipe_index pipe)
304 {
305 // These registers do not exist on later GPUs.
306 if (info.device_type.Generation() > 4)
307 return;
308
309 const uint32 value = DISPLAY_PIPE_VBLANK_STATUS | DISPLAY_PIPE_VBLANK_ENABLED;
310 switch (pipe) {
311 case INTEL_PIPE_A:
312 write32(info, INTEL_DISPLAY_A_PIPE_STATUS, value);
313 break;
314 case INTEL_PIPE_B:
315 write32(info, INTEL_DISPLAY_B_PIPE_STATUS, value);
316 break;
317 default:
318 break;
319 }
320 }
321
322
323 static void
intel_clear_pipe_interrupt(intel_info & info,pipe_index pipe)324 intel_clear_pipe_interrupt(intel_info& info, pipe_index pipe)
325 {
326 // On G35/G45, prior to clearing Display Pipe interrupt in IIR
327 // the corresponding interrupt status must first be cleared.
328 g35_clear_interrupt_status(info, pipe);
329
330 const uint32 regIdentity = find_reg(info, INTEL_INTERRUPT_IDENTITY);
331 const uint32 bit = intel_get_interrupt_mask(info, pipe, false);
332 const uint32 identity = read32(info, regIdentity);
333 write32(info, regIdentity, identity | bit);
334 }
335
336
337 /*!
338 Interrupt routine for Gen8 and Gen9.
339 See Gen12 Display Engine: Interrupt Service Routine chapter.
340 */
341 static int32
gen8_interrupt_handler(void * data)342 gen8_interrupt_handler(void* data)
343 {
344 intel_info& info = *(intel_info*)data;
345
346 uint32 interrupt = gen8_enable_global_interrupts(info, false);
347 if (interrupt == 0) {
348 gen8_enable_global_interrupts(info, true);
349 return B_UNHANDLED_INTERRUPT;
350 }
351
352 int32 handled = gen8_handle_interrupts(info, interrupt);
353
354 gen8_enable_global_interrupts(info, true);
355 return handled;
356 }
357
358
359 /*!
360 Interrupt routine for Gen11.
361 See Gen12 Display Engine: Interrupt Service Routine chapter.
362 */
363 static int32
gen11_interrupt_handler(void * data)364 gen11_interrupt_handler(void* data)
365 {
366 intel_info& info = *(intel_info*)data;
367
368 uint32 interrupt = gen11_enable_global_interrupts(info, false);
369
370 if (interrupt == 0) {
371 gen11_enable_global_interrupts(info, true);
372 return B_UNHANDLED_INTERRUPT;
373 }
374
375 int32 handled = B_HANDLED_INTERRUPT;
376 if ((interrupt & GEN11_DISPLAY_IRQ) != 0)
377 handled = gen8_handle_interrupts(info, read32(info, GEN11_DISPLAY_INT_CTL));
378
379 gen11_enable_global_interrupts(info, true);
380 return handled;
381 }
382
383
384 static int32
intel_interrupt_handler(void * data)385 intel_interrupt_handler(void* data)
386 {
387 intel_info &info = *(intel_info*)data;
388
389 pipes which;
390 bool shouldHandle = intel_check_interrupt(info, which);
391
392 if (!shouldHandle)
393 return B_UNHANDLED_INTERRUPT;
394
395 int32 handled = B_HANDLED_INTERRUPT;
396
397 while (shouldHandle) {
398 if (which.HasPipe(INTEL_PIPE_A)) {
399 handled = release_vblank_sem(info);
400
401 intel_clear_pipe_interrupt(info, INTEL_PIPE_A);
402 }
403
404 if (which.HasPipe(INTEL_PIPE_B)) {
405 handled = release_vblank_sem(info);
406
407 intel_clear_pipe_interrupt(info, INTEL_PIPE_B);
408 }
409
410 #if 0
411 // FIXME we don't have support for the 3rd pipe yet
412 if (which.HasPipe(INTEL_PIPE_C)) {
413 handled = release_vblank_sem(info);
414
415 intel_clear_pipe_interrupt(info, INTEL_PIPE_C);
416 }
417 #endif
418
419 shouldHandle = intel_check_interrupt(info, which);
420 }
421
422 return handled;
423 }
424
425
426 static void
init_interrupt_handler(intel_info & info)427 init_interrupt_handler(intel_info &info)
428 {
429 info.shared_info->vblank_sem = create_sem(0, "intel extreme vblank");
430 if (info.shared_info->vblank_sem < B_OK)
431 return;
432
433 status_t status = B_OK;
434
435 // We need to change the owner of the sem to the calling team (usually the
436 // app_server), because userland apps cannot acquire kernel semaphores
437 thread_id thread = find_thread(NULL);
438 thread_info threadInfo;
439 if (get_thread_info(thread, &threadInfo) != B_OK
440 || set_sem_owner(info.shared_info->vblank_sem, threadInfo.team)
441 != B_OK) {
442 status = B_ERROR;
443 }
444
445 // Find the right interrupt vector, using MSIs if available.
446 info.irq = 0;
447 info.use_msi = false;
448 if (info.pci->u.h0.interrupt_pin != 0x00) {
449 info.irq = info.pci->u.h0.interrupt_line;
450 if (info.irq == 0xff)
451 info.irq = 0;
452 }
453 if (gPCI->get_msi_count(info.pci->bus,
454 info.pci->device, info.pci->function) >= 1) {
455 uint32 msiVector = 0;
456 if (gPCI->configure_msi(info.pci->bus, info.pci->device,
457 info.pci->function, 1, &msiVector) == B_OK
458 && gPCI->enable_msi(info.pci->bus, info.pci->device,
459 info.pci->function) == B_OK) {
460 TRACE("using message signaled interrupts\n");
461 info.irq = msiVector;
462 info.use_msi = true;
463 }
464 }
465
466 if (status == B_OK && info.irq != 0) {
467 // we've gotten an interrupt line for us to use
468
469 info.fake_interrupts = false;
470
471 if (info.device_type.Generation() >= 8) {
472 interrupt_handler handler = &gen8_interrupt_handler;
473 if (info.device_type.Generation() >= 11)
474 handler = &gen11_interrupt_handler;
475 status = install_io_interrupt_handler(info.irq,
476 handler, (void*)&info, 0);
477 if (status == B_OK) {
478 gen8_enable_interrupts(info, INTEL_PIPE_A, true);
479 gen8_enable_interrupts(info, INTEL_PIPE_B, true);
480 if (info.device_type.Generation() >= 11)
481 gen8_enable_interrupts(info, INTEL_PIPE_C, true);
482 gen8_enable_global_interrupts(info, true);
483
484 if (info.device_type.Generation() >= 11) {
485 if (info.shared_info->pch_info >= INTEL_PCH_ICP) {
486 read32(info, SDEIIR);
487 write32(info, SDEIER, 0xffffffff);
488 write32(info, SDEIMR, ~SDE_GMBUS_ICP);
489 read32(info, SDEIMR);
490 }
491
492 uint32 mask = GEN8_AUX_CHANNEL_A;
493 mask |= GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C | GEN9_AUX_CHANNEL_D;
494 mask |= CNL_AUX_CHANNEL_F;
495 mask |= ICL_AUX_CHANNEL_E;
496 read32(info, GEN8_DE_PORT_IIR);
497 write32(info, GEN8_DE_PORT_IER, mask);
498 write32(info, GEN8_DE_PORT_IMR, ~mask);
499 read32(info, GEN8_DE_PORT_IMR);
500
501 read32(info, GEN8_DE_MISC_IIR);
502 write32(info, GEN8_DE_MISC_IER, GEN8_DE_EDP_PSR);
503 write32(info, GEN8_DE_MISC_IMR, ~GEN8_DE_EDP_PSR);
504 read32(info, GEN8_DE_MISC_IMR);
505
506 read32(info, GEN11_GU_MISC_IIR);
507 write32(info, GEN11_GU_MISC_IER, GEN11_GU_MISC_GSE);
508 write32(info, GEN11_GU_MISC_IMR, ~GEN11_GU_MISC_GSE);
509 read32(info, GEN11_GU_MISC_IMR);
510
511 read32(info, GEN11_DE_HPD_IIR);
512 write32(info, GEN11_DE_HPD_IER,
513 GEN11_DE_TC_HOTPLUG_MASK | GEN11_DE_TBT_HOTPLUG_MASK);
514 write32(info, GEN11_DE_HPD_IMR, 0xffffffff);
515 read32(info, GEN11_DE_HPD_IMR);
516
517 write32(info, GEN11_TC_HOTPLUG_CTL, 0);
518 write32(info, GEN11_TBT_HOTPLUG_CTL, 0);
519
520 if (info.shared_info->pch_info >= INTEL_PCH_ICP) {
521 if (info.shared_info->pch_info <= INTEL_PCH_TGP)
522 write32(info, SHPD_FILTER_CNT, SHPD_FILTER_CNT_500_ADJ);
523 read32(info, SDEIMR);
524 write32(info, SDEIMR, 0x3f023f07);
525 read32(info, SDEIMR);
526
527 uint32 ctl = read32(info, SHOTPLUG_CTL_DDI);
528 // we enable everything, should come from the VBT
529 ctl |= SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_A)
530 | SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_B)
531 | SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_C)
532 | SHOTPLUG_CTL_DDI_HPD_ENABLE(HPD_PORT_D);
533 write32(info, SHOTPLUG_CTL_DDI, ctl);
534 ctl = read32(info, SHOTPLUG_CTL_TC);
535 // we enable everything, should come from the VBT
536 ctl |= SHOTPLUG_CTL_TC_HPD_ENABLE(HPD_PORT_TC1)
537 | SHOTPLUG_CTL_TC_HPD_ENABLE(HPD_PORT_TC2)
538 | SHOTPLUG_CTL_TC_HPD_ENABLE(HPD_PORT_TC3)
539 | SHOTPLUG_CTL_TC_HPD_ENABLE(HPD_PORT_TC4)
540 | SHOTPLUG_CTL_TC_HPD_ENABLE(HPD_PORT_TC5)
541 | SHOTPLUG_CTL_TC_HPD_ENABLE(HPD_PORT_TC6);
542 write32(info, SHOTPLUG_CTL_TC, ctl);
543 }
544
545 gen11_enable_global_interrupts(info, true);
546 }
547 }
548 } else {
549 status = install_io_interrupt_handler(info.irq,
550 &intel_interrupt_handler, (void*)&info, 0);
551 if (status == B_OK) {
552 g35_clear_interrupt_status(info, INTEL_PIPE_A);
553 g35_clear_interrupt_status(info, INTEL_PIPE_B);
554
555 pipes which;
556 which.SetPipe(INTEL_PIPE_A);
557 which.SetPipe(INTEL_PIPE_B);
558 intel_enable_interrupts(info, which, true);
559 }
560 }
561 }
562 if (status < B_OK) {
563 // There is no interrupt reserved for us, or we couldn't install our
564 // interrupt handler, let's fake the vblank interrupt for our clients
565 // using a timer interrupt
566 info.fake_interrupts = true;
567
568 // TODO: fake interrupts!
569 ERROR("Fake interrupt mode (no PCI interrupt line assigned\n");
570 status = B_ERROR;
571 }
572
573 if (status < B_OK) {
574 delete_sem(info.shared_info->vblank_sem);
575 info.shared_info->vblank_sem = B_ERROR;
576 }
577 }
578
579
580 // #pragma mark -
581
582
583 status_t
intel_free_memory(intel_info & info,addr_t base)584 intel_free_memory(intel_info &info, addr_t base)
585 {
586 return gGART->free_memory(info.aperture, base);
587 }
588
589
590 status_t
intel_allocate_memory(intel_info & info,size_t size,size_t alignment,uint32 flags,addr_t * _base,phys_addr_t * _physicalBase)591 intel_allocate_memory(intel_info &info, size_t size, size_t alignment,
592 uint32 flags, addr_t* _base, phys_addr_t* _physicalBase)
593 {
594 return gGART->allocate_memory(info.aperture, size, alignment,
595 flags, _base, _physicalBase);
596 }
597
598
599 status_t
intel_extreme_init(intel_info & info)600 intel_extreme_init(intel_info &info)
601 {
602 CALLED();
603 info.aperture = gGART->map_aperture(info.pci->bus, info.pci->device,
604 info.pci->function, 0, &info.aperture_base);
605 if (info.aperture < B_OK) {
606 ERROR("error: could not map GART aperture! (%s)\n",
607 strerror(info.aperture));
608 return info.aperture;
609 }
610
611 AreaKeeper sharedCreator;
612 info.shared_area = sharedCreator.Create("intel extreme shared info",
613 (void**)&info.shared_info, B_ANY_KERNEL_ADDRESS,
614 ROUND_TO_PAGE_SIZE(sizeof(intel_shared_info)) + 3 * B_PAGE_SIZE,
615 B_FULL_LOCK,
616 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA);
617 if (info.shared_area < B_OK) {
618 ERROR("error: could not create shared area!\n");
619 gGART->unmap_aperture(info.aperture);
620 return info.shared_area;
621 }
622
623 // enable power
624 gPCI->set_powerstate(info.pci->bus, info.pci->device, info.pci->function,
625 PCI_pm_state_d0);
626
627 memset((void*)info.shared_info, 0, sizeof(intel_shared_info));
628
629 int mmioIndex = 1;
630 if (info.device_type.Generation() >= 3) {
631 // For some reason Intel saw the need to change the order of the
632 // mappings with the introduction of the i9xx family
633 mmioIndex = 0;
634 }
635
636 // evaluate driver settings, if any
637
638 bool hardwareCursor;
639 read_settings(hardwareCursor);
640
641 // memory mapped I/O
642
643 // TODO: registers are mapped twice (by us and intel_gart), maybe we
644 // can share it between the drivers
645
646 phys_addr_t addr = info.pci->u.h0.base_registers[mmioIndex];
647 uint64 barSize = info.pci->u.h0.base_register_sizes[mmioIndex];
648 if ((info.pci->u.h0.base_register_flags[mmioIndex] & PCI_address_type) == PCI_address_type_64) {
649 addr |= (uint64)info.pci->u.h0.base_registers[mmioIndex + 1] << 32;
650 barSize |= (uint64)info.pci->u.h0.base_register_sizes[mmioIndex + 1] << 32;
651 }
652 AreaKeeper mmioMapper;
653 info.registers_area = mmioMapper.Map("intel extreme mmio", addr, barSize,
654 B_ANY_KERNEL_ADDRESS,
655 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA,
656 (void**)&info.registers);
657 if (mmioMapper.InitCheck() < B_OK) {
658 ERROR("error: could not map memory I/O!\n");
659 gGART->unmap_aperture(info.aperture);
660 return info.registers_area;
661 }
662
663 bool hasPCH = (info.pch_info != INTEL_PCH_NONE);
664
665 ERROR("Init Intel generation %d GPU %s PCH split.\n",
666 info.device_type.Generation(), hasPCH ? "with" : "without");
667
668 uint32* blocks = info.shared_info->register_blocks;
669 blocks[REGISTER_BLOCK(REGS_FLAT)] = 0;
670
671 // setup the register blocks for the different architectures
672 if (hasPCH) {
673 // PCH based platforms (IronLake through ultra-low-power Broadwells)
674 blocks[REGISTER_BLOCK(REGS_NORTH_SHARED)]
675 = PCH_NORTH_SHARED_REGISTER_BASE;
676 blocks[REGISTER_BLOCK(REGS_NORTH_PIPE_AND_PORT)]
677 = PCH_NORTH_PIPE_AND_PORT_REGISTER_BASE;
678 blocks[REGISTER_BLOCK(REGS_NORTH_PLANE_CONTROL)]
679 = PCH_NORTH_PLANE_CONTROL_REGISTER_BASE;
680 blocks[REGISTER_BLOCK(REGS_SOUTH_SHARED)]
681 = PCH_SOUTH_SHARED_REGISTER_BASE;
682 blocks[REGISTER_BLOCK(REGS_SOUTH_TRANSCODER_PORT)]
683 = PCH_SOUTH_TRANSCODER_AND_PORT_REGISTER_BASE;
684 } else {
685 // (G)MCH/ICH based platforms
686 blocks[REGISTER_BLOCK(REGS_NORTH_SHARED)]
687 = MCH_SHARED_REGISTER_BASE;
688 blocks[REGISTER_BLOCK(REGS_NORTH_PIPE_AND_PORT)]
689 = MCH_PIPE_AND_PORT_REGISTER_BASE;
690 blocks[REGISTER_BLOCK(REGS_NORTH_PLANE_CONTROL)]
691 = MCH_PLANE_CONTROL_REGISTER_BASE;
692 blocks[REGISTER_BLOCK(REGS_SOUTH_SHARED)]
693 = ICH_SHARED_REGISTER_BASE;
694 blocks[REGISTER_BLOCK(REGS_SOUTH_TRANSCODER_PORT)]
695 = ICH_PORT_REGISTER_BASE;
696 }
697
698 // Everything in the display PRM gets +0x180000
699 if (info.device_type.InGroup(INTEL_GROUP_VLV)) {
700 // "I nearly got violent with the hw guys when they told me..."
701 blocks[REGISTER_BLOCK(REGS_SOUTH_SHARED)] += VLV_DISPLAY_BASE;
702 blocks[REGISTER_BLOCK(REGS_SOUTH_TRANSCODER_PORT)] += VLV_DISPLAY_BASE;
703 }
704
705 TRACE("REGS_NORTH_SHARED: 0x%" B_PRIx32 "\n",
706 blocks[REGISTER_BLOCK(REGS_NORTH_SHARED)]);
707 TRACE("REGS_NORTH_PIPE_AND_PORT: 0x%" B_PRIx32 "\n",
708 blocks[REGISTER_BLOCK(REGS_NORTH_PIPE_AND_PORT)]);
709 TRACE("REGS_NORTH_PLANE_CONTROL: 0x%" B_PRIx32 "\n",
710 blocks[REGISTER_BLOCK(REGS_NORTH_PLANE_CONTROL)]);
711 TRACE("REGS_SOUTH_SHARED: 0x%" B_PRIx32 "\n",
712 blocks[REGISTER_BLOCK(REGS_SOUTH_SHARED)]);
713 TRACE("REGS_SOUTH_TRANSCODER_PORT: 0x%" B_PRIx32 "\n",
714 blocks[REGISTER_BLOCK(REGS_SOUTH_TRANSCODER_PORT)]);
715
716 // make sure bus master, memory-mapped I/O, and frame buffer is enabled
717 set_pci_config(info.pci, PCI_command, 2, get_pci_config(info.pci,
718 PCI_command, 2) | PCI_command_io | PCI_command_memory
719 | PCI_command_master);
720
721 // reserve ring buffer memory (currently, this memory is placed in
722 // the graphics memory), but this could bring us problems with
723 // write combining...
724
725 ring_buffer &primary = info.shared_info->primary_ring_buffer;
726 if (intel_allocate_memory(info, 16 * B_PAGE_SIZE, 0, 0,
727 (addr_t*)&primary.base) == B_OK) {
728 primary.register_base = INTEL_PRIMARY_RING_BUFFER;
729 primary.size = 16 * B_PAGE_SIZE;
730 primary.offset = (addr_t)primary.base - info.aperture_base;
731 }
732
733 // Enable clock gating
734 intel_en_gating(info);
735
736 // Enable automatic gpu downclocking if we can to save power
737 intel_en_downclock(info);
738
739 // no errors, so keep areas and mappings
740 sharedCreator.Detach();
741 mmioMapper.Detach();
742
743 aperture_info apertureInfo;
744 gGART->get_aperture_info(info.aperture, &apertureInfo);
745
746 info.shared_info->registers_area = info.registers_area;
747 info.shared_info->graphics_memory = (uint8*)info.aperture_base;
748 info.shared_info->physical_graphics_memory = apertureInfo.physical_base;
749 info.shared_info->graphics_memory_size = apertureInfo.size;
750 info.shared_info->frame_buffer = 0;
751 info.shared_info->dpms_mode = B_DPMS_ON;
752 info.shared_info->min_brightness = 2;
753 info.shared_info->internal_crt_support = true;
754 info.shared_info->pch_info = info.pch_info;
755 info.shared_info->device_type = info.device_type;
756
757 // Pull VBIOS info for later use
758 info.shared_info->got_vbt = parse_vbt_from_bios(info.shared_info);
759
760 /* at least 855gm can't drive more than one head at time */
761 if (info.device_type.InFamily(INTEL_FAMILY_8xx))
762 info.shared_info->single_head_locked = 1;
763
764 if (info.device_type.InFamily(INTEL_FAMILY_SER5)) {
765 info.shared_info->pll_info.reference_frequency = 120000;// 120 MHz
766 info.shared_info->pll_info.max_frequency = 350000;
767 // 350 MHz RAM DAC speed
768 info.shared_info->pll_info.min_frequency = 20000; // 20 MHz
769 } else if (info.device_type.InFamily(INTEL_FAMILY_9xx)) {
770 info.shared_info->pll_info.reference_frequency = 96000; // 96 MHz
771 info.shared_info->pll_info.max_frequency = 400000;
772 // 400 MHz RAM DAC speed
773 info.shared_info->pll_info.min_frequency = 20000; // 20 MHz
774 } else if (info.device_type.HasDDI() && (info.device_type.Generation() <= 8)) {
775 info.shared_info->pll_info.reference_frequency = 135000;// 135 MHz
776 info.shared_info->pll_info.max_frequency = 350000;
777 // 350 MHz RAM DAC speed
778 info.shared_info->pll_info.min_frequency = 25000; // 25 MHz
779 } else if ((info.device_type.Generation() >= 9) &&
780 info.device_type.InGroup(INTEL_GROUP_SKY)) {
781 info.shared_info->pll_info.reference_frequency = 24000; // 24 MHz
782 info.shared_info->pll_info.max_frequency = 350000;
783 // 350 MHz RAM DAC speed
784 info.shared_info->pll_info.min_frequency = 25000; // 25 MHz
785 } else if (info.device_type.Generation() >= 9) {
786 uint32 refInfo =
787 (read32(info, ICL_DSSM) & ICL_DSSM_REF_FREQ_MASK) >> ICL_DSSM_REF_FREQ_SHIFT;
788 switch (refInfo) {
789 case ICL_DSSM_24000:
790 info.shared_info->pll_info.reference_frequency = 24000; // 24 MHz
791 break;
792 case ICL_DSSM_19200:
793 info.shared_info->pll_info.reference_frequency = 19200; // 19.2 MHz
794 break;
795 case ICL_DSSM_38400:
796 info.shared_info->pll_info.reference_frequency = 38400; // 38.4 MHz
797 break;
798 default:
799 ERROR("error: unknown ref. freq. strap, using 24Mhz! %" B_PRIx32 "\n", refInfo);
800 info.shared_info->pll_info.reference_frequency = 24000; // 24 MHz
801 break;
802 }
803 info.shared_info->pll_info.max_frequency = 350000;
804 // 350 MHz RAM DAC speed
805 info.shared_info->pll_info.min_frequency = 25000; // 25 MHz
806 } else {
807 info.shared_info->pll_info.reference_frequency = 48000; // 48 MHz
808 info.shared_info->pll_info.max_frequency = 350000;
809 // 350 MHz RAM DAC speed
810 info.shared_info->pll_info.min_frequency = 25000; // 25 MHz
811 }
812
813 info.shared_info->pll_info.divisor_register = INTEL_DISPLAY_A_PLL_DIVISOR_0;
814
815 #ifdef __HAIKU__
816 strlcpy(info.shared_info->device_identifier, info.device_identifier,
817 sizeof(info.shared_info->device_identifier));
818 #else
819 strcpy(info.shared_info->device_identifier, info.device_identifier);
820 #endif
821
822 // setup overlay registers
823
824 status_t status = intel_allocate_memory(info, B_PAGE_SIZE, 0,
825 intel_uses_physical_overlay(*info.shared_info)
826 ? B_APERTURE_NEED_PHYSICAL : 0,
827 (addr_t*)&info.overlay_registers,
828 &info.shared_info->physical_overlay_registers);
829 if (status == B_OK) {
830 info.shared_info->overlay_offset = (addr_t)info.overlay_registers
831 - info.aperture_base;
832 TRACE("Overlay registers mapped at 0x%" B_PRIx32 " = %p - %"
833 B_PRIxADDR " (%" B_PRIxPHYSADDR ")\n",
834 info.shared_info->overlay_offset, info.overlay_registers,
835 info.aperture_base, info.shared_info->physical_overlay_registers);
836 init_overlay_registers(info.overlay_registers);
837 } else {
838 ERROR("error: could not allocate overlay memory! %s\n",
839 strerror(status));
840 }
841
842 // Allocate hardware status page and the cursor memory
843 TRACE("Allocating hardware status page");
844
845 if (intel_allocate_memory(info, B_PAGE_SIZE, 0, B_APERTURE_NEED_PHYSICAL,
846 (addr_t*)info.shared_info->status_page,
847 &info.shared_info->physical_status_page) == B_OK) {
848 // TODO: set status page
849 }
850 if (hardwareCursor) {
851 intel_allocate_memory(info, B_PAGE_SIZE, 0, B_APERTURE_NEED_PHYSICAL,
852 (addr_t*)&info.shared_info->cursor_memory,
853 &info.shared_info->physical_cursor_memory);
854 }
855
856 edid1_info* edidInfo = (edid1_info*)get_boot_item(VESA_EDID_BOOT_INFO,
857 NULL);
858 if (edidInfo != NULL) {
859 info.shared_info->has_vesa_edid_info = true;
860 memcpy(&info.shared_info->vesa_edid_info, edidInfo, sizeof(edid1_info));
861 }
862
863 init_interrupt_handler(info);
864
865 if (hasPCH) {
866 if (info.device_type.Generation() == 5) {
867 info.shared_info->fdi_link_frequency = (read32(info, FDI_PLL_BIOS_0)
868 & FDI_PLL_FB_CLOCK_MASK) + 2;
869 info.shared_info->fdi_link_frequency *= 100;
870 } else {
871 info.shared_info->fdi_link_frequency = 2700;
872 }
873 if (info.shared_info->pch_info >= INTEL_PCH_CNP) {
874 // TODO read/write info.shared_info->hraw_clock
875 } else {
876 info.shared_info->hraw_clock = (read32(info, PCH_RAWCLK_FREQ)
877 & RAWCLK_FREQ_MASK) * 1000;
878 TRACE("%s: rawclk rate: %" B_PRIu32 " kHz\n", __func__, info.shared_info->hraw_clock);
879 }
880 } else {
881 // TODO read info.shared_info->hraw_clock
882 info.shared_info->fdi_link_frequency = 0;
883 }
884
885 if (info.device_type.InGroup(INTEL_GROUP_BDW)) {
886 uint32 lcpll = read32(info, LCPLL_CTL);
887 if ((lcpll & LCPLL_CD_SOURCE_FCLK) != 0)
888 info.shared_info->hw_cdclk = 800000;
889 else if ((read32(info, FUSE_STRAP) & HSW_CDCLK_LIMIT) != 0)
890 info.shared_info->hw_cdclk = 450000;
891 else if ((lcpll & LCPLL_CLK_FREQ_MASK) == LCPLL_CLK_FREQ_450)
892 info.shared_info->hw_cdclk = 450000;
893 else if ((lcpll & LCPLL_CLK_FREQ_MASK) == LCPLL_CLK_FREQ_54O_BDW)
894 info.shared_info->hw_cdclk = 540000;
895 else if ((lcpll & LCPLL_CLK_FREQ_MASK) == LCPLL_CLK_FREQ_337_5_BDW)
896 info.shared_info->hw_cdclk = 337500;
897 else
898 info.shared_info->hw_cdclk = 675000;
899 } else if (info.device_type.InGroup(INTEL_GROUP_HAS)) {
900 uint32 lcpll = read32(info, LCPLL_CTL);
901 if ((lcpll & LCPLL_CD_SOURCE_FCLK) != 0)
902 info.shared_info->hw_cdclk = 800000;
903 else if ((read32(info, FUSE_STRAP) & HSW_CDCLK_LIMIT) != 0)
904 info.shared_info->hw_cdclk = 450000;
905 else if ((lcpll & LCPLL_CLK_FREQ_MASK) == LCPLL_CLK_FREQ_450)
906 info.shared_info->hw_cdclk = 450000;
907 /* ULT type is missing
908 else if (IS_ULT)
909 info.shared_info->hw_cdclk = 337500;
910 */
911 else
912 info.shared_info->hw_cdclk = 540000;
913 } else if (info.device_type.InGroup(INTEL_GROUP_SNB)
914 || info.device_type.InGroup(INTEL_GROUP_IVB)) {
915 info.shared_info->hw_cdclk = 400000;
916 } else if (info.device_type.InGroup(INTEL_GROUP_ILK)) {
917 info.shared_info->hw_cdclk = 450000;
918 }
919 TRACE("%s: hw_cdclk: %" B_PRIu32 " kHz\n", __func__, info.shared_info->hw_cdclk);
920
921 TRACE("%s: completed successfully!\n", __func__);
922 return B_OK;
923 }
924
925
926 void
intel_extreme_uninit(intel_info & info)927 intel_extreme_uninit(intel_info &info)
928 {
929 CALLED();
930
931 if (!info.fake_interrupts && info.shared_info->vblank_sem > 0) {
932 // disable interrupt generation
933 if (info.device_type.Generation() >= 8) {
934 if (info.device_type.Generation() >= 11) {
935 gen11_enable_global_interrupts(info, false);
936 }
937 gen8_enable_global_interrupts(info, false);
938 interrupt_handler handler = &gen8_interrupt_handler;
939 if (info.device_type.Generation() >= 11)
940 handler = &gen11_interrupt_handler;
941 remove_io_interrupt_handler(info.irq, handler, &info);
942 } else {
943 write32(info, find_reg(info, INTEL_INTERRUPT_ENABLED), 0);
944 write32(info, find_reg(info, INTEL_INTERRUPT_MASK), ~0);
945 remove_io_interrupt_handler(info.irq, intel_interrupt_handler, &info);
946 }
947
948 if (info.use_msi) {
949 gPCI->disable_msi(info.pci->bus,
950 info.pci->device, info.pci->function);
951 gPCI->unconfigure_msi(info.pci->bus,
952 info.pci->device, info.pci->function);
953 }
954 }
955
956 gGART->unmap_aperture(info.aperture);
957
958 delete_area(info.registers_area);
959 delete_area(info.shared_area);
960 }
961
962