diff options
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.c | 162 |
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; +} |
