Rev 2330 | Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2327 | Serge | 1 | /* |
2 | * Copyright © 2008 Intel Corporation |
||
3 | * |
||
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
5 | * copy of this software and associated documentation files (the "Software"), |
||
6 | * to deal in the Software without restriction, including without limitation |
||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
8 | * and/or sell copies of the Software, and to permit persons to whom the |
||
9 | * Software is furnished to do so, subject to the following conditions: |
||
10 | * |
||
11 | * The above copyright notice and this permission notice (including the next |
||
12 | * paragraph) shall be included in all copies or substantial portions of the |
||
13 | * Software. |
||
14 | * |
||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||
21 | * IN THE SOFTWARE. |
||
22 | * |
||
23 | * Authors: |
||
24 | * Keith Packard |
||
25 | * |
||
26 | */ |
||
27 | |||
28 | #include |
||
29 | //#include |
||
30 | #include "drmP.h" |
||
31 | #include "drm.h" |
||
32 | #include "drm_crtc.h" |
||
33 | #include "drm_crtc_helper.h" |
||
34 | #include "intel_drv.h" |
||
35 | //#include "i915_drm.h" |
||
36 | #include "i915_drv.h" |
||
37 | #include "drm_dp_helper.h" |
||
38 | |||
39 | |||
40 | #define DP_LINK_STATUS_SIZE 6 |
||
41 | #define DP_LINK_CHECK_TIMEOUT (10 * 1000) |
||
42 | |||
43 | #define DP_LINK_CONFIGURATION_SIZE 9 |
||
44 | |||
45 | struct intel_dp { |
||
46 | struct intel_encoder base; |
||
47 | uint32_t output_reg; |
||
48 | uint32_t DP; |
||
49 | uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]; |
||
50 | bool has_audio; |
||
51 | int force_audio; |
||
52 | uint32_t color_range; |
||
53 | int dpms_mode; |
||
54 | uint8_t link_bw; |
||
55 | uint8_t lane_count; |
||
56 | uint8_t dpcd[8]; |
||
57 | struct i2c_adapter adapter; |
||
58 | struct i2c_algo_dp_aux_data algo; |
||
59 | bool is_pch_edp; |
||
60 | uint8_t train_set[4]; |
||
61 | uint8_t link_status[DP_LINK_STATUS_SIZE]; |
||
62 | }; |
||
63 | |||
64 | /** |
||
65 | * is_edp - is the given port attached to an eDP panel (either CPU or PCH) |
||
66 | * @intel_dp: DP struct |
||
67 | * |
||
68 | * If a CPU or PCH DP output is attached to an eDP panel, this function |
||
69 | * will return true, and false otherwise. |
||
70 | */ |
||
71 | static bool is_edp(struct intel_dp *intel_dp) |
||
72 | { |
||
73 | return intel_dp->base.type == INTEL_OUTPUT_EDP; |
||
74 | } |
||
75 | |||
76 | /** |
||
77 | * is_pch_edp - is the port on the PCH and attached to an eDP panel? |
||
78 | * @intel_dp: DP struct |
||
79 | * |
||
80 | * Returns true if the given DP struct corresponds to a PCH DP port attached |
||
81 | * to an eDP panel, false otherwise. Helpful for determining whether we |
||
82 | * may need FDI resources for a given DP output or not. |
||
83 | */ |
||
84 | static bool is_pch_edp(struct intel_dp *intel_dp) |
||
85 | { |
||
86 | return intel_dp->is_pch_edp; |
||
87 | } |
||
88 | |||
89 | static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder) |
||
90 | { |
||
91 | return container_of(encoder, struct intel_dp, base.base); |
||
92 | } |
||
93 | |||
94 | |||
95 | |||
96 | |||
97 | |||
98 | /** |
||
99 | * intel_encoder_is_pch_edp - is the given encoder a PCH attached eDP? |
||
100 | * @encoder: DRM encoder |
||
101 | * |
||
102 | * Return true if @encoder corresponds to a PCH attached eDP panel. Needed |
||
103 | * by intel_display.c. |
||
104 | */ |
||
105 | bool intel_encoder_is_pch_edp(struct drm_encoder *encoder) |
||
106 | { |
||
107 | struct intel_dp *intel_dp; |
||
108 | |||
109 | if (!encoder) |
||
110 | return false; |
||
111 | |||
112 | intel_dp = enc_to_intel_dp(encoder); |
||
113 | |||
114 | return is_pch_edp(intel_dp); |
||
115 | } |
||
116 | |||
117 | void |
||
118 | intel_edp_link_config (struct intel_encoder *intel_encoder, |
||
119 | int *lane_num, int *link_bw) |
||
120 | { |
||
121 | struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base); |
||
122 | |||
123 | *lane_num = intel_dp->lane_count; |
||
124 | if (intel_dp->link_bw == DP_LINK_BW_1_62) |
||
125 | *link_bw = 162000; |
||
126 | else if (intel_dp->link_bw == DP_LINK_BW_2_7) |
||
127 | *link_bw = 270000; |
||
128 | } |
||
129 | |||
130 | |||
131 | |||
132 | |||
133 | |||
134 | |||
135 | |||
136 | |||
137 | |||
138 | |||
139 | |||
140 | |||
141 | |||
142 | |||
143 | struct intel_dp_m_n { |
||
144 | uint32_t tu; |
||
145 | uint32_t gmch_m; |
||
146 | uint32_t gmch_n; |
||
147 | uint32_t link_m; |
||
148 | uint32_t link_n; |
||
149 | }; |
||
150 | |||
151 | static void |
||
152 | intel_reduce_ratio(uint32_t *num, uint32_t *den) |
||
153 | { |
||
154 | while (*num > 0xffffff || *den > 0xffffff) { |
||
155 | *num >>= 1; |
||
156 | *den >>= 1; |
||
157 | } |
||
158 | } |
||
159 | |||
160 | static void |
||
161 | intel_dp_compute_m_n(int bpp, |
||
162 | int nlanes, |
||
163 | int pixel_clock, |
||
164 | int link_clock, |
||
165 | struct intel_dp_m_n *m_n) |
||
166 | { |
||
167 | m_n->tu = 64; |
||
168 | m_n->gmch_m = (pixel_clock * bpp) >> 3; |
||
169 | m_n->gmch_n = link_clock * nlanes; |
||
170 | intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); |
||
171 | m_n->link_m = pixel_clock; |
||
172 | m_n->link_n = link_clock; |
||
173 | intel_reduce_ratio(&m_n->link_m, &m_n->link_n); |
||
174 | } |
||
175 | |||
176 | void |
||
177 | intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, |
||
178 | struct drm_display_mode *adjusted_mode) |
||
179 | { |
||
180 | struct drm_device *dev = crtc->dev; |
||
181 | struct drm_mode_config *mode_config = &dev->mode_config; |
||
182 | struct drm_encoder *encoder; |
||
183 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
184 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
||
185 | int lane_count = 4; |
||
186 | struct intel_dp_m_n m_n; |
||
187 | int pipe = intel_crtc->pipe; |
||
188 | |||
189 | /* |
||
190 | * Find the lane count in the intel_encoder private |
||
191 | */ |
||
192 | list_for_each_entry(encoder, &mode_config->encoder_list, head) { |
||
193 | struct intel_dp *intel_dp; |
||
194 | |||
195 | if (encoder->crtc != crtc) |
||
196 | continue; |
||
197 | |||
198 | intel_dp = enc_to_intel_dp(encoder); |
||
199 | if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) { |
||
200 | lane_count = intel_dp->lane_count; |
||
201 | break; |
||
202 | } else if (is_edp(intel_dp)) { |
||
203 | lane_count = dev_priv->edp.lanes; |
||
204 | break; |
||
205 | } |
||
206 | } |
||
207 | |||
208 | /* |
||
209 | * Compute the GMCH and Link ratios. The '3' here is |
||
210 | * the number of bytes_per_pixel post-LUT, which we always |
||
211 | * set up for 8-bits of R/G/B, or 3 bytes total. |
||
212 | */ |
||
213 | intel_dp_compute_m_n(intel_crtc->bpp, lane_count, |
||
214 | mode->clock, adjusted_mode->clock, &m_n); |
||
215 | |||
216 | if (HAS_PCH_SPLIT(dev)) { |
||
217 | I915_WRITE(TRANSDATA_M1(pipe), |
||
218 | ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | |
||
219 | m_n.gmch_m); |
||
220 | I915_WRITE(TRANSDATA_N1(pipe), m_n.gmch_n); |
||
221 | I915_WRITE(TRANSDPLINK_M1(pipe), m_n.link_m); |
||
222 | I915_WRITE(TRANSDPLINK_N1(pipe), m_n.link_n); |
||
223 | } else { |
||
224 | I915_WRITE(PIPE_GMCH_DATA_M(pipe), |
||
225 | ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | |
||
226 | m_n.gmch_m); |
||
227 | I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n.gmch_n); |
||
228 | I915_WRITE(PIPE_DP_LINK_M(pipe), m_n.link_m); |
||
229 | I915_WRITE(PIPE_DP_LINK_N(pipe), m_n.link_n); |
||
230 | } |
||
231 | } |
||
232 | |||
233 | |||
234 | |||
235 | |||
236 | |||
237 | |||
238 | |||
239 | |||
240 | |||
241 | |||
242 | |||
243 | |||
244 | |||
245 | |||
246 | |||
247 | |||
248 | |||
249 | |||
250 | |||
251 | |||
252 | |||
253 | |||
254 | |||
255 | |||
256 | |||
257 | |||
258 | |||
259 | |||
260 | |||
261 | |||
262 | |||
263 | |||
264 | |||
265 | |||
266 | |||
267 | |||
268 | |||
269 | |||
270 | |||
271 | |||
272 | |||
273 | |||
274 | |||
275 | |||
276 | |||
277 | |||
278 | |||
279 | |||
280 | /* Return which DP Port should be selected for Transcoder DP control */ |
||
281 | int |
||
282 | intel_trans_dp_port_sel (struct drm_crtc *crtc) |
||
283 | { |
||
284 | struct drm_device *dev = crtc->dev; |
||
285 | struct drm_mode_config *mode_config = &dev->mode_config; |
||
286 | struct drm_encoder *encoder; |
||
287 | |||
288 | list_for_each_entry(encoder, &mode_config->encoder_list, head) { |
||
289 | struct intel_dp *intel_dp; |
||
290 | |||
291 | if (encoder->crtc != crtc) |
||
292 | continue; |
||
293 | |||
294 | intel_dp = enc_to_intel_dp(encoder); |
||
295 | if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) |
||
296 | return intel_dp->output_reg; |
||
297 | } |
||
298 | |||
299 | return -1; |
||
300 | }><>><> |