⛏️ index : haiku.git

/*
 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Axel DΓΆrfler, axeld@pinc-software.de
 */


#include "accelerant_protos.h"
#include "accelerant.h"


#undef TRACE
//#define TRACE_DPMS
#ifdef TRACE_DPMS
#	define TRACE(x...) _sPrintf("intel_extreme: " x)
#else
#	define TRACE(x...)
#endif

#define ERROR(x...) _sPrintf("intel_extreme: " x)
#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)


static void
enable_all_pipes(bool enable)
{
	// Go over each port and enable pipe/plane
	for (uint32 i = 0; i < gInfo->port_count; i++) {
		if (gInfo->ports[i] == NULL)
			continue;
		if (!gInfo->ports[i]->IsConnected())
			continue;
		if (gInfo->ports[i]->GetPipe() == NULL)
			continue;

		gInfo->ports[i]->Power(enable);
	}

	read32(INTEL_DISPLAY_A_BASE);
		// flush the possibly cached PCI bus writes

	set_frame_buffer_base();
}


static void
enable_lvds_panel(bool enable)
{
	bool hasPCH = (gInfo->shared_info->pch_info != INTEL_PCH_NONE);

	int controlRegister = hasPCH ? PCH_PANEL_CONTROL : INTEL_PANEL_CONTROL;
	int statusRegister = hasPCH ? PCH_PANEL_STATUS : INTEL_PANEL_STATUS;

	uint32 control = read32(controlRegister);
	uint32 panelStatus;

	if (enable) {
		if ((control & PANEL_CONTROL_POWER_TARGET_ON) == 0) {
			write32(controlRegister, control | PANEL_CONTROL_POWER_TARGET_ON
				/*| (hasPCH ? PANEL_REGISTER_UNLOCK : 0)*/);
		}

		if (!hasPCH) {
			do {
				panelStatus = read32(statusRegister);
			} while ((panelStatus & PANEL_STATUS_POWER_ON) == 0);
		}
	} else {
		if ((control & PANEL_CONTROL_POWER_TARGET_ON) != 0) {
			write32(controlRegister, (control & ~PANEL_CONTROL_POWER_TARGET_ON)
				/*| (hasPCH ? PANEL_REGISTER_UNLOCK : 0)*/);
		}

		if (!hasPCH)
		{
			do {
				panelStatus = read32(statusRegister);
			} while ((panelStatus & PANEL_STATUS_POWER_ON) != 0);
		}
	}
}


void
set_display_power_mode(uint32 mode)
{
	uint32 monitorMode = 0;

	if (mode == B_DPMS_ON) {
		uint32 pll = read32(INTEL_DISPLAY_A_PLL);
		if ((pll & DISPLAY_PLL_ENABLED) == 0) {
			// reactivate PLL
			write32(INTEL_DISPLAY_A_PLL, pll);
			read32(INTEL_DISPLAY_A_PLL);
			spin(150);
			write32(INTEL_DISPLAY_A_PLL, pll | DISPLAY_PLL_ENABLED);
			read32(INTEL_DISPLAY_A_PLL);
			spin(150);
			write32(INTEL_DISPLAY_A_PLL, pll | DISPLAY_PLL_ENABLED);
			read32(INTEL_DISPLAY_A_PLL);
			spin(150);
		}

		pll = read32(INTEL_DISPLAY_B_PLL);
		if ((pll & DISPLAY_PLL_ENABLED) == 0) {
			// reactivate PLL
			write32(INTEL_DISPLAY_B_PLL, pll);
			read32(INTEL_DISPLAY_B_PLL);
			spin(150);
			write32(INTEL_DISPLAY_B_PLL, pll | DISPLAY_PLL_ENABLED);
			read32(INTEL_DISPLAY_B_PLL);
			spin(150);
			write32(INTEL_DISPLAY_B_PLL, pll | DISPLAY_PLL_ENABLED);
			read32(INTEL_DISPLAY_B_PLL);
			spin(150);
		}

		enable_all_pipes(true);
	}

	wait_for_vblank();

	switch (mode) {
		case B_DPMS_ON:
			monitorMode = DISPLAY_MONITOR_ON;
			break;
		case B_DPMS_SUSPEND:
			monitorMode = DISPLAY_MONITOR_SUSPEND;
			break;
		case B_DPMS_STAND_BY:
			monitorMode = DISPLAY_MONITOR_STAND_BY;
			break;
		case B_DPMS_OFF:
			monitorMode = DISPLAY_MONITOR_OFF;
			break;
	}

	//fixme: port DPMS programming should better be in Ports.cpp. Resetup..
	if (gInfo->head_mode & HEAD_MODE_A_ANALOG) {
		write32(INTEL_ANALOG_PORT, (read32(INTEL_ANALOG_PORT)
				& ~(DISPLAY_MONITOR_MODE_MASK | DISPLAY_MONITOR_PORT_ENABLED))
			| monitorMode
			| (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0));
	}

	//fixme: port DPMS programming should better be in Ports.cpp and is faulty. Resetup..
	if (false) {//gInfo->head_mode & HEAD_MODE_B_DIGITAL) {
		write32(INTEL_DIGITAL_PORT_B, (read32(INTEL_DIGITAL_PORT_B)
				& ~(/*DISPLAY_MONITOR_MODE_MASK |*/ DISPLAY_MONITOR_PORT_ENABLED))
			| (mode != B_DPMS_OFF ? DISPLAY_MONITOR_PORT_ENABLED : 0));
			// TODO: monitorMode?
	}

	if (mode != B_DPMS_ON)
		enable_all_pipes(false);

	if (mode == B_DPMS_OFF) {
		write32(INTEL_DISPLAY_A_PLL, read32(INTEL_DISPLAY_A_PLL)
			| DISPLAY_PLL_ENABLED);
		write32(INTEL_DISPLAY_B_PLL, read32(INTEL_DISPLAY_B_PLL)
			| DISPLAY_PLL_ENABLED);

		read32(INTEL_DISPLAY_B_PLL);
			// flush the possibly cached PCI bus writes

		spin(150);
	}

	if ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0)
		enable_lvds_panel(mode == B_DPMS_ON);

	read32(INTEL_DISPLAY_A_BASE);
		// flush the possibly cached PCI bus writes
}


//	#pragma mark -


uint32
intel_dpms_capabilities(void)
{
	CALLED();
	return B_DPMS_ON | B_DPMS_SUSPEND | B_DPMS_STAND_BY | B_DPMS_OFF;
}


uint32
intel_dpms_mode(void)
{
	CALLED();
	return gInfo->shared_info->dpms_mode;
}


status_t
intel_set_dpms_mode(uint32 mode)
{
	CALLED();
	gInfo->shared_info->dpms_mode = mode;
	set_display_power_mode(mode);

	return B_OK;
}