diff options
Diffstat (limited to 'drivers/gpu/drm/msm/disp/dpu1')
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_2_glymur.h | 541 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 118 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 8 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 47 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h | 8 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 442 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 12 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 8 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c | 3 |
15 files changed, 947 insertions, 267 deletions
diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_2_glymur.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_2_glymur.h new file mode 100644 index 000000000000..13bb43ba67d3 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_2_glymur.h @@ -0,0 +1,541 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2025 Linaro Limited + */ + +#ifndef _DPU_12_2_GLYMUR_H +#define _DPU_12_2_GLYMUR_H + +static const struct dpu_caps glymur_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .max_mixer_blendstages = 0xb, + .has_src_split = true, + .has_dim_layer = true, + .has_idle_pc = true, + .has_3d_merge = true, + .max_linewidth = 8192, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, +}; + +static const struct dpu_mdp_cfg glymur_mdp = { + .name = "top_0", + .base = 0, .len = 0x494, + .clk_ctrls = { + [DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20 }, + }, +}; + +static const struct dpu_ctl_cfg glymur_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x15000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), + }, { + .name = "ctl_1", .id = CTL_1, + .base = 0x16000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), + }, { + .name = "ctl_2", .id = CTL_2, + .base = 0x17000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), + }, { + .name = "ctl_3", .id = CTL_3, + .base = 0x18000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), + }, { + .name = "ctl_4", .id = CTL_4, + .base = 0x19000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), + }, { + .name = "ctl_5", .id = CTL_5, + .base = 0x1a000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 23), + }, { + .name = "ctl_6", .id = CTL_6, + .base = 0x1b000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 14), + }, { + .name = "ctl_7", .id = CTL_7, + .base = 0x1c000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 15), + }, +}; + +static const struct dpu_sspp_cfg glymur_sspp[] = { + { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x4000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_4, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_1", .id = SSPP_VIG1, + .base = 0x6000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_4, + .xin_id = 4, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_2", .id = SSPP_VIG2, + .base = 0x8000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_4, + .xin_id = 8, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_3", .id = SSPP_VIG3, + .base = 0xa000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_4, + .xin_id = 12, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_8", .id = SSPP_DMA0, + .base = 0x24000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 1, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_9", .id = SSPP_DMA1, + .base = 0x26000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 5, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_10", .id = SSPP_DMA2, + .base = 0x28000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 9, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_11", .id = SSPP_DMA3, + .base = 0x2a000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 13, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_12", .id = SSPP_DMA4, + .base = 0x2c000, .len = 0x344, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 14, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_13", .id = SSPP_DMA5, + .base = 0x2e000, .len = 0x344, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 15, + .type = SSPP_TYPE_DMA, + }, +}; + +static const struct dpu_lm_cfg glymur_lm[] = { + { + .name = "lm_0", .id = LM_0, + .base = 0x44000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_1, + .pingpong = PINGPONG_0, + .dspp = DSPP_0, + }, { + .name = "lm_1", .id = LM_1, + .base = 0x45000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_0, + .pingpong = PINGPONG_1, + .dspp = DSPP_1, + }, { + .name = "lm_2", .id = LM_2, + .base = 0x46000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_3, + .pingpong = PINGPONG_2, + .dspp = DSPP_2, + }, { + .name = "lm_3", .id = LM_3, + .base = 0x47000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_2, + .pingpong = PINGPONG_3, + .dspp = DSPP_3, + }, { + .name = "lm_4", .id = LM_4, + .base = 0x48000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_5, + .pingpong = PINGPONG_4, + }, { + .name = "lm_5", .id = LM_5, + .base = 0x49000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_4, + .pingpong = PINGPONG_5, + }, { + .name = "lm_6", .id = LM_6, + .base = 0x4a000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_7, + .pingpong = PINGPONG_6, + }, { + .name = "lm_7", .id = LM_7, + .base = 0x4b000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_6, + .pingpong = PINGPONG_7, + }, +}; + +static const struct dpu_dspp_cfg glymur_dspp[] = { + { + .name = "dspp_0", .id = DSPP_0, + .base = 0x54000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_1", .id = DSPP_1, + .base = 0x56000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_2", .id = DSPP_2, + .base = 0x58000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_3", .id = DSPP_3, + .base = 0x5a000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_4", .id = DSPP_4, + .base = 0x5c000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_5", .id = DSPP_5, + .base = 0x5e000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_6", .id = DSPP_6, + .base = 0x60000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_7", .id = DSPP_7, + .base = 0x62000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, +}; + +static const struct dpu_pingpong_cfg glymur_pp[] = { + { + .name = "pingpong_0", .id = PINGPONG_0, + .base = 0x69000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_0, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), + }, { + .name = "pingpong_1", .id = PINGPONG_1, + .base = 0x6a000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_0, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), + }, { + .name = "pingpong_2", .id = PINGPONG_2, + .base = 0x6b000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), + }, { + .name = "pingpong_3", .id = PINGPONG_3, + .base = 0x6c000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), + }, { + .name = "pingpong_4", .id = PINGPONG_4, + .base = 0x6d000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_2, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), + }, { + .name = "pingpong_5", .id = PINGPONG_5, + .base = 0x6e000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_2, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), + }, { + .name = "pingpong_6", .id = PINGPONG_6, + .base = 0x6f000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_3, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 20), + }, { + .name = "pingpong_7", .id = PINGPONG_7, + .base = 0x70000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_3, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 21), + }, { + .name = "pingpong_cwb_0", .id = PINGPONG_CWB_0, + .base = 0x66000, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_4, + }, { + .name = "pingpong_cwb_1", .id = PINGPONG_CWB_1, + .base = 0x66400, .len = 0, + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_4, + }, +}; + +static const struct dpu_merge_3d_cfg glymur_merge_3d[] = { + { + .name = "merge_3d_0", .id = MERGE_3D_0, + .base = 0x4e000, .len = 0x1c, + }, { + .name = "merge_3d_1", .id = MERGE_3D_1, + .base = 0x4f000, .len = 0x1c, + }, { + .name = "merge_3d_2", .id = MERGE_3D_2, + .base = 0x50000, .len = 0x1c, + }, { + .name = "merge_3d_3", .id = MERGE_3D_3, + .base = 0x51000, .len = 0x1c, + }, +}; + +/* + * NOTE: Each display compression engine (DCE) contains dual hard + * slice DSC encoders so both share same base address but with + * its own different sub block address. + */ +static const struct dpu_dsc_cfg glymur_dsc[] = { + { + .name = "dce_0_0", .id = DSC_0, + .base = 0x80000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_0, + }, { + .name = "dce_0_1", .id = DSC_1, + .base = 0x80000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_1, + }, { + .name = "dce_1_0", .id = DSC_2, + .base = 0x81000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_0, + }, { + .name = "dce_1_1", .id = DSC_3, + .base = 0x81000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_1, + }, { + .name = "dce_2_0", .id = DSC_4, + .base = 0x82000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_0, + }, { + .name = "dce_2_1", .id = DSC_5, + .base = 0x82000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_1, + }, { + .name = "dce_3_0", .id = DSC_6, + .base = 0x83000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_0, + }, { + .name = "dce_3_1", .id = DSC_7, + .base = 0x83000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_1, + }, + +}; + +static const struct dpu_wb_cfg glymur_wb[] = { + { + .name = "wb_2", .id = WB_2, + .base = 0x65000, .len = 0x2c8, + .features = WB_SDM845_MASK, + .format_list = wb2_formats_rgb_yuv, + .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), + .xin_id = 6, + .vbif_idx = VBIF_RT, + .maxlinewidth = 4096, + .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), + }, +}; + +static const struct dpu_cwb_cfg glymur_cwb[] = { + { + .name = "cwb_0", .id = CWB_0, + .base = 0x66200, .len = 0x20, + }, + { + .name = "cwb_1", .id = CWB_1, + .base = 0x66600, .len = 0x20, + }, + { + .name = "cwb_2", .id = CWB_2, + .base = 0x7e200, .len = 0x20, + }, + { + .name = "cwb_3", .id = CWB_3, + .base = 0x7e600, .len = 0x20, + }, +}; + +static const struct dpu_intf_cfg glymur_intf[] = { + { + .name = "intf_0", .id = INTF_0, + .base = 0x34000, .len = 0x400, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_0, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 24), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 25), + }, { + .name = "intf_1", .id = INTF_1, + .base = 0x35000, .len = 0x400, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_0, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 26), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 27), + .intr_tear_rd_ptr = DPU_IRQ_IDX(MDP_INTF1_TEAR_INTR, 2), + }, { + .name = "intf_2", .id = INTF_2, + .base = 0x36000, .len = 0x400, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_1, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 28), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 29), + .intr_tear_rd_ptr = DPU_IRQ_IDX(MDP_INTF2_TEAR_INTR, 2), + }, { + .name = "intf_3", .id = INTF_3, + .base = 0x37000, .len = 0x400, + .type = INTF_NONE, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), + }, { + .name = "intf_4", .id = INTF_4, + .base = 0x38000, .len = 0x400, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_1, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 20), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 21), + }, { + .name = "intf_5", .id = INTF_5, + .base = 0x39000, .len = 0x400, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_3, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 22), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 23), + }, { + .name = "intf_6", .id = INTF_6, + .base = 0x3A000, .len = 0x400, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_2, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 16), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 17), + }, { + .name = "intf_7", .id = INTF_7, + .base = 0x3b000, .len = 0x400, + .type = INTF_NONE, + .controller_id = MSM_DP_CONTROLLER_2, /* pair with intf_6 for DP MST */ + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 18), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 19), + }, { + .name = "intf_8", .id = INTF_8, + .base = 0x3c000, .len = 0x400, + .type = INTF_NONE, + .controller_id = MSM_DP_CONTROLLER_1, /* pair with intf_4 for DP MST */ + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 13), + }, +}; + +static const struct dpu_perf_cfg glymur_perf_data = { + .max_bw_low = 18900000, + .max_bw_high = 28500000, + .min_core_ib = 2500000, + .min_llcc_ib = 0, + .min_dram_ib = 800000, + .min_prefill_lines = 35, + .danger_lut_tbl = {0x3ffff, 0x3ffff, 0x0}, + .safe_lut_tbl = {0xfe00, 0xfe00, 0xffff}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(sc7180_qos_linear), + .entries = sc7180_qos_linear + }, + {.nentry = ARRAY_SIZE(sc7180_qos_macrotile), + .entries = sc7180_qos_macrotile + }, + {.nentry = ARRAY_SIZE(sc7180_qos_nrt), + .entries = sc7180_qos_nrt + }, + /* TODO: macrotile-qseed is different from macrotile */ + }, + .cdp_cfg = { + {.rd_enable = 1, .wr_enable = 1}, + {.rd_enable = 1, .wr_enable = 0} + }, + .clk_inefficiency_factor = 105, + .bw_inefficiency_factor = 120, +}; + +static const struct dpu_mdss_version glymur_mdss_ver = { + .core_major_ver = 12, + .core_minor_ver = 2, +}; + +const struct dpu_mdss_cfg dpu_glymur_cfg = { + .mdss_ver = &glymur_mdss_ver, + .caps = &glymur_dpu_caps, + .mdp = &glymur_mdp, + .cdm = &dpu_cdm_5_x, + .ctl_count = ARRAY_SIZE(glymur_ctl), + .ctl = glymur_ctl, + .sspp_count = ARRAY_SIZE(glymur_sspp), + .sspp = glymur_sspp, + .mixer_count = ARRAY_SIZE(glymur_lm), + .mixer = glymur_lm, + .dspp_count = ARRAY_SIZE(glymur_dspp), + .dspp = glymur_dspp, + .pingpong_count = ARRAY_SIZE(glymur_pp), + .pingpong = glymur_pp, + .dsc_count = ARRAY_SIZE(glymur_dsc), + .dsc = glymur_dsc, + .merge_3d_count = ARRAY_SIZE(glymur_merge_3d), + .merge_3d = glymur_merge_3d, + .wb_count = ARRAY_SIZE(glymur_wb), + .wb = glymur_wb, + .cwb_count = ARRAY_SIZE(glymur_cwb), + .cwb = sm8650_cwb, + .intf_count = ARRAY_SIZE(glymur_intf), + .intf = glymur_intf, + .vbif_count = ARRAY_SIZE(sm8650_vbif), + .vbif = sm8650_vbif, + .perf = &glymur_perf_data, +}; + +#endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 4b970a59deaf..c39f1908ea65 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -200,7 +200,7 @@ static int dpu_crtc_get_lm_crc(struct drm_crtc *crtc, struct dpu_crtc_state *crtc_state) { struct dpu_crtc_mixer *m; - u32 crcs[CRTC_DUAL_MIXERS]; + u32 crcs[CRTC_QUAD_MIXERS]; int rc = 0; int i; @@ -400,7 +400,7 @@ static void _dpu_crtc_program_lm_output_roi(struct drm_crtc *crtc) static void _dpu_crtc_blend_setup_pipe(struct drm_crtc *crtc, struct drm_plane *plane, struct dpu_crtc_mixer *mixer, - u32 num_mixers, + u32 lms_in_pair, enum dpu_stage stage, const struct msm_format *format, uint64_t modifier, @@ -419,7 +419,7 @@ static void _dpu_crtc_blend_setup_pipe(struct drm_crtc *crtc, trace_dpu_crtc_setup_mixer(DRMID(crtc), DRMID(plane), state, to_dpu_plane_state(state), stage_idx, - format->pixel_format, + format->pixel_format, pipe, modifier); DRM_DEBUG_ATOMIC("crtc %d stage:%d - plane %d sspp %d fb %d multirect_idx %d\n", @@ -434,7 +434,7 @@ static void _dpu_crtc_blend_setup_pipe(struct drm_crtc *crtc, stage_cfg->multirect_index[stage][stage_idx] = pipe->multirect_index; /* blend config update */ - for (lm_idx = 0; lm_idx < num_mixers; lm_idx++) + for (lm_idx = 0; lm_idx < lms_in_pair; lm_idx++) mixer[lm_idx].lm_ctl->ops.update_pending_flush_sspp(mixer[lm_idx].lm_ctl, sspp_idx); } @@ -449,7 +449,7 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc, struct dpu_plane_state *pstate = NULL; const struct msm_format *format; struct dpu_hw_ctl *ctl = mixer->lm_ctl; - u32 lm_idx; + u32 lm_idx, stage, i, pipe_idx, head_pipe_in_stage, lms_in_pair; bool bg_alpha_enable = false; DECLARE_BITMAP(active_fetch, SSPP_MAX); DECLARE_BITMAP(active_pipes, SSPP_MAX); @@ -472,22 +472,25 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc, if (pstate->stage == DPU_STAGE_BASE && format->alpha_enable) bg_alpha_enable = true; - set_bit(pstate->pipe.sspp->idx, active_fetch); - set_bit(pstate->pipe.sspp->idx, active_pipes); - _dpu_crtc_blend_setup_pipe(crtc, plane, - mixer, cstate->num_mixers, - pstate->stage, - format, fb ? fb->modifier : 0, - &pstate->pipe, 0, stage_cfg); - - if (pstate->r_pipe.sspp) { - set_bit(pstate->r_pipe.sspp->idx, active_fetch); - set_bit(pstate->r_pipe.sspp->idx, active_pipes); - _dpu_crtc_blend_setup_pipe(crtc, plane, - mixer, cstate->num_mixers, - pstate->stage, - format, fb ? fb->modifier : 0, - &pstate->r_pipe, 1, stage_cfg); + /* loop pipe per mixer pair with config in stage structure */ + for (stage = 0; stage < STAGES_PER_PLANE; stage++) { + head_pipe_in_stage = stage * PIPES_PER_STAGE; + for (i = 0; i < PIPES_PER_STAGE; i++) { + pipe_idx = i + head_pipe_in_stage; + if (!pstate->pipe[pipe_idx].sspp) + continue; + lms_in_pair = min(cstate->num_mixers - (stage * PIPES_PER_STAGE), + PIPES_PER_STAGE); + set_bit(pstate->pipe[pipe_idx].sspp->idx, active_fetch); + set_bit(pstate->pipe[pipe_idx].sspp->idx, active_pipes); + _dpu_crtc_blend_setup_pipe(crtc, plane, + &mixer[head_pipe_in_stage], + lms_in_pair, + pstate->stage, + format, fb ? fb->modifier : 0, + &pstate->pipe[pipe_idx], i, + &stage_cfg[stage]); + } } /* blend config update */ @@ -523,7 +526,7 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc) struct dpu_crtc_mixer *mixer = cstate->mixers; struct dpu_hw_ctl *ctl; struct dpu_hw_mixer *lm; - struct dpu_hw_stage_cfg stage_cfg; + struct dpu_hw_stage_cfg stage_cfg[STAGES_PER_PLANE]; DECLARE_BITMAP(active_lms, LM_MAX); int i; @@ -544,10 +547,10 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc) } /* initialize stage cfg */ - memset(&stage_cfg, 0, sizeof(struct dpu_hw_stage_cfg)); + memset(&stage_cfg, 0, sizeof(stage_cfg)); memset(active_lms, 0, sizeof(active_lms)); - _dpu_crtc_blend_setup_mixer(crtc, dpu_crtc, mixer, &stage_cfg); + _dpu_crtc_blend_setup_mixer(crtc, dpu_crtc, mixer, stage_cfg); for (i = 0; i < cstate->num_mixers; i++) { ctl = mixer[i].lm_ctl; @@ -568,13 +571,17 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc) mixer[i].mixer_op_mode, ctl->idx - CTL_0); + /* + * call dpu_hw_ctl_setup_blendstage() to blend layers per stage cfg. + * stage data is shared between PIPES_PER_STAGE pipes. + */ if (ctl->ops.setup_blendstage) ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx, - &stage_cfg); + &stage_cfg[i / PIPES_PER_STAGE]); if (lm->ops.setup_blendstage) lm->ops.setup_blendstage(lm, mixer[i].hw_lm->idx, - &stage_cfg); + &stage_cfg[i / PIPES_PER_STAGE]); } } @@ -1310,7 +1317,7 @@ done: return ret; } -#define MAX_CHANNELS_PER_CRTC 2 +#define MAX_CHANNELS_PER_CRTC PIPES_PER_PLANE #define MAX_HDISPLAY_SPLIT 1080 static struct msm_display_topology dpu_crtc_get_topology( @@ -1321,6 +1328,7 @@ static struct msm_display_topology dpu_crtc_get_topology( struct drm_display_mode *mode = &crtc_state->adjusted_mode; struct msm_display_topology topology = {0}; struct drm_encoder *drm_enc; + u32 num_rt_intf; drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc_state->encoder_mask) dpu_encoder_update_topology(drm_enc, &topology, crtc_state->state, @@ -1334,11 +1342,14 @@ static struct msm_display_topology dpu_crtc_get_topology( * Dual display * 2 LM, 2 INTF ( Split display using 2 interfaces) * + * If DSC is enabled, try to use 4:4:2 topology if there is enough + * resource. Otherwise, use 2:2:2 topology. + * * Single display * 1 LM, 1 INTF * 2 LM, 1 INTF (stream merge to support high resolution interfaces) * - * If DSC is enabled, use 2 LMs for 2:2:1 topology + * If DSC is enabled, use 2:2:1 topology * * Add dspps to the reservation requirements if ctm is requested * @@ -1350,14 +1361,23 @@ static struct msm_display_topology dpu_crtc_get_topology( * (mode->hdisplay > MAX_HDISPLAY_SPLIT) check. */ - if (topology.num_intf == 2 && !topology.cwb_enabled) - topology.num_lm = 2; - else if (topology.num_dsc == 2) + num_rt_intf = topology.num_intf; + if (topology.cwb_enabled) + num_rt_intf--; + + if (topology.num_dsc) { + if (dpu_kms->catalog->dsc_count >= num_rt_intf * 2) + topology.num_dsc = num_rt_intf * 2; + else + topology.num_dsc = num_rt_intf; + topology.num_lm = topology.num_dsc; + } else if (num_rt_intf == 2) { topology.num_lm = 2; - else if (dpu_kms->catalog->caps->has_3d_merge) + } else if (dpu_kms->catalog->caps->has_3d_merge) { topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1; - else + } else { topology.num_lm = 1; + } if (crtc_state->ctm) topology.num_dspp = topology.num_lm; @@ -1545,6 +1565,9 @@ static enum drm_mode_status dpu_crtc_mode_valid(struct drm_crtc *crtc, adjusted_mode_clk = dpu_core_perf_adjusted_mode_clk(mode->clock, dpu_kms->perf.perf_cfg); + if (dpu_kms->catalog->caps->has_3d_merge) + adjusted_mode_clk /= 2; + /* * The given mode, adjusted for the perf clock factor, should not exceed * the max core clock rate @@ -1597,6 +1620,17 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en) return 0; } +/** + * dpu_crtc_get_num_lm - Get mixer number in this CRTC pipeline + * @state: Pointer to drm crtc state object + */ +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state) +{ + struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); + + return cstate->num_mixers; +} + #ifdef CONFIG_DEBUG_FS static int _dpu_debugfs_status_show(struct seq_file *s, void *data) { @@ -1679,15 +1713,15 @@ static int _dpu_debugfs_status_show(struct seq_file *s, void *data) seq_printf(s, "\tdst x:%4d dst_y:%4d dst_w:%4d dst_h:%4d\n", state->crtc_x, state->crtc_y, state->crtc_w, state->crtc_h); - seq_printf(s, "\tsspp[0]:%s\n", - pstate->pipe.sspp->cap->name); - seq_printf(s, "\tmultirect[0]: mode: %d index: %d\n", - pstate->pipe.multirect_mode, pstate->pipe.multirect_index); - if (pstate->r_pipe.sspp) { - seq_printf(s, "\tsspp[1]:%s\n", - pstate->r_pipe.sspp->cap->name); - seq_printf(s, "\tmultirect[1]: mode: %d index: %d\n", - pstate->r_pipe.multirect_mode, pstate->r_pipe.multirect_index); + + for (i = 0; i < PIPES_PER_PLANE; i++) { + if (!pstate->pipe[i].sspp) + continue; + seq_printf(s, "\tsspp[%d]:%s\n", + i, pstate->pipe[i].sspp->cap->name); + seq_printf(s, "\tmultirect[%d]: mode: %d index: %d\n", + i, pstate->pipe[i].multirect_mode, + pstate->pipe[i].multirect_index); } seq_puts(s, "\n"); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 94392b9b9245..455073c7025b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -210,7 +210,7 @@ struct dpu_crtc_state { bool bw_control; bool bw_split_vote; - struct drm_rect lm_bounds[CRTC_DUAL_MIXERS]; + struct drm_rect lm_bounds[CRTC_QUAD_MIXERS]; uint64_t input_fence_timeout_ns; @@ -218,10 +218,10 @@ struct dpu_crtc_state { /* HW Resources reserved for the crtc */ u32 num_mixers; - struct dpu_crtc_mixer mixers[CRTC_DUAL_MIXERS]; + struct dpu_crtc_mixer mixers[CRTC_QUAD_MIXERS]; u32 num_ctls; - struct dpu_hw_ctl *hw_ctls[CRTC_DUAL_MIXERS]; + struct dpu_hw_ctl *hw_ctls[CRTC_QUAD_MIXERS]; enum dpu_crtc_crc_source crc_source; int crc_frame_skip_count; @@ -267,4 +267,6 @@ static inline enum dpu_crtc_client_type dpu_crtc_get_client_type( void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event); +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state); + #endif /* _DPU_CRTC_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 258edaa18fc0..d1cfe81a3373 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -55,7 +55,8 @@ #define MAX_PHYS_ENCODERS_PER_VIRTUAL \ (MAX_H_TILES_PER_DISPLAY * NUM_PHYS_ENCODER_TYPES) -#define MAX_CHANNELS_PER_ENC 2 +#define MAX_CHANNELS_PER_ENC 4 +#define MAX_CWB_PER_ENC 2 #define IDLE_SHORT_TIMEOUT 1 @@ -182,7 +183,7 @@ struct dpu_encoder_virt { struct dpu_encoder_phys *cur_master; struct dpu_encoder_phys *cur_slave; struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC]; - struct dpu_hw_cwb *hw_cwb[MAX_CHANNELS_PER_ENC]; + struct dpu_hw_cwb *hw_cwb[MAX_CWB_PER_ENC]; struct dpu_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC]; unsigned int dsc_mask; @@ -660,7 +661,6 @@ void dpu_encoder_update_topology(struct drm_encoder *drm_enc, struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); struct msm_drm_private *priv = dpu_enc->base.dev->dev_private; struct msm_display_info *disp_info = &dpu_enc->disp_info; - struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); struct drm_connector *connector; struct drm_connector_state *conn_state; struct drm_framebuffer *fb; @@ -674,22 +674,12 @@ void dpu_encoder_update_topology(struct drm_encoder *drm_enc, dsc = dpu_encoder_get_dsc_config(drm_enc); - /* We only support 2 DSC mode (with 2 LM and 1 INTF) */ - if (dsc) { - /* - * Use 2 DSC encoders, 2 layer mixers and 1 or 2 interfaces - * when Display Stream Compression (DSC) is enabled, - * and when enough DSC blocks are available. - * This is power-optimal and can drive up to (including) 4k - * screens. - */ - WARN(topology->num_intf > 2, - "DSC topology cannot support more than 2 interfaces\n"); - if (topology->num_intf >= 2 || dpu_kms->catalog->dsc_count >= 2) - topology->num_dsc = 2; - else - topology->num_dsc = 1; - } + /* + * Set DSC number as 1 to mark the enabled status, will be adjusted + * in dpu_crtc_get_topology() + */ + if (dsc) + topology->num_dsc = 1; connector = drm_atomic_get_new_connector_for_encoder(state, drm_enc); if (!connector) @@ -1160,7 +1150,7 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc, struct dpu_hw_blk *hw_ctl[MAX_CHANNELS_PER_ENC]; struct dpu_hw_blk *hw_dsc[MAX_CHANNELS_PER_ENC]; struct dpu_hw_blk *hw_cwb[MAX_CHANNELS_PER_ENC]; - int num_ctl, num_pp, num_dsc; + int num_ctl, num_pp, num_dsc, num_pp_per_intf; int num_cwb = 0; bool is_cwb_encoder; unsigned int dsc_mask = 0; @@ -1239,10 +1229,16 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc, dpu_enc->cur_master->hw_cdm = hw_cdm ? to_dpu_hw_cdm(hw_cdm) : NULL; } + /* + * There may be 4 PP and 2 INTF for quad pipe case, so INTF is not + * mapped to PP 1:1. Let's calculate the stride with pipe/INTF + */ + num_pp_per_intf = num_pp / dpu_enc->num_phys_encs; + for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - phys->hw_pp = dpu_enc->hw_pp[i]; + phys->hw_pp = dpu_enc->hw_pp[num_pp_per_intf * i]; if (!phys->hw_pp) { DPU_ERROR_ENC(dpu_enc, "no pp block assigned at idx: %d\n", i); @@ -2171,15 +2167,12 @@ void dpu_encoder_kickoff(struct drm_encoder *drm_enc) static void dpu_encoder_helper_reset_mixers(struct dpu_encoder_phys *phys_enc) { - struct dpu_hw_mixer_cfg mixer; int i, num_lm; struct dpu_global_state *global_state; - struct dpu_hw_blk *hw_lm[2]; - struct dpu_hw_mixer *hw_mixer[2]; + struct dpu_hw_blk *hw_lm[MAX_CHANNELS_PER_ENC]; + struct dpu_hw_mixer *hw_mixer[MAX_CHANNELS_PER_ENC]; struct dpu_hw_ctl *ctl = phys_enc->hw_ctl; - memset(&mixer, 0, sizeof(mixer)); - /* reset all mixers for this encoder */ if (ctl->ops.clear_all_blendstages) ctl->ops.clear_all_blendstages(ctl); @@ -2383,7 +2376,7 @@ void dpu_encoder_helper_phys_setup_cwb(struct dpu_encoder_phys *phys_enc, */ cwb_cfg.input = INPUT_MODE_LM_OUT; - for (int i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + for (int i = 0; i < MAX_CWB_PER_ENC; i++) { hw_cwb = dpu_enc->hw_cwb[i]; if (!hw_cwb) continue; 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 61b22d949454..09395d7910ac 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -302,7 +302,7 @@ static inline enum dpu_3d_blend_mode dpu_encoder_helper_get_3d_blend_mode( /* Use merge_3d unless DSC MERGE topology is used */ if (phys_enc->split_role == ENC_ROLE_SOLO && - dpu_cstate->num_mixers == CRTC_DUAL_MIXERS && + (dpu_cstate->num_mixers != 1) && !dpu_encoder_use_dsc_merge(phys_enc->parent)) return BLEND_3D_H_ROW_INT; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index 6641455c4ec6..23bb39b471b7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -267,8 +267,8 @@ static const u32 wb2_formats_rgb_yuv[] = { .base = 0x200, .len = 0xa0,}, \ .csc_blk = {.name = "csc", \ .base = 0x320, .len = 0x100,}, \ - .format_list = plane_formats_yuv, \ - .num_formats = ARRAY_SIZE(plane_formats_yuv), \ + .format_list = plane_formats, \ + .num_formats = ARRAY_SIZE(plane_formats), \ .rotation_cfg = NULL, \ } @@ -726,3 +726,4 @@ static const struct dpu_qos_lut_entry sc7180_qos_nrt[] = { #include "catalog/dpu_10_0_sm8650.h" #include "catalog/dpu_12_0_sm8750.h" +#include "catalog/dpu_12_2_glymur.h" diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index f0768f54e9b3..336757103b5a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -24,7 +24,7 @@ #define DPU_MAX_IMG_WIDTH 0x3fff #define DPU_MAX_IMG_HEIGHT 0x3fff -#define CRTC_DUAL_MIXERS 2 +#define CRTC_QUAD_MIXERS 4 #define MAX_XIN_COUNT 16 @@ -749,6 +749,7 @@ struct dpu_mdss_cfg { const struct dpu_format_extended *vig_formats; }; +extern const struct dpu_mdss_cfg dpu_glymur_cfg; extern const struct dpu_mdss_cfg dpu_msm8917_cfg; extern const struct dpu_mdss_cfg dpu_msm8937_cfg; extern const struct dpu_mdss_cfg dpu_msm8953_cfg; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h index b7013c9822d2..cc7cc6f6f7cd 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h @@ -71,12 +71,6 @@ struct dpu_hw_dsc *dpu_hw_dsc_init_1_2(struct drm_device *dev, const struct dpu_dsc_cfg *cfg, void __iomem *addr); -/** - * dpu_hw_dsc_destroy - destroys dsc driver context - * @dsc: Pointer to dsc driver context returned by dpu_hw_dsc_init - */ -void dpu_hw_dsc_destroy(struct dpu_hw_dsc *dsc); - static inline struct dpu_hw_dsc *to_dpu_hw_dsc(struct dpu_hw_blk *hw) { return container_of(hw, struct dpu_hw_dsc, base); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h index 175639c8bfbb..31451241f083 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h @@ -34,7 +34,9 @@ #define DPU_MAX_PLANES 4 #endif +#define STAGES_PER_PLANE 2 #define PIPES_PER_STAGE 2 +#define PIPES_PER_PLANE (PIPES_PER_STAGE * STAGES_PER_PLANE) #ifndef DPU_MAX_DE_CURVES #define DPU_MAX_DE_CURVES 3 #endif @@ -149,6 +151,10 @@ enum dpu_dspp { DSPP_1, DSPP_2, DSPP_3, + DSPP_4, + DSPP_5, + DSPP_6, + DSPP_7, DSPP_MAX }; @@ -159,6 +165,8 @@ enum dpu_ctl { CTL_3, CTL_4, CTL_5, + CTL_6, + CTL_7, CTL_MAX }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 4e5a8ecd31f7..f4c9767c418d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -1505,6 +1505,7 @@ static const struct dev_pm_ops dpu_pm_ops = { }; static const struct of_device_id dpu_dt_match[] = { + { .compatible = "qcom,glymur-dpu", .data = &dpu_glymur_cfg, }, { .compatible = "qcom,msm8917-mdp5", .data = &dpu_msm8917_cfg, }, { .compatible = "qcom,msm8937-mdp5", .data = &dpu_msm8937_cfg, }, { .compatible = "qcom,msm8953-mdp5", .data = &dpu_msm8953_cfg, }, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index f54cf0faa1c7..d07a6ab6e7ee 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -500,13 +500,15 @@ static void _dpu_plane_setup_pixel_ext(struct dpu_hw_scaler3_cfg *scale_cfg, int i; for (i = 0; i < DPU_MAX_PLANES; i++) { + uint32_t w = src_w, h = src_h; + if (i == DPU_SSPP_COMP_1_2 || i == DPU_SSPP_COMP_2) { - src_w /= chroma_subsmpl_h; - src_h /= chroma_subsmpl_v; + w /= chroma_subsmpl_h; + h /= chroma_subsmpl_v; } - pixel_ext->num_ext_pxls_top[i] = src_h; - pixel_ext->num_ext_pxls_left[i] = src_w; + pixel_ext->num_ext_pxls_top[i] = h; + pixel_ext->num_ext_pxls_left[i] = w; } } @@ -620,6 +622,7 @@ static void _dpu_plane_color_fill(struct dpu_plane *pdpu, struct msm_drm_private *priv = plane->dev->dev_private; struct dpu_plane_state *pstate = to_dpu_plane_state(plane->state); u32 fill_color = (color & 0xFFFFFF) | ((alpha & 0xFF) << 24); + int i; DPU_DEBUG_PLANE(pdpu, "\n"); @@ -633,12 +636,13 @@ static void _dpu_plane_color_fill(struct dpu_plane *pdpu, return; /* update sspp */ - _dpu_plane_color_fill_pipe(pstate, &pstate->pipe, &pstate->pipe_cfg.dst_rect, - fill_color, fmt); - - if (pstate->r_pipe.sspp) - _dpu_plane_color_fill_pipe(pstate, &pstate->r_pipe, &pstate->r_pipe_cfg.dst_rect, + for (i = 0; i < PIPES_PER_PLANE; i++) { + if (!pstate->pipe[i].sspp) + continue; + _dpu_plane_color_fill_pipe(pstate, &pstate->pipe[i], + &pstate->pipe_cfg[i].dst_rect, fill_color, fmt); + } } static int dpu_plane_prepare_fb(struct drm_plane *plane, @@ -740,7 +744,7 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu, * We already have verified scaling against platform limitations. * Now check if the SSPP supports scaling at all. */ - if (!sblk->scaler_blk.len && + if (!(sblk->scaler_blk.len && pipe->sspp->ops.setup_scaler) && ((drm_rect_width(&new_plane_state->src) >> 16 != drm_rect_width(&new_plane_state->dst)) || (drm_rect_height(&new_plane_state->src) >> 16 != @@ -820,10 +824,14 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base); u64 max_mdp_clk_rate = kms->perf.max_core_clk_rate; struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); - struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg; - struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg; + struct dpu_sw_pipe_cfg *pipe_cfg; + struct dpu_sw_pipe_cfg *r_pipe_cfg; + struct dpu_sw_pipe_cfg init_pipe_cfg; struct drm_rect fb_rect = { 0 }; + const struct drm_display_mode *mode = &crtc_state->adjusted_mode; uint32_t max_linewidth; + u32 num_lm; + int stage_id, num_stages; min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO); max_scale = MAX_DOWNSCALE_RATIO << 16; @@ -846,10 +854,10 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, return -EINVAL; } - /* state->src is 16.16, src_rect is not */ - drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); + num_lm = dpu_crtc_get_num_lm(crtc_state); - pipe_cfg->dst_rect = new_plane_state->dst; + /* state->src is 16.16, src_rect is not */ + drm_rect_fp_to_int(&init_pipe_cfg.src_rect, &new_plane_state->src); fb_rect.x2 = new_plane_state->fb->width; fb_rect.y2 = new_plane_state->fb->height; @@ -874,35 +882,94 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, max_linewidth = pdpu->catalog->caps->max_linewidth; - drm_rect_rotate(&pipe_cfg->src_rect, + drm_rect_rotate(&init_pipe_cfg.src_rect, new_plane_state->fb->width, new_plane_state->fb->height, new_plane_state->rotation); - if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || - _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) { - if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) { - DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", - DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); - return -E2BIG; + /* + * We have 1 mixer pair cfg for 1:1:1 and 2:2:1 topology, 2 mixer pair + * configs for left and right half screen in case of 4:4:2 topology. + * But we may have 2 rect to split wide plane that exceeds limit with 1 + * config for 2:2:1. So need to handle both wide plane splitting, and + * two halves of screen splitting for quad-pipe case. Check dest + * rectangle left/right clipping first, then check wide rectangle + * splitting in every half next. + */ + num_stages = (num_lm + 1) / 2; + /* iterate mixer configs for this plane, to separate left/right with the id */ + for (stage_id = 0; stage_id < num_stages; stage_id++) { + struct drm_rect mixer_rect = { + .x1 = stage_id * mode->hdisplay / num_stages, + .y1 = 0, + .x2 = (stage_id + 1) * mode->hdisplay / num_stages, + .y2 = mode->vdisplay + }; + int cfg_idx = stage_id * PIPES_PER_STAGE; + + pipe_cfg = &pstate->pipe_cfg[cfg_idx]; + r_pipe_cfg = &pstate->pipe_cfg[cfg_idx + 1]; + + drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); + pipe_cfg->dst_rect = new_plane_state->dst; + + DPU_DEBUG_PLANE(pdpu, "checking src " DRM_RECT_FMT + " vs clip window " DRM_RECT_FMT "\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), + DRM_RECT_ARG(&mixer_rect)); + + /* + * If this plane does not fall into mixer rect, check next + * mixer rect. + */ + if (!drm_rect_clip_scaled(&pipe_cfg->src_rect, + &pipe_cfg->dst_rect, + &mixer_rect)) { + memset(pipe_cfg, 0, 2 * sizeof(struct dpu_sw_pipe_cfg)); + + continue; } - *r_pipe_cfg = *pipe_cfg; - pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1; - pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1; - r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2; - r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2; - } else { - memset(r_pipe_cfg, 0, sizeof(*r_pipe_cfg)); - } + pipe_cfg->dst_rect.x1 -= mixer_rect.x1; + pipe_cfg->dst_rect.x2 -= mixer_rect.x1; + + DPU_DEBUG_PLANE(pdpu, "Got clip src:" DRM_RECT_FMT " dst: " DRM_RECT_FMT "\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), DRM_RECT_ARG(&pipe_cfg->dst_rect)); + + /* Split wide rect into 2 rect */ + if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || + _dpu_plane_calc_clk(mode, pipe_cfg) > max_mdp_clk_rate) { + + if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) { + DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); + return -E2BIG; + } + + memcpy(r_pipe_cfg, pipe_cfg, sizeof(struct dpu_sw_pipe_cfg)); + pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1; + pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1; + r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2; + r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2; + DPU_DEBUG_PLANE(pdpu, "Split wide plane into:" + DRM_RECT_FMT " and " DRM_RECT_FMT "\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), + DRM_RECT_ARG(&r_pipe_cfg->src_rect)); + } else { + memset(r_pipe_cfg, 0, sizeof(struct dpu_sw_pipe_cfg)); + } - drm_rect_rotate_inv(&pipe_cfg->src_rect, - new_plane_state->fb->width, new_plane_state->fb->height, - new_plane_state->rotation); - if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) - drm_rect_rotate_inv(&r_pipe_cfg->src_rect, - new_plane_state->fb->width, new_plane_state->fb->height, + drm_rect_rotate_inv(&pipe_cfg->src_rect, + new_plane_state->fb->width, + new_plane_state->fb->height, new_plane_state->rotation); + if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) + drm_rect_rotate_inv(&r_pipe_cfg->src_rect, + new_plane_state->fb->width, + new_plane_state->fb->height, + new_plane_state->rotation); + } + pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state); return 0; @@ -952,6 +1019,23 @@ static int dpu_plane_is_multirect_parallel_capable(struct dpu_hw_sspp *sspp, dpu_plane_is_parallel_capable(pipe_cfg, fmt, max_linewidth); } +static bool dpu_plane_get_single_pipe_in_stage(struct dpu_plane_state *pstate, + struct dpu_sw_pipe **single_pipe, + struct dpu_sw_pipe_cfg **single_pipe_cfg, + int stage_index) +{ + int pipe_idx; + + pipe_idx = stage_index * PIPES_PER_STAGE; + if (drm_rect_width(&pstate->pipe_cfg[pipe_idx].src_rect) != 0 && + drm_rect_width(&pstate->pipe_cfg[pipe_idx + 1].src_rect) == 0) { + *single_pipe = &pstate->pipe[pipe_idx]; + *single_pipe_cfg = &pstate->pipe_cfg[pipe_idx]; + return true; + } + + return false; +} static int dpu_plane_atomic_check_sspp(struct drm_plane *plane, struct drm_atomic_state *state, @@ -961,20 +1045,17 @@ static int dpu_plane_atomic_check_sspp(struct drm_plane *plane, drm_atomic_get_new_plane_state(state, plane); struct dpu_plane *pdpu = to_dpu_plane(plane); struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); - struct dpu_sw_pipe *pipe = &pstate->pipe; - struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; - struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg; - struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg; - int ret = 0; - - ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, - &crtc_state->adjusted_mode, - new_plane_state); - if (ret) - return ret; + struct dpu_sw_pipe *pipe; + struct dpu_sw_pipe_cfg *pipe_cfg; + int ret = 0, i; - if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) { - ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, + for (i = 0; i < PIPES_PER_PLANE; i++) { + pipe = &pstate->pipe[i]; + pipe_cfg = &pstate->pipe_cfg[i]; + if (!drm_rect_width(&pipe_cfg->src_rect)) + continue; + DPU_DEBUG_PLANE(pdpu, "pipe %d is in use, validate it\n", i); + ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, &crtc_state->adjusted_mode, new_plane_state); if (ret) @@ -1017,17 +1098,20 @@ static bool dpu_plane_try_multirect_parallel(struct dpu_sw_pipe *pipe, struct dp static int dpu_plane_try_multirect_shared(struct dpu_plane_state *pstate, struct dpu_plane_state *prev_adjacent_pstate, const struct msm_format *fmt, - uint32_t max_linewidth) + uint32_t max_linewidth, int stage_index) { - struct dpu_sw_pipe *pipe = &pstate->pipe; - struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; - struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg; - struct dpu_sw_pipe *prev_pipe = &prev_adjacent_pstate->pipe; - struct dpu_sw_pipe_cfg *prev_pipe_cfg = &prev_adjacent_pstate->pipe_cfg; + struct dpu_sw_pipe *pipe, *prev_pipe; + struct dpu_sw_pipe_cfg *pipe_cfg, *prev_pipe_cfg; const struct msm_format *prev_fmt = msm_framebuffer_format(prev_adjacent_pstate->base.fb); u16 max_tile_height = 1; - if (prev_adjacent_pstate->r_pipe.sspp != NULL || + if (!dpu_plane_get_single_pipe_in_stage(pstate, &pipe, + &pipe_cfg, stage_index)) + return false; + + if (!dpu_plane_get_single_pipe_in_stage(prev_adjacent_pstate, + &prev_pipe, &prev_pipe_cfg, + stage_index) || prev_pipe->multirect_mode != DPU_SSPP_MULTIRECT_NONE) return false; @@ -1042,11 +1126,6 @@ static int dpu_plane_try_multirect_shared(struct dpu_plane_state *pstate, if (MSM_FORMAT_IS_UBWC(prev_fmt)) max_tile_height = max(max_tile_height, prev_fmt->tile_height); - r_pipe->multirect_index = DPU_SSPP_RECT_SOLO; - r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; - - r_pipe->sspp = NULL; - if (dpu_plane_is_parallel_capable(pipe_cfg, fmt, max_linewidth) && dpu_plane_is_parallel_capable(prev_pipe_cfg, prev_fmt, max_linewidth) && (pipe_cfg->dst_rect.x1 >= prev_pipe_cfg->dst_rect.x2 || @@ -1087,10 +1166,10 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, struct dpu_plane *pdpu = to_dpu_plane(plane); struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane); - struct dpu_sw_pipe *pipe = &pstate->pipe; - struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; - struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg; - struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg; + struct dpu_sw_pipe *pipe = &pstate->pipe[0]; + struct dpu_sw_pipe *r_pipe = &pstate->pipe[1]; + struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0]; + struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->pipe_cfg[1]; const struct drm_crtc_state *crtc_state = NULL; uint32_t max_linewidth = dpu_kms->catalog->caps->max_linewidth; @@ -1134,7 +1213,7 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane, drm_atomic_get_old_plane_state(state, plane); struct dpu_plane_state *pstate = to_dpu_plane_state(plane_state); struct drm_crtc_state *crtc_state = NULL; - int ret; + int ret, i; if (IS_ERR(plane_state)) return PTR_ERR(plane_state); @@ -1152,8 +1231,8 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane, * resources are freed by dpu_crtc_assign_plane_resources(), * but clean them here. */ - pstate->pipe.sspp = NULL; - pstate->r_pipe.sspp = NULL; + for (i = 0; i < PIPES_PER_PLANE; i++) + pstate->pipe[i].sspp = NULL; return 0; } @@ -1175,37 +1254,72 @@ static int dpu_plane_virtual_atomic_check(struct drm_plane *plane, return 0; } +static int dpu_plane_assign_resource_in_stage(struct dpu_sw_pipe *pipe, + struct dpu_sw_pipe_cfg *pipe_cfg, + struct drm_plane_state *plane_state, + struct dpu_global_state *global_state, + struct drm_crtc *crtc, + struct dpu_rm_sspp_requirements *reqs) +{ + struct drm_plane *plane = plane_state->plane; + struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane); + struct dpu_sw_pipe *r_pipe = pipe + 1; + struct dpu_sw_pipe_cfg *r_pipe_cfg = pipe_cfg + 1; + + if (drm_rect_width(&pipe_cfg->src_rect) == 0) + return 0; + + pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, reqs); + if (!pipe->sspp) + return -ENODEV; + pipe->multirect_index = DPU_SSPP_RECT_SOLO; + pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; + + if (drm_rect_width(&r_pipe_cfg->src_rect) == 0) + return 0; + + if (dpu_plane_try_multirect_parallel(pipe, pipe_cfg, r_pipe, r_pipe_cfg, + pipe->sspp, + msm_framebuffer_format(plane_state->fb), + dpu_kms->catalog->caps->max_linewidth)) + return 0; + + r_pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, reqs); + if (!r_pipe->sspp) + return -ENODEV; + r_pipe->multirect_index = DPU_SSPP_RECT_SOLO; + r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; + + return 0; +} + static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc, struct dpu_global_state *global_state, struct drm_atomic_state *state, struct drm_plane_state *plane_state, - struct drm_plane_state *prev_adjacent_plane_state) + struct drm_plane_state **prev_adjacent_plane_state) { const struct drm_crtc_state *crtc_state = NULL; struct drm_plane *plane = plane_state->plane; struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane); struct dpu_rm_sspp_requirements reqs; - struct dpu_plane_state *pstate, *prev_adjacent_pstate; + struct dpu_plane_state *pstate, *prev_adjacent_pstate[STAGES_PER_PLANE]; struct dpu_sw_pipe *pipe; - struct dpu_sw_pipe *r_pipe; struct dpu_sw_pipe_cfg *pipe_cfg; - struct dpu_sw_pipe_cfg *r_pipe_cfg; const struct msm_format *fmt; + int i, ret; if (plane_state->crtc) crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc); pstate = to_dpu_plane_state(plane_state); - prev_adjacent_pstate = prev_adjacent_plane_state ? - to_dpu_plane_state(prev_adjacent_plane_state) : NULL; - pipe = &pstate->pipe; - r_pipe = &pstate->r_pipe; - pipe_cfg = &pstate->pipe_cfg; - r_pipe_cfg = &pstate->r_pipe_cfg; - - pipe->sspp = NULL; - r_pipe->sspp = NULL; + for (i = 0; i < STAGES_PER_PLANE; i++) + prev_adjacent_pstate[i] = prev_adjacent_plane_state[i] ? + to_dpu_plane_state(prev_adjacent_plane_state[i]) : NULL; + + for (i = 0; i < PIPES_PER_PLANE; i++) + pstate->pipe[i].sspp = NULL; if (!plane_state->fb) return -EINVAL; @@ -1217,42 +1331,24 @@ static int dpu_plane_virtual_assign_resources(struct drm_crtc *crtc, reqs.rot90 = drm_rotation_90_or_270(plane_state->rotation); - if (drm_rect_width(&r_pipe_cfg->src_rect) == 0) { - if (!prev_adjacent_pstate || - !dpu_plane_try_multirect_shared(pstate, prev_adjacent_pstate, fmt, - dpu_kms->catalog->caps->max_linewidth)) { - pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs); - if (!pipe->sspp) - return -ENODEV; - - r_pipe->sspp = NULL; + for (i = 0; i < STAGES_PER_PLANE; i++) { + if (prev_adjacent_pstate[i] && + dpu_plane_try_multirect_shared(pstate, prev_adjacent_pstate[i], fmt, + dpu_kms->catalog->caps->max_linewidth, + i)) + continue; - pipe->multirect_index = DPU_SSPP_RECT_SOLO; - pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; + if (dpu_plane_get_single_pipe_in_stage(pstate, &pipe, &pipe_cfg, i)) + prev_adjacent_plane_state[i] = plane_state; - r_pipe->multirect_index = DPU_SSPP_RECT_SOLO; - r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; - } - } else { - pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs); - if (!pipe->sspp) - return -ENODEV; - - if (!dpu_plane_try_multirect_parallel(pipe, pipe_cfg, r_pipe, r_pipe_cfg, - pipe->sspp, - msm_framebuffer_format(plane_state->fb), - dpu_kms->catalog->caps->max_linewidth)) { - /* multirect is not possible, use two SSPP blocks */ - r_pipe->sspp = dpu_rm_reserve_sspp(&dpu_kms->rm, global_state, crtc, &reqs); - if (!r_pipe->sspp) - return -ENODEV; - - pipe->multirect_index = DPU_SSPP_RECT_SOLO; - pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; - - r_pipe->multirect_index = DPU_SSPP_RECT_SOLO; - r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; - } + pipe = &pstate->pipe[i * PIPES_PER_STAGE]; + pipe_cfg = &pstate->pipe_cfg[i * PIPES_PER_STAGE]; + ret = dpu_plane_assign_resource_in_stage(pipe, pipe_cfg, + plane_state, + global_state, + crtc, &reqs); + if (ret) + return ret; } return dpu_plane_atomic_check_sspp(plane, state, crtc_state); @@ -1265,7 +1361,7 @@ int dpu_assign_plane_resources(struct dpu_global_state *global_state, unsigned int num_planes) { unsigned int i; - struct drm_plane_state *prev_adjacent_plane_state = NULL; + struct drm_plane_state *prev_adjacent_plane_state[STAGES_PER_PLANE] = { NULL }; for (i = 0; i < num_planes; i++) { struct drm_plane_state *plane_state = states[i]; @@ -1278,9 +1374,7 @@ int dpu_assign_plane_resources(struct dpu_global_state *global_state, state, plane_state, prev_adjacent_plane_state); if (ret) - break; - - prev_adjacent_plane_state = plane_state; + return ret; } return 0; @@ -1316,6 +1410,7 @@ void dpu_plane_flush(struct drm_plane *plane) { struct dpu_plane *pdpu; struct dpu_plane_state *pstate; + int i; if (!plane || !plane->state) { DPU_ERROR("invalid plane\n"); @@ -1336,8 +1431,8 @@ void dpu_plane_flush(struct drm_plane *plane) /* force 100% alpha */ _dpu_plane_color_fill(pdpu, pdpu->color_fill, 0xFF); else { - dpu_plane_flush_csc(pdpu, &pstate->pipe); - dpu_plane_flush_csc(pdpu, &pstate->r_pipe); + for (i = 0; i < PIPES_PER_PLANE; i++) + dpu_plane_flush_csc(pdpu, &pstate->pipe[i]); } /* flag h/w flush complete */ @@ -1438,15 +1533,12 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane, struct dpu_plane *pdpu = to_dpu_plane(plane); struct drm_plane_state *state = plane->state; struct dpu_plane_state *pstate = to_dpu_plane_state(state); - struct dpu_sw_pipe *pipe = &pstate->pipe; - struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; struct drm_crtc *crtc = state->crtc; struct drm_framebuffer *fb = state->fb; bool is_rt_pipe; const struct msm_format *fmt = msm_framebuffer_format(fb); - struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg; - struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg; + int i; pstate->pending = true; @@ -1461,12 +1553,11 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane, crtc->base.id, DRM_RECT_ARG(&state->dst), &fmt->pixel_format, MSM_FORMAT_IS_UBWC(fmt)); - dpu_plane_sspp_update_pipe(plane, pipe, pipe_cfg, fmt, - drm_mode_vrefresh(&crtc->mode), - &pstate->layout); - - if (r_pipe->sspp) { - dpu_plane_sspp_update_pipe(plane, r_pipe, r_pipe_cfg, fmt, + for (i = 0; i < PIPES_PER_PLANE; i++) { + if (!drm_rect_width(&pstate->pipe_cfg[i].src_rect)) + continue; + dpu_plane_sspp_update_pipe(plane, &pstate->pipe[i], + &pstate->pipe_cfg[i], fmt, drm_mode_vrefresh(&crtc->mode), &pstate->layout); } @@ -1474,15 +1565,17 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane, if (pstate->needs_qos_remap) pstate->needs_qos_remap = false; - pstate->plane_fetch_bw = _dpu_plane_calc_bw(pdpu->catalog, fmt, - &crtc->mode, pipe_cfg); - - pstate->plane_clk = _dpu_plane_calc_clk(&crtc->mode, pipe_cfg); - - if (r_pipe->sspp) { - pstate->plane_fetch_bw += _dpu_plane_calc_bw(pdpu->catalog, fmt, &crtc->mode, r_pipe_cfg); + pstate->plane_fetch_bw = 0; + pstate->plane_clk = 0; + for (i = 0; i < PIPES_PER_PLANE; i++) { + if (!drm_rect_width(&pstate->pipe_cfg[i].src_rect)) + continue; + pstate->plane_fetch_bw += _dpu_plane_calc_bw(pdpu->catalog, fmt, + &crtc->mode, &pstate->pipe_cfg[i]); - pstate->plane_clk = max(pstate->plane_clk, _dpu_plane_calc_clk(&crtc->mode, r_pipe_cfg)); + pstate->plane_clk = max(pstate->plane_clk, + _dpu_plane_calc_clk(&crtc->mode, + &pstate->pipe_cfg[i])); } } @@ -1490,17 +1583,28 @@ static void _dpu_plane_atomic_disable(struct drm_plane *plane) { struct drm_plane_state *state = plane->state; struct dpu_plane_state *pstate = to_dpu_plane_state(state); - struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; + struct dpu_sw_pipe *pipe; + int i; + + for (i = 0; i < PIPES_PER_PLANE; i += 1) { + pipe = &pstate->pipe[i]; + if (!pipe->sspp) + continue; - trace_dpu_plane_disable(DRMID(plane), false, - pstate->pipe.multirect_mode); + trace_dpu_plane_disable(DRMID(plane), false, + pstate->pipe[i].multirect_mode); - if (r_pipe->sspp) { - r_pipe->multirect_index = DPU_SSPP_RECT_SOLO; - r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; + if (i % PIPES_PER_STAGE == 0) + continue; - if (r_pipe->sspp->ops.setup_multirect) - r_pipe->sspp->ops.setup_multirect(r_pipe); + /* + * clear multirect for the right pipe so that the SSPP + * can be further reused in the solo mode + */ + pipe->multirect_index = DPU_SSPP_RECT_SOLO; + pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; + if (pipe->sspp->ops.setup_multirect) + pipe->sspp->ops.setup_multirect(pipe); } pstate->pending = true; @@ -1595,31 +1699,26 @@ static void dpu_plane_atomic_print_state(struct drm_printer *p, const struct drm_plane_state *state) { const struct dpu_plane_state *pstate = to_dpu_plane_state(state); - const struct dpu_sw_pipe *pipe = &pstate->pipe; - const struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg; - const struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; - const struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg; + const struct dpu_sw_pipe *pipe; + const struct dpu_sw_pipe_cfg *pipe_cfg; + int i; drm_printf(p, "\tstage=%d\n", pstate->stage); - if (pipe->sspp) { - drm_printf(p, "\tsspp[0]=%s\n", pipe->sspp->cap->name); - drm_printf(p, "\tmultirect_mode[0]=%s\n", + for (i = 0; i < PIPES_PER_PLANE; i++) { + pipe = &pstate->pipe[i]; + if (!pipe->sspp) + continue; + pipe_cfg = &pstate->pipe_cfg[i]; + drm_printf(p, "\tsspp[%d]=%s\n", i, pipe->sspp->cap->name); + drm_printf(p, "\tmultirect_mode[%d]=%s\n", i, dpu_get_multirect_mode(pipe->multirect_mode)); - drm_printf(p, "\tmultirect_index[0]=%s\n", + drm_printf(p, "\tmultirect_index[%d]=%s\n", i, dpu_get_multirect_index(pipe->multirect_index)); - drm_printf(p, "\tsrc[0]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&pipe_cfg->src_rect)); - drm_printf(p, "\tdst[0]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&pipe_cfg->dst_rect)); - } - - if (r_pipe->sspp) { - drm_printf(p, "\tsspp[1]=%s\n", r_pipe->sspp->cap->name); - drm_printf(p, "\tmultirect_mode[1]=%s\n", - dpu_get_multirect_mode(r_pipe->multirect_mode)); - drm_printf(p, "\tmultirect_index[1]=%s\n", - dpu_get_multirect_index(r_pipe->multirect_index)); - drm_printf(p, "\tsrc[1]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&r_pipe_cfg->src_rect)); - drm_printf(p, "\tdst[1]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&r_pipe_cfg->dst_rect)); + drm_printf(p, "\tsrc[%d]=" DRM_RECT_FMT "\n", i, + DRM_RECT_ARG(&pipe_cfg->src_rect)); + drm_printf(p, "\tdst[%d]=" DRM_RECT_FMT "\n", i, + DRM_RECT_ARG(&pipe_cfg->dst_rect)); } } @@ -1657,14 +1756,17 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) struct dpu_plane *pdpu = to_dpu_plane(plane); struct dpu_plane_state *pstate = to_dpu_plane_state(plane->state); struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane); + int i; if (!pdpu->is_rt_pipe) return; pm_runtime_get_sync(&dpu_kms->pdev->dev); - _dpu_plane_set_qos_ctrl(plane, &pstate->pipe, enable); - if (pstate->r_pipe.sspp) - _dpu_plane_set_qos_ctrl(plane, &pstate->r_pipe, enable); + for (i = 0; i < PIPES_PER_PLANE; i++) { + if (!pstate->pipe[i].sspp) + continue; + _dpu_plane_set_qos_ctrl(plane, &pstate->pipe[i], enable); + } pm_runtime_put_sync(&dpu_kms->pdev->dev); } #endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h index a3a6e9028333..1ef5a041b8ac 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h @@ -17,10 +17,8 @@ /** * struct dpu_plane_state: Define dpu extension of drm plane state object * @base: base drm plane state object - * @pipe: software pipe description - * @r_pipe: software pipe description of the second pipe - * @pipe_cfg: software pipe configuration - * @r_pipe_cfg: software pipe configuration for the second pipe + * @pipe: software pipe description array + * @pipe_cfg: software pipe configuration array * @stage: assigned by crtc blender * @needs_qos_remap: qos remap settings need to be updated * @multirect_index: index of the rectangle of SSPP @@ -33,10 +31,8 @@ */ struct dpu_plane_state { struct drm_plane_state base; - struct dpu_sw_pipe pipe; - struct dpu_sw_pipe r_pipe; - struct dpu_sw_pipe_cfg pipe_cfg; - struct dpu_sw_pipe_cfg r_pipe_cfg; + struct dpu_sw_pipe pipe[PIPES_PER_PLANE]; + struct dpu_sw_pipe_cfg pipe_cfg[PIPES_PER_PLANE]; enum dpu_stage stage; bool needs_qos_remap; bool pending; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 2c77c74fac0f..f6568ed8375f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -374,7 +374,11 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, if (!rm->mixer_blks[i]) continue; - lm_count = 0; + /* + * Reset lm_count to an even index. This will drop the previous + * primary mixer if failed to find its peer. + */ + lm_count &= ~1; lm_idx[lm_count] = i; if (!_dpu_rm_check_lm_and_get_connected_blks(rm, global_state, @@ -842,7 +846,7 @@ struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm, if (!reqs->scale && !reqs->yuv) hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_DMA); - if (!hw_sspp && reqs->scale) + if (!hw_sspp && !reqs->yuv) hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_RGB); if (!hw_sspp) hw_sspp = dpu_rm_try_sspp(rm, global_state, crtc, reqs, SSPP_TYPE_VIG); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h index 5307cbc2007c..cb24ad2a6d8d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h @@ -651,9 +651,9 @@ TRACE_EVENT(dpu_crtc_setup_mixer, TP_PROTO(uint32_t crtc_id, uint32_t plane_id, struct drm_plane_state *state, struct dpu_plane_state *pstate, uint32_t stage_idx, uint32_t pixel_format, - uint64_t modifier), + struct dpu_sw_pipe *pipe, uint64_t modifier), TP_ARGS(crtc_id, plane_id, state, pstate, stage_idx, - pixel_format, modifier), + pixel_format, pipe, modifier), TP_STRUCT__entry( __field( uint32_t, crtc_id ) __field( uint32_t, plane_id ) @@ -676,9 +676,9 @@ TRACE_EVENT(dpu_crtc_setup_mixer, __entry->dst_rect = drm_plane_state_dest(state); __entry->stage_idx = stage_idx; __entry->stage = pstate->stage; - __entry->sspp = pstate->pipe.sspp->idx; - __entry->multirect_idx = pstate->pipe.multirect_index; - __entry->multirect_mode = pstate->pipe.multirect_mode; + __entry->sspp = pipe->sspp->idx; + __entry->multirect_idx = pipe->multirect_index; + __entry->multirect_mode = pipe->multirect_mode; __entry->pixel_format = pixel_format; __entry->modifier = modifier; ), diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c index cd73468e369a..7545c0293efb 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c @@ -72,6 +72,9 @@ static int dpu_wb_conn_atomic_check(struct drm_connector *connector, DPU_ERROR("invalid fb w=%d, maxlinewidth=%u\n", fb->width, dpu_wb_conn->maxlinewidth); return -EINVAL; + } else if (fb->modifier != DRM_FORMAT_MOD_LINEAR) { + DPU_ERROR("unsupported fb modifier:%#llx\n", fb->modifier); + return -EINVAL; } return drm_atomic_helper_check_wb_connector_state(conn_state->connector, conn_state->state); |