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
42static void
43init_overlay_registers(overlay_registers* _registers)
44{
45	user_memset(_registers, 0, B_PAGE_SIZE);
46
47	overlay_registers registers;
48	memset(&registers, 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, &registers, sizeof(overlay_registers));
54}
55
56
57static void
58read_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
72static int32
73release_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
87static void
88gen8_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
103static uint32
104gen11_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
111static uint32
112gen8_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*/
123static int32
124gen8_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 */
216static uint32
217intel_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
264static void
265intel_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
286static bool
287intel_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
302static void
303g35_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
323static void
324intel_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*/
341static int32
342gen8_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*/
363static int32
364gen11_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
384static int32
385intel_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
426static void
427init_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
583status_t
584intel_free_memory(intel_info &info, addr_t base)
585{
586	return gGART->free_memory(info.aperture, base);
587}
588
589
590status_t
591intel_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
599status_t
600intel_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
926void
927intel_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