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