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
26static void
27enable_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
48static void
49enable_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
86void
87set_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
182uint32
183intel_dpms_capabilities(void)
184{
185	CALLED();
186	return B_DPMS_ON | B_DPMS_SUSPEND | B_DPMS_STAND_BY | B_DPMS_OFF;
187}
188
189
190uint32
191intel_dpms_mode(void)
192{
193	CALLED();
194	return gInfo->shared_info->dpms_mode;
195}
196
197
198status_t
199intel_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