1/*
2 * Copyright 2011, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Michael Lotz, mmlr@mlotz.ch
7 */
8
9
10#include "PanelFitter.h"
11
12#include <stdlib.h>
13#include <string.h>
14#include <Debug.h>
15
16#include "accelerant.h"
17#include "intel_extreme.h"
18
19
20#undef TRACE
21#define TRACE_FITTER
22#ifdef TRACE_FITTER
23#   define TRACE(x...) _sPrintf("intel_extreme: " x)
24#else
25#   define TRACE(x...)
26#endif
27
28#define ERROR(x...) _sPrintf("intel_extreme: " x)
29#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
30
31
32// #pragma mark - PanelFitter
33
34
35PanelFitter::PanelFitter(pipe_index pipeIndex)
36	:
37	fRegisterBase(PCH_PANEL_FITTER_BASE_REGISTER)
38{
39	// SkyLake has a newer type of panelfitter, called panelscaler (PS) there
40	if (gInfo->shared_info->device_type.Generation() >= 9) {
41		fRegisterBase += 0x100;
42	}
43	if (pipeIndex == INTEL_PIPE_B) {
44		fRegisterBase += PCH_PANEL_FITTER_PIPE_OFFSET;
45	}
46	if (pipeIndex == INTEL_PIPE_C) {
47		fRegisterBase += 2 * PCH_PANEL_FITTER_PIPE_OFFSET;
48	}
49	TRACE("%s: requested fitter #%d\n", __func__, (int)pipeIndex);
50
51	uint32 fitCtl = read32(fRegisterBase + PCH_PANEL_FITTER_CONTROL);
52	if (fitCtl & PANEL_FITTER_ENABLED) {
53		if (gInfo->shared_info->device_type.Generation() <= 8) {
54			TRACE("%s: this fitter is connected to pipe #%" B_PRIx32 "\n", __func__,
55				((fitCtl & PANEL_FITTER_PIPE_MASK) >> 29) + 1);
56		} else {
57			TRACE("%s: this fitter is enabled by the BIOS\n", __func__);
58		}
59	} else {
60		TRACE("%s: this fitter is not setup by the BIOS: Enabling.\n", __func__);
61		fitCtl |= PANEL_FITTER_ENABLED;
62		write32(fRegisterBase + PCH_PANEL_FITTER_CONTROL, fitCtl);
63	}
64}
65
66
67PanelFitter::~PanelFitter()
68{
69}
70
71
72bool
73PanelFitter::IsEnabled()
74{
75	return (read32(fRegisterBase + PCH_PANEL_FITTER_CONTROL)
76		& PANEL_FITTER_ENABLED) != 0;
77}
78
79
80void
81PanelFitter::Enable(const display_timing& timing)
82{
83	_Enable(true);
84
85	// TODO: program the window position based on the mode, setup/select filter
86	// Note: for now assuming fitter was setup by BIOS and pipeA has fitterA, etc.
87	TRACE("%s: PCH_PANEL_FITTER_CONTROL, 0x%" B_PRIx32 "\n", __func__, read32(fRegisterBase + PCH_PANEL_FITTER_CONTROL));
88	TRACE("%s: PCH_PANEL_FITTER_WINDOW_POS, 0x%" B_PRIx32 "\n", __func__, read32(fRegisterBase + PCH_PANEL_FITTER_WINDOW_POS));
89
90	// Window size _must_ be the last register programmed as it 'arms'/unlocks all the other ones..
91	write32(fRegisterBase + PCH_PANEL_FITTER_WINDOW_SIZE, (timing.h_display << 16) | timing.v_display);
92}
93
94
95void
96PanelFitter::Disable()
97{
98	_Enable(false);
99
100	// Window size _must_ be the last register programmed as it 'arms'/unlocks all the other ones..
101	write32(fRegisterBase + PCH_PANEL_FITTER_WINDOW_SIZE, 0);
102}
103
104
105void
106PanelFitter::_Enable(bool enable)
107{
108	uint32 targetRegister = fRegisterBase + PCH_PANEL_FITTER_CONTROL;
109	write32(targetRegister, (read32(targetRegister) & ~PANEL_FITTER_ENABLED)
110		| (enable ? PANEL_FITTER_ENABLED : 0));
111	read32(targetRegister);
112}
113