summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2024-03-08 12:45:20 +1000
committerDave Airlie <airlied@redhat.com>2024-03-08 12:45:21 +1000
commitb9511c6d277c31b13d4f3128eba46f4e0733d734 (patch)
tree349e3178134f25ee37957a7f44881d69a9b046c2
parentb0b6739cb9155c4ec6b4c50889313184175e687d (diff)
parent4be445f5b6b6810baf397b2d159bd07c3573fd75 (diff)
downloadlinux-b9511c6d277c31b13d4f3128eba46f4e0733d734.tar.gz
linux-b9511c6d277c31b13d4f3128eba46f4e0733d734.tar.bz2
linux-b9511c6d277c31b13d4f3128eba46f4e0733d734.zip
Merge tag 'drm-msm-next-2024-03-07' of https://gitlab.freedesktop.org/drm/msm into drm-next
Late updates for v6.9, the main part is CDM (YUV over DP) which was waiting for drm-misc-next-2024-02-29. DPU: - Add support for YUV420 over DP - Patchset to ease debugging of vblank timeouts - Small cleanup Signed-off-by: Dave Airlie <airlied@redhat.com> From: Rob Clark <robdclark@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/CAF6AEGvedk6OCOZ-NNtGf_pNiGuK9uvWj1MCDZLX9Jo2nHS=Zg@mail.gmail.com
-rw-r--r--drivers/gpu/drm/msm/Makefile3
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c244
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h26
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h26
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c32
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c100
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c2
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c17
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h10
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c6
-rw-r--r--drivers/gpu/drm/msm/dp/dp_audio.c101
-rw-r--r--drivers/gpu/drm/msm/dp/dp_catalog.c115
-rw-r--r--drivers/gpu/drm/msm/dp/dp_catalog.h9
-rw-r--r--drivers/gpu/drm/msm/dp/dp_ctrl.c17
-rw-r--r--drivers/gpu/drm/msm/dp/dp_display.c82
-rw-r--r--drivers/gpu/drm/msm/dp/dp_drm.c6
-rw-r--r--drivers/gpu/drm/msm/dp/dp_drm.h3
-rw-r--r--drivers/gpu/drm/msm/dp/dp_panel.c53
-rw-r--r--drivers/gpu/drm/msm/dp/dp_panel.h2
-rw-r--r--drivers/gpu/drm/msm/dp/dp_reg.h9
-rw-r--r--drivers/gpu/drm/msm/dp/dp_utils.c96
-rw-r--r--drivers/gpu/drm/msm/dp/dp_utils.h36
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h32
23 files changed, 736 insertions, 291 deletions
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 543e04fa72e3..b21ae2880c71 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -127,7 +127,8 @@ msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
dp/dp_drm.o \
dp/dp_link.o \
dp/dp_panel.o \
- dp/dp_audio.o
+ dp/dp_audio.o \
+ dp/dp_utils.o
msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 194dbb08331d..9a14d2232e4a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -126,6 +126,8 @@ enum dpu_enc_rc_states {
* @base: drm_encoder base class for registration with DRM
* @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes
* @enabled: True if the encoder is active, protected by enc_lock
+ * @commit_done_timedout: True if there has been a timeout on commit after
+ * enabling the encoder.
* @num_phys_encs: Actual number of physical encoders contained.
* @phys_encs: Container of physical encoders managed.
* @cur_master: Pointer to the current master in this mode. Optimization
@@ -172,6 +174,7 @@ struct dpu_encoder_virt {
spinlock_t enc_spinlock;
bool enabled;
+ bool commit_done_timedout;
unsigned int num_phys_encs;
struct dpu_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL];
@@ -218,12 +221,59 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {
15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10
};
+u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc)
+{
+ struct drm_encoder *drm_enc;
+ struct dpu_encoder_virt *dpu_enc;
+ struct drm_display_info *info;
+ struct drm_display_mode *mode;
+
+ drm_enc = phys_enc->parent;
+ dpu_enc = to_dpu_encoder_virt(drm_enc);
+ info = &dpu_enc->connector->display_info;
+ mode = &phys_enc->cached_mode;
+
+ if (drm_mode_is_420_only(info, mode))
+ return DRM_FORMAT_YUV420;
+
+ return DRM_FORMAT_RGB888;
+}
+
+bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc)
+{
+ struct drm_encoder *drm_enc;
+ struct dpu_encoder_virt *dpu_enc;
+ struct msm_display_info *disp_info;
+ struct msm_drm_private *priv;
+ struct drm_display_mode *mode;
+
+ drm_enc = phys_enc->parent;
+ dpu_enc = to_dpu_encoder_virt(drm_enc);
+ disp_info = &dpu_enc->disp_info;
+ priv = drm_enc->dev->dev_private;
+ mode = &phys_enc->cached_mode;
+
+ return phys_enc->hw_intf->cap->type == INTF_DP &&
+ msm_dp_needs_periph_flush(priv->dp[disp_info->h_tile_instance[0]], mode);
+}
bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc)
{
- const struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
+ const struct dpu_encoder_virt *dpu_enc;
+ struct msm_drm_private *priv = drm_enc->dev->dev_private;
+ const struct msm_display_info *disp_info;
+ int index;
- return dpu_enc->wide_bus_en;
+ dpu_enc = to_dpu_encoder_virt(drm_enc);
+ disp_info = &dpu_enc->disp_info;
+ index = disp_info->h_tile_instance[0];
+
+ if (disp_info->intf_type == INTF_DP)
+ return msm_dp_wide_bus_available(priv->dp[index]);
+ else if (disp_info->intf_type == INTF_DSI)
+ return msm_dsi_wide_bus_enabled(priv->dsi[index]);
+
+ return false;
}
bool dpu_encoder_is_dsc_enabled(const struct drm_encoder *drm_enc)
@@ -588,6 +638,7 @@ static int dpu_encoder_virt_atomic_check(
struct dpu_kms *dpu_kms;
struct drm_display_mode *adj_mode;
struct msm_display_topology topology;
+ struct msm_display_info *disp_info;
struct dpu_global_state *global_state;
struct drm_framebuffer *fb;
struct drm_dsc_config *dsc;
@@ -603,6 +654,7 @@ static int dpu_encoder_virt_atomic_check(
DPU_DEBUG_ENC(dpu_enc, "\n");
priv = drm_enc->dev->dev_private;
+ disp_info = &dpu_enc->disp_info;
dpu_kms = to_dpu_kms(priv->kms);
adj_mode = &crtc_state->adjusted_mode;
global_state = dpu_kms_get_global_state(crtc_state->state);
@@ -616,21 +668,24 @@ static int dpu_encoder_virt_atomic_check(
topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode, crtc_state, dsc);
/*
- * Use CDM only for writeback at the moment as other interfaces cannot handle it.
- * if writeback itself cannot handle cdm for some reason it will fail in its atomic_check()
+ * Use CDM only for writeback or DP at the moment as other interfaces cannot handle it.
+ * If writeback itself cannot handle cdm for some reason it will fail in its atomic_check()
* earlier.
*/
- if (dpu_enc->disp_info.intf_type == INTF_WB && conn_state->writeback_job) {
+ if (disp_info->intf_type == INTF_WB && conn_state->writeback_job) {
fb = conn_state->writeback_job->fb;
if (fb && DPU_FORMAT_IS_YUV(to_dpu_format(msm_framebuffer_format(fb))))
topology.needs_cdm = true;
- if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm)
- crtc_state->mode_changed = true;
- else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm)
- crtc_state->mode_changed = true;
+ } else if (disp_info->intf_type == INTF_DP) {
+ if (msm_dp_is_yuv_420_enabled(priv->dp[disp_info->h_tile_instance[0]], adj_mode))
+ topology.needs_cdm = true;
}
+ if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm)
+ crtc_state->mode_changed = true;
+ else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm)
+ crtc_state->mode_changed = true;
/*
* Release and Allocate resources on every modeset
* Dont allocate when active is false.
@@ -1102,7 +1157,8 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
dpu_enc->dsc_mask = dsc_mask;
- if (dpu_enc->disp_info.intf_type == INTF_WB && conn_state->writeback_job) {
+ if ((dpu_enc->disp_info.intf_type == INTF_WB && conn_state->writeback_job) ||
+ dpu_enc->disp_info.intf_type == INTF_DP) {
struct dpu_hw_blk *hw_cdm = NULL;
dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
@@ -1209,26 +1265,20 @@ static void dpu_encoder_virt_atomic_enable(struct drm_encoder *drm_enc,
struct dpu_encoder_virt *dpu_enc = NULL;
int ret = 0;
struct drm_display_mode *cur_mode = NULL;
- struct msm_drm_private *priv = drm_enc->dev->dev_private;
- struct msm_display_info *disp_info;
- int index;
dpu_enc = to_dpu_encoder_virt(drm_enc);
- disp_info = &dpu_enc->disp_info;
- index = disp_info->h_tile_instance[0];
-
dpu_enc->dsc = dpu_encoder_get_dsc_config(drm_enc);
atomic_set(&dpu_enc->frame_done_timeout_cnt, 0);
- if (disp_info->intf_type == INTF_DP)
- dpu_enc->wide_bus_en = msm_dp_wide_bus_available(priv->dp[index]);
- else if (disp_info->intf_type == INTF_DSI)
- dpu_enc->wide_bus_en = msm_dsi_wide_bus_enabled(priv->dsi[index]);
-
mutex_lock(&dpu_enc->enc_lock);
+
+ dpu_enc->commit_done_timedout = false;
+
cur_mode = &dpu_enc->base.crtc->state->adjusted_mode;
+ dpu_enc->wide_bus_en = dpu_encoder_is_widebus_enabled(drm_enc);
+
trace_dpu_enc_enable(DRMID(drm_enc), cur_mode->hdisplay,
cur_mode->vdisplay);
@@ -1282,7 +1332,7 @@ static void dpu_encoder_virt_atomic_disable(struct drm_encoder *drm_enc,
trace_dpu_enc_disable(DRMID(drm_enc));
/* wait for idle */
- dpu_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE);
+ dpu_encoder_wait_for_tx_complete(drm_enc);
dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_PRE_STOP);
@@ -2133,6 +2183,84 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc)
ctl->ops.clear_pending_flush(ctl);
}
+void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc,
+ const struct dpu_format *dpu_fmt,
+ u32 output_type)
+{
+ struct dpu_hw_cdm *hw_cdm;
+ struct dpu_hw_cdm_cfg *cdm_cfg;
+ struct dpu_hw_pingpong *hw_pp;
+ int ret;
+
+ if (!phys_enc)
+ return;
+
+ cdm_cfg = &phys_enc->cdm_cfg;
+ hw_pp = phys_enc->hw_pp;
+ hw_cdm = phys_enc->hw_cdm;
+
+ if (!hw_cdm)
+ return;
+
+ if (!DPU_FORMAT_IS_YUV(dpu_fmt)) {
+ DPU_DEBUG("[enc:%d] cdm_disable fmt:%x\n", DRMID(phys_enc->parent),
+ dpu_fmt->base.pixel_format);
+ if (hw_cdm->ops.bind_pingpong_blk)
+ hw_cdm->ops.bind_pingpong_blk(hw_cdm, PINGPONG_NONE);
+
+ return;
+ }
+
+ memset(cdm_cfg, 0, sizeof(struct dpu_hw_cdm_cfg));
+
+ cdm_cfg->output_width = phys_enc->cached_mode.hdisplay;
+ cdm_cfg->output_height = phys_enc->cached_mode.vdisplay;
+ cdm_cfg->output_fmt = dpu_fmt;
+ cdm_cfg->output_type = output_type;
+ cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
+ CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;
+ cdm_cfg->csc_cfg = &dpu_csc10_rgb2yuv_601l;
+
+ /* enable 10 bit logic */
+ switch (cdm_cfg->output_fmt->chroma_sample) {
+ case DPU_CHROMA_RGB:
+ cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
+ cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
+ break;
+ case DPU_CHROMA_H2V1:
+ cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
+ cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
+ break;
+ case DPU_CHROMA_420:
+ cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
+ cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE;
+ break;
+ case DPU_CHROMA_H1V2:
+ default:
+ DPU_ERROR("[enc:%d] unsupported chroma sampling type\n",
+ DRMID(phys_enc->parent));
+ cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
+ cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
+ break;
+ }
+
+ DPU_DEBUG("[enc:%d] cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n",
+ DRMID(phys_enc->parent), cdm_cfg->output_width,
+ cdm_cfg->output_height, cdm_cfg->output_fmt->base.pixel_format,
+ cdm_cfg->output_type, cdm_cfg->output_bit_depth,
+ cdm_cfg->h_cdwn_type, cdm_cfg->v_cdwn_type);
+
+ if (hw_cdm->ops.enable) {
+ cdm_cfg->pp_id = hw_pp->idx;
+ ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg);
+ if (ret < 0) {
+ DPU_ERROR("[enc:%d] failed to enable CDM; ret:%d\n",
+ DRMID(phys_enc->parent), ret);
+ return;
+ }
+ }
+}
+
#ifdef CONFIG_DEBUG_FS
static int _dpu_encoder_status_show(struct seq_file *s, void *data)
{
@@ -2402,10 +2530,18 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev,
return &dpu_enc->base;
}
-int dpu_encoder_wait_for_event(struct drm_encoder *drm_enc,
- enum msm_event_wait event)
+/**
+ * dpu_encoder_wait_for_commit_done() - Wait for encoder to flush pending state
+ * @drm_enc: encoder pointer
+ *
+ * Wait for hardware to have flushed the current pending changes to hardware at
+ * a vblank or CTL_START. Physical encoders will map this differently depending
+ * on the type: vid mode -> vsync_irq, cmd mode -> CTL_START.
+ *
+ * Return: 0 on success, -EWOULDBLOCK if already signaled, error otherwise
+ */
+int dpu_encoder_wait_for_commit_done(struct drm_encoder *drm_enc)
{
- int (*fn_wait)(struct dpu_encoder_phys *phys_enc) = NULL;
struct dpu_encoder_virt *dpu_enc = NULL;
int i, ret = 0;
@@ -2419,23 +2555,51 @@ int dpu_encoder_wait_for_event(struct drm_encoder *drm_enc,
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
- switch (event) {
- case MSM_ENC_COMMIT_DONE:
- fn_wait = phys->ops.wait_for_commit_done;
- break;
- case MSM_ENC_TX_COMPLETE:
- fn_wait = phys->ops.wait_for_tx_complete;
- break;
- default:
- DPU_ERROR_ENC(dpu_enc, "unknown wait event %d\n",
- event);
- return -EINVAL;
+ if (phys->ops.wait_for_commit_done) {
+ DPU_ATRACE_BEGIN("wait_for_commit_done");
+ ret = phys->ops.wait_for_commit_done(phys);
+ DPU_ATRACE_END("wait_for_commit_done");
+ if (ret == -ETIMEDOUT && !dpu_enc->commit_done_timedout) {
+ dpu_enc->commit_done_timedout = true;
+ msm_disp_snapshot_state(drm_enc->dev);
+ }
+ if (ret)
+ return ret;
}
+ }
+
+ return ret;
+}
+
+/**
+ * dpu_encoder_wait_for_tx_complete() - Wait for encoder to transfer pixels to panel
+ * @drm_enc: encoder pointer
+ *
+ * Wait for the hardware to transfer all the pixels to the panel. Physical
+ * encoders will map this differently depending on the type: vid mode -> vsync_irq,
+ * cmd mode -> pp_done.
+ *
+ * Return: 0 on success, -EWOULDBLOCK if already signaled, error otherwise
+ */
+int dpu_encoder_wait_for_tx_complete(struct drm_encoder *drm_enc)
+{
+ struct dpu_encoder_virt *dpu_enc = NULL;
+ int i, ret = 0;
+
+ if (!drm_enc) {
+ DPU_ERROR("invalid encoder\n");
+ return -EINVAL;
+ }
+ dpu_enc = to_dpu_encoder_virt(drm_enc);
+ DPU_DEBUG_ENC(dpu_enc, "\n");
+
+ for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+ struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
- if (fn_wait) {
- DPU_ATRACE_BEGIN("wait_for_completion_event");
- ret = fn_wait(phys);
- DPU_ATRACE_END("wait_for_completion_event");
+ if (phys->ops.wait_for_tx_complete) {
+ DPU_ATRACE_BEGIN("wait_for_tx_complete");
+ ret = phys->ops.wait_for_tx_complete(phys);
+ DPU_ATRACE_END("wait_for_tx_complete");
if (ret)
return ret;
}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index fe6b1d312a74..76be77e30954 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -93,25 +93,9 @@ void dpu_encoder_kickoff(struct drm_encoder *encoder);
*/
int dpu_encoder_vsync_time(struct drm_encoder *drm_enc, ktime_t *wakeup_time);
-/**
- * dpu_encoder_wait_for_event - Waits for encoder events
- * @encoder: encoder pointer
- * @event: event to wait for
- * MSM_ENC_COMMIT_DONE - Wait for hardware to have flushed the current pending
- * frames to hardware at a vblank or ctl_start
- * Encoders will map this differently depending on the
- * panel type.
- * vid mode -> vsync_irq
- * cmd mode -> ctl_start
- * MSM_ENC_TX_COMPLETE - Wait for the hardware to transfer all the pixels to
- * the panel. Encoders will map this differently
- * depending on the panel type.
- * vid mode -> vsync_irq
- * cmd mode -> pp_done
- * Returns: 0 on success, -EWOULDBLOCK if already signaled, error otherwise
- */
-int dpu_encoder_wait_for_event(struct drm_encoder *drm_encoder,
- enum msm_event_wait event);
+int dpu_encoder_wait_for_commit_done(struct drm_encoder *drm_encoder);
+
+int dpu_encoder_wait_for_tx_complete(struct drm_encoder *drm_encoder);
/*
* dpu_encoder_get_intf_mode - get interface mode of the given encoder
@@ -156,6 +140,10 @@ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc);
*/
int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc);
+/**
+ * dpu_encoder_is_widebus_enabled - return bool value if widebus is enabled
+ * @drm_enc: Pointer to previously created drm encoder structure
+ */
bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc);
/**
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index dd9e3603d120..98d1b64a43e8 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -147,6 +147,7 @@ enum dpu_intr_idx {
* @hw_wb: Hardware interface to the wb registers
* @hw_cdm: Hardware interface to the CDM registers
* @dpu_kms: Pointer to the dpu_kms top level
+ * @cdm_cfg: CDM block config needed to store WB/DP block's CDM configuration
* @cached_mode: DRM mode cached at mode_set time, acted on in enable
* @vblank_ctl_lock: Vblank ctl mutex lock to protect vblank_refcount
* @enabled: Whether the encoder has enabled and running a mode
@@ -177,6 +178,7 @@ struct dpu_encoder_phys {
struct dpu_hw_wb *hw_wb;
struct dpu_hw_cdm *hw_cdm;
struct dpu_kms *dpu_kms;
+ struct dpu_hw_cdm_cfg cdm_cfg;
struct drm_display_mode cached_mode;
struct mutex vblank_ctl_lock;
enum dpu_enc_split_role split_role;
@@ -206,7 +208,6 @@ static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys)
* @wbirq_refcount: Reference count of writeback interrupt
* @wb_done_timeout_cnt: number of wb done irq timeout errors
* @wb_cfg: writeback block config to store fb related details
- * @cdm_cfg: cdm block config needed to store writeback block's CDM configuration
* @wb_conn: backpointer to writeback connector
* @wb_job: backpointer to current writeback job
* @dest: dpu buffer layout for current writeback output buffer
@@ -216,7 +217,6 @@ struct dpu_encoder_phys_wb {
atomic_t wbirq_refcount;
int wb_done_timeout_cnt;
struct dpu_hw_wb_cfg wb_cfg;
- struct dpu_hw_cdm_cfg cdm_cfg;
struct drm_writeback_connector *wb_conn;
struct drm_writeback_job *wb_job;
struct dpu_hw_fmt_layout dest;
@@ -335,6 +335,19 @@ static inline enum dpu_3d_blend_mode dpu_encoder_helper_get_3d_blend_mode(
unsigned int dpu_encoder_helper_get_dsc(struct dpu_encoder_phys *phys_enc);
/**
+ * dpu_encoder_get_drm_fmt - return DRM fourcc format
+ * @phys_enc: Pointer to physical encoder structure
+ */
+u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc);
+
+/**
+ * dpu_encoder_needs_periph_flush - return true if physical encoder requires
+ * peripheral flush
+ * @phys_enc: Pointer to physical encoder structure
+ */
+bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc);
+
+/**
* dpu_encoder_helper_split_config - split display configuration helper function
* This helper function may be used by physical encoders to configure
* the split display related registers.
@@ -375,6 +388,15 @@ int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc,
void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc);
/**
+ * dpu_encoder_helper_phys_setup_cdm - setup chroma down sampling block
+ * @phys_enc: Pointer to physical encoder
+ * @output_type: HDMI/WB
+ */
+void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc,
+ const struct dpu_format *dpu_fmt,
+ u32 output_type);
+
+/**
* dpu_encoder_vblank_callback - Notify virtual encoder of vblank IRQ reception
* @drm_enc: Pointer to drm encoder structure
* @phys_enc: Pointer to physical encoder
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 2aa72b578764..d9e7dbf0499c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -236,7 +236,7 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
struct drm_display_mode mode;
struct dpu_hw_intf_timing_params timing_params = { 0 };
const struct dpu_format *fmt = NULL;
- u32 fmt_fourcc = DRM_FORMAT_RGB888;
+ u32 fmt_fourcc;
unsigned long lock_flags;
struct dpu_hw_intf_cfg intf_cfg = { 0 };
@@ -255,17 +255,21 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
DPU_DEBUG_VIDENC(phys_enc, "enabling mode:\n");
drm_mode_debug_printmodeline(&mode);
- if (phys_enc->split_role != ENC_ROLE_SOLO) {
+ fmt_fourcc = dpu_encoder_get_drm_fmt(phys_enc);
+
+ if (phys_enc->split_role != ENC_ROLE_SOLO || fmt_fourcc == DRM_FORMAT_YUV420) {
mode.hdisplay >>= 1;
mode.htotal >>= 1;
mode.hsync_start >>= 1;
mode.hsync_end >>= 1;
+ mode.hskew >>= 1;
DPU_DEBUG_VIDENC(phys_enc,
- "split_role %d, halve horizontal %d %d %d %d\n",
+ "split_role %d, halve horizontal %d %d %d %d %d\n",
phys_enc->split_role,
mode.hdisplay, mode.htotal,
- mode.hsync_start, mode.hsync_end);
+ mode.hsync_start, mode.hsync_end,
+ mode.hskew);
}
drm_mode_to_intf_timing_params(phys_enc, &mode, &timing_params);
@@ -273,6 +277,8 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
fmt = dpu_get_dpu_format(fmt_fourcc);
DPU_DEBUG_VIDENC(phys_enc, "fmt_fourcc 0x%X\n", fmt_fourcc);
+ if (phys_enc->hw_cdm)
+ intf_cfg.cdm = phys_enc->hw_cdm->idx;
intf_cfg.intf = phys_enc->hw_intf->idx;
intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_VID;
intf_cfg.stream_sel = 0; /* Don't care value for video mode */
@@ -403,8 +409,12 @@ end:
static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc)
{
struct dpu_hw_ctl *ctl;
+ const struct dpu_format *fmt;
+ u32 fmt_fourcc;
ctl = phys_enc->hw_ctl;
+ fmt_fourcc = dpu_encoder_get_drm_fmt(phys_enc);
+ fmt = dpu_get_dpu_format(fmt_fourcc);
DPU_DEBUG_VIDENC(phys_enc, "\n");
@@ -413,6 +423,8 @@ static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc)
dpu_encoder_helper_split_config(phys_enc, phys_enc->hw_intf->idx);
+ dpu_encoder_helper_phys_setup_cdm(phys_enc, fmt, CDM_CDWN_OUTPUT_HDMI);
+
dpu_encoder_phys_vid_setup_timing_engine(phys_enc);
/*
@@ -428,6 +440,16 @@ static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc)
if (ctl->ops.update_pending_flush_merge_3d && phys_enc->hw_pp->merge_3d)
ctl->ops.update_pending_flush_merge_3d(ctl, phys_enc->hw_pp->merge_3d->idx);
+ if (ctl->ops.update_pending_flush_cdm && phys_enc->hw_cdm)
+ ctl->ops.update_pending_flush_cdm(ctl, phys_enc->hw_cdm->idx);
+
+ /*
+ * Peripheral flush must be updated whenever flushing SDP packets is needed.
+ * SDP packets are required for any YUV format (YUV420, YUV422, YUV444).
+ */
+ if (ctl->ops.update_pending_flush_periph && dpu_encoder_needs_periph_flush(phys_enc))
+ ctl->ops.update_pending_flush_periph(ctl, phys_enc->hw_intf->idx);
+
skip_flush:
DPU_DEBUG_VIDENC(phys_enc,
"update pending flush ctl %d intf %d\n",
@@ -480,7 +502,7 @@ static int dpu_encoder_phys_vid_wait_for_commit_done(
(hw_ctl->ops.get_flush_register(hw_ctl) == 0),
msecs_to_jiffies(50));
if (ret <= 0) {
- DPU_ERROR("vblank timeout\n");
+ DPU_ERROR("vblank timeout: %x\n", hw_ctl->ops.get_flush_register(hw_ctl));
return -ETIMEDOUT;
}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
index 8220cd920e6f..1924a2b28e53 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -265,96 +265,6 @@ static void dpu_encoder_phys_wb_setup_ctl(struct dpu_encoder_phys *phys_enc)
}
/**
- * dpu_encoder_helper_phys_setup_cdm - setup chroma down sampling block
- * This API does not handle DPU_CHROMA_H1V2.
- * @phys_enc:Pointer to physical encoder
- */
-static void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc)
-{
- struct dpu_hw_cdm *hw_cdm;
- struct dpu_hw_cdm_cfg *cdm_cfg;
- struct dpu_hw_pingpong *hw_pp;
- struct dpu_encoder_phys_wb *wb_enc;
- const struct msm_format *format;
- const struct dpu_format *dpu_fmt;
- struct drm_writeback_job *wb_job;
- int ret;
-
- if (!phys_enc)
- return;
-
- wb_enc = to_dpu_encoder_phys_wb(phys_enc);
- cdm_cfg = &wb_enc->cdm_cfg;
- hw_pp = phys_enc->hw_pp;
- hw_cdm = phys_enc->hw_cdm;
- wb_job = wb_enc->wb_job;
-
- format = msm_framebuffer_format(wb_enc->wb_job->fb);
- dpu_fmt = dpu_get_dpu_format_ext(format->pixel_format, wb_job->fb->modifier);
-
- if (!hw_cdm)
- return;
-
- if (!DPU_FORMAT_IS_YUV(dpu_fmt)) {
- DPU_DEBUG("[enc:%d] cdm_disable fmt:%x\n", DRMID(phys_enc->parent),
- dpu_fmt->base.pixel_format);
- if (hw_cdm->ops.bind_pingpong_blk)
- hw_cdm->ops.bind_pingpong_blk(hw_cdm, PINGPONG_NONE);
-
- return;
- }
-
- memset(cdm_cfg, 0, sizeof(struct dpu_hw_cdm_cfg));
-
- cdm_cfg->output_width = wb_job->fb->width;
- cdm_cfg->output_height = wb_job->fb->height;
- cdm_cfg->output_fmt = dpu_fmt;
- cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB;
- cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
- CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;
- cdm_cfg->csc_cfg = &dpu_csc10_rgb2yuv_601l;
-
- /* enable 10 bit logic */
- switch (cdm_cfg->output_fmt->chroma_sample) {
- case DPU_CHROMA_RGB:
- cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
- cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
- break;
- case DPU_CHROMA_H2V1:
- cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
- cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
- break;
- case DPU_CHROMA_420:
- cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
- cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE;
- break;
- case DPU_CHROMA_H1V2:
- default:
- DPU_ERROR("[enc:%d] unsupported chroma sampling type\n",
- DRMID(phys_enc->parent));
- cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
- cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
- break;
- }
-
- DPU_DEBUG("[enc:%d] cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n",
- DRMID(phys_enc->parent), cdm_cfg->output_width,
- cdm_cfg->output_height, cdm_cfg->output_fmt->base.pixel_format,
- cdm_cfg->output_type, cdm_cfg->output_bit_depth,
- cdm_cfg->h_cdwn_type, cdm_cfg->v_cdwn_type);
-
- if (hw_cdm->ops.enable) {
- cdm_cfg->pp_id = hw_pp->idx;
- ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg);
- if (ret < 0) {
- DPU_ERROR("[enc:%d] failed to enable CDM; ret:%d\n",
- DRMID(phys_enc->parent), ret);
- return;
- }
- }
-}
-
-/**
* _dpu_encoder_phys_wb_update_flush - flush hardware update
* @phys_enc: Pointer to physical encoder
*/
@@ -409,6 +319,14 @@ static void dpu_encoder_phys_wb_setup(
struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
struct drm_display_mode mode = phys_enc->cached_mode;
struct drm_framebuffer *fb = NULL;
+ struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
+ struct drm_writeback_job *wb_job;
+ const struct msm_format *format;
+ const struct dpu_format *dpu_fmt;
+
+ wb_job = wb_enc->wb_job;
+ format = msm_framebuffer_format(wb_enc->wb_job->fb);
+ dpu_fmt = dpu_get_dpu_format_ext(format->pixel_format, wb_job->fb->modifier);
DPU_DEBUG("[mode_set:%d, \"%s\",%d,%d]\n",
hw_wb->idx - WB_0, mode.name,
@@ -422,7 +340,7 @@ static void dpu_encoder_phys_wb_setup(
dpu_encoder_phys_wb_setup_fb(phys_enc, fb);
- dpu_encoder_helper_phys_setup_cdm(phys_enc);
+ dpu_encoder_helper_phys_setup_cdm(phys_enc, dpu_fmt, CDM_CDWN_OUTPUT_WB);
dpu_encoder_phys_wb_setup_ctl(phys_enc);
}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
index e9cdc7934a49..9016b3ade6bc 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
@@ -186,7 +186,7 @@ static int dpu_hw_cdm_enable(struct dpu_hw_cdm *ctx, struct dpu_hw_cdm_cfg *cdm)
dpu_hw_cdm_setup_cdwn(ctx, cdm);
if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) {
- if (fmt->chroma_sample != DPU_CHROMA_H1V2)
+ if (fmt->chroma_sample == DPU_CHROMA_H1V2)
return -EINVAL; /*unsupported format */
opmode = CDM_HDMI_PACK_OP_MODE_EN;
opmode |= (fmt->chroma_sample << 1);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
index e76565c3e6a4..a06f69d0b257 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
@@ -39,6 +39,7 @@
#define CTL_WB_FLUSH 0x108
#define CTL_INTF_FLUSH 0x110
#define CTL_CDM_FLUSH 0x114
+#define CTL_PERIPH_FLUSH 0x128
#define CTL_INTF_MASTER 0x134
#define CTL_DSPP_n_FLUSH(n) ((0x13C) + ((n) * 4))
@@ -49,6 +50,7 @@
#define MERGE_3D_IDX 23
#define DSC_IDX 22
#define CDM_IDX 26
+#define PERIPH_IDX 30
#define INTF_IDX 31
#define WB_IDX 16
#define DSPP_IDX 29 /* From DPU hw rev 7.x.x */
@@ -151,6 +153,10 @@ static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx)
ctx->pending_dspp_flush_mask[dspp - DSPP_0]);
}
+ if (ctx->pending_flush_mask & BIT(PERIPH_IDX))
+ DPU_REG_WRITE(&ctx->hw, CTL_PERIPH_FLUSH,
+ ctx->pending_periph_flush_mask);
+
if (ctx->pending_flush_mask & BIT(DSC_IDX))
DPU_REG_WRITE(&ctx->hw, CTL_DSC_FLUSH,
ctx->pending_dsc_flush_mask);
@@ -311,6 +317,13 @@ static void dpu_hw_ctl_update_pending_flush_intf_v1(struct dpu_hw_ctl *ctx,
ctx->pending_flush_mask |= BIT(INTF_IDX);
}
+static void dpu_hw_ctl_update_pending_flush_periph_v1(struct dpu_hw_ctl *ctx,
+ enum dpu_intf intf)
+{
+ ctx->pending_periph_flush_mask |= BIT(intf - INTF_0);
+ ctx->pending_flush_mask |= BIT(PERIPH_IDX);
+}
+
static void dpu_hw_ctl_update_pending_flush_merge_3d_v1(struct dpu_hw_ctl *ctx,
enum dpu_merge_3d merge_3d)
{
@@ -680,6 +693,10 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops,
ops->reset_intf_cfg = dpu_hw_ctl_reset_intf_cfg_v1;
ops->update_pending_flush_intf =
dpu_hw_ctl_update_pending_flush_intf_v1;
+
+ op