summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c')
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c162
1 files changed, 97 insertions, 65 deletions
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
index 5b0f6627e29b..a80ac82a9625 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*/
@@ -12,6 +12,8 @@
#include <linux/iopoll.h>
+#include <drm/drm_managed.h>
+
#define INTF_TIMING_ENGINE_EN 0x000
#define INTF_CONFIG 0x004
#define INTF_HSYNC_CTL 0x008
@@ -94,11 +96,11 @@
#define INTF_CFG2_DCE_DATA_COMPRESS BIT(12)
-static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
- const struct intf_timing_params *p,
- const struct dpu_format *fmt)
+static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *intf,
+ const struct dpu_hw_intf_timing_params *p,
+ const struct msm_format *fmt)
{
- struct dpu_hw_blk_reg_map *c = &ctx->hw;
+ struct dpu_hw_blk_reg_map *c = &intf->hw;
u32 hsync_period, vsync_period;
u32 display_v_start, display_v_end;
u32 hsync_start_x, hsync_end_x;
@@ -116,7 +118,7 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
/* read interface_cfg */
intf_cfg = DPU_REG_READ(c, INTF_CONFIG);
- if (ctx->cap->type == INTF_DP)
+ if (intf->cap->type == INTF_DP)
dp_intf = true;
hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width +
@@ -161,16 +163,25 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
display_hctl = (hsync_end_x << 16) | hsync_start_x;
- /*
- * DATA_HCTL_EN controls data timing which can be different from
- * video timing. It is recommended to enable it for all cases, except
- * if compression is enabled in 1 pixel per clock mode
- */
if (p->wide_bus_en)
- intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN | INTF_CFG2_DATA_HCTL_EN;
+ intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN;
data_width = p->width;
+ /*
+ * If widebus is enabled, data is valid for only half the active window
+ * since the data rate is doubled in this mode. But for the compression
+ * mode in DP case, the p->width is already adjusted in
+ * drm_mode_to_intf_timing_params()
+ */
+ if (p->wide_bus_en && !dp_intf)
+ data_width = p->width >> 1;
+
+ /* TODO: handle DSC+DP case, we only handle DSC+DSI case so far */
+ if (p->compression_en && !dp_intf &&
+ intf->mdss_ver->core_major_ver >= 7)
+ intf_cfg2 |= INTF_CFG2_DCE_DATA_COMPRESS;
+
hsync_data_start_x = hsync_start_x;
hsync_data_end_x = hsync_start_x + data_width - 1;
@@ -197,16 +208,16 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
(p->vsync_polarity << 1) | /* VSYNC Polarity */
(p->hsync_polarity << 0); /* HSYNC Polarity */
- if (!DPU_FORMAT_IS_YUV(fmt))
- panel_format = (fmt->bits[C0_G_Y] |
- (fmt->bits[C1_B_Cb] << 2) |
- (fmt->bits[C2_R_Cr] << 4) |
+ if (!MSM_FORMAT_IS_YUV(fmt))
+ panel_format = (fmt->bpc_g_y |
+ (fmt->bpc_b_cb << 2) |
+ (fmt->bpc_r_cr << 4) |
(0x21 << 8));
else
/* Interface treats all the pixel data in RGB888 format */
- panel_format = (COLOR_8BIT |
- (COLOR_8BIT << 2) |
- (COLOR_8BIT << 4) |
+ panel_format = (BPC8 |
+ (BPC8 << 2) |
+ (BPC8 << 4) |
(0x21 << 8));
DPU_REG_WRITE(c, INTF_HSYNC_CTL, hsync_ctl);
@@ -226,7 +237,15 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
DPU_REG_WRITE(c, INTF_FRAME_LINE_COUNT_EN, 0x3);
DPU_REG_WRITE(c, INTF_CONFIG, intf_cfg);
DPU_REG_WRITE(c, INTF_PANEL_FORMAT, panel_format);
- if (ctx->cap->features & BIT(DPU_DATA_HCTL_EN)) {
+ if (intf->mdss_ver->core_major_ver >= 5) {
+ /*
+ * DATA_HCTL_EN controls data timing which can be different from
+ * video timing. It is recommended to enable it for all cases, except
+ * if compression is enabled in 1 pixel per clock mode
+ */
+ if (!(p->compression_en && !p->wide_bus_en))
+ intf_cfg2 |= INTF_CFG2_DATA_HCTL_EN;
+
DPU_REG_WRITE(c, INTF_CONFIG2, intf_cfg2);
DPU_REG_WRITE(c, INTF_DISPLAY_DATA_HCTL, display_data_hctl);
DPU_REG_WRITE(c, INTF_ACTIVE_DATA_HCTL, active_data_hctl);
@@ -244,7 +263,7 @@ static void dpu_hw_intf_enable_timing_engine(
static void dpu_hw_intf_setup_prg_fetch(
struct dpu_hw_intf *intf,
- const struct intf_prog_fetch *fetch)
+ const struct dpu_hw_intf_prog_fetch *fetch)
{
struct dpu_hw_blk_reg_map *c = &intf->hw;
int fetch_enable;
@@ -286,12 +305,11 @@ static void dpu_hw_intf_bind_pingpong_blk(
static void dpu_hw_intf_get_status(
struct dpu_hw_intf *intf,
- struct intf_status *s)
+ struct dpu_hw_intf_status *s)
{
struct dpu_hw_blk_reg_map *c = &intf->hw;
- unsigned long cap = intf->cap->features;
- if (cap & BIT(DPU_INTF_STATUS_SUPPORTED))
+ if (intf->mdss_ver->core_major_ver >= 5)
s->is_en = DPU_REG_READ(c, INTF_STATUS) & BIT(0);
else
s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
@@ -318,9 +336,9 @@ static u32 dpu_hw_intf_get_line_count(struct dpu_hw_intf *intf)
return DPU_REG_READ(c, INTF_LINE_COUNT);
}
-static void dpu_hw_intf_setup_misr(struct dpu_hw_intf *intf, bool enable, u32 frame_count)
+static void dpu_hw_intf_setup_misr(struct dpu_hw_intf *intf)
{
- dpu_hw_setup_misr(&intf->hw, INTF_MISR_CTRL, enable, frame_count);
+ dpu_hw_setup_misr(&intf->hw, INTF_MISR_CTRL, 0x1);
}
static int dpu_hw_intf_collect_misr(struct dpu_hw_intf *intf, u32 *misr_value)
@@ -457,7 +475,7 @@ static int dpu_hw_intf_get_vsync_info(struct dpu_hw_intf *intf,
}
static void dpu_hw_intf_vsync_sel(struct dpu_hw_intf *intf,
- u32 vsync_source)
+ enum dpu_vsync_source vsync_source)
{
struct dpu_hw_blk_reg_map *c;
@@ -513,42 +531,32 @@ static void dpu_hw_intf_disable_autorefresh(struct dpu_hw_intf *intf,
}
-static void dpu_hw_intf_enable_compression(struct dpu_hw_intf *ctx)
+static void dpu_hw_intf_program_intf_cmd_cfg(struct dpu_hw_intf *intf,
+ struct dpu_hw_intf_cmd_mode_cfg *cmd_mode_cfg)
{
- u32 intf_cfg2 = DPU_REG_READ(&ctx->hw, INTF_CONFIG2);
-
- intf_cfg2 |= INTF_CFG2_DCE_DATA_COMPRESS;
+ u32 intf_cfg2 = DPU_REG_READ(&intf->hw, INTF_CONFIG2);
- DPU_REG_WRITE(&ctx->hw, INTF_CONFIG2, intf_cfg2);
-}
+ if (cmd_mode_cfg->data_compress)
+ intf_cfg2 |= INTF_CFG2_DCE_DATA_COMPRESS;
-static void _setup_intf_ops(struct dpu_hw_intf_ops *ops,
- unsigned long cap)
-{
- ops->setup_timing_gen = dpu_hw_intf_setup_timing_engine;
- ops->setup_prg_fetch = dpu_hw_intf_setup_prg_fetch;
- ops->get_status = dpu_hw_intf_get_status;
- ops->enable_timing = dpu_hw_intf_enable_timing_engine;
- ops->get_line_count = dpu_hw_intf_get_line_count;
- if (cap & BIT(DPU_INTF_INPUT_CTRL))
- ops->bind_pingpong_blk = dpu_hw_intf_bind_pingpong_blk;
- ops->setup_misr = dpu_hw_intf_setup_misr;
- ops->collect_misr = dpu_hw_intf_collect_misr;
-
- if (cap & BIT(DPU_INTF_TE)) {
- ops->enable_tearcheck = dpu_hw_intf_enable_te;
- ops->disable_tearcheck = dpu_hw_intf_disable_te;
- ops->connect_external_te = dpu_hw_intf_connect_external_te;
- ops->vsync_sel = dpu_hw_intf_vsync_sel;
- ops->disable_autorefresh = dpu_hw_intf_disable_autorefresh;
- }
+ if (cmd_mode_cfg->wide_bus_en)
+ intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN;
- if (cap & BIT(DPU_INTF_DATA_COMPRESS))
- ops->enable_compression = dpu_hw_intf_enable_compression;
+ DPU_REG_WRITE(&intf->hw, INTF_CONFIG2, intf_cfg2);
}
-struct dpu_hw_intf *dpu_hw_intf_init(const struct dpu_intf_cfg *cfg,
- void __iomem *addr)
+/**
+ * dpu_hw_intf_init() - Initializes the INTF driver for the passed
+ * interface catalog entry.
+ * @dev: Corresponding device for devres management
+ * @cfg: interface catalog entry for which driver object is required
+ * @addr: mapped register io address of MDP
+ * @mdss_rev: dpu core's major and minor versions
+ */
+struct dpu_hw_intf *dpu_hw_intf_init(struct drm_device *dev,
+ const struct dpu_intf_cfg *cfg,
+ void __iomem *addr,
+ const struct dpu_mdss_version *mdss_rev)
{
struct dpu_hw_intf *c;
@@ -557,7 +565,7 @@ struct dpu_hw_intf *dpu_hw_intf_init(const struct dpu_intf_cfg *cfg,
return NULL;
}
- c = kzalloc(sizeof(*c), GFP_KERNEL);
+ c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL);
if (!c)
return ERR_PTR(-ENOMEM);
@@ -569,13 +577,37 @@ struct dpu_hw_intf *dpu_hw_intf_init(const struct dpu_intf_cfg *cfg,
*/
c->idx = cfg->id;
c->cap = cfg;
- _setup_intf_ops(&c->ops, c->cap->features);
- return c;
-}
+ c->mdss_ver = mdss_rev;
-void dpu_hw_intf_destroy(struct dpu_hw_intf *intf)
-{
- kfree(intf);
-}
+ c->ops.setup_timing_gen = dpu_hw_intf_setup_timing_engine;
+ c->ops.setup_prg_fetch = dpu_hw_intf_setup_prg_fetch;
+ c->ops.get_status = dpu_hw_intf_get_status;
+ c->ops.enable_timing = dpu_hw_intf_enable_timing_engine;
+ c->ops.get_line_count = dpu_hw_intf_get_line_count;
+ c->ops.setup_misr = dpu_hw_intf_setup_misr;
+ c->ops.collect_misr = dpu_hw_intf_collect_misr;
+
+ if (mdss_rev->core_major_ver >= 5)
+ c->ops.bind_pingpong_blk = dpu_hw_intf_bind_pingpong_blk;
+
+ /* INTF TE is only for DSI interfaces */
+ if (mdss_rev->core_major_ver >= 5 && cfg->type == INTF_DSI) {
+ WARN_ON(!cfg->intr_tear_rd_ptr);
+ c->ops.enable_tearcheck = dpu_hw_intf_enable_te;
+ c->ops.disable_tearcheck = dpu_hw_intf_disable_te;
+ c->ops.connect_external_te = dpu_hw_intf_connect_external_te;
+ c->ops.vsync_sel = dpu_hw_intf_vsync_sel;
+ c->ops.disable_autorefresh = dpu_hw_intf_disable_autorefresh;
+ }
+
+ /* Technically, INTF_CONFIG2 is present for DPU 5.0+, but
+ * we can configure it for DPU 7.0+ since the wide bus and DSC flags
+ * would not be set for DPU < 7.0 anyways
+ */
+ if (mdss_rev->core_major_ver >= 7)
+ c->ops.program_intf_cmd_cfg = dpu_hw_intf_program_intf_cmd_cfg;
+
+ return c;
+}