⛏️ index : haiku.git

/*
 * Copyright 2011, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Michael Lotz, mmlr@mlotz.ch
 */


#include "PanelFitter.h"

#include <stdlib.h>
#include <string.h>
#include <Debug.h>

#include "accelerant.h"
#include "intel_extreme.h"


#undef TRACE
#define TRACE_FITTER
#ifdef TRACE_FITTER
#   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__)


// #pragma mark - PanelFitter


PanelFitter::PanelFitter(pipe_index pipeIndex)
	:
	fRegisterBase(PCH_PANEL_FITTER_BASE_REGISTER)
{
	// SkyLake has a newer type of panelfitter, called panelscaler (PS) there
	if (gInfo->shared_info->device_type.Generation() >= 9) {
		fRegisterBase += 0x100;
	}
	if (pipeIndex == INTEL_PIPE_B) {
		fRegisterBase += PCH_PANEL_FITTER_PIPE_OFFSET;
	}
	if (pipeIndex == INTEL_PIPE_C) {
		fRegisterBase += 2 * PCH_PANEL_FITTER_PIPE_OFFSET;
	}
	TRACE("%s: requested fitter #%d\n", __func__, (int)pipeIndex);

	uint32 fitCtl = read32(fRegisterBase + PCH_PANEL_FITTER_CONTROL);
	if (fitCtl & PANEL_FITTER_ENABLED) {
		if (gInfo->shared_info->device_type.Generation() <= 8) {
			TRACE("%s: this fitter is connected to pipe #%" B_PRIx32 "\n", __func__,
				((fitCtl & PANEL_FITTER_PIPE_MASK) >> 29) + 1);
		} else {
			TRACE("%s: this fitter is enabled by the BIOS\n", __func__);
		}
	} else {
		TRACE("%s: this fitter is not setup by the BIOS: Enabling.\n", __func__);
		fitCtl |= PANEL_FITTER_ENABLED;
		write32(fRegisterBase + PCH_PANEL_FITTER_CONTROL, fitCtl);
	}
}


PanelFitter::~PanelFitter()
{
}


bool
PanelFitter::IsEnabled()
{
	return (read32(fRegisterBase + PCH_PANEL_FITTER_CONTROL)
		& PANEL_FITTER_ENABLED) != 0;
}


void
PanelFitter::Enable(const display_timing& timing)
{
	_Enable(true);

	// TODO: program the window position based on the mode, setup/select filter
	// Note: for now assuming fitter was setup by BIOS and pipeA has fitterA, etc.
	TRACE("%s: PCH_PANEL_FITTER_CONTROL, 0x%" B_PRIx32 "\n", __func__, read32(fRegisterBase + PCH_PANEL_FITTER_CONTROL));
	TRACE("%s: PCH_PANEL_FITTER_WINDOW_POS, 0x%" B_PRIx32 "\n", __func__, read32(fRegisterBase + PCH_PANEL_FITTER_WINDOW_POS));

	// Window size _must_ be the last register programmed as it 'arms'/unlocks all the other ones..
	write32(fRegisterBase + PCH_PANEL_FITTER_WINDOW_SIZE, (timing.h_display << 16) | timing.v_display);
}


void
PanelFitter::Disable()
{
	_Enable(false);

	// Window size _must_ be the last register programmed as it 'arms'/unlocks all the other ones..
	write32(fRegisterBase + PCH_PANEL_FITTER_WINDOW_SIZE, 0);
}


void
PanelFitter::_Enable(bool enable)
{
	uint32 targetRegister = fRegisterBase + PCH_PANEL_FITTER_CONTROL;
	write32(targetRegister, (read32(targetRegister) & ~PANEL_FITTER_ENABLED)
		| (enable ? PANEL_FITTER_ENABLED : 0));
	read32(targetRegister);
}