]>
Commit | Line | Data |
---|---|---|
fcfe0bdc MC |
1 | /* |
2 | * Copyright © 2018 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 | |
21 | * DEALINGS IN THE SOFTWARE. | |
22 | * | |
23 | * Authors: | |
24 | * Madhav Chauhan <madhav.chauhan@intel.com> | |
25 | * Jani Nikula <jani.nikula@intel.com> | |
26 | */ | |
27 | ||
28 | #include "intel_dsi.h" | |
29 | ||
d364dc66 | 30 | static enum transcoder dsi_port_to_transcoder(enum port port) |
ca8fc99f MC |
31 | { |
32 | if (port == PORT_A) | |
33 | return TRANSCODER_DSI_0; | |
34 | else | |
35 | return TRANSCODER_DSI_1; | |
36 | } | |
37 | ||
3f4b9d9d MC |
38 | static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder) |
39 | { | |
40 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
41 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
42 | enum port port; | |
43 | u32 tmp; | |
44 | int lane; | |
45 | ||
46 | for_each_dsi_port(port, intel_dsi->ports) { | |
47 | ||
48 | /* | |
49 | * Program voltage swing and pre-emphasis level values as per | |
50 | * table in BSPEC under DDI buffer programing | |
51 | */ | |
52 | tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port)); | |
53 | tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK); | |
54 | tmp |= SCALING_MODE_SEL(0x2); | |
55 | tmp |= TAP2_DISABLE | TAP3_DISABLE; | |
56 | tmp |= RTERM_SELECT(0x6); | |
57 | I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp); | |
58 | ||
59 | tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port)); | |
60 | tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK); | |
61 | tmp |= SCALING_MODE_SEL(0x2); | |
62 | tmp |= TAP2_DISABLE | TAP3_DISABLE; | |
63 | tmp |= RTERM_SELECT(0x6); | |
64 | I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp); | |
65 | ||
66 | tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port)); | |
67 | tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK | | |
68 | RCOMP_SCALAR_MASK); | |
69 | tmp |= SWING_SEL_UPPER(0x2); | |
70 | tmp |= SWING_SEL_LOWER(0x2); | |
71 | tmp |= RCOMP_SCALAR(0x98); | |
72 | I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp); | |
73 | ||
74 | tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port)); | |
75 | tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK | | |
76 | RCOMP_SCALAR_MASK); | |
77 | tmp |= SWING_SEL_UPPER(0x2); | |
78 | tmp |= SWING_SEL_LOWER(0x2); | |
79 | tmp |= RCOMP_SCALAR(0x98); | |
80 | I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp); | |
81 | ||
82 | tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port)); | |
83 | tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK | | |
84 | CURSOR_COEFF_MASK); | |
85 | tmp |= POST_CURSOR_1(0x0); | |
86 | tmp |= POST_CURSOR_2(0x0); | |
87 | tmp |= CURSOR_COEFF(0x3f); | |
88 | I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp); | |
89 | ||
90 | for (lane = 0; lane <= 3; lane++) { | |
91 | /* Bspec: must not use GRP register for write */ | |
92 | tmp = I915_READ(ICL_PORT_TX_DW4_LN(port, lane)); | |
93 | tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK | | |
94 | CURSOR_COEFF_MASK); | |
95 | tmp |= POST_CURSOR_1(0x0); | |
96 | tmp |= POST_CURSOR_2(0x0); | |
97 | tmp |= CURSOR_COEFF(0x3f); | |
98 | I915_WRITE(ICL_PORT_TX_DW4_LN(port, lane), tmp); | |
99 | } | |
100 | } | |
101 | } | |
102 | ||
fcfe0bdc MC |
103 | static void gen11_dsi_program_esc_clk_div(struct intel_encoder *encoder) |
104 | { | |
105 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
106 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
107 | enum port port; | |
108 | u32 bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format); | |
109 | u32 afe_clk_khz; /* 8X Clock */ | |
110 | u32 esc_clk_div_m; | |
111 | ||
112 | afe_clk_khz = DIV_ROUND_CLOSEST(intel_dsi->pclk * bpp, | |
113 | intel_dsi->lane_count); | |
114 | ||
115 | esc_clk_div_m = DIV_ROUND_UP(afe_clk_khz, DSI_MAX_ESC_CLK); | |
116 | ||
117 | for_each_dsi_port(port, intel_dsi->ports) { | |
118 | I915_WRITE(ICL_DSI_ESC_CLK_DIV(port), | |
119 | esc_clk_div_m & ICL_ESC_CLK_DIV_MASK); | |
120 | POSTING_READ(ICL_DSI_ESC_CLK_DIV(port)); | |
121 | } | |
122 | ||
123 | for_each_dsi_port(port, intel_dsi->ports) { | |
124 | I915_WRITE(ICL_DPHY_ESC_CLK_DIV(port), | |
125 | esc_clk_div_m & ICL_ESC_CLK_DIV_MASK); | |
126 | POSTING_READ(ICL_DPHY_ESC_CLK_DIV(port)); | |
127 | } | |
128 | } | |
129 | ||
b1cb21a5 MC |
130 | static void gen11_dsi_enable_io_power(struct intel_encoder *encoder) |
131 | { | |
132 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
133 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
134 | enum port port; | |
135 | u32 tmp; | |
136 | ||
137 | for_each_dsi_port(port, intel_dsi->ports) { | |
138 | tmp = I915_READ(ICL_DSI_IO_MODECTL(port)); | |
139 | tmp |= COMBO_PHY_MODE_DSI; | |
140 | I915_WRITE(ICL_DSI_IO_MODECTL(port), tmp); | |
141 | } | |
142 | ||
143 | for_each_dsi_port(port, intel_dsi->ports) { | |
144 | intel_display_power_get(dev_priv, port == PORT_A ? | |
145 | POWER_DOMAIN_PORT_DDI_A_IO : | |
146 | POWER_DOMAIN_PORT_DDI_B_IO); | |
147 | } | |
148 | } | |
149 | ||
45f09f7a MC |
150 | static void gen11_dsi_power_up_lanes(struct intel_encoder *encoder) |
151 | { | |
152 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
153 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
154 | enum port port; | |
155 | u32 tmp; | |
156 | u32 lane_mask; | |
157 | ||
158 | switch (intel_dsi->lane_count) { | |
159 | case 1: | |
160 | lane_mask = PWR_DOWN_LN_3_1_0; | |
161 | break; | |
162 | case 2: | |
163 | lane_mask = PWR_DOWN_LN_3_1; | |
164 | break; | |
165 | case 3: | |
166 | lane_mask = PWR_DOWN_LN_3; | |
167 | break; | |
168 | case 4: | |
169 | default: | |
170 | lane_mask = PWR_UP_ALL_LANES; | |
171 | break; | |
172 | } | |
173 | ||
174 | for_each_dsi_port(port, intel_dsi->ports) { | |
175 | tmp = I915_READ(ICL_PORT_CL_DW10(port)); | |
176 | tmp &= ~PWR_DOWN_LN_MASK; | |
177 | I915_WRITE(ICL_PORT_CL_DW10(port), tmp | lane_mask); | |
178 | } | |
179 | } | |
180 | ||
fc41001d MC |
181 | static void gen11_dsi_config_phy_lanes_sequence(struct intel_encoder *encoder) |
182 | { | |
183 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
184 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
185 | enum port port; | |
186 | u32 tmp; | |
187 | int lane; | |
188 | ||
189 | /* Step 4b(i) set loadgen select for transmit and aux lanes */ | |
190 | for_each_dsi_port(port, intel_dsi->ports) { | |
191 | tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port)); | |
192 | tmp &= ~LOADGEN_SELECT; | |
193 | I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp); | |
194 | for (lane = 0; lane <= 3; lane++) { | |
195 | tmp = I915_READ(ICL_PORT_TX_DW4_LN(port, lane)); | |
196 | tmp &= ~LOADGEN_SELECT; | |
197 | if (lane != 2) | |
198 | tmp |= LOADGEN_SELECT; | |
199 | I915_WRITE(ICL_PORT_TX_DW4_LN(port, lane), tmp); | |
200 | } | |
201 | } | |
202 | ||
203 | /* Step 4b(ii) set latency optimization for transmit and aux lanes */ | |
204 | for_each_dsi_port(port, intel_dsi->ports) { | |
205 | tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port)); | |
206 | tmp &= ~FRC_LATENCY_OPTIM_MASK; | |
207 | tmp |= FRC_LATENCY_OPTIM_VAL(0x5); | |
208 | I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp); | |
209 | tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port)); | |
210 | tmp &= ~FRC_LATENCY_OPTIM_MASK; | |
211 | tmp |= FRC_LATENCY_OPTIM_VAL(0x5); | |
212 | I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp); | |
213 | } | |
214 | ||
215 | } | |
216 | ||
3f4b9d9d MC |
217 | static void gen11_dsi_voltage_swing_program_seq(struct intel_encoder *encoder) |
218 | { | |
219 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
220 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
221 | u32 tmp; | |
222 | enum port port; | |
223 | ||
224 | /* clear common keeper enable bit */ | |
225 | for_each_dsi_port(port, intel_dsi->ports) { | |
226 | tmp = I915_READ(ICL_PORT_PCS_DW1_LN0(port)); | |
227 | tmp &= ~COMMON_KEEPER_EN; | |
228 | I915_WRITE(ICL_PORT_PCS_DW1_GRP(port), tmp); | |
229 | tmp = I915_READ(ICL_PORT_PCS_DW1_AUX(port)); | |
230 | tmp &= ~COMMON_KEEPER_EN; | |
231 | I915_WRITE(ICL_PORT_PCS_DW1_AUX(port), tmp); | |
232 | } | |
233 | ||
234 | /* | |
235 | * Set SUS Clock Config bitfield to 11b | |
236 | * Note: loadgen select program is done | |
237 | * as part of lane phy sequence configuration | |
238 | */ | |
239 | for_each_dsi_port(port, intel_dsi->ports) { | |
240 | tmp = I915_READ(ICL_PORT_CL_DW5(port)); | |
241 | tmp |= SUS_CLOCK_CONFIG; | |
242 | I915_WRITE(ICL_PORT_CL_DW5(port), tmp); | |
243 | } | |
244 | ||
245 | /* Clear training enable to change swing values */ | |
246 | for_each_dsi_port(port, intel_dsi->ports) { | |
247 | tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port)); | |
248 | tmp &= ~TX_TRAINING_EN; | |
249 | I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp); | |
250 | tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port)); | |
251 | tmp &= ~TX_TRAINING_EN; | |
252 | I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp); | |
253 | } | |
254 | ||
255 | /* Program swing and de-emphasis */ | |
256 | dsi_program_swing_and_deemphasis(encoder); | |
257 | ||
258 | /* Set training enable to trigger update */ | |
259 | for_each_dsi_port(port, intel_dsi->ports) { | |
260 | tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port)); | |
261 | tmp |= TX_TRAINING_EN; | |
262 | I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp); | |
263 | tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port)); | |
264 | tmp |= TX_TRAINING_EN; | |
265 | I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp); | |
266 | } | |
267 | } | |
268 | ||
ba3df888 MC |
269 | static void gen11_dsi_enable_ddi_buffer(struct intel_encoder *encoder) |
270 | { | |
271 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
272 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
273 | u32 tmp; | |
274 | enum port port; | |
275 | ||
276 | for_each_dsi_port(port, intel_dsi->ports) { | |
277 | tmp = I915_READ(DDI_BUF_CTL(port)); | |
278 | tmp |= DDI_BUF_CTL_ENABLE; | |
279 | I915_WRITE(DDI_BUF_CTL(port), tmp); | |
280 | ||
281 | if (wait_for_us(!(I915_READ(DDI_BUF_CTL(port)) & | |
282 | DDI_BUF_IS_IDLE), | |
283 | 500)) | |
284 | DRM_ERROR("DDI port:%c buffer idle\n", port_name(port)); | |
285 | } | |
286 | } | |
287 | ||
70a7b836 MC |
288 | static void gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder) |
289 | { | |
290 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
291 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
292 | u32 tmp; | |
293 | enum port port; | |
294 | ||
295 | /* Program T-INIT master registers */ | |
296 | for_each_dsi_port(port, intel_dsi->ports) { | |
297 | tmp = I915_READ(ICL_DSI_T_INIT_MASTER(port)); | |
298 | tmp &= ~MASTER_INIT_TIMER_MASK; | |
299 | tmp |= intel_dsi->init_count; | |
300 | I915_WRITE(ICL_DSI_T_INIT_MASTER(port), tmp); | |
301 | } | |
e72cce53 MC |
302 | |
303 | /* Program DPHY clock lanes timings */ | |
304 | for_each_dsi_port(port, intel_dsi->ports) { | |
305 | I915_WRITE(DPHY_CLK_TIMING_PARAM(port), intel_dsi->dphy_reg); | |
306 | ||
307 | /* shadow register inside display core */ | |
308 | I915_WRITE(DSI_CLK_TIMING_PARAM(port), intel_dsi->dphy_reg); | |
309 | } | |
310 | ||
311 | /* Program DPHY data lanes timings */ | |
312 | for_each_dsi_port(port, intel_dsi->ports) { | |
313 | I915_WRITE(DPHY_DATA_TIMING_PARAM(port), | |
314 | intel_dsi->dphy_data_lane_reg); | |
315 | ||
316 | /* shadow register inside display core */ | |
317 | I915_WRITE(DSI_DATA_TIMING_PARAM(port), | |
318 | intel_dsi->dphy_data_lane_reg); | |
319 | } | |
5fea8645 MC |
320 | |
321 | /* | |
322 | * If DSI link operating at or below an 800 MHz, | |
323 | * TA_SURE should be override and programmed to | |
324 | * a value '0' inside TA_PARAM_REGISTERS otherwise | |
325 | * leave all fields at HW default values. | |
326 | */ | |
327 | if (intel_dsi_bitrate(intel_dsi) <= 800000) { | |
328 | for_each_dsi_port(port, intel_dsi->ports) { | |
329 | tmp = I915_READ(DPHY_TA_TIMING_PARAM(port)); | |
330 | tmp &= ~TA_SURE_MASK; | |
331 | tmp |= TA_SURE_OVERRIDE | TA_SURE(0); | |
332 | I915_WRITE(DPHY_TA_TIMING_PARAM(port), tmp); | |
333 | ||
334 | /* shadow register inside display core */ | |
335 | tmp = I915_READ(DSI_TA_TIMING_PARAM(port)); | |
336 | tmp &= ~TA_SURE_MASK; | |
337 | tmp |= TA_SURE_OVERRIDE | TA_SURE(0); | |
338 | I915_WRITE(DSI_TA_TIMING_PARAM(port), tmp); | |
339 | } | |
340 | } | |
70a7b836 MC |
341 | } |
342 | ||
70f4f502 MC |
343 | static void |
344 | gen11_dsi_configure_transcoder(struct intel_encoder *encoder, | |
345 | const struct intel_crtc_state *pipe_config) | |
d364dc66 MC |
346 | { |
347 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
348 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
70f4f502 MC |
349 | struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc); |
350 | enum pipe pipe = intel_crtc->pipe; | |
d364dc66 MC |
351 | u32 tmp; |
352 | enum port port; | |
353 | enum transcoder dsi_trans; | |
354 | ||
355 | for_each_dsi_port(port, intel_dsi->ports) { | |
356 | dsi_trans = dsi_port_to_transcoder(port); | |
357 | tmp = I915_READ(DSI_TRANS_FUNC_CONF(dsi_trans)); | |
358 | ||
359 | if (intel_dsi->eotp_pkt) | |
360 | tmp &= ~EOTP_DISABLED; | |
361 | else | |
362 | tmp |= EOTP_DISABLED; | |
363 | ||
364 | /* enable link calibration if freq > 1.5Gbps */ | |
365 | if (intel_dsi_bitrate(intel_dsi) >= 1500 * 1000) { | |
366 | tmp &= ~LINK_CALIBRATION_MASK; | |
367 | tmp |= CALIBRATION_ENABLED_INITIAL_ONLY; | |
368 | } | |
369 | ||
370 | /* configure continuous clock */ | |
371 | tmp &= ~CONTINUOUS_CLK_MASK; | |
372 | if (intel_dsi->clock_stop) | |
373 | tmp |= CLK_ENTER_LP_AFTER_DATA; | |
374 | else | |
375 | tmp |= CLK_HS_CONTINUOUS; | |
376 | ||
377 | /* configure buffer threshold limit to minimum */ | |
378 | tmp &= ~PIX_BUF_THRESHOLD_MASK; | |
379 | tmp |= PIX_BUF_THRESHOLD_1_4; | |
380 | ||
381 | /* set virtual channel to '0' */ | |
382 | tmp &= ~PIX_VIRT_CHAN_MASK; | |
383 | tmp |= PIX_VIRT_CHAN(0); | |
384 | ||
385 | /* program BGR transmission */ | |
386 | if (intel_dsi->bgr_enabled) | |
387 | tmp |= BGR_TRANSMISSION; | |
388 | ||
389 | /* select pixel format */ | |
390 | tmp &= ~PIX_FMT_MASK; | |
391 | switch (intel_dsi->pixel_format) { | |
392 | default: | |
393 | MISSING_CASE(intel_dsi->pixel_format); | |
394 | /* fallthrough */ | |
395 | case MIPI_DSI_FMT_RGB565: | |
396 | tmp |= PIX_FMT_RGB565; | |
397 | break; | |
398 | case MIPI_DSI_FMT_RGB666_PACKED: | |
399 | tmp |= PIX_FMT_RGB666_PACKED; | |
400 | break; | |
401 | case MIPI_DSI_FMT_RGB666: | |
402 | tmp |= PIX_FMT_RGB666_LOOSE; | |
403 | break; | |
404 | case MIPI_DSI_FMT_RGB888: | |
405 | tmp |= PIX_FMT_RGB888; | |
406 | break; | |
407 | } | |
408 | ||
409 | /* program DSI operation mode */ | |
410 | if (is_vid_mode(intel_dsi)) { | |
411 | tmp &= ~OP_MODE_MASK; | |
412 | switch (intel_dsi->video_mode_format) { | |
413 | default: | |
414 | MISSING_CASE(intel_dsi->video_mode_format); | |
415 | /* fallthrough */ | |
416 | case VIDEO_MODE_NON_BURST_WITH_SYNC_EVENTS: | |
417 | tmp |= VIDEO_MODE_SYNC_EVENT; | |
418 | break; | |
419 | case VIDEO_MODE_NON_BURST_WITH_SYNC_PULSE: | |
420 | tmp |= VIDEO_MODE_SYNC_PULSE; | |
421 | break; | |
422 | } | |
423 | } | |
424 | ||
425 | I915_WRITE(DSI_TRANS_FUNC_CONF(dsi_trans), tmp); | |
426 | } | |
70f4f502 MC |
427 | |
428 | /* enable port sync mode if dual link */ | |
429 | if (intel_dsi->dual_link) { | |
430 | for_each_dsi_port(port, intel_dsi->ports) { | |
431 | dsi_trans = dsi_port_to_transcoder(port); | |
432 | tmp = I915_READ(TRANS_DDI_FUNC_CTL2(dsi_trans)); | |
433 | tmp |= PORT_SYNC_MODE_ENABLE; | |
434 | I915_WRITE(TRANS_DDI_FUNC_CTL2(dsi_trans), tmp); | |
435 | } | |
436 | ||
437 | //TODO: configure DSS_CTL1 | |
438 | } | |
439 | ||
440 | for_each_dsi_port(port, intel_dsi->ports) { | |
441 | dsi_trans = dsi_port_to_transcoder(port); | |
442 | ||
443 | /* select data lane width */ | |
444 | tmp = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans)); | |
445 | tmp &= ~DDI_PORT_WIDTH_MASK; | |
446 | tmp |= DDI_PORT_WIDTH(intel_dsi->lane_count); | |
447 | ||
448 | /* select input pipe */ | |
449 | tmp &= ~TRANS_DDI_EDP_INPUT_MASK; | |
450 | switch (pipe) { | |
451 | default: | |
452 | MISSING_CASE(pipe); | |
453 | /* fallthrough */ | |
454 | case PIPE_A: | |
455 | tmp |= TRANS_DDI_EDP_INPUT_A_ON; | |
456 | break; | |
457 | case PIPE_B: | |
458 | tmp |= TRANS_DDI_EDP_INPUT_B_ONOFF; | |
459 | break; | |
460 | case PIPE_C: | |
461 | tmp |= TRANS_DDI_EDP_INPUT_C_ONOFF; | |
462 | break; | |
463 | } | |
464 | ||
465 | /* enable DDI buffer */ | |
466 | tmp |= TRANS_DDI_FUNC_ENABLE; | |
467 | I915_WRITE(TRANS_DDI_FUNC_CTL(dsi_trans), tmp); | |
468 | } | |
469 | ||
470 | /* wait for link ready */ | |
471 | for_each_dsi_port(port, intel_dsi->ports) { | |
472 | dsi_trans = dsi_port_to_transcoder(port); | |
473 | if (wait_for_us((I915_READ(DSI_TRANS_FUNC_CONF(dsi_trans)) & | |
474 | LINK_READY), 2500)) | |
475 | DRM_ERROR("DSI link not ready\n"); | |
476 | } | |
d364dc66 MC |
477 | } |
478 | ||
70f4f502 MC |
479 | static void |
480 | gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder, | |
481 | const struct intel_crtc_state *pipe_config) | |
45f09f7a MC |
482 | { |
483 | /* step 4a: power up all lanes of the DDI used by DSI */ | |
484 | gen11_dsi_power_up_lanes(encoder); | |
fc41001d MC |
485 | |
486 | /* step 4b: configure lane sequencing of the Combo-PHY transmitters */ | |
487 | gen11_dsi_config_phy_lanes_sequence(encoder); | |
3f4b9d9d MC |
488 | |
489 | /* step 4c: configure voltage swing and skew */ | |
490 | gen11_dsi_voltage_swing_program_seq(encoder); | |
ba3df888 MC |
491 | |
492 | /* enable DDI buffer */ | |
493 | gen11_dsi_enable_ddi_buffer(encoder); | |
70a7b836 MC |
494 | |
495 | /* setup D-PHY timings */ | |
496 | gen11_dsi_setup_dphy_timings(encoder); | |
d364dc66 MC |
497 | |
498 | /* Step (4h, 4i, 4j, 4k): Configure transcoder */ | |
70f4f502 | 499 | gen11_dsi_configure_transcoder(encoder, pipe_config); |
45f09f7a MC |
500 | } |
501 | ||
fcfe0bdc MC |
502 | static void __attribute__((unused)) |
503 | gen11_dsi_pre_enable(struct intel_encoder *encoder, | |
504 | const struct intel_crtc_state *pipe_config, | |
505 | const struct drm_connector_state *conn_state) | |
506 | { | |
b1cb21a5 MC |
507 | /* step2: enable IO power */ |
508 | gen11_dsi_enable_io_power(encoder); | |
509 | ||
fcfe0bdc MC |
510 | /* step3: enable DSI PLL */ |
511 | gen11_dsi_program_esc_clk_div(encoder); | |
45f09f7a MC |
512 | |
513 | /* step4: enable DSI port and DPHY */ | |
70f4f502 | 514 | gen11_dsi_enable_port_and_phy(encoder, pipe_config); |
fcfe0bdc | 515 | } |