xref: /haiku/src/add-ons/kernel/drivers/graphics/intel_extreme/power.cpp (revision 644fa5a93845dc4a1bc155f1fd0f94ebdf0b47bc)
1 /*
2  * Copyright 2012-2013, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *	Alexander von Gluck IV, kallisti5@unixzen.com
7  */
8 
9 
10 #include "power.h"
11 
12 
13 #undef TRACE
14 #define TRACE_POWER
15 #ifdef TRACE_POWER
16 #	define TRACE(x...) dprintf("intel_extreme:" x)
17 #else
18 #	define TRACE(x...)
19 #endif
20 
21 #define ERROR(x...) dprintf("intel_extreme: " x)
22 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
23 
24 
25 status_t
26 intel_en_gating(intel_info &info)
27 {
28 	CALLED();
29 	// Fix some problems on certain chips (taken from X driver)
30 	// TODO: clean this up
31 	if (info.pci->device_id == 0x2a02 || info.pci->device_id == 0x2a12) {
32 		TRACE("i965GM/i965GME quirk\n");
33 		write32(info, 0x6204, (1L << 29));
34 	} else if (info.device_type.InGroup(INTEL_TYPE_SNB)) {
35 		TRACE("SandyBridge clock gating\n");
36 		write32(info, 0x42020, (1L << 28) | (1L << 7) | (1L << 5));
37 	} else if (info.device_type.InGroup(INTEL_TYPE_IVB)) {
38 		TRACE("IvyBridge clock gating\n");
39 		write32(info, 0x42020, (1L << 28));
40 	} else if (info.device_type.InGroup(INTEL_TYPE_ILK)) {
41 		TRACE("IronLake clock gating\n");
42 		write32(info, 0x42020, (1L << 7) | (1L << 5));
43 	} else if (info.device_type.InGroup(INTEL_TYPE_G4x)) {
44 		TRACE("G4x clock gating\n");
45 		write32(info, 0x6204, 0);
46 		write32(info, 0x6208, (1L << 9) | (1L << 7) | (1L << 6));
47 		write32(info, 0x6210, 0);
48 
49 		uint32 gateValue = (1L << 28) | (1L << 3) | (1L << 2);
50 		if ((info.device_type.type & INTEL_TYPE_MOBILE) == INTEL_TYPE_MOBILE) {
51 			TRACE("G4x mobile clock gating\n");
52 		    gateValue |= 1L << 18;
53 		}
54 		write32(info, 0x6200, gateValue);
55 	} else {
56 		TRACE("i965 quirk\n");
57 		write32(info, 0x6204, (1L << 29) | (1L << 23));
58 	}
59 	write32(info, 0x7408, 0x10);
60 
61 	return B_OK;
62 }
63 
64 
65 status_t
66 intel_en_downclock(intel_info &info)
67 {
68 	CALLED();
69 
70 	if (!info.device_type.InGroup(INTEL_TYPE_SNB)
71 		&& !info.device_type.InGroup(INTEL_TYPE_IVB)) {
72 		TRACE("%s: Downclocking not supported on this chipset.\n", __func__);
73 		return B_NOT_ALLOWED;
74 	}
75 
76 	if((info.device_type.type & INTEL_TYPE_MOBILE) == 0) {
77 		// I don't see a point enabling auto-downclocking on non-mobile devices.
78 		TRACE("%s: Skip GPU downclocking on non-mobile device.\n", __func__);
79 		return B_NOT_ALLOWED;
80 	}
81 	// TODO: Check for deep RC6
82 	// IvyBridge, SandyBridge, and Haswell can do depth 1 atm
83 	// Some chipsets can go deeper... but this is safe for now
84 	// Haswell should *NOT* do over depth 1;
85 	int depth = 1;
86 
87 	// Lets always print this for now incase it causes regressions for someone.
88 	ERROR("%s: Enabling Intel GPU auto downclocking depth %d\n", __func__,
89 		depth);
90 
91 	/* Magical sequence of register writes to enable
92 	 * downclocking from the fine folks at Xorg
93 	 */
94 	write32(info, INTEL6_RC_STATE, 0);
95 
96 	uint32 rpStateCapacity = read32(info, INTEL6_RP_STATE_CAP);
97 	uint32 gtPerfStatus = read32(info, INTEL6_GT_PERF_STATUS);
98 	uint8 maxDelay = rpStateCapacity & 0xff;
99 	uint8 minDelay = (rpStateCapacity & 0xff0000) >> 16;
100 
101 	write32(info, INTEL6_RC_CONTROL, 0);
102 
103 	write32(info, INTEL6_RC1_WAKE_RATE_LIMIT, 1000 << 16);
104 	write32(info, INTEL6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30);
105 	write32(info, INTEL6_RC6pp_WAKE_RATE_LIMIT, 30);
106 	write32(info, INTEL6_RC_EVALUATION_INTERVAL, 125000);
107 	write32(info, INTEL6_RC_IDLE_HYSTERSIS, 25);
108 
109 	// TODO: Idle each ring
110 
111 	write32(info, INTEL6_RC_SLEEP, 0);
112 	write32(info, INTEL6_RC1e_THRESHOLD, 1000);
113 	write32(info, INTEL6_RC6_THRESHOLD, 50000);
114 	write32(info, INTEL6_RC6p_THRESHOLD, 100000);
115 	write32(info, INTEL6_RC6pp_THRESHOLD, 64000);
116 
117 	uint32 rc6Mask = INTEL6_RC_CTL_RC6_ENABLE;
118 
119 	if (depth > 1)
120 		rc6Mask |= INTEL6_RC_CTL_RC6p_ENABLE;
121 	if (depth > 2)
122 		rc6Mask |= INTEL6_RC_CTL_RC6pp_ENABLE;
123 
124 	write32(info, INTEL6_RC_CONTROL, rc6Mask | INTEL6_RC_CTL_EI_MODE(1)
125 		| INTEL6_RC_CTL_HW_ENABLE);
126 	write32(info, INTEL6_RPNSWREQ, INTEL6_FREQUENCY(10) | INTEL6_OFFSET(0)
127 		| INTEL6_AGGRESSIVE_TURBO);
128 	write32(info, INTEL6_RC_VIDEO_FREQ, INTEL6_FREQUENCY(12));
129 
130 	write32(info, INTEL6_RP_DOWN_TIMEOUT, 1000000);
131 	write32(info, INTEL6_RP_INTERRUPT_LIMITS, maxDelay << 24 | minDelay << 16);
132 
133 	write32(info, INTEL6_RP_UP_THRESHOLD, 59400);
134 	write32(info, INTEL6_RP_DOWN_THRESHOLD, 245000);
135 	write32(info, INTEL6_RP_UP_EI, 66000);
136 	write32(info, INTEL6_RP_DOWN_EI, 350000);
137 
138 	write32(info, INTEL6_RP_IDLE_HYSTERSIS, 10);
139 	write32(info, INTEL6_RP_CONTROL, INTEL6_RP_MEDIA_TURBO
140 		| INTEL6_RP_MEDIA_HW_NORMAL_MODE | INTEL6_RP_MEDIA_IS_GFX
141 		| INTEL6_RP_ENABLE | INTEL6_RP_UP_BUSY_AVG
142 		| INTEL6_RP_DOWN_IDLE_CONT);
143 		// TODO: | (HASWELL ? GEN7_RP_DOWN_IDLE_AVG : INTEL6_RP_DOWN_IDLE_CONT));
144 
145 	// TODO: wait for (read32(INTEL6_PCODE_MAILBOX) & INTEL6_PCODE_READY)
146 	write32(info, INTEL6_PCODE_DATA, 0);
147 	write32(info, INTEL6_PCODE_MAILBOX, INTEL6_PCODE_READY
148 		| INTEL6_PCODE_WRITE_MIN_FREQ_TABLE);
149 	// TODO: wait for (read32(INTEL6_PCODE_MAILBOX) & INTEL6_PCODE_READY)
150 
151 	// TODO: check for overclock support and set.
152 
153 	// Calculate limits and enforce them
154 	uint8 gtPerfShift = (gtPerfStatus & 0xff00) >> 8;
155 	if (gtPerfShift >= maxDelay)
156 		gtPerfShift = maxDelay;
157 	uint32 limits = maxDelay << 24;
158 	if (gtPerfShift <= minDelay) {
159 		gtPerfShift = minDelay;
160 		limits |= minDelay << 16;
161 	}
162 	write32(info, INTEL6_RP_INTERRUPT_LIMITS, limits);
163 
164 	write32(info, INTEL6_RPNSWREQ, INTEL6_FREQUENCY(gtPerfShift)
165 		| INTEL6_OFFSET(0) | INTEL6_AGGRESSIVE_TURBO);
166 
167 	// Requires MSI to be enabled.
168 	write32(info, INTEL6_PMIER, INTEL6_PM_DEFERRED_EVENTS);
169 	// TODO: Review need for spin lock irq rps here?
170 	write32(info, INTEL6_PMIMR, 0);
171 	// TODO: Review need for spin unlock irq rps here?
172 	write32(info, INTEL6_PMINTRMSK, 0);
173 
174 	return B_OK;
175 }