Subversion Repositories Kolibri OS

Rev

Rev 5354 | Rev 6660 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2330 Serge 1
/*
2
 * Copyright © 2006-2007 Intel Corporation
3
 * Copyright (c) 2006 Dave Airlie 
4
 *
5
 * Permission is hereby granted, free of charge, to any person obtaining a
6
 * copy of this software and associated documentation files (the "Software"),
7
 * to deal in the Software without restriction, including without limitation
8
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
 * and/or sell copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following conditions:
11
 *
12
 * The above copyright notice and this permission notice (including the next
13
 * paragraph) shall be included in all copies or substantial portions of the
14
 * Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
 * DEALINGS IN THE SOFTWARE.
23
 *
24
 * Authors:
25
 *	Eric Anholt 
26
 *      Dave Airlie 
27
 *      Jesse Barnes 
28
 */
29
 
30
//#include 
5097 serge 31
#include 
2330 Serge 32
#include 
33
#include 
3031 serge 34
#include 
6084 serge 35
#include 
3031 serge 36
#include 
37
#include 
2330 Serge 38
#include "intel_drv.h"
3031 serge 39
#include 
2330 Serge 40
#include "i915_drv.h"
41
//#include 
42
 
43
/* Private structure for the integrated LVDS support */
3243 Serge 44
struct intel_lvds_connector {
45
	struct intel_connector base;
46
 
47
//	struct notifier_block lid_notifier;
48
};
49
 
50
struct intel_lvds_encoder {
2330 Serge 51
	struct intel_encoder base;
52
 
3480 Serge 53
	bool is_dual_link;
54
	u32 reg;
5060 serge 55
	u32 a3_power;
2330 Serge 56
 
3243 Serge 57
	struct intel_lvds_connector *attached_connector;
2330 Serge 58
};
59
 
3243 Serge 60
static struct intel_lvds_encoder *to_lvds_encoder(struct drm_encoder *encoder)
2330 Serge 61
{
3243 Serge 62
	return container_of(encoder, struct intel_lvds_encoder, base.base);
2330 Serge 63
}
64
 
3243 Serge 65
static struct intel_lvds_connector *to_lvds_connector(struct drm_connector *connector)
2330 Serge 66
{
3243 Serge 67
	return container_of(connector, struct intel_lvds_connector, base.base);
2330 Serge 68
}
69
 
3031 serge 70
static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
71
				    enum pipe *pipe)
72
{
73
	struct drm_device *dev = encoder->base.dev;
74
	struct drm_i915_private *dev_priv = dev->dev_private;
3480 Serge 75
	struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
5060 serge 76
	enum intel_display_power_domain power_domain;
3480 Serge 77
	u32 tmp;
3031 serge 78
 
5060 serge 79
	power_domain = intel_display_port_power_domain(encoder);
5354 serge 80
	if (!intel_display_power_is_enabled(dev_priv, power_domain))
5060 serge 81
		return false;
82
 
3480 Serge 83
	tmp = I915_READ(lvds_encoder->reg);
3031 serge 84
 
85
	if (!(tmp & LVDS_PORT_EN))
86
		return false;
87
 
88
	if (HAS_PCH_CPT(dev))
89
		*pipe = PORT_TO_PIPE_CPT(tmp);
90
	else
91
		*pipe = PORT_TO_PIPE(tmp);
92
 
93
	return true;
94
}
95
 
4104 Serge 96
static void intel_lvds_get_config(struct intel_encoder *encoder,
6084 serge 97
				  struct intel_crtc_state *pipe_config)
