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