drm/tegra: dsi: send panel commands while video is running
- When the video stream is active, queue DCS packets as video-mode command packets sent during blanking instead of using host mode, which would stall the display - Wait two frame ends before restoring the registers, so the panel has received and applied the command - Lets the OLED panel change brightness and switch off without stopping the display first
This commit is contained in:
1 parent
be77b6992d
commit
2e86a8e7d7
2 files changed
+43
No files matched your search
@@ -25,6 +25,7 @@
|
|||||||
#include <drm/drm_panel.h>
|
#include <drm/drm_panel.h>
|
||||||
#include <drm/drm_print.h>
|
#include <drm/drm_print.h>
|
||||||
#include <drm/drm_simple_kms_helper.h>
|
#include <drm/drm_simple_kms_helper.h>
|
||||||
|
#include <drm/drm_vblank.h>
|
||||||
|
|
||||||
#include "dc.h"
|
#include "dc.h"
|
||||||
#include "drm.h"
|
#include "drm.h"
|
||||||
@@ -1345,6 +1346,39 @@ static void tegra_dsi_writesl(struct tegra_dsi *dsi, unsigned long offset,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t tegra_dsi_video_transfer(struct tegra_dsi *dsi,
|
||||||
|
const struct mipi_dsi_packet *packet)
|
||||||
|
{
|
||||||
|
const u8 *header = packet->header;
|
||||||
|
u32 host_control, value;
|
||||||
|
|
||||||
|
host_control = tegra_dsi_readl(dsi, DSI_HOST_CONTROL);
|
||||||
|
|
||||||
|
value = DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_TX_TRIG_SOL |
|
||||||
|
DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC;
|
||||||
|
tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
|
||||||
|
|
||||||
|
value = DSI_VIDEO_MODE_CMD_PKT_ENABLE | DSI_VIDEO_MODE_LINE_TYPE(4);
|
||||||
|
tegra_dsi_writel(dsi, value, DSI_VIDEO_MODE_CONTROL);
|
||||||
|
|
||||||
|
value = header[2] << 16 | header[1] << 8 | header[0];
|
||||||
|
tegra_dsi_writel(dsi, value, DSI_WR_DATA);
|
||||||
|
|
||||||
|
if (packet->payload_length > 0)
|
||||||
|
tegra_dsi_writesl(dsi, DSI_WR_DATA, packet->payload,
|
||||||
|
packet->payload_length);
|
||||||
|
|
||||||
|
if (dsi->output.encoder.crtc) {
|
||||||
|
drm_crtc_wait_one_vblank(dsi->output.encoder.crtc);
|
||||||
|
drm_crtc_wait_one_vblank(dsi->output.encoder.crtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
tegra_dsi_writel(dsi, 0, DSI_VIDEO_MODE_CONTROL);
|
||||||
|
tegra_dsi_writel(dsi, host_control, DSI_HOST_CONTROL);
|
||||||
|
|
||||||
|
return packet->size;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host,
|
static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host,
|
||||||
const struct mipi_dsi_msg *msg)
|
const struct mipi_dsi_msg *msg)
|
||||||
{
|
{
|
||||||
@@ -1365,6 +1399,13 @@ static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host,
|
|||||||
if (packet.size > dsi->video_fifo_depth * 4)
|
if (packet.size > dsi->video_fifo_depth * 4)
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
|
|
||||||
|
if (tegra_dsi_readl(dsi, DSI_CONTROL) & DSI_CONTROL_VIDEO_ENABLE) {
|
||||||
|
if (msg->rx_buf && msg->rx_len > 0)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
return tegra_dsi_video_transfer(dsi, &packet);
|
||||||
|
}
|
||||||
|
|
||||||
tegra_dsi_writel(dsi, DSI_HOST_CONTROL_FIFO_RESET, DSI_HOST_CONTROL);
|
tegra_dsi_writel(dsi, DSI_HOST_CONTROL_FIFO_RESET, DSI_HOST_CONTROL);
|
||||||
usleep_range(10, 20);
|
usleep_range(10, 20);
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,8 @@
|
|||||||
#define DSI_PAD_CONTROL_CD 0x4c
|
#define DSI_PAD_CONTROL_CD 0x4c
|
||||||
#define DSI_PAD_CD_STATUS 0x4d
|
#define DSI_PAD_CD_STATUS 0x4d
|
||||||
#define DSI_VIDEO_MODE_CONTROL 0x4e
|
#define DSI_VIDEO_MODE_CONTROL 0x4e
|
||||||
|
#define DSI_VIDEO_MODE_CMD_PKT_ENABLE (1 << 0)
|
||||||
|
#define DSI_VIDEO_MODE_LINE_TYPE(x) (((x) & 0x7) << 1)
|
||||||
#define DSI_PAD_CONTROL_1 0x4f
|
#define DSI_PAD_CONTROL_1 0x4f
|
||||||
#define DSI_PAD_CONTROL_2 0x50
|
#define DSI_PAD_CONTROL_2 0x50
|
||||||
#define DSI_PAD_OUT_CLK(x) (((x) & 0x7) << 0)
|
#define DSI_PAD_OUT_CLK(x) (((x) & 0x7) << 0)
|
||||||
|
|||||||
Reference in new issue
Block a user