diff options
author | Thierry Reding <treding@nvidia.com> | 2014-11-13 09:02:46 -0500 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2014-11-13 10:12:23 -0500 |
commit | 337b443d58e2d7d04d23ed07ff61b1243d5f9f2d (patch) | |
tree | ae43d405987adfb06934e52e9ac1e030b23cba04 /drivers/gpu/drm/tegra/dsi.c | |
parent | 563eff1f989917779d8db4c5208e12adcbfcf655 (diff) |
drm/tegra: dsi: Add command mode support
Add support for DC-driven command mode. This is a mode where the video
stream sent by the display controller is packed into DCS command packets
(write_memory_start and write_memory_continue) by the DSI controller. It
can be used for panels with a remote framebuffer and is useful to save
power when used with a dynamic refresh rate (not yet supported by the
driver).
Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/gpu/drm/tegra/dsi.c')
-rw-r--r-- | drivers/gpu/drm/tegra/dsi.c | 82 |
1 files changed, 63 insertions, 19 deletions
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index b91d9e4016bc..50684a4aa4f0 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c | |||
@@ -318,6 +318,21 @@ static const u32 pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = { | |||
318 | [11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4), | 318 | [11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4), |
319 | }; | 319 | }; |
320 | 320 | ||
321 | static const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = { | ||
322 | [ 0] = 0, | ||
323 | [ 1] = 0, | ||
324 | [ 2] = 0, | ||
325 | [ 3] = 0, | ||
326 | [ 4] = 0, | ||
327 | [ 5] = 0, | ||
328 | [ 6] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(3) | PKT_LP, | ||
329 | [ 7] = 0, | ||
330 | [ 8] = 0, | ||
331 | [ 9] = 0, | ||
332 | [10] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(5) | PKT_LP, | ||
333 | [11] = 0, | ||
334 | }; | ||
335 | |||
321 | static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi) | 336 | static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi) |
322 | { | 337 | { |
323 | struct mipi_dphy_timing timing; | 338 | struct mipi_dphy_timing timing; |
@@ -447,9 +462,12 @@ static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe, | |||
447 | if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { | 462 | if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { |
448 | DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n"); | 463 | DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n"); |
449 | pkt_seq = pkt_seq_video_non_burst_sync_pulses; | 464 | pkt_seq = pkt_seq_video_non_burst_sync_pulses; |
450 | } else { | 465 | } else if (dsi->flags & MIPI_DSI_MODE_VIDEO) { |
451 | DRM_DEBUG_KMS("Non-burst video mode with sync events\n"); | 466 | DRM_DEBUG_KMS("Non-burst video mode with sync events\n"); |
452 | pkt_seq = pkt_seq_video_non_burst_sync_events; | 467 | pkt_seq = pkt_seq_video_non_burst_sync_events; |
468 | } else { | ||
469 | DRM_DEBUG_KMS("Command mode\n"); | ||
470 | pkt_seq = pkt_seq_command_mode; | ||
453 | } | 471 | } |
454 | 472 | ||
455 | err = tegra_dsi_get_muldiv(dsi->format, &mul, &div); | 473 | err = tegra_dsi_get_muldiv(dsi->format, &mul, &div); |
@@ -476,7 +494,13 @@ static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe, | |||
476 | value |= DSI_CONTROL_HS_CLK_CTRL; | 494 | value |= DSI_CONTROL_HS_CLK_CTRL; |
477 | 495 | ||
478 | value &= ~DSI_CONTROL_TX_TRIG(3); | 496 | value &= ~DSI_CONTROL_TX_TRIG(3); |
479 | value &= ~DSI_CONTROL_DCS_ENABLE; | 497 | |
498 | /* enable DCS commands for command mode */ | ||
499 | if (dsi->flags & MIPI_DSI_MODE_VIDEO) | ||
500 | value &= ~DSI_CONTROL_DCS_ENABLE; | ||
501 | else | ||
502 | value |= DSI_CONTROL_DCS_ENABLE; | ||
503 | |||
480 | value |= DSI_CONTROL_VIDEO_ENABLE; | 504 | value |= DSI_CONTROL_VIDEO_ENABLE; |
481 | value &= ~DSI_CONTROL_HOST_ENABLE; | 505 | value &= ~DSI_CONTROL_HOST_ENABLE; |
482 | tegra_dsi_writel(dsi, value, DSI_CONTROL); | 506 | tegra_dsi_writel(dsi, value, DSI_CONTROL); |
@@ -488,28 +512,48 @@ static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe, | |||
488 | for (i = 0; i < NUM_PKT_SEQ; i++) | 512 | for (i = 0; i < NUM_PKT_SEQ; i++) |
489 | tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i); | 513 | tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i); |
490 | 514 | ||
491 | /* horizontal active pixels */ | 515 | if (dsi->flags & MIPI_DSI_MODE_VIDEO) { |
492 | hact = mode->hdisplay * mul / div; | 516 | /* horizontal active pixels */ |
517 | hact = mode->hdisplay * mul / div; | ||
518 | |||
519 | /* horizontal sync width */ | ||
520 | hsw = (mode->hsync_end - mode->hsync_start) * mul / div; | ||
521 | hsw -= 10; | ||
522 | |||
523 | /* horizontal back porch */ | ||
524 | hbp = (mode->htotal - mode->hsync_end) * mul / div; | ||
525 | hbp -= 14; | ||
526 | |||
527 | /* horizontal front porch */ | ||
528 | hfp = (mode->hsync_start - mode->hdisplay) * mul / div; | ||
529 | hfp -= 8; | ||
493 | 530 | ||
494 | /* horizontal sync width */ | 531 | tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1); |
495 | hsw = (mode->hsync_end - mode->hsync_start) * mul / div; | 532 | tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3); |
496 | hsw -= 10; | 533 | tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5); |
534 | tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7); | ||
497 | 535 | ||
498 | /* horizontal back porch */ | 536 | /* set SOL delay (for non-burst mode only) */ |
499 | hbp = (mode->htotal - mode->hsync_end) * mul / div; | 537 | tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY); |
500 | hbp -= 14; | 538 | } else { |
539 | u16 bytes; | ||
540 | |||
541 | /* 1 byte (DCS command) + pixel data */ | ||
542 | bytes = 1 + mode->hdisplay * mul / div; | ||
501 | 543 | ||
502 | /* horizontal front porch */ | 544 | tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1); |
503 | hfp = (mode->hsync_start - mode->hdisplay) * mul / div; | 545 | tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_2_3); |
504 | hfp -= 8; | 546 | tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_4_5); |
547 | tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_6_7); | ||
505 | 548 | ||
506 | tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1); | 549 | value = MIPI_DCS_WRITE_MEMORY_START << 8 | |
507 | tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3); | 550 | MIPI_DCS_WRITE_MEMORY_CONTINUE; |
508 | tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5); | 551 | tegra_dsi_writel(dsi, value, DSI_DCS_CMDS); |
509 | tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7); | ||
510 | 552 | ||
511 | /* set SOL delay (for non-burst mode only) */ | 553 | value = 8 * mul / div; |
512 | tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY); | 554 | |
555 | tegra_dsi_writel(dsi, value, DSI_SOL_DELAY); | ||
556 | } | ||
513 | 557 | ||
514 | return 0; | 558 | return 0; |
515 | } | 559 | } |