diff options
-rw-r--r-- | drivers/gpu/drm/mediatek/mtk_dsi.c | 259 |
1 files changed, 158 insertions, 101 deletions
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index 09528e2e69aa..b6eac92c67f8 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c | |||
@@ -126,6 +126,10 @@ | |||
126 | #define CLK_HS_POST (0xff << 8) | 126 | #define CLK_HS_POST (0xff << 8) |
127 | #define CLK_HS_EXIT (0xff << 16) | 127 | #define CLK_HS_EXIT (0xff << 16) |
128 | 128 | ||
129 | #define DSI_VM_CMD_CON 0x130 | ||
130 | #define VM_CMD_EN BIT(0) | ||
131 | #define TS_VFP_EN BIT(5) | ||
132 | |||
129 | #define DSI_CMDQ0 0x180 | 133 | #define DSI_CMDQ0 0x180 |
130 | #define CONFIG (0xff << 0) | 134 | #define CONFIG (0xff << 0) |
131 | #define SHORT_PACKET 0 | 135 | #define SHORT_PACKET 0 |
@@ -239,85 +243,6 @@ static void mtk_dsi_reset_engine(struct mtk_dsi *dsi) | |||
239 | mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, 0); | 243 | mtk_dsi_mask(dsi, DSI_CON_CTRL, DSI_RESET, 0); |
240 | } | 244 | } |
241 | 245 | ||
242 | static int mtk_dsi_poweron(struct mtk_dsi *dsi) | ||
243 | { | ||
244 | struct device *dev = dsi->dev; | ||
245 | int ret; | ||
246 | u64 pixel_clock, total_bits; | ||
247 | u32 htotal, htotal_bits, bit_per_pixel, overhead_cycles, overhead_bits; | ||
248 | |||
249 | if (++dsi->refcount != 1) | ||
250 | return 0; | ||
251 | |||
252 | switch (dsi->format) { | ||
253 | case MIPI_DSI_FMT_RGB565: | ||
254 | bit_per_pixel = 16; | ||
255 | break; | ||
256 | case MIPI_DSI_FMT_RGB666_PACKED: | ||
257 | bit_per_pixel = 18; | ||
258 | break; | ||
259 | case MIPI_DSI_FMT_RGB666: | ||
260 | case MIPI_DSI_FMT_RGB888: | ||
261 | default: | ||
262 | bit_per_pixel = 24; | ||
263 | break; | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * vm.pixelclock is in kHz, pixel_clock unit is Hz, so multiply by 1000 | ||
268 | * htotal_time = htotal * byte_per_pixel / num_lanes | ||
269 | * overhead_time = lpx + hs_prepare + hs_zero + hs_trail + hs_exit | ||
270 | * mipi_ratio = (htotal_time + overhead_time) / htotal_time | ||
271 | * data_rate = pixel_clock * bit_per_pixel * mipi_ratio / num_lanes; | ||
272 | */ | ||
273 | pixel_clock = dsi->vm.pixelclock * 1000; | ||
274 | htotal = dsi->vm.hactive + dsi->vm.hback_porch + dsi->vm.hfront_porch + | ||
275 | dsi->vm.hsync_len; | ||
276 | htotal_bits = htotal * bit_per_pixel; | ||
277 | |||
278 | overhead_cycles = T_LPX + T_HS_PREP + T_HS_ZERO + T_HS_TRAIL + | ||
279 | T_HS_EXIT; | ||
280 | overhead_bits = overhead_cycles * dsi->lanes * 8; | ||
281 | total_bits = htotal_bits + overhead_bits; | ||
282 | |||
283 | dsi->data_rate = DIV_ROUND_UP_ULL(pixel_clock * total_bits, | ||
284 | htotal * dsi->lanes); | ||
285 | |||
286 | ret = clk_set_rate(dsi->hs_clk, dsi->data_rate); | ||
287 | if (ret < 0) { | ||
288 | dev_err(dev, "Failed to set data rate: %d\n", ret); | ||
289 | goto err_refcount; | ||
290 | } | ||
291 | |||
292 | phy_power_on(dsi->phy); | ||
293 | |||
294 | ret = clk_prepare_enable(dsi->engine_clk); | ||
295 | if (ret < 0) { | ||
296 | dev_err(dev, "Failed to enable engine clock: %d\n", ret); | ||
297 | goto err_phy_power_off; | ||
298 | } | ||
299 | |||
300 | ret = clk_prepare_enable(dsi->digital_clk); | ||
301 | if (ret < 0) { | ||
302 | dev_err(dev, "Failed to enable digital clock: %d\n", ret); | ||
303 | goto err_disable_engine_clk; | ||
304 | } | ||
305 | |||
306 | mtk_dsi_enable(dsi); | ||
307 | mtk_dsi_reset_engine(dsi); | ||
308 | mtk_dsi_phy_timconfig(dsi); | ||
309 | |||
310 | return 0; | ||
311 | |||
312 | err_disable_engine_clk: | ||
313 | clk_disable_unprepare(dsi->engine_clk); | ||
314 | err_phy_power_off: | ||
315 | phy_power_off(dsi->phy); | ||
316 | err_refcount: | ||
317 | dsi->refcount--; | ||
318 | return ret; | ||
319 | } | ||
320 | |||
321 | static void mtk_dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi) | 246 | static void mtk_dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi) |
322 | { | 247 | { |
323 | mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0); | 248 | mtk_dsi_mask(dsi, DSI_PHY_LCCON, LC_HS_TX_EN, 0); |
@@ -365,16 +290,23 @@ static void mtk_dsi_set_mode(struct mtk_dsi *dsi) | |||
365 | u32 vid_mode = CMD_MODE; | 290 | u32 vid_mode = CMD_MODE; |
366 | 291 | ||
367 | if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { | 292 | if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { |
368 | vid_mode = SYNC_PULSE_MODE; | 293 | if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) |
369 | |||
370 | if ((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) && | ||
371 | !(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) | ||
372 | vid_mode = BURST_MODE; | 294 | vid_mode = BURST_MODE; |
295 | else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) | ||
296 | vid_mode = SYNC_PULSE_MODE; | ||
297 | else | ||
298 | vid_mode = SYNC_EVENT_MODE; | ||
373 | } | 299 | } |
374 | 300 | ||
375 | writel(vid_mode, dsi->regs + DSI_MODE_CTRL); | 301 | writel(vid_mode, dsi->regs + DSI_MODE_CTRL); |
376 | } | 302 | } |
377 | 303 | ||
304 | static void mtk_dsi_set_vm_cmd(struct mtk_dsi *dsi) | ||
305 | { | ||
306 | mtk_dsi_mask(dsi, DSI_VM_CMD_CON, VM_CMD_EN, VM_CMD_EN); | ||
307 | mtk_dsi_mask(dsi, DSI_VM_CMD_CON, TS_VFP_EN, TS_VFP_EN); | ||
308 | } | ||
309 | |||
378 | static void mtk_dsi_ps_control_vact(struct mtk_dsi *dsi) | 310 | static void mtk_dsi_ps_control_vact(struct mtk_dsi *dsi) |
379 | { | 311 | { |
380 | struct videomode *vm = &dsi->vm; | 312 | struct videomode *vm = &dsi->vm; |
@@ -512,6 +444,16 @@ static void mtk_dsi_start(struct mtk_dsi *dsi) | |||
512 | writel(1, dsi->regs + DSI_START); | 444 | writel(1, dsi->regs + DSI_START); |
513 | } | 445 | } |
514 | 446 | ||
447 | static void mtk_dsi_stop(struct mtk_dsi *dsi) | ||
448 | { | ||
449 | writel(0, dsi->regs + DSI_START); | ||
450 | } | ||
451 | |||
452 | static void mtk_dsi_set_cmd_mode(struct mtk_dsi *dsi) | ||
453 | { | ||
454 | writel(CMD_MODE, dsi->regs + DSI_MODE_CTRL); | ||
455 | } | ||
456 | |||
515 | static void mtk_dsi_set_interrupt_enable(struct mtk_dsi *dsi) | 457 | static void mtk_dsi_set_interrupt_enable(struct mtk_dsi *dsi) |
516 | { | 458 | { |
517 | u32 inten = LPRX_RD_RDY_INT_FLAG | CMD_DONE_INT_FLAG | VM_DONE_INT_FLAG; | 459 | u32 inten = LPRX_RD_RDY_INT_FLAG | CMD_DONE_INT_FLAG | VM_DONE_INT_FLAG; |
@@ -570,6 +512,116 @@ static irqreturn_t mtk_dsi_irq(int irq, void *dev_id) | |||
570 | return IRQ_HANDLED; | 512 | return IRQ_HANDLED; |
571 | } | 513 | } |
572 | 514 | ||
515 | static s32 mtk_dsi_switch_to_cmd_mode(struct mtk_dsi *dsi, u8 irq_flag, u32 t) | ||
516 | { | ||
517 | mtk_dsi_irq_data_clear(dsi, irq_flag); | ||
518 | mtk_dsi_set_cmd_mode(dsi); | ||
519 | |||
520 | if (!mtk_dsi_wait_for_irq_done(dsi, irq_flag, t)) { | ||
521 | DRM_ERROR("failed to switch cmd mode\n"); | ||
522 | return -ETIME; | ||
523 | } else { | ||
524 | return 0; | ||
525 | } | ||
526 | } | ||
527 | |||
528 | static int mtk_dsi_poweron(struct mtk_dsi *dsi) | ||
529 | { | ||
530 | struct device *dev = dsi->dev; | ||
531 | int ret; | ||
532 | u64 pixel_clock, total_bits; | ||
533 | u32 htotal, htotal_bits, bit_per_pixel, overhead_cycles, overhead_bits; | ||
534 | |||
535 | if (++dsi->refcount != 1) | ||
536 | return 0; | ||
537 | |||
538 | switch (dsi->format) { | ||
539 | case MIPI_DSI_FMT_RGB565: | ||
540 | bit_per_pixel = 16; | ||
541 | break; | ||
542 | case MIPI_DSI_FMT_RGB666_PACKED: | ||
543 | bit_per_pixel = 18; | ||
544 | break; | ||
545 | case MIPI_DSI_FMT_RGB666: | ||
546 | case MIPI_DSI_FMT_RGB888: | ||
547 | default: | ||
548 | bit_per_pixel = 24; | ||
549 | break; | ||
550 | } | ||
551 | |||
552 | /** | ||
553 | * vm.pixelclock is in kHz, pixel_clock unit is Hz, so multiply by 1000 | ||
554 | * htotal_time = htotal * byte_per_pixel / num_lanes | ||
555 | * overhead_time = lpx + hs_prepare + hs_zero + hs_trail + hs_exit | ||
556 | * mipi_ratio = (htotal_time + overhead_time) / htotal_time | ||
557 | * data_rate = pixel_clock * bit_per_pixel * mipi_ratio / num_lanes; | ||
558 | */ | ||
559 | pixel_clock = dsi->vm.pixelclock * 1000; | ||
560 | htotal = dsi->vm.hactive + dsi->vm.hback_porch + dsi->vm.hfront_porch + | ||
561 | dsi->vm.hsync_len; | ||
562 | htotal_bits = htotal * bit_per_pixel; | ||
563 | |||
564 | overhead_cycles = T_LPX + T_HS_PREP + T_HS_ZERO + T_HS_TRAIL + | ||
565 | T_HS_EXIT; | ||
566 | overhead_bits = overhead_cycles * dsi->lanes * 8; | ||
567 | total_bits = htotal_bits + overhead_bits; | ||
568 | |||
569 | dsi->data_rate = DIV_ROUND_UP_ULL(pixel_clock * total_bits, | ||
570 | htotal * dsi->lanes); | ||
571 | |||
572 | ret = clk_set_rate(dsi->hs_clk, dsi->data_rate); | ||
573 | if (ret < 0) { | ||
574 | dev_err(dev, "Failed to set data rate: %d\n", ret); | ||
575 | goto err_refcount; | ||
576 | } | ||
577 | |||
578 | phy_power_on(dsi->phy); | ||
579 | |||
580 | ret = clk_prepare_enable(dsi->engine_clk); | ||
581 | if (ret < 0) { | ||
582 | dev_err(dev, "Failed to enable engine clock: %d\n", ret); | ||
583 | goto err_phy_power_off; | ||
584 | } | ||
585 | |||
586 | ret = clk_prepare_enable(dsi->digital_clk); | ||
587 | if (ret < 0) { | ||
588 | dev_err(dev, "Failed to enable digital clock: %d\n", ret); | ||
589 | goto err_disable_engine_clk; | ||
590 | } | ||
591 | |||
592 | mtk_dsi_enable(dsi); | ||
593 | mtk_dsi_reset_engine(dsi); | ||
594 | mtk_dsi_phy_timconfig(dsi); | ||
595 | |||
596 | mtk_dsi_rxtx_control(dsi); | ||
597 | mtk_dsi_ps_control_vact(dsi); | ||
598 | mtk_dsi_set_vm_cmd(dsi); | ||
599 | mtk_dsi_config_vdo_timing(dsi); | ||
600 | mtk_dsi_set_interrupt_enable(dsi); | ||
601 | |||
602 | mtk_dsi_clk_ulp_mode_leave(dsi); | ||
603 | mtk_dsi_lane0_ulp_mode_leave(dsi); | ||
604 | mtk_dsi_clk_hs_mode(dsi, 0); | ||
605 | |||
606 | if (dsi->panel) { | ||
607 | if (drm_panel_prepare(dsi->panel)) { | ||
608 | DRM_ERROR("failed to prepare the panel\n"); | ||
609 | goto err_disable_digital_clk; | ||
610 | } | ||
611 | } | ||
612 | |||
613 | return 0; | ||
614 | err_disable_digital_clk: | ||
615 | clk_disable_unprepare(dsi->digital_clk); | ||
616 | err_disable_engine_clk: | ||
617 | clk_disable_unprepare(dsi->engine_clk); | ||
618 | err_phy_power_off: | ||
619 | phy_power_off(dsi->phy); | ||
620 | err_refcount: | ||
621 | dsi->refcount--; | ||
622 | return ret; | ||
623 | } | ||
624 | |||
573 | static void mtk_dsi_poweroff(struct mtk_dsi *dsi) | 625 | static void mtk_dsi_poweroff(struct mtk_dsi *dsi) |
574 | { | 626 | { |
575 | if (WARN_ON(dsi->refcount == 0)) | 627 | if (WARN_ON(dsi->refcount == 0)) |
@@ -578,6 +630,16 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi) | |||
578 | if (--dsi->refcount != 0) | 630 | if (--dsi->refcount != 0) |
579 | return; | 631 | return; |
580 | 632 | ||
633 | if (!mtk_dsi_switch_to_cmd_mode(dsi, VM_DONE_INT_FLAG, 500)) { | ||
634 | if (dsi->panel) { | ||
635 | if (drm_panel_unprepare(dsi->panel)) { | ||
636 | DRM_ERROR("failed to unprepare the panel\n"); | ||
637 | return; | ||
638 | } | ||
639 | } | ||
640 | } | ||
641 | |||
642 | mtk_dsi_reset_engine(dsi); | ||
581 | mtk_dsi_lane0_ulp_mode_enter(dsi); | 643 | mtk_dsi_lane0_ulp_mode_enter(dsi); |
582 | mtk_dsi_clk_ulp_mode_enter(dsi); | 644 | mtk_dsi_clk_ulp_mode_enter(dsi); |
583 | 645 | ||
@@ -596,36 +658,30 @@ static void mtk_output_dsi_enable(struct mtk_dsi *dsi) | |||
596 | if (dsi->enabled) | 658 | if (dsi->enabled) |
597 | return; | 659 | return; |
598 | 660 | ||
599 | if (dsi->panel) { | ||
600 | if (drm_panel_prepare(dsi->panel)) { | ||
601 | DRM_ERROR("failed to setup the panel\n"); | ||
602 | return; | ||
603 | } | ||
604 | } | ||
605 | |||
606 | ret = mtk_dsi_poweron(dsi); | 661 | ret = mtk_dsi_poweron(dsi); |
607 | if (ret < 0) { | 662 | if (ret < 0) { |
608 | DRM_ERROR("failed to power on dsi\n"); | 663 | DRM_ERROR("failed to power on dsi\n"); |
609 | return; | 664 | return; |
610 | } | 665 | } |
611 | 666 | ||
612 | mtk_dsi_rxtx_control(dsi); | ||
613 | |||
614 | mtk_dsi_clk_ulp_mode_leave(dsi); | ||
615 | mtk_dsi_lane0_ulp_mode_leave(dsi); | ||
616 | mtk_dsi_clk_hs_mode(dsi, 0); | ||
617 | mtk_dsi_set_mode(dsi); | ||
618 | |||
619 | mtk_dsi_ps_control_vact(dsi); | ||
620 | mtk_dsi_config_vdo_timing(dsi); | ||
621 | mtk_dsi_set_interrupt_enable(dsi); | ||
622 | |||
623 | mtk_dsi_set_mode(dsi); | 667 | mtk_dsi_set_mode(dsi); |
624 | mtk_dsi_clk_hs_mode(dsi, 1); | 668 | mtk_dsi_clk_hs_mode(dsi, 1); |
625 | 669 | ||
626 | mtk_dsi_start(dsi); | 670 | mtk_dsi_start(dsi); |
627 | 671 | ||
672 | if (dsi->panel) { | ||
673 | if (drm_panel_enable(dsi->panel)) { | ||
674 | DRM_ERROR("failed to enable the panel\n"); | ||
675 | goto err_dsi_power_off; | ||
676 | } | ||
677 | } | ||
678 | |||
628 | dsi->enabled = true; | 679 | dsi->enabled = true; |
680 | |||
681 | return; | ||
682 | err_dsi_power_off: | ||
683 | mtk_dsi_stop(dsi); | ||
684 | mtk_dsi_poweroff(dsi); | ||
629 | } | 685 | } |
630 | 686 | ||
631 | static void mtk_output_dsi_disable(struct mtk_dsi *dsi) | 687 | static void mtk_output_dsi_disable(struct mtk_dsi *dsi) |
@@ -640,6 +696,7 @@ static void mtk_output_dsi_disable(struct mtk_dsi *dsi) | |||
640 | } | 696 | } |
641 | } | 697 | } |
642 | 698 | ||
699 | mtk_dsi_stop(dsi); | ||
643 | mtk_dsi_poweroff(dsi); | 700 | mtk_dsi_poweroff(dsi); |
644 | 701 | ||
645 | dsi->enabled = false; | 702 | dsi->enabled = false; |