xref: /haiku/src/add-ons/accelerants/intel_extreme/dpms.cpp (revision 79d6f0870e70cb72a2bbd7910e05cb531335e9b7)
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: " x)
18 #else
19 #	define TRACE(x...)
20 #endif
21 
22 #define ERROR(x...) _sPrintf("intel_extreme: " x)
23 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
24 
25 
26 static void
27 enable_all_pipes(bool enable)
28 {
29 	// Go over each port and enable pipe/plane
30 	for (uint32 i = 0; i < gInfo->port_count; i++) {
31 		if (gInfo->ports[i] == NULL)
32 			continue;
33 		if (!gInfo->ports[i]->IsConnected())
34 			continue;
35 
36 		gInfo->ports[i]->Power(enable);
37 	}
38 
39 	read32(INTEL_DISPLAY_A_BASE);
40 		// flush the possibly cached PCI bus writes
41 
42 	set_frame_buffer_base();
43 }
44 
45 
46 static void
47 enable_lvds_panel(bool enable)
48 {
49 	bool hasPCH = (gInfo->shared_info->pch_info != INTEL_PCH_NONE);
50 
51 	int controlRegister = hasPCH ? PCH_PANEL_CONTROL : INTEL_PANEL_CONTROL;
52 	int statusRegister = hasPCH ? PCH_PANEL_STATUS : INTEL_PANEL_STATUS;
53 
54 	uint32 control = read32(controlRegister);
55 	uint32 panelStatus;
56 
57 	if (enable) {
58 		if ((control & PANEL_CONTROL_POWER_TARGET_ON) == 0) {
59 			write32(controlRegister, control | PANEL_CONTROL_POWER_TARGET_ON
60 				/*| (hasPCH ? PANEL_REGISTER_UNLOCK : 0)*/);
61 		}
62 
63 		if (!hasPCH) {
64 			do {
65 				panelStatus = read32(statusRegister);
66 			} while ((panelStatus & PANEL_STATUS_POWER_ON) == 0);
67 		}
68 	} else {
69 		if ((control & PANEL_CONTROL_POWER_TARGET_ON) != 0) {
70 			write32(controlRegister, (control & ~PANEL_CONTROL_POWER_TARGET_ON)
71 				/*| (hasPCH ? PANEL_REGISTER_UNLOCK : 0)*/);
72 		}
73 
74 		if (!hasPCH)
75 		{
76 			do {
77 				panelStatus = read32(statusRegister);
78 			} while ((panelStatus & PANEL_STATUS_POWER_ON) != 0);
79 		}
80 	}
81 }
82 
83 
84 void
85 set_display_power_mode(uint32 mode)
86 {
87 	uint32 monitorMode = 0;
88 
89 	if (mode == B_DPMS_ON) {
90 		uint32 pll = read32(INTEL_DISPLAY_A_PLL);
91 		if ((pll & DISPLAY_PLL_ENABLED) == 0) {
92 			// reactivate PLL
93 			write32(INTEL_DISPLAY_A_PLL, pll);
94 			read32(INTEL_DISPLAY_A_PLL);
95 			spin(150);
96 			write32(INTEL_DISPLAY_A_PLL, pll | DISPLAY_PLL_ENABLED);
97 			read32(INTEL_DISPLAY_A_PLL);
98 			spin(150);
99 			write32(INTEL_DISPLAY_A_PLL, pll | DISPLAY_PLL_ENABLED);
100 			read32(INTEL_DISPLAY_A_PLL);
101 			spin(150);
102 		}
103 
104 		pll = read32(INTEL_DISPLAY_B_PLL);
105 		if ((pll & DISPLAY_PLL_ENABLED) == 0) {
106 			// reactivate PLL
107 			write32(INTEL_DISPLAY_B_PLL, pll);
108 			read32(INTEL_DISPLAY_B_PLL);
109 			spin(150);
110 			write32(INTEL_DISPLAY_B_PLL, pll | DISPLAY_PLL_ENABLED);
111 			read32(INTEL_DISPLAY_B_PLL);
112 			spin(150);
113 			write32(INTEL_DISPLAY_B_PLL, pll | DISPLAY_PLL_ENABLED);
114 			read32(INTEL_DISPLAY_B_PLL);
115 			spin(150);
116 		}
117 
118 		enable_all_pipes(true);
119 	}
120 
121 	wait_for_vblank();
122 
123 	switch (mode) {
124 		case B_DPMS_ON:
125 			monitorMode = DISPLAY_MONITOR_ON;
126 			break;
127 		case B_DPMS_SUSPEND:
128 			monitorMode = DISPLAY_MONITOR_SUSPEND;
129 			break;
130 		case B_DPMS_STAND_BY:
131 			monitorMode = DISPLAY_MONITOR_STAND_BY;
132 			break;
133 		case B_DPMS_OFF:
134 			monitorMode = DISPLAY_MONITOR_OFF;
135 			break;
136 	}
137 
138 	if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
139 		write32(INTEL_ANALOG_PORT, (read32(INTEL_ANALOG_PORT)
140 				& ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED))
141 			| monitorMode
142 			| (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0));
143 	}
144 
145 	if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
146 		write32(INTEL_DIGITAL_PORT_B, (read32(INTEL_DIGITAL_PORT_B)
147 				& ~(/*DISPLAY_MONITOR_MODE_MASK |*/ DISPLAY_MONITOR_PORT_ENABLED))
148 			| (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0));
149 			// TODO: monitorMode?
150 	}
151 
152 	if (mode != B_DPMS_ON)
153 		enable_all_pipes(false);
154 
155 	if (mode == B_DPMS_OFF) {
156 		write32(INTEL_DISPLAY_A_PLL, read32(INTEL_DISPLAY_A_PLL)
157 			| DISPLAY_PLL_ENABLED);
158 		write32(INTEL_DISPLAY_B_PLL, read32(INTEL_DISPLAY_B_PLL)
159 			| DISPLAY_PLL_ENABLED);
160 
161 		read32(INTEL_DISPLAY_B_PLL);
162 			// flush the possibly cached PCI bus writes
163 
164 		spin(150);
165 	}
166 
167 	if ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0)
168 		enable_lvds_panel(mode == B_DPMS_ON);
169 
170 	read32(INTEL_DISPLAY_A_BASE);
171 		// flush the possibly cached PCI bus writes
172 }
173 
174 
175 //	#pragma mark -
176 
177 
178 uint32
179 intel_dpms_capabilities(void)
180 {
181 	CALLED();
182 	return B_DPMS_ON | B_DPMS_SUSPEND | B_DPMS_STAND_BY | B_DPMS_OFF;
183 }
184 
185 
186 uint32
187 intel_dpms_mode(void)
188 {
189 	CALLED();
190 	return gInfo->shared_info->dpms_mode;
191 }
192 
193 
194 status_t
195 intel_set_dpms_mode(uint32 mode)
196 {
197 	CALLED();
198 	gInfo->shared_info->dpms_mode = mode;
199 	set_display_power_mode(mode);
200 
201 	return B_OK;
202 }
203 
204