1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2015, The Linux Foundation. All rights reserved. |
4 | */ |
5 | |
6 | #include <linux/clk.h> |
7 | #include <linux/delay.h> |
8 | #include <linux/dma-mapping.h> |
9 | #include <linux/err.h> |
10 | #include <linux/gpio/consumer.h> |
11 | #include <linux/interrupt.h> |
12 | #include <linux/mfd/syscon.h> |
13 | #include <linux/of.h> |
14 | #include <linux/of_graph.h> |
15 | #include <linux/of_irq.h> |
16 | #include <linux/pinctrl/consumer.h> |
17 | #include <linux/pm_opp.h> |
18 | #include <linux/regmap.h> |
19 | #include <linux/regulator/consumer.h> |
20 | #include <linux/spinlock.h> |
21 | |
22 | #include <video/mipi_display.h> |
23 | |
24 | #include <drm/display/drm_dsc_helper.h> |
25 | #include <drm/drm_of.h> |
26 | |
27 | #include "dsi.h" |
28 | #include "dsi.xml.h" |
29 | #include "sfpb.xml.h" |
30 | #include "dsi_cfg.h" |
31 | #include "msm_dsc_helper.h" |
32 | #include "msm_kms.h" |
33 | #include "msm_gem.h" |
34 | #include "phy/dsi_phy.h" |
35 | |
36 | #define DSI_RESET_TOGGLE_DELAY_MS 20 |
37 | |
38 | static int dsi_populate_dsc_params(struct msm_dsi_host *msm_host, struct drm_dsc_config *dsc); |
39 | |
40 | static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor) |
41 | { |
42 | u32 ver; |
43 | |
44 | if (!major || !minor) |
45 | return -EINVAL; |
46 | |
47 | /* |
48 | * From DSI6G(v3), addition of a 6G_HW_VERSION register at offset 0 |
49 | * makes all other registers 4-byte shifted down. |
50 | * |
51 | * In order to identify between DSI6G(v3) and beyond, and DSIv2 and |
52 | * older, we read the DSI_VERSION register without any shift(offset |
53 | * 0x1f0). In the case of DSIv2, this hast to be a non-zero value. In |
54 | * the case of DSI6G, this has to be zero (the offset points to a |
55 | * scratch register which we never touch) |
56 | */ |
57 | |
58 | ver = msm_readl(base + REG_DSI_VERSION); |
59 | if (ver) { |
60 | /* older dsi host, there is no register shift */ |
61 | ver = FIELD(ver, DSI_VERSION_MAJOR); |
62 | if (ver <= MSM_DSI_VER_MAJOR_V2) { |
63 | /* old versions */ |
64 | *major = ver; |
65 | *minor = 0; |
66 | return 0; |
67 | } else { |
68 | return -EINVAL; |
69 | } |
70 | } else { |
71 | /* |
72 | * newer host, offset 0 has 6G_HW_VERSION, the rest of the |
73 | * registers are shifted down, read DSI_VERSION again with |
74 | * the shifted offset |
75 | */ |
76 | ver = msm_readl(base + DSI_6G_REG_SHIFT + REG_DSI_VERSION); |
77 | ver = FIELD(ver, DSI_VERSION_MAJOR); |
78 | if (ver == MSM_DSI_VER_MAJOR_6G) { |
79 | /* 6G version */ |
80 | *major = ver; |
81 | *minor = msm_readl(base + REG_DSI_6G_HW_VERSION); |
82 | return 0; |
83 | } else { |
84 | return -EINVAL; |
85 | } |
86 | } |
87 | } |
88 | |
89 | #define DSI_ERR_STATE_ACK 0x0000 |
90 | #define DSI_ERR_STATE_TIMEOUT 0x0001 |
91 | #define DSI_ERR_STATE_DLN0_PHY 0x0002 |
92 | #define DSI_ERR_STATE_FIFO 0x0004 |
93 | #define DSI_ERR_STATE_MDP_FIFO_UNDERFLOW 0x0008 |
94 | #define DSI_ERR_STATE_INTERLEAVE_OP_CONTENTION 0x0010 |
95 | #define DSI_ERR_STATE_PLL_UNLOCKED 0x0020 |
96 | |
97 | #define DSI_CLK_CTRL_ENABLE_CLKS \ |
98 | (DSI_CLK_CTRL_AHBS_HCLK_ON | DSI_CLK_CTRL_AHBM_SCLK_ON | \ |
99 | DSI_CLK_CTRL_PCLK_ON | DSI_CLK_CTRL_DSICLK_ON | \ |
100 | DSI_CLK_CTRL_BYTECLK_ON | DSI_CLK_CTRL_ESCCLK_ON | \ |
101 | DSI_CLK_CTRL_FORCE_ON_DYN_AHBM_HCLK) |
102 | |
103 | struct msm_dsi_host { |
104 | struct mipi_dsi_host base; |
105 | |
106 | struct platform_device *pdev; |
107 | struct drm_device *dev; |
108 | |
109 | int id; |
110 | |
111 | void __iomem *ctrl_base; |
112 | phys_addr_t ctrl_size; |
113 | struct regulator_bulk_data *supplies; |
114 | |
115 | int num_bus_clks; |
116 | struct clk_bulk_data bus_clks[DSI_BUS_CLK_MAX]; |
117 | |
118 | struct clk *byte_clk; |
119 | struct clk *esc_clk; |
120 | struct clk *pixel_clk; |
121 | struct clk *byte_intf_clk; |
122 | |
123 | unsigned long byte_clk_rate; |
124 | unsigned long byte_intf_clk_rate; |
125 | unsigned long pixel_clk_rate; |
126 | unsigned long esc_clk_rate; |
127 | |
128 | /* DSI v2 specific clocks */ |
129 | struct clk *src_clk; |
130 | |
131 | unsigned long src_clk_rate; |
132 | |
133 | struct gpio_desc *disp_en_gpio; |
134 | struct gpio_desc *te_gpio; |
135 | |
136 | const struct msm_dsi_cfg_handler *cfg_hnd; |
137 | |
138 | struct completion dma_comp; |
139 | struct completion video_comp; |
140 | struct mutex dev_mutex; |
141 | struct mutex cmd_mutex; |
142 | spinlock_t intr_lock; /* Protect interrupt ctrl register */ |
143 | |
144 | u32 err_work_state; |
145 | struct work_struct err_work; |
146 | struct workqueue_struct *workqueue; |
147 | |
148 | /* DSI 6G TX buffer*/ |
149 | struct drm_gem_object *tx_gem_obj; |
150 | struct msm_gem_address_space *aspace; |
151 | |
152 | /* DSI v2 TX buffer */ |
153 | void *tx_buf; |
154 | dma_addr_t tx_buf_paddr; |
155 | |
156 | int tx_size; |
157 | |
158 | u8 *rx_buf; |
159 | |
160 | struct regmap *sfpb; |
161 | |
162 | struct drm_display_mode *mode; |
163 | struct drm_dsc_config *dsc; |
164 | |
165 | /* connected device info */ |
166 | unsigned int channel; |
167 | unsigned int lanes; |
168 | enum mipi_dsi_pixel_format format; |
169 | unsigned long mode_flags; |
170 | |
171 | /* lane data parsed via DT */ |
172 | int dlane_swap; |
173 | int num_data_lanes; |
174 | |
175 | /* from phy DT */ |
176 | bool cphy_mode; |
177 | |
178 | u32 dma_cmd_ctrl_restore; |
179 | |
180 | bool registered; |
181 | bool power_on; |
182 | bool enabled; |
183 | int irq; |
184 | }; |
185 | |
186 | |
187 | static inline u32 dsi_read(struct msm_dsi_host *msm_host, u32 reg) |
188 | { |
189 | return msm_readl(msm_host->ctrl_base + reg); |
190 | } |
191 | static inline void dsi_write(struct msm_dsi_host *msm_host, u32 reg, u32 data) |
192 | { |
193 | msm_writel(data, msm_host->ctrl_base + reg); |
194 | } |
195 | |
196 | static const struct msm_dsi_cfg_handler *dsi_get_config( |
197 | struct msm_dsi_host *msm_host) |
198 | { |
199 | const struct msm_dsi_cfg_handler *cfg_hnd = NULL; |
200 | struct device *dev = &msm_host->pdev->dev; |
201 | struct clk *ahb_clk; |
202 | int ret; |
203 | u32 major = 0, minor = 0; |
204 | |
205 | ahb_clk = msm_clk_get(msm_host->pdev, "iface" ); |
206 | if (IS_ERR(ptr: ahb_clk)) { |
207 | pr_err("%s: cannot get interface clock\n" , __func__); |
208 | goto exit; |
209 | } |
210 | |
211 | pm_runtime_get_sync(dev); |
212 | |
213 | ret = clk_prepare_enable(clk: ahb_clk); |
214 | if (ret) { |
215 | pr_err("%s: unable to enable ahb_clk\n" , __func__); |
216 | goto runtime_put; |
217 | } |
218 | |
219 | ret = dsi_get_version(base: msm_host->ctrl_base, major: &major, minor: &minor); |
220 | if (ret) { |
221 | pr_err("%s: Invalid version\n" , __func__); |
222 | goto disable_clks; |
223 | } |
224 | |
225 | cfg_hnd = msm_dsi_cfg_get(major, minor); |
226 | |
227 | DBG("%s: Version %x:%x\n" , __func__, major, minor); |
228 | |
229 | disable_clks: |
230 | clk_disable_unprepare(clk: ahb_clk); |
231 | runtime_put: |
232 | pm_runtime_put_sync(dev); |
233 | exit: |
234 | return cfg_hnd; |
235 | } |
236 | |
237 | static inline struct msm_dsi_host *to_msm_dsi_host(struct mipi_dsi_host *host) |
238 | { |
239 | return container_of(host, struct msm_dsi_host, base); |
240 | } |
241 | |
242 | int dsi_clk_init_v2(struct msm_dsi_host *msm_host) |
243 | { |
244 | struct platform_device *pdev = msm_host->pdev; |
245 | int ret = 0; |
246 | |
247 | msm_host->src_clk = msm_clk_get(pdev, "src" ); |
248 | |
249 | if (IS_ERR(ptr: msm_host->src_clk)) { |
250 | ret = PTR_ERR(ptr: msm_host->src_clk); |
251 | pr_err("%s: can't find src clock. ret=%d\n" , |
252 | __func__, ret); |
253 | msm_host->src_clk = NULL; |
254 | return ret; |
255 | } |
256 | |
257 | return ret; |
258 | } |
259 | |
260 | int dsi_clk_init_6g_v2(struct msm_dsi_host *msm_host) |
261 | { |
262 | struct platform_device *pdev = msm_host->pdev; |
263 | int ret = 0; |
264 | |
265 | msm_host->byte_intf_clk = msm_clk_get(pdev, "byte_intf" ); |
266 | if (IS_ERR(ptr: msm_host->byte_intf_clk)) { |
267 | ret = PTR_ERR(ptr: msm_host->byte_intf_clk); |
268 | pr_err("%s: can't find byte_intf clock. ret=%d\n" , |
269 | __func__, ret); |
270 | } |
271 | |
272 | return ret; |
273 | } |
274 | |
275 | static int dsi_clk_init(struct msm_dsi_host *msm_host) |
276 | { |
277 | struct platform_device *pdev = msm_host->pdev; |
278 | const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; |
279 | const struct msm_dsi_config *cfg = cfg_hnd->cfg; |
280 | int i, ret = 0; |
281 | |
282 | /* get bus clocks */ |
283 | for (i = 0; i < cfg->num_bus_clks; i++) |
284 | msm_host->bus_clks[i].id = cfg->bus_clk_names[i]; |
285 | msm_host->num_bus_clks = cfg->num_bus_clks; |
286 | |
287 | ret = devm_clk_bulk_get(dev: &pdev->dev, num_clks: msm_host->num_bus_clks, clks: msm_host->bus_clks); |
288 | if (ret < 0) { |
289 | dev_err(&pdev->dev, "Unable to get clocks, ret = %d\n" , ret); |
290 | goto exit; |
291 | } |
292 | |
293 | /* get link and source clocks */ |
294 | msm_host->byte_clk = msm_clk_get(pdev, "byte" ); |
295 | if (IS_ERR(ptr: msm_host->byte_clk)) { |
296 | ret = PTR_ERR(ptr: msm_host->byte_clk); |
297 | pr_err("%s: can't find dsi_byte clock. ret=%d\n" , |
298 | __func__, ret); |
299 | msm_host->byte_clk = NULL; |
300 | goto exit; |
301 | } |
302 | |
303 | msm_host->pixel_clk = msm_clk_get(pdev, "pixel" ); |
304 | if (IS_ERR(ptr: msm_host->pixel_clk)) { |
305 | ret = PTR_ERR(ptr: msm_host->pixel_clk); |
306 | pr_err("%s: can't find dsi_pixel clock. ret=%d\n" , |
307 | __func__, ret); |
308 | msm_host->pixel_clk = NULL; |
309 | goto exit; |
310 | } |
311 | |
312 | msm_host->esc_clk = msm_clk_get(pdev, "core" ); |
313 | if (IS_ERR(ptr: msm_host->esc_clk)) { |
314 | ret = PTR_ERR(ptr: msm_host->esc_clk); |
315 | pr_err("%s: can't find dsi_esc clock. ret=%d\n" , |
316 | __func__, ret); |
317 | msm_host->esc_clk = NULL; |
318 | goto exit; |
319 | } |
320 | |
321 | if (cfg_hnd->ops->clk_init_ver) |
322 | ret = cfg_hnd->ops->clk_init_ver(msm_host); |
323 | exit: |
324 | return ret; |
325 | } |
326 | |
327 | int msm_dsi_runtime_suspend(struct device *dev) |
328 | { |
329 | struct platform_device *pdev = to_platform_device(dev); |
330 | struct msm_dsi *msm_dsi = platform_get_drvdata(pdev); |
331 | struct mipi_dsi_host *host = msm_dsi->host; |
332 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
333 | |
334 | if (!msm_host->cfg_hnd) |
335 | return 0; |
336 | |
337 | clk_bulk_disable_unprepare(num_clks: msm_host->num_bus_clks, clks: msm_host->bus_clks); |
338 | |
339 | return 0; |
340 | } |
341 | |
342 | int msm_dsi_runtime_resume(struct device *dev) |
343 | { |
344 | struct platform_device *pdev = to_platform_device(dev); |
345 | struct msm_dsi *msm_dsi = platform_get_drvdata(pdev); |
346 | struct mipi_dsi_host *host = msm_dsi->host; |
347 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
348 | |
349 | if (!msm_host->cfg_hnd) |
350 | return 0; |
351 | |
352 | return clk_bulk_prepare_enable(num_clks: msm_host->num_bus_clks, clks: msm_host->bus_clks); |
353 | } |
354 | |
355 | int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host) |
356 | { |
357 | int ret; |
358 | |
359 | DBG("Set clk rates: pclk=%d, byteclk=%lu" , |
360 | msm_host->mode->clock, msm_host->byte_clk_rate); |
361 | |
362 | ret = dev_pm_opp_set_rate(dev: &msm_host->pdev->dev, |
363 | target_freq: msm_host->byte_clk_rate); |
364 | if (ret) { |
365 | pr_err("%s: dev_pm_opp_set_rate failed %d\n" , __func__, ret); |
366 | return ret; |
367 | } |
368 | |
369 | ret = clk_set_rate(clk: msm_host->pixel_clk, rate: msm_host->pixel_clk_rate); |
370 | if (ret) { |
371 | pr_err("%s: Failed to set rate pixel clk, %d\n" , __func__, ret); |
372 | return ret; |
373 | } |
374 | |
375 | if (msm_host->byte_intf_clk) { |
376 | ret = clk_set_rate(clk: msm_host->byte_intf_clk, rate: msm_host->byte_intf_clk_rate); |
377 | if (ret) { |
378 | pr_err("%s: Failed to set rate byte intf clk, %d\n" , |
379 | __func__, ret); |
380 | return ret; |
381 | } |
382 | } |
383 | |
384 | return 0; |
385 | } |
386 | |
387 | |
388 | int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) |
389 | { |
390 | int ret; |
391 | |
392 | ret = clk_prepare_enable(clk: msm_host->esc_clk); |
393 | if (ret) { |
394 | pr_err("%s: Failed to enable dsi esc clk\n" , __func__); |
395 | goto error; |
396 | } |
397 | |
398 | ret = clk_prepare_enable(clk: msm_host->byte_clk); |
399 | if (ret) { |
400 | pr_err("%s: Failed to enable dsi byte clk\n" , __func__); |
401 | goto byte_clk_err; |
402 | } |
403 | |
404 | ret = clk_prepare_enable(clk: msm_host->pixel_clk); |
405 | if (ret) { |
406 | pr_err("%s: Failed to enable dsi pixel clk\n" , __func__); |
407 | goto pixel_clk_err; |
408 | } |
409 | |
410 | ret = clk_prepare_enable(clk: msm_host->byte_intf_clk); |
411 | if (ret) { |
412 | pr_err("%s: Failed to enable byte intf clk\n" , |
413 | __func__); |
414 | goto byte_intf_clk_err; |
415 | } |
416 | |
417 | return 0; |
418 | |
419 | byte_intf_clk_err: |
420 | clk_disable_unprepare(clk: msm_host->pixel_clk); |
421 | pixel_clk_err: |
422 | clk_disable_unprepare(clk: msm_host->byte_clk); |
423 | byte_clk_err: |
424 | clk_disable_unprepare(clk: msm_host->esc_clk); |
425 | error: |
426 | return ret; |
427 | } |
428 | |
429 | int dsi_link_clk_set_rate_v2(struct msm_dsi_host *msm_host) |
430 | { |
431 | int ret; |
432 | |
433 | DBG("Set clk rates: pclk=%d, byteclk=%lu, esc_clk=%lu, dsi_src_clk=%lu" , |
434 | msm_host->mode->clock, msm_host->byte_clk_rate, |
435 | msm_host->esc_clk_rate, msm_host->src_clk_rate); |
436 | |
437 | ret = clk_set_rate(clk: msm_host->byte_clk, rate: msm_host->byte_clk_rate); |
438 | if (ret) { |
439 | pr_err("%s: Failed to set rate byte clk, %d\n" , __func__, ret); |
440 | return ret; |
441 | } |
442 | |
443 | ret = clk_set_rate(clk: msm_host->esc_clk, rate: msm_host->esc_clk_rate); |
444 | if (ret) { |
445 | pr_err("%s: Failed to set rate esc clk, %d\n" , __func__, ret); |
446 | return ret; |
447 | } |
448 | |
449 | ret = clk_set_rate(clk: msm_host->src_clk, rate: msm_host->src_clk_rate); |
450 | if (ret) { |
451 | pr_err("%s: Failed to set rate src clk, %d\n" , __func__, ret); |
452 | return ret; |
453 | } |
454 | |
455 | ret = clk_set_rate(clk: msm_host->pixel_clk, rate: msm_host->pixel_clk_rate); |
456 | if (ret) { |
457 | pr_err("%s: Failed to set rate pixel clk, %d\n" , __func__, ret); |
458 | return ret; |
459 | } |
460 | |
461 | return 0; |
462 | } |
463 | |
464 | int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host) |
465 | { |
466 | int ret; |
467 | |
468 | ret = clk_prepare_enable(clk: msm_host->byte_clk); |
469 | if (ret) { |
470 | pr_err("%s: Failed to enable dsi byte clk\n" , __func__); |
471 | goto error; |
472 | } |
473 | |
474 | ret = clk_prepare_enable(clk: msm_host->esc_clk); |
475 | if (ret) { |
476 | pr_err("%s: Failed to enable dsi esc clk\n" , __func__); |
477 | goto esc_clk_err; |
478 | } |
479 | |
480 | ret = clk_prepare_enable(clk: msm_host->src_clk); |
481 | if (ret) { |
482 | pr_err("%s: Failed to enable dsi src clk\n" , __func__); |
483 | goto src_clk_err; |
484 | } |
485 | |
486 | ret = clk_prepare_enable(clk: msm_host->pixel_clk); |
487 | if (ret) { |
488 | pr_err("%s: Failed to enable dsi pixel clk\n" , __func__); |
489 | goto pixel_clk_err; |
490 | } |
491 | |
492 | return 0; |
493 | |
494 | pixel_clk_err: |
495 | clk_disable_unprepare(clk: msm_host->src_clk); |
496 | src_clk_err: |
497 | clk_disable_unprepare(clk: msm_host->esc_clk); |
498 | esc_clk_err: |
499 | clk_disable_unprepare(clk: msm_host->byte_clk); |
500 | error: |
501 | return ret; |
502 | } |
503 | |
504 | void dsi_link_clk_disable_6g(struct msm_dsi_host *msm_host) |
505 | { |
506 | /* Drop the performance state vote */ |
507 | dev_pm_opp_set_rate(dev: &msm_host->pdev->dev, target_freq: 0); |
508 | clk_disable_unprepare(clk: msm_host->esc_clk); |
509 | clk_disable_unprepare(clk: msm_host->pixel_clk); |
510 | clk_disable_unprepare(clk: msm_host->byte_intf_clk); |
511 | clk_disable_unprepare(clk: msm_host->byte_clk); |
512 | } |
513 | |
514 | void dsi_link_clk_disable_v2(struct msm_dsi_host *msm_host) |
515 | { |
516 | clk_disable_unprepare(clk: msm_host->pixel_clk); |
517 | clk_disable_unprepare(clk: msm_host->src_clk); |
518 | clk_disable_unprepare(clk: msm_host->esc_clk); |
519 | clk_disable_unprepare(clk: msm_host->byte_clk); |
520 | } |
521 | |
522 | /** |
523 | * dsi_adjust_pclk_for_compression() - Adjust the pclk rate for compression case |
524 | * @mode: The selected mode for the DSI output |
525 | * @dsc: DRM DSC configuration for this DSI output |
526 | * |
527 | * Adjust the pclk rate by calculating a new hdisplay proportional to |
528 | * the compression ratio such that: |
529 | * new_hdisplay = old_hdisplay * compressed_bpp / uncompressed_bpp |
530 | * |
531 | * Porches do not need to be adjusted: |
532 | * - For VIDEO mode they are not compressed by DSC and are passed as is. |
533 | * - For CMD mode there are no actual porches. Instead these fields |
534 | * currently represent the overhead to the image data transfer. As such, they |
535 | * are calculated for the final mode parameters (after the compression) and |
536 | * are not to be adjusted too. |
537 | * |
538 | * FIXME: Reconsider this if/when CMD mode handling is rewritten to use |
539 | * transfer time and data overhead as a starting point of the calculations. |
540 | */ |
541 | static unsigned long dsi_adjust_pclk_for_compression(const struct drm_display_mode *mode, |
542 | const struct drm_dsc_config *dsc) |
543 | { |
544 | int new_hdisplay = DIV_ROUND_UP(mode->hdisplay * drm_dsc_get_bpp_int(dsc), |
545 | dsc->bits_per_component * 3); |
546 | |
547 | int new_htotal = mode->htotal - mode->hdisplay + new_hdisplay; |
548 | |
549 | return new_htotal * mode->vtotal * drm_mode_vrefresh(mode); |
550 | } |
551 | |
552 | static unsigned long dsi_get_pclk_rate(const struct drm_display_mode *mode, |
553 | const struct drm_dsc_config *dsc, bool is_bonded_dsi) |
554 | { |
555 | unsigned long pclk_rate; |
556 | |
557 | pclk_rate = mode->clock * 1000; |
558 | |
559 | if (dsc) |
560 | pclk_rate = dsi_adjust_pclk_for_compression(mode, dsc); |
561 | |
562 | /* |
563 | * For bonded DSI mode, the current DRM mode has the complete width of the |
564 | * panel. Since, the complete panel is driven by two DSI controllers, |
565 | * the clock rates have to be split between the two dsi controllers. |
566 | * Adjust the byte and pixel clock rates for each dsi host accordingly. |
567 | */ |
568 | if (is_bonded_dsi) |
569 | pclk_rate /= 2; |
570 | |
571 | return pclk_rate; |
572 | } |
573 | |
574 | unsigned long dsi_byte_clk_get_rate(struct mipi_dsi_host *host, bool is_bonded_dsi, |
575 | const struct drm_display_mode *mode) |
576 | { |
577 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
578 | u8 lanes = msm_host->lanes; |
579 | u32 bpp = mipi_dsi_pixel_format_to_bpp(fmt: msm_host->format); |
580 | unsigned long pclk_rate = dsi_get_pclk_rate(mode, dsc: msm_host->dsc, is_bonded_dsi); |
581 | unsigned long pclk_bpp; |
582 | |
583 | if (lanes == 0) { |
584 | pr_err("%s: forcing mdss_dsi lanes to 1\n" , __func__); |
585 | lanes = 1; |
586 | } |
587 | |
588 | /* CPHY "byte_clk" is in units of 16 bits */ |
589 | if (msm_host->cphy_mode) |
590 | pclk_bpp = mult_frac(pclk_rate, bpp, 16 * lanes); |
591 | else |
592 | pclk_bpp = mult_frac(pclk_rate, bpp, 8 * lanes); |
593 | |
594 | return pclk_bpp; |
595 | } |
596 | |
597 | static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi) |
598 | { |
599 | msm_host->pixel_clk_rate = dsi_get_pclk_rate(mode: msm_host->mode, dsc: msm_host->dsc, is_bonded_dsi); |
600 | msm_host->byte_clk_rate = dsi_byte_clk_get_rate(host: &msm_host->base, is_bonded_dsi, |
601 | mode: msm_host->mode); |
602 | |
603 | DBG("pclk=%lu, bclk=%lu" , msm_host->pixel_clk_rate, |
604 | msm_host->byte_clk_rate); |
605 | |
606 | } |
607 | |
608 | int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_bonded_dsi) |
609 | { |
610 | if (!msm_host->mode) { |
611 | pr_err("%s: mode not set\n" , __func__); |
612 | return -EINVAL; |
613 | } |
614 | |
615 | dsi_calc_pclk(msm_host, is_bonded_dsi); |
616 | msm_host->esc_clk_rate = clk_get_rate(clk: msm_host->esc_clk); |
617 | return 0; |
618 | } |
619 | |
620 | int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_bonded_dsi) |
621 | { |
622 | u32 bpp = mipi_dsi_pixel_format_to_bpp(fmt: msm_host->format); |
623 | unsigned int esc_mhz, esc_div; |
624 | unsigned long byte_mhz; |
625 | |
626 | dsi_calc_pclk(msm_host, is_bonded_dsi); |
627 | |
628 | msm_host->src_clk_rate = mult_frac(msm_host->pixel_clk_rate, bpp, 8); |
629 | |
630 | /* |
631 | * esc clock is byte clock followed by a 4 bit divider, |
632 | * we need to find an escape clock frequency within the |
633 | * mipi DSI spec range within the maximum divider limit |
634 | * We iterate here between an escape clock frequencey |
635 | * between 20 Mhz to 5 Mhz and pick up the first one |
636 | * that can be supported by our divider |
637 | */ |
638 | |
639 | byte_mhz = msm_host->byte_clk_rate / 1000000; |
640 | |
641 | for (esc_mhz = 20; esc_mhz >= 5; esc_mhz--) { |
642 | esc_div = DIV_ROUND_UP(byte_mhz, esc_mhz); |
643 | |
644 | /* |
645 | * TODO: Ideally, we shouldn't know what sort of divider |
646 | * is available in mmss_cc, we're just assuming that |
647 | * it'll always be a 4 bit divider. Need to come up with |
648 | * a better way here. |
649 | */ |
650 | if (esc_div >= 1 && esc_div <= 16) |
651 | break; |
652 | } |
653 | |
654 | if (esc_mhz < 5) |
655 | return -EINVAL; |
656 | |
657 | msm_host->esc_clk_rate = msm_host->byte_clk_rate / esc_div; |
658 | |
659 | DBG("esc=%lu, src=%lu" , msm_host->esc_clk_rate, |
660 | msm_host->src_clk_rate); |
661 | |
662 | return 0; |
663 | } |
664 | |
665 | static void dsi_intr_ctrl(struct msm_dsi_host *msm_host, u32 mask, int enable) |
666 | { |
667 | u32 intr; |
668 | unsigned long flags; |
669 | |
670 | spin_lock_irqsave(&msm_host->intr_lock, flags); |
671 | intr = dsi_read(msm_host, REG_DSI_INTR_CTRL); |
672 | |
673 | if (enable) |
674 | intr |= mask; |
675 | else |
676 | intr &= ~mask; |
677 | |
678 | DBG("intr=%x enable=%d" , intr, enable); |
679 | |
680 | dsi_write(msm_host, REG_DSI_INTR_CTRL, data: intr); |
681 | spin_unlock_irqrestore(lock: &msm_host->intr_lock, flags); |
682 | } |
683 | |
684 | static inline enum dsi_traffic_mode dsi_get_traffic_mode(const u32 mode_flags) |
685 | { |
686 | if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST) |
687 | return BURST_MODE; |
688 | else if (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) |
689 | return NON_BURST_SYNCH_PULSE; |
690 | |
691 | return NON_BURST_SYNCH_EVENT; |
692 | } |
693 | |
694 | static inline enum dsi_vid_dst_format dsi_get_vid_fmt( |
695 | const enum mipi_dsi_pixel_format mipi_fmt) |
696 | { |
697 | switch (mipi_fmt) { |
698 | case MIPI_DSI_FMT_RGB888: return VID_DST_FORMAT_RGB888; |
699 | case MIPI_DSI_FMT_RGB666: return VID_DST_FORMAT_RGB666_LOOSE; |
700 | case MIPI_DSI_FMT_RGB666_PACKED: return VID_DST_FORMAT_RGB666; |
701 | case MIPI_DSI_FMT_RGB565: return VID_DST_FORMAT_RGB565; |
702 | default: return VID_DST_FORMAT_RGB888; |
703 | } |
704 | } |
705 | |
706 | static inline enum dsi_cmd_dst_format dsi_get_cmd_fmt( |
707 | const enum mipi_dsi_pixel_format mipi_fmt) |
708 | { |
709 | switch (mipi_fmt) { |
710 | case MIPI_DSI_FMT_RGB888: return CMD_DST_FORMAT_RGB888; |
711 | case MIPI_DSI_FMT_RGB666_PACKED: |
712 | case MIPI_DSI_FMT_RGB666: return CMD_DST_FORMAT_RGB666; |
713 | case MIPI_DSI_FMT_RGB565: return CMD_DST_FORMAT_RGB565; |
714 | default: return CMD_DST_FORMAT_RGB888; |
715 | } |
716 | } |
717 | |
718 | static void dsi_ctrl_disable(struct msm_dsi_host *msm_host) |
719 | { |
720 | dsi_write(msm_host, REG_DSI_CTRL, data: 0); |
721 | } |
722 | |
723 | bool msm_dsi_host_is_wide_bus_enabled(struct mipi_dsi_host *host) |
724 | { |
725 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
726 | |
727 | return msm_host->dsc && |
728 | (msm_host->cfg_hnd->major == MSM_DSI_VER_MAJOR_6G && |
729 | msm_host->cfg_hnd->minor >= MSM_DSI_6G_VER_MINOR_V2_5_0); |
730 | } |
731 | |
732 | static void dsi_ctrl_enable(struct msm_dsi_host *msm_host, |
733 | struct msm_dsi_phy_shared_timings *phy_shared_timings, struct msm_dsi_phy *phy) |
734 | { |
735 | u32 flags = msm_host->mode_flags; |
736 | enum mipi_dsi_pixel_format mipi_fmt = msm_host->format; |
737 | const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; |
738 | u32 data = 0, lane_ctrl = 0; |
739 | |
740 | if (flags & MIPI_DSI_MODE_VIDEO) { |
741 | if (flags & MIPI_DSI_MODE_VIDEO_HSE) |
742 | data |= DSI_VID_CFG0_PULSE_MODE_HSA_HE; |
743 | if (flags & MIPI_DSI_MODE_VIDEO_NO_HFP) |
744 | data |= DSI_VID_CFG0_HFP_POWER_STOP; |
745 | if (flags & MIPI_DSI_MODE_VIDEO_NO_HBP) |
746 | data |= DSI_VID_CFG0_HBP_POWER_STOP; |
747 | if (flags & MIPI_DSI_MODE_VIDEO_NO_HSA) |
748 | data |= DSI_VID_CFG0_HSA_POWER_STOP; |
749 | /* Always set low power stop mode for BLLP |
750 | * to let command engine send packets |
751 | */ |
752 | data |= DSI_VID_CFG0_EOF_BLLP_POWER_STOP | |
753 | DSI_VID_CFG0_BLLP_POWER_STOP; |
754 | data |= DSI_VID_CFG0_TRAFFIC_MODE(val: dsi_get_traffic_mode(mode_flags: flags)); |
755 | data |= DSI_VID_CFG0_DST_FORMAT(val: dsi_get_vid_fmt(mipi_fmt)); |
756 | data |= DSI_VID_CFG0_VIRT_CHANNEL(val: msm_host->channel); |
757 | dsi_write(msm_host, REG_DSI_VID_CFG0, data); |
758 | |
759 | /* Do not swap RGB colors */ |
760 | data = DSI_VID_CFG1_RGB_SWAP(val: SWAP_RGB); |
761 | dsi_write(msm_host, REG_DSI_VID_CFG1, data: 0); |
762 | } else { |
763 | /* Do not swap RGB colors */ |
764 | data = DSI_CMD_CFG0_RGB_SWAP(val: SWAP_RGB); |
765 | data |= DSI_CMD_CFG0_DST_FORMAT(val: dsi_get_cmd_fmt(mipi_fmt)); |
766 | dsi_write(msm_host, REG_DSI_CMD_CFG0, data); |
767 | |
768 | data = DSI_CMD_CFG1_WR_MEM_START(val: MIPI_DCS_WRITE_MEMORY_START) | |
769 | DSI_CMD_CFG1_WR_MEM_CONTINUE( |
770 | val: MIPI_DCS_WRITE_MEMORY_CONTINUE); |
771 | /* Always insert DCS command */ |
772 | data |= DSI_CMD_CFG1_INSERT_DCS_COMMAND; |
773 | dsi_write(msm_host, REG_DSI_CMD_CFG1, data); |
774 | |
775 | if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) { |
776 | data = dsi_read(msm_host, REG_DSI_CMD_MODE_MDP_CTRL2); |
777 | |
778 | if (cfg_hnd->minor >= MSM_DSI_6G_VER_MINOR_V1_3) |
779 | data |= DSI_CMD_MODE_MDP_CTRL2_BURST_MODE; |
780 | |
781 | /* TODO: Allow for video-mode support once tested/fixed */ |
782 | if (msm_dsi_host_is_wide_bus_enabled(host: &msm_host->base)) |
783 | data |= DSI_CMD_MODE_MDP_CTRL2_DATABUS_WIDEN; |
784 | |
785 | dsi_write(msm_host, REG_DSI_CMD_MODE_MDP_CTRL2, data); |
786 | } |
787 | } |
788 | |
789 | dsi_write(msm_host, REG_DSI_CMD_DMA_CTRL, |
790 | DSI_CMD_DMA_CTRL_FROM_FRAME_BUFFER | |
791 | DSI_CMD_DMA_CTRL_LOW_POWER); |
792 | |
793 | data = 0; |
794 | /* Always assume dedicated TE pin */ |
795 | data |= DSI_TRIG_CTRL_TE; |
796 | data |= DSI_TRIG_CTRL_MDP_TRIGGER(val: TRIGGER_NONE); |
797 | data |= DSI_TRIG_CTRL_DMA_TRIGGER(val: TRIGGER_SW); |
798 | data |= DSI_TRIG_CTRL_STREAM(val: msm_host->channel); |
799 | if ((cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) && |
800 | (cfg_hnd->minor >= MSM_DSI_6G_VER_MINOR_V1_2)) |
801 | data |= DSI_TRIG_CTRL_BLOCK_DMA_WITHIN_FRAME; |
802 | dsi_write(msm_host, REG_DSI_TRIG_CTRL, data); |
803 | |
804 | data = DSI_CLKOUT_TIMING_CTRL_T_CLK_POST(val: phy_shared_timings->clk_post) | |
805 | DSI_CLKOUT_TIMING_CTRL_T_CLK_PRE(val: phy_shared_timings->clk_pre); |
806 | dsi_write(msm_host, REG_DSI_CLKOUT_TIMING_CTRL, data); |
807 | |
808 | if ((cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) && |
809 | (cfg_hnd->minor > MSM_DSI_6G_VER_MINOR_V1_0) && |
810 | phy_shared_timings->clk_pre_inc_by_2) |
811 | dsi_write(msm_host, REG_DSI_T_CLK_PRE_EXTEND, |
812 | DSI_T_CLK_PRE_EXTEND_INC_BY_2_BYTECLK); |
813 | |
814 | data = 0; |
815 | if (!(flags & MIPI_DSI_MODE_NO_EOT_PACKET)) |
816 | data |= DSI_EOT_PACKET_CTRL_TX_EOT_APPEND; |
817 | dsi_write(msm_host, REG_DSI_EOT_PACKET_CTRL, data); |
818 | |
819 | /* allow only ack-err-status to generate interrupt */ |
820 | dsi_write(msm_host, REG_DSI_ERR_INT_MASK0, data: 0x13ff3fe0); |
821 | |
822 | dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_ERROR, enable: 1); |
823 | |
824 | dsi_write(msm_host, REG_DSI_CLK_CTRL, DSI_CLK_CTRL_ENABLE_CLKS); |
825 | |
826 | data = DSI_CTRL_CLK_EN; |
827 | |
828 | DBG("lane number=%d" , msm_host->lanes); |
829 | data |= ((DSI_CTRL_LANE0 << msm_host->lanes) - DSI_CTRL_LANE0); |
830 | |
831 | dsi_write(msm_host, REG_DSI_LANE_SWAP_CTRL, |
832 | data: DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL(val: msm_host->dlane_swap)); |
833 | |
834 | if (!(flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)) { |
835 | lane_ctrl = dsi_read(msm_host, REG_DSI_LANE_CTRL); |
836 | |
837 | if (msm_dsi_phy_set_continuous_clock(phy, enable: true)) |
838 | lane_ctrl &= ~DSI_LANE_CTRL_HS_REQ_SEL_PHY; |
839 | |
840 | dsi_write(msm_host, REG_DSI_LANE_CTRL, |
841 | data: lane_ctrl | DSI_LANE_CTRL_CLKLN_HS_FORCE_REQUEST); |
842 | } |
843 | |
844 | data |= DSI_CTRL_ENABLE; |
845 | |
846 | dsi_write(msm_host, REG_DSI_CTRL, data); |
847 | |
848 | if (msm_host->cphy_mode) |
849 | dsi_write(msm_host, REG_DSI_CPHY_MODE_CTRL, BIT(0)); |
850 | } |
851 | |
852 | static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool is_cmd_mode, u32 hdisplay) |
853 | { |
854 | struct drm_dsc_config *dsc = msm_host->dsc; |
855 | u32 reg, reg_ctrl, reg_ctrl2; |
856 | u32 slice_per_intf, total_bytes_per_intf; |
857 | u32 pkt_per_line; |
858 | u32 eol_byte_num; |
859 | |
860 | /* first calculate dsc parameters and then program |
861 | * compress mode registers |
862 | */ |
863 | slice_per_intf = msm_dsc_get_slices_per_intf(dsc, hdisplay); |
864 | |
865 | total_bytes_per_intf = dsc->slice_chunk_size * slice_per_intf; |
866 | |
867 | eol_byte_num = total_bytes_per_intf % 3; |
868 | |
869 | /* |
870 | * Typically, pkt_per_line = slice_per_intf * slice_per_pkt. |
871 | * |
872 | * Since the current driver only supports slice_per_pkt = 1, |
873 | * pkt_per_line will be equal to slice per intf for now. |
874 | */ |
875 | pkt_per_line = slice_per_intf; |
876 | |
877 | if (is_cmd_mode) /* packet data type */ |
878 | reg = DSI_COMMAND_COMPRESSION_MODE_CTRL_STREAM0_DATATYPE(val: MIPI_DSI_DCS_LONG_WRITE); |
879 | else |
880 | reg = DSI_VIDEO_COMPRESSION_MODE_CTRL_DATATYPE(val: MIPI_DSI_COMPRESSED_PIXEL_STREAM); |
881 | |
882 | /* DSI_VIDEO_COMPRESSION_MODE & DSI_COMMAND_COMPRESSION_MODE |
883 | * registers have similar offsets, so for below common code use |
884 | * DSI_VIDEO_COMPRESSION_MODE_XXXX for setting bits |
885 | */ |
886 | reg |= DSI_VIDEO_COMPRESSION_MODE_CTRL_PKT_PER_LINE(val: pkt_per_line >> 1); |
887 | reg |= DSI_VIDEO_COMPRESSION_MODE_CTRL_EOL_BYTE_NUM(val: eol_byte_num); |
888 | reg |= DSI_VIDEO_COMPRESSION_MODE_CTRL_EN; |
889 | |
890 | if (is_cmd_mode) { |
891 | reg_ctrl = dsi_read(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL); |
892 | reg_ctrl2 = dsi_read(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2); |
893 | |
894 | reg_ctrl &= ~0xffff; |
895 | reg_ctrl |= reg; |
896 | |
897 | reg_ctrl2 &= ~DSI_COMMAND_COMPRESSION_MODE_CTRL2_STREAM0_SLICE_WIDTH__MASK; |
898 | reg_ctrl2 |= DSI_COMMAND_COMPRESSION_MODE_CTRL2_STREAM0_SLICE_WIDTH(val: dsc->slice_chunk_size); |
899 | |
900 | dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL, data: reg_ctrl); |
901 | dsi_write(msm_host, REG_DSI_COMMAND_COMPRESSION_MODE_CTRL2, data: reg_ctrl2); |
902 | } else { |
903 | dsi_write(msm_host, REG_DSI_VIDEO_COMPRESSION_MODE_CTRL, data: reg); |
904 | } |
905 | } |
906 | |
907 | static void dsi_timing_setup(struct msm_dsi_host *msm_host, bool is_bonded_dsi) |
908 | { |
909 | struct drm_display_mode *mode = msm_host->mode; |
910 | u32 hs_start = 0, vs_start = 0; /* take sync start as 0 */ |
911 | u32 h_total = mode->htotal; |
912 | u32 v_total = mode->vtotal; |
913 | u32 hs_end = mode->hsync_end - mode->hsync_start; |
914 | u32 vs_end = mode->vsync_end - mode->vsync_start; |
915 | u32 ha_start = h_total - mode->hsync_start; |
916 | u32 ha_end = ha_start + mode->hdisplay; |
917 | u32 va_start = v_total - mode->vsync_start; |
918 | u32 va_end = va_start + mode->vdisplay; |
919 | u32 hdisplay = mode->hdisplay; |
920 | u32 wc; |
921 | int ret; |
922 | bool wide_bus_enabled = msm_dsi_host_is_wide_bus_enabled(host: &msm_host->base); |
923 | |
924 | DBG("" ); |
925 | |
926 | /* |
927 | * For bonded DSI mode, the current DRM mode has |
928 | * the complete width of the panel. Since, the complete |
929 | * panel is driven by two DSI controllers, the horizontal |
930 | * timings have to be split between the two dsi controllers. |
931 | * Adjust the DSI host timing values accordingly. |
932 | */ |
933 | if (is_bonded_dsi) { |
934 | h_total /= 2; |
935 | hs_end /= 2; |
936 | ha_start /= 2; |
937 | ha_end /= 2; |
938 | hdisplay /= 2; |
939 | } |
940 | |
941 | if (msm_host->dsc) { |
942 | struct drm_dsc_config *dsc = msm_host->dsc; |
943 | u32 bytes_per_pclk; |
944 | |
945 | /* update dsc params with timing params */ |
946 | if (!dsc || !mode->hdisplay || !mode->vdisplay) { |
947 | pr_err("DSI: invalid input: pic_width: %d pic_height: %d\n" , |
948 | mode->hdisplay, mode->vdisplay); |
949 | return; |
950 | } |
951 | |
952 | dsc->pic_width = mode->hdisplay; |
953 | dsc->pic_height = mode->vdisplay; |
954 | DBG("Mode %dx%d\n" , dsc->pic_width, dsc->pic_height); |
955 | |
956 | /* we do the calculations for dsc parameters here so that |
957 | * panel can use these parameters |
958 | */ |
959 | ret = dsi_populate_dsc_params(msm_host, dsc); |
960 | if (ret) |
961 | return; |
962 | |
963 | /* |
964 | * DPU sends 3 bytes per pclk cycle to DSI. If widebus is |
965 | * enabled, bus width is extended to 6 bytes. |
966 | * |
967 | * Calculate the number of pclks needed to transmit one line of |
968 | * the compressed data. |
969 | |
970 | * The back/font porch and pulse width are kept intact. For |
971 | * VIDEO mode they represent timing parameters rather than |
972 | * actual data transfer, see the documentation for |
973 | * dsi_adjust_pclk_for_compression(). For CMD mode they are |
974 | * unused anyway. |
975 | */ |
976 | h_total -= hdisplay; |
977 | if (wide_bus_enabled && !(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO)) |
978 | bytes_per_pclk = 6; |
979 | else |
980 | bytes_per_pclk = 3; |
981 | |
982 | hdisplay = DIV_ROUND_UP(msm_dsc_get_bytes_per_line(msm_host->dsc), bytes_per_pclk); |
983 | |
984 | h_total += hdisplay; |
985 | ha_end = ha_start + hdisplay; |
986 | } |
987 | |
988 | if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) { |
989 | if (msm_host->dsc) |
990 | dsi_update_dsc_timing(msm_host, is_cmd_mode: false, hdisplay: mode->hdisplay); |
991 | |
992 | dsi_write(msm_host, REG_DSI_ACTIVE_H, |
993 | data: DSI_ACTIVE_H_START(val: ha_start) | |
994 | DSI_ACTIVE_H_END(val: ha_end)); |
995 | dsi_write(msm_host, REG_DSI_ACTIVE_V, |
996 | data: DSI_ACTIVE_V_START(val: va_start) | |
997 | DSI_ACTIVE_V_END(val: va_end)); |
998 | dsi_write(msm_host, REG_DSI_TOTAL, |
999 | data: DSI_TOTAL_H_TOTAL(val: h_total - 1) | |
1000 | DSI_TOTAL_V_TOTAL(val: v_total - 1)); |
1001 | |
1002 | dsi_write(msm_host, REG_DSI_ACTIVE_HSYNC, |
1003 | data: DSI_ACTIVE_HSYNC_START(val: hs_start) | |
1004 | DSI_ACTIVE_HSYNC_END(val: hs_end)); |
1005 | dsi_write(msm_host, REG_DSI_ACTIVE_VSYNC_HPOS, data: 0); |
1006 | dsi_write(msm_host, REG_DSI_ACTIVE_VSYNC_VPOS, |
1007 | data: DSI_ACTIVE_VSYNC_VPOS_START(val: vs_start) | |
1008 | DSI_ACTIVE_VSYNC_VPOS_END(val: vs_end)); |
1009 | } else { /* command mode */ |
1010 | if (msm_host->dsc) |
1011 | dsi_update_dsc_timing(msm_host, is_cmd_mode: true, hdisplay: mode->hdisplay); |
1012 | |
1013 | /* image data and 1 byte write_memory_start cmd */ |
1014 | if (!msm_host->dsc) |
1015 | wc = hdisplay * mipi_dsi_pixel_format_to_bpp(fmt: msm_host->format) / 8 + 1; |
1016 | else |
1017 | /* |
1018 | * When DSC is enabled, WC = slice_chunk_size * slice_per_pkt + 1. |
1019 | * Currently, the driver only supports default value of slice_per_pkt = 1 |
1020 | * |
1021 | * TODO: Expand mipi_dsi_device struct to hold slice_per_pkt info |
1022 | * and adjust DSC math to account for slice_per_pkt. |
1023 | */ |
1024 | wc = msm_host->dsc->slice_chunk_size + 1; |
1025 | |
1026 | dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_CTRL, |
1027 | data: DSI_CMD_MDP_STREAM0_CTRL_WORD_COUNT(val: wc) | |
1028 | DSI_CMD_MDP_STREAM0_CTRL_VIRTUAL_CHANNEL( |
1029 | val: msm_host->channel) | |
1030 | DSI_CMD_MDP_STREAM0_CTRL_DATA_TYPE( |
1031 | val: MIPI_DSI_DCS_LONG_WRITE)); |
1032 | |
1033 | dsi_write(msm_host, REG_DSI_CMD_MDP_STREAM0_TOTAL, |
1034 | data: DSI_CMD_MDP_STREAM0_TOTAL_H_TOTAL(val: hdisplay) | |
1035 | DSI_CMD_MDP_STREAM0_TOTAL_V_TOTAL(val: mode->vdisplay)); |
1036 | } |
1037 | } |
1038 | |
1039 | static void dsi_sw_reset(struct msm_dsi_host *msm_host) |
1040 | { |
1041 | u32 ctrl; |
1042 | |
1043 | ctrl = dsi_read(msm_host, REG_DSI_CTRL); |
1044 | |
1045 | if (ctrl & DSI_CTRL_ENABLE) { |
1046 | dsi_write(msm_host, REG_DSI_CTRL, data: ctrl & ~DSI_CTRL_ENABLE); |
1047 | /* |
1048 | * dsi controller need to be disabled before |
1049 | * clocks turned on |
1050 | */ |
1051 | wmb(); |
1052 | } |
1053 | |
1054 | dsi_write(msm_host, REG_DSI_CLK_CTRL, DSI_CLK_CTRL_ENABLE_CLKS); |
1055 | wmb(); /* clocks need to be enabled before reset */ |
1056 | |
1057 | /* dsi controller can only be reset while clocks are running */ |
1058 | dsi_write(msm_host, REG_DSI_RESET, data: 1); |
1059 | msleep(DSI_RESET_TOGGLE_DELAY_MS); /* make sure reset happen */ |
1060 | dsi_write(msm_host, REG_DSI_RESET, data: 0); |
1061 | wmb(); /* controller out of reset */ |
1062 | |
1063 | if (ctrl & DSI_CTRL_ENABLE) { |
1064 | dsi_write(msm_host, REG_DSI_CTRL, data: ctrl); |
1065 | wmb(); /* make sure dsi controller enabled again */ |
1066 | } |
1067 | } |
1068 | |
1069 | static void dsi_op_mode_config(struct msm_dsi_host *msm_host, |
1070 | bool video_mode, bool enable) |
1071 | { |
1072 | u32 dsi_ctrl; |
1073 | |
1074 | dsi_ctrl = dsi_read(msm_host, REG_DSI_CTRL); |
1075 | |
1076 | if (!enable) { |
1077 | dsi_ctrl &= ~(DSI_CTRL_ENABLE | DSI_CTRL_VID_MODE_EN | |
1078 | DSI_CTRL_CMD_MODE_EN); |
1079 | dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_MDP_DONE | |
1080 | DSI_IRQ_MASK_VIDEO_DONE, enable: 0); |
1081 | } else { |
1082 | if (video_mode) { |
1083 | dsi_ctrl |= DSI_CTRL_VID_MODE_EN; |
1084 | } else { /* command mode */ |
1085 | dsi_ctrl |= DSI_CTRL_CMD_MODE_EN; |
1086 | dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_MDP_DONE, enable: 1); |
1087 | } |
1088 | dsi_ctrl |= DSI_CTRL_ENABLE; |
1089 | } |
1090 | |
1091 | dsi_write(msm_host, REG_DSI_CTRL, data: dsi_ctrl); |
1092 | } |
1093 | |
1094 | static void dsi_set_tx_power_mode(int mode, struct msm_dsi_host *msm_host) |
1095 | { |
1096 | u32 data; |
1097 | |
1098 | data = dsi_read(msm_host, REG_DSI_CMD_DMA_CTRL); |
1099 | |
1100 | if (mode == 0) |
1101 | data &= ~DSI_CMD_DMA_CTRL_LOW_POWER; |
1102 | else |
1103 | data |= DSI_CMD_DMA_CTRL_LOW_POWER; |
1104 | |
1105 | dsi_write(msm_host, REG_DSI_CMD_DMA_CTRL, data); |
1106 | } |
1107 | |
1108 | static void dsi_wait4video_done(struct msm_dsi_host *msm_host) |
1109 | { |
1110 | u32 ret = 0; |
1111 | struct device *dev = &msm_host->pdev->dev; |
1112 | |
1113 | dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_VIDEO_DONE, enable: 1); |
1114 | |
1115 | reinit_completion(x: &msm_host->video_comp); |
1116 | |
1117 | ret = wait_for_completion_timeout(x: &msm_host->video_comp, |
1118 | timeout: msecs_to_jiffies(m: 70)); |
1119 | |
1120 | if (ret == 0) |
1121 | DRM_DEV_ERROR(dev, "wait for video done timed out\n" ); |
1122 | |
1123 | dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_VIDEO_DONE, enable: 0); |
1124 | } |
1125 | |
1126 | static void dsi_wait4video_eng_busy(struct msm_dsi_host *msm_host) |
1127 | { |
1128 | u32 data; |
1129 | |
1130 | if (!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO)) |
1131 | return; |
1132 | |
1133 | data = dsi_read(msm_host, REG_DSI_STATUS0); |
1134 | |
1135 | /* if video mode engine is not busy, its because |
1136 | * either timing engine was not turned on or the |
1137 | * DSI controller has finished transmitting the video |
1138 | * data already, so no need to wait in those cases |
1139 | */ |
1140 | if (!(data & DSI_STATUS0_VIDEO_MODE_ENGINE_BUSY)) |
1141 | return; |
1142 | |
1143 | if (msm_host->power_on && msm_host->enabled) { |
1144 | dsi_wait4video_done(msm_host); |
1145 | /* delay 4 ms to skip BLLP */ |
1146 | usleep_range(min: 2000, max: 4000); |
1147 | } |
1148 | } |
1149 | |
1150 | int dsi_tx_buf_alloc_6g(struct msm_dsi_host *msm_host, int size) |
1151 | { |
1152 | struct drm_device *dev = msm_host->dev; |
1153 | struct msm_drm_private *priv = dev->dev_private; |
1154 | uint64_t iova; |
1155 | u8 *data; |
1156 | |
1157 | msm_host->aspace = msm_gem_address_space_get(priv->kms->aspace); |
1158 | |
1159 | data = msm_gem_kernel_new(dev, size, MSM_BO_WC, |
1160 | msm_host->aspace, |
1161 | &msm_host->tx_gem_obj, &iova); |
1162 | |
1163 | if (IS_ERR(ptr: data)) { |
1164 | msm_host->tx_gem_obj = NULL; |
1165 | return PTR_ERR(ptr: data); |
1166 | } |
1167 | |
1168 | msm_gem_object_set_name(msm_host->tx_gem_obj, "tx_gem" ); |
1169 | |
1170 | msm_host->tx_size = msm_host->tx_gem_obj->size; |
1171 | |
1172 | return 0; |
1173 | } |
1174 | |
1175 | int dsi_tx_buf_alloc_v2(struct msm_dsi_host *msm_host, int size) |
1176 | { |
1177 | struct drm_device *dev = msm_host->dev; |
1178 | |
1179 | msm_host->tx_buf = dma_alloc_coherent(dev: dev->dev, size, |
1180 | dma_handle: &msm_host->tx_buf_paddr, GFP_KERNEL); |
1181 | if (!msm_host->tx_buf) |
1182 | return -ENOMEM; |
1183 | |
1184 | msm_host->tx_size = size; |
1185 | |
1186 | return 0; |
1187 | } |
1188 | |
1189 | void msm_dsi_tx_buf_free(struct mipi_dsi_host *host) |
1190 | { |
1191 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
1192 | struct drm_device *dev = msm_host->dev; |
1193 | |
1194 | /* |
1195 | * This is possible if we're tearing down before we've had a chance to |
1196 | * fully initialize. A very real possibility if our probe is deferred, |
1197 | * in which case we'll hit msm_dsi_host_destroy() without having run |
1198 | * through the dsi_tx_buf_alloc(). |
1199 | */ |
1200 | if (!dev) |
1201 | return; |
1202 | |
1203 | if (msm_host->tx_gem_obj) { |
1204 | msm_gem_kernel_put(msm_host->tx_gem_obj, msm_host->aspace); |
1205 | msm_gem_address_space_put(msm_host->aspace); |
1206 | msm_host->tx_gem_obj = NULL; |
1207 | msm_host->aspace = NULL; |
1208 | } |
1209 | |
1210 | if (msm_host->tx_buf) |
1211 | dma_free_coherent(dev: dev->dev, size: msm_host->tx_size, cpu_addr: msm_host->tx_buf, |
1212 | dma_handle: msm_host->tx_buf_paddr); |
1213 | } |
1214 | |
1215 | void *dsi_tx_buf_get_6g(struct msm_dsi_host *msm_host) |
1216 | { |
1217 | return msm_gem_get_vaddr(msm_host->tx_gem_obj); |
1218 | } |
1219 | |
1220 | void *dsi_tx_buf_get_v2(struct msm_dsi_host *msm_host) |
1221 | { |
1222 | return msm_host->tx_buf; |
1223 | } |
1224 | |
1225 | void dsi_tx_buf_put_6g(struct msm_dsi_host *msm_host) |
1226 | { |
1227 | msm_gem_put_vaddr(msm_host->tx_gem_obj); |
1228 | } |
1229 | |
1230 | /* |
1231 | * prepare cmd buffer to be txed |
1232 | */ |
1233 | static int dsi_cmd_dma_add(struct msm_dsi_host *msm_host, |
1234 | const struct mipi_dsi_msg *msg) |
1235 | { |
1236 | const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; |
1237 | struct mipi_dsi_packet packet; |
1238 | int len; |
1239 | int ret; |
1240 | u8 *data; |
1241 | |
1242 | ret = mipi_dsi_create_packet(packet: &packet, msg); |
1243 | if (ret) { |
1244 | pr_err("%s: create packet failed, %d\n" , __func__, ret); |
1245 | return ret; |
1246 | } |
1247 | len = (packet.size + 3) & (~0x3); |
1248 | |
1249 | if (len > msm_host->tx_size) { |
1250 | pr_err("%s: packet size is too big\n" , __func__); |
1251 | return -EINVAL; |
1252 | } |
1253 | |
1254 | data = cfg_hnd->ops->tx_buf_get(msm_host); |
1255 | if (IS_ERR(ptr: data)) { |
1256 | ret = PTR_ERR(ptr: data); |
1257 | pr_err("%s: get vaddr failed, %d\n" , __func__, ret); |
1258 | return ret; |
1259 | } |
1260 | |
1261 | /* MSM specific command format in memory */ |
1262 | data[0] = packet.header[1]; |
1263 | data[1] = packet.header[2]; |
1264 | data[2] = packet.header[0]; |
1265 | data[3] = BIT(7); /* Last packet */ |
1266 | if (mipi_dsi_packet_format_is_long(type: msg->type)) |
1267 | data[3] |= BIT(6); |
1268 | if (msg->rx_buf && msg->rx_len) |
1269 | data[3] |= BIT(5); |
1270 | |
1271 | /* Long packet */ |
1272 | if (packet.payload && packet.payload_length) |
1273 | memcpy(data + 4, packet.payload, packet.payload_length); |
1274 | |
1275 | /* Append 0xff to the end */ |
1276 | if (packet.size < len) |
1277 | memset(data + packet.size, 0xff, len - packet.size); |
1278 | |
1279 | if (cfg_hnd->ops->tx_buf_put) |
1280 | cfg_hnd->ops->tx_buf_put(msm_host); |
1281 | |
1282 | return len; |
1283 | } |
1284 | |
1285 | /* |
1286 | * dsi_short_read1_resp: 1 parameter |
1287 | */ |
1288 | static int dsi_short_read1_resp(u8 *buf, const struct mipi_dsi_msg *msg) |
1289 | { |
1290 | u8 *data = msg->rx_buf; |
1291 | if (data && (msg->rx_len >= 1)) { |
1292 | *data = buf[1]; /* strip out dcs type */ |
1293 | return 1; |
1294 | } else { |
1295 | pr_err("%s: read data does not match with rx_buf len %zu\n" , |
1296 | __func__, msg->rx_len); |
1297 | return -EINVAL; |
1298 | } |
1299 | } |
1300 | |
1301 | /* |
1302 | * dsi_short_read2_resp: 2 parameter |
1303 | */ |
1304 | static int dsi_short_read2_resp(u8 *buf, const struct mipi_dsi_msg *msg) |
1305 | { |
1306 | u8 *data = msg->rx_buf; |
1307 | if (data && (msg->rx_len >= 2)) { |
1308 | data[0] = buf[1]; /* strip out dcs type */ |
1309 | data[1] = buf[2]; |
1310 | return 2; |
1311 | } else { |
1312 | pr_err("%s: read data does not match with rx_buf len %zu\n" , |
1313 | __func__, msg->rx_len); |
1314 | return -EINVAL; |
1315 | } |
1316 | } |
1317 | |
1318 | static int dsi_long_read_resp(u8 *buf, const struct mipi_dsi_msg *msg) |
1319 | { |
1320 | /* strip out 4 byte dcs header */ |
1321 | if (msg->rx_buf && msg->rx_len) |
1322 | memcpy(msg->rx_buf, buf + 4, msg->rx_len); |
1323 | |
1324 | return msg->rx_len; |
1325 | } |
1326 | |
1327 | int dsi_dma_base_get_6g(struct msm_dsi_host *msm_host, uint64_t *dma_base) |
1328 | { |
1329 | struct drm_device *dev = msm_host->dev; |
1330 | struct msm_drm_private *priv = dev->dev_private; |
1331 | |
1332 | if (!dma_base) |
1333 | return -EINVAL; |
1334 | |
1335 | return msm_gem_get_and_pin_iova(msm_host->tx_gem_obj, |
1336 | priv->kms->aspace, dma_base); |
1337 | } |
1338 | |
1339 | int dsi_dma_base_get_v2(struct msm_dsi_host *msm_host, uint64_t *dma_base) |
1340 | { |
1341 | if (!dma_base) |
1342 | return -EINVAL; |
1343 | |
1344 | *dma_base = msm_host->tx_buf_paddr; |
1345 | return 0; |
1346 | } |
1347 | |
1348 | static int dsi_cmd_dma_tx(struct msm_dsi_host *msm_host, int len) |
1349 | { |
1350 | const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; |
1351 | int ret; |
1352 | uint64_t dma_base; |
1353 | bool triggered; |
1354 | |
1355 | ret = cfg_hnd->ops->dma_base_get(msm_host, &dma_base); |
1356 | if (ret) { |
1357 | pr_err("%s: failed to get iova: %d\n" , __func__, ret); |
1358 | return ret; |
1359 | } |
1360 | |
1361 | reinit_completion(x: &msm_host->dma_comp); |
1362 | |
1363 | dsi_wait4video_eng_busy(msm_host); |
1364 | |
1365 | triggered = msm_dsi_manager_cmd_xfer_trigger( |
1366 | id: msm_host->id, dma_base, len); |
1367 | if (triggered) { |
1368 | ret = wait_for_completion_timeout(x: &msm_host->dma_comp, |
1369 | timeout: msecs_to_jiffies(m: 200)); |
1370 | DBG("ret=%d" , ret); |
1371 | if (ret == 0) |
1372 | ret = -ETIMEDOUT; |
1373 | else |
1374 | ret = len; |
1375 | } else |
1376 | ret = len; |
1377 | |
1378 | return ret; |
1379 | } |
1380 | |
1381 | static int dsi_cmd_dma_rx(struct msm_dsi_host *msm_host, |
1382 | u8 *buf, int rx_byte, int pkt_size) |
1383 | { |
1384 | u32 *temp, data; |
1385 | int i, j = 0, cnt; |
1386 | u32 read_cnt; |
1387 | u8 reg[16]; |
1388 | int repeated_bytes = 0; |
1389 | int buf_offset = buf - msm_host->rx_buf; |
1390 | |
1391 | temp = (u32 *)reg; |
1392 | cnt = (rx_byte + 3) >> 2; |
1393 | if (cnt > 4) |
1394 | cnt = 4; /* 4 x 32 bits registers only */ |
1395 | |
1396 | if (rx_byte == 4) |
1397 | read_cnt = 4; |
1398 | else |
1399 | read_cnt = pkt_size + 6; |
1400 | |
1401 | /* |
1402 | * In case of multiple reads from the panel, after the first read, there |
1403 | * is possibility that there are some bytes in the payload repeating in |
1404 | * the RDBK_DATA registers. Since we read all the parameters from the |
1405 | * panel right from the first byte for every pass. We need to skip the |
1406 | * repeating bytes and then append the new parameters to the rx buffer. |
1407 | */ |
1408 | if (read_cnt > 16) { |
1409 | int bytes_shifted; |
1410 | /* Any data more than 16 bytes will be shifted out. |
1411 | * The temp read buffer should already contain these bytes. |
1412 | * The remaining bytes in read buffer are the repeated bytes. |
1413 | */ |
1414 | bytes_shifted = read_cnt - 16; |
1415 | repeated_bytes = buf_offset - bytes_shifted; |
1416 | } |
1417 | |
1418 | for (i = cnt - 1; i >= 0; i--) { |
1419 | data = dsi_read(msm_host, reg: REG_DSI_RDBK_DATA(i0: i)); |
1420 | *temp++ = ntohl(data); /* to host byte order */ |
1421 | DBG("data = 0x%x and ntohl(data) = 0x%x" , data, ntohl(data)); |
1422 | } |
1423 | |
1424 | for (i = repeated_bytes; i < 16; i++) |
1425 | buf[j++] = reg[i]; |
1426 | |
1427 | return j; |
1428 | } |
1429 | |
1430 | static int dsi_cmds2buf_tx(struct msm_dsi_host *msm_host, |
1431 | const struct mipi_dsi_msg *msg) |
1432 | { |
1433 | int len, ret; |
1434 | int bllp_len = msm_host->mode->hdisplay * |
1435 | mipi_dsi_pixel_format_to_bpp(fmt: msm_host->format) / 8; |
1436 | |
1437 | len = dsi_cmd_dma_add(msm_host, msg); |
1438 | if (len < 0) { |
1439 | pr_err("%s: failed to add cmd type = 0x%x\n" , |
1440 | __func__, msg->type); |
1441 | return len; |
1442 | } |
1443 | |
1444 | /* for video mode, do not send cmds more than |
1445 | * one pixel line, since it only transmit it |
1446 | * during BLLP. |
1447 | */ |
1448 | /* TODO: if the command is sent in LP mode, the bit rate is only |
1449 | * half of esc clk rate. In this case, if the video is already |
1450 | * actively streaming, we need to check more carefully if the |
1451 | * command can be fit into one BLLP. |
1452 | */ |
1453 | if ((msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) && (len > bllp_len)) { |
1454 | pr_err("%s: cmd cannot fit into BLLP period, len=%d\n" , |
1455 | __func__, len); |
1456 | return -EINVAL; |
1457 | } |
1458 | |
1459 | ret = dsi_cmd_dma_tx(msm_host, len); |
1460 | if (ret < 0) { |
1461 | pr_err("%s: cmd dma tx failed, type=0x%x, data0=0x%x, len=%d, ret=%d\n" , |
1462 | __func__, msg->type, (*(u8 *)(msg->tx_buf)), len, ret); |
1463 | return ret; |
1464 | } else if (ret < len) { |
1465 | pr_err("%s: cmd dma tx failed, type=0x%x, data0=0x%x, ret=%d len=%d\n" , |
1466 | __func__, msg->type, (*(u8 *)(msg->tx_buf)), ret, len); |
1467 | return -EIO; |
1468 | } |
1469 | |
1470 | return len; |
1471 | } |
1472 | |
1473 | static void dsi_err_worker(struct work_struct *work) |
1474 | { |
1475 | struct msm_dsi_host *msm_host = |
1476 | container_of(work, struct msm_dsi_host, err_work); |
1477 | u32 status = msm_host->err_work_state; |
1478 | |
1479 | pr_err_ratelimited("%s: status=%x\n" , __func__, status); |
1480 | if (status & DSI_ERR_STATE_MDP_FIFO_UNDERFLOW) |
1481 | dsi_sw_reset(msm_host); |
1482 | |
1483 | /* It is safe to clear here because error irq is disabled. */ |
1484 | msm_host->err_work_state = 0; |
1485 | |
1486 | /* enable dsi error interrupt */ |
1487 | dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_ERROR, enable: 1); |
1488 | } |
1489 | |
1490 | static void dsi_ack_err_status(struct msm_dsi_host *msm_host) |
1491 | { |
1492 | u32 status; |
1493 | |
1494 | status = dsi_read(msm_host, REG_DSI_ACK_ERR_STATUS); |
1495 | |
1496 | if (status) { |
1497 | dsi_write(msm_host, REG_DSI_ACK_ERR_STATUS, data: status); |
1498 | /* Writing of an extra 0 needed to clear error bits */ |
1499 | dsi_write(msm_host, REG_DSI_ACK_ERR_STATUS, data: 0); |
1500 | msm_host->err_work_state |= DSI_ERR_STATE_ACK; |
1501 | } |
1502 | } |
1503 | |
1504 | static void dsi_timeout_status(struct msm_dsi_host *msm_host) |
1505 | { |
1506 | u32 status; |
1507 | |
1508 | status = dsi_read(msm_host, REG_DSI_TIMEOUT_STATUS); |
1509 | |
1510 | if (status) { |
1511 | dsi_write(msm_host, REG_DSI_TIMEOUT_STATUS, data: status); |
1512 | msm_host->err_work_state |= DSI_ERR_STATE_TIMEOUT; |
1513 | } |
1514 | } |
1515 | |
1516 | static void dsi_dln0_phy_err(struct msm_dsi_host *msm_host) |
1517 | { |
1518 | u32 status; |
1519 | |
1520 | status = dsi_read(msm_host, REG_DSI_DLN0_PHY_ERR); |
1521 | |
1522 | if (status & (DSI_DLN0_PHY_ERR_DLN0_ERR_ESC | |
1523 | DSI_DLN0_PHY_ERR_DLN0_ERR_SYNC_ESC | |
1524 | DSI_DLN0_PHY_ERR_DLN0_ERR_CONTROL | |
1525 | DSI_DLN0_PHY_ERR_DLN0_ERR_CONTENTION_LP0 | |
1526 | DSI_DLN0_PHY_ERR_DLN0_ERR_CONTENTION_LP1)) { |
1527 | dsi_write(msm_host, REG_DSI_DLN0_PHY_ERR, data: status); |
1528 | msm_host->err_work_state |= DSI_ERR_STATE_DLN0_PHY; |
1529 | } |
1530 | } |
1531 | |
1532 | static void dsi_fifo_status(struct msm_dsi_host *msm_host) |
1533 | { |
1534 | u32 status; |
1535 | |
1536 | status = dsi_read(msm_host, REG_DSI_FIFO_STATUS); |
1537 | |
1538 | /* fifo underflow, overflow */ |
1539 | if (status) { |
1540 | dsi_write(msm_host, REG_DSI_FIFO_STATUS, data: status); |
1541 | msm_host->err_work_state |= DSI_ERR_STATE_FIFO; |
1542 | if (status & DSI_FIFO_STATUS_CMD_MDP_FIFO_UNDERFLOW) |
1543 | msm_host->err_work_state |= |
1544 | DSI_ERR_STATE_MDP_FIFO_UNDERFLOW; |
1545 | } |
1546 | } |
1547 | |
1548 | static void dsi_status(struct msm_dsi_host *msm_host) |
1549 | { |
1550 | u32 status; |
1551 | |
1552 | status = dsi_read(msm_host, REG_DSI_STATUS0); |
1553 | |
1554 | if (status & DSI_STATUS0_INTERLEAVE_OP_CONTENTION) { |
1555 | dsi_write(msm_host, REG_DSI_STATUS0, data: status); |
1556 | msm_host->err_work_state |= |
1557 | DSI_ERR_STATE_INTERLEAVE_OP_CONTENTION; |
1558 | } |
1559 | } |
1560 | |
1561 | static void dsi_clk_status(struct msm_dsi_host *msm_host) |
1562 | { |
1563 | u32 status; |
1564 | |
1565 | status = dsi_read(msm_host, REG_DSI_CLK_STATUS); |
1566 | |
1567 | if (status & DSI_CLK_STATUS_PLL_UNLOCKED) { |
1568 | dsi_write(msm_host, REG_DSI_CLK_STATUS, data: status); |
1569 | msm_host->err_work_state |= DSI_ERR_STATE_PLL_UNLOCKED; |
1570 | } |
1571 | } |
1572 | |
1573 | static void dsi_error(struct msm_dsi_host *msm_host) |
1574 | { |
1575 | /* disable dsi error interrupt */ |
1576 | dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_ERROR, enable: 0); |
1577 | |
1578 | dsi_clk_status(msm_host); |
1579 | dsi_fifo_status(msm_host); |
1580 | dsi_ack_err_status(msm_host); |
1581 | dsi_timeout_status(msm_host); |
1582 | dsi_status(msm_host); |
1583 | dsi_dln0_phy_err(msm_host); |
1584 | |
1585 | queue_work(wq: msm_host->workqueue, work: &msm_host->err_work); |
1586 | } |
1587 | |
1588 | static irqreturn_t dsi_host_irq(int irq, void *ptr) |
1589 | { |
1590 | struct msm_dsi_host *msm_host = ptr; |
1591 | u32 isr; |
1592 | unsigned long flags; |
1593 | |
1594 | if (!msm_host->ctrl_base) |
1595 | return IRQ_HANDLED; |
1596 | |
1597 | spin_lock_irqsave(&msm_host->intr_lock, flags); |
1598 | isr = dsi_read(msm_host, REG_DSI_INTR_CTRL); |
1599 | dsi_write(msm_host, REG_DSI_INTR_CTRL, data: isr); |
1600 | spin_unlock_irqrestore(lock: &msm_host->intr_lock, flags); |
1601 | |
1602 | DBG("isr=0x%x, id=%d" , isr, msm_host->id); |
1603 | |
1604 | if (isr & DSI_IRQ_ERROR) |
1605 | dsi_error(msm_host); |
1606 | |
1607 | if (isr & DSI_IRQ_VIDEO_DONE) |
1608 | complete(&msm_host->video_comp); |
1609 | |
1610 | if (isr & DSI_IRQ_CMD_DMA_DONE) |
1611 | complete(&msm_host->dma_comp); |
1612 | |
1613 | return IRQ_HANDLED; |
1614 | } |
1615 | |
1616 | static int dsi_host_init_panel_gpios(struct msm_dsi_host *msm_host, |
1617 | struct device *panel_device) |
1618 | { |
1619 | msm_host->disp_en_gpio = devm_gpiod_get_optional(dev: panel_device, |
1620 | con_id: "disp-enable" , |
1621 | flags: GPIOD_OUT_LOW); |
1622 | if (IS_ERR(ptr: msm_host->disp_en_gpio)) { |
1623 | DBG("cannot get disp-enable-gpios %ld" , |
1624 | PTR_ERR(ptr: msm_host->disp_en_gpio)); |
1625 | return PTR_ERR(ptr: msm_host->disp_en_gpio); |
1626 | } |
1627 | |
1628 | msm_host->te_gpio = devm_gpiod_get_optional(dev: panel_device, con_id: "disp-te" , |
1629 | flags: GPIOD_IN); |
1630 | if (IS_ERR(ptr: msm_host->te_gpio)) { |
1631 | DBG("cannot get disp-te-gpios %ld" , PTR_ERR(ptr: msm_host->te_gpio)); |
1632 | return PTR_ERR(ptr: msm_host->te_gpio); |
1633 | } |
1634 | |
1635 | return 0; |
1636 | } |
1637 | |
1638 | static int dsi_host_attach(struct mipi_dsi_host *host, |
1639 | struct mipi_dsi_device *dsi) |
1640 | { |
1641 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
1642 | int ret; |
1643 | |
1644 | if (dsi->lanes > msm_host->num_data_lanes) |
1645 | return -EINVAL; |
1646 | |
1647 | msm_host->channel = dsi->channel; |
1648 | msm_host->lanes = dsi->lanes; |
1649 | msm_host->format = dsi->format; |
1650 | msm_host->mode_flags = dsi->mode_flags; |
1651 | if (dsi->dsc) |
1652 | msm_host->dsc = dsi->dsc; |
1653 | |
1654 | /* Some gpios defined in panel DT need to be controlled by host */ |
1655 | ret = dsi_host_init_panel_gpios(msm_host, panel_device: &dsi->dev); |
1656 | if (ret) |
1657 | return ret; |
1658 | |
1659 | ret = dsi_dev_attach(msm_host->pdev); |
1660 | if (ret) |
1661 | return ret; |
1662 | |
1663 | DBG("id=%d" , msm_host->id); |
1664 | |
1665 | return 0; |
1666 | } |
1667 | |
1668 | static int dsi_host_detach(struct mipi_dsi_host *host, |
1669 | struct mipi_dsi_device *dsi) |
1670 | { |
1671 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
1672 | |
1673 | dsi_dev_detach(msm_host->pdev); |
1674 | |
1675 | DBG("id=%d" , msm_host->id); |
1676 | |
1677 | return 0; |
1678 | } |
1679 | |
1680 | static ssize_t dsi_host_transfer(struct mipi_dsi_host *host, |
1681 | const struct mipi_dsi_msg *msg) |
1682 | { |
1683 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
1684 | int ret; |
1685 | |
1686 | if (!msg || !msm_host->power_on) |
1687 | return -EINVAL; |
1688 | |
1689 | mutex_lock(&msm_host->cmd_mutex); |
1690 | ret = msm_dsi_manager_cmd_xfer(id: msm_host->id, msg); |
1691 | mutex_unlock(lock: &msm_host->cmd_mutex); |
1692 | |
1693 | return ret; |
1694 | } |
1695 | |
1696 | static const struct mipi_dsi_host_ops dsi_host_ops = { |
1697 | .attach = dsi_host_attach, |
1698 | .detach = dsi_host_detach, |
1699 | .transfer = dsi_host_transfer, |
1700 | }; |
1701 | |
1702 | /* |
1703 | * List of supported physical to logical lane mappings. |
1704 | * For example, the 2nd entry represents the following mapping: |
1705 | * |
1706 | * "3012": Logic 3->Phys 0; Logic 0->Phys 1; Logic 1->Phys 2; Logic 2->Phys 3; |
1707 | */ |
1708 | static const int supported_data_lane_swaps[][4] = { |
1709 | { 0, 1, 2, 3 }, |
1710 | { 3, 0, 1, 2 }, |
1711 | { 2, 3, 0, 1 }, |
1712 | { 1, 2, 3, 0 }, |
1713 | { 0, 3, 2, 1 }, |
1714 | { 1, 0, 3, 2 }, |
1715 | { 2, 1, 0, 3 }, |
1716 | { 3, 2, 1, 0 }, |
1717 | }; |
1718 | |
1719 | static int dsi_host_parse_lane_data(struct msm_dsi_host *msm_host, |
1720 | struct device_node *ep) |
1721 | { |
1722 | struct device *dev = &msm_host->pdev->dev; |
1723 | struct property *prop; |
1724 | u32 lane_map[4]; |
1725 | int ret, i, len, num_lanes; |
1726 | |
1727 | prop = of_find_property(np: ep, name: "data-lanes" , lenp: &len); |
1728 | if (!prop) { |
1729 | DRM_DEV_DEBUG(dev, |
1730 | "failed to find data lane mapping, using default\n" ); |
1731 | /* Set the number of date lanes to 4 by default. */ |
1732 | msm_host->num_data_lanes = 4; |
1733 | return 0; |
1734 | } |
1735 | |
1736 | num_lanes = drm_of_get_data_lanes_count(endpoint: ep, min: 1, max: 4); |
1737 | if (num_lanes < 0) { |
1738 | DRM_DEV_ERROR(dev, "bad number of data lanes\n" ); |
1739 | return num_lanes; |
1740 | } |
1741 | |
1742 | msm_host->num_data_lanes = num_lanes; |
1743 | |
1744 | ret = of_property_read_u32_array(np: ep, propname: "data-lanes" , out_values: lane_map, |
1745 | sz: num_lanes); |
1746 | if (ret) { |
1747 | DRM_DEV_ERROR(dev, "failed to read lane data\n" ); |
1748 | return ret; |
1749 | } |
1750 | |
1751 | /* |
1752 | * compare DT specified physical-logical lane mappings with the ones |
1753 | * supported by hardware |
1754 | */ |
1755 | for (i = 0; i < ARRAY_SIZE(supported_data_lane_swaps); i++) { |
1756 | const int *swap = supported_data_lane_swaps[i]; |
1757 | int j; |
1758 | |
1759 | /* |
1760 | * the data-lanes array we get from DT has a logical->physical |
1761 | * mapping. The "data lane swap" register field represents |
1762 | * supported configurations in a physical->logical mapping. |
1763 | * Translate the DT mapping to what we understand and find a |
1764 | * configuration that works. |
1765 | */ |
1766 | for (j = 0; j < num_lanes; j++) { |
1767 | if (lane_map[j] < 0 || lane_map[j] > 3) |
1768 | DRM_DEV_ERROR(dev, "bad physical lane entry %u\n" , |
1769 | lane_map[j]); |
1770 | |
1771 | if (swap[lane_map[j]] != j) |
1772 | break; |
1773 | } |
1774 | |
1775 | if (j == num_lanes) { |
1776 | msm_host->dlane_swap = i; |
1777 | return 0; |
1778 | } |
1779 | } |
1780 | |
1781 | return -EINVAL; |
1782 | } |
1783 | |
1784 | static int dsi_populate_dsc_params(struct msm_dsi_host *msm_host, struct drm_dsc_config *dsc) |
1785 | { |
1786 | int ret; |
1787 | |
1788 | if (dsc->bits_per_pixel & 0xf) { |
1789 | DRM_DEV_ERROR(&msm_host->pdev->dev, "DSI does not support fractional bits_per_pixel\n" ); |
1790 | return -EINVAL; |
1791 | } |
1792 | |
1793 | if (dsc->bits_per_component != 8) { |
1794 | DRM_DEV_ERROR(&msm_host->pdev->dev, "DSI does not support bits_per_component != 8 yet\n" ); |
1795 | return -EOPNOTSUPP; |
1796 | } |
1797 | |
1798 | dsc->simple_422 = 0; |
1799 | dsc->convert_rgb = 1; |
1800 | dsc->vbr_enable = 0; |
1801 | |
1802 | drm_dsc_set_const_params(vdsc_cfg: dsc); |
1803 | drm_dsc_set_rc_buf_thresh(vdsc_cfg: dsc); |
1804 | |
1805 | /* handle only bpp = bpc = 8, pre-SCR panels */ |
1806 | ret = drm_dsc_setup_rc_params(vdsc_cfg: dsc, type: DRM_DSC_1_1_PRE_SCR); |
1807 | if (ret) { |
1808 | DRM_DEV_ERROR(&msm_host->pdev->dev, "could not find DSC RC parameters\n" ); |
1809 | return ret; |
1810 | } |
1811 | |
1812 | dsc->initial_scale_value = drm_dsc_initial_scale_value(dsc); |
1813 | dsc->line_buf_depth = dsc->bits_per_component + 1; |
1814 | |
1815 | return drm_dsc_compute_rc_parameters(vdsc_cfg: dsc); |
1816 | } |
1817 | |
1818 | static int dsi_host_parse_dt(struct msm_dsi_host *msm_host) |
1819 | { |
1820 | struct device *dev = &msm_host->pdev->dev; |
1821 | struct device_node *np = dev->of_node; |
1822 | struct device_node *endpoint; |
1823 | int ret = 0; |
1824 | |
1825 | /* |
1826 | * Get the endpoint of the output port of the DSI host. In our case, |
1827 | * this is mapped to port number with reg = 1. Don't return an error if |
1828 | * the remote endpoint isn't defined. It's possible that there is |
1829 | * nothing connected to the dsi output. |
1830 | */ |
1831 | endpoint = of_graph_get_endpoint_by_regs(parent: np, port_reg: 1, reg: -1); |
1832 | if (!endpoint) { |
1833 | DRM_DEV_DEBUG(dev, "%s: no endpoint\n" , __func__); |
1834 | return 0; |
1835 | } |
1836 | |
1837 | ret = dsi_host_parse_lane_data(msm_host, ep: endpoint); |
1838 | if (ret) { |
1839 | DRM_DEV_ERROR(dev, "%s: invalid lane configuration %d\n" , |
1840 | __func__, ret); |
1841 | ret = -EINVAL; |
1842 | goto err; |
1843 | } |
1844 | |
1845 | if (of_property_read_bool(np, propname: "syscon-sfpb" )) { |
1846 | msm_host->sfpb = syscon_regmap_lookup_by_phandle(np, |
1847 | property: "syscon-sfpb" ); |
1848 | if (IS_ERR(ptr: msm_host->sfpb)) { |
1849 | DRM_DEV_ERROR(dev, "%s: failed to get sfpb regmap\n" , |
1850 | __func__); |
1851 | ret = PTR_ERR(ptr: msm_host->sfpb); |
1852 | } |
1853 | } |
1854 | |
1855 | err: |
1856 | of_node_put(node: endpoint); |
1857 | |
1858 | return ret; |
1859 | } |
1860 | |
1861 | static int dsi_host_get_id(struct msm_dsi_host *msm_host) |
1862 | { |
1863 | struct platform_device *pdev = msm_host->pdev; |
1864 | const struct msm_dsi_config *cfg = msm_host->cfg_hnd->cfg; |
1865 | struct resource *res; |
1866 | int i, j; |
1867 | |
1868 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dsi_ctrl" ); |
1869 | if (!res) |
1870 | return -EINVAL; |
1871 | |
1872 | for (i = 0; i < VARIANTS_MAX; i++) |
1873 | for (j = 0; j < DSI_MAX; j++) |
1874 | if (cfg->io_start[i][j] == res->start) |
1875 | return j; |
1876 | |
1877 | return -EINVAL; |
1878 | } |
1879 | |
1880 | int msm_dsi_host_init(struct msm_dsi *msm_dsi) |
1881 | { |
1882 | struct msm_dsi_host *msm_host = NULL; |
1883 | struct platform_device *pdev = msm_dsi->pdev; |
1884 | const struct msm_dsi_config *cfg; |
1885 | int ret; |
1886 | |
1887 | msm_host = devm_kzalloc(dev: &pdev->dev, size: sizeof(*msm_host), GFP_KERNEL); |
1888 | if (!msm_host) { |
1889 | return -ENOMEM; |
1890 | } |
1891 | |
1892 | msm_host->pdev = pdev; |
1893 | msm_dsi->host = &msm_host->base; |
1894 | |
1895 | ret = dsi_host_parse_dt(msm_host); |
1896 | if (ret) { |
1897 | pr_err("%s: failed to parse dt\n" , __func__); |
1898 | return ret; |
1899 | } |
1900 | |
1901 | msm_host->ctrl_base = msm_ioremap_size(pdev, "dsi_ctrl" , &msm_host->ctrl_size); |
1902 | if (IS_ERR(ptr: msm_host->ctrl_base)) { |
1903 | pr_err("%s: unable to map Dsi ctrl base\n" , __func__); |
1904 | return PTR_ERR(ptr: msm_host->ctrl_base); |
1905 | } |
1906 | |
1907 | pm_runtime_enable(&pdev->dev); |
1908 | |
1909 | msm_host->cfg_hnd = dsi_get_config(msm_host); |
1910 | if (!msm_host->cfg_hnd) { |
1911 | pr_err("%s: get config failed\n" , __func__); |
1912 | return -EINVAL; |
1913 | } |
1914 | cfg = msm_host->cfg_hnd->cfg; |
1915 | |
1916 | msm_host->id = dsi_host_get_id(msm_host); |
1917 | if (msm_host->id < 0) { |
1918 | pr_err("%s: unable to identify DSI host index\n" , __func__); |
1919 | return msm_host->id; |
1920 | } |
1921 | |
1922 | /* fixup base address by io offset */ |
1923 | msm_host->ctrl_base += cfg->io_offset; |
1924 | |
1925 | ret = devm_regulator_bulk_get_const(dev: &pdev->dev, num_consumers: cfg->num_regulators, |
1926 | in_consumers: cfg->regulator_data, |
1927 | out_consumers: &msm_host->supplies); |
1928 | if (ret) |
1929 | return ret; |
1930 | |
1931 | ret = dsi_clk_init(msm_host); |
1932 | if (ret) { |
1933 | pr_err("%s: unable to initialize dsi clks\n" , __func__); |
1934 | return ret; |
1935 | } |
1936 | |
1937 | msm_host->rx_buf = devm_kzalloc(dev: &pdev->dev, SZ_4K, GFP_KERNEL); |
1938 | if (!msm_host->rx_buf) { |
1939 | pr_err("%s: alloc rx temp buf failed\n" , __func__); |
1940 | return -ENOMEM; |
1941 | } |
1942 | |
1943 | ret = devm_pm_opp_set_clkname(dev: &pdev->dev, name: "byte" ); |
1944 | if (ret) |
1945 | return ret; |
1946 | /* OPP table is optional */ |
1947 | ret = devm_pm_opp_of_add_table(dev: &pdev->dev); |
1948 | if (ret && ret != -ENODEV) { |
1949 | dev_err(&pdev->dev, "invalid OPP table in device tree\n" ); |
1950 | return ret; |
1951 | } |
1952 | |
1953 | msm_host->irq = irq_of_parse_and_map(node: pdev->dev.of_node, index: 0); |
1954 | if (!msm_host->irq) { |
1955 | dev_err(&pdev->dev, "failed to get irq\n" ); |
1956 | return -EINVAL; |
1957 | } |
1958 | |
1959 | /* do not autoenable, will be enabled later */ |
1960 | ret = devm_request_irq(dev: &pdev->dev, irq: msm_host->irq, handler: dsi_host_irq, |
1961 | IRQF_TRIGGER_HIGH | IRQF_NO_AUTOEN, |
1962 | devname: "dsi_isr" , dev_id: msm_host); |
1963 | if (ret < 0) { |
1964 | dev_err(&pdev->dev, "failed to request IRQ%u: %d\n" , |
1965 | msm_host->irq, ret); |
1966 | return ret; |
1967 | } |
1968 | |
1969 | init_completion(x: &msm_host->dma_comp); |
1970 | init_completion(x: &msm_host->video_comp); |
1971 | mutex_init(&msm_host->dev_mutex); |
1972 | mutex_init(&msm_host->cmd_mutex); |
1973 | spin_lock_init(&msm_host->intr_lock); |
1974 | |
1975 | /* setup workqueue */ |
1976 | msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work" , 0); |
1977 | if (!msm_host->workqueue) |
1978 | return -ENOMEM; |
1979 | |
1980 | INIT_WORK(&msm_host->err_work, dsi_err_worker); |
1981 | |
1982 | msm_dsi->id = msm_host->id; |
1983 | |
1984 | DBG("Dsi Host %d initialized" , msm_host->id); |
1985 | return 0; |
1986 | } |
1987 | |
1988 | void msm_dsi_host_destroy(struct mipi_dsi_host *host) |
1989 | { |
1990 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
1991 | |
1992 | DBG("" ); |
1993 | if (msm_host->workqueue) { |
1994 | destroy_workqueue(wq: msm_host->workqueue); |
1995 | msm_host->workqueue = NULL; |
1996 | } |
1997 | |
1998 | mutex_destroy(lock: &msm_host->cmd_mutex); |
1999 | mutex_destroy(lock: &msm_host->dev_mutex); |
2000 | |
2001 | pm_runtime_disable(&msm_host->pdev->dev); |
2002 | } |
2003 | |
2004 | int msm_dsi_host_modeset_init(struct mipi_dsi_host *host, |
2005 | struct drm_device *dev) |
2006 | { |
2007 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2008 | const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; |
2009 | int ret; |
2010 | |
2011 | msm_host->dev = dev; |
2012 | |
2013 | ret = cfg_hnd->ops->tx_buf_alloc(msm_host, SZ_4K); |
2014 | if (ret) { |
2015 | pr_err("%s: alloc tx gem obj failed, %d\n" , __func__, ret); |
2016 | return ret; |
2017 | } |
2018 | |
2019 | return 0; |
2020 | } |
2021 | |
2022 | int msm_dsi_host_register(struct mipi_dsi_host *host) |
2023 | { |
2024 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2025 | int ret; |
2026 | |
2027 | /* Register mipi dsi host */ |
2028 | if (!msm_host->registered) { |
2029 | host->dev = &msm_host->pdev->dev; |
2030 | host->ops = &dsi_host_ops; |
2031 | ret = mipi_dsi_host_register(host); |
2032 | if (ret) |
2033 | return ret; |
2034 | |
2035 | msm_host->registered = true; |
2036 | } |
2037 | |
2038 | return 0; |
2039 | } |
2040 | |
2041 | void msm_dsi_host_unregister(struct mipi_dsi_host *host) |
2042 | { |
2043 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2044 | |
2045 | if (msm_host->registered) { |
2046 | mipi_dsi_host_unregister(host); |
2047 | host->dev = NULL; |
2048 | host->ops = NULL; |
2049 | msm_host->registered = false; |
2050 | } |
2051 | } |
2052 | |
2053 | int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host, |
2054 | const struct mipi_dsi_msg *msg) |
2055 | { |
2056 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2057 | const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; |
2058 | |
2059 | /* TODO: make sure dsi_cmd_mdp is idle. |
2060 | * Since DSI6G v1.2.0, we can set DSI_TRIG_CTRL.BLOCK_DMA_WITHIN_FRAME |
2061 | * to ask H/W to wait until cmd mdp is idle. S/W wait is not needed. |
2062 | * How to handle the old versions? Wait for mdp cmd done? |
2063 | */ |
2064 | |
2065 | /* |
2066 | * mdss interrupt is generated in mdp core clock domain |
2067 | * mdp clock need to be enabled to receive dsi interrupt |
2068 | */ |
2069 | pm_runtime_get_sync(&msm_host->pdev->dev); |
2070 | cfg_hnd->ops->link_clk_set_rate(msm_host); |
2071 | cfg_hnd->ops->link_clk_enable(msm_host); |
2072 | |
2073 | /* TODO: vote for bus bandwidth */ |
2074 | |
2075 | if (!(msg->flags & MIPI_DSI_MSG_USE_LPM)) |
2076 | dsi_set_tx_power_mode(mode: 0, msm_host); |
2077 | |
2078 | msm_host->dma_cmd_ctrl_restore = dsi_read(msm_host, REG_DSI_CTRL); |
2079 | dsi_write(msm_host, REG_DSI_CTRL, |
2080 | data: msm_host->dma_cmd_ctrl_restore | |
2081 | DSI_CTRL_CMD_MODE_EN | |
2082 | DSI_CTRL_ENABLE); |
2083 | dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_DMA_DONE, enable: 1); |
2084 | |
2085 | return 0; |
2086 | } |
2087 | |
2088 | void msm_dsi_host_xfer_restore(struct mipi_dsi_host *host, |
2089 | const struct mipi_dsi_msg *msg) |
2090 | { |
2091 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2092 | const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; |
2093 | |
2094 | dsi_intr_ctrl(msm_host, DSI_IRQ_MASK_CMD_DMA_DONE, enable: 0); |
2095 | dsi_write(msm_host, REG_DSI_CTRL, data: msm_host->dma_cmd_ctrl_restore); |
2096 | |
2097 | if (!(msg->flags & MIPI_DSI_MSG_USE_LPM)) |
2098 | dsi_set_tx_power_mode(mode: 1, msm_host); |
2099 | |
2100 | /* TODO: unvote for bus bandwidth */ |
2101 | |
2102 | cfg_hnd->ops->link_clk_disable(msm_host); |
2103 | pm_runtime_put(&msm_host->pdev->dev); |
2104 | } |
2105 | |
2106 | int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host, |
2107 | const struct mipi_dsi_msg *msg) |
2108 | { |
2109 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2110 | |
2111 | return dsi_cmds2buf_tx(msm_host, msg); |
2112 | } |
2113 | |
2114 | int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host, |
2115 | const struct mipi_dsi_msg *msg) |
2116 | { |
2117 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2118 | const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; |
2119 | int data_byte, rx_byte, dlen, end; |
2120 | int short_response, diff, pkt_size, ret = 0; |
2121 | char cmd; |
2122 | int rlen = msg->rx_len; |
2123 | u8 *buf; |
2124 | |
2125 | if (rlen <= 2) { |
2126 | short_response = 1; |
2127 | pkt_size = rlen; |
2128 | rx_byte = 4; |
2129 | } else { |
2130 | short_response = 0; |
2131 | data_byte = 10; /* first read */ |
2132 | if (rlen < data_byte) |
2133 | pkt_size = rlen; |
2134 | else |
2135 | pkt_size = data_byte; |
2136 | rx_byte = data_byte + 6; /* 4 header + 2 crc */ |
2137 | } |
2138 | |
2139 | buf = msm_host->rx_buf; |
2140 | end = 0; |
2141 | while (!end) { |
2142 | u8 tx[2] = {pkt_size & 0xff, pkt_size >> 8}; |
2143 | struct mipi_dsi_msg max_pkt_size_msg = { |
2144 | .channel = msg->channel, |
2145 | .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, |
2146 | .tx_len = 2, |
2147 | .tx_buf = tx, |
2148 | }; |
2149 | |
2150 | DBG("rlen=%d pkt_size=%d rx_byte=%d" , |
2151 | rlen, pkt_size, rx_byte); |
2152 | |
2153 | ret = dsi_cmds2buf_tx(msm_host, msg: &max_pkt_size_msg); |
2154 | if (ret < 2) { |
2155 | pr_err("%s: Set max pkt size failed, %d\n" , |
2156 | __func__, ret); |
2157 | return -EINVAL; |
2158 | } |
2159 | |
2160 | if ((cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) && |
2161 | (cfg_hnd->minor >= MSM_DSI_6G_VER_MINOR_V1_1)) { |
2162 | /* Clear the RDBK_DATA registers */ |
2163 | dsi_write(msm_host, REG_DSI_RDBK_DATA_CTRL, |
2164 | DSI_RDBK_DATA_CTRL_CLR); |
2165 | wmb(); /* make sure the RDBK registers are cleared */ |
2166 | dsi_write(msm_host, REG_DSI_RDBK_DATA_CTRL, data: 0); |
2167 | wmb(); /* release cleared status before transfer */ |
2168 | } |
2169 | |
2170 | ret = dsi_cmds2buf_tx(msm_host, msg); |
2171 | if (ret < 0) { |
2172 | pr_err("%s: Read cmd Tx failed, %d\n" , __func__, ret); |
2173 | return ret; |
2174 | } else if (ret < msg->tx_len) { |
2175 | pr_err("%s: Read cmd Tx failed, too short: %d\n" , __func__, ret); |
2176 | return -ECOMM; |
2177 | } |
2178 | |
2179 | /* |
2180 | * once cmd_dma_done interrupt received, |
2181 | * return data from client is ready and stored |
2182 | * at RDBK_DATA register already |
2183 | * since rx fifo is 16 bytes, dcs header is kept at first loop, |
2184 | * after that dcs header lost during shift into registers |
2185 | */ |
2186 | dlen = dsi_cmd_dma_rx(msm_host, buf, rx_byte, pkt_size); |
2187 | |
2188 | if (dlen <= 0) |
2189 | return 0; |
2190 | |
2191 | if (short_response) |
2192 | break; |
2193 | |
2194 | if (rlen <= data_byte) { |
2195 | diff = data_byte - rlen; |
2196 | end = 1; |
2197 | } else { |
2198 | diff = 0; |
2199 | rlen -= data_byte; |
2200 | } |
2201 | |
2202 | if (!end) { |
2203 | dlen -= 2; /* 2 crc */ |
2204 | dlen -= diff; |
2205 | buf += dlen; /* next start position */ |
2206 | data_byte = 14; /* NOT first read */ |
2207 | if (rlen < data_byte) |
2208 | pkt_size += rlen; |
2209 | else |
2210 | pkt_size += data_byte; |
2211 | DBG("buf=%p dlen=%d diff=%d" , buf, dlen, diff); |
2212 | } |
2213 | } |
2214 | |
2215 | /* |
2216 | * For single Long read, if the requested rlen < 10, |
2217 | * we need to shift the start position of rx |
2218 | * data buffer to skip the bytes which are not |
2219 | * updated. |
2220 | */ |
2221 | if (pkt_size < 10 && !short_response) |
2222 | buf = msm_host->rx_buf + (10 - rlen); |
2223 | else |
2224 | buf = msm_host->rx_buf; |
2225 | |
2226 | cmd = buf[0]; |
2227 | switch (cmd) { |
2228 | case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: |
2229 | pr_err("%s: rx ACK_ERR_PACLAGE\n" , __func__); |
2230 | ret = 0; |
2231 | break; |
2232 | case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE: |
2233 | case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE: |
2234 | ret = dsi_short_read1_resp(buf, msg); |
2235 | break; |
2236 | case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE: |
2237 | case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE: |
2238 | ret = dsi_short_read2_resp(buf, msg); |
2239 | break; |
2240 | case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE: |
2241 | case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE: |
2242 | ret = dsi_long_read_resp(buf, msg); |
2243 | break; |
2244 | default: |
2245 | pr_warn("%s:Invalid response cmd\n" , __func__); |
2246 | ret = 0; |
2247 | } |
2248 | |
2249 | return ret; |
2250 | } |
2251 | |
2252 | void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, u32 dma_base, |
2253 | u32 len) |
2254 | { |
2255 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2256 | |
2257 | dsi_write(msm_host, REG_DSI_DMA_BASE, data: dma_base); |
2258 | dsi_write(msm_host, REG_DSI_DMA_LEN, data: len); |
2259 | dsi_write(msm_host, REG_DSI_TRIG_DMA, data: 1); |
2260 | |
2261 | /* Make sure trigger happens */ |
2262 | wmb(); |
2263 | } |
2264 | |
2265 | void msm_dsi_host_set_phy_mode(struct mipi_dsi_host *host, |
2266 | struct msm_dsi_phy *src_phy) |
2267 | { |
2268 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2269 | |
2270 | msm_host->cphy_mode = src_phy->cphy_mode; |
2271 | } |
2272 | |
2273 | void msm_dsi_host_reset_phy(struct mipi_dsi_host *host) |
2274 | { |
2275 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2276 | |
2277 | DBG("" ); |
2278 | dsi_write(msm_host, REG_DSI_PHY_RESET, DSI_PHY_RESET_RESET); |
2279 | /* Make sure fully reset */ |
2280 | wmb(); |
2281 | udelay(1000); |
2282 | dsi_write(msm_host, REG_DSI_PHY_RESET, data: 0); |
2283 | udelay(100); |
2284 | } |
2285 | |
2286 | void msm_dsi_host_get_phy_clk_req(struct mipi_dsi_host *host, |
2287 | struct msm_dsi_phy_clk_request *clk_req, |
2288 | bool is_bonded_dsi) |
2289 | { |
2290 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2291 | const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; |
2292 | int ret; |
2293 | |
2294 | ret = cfg_hnd->ops->calc_clk_rate(msm_host, is_bonded_dsi); |
2295 | if (ret) { |
2296 | pr_err("%s: unable to calc clk rate, %d\n" , __func__, ret); |
2297 | return; |
2298 | } |
2299 | |
2300 | /* CPHY transmits 16 bits over 7 clock cycles |
2301 | * "byte_clk" is in units of 16-bits (see dsi_calc_pclk), |
2302 | * so multiply by 7 to get the "bitclk rate" |
2303 | */ |
2304 | if (msm_host->cphy_mode) |
2305 | clk_req->bitclk_rate = msm_host->byte_clk_rate * 7; |
2306 | else |
2307 | clk_req->bitclk_rate = msm_host->byte_clk_rate * 8; |
2308 | clk_req->escclk_rate = msm_host->esc_clk_rate; |
2309 | } |
2310 | |
2311 | void msm_dsi_host_enable_irq(struct mipi_dsi_host *host) |
2312 | { |
2313 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2314 | |
2315 | enable_irq(irq: msm_host->irq); |
2316 | } |
2317 | |
2318 | void msm_dsi_host_disable_irq(struct mipi_dsi_host *host) |
2319 | { |
2320 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2321 | |
2322 | disable_irq(irq: msm_host->irq); |
2323 | } |
2324 | |
2325 | int msm_dsi_host_enable(struct mipi_dsi_host *host) |
2326 | { |
2327 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2328 | |
2329 | dsi_op_mode_config(msm_host, |
2330 | video_mode: !!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO), enable: true); |
2331 | |
2332 | /* TODO: clock should be turned off for command mode, |
2333 | * and only turned on before MDP START. |
2334 | * This part of code should be enabled once mdp driver support it. |
2335 | */ |
2336 | /* if (msm_panel->mode == MSM_DSI_CMD_MODE) { |
2337 | * dsi_link_clk_disable(msm_host); |
2338 | * pm_runtime_put(&msm_host->pdev->dev); |
2339 | * } |
2340 | */ |
2341 | msm_host->enabled = true; |
2342 | return 0; |
2343 | } |
2344 | |
2345 | int msm_dsi_host_disable(struct mipi_dsi_host *host) |
2346 | { |
2347 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2348 | |
2349 | msm_host->enabled = false; |
2350 | dsi_op_mode_config(msm_host, |
2351 | video_mode: !!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO), enable: false); |
2352 | |
2353 | /* Since we have disabled INTF, the video engine won't stop so that |
2354 | * the cmd engine will be blocked. |
2355 | * Reset to disable video engine so that we can send off cmd. |
2356 | */ |
2357 | dsi_sw_reset(msm_host); |
2358 | |
2359 | return 0; |
2360 | } |
2361 | |
2362 | static void msm_dsi_sfpb_config(struct msm_dsi_host *msm_host, bool enable) |
2363 | { |
2364 | enum sfpb_ahb_arb_master_port_en en; |
2365 | |
2366 | if (!msm_host->sfpb) |
2367 | return; |
2368 | |
2369 | en = enable ? SFPB_MASTER_PORT_ENABLE : SFPB_MASTER_PORT_DISABLE; |
2370 | |
2371 | regmap_update_bits(map: msm_host->sfpb, REG_SFPB_GPREG, |
2372 | SFPB_GPREG_MASTER_PORT_EN__MASK, |
2373 | val: SFPB_GPREG_MASTER_PORT_EN(val: en)); |
2374 | } |
2375 | |
2376 | int msm_dsi_host_power_on(struct mipi_dsi_host *host, |
2377 | struct msm_dsi_phy_shared_timings *phy_shared_timings, |
2378 | bool is_bonded_dsi, struct msm_dsi_phy *phy) |
2379 | { |
2380 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2381 | const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; |
2382 | int ret = 0; |
2383 | |
2384 | mutex_lock(&msm_host->dev_mutex); |
2385 | if (msm_host->power_on) { |
2386 | DBG("dsi host already on" ); |
2387 | goto unlock_ret; |
2388 | } |
2389 | |
2390 | msm_host->byte_intf_clk_rate = msm_host->byte_clk_rate; |
2391 | if (phy_shared_timings->byte_intf_clk_div_2) |
2392 | msm_host->byte_intf_clk_rate /= 2; |
2393 | |
2394 | msm_dsi_sfpb_config(msm_host, enable: true); |
2395 | |
2396 | ret = regulator_bulk_enable(num_consumers: msm_host->cfg_hnd->cfg->num_regulators, |
2397 | consumers: msm_host->supplies); |
2398 | if (ret) { |
2399 | pr_err("%s:Failed to enable vregs.ret=%d\n" , |
2400 | __func__, ret); |
2401 | goto unlock_ret; |
2402 | } |
2403 | |
2404 | pm_runtime_get_sync(&msm_host->pdev->dev); |
2405 | ret = cfg_hnd->ops->link_clk_set_rate(msm_host); |
2406 | if (!ret) |
2407 | ret = cfg_hnd->ops->link_clk_enable(msm_host); |
2408 | if (ret) { |
2409 | pr_err("%s: failed to enable link clocks. ret=%d\n" , |
2410 | __func__, ret); |
2411 | goto fail_disable_reg; |
2412 | } |
2413 | |
2414 | ret = pinctrl_pm_select_default_state(dev: &msm_host->pdev->dev); |
2415 | if (ret) { |
2416 | pr_err("%s: failed to set pinctrl default state, %d\n" , |
2417 | __func__, ret); |
2418 | goto fail_disable_clk; |
2419 | } |
2420 | |
2421 | dsi_timing_setup(msm_host, is_bonded_dsi); |
2422 | dsi_sw_reset(msm_host); |
2423 | dsi_ctrl_enable(msm_host, phy_shared_timings, phy); |
2424 | |
2425 | if (msm_host->disp_en_gpio) |
2426 | gpiod_set_value(desc: msm_host->disp_en_gpio, value: 1); |
2427 | |
2428 | msm_host->power_on = true; |
2429 | mutex_unlock(lock: &msm_host->dev_mutex); |
2430 | |
2431 | return 0; |
2432 | |
2433 | fail_disable_clk: |
2434 | cfg_hnd->ops->link_clk_disable(msm_host); |
2435 | pm_runtime_put(&msm_host->pdev->dev); |
2436 | fail_disable_reg: |
2437 | regulator_bulk_disable(num_consumers: msm_host->cfg_hnd->cfg->num_regulators, |
2438 | consumers: msm_host->supplies); |
2439 | unlock_ret: |
2440 | mutex_unlock(lock: &msm_host->dev_mutex); |
2441 | return ret; |
2442 | } |
2443 | |
2444 | int msm_dsi_host_power_off(struct mipi_dsi_host *host) |
2445 | { |
2446 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2447 | const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; |
2448 | |
2449 | mutex_lock(&msm_host->dev_mutex); |
2450 | if (!msm_host->power_on) { |
2451 | DBG("dsi host already off" ); |
2452 | goto unlock_ret; |
2453 | } |
2454 | |
2455 | dsi_ctrl_disable(msm_host); |
2456 | |
2457 | if (msm_host->disp_en_gpio) |
2458 | gpiod_set_value(desc: msm_host->disp_en_gpio, value: 0); |
2459 | |
2460 | pinctrl_pm_select_sleep_state(dev: &msm_host->pdev->dev); |
2461 | |
2462 | cfg_hnd->ops->link_clk_disable(msm_host); |
2463 | pm_runtime_put(&msm_host->pdev->dev); |
2464 | |
2465 | regulator_bulk_disable(num_consumers: msm_host->cfg_hnd->cfg->num_regulators, |
2466 | consumers: msm_host->supplies); |
2467 | |
2468 | msm_dsi_sfpb_config(msm_host, enable: false); |
2469 | |
2470 | DBG("-" ); |
2471 | |
2472 | msm_host->power_on = false; |
2473 | |
2474 | unlock_ret: |
2475 | mutex_unlock(lock: &msm_host->dev_mutex); |
2476 | return 0; |
2477 | } |
2478 | |
2479 | int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host, |
2480 | const struct drm_display_mode *mode) |
2481 | { |
2482 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2483 | |
2484 | if (msm_host->mode) { |
2485 | drm_mode_destroy(dev: msm_host->dev, mode: msm_host->mode); |
2486 | msm_host->mode = NULL; |
2487 | } |
2488 | |
2489 | msm_host->mode = drm_mode_duplicate(dev: msm_host->dev, mode); |
2490 | if (!msm_host->mode) { |
2491 | pr_err("%s: cannot duplicate mode\n" , __func__); |
2492 | return -ENOMEM; |
2493 | } |
2494 | |
2495 | return 0; |
2496 | } |
2497 | |
2498 | enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host, |
2499 | const struct drm_display_mode *mode) |
2500 | { |
2501 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2502 | struct drm_dsc_config *dsc = msm_host->dsc; |
2503 | int pic_width = mode->hdisplay; |
2504 | int pic_height = mode->vdisplay; |
2505 | |
2506 | if (!msm_host->dsc) |
2507 | return MODE_OK; |
2508 | |
2509 | if (pic_width % dsc->slice_width) { |
2510 | pr_err("DSI: pic_width %d has to be multiple of slice %d\n" , |
2511 | pic_width, dsc->slice_width); |
2512 | return MODE_H_ILLEGAL; |
2513 | } |
2514 | |
2515 | if (pic_height % dsc->slice_height) { |
2516 | pr_err("DSI: pic_height %d has to be multiple of slice %d\n" , |
2517 | pic_height, dsc->slice_height); |
2518 | return MODE_V_ILLEGAL; |
2519 | } |
2520 | |
2521 | return MODE_OK; |
2522 | } |
2523 | |
2524 | unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host) |
2525 | { |
2526 | return to_msm_dsi_host(host)->mode_flags; |
2527 | } |
2528 | |
2529 | void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host) |
2530 | { |
2531 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2532 | |
2533 | pm_runtime_get_sync(&msm_host->pdev->dev); |
2534 | |
2535 | msm_disp_snapshot_add_block(disp_state, msm_host->ctrl_size, |
2536 | msm_host->ctrl_base, "dsi%d_ctrl" , msm_host->id); |
2537 | |
2538 | pm_runtime_put_sync(&msm_host->pdev->dev); |
2539 | } |
2540 | |
2541 | static void msm_dsi_host_video_test_pattern_setup(struct msm_dsi_host *msm_host) |
2542 | { |
2543 | u32 reg; |
2544 | |
2545 | reg = dsi_read(msm_host, REG_DSI_TEST_PATTERN_GEN_CTRL); |
2546 | |
2547 | dsi_write(msm_host, REG_DSI_TEST_PATTERN_GEN_VIDEO_INIT_VAL, data: 0xff); |
2548 | /* draw checkered rectangle pattern */ |
2549 | dsi_write(msm_host, REG_DSI_TPG_MAIN_CONTROL, |
2550 | DSI_TPG_MAIN_CONTROL_CHECKERED_RECTANGLE_PATTERN); |
2551 | /* use 24-bit RGB test pttern */ |
2552 | dsi_write(msm_host, REG_DSI_TPG_VIDEO_CONFIG, |
2553 | data: DSI_TPG_VIDEO_CONFIG_BPP(val: VIDEO_CONFIG_24BPP) | |
2554 | DSI_TPG_VIDEO_CONFIG_RGB); |
2555 | |
2556 | reg |= DSI_TEST_PATTERN_GEN_CTRL_VIDEO_PATTERN_SEL(val: VID_MDSS_GENERAL_PATTERN); |
2557 | dsi_write(msm_host, REG_DSI_TEST_PATTERN_GEN_CTRL, data: reg); |
2558 | |
2559 | DBG("Video test pattern setup done\n" ); |
2560 | } |
2561 | |
2562 | static void msm_dsi_host_cmd_test_pattern_setup(struct msm_dsi_host *msm_host) |
2563 | { |
2564 | u32 reg; |
2565 | |
2566 | reg = dsi_read(msm_host, REG_DSI_TEST_PATTERN_GEN_CTRL); |
2567 | |
2568 | /* initial value for test pattern */ |
2569 | dsi_write(msm_host, REG_DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL0, data: 0xff); |
2570 | |
2571 | reg |= DSI_TEST_PATTERN_GEN_CTRL_CMD_MDP_STREAM0_PATTERN_SEL(val: CMD_MDP_MDSS_GENERAL_PATTERN); |
2572 | |
2573 | dsi_write(msm_host, REG_DSI_TEST_PATTERN_GEN_CTRL, data: reg); |
2574 | /* draw checkered rectangle pattern */ |
2575 | dsi_write(msm_host, REG_DSI_TPG_MAIN_CONTROL2, |
2576 | DSI_TPG_MAIN_CONTROL2_CMD_MDP0_CHECKERED_RECTANGLE_PATTERN); |
2577 | |
2578 | DBG("Cmd test pattern setup done\n" ); |
2579 | } |
2580 | |
2581 | void msm_dsi_host_test_pattern_en(struct mipi_dsi_host *host) |
2582 | { |
2583 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2584 | bool is_video_mode = !!(msm_host->mode_flags & MIPI_DSI_MODE_VIDEO); |
2585 | u32 reg; |
2586 | |
2587 | if (is_video_mode) |
2588 | msm_dsi_host_video_test_pattern_setup(msm_host); |
2589 | else |
2590 | msm_dsi_host_cmd_test_pattern_setup(msm_host); |
2591 | |
2592 | reg = dsi_read(msm_host, REG_DSI_TEST_PATTERN_GEN_CTRL); |
2593 | /* enable the test pattern generator */ |
2594 | dsi_write(msm_host, REG_DSI_TEST_PATTERN_GEN_CTRL, data: (reg | DSI_TEST_PATTERN_GEN_CTRL_EN)); |
2595 | |
2596 | /* for command mode need to trigger one frame from tpg */ |
2597 | if (!is_video_mode) |
2598 | dsi_write(msm_host, REG_DSI_TEST_PATTERN_GEN_CMD_STREAM0_TRIGGER, |
2599 | DSI_TEST_PATTERN_GEN_CMD_STREAM0_TRIGGER_SW_TRIGGER); |
2600 | } |
2601 | |
2602 | struct drm_dsc_config *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host) |
2603 | { |
2604 | struct msm_dsi_host *msm_host = to_msm_dsi_host(host); |
2605 | |
2606 | return msm_host->dsc; |
2607 | } |
2608 | |