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 | { |