xref: /haiku/src/add-ons/accelerants/intel_extreme/dpms.cpp (revision a3e794ae459fec76826407f8ba8c94cd3535f128)
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 		do {
64 			panelStatus = read32(statusRegister);
65 		} while ((panelStatus & PANEL_STATUS_POWER_ON) == 0);
66 	} else {
67 		if ((control & PANEL_CONTROL_POWER_TARGET_ON) != 0) {
68 			write32(controlRegister, (control & ~PANEL_CONTROL_POWER_TARGET_ON)
69 				| (hasPCH ? PANEL_REGISTER_UNLOCK : 0));
70 		}
71 
72 		do {
73 			panelStatus = read32(statusRegister);
74 		} while ((panelStatus & PANEL_STATUS_POWER_ON) != 0);
75 	}
76 }
77 
78 
79 void
80 set_display_power_mode(uint32 mode)
81 {
82 	uint32 monitorMode = 0;
83 
84 	if (mode == B_DPMS_ON) {
85 		uint32 pll = read32(INTEL_DISPLAY_A_PLL);
86 		if ((pll & DISPLAY_PLL_ENABLED) == 0) {
87 			// reactivate PLL
88 			write32(INTEL_DISPLAY_A_PLL, pll);
89 			read32(INTEL_DISPLAY_A_PLL);
90 			spin(150);
91 			write32(INTEL_DISPLAY_A_PLL, pll | DISPLAY_PLL_ENABLED);
92 			read32(INTEL_DISPLAY_A_PLL);
93 			spin(150);
94 			write32(INTEL_DISPLAY_A_PLL, pll | DISPLAY_PLL_ENABLED);
95 			read32(INTEL_DISPLAY_A_PLL);
96 			spin(150);
97 		}
98 
99 		pll = read32(INTEL_DISPLAY_B_PLL);
100 		if ((pll & DISPLAY_PLL_ENABLED) == 0) {
101 			// reactivate PLL
102 			write32(INTEL_DISPLAY_B_PLL, pll);
103 			read32(INTEL_DISPLAY_B_PLL);
104 			spin(150);
105 			write32(INTEL_DISPLAY_B_PLL, pll | DISPLAY_PLL_ENABLED);
106 			read32(INTEL_DISPLAY_B_PLL);
107 			spin(150);
108 			write32(INTEL_DISPLAY_B_PLL, pll | DISPLAY_PLL_ENABLED);
109 			read32(INTEL_DISPLAY_B_PLL);
110 			spin(150);
111 		}
112 
113 		enable_all_pipes(true);
114 	}
115 
116 	wait_for_vblank();
117 
118 	switch (mode) {
119 		case B_DPMS_ON:
120 			monitorMode = DISPLAY_MONITOR_ON;
121 			break;
122 		case B_DPMS_SUSPEND:
123 			monitorMode = DISPLAY_MONITOR_SUSPEND;
124 			break;
125 		case B_DPMS_STAND_BY:
126 			monitorMode = DISPLAY_MONITOR_STAND_BY;
127 			break;
128 		case B_DPMS_OFF:
129 			monitorMode = DISPLAY_MONITOR_OFF;
130 			break;
131 	}
132 
133 	if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
134 		write32(INTEL_ANALOG_PORT, (read32(INTEL_ANALOG_PORT)
135 				& ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED))
136 			| monitorMode
137 			| (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0));
138 	}
139 
140 	if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
141 		write32(INTEL_DIGITAL_PORT_B, (read32(INTEL_DIGITAL_PORT_B)
142 				& ~(/*DISPLAY_MONITOR_MODE_MASK |*/ DISPLAY_MONITOR_PORT_ENABLED))
143 			| (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0));
144 			// TODO: monitorMode?
145 	}
146 
147 	if (mode != B_DPMS_ON)
148 		enable_all_pipes(false);
149 
150 	if (mode == B_DPMS_OFF) {
151 		write32(INTEL_DISPLAY_A_PLL, read32(INTEL_DISPLAY_A_PLL)
152 			| DISPLAY_PLL_ENABLED);
153 		write32(INTEL_DISPLAY_B_PLL, read32(INTEL_DISPLAY_B_PLL)
154 			| DISPLAY_PLL_ENABLED);
155 
156 		read32(INTEL_DISPLAY_B_PLL);
157 			// flush the possibly cached PCI bus writes
158 
159 		spin(150);
160 	}
161 
162 	if ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0)
163 		enable_lvds_panel(mode == B_DPMS_ON);
164 
165 	read32(INTEL_DISPLAY_A_BASE);
166 		// flush the possibly cached PCI bus writes
167 }
168 
169 
170 //	#pragma mark -
171 
172 
173 uint32
174 intel_dpms_capabilities(void)
175 {
176 	CALLED();
177 	return B_DPMS_ON | B_DPMS_SUSPEND | B_DPMS_STAND_BY | B_DPMS_OFF;
178 }
179 
180 
181 uint32
182 intel_dpms_mode(void)
183 {
184 	CALLED();
185 	return gInfo->shared_info->dpms_mode;
186 }
187 
188 
189 status_t
190 intel_set_dpms_mode(uint32 mode)
191 {
192 	CALLED();
193 	gInfo->shared_info->dpms_mode = mode;
194 	set_display_power_mode(mode);
195 
196 	return B_OK;
197 }
198 
199