]>
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 | ||
e2758048 | 28 | #include <drm/drm_atomic_helper.h> |
fdc24cf3 JN |
29 | #include <drm/drm_mipi_dsi.h> |
30 | ||
ec7f29ff | 31 | #include "intel_connector.h" |
fdc24cf3 | 32 | #include "intel_ddi.h" |
fcfe0bdc MC |
33 | #include "intel_dsi.h" |
34 | ||
32bbc3d4 MC |
35 | static inline int header_credits_available(struct drm_i915_private *dev_priv, |
36 | enum transcoder dsi_trans) | |
37 | { | |
38 | return (I915_READ(DSI_CMD_TXCTL(dsi_trans)) & FREE_HEADER_CREDIT_MASK) | |
39 | >> FREE_HEADER_CREDIT_SHIFT; | |
40 | } | |
41 | ||
42 | static inline int payload_credits_available(struct drm_i915_private *dev_priv, | |
43 | enum transcoder dsi_trans) | |
44 | { | |
45 | return (I915_READ(DSI_CMD_TXCTL(dsi_trans)) & FREE_PLOAD_CREDIT_MASK) | |
46 | >> FREE_PLOAD_CREDIT_SHIFT; | |
47 | } | |
48 | ||
49 | static void wait_for_header_credits(struct drm_i915_private *dev_priv, | |
50 | enum transcoder dsi_trans) | |
51 | { | |
52 | if (wait_for_us(header_credits_available(dev_priv, dsi_trans) >= | |
53 | MAX_HEADER_CREDIT, 100)) | |
54 | DRM_ERROR("DSI header credits not released\n"); | |
55 | } | |
56 | ||
57 | static void wait_for_payload_credits(struct drm_i915_private *dev_priv, | |
58 | enum transcoder dsi_trans) | |
59 | { | |
60 | if (wait_for_us(payload_credits_available(dev_priv, dsi_trans) >= | |
61 | MAX_PLOAD_CREDIT, 100)) | |
62 | DRM_ERROR("DSI payload credits not released\n"); | |
63 | } | |
64 | ||
d364dc66 | 65 | static enum transcoder dsi_port_to_transcoder(enum port port) |
ca8fc99f MC |
66 | { |
67 | if (port == PORT_A) | |
68 | return TRANSCODER_DSI_0; | |
69 | else | |
70 | return TRANSCODER_DSI_1; | |
71 | } | |
72 | ||
32bbc3d4 MC |
73 | static void wait_for_cmds_dispatched_to_panel(struct intel_encoder *encoder) |
74 | { | |
75 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
76 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
77 | struct mipi_dsi_device *dsi; | |
78 | enum port port; | |
79 | enum transcoder dsi_trans; | |
80 | int ret; | |
81 | ||
82 | /* wait for header/payload credits to be released */ | |
83 | for_each_dsi_port(port, intel_dsi->ports) { | |
84 | dsi_trans = dsi_port_to_transcoder(port); | |
85 | wait_for_header_credits(dev_priv, dsi_trans); | |
86 | wait_for_payload_credits(dev_priv, dsi_trans); | |
87 | } | |
88 | ||
89 | /* send nop DCS command */ | |
90 | for_each_dsi_port(port, intel_dsi->ports) { | |
91 | dsi = intel_dsi->dsi_hosts[port]->device; | |
92 | dsi->mode_flags |= MIPI_DSI_MODE_LPM; | |
93 | dsi->channel = 0; | |
94 | ret = mipi_dsi_dcs_nop(dsi); | |
95 | if (ret < 0) | |
96 | DRM_ERROR("error sending DCS NOP command\n"); | |
97 | } | |
98 | ||
99 | /* wait for header credits to be released */ | |
100 | for_each_dsi_port(port, intel_dsi->ports) { | |
101 | dsi_trans = dsi_port_to_transcoder(port); | |
102 | wait_for_header_credits(dev_priv, dsi_trans); | |
103 | } | |
104 | ||
105 | /* wait for LP TX in progress bit to be cleared */ | |
106 | for_each_dsi_port(port, intel_dsi->ports) { | |
107 | dsi_trans = dsi_port_to_transcoder(port); | |
108 | if (wait_for_us(!(I915_READ(DSI_LP_MSG(dsi_trans)) & | |
109 | LPTX_IN_PROGRESS), 20)) | |
110 | DRM_ERROR("LPTX bit not cleared\n"); | |
111 | } | |
112 | } | |
113 | ||
c5f9c934 MC |
114 | static bool add_payld_to_queue(struct intel_dsi_host *host, const u8 *data, |
115 | u32 len) | |
116 | { | |
117 | struct intel_dsi *intel_dsi = host->intel_dsi; | |
118 | struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev); | |
119 | enum transcoder dsi_trans = dsi_port_to_transcoder(host->port); | |
120 | int free_credits; | |
121 | int i, j; | |
122 | ||
123 | for (i = 0; i < len; i += 4) { | |
124 | u32 tmp = 0; | |
125 | ||
126 | free_credits = payload_credits_available(dev_priv, dsi_trans); | |
127 | if (free_credits < 1) { | |
128 | DRM_ERROR("Payload credit not available\n"); | |
129 | return false; | |
130 | } | |
131 | ||
132 | for (j = 0; j < min_t(u32, len - i, 4); j++) | |
133 | tmp |= *data++ << 8 * j; | |
134 | ||
135 | I915_WRITE(DSI_CMD_TXPYLD(dsi_trans), tmp); | |
136 | } | |
137 | ||
138 | return true; | |
139 | } | |
140 | ||
141 | static int dsi_send_pkt_hdr(struct intel_dsi_host *host, | |
142 | struct mipi_dsi_packet pkt, bool enable_lpdt) | |
143 | { | |
144 | struct intel_dsi *intel_dsi = host->intel_dsi; | |
145 | struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev); | |
146 | enum transcoder dsi_trans = dsi_port_to_transcoder(host->port); | |
147 | u32 tmp; | |
148 | int free_credits; | |
149 | ||
150 | /* check if header credit available */ | |
151 | free_credits = header_credits_available(dev_priv, dsi_trans); | |
152 | if (free_credits < 1) { | |
153 | DRM_ERROR("send pkt header failed, not enough hdr credits\n"); | |
154 | return -1; | |
155 | } | |
156 | ||
157 | tmp = I915_READ(DSI_CMD_TXHDR(dsi_trans)); | |
158 | ||
159 | if (pkt.payload) | |
160 | tmp |= PAYLOAD_PRESENT; | |
161 | else | |
162 | tmp &= ~PAYLOAD_PRESENT; | |
163 | ||
164 | tmp &= ~VBLANK_FENCE; | |
165 | ||
166 | if (enable_lpdt) | |
167 | tmp |= LP_DATA_TRANSFER; | |
168 | ||
169 | tmp &= ~(PARAM_WC_MASK | VC_MASK | DT_MASK); | |
170 | tmp |= ((pkt.header[0] & VC_MASK) << VC_SHIFT); | |
171 | tmp |= ((pkt.header[0] & DT_MASK) << DT_SHIFT); | |
172 | tmp |= (pkt.header[1] << PARAM_WC_LOWER_SHIFT); | |
173 | tmp |= (pkt.header[2] << PARAM_WC_UPPER_SHIFT); | |
174 | I915_WRITE(DSI_CMD_TXHDR(dsi_trans), tmp); | |
175 | ||
176 | return 0; | |
177 | } | |
178 | ||
179 | static int dsi_send_pkt_payld(struct intel_dsi_host *host, | |
180 | struct mipi_dsi_packet pkt) | |
181 | { | |
182 | /* payload queue can accept *256 bytes*, check limit */ | |
183 | if (pkt.payload_length > MAX_PLOAD_CREDIT * 4) { | |
184 | DRM_ERROR("payload size exceeds max queue limit\n"); | |
185 | return -1; | |
186 | } | |
187 | ||
188 | /* load data into command payload queue */ | |
189 | if (!add_payld_to_queue(host, pkt.payload, | |
190 | pkt.payload_length)) { | |
191 | DRM_ERROR("adding payload to queue failed\n"); | |
192 | return -1; | |
193 | } | |
194 | ||
195 | return 0; | |
196 | } | |
197 | ||
3f4b9d9d MC |
198 | static void dsi_program_swing_and_deemphasis(struct intel_encoder *encoder) |
199 | { | |
200 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
201 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
202 | enum port port; | |
203 | u32 tmp; | |
204 | int lane; | |
205 | ||
206 | for_each_dsi_port(port, intel_dsi->ports) { | |
207 | ||
208 | /* | |
209 | * Program voltage swing and pre-emphasis level values as per | |
210 | * table in BSPEC under DDI buffer programing | |
211 | */ | |
212 | tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port)); | |
213 | tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK); | |
214 | tmp |= SCALING_MODE_SEL(0x2); | |
215 | tmp |= TAP2_DISABLE | TAP3_DISABLE; | |
216 | tmp |= RTERM_SELECT(0x6); | |
217 | I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp); | |
218 | ||
219 | tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port)); | |
220 | tmp &= ~(SCALING_MODE_SEL_MASK | RTERM_SELECT_MASK); | |
221 | tmp |= SCALING_MODE_SEL(0x2); | |
222 | tmp |= TAP2_DISABLE | TAP3_DISABLE; | |
223 | tmp |= RTERM_SELECT(0x6); | |
224 | I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp); | |
225 | ||
226 | tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port)); | |
227 | tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK | | |
228 | RCOMP_SCALAR_MASK); | |
229 | tmp |= SWING_SEL_UPPER(0x2); | |
230 | tmp |= SWING_SEL_LOWER(0x2); | |
231 | tmp |= RCOMP_SCALAR(0x98); | |
232 | I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp); | |
233 | ||
234 | tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port)); | |
235 | tmp &= ~(SWING_SEL_LOWER_MASK | SWING_SEL_UPPER_MASK | | |
236 | RCOMP_SCALAR_MASK); | |
237 | tmp |= SWING_SEL_UPPER(0x2); | |
238 | tmp |= SWING_SEL_LOWER(0x2); | |
239 | tmp |= RCOMP_SCALAR(0x98); | |
240 | I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp); | |
241 | ||
242 | tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port)); | |
243 | tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK | | |
244 | CURSOR_COEFF_MASK); | |
245 | tmp |= POST_CURSOR_1(0x0); | |
246 | tmp |= POST_CURSOR_2(0x0); | |
247 | tmp |= CURSOR_COEFF(0x3f); | |
248 | I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp); | |
249 | ||
250 | for (lane = 0; lane <= 3; lane++) { | |
251 | /* Bspec: must not use GRP register for write */ | |
9194e42a | 252 | tmp = I915_READ(ICL_PORT_TX_DW4_LN(lane, port)); |
3f4b9d9d MC |
253 | tmp &= ~(POST_CURSOR_1_MASK | POST_CURSOR_2_MASK | |
254 | CURSOR_COEFF_MASK); | |
255 | tmp |= POST_CURSOR_1(0x0); | |
256 | tmp |= POST_CURSOR_2(0x0); | |
257 | tmp |= CURSOR_COEFF(0x3f); | |
9194e42a | 258 | I915_WRITE(ICL_PORT_TX_DW4_LN(lane, port), tmp); |
3f4b9d9d MC |
259 | } |
260 | } | |
261 | } | |
262 | ||
5a8507b5 MC |
263 | static void configure_dual_link_mode(struct intel_encoder *encoder, |
264 | const struct intel_crtc_state *pipe_config) | |
265 | { | |
266 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
267 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
268 | u32 dss_ctl1; | |
269 | ||
270 | dss_ctl1 = I915_READ(DSS_CTL1); | |
271 | dss_ctl1 |= SPLITTER_ENABLE; | |
272 | dss_ctl1 &= ~OVERLAP_PIXELS_MASK; | |
273 | dss_ctl1 |= OVERLAP_PIXELS(intel_dsi->pixel_overlap); | |
274 | ||
275 | if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) { | |
276 | const struct drm_display_mode *adjusted_mode = | |
277 | &pipe_config->base.adjusted_mode; | |
278 | u32 dss_ctl2; | |
279 | u16 hactive = adjusted_mode->crtc_hdisplay; | |
280 | u16 dl_buffer_depth; | |
281 | ||
282 | dss_ctl1 &= ~DUAL_LINK_MODE_INTERLEAVE; | |
283 | dl_buffer_depth = hactive / 2 + intel_dsi->pixel_overlap; | |
284 | ||
285 | if (dl_buffer_depth > MAX_DL_BUFFER_TARGET_DEPTH) | |
286 | DRM_ERROR("DL buffer depth exceed max value\n"); | |
287 | ||
288 | dss_ctl1 &= ~LEFT_DL_BUF_TARGET_DEPTH_MASK; | |
289 | dss_ctl1 |= LEFT_DL_BUF_TARGET_DEPTH(dl_buffer_depth); | |
290 | dss_ctl2 = I915_READ(DSS_CTL2); | |
291 | dss_ctl2 &= ~RIGHT_DL_BUF_TARGET_DEPTH_MASK; | |
292 | dss_ctl2 |= RIGHT_DL_BUF_TARGET_DEPTH(dl_buffer_depth); | |
293 | I915_WRITE(DSS_CTL2, dss_ctl2); | |
294 | } else { | |
295 | /* Interleave */ | |
296 | dss_ctl1 |= DUAL_LINK_MODE_INTERLEAVE; | |
297 | } | |
298 | ||
299 | I915_WRITE(DSS_CTL1, dss_ctl1); | |
300 | } | |
301 | ||
fcfe0bdc MC |
302 | static void gen11_dsi_program_esc_clk_div(struct intel_encoder *encoder) |
303 | { | |
304 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
305 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
306 | enum port port; | |
307 | u32 bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format); | |
308 | u32 afe_clk_khz; /* 8X Clock */ | |
309 | u32 esc_clk_div_m; | |
310 | ||
311 | afe_clk_khz = DIV_ROUND_CLOSEST(intel_dsi->pclk * bpp, | |
312 | intel_dsi->lane_count); | |
313 | ||
314 | esc_clk_div_m = DIV_ROUND_UP(afe_clk_khz, DSI_MAX_ESC_CLK); | |
315 | ||
316 | for_each_dsi_port(port, intel_dsi->ports) { | |
317 | I915_WRITE(ICL_DSI_ESC_CLK_DIV(port), | |
318 | esc_clk_div_m & ICL_ESC_CLK_DIV_MASK); | |
319 | POSTING_READ(ICL_DSI_ESC_CLK_DIV(port)); | |
320 | } | |
321 | ||
322 | for_each_dsi_port(port, intel_dsi->ports) { | |
323 | I915_WRITE(ICL_DPHY_ESC_CLK_DIV(port), | |
324 | esc_clk_div_m & ICL_ESC_CLK_DIV_MASK); | |
325 | POSTING_READ(ICL_DPHY_ESC_CLK_DIV(port)); | |
326 | } | |
327 | } | |
328 | ||
b1cb21a5 MC |
329 | static void gen11_dsi_enable_io_power(struct intel_encoder *encoder) |
330 | { | |
331 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
332 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
333 | enum port port; | |
334 | u32 tmp; | |
335 | ||
336 | for_each_dsi_port(port, intel_dsi->ports) { | |
337 | tmp = I915_READ(ICL_DSI_IO_MODECTL(port)); | |
338 | tmp |= COMBO_PHY_MODE_DSI; | |
339 | I915_WRITE(ICL_DSI_IO_MODECTL(port), tmp); | |
340 | } | |
341 | ||
342 | for_each_dsi_port(port, intel_dsi->ports) { | |
0e6e0be4 CW |
343 | intel_dsi->io_wakeref[port] = |
344 | intel_display_power_get(dev_priv, | |
345 | port == PORT_A ? | |
346 | POWER_DOMAIN_PORT_DDI_A_IO : | |
347 | POWER_DOMAIN_PORT_DDI_B_IO); | |
b1cb21a5 MC |
348 | } |
349 | } | |
350 | ||
45f09f7a MC |
351 | static void gen11_dsi_power_up_lanes(struct intel_encoder *encoder) |
352 | { | |
353 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
354 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
355 | enum port port; | |
356 | u32 tmp; | |
357 | u32 lane_mask; | |
358 | ||
359 | switch (intel_dsi->lane_count) { | |
360 | case 1: | |
361 | lane_mask = PWR_DOWN_LN_3_1_0; | |
362 | break; | |
363 | case 2: | |
364 | lane_mask = PWR_DOWN_LN_3_1; | |
365 | break; | |
366 | case 3: | |
367 | lane_mask = PWR_DOWN_LN_3; | |
368 | break; | |
369 | case 4: | |
370 | default: | |
371 | lane_mask = PWR_UP_ALL_LANES; | |
372 | break; | |
373 | } | |
374 | ||
375 | for_each_dsi_port(port, intel_dsi->ports) { | |
376 | tmp = I915_READ(ICL_PORT_CL_DW10(port)); | |
377 | tmp &= ~PWR_DOWN_LN_MASK; | |
378 | I915_WRITE(ICL_PORT_CL_DW10(port), tmp | lane_mask); | |
379 | } | |
380 | } | |
381 | ||
fc41001d MC |
382 | static void gen11_dsi_config_phy_lanes_sequence(struct intel_encoder *encoder) |
383 | { | |
384 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
385 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
386 | enum port port; | |
387 | u32 tmp; | |
388 | int lane; | |
389 | ||
390 | /* Step 4b(i) set loadgen select for transmit and aux lanes */ | |
391 | for_each_dsi_port(port, intel_dsi->ports) { | |
392 | tmp = I915_READ(ICL_PORT_TX_DW4_AUX(port)); | |
393 | tmp &= ~LOADGEN_SELECT; | |
394 | I915_WRITE(ICL_PORT_TX_DW4_AUX(port), tmp); | |
395 | for (lane = 0; lane <= 3; lane++) { | |
9194e42a | 396 | tmp = I915_READ(ICL_PORT_TX_DW4_LN(lane, port)); |
fc41001d MC |
397 | tmp &= ~LOADGEN_SELECT; |
398 | if (lane != 2) | |
399 | tmp |= LOADGEN_SELECT; | |
9194e42a | 400 | I915_WRITE(ICL_PORT_TX_DW4_LN(lane, port), tmp); |
fc41001d MC |
401 | } |
402 | } | |
403 | ||
404 | /* Step 4b(ii) set latency optimization for transmit and aux lanes */ | |
405 | for_each_dsi_port(port, intel_dsi->ports) { | |
406 | tmp = I915_READ(ICL_PORT_TX_DW2_AUX(port)); | |
407 | tmp &= ~FRC_LATENCY_OPTIM_MASK; | |
408 | tmp |= FRC_LATENCY_OPTIM_VAL(0x5); | |
409 | I915_WRITE(ICL_PORT_TX_DW2_AUX(port), tmp); | |
410 | tmp = I915_READ(ICL_PORT_TX_DW2_LN0(port)); | |
411 | tmp &= ~FRC_LATENCY_OPTIM_MASK; | |
412 | tmp |= FRC_LATENCY_OPTIM_VAL(0x5); | |
413 | I915_WRITE(ICL_PORT_TX_DW2_GRP(port), tmp); | |
414 | } | |
415 | ||
416 | } | |
417 | ||
3f4b9d9d MC |
418 | static void gen11_dsi_voltage_swing_program_seq(struct intel_encoder *encoder) |
419 | { | |
420 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
421 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
422 | u32 tmp; | |
423 | enum port port; | |
424 | ||
425 | /* clear common keeper enable bit */ | |
426 | for_each_dsi_port(port, intel_dsi->ports) { | |
427 | tmp = I915_READ(ICL_PORT_PCS_DW1_LN0(port)); | |
428 | tmp &= ~COMMON_KEEPER_EN; | |
429 | I915_WRITE(ICL_PORT_PCS_DW1_GRP(port), tmp); | |
430 | tmp = I915_READ(ICL_PORT_PCS_DW1_AUX(port)); | |
431 | tmp &= ~COMMON_KEEPER_EN; | |
432 | I915_WRITE(ICL_PORT_PCS_DW1_AUX(port), tmp); | |
433 | } | |
434 | ||
435 | /* | |
436 | * Set SUS Clock Config bitfield to 11b | |
437 | * Note: loadgen select program is done | |
438 | * as part of lane phy sequence configuration | |
439 | */ | |
440 | for_each_dsi_port(port, intel_dsi->ports) { | |
441 | tmp = I915_READ(ICL_PORT_CL_DW5(port)); | |
442 | tmp |= SUS_CLOCK_CONFIG; | |
443 | I915_WRITE(ICL_PORT_CL_DW5(port), tmp); | |
444 | } | |
445 | ||
446 | /* Clear training enable to change swing values */ | |
447 | for_each_dsi_port(port, intel_dsi->ports) { | |
448 | tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port)); | |
449 | tmp &= ~TX_TRAINING_EN; | |
450 | I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp); | |
451 | tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port)); | |
452 | tmp &= ~TX_TRAINING_EN; | |
453 | I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp); | |
454 | } | |
455 | ||
456 | /* Program swing and de-emphasis */ | |
457 | dsi_program_swing_and_deemphasis(encoder); | |
458 | ||
459 | /* Set training enable to trigger update */ | |
460 | for_each_dsi_port(port, intel_dsi->ports) { | |
461 | tmp = I915_READ(ICL_PORT_TX_DW5_LN0(port)); | |
462 | tmp |= TX_TRAINING_EN; | |
463 | I915_WRITE(ICL_PORT_TX_DW5_GRP(port), tmp); | |
464 | tmp = I915_READ(ICL_PORT_TX_DW5_AUX(port)); | |
465 | tmp |= TX_TRAINING_EN; | |
466 | I915_WRITE(ICL_PORT_TX_DW5_AUX(port), tmp); | |
467 | } | |
468 | } | |
469 | ||
ba3df888 MC |
470 | static void gen11_dsi_enable_ddi_buffer(struct intel_encoder *encoder) |
471 | { | |
472 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
473 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
474 | u32 tmp; | |
475 | enum port port; | |
476 | ||
477 | for_each_dsi_port(port, intel_dsi->ports) { | |
478 | tmp = I915_READ(DDI_BUF_CTL(port)); | |
479 | tmp |= DDI_BUF_CTL_ENABLE; | |
480 | I915_WRITE(DDI_BUF_CTL(port), tmp); | |
481 | ||
482 | if (wait_for_us(!(I915_READ(DDI_BUF_CTL(port)) & | |
483 | DDI_BUF_IS_IDLE), | |
484 | 500)) | |
485 | DRM_ERROR("DDI port:%c buffer idle\n", port_name(port)); | |
486 | } | |
487 | } | |
488 | ||
70a7b836 MC |
489 | static void gen11_dsi_setup_dphy_timings(struct intel_encoder *encoder) |
490 | { | |
491 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
492 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
493 | u32 tmp; | |
494 | enum port port; | |
495 | ||
496 | /* Program T-INIT master registers */ | |
497 | for_each_dsi_port(port, intel_dsi->ports) { | |
498 | tmp = I915_READ(ICL_DSI_T_INIT_MASTER(port)); | |
499 | tmp &= ~MASTER_INIT_TIMER_MASK; | |
500 | tmp |= intel_dsi->init_count; | |
501 | I915_WRITE(ICL_DSI_T_INIT_MASTER(port), tmp); | |
502 | } | |
e72cce53 MC |
503 | |
504 | /* Program DPHY clock lanes timings */ | |
505 | for_each_dsi_port(port, intel_dsi->ports) { | |
506 | I915_WRITE(DPHY_CLK_TIMING_PARAM(port), intel_dsi->dphy_reg); | |
507 | ||
508 | /* shadow register inside display core */ | |
509 | I915_WRITE(DSI_CLK_TIMING_PARAM(port), intel_dsi->dphy_reg); | |
510 | } | |
511 | ||
512 | /* Program DPHY data lanes timings */ | |
513 | for_each_dsi_port(port, intel_dsi->ports) { | |
514 | I915_WRITE(DPHY_DATA_TIMING_PARAM(port), | |
515 | intel_dsi->dphy_data_lane_reg); | |
516 | ||
517 | /* shadow register inside display core */ | |
518 | I915_WRITE(DSI_DATA_TIMING_PARAM(port), | |
519 | intel_dsi->dphy_data_lane_reg); | |
520 | } | |
5fea8645 MC |
521 | |
522 | /* | |
523 | * If DSI link operating at or below an 800 MHz, | |
524 | * TA_SURE should be override and programmed to | |
525 | * a value '0' inside TA_PARAM_REGISTERS otherwise | |
526 | * leave all fields at HW default values. | |
527 | */ | |
528 | if (intel_dsi_bitrate(intel_dsi) <= 800000) { | |
529 | for_each_dsi_port(port, intel_dsi->ports) { | |
530 | tmp = I915_READ(DPHY_TA_TIMING_PARAM(port)); | |
531 | tmp &= ~TA_SURE_MASK; | |
532 | tmp |= TA_SURE_OVERRIDE | TA_SURE(0); | |
533 | I915_WRITE(DPHY_TA_TIMING_PARAM(port), tmp); | |
534 | ||
535 | /* shadow register inside display core */ | |
536 | tmp = I915_READ(DSI_TA_TIMING_PARAM(port)); | |
537 | tmp &= ~TA_SURE_MASK; | |
538 | tmp |= TA_SURE_OVERRIDE | TA_SURE(0); | |
539 | I915_WRITE(DSI_TA_TIMING_PARAM(port), tmp); | |
540 | } | |
541 | } | |
70a7b836 MC |
542 | } |
543 | ||
32250c8e MC |
544 | static void gen11_dsi_gate_clocks(struct intel_encoder *encoder) |
545 | { | |
546 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
547 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
548 | u32 tmp; | |
549 | enum port port; | |
550 | ||
551 | mutex_lock(&dev_priv->dpll_lock); | |
552 | tmp = I915_READ(DPCLKA_CFGCR0_ICL); | |
553 | for_each_dsi_port(port, intel_dsi->ports) { | |
554 | tmp |= DPCLKA_CFGCR0_DDI_CLK_OFF(port); | |
555 | } | |
556 | ||
557 | I915_WRITE(DPCLKA_CFGCR0_ICL, tmp); | |
558 | mutex_unlock(&dev_priv->dpll_lock); | |
559 | } | |
560 | ||
1026bea0 MC |
561 | static void gen11_dsi_ungate_clocks(struct intel_encoder *encoder) |
562 | { | |
563 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
564 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
565 | u32 tmp; | |
566 | enum port port; | |
567 | ||
568 | mutex_lock(&dev_priv->dpll_lock); | |
569 | tmp = I915_READ(DPCLKA_CFGCR0_ICL); | |
570 | for_each_dsi_port(port, intel_dsi->ports) { | |
571 | tmp &= ~DPCLKA_CFGCR0_DDI_CLK_OFF(port); | |
572 | } | |
573 | ||
574 | I915_WRITE(DPCLKA_CFGCR0_ICL, tmp); | |
575 | mutex_unlock(&dev_priv->dpll_lock); | |
576 | } | |
577 | ||
949fc52a JN |
578 | static void gen11_dsi_map_pll(struct intel_encoder *encoder, |
579 | const struct intel_crtc_state *crtc_state) | |
580 | { | |
581 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
582 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
583 | struct intel_shared_dpll *pll = crtc_state->shared_dpll; | |
584 | enum port port; | |
585 | u32 val; | |
586 | ||
587 | mutex_lock(&dev_priv->dpll_lock); | |
588 | ||
589 | val = I915_READ(DPCLKA_CFGCR0_ICL); | |
590 | for_each_dsi_port(port, intel_dsi->ports) { | |
591 | val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port); | |
592 | val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port); | |
593 | } | |
594 | I915_WRITE(DPCLKA_CFGCR0_ICL, val); | |
595 | POSTING_READ(DPCLKA_CFGCR0_ICL); | |
596 | ||
597 | mutex_unlock(&dev_priv->dpll_lock); | |
598 | } | |
599 | ||
70f4f502 MC |
600 | static void |
601 | gen11_dsi_configure_transcoder(struct intel_encoder *encoder, | |
602 | const struct intel_crtc_state *pipe_config) | |
d364dc66 MC |
603 | { |
604 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
605 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
70f4f502 MC |
606 | struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc); |
607 | enum pipe pipe = intel_crtc->pipe; | |
d364dc66 MC |
608 | u32 tmp; |
609 | enum port port; | |
610 | enum transcoder dsi_trans; | |
611 | ||
612 | for_each_dsi_port(port, intel_dsi->ports) { | |
613 | dsi_trans = dsi_port_to_transcoder(port); | |
614 | tmp = I915_READ(DSI_TRANS_FUNC_CONF(dsi_trans)); | |
615 | ||
616 | if (intel_dsi->eotp_pkt) | |
617 | tmp &= ~EOTP_DISABLED; | |
618 | else | |
619 | tmp |= EOTP_DISABLED; | |
620 | ||
621 | /* enable link calibration if freq > 1.5Gbps */ | |
622 | if (intel_dsi_bitrate(intel_dsi) >= 1500 * 1000) { | |
623 | tmp &= ~LINK_CALIBRATION_MASK; | |
624 | tmp |= CALIBRATION_ENABLED_INITIAL_ONLY; | |
625 | } | |
626 | ||
627 | /* configure continuous clock */ | |
628 | tmp &= ~CONTINUOUS_CLK_MASK; | |
629 | if (intel_dsi->clock_stop) | |
630 | tmp |= CLK_ENTER_LP_AFTER_DATA; | |
631 | else | |
632 | tmp |= CLK_HS_CONTINUOUS; | |
633 | ||
634 | /* configure buffer threshold limit to minimum */ | |
635 | tmp &= ~PIX_BUF_THRESHOLD_MASK; | |
636 | tmp |= PIX_BUF_THRESHOLD_1_4; | |
637 | ||
638 | /* set virtual channel to '0' */ | |
639 | tmp &= ~PIX_VIRT_CHAN_MASK; | |
640 | tmp |= PIX_VIRT_CHAN(0); | |
641 | ||
642 | /* program BGR transmission */ | |
643 | if (intel_dsi->bgr_enabled) | |
644 | tmp |= BGR_TRANSMISSION; | |
645 | ||
646 | /* select pixel format */ | |
647 | tmp &= ~PIX_FMT_MASK; | |
648 | switch (intel_dsi->pixel_format) { | |
649 | default: | |
650 | MISSING_CASE(intel_dsi->pixel_format); | |
651 | /* fallthrough */ | |
652 | case MIPI_DSI_FMT_RGB565: | |
653 | tmp |= PIX_FMT_RGB565; | |
654 | break; | |
655 | case MIPI_DSI_FMT_RGB666_PACKED: | |
656 | tmp |= PIX_FMT_RGB666_PACKED; | |
657 | break; | |
658 | case MIPI_DSI_FMT_RGB666: | |
659 | tmp |= PIX_FMT_RGB666_LOOSE; | |
660 | break; | |
661 | case MIPI_DSI_FMT_RGB888: | |
662 | tmp |= PIX_FMT_RGB888; | |
663 | break; | |
664 | } | |
665 | ||
666 | /* program DSI operation mode */ | |
667 | if (is_vid_mode(intel_dsi)) { | |
668 | tmp &= ~OP_MODE_MASK; | |
669 | switch (intel_dsi->video_mode_format) { | |
670 | default: | |
671 | MISSING_CASE(intel_dsi->video_mode_format); | |
672 | /* fallthrough */ | |
673 | case VIDEO_MODE_NON_BURST_WITH_SYNC_EVENTS: | |
674 | tmp |= VIDEO_MODE_SYNC_EVENT; | |
675 | break; | |
676 | case VIDEO_MODE_NON_BURST_WITH_SYNC_PULSE: | |
677 | tmp |= VIDEO_MODE_SYNC_PULSE; | |
678 | break; | |
679 | } | |
680 | } | |
681 | ||
682 | I915_WRITE(DSI_TRANS_FUNC_CONF(dsi_trans), tmp); | |
683 | } | |
70f4f502 MC |
684 | |
685 | /* enable port sync mode if dual link */ | |
686 | if (intel_dsi->dual_link) { | |
687 | for_each_dsi_port(port, intel_dsi->ports) { | |
688 | dsi_trans = dsi_port_to_transcoder(port); | |
689 | tmp = I915_READ(TRANS_DDI_FUNC_CTL2(dsi_trans)); | |
690 | tmp |= PORT_SYNC_MODE_ENABLE; | |
691 | I915_WRITE(TRANS_DDI_FUNC_CTL2(dsi_trans), tmp); | |
692 | } | |
693 | ||
5a8507b5 MC |
694 | /* configure stream splitting */ |
695 | configure_dual_link_mode(encoder, pipe_config); | |
70f4f502 MC |
696 | } |
697 | ||
698 | for_each_dsi_port(port, intel_dsi->ports) { | |
699 | dsi_trans = dsi_port_to_transcoder(port); | |
700 | ||
701 | /* select data lane width */ | |
702 | tmp = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans)); | |
703 | tmp &= ~DDI_PORT_WIDTH_MASK; | |
704 | tmp |= DDI_PORT_WIDTH(intel_dsi->lane_count); | |
705 | ||
706 | /* select input pipe */ | |
707 | tmp &= ~TRANS_DDI_EDP_INPUT_MASK; | |
708 | switch (pipe) { | |
709 | default: | |
710 | MISSING_CASE(pipe); | |
711 | /* fallthrough */ | |
712 | case PIPE_A: | |
713 | tmp |= TRANS_DDI_EDP_INPUT_A_ON; | |
714 | break; | |
715 | case PIPE_B: | |
716 | tmp |= TRANS_DDI_EDP_INPUT_B_ONOFF; | |
717 | break; | |
718 | case PIPE_C: | |
719 | tmp |= TRANS_DDI_EDP_INPUT_C_ONOFF; | |
720 | break; | |
721 | } | |
722 | ||
723 | /* enable DDI buffer */ | |
724 | tmp |= TRANS_DDI_FUNC_ENABLE; | |
725 | I915_WRITE(TRANS_DDI_FUNC_CTL(dsi_trans), tmp); | |
726 | } | |
727 | ||
728 | /* wait for link ready */ | |
729 | for_each_dsi_port(port, intel_dsi->ports) { | |
730 | dsi_trans = dsi_port_to_transcoder(port); | |
731 | if (wait_for_us((I915_READ(DSI_TRANS_FUNC_CONF(dsi_trans)) & | |
732 | LINK_READY), 2500)) | |
733 | DRM_ERROR("DSI link not ready\n"); | |
734 | } | |
d364dc66 MC |
735 | } |
736 | ||
d1aeb5f3 MC |
737 | static void |
738 | gen11_dsi_set_transcoder_timings(struct intel_encoder *encoder, | |
739 | const struct intel_crtc_state *pipe_config) | |
740 | { | |
741 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
742 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
743 | const struct drm_display_mode *adjusted_mode = | |
744 | &pipe_config->base.adjusted_mode; | |
745 | enum port port; | |
746 | enum transcoder dsi_trans; | |
747 | /* horizontal timings */ | |
748 | u16 htotal, hactive, hsync_start, hsync_end, hsync_size; | |
749 | u16 hfront_porch, hback_porch; | |
750 | /* vertical timings */ | |
751 | u16 vtotal, vactive, vsync_start, vsync_end, vsync_shift; | |
752 | ||
753 | hactive = adjusted_mode->crtc_hdisplay; | |
754 | htotal = adjusted_mode->crtc_htotal; | |
755 | hsync_start = adjusted_mode->crtc_hsync_start; | |
756 | hsync_end = adjusted_mode->crtc_hsync_end; | |
757 | hsync_size = hsync_end - hsync_start; | |
758 | hfront_porch = (adjusted_mode->crtc_hsync_start - | |
759 | adjusted_mode->crtc_hdisplay); | |
760 | hback_porch = (adjusted_mode->crtc_htotal - | |
761 | adjusted_mode->crtc_hsync_end); | |
762 | vactive = adjusted_mode->crtc_vdisplay; | |
763 | vtotal = adjusted_mode->crtc_vtotal; | |
764 | vsync_start = adjusted_mode->crtc_vsync_start; | |
765 | vsync_end = adjusted_mode->crtc_vsync_end; | |
766 | vsync_shift = hsync_start - htotal / 2; | |
767 | ||
768 | if (intel_dsi->dual_link) { | |
769 | hactive /= 2; | |
770 | if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) | |
771 | hactive += intel_dsi->pixel_overlap; | |
772 | htotal /= 2; | |
773 | } | |
774 | ||
775 | /* minimum hactive as per bspec: 256 pixels */ | |
776 | if (adjusted_mode->crtc_hdisplay < 256) | |
777 | DRM_ERROR("hactive is less then 256 pixels\n"); | |
778 | ||
779 | /* if RGB666 format, then hactive must be multiple of 4 pixels */ | |
780 | if (intel_dsi->pixel_format == MIPI_DSI_FMT_RGB666 && hactive % 4 != 0) | |
781 | DRM_ERROR("hactive pixels are not multiple of 4\n"); | |
782 | ||
783 | /* program TRANS_HTOTAL register */ | |
784 | for_each_dsi_port(port, intel_dsi->ports) { | |
785 | dsi_trans = dsi_port_to_transcoder(port); | |
786 | I915_WRITE(HTOTAL(dsi_trans), | |
787 | (hactive - 1) | ((htotal - 1) << 16)); | |
788 | } | |
789 | ||
790 | /* TRANS_HSYNC register to be programmed only for video mode */ | |
791 | if (intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE) { | |
792 | if (intel_dsi->video_mode_format == | |
793 | VIDEO_MODE_NON_BURST_WITH_SYNC_PULSE) { | |
794 | /* BSPEC: hsync size should be atleast 16 pixels */ | |
795 | if (hsync_size < 16) | |
796 | DRM_ERROR("hsync size < 16 pixels\n"); | |
797 | } | |
798 | ||
799 | if (hback_porch < 16) | |
800 | DRM_ERROR("hback porch < 16 pixels\n"); | |
801 | ||
802 | if (intel_dsi->dual_link) { | |
803 | hsync_start /= 2; | |
804 | hsync_end /= 2; | |
805 | } | |
806 | ||
807 | for_each_dsi_port(port, intel_dsi->ports) { | |
808 | dsi_trans = dsi_port_to_transcoder(port); | |
809 | I915_WRITE(HSYNC(dsi_trans), | |
810 | (hsync_start - 1) | ((hsync_end - 1) << 16)); | |
811 | } | |
812 | } | |
813 | ||
814 | /* program TRANS_VTOTAL register */ | |
815 | for_each_dsi_port(port, intel_dsi->ports) { | |
816 | dsi_trans = dsi_port_to_transcoder(port); | |
817 | /* | |
818 | * FIXME: Programing this by assuming progressive mode, since | |
819 | * non-interlaced info from VBT is not saved inside | |
820 | * struct drm_display_mode. | |
821 | * For interlace mode: program required pixel minus 2 | |
822 | */ | |
823 | I915_WRITE(VTOTAL(dsi_trans), | |
824 | (vactive - 1) | ((vtotal - 1) << 16)); | |
825 | } | |
826 | ||
827 | if (vsync_end < vsync_start || vsync_end > vtotal) | |
828 | DRM_ERROR("Invalid vsync_end value\n"); | |
829 | ||
830 | if (vsync_start < vactive) | |
831 | DRM_ERROR("vsync_start less than vactive\n"); | |
832 | ||
833 | /* program TRANS_VSYNC register */ | |
834 | for_each_dsi_port(port, intel_dsi->ports) { | |
835 | dsi_trans = dsi_port_to_transcoder(port); | |
836 | I915_WRITE(VSYNC(dsi_trans), | |
837 | (vsync_start - 1) | ((vsync_end - 1) << 16)); | |
838 | } | |
839 | ||
840 | /* | |
841 | * FIXME: It has to be programmed only for interlaced | |
842 | * modes. Put the check condition here once interlaced | |
843 | * info available as described above. | |
844 | * program TRANS_VSYNCSHIFT register | |
845 | */ | |
846 | for_each_dsi_port(port, intel_dsi->ports) { | |
847 | dsi_trans = dsi_port_to_transcoder(port); | |
848 | I915_WRITE(VSYNCSHIFT(dsi_trans), vsync_shift); | |
849 | } | |
850 | } | |
851 | ||
303e347c MC |
852 | static void gen11_dsi_enable_transcoder(struct intel_encoder *encoder) |
853 | { | |
854 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
855 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
856 | enum port port; | |
857 | enum transcoder dsi_trans; | |
858 | u32 tmp; | |
859 | ||
860 | for_each_dsi_port(port, intel_dsi->ports) { | |
861 | dsi_trans = dsi_port_to_transcoder(port); | |
862 | tmp = I915_READ(PIPECONF(dsi_trans)); | |
863 | tmp |= PIPECONF_ENABLE; | |
864 | I915_WRITE(PIPECONF(dsi_trans), tmp); | |
865 | ||
866 | /* wait for transcoder to be enabled */ | |
97a04e0d DCS |
867 | if (intel_wait_for_register(&dev_priv->uncore, |
868 | PIPECONF(dsi_trans), | |
303e347c MC |
869 | I965_PIPECONF_ACTIVE, |
870 | I965_PIPECONF_ACTIVE, 10)) | |
871 | DRM_ERROR("DSI transcoder not enabled\n"); | |
872 | } | |
873 | } | |
874 | ||
5a4712f4 MC |
875 | static void gen11_dsi_setup_timeouts(struct intel_encoder *encoder) |
876 | { | |
877 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
878 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
879 | enum port port; | |
880 | enum transcoder dsi_trans; | |
881 | u32 tmp, hs_tx_timeout, lp_rx_timeout, ta_timeout, divisor, mul; | |
882 | ||
883 | /* | |
884 | * escape clock count calculation: | |
885 | * BYTE_CLK_COUNT = TIME_NS/(8 * UI) | |
886 | * UI (nsec) = (10^6)/Bitrate | |
887 | * TIME_NS = (BYTE_CLK_COUNT * 8 * 10^6)/ Bitrate | |
888 | * ESCAPE_CLK_COUNT = TIME_NS/ESC_CLK_NS | |
889 | */ | |
890 | divisor = intel_dsi_tlpx_ns(intel_dsi) * intel_dsi_bitrate(intel_dsi) * 1000; | |
891 | mul = 8 * 1000000; | |
892 | hs_tx_timeout = DIV_ROUND_UP(intel_dsi->hs_tx_timeout * mul, | |
893 | divisor); | |
894 | lp_rx_timeout = DIV_ROUND_UP(intel_dsi->lp_rx_timeout * mul, divisor); | |
895 | ta_timeout = DIV_ROUND_UP(intel_dsi->turn_arnd_val * mul, divisor); | |
896 | ||
897 | for_each_dsi_port(port, intel_dsi->ports) { | |
898 | dsi_trans = dsi_port_to_transcoder(port); | |
899 | ||
900 | /* program hst_tx_timeout */ | |
901 | tmp = I915_READ(DSI_HSTX_TO(dsi_trans)); | |
902 | tmp &= ~HSTX_TIMEOUT_VALUE_MASK; | |
903 | tmp |= HSTX_TIMEOUT_VALUE(hs_tx_timeout); | |
904 | I915_WRITE(DSI_HSTX_TO(dsi_trans), tmp); | |
905 | ||
906 | /* FIXME: DSI_CALIB_TO */ | |
907 | ||
908 | /* program lp_rx_host timeout */ | |
909 | tmp = I915_READ(DSI_LPRX_HOST_TO(dsi_trans)); | |
910 | tmp &= ~LPRX_TIMEOUT_VALUE_MASK; | |
911 | tmp |= LPRX_TIMEOUT_VALUE(lp_rx_timeout); | |
912 | I915_WRITE(DSI_LPRX_HOST_TO(dsi_trans), tmp); | |
913 | ||
914 | /* FIXME: DSI_PWAIT_TO */ | |
915 | ||
916 | /* program turn around timeout */ | |
917 | tmp = I915_READ(DSI_TA_TO(dsi_trans)); | |
918 | tmp &= ~TA_TIMEOUT_VALUE_MASK; | |
919 | tmp |= TA_TIMEOUT_VALUE(ta_timeout); | |
920 | I915_WRITE(DSI_TA_TO(dsi_trans), tmp); | |
921 | } | |
922 | } | |
923 | ||
70f4f502 MC |
924 | static void |
925 | gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder, | |
926 | const struct intel_crtc_state *pipe_config) | |
45f09f7a MC |
927 | { |
928 | /* step 4a: power up all lanes of the DDI used by DSI */ | |
929 | gen11_dsi_power_up_lanes(encoder); | |
fc41001d MC |
930 | |
931 | /* step 4b: configure lane sequencing of the Combo-PHY transmitters */ | |
932 | gen11_dsi_config_phy_lanes_sequence(encoder); | |
3f4b9d9d MC |
933 | |
934 | /* step 4c: configure voltage swing and skew */ | |
935 | gen11_dsi_voltage_swing_program_seq(encoder); | |
ba3df888 MC |
936 | |
937 | /* enable DDI buffer */ | |
938 | gen11_dsi_enable_ddi_buffer(encoder); | |
70a7b836 MC |
939 | |
940 | /* setup D-PHY timings */ | |
941 | gen11_dsi_setup_dphy_timings(encoder); | |
d364dc66 | 942 | |
5a4712f4 MC |
943 | /* step 4h: setup DSI protocol timeouts */ |
944 | gen11_dsi_setup_timeouts(encoder); | |
945 | ||
d364dc66 | 946 | /* Step (4h, 4i, 4j, 4k): Configure transcoder */ |
70f4f502 | 947 | gen11_dsi_configure_transcoder(encoder, pipe_config); |
32250c8e MC |
948 | |
949 | /* Step 4l: Gate DDI clocks */ | |
950 | gen11_dsi_gate_clocks(encoder); | |
45f09f7a MC |
951 | } |
952 | ||
bfee32bf MC |
953 | static void gen11_dsi_powerup_panel(struct intel_encoder *encoder) |
954 | { | |
955 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
956 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
957 | struct mipi_dsi_device *dsi; | |
958 | enum port port; | |
959 | enum transcoder dsi_trans; | |
960 | u32 tmp; | |
961 | int ret; | |
962 | ||
963 | /* set maximum return packet size */ | |
964 | for_each_dsi_port(port, intel_dsi->ports) { | |
965 | dsi_trans = dsi_port_to_transcoder(port); | |
966 | ||
967 | /* | |
968 | * FIXME: This uses the number of DW's currently in the payload | |
969 | * receive queue. This is probably not what we want here. | |
970 | */ | |
971 | tmp = I915_READ(DSI_CMD_RXCTL(dsi_trans)); | |
972 | tmp &= NUMBER_RX_PLOAD_DW_MASK; | |
973 | /* multiply "Number Rx Payload DW" by 4 to get max value */ | |
974 | tmp = tmp * 4; | |
975 | dsi = intel_dsi->dsi_hosts[port]->device; | |
976 | ret = mipi_dsi_set_maximum_return_packet_size(dsi, tmp); | |
977 | if (ret < 0) | |
978 | DRM_ERROR("error setting max return pkt size%d\n", tmp); | |
979 | } | |
c2661638 MC |
980 | |
981 | /* panel power on related mipi dsi vbt sequences */ | |
982 | intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_ON); | |
983 | intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay); | |
984 | intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET); | |
985 | intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP); | |
986 | intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON); | |
32bbc3d4 MC |
987 | |
988 | /* ensure all panel commands dispatched before enabling transcoder */ | |
989 | wait_for_cmds_dispatched_to_panel(encoder); | |
bfee32bf MC |
990 | } |
991 | ||
95f2f4db VK |
992 | static void gen11_dsi_pre_pll_enable(struct intel_encoder *encoder, |
993 | const struct intel_crtc_state *pipe_config, | |
994 | const struct drm_connector_state *conn_state) | |
fcfe0bdc | 995 | { |
b1cb21a5 MC |
996 | /* step2: enable IO power */ |
997 | gen11_dsi_enable_io_power(encoder); | |
998 | ||
fcfe0bdc MC |
999 | /* step3: enable DSI PLL */ |
1000 | gen11_dsi_program_esc_clk_div(encoder); | |
95f2f4db VK |
1001 | } |
1002 | ||
1003 | static void gen11_dsi_pre_enable(struct intel_encoder *encoder, | |
1004 | const struct intel_crtc_state *pipe_config, | |
1005 | const struct drm_connector_state *conn_state) | |
1006 | { | |
1007 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
45f09f7a | 1008 | |
949fc52a JN |
1009 | /* step3b */ |
1010 | gen11_dsi_map_pll(encoder, pipe_config); | |
1011 | ||
45f09f7a | 1012 | /* step4: enable DSI port and DPHY */ |
70f4f502 | 1013 | gen11_dsi_enable_port_and_phy(encoder, pipe_config); |
d1aeb5f3 | 1014 | |
bfee32bf MC |
1015 | /* step5: program and powerup panel */ |
1016 | gen11_dsi_powerup_panel(encoder); | |
1017 | ||
d1aeb5f3 MC |
1018 | /* step6c: configure transcoder timings */ |
1019 | gen11_dsi_set_transcoder_timings(encoder, pipe_config); | |
303e347c MC |
1020 | |
1021 | /* step6d: enable dsi transcoder */ | |
1022 | gen11_dsi_enable_transcoder(encoder); | |
20801315 MC |
1023 | |
1024 | /* step7: enable backlight */ | |
1025 | intel_panel_enable_backlight(pipe_config, conn_state); | |
1026 | intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON); | |
fcfe0bdc | 1027 | } |
d9d996b6 | 1028 | |
4e123bd3 MC |
1029 | static void gen11_dsi_disable_transcoder(struct intel_encoder *encoder) |
1030 | { | |
1031 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
1032 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
1033 | enum port port; | |
1034 | enum transcoder dsi_trans; | |
1035 | u32 tmp; | |
1036 | ||
1037 | for_each_dsi_port(port, intel_dsi->ports) { | |
1038 | dsi_trans = dsi_port_to_transcoder(port); | |
1039 | ||
1040 | /* disable transcoder */ | |
1041 | tmp = I915_READ(PIPECONF(dsi_trans)); | |
1042 | tmp &= ~PIPECONF_ENABLE; | |
1043 | I915_WRITE(PIPECONF(dsi_trans), tmp); | |
1044 | ||
1045 | /* wait for transcoder to be disabled */ | |
97a04e0d DCS |
1046 | if (intel_wait_for_register(&dev_priv->uncore, |
1047 | PIPECONF(dsi_trans), | |
4e123bd3 MC |
1048 | I965_PIPECONF_ACTIVE, 0, 50)) |
1049 | DRM_ERROR("DSI trancoder not disabled\n"); | |
1050 | } | |
1051 | } | |
1052 | ||
522cc3f7 MC |
1053 | static void gen11_dsi_powerdown_panel(struct intel_encoder *encoder) |
1054 | { | |
1055 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
1056 | ||
1057 | intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_OFF); | |
1058 | intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_ASSERT_RESET); | |
1059 | intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_OFF); | |
1060 | ||
1061 | /* ensure cmds dispatched to panel */ | |
1062 | wait_for_cmds_dispatched_to_panel(encoder); | |
1063 | } | |
1064 | ||
4769b598 MC |
1065 | static void gen11_dsi_deconfigure_trancoder(struct intel_encoder *encoder) |
1066 | { | |
1067 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
1068 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
1069 | enum port port; | |
1070 | enum transcoder dsi_trans; | |
1071 | u32 tmp; | |
1072 | ||
1073 | /* put dsi link in ULPS */ | |
1074 | for_each_dsi_port(port, intel_dsi->ports) { | |
1075 | dsi_trans = dsi_port_to_transcoder(port); | |
1076 | tmp = I915_READ(DSI_LP_MSG(dsi_trans)); | |
1077 | tmp |= LINK_ENTER_ULPS; | |
1078 | tmp &= ~LINK_ULPS_TYPE_LP11; | |
1079 | I915_WRITE(DSI_LP_MSG(dsi_trans), tmp); | |
1080 | ||
1081 | if (wait_for_us((I915_READ(DSI_LP_MSG(dsi_trans)) & | |
1082 | LINK_IN_ULPS), | |
1083 | 10)) | |
1084 | DRM_ERROR("DSI link not in ULPS\n"); | |
1085 | } | |
7aa32f7c MC |
1086 | |
1087 | /* disable ddi function */ | |
1088 | for_each_dsi_port(port, intel_dsi->ports) { | |
1089 | dsi_trans = dsi_port_to_transcoder(port); | |
1090 | tmp = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans)); | |
1091 | tmp &= ~TRANS_DDI_FUNC_ENABLE; | |
1092 | I915_WRITE(TRANS_DDI_FUNC_CTL(dsi_trans), tmp); | |
1093 | } | |
9c83ab1b MC |
1094 | |
1095 | /* disable port sync mode if dual link */ | |
1096 | if (intel_dsi->dual_link) { | |
1097 | for_each_dsi_port(port, intel_dsi->ports) { | |
1098 | dsi_trans = dsi_port_to_transcoder(port); | |
1099 | tmp = I915_READ(TRANS_DDI_FUNC_CTL2(dsi_trans)); | |
1100 | tmp &= ~PORT_SYNC_MODE_ENABLE; | |
1101 | I915_WRITE(TRANS_DDI_FUNC_CTL2(dsi_trans), tmp); | |
1102 | } | |
1103 | } | |
4769b598 MC |
1104 | } |
1105 | ||
019cec36 MC |
1106 | static void gen11_dsi_disable_port(struct intel_encoder *encoder) |
1107 | { | |
1108 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
1109 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
1110 | u32 tmp; | |
1111 | enum port port; | |
1112 | ||
1026bea0 | 1113 | gen11_dsi_ungate_clocks(encoder); |
019cec36 MC |
1114 | for_each_dsi_port(port, intel_dsi->ports) { |
1115 | tmp = I915_READ(DDI_BUF_CTL(port)); | |
1116 | tmp &= ~DDI_BUF_CTL_ENABLE; | |
1117 | I915_WRITE(DDI_BUF_CTL(port), tmp); | |
1118 | ||
1119 | if (wait_for_us((I915_READ(DDI_BUF_CTL(port)) & | |
1120 | DDI_BUF_IS_IDLE), | |
1121 | 8)) | |
1122 | DRM_ERROR("DDI port:%c buffer not idle\n", | |
1123 | port_name(port)); | |
1124 | } | |
1026bea0 | 1125 | gen11_dsi_ungate_clocks(encoder); |
019cec36 MC |
1126 | } |
1127 | ||
0f0fe849 MC |
1128 | static void gen11_dsi_disable_io_power(struct intel_encoder *encoder) |
1129 | { | |
1130 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
1131 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
1132 | enum port port; | |
1133 | u32 tmp; | |
1134 | ||
0e6e0be4 CW |
1135 | for_each_dsi_port(port, intel_dsi->ports) { |
1136 | intel_wakeref_t wakeref; | |
1137 | ||
1138 | wakeref = fetch_and_zero(&intel_dsi->io_wakeref[port]); | |
1139 | if (wakeref) { | |
1140 | intel_display_power_put(dev_priv, | |
1141 | port == PORT_A ? | |
1142 | POWER_DOMAIN_PORT_DDI_A_IO : | |
1143 | POWER_DOMAIN_PORT_DDI_B_IO, | |
1144 | wakeref); | |
1145 | } | |
1146 | } | |
0f0fe849 MC |
1147 | |
1148 | /* set mode to DDI */ | |
1149 | for_each_dsi_port(port, intel_dsi->ports) { | |
1150 | tmp = I915_READ(ICL_DSI_IO_MODECTL(port)); | |
1151 | tmp &= ~COMBO_PHY_MODE_DSI; | |
1152 | I915_WRITE(ICL_DSI_IO_MODECTL(port), tmp); | |
1153 | } | |
1154 | } | |
1155 | ||
e2758048 MC |
1156 | static void gen11_dsi_disable(struct intel_encoder *encoder, |
1157 | const struct intel_crtc_state *old_crtc_state, | |
1158 | const struct drm_connector_state *old_conn_state) | |
d9d996b6 MC |
1159 | { |
1160 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
1161 | ||
1162 | /* step1: turn off backlight */ | |
1163 | intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF); | |
1164 | intel_panel_disable_backlight(old_conn_state); | |
4e123bd3 MC |
1165 | |
1166 | /* step2d,e: disable transcoder and wait */ | |
1167 | gen11_dsi_disable_transcoder(encoder); | |
522cc3f7 MC |
1168 | |
1169 | /* step2f,g: powerdown panel */ | |
1170 | gen11_dsi_powerdown_panel(encoder); | |
4769b598 MC |
1171 | |
1172 | /* step2h,i,j: deconfig trancoder */ | |
1173 | gen11_dsi_deconfigure_trancoder(encoder); | |
019cec36 MC |
1174 | |
1175 | /* step3: disable port */ | |
1176 | gen11_dsi_disable_port(encoder); | |
0f0fe849 MC |
1177 | |
1178 | /* step4: disable IO power */ | |
1179 | gen11_dsi_disable_io_power(encoder); | |
d9d996b6 | 1180 | } |
bf4d57ff | 1181 | |
8327af28 VK |
1182 | static void gen11_dsi_get_config(struct intel_encoder *encoder, |
1183 | struct intel_crtc_state *pipe_config) | |
1184 | { | |
1185 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
1186 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
8327af28 VK |
1187 | |
1188 | /* FIXME: adapt icl_ddi_clock_get() for DSI and use that? */ | |
5e65216d LDM |
1189 | pipe_config->port_clock = |
1190 | cnl_calc_wrpll_link(dev_priv, &pipe_config->dpll_hw_state); | |
8327af28 VK |
1191 | pipe_config->base.adjusted_mode.crtc_clock = intel_dsi->pclk; |
1192 | pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI); | |
1193 | } | |
1194 | ||
204474a6 LP |
1195 | static int gen11_dsi_compute_config(struct intel_encoder *encoder, |
1196 | struct intel_crtc_state *pipe_config, | |
1197 | struct drm_connector_state *conn_state) | |
d04afb15 MC |
1198 | { |
1199 | struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi, | |
1200 | base); | |
1201 | struct intel_connector *intel_connector = intel_dsi->attached_connector; | |
1202 | struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc); | |
1203 | const struct drm_display_mode *fixed_mode = | |
1204 | intel_connector->panel.fixed_mode; | |
1205 | struct drm_display_mode *adjusted_mode = | |
1206 | &pipe_config->base.adjusted_mode; | |
1207 | ||
1208 | intel_fixed_panel_mode(fixed_mode, adjusted_mode); | |
1209 | intel_pch_panel_fitting(crtc, pipe_config, conn_state->scaling_mode); | |
1210 | ||
1211 | adjusted_mode->flags = 0; | |
1212 | ||
1213 | /* Dual link goes to trancoder DSI'0' */ | |
1214 | if (intel_dsi->ports == BIT(PORT_B)) | |
1215 | pipe_config->cpu_transcoder = TRANSCODER_DSI_1; | |
1216 | else | |
1217 | pipe_config->cpu_transcoder = TRANSCODER_DSI_0; | |
1218 | ||
1219 | pipe_config->clock_set = true; | |
1220 | pipe_config->port_clock = intel_dsi_bitrate(intel_dsi) / 5; | |
1221 | ||
204474a6 | 1222 | return 0; |
d04afb15 MC |
1223 | } |
1224 | ||
ab841148 MC |
1225 | static u64 gen11_dsi_get_power_domains(struct intel_encoder *encoder, |
1226 | struct intel_crtc_state *crtc_state) | |
1227 | { | |
1228 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
1229 | u64 domains = 0; | |
1230 | enum port port; | |
1231 | ||
1232 | for_each_dsi_port(port, intel_dsi->ports) | |
1233 | if (port == PORT_A) | |
1234 | domains |= BIT_ULL(POWER_DOMAIN_PORT_DDI_A_IO); | |
1235 | else | |
1236 | domains |= BIT_ULL(POWER_DOMAIN_PORT_DDI_B_IO); | |
1237 | ||
1238 | return domains; | |
1239 | } | |
1240 | ||
1241 | static bool gen11_dsi_get_hw_state(struct intel_encoder *encoder, | |
1242 | enum pipe *pipe) | |
1243 | { | |
1244 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
1245 | struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); | |
ab841148 | 1246 | enum transcoder dsi_trans; |
0e6e0be4 CW |
1247 | intel_wakeref_t wakeref; |
1248 | enum port port; | |
ab841148 | 1249 | bool ret = false; |
0e6e0be4 | 1250 | u32 tmp; |
ab841148 | 1251 | |
0e6e0be4 CW |
1252 | wakeref = intel_display_power_get_if_enabled(dev_priv, |
1253 | encoder->power_domain); | |
1254 | if (!wakeref) | |
ab841148 MC |
1255 | return false; |
1256 | ||
1257 | for_each_dsi_port(port, intel_dsi->ports) { | |
1258 | dsi_trans = dsi_port_to_transcoder(port); | |
1259 | tmp = I915_READ(TRANS_DDI_FUNC_CTL(dsi_trans)); | |
1260 | switch (tmp & TRANS_DDI_EDP_INPUT_MASK) { | |
1261 | case TRANS_DDI_EDP_INPUT_A_ON: | |
1262 | *pipe = PIPE_A; | |
1263 | break; | |
1264 | case TRANS_DDI_EDP_INPUT_B_ONOFF: | |
1265 | *pipe = PIPE_B; | |
1266 | break; | |
1267 | case TRANS_DDI_EDP_INPUT_C_ONOFF: | |
1268 | *pipe = PIPE_C; | |
1269 | break; | |
1270 | default: | |
1271 | DRM_ERROR("Invalid PIPE input\n"); | |
1272 | goto out; | |
1273 | } | |
1274 | ||
1275 | tmp = I915_READ(PIPECONF(dsi_trans)); | |
1276 | ret = tmp & PIPECONF_ENABLE; | |
1277 | } | |
1278 | out: | |
0e6e0be4 | 1279 | intel_display_power_put(dev_priv, encoder->power_domain, wakeref); |
ab841148 MC |
1280 | return ret; |
1281 | } | |
1282 | ||
e2758048 MC |
1283 | static void gen11_dsi_encoder_destroy(struct drm_encoder *encoder) |
1284 | { | |
1285 | intel_encoder_destroy(encoder); | |
1286 | } | |
1287 | ||
1288 | static const struct drm_encoder_funcs gen11_dsi_encoder_funcs = { | |
1289 | .destroy = gen11_dsi_encoder_destroy, | |
1290 | }; | |
1291 | ||
1292 | static const struct drm_connector_funcs gen11_dsi_connector_funcs = { | |
1293 | .late_register = intel_connector_register, | |
1294 | .early_unregister = intel_connector_unregister, | |
1295 | .destroy = intel_connector_destroy, | |
1296 | .fill_modes = drm_helper_probe_single_connector_modes, | |
1297 | .atomic_get_property = intel_digital_connector_atomic_get_property, | |
1298 | .atomic_set_property = intel_digital_connector_atomic_set_property, | |
1299 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | |
1300 | .atomic_duplicate_state = intel_digital_connector_duplicate_state, | |
1301 | }; | |
1302 | ||
1303 | static const struct drm_connector_helper_funcs gen11_dsi_connector_helper_funcs = { | |
1304 | .get_modes = intel_dsi_get_modes, | |
1305 | .mode_valid = intel_dsi_mode_valid, | |
1306 | .atomic_check = intel_digital_connector_atomic_check, | |
1307 | }; | |
1308 | ||
c5f9c934 MC |
1309 | static int gen11_dsi_host_attach(struct mipi_dsi_host *host, |
1310 | struct mipi_dsi_device *dsi) | |
1311 | { | |
1312 | return 0; | |
1313 | } | |
1314 | ||
1315 | static int gen11_dsi_host_detach(struct mipi_dsi_host *host, | |
1316 | struct mipi_dsi_device *dsi) | |
1317 | { | |
1318 | return 0; | |
1319 | } | |
1320 | ||
1321 | static ssize_t gen11_dsi_host_transfer(struct mipi_dsi_host *host, | |
1322 | const struct mipi_dsi_msg *msg) | |
1323 | { | |
1324 | struct intel_dsi_host *intel_dsi_host = to_intel_dsi_host(host); | |
1325 | struct mipi_dsi_packet dsi_pkt; | |
1326 | ssize_t ret; | |
1327 | bool enable_lpdt = false; | |
1328 | ||
1329 | ret = mipi_dsi_create_packet(&dsi_pkt, msg); | |
1330 | if (ret < 0) | |
1331 | return ret; | |
1332 | ||
1333 | if (msg->flags & MIPI_DSI_MSG_USE_LPM) | |
1334 | enable_lpdt = true; | |
1335 | ||
1336 | /* send packet header */ | |
1337 | ret = dsi_send_pkt_hdr(intel_dsi_host, dsi_pkt, enable_lpdt); | |
1338 | if (ret < 0) | |
1339 | return ret; | |
1340 | ||
1341 | /* only long packet contains payload */ | |
1342 | if (mipi_dsi_packet_format_is_long(msg->type)) { | |
1343 | ret = dsi_send_pkt_payld(intel_dsi_host, dsi_pkt); | |
1344 | if (ret < 0) | |
1345 | return ret; | |
1346 | } | |
1347 | ||
1348 | //TODO: add payload receive code if needed | |
1349 | ||
1350 | ret = sizeof(dsi_pkt.header) + dsi_pkt.payload_length; | |
1351 | ||
1352 | return ret; | |
1353 | } | |
1354 | ||
1355 | static const struct mipi_dsi_host_ops gen11_dsi_host_ops = { | |
1356 | .attach = gen11_dsi_host_attach, | |
1357 | .detach = gen11_dsi_host_detach, | |
1358 | .transfer = gen11_dsi_host_transfer, | |
1359 | }; | |
1360 | ||
bf4d57ff MC |
1361 | void icl_dsi_init(struct drm_i915_private *dev_priv) |
1362 | { | |
e2758048 MC |
1363 | struct drm_device *dev = &dev_priv->drm; |
1364 | struct intel_dsi *intel_dsi; | |
1365 | struct intel_encoder *encoder; | |
1366 | struct intel_connector *intel_connector; | |
1367 | struct drm_connector *connector; | |
dee2370c | 1368 | struct drm_display_mode *fixed_mode; |
bf4d57ff MC |
1369 | enum port port; |
1370 | ||
1371 | if (!intel_bios_is_dsi_present(dev_priv, &port)) | |
1372 | return; | |
e2758048 MC |
1373 | |
1374 | intel_dsi = kzalloc(sizeof(*intel_dsi), GFP_KERNEL); | |
1375 | if (!intel_dsi) | |
1376 | return; | |
1377 | ||
1378 | intel_connector = intel_connector_alloc(); | |
1379 | if (!intel_connector) { | |
1380 | kfree(intel_dsi); | |
1381 | return; | |
1382 | } | |
1383 | ||
1384 | encoder = &intel_dsi->base; | |
1385 | intel_dsi->attached_connector = intel_connector; | |
1386 | connector = &intel_connector->base; | |
1387 | ||
1388 | /* register DSI encoder with DRM subsystem */ | |
1389 | drm_encoder_init(dev, &encoder->base, &gen11_dsi_encoder_funcs, | |
1390 | DRM_MODE_ENCODER_DSI, "DSI %c", port_name(port)); | |
1391 | ||
95f2f4db | 1392 | encoder->pre_pll_enable = gen11_dsi_pre_pll_enable; |
e2758048 MC |
1393 | encoder->pre_enable = gen11_dsi_pre_enable; |
1394 | encoder->disable = gen11_dsi_disable; | |
1395 | encoder->port = port; | |
8327af28 | 1396 | encoder->get_config = gen11_dsi_get_config; |
63a23d24 | 1397 | encoder->update_pipe = intel_panel_update_backlight; |
d04afb15 | 1398 | encoder->compute_config = gen11_dsi_compute_config; |
ab841148 | 1399 | encoder->get_hw_state = gen11_dsi_get_hw_state; |
e2758048 MC |
1400 | encoder->type = INTEL_OUTPUT_DSI; |
1401 | encoder->cloneable = 0; | |
1402 | encoder->crtc_mask = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C); | |
1403 | encoder->power_domain = POWER_DOMAIN_PORT_DSI; | |
ab841148 | 1404 | encoder->get_power_domains = gen11_dsi_get_power_domains; |
e2758048 MC |
1405 | |
1406 | /* register DSI connector with DRM subsystem */ | |
1407 | drm_connector_init(dev, connector, &gen11_dsi_connector_funcs, | |
1408 | DRM_MODE_CONNECTOR_DSI); | |
1409 | drm_connector_helper_add(connector, &gen11_dsi_connector_helper_funcs); | |
1410 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | |
1411 | connector->interlace_allowed = false; | |
1412 | connector->doublescan_allowed = false; | |
ab841148 | 1413 | intel_connector->get_hw_state = intel_connector_get_hw_state; |
e2758048 MC |
1414 | |
1415 | /* attach connector to encoder */ | |
1416 | intel_connector_attach_encoder(intel_connector, encoder); | |
1417 | ||
e2758048 | 1418 | mutex_lock(&dev->mode_config.mutex); |
dee2370c | 1419 | fixed_mode = intel_panel_vbt_fixed_mode(intel_connector); |
e2758048 MC |
1420 | mutex_unlock(&dev->mode_config.mutex); |
1421 | ||
1422 | if (!fixed_mode) { | |
1423 | DRM_ERROR("DSI fixed mode info missing\n"); | |
1424 | goto err; | |
1425 | } | |
1426 | ||
e2758048 MC |
1427 | intel_panel_init(&intel_connector->panel, fixed_mode, NULL); |
1428 | intel_panel_setup_backlight(connector, INVALID_PIPE); | |
1429 | ||
972d607c MC |
1430 | if (dev_priv->vbt.dsi.config->dual_link) |
1431 | intel_dsi->ports = BIT(PORT_A) | BIT(PORT_B); | |
1432 | else | |
1433 | intel_dsi->ports = BIT(port); | |
1434 | ||
1435 | intel_dsi->dcs_backlight_ports = dev_priv->vbt.dsi.bl_ports; | |
1436 | intel_dsi->dcs_cabc_ports = dev_priv->vbt.dsi.cabc_ports; | |
1437 | ||
c5f9c934 MC |
1438 | for_each_dsi_port(port, intel_dsi->ports) { |
1439 | struct intel_dsi_host *host; | |
1440 | ||
1441 | host = intel_dsi_host_init(intel_dsi, &gen11_dsi_host_ops, port); | |
1442 | if (!host) | |
1443 | goto err; | |
1444 | ||
1445 | intel_dsi->dsi_hosts[port] = host; | |
1446 | } | |
1447 | ||
e2758048 MC |
1448 | if (!intel_dsi_vbt_init(intel_dsi, MIPI_DSI_GENERIC_PANEL_ID)) { |
1449 | DRM_DEBUG_KMS("no device found\n"); | |
1450 | goto err; | |
1451 | } | |
1452 | ||
1453 | return; | |
1454 | ||
1455 | err: | |
1456 | drm_encoder_cleanup(&encoder->base); | |
1457 | kfree(intel_dsi); | |
1458 | kfree(intel_connector); | |
bf4d57ff | 1459 | } |