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