4104 Serge 98
{
99
	struct drm_device *dev = encoder->base.dev;
100
	struct drm_i915_private *dev_priv = dev->dev_private;
6084 serge 101
	struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
102
	u32 tmp, flags = 0;
4560 Serge 103
	int dotclock;
4104 Serge 104
 
6084 serge 105
	tmp = I915_READ(lvds_encoder->reg);
4104 Serge 106
	if (tmp & LVDS_HSYNC_POLARITY)
107
		flags |= DRM_MODE_FLAG_NHSYNC;
108
	else
109
		flags |= DRM_MODE_FLAG_PHSYNC;
110
	if (tmp & LVDS_VSYNC_POLARITY)
111
		flags |= DRM_MODE_FLAG_NVSYNC;
112
	else
113
		flags |= DRM_MODE_FLAG_PVSYNC;
114
 
6084 serge 115
	pipe_config->base.adjusted_mode.flags |= flags;
4104 Serge 116
 
117
	/* gen2/3 store dither state in pfit control, needs to match */
118
	if (INTEL_INFO(dev)->gen < 4) {
119
		tmp = I915_READ(PFIT_CONTROL);
120
 
121
		pipe_config->gmch_pfit.control |= tmp & PANEL_8TO6_DITHER_ENABLE;
122
	}
4560 Serge 123
 
124
	dotclock = pipe_config->port_clock;
125
 
126
	if (HAS_PCH_SPLIT(dev_priv->dev))
127
		ironlake_check_encoder_dotclock(pipe_config, dotclock);
128
 
6084 serge 129
	pipe_config->base.adjusted_mode.crtc_clock = dotclock;
4104 Serge 130
}
131
 
132
static void intel_pre_enable_lvds(struct intel_encoder *encoder)
3480 Serge 133
{
134
	struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
135
	struct drm_device *dev = encoder->base.dev;
136
	struct drm_i915_private *dev_priv = dev->dev_private;
4104 Serge 137
	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
6084 serge 138
	const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
4104 Serge 139
	int pipe = crtc->pipe;
3480 Serge 140
	u32 temp;
141
 
4104 Serge 142
	if (HAS_PCH_SPLIT(dev)) {
143
		assert_fdi_rx_pll_disabled(dev_priv, pipe);
144
		assert_shared_dpll_disabled(dev_priv,
145
					    intel_crtc_to_shared_dpll(crtc));
146
	} else {
147
		assert_pll_disabled(dev_priv, pipe);
148
	}
149
 
3480 Serge 150
	temp = I915_READ(lvds_encoder->reg);
151
	temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
152
 
153
	if (HAS_PCH_CPT(dev)) {
154
		temp &= ~PORT_TRANS_SEL_MASK;
155
		temp |= PORT_TRANS_SEL_CPT(pipe);
156
	} else {
157
		if (pipe == 1) {
158
			temp |= LVDS_PIPEB_SELECT;
159
		} else {
160
			temp &= ~LVDS_PIPEB_SELECT;
161
		}
162
	}
163
 
164
	/* set the corresponsding LVDS_BORDER bit */
4104 Serge 165
	temp &= ~LVDS_BORDER_ENABLE;
6084 serge 166
	temp |= crtc->config->gmch_pfit.lvds_border_bits;
3480 Serge 167
	/* Set the B0-B3 data pairs corresponding to whether we're going to
168
	 * set the DPLLs for dual-channel mode or not.
169
	 */
170
	if (lvds_encoder->is_dual_link)
171
		temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
172
	else
173
		temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
174
 
175
	/* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
176
	 * appropriately here, but we need to look more thoroughly into how
5060 serge 177
	 * panels behave in the two modes. For now, let's just maintain the
178
	 * value we got from the BIOS.
3480 Serge 179
	 */
5060 serge 180
	 temp &= ~LVDS_A3_POWER_MASK;
181
	 temp |= lvds_encoder->a3_power;
3480 Serge 182
 
183
	/* Set the dithering flag on LVDS as needed, note that there is no
184
	 * special lvds dither control bit on pch-split platforms, dithering is
185
	 * only controlled through the PIPECONF reg. */
186
	if (INTEL_INFO(dev)->gen == 4) {
4104 Serge 187
		/* Bspec wording suggests that LVDS port dithering only exists
188
		 * for 18bpp panels. */
6084 serge 189
		if (crtc->config->dither && crtc->config->pipe_bpp == 18)
3480 Serge 190
			temp |= LVDS_ENABLE_DITHER;
191
		else
192
			temp &= ~LVDS_ENABLE_DITHER;
193
	}
194
	temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
4104 Serge 195
	if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
3480 Serge 196
		temp |= LVDS_HSYNC_POLARITY;
4104 Serge 197
	if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
3480 Serge 198
		temp |= LVDS_VSYNC_POLARITY;
199
 
200
	I915_WRITE(lvds_encoder->reg, temp);
201
}
202
 
2330 Serge 203
/**
204
 * Sets the power state for the panel.
205
 */
3031 serge 206
static void intel_enable_lvds(struct intel_encoder *encoder)
2330 Serge 207
{