xref: /haiku/src/add-ons/accelerants/intel_extreme/dpms.cpp (revision 60c26cd332a044bb9003091b9196cc404ebe5482)
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 automatically
31 		if (gInfo->head_mode & HEAD_MODE_A_ANALOG)
32 			write32(INTEL_DISPLAY_A_CONTROL, planeAControl | DISPLAY_CONTROL_ENABLED);
33 		if (gInfo->head_mode & HEAD_MODE_B_DIGITAL)
34 			write32(INTEL_DISPLAY_B_CONTROL, planeBControl | DISPLAY_CONTROL_ENABLED);
35 
36 		read32(INTEL_DISPLAY_A_BASE);
37 			// flush the eventually cached PCI bus writes
38 	} else {
39 		// when disabling it, we have to trigger the update using a write to
40 		// the display base address
41 		if (gInfo->head_mode & HEAD_MODE_A_ANALOG)
42 			write32(INTEL_DISPLAY_A_CONTROL, planeAControl & ~DISPLAY_CONTROL_ENABLED);
43 		if (gInfo->head_mode & HEAD_MODE_B_DIGITAL)
44 			write32(INTEL_DISPLAY_B_CONTROL, planeBControl & ~DISPLAY_CONTROL_ENABLED);
45 
46 		set_frame_buffer_base();
47 	}
48 }
49 
50 
51 static void
52 enable_display_pipe(bool enable)
53 {
54 	uint32 pipeAControl = read32(INTEL_DISPLAY_A_PIPE_CONTROL);
55 	uint32 pipeBControl = read32(INTEL_DISPLAY_B_PIPE_CONTROL);
56 
57 	if (enable) {
58 		if (gInfo->head_mode & HEAD_MODE_A_ANALOG)
59 			write32(INTEL_DISPLAY_A_PIPE_CONTROL, pipeAControl | DISPLAY_PIPE_ENABLED);
60 		if (gInfo->head_mode & HEAD_MODE_B_DIGITAL)
61 			write32(INTEL_DISPLAY_B_PIPE_CONTROL, pipeBControl | DISPLAY_PIPE_ENABLED);
62 	} else {
63 		if (gInfo->head_mode & HEAD_MODE_A_ANALOG)
64 			write32(INTEL_DISPLAY_A_PIPE_CONTROL, pipeAControl & ~DISPLAY_PIPE_ENABLED);
65 		if (gInfo->head_mode & HEAD_MODE_B_DIGITAL)
66 			write32(INTEL_DISPLAY_B_PIPE_CONTROL, pipeBControl & ~DISPLAY_PIPE_ENABLED);
67 	}
68 
69 	read32(INTEL_DISPLAY_A_BASE);
70 		// flush the eventually cached PCI bus writes
71 }
72 
73 
74 static void
75 enable_lvds_panel(bool enable)
76 {
77 	uint32 control = read32(INTEL_PANEL_CONTROL);
78 	uint32 panelStatus;
79 
80 	if (enable) {
81 		if ((control & PANEL_CONTROL_POWER_TARGET_ON) == 0) {
82 			write32(INTEL_PANEL_CONTROL, control
83 				| PANEL_CONTROL_POWER_TARGET_ON);
84 		}
85 
86 		do {
87 			panelStatus = read32(INTEL_PANEL_STATUS);
88 		} while ((panelStatus & PANEL_STATUS_POWER_ON) == 0);
89 	} else {
90 		if ((control & PANEL_CONTROL_POWER_TARGET_ON) != 0) {
91 			write32(INTEL_PANEL_CONTROL, control
92 				& ~PANEL_CONTROL_POWER_TARGET_ON);
93 		}
94 
95 		do {
96 			panelStatus = read32(INTEL_PANEL_STATUS);
97 		} while ((panelStatus & PANEL_STATUS_POWER_ON) != 0);
98 	}
99 }
100 
101 
102 void
103 set_display_power_mode(uint32 mode)
104 {
105 	uint32 monitorMode = 0;
106 
107 	if (mode == B_DPMS_ON) {
108 		uint32 pll = read32(INTEL_DISPLAY_A_PLL);
109 		if ((pll & DISPLAY_PLL_ENABLED) == 0) {
110 			// reactivate PLL
111 			write32(INTEL_DISPLAY_A_PLL, pll);
112 			read32(INTEL_DISPLAY_A_PLL);
113 			spin(150);
114 			write32(INTEL_DISPLAY_A_PLL, pll | DISPLAY_PLL_ENABLED);
115 			read32(INTEL_DISPLAY_A_PLL);
116 			spin(150);
117 			write32(INTEL_DISPLAY_A_PLL, pll | DISPLAY_PLL_ENABLED);
118 			read32(INTEL_DISPLAY_A_PLL);
119 			spin(150);
120 		}
121 
122 		pll = read32(INTEL_DISPLAY_B_PLL);
123 		if ((pll & DISPLAY_PLL_ENABLED) == 0) {
124 			// reactivate PLL
125 			write32(INTEL_DISPLAY_B_PLL, pll);
126 			read32(INTEL_DISPLAY_B_PLL);
127 			spin(150);
128 			write32(INTEL_DISPLAY_B_PLL, pll | DISPLAY_PLL_ENABLED);
129 			read32(INTEL_DISPLAY_B_PLL);
130 			spin(150);
131 			write32(INTEL_DISPLAY_B_PLL, pll | DISPLAY_PLL_ENABLED);
132 			read32(INTEL_DISPLAY_B_PLL);
133 			spin(150);
134 		}
135 
136 		enable_display_pipe(true);
137 		enable_display_plane(true);
138 	}
139 
140 	wait_for_vblank();
141 
142 	switch (mode) {
143 		case B_DPMS_ON:
144 			monitorMode = DISPLAY_MONITOR_ON;
145 			break;
146 		case B_DPMS_SUSPEND:
147 			monitorMode = DISPLAY_MONITOR_SUSPEND;
148 			break;
149 		case B_DPMS_STAND_BY:
150 			monitorMode = DISPLAY_MONITOR_STAND_BY;
151 			break;
152 		case B_DPMS_OFF:
153 			monitorMode = DISPLAY_MONITOR_OFF;
154 			break;
155 	}
156 
157 	if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
158 		write32(INTEL_DISPLAY_A_ANALOG_PORT, (read32(INTEL_DISPLAY_A_ANALOG_PORT)
159 			& ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED))
160 			| monitorMode | (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0));
161 	}
162 	if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
163 		write32(INTEL_DISPLAY_B_DIGITAL_PORT, (read32(INTEL_DISPLAY_B_DIGITAL_PORT)
164 			& ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED))
165 			| (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0));
166 			// TODO: monitorMode?
167 	}
168 
169 	if (mode != B_DPMS_ON) {
170 		enable_display_plane(false);
171 		wait_for_vblank();
172 		enable_display_pipe(false);
173 	}
174 
175 	if (mode == B_DPMS_OFF) {
176 		write32(INTEL_DISPLAY_A_PLL, read32(INTEL_DISPLAY_A_PLL)
177 			| DISPLAY_PLL_ENABLED);
178 		write32(INTEL_DISPLAY_B_PLL, read32(INTEL_DISPLAY_B_PLL)
179 			| DISPLAY_PLL_ENABLED);
180 
181 		read32(INTEL_DISPLAY_B_PLL);
182 			// flush the eventually cached PCI bus writes
183 
184 		spin(150);
185 	}
186 
187 	if ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0)
188 		enable_lvds_panel(mode == B_DPMS_ON);
189 
190 	read32(INTEL_DISPLAY_A_BASE);
191 		// flush the eventually cached PCI bus writes
192 }
193 
194 
195 //	#pragma mark -
196 
197 
198 uint32
199 intel_dpms_capabilities(void)
200 {
201 	TRACE(("intel_dpms_capabilities()\n"));
202 	return B_DPMS_ON | B_DPMS_SUSPEND | B_DPMS_STAND_BY | B_DPMS_OFF;
203 }
204 
205 
206 uint32
207 intel_dpms_mode(void)
208 {
209 	TRACE(("intel_dpms_mode()\n"));
210 	return gInfo->shared_info->dpms_mode;
211 }
212 
213 
214 status_t
215 intel_set_dpms_mode(uint32 mode)
216 {
217 	TRACE(("intel_set_dpms_mode()\n"));
218 	gInfo->shared_info->dpms_mode = mode;
219 	set_display_power_mode(mode);
220 
221 	return B_OK;
222 }
223 
224