xref: /haiku/src/add-ons/accelerants/intel_extreme/dpms.cpp (revision 2b76973fa2401f7a5edf68e6470f3d3210cbcff3)
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 
14 #undef TRACE
15 //#define TRACE_DPMS
16 #ifdef TRACE_DPMS
17 #	define TRACE(x...) _sPrintf("intel_extreme accelerant:" x)
18 #else
19 #	define TRACE(x...)
20 #endif
21 
22 #define ERROR(x...) _sPrintf("intel_extreme accelerant: " x)
23 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
24 
25 
26 void
27 enable_display_plane(bool enable)
28 {
29 	uint32 planeAControl = read32(INTEL_DISPLAY_A_CONTROL);
30 	uint32 planeBControl = read32(INTEL_DISPLAY_B_CONTROL);
31 
32 	if (enable) {
33 		// when enabling the display, the register values are updated
34 		// automatically
35 		if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
36 			write32(INTEL_DISPLAY_A_CONTROL,
37 				planeAControl | DISPLAY_CONTROL_ENABLED);
38 		}
39 
40 		if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
41 			write32(INTEL_DISPLAY_B_CONTROL,
42 				planeBControl | DISPLAY_CONTROL_ENABLED);
43 		}
44 
45 		read32(INTEL_DISPLAY_A_BASE);
46 			// flush the eventually cached PCI bus writes
47 	} else {
48 		// when disabling it, we have to trigger the update using a write to
49 		// the display base address
50 		if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
51 			write32(INTEL_DISPLAY_A_CONTROL,
52 				planeAControl & ~DISPLAY_CONTROL_ENABLED);
53 		}
54 
55 		if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
56 			write32(INTEL_DISPLAY_B_CONTROL,
57 				planeBControl & ~DISPLAY_CONTROL_ENABLED);
58 		}
59 
60 		set_frame_buffer_base();
61 	}
62 }
63 
64 
65 static void
66 enable_display_pipe(bool enable)
67 {
68 	uint32 pipeAControl = read32(INTEL_DISPLAY_A_PIPE_CONTROL);
69 	uint32 pipeBControl = read32(INTEL_DISPLAY_B_PIPE_CONTROL);
70 
71 	if (enable) {
72 		if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
73 			write32(INTEL_DISPLAY_A_PIPE_CONTROL,
74 				pipeAControl | DISPLAY_PIPE_ENABLED);
75 		}
76 
77 		if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
78 			write32(INTEL_DISPLAY_B_PIPE_CONTROL,
79 				pipeBControl | DISPLAY_PIPE_ENABLED);
80 		}
81 	} else {
82 		if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
83 			write32(INTEL_DISPLAY_A_PIPE_CONTROL,
84 				pipeAControl & ~DISPLAY_PIPE_ENABLED);
85 		}
86 
87 		if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
88 			write32(INTEL_DISPLAY_B_PIPE_CONTROL,
89 				pipeBControl & ~DISPLAY_PIPE_ENABLED);
90 		}
91 	}
92 
93 	read32(INTEL_DISPLAY_A_BASE);
94 		// flush the eventually cached PCI bus writes
95 }
96 
97 
98 static void
99 enable_lvds_panel(bool enable)
100 {
101 	bool hasPCH = gInfo->shared_info->device_type.HasPlatformControlHub();
102 	if (hasPCH) {
103 		// TODO: fix for PCH
104 		return;
105 	}
106 
107 	int controlRegister = hasPCH ? PCH_PANEL_CONTROL : INTEL_PANEL_CONTROL;
108 	int statusRegister = hasPCH ? PCH_PANEL_STATUS : INTEL_PANEL_STATUS;
109 
110 	uint32 control = read32(controlRegister);
111 	uint32 panelStatus;
112 
113 	if (enable) {
114 		if ((control & PANEL_CONTROL_POWER_TARGET_ON) == 0) {
115 			write32(controlRegister, control | PANEL_CONTROL_POWER_TARGET_ON
116 				| (hasPCH ? PANEL_REGISTER_UNLOCK : 0));
117 		}
118 
119 		do {
120 			panelStatus = read32(statusRegister);
121 		} while ((panelStatus & PANEL_STATUS_POWER_ON) == 0);
122 	} else {
123 		if ((control & PANEL_CONTROL_POWER_TARGET_ON) != 0) {
124 			write32(controlRegister, (control & ~PANEL_CONTROL_POWER_TARGET_ON)
125 				| (hasPCH ? PANEL_REGISTER_UNLOCK : 0));
126 		}
127 
128 		do {
129 			panelStatus = read32(statusRegister);
130 		} while ((panelStatus & PANEL_STATUS_POWER_ON) != 0);
131 	}
132 }
133 
134 
135 void
136 set_display_power_mode(uint32 mode)
137 {
138 	uint32 monitorMode = 0;
139 
140 	if (mode == B_DPMS_ON) {
141 		uint32 pll = read32(INTEL_DISPLAY_A_PLL);
142 		if ((pll & DISPLAY_PLL_ENABLED) == 0) {
143 			// reactivate PLL
144 			write32(INTEL_DISPLAY_A_PLL, pll);
145 			read32(INTEL_DISPLAY_A_PLL);
146 			spin(150);
147 			write32(INTEL_DISPLAY_A_PLL, pll | DISPLAY_PLL_ENABLED);
148 			read32(INTEL_DISPLAY_A_PLL);
149 			spin(150);
150 			write32(INTEL_DISPLAY_A_PLL, pll | DISPLAY_PLL_ENABLED);
151 			read32(INTEL_DISPLAY_A_PLL);
152 			spin(150);
153 		}
154 
155 		pll = read32(INTEL_DISPLAY_B_PLL);
156 		if ((pll & DISPLAY_PLL_ENABLED) == 0) {
157 			// reactivate PLL
158 			write32(INTEL_DISPLAY_B_PLL, pll);
159 			read32(INTEL_DISPLAY_B_PLL);
160 			spin(150);
161 			write32(INTEL_DISPLAY_B_PLL, pll | DISPLAY_PLL_ENABLED);
162 			read32(INTEL_DISPLAY_B_PLL);
163 			spin(150);
164 			write32(INTEL_DISPLAY_B_PLL, pll | DISPLAY_PLL_ENABLED);
165 			read32(INTEL_DISPLAY_B_PLL);
166 			spin(150);
167 		}
168 
169 		enable_display_pipe(true);
170 		enable_display_plane(true);
171 	}
172 
173 	wait_for_vblank();
174 
175 	switch (mode) {
176 		case B_DPMS_ON:
177 			monitorMode = DISPLAY_MONITOR_ON;
178 			break;
179 		case B_DPMS_SUSPEND:
180 			monitorMode = DISPLAY_MONITOR_SUSPEND;
181 			break;
182 		case B_DPMS_STAND_BY:
183 			monitorMode = DISPLAY_MONITOR_STAND_BY;
184 			break;
185 		case B_DPMS_OFF:
186 			monitorMode = DISPLAY_MONITOR_OFF;
187 			break;
188 	}
189 
190 	if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
191 		write32(INTEL_DISPLAY_A_ANALOG_PORT,
192 			(read32(INTEL_DISPLAY_A_ANALOG_PORT)
193 				& ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED))
194 			| monitorMode
195 			| (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0));
196 	}
197 	if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
198 		write32(INTEL_DISPLAY_B_DIGITAL_PORT,
199 			(read32(INTEL_DISPLAY_B_DIGITAL_PORT)
200 				& ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED))
201 			| (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0));
202 			// TODO: monitorMode?
203 	}
204 
205 	if (mode != B_DPMS_ON) {
206 		enable_display_plane(false);
207 		wait_for_vblank();
208 		enable_display_pipe(false);
209 	}
210 
211 	if (mode == B_DPMS_OFF) {
212 		write32(INTEL_DISPLAY_A_PLL, read32(INTEL_DISPLAY_A_PLL)
213 			| DISPLAY_PLL_ENABLED);
214 		write32(INTEL_DISPLAY_B_PLL, read32(INTEL_DISPLAY_B_PLL)
215 			| DISPLAY_PLL_ENABLED);
216 
217 		read32(INTEL_DISPLAY_B_PLL);
218 			// flush the possibly cached PCI bus writes
219 
220 		spin(150);
221 	}
222 
223 	if ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0)
224 		enable_lvds_panel(mode == B_DPMS_ON);
225 
226 	read32(INTEL_DISPLAY_A_BASE);
227 		// flush the possibly cached PCI bus writes
228 }
229 
230 
231 //	#pragma mark -
232 
233 
234 uint32
235 intel_dpms_capabilities(void)
236 {
237 	CALLED();
238 	return B_DPMS_ON | B_DPMS_SUSPEND | B_DPMS_STAND_BY | B_DPMS_OFF;
239 }
240 
241 
242 uint32
243 intel_dpms_mode(void)
244 {
245 	CALLED();
246 	return gInfo->shared_info->dpms_mode;
247 }
248 
249 
250 status_t
251 intel_set_dpms_mode(uint32 mode)
252 {
253 	CALLED();
254 	gInfo->shared_info->dpms_mode = mode;
255 	set_display_power_mode(mode);
256 
257 	return B_OK;
258 }
259 
260