diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 0c0dfb25f01b1..5a7fc4ba365b8 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -85,6 +85,7 @@ msm-display-$(CONFIG_DRM_MSM_DPU) += \ disp/dpu1/dpu_hw_lm.o \ disp/dpu1/dpu_hw_pingpong.o \ disp/dpu1/dpu_hw_sspp.o \ + disp/dpu1/dpu_hw_sspp_v13.o \ disp/dpu1/dpu_hw_dspp.o \ disp/dpu1/dpu_hw_merge3d.o \ disp/dpu1/dpu_hw_top.o \ @@ -142,7 +143,8 @@ msm-display-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \ dp/dp_link.o \ dp/dp_panel.o \ dp/dp_audio.o \ - dp/dp_utils.o + dp/dp_utils.o \ + dp/dp_mst_drm.o msm-display-$(CONFIG_DRM_MSM_HDMI_HDCP) += hdmi/hdmi_hdcp.o diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_0_sm8650.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_0_sm8650.h index 56d3c38c87781..bd8139b5d7112 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_0_sm8650.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_0_sm8650.h @@ -378,7 +378,7 @@ static const struct dpu_intf_cfg sm8650_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .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), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_0_sm8750.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_0_sm8750.h index db8cc2d0112c8..73c19a942d295 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_0_sm8750.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_0_sm8750.h @@ -420,7 +420,7 @@ static const struct dpu_intf_cfg sm8750_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x4bc, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .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), 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 0000000000000..a3b590cca21dc --- /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_DP, + .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_DP, + .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_DP, + .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/catalog/dpu_13_0_kaanapali.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_13_0_kaanapali.h new file mode 100644 index 0000000000000..80c532a78b782 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_13_0_kaanapali.h @@ -0,0 +1,492 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _DPU_13_0_KAANAPALI_H +#define _DPU_13_0_KAANAPALI_H + +static const struct dpu_caps kaanapali_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 kaanapali_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 kaanapali_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x1f000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), + }, { + .name = "ctl_1", .id = CTL_1, + .base = 0x20000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), + }, { + .name = "ctl_2", .id = CTL_2, + .base = 0x21000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), + }, { + .name = "ctl_3", .id = CTL_3, + .base = 0x22000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), + }, { + .name = "ctl_4", .id = CTL_4, + .base = 0x23000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), + }, { + .name = "ctl_5", .id = CTL_5, + .base = 0x24000, .len = 0x1000, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 23), + }, +}; + +static const struct dpu_sspp_cfg kaanapali_sspp[] = { + { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x2b000, .len = 0x84, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_5, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_1", .id = SSPP_VIG1, + .base = 0x34000, .len = 0x84, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_5, + .xin_id = 4, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_2", .id = SSPP_VIG2, + .base = 0x3d000, .len = 0x84, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_5, + .xin_id = 8, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_3", .id = SSPP_VIG3, + .base = 0x46000, .len = 0x84, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_5, + .xin_id = 12, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_8", .id = SSPP_DMA0, + .base = 0x97000, .len = 0x84, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 1, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_9", .id = SSPP_DMA1, + .base = 0xa0000, .len = 0x84, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 5, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_10", .id = SSPP_DMA2, + .base = 0xa9000, .len = 0x84, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 9, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_11", .id = SSPP_DMA3, + .base = 0xb2000, .len = 0x84, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 13, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_12", .id = SSPP_DMA4, + .base = 0xbb000, .len = 0x84, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 14, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_13", .id = SSPP_DMA5, + .base = 0xc4000, .len = 0x84, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 15, + .type = SSPP_TYPE_DMA, + }, +}; + +static const struct dpu_lm_cfg kaanapali_lm[] = { + { + .name = "lm_0", .id = LM_0, + .base = 0x103000, .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 = 0x10b000, .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 = 0x113000, .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 = 0x11b000, .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 = 0x123000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_5, + .pingpong = PINGPONG_4, + }, { + .name = "lm_5", .id = LM_5, + .base = 0x12b000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_4, + .pingpong = PINGPONG_5, + }, { + .name = "lm_6", .id = LM_6, + .base = 0x133000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_7, + .pingpong = PINGPONG_6, + }, { + .name = "lm_7", .id = LM_7, + .base = 0x13b000, .len = 0x400, + .features = MIXER_MSM8998_MASK, + .sblk = &sm8750_lm_sblk, + .lm_pair = LM_6, + .pingpong = PINGPONG_7, + }, +}; + +static const struct dpu_dspp_cfg kaanapali_dspp[] = { + { + .name = "dspp_0", .id = DSPP_0, + .base = 0x105000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_1", .id = DSPP_1, + .base = 0x10d000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_2", .id = DSPP_2, + .base = 0x115000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, { + .name = "dspp_3", .id = DSPP_3, + .base = 0x11d000, .len = 0x1800, + .sblk = &sm8750_dspp_sblk, + }, +}; + +static const struct dpu_pingpong_cfg kaanapali_pp[] = { + { + .name = "pingpong_0", .id = PINGPONG_0, + .base = 0x108000, .len = 0, + .sblk = &kaanapali_pp_sblk, + .merge_3d = MERGE_3D_0, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), + }, { + .name = "pingpong_1", .id = PINGPONG_1, + .base = 0x110000, .len = 0, + .sblk = &kaanapali_pp_sblk, + .merge_3d = MERGE_3D_0, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), + }, { + .name = "pingpong_2", .id = PINGPONG_2, + .base = 0x118000, .len = 0, + .sblk = &kaanapali_pp_sblk, + .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), + }, { + .name = "pingpong_3", .id = PINGPONG_3, + .base = 0x120000, .len = 0, + .sblk = &kaanapali_pp_sblk, + .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), + }, { + .name = "pingpong_4", .id = PINGPONG_4, + .base = 0x128000, .len = 0, + .sblk = &kaanapali_pp_sblk, + .merge_3d = MERGE_3D_2, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), + }, { + .name = "pingpong_5", .id = PINGPONG_5, + .base = 0x130000, .len = 0, + .sblk = &kaanapali_pp_sblk, + .merge_3d = MERGE_3D_2, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), + }, { + .name = "pingpong_6", .id = PINGPONG_6, + .base = 0x138000, .len = 0, + .sblk = &kaanapali_pp_sblk, + .merge_3d = MERGE_3D_3, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 20), + }, { + .name = "pingpong_7", .id = PINGPONG_7, + .base = 0x140000, .len = 0, + .sblk = &kaanapali_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 = 0x169000, .len = 0, + .sblk = &kaanapali_pp_sblk, + .merge_3d = MERGE_3D_4, + }, { + .name = "pingpong_cwb_1", .id = PINGPONG_CWB_1, + .base = 0x169400, .len = 0, + .sblk = &kaanapali_pp_sblk, + .merge_3d = MERGE_3D_4, + }, { + .name = "pingpong_cwb_2", .id = PINGPONG_CWB_2, + .base = 0x16a000, .len = 0, + .sblk = &kaanapali_pp_sblk, + .merge_3d = MERGE_3D_5, + }, { + .name = "pingpong_cwb_3", .id = PINGPONG_CWB_3, + .base = 0x16a400, .len = 0, + .sblk = &kaanapali_pp_sblk, + .merge_3d = MERGE_3D_5, + }, +}; + +static const struct dpu_merge_3d_cfg kaanapali_merge_3d[] = { + { + .name = "merge_3d_0", .id = MERGE_3D_0, + .base = 0x163000, .len = 0x1c, + }, { + .name = "merge_3d_1", .id = MERGE_3D_1, + .base = 0x164000, .len = 0x1c, + }, { + .name = "merge_3d_2", .id = MERGE_3D_2, + .base = 0x165000, .len = 0x1c, + }, { + .name = "merge_3d_3", .id = MERGE_3D_3, + .base = 0x166000, .len = 0x1c, + }, { + .name = "merge_3d_4", .id = MERGE_3D_4, + .base = 0x169700, .len = 0x1c, + }, { + .name = "merge_3d_5", .id = MERGE_3D_5, + .base = 0x16a700, .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 kaanapali_dsc[] = { + { + .name = "dce_0_0", .id = DSC_0, + .base = 0x181000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_0, + }, { + .name = "dce_0_1", .id = DSC_1, + .base = 0x181000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_1, + }, { + .name = "dce_1_0", .id = DSC_2, + .base = 0x183000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_0, + }, { + .name = "dce_1_1", .id = DSC_3, + .base = 0x183000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_1, + }, { + .name = "dce_2_0", .id = DSC_4, + .base = 0x185000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_0, + }, { + .name = "dce_2_1", .id = DSC_5, + .base = 0x185000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_1, + }, { + .name = "dce_3_0", .id = DSC_6, + .base = 0x187000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_0, + }, { + .name = "dce_3_1", .id = DSC_7, + .base = 0x187000, .len = 0x8, + .features = BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &sm8750_dsc_sblk_1, + }, +}; + +static const struct dpu_wb_cfg kaanapali_wb[] = { + { + .name = "wb_2", .id = WB_2, + .base = 0x16e000, .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 kaanapali_cwb[] = { + { + .name = "cwb_0", .id = CWB_0, + .base = 0x169200, .len = 0x20, + }, + { + .name = "cwb_1", .id = CWB_1, + .base = 0x169600, .len = 0x20, + }, + { + .name = "cwb_2", .id = CWB_2, + .base = 0x16a200, .len = 0x20, + }, + { + .name = "cwb_3", .id = CWB_3, + .base = 0x16a600, .len = 0x20, + }, +}; + +static const struct dpu_intf_cfg kaanapali_intf[] = { + { + .name = "intf_0", .id = INTF_0, + .base = 0x18d000, .len = 0x4bc, + .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 = 0x18e000, .len = 0x4bc, + .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 = 0x18f000, .len = 0x4bc, + .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 = 0x190000, .len = 0x4bc, + .type = INTF_DP, + .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), + }, +}; + +static const struct dpu_perf_cfg kaanapali_perf_data = { + .max_bw_low = 21400000, + .max_bw_high = 30200000, + .min_core_ib = 2500000, + .min_llcc_ib = 0, + .min_dram_ib = 800000, + .min_prefill_lines = 35, + .danger_lut_tbl = {0x0ffff, 0x0ffff, 0x0}, + .safe_lut_tbl = {0xff00, 0xff00, 0xffff}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(kaanapali_qos_linear), + .entries = kaanapali_qos_linear + }, + {.nentry = ARRAY_SIZE(kaanapali_qos_macrotile), + .entries = kaanapali_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 kaanapali_mdss_ver = { + .core_major_ver = 13, + .core_minor_ver = 0, +}; + +const struct dpu_mdss_cfg dpu_kaanapali_cfg = { + .mdss_ver = &kaanapali_mdss_ver, + .caps = &kaanapali_dpu_caps, + .mdp = &kaanapali_mdp, + .cdm = &dpu_cdm_13_x, + .ctl_count = ARRAY_SIZE(kaanapali_ctl), + .ctl = kaanapali_ctl, + .sspp_count = ARRAY_SIZE(kaanapali_sspp), + .sspp = kaanapali_sspp, + .mixer_count = ARRAY_SIZE(kaanapali_lm), + .mixer = kaanapali_lm, + .dspp_count = ARRAY_SIZE(kaanapali_dspp), + .dspp = kaanapali_dspp, + .pingpong_count = ARRAY_SIZE(kaanapali_pp), + .pingpong = kaanapali_pp, + .dsc_count = ARRAY_SIZE(kaanapali_dsc), + .dsc = kaanapali_dsc, + .merge_3d_count = ARRAY_SIZE(kaanapali_merge_3d), + .merge_3d = kaanapali_merge_3d, + .wb_count = ARRAY_SIZE(kaanapali_wb), + .wb = kaanapali_wb, + .cwb_count = ARRAY_SIZE(kaanapali_cwb), + .cwb = sm8650_cwb, + .intf_count = ARRAY_SIZE(kaanapali_intf), + .intf = kaanapali_intf, + .vbif_count = ARRAY_SIZE(sm8650_vbif), + .vbif = sm8650_vbif, + .perf = &kaanapali_perf_data, +}; + +#endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h index f91220496082b..b1b03d8b30fa0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h @@ -42,24 +42,19 @@ static const struct dpu_ctl_cfg msm8998_ctl[] = { .name = "ctl_0", .id = CTL_0, .base = 0x1000, .len = 0x94, .features = BIT(DPU_CTL_SPLIT_DISPLAY), - .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), }, { .name = "ctl_1", .id = CTL_1, .base = 0x1200, .len = 0x94, - .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), }, { .name = "ctl_2", .id = CTL_2, .base = 0x1400, .len = 0x94, .features = BIT(DPU_CTL_SPLIT_DISPLAY), - .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), }, { .name = "ctl_3", .id = CTL_3, .base = 0x1600, .len = 0x94, - .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), }, { .name = "ctl_4", .id = CTL_4, .base = 0x1800, .len = 0x94, - .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), }, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_2_sdm660.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_2_sdm660.h index 8f9a097147c02..64df4e80ea43d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_2_sdm660.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_2_sdm660.h @@ -37,24 +37,19 @@ static const struct dpu_ctl_cfg sdm660_ctl[] = { .name = "ctl_0", .id = CTL_0, .base = 0x1000, .len = 0x94, .features = BIT(DPU_CTL_SPLIT_DISPLAY), - .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), }, { .name = "ctl_1", .id = CTL_1, .base = 0x1200, .len = 0x94, - .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), }, { .name = "ctl_2", .id = CTL_2, .base = 0x1400, .len = 0x94, .features = BIT(DPU_CTL_SPLIT_DISPLAY), - .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), }, { .name = "ctl_3", .id = CTL_3, .base = 0x1600, .len = 0x94, - .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), }, { .name = "ctl_4", .id = CTL_4, .base = 0x1800, .len = 0x94, - .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), }, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_3_sdm630.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_3_sdm630.h index 0ad18bd273ff8..b409af8999182 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_3_sdm630.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_3_sdm630.h @@ -36,24 +36,19 @@ static const struct dpu_ctl_cfg sdm630_ctl[] = { .name = "ctl_0", .id = CTL_0, .base = 0x1000, .len = 0x94, .features = BIT(DPU_CTL_SPLIT_DISPLAY), - .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), }, { .name = "ctl_1", .id = CTL_1, .base = 0x1200, .len = 0x94, - .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), }, { .name = "ctl_2", .id = CTL_2, .base = 0x1400, .len = 0x94, .features = BIT(DPU_CTL_SPLIT_DISPLAY), - .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), }, { .name = "ctl_3", .id = CTL_3, .base = 0x1600, .len = 0x94, - .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), }, { .name = "ctl_4", .id = CTL_4, .base = 0x1800, .len = 0x94, - .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), }, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h index 5cc9f55d542b7..1a201cb7746d3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h @@ -258,7 +258,7 @@ static const struct dpu_intf_cfg sdm845_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x6b800, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .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), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h index ae1b2ed96e9f1..adad0114fbb77 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h @@ -317,7 +317,7 @@ static const struct dpu_intf_cfg sm8150_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x6b800, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .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), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_2_sm7150.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_2_sm7150.h index a56c288ac10cd..d81d3c616b3b0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_2_sm7150.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_2_sm7150.h @@ -230,7 +230,7 @@ static const struct dpu_intf_cfg sm7150_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x6b800, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .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), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_3_sm6150.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_3_sm6150.h index 26883f6b66b3e..e65f198db9a78 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_3_sm6150.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_3_sm6150.h @@ -186,7 +186,7 @@ static const struct dpu_intf_cfg sm6150_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x6b800, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .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), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h index 7b8b7a1c2d767..1562b8363f3fa 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h @@ -301,7 +301,7 @@ static const struct dpu_intf_cfg sm8250_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x6b800, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .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), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h index 85aae40c210f3..1d8a32d109905 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h @@ -327,7 +327,7 @@ static const struct dpu_intf_cfg sm8350_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .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), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h index 303d33dc7783a..cd6b4c9954c36 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h @@ -288,7 +288,6 @@ static const struct dpu_dsc_cfg sc8280xp_dsc[] = { }, }; -/* TODO: INTF 3, 8 and 7 are used for MST, marked as INTF_NONE for now */ static const struct dpu_intf_cfg sc8280xp_intf[] = { { .name = "intf_0", .id = INTF_0, @@ -319,8 +318,8 @@ static const struct dpu_intf_cfg sc8280xp_intf[] = { }, { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, - .type = INTF_NONE, - .controller_id = MSM_DP_CONTROLLER_0, + .type = INTF_DP, + .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), @@ -351,16 +350,16 @@ static const struct dpu_intf_cfg sc8280xp_intf[] = { }, { .name = "intf_7", .id = INTF_7, .base = 0x3b000, .len = 0x280, - .type = INTF_NONE, - .controller_id = MSM_DP_CONTROLLER_2, + .type = INTF_DP, + .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 = 0x280, - .type = INTF_NONE, - .controller_id = MSM_DP_CONTROLLER_1, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_1, /* pair with intf_8 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), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h index b09a6af4c474a..f26575d460790 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h @@ -340,7 +340,7 @@ static const struct dpu_intf_cfg sm8450_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .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), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h index 42cf3bd5a12ad..0b78180eca813 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h @@ -316,7 +316,6 @@ static const struct dpu_wb_cfg sa8775p_wb[] = { }, }; -/* TODO: INTF 3, 6, 7 and 8 are used for MST, marked as INTF_NONE for now */ static const struct dpu_intf_cfg sa8775p_intf[] = { { .name = "intf_0", .id = INTF_0, @@ -347,7 +346,7 @@ static const struct dpu_intf_cfg sa8775p_intf[] = { }, { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, - .type = INTF_NONE, + .type = INTF_DP, .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), @@ -363,7 +362,7 @@ static const struct dpu_intf_cfg sa8775p_intf[] = { }, { .name = "intf_6", .id = INTF_6, .base = 0x3A000, .len = 0x280, - .type = INTF_NONE, + .type = INTF_DP, .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, 16), @@ -371,7 +370,7 @@ static const struct dpu_intf_cfg sa8775p_intf[] = { }, { .name = "intf_7", .id = INTF_7, .base = 0x3b000, .len = 0x280, - .type = INTF_NONE, + .type = INTF_DP, .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, 18), @@ -379,7 +378,7 @@ static const struct dpu_intf_cfg sa8775p_intf[] = { }, { .name = "intf_8", .id = INTF_8, .base = 0x3c000, .len = 0x280, - .type = INTF_NONE, + .type = INTF_DP, .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), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h index 465b6460f8754..e83d1d85c4a4b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h @@ -335,7 +335,7 @@ static const struct dpu_intf_cfg sm8550_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .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), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_1_sar2130p.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_1_sar2130p.h index 6caa7d40f3688..7d2458bfafe5d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_1_sar2130p.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_1_sar2130p.h @@ -335,7 +335,7 @@ static const struct dpu_intf_cfg sar2130p_intf[] = { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, .type = INTF_DP, - .controller_id = MSM_DP_CONTROLLER_1, + .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), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h index 7243eebb85f36..d2093e0002e4e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_2_x1e80100.h @@ -304,7 +304,6 @@ static const struct dpu_wb_cfg x1e80100_wb[] = { }, }; -/* TODO: INTF 3, 8 and 7 are used for MST, marked as INTF_NONE for now */ static const struct dpu_intf_cfg x1e80100_intf[] = { { .name = "intf_0", .id = INTF_0, @@ -335,7 +334,7 @@ static const struct dpu_intf_cfg x1e80100_intf[] = { }, { .name = "intf_3", .id = INTF_3, .base = 0x37000, .len = 0x280, - .type = INTF_NONE, + .type = INTF_DP, .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), @@ -367,7 +366,7 @@ static const struct dpu_intf_cfg x1e80100_intf[] = { }, { .name = "intf_7", .id = INTF_7, .base = 0x3b000, .len = 0x280, - .type = INTF_NONE, + .type = INTF_DP, .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), @@ -375,7 +374,7 @@ static const struct dpu_intf_cfg x1e80100_intf[] = { }, { .name = "intf_8", .id = INTF_8, .base = 0x3c000, .len = 0x280, - .type = INTF_NONE, + .type = INTF_DP, .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), diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 2f8156051d9b0..97aca969337fb 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -326,43 +326,39 @@ static void _dpu_crtc_setup_blend_cfg(struct dpu_crtc_mixer *mixer, { struct dpu_hw_mixer *lm = mixer->hw_lm; u32 blend_op; - u32 fg_alpha, bg_alpha, max_alpha; + u32 fg_alpha, bg_alpha; - if (mdss_ver->core_major_ver < 12) { - max_alpha = 0xff; - fg_alpha = pstate->base.alpha >> 8; - } else { - max_alpha = 0x3ff; - fg_alpha = pstate->base.alpha >> 6; - } - bg_alpha = max_alpha - fg_alpha; + fg_alpha = pstate->base.alpha; /* default to opaque blending */ if (pstate->base.pixel_blend_mode == DRM_MODE_BLEND_PIXEL_NONE || !format->alpha_enable) { blend_op = DPU_BLEND_FG_ALPHA_FG_CONST | DPU_BLEND_BG_ALPHA_BG_CONST; + bg_alpha = DRM_BLEND_ALPHA_OPAQUE - fg_alpha; } else if (pstate->base.pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) { blend_op = DPU_BLEND_FG_ALPHA_FG_CONST | DPU_BLEND_BG_ALPHA_FG_PIXEL; - if (fg_alpha != max_alpha) { + if (fg_alpha != DRM_BLEND_ALPHA_OPAQUE) { bg_alpha = fg_alpha; blend_op |= DPU_BLEND_BG_MOD_ALPHA | DPU_BLEND_BG_INV_MOD_ALPHA; } else { + bg_alpha = 0; blend_op |= DPU_BLEND_BG_INV_ALPHA; } } else { /* coverage blending */ blend_op = DPU_BLEND_FG_ALPHA_FG_PIXEL | DPU_BLEND_BG_ALPHA_FG_PIXEL; - if (fg_alpha != max_alpha) { + if (fg_alpha != DRM_BLEND_ALPHA_OPAQUE) { bg_alpha = fg_alpha; blend_op |= DPU_BLEND_FG_MOD_ALPHA | DPU_BLEND_FG_INV_MOD_ALPHA | DPU_BLEND_BG_MOD_ALPHA | DPU_BLEND_BG_INV_MOD_ALPHA; } else { + bg_alpha = 0; blend_op |= DPU_BLEND_BG_INV_ALPHA; } } @@ -400,7 +396,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 +415,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 +430,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 +445,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 +468,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 +522,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 +543,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 +567,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]); } } @@ -812,12 +815,42 @@ static void _dpu_crtc_get_pcc_coeff(struct drm_crtc_state *state, cfg->b.b = CONVERT_S3_15(ctm->matrix[8]); } +static void _dpu_crtc_get_gc_lut(struct drm_crtc_state *state, + struct dpu_hw_gc_lut *gc_lut) +{ + struct drm_color_lut *lut; + int i; + u32 val_even, val_odd; + + lut = (struct drm_color_lut *)state->gamma_lut->data; + + if (!lut) + return; + + /* Pack 1024 10-bit entries in 512 32-bit registers */ + for (i = 0; i < PGC_TBL_LEN; i++) { + val_even = drm_color_lut_extract(lut[i * 2].green, 10); + val_odd = drm_color_lut_extract(lut[i * 2 + 1].green, 10); + gc_lut->c0[i] = val_even | (val_odd << 16); + val_even = drm_color_lut_extract(lut[i * 2].blue, 10); + val_odd = drm_color_lut_extract(lut[i * 2 + 1].blue, 10); + gc_lut->c1[i] = val_even | (val_odd << 16); + val_even = drm_color_lut_extract(lut[i * 2].red, 10); + val_odd = drm_color_lut_extract(lut[i * 2 + 1].red, 10); + gc_lut->c2[i] = val_even | (val_odd << 16); + } + + /* Disable 8-bit rounding mode */ + gc_lut->flags = 0; +} + static void _dpu_crtc_setup_cp_blocks(struct drm_crtc *crtc) { struct drm_crtc_state *state = crtc->state; struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); struct dpu_crtc_mixer *mixer = cstate->mixers; struct dpu_hw_pcc_cfg cfg; + struct dpu_hw_gc_lut *gc_lut; struct dpu_hw_ctl *ctl; struct dpu_hw_dspp *dspp; int i; @@ -830,19 +863,38 @@ static void _dpu_crtc_setup_cp_blocks(struct drm_crtc *crtc) ctl = mixer[i].lm_ctl; dspp = mixer[i].hw_dspp; - if (!dspp || !dspp->ops.setup_pcc) + if (!dspp) continue; - if (!state->ctm) { - dspp->ops.setup_pcc(dspp, NULL); - } else { - _dpu_crtc_get_pcc_coeff(state, &cfg); - dspp->ops.setup_pcc(dspp, &cfg); + if (dspp->ops.setup_pcc) { + if (!state->ctm) { + dspp->ops.setup_pcc(dspp, NULL); + } else { + _dpu_crtc_get_pcc_coeff(state, &cfg); + dspp->ops.setup_pcc(dspp, &cfg); + } + + /* stage config flush mask */ + ctl->ops.update_pending_flush_dspp(ctl, + mixer[i].hw_dspp->idx, DPU_DSPP_PCC); } - /* stage config flush mask */ - ctl->ops.update_pending_flush_dspp(ctl, - mixer[i].hw_dspp->idx, DPU_DSPP_PCC); + if (dspp->ops.setup_gc) { + if (!state->gamma_lut) { + dspp->ops.setup_gc(dspp, NULL); + } else { + gc_lut = kzalloc(sizeof(*gc_lut), GFP_KERNEL); + if (!gc_lut) + continue; + _dpu_crtc_get_gc_lut(state, gc_lut); + dspp->ops.setup_gc(dspp, gc_lut); + kfree(gc_lut); + } + + /* stage config flush mask */ + ctl->ops.update_pending_flush_dspp(ctl, + mixer[i].hw_dspp->idx, DPU_DSPP_GC); + } } } @@ -1310,7 +1362,7 @@ static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state 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( @@ -1340,7 +1392,7 @@ static struct msm_display_topology dpu_crtc_get_topology( * * If DSC is enabled, use 2 LMs for 2:2:1 topology * - * Add dspps to the reservation requirements if ctm is requested + * Add dspps to the reservation requirements if ctm or gamma_lut are requested * * Only hardcode num_lm to 2 for cases where num_intf == 2 and CWB is not * enabled. This is because in cases where CWB is enabled, num_intf will @@ -1359,7 +1411,7 @@ static struct msm_display_topology dpu_crtc_get_topology( else topology.num_lm = 1; - if (crtc_state->ctm) + if (crtc_state->ctm || crtc_state->gamma_lut) topology.num_dspp = topology.num_lm; return topology; @@ -1471,7 +1523,8 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, bool needs_dirtyfb = dpu_crtc_needs_dirtyfb(crtc_state); /* don't reallocate resources if only ACTIVE has beeen changed */ - if (crtc_state->mode_changed || crtc_state->connectors_changed) { + if (crtc_state->mode_changed || crtc_state->connectors_changed || + crtc_state->color_mgmt_changed) { rc = dpu_crtc_assign_resources(crtc, crtc_state); if (rc < 0) return rc; @@ -1682,15 +1735,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"); @@ -1834,8 +1887,16 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, drm_crtc_helper_add(crtc, &dpu_crtc_helper_funcs); - if (dpu_kms->catalog->dspp_count) - drm_crtc_enable_color_mgmt(crtc, 0, true, 0); + if (dpu_kms->catalog->dspp_count) { + const struct dpu_dspp_cfg *dspp = &dpu_kms->catalog->dspp[0]; + + if (dspp->sblk->gc.base) { + drm_mode_crtc_set_gamma_size(crtc, DPU_GAMMA_LUT_SIZE); + drm_crtc_enable_color_mgmt(crtc, 0, true, DPU_GAMMA_LUT_SIZE); + } else { + drm_crtc_enable_color_mgmt(crtc, 0, true, 0); + } + } /* save user friendly CRTC name for later */ snprintf(dpu_crtc->name, DPU_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 777eab5ad844e..d6813107a27df 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -56,6 +56,7 @@ (MAX_H_TILES_PER_DISPLAY * NUM_PHYS_ENCODER_TYPES) #define MAX_CHANNELS_PER_ENC 2 +#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; @@ -1160,7 +1161,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 +1240,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); @@ -1431,18 +1438,21 @@ static void dpu_encoder_virt_atomic_disable(struct drm_encoder *drm_enc, static struct dpu_hw_intf *dpu_encoder_get_intf(const struct dpu_mdss_cfg *catalog, struct dpu_rm *dpu_rm, - enum dpu_intf_type type, u32 controller_id) + struct msm_display_info *disp_info, u32 controller_id) { - int i = 0; + int i = 0, cnt = 0; + int stream_id = disp_info->stream_id; - if (type == INTF_WB) + if (disp_info->intf_type == INTF_WB) return NULL; + DPU_DEBUG("intf_type 0x%x controller_id %d stream_id %d\n", + disp_info->intf_type, controller_id, stream_id); for (i = 0; i < catalog->intf_count; i++) { - if (catalog->intf[i].type == type - && catalog->intf[i].controller_id == controller_id) { - return dpu_rm_get_intf(dpu_rm, catalog->intf[i].id); - } + if (catalog->intf[i].type == disp_info->intf_type && + controller_id == catalog->intf[i].controller_id) + if (cnt++ == stream_id) + return dpu_rm_get_intf(dpu_rm, catalog->intf[i].id); } return NULL; @@ -2171,15 +2181,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_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 +2390,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; @@ -2671,8 +2678,7 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc, i, controller_id, phys_params.split_role); phys_params.hw_intf = dpu_encoder_get_intf(dpu_kms->catalog, &dpu_kms->rm, - disp_info->intf_type, - controller_id); + disp_info, controller_id); if (disp_info->intf_type == INTF_WB && controller_id < WB_MAX) phys_params.hw_wb = dpu_rm_get_wb(&dpu_kms->rm, controller_id); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index ca1ca2e51d7ea..2eb4c39b111c1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -28,6 +28,7 @@ * @h_tile_instance: Controller instance used per tile. Number of elements is * based on num_of_h_tiles * @is_cmd_mode Boolean to indicate if the CMD mode is requested + * @stream_id stream id for which the interface needs to be acquired * @vsync_source: Source of the TE signal for DSI CMD devices */ struct msm_display_info { @@ -35,6 +36,7 @@ struct msm_display_info { uint32_t num_of_h_tiles; uint32_t h_tile_instance[MAX_H_TILES_PER_DISPLAY]; bool is_cmd_mode; + int stream_id; enum dpu_vsync_source vsync_source; }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c index 93db1484f6069..45079ee59cf67 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c @@ -257,6 +257,12 @@ static int dpu_encoder_phys_cmd_control_vblank_irq( if (!dpu_encoder_phys_cmd_is_master(phys_enc)) goto end; + /* IRQ not yet initialized */ + if (!phys_enc->irq[INTR_IDX_RDPTR]) { + ret = -EINVAL; + goto end; + } + /* protect against negative */ if (!enable && refcount == 0) { ret = -EINVAL; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c index b0d585c5315ca..6e8883dbfad43 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c @@ -7,7 +7,6 @@ #include #include -#include "msm_media_info.h" #include "dpu_kms.h" #include "dpu_formats.h" @@ -54,116 +53,90 @@ static void _dpu_get_v_h_subsample_rate( } } -static int _dpu_format_get_media_color_ubwc(const struct msm_format *fmt) -{ - static const struct dpu_media_color_map dpu_media_ubwc_map[] = { - {DRM_FORMAT_ABGR8888, COLOR_FMT_RGBA8888_UBWC}, - {DRM_FORMAT_ARGB8888, COLOR_FMT_RGBA8888_UBWC}, - {DRM_FORMAT_XBGR8888, COLOR_FMT_RGBA8888_UBWC}, - {DRM_FORMAT_XRGB8888, COLOR_FMT_RGBA8888_UBWC}, - {DRM_FORMAT_ABGR2101010, COLOR_FMT_RGBA1010102_UBWC}, - {DRM_FORMAT_ARGB2101010, COLOR_FMT_RGBA1010102_UBWC}, - {DRM_FORMAT_XRGB2101010, COLOR_FMT_RGBA1010102_UBWC}, - {DRM_FORMAT_XBGR2101010, COLOR_FMT_RGBA1010102_UBWC}, - {DRM_FORMAT_BGR565, COLOR_FMT_RGB565_UBWC}, - }; - int color_fmt = -1; - int i; - - if (fmt->pixel_format == DRM_FORMAT_NV12 || - fmt->pixel_format == DRM_FORMAT_P010) { - if (MSM_FORMAT_IS_DX(fmt)) { - if (fmt->flags & MSM_FORMAT_FLAG_UNPACK_TIGHT) - color_fmt = COLOR_FMT_NV12_BPP10_UBWC; - else - color_fmt = COLOR_FMT_P010_UBWC; - } else - color_fmt = COLOR_FMT_NV12_UBWC; - return color_fmt; - } - - for (i = 0; i < ARRAY_SIZE(dpu_media_ubwc_map); ++i) - if (fmt->pixel_format == dpu_media_ubwc_map[i].format) { - color_fmt = dpu_media_ubwc_map[i].color; - break; - } - return color_fmt; -} - static int _dpu_format_populate_plane_sizes_ubwc( const struct msm_format *fmt, struct drm_framebuffer *fb, struct dpu_hw_fmt_layout *layout) { - int i; - int color; bool meta = MSM_FORMAT_IS_UBWC(fmt); - memset(layout, 0, sizeof(struct dpu_hw_fmt_layout)); - layout->width = fb->width; - layout->height = fb->height; - layout->num_planes = fmt->num_planes; + if (MSM_FORMAT_IS_YUV(fmt)) { + unsigned int stride, sclines; + unsigned int y_tile_width, y_tile_height; + unsigned int y_meta_stride, y_meta_scanlines; + unsigned int uv_meta_stride, uv_meta_scanlines; - color = _dpu_format_get_media_color_ubwc(fmt); - if (color < 0) { - DRM_ERROR("UBWC format not supported for fmt: %p4cc\n", - &fmt->pixel_format); - return -EINVAL; - } + if (MSM_FORMAT_IS_DX(fmt)) { + if (fmt->flags & MSM_FORMAT_FLAG_UNPACK_TIGHT) { + /* can't use round_up() here because 192 is NPoT */ + stride = roundup(fb->width, 192); + stride = round_up(stride * 4 / 3, 256); + y_tile_width = 48; + } else { + stride = round_up(fb->width * 2, 256); + y_tile_width = 32; + } + + sclines = round_up(fb->height, 16); + y_tile_height = 4; + } else { + stride = round_up(fb->width, 128); + y_tile_width = 32; - if (MSM_FORMAT_IS_YUV(fmt)) { - uint32_t y_sclines, uv_sclines; - uint32_t y_meta_scanlines = 0; - uint32_t uv_meta_scanlines = 0; + sclines = round_up(fb->height, 32); + y_tile_height = 8; + } - layout->num_planes = 2; - layout->plane_pitch[0] = VENUS_Y_STRIDE(color, fb->width); - y_sclines = VENUS_Y_SCANLINES(color, fb->height); - layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] * - y_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); + layout->plane_pitch[0] = stride; + layout->plane_size[0] = round_up(layout->plane_pitch[0] * + sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); - layout->plane_pitch[1] = VENUS_UV_STRIDE(color, fb->width); - uv_sclines = VENUS_UV_SCANLINES(color, fb->height); - layout->plane_size[1] = MSM_MEDIA_ALIGN(layout->plane_pitch[1] * - uv_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); + layout->plane_pitch[1] = stride; + layout->plane_size[1] = round_up(layout->plane_pitch[1] * + sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); if (!meta) - goto done; + return 0; + + y_meta_stride = DIV_ROUND_UP(fb->width, y_tile_width); + layout->plane_pitch[2] = round_up(y_meta_stride, 64); - layout->num_planes += 2; - layout->plane_pitch[2] = VENUS_Y_META_STRIDE(color, fb->width); - y_meta_scanlines = VENUS_Y_META_SCANLINES(color, fb->height); - layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] * + y_meta_scanlines = DIV_ROUND_UP(fb->height, y_tile_height); + y_meta_scanlines = round_up(y_meta_scanlines, 16); + layout->plane_size[2] = round_up(layout->plane_pitch[2] * y_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); - layout->plane_pitch[3] = VENUS_UV_META_STRIDE(color, fb->width); - uv_meta_scanlines = VENUS_UV_META_SCANLINES(color, fb->height); - layout->plane_size[3] = MSM_MEDIA_ALIGN(layout->plane_pitch[3] * - uv_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); + uv_meta_stride = DIV_ROUND_UP((fb->width+1)>>1, y_tile_width / 2); + layout->plane_pitch[3] = round_up(uv_meta_stride, 64); + uv_meta_scanlines = DIV_ROUND_UP((fb->height+1)>>1, y_tile_height); + uv_meta_scanlines = round_up(uv_meta_scanlines, 16); + layout->plane_size[3] = round_up(layout->plane_pitch[3] * + uv_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); } else { - uint32_t rgb_scanlines, rgb_meta_scanlines; - - layout->num_planes = 1; + unsigned int rgb_scanlines, rgb_meta_scanlines, rgb_meta_stride; - layout->plane_pitch[0] = VENUS_RGB_STRIDE(color, fb->width); - rgb_scanlines = VENUS_RGB_SCANLINES(color, fb->height); - layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] * + layout->plane_pitch[0] = round_up(fb->width * fmt->bpp, 256); + rgb_scanlines = round_up(fb->height, 16); + layout->plane_size[0] = round_up(layout->plane_pitch[0] * rgb_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); if (!meta) - goto done; - layout->num_planes += 2; - layout->plane_pitch[2] = VENUS_RGB_META_STRIDE(color, fb->width); - rgb_meta_scanlines = VENUS_RGB_META_SCANLINES(color, fb->height); - layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] * + return 0; + + /* uAPI leaves plane[1] empty and plane[2] as meta */ + layout->num_planes += 1; + + rgb_meta_stride = DIV_ROUND_UP(fb->width, 16); + layout->plane_pitch[2] = round_up(rgb_meta_stride, 64); + + rgb_meta_scanlines = DIV_ROUND_UP(fb->height, 4); + rgb_meta_scanlines = round_up(rgb_meta_scanlines, 16); + + layout->plane_size[2] = round_up(layout->plane_pitch[2] * rgb_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); } -done: - for (i = 0; i < DPU_MAX_PLANES; i++) - layout->total_size += layout->plane_size[i]; - return 0; } @@ -174,14 +147,8 @@ static int _dpu_format_populate_plane_sizes_linear( { int i; - memset(layout, 0, sizeof(struct dpu_hw_fmt_layout)); - layout->width = fb->width; - layout->height = fb->height; - layout->num_planes = fmt->num_planes; - /* Due to memset above, only need to set planes of interest */ if (fmt->fetch_type == MDP_PLANE_INTERLEAVED) { - layout->num_planes = 1; layout->plane_size[0] = fb->width * fb->height * fmt->bpp; layout->plane_pitch[0] = fb->width * fmt->bpp; } else { @@ -208,12 +175,10 @@ static int _dpu_format_populate_plane_sizes_linear( (fb->height / v_subsample); if (fmt->fetch_type == MDP_PLANE_PSEUDO_PLANAR) { - layout->num_planes = 2; layout->plane_size[1] *= 2; layout->plane_pitch[1] *= 2; } else { /* planar */ - layout->num_planes = 3; layout->plane_size[2] = layout->plane_size[1]; layout->plane_pitch[2] = layout->plane_pitch[1]; } @@ -235,9 +200,6 @@ static int _dpu_format_populate_plane_sizes_linear( } } - for (i = 0; i < DPU_MAX_PLANES; i++) - layout->total_size += layout->plane_size[i]; - return 0; } @@ -254,6 +216,7 @@ int dpu_format_populate_plane_sizes( struct dpu_hw_fmt_layout *layout) { const struct msm_format *fmt; + int ret, i; if (!layout || !fb) { DRM_ERROR("invalid pointer\n"); @@ -268,10 +231,23 @@ int dpu_format_populate_plane_sizes( fmt = msm_framebuffer_format(fb); + memset(layout, 0, sizeof(struct dpu_hw_fmt_layout)); + layout->width = fb->width; + layout->height = fb->height; + layout->num_planes = fmt->num_planes; + if (MSM_FORMAT_IS_UBWC(fmt) || MSM_FORMAT_IS_TILE(fmt)) - return _dpu_format_populate_plane_sizes_ubwc(fmt, fb, layout); + ret = _dpu_format_populate_plane_sizes_ubwc(fmt, fb, layout); + else + ret = _dpu_format_populate_plane_sizes_linear(fmt, fb, layout); + + if (ret) + return ret; + + for (i = 0; i < DPU_MAX_PLANES; i++) + layout->total_size += layout->plane_size[i]; - return _dpu_format_populate_plane_sizes_linear(fmt, fb, layout); + return 0; } static void _dpu_format_populate_addrs_ubwc(struct drm_framebuffer *fb, 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 9f8d1bba9139a..c4e1f6b7345db 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -241,6 +241,23 @@ static const u32 wb2_formats_rgb_yuv[] = { .rotation_cfg = NULL, \ } +/* kaanapali SSPP common configuration */ +#define _VIG_SBLK_REC0_REC1(scaler_ver) \ + { \ + .sspp_rec0_blk = {.name = "sspp_rec0", \ + .base = 0x1000, .len = 0x180,}, \ + .csc_blk = {.name = "csc", \ + .base = 0x1800, .len = 0x100,}, \ + .scaler_blk = {.name = "scaler", \ + .version = scaler_ver, \ + .base = 0x2000, .len = 0xec,}, \ + .sspp_rec1_blk = {.name = "sspp_rec1", \ + .base = 0x3000, .len = 0x180,}, \ + .format_list = plane_formats_yuv, \ + .num_formats = ARRAY_SIZE(plane_formats_yuv), \ + .rotation_cfg = NULL, \ + } + #define _VIG_SBLK_ROT(scaler_ver, rot_cfg) \ { \ .scaler_blk = {.name = "scaler", \ @@ -329,6 +346,9 @@ static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_3 = static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_4 = _VIG_SBLK(SSPP_SCALER_VER(3, 4)); +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_5 = + _VIG_SBLK_REC0_REC1(SSPP_SCALER_VER(3, 5)); + static const struct dpu_sspp_sub_blks dpu_rgb_sblk = _RGB_SBLK(); static const struct dpu_sspp_sub_blks dpu_dma_sblk = _DMA_SBLK(); @@ -382,11 +402,15 @@ static const struct dpu_lm_sub_blks qcm2290_lm_sblk = { static const struct dpu_dspp_sub_blks msm8998_dspp_sblk = { .pcc = {.name = "pcc", .base = 0x1700, .len = 0x90, .version = 0x10007}, + .gc = {.name = "gc", .base = 0x17c0, + .len = 0x40, .version = 0x10007}, }; static const struct dpu_dspp_sub_blks sdm845_dspp_sblk = { .pcc = {.name = "pcc", .base = 0x1700, .len = 0x90, .version = 0x40000}, + .gc = {.name = "gc", .base = 0x17c0, + .len = 0x40, .version = 0x10008}, }; static const struct dpu_dspp_sub_blks sm8750_dspp_sblk = { @@ -412,6 +436,11 @@ static const struct dpu_pingpong_sub_blks sc7280_pp_sblk = { .len = 0x20, .version = 0x20000}, }; +static const struct dpu_pingpong_sub_blks kaanapali_pp_sblk = { + .dither = {.name = "dither", .base = 0xc0, + .len = 0x40, .version = 0x30000}, +}; + /************************************************************* * DSC sub blocks config *************************************************************/ @@ -452,6 +481,13 @@ static const struct dpu_cdm_cfg dpu_cdm_5_x = { .base = 0x79200, }; +static const struct dpu_cdm_cfg dpu_cdm_13_x = { + .name = "cdm_0", + .id = CDM_0, + .len = 0x240, + .base = 0x19e000, +}; + /************************************************************* * VBIF sub blocks config *************************************************************/ @@ -639,6 +675,10 @@ static const struct dpu_qos_lut_entry sc7180_qos_linear[] = { {.fl = 0, .lut = 0x0011222222335777}, }; +static const struct dpu_qos_lut_entry kaanapali_qos_linear[] = { + {.fl = 0, .lut = 0x0011223344556666}, +}; + static const struct dpu_qos_lut_entry sm6350_qos_linear_macrotile[] = { {.fl = 0, .lut = 0x0011223445566777 }, }; @@ -668,6 +708,10 @@ static const struct dpu_qos_lut_entry sc7180_qos_macrotile[] = { {.fl = 0, .lut = 0x0011223344556677}, }; +static const struct dpu_qos_lut_entry kaanapali_qos_macrotile[] = { + {.fl = 0, .lut = 0x0011223344556666}, +}; + static const struct dpu_qos_lut_entry sc8180x_qos_macrotile[] = { {.fl = 10, .lut = 0x0000000344556677}, }; @@ -726,3 +770,5 @@ 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" +#include "catalog/dpu_13_0_kaanapali.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 f0768f54e9b3d..70d5ed4732f2e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -77,9 +77,11 @@ enum { /** * DSPP sub-blocks * @DPU_DSPP_PCC Panel color correction block + * @DPU_DSPP_GC Gamma correction block */ enum { DPU_DSPP_PCC = 0x1, + DPU_DSPP_GC, DPU_DSPP_MAX }; @@ -208,6 +210,18 @@ struct dpu_dsc_blk { u32 len; }; +/** + * struct dpu_sspp_v13_rec_blk - SSPP REC sub-blk information + * @name: string name for debug purposes + * @base: offset of this sub-block relative to the block offset + * @len: register block length of this sub-block + */ +struct dpu_sspp_v13_rec_blk { + char name[DPU_HW_BLK_NAME_LEN]; + u32 base; + u32 len; +}; + /** * enum dpu_qos_lut_usage - define QoS LUT use cases */ @@ -294,6 +308,8 @@ struct dpu_sspp_sub_blks { u32 qseed_ver; struct dpu_scaler_blk scaler_blk; struct dpu_pp_blk csc_blk; + struct dpu_sspp_v13_rec_blk sspp_rec0_blk; + struct dpu_sspp_v13_rec_blk sspp_rec1_blk; const u32 *format_list; u32 num_formats; @@ -314,9 +330,11 @@ struct dpu_lm_sub_blks { /** * struct dpu_dspp_sub_blks: Information of DSPP block * @pcc: pixel color correction block + * @gc: gamma correction block */ struct dpu_dspp_sub_blks { struct dpu_pp_blk pcc; + struct dpu_pp_blk gc; }; struct dpu_pingpong_sub_blks { @@ -749,6 +767,8 @@ 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_kaanapali_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_cdm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h index 6bb3476a05f80..75e6dae0fcd9b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h @@ -89,13 +89,13 @@ enum dpu_hw_cdwn_op_mode_method_h_v { */ struct dpu_hw_cdm_ops { /** - * Enable the CDM module + * @enable: Enable the CDM module * @cdm Pointer to chroma down context */ int (*enable)(struct dpu_hw_cdm *cdm, struct dpu_hw_cdm_cfg *cfg); /** - * Enable/disable the connection with pingpong + * @bind_pingpong_blk: Enable/disable the connection with pingpong * @cdm Pointer to chroma down context * @pp pingpong block id. */ 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 ac834db2e4c16..36a497f1d6c12 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -399,6 +399,9 @@ static void dpu_hw_ctl_update_pending_flush_dspp_sub_blocks( case DPU_DSPP_PCC: ctx->pending_dspp_flush_mask[dspp - DSPP_0] |= BIT(4); break; + case DPU_DSPP_GC: + ctx->pending_dspp_flush_mask[dspp - DSPP_0] |= BIT(5); + break; default: return; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h index 15931b22ec941..e535bf013825b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h @@ -12,9 +12,9 @@ #include "dpu_hw_sspp.h" /** - * dpu_ctl_mode_sel: Interface mode selection - * DPU_CTL_MODE_SEL_VID: Video mode interface - * DPU_CTL_MODE_SEL_CMD: Command mode interface + * enum dpu_ctl_mode_sel: Interface mode selection + * @DPU_CTL_MODE_SEL_VID: Video mode interface + * @DPU_CTL_MODE_SEL_CMD: Command mode interface */ enum dpu_ctl_mode_sel { DPU_CTL_MODE_SEL_VID = 0, @@ -37,6 +37,7 @@ struct dpu_hw_stage_cfg { * struct dpu_hw_intf_cfg :Describes how the DPU writes data to output interface * @intf : Interface id * @intf_master: Master interface id in the dual pipe topology + * @wb: Writeback mode * @mode_3d: 3d mux configuration * @merge_3d: 3d merge block used * @intf_mode_sel: Interface mode, cmd / vid @@ -64,21 +65,21 @@ struct dpu_hw_intf_cfg { */ struct dpu_hw_ctl_ops { /** - * kickoff hw operation for Sw controlled interfaces + * @trigger_start: kickoff hw operation for Sw controlled interfaces * DSI cmd mode and WB interface are SW controlled * @ctx : ctl path ctx pointer */ void (*trigger_start)(struct dpu_hw_ctl *ctx); /** - * check if the ctl is started + * @is_started: check if the ctl is started * @ctx : ctl path ctx pointer * @Return: true if started, false if stopped */ bool (*is_started)(struct dpu_hw_ctl *ctx); /** - * kickoff prepare is in progress hw operation for sw + * @trigger_pending: kickoff prepare is in progress hw operation for sw * controlled interfaces: DSI cmd mode and WB interface * are SW controlled * @ctx : ctl path ctx pointer @@ -86,7 +87,7 @@ struct dpu_hw_ctl_ops { void (*trigger_pending)(struct dpu_hw_ctl *ctx); /** - * Clear the value of the cached pending_flush_mask + * @clear_pending_flush: Clear the value of the cached pending_flush_mask * No effect on hardware. * Required to be implemented. * @ctx : ctl path ctx pointer @@ -94,14 +95,15 @@ struct dpu_hw_ctl_ops { void (*clear_pending_flush)(struct dpu_hw_ctl *ctx); /** - * Query the value of the cached pending_flush_mask + * @get_pending_flush: Query the value of the cached pending_flush_mask * No effect on hardware * @ctx : ctl path ctx pointer */ u32 (*get_pending_flush)(struct dpu_hw_ctl *ctx); /** - * OR in the given flushbits to the cached pending_flush_mask + * @update_pending_flush: OR in the given flushbits to the cached + * pending_flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @flushbits : module flushmask @@ -110,7 +112,8 @@ struct dpu_hw_ctl_ops { u32 flushbits); /** - * OR in the given flushbits to the cached pending_(wb_)flush_mask + * @update_pending_flush_wb: OR in the given flushbits to the + * cached pending_(wb_)flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : writeback block index @@ -119,7 +122,8 @@ struct dpu_hw_ctl_ops { enum dpu_wb blk); /** - * OR in the given flushbits to the cached pending_(cwb_)flush_mask + * @update_pending_flush_cwb: OR in the given flushbits to the + * cached pending_(cwb_)flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : concurrent writeback block index @@ -128,7 +132,8 @@ struct dpu_hw_ctl_ops { enum dpu_cwb blk); /** - * OR in the given flushbits to the cached pending_(intf_)flush_mask + * @update_pending_flush_intf: OR in the given flushbits to the + * cached pending_(intf_)flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : interface block index @@ -137,7 +142,8 @@ struct dpu_hw_ctl_ops { enum dpu_intf blk); /** - * OR in the given flushbits to the cached pending_(periph_)flush_mask + * @update_pending_flush_periph: OR in the given flushbits to the + * cached pending_(periph_)flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : interface block index @@ -146,7 +152,8 @@ struct dpu_hw_ctl_ops { enum dpu_intf blk); /** - * OR in the given flushbits to the cached pending_(merge_3d_)flush_mask + * @update_pending_flush_merge_3d: OR in the given flushbits to the + * cached pending_(merge_3d_)flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : interface block index @@ -155,7 +162,8 @@ struct dpu_hw_ctl_ops { enum dpu_merge_3d blk); /** - * OR in the given flushbits to the cached pending_flush_mask + * @update_pending_flush_sspp: OR in the given flushbits to the + * cached pending_flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : SSPP block index @@ -164,7 +172,8 @@ struct dpu_hw_ctl_ops { enum dpu_sspp blk); /** - * OR in the given flushbits to the cached pending_flush_mask + * @update_pending_flush_mixer: OR in the given flushbits to the + * cached pending_flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : LM block index @@ -173,7 +182,8 @@ struct dpu_hw_ctl_ops { enum dpu_lm blk); /** - * OR in the given flushbits to the cached pending_flush_mask + * @update_pending_flush_dspp: OR in the given flushbits to the + * cached pending_flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : DSPP block index @@ -183,7 +193,8 @@ struct dpu_hw_ctl_ops { enum dpu_dspp blk, u32 dspp_sub_blk); /** - * OR in the given flushbits to the cached pending_(dsc_)flush_mask + * @update_pending_flush_dsc: OR in the given flushbits to the + * cached pending_(dsc_)flush_mask. * No effect on hardware * @ctx: ctl path ctx pointer * @blk: interface block index @@ -192,7 +203,8 @@ struct dpu_hw_ctl_ops { enum dpu_dsc blk); /** - * OR in the given flushbits to the cached pending_(cdm_)flush_mask + * @update_pending_flush_cdm: OR in the given flushbits to the + * cached pending_(cdm_)flush_mask. * No effect on hardware * @ctx: ctl path ctx pointer * @cdm_num: idx of cdm to be flushed @@ -200,20 +212,20 @@ struct dpu_hw_ctl_ops { void (*update_pending_flush_cdm)(struct dpu_hw_ctl *ctx, enum dpu_cdm cdm_num); /** - * Write the value of the pending_flush_mask to hardware + * @trigger_flush: Write the value of the pending_flush_mask to hardware * @ctx : ctl path ctx pointer */ void (*trigger_flush)(struct dpu_hw_ctl *ctx); /** - * Read the value of the flush register + * @get_flush_register: Read the value of the flush register * @ctx : ctl path ctx pointer * @Return: value of the ctl flush register. */ u32 (*get_flush_register)(struct dpu_hw_ctl *ctx); /** - * Setup ctl_path interface config + * @setup_intf_cfg: Setup ctl_path interface config * @ctx * @cfg : interface config structure pointer */ @@ -221,17 +233,20 @@ struct dpu_hw_ctl_ops { struct dpu_hw_intf_cfg *cfg); /** - * reset ctl_path interface config + * @reset_intf_cfg: reset ctl_path interface config * @ctx : ctl path ctx pointer * @cfg : interface config structure pointer */ void (*reset_intf_cfg)(struct dpu_hw_ctl *ctx, struct dpu_hw_intf_cfg *cfg); + /** + * @reset: reset function for this ctl type + */ int (*reset)(struct dpu_hw_ctl *c); - /* - * wait_reset_status - checks ctl reset status + /** + * @wait_reset_status: checks ctl reset status * @ctx : ctl path ctx pointer * * This function checks the ctl reset status bit. @@ -242,13 +257,13 @@ struct dpu_hw_ctl_ops { int (*wait_reset_status)(struct dpu_hw_ctl *ctx); /** - * Set all blend stages to disabled + * @clear_all_blendstages: Set all blend stages to disabled * @ctx : ctl path ctx pointer */ void (*clear_all_blendstages)(struct dpu_hw_ctl *ctx); /** - * Configure layer mixer to pipe configuration + * @setup_blendstage: Configure layer mixer to pipe configuration * @ctx : ctl path ctx pointer * @lm : layer mixer enumeration * @cfg : blend stage configuration @@ -256,11 +271,16 @@ struct dpu_hw_ctl_ops { void (*setup_blendstage)(struct dpu_hw_ctl *ctx, enum dpu_lm lm, struct dpu_hw_stage_cfg *cfg); + /** + * @set_active_fetch_pipes: Set active pipes attached to this CTL + * @ctx: ctl path ctx pointer + * @active_pipes: bitmap of enum dpu_sspp + */ void (*set_active_fetch_pipes)(struct dpu_hw_ctl *ctx, unsigned long *fetch_active); /** - * Set active pipes attached to this CTL + * @set_active_pipes: Set active pipes attached to this CTL * @ctx: ctl path ctx pointer * @active_pipes: bitmap of enum dpu_sspp */ @@ -268,13 +288,12 @@ struct dpu_hw_ctl_ops { unsigned long *active_pipes); /** - * Set active layer mixers attached to this CTL + * @set_active_lms: Set active layer mixers attached to this CTL * @ctx: ctl path ctx pointer * @active_lms: bitmap of enum dpu_lm */ void (*set_active_lms)(struct dpu_hw_ctl *ctx, unsigned long *active_lms); - }; /** @@ -289,6 +308,9 @@ struct dpu_hw_ctl_ops { * @pending_intf_flush_mask: pending INTF flush * @pending_wb_flush_mask: pending WB flush * @pending_cwb_flush_mask: pending CWB flush + * @pending_periph_flush_mask: pending PERIPH flush + * @pending_merge_3d_flush_mask: pending MERGE 3D flush + * @pending_dspp_flush_mask: pending DSPP flush * @pending_dsc_flush_mask: pending DSC flush * @pending_cdm_flush_mask: pending CDM flush * @mdss_ver: MDSS revision information @@ -320,7 +342,7 @@ struct dpu_hw_ctl { }; /** - * dpu_hw_ctl - convert base object dpu_hw_base to container + * to_dpu_hw_ctl - convert base object dpu_hw_base to container * @hw: Pointer to base hardware block * return: Pointer to hardware block container */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cwb.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cwb.h index 96b6edf6b2bbf..ed7bfcee7f1cc 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cwb.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cwb.h @@ -28,7 +28,6 @@ struct dpu_hw_cwb_setup_cfg { }; /** - * * struct dpu_hw_cwb_ops : Interface to the cwb hw driver functions * @config_cwb: configure CWB mux */ @@ -54,7 +53,7 @@ struct dpu_hw_cwb { }; /** - * dpu_hw_cwb - convert base object dpu_hw_base to container + * to_dpu_hw_cwb - convert base object dpu_hw_base to container * @hw: Pointer to base hardware block * return: Pointer to hardware block container */ 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 cc7cc6f6f7cda..39d93b9df0515 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h @@ -21,13 +21,13 @@ struct dpu_hw_dsc; */ struct dpu_hw_dsc_ops { /** - * dsc_disable - disable dsc + * @dsc_disable: disable dsc * @hw_dsc: Pointer to dsc context */ void (*dsc_disable)(struct dpu_hw_dsc *hw_dsc); /** - * dsc_config - configures dsc encoder + * @dsc_config: configures dsc encoder * @hw_dsc: Pointer to dsc context * @dsc: panel dsc parameters * @mode: dsc topology mode to be set @@ -39,13 +39,17 @@ struct dpu_hw_dsc_ops { u32 initial_lines); /** - * dsc_config_thresh - programs panel thresholds + * @dsc_config_thresh: programs panel thresholds * @hw_dsc: Pointer to dsc context * @dsc: panel dsc parameters */ void (*dsc_config_thresh)(struct dpu_hw_dsc *hw_dsc, struct drm_dsc_config *dsc); + /** + * @dsc_bind_pingpong_blk: binds pixel output from a DSC block + * to a pingpong block + */ void (*dsc_bind_pingpong_blk)(struct dpu_hw_dsc *hw_dsc, enum dpu_pingpong pp); }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c index 54b20faa0b697..23dcbe1ce1b83 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c @@ -24,6 +24,18 @@ #define PCC_BLUE_G_OFF 0x24 #define PCC_BLUE_B_OFF 0x30 +/* DSPP_GC */ +#define GC_EN BIT(0) +#define GC_DIS 0 +#define GC_8B_ROUND_EN BIT(1) +#define GC_LUT_SWAP_OFF 0x1c +#define GC_C0_OFF 0x4 +#define GC_C1_OFF 0xc +#define GC_C2_OFF 0x14 +#define GC_C0_INDEX_OFF 0x8 +#define GC_C1_INDEX_OFF 0x10 +#define GC_C2_INDEX_OFF 0x18 + static void dpu_setup_dspp_pcc(struct dpu_hw_dspp *ctx, struct dpu_hw_pcc_cfg *cfg) { @@ -63,6 +75,46 @@ static void dpu_setup_dspp_pcc(struct dpu_hw_dspp *ctx, DPU_REG_WRITE(&ctx->hw, base, PCC_EN); } +static void dpu_setup_dspp_gc(struct dpu_hw_dspp *ctx, + struct dpu_hw_gc_lut *gc_lut) +{ + int i = 0; + u32 base, reg; + + if (!ctx) { + DRM_ERROR("invalid ctx\n"); + return; + } + + base = ctx->cap->sblk->gc.base; + + if (!base) { + DRM_ERROR("invalid ctx %p gc base\n", ctx); + return; + } + + if (!gc_lut) { + DRM_DEBUG_DRIVER("disable gc feature\n"); + DPU_REG_WRITE(&ctx->hw, base, GC_DIS); + return; + } + + DPU_REG_WRITE(&ctx->hw, base + GC_C0_INDEX_OFF, 0); + DPU_REG_WRITE(&ctx->hw, base + GC_C1_INDEX_OFF, 0); + DPU_REG_WRITE(&ctx->hw, base + GC_C2_INDEX_OFF, 0); + + for (i = 0; i < PGC_TBL_LEN; i++) { + DPU_REG_WRITE(&ctx->hw, base + GC_C0_OFF, gc_lut->c0[i]); + DPU_REG_WRITE(&ctx->hw, base + GC_C1_OFF, gc_lut->c1[i]); + DPU_REG_WRITE(&ctx->hw, base + GC_C2_OFF, gc_lut->c2[i]); + } + + DPU_REG_WRITE(&ctx->hw, base + GC_LUT_SWAP_OFF, BIT(0)); + + reg = GC_EN | ((gc_lut->flags & PGC_8B_ROUND) ? GC_8B_ROUND_EN : 0); + DPU_REG_WRITE(&ctx->hw, base, reg); +} + /** * dpu_hw_dspp_init() - Initializes the DSPP hw driver object. * should be called once before accessing every DSPP. @@ -92,6 +144,8 @@ struct dpu_hw_dspp *dpu_hw_dspp_init(struct drm_device *dev, c->cap = cfg; if (c->cap->sblk->pcc.base) c->ops.setup_pcc = dpu_setup_dspp_pcc; + if (c->cap->sblk->gc.base) + c->ops.setup_gc = dpu_setup_dspp_gc; return c; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h index 45c26cd49fa3e..b47b7788064b2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h @@ -22,7 +22,7 @@ struct dpu_hw_pcc_coeff { }; /** - * struct dpu_hw_pcc - pcc feature structure + * struct dpu_hw_pcc_cfg - pcc feature structure * @r: red coefficients. * @g: green coefficients. * @b: blue coefficients. @@ -33,6 +33,25 @@ struct dpu_hw_pcc_cfg { struct dpu_hw_pcc_coeff b; }; +#define DPU_GAMMA_LUT_SIZE 1024 +#define PGC_TBL_LEN 512 +#define PGC_8B_ROUND BIT(0) + +/** + * struct dpu_hw_gc_lut - gc lut feature structure + * @flags: flags for the feature values can be: + * - PGC_8B_ROUND + * @c0: color0 component lut + * @c1: color1 component lut + * @c2: color2 component lut + */ +struct dpu_hw_gc_lut { + __u64 flags; + __u32 c0[PGC_TBL_LEN]; + __u32 c1[PGC_TBL_LEN]; + __u32 c2[PGC_TBL_LEN]; +}; + /** * struct dpu_hw_dspp_ops - interface to the dspp hardware driver functions * Caller must call the init function to get the dspp context for each dspp @@ -40,12 +59,19 @@ struct dpu_hw_pcc_cfg { */ struct dpu_hw_dspp_ops { /** - * setup_pcc - setup dspp pcc + * @setup_pcc: setup_pcc - setup dspp pcc * @ctx: Pointer to dspp context * @cfg: Pointer to configuration */ void (*setup_pcc)(struct dpu_hw_dspp *ctx, struct dpu_hw_pcc_cfg *cfg); + /** + * setup_gc - setup dspp gc + * @ctx: Pointer to dspp context + * @gc_lut: Pointer to lut content + */ + void (*setup_gc)(struct dpu_hw_dspp *ctx, struct dpu_hw_gc_lut *gc_lut); + }; /** @@ -69,7 +95,7 @@ struct dpu_hw_dspp { }; /** - * dpu_hw_dspp - convert base object dpu_hw_base to container + * to_dpu_hw_dspp - convert base object dpu_hw_base to container * @hw: Pointer to base hardware block * return: Pointer to hardware block container */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c index 49bd77a755aa5..5b7cd5241f450 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c @@ -40,6 +40,15 @@ #define MDP_INTF_REV_7xxx_INTR_TEAR_STATUS(intf) (MDP_INTF_REV_7xxx_TEAR_OFF(intf) + 0x004) #define MDP_INTF_REV_7xxx_INTR_TEAR_CLEAR(intf) (MDP_INTF_REV_7xxx_TEAR_OFF(intf) + 0x008) +#define MDP_INTF_REV_13xx_OFF(intf) (0x18d000 + 0x1000 * (intf)) +#define MDP_INTF_REV_13xx_INTR_EN(intf) (MDP_INTF_REV_13xx_OFF(intf) + 0x1c0) +#define MDP_INTF_REV_13xx_INTR_STATUS(intf) (MDP_INTF_REV_13xx_OFF(intf) + 0x1c4) +#define MDP_INTF_REV_13xx_INTR_CLEAR(intf) (MDP_INTF_REV_13xx_OFF(intf) + 0x1c8) +#define MDP_INTF_REV_13xx_TEAR_OFF(intf) (0x18d800 + 0x1000 * (intf)) +#define MDP_INTF_REV_13xx_INTR_TEAR_EN(intf) (MDP_INTF_REV_13xx_TEAR_OFF(intf) + 0x000) +#define MDP_INTF_REV_13xx_INTR_TEAR_STATUS(intf) (MDP_INTF_REV_13xx_TEAR_OFF(intf) + 0x004) +#define MDP_INTF_REV_13xx_INTR_TEAR_CLEAR(intf) (MDP_INTF_REV_13xx_TEAR_OFF(intf) + 0x008) + /** * struct dpu_intr_reg - array of DPU register sets * @clr_off: offset to CLEAR reg @@ -199,6 +208,82 @@ static const struct dpu_intr_reg dpu_intr_set_7xxx[] = { }, }; +/* + * dpu_intr_set_13xx - List of DPU interrupt registers for DPU >= 13.0 + */ +static const struct dpu_intr_reg dpu_intr_set_13xx[] = { + [MDP_SSPP_TOP0_INTR] = { + INTR_CLEAR, + INTR_EN, + INTR_STATUS + }, + [MDP_SSPP_TOP0_INTR2] = { + INTR2_CLEAR, + INTR2_EN, + INTR2_STATUS + }, + [MDP_SSPP_TOP0_HIST_INTR] = { + HIST_INTR_CLEAR, + HIST_INTR_EN, + HIST_INTR_STATUS + }, + [MDP_INTF0_INTR] = { + MDP_INTF_REV_13xx_INTR_CLEAR(0), + MDP_INTF_REV_13xx_INTR_EN(0), + MDP_INTF_REV_13xx_INTR_STATUS(0) + }, + [MDP_INTF1_INTR] = { + MDP_INTF_REV_13xx_INTR_CLEAR(1), + MDP_INTF_REV_13xx_INTR_EN(1), + MDP_INTF_REV_13xx_INTR_STATUS(1) + }, + [MDP_INTF1_TEAR_INTR] = { + MDP_INTF_REV_13xx_INTR_TEAR_CLEAR(1), + MDP_INTF_REV_13xx_INTR_TEAR_EN(1), + MDP_INTF_REV_13xx_INTR_TEAR_STATUS(1) + }, + [MDP_INTF2_INTR] = { + MDP_INTF_REV_13xx_INTR_CLEAR(2), + MDP_INTF_REV_13xx_INTR_EN(2), + MDP_INTF_REV_13xx_INTR_STATUS(2) + }, + [MDP_INTF2_TEAR_INTR] = { + MDP_INTF_REV_13xx_INTR_TEAR_CLEAR(2), + MDP_INTF_REV_13xx_INTR_TEAR_EN(2), + MDP_INTF_REV_13xx_INTR_TEAR_STATUS(2) + }, + [MDP_INTF3_INTR] = { + MDP_INTF_REV_13xx_INTR_CLEAR(3), + MDP_INTF_REV_13xx_INTR_EN(3), + MDP_INTF_REV_13xx_INTR_STATUS(3) + }, + [MDP_INTF4_INTR] = { + MDP_INTF_REV_13xx_INTR_CLEAR(4), + MDP_INTF_REV_13xx_INTR_EN(4), + MDP_INTF_REV_13xx_INTR_STATUS(4) + }, + [MDP_INTF5_INTR] = { + MDP_INTF_REV_13xx_INTR_CLEAR(5), + MDP_INTF_REV_13xx_INTR_EN(5), + MDP_INTF_REV_13xx_INTR_STATUS(5) + }, + [MDP_INTF6_INTR] = { + MDP_INTF_REV_13xx_INTR_CLEAR(6), + MDP_INTF_REV_13xx_INTR_EN(6), + MDP_INTF_REV_13xx_INTR_STATUS(6) + }, + [MDP_INTF7_INTR] = { + MDP_INTF_REV_13xx_INTR_CLEAR(7), + MDP_INTF_REV_13xx_INTR_EN(7), + MDP_INTF_REV_13xx_INTR_STATUS(7) + }, + [MDP_INTF8_INTR] = { + MDP_INTF_REV_13xx_INTR_CLEAR(8), + MDP_INTF_REV_13xx_INTR_EN(8), + MDP_INTF_REV_13xx_INTR_STATUS(8) + }, +}; + #define DPU_IRQ_MASK(irq_idx) (BIT(DPU_IRQ_BIT(irq_idx))) static inline bool dpu_core_irq_is_valid(unsigned int irq_idx) @@ -507,7 +592,9 @@ struct dpu_hw_intr *dpu_hw_intr_init(struct drm_device *dev, if (!intr) return ERR_PTR(-ENOMEM); - if (m->mdss_ver->core_major_ver >= 7) + if (m->mdss_ver->core_major_ver >= 13) + intr->intr_set = dpu_intr_set_13xx; + else if (m->mdss_ver->core_major_ver >= 7) intr->intr_set = dpu_intr_set_7xxx; else intr->intr_set = dpu_intr_set_legacy; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h index e84ab849d71a9..f6ef2c21b66d4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h @@ -58,11 +58,11 @@ struct dpu_hw_intf_cmd_mode_cfg { /** * struct dpu_hw_intf_ops : Interface to the interface Hw driver functions * Assumption is these functions will be called after clocks are enabled - * @ setup_timing_gen : programs the timing engine - * @ setup_prog_fetch : enables/disables the programmable fetch logic - * @ enable_timing: enable/disable timing engine - * @ get_status: returns if timing engine is enabled or not - * @ get_line_count: reads current vertical line counter + * @setup_timing_gen : programs the timing engine + * @setup_prg_fetch : enables/disables the programmable fetch logic + * @enable_timing: enable/disable timing engine + * @get_status: returns if timing engine is enabled or not + * @get_line_count: reads current vertical line counter * @bind_pingpong_blk: enable/disable the connection with pingpong which will * feed pixels to this interface * @setup_misr: enable/disable MISR @@ -71,12 +71,9 @@ struct dpu_hw_intf_cmd_mode_cfg { * pointer and programs the tear check configuration * @disable_tearcheck: Disables tearcheck block * @connect_external_te: Read, modify, write to either set or clear listening to external TE - * Return: 1 if TE was originally connected, 0 if not, or -ERROR - * @get_vsync_info: Provides the programmed and current line_count - * @setup_autorefresh: Configure and enable the autorefresh config - * @get_autorefresh: Retrieve autorefresh config from hardware - * Return: 0 on success, -ETIMEDOUT on timeout + * Returns 1 if TE was originally connected, 0 if not, or -ERROR * @vsync_sel: Select vsync signal for tear-effect configuration + * @disable_autorefresh: Disable autorefresh if enabled * @program_intf_cmd_cfg: Program the DPU to interface datapath for command mode */ struct dpu_hw_intf_ops { @@ -110,9 +107,6 @@ struct dpu_hw_intf_ops { void (*vsync_sel)(struct dpu_hw_intf *intf, struct dpu_vsync_source_cfg *cfg); - /** - * Disable autorefresh if enabled - */ void (*disable_autorefresh)(struct dpu_hw_intf *intf, uint32_t encoder_id, u16 vdisplay); void (*program_intf_cmd_cfg)(struct dpu_hw_intf *intf, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c index e8a76d5192c23..b7779726bf106 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c @@ -126,7 +126,9 @@ static int dpu_hw_lm_collect_misr(struct dpu_hw_mixer *ctx, u32 *misr_value) } static void dpu_hw_lm_setup_blend_config_combined_alpha(struct dpu_hw_mixer *ctx, - u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op) + u32 stage, + u16 fg_alpha, u16 bg_alpha, + u32 blend_op) { struct dpu_hw_blk_reg_map *c = &ctx->hw; int stage_off; @@ -139,15 +141,16 @@ static void dpu_hw_lm_setup_blend_config_combined_alpha(struct dpu_hw_mixer *ctx if (WARN_ON(stage_off < 0)) return; - const_alpha = (bg_alpha & 0xFF) | ((fg_alpha & 0xFF) << 16); + const_alpha = (bg_alpha >> 8) | ((fg_alpha >> 8) << 16); DPU_REG_WRITE(c, LM_BLEND0_CONST_ALPHA + stage_off, const_alpha); DPU_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op); } static void dpu_hw_lm_setup_blend_config_combined_alpha_v12(struct dpu_hw_mixer *ctx, - u32 stage, u32 fg_alpha, - u32 bg_alpha, u32 blend_op) + u32 stage, + u16 fg_alpha, u16 bg_alpha, + u32 blend_op) { struct dpu_hw_blk_reg_map *c = &ctx->hw; int stage_off; @@ -160,13 +163,15 @@ dpu_hw_lm_setup_blend_config_combined_alpha_v12(struct dpu_hw_mixer *ctx, if (WARN_ON(stage_off < 0)) return; - const_alpha = (bg_alpha & 0x3ff) | ((fg_alpha & 0x3ff) << 16); + const_alpha = (bg_alpha >> 6) | ((fg_alpha >> 6) << 16); DPU_REG_WRITE(c, LM_BLEND0_CONST_ALPHA_V12 + stage_off, const_alpha); DPU_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op); } static void dpu_hw_lm_setup_blend_config(struct dpu_hw_mixer *ctx, - u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op) + u32 stage, + u16 fg_alpha, u16 bg_alpha, + u32 blend_op) { struct dpu_hw_blk_reg_map *c = &ctx->hw; int stage_off; @@ -178,8 +183,8 @@ static void dpu_hw_lm_setup_blend_config(struct dpu_hw_mixer *ctx, if (WARN_ON(stage_off < 0)) return; - DPU_REG_WRITE(c, LM_BLEND0_FG_ALPHA + stage_off, fg_alpha); - DPU_REG_WRITE(c, LM_BLEND0_BG_ALPHA + stage_off, bg_alpha); + DPU_REG_WRITE(c, LM_BLEND0_FG_ALPHA + stage_off, fg_alpha >> 8); + DPU_REG_WRITE(c, LM_BLEND0_BG_ALPHA + stage_off, bg_alpha >> 8); DPU_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h index 1b9ecd082d7fd..380ca673f6de4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h @@ -25,39 +25,38 @@ struct dpu_hw_color3_cfg { }; /** - * * struct dpu_hw_lm_ops : Interface to the mixer Hw driver functions * Assumption is these functions will be called after clocks are enabled */ struct dpu_hw_lm_ops { - /* - * Sets up mixer output width and height + /** + * @setup_mixer_out: Sets up mixer output width and height * and border color if enabled */ void (*setup_mixer_out)(struct dpu_hw_mixer *ctx, struct dpu_hw_mixer_cfg *cfg); - /* - * Alpha blending configuration + /** + * @setup_blend_config: Alpha blending configuration * for the specified stage */ void (*setup_blend_config)(struct dpu_hw_mixer *ctx, uint32_t stage, - uint32_t fg_alpha, uint32_t bg_alpha, uint32_t blend_op); + u16 fg_alpha, u16 bg_alpha, uint32_t blend_op); - /* - * Alpha color component selection from either fg or bg + /** + * @setup_alpha_out: Alpha color component selection from either fg or bg */ void (*setup_alpha_out)(struct dpu_hw_mixer *ctx, uint32_t mixer_op); /** - * Clear layer mixer to pipe configuration + * @clear_all_blendstages: Clear layer mixer to pipe configuration * @ctx : mixer ctx pointer * Returns: 0 on success or -error */ int (*clear_all_blendstages)(struct dpu_hw_mixer *ctx); /** - * Configure layer mixer to pipe configuration + * @setup_blendstage: Configure layer mixer to pipe configuration * @ctx : mixer ctx pointer * @lm : layer mixer enumeration * @stage_cfg : blend stage configuration @@ -67,19 +66,19 @@ struct dpu_hw_lm_ops { struct dpu_hw_stage_cfg *stage_cfg); /** - * setup_border_color : enable/disable border color + * @setup_border_color : enable/disable border color */ void (*setup_border_color)(struct dpu_hw_mixer *ctx, struct dpu_mdss_color *color, u8 border_en); /** - * setup_misr: Enable/disable MISR + * @setup_misr: Enable/disable MISR */ void (*setup_misr)(struct dpu_hw_mixer *ctx); /** - * collect_misr: Read MISR signature + * @collect_misr: Read MISR signature */ int (*collect_misr)(struct dpu_hw_mixer *ctx, u32 *misr_value); }; 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 175639c8bfbb9..046b683d4c66d 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 1 #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_hw_merge3d.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h index 6833c02075236..b57f88187148b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h @@ -12,7 +12,6 @@ struct dpu_hw_merge_3d; /** - * * struct dpu_hw_merge_3d_ops : Interface to the merge_3d Hw driver functions * Assumption is these functions will be called after clocks are enabled * @setup_3d_mode : enable 3D merge diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h index dd99e1c21a1ee..effd012d864af 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h @@ -34,7 +34,6 @@ struct dpu_hw_dither_cfg { }; /** - * * struct dpu_hw_pingpong_ops : Interface to the pingpong Hw driver functions * Assumption is these functions will be called after clocks are enabled * @enable_tearcheck: program and enable tear check block @@ -44,51 +43,52 @@ struct dpu_hw_dither_cfg { */ struct dpu_hw_pingpong_ops { /** - * enables vysnc generation and sets up init value of + * @enable_tearcheck: enables vysnc generation and sets up init value of * read pointer and programs the tear check cofiguration */ int (*enable_tearcheck)(struct dpu_hw_pingpong *pp, struct dpu_hw_tear_check *cfg); /** - * disables tear check block + * @disable_tearcheck: disables tear check block */ int (*disable_tearcheck)(struct dpu_hw_pingpong *pp); /** - * read, modify, write to either set or clear listening to external TE + * @connect_external_te: read, modify, write to either set or clear + * listening to external TE * @Return: 1 if TE was originally connected, 0 if not, or -ERROR */ int (*connect_external_te)(struct dpu_hw_pingpong *pp, bool enable_external_te); /** - * Obtain current vertical line counter + * @get_line_count: Obtain current vertical line counter */ u32 (*get_line_count)(struct dpu_hw_pingpong *pp); /** - * Disable autorefresh if enabled + * @disable_autorefresh: Disable autorefresh if enabled */ void (*disable_autorefresh)(struct dpu_hw_pingpong *pp, uint32_t encoder_id, u16 vdisplay); /** - * Setup dither matix for pingpong block + * @setup_dither: Setup dither matix for pingpong block */ void (*setup_dither)(struct dpu_hw_pingpong *pp, struct dpu_hw_dither_cfg *cfg); /** - * Enable DSC + * @enable_dsc: Enable DSC */ int (*enable_dsc)(struct dpu_hw_pingpong *pp); /** - * Disable DSC + * @disable_dsc: Disable DSC */ void (*disable_dsc)(struct dpu_hw_pingpong *pp); /** - * Setup DSC + * @setup_dsc: Setup DSC */ int (*setup_dsc)(struct dpu_hw_pingpong *pp); }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c index 6ff4902fce08e..d3da700092343 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c @@ -147,11 +147,18 @@ static void dpu_hw_sspp_setup_multirect(struct dpu_sw_pipe *pipe) { struct dpu_hw_sspp *ctx = pipe->sspp; - u32 mode_mask; if (!ctx) return; + dpu_hw_setup_multirect_impl(pipe, ctx, SSPP_MULTIRECT_OPMODE); +} + +void dpu_hw_setup_multirect_impl(struct dpu_sw_pipe *pipe, + struct dpu_hw_sspp *ctx, u32 op_mode_off) +{ + u32 mode_mask; + if (pipe->multirect_index == DPU_SSPP_RECT_SOLO) { /** * if rect index is RECT_SOLO, we cannot expect a @@ -160,7 +167,7 @@ static void dpu_hw_sspp_setup_multirect(struct dpu_sw_pipe *pipe) */ mode_mask = 0; } else { - mode_mask = DPU_REG_READ(&ctx->hw, SSPP_MULTIRECT_OPMODE); + mode_mask = DPU_REG_READ(&ctx->hw, op_mode_off); mode_mask |= pipe->multirect_index; if (pipe->multirect_mode == DPU_SSPP_MULTIRECT_TIME_MX) mode_mask |= BIT(2); @@ -168,10 +175,10 @@ static void dpu_hw_sspp_setup_multirect(struct dpu_sw_pipe *pipe) mode_mask &= ~BIT(2); } - DPU_REG_WRITE(&ctx->hw, SSPP_MULTIRECT_OPMODE, mode_mask); + DPU_REG_WRITE(&ctx->hw, op_mode_off, mode_mask); } -static void _sspp_setup_opmode(struct dpu_hw_sspp *ctx, +void dpu_hw_sspp_setup_opmode(struct dpu_hw_sspp *ctx, u32 mask, u8 en) { const struct dpu_sspp_sub_blks *sblk = ctx->cap->sblk; @@ -191,7 +198,7 @@ static void _sspp_setup_opmode(struct dpu_hw_sspp *ctx, DPU_REG_WRITE(&ctx->hw, sblk->scaler_blk.base + SSPP_VIG_OP_MODE, opmode); } -static void _sspp_setup_csc10_opmode(struct dpu_hw_sspp *ctx, +void dpu_hw_sspp_setup_csc10_opmode(struct dpu_hw_sspp *ctx, u32 mask, u8 en) { const struct dpu_sspp_sub_blks *sblk = ctx->cap->sblk; @@ -213,10 +220,6 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, const struct msm_format *fmt, u32 flags) { struct dpu_hw_sspp *ctx = pipe->sspp; - struct dpu_hw_blk_reg_map *c; - u32 chroma_samp, unpack, src_format; - u32 opmode = 0; - u32 fast_clear = 0; u32 op_mode_off, unpack_pat_off, format_off, ubwc_ctrl_off, ubwc_error_off; if (!ctx || !fmt) @@ -244,6 +247,29 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, } } + if (fmt->fetch_mode != MDP_FETCH_LINEAR) { + u32 hbb = ctx->ubwc->highest_bank_bit - 13; + + DPU_REG_WRITE(&ctx->hw, SSPP_FETCH_CONFIG, + DPU_FETCH_CONFIG_RESET_VALUE | + hbb << 18); + } + + dpu_hw_setup_format_impl(pipe, fmt, flags, ctx, op_mode_off, + unpack_pat_off, format_off, + ubwc_ctrl_off, ubwc_error_off); +} + +void dpu_hw_setup_format_impl(struct dpu_sw_pipe *pipe, const struct msm_format *fmt, + u32 flags, struct dpu_hw_sspp *ctx, u32 op_mode_off, + u32 unpack_pat_off, u32 format_off, u32 ubwc_ctrl_off, + u32 ubwc_error_off) +{ + struct dpu_hw_blk_reg_map *c; + u32 chroma_samp, unpack, src_format; + u32 opmode; + u32 fast_clear; + c = &ctx->hw; opmode = DPU_REG_READ(c, op_mode_off); opmode &= ~(MDSS_MDP_OP_FLIP_LR | MDSS_MDP_OP_FLIP_UD | @@ -284,37 +310,37 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, if (fmt->fetch_mode != MDP_FETCH_LINEAR) { u32 hbb = ctx->ubwc->highest_bank_bit - 13; + u32 ctrl_val; if (MSM_FORMAT_IS_UBWC(fmt)) opmode |= MDSS_MDP_OP_BWC_EN; src_format |= (fmt->fetch_mode & 3) << 30; /*FRAME_FORMAT */ - DPU_REG_WRITE(c, SSPP_FETCH_CONFIG, - DPU_FETCH_CONFIG_RESET_VALUE | - hbb << 18); - switch (ctx->ubwc->ubwc_enc_version) { - case UBWC_1_0: + + if (ctx->ubwc->ubwc_enc_version == UBWC_1_0) { fast_clear = fmt->alpha_enable ? BIT(31) : 0; - DPU_REG_WRITE(c, ubwc_ctrl_off, - fast_clear | (ctx->ubwc->ubwc_swizzle & 0x1) | - BIT(8) | - (hbb << 4)); - break; - case UBWC_2_0: + ctrl_val = fast_clear | (ctx->ubwc->ubwc_swizzle & 0x1) | + BIT(8) | (hbb << 4); + } else if (ctx->ubwc->ubwc_enc_version == UBWC_2_0) { fast_clear = fmt->alpha_enable ? BIT(31) : 0; - DPU_REG_WRITE(c, ubwc_ctrl_off, - fast_clear | (ctx->ubwc->ubwc_swizzle) | - (hbb << 4)); - break; - case UBWC_3_0: - DPU_REG_WRITE(c, ubwc_ctrl_off, - BIT(30) | (ctx->ubwc->ubwc_swizzle) | - (hbb << 4)); - break; - case UBWC_4_0: - DPU_REG_WRITE(c, ubwc_ctrl_off, - MSM_FORMAT_IS_YUV(fmt) ? 0 : BIT(30)); - break; + ctrl_val = fast_clear | ctx->ubwc->ubwc_swizzle | (hbb << 4); + } else if (ctx->ubwc->ubwc_enc_version == UBWC_3_0) { + ctrl_val = BIT(30) | (ctx->ubwc->ubwc_swizzle) | (hbb << 4); + } else if (ctx->ubwc->ubwc_enc_version == UBWC_4_0) { + ctrl_val = MSM_FORMAT_IS_YUV(fmt) ? 0 : BIT(30); + } else if (ctx->ubwc->ubwc_enc_version <= UBWC_6_0) { + if (MSM_FORMAT_IS_YUV(fmt)) + ctrl_val = 0; + else if (MSM_FORMAT_IS_DX(fmt)) /* or FP16, but it's unsupported */ + ctrl_val = BIT(30); + else + ctrl_val = BIT(30) | BIT(31); + /* SDE also sets bits for lossy formats, but we don't support them yet */ + } else { + DRM_WARN_ONCE("Unsupported UBWC version %x\n", ctx->ubwc->ubwc_enc_version); + ctrl_val = 0; } + + DPU_REG_WRITE(c, ubwc_ctrl_off, ctrl_val); } opmode |= MDSS_MDP_OP_PE_OVERRIDE; @@ -328,10 +354,10 @@ static void dpu_hw_sspp_setup_format(struct dpu_sw_pipe *pipe, /* update scaler opmode, if appropriate */ if (test_bit(DPU_SSPP_CSC, &ctx->cap->features)) - _sspp_setup_opmode(ctx, VIG_OP_CSC_EN | VIG_OP_CSC_SRC_DATAFMT, + dpu_hw_sspp_setup_opmode(ctx, VIG_OP_CSC_EN | VIG_OP_CSC_SRC_DATAFMT, MSM_FORMAT_IS_YUV(fmt)); else if (test_bit(DPU_SSPP_CSC_10BIT, &ctx->cap->features)) - _sspp_setup_csc10_opmode(ctx, + dpu_hw_sspp_setup_csc10_opmode(ctx, VIG_CSC_10_EN | VIG_CSC_10_SRC_DATAFMT, MSM_FORMAT_IS_YUV(fmt)); @@ -400,7 +426,7 @@ static void dpu_hw_sspp_setup_pe_config(struct dpu_hw_sspp *ctx, tot_req_pixels[3]); } -static void _dpu_hw_sspp_setup_scaler3(struct dpu_hw_sspp *ctx, +void dpu_hw_sspp_setup_scaler3(struct dpu_hw_sspp *ctx, struct dpu_hw_scaler3_cfg *scaler3_cfg, const struct msm_format *format) { @@ -420,15 +446,11 @@ static void dpu_hw_sspp_setup_rects(struct dpu_sw_pipe *pipe, struct dpu_sw_pipe_cfg *cfg) { struct dpu_hw_sspp *ctx = pipe->sspp; - struct dpu_hw_blk_reg_map *c; - u32 src_size, src_xy, dst_size, dst_xy; u32 src_size_off, src_xy_off, out_size_off, out_xy_off; if (!ctx || !cfg) return; - c = &ctx->hw; - if (pipe->multirect_index == DPU_SSPP_RECT_SOLO || pipe->multirect_index == DPU_SSPP_RECT_0) { src_size_off = SSPP_SRC_SIZE; @@ -442,20 +464,8 @@ static void dpu_hw_sspp_setup_rects(struct dpu_sw_pipe *pipe, out_xy_off = SSPP_OUT_XY_REC1; } - - /* src and dest rect programming */ - src_xy = (cfg->src_rect.y1 << 16) | cfg->src_rect.x1; - src_size = (drm_rect_height(&cfg->src_rect) << 16) | - drm_rect_width(&cfg->src_rect); - dst_xy = (cfg->dst_rect.y1 << 16) | cfg->dst_rect.x1; - dst_size = (drm_rect_height(&cfg->dst_rect) << 16) | - drm_rect_width(&cfg->dst_rect); - - /* rectangle register programming */ - DPU_REG_WRITE(c, src_size_off, src_size); - DPU_REG_WRITE(c, src_xy_off, src_xy); - DPU_REG_WRITE(c, out_size_off, dst_size); - DPU_REG_WRITE(c, out_xy_off, dst_xy); + dpu_hw_setup_rects_impl(pipe, cfg, ctx, src_size_off, + src_xy_off, out_size_off, out_xy_off); } static void dpu_hw_sspp_setup_sourceaddress(struct dpu_sw_pipe *pipe, @@ -512,7 +522,7 @@ static void dpu_hw_sspp_setup_sourceaddress(struct dpu_sw_pipe *pipe, DPU_REG_WRITE(&ctx->hw, SSPP_SRC_YSTRIDE1, ystride1); } -static void dpu_hw_sspp_setup_csc(struct dpu_hw_sspp *ctx, +void dpu_hw_sspp_setup_csc(struct dpu_hw_sspp *ctx, const struct dpu_csc_cfg *data) { u32 offset; @@ -534,21 +544,31 @@ static void dpu_hw_sspp_setup_csc(struct dpu_hw_sspp *ctx, static void dpu_hw_sspp_setup_solidfill(struct dpu_sw_pipe *pipe, u32 color) { struct dpu_hw_sspp *ctx = pipe->sspp; - struct dpu_hw_fmt_layout cfg; + u32 const_clr_off; if (!ctx) return; + if (pipe->multirect_index == DPU_SSPP_RECT_SOLO || + pipe->multirect_index == DPU_SSPP_RECT_0) + const_clr_off = SSPP_SRC_CONSTANT_COLOR; + else + const_clr_off = SSPP_SRC_CONSTANT_COLOR_REC1; + + dpu_hw_setup_solidfill_impl(pipe, color, ctx, const_clr_off); +} + +void dpu_hw_setup_solidfill_impl(struct dpu_sw_pipe *pipe, + u32 color, struct dpu_hw_sspp *ctx, + u32 const_clr_off) +{ + struct dpu_hw_fmt_layout cfg; + /* cleanup source addresses */ memset(&cfg, 0, sizeof(cfg)); ctx->ops.setup_sourceaddress(pipe, &cfg); - if (pipe->multirect_index == DPU_SSPP_RECT_SOLO || - pipe->multirect_index == DPU_SSPP_RECT_0) - DPU_REG_WRITE(&ctx->hw, SSPP_SRC_CONSTANT_COLOR, color); - else - DPU_REG_WRITE(&ctx->hw, SSPP_SRC_CONSTANT_COLOR_REC1, - color); + DPU_REG_WRITE(&ctx->hw, const_clr_off, color); } static void dpu_hw_sspp_setup_qos_lut(struct dpu_hw_sspp *ctx, @@ -562,14 +582,20 @@ static void dpu_hw_sspp_setup_qos_lut(struct dpu_hw_sspp *ctx, cfg); } +void dpu_hw_sspp_setup_qos_ctrl_impl(struct dpu_hw_sspp *ctx, + bool danger_safe_en, u32 ctrl_off) +{ + DPU_REG_WRITE(&ctx->hw, ctrl_off, + danger_safe_en ? SSPP_QOS_CTRL_DANGER_SAFE_EN : 0); +} + static void dpu_hw_sspp_setup_qos_ctrl(struct dpu_hw_sspp *ctx, bool danger_safe_en) { if (!ctx) return; - DPU_REG_WRITE(&ctx->hw, SSPP_QOS_CTRL, - danger_safe_en ? SSPP_QOS_CTRL_DANGER_SAFE_EN : 0); + dpu_hw_sspp_setup_qos_ctrl_impl(ctx, danger_safe_en, SSPP_QOS_CTRL); } static void dpu_hw_sspp_setup_cdp(struct dpu_sw_pipe *pipe, @@ -624,7 +650,7 @@ static void _setup_layer_ops(struct dpu_hw_sspp *c, c->ops.setup_multirect = dpu_hw_sspp_setup_multirect; if (test_bit(DPU_SSPP_SCALER_QSEED3_COMPATIBLE, &features)) - c->ops.setup_scaler = _dpu_hw_sspp_setup_scaler3; + c->ops.setup_scaler = dpu_hw_sspp_setup_scaler3; if (test_bit(DPU_SSPP_CDP, &features)) c->ops.setup_cdp = dpu_hw_sspp_setup_cdp; @@ -721,7 +747,10 @@ struct dpu_hw_sspp *dpu_hw_sspp_init(struct drm_device *dev, hw_pipe->mdss_ver = mdss_rev; - _setup_layer_ops(hw_pipe, hw_pipe->cap->features, mdss_rev); + if (mdss_rev->core_major_ver >= 13) + dpu_hw_sspp_init_v13(hw_pipe, hw_pipe->cap->features, mdss_rev); + else + _setup_layer_ops(hw_pipe, hw_pipe->cap->features, mdss_rev); return hw_pipe; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h index bdac5c04bf790..69d68cc916b2e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h @@ -14,7 +14,7 @@ struct dpu_hw_sspp; #define DPU_SSPP_MAX_PITCH_SIZE 0xffff -/** +/* * Flags */ #define DPU_SSPP_FLIP_LR BIT(0) @@ -23,7 +23,7 @@ struct dpu_hw_sspp; #define DPU_SSPP_ROT_90 BIT(3) #define DPU_SSPP_SOLID_FILL BIT(4) -/** +/* * Component indices */ enum { @@ -36,9 +36,10 @@ enum { }; /** - * DPU_SSPP_RECT_SOLO - multirect disabled - * DPU_SSPP_RECT_0 - rect0 of a multirect pipe - * DPU_SSPP_RECT_1 - rect1 of a multirect pipe + * enum dpu_sspp_multirect_index - multirect mode + * @DPU_SSPP_RECT_SOLO: multirect disabled + * @DPU_SSPP_RECT_0: rect0 of a multirect pipe + * @DPU_SSPP_RECT_1: rect1 of a multirect pipe * * Note: HW supports multirect with either RECT0 or * RECT1. Considering no benefit of such configs over @@ -143,7 +144,7 @@ struct dpu_hw_pixel_ext { * struct dpu_sw_pipe_cfg : software pipe configuration * @src_rect: src ROI, caller takes into account the different operations * such as decimation, flip etc to program this field - * @dest_rect: destination ROI. + * @dst_rect: destination ROI. * @rotation: simplified drm rotation hint */ struct dpu_sw_pipe_cfg { @@ -165,8 +166,8 @@ struct dpu_hw_pipe_ts_cfg { /** * struct dpu_sw_pipe - software pipe description * @sspp: backing SSPP pipe - * @index: index of the rectangle of SSPP - * @mode: parallel or time multiplex multirect mode + * @multirect_index: index of the rectangle of SSPP + * @multirect_mode: parallel or time multiplex multirect mode */ struct dpu_sw_pipe { struct dpu_hw_sspp *sspp; @@ -181,7 +182,7 @@ struct dpu_sw_pipe { */ struct dpu_hw_sspp_ops { /** - * setup_format - setup pixel format cropping rectangle, flip + * @setup_format: setup pixel format cropping rectangle, flip * @pipe: Pointer to software pipe context * @cfg: Pointer to pipe config structure * @flags: Extra flags for format config @@ -190,7 +191,7 @@ struct dpu_hw_sspp_ops { const struct msm_format *fmt, u32 flags); /** - * setup_rects - setup pipe ROI rectangles + * @setup_rects: setup pipe ROI rectangles * @pipe: Pointer to software pipe context * @cfg: Pointer to pipe config structure */ @@ -198,7 +199,7 @@ struct dpu_hw_sspp_ops { struct dpu_sw_pipe_cfg *cfg); /** - * setup_pe - setup pipe pixel extension + * @setup_pe: setup pipe pixel extension * @ctx: Pointer to pipe context * @pe_ext: Pointer to pixel ext settings */ @@ -206,7 +207,7 @@ struct dpu_hw_sspp_ops { struct dpu_hw_pixel_ext *pe_ext); /** - * setup_sourceaddress - setup pipe source addresses + * @setup_sourceaddress: setup pipe source addresses * @pipe: Pointer to software pipe context * @layout: format layout information for programming buffer to hardware */ @@ -214,14 +215,14 @@ struct dpu_hw_sspp_ops { struct dpu_hw_fmt_layout *layout); /** - * setup_csc - setup color space coversion + * @setup_csc: setup color space coversion * @ctx: Pointer to pipe context * @data: Pointer to config structure */ void (*setup_csc)(struct dpu_hw_sspp *ctx, const struct dpu_csc_cfg *data); /** - * setup_solidfill - enable/disable colorfill + * @setup_solidfill: enable/disable colorfill * @pipe: Pointer to software pipe context * @const_color: Fill color value * @flags: Pipe flags @@ -229,23 +230,22 @@ struct dpu_hw_sspp_ops { void (*setup_solidfill)(struct dpu_sw_pipe *pipe, u32 color); /** - * setup_multirect - setup multirect configuration + * @setup_multirect: setup multirect configuration * @pipe: Pointer to software pipe context */ void (*setup_multirect)(struct dpu_sw_pipe *pipe); /** - * setup_sharpening - setup sharpening + * @setup_sharpening: setup sharpening * @ctx: Pointer to pipe context * @cfg: Pointer to config structure */ void (*setup_sharpening)(struct dpu_hw_sspp *ctx, struct dpu_hw_sharp_cfg *cfg); - /** - * setup_qos_lut - setup QoS LUTs + * @setup_qos_lut: setup QoS LUTs * @ctx: Pointer to pipe context * @cfg: LUT configuration */ @@ -253,7 +253,7 @@ struct dpu_hw_sspp_ops { struct dpu_hw_qos_cfg *cfg); /** - * setup_qos_ctrl - setup QoS control + * @setup_qos_ctrl: setup QoS control * @ctx: Pointer to pipe context * @danger_safe_en: flags controlling enabling of danger/safe QoS/LUT */ @@ -261,7 +261,7 @@ struct dpu_hw_sspp_ops { bool danger_safe_en); /** - * setup_clk_force_ctrl - setup clock force control + * @setup_clk_force_ctrl: setup clock force control * @ctx: Pointer to pipe context * @enable: enable clock force if true */ @@ -269,7 +269,7 @@ struct dpu_hw_sspp_ops { bool enable); /** - * setup_histogram - setup histograms + * @setup_histogram: setup histograms * @ctx: Pointer to pipe context * @cfg: Pointer to histogram configuration */ @@ -277,7 +277,7 @@ struct dpu_hw_sspp_ops { void *cfg); /** - * setup_scaler - setup scaler + * @setup_scaler: setup scaler * @scaler3_cfg: Pointer to scaler configuration * @format: pixel format parameters */ @@ -286,7 +286,7 @@ struct dpu_hw_sspp_ops { const struct msm_format *format); /** - * setup_cdp - setup client driven prefetch + * @setup_cdp: setup client driven prefetch * @pipe: Pointer to software pipe context * @fmt: format used by the sw pipe * @enable: whether the CDP should be enabled for this pipe @@ -303,6 +303,7 @@ struct dpu_hw_sspp_ops { * @ubwc: UBWC configuration data * @idx: pipe index * @cap: pointer to layer_cfg + * @mdss_ver: MDSS version info to use for feature checks * @ops: pointer to operations possible for this pipe */ struct dpu_hw_sspp { @@ -331,5 +332,61 @@ struct dpu_hw_sspp *dpu_hw_sspp_init(struct drm_device *dev, int _dpu_hw_sspp_init_debugfs(struct dpu_hw_sspp *hw_pipe, struct dpu_kms *kms, struct dentry *entry); +void dpu_hw_sspp_setup_opmode(struct dpu_hw_sspp *ctx, + u32 mask, u8 en); + +void dpu_hw_sspp_setup_csc10_opmode(struct dpu_hw_sspp *ctx, + u32 mask, u8 en); + +void dpu_hw_sspp_setup_scaler3(struct dpu_hw_sspp *ctx, + struct dpu_hw_scaler3_cfg *scaler3_cfg, + const struct msm_format *format); + +void dpu_hw_sspp_setup_csc(struct dpu_hw_sspp *ctx, + const struct dpu_csc_cfg *data); + +void dpu_hw_setup_multirect_impl(struct dpu_sw_pipe *pipe, + struct dpu_hw_sspp *ctx, + u32 op_mode_off); + +void dpu_hw_setup_format_impl(struct dpu_sw_pipe *pipe, const struct msm_format *fmt, + u32 flags, struct dpu_hw_sspp *ctx, + u32 op_mode_off, u32 unpack_pat_off, u32 format_off, + u32 ubwc_ctrl_off, u32 ubwc_err_off); + +static inline void dpu_hw_setup_rects_impl(struct dpu_sw_pipe *pipe, struct dpu_sw_pipe_cfg *cfg, + struct dpu_hw_sspp *ctx, u32 src_size_off, + u32 src_xy_off, u32 out_size_off, u32 out_xy_off) +{ + struct dpu_hw_blk_reg_map *c; + u32 src_size, src_xy, dst_size, dst_xy; + + c = &ctx->hw; + + /* src and dest rect programming */ + src_xy = (cfg->src_rect.y1 << 16) | cfg->src_rect.x1; + src_size = (drm_rect_height(&cfg->src_rect) << 16) | + drm_rect_width(&cfg->src_rect); + dst_xy = (cfg->dst_rect.y1 << 16) | cfg->dst_rect.x1; + dst_size = (drm_rect_height(&cfg->dst_rect) << 16) | + drm_rect_width(&cfg->dst_rect); + + /* rectangle register programming */ + DPU_REG_WRITE(c, src_size_off, src_size); + DPU_REG_WRITE(c, src_xy_off, src_xy); + DPU_REG_WRITE(c, out_size_off, dst_size); + DPU_REG_WRITE(c, out_xy_off, dst_xy); +} + +void dpu_hw_setup_solidfill_impl(struct dpu_sw_pipe *pipe, + u32 color, struct dpu_hw_sspp *ctx, u32 const_clr_off); + +void dpu_hw_sspp_setup_qos_ctrl_impl(struct dpu_hw_sspp *ctx, + bool danger_safe_en, u32 ctrl_off); + +void dpu_hw_sspp_init_v13(struct dpu_hw_sspp *c, + unsigned long features, + const struct dpu_mdss_version *mdss_rev); + #endif /*_DPU_HW_SSPP_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp_v13.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp_v13.c new file mode 100644 index 0000000000000..f8f96ad971d78 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp_v13.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include + +#include "dpu_hw_sspp.h" + +/* >= v13 DPU */ +/* CMN Registers -> Source Surface Processing Pipe Common SSPP registers */ +/* Name Offset */ +#define SSPP_CMN_CLK_CTRL 0x0 +#define SSPP_CMN_CLK_STATUS 0x4 +#define SSPP_CMN_MULTI_REC_OP_MODE 0x10 +#define SSPP_CMN_ADDR_CONFIG 0x14 +#define SSPP_CMN_CAC_CTRL 0x20 +#define SSPP_CMN_SYS_CACHE_MODE 0x24 +#define SSPP_CMN_QOS_CTRL 0x28 + +#define SSPP_CMN_FILL_LEVEL_SCALE 0x3c +#define SSPP_CMN_FILL_LEVELS 0x40 +#define SSPP_CMN_STATUS 0x44 +#define SSPP_CMN_FETCH_DMA_RD_OTS 0x48 +#define SSPP_CMN_FETCH_DTB_WR_PLANE0 0x4c +#define SSPP_CMN_FETCH_DTB_WR_PLANE1 0x50 +#define SSPP_CMN_FETCH_DTB_WR_PLANE2 0x54 +#define SSPP_CMN_DTB_UNPACK_RD_PLANE0 0x58 +#define SSPP_CMN_DTB_UNPACK_RD_PLANE1 0x5c +#define SSPP_CMN_DTB_UNPACK_RD_PLANE2 0x60 +#define SSPP_CMN_UNPACK_LINE_COUNT 0x64 +#define SSPP_CMN_TPG_CONTROL 0x68 +#define SSPP_CMN_TPG_CONFIG 0x6c +#define SSPP_CMN_TPG_COMPONENT_LIMITS 0x70 +#define SSPP_CMN_TPG_RECTANGLE 0x74 +#define SSPP_CMN_TPG_BLACK_WHITE_PATTERN_FRAMES 0x78 +#define SSPP_CMN_TPG_RGB_MAPPING 0x7c +#define SSPP_CMN_TPG_PATTERN_GEN_INIT_VAL 0x80 + +/*RECRegisterset*/ +/*Name Offset*/ +#define SSPP_REC_SRC_FORMAT 0x0 +#define SSPP_REC_SRC_UNPACK_PATTERN 0x4 +#define SSPP_REC_SRC_OP_MODE 0x8 +#define SSPP_REC_SRC_CONSTANT_COLOR 0xc +#define SSPP_REC_SRC_IMG_SIZE 0x10 +#define SSPP_REC_SRC_SIZE 0x14 +#define SSPP_REC_SRC_XY 0x18 +#define SSPP_REC_OUT_SIZE 0x1c +#define SSPP_REC_OUT_XY 0x20 +#define SSPP_REC_SW_PIX_EXT_LR 0x24 +#define SSPP_REC_SW_PIX_EXT_TB 0x28 +#define SSPP_REC_SRC_SIZE_ODX 0x30 +#define SSPP_REC_SRC_XY_ODX 0x34 +#define SSPP_REC_OUT_SIZE_ODX 0x38 +#define SSPP_REC_OUT_XY_ODX 0x3c +#define SSPP_REC_SW_PIX_EXT_LR_ODX 0x40 +#define SSPP_REC_SW_PIX_EXT_TB_ODX 0x44 +#define SSPP_REC_PRE_DOWN_SCALE 0x48 +#define SSPP_REC_SRC0_ADDR 0x4c +#define SSPP_REC_SRC1_ADDR 0x50 +#define SSPP_REC_SRC2_ADDR 0x54 +#define SSPP_REC_SRC3_ADDR 0x58 +#define SSPP_REC_SRC_YSTRIDE0 0x5c +#define SSPP_REC_SRC_YSTRIDE1 0x60 +#define SSPP_REC_CURRENT_SRC0_ADDR 0x64 +#define SSPP_REC_CURRENT_SRC1_ADDR 0x68 +#define SSPP_REC_CURRENT_SRC2_ADDR 0x6c +#define SSPP_REC_CURRENT_SRC3_ADDR 0x70 +#define SSPP_REC_SRC_ADDR_SW_STATUS 0x74 +#define SSPP_REC_CDP_CNTL 0x78 +#define SSPP_REC_TRAFFIC_SHAPER 0x7c +#define SSPP_REC_TRAFFIC_SHAPER_PREFILL 0x80 +#define SSPP_REC_PD_MEM_ALLOC 0x84 +#define SSPP_REC_QOS_CLAMP 0x88 +#define SSPP_REC_UIDLE_CTRL_VALUE 0x8c +#define SSPP_REC_UBWC_STATIC_CTRL 0x90 +#define SSPP_REC_UBWC_STATIC_CTRL_OVERRIDE 0x94 +#define SSPP_REC_UBWC_STATS_ROI 0x98 +#define SSPP_REC_UBWC_STATS_WORST_TILE_ROW_BW_ROI0 0x9c +#define SSPP_REC_UBWC_STATS_TOTAL_BW_ROI0 0xa0 +#define SSPP_REC_UBWC_STATS_WORST_TILE_ROW_BW_ROI1 0xa4 +#define SSPP_REC_UBWC_STATS_TOTAL_BW_ROI1 0xa8 +#define SSPP_REC_UBWC_STATS_WORST_TILE_ROW_BW_ROI2 0xac +#define SSPP_REC_UBWC_STATS_TOTAL_BW_ROI2 0xb0 +#define SSPP_REC_EXCL_REC_CTRL 0xb4 +#define SSPP_REC_EXCL_REC_SIZE 0xb8 +#define SSPP_REC_EXCL_REC_XY 0xbc +#define SSPP_REC_LINE_INSERTION_CTRL 0xc0 +#define SSPP_REC_LINE_INSERTION_OUT_SIZE 0xc4 +#define SSPP_REC_FETCH_PIPE_ACTIVE 0xc8 +#define SSPP_REC_META_ERROR_STATUS 0xcc +#define SSPP_REC_UBWC_ERROR_STATUS 0xd0 +#define SSPP_REC_FLUSH_CTRL 0xd4 +#define SSPP_REC_INTR_EN 0xd8 +#define SSPP_REC_INTR_STATUS 0xdc +#define SSPP_REC_INTR_CLEAR 0xe0 +#define SSPP_REC_HSYNC_STATUS 0xe4 +#define SSPP_REC_FP16_CONFIG 0x150 +#define SSPP_REC_FP16_CSC_MATRIX_COEFF_R_0 0x154 +#define SSPP_REC_FP16_CSC_MATRIX_COEFF_R_1 0x158 +#define SSPP_REC_FP16_CSC_MATRIX_COEFF_G_0 0x15c +#define SSPP_REC_FP16_CSC_MATRIX_COEFF_G_1 0x160 +#define SSPP_REC_FP16_CSC_MATRIX_COEFF_B_0 0x164 +#define SSPP_REC_FP16_CSC_MATRIX_COEFF_B_1 0x168 +#define SSPP_REC_FP16_CSC_PRE_CLAMP_R 0x16c +#define SSPP_REC_FP16_CSC_PRE_CLAMP_G 0x170 +#define SSPP_REC_FP16_CSC_PRE_CLAMP_B 0x174 +#define SSPP_REC_FP16_CSC_POST_CLAMP 0x178 + +static inline u32 dpu_hw_sspp_calculate_rect_off(enum dpu_sspp_multirect_index rect_index, + struct dpu_hw_sspp *ctx) +{ + return (rect_index == DPU_SSPP_RECT_SOLO || rect_index == DPU_SSPP_RECT_0) ? + ctx->cap->sblk->sspp_rec0_blk.base : ctx->cap->sblk->sspp_rec1_blk.base; +} + +static void dpu_hw_sspp_setup_multirect_v13(struct dpu_sw_pipe *pipe) +{ + struct dpu_hw_sspp *ctx = pipe->sspp; + + if (!ctx) + return; + + dpu_hw_setup_multirect_impl(pipe, ctx, SSPP_CMN_MULTI_REC_OP_MODE); +} + +static void dpu_hw_sspp_setup_format_v13(struct dpu_sw_pipe *pipe, + const struct msm_format *fmt, u32 flags) +{ + struct dpu_hw_sspp *ctx = pipe->sspp; + u32 op_mode_off, unpack_pat_off, format_off; + u32 ubwc_ctrl_off, ubwc_err_off; + u32 offset; + + if (!ctx || !fmt) + return; + + offset = dpu_hw_sspp_calculate_rect_off(pipe->multirect_index, ctx); + + op_mode_off = offset + SSPP_REC_SRC_OP_MODE; + unpack_pat_off = offset + SSPP_REC_SRC_UNPACK_PATTERN; + format_off = offset + SSPP_REC_SRC_FORMAT; + ubwc_ctrl_off = offset + SSPP_REC_UBWC_STATIC_CTRL; + ubwc_err_off = offset + SSPP_REC_UBWC_ERROR_STATUS; + + dpu_hw_setup_format_impl(pipe, fmt, flags, ctx, op_mode_off, + unpack_pat_off, format_off, ubwc_ctrl_off, ubwc_err_off); +} + +static void dpu_hw_sspp_setup_pe_config_v13(struct dpu_hw_sspp *ctx, + struct dpu_hw_pixel_ext *pe_ext) +{ + struct dpu_hw_blk_reg_map *c; + u8 color; + u32 lr_pe[4], tb_pe[4]; + const u32 bytemask = 0xff; + u32 offset; + + if (!ctx || !pe_ext) + return; + + offset = ctx->cap->sblk->sspp_rec0_blk.base; + + c = &ctx->hw; + /* program SW pixel extension override for all pipes*/ + for (color = 0; color < DPU_MAX_PLANES; color++) { + /* color 2 has the same set of registers as color 1 */ + if (color == 2) + continue; + + lr_pe[color] = ((pe_ext->right_ftch[color] & bytemask) << 24) | + ((pe_ext->right_rpt[color] & bytemask) << 16) | + ((pe_ext->left_ftch[color] & bytemask) << 8) | + (pe_ext->left_rpt[color] & bytemask); + + tb_pe[color] = ((pe_ext->btm_ftch[color] & bytemask) << 24) | + ((pe_ext->btm_rpt[color] & bytemask) << 16) | + ((pe_ext->top_ftch[color] & bytemask) << 8) | + (pe_ext->top_rpt[color] & bytemask); + } + + /* color 0 */ + DPU_REG_WRITE(c, SSPP_REC_SW_PIX_EXT_LR + offset, lr_pe[0]); + DPU_REG_WRITE(c, SSPP_REC_SW_PIX_EXT_TB + offset, tb_pe[0]); + + /* color 1 and color 2 */ + DPU_REG_WRITE(c, SSPP_REC_SW_PIX_EXT_LR_ODX + offset, lr_pe[1]); + DPU_REG_WRITE(c, SSPP_REC_SW_PIX_EXT_TB_ODX + offset, tb_pe[1]); +} + +static void dpu_hw_sspp_setup_rects_v13(struct dpu_sw_pipe *pipe, + struct dpu_sw_pipe_cfg *cfg) +{ + struct dpu_hw_sspp *ctx = pipe->sspp; + u32 src_size_off, src_xy_off, out_size_off, out_xy_off; + u32 offset; + + if (!ctx || !cfg) + return; + + offset = dpu_hw_sspp_calculate_rect_off(pipe->multirect_index, ctx); + + src_size_off = offset + SSPP_REC_SRC_SIZE; + src_xy_off = offset + SSPP_REC_SRC_XY; + out_size_off = offset + SSPP_REC_OUT_SIZE; + out_xy_off = offset + SSPP_REC_OUT_XY; + + dpu_hw_setup_rects_impl(pipe, cfg, ctx, src_size_off, + src_xy_off, out_size_off, out_xy_off); +} + +static void dpu_hw_sspp_setup_sourceaddress_v13(struct dpu_sw_pipe *pipe, + struct dpu_hw_fmt_layout *layout) +{ + struct dpu_hw_sspp *ctx = pipe->sspp; + int i; + u32 offset, ystride0, ystride1; + + if (!ctx) + return; + + offset = dpu_hw_sspp_calculate_rect_off(pipe->multirect_index, ctx); + + for (i = 0; i < ARRAY_SIZE(layout->plane_addr); i++) + DPU_REG_WRITE(&ctx->hw, offset + SSPP_REC_SRC0_ADDR + i * 0x4, + layout->plane_addr[i]); + + ystride0 = (layout->plane_pitch[0]) | (layout->plane_pitch[2] << 16); + ystride1 = (layout->plane_pitch[1]) | (layout->plane_pitch[3] << 16); + + DPU_REG_WRITE(&ctx->hw, offset + SSPP_REC_SRC_YSTRIDE0, ystride0); + DPU_REG_WRITE(&ctx->hw, offset + SSPP_REC_SRC_YSTRIDE1, ystride1); +} + +static void dpu_hw_sspp_setup_solidfill_v13(struct dpu_sw_pipe *pipe, u32 color) +{ + struct dpu_hw_sspp *ctx = pipe->sspp; + u32 const_clr_off; + u32 offset; + + if (!ctx) + return; + + offset = dpu_hw_sspp_calculate_rect_off(pipe->multirect_index, ctx); + const_clr_off = offset + SSPP_REC_SRC_CONSTANT_COLOR; + + dpu_hw_setup_solidfill_impl(pipe, color, ctx, const_clr_off); +} + +static void dpu_hw_sspp_setup_qos_lut_v13(struct dpu_hw_sspp *ctx, + struct dpu_hw_qos_cfg *cfg) +{ + if (!ctx || !cfg) + return; + + dpu_hw_setup_qos_lut_v13(&ctx->hw, cfg); +} + +static void dpu_hw_sspp_setup_qos_ctrl_v13(struct dpu_hw_sspp *ctx, + bool danger_safe_en) +{ + if (!ctx) + return; + + dpu_hw_sspp_setup_qos_ctrl_impl(ctx, danger_safe_en, SSPP_CMN_QOS_CTRL); +} + +static void dpu_hw_sspp_setup_cdp_v13(struct dpu_sw_pipe *pipe, + const struct msm_format *fmt, + bool enable) +{ + struct dpu_hw_sspp *ctx = pipe->sspp; + u32 offset = 0; + + if (!ctx) + return; + + offset = dpu_hw_sspp_calculate_rect_off(pipe->multirect_index, ctx); + dpu_setup_cdp(&ctx->hw, offset + SSPP_REC_CDP_CNTL, fmt, enable); +} + +static bool dpu_hw_sspp_setup_clk_force_ctrl_v13(struct dpu_hw_sspp *ctx, bool enable) +{ + static const struct dpu_clk_ctrl_reg sspp_clk_ctrl = { + .reg_off = SSPP_CMN_CLK_CTRL, + .bit_off = 0 + }; + + return dpu_hw_clk_force_ctrl(&ctx->hw, &sspp_clk_ctrl, enable); +} + +void dpu_hw_sspp_init_v13(struct dpu_hw_sspp *c, + unsigned long features, const struct dpu_mdss_version *mdss_rev) +{ + c->ops.setup_format = dpu_hw_sspp_setup_format_v13; + c->ops.setup_rects = dpu_hw_sspp_setup_rects_v13; + c->ops.setup_sourceaddress = dpu_hw_sspp_setup_sourceaddress_v13; + c->ops.setup_solidfill = dpu_hw_sspp_setup_solidfill_v13; + c->ops.setup_pe = dpu_hw_sspp_setup_pe_config_v13; + + if (test_bit(DPU_SSPP_QOS, &features)) { + c->ops.setup_qos_lut = dpu_hw_sspp_setup_qos_lut_v13; + c->ops.setup_qos_ctrl = dpu_hw_sspp_setup_qos_ctrl_v13; + } + + if (test_bit(DPU_SSPP_CSC, &features) || + test_bit(DPU_SSPP_CSC_10BIT, &features)) + c->ops.setup_csc = dpu_hw_sspp_setup_csc; + + if (test_bit(DPU_SSPP_SMART_DMA_V1, &c->cap->features) || + test_bit(DPU_SSPP_SMART_DMA_V2, &c->cap->features)) + c->ops.setup_multirect = dpu_hw_sspp_setup_multirect_v13; + + if (test_bit(DPU_SSPP_SCALER_QSEED3_COMPATIBLE, &features)) + c->ops.setup_scaler = dpu_hw_sspp_setup_scaler3; + + if (test_bit(DPU_SSPP_CDP, &features)) + c->ops.setup_cdp = dpu_hw_sspp_setup_cdp_v13; + + c->ops.setup_clk_force_ctrl = dpu_hw_sspp_setup_clk_force_ctrl_v13; +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h index 04efdcd21ceb0..80279d87c2cde 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h @@ -77,12 +77,11 @@ enum dpu_dp_phy_sel { /** * struct dpu_hw_mdp_ops - interface to the MDP TOP Hw driver functions * Assumption is these functions will be called after clocks are enabled. - * @setup_split_pipe : Programs the pipe control registers - * @setup_pp_split : Programs the pp split control registers - * @setup_traffic_shaper : programs traffic shaper control */ struct dpu_hw_mdp_ops { - /** setup_split_pipe() : Registers are not double buffered, thisk + /** + * @setup_split_pipe : Programs the pipe control registers. + * Registers are not double buffered, this * function should be called before timing control enable * @mdp : mdp top context driver * @cfg : upper and lower part of pipe configuration @@ -91,7 +90,7 @@ struct dpu_hw_mdp_ops { struct split_pipe_cfg *p); /** - * setup_traffic_shaper() : Setup traffic shaper control + * @setup_traffic_shaper : programs traffic shaper control. * @mdp : mdp top context driver * @cfg : traffic shaper configuration */ @@ -99,7 +98,7 @@ struct dpu_hw_mdp_ops { struct traffic_shaper_cfg *cfg); /** - * setup_clk_force_ctrl - set clock force control + * @setup_clk_force_ctrl: set clock force control * @mdp: mdp top context driver * @clk_ctrl: clock to be controlled * @enable: force on enable @@ -109,7 +108,7 @@ struct dpu_hw_mdp_ops { enum dpu_clk_ctrl_type clk_ctrl, bool enable); /** - * get_danger_status - get danger status + * @get_danger_status: get danger status * @mdp: mdp top context driver * @status: Pointer to danger safe status */ @@ -117,7 +116,7 @@ struct dpu_hw_mdp_ops { struct dpu_danger_safe_status *status); /** - * setup_vsync_source - setup vsync source configuration details + * @setup_vsync_source: setup vsync source configuration details * @mdp: mdp top context driver * @cfg: vsync source selection configuration */ @@ -125,7 +124,7 @@ struct dpu_hw_mdp_ops { struct dpu_vsync_source_cfg *cfg); /** - * get_safe_status - get safe status + * @get_safe_status: get safe status * @mdp: mdp top context driver * @status: Pointer to danger safe status */ @@ -133,14 +132,14 @@ struct dpu_hw_mdp_ops { struct dpu_danger_safe_status *status); /** - * dp_phy_intf_sel - configure intf to phy mapping + * @dp_phy_intf_sel: configure intf to phy mapping * @mdp: mdp top context driver * @phys: list of phys the DP interfaces should be connected to. 0 disables the INTF. */ void (*dp_phy_intf_sel)(struct dpu_hw_mdp *mdp, enum dpu_dp_phy_sel phys[2]); /** - * intf_audio_select - select the external interface for audio + * @intf_audio_select: select the external interface for audio * @mdp: mdp top context driver */ void (*intf_audio_select)(struct dpu_hw_mdp *mdp); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c index 486be346d40d8..c7a5f4a0d0541 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c @@ -81,6 +81,13 @@ static u32 dpu_hw_util_log_mask = DPU_DBG_MASK_NONE; #define QOS_CREQ_LUT_0 0x14 #define QOS_CREQ_LUT_1 0x18 +/* CMN_QOS_LUT */ +#define SSPP_CMN_QOS_CTRL 0x28 +#define SSPP_CMN_DANGER_LUT 0x2c +#define SSPP_CMN_SAFE_LUT 0x30 +#define SSPP_CMN_CREQ_LUT_0 0x34 +#define SSPP_CMN_CREQ_LUT_1 0x38 + /* QOS_QOS_CTRL */ #define QOS_QOS_CTRL_DANGER_SAFE_EN BIT(0) #define QOS_QOS_CTRL_DANGER_VBLANK_MASK GENMASK(5, 4) @@ -475,6 +482,17 @@ void _dpu_hw_setup_qos_lut(struct dpu_hw_blk_reg_map *c, u32 offset, cfg->danger_safe_en ? QOS_QOS_CTRL_DANGER_SAFE_EN : 0); } +void dpu_hw_setup_qos_lut_v13(struct dpu_hw_blk_reg_map *c, + const struct dpu_hw_qos_cfg *cfg) +{ + DPU_REG_WRITE(c, SSPP_CMN_DANGER_LUT, cfg->danger_lut); + DPU_REG_WRITE(c, SSPP_CMN_SAFE_LUT, cfg->safe_lut); + DPU_REG_WRITE(c, SSPP_CMN_CREQ_LUT_0, cfg->creq_lut); + DPU_REG_WRITE(c, SSPP_CMN_CREQ_LUT_1, cfg->creq_lut >> 32); + DPU_REG_WRITE(c, SSPP_CMN_QOS_CTRL, + cfg->danger_safe_en ? QOS_QOS_CTRL_DANGER_SAFE_EN : 0); +} + /* * note: Aside from encoders, input_sel should be set to 0x0 by default */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h index 6fe65bc3bff4e..628befc65ce35 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h @@ -367,6 +367,9 @@ void _dpu_hw_setup_qos_lut(struct dpu_hw_blk_reg_map *c, u32 offset, bool qos_8lvl, const struct dpu_hw_qos_cfg *cfg); +void dpu_hw_setup_qos_lut_v13(struct dpu_hw_blk_reg_map *c, + const struct dpu_hw_qos_cfg *cfg); + void dpu_hw_setup_misr(struct dpu_hw_blk_reg_map *c, u32 misr_ctrl_offset, u8 input_sel); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h index 285121ec804cc..9ac49448e4325 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h @@ -17,7 +17,7 @@ struct dpu_hw_vbif; */ struct dpu_hw_vbif_ops { /** - * set_limit_conf - set transaction limit config + * @set_limit_conf: set transaction limit config * @vbif: vbif context driver * @xin_id: client interface identifier * @rd: true for read limit; false for write limit @@ -27,7 +27,7 @@ struct dpu_hw_vbif_ops { u32 xin_id, bool rd, u32 limit); /** - * get_limit_conf - get transaction limit config + * @get_limit_conf: get transaction limit config * @vbif: vbif context driver * @xin_id: client interface identifier * @rd: true for read limit; false for write limit @@ -37,7 +37,7 @@ struct dpu_hw_vbif_ops { u32 xin_id, bool rd); /** - * set_halt_ctrl - set halt control + * @set_halt_ctrl: set halt control * @vbif: vbif context driver * @xin_id: client interface identifier * @enable: halt control enable @@ -46,7 +46,7 @@ struct dpu_hw_vbif_ops { u32 xin_id, bool enable); /** - * get_halt_ctrl - get halt control + * @get_halt_ctrl: get halt control * @vbif: vbif context driver * @xin_id: client interface identifier * @return: halt control enable @@ -55,7 +55,7 @@ struct dpu_hw_vbif_ops { u32 xin_id); /** - * set_qos_remap - set QoS priority remap + * @set_qos_remap: set QoS priority remap * @vbif: vbif context driver * @xin_id: client interface identifier * @level: priority level @@ -65,7 +65,7 @@ struct dpu_hw_vbif_ops { u32 xin_id, u32 level, u32 remap_level); /** - * set_mem_type - set memory type + * @set_mem_type: set memory type * @vbif: vbif context driver * @xin_id: client interface identifier * @value: memory type value @@ -74,7 +74,7 @@ struct dpu_hw_vbif_ops { u32 xin_id, u32 value); /** - * clear_errors - clear any vbif errors + * @clear_errors: clear any vbif errors * This function clears any detected pending/source errors * on the VBIF interface, and optionally returns the detected * error mask(s). @@ -86,7 +86,7 @@ struct dpu_hw_vbif_ops { u32 *pnd_errors, u32 *src_errors); /** - * set_write_gather_en - set write_gather enable + * @set_write_gather_en: set write_gather enable * @vbif: vbif context driver * @xin_id: client interface identifier */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c index 478a091aeccfc..4da4bd6a997c5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c @@ -148,6 +148,15 @@ static void dpu_hw_wb_setup_qos_lut(struct dpu_hw_wb *ctx, cfg); } +static void dpu_hw_wb_setup_qos_lut_v13(struct dpu_hw_wb *ctx, + struct dpu_hw_qos_cfg *cfg) +{ + if (!ctx || !cfg) + return; + + dpu_hw_setup_qos_lut_v13(&ctx->hw, cfg); +} + static void dpu_hw_wb_setup_cdp(struct dpu_hw_wb *ctx, const struct msm_format *fmt, bool enable) @@ -202,8 +211,12 @@ static void _setup_wb_ops(struct dpu_hw_wb_ops *ops, if (test_bit(DPU_WB_XY_ROI_OFFSET, &features)) ops->setup_roi = dpu_hw_wb_roi; - if (test_bit(DPU_WB_QOS, &features)) - ops->setup_qos_lut = dpu_hw_wb_setup_qos_lut; + if (test_bit(DPU_WB_QOS, &features)) { + if (mdss_rev->core_major_ver >= 13) + ops->setup_qos_lut = dpu_hw_wb_setup_qos_lut_v13; + else + ops->setup_qos_lut = dpu_hw_wb_setup_qos_lut; + } if (test_bit(DPU_WB_CDP, &features)) ops->setup_cdp = dpu_hw_wb_setup_cdp; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h index ee5e5ab786e1b..cfdbb5bb2a0f3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h @@ -22,11 +22,11 @@ struct dpu_hw_wb_cfg { }; /** - * * struct dpu_hw_wb_ops : Interface to the wb hw driver functions * Assumption is these functions will be called after clocks are enabled * @setup_outaddress: setup output address from the writeback job * @setup_outformat: setup output format of writeback block from writeback job + * @setup_roi: setup ROI (Region of Interest) parameters * @setup_qos_lut: setup qos LUT for writeback block based on input * @setup_cdp: setup chroma down prefetch block for writeback block * @setup_clk_force_ctrl: setup clock force control @@ -61,7 +61,7 @@ struct dpu_hw_wb_ops { * struct dpu_hw_wb : WB driver object * @hw: block hardware details * @idx: hardware index number within type - * @wb_hw_caps: hardware capabilities + * @caps: hardware capabilities * @ops: function pointers */ struct dpu_hw_wb { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 45bf345493164..938f50ac655b8 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -612,6 +612,7 @@ static int _dpu_kms_initialize_dsi(struct drm_device *dev, info.h_tile_instance[info.num_of_h_tiles++] = other; info.is_cmd_mode = msm_dsi_is_cmd_mode(priv->kms->dsi[i]); + info.stream_id = 0; rc = dpu_kms_dsi_set_te_source(&info, priv->kms->dsi[i]); if (rc) { @@ -653,7 +654,7 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev, struct msm_display_info info; bool yuv_supported; int rc; - int i; + int i, stream_id, stream_cnt; for (i = 0; i < ARRAY_SIZE(priv->kms->dp); i++) { if (!priv->kms->dp[i]) @@ -676,6 +677,31 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev, DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc); return rc; } + + stream_cnt = msm_dp_get_mst_max_stream(priv->kms->dp[i]); + + if (stream_cnt > 1) { + rc = msm_dp_mst_register(priv->kms->dp[i]); + if (rc) { + DPU_ERROR("dp_mst_init failed for DP, rc = %d\n", rc); + return rc; + } + + for (stream_id = 0; stream_id < stream_cnt; stream_id++) { + info.stream_id = stream_id; + encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_DPMST, &info); + if (IS_ERR(encoder)) { + DPU_ERROR("encoder init failed for dp mst display\n"); + return PTR_ERR(encoder); + } + + rc = msm_dp_mst_attach_encoder(priv->kms->dp[i], encoder); + if (rc) { + DPU_ERROR("DP MST init failed, %d\n", rc); + continue; + } + } + } } return 0; @@ -696,6 +722,7 @@ static int _dpu_kms_initialize_hdmi(struct drm_device *dev, info.num_of_h_tiles = 1; info.h_tile_instance[0] = 0; info.intf_type = INTF_HDMI; + info.stream_id = 0; encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_TMDS, &info); if (IS_ERR(encoder)) { @@ -728,6 +755,7 @@ static int _dpu_kms_initialize_writeback(struct drm_device *dev, /* use only WB idx 2 instance for DPU */ info.h_tile_instance[0] = wb_idx; info.intf_type = INTF_WB; + info.stream_id = 0; maxlinewidth = dpu_rm_get_wb(&dpu_kms->rm, info.h_tile_instance[0])->caps->maxlinewidth; @@ -1461,8 +1489,6 @@ static int __maybe_unused dpu_runtime_suspend(struct device *dev) struct msm_drm_private *priv = platform_get_drvdata(pdev); struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); - /* Drop the performance state vote */ - dev_pm_opp_set_rate(dev, 0); clk_bulk_disable_unprepare(dpu_kms->num_clocks, dpu_kms->clocks); for (i = 0; i < dpu_kms->num_paths; i++) @@ -1505,6 +1531,8 @@ 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,kaanapali-dpu", .data = &dpu_kaanapali_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 905524ceeb1f1..9b7a8b46bfa91 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -622,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"); @@ -635,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, @@ -822,8 +824,8 @@ 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 drm_rect fb_rect = { 0 }; uint32_t max_linewidth; @@ -848,6 +850,9 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, return -EINVAL; } + /* move the assignment here, to ease handling to another pairs later */ + pipe_cfg = &pstate->pipe_cfg[0]; + r_pipe_cfg = &pstate->pipe_cfg[1]; /* state->src is 16.16, src_rect is not */ drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); @@ -954,6 +959,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, @@ -963,10 +985,10 @@ 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; + 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]; int ret = 0; ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, @@ -1019,17 +1041,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; @@ -1044,11 +1069,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 || @@ -1089,10 +1109,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; @@ -1136,7 +1156,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); @@ -1154,8 +1174,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; } @@ -1177,37 +1197,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; @@ -1219,42 +1274,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); @@ -1267,7 +1304,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]; @@ -1281,8 +1318,6 @@ int dpu_assign_plane_resources(struct dpu_global_state *global_state, prev_adjacent_plane_state); if (ret) return ret; - - prev_adjacent_plane_state = plane_state; } return 0; @@ -1318,6 +1353,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"); @@ -1338,8 +1374,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 */ @@ -1440,15 +1476,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; @@ -1463,12 +1496,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); } @@ -1476,15 +1508,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])); } } @@ -1492,17 +1526,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; - trace_dpu_plane_disable(DRMID(plane), false, - pstate->pipe.multirect_mode); + for (i = 0; i < PIPES_PER_PLANE; i += 1) { + pipe = &pstate->pipe[i]; + if (!pipe->sspp) + continue; - if (r_pipe->sspp) { - r_pipe->multirect_index = DPU_SSPP_RECT_SOLO; - r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; + trace_dpu_plane_disable(DRMID(plane), false, + pstate->pipe[i].multirect_mode); - if (r_pipe->sspp->ops.setup_multirect) - r_pipe->sspp->ops.setup_multirect(r_pipe); + if (i % PIPES_PER_STAGE == 0) + continue; + + /* + * 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; @@ -1597,31 +1642,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)); } } @@ -1659,14 +1699,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 a3a6e90283330..1ef5a041b8aca 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 d9c3b0a1d0914..7e77d88f89592 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -315,20 +315,19 @@ static bool _dpu_rm_check_lm_and_get_connected_blks(struct dpu_rm *rm, /* Already reserved? */ if (reserved_by_other(global_state->mixer_to_crtc_id, lm_idx, crtc_id)) { - DPU_DEBUG("lm %d already reserved\n", lm_idx + LM_0); + DPU_DEBUG("LM_%d already reserved\n", lm_idx); return false; } lm_cfg = to_dpu_hw_mixer(rm->mixer_blks[lm_idx])->cap; idx = lm_cfg->pingpong - PINGPONG_0; - if (idx < 0 || idx >= ARRAY_SIZE(rm->pingpong_blks)) { - DPU_ERROR("failed to get pp on lm %d\n", lm_cfg->pingpong); + if (idx < 0 || idx >= ARRAY_SIZE(rm->pingpong_blks) || !rm->pingpong_blks[idx]) { + DPU_ERROR("LM_%d, invalid PP_%d\n", lm_idx, idx); return false; } if (reserved_by_other(global_state->pingpong_to_crtc_id, idx, crtc_id)) { - DPU_DEBUG("lm %d pp %d already reserved\n", lm_cfg->id, - lm_cfg->pingpong); + DPU_DEBUG("LM_%d PP_%d already reserved\n", lm_idx, idx); return false; } *pp_idx = idx; @@ -337,14 +336,13 @@ static bool _dpu_rm_check_lm_and_get_connected_blks(struct dpu_rm *rm, return true; idx = lm_cfg->dspp - DSPP_0; - if (idx < 0 || idx >= ARRAY_SIZE(rm->dspp_blks)) { - DPU_ERROR("failed to get dspp on lm %d\n", lm_cfg->dspp); + if (idx < 0 || idx >= ARRAY_SIZE(rm->dspp_blks) || !rm->dspp_blks[idx]) { + DPU_ERROR("LM_%d, invalid DSPP_%d\n", lm_idx, idx); return false; } if (reserved_by_other(global_state->dspp_to_crtc_id, idx, crtc_id)) { - DPU_DEBUG("lm %d dspp %d already reserved\n", lm_cfg->id, - lm_cfg->dspp); + DPU_DEBUG("LM_%d DSPP_%d already reserved\n", lm_idx, idx); return false; } *dspp_idx = idx; @@ -364,7 +362,7 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm, int i, lm_count = 0; if (!topology->num_lm) { - DPU_ERROR("invalid number of lm: %d\n", topology->num_lm); + DPU_ERROR("zero LMs in topology\n"); return -EINVAL; } @@ -374,7 +372,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, @@ -464,13 +466,13 @@ static int _dpu_rm_reserve_ctls( features = ctl->caps->features; has_split_display = BIT(DPU_CTL_SPLIT_DISPLAY) & features; - DPU_DEBUG("ctl %d caps 0x%lX\n", j + CTL_0, features); + DPU_DEBUG("CTL_%d caps 0x%lX\n", j, features); if (needs_split_display != has_split_display) continue; ctl_idx[i] = j; - DPU_DEBUG("ctl %d match\n", j + CTL_0); + DPU_DEBUG("CTL_%d match\n", j); if (++i == num_ctls) break; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h index 5307cbc2007c5..cb24ad2a6d8d3 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/msm_media_info.h b/drivers/gpu/drm/msm/disp/dpu1/msm_media_info.h deleted file mode 100644 index 9fc9dbde8a27c..0000000000000 --- a/drivers/gpu/drm/msm/disp/dpu1/msm_media_info.h +++ /dev/null @@ -1,1155 +0,0 @@ -#ifndef __MEDIA_INFO_H__ -#define __MEDIA_INFO_H__ - -#ifndef MSM_MEDIA_ALIGN -#define MSM_MEDIA_ALIGN(__sz, __align) (((__align) & ((__align) - 1)) ?\ - ((((__sz) + (__align) - 1) / (__align)) * (__align)) :\ - (((__sz) + (__align) - 1) & (~((__align) - 1)))) -#endif - -#ifndef MSM_MEDIA_ROUNDUP -#define MSM_MEDIA_ROUNDUP(__sz, __r) (((__sz) + ((__r) - 1)) / (__r)) -#endif - -#ifndef MSM_MEDIA_MAX -#define MSM_MEDIA_MAX(__a, __b) ((__a) > (__b)?(__a):(__b)) -#endif - -enum color_fmts { - /* Venus NV12: - * YUV 4:2:0 image with a plane of 8 bit Y samples followed - * by an interleaved U/V plane containing 8 bit 2x2 subsampled - * colour difference samples. - * - * <-------- Y/UV_Stride --------> - * <------- Width -------> - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . V - * U V U V U V U V U V U V . . . . ^ - * U V U V U V U V U V U V . . . . | - * U V U V U V U V U V U V . . . . | - * U V U V U V U V U V U V . . . . UV_Scanlines - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . V - * . . . . . . . . . . . . . . . . --> Buffer size alignment - * - * Y_Stride : Width aligned to 128 - * UV_Stride : Width aligned to 128 - * Y_Scanlines: Height aligned to 32 - * UV_Scanlines: Height/2 aligned to 16 - * Extradata: Arbitrary (software-imposed) padding - * Total size = align((Y_Stride * Y_Scanlines - * + UV_Stride * UV_Scanlines - * + max(Extradata, Y_Stride * 8), 4096) - */ - COLOR_FMT_NV12, - - /* Venus NV21: - * YUV 4:2:0 image with a plane of 8 bit Y samples followed - * by an interleaved V/U plane containing 8 bit 2x2 subsampled - * colour difference samples. - * - * <-------- Y/UV_Stride --------> - * <------- Width -------> - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . V - * V U V U V U V U V U V U . . . . ^ - * V U V U V U V U V U V U . . . . | - * V U V U V U V U V U V U . . . . | - * V U V U V U V U V U V U . . . . UV_Scanlines - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . V - * . . . . . . . . . . . . . . . . --> Padding & Buffer size alignment - * - * Y_Stride : Width aligned to 128 - * UV_Stride : Width aligned to 128 - * Y_Scanlines: Height aligned to 32 - * UV_Scanlines: Height/2 aligned to 16 - * Extradata: Arbitrary (software-imposed) padding - * Total size = align((Y_Stride * Y_Scanlines - * + UV_Stride * UV_Scanlines - * + max(Extradata, Y_Stride * 8), 4096) - */ - COLOR_FMT_NV21, - /* Venus NV12_MVTB: - * Two YUV 4:2:0 images/views one after the other - * in a top-bottom layout, same as NV12 - * with a plane of 8 bit Y samples followed - * by an interleaved U/V plane containing 8 bit 2x2 subsampled - * colour difference samples. - * - * - * <-------- Y/UV_Stride --------> - * <------- Width -------> - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ ^ - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | | - * . . . . . . . . . . . . . . . . | View_1 - * . . . . . . . . . . . . . . . . | | - * . . . . . . . . . . . . . . . . | | - * . . . . . . . . . . . . . . . . V | - * U V U V U V U V U V U V . . . . ^ | - * U V U V U V U V U V U V . . . . | | - * U V U V U V U V U V U V . . . . | | - * U V U V U V U V U V U V . . . . UV_Scanlines | - * . . . . . . . . . . . . . . . . | | - * . . . . . . . . . . . . . . . . V V - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ ^ - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | | - * . . . . . . . . . . . . . . . . | View_2 - * . . . . . . . . . . . . . . . . | | - * . . . . . . . . . . . . . . . . | | - * . . . . . . . . . . . . . . . . V | - * U V U V U V U V U V U V . . . . ^ | - * U V U V U V U V U V U V . . . . | | - * U V U V U V U V U V U V . . . . | | - * U V U V U V U V U V U V . . . . UV_Scanlines | - * . . . . . . . . . . . . . . . . | | - * . . . . . . . . . . . . . . . . V V - * . . . . . . . . . . . . . . . . --> Buffer size alignment - * - * Y_Stride : Width aligned to 128 - * UV_Stride : Width aligned to 128 - * Y_Scanlines: Height aligned to 32 - * UV_Scanlines: Height/2 aligned to 16 - * View_1 begin at: 0 (zero) - * View_2 begin at: Y_Stride * Y_Scanlines + UV_Stride * UV_Scanlines - * Extradata: Arbitrary (software-imposed) padding - * Total size = align((2*(Y_Stride * Y_Scanlines) - * + 2*(UV_Stride * UV_Scanlines) + Extradata), 4096) - */ - COLOR_FMT_NV12_MVTB, - /* - * The buffer can be of 2 types: - * (1) Venus NV12 UBWC Progressive - * (2) Venus NV12 UBWC Interlaced - * - * (1) Venus NV12 UBWC Progressive Buffer Format: - * Compressed Macro-tile format for NV12. - * Contains 4 planes in the following order - - * (A) Y_Meta_Plane - * (B) Y_UBWC_Plane - * (C) UV_Meta_Plane - * (D) UV_UBWC_Plane - * - * Y_Meta_Plane consists of meta information to decode compressed - * tile data in Y_UBWC_Plane. - * Y_UBWC_Plane consists of Y data in compressed macro-tile format. - * UBWC decoder block will use the Y_Meta_Plane data together with - * Y_UBWC_Plane data to produce loss-less uncompressed 8 bit Y samples. - * - * UV_Meta_Plane consists of meta information to decode compressed - * tile data in UV_UBWC_Plane. - * UV_UBWC_Plane consists of UV data in compressed macro-tile format. - * UBWC decoder block will use UV_Meta_Plane data together with - * UV_UBWC_Plane data to produce loss-less uncompressed 8 bit 2x2 - * subsampled color difference samples. - * - * Each tile in Y_UBWC_Plane/UV_UBWC_Plane is independently decodable - * and randomly accessible. There is no dependency between tiles. - * - * <----- Y_Meta_Stride ----> - * <-------- Width ------> - * M M M M M M M M M M M M . . ^ ^ - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . Height | - * M M M M M M M M M M M M . . | Meta_Y_Scanlines - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . V | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . V - * <--Compressed tile Y Stride---> - * <------- Width -------> - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Height | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_Scanlines - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . . . V - * <----- UV_Meta_Stride ----> - * M M M M M M M M M M M M . . ^ - * M M M M M M M M M M M M . . | - * M M M M M M M M M M M M . . | - * M M M M M M M M M M M M . . M_UV_Scanlines - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . V - * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * <--Compressed tile UV Stride---> - * U* V* U* V* U* V* U* V* . . . . ^ - * U* V* U* V* U* V* U* V* . . . . | - * U* V* U* V* U* V* U* V* . . . . | - * U* V* U* V* U* V* U* V* . . . . UV_Scanlines - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . V - * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * - * Y_Stride = align(Width, 128) - * UV_Stride = align(Width, 128) - * Y_Scanlines = align(Height, 32) - * UV_Scanlines = align(Height/2, 16) - * Y_UBWC_Plane_size = align(Y_Stride * Y_Scanlines, 4096) - * UV_UBWC_Plane_size = align(UV_Stride * UV_Scanlines, 4096) - * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) - * Y_Meta_Scanlines = align(roundup(Height, Y_TileHeight), 16) - * Y_Meta_Plane_size = align(Y_Meta_Stride * Y_Meta_Scanlines, 4096) - * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) - * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16) - * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096) - * Extradata = 8k - * - * Total size = align( Y_UBWC_Plane_size + UV_UBWC_Plane_size + - * Y_Meta_Plane_size + UV_Meta_Plane_size - * + max(Extradata, Y_Stride * 48), 4096) - * - * - * (2) Venus NV12 UBWC Interlaced Buffer Format: - * Compressed Macro-tile format for NV12 interlaced. - * Contains 8 planes in the following order - - * (A) Y_Meta_Top_Field_Plane - * (B) Y_UBWC_Top_Field_Plane - * (C) UV_Meta_Top_Field_Plane - * (D) UV_UBWC_Top_Field_Plane - * (E) Y_Meta_Bottom_Field_Plane - * (F) Y_UBWC_Bottom_Field_Plane - * (G) UV_Meta_Bottom_Field_Plane - * (H) UV_UBWC_Bottom_Field_Plane - * Y_Meta_Top_Field_Plane consists of meta information to decode - * compressed tile data for Y_UBWC_Top_Field_Plane. - * Y_UBWC_Top_Field_Plane consists of Y data in compressed macro-tile - * format for top field of an interlaced frame. - * UBWC decoder block will use the Y_Meta_Top_Field_Plane data together - * with Y_UBWC_Top_Field_Plane data to produce loss-less uncompressed - * 8 bit Y samples for top field of an interlaced frame. - * - * UV_Meta_Top_Field_Plane consists of meta information to decode - * compressed tile data in UV_UBWC_Top_Field_Plane. - * UV_UBWC_Top_Field_Plane consists of UV data in compressed macro-tile - * format for top field of an interlaced frame. - * UBWC decoder block will use UV_Meta_Top_Field_Plane data together - * with UV_UBWC_Top_Field_Plane data to produce loss-less uncompressed - * 8 bit subsampled color difference samples for top field of an - * interlaced frame. - * - * Each tile in Y_UBWC_Top_Field_Plane/UV_UBWC_Top_Field_Plane is - * independently decodable and randomly accessible. There is no - * dependency between tiles. - * - * Y_Meta_Bottom_Field_Plane consists of meta information to decode - * compressed tile data for Y_UBWC_Bottom_Field_Plane. - * Y_UBWC_Bottom_Field_Plane consists of Y data in compressed macro-tile - * format for bottom field of an interlaced frame. - * UBWC decoder block will use the Y_Meta_Bottom_Field_Plane data - * together with Y_UBWC_Bottom_Field_Plane data to produce loss-less - * uncompressed 8 bit Y samples for bottom field of an interlaced frame. - * - * UV_Meta_Bottom_Field_Plane consists of meta information to decode - * compressed tile data in UV_UBWC_Bottom_Field_Plane. - * UV_UBWC_Bottom_Field_Plane consists of UV data in compressed - * macro-tile format for bottom field of an interlaced frame. - * UBWC decoder block will use UV_Meta_Bottom_Field_Plane data together - * with UV_UBWC_Bottom_Field_Plane data to produce loss-less - * uncompressed 8 bit subsampled color difference samples for bottom - * field of an interlaced frame. - * - * Each tile in Y_UBWC_Bottom_Field_Plane/UV_UBWC_Bottom_Field_Plane is - * independently decodable and randomly accessible. There is no - * dependency between tiles. - * - * <-----Y_TF_Meta_Stride----> - * <-------- Width ------> - * M M M M M M M M M M M M . . ^ ^ - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . Half_height | - * M M M M M M M M M M M M . . | Meta_Y_TF_Scanlines - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . V | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . V - * <-Compressed tile Y_TF Stride-> - * <------- Width -------> - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Half_height | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_TF_Scanlines - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . . . V - * <----UV_TF_Meta_Stride----> - * M M M M M M M M M M M M . . ^ - * M M M M M M M M M M M M . . | - * M M M M M M M M M M M M . . | - * M M M M M M M M M M M M . . M_UV_TF_Scanlines - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . V - * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * <-Compressed tile UV_TF Stride-> - * U* V* U* V* U* V* U* V* . . . . ^ - * U* V* U* V* U* V* U* V* . . . . | - * U* V* U* V* U* V* U* V* . . . . | - * U* V* U* V* U* V* U* V* . . . . UV_TF_Scanlines - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . V - * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * <-----Y_BF_Meta_Stride----> - * <-------- Width ------> - * M M M M M M M M M M M M . . ^ ^ - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . Half_height | - * M M M M M M M M M M M M . . | Meta_Y_BF_Scanlines - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . V | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . V - * <-Compressed tile Y_BF Stride-> - * <------- Width -------> - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Half_height | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_BF_Scanlines - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . . . V - * <----UV_BF_Meta_Stride----> - * M M M M M M M M M M M M . . ^ - * M M M M M M M M M M M M . . | - * M M M M M M M M M M M M . . | - * M M M M M M M M M M M M . . M_UV_BF_Scanlines - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . V - * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * <-Compressed tile UV_BF Stride-> - * U* V* U* V* U* V* U* V* . . . . ^ - * U* V* U* V* U* V* U* V* . . . . | - * U* V* U* V* U* V* U* V* . . . . | - * U* V* U* V* U* V* U* V* . . . . UV_BF_Scanlines - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . V - * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * - * Half_height = (Height+1)>>1 - * Y_TF_Stride = align(Width, 128) - * UV_TF_Stride = align(Width, 128) - * Y_TF_Scanlines = align(Half_height, 32) - * UV_TF_Scanlines = align((Half_height+1)/2, 32) - * Y_UBWC_TF_Plane_size = align(Y_TF_Stride * Y_TF_Scanlines, 4096) - * UV_UBWC_TF_Plane_size = align(UV_TF_Stride * UV_TF_Scanlines, 4096) - * Y_TF_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) - * Y_TF_Meta_Scanlines = align(roundup(Half_height, Y_TileHeight), 16) - * Y_TF_Meta_Plane_size = - * align(Y_TF_Meta_Stride * Y_TF_Meta_Scanlines, 4096) - * UV_TF_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) - * UV_TF_Meta_Scanlines = align(roundup(Half_height, UV_TileHeight), 16) - * UV_TF_Meta_Plane_size = - * align(UV_TF_Meta_Stride * UV_TF_Meta_Scanlines, 4096) - * Y_BF_Stride = align(Width, 128) - * UV_BF_Stride = align(Width, 128) - * Y_BF_Scanlines = align(Half_height, 32) - * UV_BF_Scanlines = align((Half_height+1)/2, 32) - * Y_UBWC_BF_Plane_size = align(Y_BF_Stride * Y_BF_Scanlines, 4096) - * UV_UBWC_BF_Plane_size = align(UV_BF_Stride * UV_BF_Scanlines, 4096) - * Y_BF_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) - * Y_BF_Meta_Scanlines = align(roundup(Half_height, Y_TileHeight), 16) - * Y_BF_Meta_Plane_size = - * align(Y_BF_Meta_Stride * Y_BF_Meta_Scanlines, 4096) - * UV_BF_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) - * UV_BF_Meta_Scanlines = align(roundup(Half_height, UV_TileHeight), 16) - * UV_BF_Meta_Plane_size = - * align(UV_BF_Meta_Stride * UV_BF_Meta_Scanlines, 4096) - * Extradata = 8k - * - * Total size = align( Y_UBWC_TF_Plane_size + UV_UBWC_TF_Plane_size + - * Y_TF_Meta_Plane_size + UV_TF_Meta_Plane_size + - * Y_UBWC_BF_Plane_size + UV_UBWC_BF_Plane_size + - * Y_BF_Meta_Plane_size + UV_BF_Meta_Plane_size + - * + max(Extradata, Y_TF_Stride * 48), 4096) - */ - COLOR_FMT_NV12_UBWC, - /* Venus NV12 10-bit UBWC: - * Compressed Macro-tile format for NV12. - * Contains 4 planes in the following order - - * (A) Y_Meta_Plane - * (B) Y_UBWC_Plane - * (C) UV_Meta_Plane - * (D) UV_UBWC_Plane - * - * Y_Meta_Plane consists of meta information to decode compressed - * tile data in Y_UBWC_Plane. - * Y_UBWC_Plane consists of Y data in compressed macro-tile format. - * UBWC decoder block will use the Y_Meta_Plane data together with - * Y_UBWC_Plane data to produce loss-less uncompressed 10 bit Y samples. - * - * UV_Meta_Plane consists of meta information to decode compressed - * tile data in UV_UBWC_Plane. - * UV_UBWC_Plane consists of UV data in compressed macro-tile format. - * UBWC decoder block will use UV_Meta_Plane data together with - * UV_UBWC_Plane data to produce loss-less uncompressed 10 bit 2x2 - * subsampled color difference samples. - * - * Each tile in Y_UBWC_Plane/UV_UBWC_Plane is independently decodable - * and randomly accessible. There is no dependency between tiles. - * - * <----- Y_Meta_Stride -----> - * <-------- Width ------> - * M M M M M M M M M M M M . . ^ ^ - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . Height | - * M M M M M M M M M M M M . . | Meta_Y_Scanlines - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . V | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . V - * <--Compressed tile Y Stride---> - * <------- Width -------> - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Height | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_Scanlines - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . . . V - * <----- UV_Meta_Stride ----> - * M M M M M M M M M M M M . . ^ - * M M M M M M M M M M M M . . | - * M M M M M M M M M M M M . . | - * M M M M M M M M M M M M . . M_UV_Scanlines - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . V - * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * <--Compressed tile UV Stride---> - * U* V* U* V* U* V* U* V* . . . . ^ - * U* V* U* V* U* V* U* V* . . . . | - * U* V* U* V* U* V* U* V* . . . . | - * U* V* U* V* U* V* U* V* . . . . UV_Scanlines - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . V - * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * - * - * Y_Stride = align(Width * 4/3, 128) - * UV_Stride = align(Width * 4/3, 128) - * Y_Scanlines = align(Height, 32) - * UV_Scanlines = align(Height/2, 16) - * Y_UBWC_Plane_Size = align(Y_Stride * Y_Scanlines, 4096) - * UV_UBWC_Plane_Size = align(UV_Stride * UV_Scanlines, 4096) - * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) - * Y_Meta_Scanlines = align(roundup(Height, Y_TileHeight), 16) - * Y_Meta_Plane_size = align(Y_Meta_Stride * Y_Meta_Scanlines, 4096) - * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) - * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16) - * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096) - * Extradata = 8k - * - * Total size = align(Y_UBWC_Plane_size + UV_UBWC_Plane_size + - * Y_Meta_Plane_size + UV_Meta_Plane_size - * + max(Extradata, Y_Stride * 48), 4096) - */ - COLOR_FMT_NV12_BPP10_UBWC, - /* Venus RGBA8888 format: - * Contains 1 plane in the following order - - * (A) RGBA plane - * - * <-------- RGB_Stride --------> - * <------- Width -------> - * R R R R R R R R R R R R . . . . ^ ^ - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . Height | - * R R R R R R R R R R R R . . . . | RGB_Scanlines - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . V | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . V - * - * RGB_Stride = align(Width * 4, 128) - * RGB_Scanlines = align(Height, 32) - * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) - * Extradata = 8k - * - * Total size = align(RGB_Plane_size + Extradata, 4096) - */ - COLOR_FMT_RGBA8888, - /* Venus RGBA8888 UBWC format: - * Contains 2 planes in the following order - - * (A) Meta plane - * (B) RGBA plane - * - * <--- RGB_Meta_Stride ----> - * <-------- Width ------> - * M M M M M M M M M M M M . . ^ ^ - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . Height | - * M M M M M M M M M M M M . . | Meta_RGB_Scanlines - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . V | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . V - * <-------- RGB_Stride --------> - * <------- Width -------> - * R R R R R R R R R R R R . . . . ^ ^ - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . Height | - * R R R R R R R R R R R R . . . . | RGB_Scanlines - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . V | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . . . V - * - * RGB_Stride = align(Width * 4, 128) - * RGB_Scanlines = align(Height, 32) - * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) - * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64) - * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16) - * RGB_Meta_Plane_size = align(RGB_Meta_Stride * - * RGB_Meta_Scanlines, 4096) - * Extradata = 8k - * - * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size + - * Extradata, 4096) - */ - COLOR_FMT_RGBA8888_UBWC, - /* Venus RGBA1010102 UBWC format: - * Contains 2 planes in the following order - - * (A) Meta plane - * (B) RGBA plane - * - * <--- RGB_Meta_Stride ----> - * <-------- Width ------> - * M M M M M M M M M M M M . . ^ ^ - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . Height | - * M M M M M M M M M M M M . . | Meta_RGB_Scanlines - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . V | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . V - * <-------- RGB_Stride --------> - * <------- Width -------> - * R R R R R R R R R R R R . . . . ^ ^ - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . Height | - * R R R R R R R R R R R R . . . . | RGB_Scanlines - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . V | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . . . V - * - * RGB_Stride = align(Width * 4, 256) - * RGB_Scanlines = align(Height, 16) - * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) - * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64) - * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16) - * RGB_Meta_Plane_size = align(RGB_Meta_Stride * - * RGB_Meta_Scanlines, 4096) - * Extradata = 8k - * - * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size + - * Extradata, 4096) - */ - COLOR_FMT_RGBA1010102_UBWC, - /* Venus RGB565 UBWC format: - * Contains 2 planes in the following order - - * (A) Meta plane - * (B) RGB plane - * - * <--- RGB_Meta_Stride ----> - * <-------- Width ------> - * M M M M M M M M M M M M . . ^ ^ - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . Height | - * M M M M M M M M M M M M . . | Meta_RGB_Scanlines - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . V | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . V - * <-------- RGB_Stride --------> - * <------- Width -------> - * R R R R R R R R R R R R . . . . ^ ^ - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . Height | - * R R R R R R R R R R R R . . . . | RGB_Scanlines - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . | | - * R R R R R R R R R R R R . . . . V | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . . . V - * - * RGB_Stride = align(Width * 2, 128) - * RGB_Scanlines = align(Height, 16) - * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) - * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64) - * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16) - * RGB_Meta_Plane_size = align(RGB_Meta_Stride * - * RGB_Meta_Scanlines, 4096) - * Extradata = 8k - * - * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size + - * Extradata, 4096) - */ - COLOR_FMT_RGB565_UBWC, - /* P010 UBWC: - * Compressed Macro-tile format for NV12. - * Contains 4 planes in the following order - - * (A) Y_Meta_Plane - * (B) Y_UBWC_Plane - * (C) UV_Meta_Plane - * (D) UV_UBWC_Plane - * - * Y_Meta_Plane consists of meta information to decode compressed - * tile data in Y_UBWC_Plane. - * Y_UBWC_Plane consists of Y data in compressed macro-tile format. - * UBWC decoder block will use the Y_Meta_Plane data together with - * Y_UBWC_Plane data to produce loss-less uncompressed 10 bit Y samples. - * - * UV_Meta_Plane consists of meta information to decode compressed - * tile data in UV_UBWC_Plane. - * UV_UBWC_Plane consists of UV data in compressed macro-tile format. - * UBWC decoder block will use UV_Meta_Plane data together with - * UV_UBWC_Plane data to produce loss-less uncompressed 10 bit 2x2 - * subsampled color difference samples. - * - * Each tile in Y_UBWC_Plane/UV_UBWC_Plane is independently decodable - * and randomly accessible. There is no dependency between tiles. - * - * <----- Y_Meta_Stride -----> - * <-------- Width ------> - * M M M M M M M M M M M M . . ^ ^ - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . Height | - * M M M M M M M M M M M M . . | Meta_Y_Scanlines - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . | | - * M M M M M M M M M M M M . . V | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . V - * <--Compressed tile Y Stride---> - * <------- Width -------> - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Height | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_Scanlines - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | - * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * . . . . . . . . . . . . . . . . V - * <----- UV_Meta_Stride ----> - * M M M M M M M M M M M M . . ^ - * M M M M M M M M M M M M . . | - * M M M M M M M M M M M M . . | - * M M M M M M M M M M M M . . M_UV_Scanlines - * . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . V - * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * <--Compressed tile UV Stride---> - * U* V* U* V* U* V* U* V* . . . . ^ - * U* V* U* V* U* V* U* V* . . . . | - * U* V* U* V* U* V* U* V* . . . . | - * U* V* U* V* U* V* U* V* . . . . UV_Scanlines - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . V - * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k - * - * - * Y_Stride = align(Width * 2, 256) - * UV_Stride = align(Width * 2, 256) - * Y_Scanlines = align(Height, 16) - * UV_Scanlines = align(Height/2, 16) - * Y_UBWC_Plane_Size = align(Y_Stride * Y_Scanlines, 4096) - * UV_UBWC_Plane_Size = align(UV_Stride * UV_Scanlines, 4096) - * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) - * Y_Meta_Scanlines = align(roundup(Height, Y_TileHeight), 16) - * Y_Meta_Plane_size = align(Y_Meta_Stride * Y_Meta_Scanlines, 4096) - * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) - * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16) - * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096) - * Extradata = 8k - * - * Total size = align(Y_UBWC_Plane_size + UV_UBWC_Plane_size + - * Y_Meta_Plane_size + UV_Meta_Plane_size - * + max(Extradata, Y_Stride * 48), 4096) - */ - COLOR_FMT_P010_UBWC, - /* Venus P010: - * YUV 4:2:0 image with a plane of 10 bit Y samples followed - * by an interleaved U/V plane containing 10 bit 2x2 subsampled - * colour difference samples. - * - * <-------- Y/UV_Stride --------> - * <------- Width -------> - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | - * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . V - * U V U V U V U V U V U V . . . . ^ - * U V U V U V U V U V U V . . . . | - * U V U V U V U V U V U V . . . . | - * U V U V U V U V U V U V . . . . UV_Scanlines - * . . . . . . . . . . . . . . . . | - * . . . . . . . . . . . . . . . . V - * . . . . . . . . . . . . . . . . --> Buffer size alignment - * - * Y_Stride : Width * 2 aligned to 128 - * UV_Stride : Width * 2 aligned to 128 - * Y_Scanlines: Height aligned to 32 - * UV_Scanlines: Height/2 aligned to 16 - * Extradata: Arbitrary (software-imposed) padding - * Total size = align((Y_Stride * Y_Scanlines - * + UV_Stride * UV_Scanlines - * + max(Extradata, Y_Stride * 8), 4096) - */ - COLOR_FMT_P010, -}; - -#define COLOR_FMT_RGBA1010102_UBWC COLOR_FMT_RGBA1010102_UBWC -#define COLOR_FMT_RGB565_UBWC COLOR_FMT_RGB565_UBWC -#define COLOR_FMT_P010_UBWC COLOR_FMT_P010_UBWC -#define COLOR_FMT_P010 COLOR_FMT_P010 - -/* - * Function arguments: - * @color_fmt - * @width - * Progressive: width - * Interlaced: width - */ -static unsigned int VENUS_Y_STRIDE(int color_fmt, int width) -{ - unsigned int stride = 0; - - if (!width) - return 0; - - switch (color_fmt) { - case COLOR_FMT_NV21: - case COLOR_FMT_NV12: - case COLOR_FMT_NV12_MVTB: - case COLOR_FMT_NV12_UBWC: - stride = MSM_MEDIA_ALIGN(width, 128); - break; - case COLOR_FMT_NV12_BPP10_UBWC: - stride = MSM_MEDIA_ALIGN(width, 192); - stride = MSM_MEDIA_ALIGN(stride * 4 / 3, 256); - break; - case COLOR_FMT_P010_UBWC: - stride = MSM_MEDIA_ALIGN(width * 2, 256); - break; - case COLOR_FMT_P010: - stride = MSM_MEDIA_ALIGN(width * 2, 128); - break; - } - - return stride; -} - -/* - * Function arguments: - * @color_fmt - * @width - * Progressive: width - * Interlaced: width - */ -static unsigned int VENUS_UV_STRIDE(int color_fmt, int width) -{ - unsigned int stride = 0; - - if (!width) - return 0; - - switch (color_fmt) { - case COLOR_FMT_NV21: - case COLOR_FMT_NV12: - case COLOR_FMT_NV12_MVTB: - case COLOR_FMT_NV12_UBWC: - stride = MSM_MEDIA_ALIGN(width, 128); - break; - case COLOR_FMT_NV12_BPP10_UBWC: - stride = MSM_MEDIA_ALIGN(width, 192); - stride = MSM_MEDIA_ALIGN(stride * 4 / 3, 256); - break; - case COLOR_FMT_P010_UBWC: - stride = MSM_MEDIA_ALIGN(width * 2, 256); - break; - case COLOR_FMT_P010: - stride = MSM_MEDIA_ALIGN(width * 2, 128); - break; - } - - return stride; -} - -/* - * Function arguments: - * @color_fmt - * @height - * Progressive: height - * Interlaced: (height+1)>>1 - */ -static unsigned int VENUS_Y_SCANLINES(int color_fmt, int height) -{ - unsigned int sclines = 0; - - if (!height) - return 0; - - switch (color_fmt) { - case COLOR_FMT_NV21: - case COLOR_FMT_NV12: - case COLOR_FMT_NV12_MVTB: - case COLOR_FMT_NV12_UBWC: - case COLOR_FMT_P010: - sclines = MSM_MEDIA_ALIGN(height, 32); - break; - case COLOR_FMT_NV12_BPP10_UBWC: - case COLOR_FMT_P010_UBWC: - sclines = MSM_MEDIA_ALIGN(height, 16); - break; - } - - return sclines; -} - -/* - * Function arguments: - * @color_fmt - * @height - * Progressive: height - * Interlaced: (height+1)>>1 - */ -static unsigned int VENUS_UV_SCANLINES(int color_fmt, int height) -{ - unsigned int sclines = 0; - - if (!height) - return 0; - - switch (color_fmt) { - case COLOR_FMT_NV21: - case COLOR_FMT_NV12: - case COLOR_FMT_NV12_MVTB: - case COLOR_FMT_NV12_BPP10_UBWC: - case COLOR_FMT_P010_UBWC: - case COLOR_FMT_P010: - sclines = MSM_MEDIA_ALIGN((height + 1) >> 1, 16); - break; - case COLOR_FMT_NV12_UBWC: - sclines = MSM_MEDIA_ALIGN((height + 1) >> 1, 32); - break; - } - - return sclines; -} - -/* - * Function arguments: - * @color_fmt - * @width - * Progressive: width - * Interlaced: width - */ -static unsigned int VENUS_Y_META_STRIDE(int color_fmt, int width) -{ - int y_tile_width = 0, y_meta_stride; - - if (!width) - return 0; - - switch (color_fmt) { - case COLOR_FMT_NV12_UBWC: - case COLOR_FMT_P010_UBWC: - y_tile_width = 32; - break; - case COLOR_FMT_NV12_BPP10_UBWC: - y_tile_width = 48; - break; - default: - return 0; - } - - y_meta_stride = MSM_MEDIA_ROUNDUP(width, y_tile_width); - return MSM_MEDIA_ALIGN(y_meta_stride, 64); -} - -/* - * Function arguments: - * @color_fmt - * @height - * Progressive: height - * Interlaced: (height+1)>>1 - */ -static unsigned int VENUS_Y_META_SCANLINES(int color_fmt, int height) -{ - int y_tile_height = 0, y_meta_scanlines; - - if (!height) - return 0; - - switch (color_fmt) { - case COLOR_FMT_NV12_UBWC: - y_tile_height = 8; - break; - case COLOR_FMT_NV12_BPP10_UBWC: - case COLOR_FMT_P010_UBWC: - y_tile_height = 4; - break; - default: - return 0; - } - - y_meta_scanlines = MSM_MEDIA_ROUNDUP(height, y_tile_height); - return MSM_MEDIA_ALIGN(y_meta_scanlines, 16); -} - -/* - * Function arguments: - * @color_fmt - * @width - * Progressive: width - * Interlaced: width - */ -static unsigned int VENUS_UV_META_STRIDE(int color_fmt, int width) -{ - int uv_tile_width = 0, uv_meta_stride; - - if (!width) - return 0; - - switch (color_fmt) { - case COLOR_FMT_NV12_UBWC: - case COLOR_FMT_P010_UBWC: - uv_tile_width = 16; - break; - case COLOR_FMT_NV12_BPP10_UBWC: - uv_tile_width = 24; - break; - default: - return 0; - } - - uv_meta_stride = MSM_MEDIA_ROUNDUP((width+1)>>1, uv_tile_width); - return MSM_MEDIA_ALIGN(uv_meta_stride, 64); -} - -/* - * Function arguments: - * @color_fmt - * @height - * Progressive: height - * Interlaced: (height+1)>>1 - */ -static unsigned int VENUS_UV_META_SCANLINES(int color_fmt, int height) -{ - int uv_tile_height = 0, uv_meta_scanlines; - - if (!height) - return 0; - - switch (color_fmt) { - case COLOR_FMT_NV12_UBWC: - uv_tile_height = 8; - break; - case COLOR_FMT_NV12_BPP10_UBWC: - case COLOR_FMT_P010_UBWC: - uv_tile_height = 4; - break; - default: - return 0; - } - - uv_meta_scanlines = MSM_MEDIA_ROUNDUP((height+1)>>1, uv_tile_height); - return MSM_MEDIA_ALIGN(uv_meta_scanlines, 16); -} - -static unsigned int VENUS_RGB_STRIDE(int color_fmt, int width) -{ - unsigned int alignment = 0, bpp = 4; - - if (!width) - return 0; - - switch (color_fmt) { - case COLOR_FMT_RGBA8888: - alignment = 128; - break; - case COLOR_FMT_RGB565_UBWC: - alignment = 256; - bpp = 2; - break; - case COLOR_FMT_RGBA8888_UBWC: - case COLOR_FMT_RGBA1010102_UBWC: - alignment = 256; - break; - default: - return 0; - } - - return MSM_MEDIA_ALIGN(width * bpp, alignment); -} - -static unsigned int VENUS_RGB_SCANLINES(int color_fmt, int height) -{ - unsigned int alignment = 0; - - if (!height) - return 0; - - switch (color_fmt) { - case COLOR_FMT_RGBA8888: - alignment = 32; - break; - case COLOR_FMT_RGBA8888_UBWC: - case COLOR_FMT_RGBA1010102_UBWC: - case COLOR_FMT_RGB565_UBWC: - alignment = 16; - break; - default: - return 0; - } - - return MSM_MEDIA_ALIGN(height, alignment); -} - -static unsigned int VENUS_RGB_META_STRIDE(int color_fmt, int width) -{ - int rgb_meta_stride; - - if (!width) - return 0; - - switch (color_fmt) { - case COLOR_FMT_RGBA8888_UBWC: - case COLOR_FMT_RGBA1010102_UBWC: - case COLOR_FMT_RGB565_UBWC: - rgb_meta_stride = MSM_MEDIA_ROUNDUP(width, 16); - return MSM_MEDIA_ALIGN(rgb_meta_stride, 64); - } - - return 0; -} - -static unsigned int VENUS_RGB_META_SCANLINES(int color_fmt, int height) -{ - int rgb_meta_scanlines; - - if (!height) - return 0; - - switch (color_fmt) { - case COLOR_FMT_RGBA8888_UBWC: - case COLOR_FMT_RGBA1010102_UBWC: - case COLOR_FMT_RGB565_UBWC: - rgb_meta_scanlines = MSM_MEDIA_ROUNDUP(height, 4); - return MSM_MEDIA_ALIGN(rgb_meta_scanlines, 16); - } - - return 0; -} - -#endif diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c index da53ca88251e7..e8066f9fd5343 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c @@ -527,13 +527,14 @@ static void mdp4_crtc_wait_for_flush_done(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); struct mdp4_kms *mdp4_kms = get_kms(crtc); + wait_queue_head_t *queue = drm_crtc_vblank_waitqueue(crtc); int ret; ret = drm_crtc_vblank_get(crtc); if (ret) return; - ret = wait_event_timeout(dev->vblank[drm_crtc_index(crtc)].queue, + ret = wait_event_timeout(*queue, !(mdp4_read(mdp4_kms, REG_MDP4_OVERLAY_FLUSH) & mdp4_crtc->flushed_mask), msecs_to_jiffies(50)); diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c index 4c4900a7beda8..373ae7d9bf01c 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c @@ -1234,6 +1234,7 @@ static void mdp5_crtc_wait_for_flush_done(struct drm_crtc *crtc) struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state); struct mdp5_ctl *ctl = mdp5_cstate->ctl; + wait_queue_head_t *queue = drm_crtc_vblank_waitqueue(crtc); int ret; /* Should not call this function if crtc is disabled. */ @@ -1244,7 +1245,7 @@ static void mdp5_crtc_wait_for_flush_done(struct drm_crtc *crtc) if (ret) return; - ret = wait_event_timeout(dev->vblank[drm_crtc_index(crtc)].queue, + ret = wait_event_timeout(*queue, ((mdp5_ctl_get_commit_status(ctl) & mdp5_crtc->flushed_mask) == 0), msecs_to_jiffies(50)); diff --git a/drivers/gpu/drm/msm/disp/mdp_format.c b/drivers/gpu/drm/msm/disp/mdp_format.c index eebedb1a2636e..33da569eae5ef 100644 --- a/drivers/gpu/drm/msm/disp/mdp_format.c +++ b/drivers/gpu/drm/msm/disp/mdp_format.c @@ -66,87 +66,205 @@ static struct csc_cfg csc_convert[CSC_MAX] = { #define MDP_TILE_HEIGHT_UBWC 4 #define MDP_TILE_HEIGHT_NV12 8 -#define INTERLEAVED_RGB_FMT(fmt, a, r, g, b, e0, e1, e2, e3, uc, alpha, \ -bp, flg, fm, np) \ +#define INTERLEAVED_RGB_FMT(fmt, bp, r, g, b, e0, e1, e2) \ { \ .pixel_format = DRM_FORMAT_ ## fmt, \ .fetch_type = MDP_PLANE_INTERLEAVED, \ - .alpha_enable = alpha, \ + .alpha_enable = false, \ + .element = { (e0), (e1), (e2), 0 }, \ + .bpc_g_y = g, \ + .bpc_b_cb = b, \ + .bpc_r_cr = r, \ + .bpc_a = 0, \ + .chroma_sample = CHROMA_FULL, \ + .unpack_count = 3, \ + .bpp = bp, \ + .fetch_mode = MDP_FETCH_LINEAR, \ + .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT, \ + .num_planes = 1, \ + .tile_height = MDP_TILE_HEIGHT_DEFAULT \ +} + +#define INTERLEAVED_RGBA_FMT(fmt, bp, a, r, g, b, e0, e1, e2, e3) \ +{ \ + .pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_type = MDP_PLANE_INTERLEAVED, \ + .alpha_enable = true, \ .element = { (e0), (e1), (e2), (e3) }, \ .bpc_g_y = g, \ .bpc_b_cb = b, \ .bpc_r_cr = r, \ .bpc_a = a, \ .chroma_sample = CHROMA_FULL, \ - .unpack_count = uc, \ + .unpack_count = 4, \ .bpp = bp, \ - .fetch_mode = fm, \ - .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | flg, \ - .num_planes = np, \ + .fetch_mode = MDP_FETCH_LINEAR, \ + .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT, \ + .num_planes = 1, \ .tile_height = MDP_TILE_HEIGHT_DEFAULT \ } -#define INTERLEAVED_RGB_FMT_TILED(fmt, a, r, g, b, e0, e1, e2, e3, uc, \ -alpha, bp, flg, fm, np, th) \ +#define INTERLEAVED_RGBX_FMT(fmt, bp, a, r, g, b, e0, e1, e2, e3) \ { \ .pixel_format = DRM_FORMAT_ ## fmt, \ .fetch_type = MDP_PLANE_INTERLEAVED, \ - .alpha_enable = alpha, \ + .alpha_enable = false, \ .element = { (e0), (e1), (e2), (e3) }, \ .bpc_g_y = g, \ .bpc_b_cb = b, \ .bpc_r_cr = r, \ .bpc_a = a, \ .chroma_sample = CHROMA_FULL, \ - .unpack_count = uc, \ + .unpack_count = 4, \ .bpp = bp, \ - .fetch_mode = fm, \ - .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | flg, \ - .num_planes = np, \ - .tile_height = th \ + .fetch_mode = MDP_FETCH_LINEAR, \ + .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT, \ + .num_planes = 1, \ + .tile_height = MDP_TILE_HEIGHT_DEFAULT \ } -#define INTERLEAVED_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, e3, \ -alpha, chroma, count, bp, flg, fm, np) \ +#define INTERLEAVED_RGBA_DX_FMT(fmt, bp, a, r, g, b, e0, e1, e2, e3) \ { \ .pixel_format = DRM_FORMAT_ ## fmt, \ .fetch_type = MDP_PLANE_INTERLEAVED, \ - .alpha_enable = alpha, \ - .element = { (e0), (e1), (e2), (e3)}, \ + .alpha_enable = true, \ + .element = { (e0), (e1), (e2), (e3) }, \ .bpc_g_y = g, \ .bpc_b_cb = b, \ .bpc_r_cr = r, \ .bpc_a = a, \ - .chroma_sample = chroma, \ - .unpack_count = count, \ + .chroma_sample = CHROMA_FULL, \ + .unpack_count = 4, \ .bpp = bp, \ - .fetch_mode = fm, \ - .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | flg, \ - .num_planes = np, \ + .fetch_mode = MDP_FETCH_LINEAR, \ + .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | \ + MSM_FORMAT_FLAG_DX, \ + .num_planes = 1, \ .tile_height = MDP_TILE_HEIGHT_DEFAULT \ } -#define PSEUDO_YUV_FMT(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np) \ +#define INTERLEAVED_RGBX_DX_FMT(fmt, bp, a, r, g, b, e0, e1, e2, e3) \ { \ .pixel_format = DRM_FORMAT_ ## fmt, \ - .fetch_type = MDP_PLANE_PSEUDO_PLANAR, \ - .alpha_enable = 0, \ - .element = { (e0), (e1), 0, 0 }, \ + .fetch_type = MDP_PLANE_INTERLEAVED, \ + .alpha_enable = false, \ + .element = { (e0), (e1), (e2), (e3) }, \ + .bpc_g_y = g, \ + .bpc_b_cb = b, \ + .bpc_r_cr = r, \ + .bpc_a = a, \ + .chroma_sample = CHROMA_FULL, \ + .unpack_count = 4, \ + .bpp = bp, \ + .fetch_mode = MDP_FETCH_LINEAR, \ + .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | \ + MSM_FORMAT_FLAG_DX, \ + .num_planes = 1, \ + .tile_height = MDP_TILE_HEIGHT_DEFAULT \ +} + +#define INTERLEAVED_RGB_FMT_TILED(fmt, bp, r, g, b, e0, e1, e2) \ +{ \ + .pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_type = MDP_PLANE_INTERLEAVED, \ + .alpha_enable = false, \ + .element = { (e0), (e1), (e2), 0 }, \ + .bpc_g_y = g, \ + .bpc_b_cb = b, \ + .bpc_r_cr = r, \ + .bpc_a = 0, \ + .chroma_sample = CHROMA_FULL, \ + .unpack_count = 3, \ + .bpp = bp, \ + .fetch_mode = MDP_FETCH_UBWC, \ + .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | \ + MSM_FORMAT_FLAG_COMPRESSED, \ + .num_planes = 2, \ + .tile_height = MDP_TILE_HEIGHT_UBWC, \ +} + +#define INTERLEAVED_RGBA_FMT_TILED(fmt, bp, a, r, g, b, e0, e1, e2, e3) \ +{ \ + .pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_type = MDP_PLANE_INTERLEAVED, \ + .alpha_enable = true, \ + .element = { (e0), (e1), (e2), (e3) }, \ + .bpc_g_y = g, \ + .bpc_b_cb = b, \ + .bpc_r_cr = r, \ + .bpc_a = a, \ + .chroma_sample = CHROMA_FULL, \ + .unpack_count = 4, \ + .bpp = bp, \ + .fetch_mode = MDP_FETCH_UBWC, \ + .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | \ + MSM_FORMAT_FLAG_COMPRESSED, \ + .num_planes = 2, \ + .tile_height = MDP_TILE_HEIGHT_UBWC, \ +} + +#define INTERLEAVED_RGBX_FMT_TILED(fmt, bp, a, r, g, b, e0, e1, e2, e3) \ +{ \ + .pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_type = MDP_PLANE_INTERLEAVED, \ + .alpha_enable = false, \ + .element = { (e0), (e1), (e2), (e3) }, \ .bpc_g_y = g, \ .bpc_b_cb = b, \ .bpc_r_cr = r, \ .bpc_a = a, \ + .chroma_sample = CHROMA_FULL, \ + .unpack_count = 4, \ + .bpp = bp, \ + .fetch_mode = MDP_FETCH_UBWC, \ + .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | \ + MSM_FORMAT_FLAG_COMPRESSED, \ + .num_planes = 2, \ + .tile_height = MDP_TILE_HEIGHT_UBWC, \ +} + +#define INTERLEAVED_RGBA_DX_FMT_TILED(fmt, bp, a, r, g, b, e0, e1, e2, e3) \ +{ \ + .pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_type = MDP_PLANE_INTERLEAVED, \ + .alpha_enable = true, \ + .element = { (e0), (e1), (e2), (e3) }, \ + .bpc_g_y = g, \ + .bpc_b_cb = b, \ + .bpc_r_cr = r, \ + .bpc_a = a, \ + .chroma_sample = CHROMA_FULL, \ + .unpack_count = 4, \ + .bpp = bp, \ + .fetch_mode = MDP_FETCH_UBWC, \ + .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | \ + MSM_FORMAT_FLAG_DX | \ + MSM_FORMAT_FLAG_COMPRESSED, \ + .num_planes = 2, \ + .tile_height = MDP_TILE_HEIGHT_UBWC, \ +} + +#define INTERLEAVED_YUV_FMT(fmt, bp, r, g, b, e0, e1, e2, e3, chroma) \ +{ \ + .pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_type = MDP_PLANE_INTERLEAVED, \ + .alpha_enable = false, \ + .element = { (e0), (e1), (e2), (e3)}, \ + .bpc_g_y = g, \ + .bpc_b_cb = b, \ + .bpc_r_cr = r, \ + .bpc_a = 0, \ .chroma_sample = chroma, \ - .unpack_count = 2, \ - .bpp = 2, \ - .fetch_mode = fm, \ - .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | flg, \ - .num_planes = np, \ + .unpack_count = 4, \ + .bpp = bp, \ + .fetch_mode = MDP_FETCH_LINEAR, \ + .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | \ + MSM_FORMAT_FLAG_YUV, \ + .num_planes = 1, \ .tile_height = MDP_TILE_HEIGHT_DEFAULT \ } -#define PSEUDO_YUV_FMT_TILED(fmt, a, r, g, b, e0, e1, chroma, \ -flg, fm, np, th) \ +#define PSEUDO_YUV_FMT(fmt, r, g, b, e0, e1, chroma) \ { \ .pixel_format = DRM_FORMAT_ ## fmt, \ .fetch_type = MDP_PLANE_PSEUDO_PLANAR, \ @@ -155,17 +273,18 @@ flg, fm, np, th) \ .bpc_g_y = g, \ .bpc_b_cb = b, \ .bpc_r_cr = r, \ - .bpc_a = a, \ + .bpc_a = 0, \ .chroma_sample = chroma, \ .unpack_count = 2, \ .bpp = 2, \ - .fetch_mode = fm, \ - .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | flg, \ - .num_planes = np, \ - .tile_height = th \ + .fetch_mode = MDP_FETCH_LINEAR, \ + .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | \ + MSM_FORMAT_FLAG_YUV, \ + .num_planes = 2, \ + .tile_height = MDP_TILE_HEIGHT_DEFAULT \ } -#define PSEUDO_YUV_FMT_LOOSE(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np)\ +#define PSEUDO_YUV_FMT_TILED(fmt, r, g, b, e0, e1, chroma, flg, th) \ { \ .pixel_format = DRM_FORMAT_ ## fmt, \ .fetch_type = MDP_PLANE_PSEUDO_PLANAR, \ @@ -174,18 +293,19 @@ flg, fm, np, th) \ .bpc_g_y = g, \ .bpc_b_cb = b, \ .bpc_r_cr = r, \ - .bpc_a = a, \ + .bpc_a = 0, \ .chroma_sample = chroma, \ .unpack_count = 2, \ .bpp = 2, \ - .fetch_mode = fm, \ - .flags = MSM_FORMAT_FLAG_UNPACK_ALIGN_MSB | flg, \ - .num_planes = np, \ - .tile_height = MDP_TILE_HEIGHT_DEFAULT \ + .fetch_mode = MDP_FETCH_UBWC, \ + .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | \ + MSM_FORMAT_FLAG_YUV | \ + MSM_FORMAT_FLAG_COMPRESSED | flg, \ + .num_planes = 4, \ + .tile_height = th \ } -#define PSEUDO_YUV_FMT_LOOSE_TILED(fmt, a, r, g, b, e0, e1, chroma, \ -flg, fm, np, th) \ +#define PSEUDO_YUV_FMT_LOOSE(fmt, r, g, b, e0, e1, chroma) \ { \ .pixel_format = DRM_FORMAT_ ## fmt, \ .fetch_type = MDP_PLANE_PSEUDO_PLANAR, \ @@ -194,323 +314,242 @@ flg, fm, np, th) \ .bpc_g_y = g, \ .bpc_b_cb = b, \ .bpc_r_cr = r, \ - .bpc_a = a, \ + .bpc_a = 0, \ .chroma_sample = chroma, \ .unpack_count = 2, \ .bpp = 2, \ - .fetch_mode = fm, \ - .flags = MSM_FORMAT_FLAG_UNPACK_ALIGN_MSB | flg, \ - .num_planes = np, \ - .tile_height = th \ + .fetch_mode = MDP_FETCH_LINEAR, \ + .flags = MSM_FORMAT_FLAG_UNPACK_ALIGN_MSB | \ + MSM_FORMAT_FLAG_DX | \ + MSM_FORMAT_FLAG_YUV, \ + .num_planes = 2, \ + .tile_height = MDP_TILE_HEIGHT_DEFAULT \ } -#define PLANAR_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, alpha, chroma, bp, \ -flg, fm, np) \ +#define PLANAR_YUV_FMT(fmt, bp, r, g, b, e0, e1, e2, chroma) \ { \ .pixel_format = DRM_FORMAT_ ## fmt, \ .fetch_type = MDP_PLANE_PLANAR, \ - .alpha_enable = alpha, \ + .alpha_enable = false, \ .element = { (e0), (e1), (e2), 0 }, \ .bpc_g_y = g, \ .bpc_b_cb = b, \ .bpc_r_cr = r, \ - .bpc_a = a, \ + .bpc_a = 0, \ .chroma_sample = chroma, \ .unpack_count = 1, \ .bpp = bp, \ - .fetch_mode = fm, \ - .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | flg, \ - .num_planes = np, \ + .fetch_mode = MDP_FETCH_LINEAR, \ + .flags = MSM_FORMAT_FLAG_UNPACK_TIGHT | \ + MSM_FORMAT_FLAG_YUV, \ + .num_planes = 3, \ .tile_height = MDP_TILE_HEIGHT_DEFAULT \ } static const struct msm_format mdp_formats[] = { - INTERLEAVED_RGB_FMT(ARGB8888, + INTERLEAVED_RGBA_FMT(ARGB8888, 4, BPC8A, BPC8, BPC8, BPC8, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, - true, 4, 0, - MDP_FETCH_LINEAR, 1), + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), - INTERLEAVED_RGB_FMT(ABGR8888, + INTERLEAVED_RGBA_FMT(ABGR8888, 4, BPC8A, BPC8, BPC8, BPC8, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - true, 4, 0, - MDP_FETCH_LINEAR, 1), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), - INTERLEAVED_RGB_FMT(XBGR8888, + INTERLEAVED_RGBX_FMT(XBGR8888, 4, BPC8A, BPC8, BPC8, BPC8, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - false, 4, 0, - MDP_FETCH_LINEAR, 1), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), - INTERLEAVED_RGB_FMT(RGBA8888, + INTERLEAVED_RGBA_FMT(RGBA8888, 4, BPC8A, BPC8, BPC8, BPC8, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, - true, 4, 0, - MDP_FETCH_LINEAR, 1), + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), - INTERLEAVED_RGB_FMT(BGRA8888, + INTERLEAVED_RGBA_FMT(BGRA8888, 4, BPC8A, BPC8, BPC8, BPC8, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, - true, 4, 0, - MDP_FETCH_LINEAR, 1), + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), - INTERLEAVED_RGB_FMT(BGRX8888, + INTERLEAVED_RGBX_FMT(BGRX8888, 4, BPC8A, BPC8, BPC8, BPC8, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, - false, 4, 0, - MDP_FETCH_LINEAR, 1), + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), - INTERLEAVED_RGB_FMT(XRGB8888, + INTERLEAVED_RGBX_FMT(XRGB8888, 4, BPC8A, BPC8, BPC8, BPC8, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, - false, 4, 0, - MDP_FETCH_LINEAR, 1), + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), - INTERLEAVED_RGB_FMT(RGBX8888, + INTERLEAVED_RGBX_FMT(RGBX8888, 4, BPC8A, BPC8, BPC8, BPC8, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, - false, 4, 0, - MDP_FETCH_LINEAR, 1), - - INTERLEAVED_RGB_FMT(RGB888, - 0, BPC8, BPC8, BPC8, - C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3, - false, 3, 0, - MDP_FETCH_LINEAR, 1), - - INTERLEAVED_RGB_FMT(BGR888, - 0, BPC8, BPC8, BPC8, - C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, - false, 3, 0, - MDP_FETCH_LINEAR, 1), - - INTERLEAVED_RGB_FMT(RGB565, - 0, BPC5, BPC6, BPC5, - C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3, - false, 2, 0, - MDP_FETCH_LINEAR, 1), - - INTERLEAVED_RGB_FMT(BGR565, - 0, BPC5, BPC6, BPC5, - C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, - false, 2, 0, - MDP_FETCH_LINEAR, 1), - - INTERLEAVED_RGB_FMT(ARGB1555, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), + + INTERLEAVED_RGB_FMT(RGB888, 3, + BPC8, BPC8, BPC8, + C1_B_Cb, C0_G_Y, C2_R_Cr), + + INTERLEAVED_RGB_FMT(BGR888, 3, + BPC8, BPC8, BPC8, + C2_R_Cr, C0_G_Y, C1_B_Cb), + + INTERLEAVED_RGB_FMT(RGB565, 2, + BPC5, BPC6, BPC5, + C1_B_Cb, C0_G_Y, C2_R_Cr), + + INTERLEAVED_RGB_FMT(BGR565, 2, + BPC5, BPC6, BPC5, + C2_R_Cr, C0_G_Y, C1_B_Cb), + + INTERLEAVED_RGBA_FMT(ARGB1555, 2, BPC1A, BPC5, BPC5, BPC5, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, - true, 2, 0, - MDP_FETCH_LINEAR, 1), + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), - INTERLEAVED_RGB_FMT(ABGR1555, + INTERLEAVED_RGBA_FMT(ABGR1555, 2, BPC1A, BPC5, BPC5, BPC5, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - true, 2, 0, - MDP_FETCH_LINEAR, 1), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), - INTERLEAVED_RGB_FMT(RGBA5551, + INTERLEAVED_RGBA_FMT(RGBA5551, 2, BPC1A, BPC5, BPC5, BPC5, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, - true, 2, 0, - MDP_FETCH_LINEAR, 1), + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), - INTERLEAVED_RGB_FMT(BGRA5551, + INTERLEAVED_RGBA_FMT(BGRA5551, 2, BPC1A, BPC5, BPC5, BPC5, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, - true, 2, 0, - MDP_FETCH_LINEAR, 1), + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), - INTERLEAVED_RGB_FMT(XRGB1555, + INTERLEAVED_RGBX_FMT(XRGB1555, 2, BPC1A, BPC5, BPC5, BPC5, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, - false, 2, 0, - MDP_FETCH_LINEAR, 1), + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), - INTERLEAVED_RGB_FMT(XBGR1555, + INTERLEAVED_RGBX_FMT(XBGR1555, 2, BPC1A, BPC5, BPC5, BPC5, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - false, 2, 0, - MDP_FETCH_LINEAR, 1), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), - INTERLEAVED_RGB_FMT(RGBX5551, + INTERLEAVED_RGBX_FMT(RGBX5551, 2, BPC1A, BPC5, BPC5, BPC5, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, - false, 2, 0, - MDP_FETCH_LINEAR, 1), + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), - INTERLEAVED_RGB_FMT(BGRX5551, + INTERLEAVED_RGBX_FMT(BGRX5551, 2, BPC1A, BPC5, BPC5, BPC5, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, - false, 2, 0, - MDP_FETCH_LINEAR, 1), + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), - INTERLEAVED_RGB_FMT(ARGB4444, + INTERLEAVED_RGBA_FMT(ARGB4444, 2, BPC4A, BPC4, BPC4, BPC4, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, - true, 2, 0, - MDP_FETCH_LINEAR, 1), + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), - INTERLEAVED_RGB_FMT(ABGR4444, + INTERLEAVED_RGBA_FMT(ABGR4444, 2, BPC4A, BPC4, BPC4, BPC4, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - true, 2, 0, - MDP_FETCH_LINEAR, 1), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), - INTERLEAVED_RGB_FMT(RGBA4444, + INTERLEAVED_RGBA_FMT(RGBA4444, 2, BPC4A, BPC4, BPC4, BPC4, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, - true, 2, 0, - MDP_FETCH_LINEAR, 1), + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), - INTERLEAVED_RGB_FMT(BGRA4444, + INTERLEAVED_RGBA_FMT(BGRA4444, 2, BPC4A, BPC4, BPC4, BPC4, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, - true, 2, 0, - MDP_FETCH_LINEAR, 1), + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), - INTERLEAVED_RGB_FMT(XRGB4444, + INTERLEAVED_RGBX_FMT(XRGB4444, 2, BPC4A, BPC4, BPC4, BPC4, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, - false, 2, 0, - MDP_FETCH_LINEAR, 1), + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), - INTERLEAVED_RGB_FMT(XBGR4444, + INTERLEAVED_RGBX_FMT(XBGR4444, 2, BPC4A, BPC4, BPC4, BPC4, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - false, 2, 0, - MDP_FETCH_LINEAR, 1), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), - INTERLEAVED_RGB_FMT(RGBX4444, + INTERLEAVED_RGBX_FMT(RGBX4444, 2, BPC4A, BPC4, BPC4, BPC4, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, - false, 2, 0, - MDP_FETCH_LINEAR, 1), + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), - INTERLEAVED_RGB_FMT(BGRX4444, + INTERLEAVED_RGBX_FMT(BGRX4444, 2, BPC4A, BPC4, BPC4, BPC4, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, - false, 2, 0, - MDP_FETCH_LINEAR, 1), + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), - INTERLEAVED_RGB_FMT(BGRA1010102, + INTERLEAVED_RGBA_DX_FMT(BGRA1010102, 4, BPC8A, BPC8, BPC8, BPC8, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, - true, 4, MSM_FORMAT_FLAG_DX, - MDP_FETCH_LINEAR, 1), + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), - INTERLEAVED_RGB_FMT(RGBA1010102, + INTERLEAVED_RGBA_DX_FMT(RGBA1010102, 4, BPC8A, BPC8, BPC8, BPC8, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, - true, 4, MSM_FORMAT_FLAG_DX, - MDP_FETCH_LINEAR, 1), + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), - INTERLEAVED_RGB_FMT(ABGR2101010, + INTERLEAVED_RGBA_DX_FMT(ABGR2101010, 4, BPC8A, BPC8, BPC8, BPC8, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - true, 4, MSM_FORMAT_FLAG_DX, - MDP_FETCH_LINEAR, 1), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), - INTERLEAVED_RGB_FMT(ARGB2101010, + INTERLEAVED_RGBA_DX_FMT(ARGB2101010, 4, BPC8A, BPC8, BPC8, BPC8, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, - true, 4, MSM_FORMAT_FLAG_DX, - MDP_FETCH_LINEAR, 1), + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), - INTERLEAVED_RGB_FMT(XRGB2101010, + INTERLEAVED_RGBX_DX_FMT(XRGB2101010, 4, BPC8A, BPC8, BPC8, BPC8, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, - false, 4, MSM_FORMAT_FLAG_DX, - MDP_FETCH_LINEAR, 1), + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), - INTERLEAVED_RGB_FMT(BGRX1010102, + INTERLEAVED_RGBX_DX_FMT(BGRX1010102, 4, BPC8A, BPC8, BPC8, BPC8, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, - false, 4, MSM_FORMAT_FLAG_DX, - MDP_FETCH_LINEAR, 1), + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), - INTERLEAVED_RGB_FMT(XBGR2101010, + INTERLEAVED_RGBX_DX_FMT(XBGR2101010, 4, BPC8A, BPC8, BPC8, BPC8, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - false, 4, MSM_FORMAT_FLAG_DX, - MDP_FETCH_LINEAR, 1), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), - INTERLEAVED_RGB_FMT(RGBX1010102, + INTERLEAVED_RGBX_DX_FMT(RGBX1010102, 4, BPC8A, BPC8, BPC8, BPC8, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, - false, 4, MSM_FORMAT_FLAG_DX, - MDP_FETCH_LINEAR, 1), + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), /* --- RGB formats above / YUV formats below this line --- */ /* 2 plane YUV */ PSEUDO_YUV_FMT(NV12, - 0, BPC8, BPC8, BPC8, + BPC8, BPC8, BPC8, C1_B_Cb, C2_R_Cr, - CHROMA_420, MSM_FORMAT_FLAG_YUV, - MDP_FETCH_LINEAR, 2), + CHROMA_420), PSEUDO_YUV_FMT(NV21, - 0, BPC8, BPC8, BPC8, + BPC8, BPC8, BPC8, C2_R_Cr, C1_B_Cb, - CHROMA_420, MSM_FORMAT_FLAG_YUV, - MDP_FETCH_LINEAR, 2), + CHROMA_420), PSEUDO_YUV_FMT(NV16, - 0, BPC8, BPC8, BPC8, + BPC8, BPC8, BPC8, C1_B_Cb, C2_R_Cr, - CHROMA_H2V1, MSM_FORMAT_FLAG_YUV, - MDP_FETCH_LINEAR, 2), + CHROMA_H2V1), PSEUDO_YUV_FMT(NV61, - 0, BPC8, BPC8, BPC8, + BPC8, BPC8, BPC8, C2_R_Cr, C1_B_Cb, - CHROMA_H2V1, MSM_FORMAT_FLAG_YUV, - MDP_FETCH_LINEAR, 2), + CHROMA_H2V1), PSEUDO_YUV_FMT_LOOSE(P010, - 0, BPC8, BPC8, BPC8, + BPC8, BPC8, BPC8, C1_B_Cb, C2_R_Cr, - CHROMA_420, MSM_FORMAT_FLAG_DX | MSM_FORMAT_FLAG_YUV, - MDP_FETCH_LINEAR, 2), + CHROMA_420), /* 1 plane YUV */ - INTERLEAVED_YUV_FMT(VYUY, - 0, BPC8, BPC8, BPC8, + INTERLEAVED_YUV_FMT(VYUY, 2, + BPC8, BPC8, BPC8, C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y, - false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, - MDP_FETCH_LINEAR, 1), + CHROMA_H2V1), - INTERLEAVED_YUV_FMT(UYVY, - 0, BPC8, BPC8, BPC8, + INTERLEAVED_YUV_FMT(UYVY, 2, + BPC8, BPC8, BPC8, C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y, - false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, - MDP_FETCH_LINEAR, 1), + CHROMA_H2V1), - INTERLEAVED_YUV_FMT(YUYV, - 0, BPC8, BPC8, BPC8, + INTERLEAVED_YUV_FMT(YUYV, 2, + BPC8, BPC8, BPC8, C0_G_Y, C1_B_Cb, C0_G_Y, C2_R_Cr, - false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, - MDP_FETCH_LINEAR, 1), + CHROMA_H2V1), - INTERLEAVED_YUV_FMT(YVYU, - 0, BPC8, BPC8, BPC8, + INTERLEAVED_YUV_FMT(YVYU, 2, + BPC8, BPC8, BPC8, C0_G_Y, C2_R_Cr, C0_G_Y, C1_B_Cb, - false, CHROMA_H2V1, 4, 2, MSM_FORMAT_FLAG_YUV, - MDP_FETCH_LINEAR, 1), + CHROMA_H2V1), /* 3 plane YUV */ - PLANAR_YUV_FMT(YUV420, - 0, BPC8, BPC8, BPC8, + PLANAR_YUV_FMT(YUV420, 1, + BPC8, BPC8, BPC8, C2_R_Cr, C1_B_Cb, C0_G_Y, - false, CHROMA_420, 1, MSM_FORMAT_FLAG_YUV, - MDP_FETCH_LINEAR, 3), + CHROMA_420), - PLANAR_YUV_FMT(YVU420, - 0, BPC8, BPC8, BPC8, + PLANAR_YUV_FMT(YVU420, 1, + BPC8, BPC8, BPC8, C1_B_Cb, C2_R_Cr, C0_G_Y, - false, CHROMA_420, 1, MSM_FORMAT_FLAG_YUV, - MDP_FETCH_LINEAR, 3), + CHROMA_420), }; /* @@ -520,82 +559,61 @@ static const struct msm_format mdp_formats[] = { * the data will be passed by user-space. */ static const struct msm_format mdp_formats_ubwc[] = { - INTERLEAVED_RGB_FMT_TILED(BGR565, - 0, BPC5, BPC6, BPC5, - C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, - false, 2, MSM_FORMAT_FLAG_COMPRESSED, - MDP_FETCH_UBWC, 2, MDP_TILE_HEIGHT_UBWC), + INTERLEAVED_RGB_FMT_TILED(BGR565, 2, + BPC5, BPC6, BPC5, + C2_R_Cr, C0_G_Y, C1_B_Cb), - INTERLEAVED_RGB_FMT_TILED(ABGR8888, + INTERLEAVED_RGBA_FMT_TILED(ABGR8888, 4, BPC8A, BPC8, BPC8, BPC8, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - true, 4, MSM_FORMAT_FLAG_COMPRESSED, - MDP_FETCH_UBWC, 2, MDP_TILE_HEIGHT_UBWC), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), /* ARGB8888 and ABGR8888 purposely have the same color * ordering. The hardware only supports ABGR8888 UBWC * natively. */ - INTERLEAVED_RGB_FMT_TILED(ARGB8888, + INTERLEAVED_RGBA_FMT_TILED(ARGB8888, 4, BPC8A, BPC8, BPC8, BPC8, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - true, 4, MSM_FORMAT_FLAG_COMPRESSED, - MDP_FETCH_UBWC, 2, MDP_TILE_HEIGHT_UBWC), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), - INTERLEAVED_RGB_FMT_TILED(XBGR8888, + INTERLEAVED_RGBX_FMT_TILED(XBGR8888, 4, BPC8A, BPC8, BPC8, BPC8, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - false, 4, MSM_FORMAT_FLAG_COMPRESSED, - MDP_FETCH_UBWC, 2, MDP_TILE_HEIGHT_UBWC), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), - INTERLEAVED_RGB_FMT_TILED(XRGB8888, + INTERLEAVED_RGBX_FMT_TILED(XRGB8888, 4, BPC8A, BPC8, BPC8, BPC8, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - false, 4, MSM_FORMAT_FLAG_COMPRESSED, - MDP_FETCH_UBWC, 2, MDP_TILE_HEIGHT_UBWC), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), - INTERLEAVED_RGB_FMT_TILED(ABGR2101010, + INTERLEAVED_RGBA_DX_FMT_TILED(ABGR2101010, 4, BPC8A, BPC8, BPC8, BPC8, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - true, 4, MSM_FORMAT_FLAG_DX | MSM_FORMAT_FLAG_COMPRESSED, - MDP_FETCH_UBWC, 2, MDP_TILE_HEIGHT_UBWC), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), - INTERLEAVED_RGB_FMT_TILED(XBGR2101010, + INTERLEAVED_RGBA_DX_FMT_TILED(XBGR2101010, 4, BPC8A, BPC8, BPC8, BPC8, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - true, 4, MSM_FORMAT_FLAG_DX | MSM_FORMAT_FLAG_COMPRESSED, - MDP_FETCH_UBWC, 2, MDP_TILE_HEIGHT_UBWC), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), - INTERLEAVED_RGB_FMT_TILED(XRGB2101010, + INTERLEAVED_RGBA_DX_FMT_TILED(XRGB2101010, 4, BPC8A, BPC8, BPC8, BPC8, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - true, 4, MSM_FORMAT_FLAG_DX | MSM_FORMAT_FLAG_COMPRESSED, - MDP_FETCH_UBWC, 2, MDP_TILE_HEIGHT_UBWC), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), /* XRGB2101010 and ARGB2101010 purposely have the same color * ordering. The hardware only supports ARGB2101010 UBWC * natively. */ - INTERLEAVED_RGB_FMT_TILED(ARGB2101010, + INTERLEAVED_RGBA_DX_FMT_TILED(ARGB2101010, 4, BPC8A, BPC8, BPC8, BPC8, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, - true, 4, MSM_FORMAT_FLAG_DX | MSM_FORMAT_FLAG_COMPRESSED, - MDP_FETCH_UBWC, 2, MDP_TILE_HEIGHT_UBWC), + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), PSEUDO_YUV_FMT_TILED(NV12, - 0, BPC8, BPC8, BPC8, + BPC8, BPC8, BPC8, C1_B_Cb, C2_R_Cr, - CHROMA_420, MSM_FORMAT_FLAG_YUV | - MSM_FORMAT_FLAG_COMPRESSED, - MDP_FETCH_UBWC, 4, MDP_TILE_HEIGHT_NV12), + CHROMA_420, 0, + MDP_TILE_HEIGHT_NV12), PSEUDO_YUV_FMT_TILED(P010, - 0, BPC8, BPC8, BPC8, + BPC8, BPC8, BPC8, C1_B_Cb, C2_R_Cr, - CHROMA_420, MSM_FORMAT_FLAG_DX | - MSM_FORMAT_FLAG_YUV | - MSM_FORMAT_FLAG_COMPRESSED, - MDP_FETCH_UBWC, 4, MDP_TILE_HEIGHT_UBWC), + CHROMA_420, MSM_FORMAT_FLAG_DX, + MDP_TILE_HEIGHT_UBWC), }; const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format, diff --git a/drivers/gpu/drm/msm/disp/mdp_format.h b/drivers/gpu/drm/msm/disp/mdp_format.h index a00d646ff4d47..915954bf5dc76 100644 --- a/drivers/gpu/drm/msm/disp/mdp_format.h +++ b/drivers/gpu/drm/msm/disp/mdp_format.h @@ -24,7 +24,7 @@ enum msm_format_flags { #define MSM_FORMAT_FLAG_UNPACK_TIGHT BIT(MSM_FORMAT_FLAG_UNPACK_TIGHT_BIT) #define MSM_FORMAT_FLAG_UNPACK_ALIGN_MSB BIT(MSM_FORMAT_FLAG_UNPACK_ALIGN_MSB_BIT) -/** +/* * DPU HW,Component order color map */ enum { @@ -37,6 +37,10 @@ enum { /** * struct msm_format: defines the format configuration * @pixel_format: format fourcc + * @bpc_g_y: element bit widths: BPC for G or Y + * @bpc_b_cb: element bit widths: BPC for B or Cb + * @bpc_r_cr: element bit widths: BPC for R or Cr + * @bpc_a: element bit widths: BPC for the alpha channel * @element: element color ordering * @fetch_type: how the color components are packed in pixel format * @chroma_sample: chroma sub-samplng type diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.h b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.h index b5f452bd7ada5..53bd1dcde15fb 100644 --- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.h +++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.h @@ -38,6 +38,7 @@ * struct msm_disp_state - structure to store current dpu state * @dev: device pointer * @drm_dev: drm device pointer + * @blocks: list head for hardware state blocks * @atomic_state: atomic state duplicated at the time of the error * @time: timestamp at which the coredump was captured */ @@ -55,7 +56,7 @@ struct msm_disp_state { /** * struct msm_disp_state_block - structure to store each hardware block state * @name: name of the block - * @drm_dev: handle to the linked list head + * @node: handle to the linked list head * @size: size of the register space of this hardware block * @state: array holding the register dump of this hardware block * @base_addr: starting address of this hardware block's register space @@ -88,8 +89,9 @@ void msm_disp_snapshot_destroy(struct drm_device *drm_dev); * msm_disp_snapshot_state_sync - synchronously snapshot display state * @kms: the kms object * - * Returns state or error + * Returns: state or error * + * Context: * Must be called with &kms->dump_mutex held */ struct msm_disp_state *msm_disp_snapshot_state_sync(struct msm_kms *kms); @@ -97,7 +99,7 @@ struct msm_disp_state *msm_disp_snapshot_state_sync(struct msm_kms *kms); /** * msm_disp_snapshot_state - trigger to dump the display snapshot * @drm_dev: handle to drm device - + * * Returns: none */ void msm_disp_snapshot_state(struct drm_device *drm_dev); @@ -114,7 +116,7 @@ void msm_disp_state_print(struct msm_disp_state *disp_state, struct drm_printer /** * msm_disp_snapshot_capture_state - utility to capture atomic state and hw registers * @disp_state: handle to msm_disp_state struct - + * * Returns: none */ void msm_disp_snapshot_capture_state(struct msm_disp_state *disp_state); @@ -122,7 +124,7 @@ void msm_disp_snapshot_capture_state(struct msm_disp_state *disp_state); /** * msm_disp_state_free - free the memory after the coredump has been read * @data: handle to struct msm_disp_state - + * * Returns: none */ void msm_disp_state_free(void *data); @@ -130,7 +132,6 @@ void msm_disp_state_free(void *data); /** * msm_disp_snapshot_add_block - add a hardware block with its register dump * @disp_state: handle to struct msm_disp_state - * @name: name of the hardware block * @len: size of the register space of the hardware block * @base_addr: starting address of the register space of the hardware block * @fmt: format in which the block names need to be printed diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c index 071bcdea80f71..19b470968f4db 100644 --- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c +++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c @@ -82,8 +82,7 @@ void msm_disp_state_print(struct msm_disp_state *state, struct drm_printer *p) drm_printf(p, "kernel: " UTS_RELEASE "\n"); drm_printf(p, "module: " KBUILD_MODNAME "\n"); drm_printf(p, "dpu devcoredump\n"); - drm_printf(p, "time: %lld.%09ld\n", - state->time.tv_sec, state->time.tv_nsec); + drm_printf(p, "time: %ptSp\n", &state->time); list_for_each_entry_safe(block, tmp, &state->blocks, node) { drm_printf(p, "====================%s================\n", block->name); diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c index 41018e82efa10..035e230201fd9 100644 --- a/drivers/gpu/drm/msm/dp/dp_audio.c +++ b/drivers/gpu/drm/msm/dp/dp_audio.c @@ -284,7 +284,7 @@ int msm_dp_audio_prepare(struct drm_bridge *bridge, * such cases check for connection status and bail out if not * connected. */ - if (!msm_dp_display->power_on) { + if (!msm_dp_display->active_stream_cnt) { rc = -EINVAL; goto end; } diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index 94411870a5e0a..ee8ec87b1a277 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -65,14 +65,24 @@ (PSR_UPDATE_MASK | PSR_CAPTURE_MASK | PSR_EXIT_MASK | \ PSR_UPDATE_ERROR_MASK | PSR_WAKE_ERROR_MASK) +#define DP_INTERRUPT_STATUS5 \ + (DP_INTR_DP0_VCPF_SENT | DP_INTR_DP1_VCPF_SENT) +#define DP_INTERRUPT_STATUS5_MASK \ + (DP_INTERRUPT_STATUS5 << DP_INTERRUPT_STATUS_MASK_SHIFT) + #define DP_CTRL_INTR_READY_FOR_VIDEO BIT(0) #define DP_CTRL_INTR_IDLE_PATTERN_SENT BIT(3) +#define DP_DP0_PUSH_VCPF BIT(12) +#define DP_DP1_PUSH_VCPF BIT(14) +#define DP_MSTLINK_PUSH_VCPF BIT(12) + #define MR_LINK_TRAINING1 0x8 #define MR_LINK_SYMBOL_ERM 0x80 #define MR_LINK_PRBS7 0x100 #define MR_LINK_CUSTOM80 0x200 #define MR_LINK_TRAINING4 0x40 +#define DP_MAX_TIME_SLOTS 64 enum { DP_TRAINING_NONE, @@ -109,6 +119,11 @@ struct msm_dp_vc_tu_mapping_table { u8 tu_size_minus1; }; +struct msm_dp_mst_ch_slot_info { + u32 start_slot; + u32 tot_slots; +}; + struct msm_dp_ctrl_private { struct msm_dp_ctrl msm_dp_ctrl; struct drm_device *drm_dev; @@ -118,6 +133,8 @@ struct msm_dp_ctrl_private { struct msm_dp_link *link; void __iomem *ahb_base; void __iomem *link_base; + void __iomem *mst2link_base; + void __iomem *mst3link_base; struct phy *phy; @@ -127,7 +144,8 @@ struct msm_dp_ctrl_private { unsigned int num_link_clks; struct clk_bulk_data *link_clks; - struct clk *pixel_clk; + struct clk *pixel_clk[DP_STREAM_MAX]; + unsigned int num_pixel_clks; union phy_configure_opts phy_opts; @@ -139,7 +157,10 @@ struct msm_dp_ctrl_private { bool core_clks_on; bool link_clks_on; - bool stream_clks_on; + bool stream_clks_on[DP_STREAM_MAX]; + bool mst_active; + + struct msm_dp_mst_ch_slot_info mst_ch_info[DP_STREAM_MAX]; }; static inline u32 msm_dp_read_ahb(const struct msm_dp_ctrl_private *ctrl, u32 offset) @@ -157,40 +178,180 @@ static inline void msm_dp_write_ahb(struct msm_dp_ctrl_private *ctrl, writel(data, ctrl->ahb_base + offset); } -static inline u32 msm_dp_read_link(struct msm_dp_ctrl_private *ctrl, u32 offset) +static inline u32 msm_dp_read_link(struct msm_dp_ctrl_private *ctrl, + enum msm_dp_stream_id stream_id, u32 offset) { - return readl_relaxed(ctrl->link_base + offset); + switch (stream_id) { + case DP_STREAM_0: + case DP_STREAM_1: + return readl_relaxed(ctrl->link_base + offset); + case DP_STREAM_2: + return readl_relaxed(ctrl->mst2link_base + offset); + case DP_STREAM_3: + return readl_relaxed(ctrl->mst3link_base + offset); + default: + DRM_ERROR("error stream_id\n"); + return 0; + } } static inline void msm_dp_write_link(struct msm_dp_ctrl_private *ctrl, - u32 offset, u32 data) + enum msm_dp_stream_id stream_id, u32 offset, u32 data) { /* * To make sure link reg writes happens before any other operation, * this function uses writel() instread of writel_relaxed() */ - writel(data, ctrl->link_base + offset); + switch (stream_id) { + case DP_STREAM_0: + case DP_STREAM_1: + writel(data, ctrl->link_base + offset); + break; + case DP_STREAM_2: + writel(data, ctrl->mst2link_base + offset); + break; + case DP_STREAM_3: + writel(data, ctrl->mst3link_base + offset); + break; + default: + DRM_ERROR("error stream_id\n"); + break; + } } static int msm_dp_aux_link_configure(struct drm_dp_aux *aux, struct msm_dp_link_info *link) { - u8 values[2]; + u8 lane_count, bw_code; int err; - values[0] = drm_dp_link_rate_to_bw_code(link->rate); - values[1] = link->num_lanes; + lane_count = link->num_lanes; if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING) - values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + lane_count |= DP_LANE_COUNT_ENHANCED_FRAME_EN; - err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, values, sizeof(values)); + err = drm_dp_dpcd_writeb(aux, DP_LANE_COUNT_SET, lane_count); if (err < 0) return err; + if (link->use_rate_set) { + DRM_DEBUG_DP("using LINK_RATE_SET: 0x%02x", link->rate_set); + err = drm_dp_dpcd_writeb(aux, DP_LINK_RATE_SET, link->rate_set); + } else { + bw_code = drm_dp_link_rate_to_bw_code(link->rate); + DRM_DEBUG_DP("using LINK_BW_SET: 0x%02x", bw_code); + err = drm_dp_dpcd_writeb(aux, DP_LINK_BW_SET, bw_code); + } + + return err; +} + +int msm_dp_ctrl_mst_send_act(struct msm_dp_ctrl *msm_dp_ctrl) +{ + struct msm_dp_ctrl_private *ctrl; + bool act_complete; + + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); + + if (!ctrl->mst_active) + return 0; + + msm_dp_write_link(ctrl, 0, REG_DP_MST_ACT, 0x1); + /* make sure ACT signal is performed */ + wmb(); + + msleep(20); /* needs 1 frame time */ + + act_complete = msm_dp_read_link(ctrl, 0, REG_DP_MST_ACT); + + if (!act_complete) { + drm_dbg_dp(ctrl->drm_dev, "MST ACT trigger complete failed\n"); + return 0; + } + return 0; } +static void msm_dp_ctrl_mst_config(struct msm_dp_ctrl_private *ctrl, bool enable) +{ + u32 mainlink_ctrl; + + mainlink_ctrl = msm_dp_read_link(ctrl, 0, REG_DP_MAINLINK_CTRL); + if (enable) + mainlink_ctrl |= DP_MAINLINK_CTRL_MST_EN; + else + mainlink_ctrl &= ~DP_MAINLINK_CTRL_MST_EN; + + msm_dp_write_link(ctrl, 0, REG_DP_MAINLINK_CTRL, mainlink_ctrl); +} + +static void msm_dp_ctrl_mst_channel_alloc(struct msm_dp_ctrl_private *ctrl, + enum msm_dp_stream_id stream_id, u32 ch_start_slot, + u32 tot_slot_cnt) +{ + u32 i, slot; + u32 slot_reg_1, slot_reg_2; + u32 reg_off = 0; + int const num_slots_per_reg = 32; + + if (ch_start_slot > DP_MAX_TIME_SLOTS || + (ch_start_slot + tot_slot_cnt > DP_MAX_TIME_SLOTS)) { + DRM_ERROR("invalid slots start %d, tot %d\n", + ch_start_slot, tot_slot_cnt); + return; + } + + drm_dbg_dp(ctrl->drm_dev, "stream_id %d, start_slot %d, tot_slot %d\n", + stream_id, ch_start_slot, tot_slot_cnt); + + if (stream_id == DP_STREAM_1) + reg_off = REG_DP_DP1_TIMESLOT_1_32 - REG_DP_DP0_TIMESLOT_1_32; + + slot_reg_1 = 0; + slot_reg_2 = 0; + + if (ch_start_slot && tot_slot_cnt) { + ch_start_slot--; + for (i = 0; i < tot_slot_cnt; i++) { + if (ch_start_slot < num_slots_per_reg) { + slot_reg_1 |= BIT(ch_start_slot); + } else { + slot = ch_start_slot - num_slots_per_reg; + slot_reg_2 |= BIT(slot); + } + ch_start_slot++; + } + } + + drm_dbg_dp(ctrl->drm_dev, "stream_id:%d slot_reg_1:%d, slot_reg_2:%d\n", stream_id, + slot_reg_1, slot_reg_2); + + msm_dp_write_link(ctrl, stream_id, stream_id > DP_STREAM_1 ? + REG_DP_MSTLINK_TIMESLOT_1_32 : REG_DP_DP0_TIMESLOT_1_32 + reg_off, + slot_reg_1); + msm_dp_write_link(ctrl, stream_id, stream_id > DP_STREAM_1 ? + REG_DP_MSTLINK_TIMESLOT_33_63 : REG_DP_DP0_TIMESLOT_33_63 + reg_off, + slot_reg_2); +} + +static void msm_dp_ctrl_update_rg(struct msm_dp_ctrl_private *ctrl, + enum msm_dp_stream_id stream_id, u32 x_int, u32 y_frac_enum) +{ + u32 rg, reg_off = 0; + + rg = y_frac_enum; + rg |= (x_int << 16); + + drm_dbg_dp(ctrl->drm_dev, "stream_id: %d x_int:%d y_frac_enum:%d rg:%d\n", + stream_id, x_int, y_frac_enum, rg); + + if (stream_id == DP_STREAM_1) + reg_off = REG_DP_DP1_RG - REG_DP_DP0_RG; + + msm_dp_write_link(ctrl, stream_id, stream_id > 1 ? + REG_DP_MSTLINK_DP_RG : REG_DP_DP0_RG + reg_off, rg); +} + /* * NOTE: resetting DP controller will also clear any pending HPD related interrupts */ @@ -253,6 +414,8 @@ void msm_dp_ctrl_enable_irq(struct msm_dp_ctrl *msm_dp_ctrl) DP_INTERRUPT_STATUS1_MASK); msm_dp_write_ahb(ctrl, REG_DP_INTR_STATUS2, DP_INTERRUPT_STATUS2_MASK); + msm_dp_write_ahb(ctrl, REG_DP_INTR_STATUS5, + DP_INTERRUPT_STATUS5_MASK); } void msm_dp_ctrl_disable_irq(struct msm_dp_ctrl *msm_dp_ctrl) @@ -262,6 +425,7 @@ void msm_dp_ctrl_disable_irq(struct msm_dp_ctrl *msm_dp_ctrl) msm_dp_write_ahb(ctrl, REG_DP_INTR_STATUS, 0x00); msm_dp_write_ahb(ctrl, REG_DP_INTR_STATUS2, 0x00); + msm_dp_write_ahb(ctrl, REG_DP_INTR_STATUS5, 0x00); } static u32 msm_dp_ctrl_get_psr_interrupt(struct msm_dp_ctrl_private *ctrl) @@ -281,22 +445,36 @@ static void msm_dp_ctrl_config_psr_interrupt(struct msm_dp_ctrl_private *ctrl) msm_dp_write_ahb(ctrl, REG_DP_INTR_MASK4, DP_INTERRUPT_MASK4); } +static u32 msm_dp_ctrl_get_mst_interrupt(struct msm_dp_ctrl_private *ctrl) +{ + u32 intr, intr_ack; + + intr = msm_dp_read_ahb(ctrl, REG_DP_INTR_STATUS5); + intr &= ~DP_INTERRUPT_STATUS5_MASK; + intr_ack = (intr & DP_INTERRUPT_STATUS5) + << DP_INTERRUPT_STATUS_ACK_SHIFT; + msm_dp_write_ahb(ctrl, REG_DP_INTR_STATUS5, + intr_ack | DP_INTERRUPT_STATUS5_MASK); + + return intr; +} + static void msm_dp_ctrl_psr_mainlink_enable(struct msm_dp_ctrl_private *ctrl) { u32 val; - val = msm_dp_read_link(ctrl, REG_DP_MAINLINK_CTRL); + val = msm_dp_read_link(ctrl, 0, REG_DP_MAINLINK_CTRL); val |= DP_MAINLINK_CTRL_ENABLE; - msm_dp_write_link(ctrl, REG_DP_MAINLINK_CTRL, val); + msm_dp_write_link(ctrl, 0, REG_DP_MAINLINK_CTRL, val); } static void msm_dp_ctrl_psr_mainlink_disable(struct msm_dp_ctrl_private *ctrl) { u32 val; - val = msm_dp_read_link(ctrl, REG_DP_MAINLINK_CTRL); + val = msm_dp_read_link(ctrl, 0, REG_DP_MAINLINK_CTRL); val &= ~DP_MAINLINK_CTRL_ENABLE; - msm_dp_write_link(ctrl, REG_DP_MAINLINK_CTRL, val); + msm_dp_write_link(ctrl, 0, REG_DP_MAINLINK_CTRL, val); } static void msm_dp_ctrl_mainlink_enable(struct msm_dp_ctrl_private *ctrl) @@ -305,21 +483,21 @@ static void msm_dp_ctrl_mainlink_enable(struct msm_dp_ctrl_private *ctrl) drm_dbg_dp(ctrl->drm_dev, "enable\n"); - mainlink_ctrl = msm_dp_read_link(ctrl, REG_DP_MAINLINK_CTRL); + mainlink_ctrl = msm_dp_read_link(ctrl, 0, REG_DP_MAINLINK_CTRL); mainlink_ctrl &= ~(DP_MAINLINK_CTRL_RESET | DP_MAINLINK_CTRL_ENABLE); - msm_dp_write_link(ctrl, REG_DP_MAINLINK_CTRL, mainlink_ctrl); + msm_dp_write_link(ctrl, 0, REG_DP_MAINLINK_CTRL, mainlink_ctrl); mainlink_ctrl |= DP_MAINLINK_CTRL_RESET; - msm_dp_write_link(ctrl, REG_DP_MAINLINK_CTRL, mainlink_ctrl); + msm_dp_write_link(ctrl, 0, REG_DP_MAINLINK_CTRL, mainlink_ctrl); mainlink_ctrl &= ~DP_MAINLINK_CTRL_RESET; - msm_dp_write_link(ctrl, REG_DP_MAINLINK_CTRL, mainlink_ctrl); + msm_dp_write_link(ctrl, 0, REG_DP_MAINLINK_CTRL, mainlink_ctrl); mainlink_ctrl |= (DP_MAINLINK_CTRL_ENABLE | DP_MAINLINK_FB_BOUNDARY_SEL); - msm_dp_write_link(ctrl, REG_DP_MAINLINK_CTRL, mainlink_ctrl); + msm_dp_write_link(ctrl, 0, REG_DP_MAINLINK_CTRL, mainlink_ctrl); } static void msm_dp_ctrl_mainlink_disable(struct msm_dp_ctrl_private *ctrl) @@ -328,23 +506,23 @@ static void msm_dp_ctrl_mainlink_disable(struct msm_dp_ctrl_private *ctrl) drm_dbg_dp(ctrl->drm_dev, "disable\n"); - mainlink_ctrl = msm_dp_read_link(ctrl, REG_DP_MAINLINK_CTRL); + mainlink_ctrl = msm_dp_read_link(ctrl, 0, REG_DP_MAINLINK_CTRL); mainlink_ctrl &= ~DP_MAINLINK_CTRL_ENABLE; - msm_dp_write_link(ctrl, REG_DP_MAINLINK_CTRL, mainlink_ctrl); + msm_dp_write_link(ctrl, 0, REG_DP_MAINLINK_CTRL, mainlink_ctrl); } static void msm_dp_setup_peripheral_flush(struct msm_dp_ctrl_private *ctrl) { u32 mainlink_ctrl; - mainlink_ctrl = msm_dp_read_link(ctrl, REG_DP_MAINLINK_CTRL); + mainlink_ctrl = msm_dp_read_link(ctrl, 0, REG_DP_MAINLINK_CTRL); if (ctrl->hw_revision >= DP_HW_VERSION_1_2) mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE; else mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_UPDATE_SDP; - msm_dp_write_link(ctrl, REG_DP_MAINLINK_CTRL, mainlink_ctrl); + msm_dp_write_link(ctrl, 0, REG_DP_MAINLINK_CTRL, mainlink_ctrl); } static bool msm_dp_ctrl_mainlink_ready(struct msm_dp_ctrl_private *ctrl) @@ -364,14 +542,28 @@ static bool msm_dp_ctrl_mainlink_ready(struct msm_dp_ctrl_private *ctrl) return true; } -void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl) +void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl, struct msm_dp_panel *msm_dp_panel) { struct msm_dp_ctrl_private *ctrl; + u32 state = 0x0; ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); + if (!ctrl->mst_active) + state |= DP_STATE_CTRL_PUSH_IDLE; + else if (msm_dp_panel->stream_id == DP_STREAM_0) + state |= DP_DP0_PUSH_VCPF; + else if (msm_dp_panel->stream_id == DP_STREAM_1) + state |= DP_DP1_PUSH_VCPF; + else + state |= DP_MSTLINK_PUSH_VCPF; + reinit_completion(&ctrl->idle_comp); - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, DP_STATE_CTRL_PUSH_IDLE); + + msm_dp_write_link(ctrl, msm_dp_panel->stream_id, + msm_dp_panel->stream_id > 1 ? + REG_DP_MSTLINK_STATE_CTRL : REG_DP_STATE_CTRL, + state); if (!wait_for_completion_timeout(&ctrl->idle_comp, IDLE_PATTERN_COMPLETION_TIMEOUT_JIFFIES)) @@ -380,26 +572,49 @@ void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl) drm_dbg_dp(ctrl->drm_dev, "mainlink off\n"); } -static void msm_dp_ctrl_config_ctrl(struct msm_dp_ctrl_private *ctrl) +static void msm_dp_ctrl_config_ctrl_streams(struct msm_dp_ctrl_private *ctrl, + struct msm_dp_panel *msm_dp_panel) { u32 config = 0, tbd; + u32 reg_offset = 0; + + if (msm_dp_panel->stream_id == DP_STREAM_0) + config = msm_dp_read_link(ctrl, 0, REG_DP_CONFIGURATION_CTRL); + + if (msm_dp_panel->stream_id == DP_STREAM_1) + reg_offset = REG_DP1_CONFIGURATION_CTRL - REG_DP_CONFIGURATION_CTRL; + + if (msm_dp_panel->msm_dp_mode.out_fmt_is_yuv_420) + config |= DP_CONFIGURATION_CTRL_RGB_YUV; /* YUV420 */ + + tbd = msm_dp_link_get_test_bits_depth(ctrl->link, + msm_dp_panel->msm_dp_mode.bpp); + + config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT; + + if (msm_dp_panel->psr_cap.version) + config |= DP_CONFIGURATION_CTRL_SEND_VSC; + + drm_dbg_dp(ctrl->drm_dev, "stream DP_CONFIGURATION_CTRL=0x%x\n", config); + + msm_dp_write_link(ctrl, msm_dp_panel->stream_id, msm_dp_panel->stream_id > 1 ? + REG_DP_MSTLINK_CONFIGURATION_CTRL : + REG_DP_CONFIGURATION_CTRL + reg_offset, config); + +} + +static void msm_dp_ctrl_config_ctrl_link(struct msm_dp_ctrl_private *ctrl) +{ + u32 config = 0; const u8 *dpcd = ctrl->panel->dpcd; /* Default-> LSCLK DIV: 1/4 LCLK */ config |= (2 << DP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT); - if (ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420) - config |= DP_CONFIGURATION_CTRL_RGB_YUV; /* YUV420 */ - /* Scrambler reset enable */ if (drm_dp_alternate_scrambler_reset_cap(dpcd)) config |= DP_CONFIGURATION_CTRL_ASSR; - tbd = msm_dp_link_get_test_bits_depth(ctrl->link, - ctrl->panel->msm_dp_mode.bpp); - - config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT; - /* Num of Lanes */ config |= ((ctrl->link->link_params.num_lanes - 1) << DP_CONFIGURATION_CTRL_NUM_OF_LANES_SHIFT); @@ -413,12 +628,9 @@ static void msm_dp_ctrl_config_ctrl(struct msm_dp_ctrl_private *ctrl) config |= DP_CONFIGURATION_CTRL_STATIC_DYNAMIC_CN; config |= DP_CONFIGURATION_CTRL_SYNC_ASYNC_CLK; - if (ctrl->panel->psr_cap.version) - config |= DP_CONFIGURATION_CTRL_SEND_VSC; + drm_dbg_dp(ctrl->drm_dev, "link DP_CONFIGURATION_CTRL=0x%x\n", config); - drm_dbg_dp(ctrl->drm_dev, "DP_CONFIGURATION_CTRL=0x%x\n", config); - - msm_dp_write_link(ctrl, REG_DP_CONFIGURATION_CTRL, config); + msm_dp_write_link(ctrl, 0, REG_DP_CONFIGURATION_CTRL, config); } static void msm_dp_ctrl_lane_mapping(struct msm_dp_ctrl_private *ctrl) @@ -431,23 +643,25 @@ static void msm_dp_ctrl_lane_mapping(struct msm_dp_ctrl_private *ctrl) ln_mapping |= lane_map[2] << LANE2_MAPPING_SHIFT; ln_mapping |= lane_map[3] << LANE3_MAPPING_SHIFT; - msm_dp_write_link(ctrl, REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING, - ln_mapping); + msm_dp_write_link(ctrl, 0, REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING, + ln_mapping); } -static void msm_dp_ctrl_configure_source_params(struct msm_dp_ctrl_private *ctrl) +static void msm_dp_ctrl_config_misc1_misc0(struct msm_dp_ctrl_private *ctrl, + struct msm_dp_panel *msm_dp_panel) { u32 colorimetry_cfg, test_bits_depth, misc_val; + u32 reg_offset = 0; - msm_dp_ctrl_lane_mapping(ctrl); - msm_dp_setup_peripheral_flush(ctrl); - - msm_dp_ctrl_config_ctrl(ctrl); - - test_bits_depth = msm_dp_link_get_test_bits_depth(ctrl->link, ctrl->panel->msm_dp_mode.bpp); + test_bits_depth = msm_dp_link_get_test_bits_depth(ctrl->link, + msm_dp_panel->msm_dp_mode.bpp); colorimetry_cfg = msm_dp_link_get_colorimetry_config(ctrl->link); - misc_val = msm_dp_read_link(ctrl, REG_DP_MISC1_MISC0); + if (msm_dp_panel->stream_id == DP_STREAM_1) + reg_offset = REG_DP1_MISC1_MISC0 - REG_DP_MISC1_MISC0; + + misc_val = msm_dp_read_link(ctrl, msm_dp_panel->stream_id, msm_dp_panel->stream_id > 1 ? + REG_DP_MSTLINK_MISC1_MISC0 : REG_DP_MISC1_MISC0 + reg_offset); /* clear bpp bits */ misc_val &= ~(0x07 << DP_MISC0_TEST_BITS_DEPTH_SHIFT); @@ -457,9 +671,22 @@ static void msm_dp_ctrl_configure_source_params(struct msm_dp_ctrl_private *ctrl misc_val |= DP_MISC0_SYNCHRONOUS_CLK; drm_dbg_dp(ctrl->drm_dev, "misc settings = 0x%x\n", misc_val); - msm_dp_write_link(ctrl, REG_DP_MISC1_MISC0, misc_val); + msm_dp_write_link(ctrl, msm_dp_panel->stream_id, + msm_dp_panel->stream_id > 1 ? + REG_DP_MSTLINK_MISC1_MISC0 : REG_DP_MISC1_MISC0 + reg_offset, + misc_val); +} + +static void msm_dp_ctrl_configure_source_params(struct msm_dp_ctrl_private *ctrl, + struct msm_dp_panel *msm_dp_panel) +{ + msm_dp_ctrl_config_ctrl_streams(ctrl, msm_dp_panel); + + msm_dp_ctrl_config_misc1_misc0(ctrl, msm_dp_panel); + + msm_dp_panel_timing_cfg(msm_dp_panel, ctrl->msm_dp_ctrl.wide_bus_en); - msm_dp_panel_timing_cfg(ctrl->panel, ctrl->msm_dp_ctrl.wide_bus_en); + msm_dp_panel_mst_async_fifo(msm_dp_panel, ctrl->mst_active); } /* @@ -1275,9 +1502,9 @@ static void msm_dp_ctrl_setup_tr_unit(struct msm_dp_ctrl_private *ctrl) pr_debug("dp_tu=0x%x, valid_boundary=0x%x, valid_boundary2=0x%x\n", msm_dp_tu, valid_boundary, valid_boundary2); - msm_dp_write_link(ctrl, REG_DP_VALID_BOUNDARY, valid_boundary); - msm_dp_write_link(ctrl, REG_DP_TU, msm_dp_tu); - msm_dp_write_link(ctrl, REG_DP_VALID_BOUNDARY_2, valid_boundary2); + msm_dp_write_link(ctrl, 0, REG_DP_VALID_BOUNDARY, valid_boundary); + msm_dp_write_link(ctrl, 0, REG_DP_TU, msm_dp_tu); + msm_dp_write_link(ctrl, 0, REG_DP_VALID_BOUNDARY_2, valid_boundary2); } static int msm_dp_ctrl_wait4video_ready(struct msm_dp_ctrl_private *ctrl) @@ -1394,7 +1621,7 @@ static int msm_dp_ctrl_set_pattern_state_bit(struct msm_dp_ctrl_private *ctrl, bit = BIT(state_bit - 1); drm_dbg_dp(ctrl->drm_dev, "hw: bit=%d train=%d\n", bit, state_bit); - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, bit); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, bit); bit = BIT(state_bit - 1) << DP_MAINLINK_READY_LINK_TRAINING_SHIFT; @@ -1421,7 +1648,7 @@ static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl, delay_us = drm_dp_read_clock_recovery_delay(ctrl->aux, ctrl->panel->dpcd, dp_phy, false); - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, 0); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, 0); *training_step = DP_TRAINING_1; @@ -1474,26 +1701,32 @@ static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl, static int msm_dp_ctrl_link_rate_down_shift(struct msm_dp_ctrl_private *ctrl) { int ret = 0; + struct msm_dp_link_info *link_params = &ctrl->link->link_params; - switch (ctrl->link->link_params.rate) { - case 810000: - ctrl->link->link_params.rate = 540000; - break; - case 540000: - ctrl->link->link_params.rate = 270000; - break; - case 270000: - ctrl->link->link_params.rate = 162000; - break; - case 162000: - default: - ret = -EINVAL; - break; + if (link_params->rate_set) { + --link_params->rate_set; + link_params->rate = link_params->supported_rates[link_params->rate_set]; + } else { + switch (link_params->rate) { + case 810000: + link_params->rate = 540000; + break; + case 540000: + link_params->rate = 270000; + break; + case 270000: + link_params->rate = 162000; + break; + case 162000: + default: + ret = -EINVAL; + break; + } } if (!ret) { drm_dbg_dp(ctrl->drm_dev, "new rate=0x%x\n", - ctrl->link->link_params.rate); + link_params->rate); } return ret; @@ -1539,7 +1772,7 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl, delay_us = drm_dp_read_channel_eq_delay(ctrl->aux, ctrl->panel->dpcd, dp_phy, false); - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, 0); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, 0); *training_step = DP_TRAINING_2; @@ -1614,7 +1847,7 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl, u8 assr; struct msm_dp_link_info link_info = {0}; - msm_dp_ctrl_config_ctrl(ctrl); + msm_dp_ctrl_config_ctrl_link(ctrl); link_info.num_lanes = ctrl->link->link_params.num_lanes; link_info.rate = ctrl->link->link_params.rate; @@ -1656,7 +1889,7 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl, } end: - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, 0); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, 0); return ret; } @@ -1802,34 +2035,34 @@ static int msm_dp_ctrl_enable_mainlink_clocks(struct msm_dp_ctrl_private *ctrl) static void msm_dp_ctrl_enable_sdp(struct msm_dp_ctrl_private *ctrl) { /* trigger sdp */ - msm_dp_write_link(ctrl, MMSS_DP_SDP_CFG3, UPDATE_SDP); - msm_dp_write_link(ctrl, MMSS_DP_SDP_CFG3, 0x0); + msm_dp_write_link(ctrl, 0, MMSS_DP_SDP_CFG3, UPDATE_SDP); + msm_dp_write_link(ctrl, 0, MMSS_DP_SDP_CFG3, 0x0); } static void msm_dp_ctrl_psr_enter(struct msm_dp_ctrl_private *ctrl) { u32 cmd; - cmd = msm_dp_read_link(ctrl, REG_PSR_CMD); + cmd = msm_dp_read_link(ctrl, 0, REG_PSR_CMD); cmd &= ~(PSR_ENTER | PSR_EXIT); cmd |= PSR_ENTER; msm_dp_ctrl_enable_sdp(ctrl); - msm_dp_write_link(ctrl, REG_PSR_CMD, cmd); + msm_dp_write_link(ctrl, 0, REG_PSR_CMD, cmd); } static void msm_dp_ctrl_psr_exit(struct msm_dp_ctrl_private *ctrl) { u32 cmd; - cmd = msm_dp_read_link(ctrl, REG_PSR_CMD); + cmd = msm_dp_read_link(ctrl, 0, REG_PSR_CMD); cmd &= ~(PSR_ENTER | PSR_EXIT); cmd |= PSR_EXIT; msm_dp_ctrl_enable_sdp(ctrl); - msm_dp_write_link(ctrl, REG_PSR_CMD, cmd); + msm_dp_write_link(ctrl, 0, REG_PSR_CMD, cmd); } void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl) @@ -1842,9 +2075,9 @@ void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl) return; /* enable PSR1 function */ - cfg = msm_dp_read_link(ctrl, REG_PSR_CONFIG); + cfg = msm_dp_read_link(ctrl, 0, REG_PSR_CONFIG); cfg |= PSR1_SUPPORTED; - msm_dp_write_link(ctrl, REG_PSR_CONFIG, cfg); + msm_dp_write_link(ctrl, 0, REG_PSR_CONFIG, cfg); msm_dp_ctrl_config_psr_interrupt(ctrl); msm_dp_ctrl_enable_sdp(ctrl); @@ -1882,17 +2115,17 @@ void msm_dp_ctrl_set_psr(struct msm_dp_ctrl *msm_dp_ctrl, bool enter) return; } - msm_dp_ctrl_push_idle(msm_dp_ctrl); - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, 0); + msm_dp_ctrl_push_idle(msm_dp_ctrl, ctrl->panel); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, 0); msm_dp_ctrl_psr_mainlink_disable(ctrl); } else { msm_dp_ctrl_psr_mainlink_enable(ctrl); msm_dp_ctrl_psr_exit(ctrl); - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, DP_STATE_CTRL_SEND_VIDEO); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, DP_STATE_CTRL_SEND_VIDEO); msm_dp_ctrl_wait4video_ready(ctrl); - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, 0); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, 0); } } @@ -1992,7 +2225,7 @@ static int msm_dp_ctrl_link_maintenance(struct msm_dp_ctrl_private *ctrl) int ret = 0; int training_step = DP_TRAINING_NONE; - msm_dp_ctrl_push_idle(&ctrl->msm_dp_ctrl); + msm_dp_ctrl_push_idle(&ctrl->msm_dp_ctrl, ctrl->panel); ctrl->link->phy_params.p_level = 0; ctrl->link->phy_params.v_level = 0; @@ -2003,7 +2236,11 @@ static int msm_dp_ctrl_link_maintenance(struct msm_dp_ctrl_private *ctrl) msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX); - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, DP_STATE_CTRL_SEND_VIDEO); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, DP_STATE_CTRL_SEND_VIDEO); + + ret = msm_dp_ctrl_mst_send_act(&ctrl->msm_dp_ctrl); + if (ret) + return ret; ret = msm_dp_ctrl_wait4video_ready(ctrl); end: @@ -2018,72 +2255,72 @@ static void msm_dp_ctrl_send_phy_pattern(struct msm_dp_ctrl_private *ctrl, u32 value = 0x0; /* Make sure to clear the current pattern before starting a new one */ - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, 0x0); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, 0x0); drm_dbg_dp(ctrl->drm_dev, "pattern: %#x\n", pattern); switch (pattern) { case DP_PHY_TEST_PATTERN_D10_2: - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, - DP_STATE_CTRL_LINK_TRAINING_PATTERN1); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, + DP_STATE_CTRL_LINK_TRAINING_PATTERN1); break; case DP_PHY_TEST_PATTERN_ERROR_COUNT: value &= ~(1 << 16); - msm_dp_write_link(ctrl, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, - value); + msm_dp_write_link(ctrl, 0, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, + value); value |= SCRAMBLER_RESET_COUNT_VALUE; - msm_dp_write_link(ctrl, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, - value); - msm_dp_write_link(ctrl, REG_DP_MAINLINK_LEVELS, - DP_MAINLINK_SAFE_TO_EXIT_LEVEL_2); - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, - DP_STATE_CTRL_LINK_SYMBOL_ERR_MEASURE); + msm_dp_write_link(ctrl, 0, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, + value); + msm_dp_write_link(ctrl, 0, REG_DP_MAINLINK_LEVELS, + DP_MAINLINK_SAFE_TO_EXIT_LEVEL_2); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, + DP_STATE_CTRL_LINK_SYMBOL_ERR_MEASURE); break; case DP_PHY_TEST_PATTERN_PRBS7: - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, - DP_STATE_CTRL_LINK_PRBS7); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, + DP_STATE_CTRL_LINK_PRBS7); break; case DP_PHY_TEST_PATTERN_80BIT_CUSTOM: - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, - DP_STATE_CTRL_LINK_TEST_CUSTOM_PATTERN); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, + DP_STATE_CTRL_LINK_TEST_CUSTOM_PATTERN); /* 00111110000011111000001111100000 */ - msm_dp_write_link(ctrl, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG0, - 0x3E0F83E0); + msm_dp_write_link(ctrl, 0, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG0, + 0x3E0F83E0); /* 00001111100000111110000011111000 */ - msm_dp_write_link(ctrl, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG1, - 0x0F83E0F8); + msm_dp_write_link(ctrl, 0, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG1, + 0x0F83E0F8); /* 1111100000111110 */ - msm_dp_write_link(ctrl, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG2, - 0x0000F83E); + msm_dp_write_link(ctrl, 0, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG2, + 0x0000F83E); break; case DP_PHY_TEST_PATTERN_CP2520: - value = msm_dp_read_link(ctrl, REG_DP_MAINLINK_CTRL); + value = msm_dp_read_link(ctrl, 0, REG_DP_MAINLINK_CTRL); value &= ~DP_MAINLINK_CTRL_SW_BYPASS_SCRAMBLER; - msm_dp_write_link(ctrl, REG_DP_MAINLINK_CTRL, value); + msm_dp_write_link(ctrl, 0, REG_DP_MAINLINK_CTRL, value); value = DP_HBR2_ERM_PATTERN; - msm_dp_write_link(ctrl, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, - value); + msm_dp_write_link(ctrl, 0, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, + value); value |= SCRAMBLER_RESET_COUNT_VALUE; - msm_dp_write_link(ctrl, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, - value); - msm_dp_write_link(ctrl, REG_DP_MAINLINK_LEVELS, - DP_MAINLINK_SAFE_TO_EXIT_LEVEL_2); - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, - DP_STATE_CTRL_LINK_SYMBOL_ERR_MEASURE); - value = msm_dp_read_link(ctrl, REG_DP_MAINLINK_CTRL); + msm_dp_write_link(ctrl, 0, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, + value); + msm_dp_write_link(ctrl, 0, REG_DP_MAINLINK_LEVELS, + DP_MAINLINK_SAFE_TO_EXIT_LEVEL_2); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, + DP_STATE_CTRL_LINK_SYMBOL_ERR_MEASURE); + value = msm_dp_read_link(ctrl, 0, REG_DP_MAINLINK_CTRL); value |= DP_MAINLINK_CTRL_ENABLE; - msm_dp_write_link(ctrl, REG_DP_MAINLINK_CTRL, value); + msm_dp_write_link(ctrl, 0, REG_DP_MAINLINK_CTRL, value); break; case DP_PHY_TEST_PATTERN_SEL_MASK: - msm_dp_write_link(ctrl, REG_DP_MAINLINK_CTRL, - DP_MAINLINK_CTRL_ENABLE); - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, - DP_STATE_CTRL_LINK_TRAINING_PATTERN4); + msm_dp_write_link(ctrl, 0, REG_DP_MAINLINK_CTRL, + DP_MAINLINK_CTRL_ENABLE); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, + DP_STATE_CTRL_LINK_TRAINING_PATTERN4); break; default: @@ -2111,7 +2348,7 @@ static bool msm_dp_ctrl_send_phy_test_pattern(struct msm_dp_ctrl_private *ctrl) msm_dp_ctrl_update_phy_vx_px(ctrl, DP_PHY_DPRX); msm_dp_link_send_test_response(ctrl->link); - pattern_sent = msm_dp_read_link(ctrl, REG_DP_MAINLINK_READY); + pattern_sent = msm_dp_read_link(ctrl, 0, REG_DP_MAINLINK_READY); switch (pattern_sent) { case MR_LINK_TRAINING1: @@ -2145,6 +2382,43 @@ static bool msm_dp_ctrl_send_phy_test_pattern(struct msm_dp_ctrl_private *ctrl) return success; } +static int msm_dp_ctrl_on_pixel_clk(struct msm_dp_ctrl_private *ctrl, unsigned long pixel_rate, + enum msm_dp_stream_id stream_id) +{ + int ret; + + ret = clk_set_rate(ctrl->pixel_clk[stream_id], pixel_rate * 1000); + if (ret) { + DRM_ERROR("Failed to set pixel clock rate. ret=%d\n", ret); + return ret; + } + + if (ctrl->stream_clks_on[stream_id]) { + drm_dbg_dp(ctrl->drm_dev, "pixel clks already enabled\n"); + } else { + ret = clk_prepare_enable(ctrl->pixel_clk[stream_id]); + if (ret) { + DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret); + return ret; + } + ctrl->stream_clks_on[stream_id] = true; + } + + return ret; +} + +void msm_dp_ctrl_off_pixel_clk(struct msm_dp_ctrl *msm_dp_ctrl, enum msm_dp_stream_id stream_id) +{ + struct msm_dp_ctrl_private *ctrl; + + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); + + if (ctrl->stream_clks_on[stream_id]) { + clk_disable_unprepare(ctrl->pixel_clk[stream_id]); + ctrl->stream_clks_on[stream_id] = false; + } +} + static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl) { int ret; @@ -2161,31 +2435,17 @@ static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl * running. Add the global reset just before disabling the * link clocks and core clocks. */ - msm_dp_ctrl_off(&ctrl->msm_dp_ctrl); + msm_dp_ctrl_off_pixel_clk(&ctrl->msm_dp_ctrl, ctrl->panel->stream_id); + msm_dp_ctrl_off_link(&ctrl->msm_dp_ctrl); - ret = msm_dp_ctrl_on_link(&ctrl->msm_dp_ctrl); + ret = msm_dp_ctrl_on_link(&ctrl->msm_dp_ctrl, false); if (ret) { DRM_ERROR("failed to enable DP link controller\n"); return ret; } pixel_rate = ctrl->panel->msm_dp_mode.drm_mode.clock; - ret = clk_set_rate(ctrl->pixel_clk, pixel_rate * 1000); - if (ret) { - DRM_ERROR("Failed to set pixel clock rate. ret=%d\n", ret); - return ret; - } - - if (ctrl->stream_clks_on) { - drm_dbg_dp(ctrl->drm_dev, "pixel clks already enabled\n"); - } else { - ret = clk_prepare_enable(ctrl->pixel_clk); - if (ret) { - DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret); - return ret; - } - ctrl->stream_clks_on = true; - } + ret = msm_dp_ctrl_on_pixel_clk(ctrl, pixel_rate, ctrl->panel->stream_id); msm_dp_ctrl_send_phy_test_pattern(ctrl); @@ -2258,7 +2518,7 @@ static bool msm_dp_ctrl_channel_eq_ok(struct msm_dp_ctrl_private *ctrl) return drm_dp_channel_eq_ok(link_status, num_lanes); } -int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl) +int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl, bool mst_active) { int rc = 0; struct msm_dp_ctrl_private *ctrl; @@ -2276,6 +2536,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl) rate = ctrl->panel->link_info.rate; pixel_rate = ctrl->panel->msm_dp_mode.drm_mode.clock; + ctrl->mst_active = mst_active; msm_dp_ctrl_core_clk_enable(&ctrl->msm_dp_ctrl); @@ -2391,6 +2652,7 @@ static int msm_dp_ctrl_link_retrain(struct msm_dp_ctrl_private *ctrl) } static void msm_dp_ctrl_config_msa(struct msm_dp_ctrl_private *ctrl, + struct msm_dp_panel *msm_dp_panel, u32 rate, u32 stream_rate_khz, bool is_ycbcr_420) { @@ -2400,6 +2662,12 @@ static void msm_dp_ctrl_config_msa(struct msm_dp_ctrl_private *ctrl, u32 const link_rate_hbr2 = 540000; u32 const link_rate_hbr3 = 810000; unsigned long den, num; + u32 mvid_reg_off = 0, nvid_reg_off = 0; + + if (msm_dp_panel->stream_id == DP_STREAM_1) { + mvid_reg_off = REG_DP1_SOFTWARE_MVID - REG_DP_SOFTWARE_MVID; + nvid_reg_off = REG_DP1_SOFTWARE_NVID - REG_DP_SOFTWARE_NVID; + } switch (rate) { case link_rate_hbr3: @@ -2454,59 +2722,136 @@ static void msm_dp_ctrl_config_msa(struct msm_dp_ctrl_private *ctrl, nvid *= 3; drm_dbg_dp(ctrl->drm_dev, "mvid=0x%x, nvid=0x%x\n", mvid, nvid); - msm_dp_write_link(ctrl, REG_DP_SOFTWARE_MVID, mvid); - msm_dp_write_link(ctrl, REG_DP_SOFTWARE_NVID, nvid); + msm_dp_write_link(ctrl, msm_dp_panel->stream_id, + msm_dp_panel->stream_id > 1 ? + REG_MSTLINK_SOFTWARE_MVID : REG_DP_SOFTWARE_MVID + mvid_reg_off, + mvid); + msm_dp_write_link(ctrl, msm_dp_panel->stream_id, + msm_dp_panel->stream_id > 1 ? + REG_MSTLINK_SOFTWARE_NVID : REG_DP_SOFTWARE_NVID + nvid_reg_off, + nvid); +} + +/* TODO: comments here. */ +static void msm_dp_ctrl_mst_calculate_rg(struct msm_dp_ctrl_private *ctrl, + struct msm_dp_panel *panel, + u32 *p_x_int, u32 *p_y_frac_enum) +{ + u64 min_slot_cnt, max_slot_cnt; + u64 raw_target_sc, target_sc_fixp; + u64 ts_denom, ts_enum, ts_int; + u64 pclk = panel->msm_dp_mode.drm_mode.clock; + u64 lclk = 0; + u64 lanes = ctrl->link->link_params.num_lanes; + u64 bpp = panel->msm_dp_mode.bpp; + u64 pbn = panel->pbn; + u64 numerator, denominator, temp, temp1, temp2; + u32 x_int = 0, y_frac_enum = 0; + u64 target_strm_sym, ts_int_fixp, ts_frac_fixp, y_frac_enum_fixp; + + lclk = ctrl->link->link_params.rate; + + /* min_slot_cnt */ + numerator = pclk * bpp * 64 * 1000; + denominator = lclk * lanes * 8 * 1000; + min_slot_cnt = drm_fixp_from_fraction(numerator, denominator); + + /* max_slot_cnt */ + numerator = pbn * 54 * 1000; + denominator = lclk * lanes; + max_slot_cnt = drm_fixp_from_fraction(numerator, denominator); + + /* raw_target_sc */ + numerator = max_slot_cnt + min_slot_cnt; + denominator = drm_fixp_from_fraction(2, 1); + raw_target_sc = drm_fixp_div(numerator, denominator); + + /* target_sc */ + temp = drm_fixp_from_fraction(256 * lanes, 1); + numerator = drm_fixp_mul(raw_target_sc, temp); + denominator = drm_fixp_from_fraction(256 * lanes, 1); + target_sc_fixp = drm_fixp_div(numerator, denominator); + + ts_enum = 256 * lanes; + ts_denom = drm_fixp_from_fraction(256 * lanes, 1); + ts_int = drm_fixp2int(target_sc_fixp); + + temp = drm_fixp2int_ceil(raw_target_sc); + if (temp != ts_int) { + temp = drm_fixp_from_fraction(ts_int, 1); + temp1 = raw_target_sc - temp; + temp2 = drm_fixp_mul(temp1, ts_denom); + ts_enum = drm_fixp2int(temp2); + } + + /* target_strm_sym */ + ts_int_fixp = drm_fixp_from_fraction(ts_int, 1); + ts_frac_fixp = drm_fixp_from_fraction(ts_enum, drm_fixp2int(ts_denom)); + temp = ts_int_fixp + ts_frac_fixp; + temp1 = drm_fixp_from_fraction(lanes, 1); + target_strm_sym = drm_fixp_mul(temp, temp1); + + /* x_int */ + x_int = drm_fixp2int(target_strm_sym); + + /* y_enum_frac */ + temp = drm_fixp_from_fraction(x_int, 1); + temp1 = target_strm_sym - temp; + temp2 = drm_fixp_from_fraction(256, 1); + y_frac_enum_fixp = drm_fixp_mul(temp1, temp2); + + temp1 = drm_fixp2int(y_frac_enum_fixp); + temp2 = drm_fixp2int_ceil(y_frac_enum_fixp); + + y_frac_enum = (u32)((temp1 == temp2) ? temp1 : temp1 + 1); + + *p_x_int = x_int; + *p_y_frac_enum = y_frac_enum; + + drm_dbg_dp(ctrl->drm_dev, "MST lane_cnt:%llu, rate:%llu x_int:%d, y_frac:%d\n", + lanes, lclk, x_int, y_frac_enum); +} + +static void msm_dp_ctrl_mst_stream_setup(struct msm_dp_ctrl_private *ctrl, + struct msm_dp_panel *panel) +{ + u32 x_int, y_frac_enum; + + if (!ctrl->mst_active) + return; + + drm_dbg_dp(ctrl->drm_dev, "MST stream channel allocation\n"); + + msm_dp_ctrl_mst_stream_channel_slot_setup(&ctrl->msm_dp_ctrl); + + msm_dp_ctrl_mst_calculate_rg(ctrl, panel, &x_int, &y_frac_enum); + + msm_dp_ctrl_update_rg(ctrl, panel->stream_id, x_int, y_frac_enum); } -int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train) +int msm_dp_ctrl_prepare_stream_on(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train) { int ret = 0; - bool mainlink_ready = false; struct msm_dp_ctrl_private *ctrl; - unsigned long pixel_rate; - unsigned long pixel_rate_orig; if (!msm_dp_ctrl) return -EINVAL; ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); - pixel_rate = pixel_rate_orig = ctrl->panel->msm_dp_mode.drm_mode.clock; - - if (msm_dp_ctrl->wide_bus_en || ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420) - pixel_rate >>= 1; - - drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n", - ctrl->link->link_params.rate, - ctrl->link->link_params.num_lanes, pixel_rate); + drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d\n", + ctrl->link->link_params.rate, + ctrl->link->link_params.num_lanes); - drm_dbg_dp(ctrl->drm_dev, - "core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n", - ctrl->core_clks_on, ctrl->link_clks_on, ctrl->stream_clks_on); + drm_dbg_dp(ctrl->drm_dev, "core_clk_on=%d link_clk_on=%d\n", + ctrl->core_clks_on, ctrl->link_clks_on); if (!ctrl->link_clks_on) { /* link clk is off */ ret = msm_dp_ctrl_enable_mainlink_clocks(ctrl); if (ret) { DRM_ERROR("Failed to start link clocks. ret=%d\n", ret); - goto end; - } - } - - ret = clk_set_rate(ctrl->pixel_clk, pixel_rate * 1000); - if (ret) { - DRM_ERROR("Failed to set pixel clock rate. ret=%d\n", ret); - goto end; - } - - if (ctrl->stream_clks_on) { - drm_dbg_dp(ctrl->drm_dev, "pixel clks already enabled\n"); - } else { - ret = clk_prepare_enable(ctrl->pixel_clk); - if (ret) { - DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret); - goto end; + return ret; } - ctrl->stream_clks_on = true; } if (force_link_train || !msm_dp_ctrl_channel_eq_ok(ctrl)) @@ -2515,24 +2860,68 @@ int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train /* stop txing train pattern to end link training */ msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX); + return ret; +} + +int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, struct msm_dp_panel *msm_dp_panel) +{ + int ret = 0; + bool mainlink_ready = false; + struct msm_dp_ctrl_private *ctrl; + unsigned long pixel_rate; + unsigned long pixel_rate_orig; + + if (!msm_dp_ctrl) + return -EINVAL; + + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); + + pixel_rate_orig = msm_dp_panel->msm_dp_mode.drm_mode.clock; + pixel_rate = pixel_rate_orig; + + if (msm_dp_ctrl->wide_bus_en || msm_dp_panel->msm_dp_mode.out_fmt_is_yuv_420) + pixel_rate >>= 1; + + drm_dbg_dp(ctrl->drm_dev, "pixel_rate=%lu\n", pixel_rate); + + ret = msm_dp_ctrl_on_pixel_clk(ctrl, pixel_rate, msm_dp_panel->stream_id); + if (ret) + return ret; + /* * Set up transfer unit values and set controller state to send * video. */ reinit_completion(&ctrl->video_comp); - msm_dp_ctrl_configure_source_params(ctrl); + msm_dp_ctrl_lane_mapping(ctrl); + msm_dp_setup_peripheral_flush(ctrl); + if (ctrl->mst_active) + msm_dp_ctrl_mst_config(ctrl, true); + + if (msm_dp_panel->stream_id == DP_STREAM_0) + msm_dp_ctrl_config_ctrl_link(ctrl); + + msm_dp_ctrl_configure_source_params(ctrl, msm_dp_panel); msm_dp_ctrl_config_msa(ctrl, + msm_dp_panel, ctrl->link->link_params.rate, pixel_rate_orig, - ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420); + msm_dp_panel->msm_dp_mode.out_fmt_is_yuv_420); + + msm_dp_panel_clear_dsc_dto(msm_dp_panel); - msm_dp_panel_clear_dsc_dto(ctrl->panel); + if (!ctrl->mst_active) + msm_dp_ctrl_setup_tr_unit(ctrl); - msm_dp_ctrl_setup_tr_unit(ctrl); + msm_dp_ctrl_mst_stream_setup(ctrl, msm_dp_panel); - msm_dp_write_link(ctrl, REG_DP_STATE_CTRL, DP_STATE_CTRL_SEND_VIDEO); + msm_dp_write_link(ctrl, 0, REG_DP_STATE_CTRL, DP_STATE_CTRL_SEND_VIDEO); + + ret = msm_dp_ctrl_mst_send_act(msm_dp_ctrl); + if (ret) + return ret; ret = msm_dp_ctrl_wait4video_ready(ctrl); if (ret) @@ -2542,11 +2931,10 @@ int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train drm_dbg_dp(ctrl->drm_dev, "mainlink %s\n", mainlink_ready ? "READY" : "NOT READY"); -end: return ret; } -void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl) +void msm_dp_ctrl_reinit_phy(struct msm_dp_ctrl *msm_dp_ctrl) { struct msm_dp_ctrl_private *ctrl; struct phy *phy; @@ -2554,23 +2942,6 @@ void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl) ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); phy = ctrl->phy; - msm_dp_panel_disable_vsc_sdp(ctrl->panel); - - /* set dongle to D3 (power off) mode */ - msm_dp_link_psm_config(ctrl->link, &ctrl->panel->link_info, true); - - msm_dp_ctrl_mainlink_disable(ctrl); - - if (ctrl->stream_clks_on) { - clk_disable_unprepare(ctrl->pixel_clk); - ctrl->stream_clks_on = false; - } - - dev_pm_opp_set_rate(ctrl->dev, 0); - msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl); - - phy_power_off(phy); - /* aux channel down, reinit phy */ phy_exit(phy); phy_init(phy); @@ -2588,44 +2959,51 @@ void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl) phy = ctrl->phy; msm_dp_ctrl_mainlink_disable(ctrl); + msm_dp_ctrl_mst_config(ctrl, false); + + msm_dp_ctrl_reset(&ctrl->msm_dp_ctrl); + + ctrl->mst_active = false; dev_pm_opp_set_rate(ctrl->dev, 0); msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl); - DRM_DEBUG_DP("Before, phy=%p init_count=%d power_on=%d\n", - phy, phy->init_count, phy->power_count); - phy_power_off(phy); - - DRM_DEBUG_DP("After, phy=%p init_count=%d power_on=%d\n", - phy, phy->init_count, phy->power_count); + drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n", + phy, phy->init_count, phy->power_count); } -void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl) +void msm_dp_ctrl_set_mst_channel_info(struct msm_dp_ctrl *msm_dp_ctrl, + enum msm_dp_stream_id stream_id, + u32 start_slot, u32 tot_slots) { struct msm_dp_ctrl_private *ctrl; - struct phy *phy; - ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); - phy = ctrl->phy; + if (!msm_dp_ctrl || stream_id >= DP_STREAM_MAX) { + DRM_ERROR("invalid input\n"); + return; + } - msm_dp_panel_disable_vsc_sdp(ctrl->panel); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); - msm_dp_ctrl_mainlink_disable(ctrl); + ctrl->mst_ch_info[stream_id].start_slot = start_slot; + ctrl->mst_ch_info[stream_id].tot_slots = tot_slots; +} - msm_dp_ctrl_reset(&ctrl->msm_dp_ctrl); +void msm_dp_ctrl_mst_stream_channel_slot_setup(struct msm_dp_ctrl *msm_dp_ctrl) +{ + struct msm_dp_ctrl_private *ctrl; + int i; - if (ctrl->stream_clks_on) { - clk_disable_unprepare(ctrl->pixel_clk); - ctrl->stream_clks_on = false; - } + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); - dev_pm_opp_set_rate(ctrl->dev, 0); - msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl); + if (!ctrl->mst_active) + return; - phy_power_off(phy); - drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n", - phy, phy->init_count, phy->power_count); + for (i = DP_STREAM_0; i < ctrl->num_pixel_clks; i++) { + msm_dp_ctrl_mst_channel_alloc(ctrl, i, ctrl->mst_ch_info[i].start_slot, + ctrl->mst_ch_info[i].tot_slots); + } } irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl) @@ -2669,6 +3047,13 @@ irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl) ret = IRQ_HANDLED; } + isr = msm_dp_ctrl_get_mst_interrupt(ctrl); + if (isr & (DP_INTR_DP0_VCPF_SENT | DP_INTR_DP1_VCPF_SENT)) { + drm_dbg_dp(ctrl->drm_dev, "vcpf sent\n"); + complete(&ctrl->idle_comp); + ret = IRQ_HANDLED; + } + /* DP aux isr */ isr = msm_dp_ctrl_get_aux_interrupt(ctrl); if (isr) @@ -2687,7 +3072,14 @@ static const char *ctrl_clks[] = { "ctrl_link_iface", }; -static int msm_dp_ctrl_clk_init(struct msm_dp_ctrl *msm_dp_ctrl) +static const char * const pixel_clks[] = { + "stream_pixel", + "stream_1_pixel", + "stream_2_pixel", + "stream_3_pixel", +}; + +static int msm_dp_ctrl_clk_init(struct msm_dp_ctrl *msm_dp_ctrl, int max_stream) { struct msm_dp_ctrl_private *ctrl; struct device *dev; @@ -2720,18 +3112,41 @@ static int msm_dp_ctrl_clk_init(struct msm_dp_ctrl *msm_dp_ctrl) if (rc) return rc; - ctrl->pixel_clk = devm_clk_get(dev, "stream_pixel"); - if (IS_ERR(ctrl->pixel_clk)) - return PTR_ERR(ctrl->pixel_clk); + ctrl->num_pixel_clks = 0; + for (i = DP_STREAM_0; i < max_stream; i++) { + ctrl->pixel_clk[i] = devm_clk_get(dev, pixel_clks[i]); + + if (i == 0 && IS_ERR(ctrl->pixel_clk[i])) + return PTR_ERR(ctrl->pixel_clk[i]); + + if (IS_ERR(ctrl->pixel_clk[i])) { + DRM_DEBUG_DP("stream %d pixel clock not exist", i); + break; + } + + ctrl->num_pixel_clks++; + } return 0; } +int msm_dp_ctrl_get_stream_cnt(struct msm_dp_ctrl *msm_dp_ctrl) +{ + struct msm_dp_ctrl_private *ctrl; + + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); + + return ctrl->num_pixel_clks; +} + struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev, struct msm_dp_link *link, struct msm_dp_panel *panel, struct drm_dp_aux *aux, struct phy *phy, + int max_stream, void __iomem *ahb_base, - void __iomem *link_base) + void __iomem *link_base, + void __iomem *mst2link_base, + void __iomem *mst3link_base) { struct msm_dp_ctrl_private *ctrl; int ret; @@ -2771,8 +3186,11 @@ struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev, struct msm_dp_link *link ctrl->phy = phy; ctrl->ahb_base = ahb_base; ctrl->link_base = link_base; + ctrl->mst2link_base = mst2link_base; + ctrl->mst3link_base = mst3link_base; + ctrl->mst_active = false; - ret = msm_dp_ctrl_clk_init(&ctrl->msm_dp_ctrl); + ret = msm_dp_ctrl_clk_init(&ctrl->msm_dp_ctrl, max_stream); if (ret) { dev_err(dev, "failed to init clocks\n"); return ERR_PTR(ret); diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h index 124b9b21bb7f2..cfe7e44969437 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.h +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h @@ -16,12 +16,13 @@ struct msm_dp_ctrl { struct phy; -int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl); -int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train); -void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl); +int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl, bool mst_active); +int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, + struct msm_dp_panel *msm_dp_panel); +int msm_dp_ctrl_prepare_stream_on(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train); void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl); -void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl); -void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl); +void msm_dp_ctrl_off_pixel_clk(struct msm_dp_ctrl *msm_dp_ctrl, enum msm_dp_stream_id stream_id); +void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl, struct msm_dp_panel *msm_dp_panel); irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl); void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl); struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev, @@ -29,8 +30,11 @@ struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev, struct msm_dp_panel *panel, struct drm_dp_aux *aux, struct phy *phy, + int max_stream, void __iomem *ahb_base, - void __iomem *link_base); + void __iomem *link_base, + void __iomem *mst2link_base, + void __iomem *mst3link_base); void msm_dp_ctrl_reset(struct msm_dp_ctrl *msm_dp_ctrl); void msm_dp_ctrl_phy_init(struct msm_dp_ctrl *msm_dp_ctrl); @@ -46,4 +50,11 @@ void msm_dp_ctrl_core_clk_disable(struct msm_dp_ctrl *msm_dp_ctrl); void msm_dp_ctrl_enable_irq(struct msm_dp_ctrl *msm_dp_ctrl); void msm_dp_ctrl_disable_irq(struct msm_dp_ctrl *msm_dp_ctrl); +void msm_dp_ctrl_reinit_phy(struct msm_dp_ctrl *msm_dp_ctrl); +int msm_dp_ctrl_get_stream_cnt(struct msm_dp_ctrl *dp_ctrl); +int msm_dp_ctrl_mst_send_act(struct msm_dp_ctrl *msm_dp_ctrl); +void msm_dp_ctrl_mst_stream_channel_slot_setup(struct msm_dp_ctrl *msm_dp_ctrl); +void msm_dp_ctrl_set_mst_channel_info(struct msm_dp_ctrl *msm_dp_ctrl, + enum msm_dp_stream_id stream_id, + u32 start_slot, u32 tot_slots); #endif /* _DP_CTRL_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h index 6dc0ff4f0f650..a90083fec856d 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.h +++ b/drivers/gpu/drm/msm/dp/dp_debug.h @@ -12,7 +12,7 @@ #if defined(CONFIG_DEBUG_FS) /** - * msm_dp_debug_get() - configure and get the DisplayPlot debug module data + * msm_dp_debug_init() - configure and get the DisplayPlot debug module data * * @dev: device instance of the caller * @panel: instance of panel module diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index f247aad553975..77ea491efbd58 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "msm_drv.h" @@ -27,6 +28,7 @@ #include "dp_drm.h" #include "dp_audio.h" #include "dp_debug.h" +#include "dp_mst_drm.h" static bool psr_enabled = false; module_param(psr_enabled, bool, 0); @@ -38,40 +40,9 @@ enum { ISR_DISCONNECTED, ISR_CONNECT_PENDING, ISR_CONNECTED, - ISR_HPD_REPLUG_COUNT, + ISR_HPD_IO_GLITCH_COUNT, ISR_IRQ_HPD_PULSE_COUNT, - ISR_HPD_LO_GLITH_COUNT, -}; - -/* event thread connection state */ -enum { - ST_DISCONNECTED, - ST_MAINLINK_READY, - ST_CONNECTED, - ST_DISCONNECT_PENDING, - ST_DISPLAY_OFF, -}; - -enum { - EV_NO_EVENT, - /* hpd events */ - EV_HPD_PLUG_INT, - EV_IRQ_HPD_INT, - EV_HPD_UNPLUG_INT, - EV_USER_NOTIFICATION, -}; - -#define EVENT_TIMEOUT (HZ/10) /* 100ms */ -#define DP_EVENT_Q_MAX 8 - -#define DP_TIMEOUT_NONE 0 - -#define WAIT_FOR_RESUME_TIMEOUT_JIFFIES (HZ / 2) - -struct msm_dp_event { - u32 event_id; - u32 data; - u32 delay; + ISR_HPD_REPLUG_COUNT, }; struct msm_dp_display_private { @@ -84,6 +55,9 @@ struct msm_dp_display_private { bool phy_initialized; bool audio_supported; + struct mutex plugged_lock; + bool plugged; + struct drm_device *drm_dev; struct drm_dp_aux *aux; @@ -91,21 +65,14 @@ struct msm_dp_display_private { struct msm_dp_panel *panel; struct msm_dp_ctrl *ctrl; - struct msm_dp_display_mode msm_dp_mode; struct msm_dp msm_dp_display; /* wait for audio signaling */ struct completion audio_comp; - /* event related only access by event thread */ - struct mutex event_mutex; - wait_queue_head_t event_q; - u32 hpd_state; - u32 event_pndx; - u32 event_gndx; - struct task_struct *ev_tsk; - struct msm_dp_event event_list[DP_EVENT_Q_MAX]; - spinlock_t event_lock; + /* HPD IRQ handling */ + spinlock_t irq_thread_lock; + u32 hpd_isr_status; bool wide_bus_supported; @@ -120,19 +87,38 @@ struct msm_dp_display_private { void __iomem *link_base; size_t link_len; - void __iomem *p0_base; - size_t p0_len; + void __iomem *mst2link_base; + size_t mst2link_len; + + void __iomem *mst3link_base; + size_t mst3link_len; + + void __iomem *pixel_base[DP_STREAM_MAX]; + size_t pixel_len; + + int max_stream; }; struct msm_dp_desc { phys_addr_t io_start; unsigned int id; bool wide_bus_supported; + int mst_streams; }; -static const struct msm_dp_desc msm_dp_desc_sa8775p[] = { +static const struct msm_dp_desc msm_dp_desc_glymur[] = { { .io_start = 0x0af54000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, { .io_start = 0x0af5c000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, + { .io_start = 0x0af64000, .id = MSM_DP_CONTROLLER_2, .wide_bus_supported = true }, + { .io_start = 0x0af6c000, .id = MSM_DP_CONTROLLER_3, .wide_bus_supported = true }, + {} +}; + +static const struct msm_dp_desc msm_dp_desc_sa8775p[] = { + { .io_start = 0x0af54000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true, + .mst_streams = 4}, + { .io_start = 0x0af5c000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true, + .mst_streams = 2}, { .io_start = 0x22154000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, { .io_start = 0x2215c000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, {} @@ -187,6 +173,7 @@ static const struct msm_dp_desc msm_dp_desc_x1e80100[] = { }; static const struct of_device_id msm_dp_dt_match[] = { + { .compatible = "qcom,glymur-dp", .data = &msm_dp_desc_glymur }, { .compatible = "qcom,sa8775p-dp", .data = &msm_dp_desc_sa8775p }, { .compatible = "qcom,sc7180-dp", .data = &msm_dp_desc_sc7180 }, { .compatible = "qcom,sc7280-dp", .data = &msm_dp_desc_sc7280 }, @@ -201,6 +188,7 @@ static const struct of_device_id msm_dp_dt_match[] = { { .compatible = "qcom,x1e80100-dp", .data = &msm_dp_desc_x1e80100 }, {} }; +MODULE_DEVICE_TABLE(of, msm_dp_dt_match); static struct msm_dp_display_private *dev_get_dp_display_private(struct device *dev) { @@ -209,60 +197,6 @@ static struct msm_dp_display_private *dev_get_dp_display_private(struct device * return container_of(dp, struct msm_dp_display_private, msm_dp_display); } -static int msm_dp_add_event(struct msm_dp_display_private *msm_dp_priv, u32 event, - u32 data, u32 delay) -{ - unsigned long flag; - struct msm_dp_event *todo; - int pndx; - - spin_lock_irqsave(&msm_dp_priv->event_lock, flag); - pndx = msm_dp_priv->event_pndx + 1; - pndx %= DP_EVENT_Q_MAX; - if (pndx == msm_dp_priv->event_gndx) { - pr_err("event_q is full: pndx=%d gndx=%d\n", - msm_dp_priv->event_pndx, msm_dp_priv->event_gndx); - spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag); - return -EPERM; - } - todo = &msm_dp_priv->event_list[msm_dp_priv->event_pndx++]; - msm_dp_priv->event_pndx %= DP_EVENT_Q_MAX; - todo->event_id = event; - todo->data = data; - todo->delay = delay; - wake_up(&msm_dp_priv->event_q); - spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag); - - return 0; -} - -static int msm_dp_del_event(struct msm_dp_display_private *msm_dp_priv, u32 event) -{ - unsigned long flag; - struct msm_dp_event *todo; - u32 gndx; - - spin_lock_irqsave(&msm_dp_priv->event_lock, flag); - if (msm_dp_priv->event_pndx == msm_dp_priv->event_gndx) { - spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag); - return -ENOENT; - } - - gndx = msm_dp_priv->event_gndx; - while (msm_dp_priv->event_pndx != gndx) { - todo = &msm_dp_priv->event_list[gndx]; - if (todo->event_id == event) { - todo->event_id = EV_NO_EVENT; /* deleted */ - todo->delay = 0; - } - gndx++; - gndx %= DP_EVENT_Q_MAX; - } - spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag); - - return 0; -} - void msm_dp_display_signal_audio_start(struct msm_dp *msm_dp_display) { struct msm_dp_display_private *dp; @@ -281,8 +215,6 @@ void msm_dp_display_signal_audio_complete(struct msm_dp *msm_dp_display) complete_all(&dp->audio_comp); } -static int msm_dp_hpd_event_thread_start(struct msm_dp_display_private *msm_dp_priv); - static int msm_dp_display_bind(struct device *dev, struct device *master, void *data) { @@ -302,12 +234,6 @@ static int msm_dp_display_bind(struct device *dev, struct device *master, goto end; } - rc = msm_dp_hpd_event_thread_start(dp); - if (rc) { - DRM_ERROR("Event thread create failed\n"); - goto end; - } - return 0; end: return rc; @@ -319,8 +245,6 @@ static void msm_dp_display_unbind(struct device *dev, struct device *master, struct msm_dp_display_private *dp = dev_get_dp_display_private(dev); struct msm_drm_private *priv = dev_get_drvdata(master); - kthread_stop(dp->ev_tsk); - of_dp_aux_depopulate_bus(dp->aux); msm_dp_aux_unregister(dp->aux); @@ -334,45 +258,6 @@ static const struct component_ops msm_dp_display_comp_ops = { .unbind = msm_dp_display_unbind, }; -static void msm_dp_display_send_hpd_event(struct msm_dp *msm_dp_display) -{ - struct msm_dp_display_private *dp; - struct drm_connector *connector; - - dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - - connector = dp->msm_dp_display.connector; - drm_helper_hpd_irq_event(connector->dev); -} - -static int msm_dp_display_send_hpd_notification(struct msm_dp_display_private *dp, - bool hpd) -{ - if ((hpd && dp->msm_dp_display.link_ready) || - (!hpd && !dp->msm_dp_display.link_ready)) { - drm_dbg_dp(dp->drm_dev, "HPD already %s\n", str_on_off(hpd)); - return 0; - } - - /* reset video pattern flag on disconnect */ - if (!hpd) { - dp->panel->video_test = false; - if (!dp->msm_dp_display.is_edp) - drm_dp_set_subconnector_property(dp->msm_dp_display.connector, - connector_status_disconnected, - dp->panel->dpcd, - dp->panel->downstream_ports); - } - - dp->msm_dp_display.link_ready = hpd; - - drm_dbg_dp(dp->drm_dev, "type=%d hpd=%d\n", - dp->msm_dp_display.connector_type, hpd); - msm_dp_display_send_hpd_event(&dp->msm_dp_display); - - return 0; -} - static int msm_dp_display_lttpr_init(struct msm_dp_display_private *dp, u8 *dpcd) { int rc, lttpr_count; @@ -390,12 +275,47 @@ static int msm_dp_display_lttpr_init(struct msm_dp_display_private *dp, u8 *dpcd return lttpr_count; } +static void msm_dp_display_mst_init(struct msm_dp_display_private *dp) +{ + const unsigned long clear_mstm_ctrl_timeout_us = 100000; + u8 old_mstm_ctrl; + struct msm_dp *msm_dp = &dp->msm_dp_display; + int ret; + + /* clear sink MST state */ + drm_dp_dpcd_read_byte(dp->aux, DP_MSTM_CTRL, &old_mstm_ctrl); + + ret = drm_dp_dpcd_write_byte(dp->aux, DP_MSTM_CTRL, 0); + if (ret < 0) { + DRM_ERROR("failed to clear DP_MSTM_CTRL, ret=%d\n", ret); + return; + } + + /* add extra delay if MST old state is on*/ + if (old_mstm_ctrl) { + drm_dbg_dp(dp->drm_dev, "wait %luus to set DP_MSTM_CTRL set 0\n", + clear_mstm_ctrl_timeout_us); + usleep_range(clear_mstm_ctrl_timeout_us, + clear_mstm_ctrl_timeout_us + 1000); + } + + ret = drm_dp_dpcd_write_byte(dp->aux, DP_MSTM_CTRL, + DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC); + if (ret < 0) { + DRM_ERROR("sink MST enablement failed\n"); + return; + } + + msm_dp->mst_active = true; +} + static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp) { struct drm_connector *connector = dp->msm_dp_display.connector; const struct drm_display_info *info = &connector->display_info; int rc = 0; u8 dpcd[DP_RECEIVER_CAP_SIZE]; + const struct drm_edid *drm_edid; rc = drm_dp_read_dpcd_caps(dp->aux, dpcd); if (rc) @@ -403,10 +323,25 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp) dp->link->lttpr_count = msm_dp_display_lttpr_init(dp, dpcd); - rc = msm_dp_panel_read_sink_caps(dp->panel, connector); + rc = msm_dp_panel_read_link_caps(dp->panel, connector); if (rc) goto end; + if (!(dp->max_stream > 1) || !drm_dp_read_mst_cap(dp->aux, dp->panel->dpcd)) { + drm_edid = drm_edid_read_ddc(connector, &dp->aux->ddc); + drm_edid_connector_update(connector, drm_edid); + + if (!drm_edid) { + DRM_ERROR("panel edid read failed\n"); + /* check edid read fail is due to unplug */ + if (!msm_dp_aux_is_link_connected(dp->aux)) + return -ETIMEDOUT; + } + + if (rc) + goto end; + } + msm_dp_link_process_request(dp->link); if (!dp->msm_dp_display.is_edp) @@ -418,7 +353,7 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp) dp->msm_dp_display.psr_supported = dp->panel->psr_cap.version && psr_enabled; dp->audio_supported = info->has_audio; - msm_dp_panel_handle_sink_request(dp->panel); + msm_dp_panel_handle_sink_request(dp->panel, drm_edid); /* * set sink to normal operation mode -- D0 @@ -426,20 +361,19 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp) */ msm_dp_link_psm_config(dp->link, &dp->panel->link_info, false); - msm_dp_link_reset_phy_params_vx_px(dp->link); - rc = msm_dp_ctrl_on_link(dp->ctrl); - if (rc) { - DRM_ERROR("failed to complete DP link training\n"); - goto end; - } + if (dp->max_stream > 1 && drm_dp_read_mst_cap(dp->aux, dp->panel->dpcd)) + msm_dp_display_mst_init(dp); + + if (dp->msm_dp_display.mst_active) + msm_dp_mst_display_set_mgr_state(&dp->msm_dp_display, true); - msm_dp_add_event(dp, EV_USER_NOTIFICATION, true, 0); + msm_dp_link_reset_phy_params_vx_px(dp->link); end: return rc; } -static void msm_dp_display_host_phy_init(struct msm_dp_display_private *dp) +static bool msm_dp_display_host_phy_init(struct msm_dp_display_private *dp) { drm_dbg_dp(dp->drm_dev, "type=%d core_init=%d phy_init=%d\n", dp->msm_dp_display.connector_type, dp->core_initialized, @@ -448,7 +382,10 @@ static void msm_dp_display_host_phy_init(struct msm_dp_display_private *dp) if (!dp->phy_initialized) { msm_dp_ctrl_phy_init(dp->ctrl); dp->phy_initialized = true; + return true; } + + return false; } static void msm_dp_display_host_phy_exit(struct msm_dp_display_private *dp) @@ -489,24 +426,6 @@ static void msm_dp_display_host_deinit(struct msm_dp_display_private *dp) dp->core_initialized = false; } -static int msm_dp_display_usbpd_configure_cb(struct device *dev) -{ - struct msm_dp_display_private *dp = dev_get_dp_display_private(dev); - - msm_dp_display_host_phy_init(dp); - - return msm_dp_display_process_hpd_high(dp); -} - -static int msm_dp_display_notify_disconnect(struct device *dev) -{ - struct msm_dp_display_private *dp = dev_get_dp_display_private(dev); - - msm_dp_add_event(dp, EV_USER_NOTIFICATION, false, 0); - - return 0; -} - static void msm_dp_display_handle_video_request(struct msm_dp_display_private *dp) { if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) { @@ -515,41 +434,11 @@ static void msm_dp_display_handle_video_request(struct msm_dp_display_private *d } } -static int msm_dp_display_handle_port_status_changed(struct msm_dp_display_private *dp) -{ - int rc = 0; - - if (drm_dp_is_branch(dp->panel->dpcd) && dp->link->sink_count == 0) { - drm_dbg_dp(dp->drm_dev, "sink count is zero, nothing to do\n"); - if (dp->hpd_state != ST_DISCONNECTED) { - dp->hpd_state = ST_DISCONNECT_PENDING; - msm_dp_add_event(dp, EV_USER_NOTIFICATION, false, 0); - } - } else { - if (dp->hpd_state == ST_DISCONNECTED) { - dp->hpd_state = ST_MAINLINK_READY; - rc = msm_dp_display_process_hpd_high(dp); - if (rc) - dp->hpd_state = ST_DISCONNECTED; - } - } - - return rc; -} - static int msm_dp_display_handle_irq_hpd(struct msm_dp_display_private *dp) { u32 sink_request = dp->link->sink_request; drm_dbg_dp(dp->drm_dev, "%d\n", sink_request); - if (dp->hpd_state == ST_DISCONNECTED) { - if (sink_request & DP_LINK_STATUS_UPDATED) { - drm_dbg_dp(dp->drm_dev, "Disconnected sink_request: %d\n", - sink_request); - DRM_ERROR("Disconnected, no DP_LINK_STATUS_UPDATED\n"); - return -EINVAL; - } - } msm_dp_ctrl_handle_sink_request(dp->ctrl); @@ -559,79 +448,42 @@ static int msm_dp_display_handle_irq_hpd(struct msm_dp_display_private *dp) return 0; } -static int msm_dp_display_usbpd_attention_cb(struct device *dev) +static int msm_dp_hpd_plug_handle(struct msm_dp_display_private *dp) { - int rc = 0; - u32 sink_request; - struct msm_dp_display_private *dp = dev_get_dp_display_private(dev); - - /* check for any test request issued by sink */ - rc = msm_dp_link_process_request(dp->link); - if (!rc) { - sink_request = dp->link->sink_request; - drm_dbg_dp(dp->drm_dev, "hpd_state=%d sink_request=%d\n", - dp->hpd_state, sink_request); - if (sink_request & DS_PORT_STATUS_CHANGED) - rc = msm_dp_display_handle_port_status_changed(dp); - else - rc = msm_dp_display_handle_irq_hpd(dp); - } - - return rc; -} - -static int msm_dp_hpd_plug_handle(struct msm_dp_display_private *dp, u32 data) -{ - u32 state; int ret; struct platform_device *pdev = dp->msm_dp_display.pdev; - msm_dp_aux_enable_xfers(dp->aux, true); - - mutex_lock(&dp->event_mutex); + drm_dbg_dp(dp->drm_dev, "Before, type=%d sink_count=%d\n", + dp->msm_dp_display.connector_type, + dp->link->sink_count); - state = dp->hpd_state; - drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", - dp->msm_dp_display.connector_type, state); - - if (state == ST_DISPLAY_OFF) { - mutex_unlock(&dp->event_mutex); + if (dp->plugged && dp->msm_dp_display.mst_active) return 0; - } - if (state == ST_MAINLINK_READY || state == ST_CONNECTED) { - mutex_unlock(&dp->event_mutex); - return 0; - } - - if (state == ST_DISCONNECT_PENDING) { - /* wait until ST_DISCONNECTED */ - msm_dp_add_event(dp, EV_HPD_PLUG_INT, 0, 1); /* delay = 1 */ - mutex_unlock(&dp->event_mutex); - return 0; - } + mutex_lock(&dp->plugged_lock); ret = pm_runtime_resume_and_get(&pdev->dev); if (ret) { + mutex_unlock(&dp->plugged_lock); DRM_ERROR("failed to pm_runtime_resume\n"); - mutex_unlock(&dp->event_mutex); return ret; } - ret = msm_dp_display_usbpd_configure_cb(&pdev->dev); - if (ret) { /* link train failed */ - dp->hpd_state = ST_DISCONNECTED; - pm_runtime_put_sync(&pdev->dev); - } else { - dp->hpd_state = ST_MAINLINK_READY; - } + msm_dp_aux_enable_xfers(dp->aux, true); + + msm_dp_display_host_phy_init(dp); - drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n", - dp->msm_dp_display.connector_type, state); - mutex_unlock(&dp->event_mutex); + ret = msm_dp_display_process_hpd_high(dp); - /* uevent will complete connection part */ - return 0; + drm_dbg_dp(dp->drm_dev, "After, type=%d sink_count=%d\n", + dp->msm_dp_display.connector_type, + dp->link->sink_count); + + dp->plugged = true; + + mutex_unlock(&dp->plugged_lock); + + return ret; }; static void msm_dp_display_handle_plugged_change(struct msm_dp *msm_dp_display, @@ -648,105 +500,126 @@ static void msm_dp_display_handle_plugged_change(struct msm_dp *msm_dp_display, plugged); } -static int msm_dp_hpd_unplug_handle(struct msm_dp_display_private *dp, u32 data) +static int msm_dp_hpd_unplug_handle(struct msm_dp_display_private *dp) { - u32 state; struct platform_device *pdev = dp->msm_dp_display.pdev; + dp->panel->video_test = false; + msm_dp_aux_enable_xfers(dp->aux, false); - mutex_lock(&dp->event_mutex); + drm_dbg_dp(dp->drm_dev, "Before, type=%d sink_count=%d\n", + dp->msm_dp_display.connector_type, + dp->link->sink_count); - state = dp->hpd_state; + mutex_lock(&dp->plugged_lock); + if (!dp->plugged) { + mutex_unlock(&dp->plugged_lock); - drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", - dp->msm_dp_display.connector_type, state); + return 0; + } - /* unplugged, no more irq_hpd handle */ - msm_dp_del_event(dp, EV_IRQ_HPD_INT); + /* Don't forget modes for eDP */ + if (!dp->msm_dp_display.is_edp) + drm_edid_connector_update(dp->msm_dp_display.connector, NULL); - if (state == ST_DISCONNECTED) { - /* triggered by irq_hdp with sink_count = 0 */ - if (dp->link->sink_count == 0) { - msm_dp_display_host_phy_exit(dp); - } - msm_dp_display_notify_disconnect(&dp->msm_dp_display.pdev->dev); - mutex_unlock(&dp->event_mutex); - return 0; - } else if (state == ST_DISCONNECT_PENDING) { - mutex_unlock(&dp->event_mutex); - return 0; - } else if (state == ST_MAINLINK_READY) { - msm_dp_ctrl_off_link(dp->ctrl); + /* triggered by irq_hdp with sink_count = 0 */ + if (dp->link->sink_count == 0) msm_dp_display_host_phy_exit(dp); - dp->hpd_state = ST_DISCONNECTED; - msm_dp_display_notify_disconnect(&dp->msm_dp_display.pdev->dev); - pm_runtime_put_sync(&pdev->dev); - mutex_unlock(&dp->event_mutex); - return 0; - } /* * We don't need separate work for disconnect as * connect/attention interrupts are disabled */ - msm_dp_display_notify_disconnect(&dp->msm_dp_display.pdev->dev); + if (!dp->msm_dp_display.is_edp) + drm_dp_set_subconnector_property(dp->msm_dp_display.connector, + connector_status_disconnected, + dp->panel->dpcd, + dp->panel->downstream_ports); - if (state == ST_DISPLAY_OFF) { - dp->hpd_state = ST_DISCONNECTED; - } else { - dp->hpd_state = ST_DISCONNECT_PENDING; + if (dp->msm_dp_display.mst_active) { + msm_dp_mst_display_set_mgr_state(&dp->msm_dp_display, false); + dp->msm_dp_display.mst_active = false; } /* signal the disconnect event early to ensure proper teardown */ msm_dp_display_handle_plugged_change(&dp->msm_dp_display, false); - drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n", - dp->msm_dp_display.connector_type, state); + drm_dbg_dp(dp->drm_dev, "After, type=%d, sink_count=%d\n", + dp->msm_dp_display.connector_type, + dp->link->sink_count); + + if (dp->plugged) { + pm_runtime_put_sync(&pdev->dev); + dp->plugged = false; + } + mutex_unlock(&dp->plugged_lock); - /* uevent will complete disconnection part */ - pm_runtime_put_sync(&pdev->dev); - mutex_unlock(&dp->event_mutex); return 0; } -static int msm_dp_irq_hpd_handle(struct msm_dp_display_private *dp, u32 data) +static int msm_dp_irq_hpd_handle(struct msm_dp_display_private *dp) { - u32 state; - - mutex_lock(&dp->event_mutex); + u32 sink_request; + int rc = 0; + struct msm_dp *msm_dp_display = &dp->msm_dp_display; /* irq_hpd can happen at either connected or disconnected state */ - state = dp->hpd_state; - drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", - dp->msm_dp_display.connector_type, state); + drm_dbg_dp(dp->drm_dev, "Before, type=%d, sink_count=%d\n", + dp->msm_dp_display.connector_type, + dp->link->sink_count); - if (state == ST_DISPLAY_OFF) { - mutex_unlock(&dp->event_mutex); + if (msm_dp_display->mst_active) { + if (msm_dp_aux_is_link_connected(dp->aux) != ISR_DISCONNECTED) + msm_dp_mst_display_hpd_irq(&dp->msm_dp_display); return 0; } - if (state == ST_MAINLINK_READY || state == ST_DISCONNECT_PENDING) { - /* wait until ST_CONNECTED */ - msm_dp_add_event(dp, EV_IRQ_HPD_INT, 0, 1); /* delay = 1 */ - mutex_unlock(&dp->event_mutex); - return 0; + /* check for any test request issued by sink */ + rc = msm_dp_link_process_request(dp->link); + if (!rc) { + sink_request = dp->link->sink_request; + drm_dbg_dp(dp->drm_dev, "sink_request=%d\n", sink_request); + if (sink_request & DS_PORT_STATUS_CHANGED) + rc = msm_dp_display_process_hpd_high(dp); + else + rc = msm_dp_display_handle_irq_hpd(dp); } - msm_dp_display_usbpd_attention_cb(&dp->msm_dp_display.pdev->dev); + drm_dbg_dp(dp->drm_dev, "After, type=%d, sink_count=%d\n", + dp->msm_dp_display.connector_type, + dp->link->sink_count); - drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n", - dp->msm_dp_display.connector_type, state); + return rc; +} - mutex_unlock(&dp->event_mutex); +struct msm_dp_panel *msm_dp_display_get_panel(struct msm_dp *msm_dp_display) +{ + struct msm_dp_display_private *dp; + struct msm_dp_panel *dp_panel; - return 0; + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); + + dp_panel = msm_dp_panel_get(&dp->msm_dp_display.pdev->dev, dp->aux, dp->link, + dp->link_base, dp->mst2link_base, dp->mst3link_base, + dp->pixel_base[0]); + + if (IS_ERR(dp->panel)) { + DRM_ERROR("failed to initialize panel\n"); + return NULL; + } + + /* FIXME: move out of panel */ + memcpy(dp_panel->dpcd, dp->panel->dpcd, DP_RECEIVER_CAP_SIZE); + memcpy(&dp_panel->link_info, &dp->panel->link_info, + sizeof(dp->panel->link_info)); + + return dp_panel; } static void msm_dp_display_deinit_sub_modules(struct msm_dp_display_private *dp) { msm_dp_audio_put(dp->audio); - msm_dp_panel_put(dp->panel); msm_dp_aux_put(dp->aux); } @@ -783,7 +656,8 @@ static int msm_dp_init_sub_modules(struct msm_dp_display_private *dp) goto error_link; } - dp->panel = msm_dp_panel_get(dev, dp->aux, dp->link, dp->link_base, dp->p0_base); + dp->panel = msm_dp_panel_get(dev, dp->aux, dp->link, dp->link_base, + dp->mst2link_base, dp->mst3link_base, dp->pixel_base[0]); if (IS_ERR(dp->panel)) { rc = PTR_ERR(dp->panel); DRM_ERROR("failed to initialize panel, rc = %d\n", rc); @@ -792,26 +666,27 @@ static int msm_dp_init_sub_modules(struct msm_dp_display_private *dp) } dp->ctrl = msm_dp_ctrl_get(dev, dp->link, dp->panel, dp->aux, - phy, dp->ahb_base, dp->link_base); + phy, dp->max_stream, dp->ahb_base, + dp->link_base, dp->mst2link_base, dp->mst3link_base); if (IS_ERR(dp->ctrl)) { rc = PTR_ERR(dp->ctrl); DRM_ERROR("failed to initialize ctrl, rc = %d\n", rc); dp->ctrl = NULL; - goto error_ctrl; + goto error_link; } + if (dp->max_stream != msm_dp_ctrl_get_stream_cnt(dp->ctrl)) + dp->max_stream = 1; dp->audio = msm_dp_audio_get(dp->msm_dp_display.pdev, dp->link_base); if (IS_ERR(dp->audio)) { rc = PTR_ERR(dp->audio); pr_err("failed to initialize audio, rc = %d\n", rc); dp->audio = NULL; - goto error_ctrl; + goto error_link; } return rc; -error_ctrl: - msm_dp_panel_put(dp->panel); error_link: msm_dp_aux_put(dp->aux); error: @@ -819,34 +694,90 @@ static int msm_dp_init_sub_modules(struct msm_dp_display_private *dp) } static int msm_dp_display_set_mode(struct msm_dp *msm_dp_display, - struct msm_dp_display_mode *mode) + const struct drm_display_mode *adjusted_mode, + struct msm_dp_panel *msm_dp_panel) { struct msm_dp_display_private *dp; + u32 bpp; dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - drm_mode_copy(&dp->panel->msm_dp_mode.drm_mode, &mode->drm_mode); - dp->panel->msm_dp_mode.bpp = mode->bpp; - dp->panel->msm_dp_mode.out_fmt_is_yuv_420 = mode->out_fmt_is_yuv_420; - msm_dp_panel_init_panel_info(dp->panel); + drm_mode_copy(&msm_dp_panel->msm_dp_mode.drm_mode, adjusted_mode); + if (msm_dp_display_check_video_test(msm_dp_display)) + bpp = msm_dp_display_get_test_bpp(msm_dp_display); + else + bpp = msm_dp_panel->connector->display_info.bpc * 3; + + msm_dp_panel->msm_dp_mode.bpp = bpp ? bpp : 24; /* Default bpp */ + msm_dp_panel->msm_dp_mode.v_active_low = + !!(adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC); + msm_dp_panel->msm_dp_mode.h_active_low = + !!(adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC); + msm_dp_panel->msm_dp_mode.out_fmt_is_yuv_420 = + drm_mode_is_420_only(&msm_dp_panel->connector->display_info, adjusted_mode) && + msm_dp_panel->vsc_sdp_supported; + msm_dp_panel_init_panel_info(msm_dp_panel); + + /* populate wide_bus_support to different layers */ + dp->ctrl->wide_bus_en = + msm_dp_panel->msm_dp_mode.out_fmt_is_yuv_420 ? false : dp->wide_bus_supported; return 0; } -static int msm_dp_display_enable(struct msm_dp_display_private *dp, bool force_link_train) +int msm_dp_display_prepare(struct msm_dp *msm_dp_display) { + struct msm_dp_display_private *dp; int rc = 0; - struct msm_dp *msm_dp_display = &dp->msm_dp_display; + bool force_link_train = false; + + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); drm_dbg_dp(dp->drm_dev, "sink_count=%d\n", dp->link->sink_count); - if (msm_dp_display->power_on) { + + if (msm_dp_display->is_edp) + msm_dp_hpd_plug_handle(dp); + + if (msm_dp_display->prepared) { drm_dbg_dp(dp->drm_dev, "Link already setup, return\n"); return 0; } - rc = msm_dp_ctrl_on_stream(dp->ctrl, force_link_train); + rc = pm_runtime_resume_and_get(&msm_dp_display->pdev->dev); + if (rc) { + DRM_ERROR("failed to pm_runtime_resume\n"); + return rc; + } + + if (dp->link->sink_count == 0) + return rc; + + if (!msm_dp_display->active_stream_cnt) { + msm_dp_display_host_phy_init(dp); + force_link_train = true; + + rc = msm_dp_ctrl_on_link(dp->ctrl, msm_dp_display->mst_active); + if (rc) + DRM_ERROR("Failed link training (rc=%d)\n", rc); + // TODO: schedule drm_connector_set_link_status_property() + } + + rc = msm_dp_ctrl_prepare_stream_on(dp->ctrl, force_link_train); if (!rc) - msm_dp_display->power_on = true; + msm_dp_display->prepared = true; + + return rc; +} +static int msm_dp_display_enable(struct msm_dp_display_private *dp, + struct msm_dp_panel *msm_dp_panel) +{ + int rc = 0; + + drm_dbg_dp(dp->drm_dev, "sink_count=%d\n", dp->link->sink_count); + + rc = msm_dp_ctrl_on_stream(dp->ctrl, msm_dp_panel); + + dp->msm_dp_display.active_stream_cnt++; return rc; } @@ -873,13 +804,10 @@ static int msm_dp_display_post_enable(struct msm_dp *msm_dp_display) return 0; } -static int msm_dp_display_disable(struct msm_dp_display_private *dp) +static void msm_dp_display_audio_notify_disable(struct msm_dp_display_private *dp) { struct msm_dp *msm_dp_display = &dp->msm_dp_display; - if (!msm_dp_display->power_on) - return 0; - /* wait only if audio was enabled */ if (msm_dp_display->audio_enabled) { /* signal the disconnect event */ @@ -890,48 +818,71 @@ static int msm_dp_display_disable(struct msm_dp_display_private *dp) } msm_dp_display->audio_enabled = false; +} - if (dp->link->sink_count == 0) { - /* - * irq_hpd with sink_count = 0 - * hdmi unplugged out of dongle - */ - msm_dp_ctrl_off_link_stream(dp->ctrl); - } else { - /* - * unplugged interrupt - * dongle unplugged out of DUT - */ - msm_dp_ctrl_off(dp->ctrl); - msm_dp_display_host_phy_exit(dp); - } +static int msm_dp_display_disable(struct msm_dp_display_private *dp, + struct msm_dp_panel *msm_dp_panel) +{ + if (!dp->msm_dp_display.active_stream_cnt) + return 0; + + msm_dp_panel_disable_vsc_sdp(msm_dp_panel); - msm_dp_display->power_on = false; + msm_dp_ctrl_off_pixel_clk(dp->ctrl, msm_dp_panel->stream_id); + + dp->msm_dp_display.active_stream_cnt--; drm_dbg_dp(dp->drm_dev, "sink count: %d\n", dp->link->sink_count); return 0; } +int msm_dp_display_set_stream_info(struct msm_dp *msm_dp_display, struct msm_dp_panel *panel, + enum msm_dp_stream_id stream_id, u32 start_slot, + u32 num_slots, u32 pbn) +{ + int rc = 0; + struct msm_dp_display_private *dp; + const int max_slots = 64; + + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); + + if (!dp) { + DRM_ERROR("invalid input\n"); + return -EINVAL; + } + + if (start_slot + num_slots > max_slots) { + DRM_ERROR("invalid channel info received. start:%d, slots:%d\n", + start_slot, num_slots); + return -EINVAL; + } + + msm_dp_ctrl_set_mst_channel_info(dp->ctrl, stream_id, start_slot, num_slots); + + panel->stream_id = stream_id; + panel->pbn = pbn; + msm_dp_panel_set_pixel_base(panel, dp->pixel_base[stream_id]); + + return rc; +} + /** * msm_dp_bridge_mode_valid - callback to determine if specified mode is valid - * @bridge: Pointer to drm bridge structure + * @dp: Pointer to dp display structure * @info: display info * @mode: Pointer to drm mode structure * Returns: Validity status for specified mode */ -enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge, - const struct drm_display_info *info, - const struct drm_display_mode *mode) +enum drm_mode_status msm_dp_display_mode_valid(struct msm_dp *dp, + const struct drm_display_info *info, + const struct drm_display_mode *mode) { const u32 num_components = 3, default_bpp = 24; struct msm_dp_display_private *msm_dp_display; struct msm_dp_link_info *link_info; u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0; - struct msm_dp *dp; int mode_pclk_khz = mode->clock; - dp = to_dp_bridge(bridge)->msm_dp_display; - if (!dp || !mode_pclk_khz || !dp->connector) { DRM_ERROR("invalid params\n"); return -EINVAL; @@ -975,8 +926,7 @@ int msm_dp_display_get_modes(struct msm_dp *dp) msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); - return msm_dp_panel_get_modes(msm_dp_display->panel, - dp->connector); + return drm_edid_connector_add_modes(msm_dp_display->panel->connector); } bool msm_dp_display_check_video_test(struct msm_dp *dp) @@ -1016,12 +966,8 @@ void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp) * power_on status before dumping DP registers to avoid crash due * to unclocked access */ - mutex_lock(&msm_dp_display->event_mutex); - - if (!dp->power_on) { - mutex_unlock(&msm_dp_display->event_mutex); + if (!dp->active_stream_cnt) return; - } msm_disp_snapshot_add_block(disp_state, msm_dp_display->ahb_len, msm_dp_display->ahb_base, "dp_ahb"); @@ -1029,10 +975,18 @@ void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp) msm_dp_display->aux_base, "dp_aux"); msm_disp_snapshot_add_block(disp_state, msm_dp_display->link_len, msm_dp_display->link_base, "dp_link"); - msm_disp_snapshot_add_block(disp_state, msm_dp_display->p0_len, - msm_dp_display->p0_base, "dp_p0"); - - mutex_unlock(&msm_dp_display->event_mutex); + msm_disp_snapshot_add_block(disp_state, msm_dp_display->mst2link_len, + msm_dp_display->mst2link_base, "dp_mst2link"); + msm_disp_snapshot_add_block(disp_state, msm_dp_display->mst3link_len, + msm_dp_display->mst3link_base, "dp_mst3link"); + msm_disp_snapshot_add_block(disp_state, msm_dp_display->pixel_len, + msm_dp_display->pixel_base[0], "dp_p0"); + msm_disp_snapshot_add_block(disp_state, msm_dp_display->pixel_len, + msm_dp_display->pixel_base[1], "dp_p1"); + msm_disp_snapshot_add_block(disp_state, msm_dp_display->pixel_len, + msm_dp_display->pixel_base[2], "dp_p2"); + msm_disp_snapshot_add_block(disp_state, msm_dp_display->pixel_len, + msm_dp_display->pixel_base[3], "dp_p3"); } void msm_dp_display_set_psr(struct msm_dp *msm_dp_display, bool enter) @@ -1048,137 +1002,153 @@ void msm_dp_display_set_psr(struct msm_dp *msm_dp_display, bool enter) msm_dp_ctrl_set_psr(dp->ctrl, enter); } -static int hpd_event_thread(void *data) +/** + * msm_dp_bridge_detect - callback to determine if connector is connected + * @bridge: Pointer to drm bridge structure + * @connector: Pointer to drm connector structure + * Returns: Bridge's 'is connected' status + */ +enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge, + struct drm_connector *connector) { - struct msm_dp_display_private *msm_dp_priv; - unsigned long flag; - struct msm_dp_event *todo; - int timeout_mode = 0; + struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(bridge); + struct msm_dp *dp = msm_dp_bridge->msm_dp_display; + struct msm_dp_display_private *priv; + int ret = 0; + int status = connector_status_disconnected; + u8 dpcd[DP_RECEIVER_CAP_SIZE]; + struct drm_dp_desc desc; + bool phy_deinit; - msm_dp_priv = (struct msm_dp_display_private *)data; + dp = to_dp_bridge(bridge)->msm_dp_display; - while (1) { - if (timeout_mode) { - wait_event_timeout(msm_dp_priv->event_q, - (msm_dp_priv->event_pndx == msm_dp_priv->event_gndx) || - kthread_should_stop(), EVENT_TIMEOUT); - } else { - wait_event_interruptible(msm_dp_priv->event_q, - (msm_dp_priv->event_pndx != msm_dp_priv->event_gndx) || - kthread_should_stop()); - } + priv = container_of(dp, struct msm_dp_display_private, msm_dp_display); - if (kthread_should_stop()) - break; + if (dp->mst_active) + return status; - spin_lock_irqsave(&msm_dp_priv->event_lock, flag); - todo = &msm_dp_priv->event_list[msm_dp_priv->event_gndx]; - if (todo->delay) { - struct msm_dp_event *todo_next; - - msm_dp_priv->event_gndx++; - msm_dp_priv->event_gndx %= DP_EVENT_Q_MAX; - - /* re enter delay event into q */ - todo_next = &msm_dp_priv->event_list[msm_dp_priv->event_pndx++]; - msm_dp_priv->event_pndx %= DP_EVENT_Q_MAX; - todo_next->event_id = todo->event_id; - todo_next->data = todo->data; - todo_next->delay = todo->delay - 1; - - /* clean up older event */ - todo->event_id = EV_NO_EVENT; - todo->delay = 0; - - /* switch to timeout mode */ - timeout_mode = 1; - spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag); - continue; - } + mutex_lock(&priv->plugged_lock); + ret = pm_runtime_resume_and_get(&dp->pdev->dev); + if (ret) { + DRM_ERROR("failed to pm_runtime_resume\n"); + mutex_unlock(&priv->plugged_lock); + return status; + } - /* timeout with no events in q */ - if (msm_dp_priv->event_pndx == msm_dp_priv->event_gndx) { - spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag); - continue; - } + phy_deinit = msm_dp_display_host_phy_init(priv); - msm_dp_priv->event_gndx++; - msm_dp_priv->event_gndx %= DP_EVENT_Q_MAX; - timeout_mode = 0; - spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag); + msm_dp_aux_enable_xfers(priv->aux, true); - switch (todo->event_id) { - case EV_HPD_PLUG_INT: - msm_dp_hpd_plug_handle(msm_dp_priv, todo->data); - break; - case EV_HPD_UNPLUG_INT: - msm_dp_hpd_unplug_handle(msm_dp_priv, todo->data); - break; - case EV_IRQ_HPD_INT: - msm_dp_irq_hpd_handle(msm_dp_priv, todo->data); - break; - case EV_USER_NOTIFICATION: - msm_dp_display_send_hpd_notification(msm_dp_priv, - todo->data); - break; - default: - break; - } + ret = msm_dp_aux_is_link_connected(priv->aux); + DRM_DEBUG_DP("aux link status: %x\n", ret); + if (!priv->plugged && !ret) { + DRM_DEBUG_DP("aux not connected\n"); + priv->plugged = false; + goto end; } - return 0; -} + ret = drm_dp_read_dpcd_caps(priv->aux, dpcd); + if (ret) { + DRM_DEBUG_DP("failed to read caps\n"); + priv->plugged = false; + goto end; + } -static int msm_dp_hpd_event_thread_start(struct msm_dp_display_private *msm_dp_priv) -{ - /* set event q to empty */ - msm_dp_priv->event_gndx = 0; - msm_dp_priv->event_pndx = 0; + ret = drm_dp_read_desc(priv->aux, &desc, drm_dp_is_branch(dpcd)); + if (ret) { + DRM_DEBUG_DP("failed to read desc\n"); + priv->plugged = false; + goto end; + } - msm_dp_priv->ev_tsk = kthread_run(hpd_event_thread, msm_dp_priv, "dp_hpd_handler"); - if (IS_ERR(msm_dp_priv->ev_tsk)) - return PTR_ERR(msm_dp_priv->ev_tsk); + status = connector_status_connected; + priv->plugged = true; - return 0; + if (drm_dp_read_sink_count_cap(connector, dpcd, &desc)) { + int sink_count = drm_dp_read_sink_count(priv->aux); + + drm_dbg_dp(dp->drm_dev, "sink_count = %d\n", sink_count); + + if (sink_count <= 0) + status = connector_status_disconnected; + } + + if (priv->max_stream > 1 && drm_dp_read_mst_cap(priv->aux, dpcd)) + status = connector_status_disconnected; +end: + /* + * If we detected the DPRX, leave the controller on so that it doesn't + * loose the state. + */ + if (!priv->plugged) { + if (phy_deinit) { + msm_dp_aux_enable_xfers(priv->aux, false); + msm_dp_display_host_phy_exit(priv); + } + + pm_runtime_put_sync(&dp->pdev->dev); + } + + mutex_unlock(&priv->plugged_lock); + + return status; } static irqreturn_t msm_dp_display_irq_handler(int irq, void *dev_id) { struct msm_dp_display_private *dp = dev_id; - irqreturn_t ret = IRQ_NONE; u32 hpd_isr_status; - - if (!dp) { - DRM_ERROR("invalid data\n"); - return IRQ_NONE; - } + unsigned long flags; + irqreturn_t ret = IRQ_HANDLED; hpd_isr_status = msm_dp_aux_get_hpd_intr_status(dp->aux); if (hpd_isr_status & 0x0F) { drm_dbg_dp(dp->drm_dev, "type=%d isr=0x%x\n", dp->msm_dp_display.connector_type, hpd_isr_status); - /* hpd related interrupts */ - if (hpd_isr_status & DP_DP_HPD_PLUG_INT_MASK) - msm_dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0); - if (hpd_isr_status & DP_DP_IRQ_HPD_INT_MASK) { - msm_dp_add_event(dp, EV_IRQ_HPD_INT, 0, 0); - } + spin_lock_irqsave(&dp->irq_thread_lock, flags); + dp->hpd_isr_status |= hpd_isr_status; + ret = IRQ_WAKE_THREAD; + spin_unlock_irqrestore(&dp->irq_thread_lock, flags); + } - if (hpd_isr_status & DP_DP_HPD_REPLUG_INT_MASK) { - msm_dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0); - msm_dp_add_event(dp, EV_HPD_PLUG_INT, 0, 3); - } + /* DP controller isr */ + ret |= msm_dp_ctrl_isr(dp->ctrl); + + return ret; +} - if (hpd_isr_status & DP_DP_HPD_UNPLUG_INT_MASK) - msm_dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0); +static irqreturn_t msm_dp_display_irq_thread(int irq, void *dev_id) +{ + struct msm_dp_display_private *dp = dev_id; + irqreturn_t ret = IRQ_NONE; + unsigned long flags; + u32 hpd_isr_status; + + spin_lock_irqsave(&dp->irq_thread_lock, flags); + hpd_isr_status = dp->hpd_isr_status; + dp->hpd_isr_status = 0; + spin_unlock_irqrestore(&dp->irq_thread_lock, flags); + + if (hpd_isr_status & DP_DP_HPD_UNPLUG_INT_MASK) + drm_bridge_hpd_notify(dp->msm_dp_display.bridge, + connector_status_disconnected); + + if (hpd_isr_status & DP_DP_HPD_PLUG_INT_MASK) + drm_bridge_hpd_notify(dp->msm_dp_display.bridge, + connector_status_connected); - ret = IRQ_HANDLED; + /* Send HPD as connected and distinguish it in the notifier */ + if (hpd_isr_status & DP_DP_IRQ_HPD_INT_MASK) { + if (dp->msm_dp_display.mst_active) + msm_dp_irq_hpd_handle(dp); + else + drm_bridge_hpd_notify(dp->msm_dp_display.bridge, + connector_status_connected); } - /* DP controller isr */ - ret |= msm_dp_ctrl_isr(dp->ctrl); + ret = IRQ_HANDLED; return ret; } @@ -1194,9 +1164,13 @@ static int msm_dp_display_request_irq(struct msm_dp_display_private *dp) return dp->irq; } - rc = devm_request_irq(&pdev->dev, dp->irq, msm_dp_display_irq_handler, - IRQF_TRIGGER_HIGH|IRQF_NO_AUTOEN, - "dp_display_isr", dp); + spin_lock_init(&dp->irq_thread_lock); + irq_set_status_flags(dp->irq, IRQ_NOAUTOEN); + rc = devm_request_threaded_irq(&pdev->dev, dp->irq, + msm_dp_display_irq_handler, + msm_dp_display_irq_thread, + IRQ_TYPE_LEVEL_HIGH, + "dp_display_isr", dp); if (rc < 0) { DRM_ERROR("failed to request IRQ%u: %d\n", @@ -1301,6 +1275,7 @@ static void __iomem *msm_dp_ioremap(struct platform_device *pdev, int idx, size_ static int msm_dp_display_get_io(struct msm_dp_display_private *display) { struct platform_device *pdev = display->msm_dp_display.pdev; + int i; display->ahb_base = msm_dp_ioremap(pdev, 0, &display->ahb_len); if (IS_ERR(display->ahb_base)) @@ -1330,8 +1305,8 @@ static int msm_dp_display_get_io(struct msm_dp_display_private *display) display->aux_len = DP_DEFAULT_AUX_SIZE; display->link_base = display->ahb_base + DP_DEFAULT_LINK_OFFSET; display->link_len = DP_DEFAULT_LINK_SIZE; - display->p0_base = display->ahb_base + DP_DEFAULT_P0_OFFSET; - display->p0_len = DP_DEFAULT_P0_SIZE; + display->pixel_base[0] = display->ahb_base + DP_DEFAULT_P0_OFFSET; + display->pixel_len = DP_DEFAULT_P0_SIZE; return 0; } @@ -1342,15 +1317,42 @@ static int msm_dp_display_get_io(struct msm_dp_display_private *display) return PTR_ERR(display->link_base); } - display->p0_base = msm_dp_ioremap(pdev, 3, &display->p0_len); - if (IS_ERR(display->p0_base)) { - DRM_ERROR("unable to remap p0 region: %pe\n", display->p0_base); - return PTR_ERR(display->p0_base); + display->pixel_base[0] = msm_dp_ioremap(pdev, 3, &display->pixel_len); + if (IS_ERR(display->pixel_base[0])) { + DRM_ERROR("unable to remap p0 region: %pe\n", display->pixel_base[0]); + return PTR_ERR(display->pixel_base[0]); } + for (i = DP_STREAM_1; i < display->max_stream; i++) { + /* pixels clk reg index start from 3*/ + display->pixel_base[i] = msm_dp_ioremap(pdev, i + 3, &display->pixel_len); + if (IS_ERR(display->pixel_base[i])) { + DRM_DEBUG_DP("unable to remap p%d region: %pe\n", i, + display->pixel_base[i]); + break; + } + } + + display->mst2link_base = msm_dp_ioremap(pdev, 7, &display->mst2link_len); + if (IS_ERR(display->mst2link_base)) + DRM_DEBUG_DP("unable to remap link region: %pe\n", display->mst2link_base); + + display->mst3link_base = msm_dp_ioremap(pdev, 8, &display->mst3link_len); + if (IS_ERR(display->mst3link_base)) + DRM_DEBUG_DP("unable to remap link region: %pe\n", display->mst3link_base); + return 0; } +int msm_dp_get_mst_max_stream(struct msm_dp *msm_dp_display) +{ + struct msm_dp_display_private *dp; + + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); + + return dp->max_stream; +} + static int msm_dp_display_probe(struct platform_device *pdev) { int rc = 0; @@ -1376,6 +1378,13 @@ static int msm_dp_display_probe(struct platform_device *pdev) dp->wide_bus_supported = desc->wide_bus_supported; dp->msm_dp_display.is_edp = (dp->msm_dp_display.connector_type == DRM_MODE_CONNECTOR_eDP); + dp->hpd_isr_status = 0; + dp->max_stream = 1; + + if (desc->mst_streams > 1) + dp->max_stream = desc->mst_streams; + + mutex_init(&dp->plugged_lock); rc = msm_dp_display_get_io(dp); if (rc) @@ -1387,11 +1396,6 @@ static int msm_dp_display_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - /* setup event q */ - mutex_init(&dp->event_mutex); - init_waitqueue_head(&dp->event_q); - spin_lock_init(&dp->event_lock); - /* Store DP audio handle inside DP display */ dp->msm_dp_display.msm_dp_audio = dp->audio; @@ -1529,7 +1533,7 @@ bool msm_dp_wide_bus_available(const struct msm_dp *msm_dp_display) dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - if (dp->msm_dp_mode.out_fmt_is_yuv_420) + if (dp->panel->msm_dp_mode.out_fmt_is_yuv_420) return false; return dp->wide_bus_supported; @@ -1580,152 +1584,168 @@ int msm_dp_modeset_init(struct msm_dp *msm_dp_display, struct drm_device *dev, return 0; } -void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge, - struct drm_atomic_state *state) +int msm_dp_mst_register(struct msm_dp *msm_dp_display) { - struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge); - struct msm_dp *dp = msm_dp_bridge->msm_dp_display; - int rc = 0; - struct msm_dp_display_private *msm_dp_display; - u32 hpd_state; - bool force_link_train = false; + struct msm_dp_display_private *dp; - msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); - if (!msm_dp_display->msm_dp_mode.drm_mode.clock) { - DRM_ERROR("invalid params\n"); - return; - } + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - if (dp->is_edp) - msm_dp_hpd_plug_handle(msm_dp_display, 0); + return msm_dp_mst_init(msm_dp_display, dp->max_stream, dp->aux); +} - mutex_lock(&msm_dp_display->event_mutex); - if (pm_runtime_resume_and_get(&dp->pdev->dev)) { - DRM_ERROR("failed to pm_runtime_resume\n"); - mutex_unlock(&msm_dp_display->event_mutex); - return; - } +int msm_dp_display_set_mode_helper(struct msm_dp *msm_dp_display, + struct drm_atomic_state *state, + struct drm_encoder *drm_encoder, + struct msm_dp_panel *msm_dp_panel) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; - hpd_state = msm_dp_display->hpd_state; - if (hpd_state != ST_DISPLAY_OFF && hpd_state != ST_MAINLINK_READY) { - mutex_unlock(&msm_dp_display->event_mutex); - return; - } + crtc = drm_atomic_get_new_crtc_for_encoder(state, drm_encoder); + if (!crtc) + return 0; + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + + return msm_dp_display_set_mode(msm_dp_display, &crtc_state->adjusted_mode, msm_dp_panel); +} + +void msm_dp_display_atomic_prepare(struct msm_dp *msm_dp_display, + struct drm_atomic_state *state) +{ + int rc = 0; + struct msm_dp_display_private *dp; + + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - rc = msm_dp_display_set_mode(dp, &msm_dp_display->msm_dp_mode); + rc = msm_dp_display_set_mode_helper(msm_dp_display, state, + msm_dp_display->bridge->encoder, dp->panel); if (rc) { DRM_ERROR("Failed to perform a mode set, rc=%d\n", rc); - mutex_unlock(&msm_dp_display->event_mutex); return; } - hpd_state = msm_dp_display->hpd_state; + rc = msm_dp_display_prepare(msm_dp_display); + if (rc) + DRM_ERROR("DP display prepare failed, rc=%d\n", rc); +} - if (hpd_state == ST_DISPLAY_OFF) { - msm_dp_display_host_phy_init(msm_dp_display); - force_link_train = true; - } +void msm_dp_display_enable_helper(struct msm_dp *msm_dp_display, struct msm_dp_panel *msm_dp_panel) +{ + struct msm_dp_display_private *dp; + int rc = 0; - msm_dp_display_enable(msm_dp_display, force_link_train); + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - rc = msm_dp_display_post_enable(dp); - if (rc) { - DRM_ERROR("DP display post enable failed, rc=%d\n", rc); - msm_dp_display_disable(msm_dp_display); + if (msm_dp_display->prepared) { + rc = msm_dp_display_enable(dp, msm_dp_panel); + if (rc) + DRM_ERROR("DP display enable failed, rc=%d\n", rc); + + rc = msm_dp_display_post_enable(msm_dp_display); + if (rc) { + DRM_ERROR("DP display post enable failed, rc=%d\n", rc); + msm_dp_display_disable(dp, msm_dp_panel); + } } - /* completed connection */ - msm_dp_display->hpd_state = ST_CONNECTED; + drm_dbg_dp(msm_dp_display->drm_dev, "type=%d Done\n", msm_dp_display->connector_type); +} - drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type); - mutex_unlock(&msm_dp_display->event_mutex); +void msm_dp_display_atomic_enable(struct msm_dp *msm_dp_display) +{ + struct msm_dp_display_private *dp; + + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); + + msm_dp_display_set_stream_info(msm_dp_display, dp->panel, 0, 0, 0, 0); + + msm_dp_display_enable_helper(msm_dp_display, dp->panel); } -void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge, - struct drm_atomic_state *state) +void msm_dp_display_disable_helper(struct msm_dp *msm_dp_display, + struct msm_dp_panel *msm_dp_panel) { - struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge); - struct msm_dp *dp = msm_dp_bridge->msm_dp_display; - struct msm_dp_display_private *msm_dp_display; + struct msm_dp_display_private *dp; - msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); + + if (!msm_dp_display->active_stream_cnt) { + drm_dbg_dp(dp->drm_dev, "no active streams\n"); + return; + } - msm_dp_ctrl_push_idle(msm_dp_display->ctrl); + msm_dp_ctrl_push_idle(dp->ctrl, msm_dp_panel); + msm_dp_ctrl_mst_stream_channel_slot_setup(dp->ctrl); + msm_dp_ctrl_mst_send_act(dp->ctrl); } -void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, - struct drm_atomic_state *state) +void msm_dp_display_atomic_disable(struct msm_dp *msm_dp_display) { - struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge); - struct msm_dp *dp = msm_dp_bridge->msm_dp_display; - u32 hpd_state; - struct msm_dp_display_private *msm_dp_display; + struct msm_dp_display_private *dp; - msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - if (dp->is_edp) - msm_dp_hpd_unplug_handle(msm_dp_display, 0); + msm_dp_display_disable_helper(msm_dp_display, dp->panel); +} - mutex_lock(&msm_dp_display->event_mutex); +void msm_dp_display_unprepare(struct msm_dp *msm_dp_display) +{ + struct msm_dp_display_private *dp; - hpd_state = msm_dp_display->hpd_state; - if (hpd_state != ST_DISCONNECT_PENDING && hpd_state != ST_CONNECTED) - drm_dbg_dp(dp->drm_dev, "type=%d wrong hpd_state=%d\n", - dp->connector_type, hpd_state); + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - msm_dp_display_disable(msm_dp_display); + if (!msm_dp_display->prepared) { + drm_dbg_dp(dp->drm_dev, "Link already setup, return\n"); + return; + } - hpd_state = msm_dp_display->hpd_state; - if (hpd_state == ST_DISCONNECT_PENDING) { - /* completed disconnection */ - msm_dp_display->hpd_state = ST_DISCONNECTED; - } else { - msm_dp_display->hpd_state = ST_DISPLAY_OFF; + if (msm_dp_display->active_stream_cnt) { + drm_dbg_dp(dp->drm_dev, "stream still active, return\n"); + return; } - drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type); + /* dongle is still connected but sinks are disconnected */ + if (dp->link->sink_count == 0) + msm_dp_link_psm_config(dp->link, &dp->panel->link_info, true); + + msm_dp_ctrl_off_link(dp->ctrl); - pm_runtime_put_sync(&dp->pdev->dev); - mutex_unlock(&msm_dp_display->event_mutex); + /* re-init the PHY so that we can listen to Dongle disconnect */ + if (dp->link->sink_count == 0) + msm_dp_ctrl_reinit_phy(dp->ctrl); + else + msm_dp_display_host_phy_exit(dp); + + pm_runtime_put_sync(&msm_dp_display->pdev->dev); + + msm_dp_display->prepared = false; } -void msm_dp_bridge_mode_set(struct drm_bridge *drm_bridge, - const struct drm_display_mode *mode, - const struct drm_display_mode *adjusted_mode) +void msm_dp_display_atomic_post_disable_helper(struct msm_dp *dp, struct msm_dp_panel *msm_dp_panel) { - struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge); - struct msm_dp *dp = msm_dp_bridge->msm_dp_display; struct msm_dp_display_private *msm_dp_display; - struct msm_dp_panel *msm_dp_panel; msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); - msm_dp_panel = msm_dp_display->panel; - memset(&msm_dp_display->msm_dp_mode, 0x0, sizeof(struct msm_dp_display_mode)); + if (dp->is_edp) + msm_dp_hpd_unplug_handle(msm_dp_display); - if (msm_dp_display_check_video_test(dp)) - msm_dp_display->msm_dp_mode.bpp = msm_dp_display_get_test_bpp(dp); - else /* Default num_components per pixel = 3 */ - msm_dp_display->msm_dp_mode.bpp = dp->connector->display_info.bpc * 3; + msm_dp_display_audio_notify_disable(msm_dp_display); - if (!msm_dp_display->msm_dp_mode.bpp) - msm_dp_display->msm_dp_mode.bpp = 24; /* Default bpp */ + msm_dp_display_disable(msm_dp_display, msm_dp_panel); - drm_mode_copy(&msm_dp_display->msm_dp_mode.drm_mode, adjusted_mode); + drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type); +} - msm_dp_display->msm_dp_mode.v_active_low = - !!(msm_dp_display->msm_dp_mode.drm_mode.flags & DRM_MODE_FLAG_NVSYNC); +void msm_dp_display_atomic_post_disable(struct msm_dp *msm_dp_display) +{ + struct msm_dp_display_private *dp; - msm_dp_display->msm_dp_mode.h_active_low = - !!(msm_dp_display->msm_dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC); + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - msm_dp_display->msm_dp_mode.out_fmt_is_yuv_420 = - drm_mode_is_420_only(&dp->connector->display_info, adjusted_mode) && - msm_dp_panel->vsc_sdp_supported; + msm_dp_display_atomic_post_disable_helper(msm_dp_display, dp->panel); - /* populate wide_bus_support to different layers */ - msm_dp_display->ctrl->wide_bus_en = - msm_dp_display->msm_dp_mode.out_fmt_is_yuv_420 ? false : msm_dp_display->wide_bus_supported; + msm_dp_display_unprepare(msm_dp_display); } void msm_dp_bridge_hpd_enable(struct drm_bridge *bridge) @@ -1742,18 +1762,13 @@ void msm_dp_bridge_hpd_enable(struct drm_bridge *bridge) * step-4: DP PHY is initialized at plugin handler before link training * */ - mutex_lock(&dp->event_mutex); if (pm_runtime_resume_and_get(&msm_dp_display->pdev->dev)) { DRM_ERROR("failed to resume power\n"); - mutex_unlock(&dp->event_mutex); return; } msm_dp_aux_hpd_enable(dp->aux); msm_dp_aux_hpd_intr_enable(dp->aux); - - msm_dp_display->internal_hpd = true; - mutex_unlock(&dp->event_mutex); } void msm_dp_bridge_hpd_disable(struct drm_bridge *bridge) @@ -1762,15 +1777,10 @@ void msm_dp_bridge_hpd_disable(struct drm_bridge *bridge) struct msm_dp *msm_dp_display = msm_dp_bridge->msm_dp_display; struct msm_dp_display_private *dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - mutex_lock(&dp->event_mutex); - msm_dp_aux_hpd_intr_disable(dp->aux); msm_dp_aux_hpd_disable(dp->aux); - msm_dp_display->internal_hpd = false; - pm_runtime_put_sync(&msm_dp_display->pdev->dev); - mutex_unlock(&dp->event_mutex); } void msm_dp_bridge_hpd_notify(struct drm_bridge *bridge, @@ -1779,13 +1789,31 @@ void msm_dp_bridge_hpd_notify(struct drm_bridge *bridge, struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(bridge); struct msm_dp *msm_dp_display = msm_dp_bridge->msm_dp_display; struct msm_dp_display_private *dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); + u32 hpd_link_status = 0; - /* Without next_bridge interrupts are handled by the DP core directly */ - if (msm_dp_display->internal_hpd) + if (pm_runtime_resume_and_get(&msm_dp_display->pdev->dev)) { + DRM_ERROR("failed to pm_runtime_resume\n"); return; + } + + hpd_link_status = msm_dp_aux_is_link_connected(dp->aux); - if (!msm_dp_display->link_ready && status == connector_status_connected) - msm_dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0); - else if (msm_dp_display->link_ready && status == connector_status_disconnected) - msm_dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0); + drm_dbg_dp(dp->drm_dev, "type=%d link hpd_link_status=0x%x, status=%d\n", + msm_dp_display->connector_type, hpd_link_status, status); + + if (status == connector_status_connected) { + if (hpd_link_status == ISR_HPD_REPLUG_COUNT) { + msm_dp_hpd_unplug_handle(dp); + msm_dp_hpd_plug_handle(dp); + } else if (hpd_link_status == ISR_IRQ_HPD_PULSE_COUNT) { + msm_dp_irq_hpd_handle(dp); + } else { + msm_dp_hpd_plug_handle(dp); + } + } else { + if (hpd_link_status == ISR_DISCONNECTED) + msm_dp_hpd_unplug_handle(dp); + } + + pm_runtime_put_sync(&msm_dp_display->pdev->dev); } diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h index cc6e2cab36e9c..55874daf41c44 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -16,17 +16,21 @@ struct msm_dp { struct platform_device *pdev; struct drm_connector *connector; struct drm_bridge *next_bridge; - bool link_ready; + struct drm_bridge *bridge; bool audio_enabled; - bool power_on; + u32 active_stream_cnt; + bool mst_active; unsigned int connector_type; bool is_edp; - bool internal_hpd; + bool prepared; + + void *msm_dp_mst; struct msm_dp_audio *msm_dp_audio; bool psr_supported; }; +int msm_dp_get_mst_max_stream(struct msm_dp *msm_dp_display); int msm_dp_display_get_modes(struct msm_dp *msm_dp_display); bool msm_dp_display_check_video_test(struct msm_dp *msm_dp_display); int msm_dp_display_get_test_bpp(struct msm_dp *msm_dp_display); @@ -34,5 +38,29 @@ void msm_dp_display_signal_audio_start(struct msm_dp *msm_dp_display); void msm_dp_display_signal_audio_complete(struct msm_dp *msm_dp_display); void msm_dp_display_set_psr(struct msm_dp *dp, bool enter); void msm_dp_display_debugfs_init(struct msm_dp *msm_dp_display, struct dentry *dentry, bool is_edp); +void msm_dp_display_atomic_post_disable(struct msm_dp *dp_display); +void msm_dp_display_atomic_disable(struct msm_dp *dp_display); +void msm_dp_display_atomic_prepare(struct msm_dp *dp_display, + struct drm_atomic_state *state); +void msm_dp_display_atomic_enable(struct msm_dp *dp_display); +enum drm_mode_status msm_dp_display_mode_valid(struct msm_dp *dp, + const struct drm_display_info *info, + const struct drm_display_mode *mode); +int msm_dp_display_set_stream_info(struct msm_dp *msm_dp_display, struct msm_dp_panel *panel, + enum msm_dp_stream_id stream_id, + u32 start_slot, u32 num_slots, u32 pbn); +void msm_dp_display_enable_helper(struct msm_dp *msm_dp_display, + struct msm_dp_panel *msm_dp_panel); +void msm_dp_display_disable_helper(struct msm_dp *msm_dp_display, + struct msm_dp_panel *msm_dp_panel); +void msm_dp_display_atomic_post_disable_helper(struct msm_dp *msm_dp_display, + struct msm_dp_panel *msm_dp_panel); +int msm_dp_display_set_mode_helper(struct msm_dp *msm_dp_display, + struct drm_atomic_state *state, + struct drm_encoder *drm_encoder, + struct msm_dp_panel *msm_dp_panel); +int msm_dp_display_prepare(struct msm_dp *msm_dp_display); +void msm_dp_display_unprepare(struct msm_dp *dp); +struct msm_dp_panel *msm_dp_display_get_panel(struct msm_dp *msm_dp_display); #endif /* _DP_DISPLAY_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index 9a461ab2f32fc..0feb757e2db90 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -15,55 +15,6 @@ #include "dp_audio.h" #include "dp_drm.h" -/** - * msm_dp_bridge_detect - callback to determine if connector is connected - * @bridge: Pointer to drm bridge structure - * Returns: Bridge's 'is connected' status - */ -static enum drm_connector_status -msm_dp_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector) -{ - struct msm_dp *dp; - - dp = to_dp_bridge(bridge)->msm_dp_display; - - drm_dbg_dp(dp->drm_dev, "link_ready = %s\n", - str_true_false(dp->link_ready)); - - return (dp->link_ready) ? connector_status_connected : - connector_status_disconnected; -} - -static int msm_dp_bridge_atomic_check(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct msm_dp *dp; - - dp = to_dp_bridge(bridge)->msm_dp_display; - - drm_dbg_dp(dp->drm_dev, "link_ready = %s\n", - str_true_false(dp->link_ready)); - - /* - * There is no protection in the DRM framework to check if the display - * pipeline has been already disabled before trying to disable it again. - * Hence if the sink is unplugged, the pipeline gets disabled, but the - * crtc->active is still true. Any attempt to set the mode or manually - * disable this encoder will result in the crash. - * - * TODO: add support for telling the DRM subsystem that the pipeline is - * disabled by the hardware and thus all access to it should be forbidden. - * After that this piece of code can be removed. - */ - if (bridge->ops & DRM_BRIDGE_OP_HPD) - return (dp->link_ready) ? 0 : -ENOTCONN; - - return 0; -} - - /** * msm_dp_bridge_get_modes - callback to add drm modes via drm_mode_probed_add() * @bridge: Poiner to drm bridge @@ -81,12 +32,10 @@ static int msm_dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connect dp = to_dp_bridge(bridge)->msm_dp_display; /* pluggable case assumes EDID is read when HPD */ - if (dp->link_ready) { - rc = msm_dp_display_get_modes(dp); - if (rc <= 0) { - DRM_ERROR("failed to get DP sink modes, rc=%d\n", rc); - return rc; - } + rc = msm_dp_display_get_modes(dp); + if (rc <= 0) { + DRM_ERROR("failed to get DP sink modes, rc=%d\n", rc); + return rc; } else { drm_dbg_dp(connector->dev, "No sink connected\n"); } @@ -100,6 +49,44 @@ static void msm_dp_bridge_debugfs_init(struct drm_bridge *bridge, struct dentry msm_dp_display_debugfs_init(dp, root, false); } +static void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge, + struct drm_atomic_state *state) +{ + struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge); + struct msm_dp *dp = dp_bridge->msm_dp_display; + + msm_dp_display_atomic_prepare(dp, state); + msm_dp_display_atomic_enable(dp); +} + +static void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge, + struct drm_atomic_state *state) +{ + struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge); + struct msm_dp *dp = dp_bridge->msm_dp_display; + + msm_dp_display_atomic_disable(dp); +} + +static void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, + struct drm_atomic_state *state) +{ + struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge); + struct msm_dp *dp = dp_bridge->msm_dp_display; + + msm_dp_display_atomic_post_disable(dp); +} + +static enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *drm_bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge); + struct msm_dp *dp = dp_bridge->msm_dp_display; + + return msm_dp_display_mode_valid(dp, info, mode); +} + static const struct drm_bridge_funcs msm_dp_bridge_ops = { .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, @@ -107,11 +94,9 @@ static const struct drm_bridge_funcs msm_dp_bridge_ops = { .atomic_enable = msm_dp_bridge_atomic_enable, .atomic_disable = msm_dp_bridge_atomic_disable, .atomic_post_disable = msm_dp_bridge_atomic_post_disable, - .mode_set = msm_dp_bridge_mode_set, .mode_valid = msm_dp_bridge_mode_valid, .get_modes = msm_dp_bridge_get_modes, .detect = msm_dp_bridge_detect, - .atomic_check = msm_dp_bridge_atomic_check, .hpd_enable = msm_dp_bridge_hpd_enable, .hpd_disable = msm_dp_bridge_hpd_disable, .hpd_notify = msm_dp_bridge_hpd_notify, @@ -168,7 +153,8 @@ static void msm_edp_bridge_atomic_enable(struct drm_bridge *drm_bridge, return; } - msm_dp_bridge_atomic_enable(drm_bridge, state); + msm_dp_display_atomic_prepare(dp, state); + msm_dp_display_atomic_enable(dp); } static void msm_edp_bridge_atomic_disable(struct drm_bridge *drm_bridge, @@ -285,7 +271,6 @@ static const struct drm_bridge_funcs msm_edp_bridge_ops = { .atomic_enable = msm_edp_bridge_atomic_enable, .atomic_disable = msm_edp_bridge_atomic_disable, .atomic_post_disable = msm_edp_bridge_atomic_post_disable, - .mode_set = msm_dp_bridge_mode_set, .mode_valid = msm_edp_bridge_mode_valid, .atomic_reset = drm_atomic_helper_bridge_reset, .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, @@ -359,6 +344,8 @@ int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev, } } + msm_dp_display->bridge = bridge; + return 0; } diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h index d8c9b905f8bfb..111df516e4bd9 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.h +++ b/drivers/gpu/drm/msm/dp/dp_drm.h @@ -25,18 +25,8 @@ int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev, struct drm_encoder *encoder, bool yuv_supported); -void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge, - struct drm_atomic_state *state); -void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge, - struct drm_atomic_state *state); -void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, - struct drm_atomic_state *state); -enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge, - const struct drm_display_info *info, - const struct drm_display_mode *mode); -void msm_dp_bridge_mode_set(struct drm_bridge *drm_bridge, - const struct drm_display_mode *mode, - const struct drm_display_mode *adjusted_mode); +enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge, + struct drm_connector *connector); void msm_dp_bridge_hpd_enable(struct drm_bridge *bridge); void msm_dp_bridge_hpd_disable(struct drm_bridge *bridge); void msm_dp_bridge_hpd_notify(struct drm_bridge *bridge, diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h index b1eb2de6d2a76..76125e9c07e9c 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.h +++ b/drivers/gpu/drm/msm/dp/dp_link.h @@ -17,6 +17,9 @@ struct msm_dp_link_info { unsigned char revision; unsigned int rate; + unsigned int supported_rates[DP_MAX_SUPPORTED_RATES]; + unsigned int rate_set; + bool use_rate_set; unsigned int num_lanes; unsigned long capabilities; }; @@ -80,11 +83,11 @@ struct msm_dp_link { }; /** - * mdss_dp_test_bit_depth_to_bpp() - convert test bit depth to bpp + * msm_dp_link_bit_depth_to_bpp() - convert test bit depth to bpp * @tbd: test bit depth * - * Returns the bits per pixel (bpp) to be used corresponding to the - * git bit depth value. This function assumes that bit depth has + * Returns: the bits per pixel (bpp) to be used corresponding to the + * bit depth value. This function assumes that bit depth has * already been validated. */ static inline u32 msm_dp_link_bit_depth_to_bpp(u32 tbd) @@ -120,7 +123,8 @@ bool msm_dp_link_send_edid_checksum(struct msm_dp_link *msm_dp_link, u8 checksum /** * msm_dp_link_get() - get the functionalities of dp test module - * + * @dev: kernel device structure + * @aux: DisplayPort AUX channel * * return: a pointer to msm_dp_link struct */ diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.c b/drivers/gpu/drm/msm/dp/dp_mst_drm.c new file mode 100644 index 0000000000000..cb5da84ead146 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.c @@ -0,0 +1,869 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include "dp_mst_drm.h" +#include "dp_panel.h" + +#define MAX_DPCD_TRANSACTION_BYTES 16 + +#define to_dp_mst_bridge(x) container_of((x), struct msm_dp_mst_bridge, base) +#define to_dp_mst_bridge_state_priv(x) \ + container_of((x), struct msm_dp_mst_bridge_state, base) +#define to_dp_mst_bridge_state(x) \ + to_dp_mst_bridge_state_priv((x)->obj.state) +#define to_dp_mst_connector(x) \ + container_of((x), struct msm_dp_mst_connector, connector) + +#define DP_MST_CONN_ID(x) ((x)->connector ? \ + (x)->connector->base.id : 0) + +struct msm_dp_mst_bridge { + struct drm_bridge base; + struct drm_private_obj obj; + u32 id; + + bool initialized; + + struct msm_dp *display; + struct drm_encoder *encoder; + + struct drm_connector *connector; + struct msm_dp_panel *msm_dp_panel; +}; + +struct msm_dp_mst_bridge_state { + struct drm_private_state base; + struct drm_connector *connector; + struct msm_dp_panel *msm_dp_panel; +}; + +struct msm_dp_mst_connector { + struct drm_connector connector; + struct drm_dp_mst_port *mst_port; + struct msm_dp_mst *dp_mst; + struct msm_dp_panel *dp_panel; +}; + +struct msm_dp_mst { + struct drm_dp_mst_topology_mgr mst_mgr; + struct msm_dp_mst_bridge *mst_bridge[DP_STREAM_MAX]; + struct msm_dp *msm_dp; + struct drm_dp_aux *dp_aux; + u32 max_streams; + /* Protects MST bridge enable/disable handling. */ + struct mutex mst_lock; +}; + +static struct drm_private_state *msm_dp_mst_duplicate_bridge_state(struct drm_private_obj *obj) +{ + struct msm_dp_mst_bridge_state *mst_bridge_state; + + mst_bridge_state = kmemdup(obj->state, sizeof(*mst_bridge_state), GFP_KERNEL); + if (!mst_bridge_state) + return NULL; + + __drm_atomic_helper_private_obj_duplicate_state(obj, &mst_bridge_state->base); + + return &mst_bridge_state->base; +} + +static void msm_dp_mst_destroy_bridge_state(struct drm_private_obj *obj, + struct drm_private_state *state) +{ + struct msm_dp_mst_bridge_state *mst_bridge_state = + to_dp_mst_bridge_state_priv(state); + + kfree(mst_bridge_state); +} + +static const struct drm_private_state_funcs msm_dp_mst_bridge_state_funcs = { + .atomic_duplicate_state = msm_dp_mst_duplicate_bridge_state, + .atomic_destroy_state = msm_dp_mst_destroy_bridge_state, +}; + +static struct msm_dp_mst_bridge_state *msm_dp_mst_br_priv_state(struct drm_atomic_state *st, + struct msm_dp_mst_bridge *bridge) +{ + struct drm_device *dev = bridge->base.dev; + struct drm_private_state *obj_state = drm_atomic_get_private_obj_state(st, &bridge->obj); + + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); + + return to_dp_mst_bridge_state_priv(obj_state); +} + +static void msm_dp_mst_update_timeslots(struct msm_dp_mst *mst, + struct msm_dp_mst_bridge *mst_bridge, + struct drm_atomic_state *state, + struct drm_dp_mst_port *port) +{ + struct drm_dp_mst_topology_state *mst_state; + struct drm_dp_mst_atomic_payload *payload; + + mst_state = to_drm_dp_mst_topology_state(mst->mst_mgr.base.state); + payload = drm_atomic_get_mst_payload_state(mst_state, port); + + if (!payload) { + DRM_ERROR("MST bridge [%d] update_timeslots failed, null payload\n", + mst_bridge->id); + return; + } + + if (payload->vc_start_slot < 0) + msm_dp_display_set_stream_info(mst->msm_dp, mst_bridge->msm_dp_panel, + mst_bridge->id, 1, 0, 0); + else + msm_dp_display_set_stream_info(mst->msm_dp, mst_bridge->msm_dp_panel, + mst_bridge->id, payload->vc_start_slot, + payload->time_slots, payload->pbn); +} + +static int msm_dp_mst_bridge_pre_enable_part1(struct msm_dp_mst_bridge *dp_bridge, + struct drm_atomic_state *state) +{ + struct msm_dp *dp_display = dp_bridge->display; + struct msm_dp_mst *mst = dp_display->msm_dp_mst; + struct msm_dp_mst_connector *mst_conn = to_dp_mst_connector(dp_bridge->connector); + struct drm_dp_mst_port *port = mst_conn->mst_port; + struct drm_dp_mst_topology_state *mst_state; + struct drm_dp_mst_atomic_payload *payload; + struct msm_dp_panel *dp_panel = mst_conn->dp_panel; + int pbn; + int rc = 0; + + mst_state = drm_atomic_get_new_mst_topology_state(state, &mst->mst_mgr); + + pbn = drm_dp_calc_pbn_mode(dp_panel->msm_dp_mode.drm_mode.clock, + (mst_conn->connector.display_info.bpc * 3) << 4); + + payload = drm_atomic_get_mst_payload_state(mst_state, port); + if (!payload || payload->time_slots <= 0) { + DRM_ERROR("time slots not allocated for conn:%d\n", DP_MST_CONN_ID(dp_bridge)); + rc = -EINVAL; + return rc; + } + + drm_dbg_dp(dp_display->drm_dev, "conn:%d pbn:%d, slots:%d\n", DP_MST_CONN_ID(dp_bridge), + pbn, payload->time_slots); + + drm_dp_mst_update_slots(mst_state, DP_CAP_ANSI_8B10B); + + rc = drm_dp_add_payload_part1(&mst->mst_mgr, mst_state, payload); + if (rc) { + DRM_ERROR("payload allocation failure for conn:%d\n", DP_MST_CONN_ID(dp_bridge)); + return rc; + } + + msm_dp_mst_update_timeslots(mst, dp_bridge, state, port); + + return rc; +} + +static void _msm_dp_mst_bridge_pre_enable_part2(struct msm_dp_mst_bridge *dp_bridge, + struct drm_atomic_state *state) +{ + struct msm_dp *dp_display = dp_bridge->display; + struct msm_dp_mst *mst = dp_display->msm_dp_mst; + struct msm_dp_mst_connector *mst_conn = to_dp_mst_connector(dp_bridge->connector); + struct drm_dp_mst_port *port = mst_conn->mst_port; + struct drm_dp_mst_topology_state *mst_state; + struct drm_dp_mst_atomic_payload *payload; + + drm_dp_check_act_status(&mst->mst_mgr); + + mst_state = to_drm_dp_mst_topology_state(mst->mst_mgr.base.state); + payload = drm_atomic_get_mst_payload_state(mst_state, port); + + drm_dp_add_payload_part2(&mst->mst_mgr, payload); + + drm_dbg_dp(dp_display->drm_dev, "MST bridge [%d] _pre enable part-2 complete\n", + dp_bridge->id); +} + +static void msm_dp_mst_bridge_pre_disable_part1(struct msm_dp_mst_bridge *dp_bridge, + struct drm_atomic_state *state) +{ + struct msm_dp *dp_display = dp_bridge->display; + struct msm_dp_mst *mst = dp_display->msm_dp_mst; + struct msm_dp_mst_connector *mst_conn = to_dp_mst_connector(dp_bridge->connector); + struct drm_dp_mst_port *port = mst_conn->mst_port; + struct drm_dp_mst_topology_state *old_mst_state; + struct drm_dp_mst_topology_state *new_mst_state; + const struct drm_dp_mst_atomic_payload *old_payload; + struct drm_dp_mst_atomic_payload *new_payload; + + old_mst_state = drm_atomic_get_old_mst_topology_state(state, &mst->mst_mgr); + new_mst_state = drm_atomic_get_new_mst_topology_state(state, &mst->mst_mgr); + + old_payload = drm_atomic_get_mst_payload_state(old_mst_state, port); + new_payload = drm_atomic_get_mst_payload_state(new_mst_state, port); + + if (!old_payload || !new_payload) { + DRM_ERROR("MST bridge [%d] _pre disable part-1 failed, null payload\n", + dp_bridge->id); + return; + } + + drm_dp_remove_payload_part1(&mst->mst_mgr, new_mst_state, new_payload); + drm_dp_remove_payload_part2(&mst->mst_mgr, new_mst_state, old_payload, new_payload); + + msm_dp_mst_update_timeslots(mst, dp_bridge, state, port); + + drm_dbg_dp(dp_display->drm_dev, "MST bridge [%d] _pre disable part-1 complete\n", + dp_bridge->id); +} + +static void msm_dp_mst_bridge_atomic_pre_enable(struct drm_bridge *drm_bridge, + struct drm_atomic_state *state) +{ + int rc = 0; + struct msm_dp_mst_bridge *bridge; + struct msm_dp *dp_display; + struct msm_dp_mst_bridge_state *mst_bridge_state; + struct msm_dp_mst *dp_mst; + struct msm_dp_panel *msm_dp_panel; + + if (!drm_bridge) { + DRM_ERROR("Invalid params\n"); + return; + } + + bridge = to_dp_mst_bridge(drm_bridge); + mst_bridge_state = to_dp_mst_bridge_state(bridge); + dp_display = bridge->display; + dp_mst = dp_display->msm_dp_mst; + + /* to cover cases of bridge_disable/bridge_enable without modeset */ + bridge->connector = mst_bridge_state->connector; + bridge->msm_dp_panel = mst_bridge_state->msm_dp_panel; + + if (!bridge->connector) { + DRM_ERROR("Invalid connector\n"); + return; + } + + msm_dp_panel = bridge->msm_dp_panel; + mutex_lock(&dp_mst->mst_lock); + + rc = msm_dp_display_set_mode_helper(dp_display, state, drm_bridge->encoder, msm_dp_panel); + if (rc) { + DRM_ERROR("Failed to perform a mode set, rc=%d\n", rc); + mutex_unlock(&dp_mst->mst_lock); + return; + } + msm_dp_panel->pbn = drm_dp_calc_pbn_mode(msm_dp_panel->msm_dp_mode.drm_mode.clock, + msm_dp_panel->msm_dp_mode.bpp << 4); + rc = msm_dp_display_prepare(dp_display); + if (rc) { + DRM_ERROR("[%d] DP display pre-enable failed, rc=%d\n", bridge->id, rc); + msm_dp_display_unprepare(dp_display); + mutex_unlock(&dp_mst->mst_lock); + return; + } + + rc = msm_dp_mst_bridge_pre_enable_part1(bridge, state); + if (rc) { + DRM_ERROR("[%d] DP display pre-enable failed, rc=%d\n", bridge->id, rc); + mutex_unlock(&dp_mst->mst_lock); + return; + } + + msm_dp_display_enable_helper(dp_display, bridge->msm_dp_panel); + + _msm_dp_mst_bridge_pre_enable_part2(bridge, state); + + mutex_unlock(&dp_mst->mst_lock); + + drm_dbg_dp(dp_display->drm_dev, "conn:%d mode:%s pre enable done\n", + DP_MST_CONN_ID(bridge), bridge->msm_dp_panel->msm_dp_mode.drm_mode.name); +} + +static void msm_dp_mst_bridge_atomic_disable(struct drm_bridge *drm_bridge, + struct drm_atomic_state *state) +{ + struct msm_dp_mst_bridge *bridge; + struct msm_dp *dp_display; + struct msm_dp_mst *mst; + + if (!drm_bridge) { + DRM_ERROR("Invalid params\n"); + return; + } + + bridge = to_dp_mst_bridge(drm_bridge); + if (!bridge->connector) { + DRM_ERROR("Invalid connector\n"); + return; + } + + dp_display = bridge->display; + mst = dp_display->msm_dp_mst; + + mutex_lock(&mst->mst_lock); + + msm_dp_mst_bridge_pre_disable_part1(bridge, state); + + msm_dp_display_disable_helper(dp_display, bridge->msm_dp_panel); + + drm_dp_check_act_status(&mst->mst_mgr); + + mutex_unlock(&mst->mst_lock); + + drm_dbg_dp(dp_display->drm_dev, "MST bridge:%d disable complete\n", bridge->id); +} + +static void msm_dp_mst_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, + struct drm_atomic_state *state) +{ + struct msm_dp_mst_bridge *bridge; + struct msm_dp *dp_display; + struct msm_dp_mst *mst; + + if (!drm_bridge) { + DRM_ERROR("Invalid params\n"); + return; + } + + bridge = to_dp_mst_bridge(drm_bridge); + if (!bridge->connector) { + DRM_ERROR("Invalid connector\n"); + return; + } + + dp_display = bridge->display; + mst = dp_display->msm_dp_mst; + + mutex_lock(&mst->mst_lock); + + msm_dp_display_atomic_post_disable_helper(dp_display, bridge->msm_dp_panel); + + if (!dp_display->mst_active) + msm_dp_display_unprepare(dp_display); + + bridge->connector = NULL; + bridge->msm_dp_panel = NULL; + + mutex_unlock(&mst->mst_lock); + + drm_dbg_dp(dp_display->drm_dev, "MST bridge:%d conn:%d post disable complete\n", + bridge->id, DP_MST_CONN_ID(bridge)); +} + +static int msm_dp_mst_bridge_atomic_check(struct drm_bridge *drm_bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_atomic_state *state = crtc_state->state; + struct drm_connector *connector = conn_state->connector; + struct drm_dp_mst_topology_state *mst_state; + struct msm_dp_mst_connector *mst_conn; + struct msm_dp_mst *mst; + int rc = 0, pbn, slots; + struct msm_dp_mst_bridge_state *mst_bridge_state; + u32 bpp; + + if (!drm_atomic_crtc_needs_modeset(crtc_state) || !crtc_state->enable) + return 0; + + mst_conn = to_dp_mst_connector(connector); + mst = mst_conn->dp_mst; + + bpp = connector->display_info.bpc * 3; + + if (!bpp) + bpp = 24; + + pbn = drm_dp_calc_pbn_mode(crtc_state->mode.clock, bpp << 4); + + mst_state = to_drm_dp_mst_topology_state(mst->mst_mgr.base.state); + if (IS_ERR(mst_state)) + return PTR_ERR(mst_state); + + if (!dfixed_trunc(mst_state->pbn_div)) { + mst_state->pbn_div = + drm_dp_get_vc_payload_bw(mst_conn->dp_panel->link_info.rate, + mst_conn->dp_panel->link_info.num_lanes); + } + + slots = drm_dp_atomic_find_time_slots(state, &mst->mst_mgr, mst_conn->mst_port, pbn); + + drm_dbg_dp(drm_bridge->dev, "add slots, conn:%d pbn:%d slots:%d rc:%d\n", + connector->base.id, pbn, slots, rc); + + if (!conn_state->crtc) { + mst_bridge_state = msm_dp_mst_br_priv_state(state, to_dp_mst_bridge(drm_bridge)); + mst_bridge_state->connector = NULL; + mst_bridge_state->msm_dp_panel = NULL; + } + + return 0; +} + +/* DP MST Bridge APIs */ +static const struct drm_bridge_funcs msm_dp_mst_bridge_ops = { + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_pre_enable = msm_dp_mst_bridge_atomic_pre_enable, + .atomic_disable = msm_dp_mst_bridge_atomic_disable, + .atomic_post_disable = msm_dp_mst_bridge_atomic_post_disable, + .atomic_check = msm_dp_mst_bridge_atomic_check, +}; + +int msm_dp_mst_attach_encoder(struct msm_dp *dp_display, struct drm_encoder *encoder) +{ + int rc = 0; + struct msm_dp_mst_bridge *bridge = NULL; + struct msm_dp_mst_bridge_state *mst_bridge_state; + struct drm_device *dev; + struct msm_dp_mst *mst = dp_display->msm_dp_mst; + int i; + + for (i = 0; i < mst->max_streams; i++) { + if (!mst->mst_bridge[i]->initialized) { + bridge = mst->mst_bridge[i]; + bridge->encoder = encoder; + bridge->initialized = true; + bridge->id = i; + break; + } + } + + if (i == mst->max_streams) { + DRM_ERROR("MST supports only %d bridges\n", mst->max_streams); + rc = -EACCES; + goto end; + } + + dev = dp_display->drm_dev; + bridge->display = dp_display; + bridge->base.encoder = encoder; + bridge->base.type = dp_display->connector_type; + bridge->base.ops = DRM_BRIDGE_OP_MODES; + drm_bridge_add(&bridge->base); + + rc = drm_bridge_attach(encoder, &bridge->base, NULL, 0); + if (rc) { + DRM_ERROR("failed to attach bridge, rc=%d\n", rc); + goto end; + } + + mst_bridge_state = kzalloc(sizeof(*mst_bridge_state), GFP_KERNEL); + if (!mst_bridge_state) { + rc = -ENOMEM; + goto end; + } + + drm_atomic_private_obj_init(dev, &bridge->obj, + &mst_bridge_state->base, + &msm_dp_mst_bridge_state_funcs); + + drm_dbg_dp(dp_display->drm_dev, "MST drm bridge init. bridge id:%d\n", i); + + return 0; + +end: + return rc; +} + +int msm_dp_mst_display_set_mgr_state(struct msm_dp *dp_display, bool state) +{ + struct msm_dp_mst *mst = dp_display->msm_dp_mst; + int rc; + + rc = drm_dp_mst_topology_mgr_set_mst(&mst->mst_mgr, state); + if (rc < 0) { + DRM_ERROR("failed to set topology mgr state to %d. rc %d\n", + state, rc); + } + + drm_dbg_dp(dp_display->drm_dev, "dp_mst_display_set_mgr_state state:%d\n", state); + return rc; +} + +/* DP MST HPD IRQ callback */ +void msm_dp_mst_display_hpd_irq(struct msm_dp *dp_display) +{ + int rc; + struct msm_dp_mst *mst = dp_display->msm_dp_mst; + u8 ack[8] = {}; + u8 esi[4]; + unsigned int esi_res = DP_SINK_COUNT_ESI + 1; + bool handled; + + rc = drm_dp_dpcd_read_data(mst->dp_aux, DP_SINK_COUNT_ESI, esi, 4); + if (rc < 0) { + DRM_ERROR("DPCD sink status read failed, rlen=%d\n", rc); + return; + } + + drm_dbg_dp(dp_display->drm_dev, "MST irq: esi1[0x%x] esi2[0x%x] esi3[%x]\n", + esi[1], esi[2], esi[3]); + + rc = drm_dp_mst_hpd_irq_handle_event(&mst->mst_mgr, esi, ack, &handled); + + /* ack the request */ + if (handled) { + rc = drm_dp_dpcd_write_byte(mst->dp_aux, esi_res, ack[1]); + if (rc < 0) { + DRM_ERROR("DPCD esi_res failed. rc=%d\n", rc); + return; + } + + drm_dp_mst_hpd_irq_send_new_request(&mst->mst_mgr); + } + drm_dbg_dp(dp_display->drm_dev, "MST display hpd_irq handled:%d rc:%d\n", handled, rc); +} + +/* DP MST Connector OPs */ +static int +msm_dp_mst_connector_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) +{ + struct msm_dp_mst_connector *mst_conn = to_dp_mst_connector(connector); + struct msm_dp_mst *mst = mst_conn->dp_mst; + struct msm_dp *dp_display = mst->msm_dp; + struct device *dev = dp_display->drm_dev->dev; + enum drm_connector_status status = connector_status_disconnected; + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return status; + + if (dp_display->mst_active) + status = drm_dp_mst_detect_port(connector, + ctx, &mst->mst_mgr, mst_conn->mst_port); + + pm_runtime_put_autosuspend(dev); + + return status; +} + +static int msm_dp_mst_connector_get_modes(struct drm_connector *connector) +{ + struct msm_dp_mst_connector *mst_conn = to_dp_mst_connector(connector); + struct msm_dp_mst *mst = mst_conn->dp_mst; + const struct drm_edid *drm_edid; + + drm_edid = drm_dp_mst_edid_read(connector, &mst->mst_mgr, mst_conn->mst_port); + drm_edid_connector_update(connector, drm_edid); + + return drm_edid_connector_add_modes(connector); +} + +static enum drm_mode_status msm_dp_mst_connector_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode) +{ + struct msm_dp_mst_connector *mst_conn; + struct drm_dp_mst_port *mst_port; + struct msm_dp *dp_display; + int required_pbn; + + if (drm_connector_is_unregistered(connector)) + return 0; + + mst_conn = to_dp_mst_connector(connector); + mst_port = mst_conn->mst_port; + dp_display = mst_conn->dp_mst->msm_dp; + + if (!mst_port) + return MODE_ERROR; + + required_pbn = drm_dp_calc_pbn_mode(mode->clock, (6 * 3) << 4); + + if (required_pbn > mst_port->full_pbn) { + drm_dbg_dp(dp_display->drm_dev, "mode:%s not supported.\n", mode->name); + return MODE_CLOCK_HIGH; + } + + return msm_dp_display_mode_valid(dp_display, &connector->display_info, mode); +} + +static struct drm_encoder * +msm_dp_mst_atomic_best_encoder(struct drm_connector *connector, struct drm_atomic_state *state) +{ + struct msm_dp_mst_connector *mst_conn = to_dp_mst_connector(connector); + struct msm_dp_mst *mst = mst_conn->dp_mst; + struct msm_dp *dp_display = mst->msm_dp; + struct drm_encoder *enc = NULL; + struct msm_dp_mst_bridge_state *mst_bridge_state; + u32 i; + struct drm_connector_state *conn_state = drm_atomic_get_new_connector_state(state, + connector); + + if (conn_state && conn_state->best_encoder) + return conn_state->best_encoder; + + for (i = 0; i < mst->max_streams; i++) { + mst_bridge_state = msm_dp_mst_br_priv_state(state, mst->mst_bridge[i]); + if (IS_ERR(mst_bridge_state)) + goto end; + + if (mst_bridge_state->connector == connector) { + enc = mst->mst_bridge[i]->encoder; + goto end; + } + } + + for (i = 0; i < mst->max_streams; i++) { + mst_bridge_state = msm_dp_mst_br_priv_state(state, mst->mst_bridge[i]); + + if (!mst_bridge_state->connector) { + mst_bridge_state->connector = connector; + mst_bridge_state->msm_dp_panel = mst_conn->dp_panel; + enc = mst->mst_bridge[i]->encoder; + break; + } + } + +end: + if (enc) + drm_dbg_dp(dp_display->drm_dev, "MST connector:%d atomic best encoder:%d\n", + connector->base.id, i); + else + drm_dbg_dp(dp_display->drm_dev, "MST connector:%d atomic best encoder failed\n", + connector->base.id); + + return enc; +} + +static int msm_dp_mst_connector_atomic_check(struct drm_connector *connector, + struct drm_atomic_state *state) +{ + int rc = 0, slots; + struct drm_connector_state *old_conn_state; + struct drm_connector_state *new_conn_state; + struct drm_crtc *old_crtc; + struct drm_crtc_state *crtc_state; + struct msm_dp_mst_bridge *bridge; + struct msm_dp_mst_bridge_state *mst_bridge_state; + struct drm_bridge *drm_bridge; + struct msm_dp_mst_connector *mst_conn = to_dp_mst_connector(connector); + struct msm_dp_mst *mst = mst_conn->dp_mst; + struct msm_dp *dp_display = mst->msm_dp; + struct drm_dp_mst_atomic_payload *payload; + struct drm_dp_mst_topology_state *mst_state; + + if (!state) + return rc; + + new_conn_state = drm_atomic_get_new_connector_state(state, connector); + if (!new_conn_state) + return rc; + + old_conn_state = drm_atomic_get_old_connector_state(state, connector); + if (!old_conn_state) + goto end; + + old_crtc = old_conn_state->crtc; + if (!old_crtc) + goto end; + + crtc_state = drm_atomic_get_new_crtc_state(state, old_crtc); + + /* attempt to release vcpi slots on a modeset change for crtc state */ + if (drm_atomic_crtc_needs_modeset(crtc_state)) { + if (WARN_ON(!old_conn_state->best_encoder)) { + rc = -EINVAL; + goto end; + } + + drm_bridge = drm_bridge_chain_get_first_bridge(old_conn_state->best_encoder); + if (WARN_ON(!drm_bridge)) { + rc = -EINVAL; + goto end; + } + bridge = to_dp_mst_bridge(drm_bridge); + + mst_bridge_state = msm_dp_mst_br_priv_state(state, bridge); + + mst_state = to_drm_dp_mst_topology_state(mst->mst_mgr.base.state); + + payload = drm_atomic_get_mst_payload_state(mst_state, mst_conn->mst_port); + + slots = payload->time_slots; + if (slots > 0) { + rc = drm_dp_atomic_release_time_slots(state, + &mst->mst_mgr, + mst_conn->mst_port); + if (rc) { + DRM_ERROR("failed releasing %d vcpi slots %d\n", slots, rc); + goto end; + } + } + + if (!new_conn_state->crtc) { + /* for cases where crtc is not disabled the slots are not + * freed by drm_dp_atomic_release_time_slots. this results + * in subsequent atomic_check failing since internal slots + * were freed but not the DP MST mgr's + */ + mst_bridge_state->connector = NULL; + mst_bridge_state->msm_dp_panel = NULL; + drm_dbg_dp(dp_display->drm_dev, "clear best encoder: %d\n", bridge->id); + } + } + +end: + drm_dbg_dp(dp_display->drm_dev, "mst connector:%d atomic check ret %d\n", + connector->base.id, rc); + return rc; +} + +static void dp_mst_connector_destroy(struct drm_connector *connector) +{ + struct msm_dp_mst_connector *mst_conn = to_dp_mst_connector(connector); + + drm_connector_cleanup(connector); + drm_dp_mst_put_port_malloc(mst_conn->mst_port); + kfree(mst_conn); +} + +/* DRM MST callbacks */ +static const struct drm_connector_helper_funcs msm_dp_drm_mst_connector_helper_funcs = { + .get_modes = msm_dp_mst_connector_get_modes, + .detect_ctx = msm_dp_mst_connector_detect, + .mode_valid = msm_dp_mst_connector_mode_valid, + .atomic_best_encoder = msm_dp_mst_atomic_best_encoder, + .atomic_check = msm_dp_mst_connector_atomic_check, +}; + +static const struct drm_connector_funcs msm_dp_drm_mst_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .destroy = dp_mst_connector_destroy, + .fill_modes = drm_helper_probe_single_connector_modes, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static struct drm_connector * +msm_dp_mst_add_connector(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, const char *pathprop) +{ + struct msm_dp_mst *dp_mst; + struct drm_device *dev; + struct msm_dp *dp_display; + struct msm_dp_mst_connector *mst_conn; + struct drm_connector *connector; + int rc, i; + + dp_mst = container_of(mgr, struct msm_dp_mst, mst_mgr); + + dp_display = dp_mst->msm_dp; + dev = dp_display->drm_dev; + + mst_conn = kzalloc(sizeof(*mst_conn), GFP_KERNEL); + + if (!mst_conn) + return NULL; + + drm_modeset_lock_all(dev); + + connector = &mst_conn->connector; + rc = drm_connector_dynamic_init(dev, connector, + &msm_dp_drm_mst_connector_funcs, + DRM_MODE_CONNECTOR_DisplayPort, NULL); + if (rc) { + kfree(mst_conn); + drm_modeset_unlock_all(dev); + return NULL; + } + + mst_conn->dp_panel = msm_dp_display_get_panel(dp_display); + if (!mst_conn->dp_panel) { + DRM_ERROR("failed to get dp_panel for connector\n"); + kfree(mst_conn); + drm_modeset_unlock_all(dev); + return NULL; + } + + mst_conn->dp_panel->connector = connector; + mst_conn->dp_mst = dp_mst; + + drm_connector_helper_add(connector, &msm_dp_drm_mst_connector_helper_funcs); + + if (connector->funcs->reset) + connector->funcs->reset(connector); + + /* add all encoders as possible encoders */ + for (i = 0; i < dp_mst->max_streams; i++) { + rc = drm_connector_attach_encoder(connector, dp_mst->mst_bridge[i]->encoder); + + if (rc) { + DRM_ERROR("failed to attach encoder to connector, %d\n", rc); + kfree(mst_conn); + drm_modeset_unlock_all(dev); + return NULL; + } + } + + mst_conn->mst_port = port; + drm_dp_mst_get_port_malloc(mst_conn->mst_port); + + drm_object_attach_property(&connector->base, + dev->mode_config.path_property, 0); + drm_object_attach_property(&connector->base, + dev->mode_config.tile_property, 0); + drm_connector_set_path_property(connector, pathprop); + drm_modeset_unlock_all(dev); + + drm_dbg_dp(dp_display->drm_dev, "add MST connector id:%d\n", connector->base.id); + + return connector; +} + +static const struct drm_dp_mst_topology_cbs msm_dp_mst_drm_cbs = { + .add_connector = msm_dp_mst_add_connector, +}; + +int msm_dp_mst_init(struct msm_dp *dp_display, u32 max_streams, struct drm_dp_aux *drm_aux) +{ + struct drm_device *dev = dp_display->drm_dev; + int conn_base_id = 0; + int ret; + struct msm_dp_mst *msm_dp_mst; + + msm_dp_mst = devm_kzalloc(dev->dev, sizeof(*msm_dp_mst), GFP_KERNEL); + if (!msm_dp_mst) + return -ENOMEM; + + memset(&msm_dp_mst->mst_mgr, 0, sizeof(msm_dp_mst->mst_mgr)); + msm_dp_mst->mst_mgr.cbs = &msm_dp_mst_drm_cbs; + conn_base_id = dp_display->connector->base.id; + msm_dp_mst->msm_dp = dp_display; + msm_dp_mst->max_streams = max_streams; + + for (int i = 0; i < DP_STREAM_MAX; i++) { + msm_dp_mst->mst_bridge[i] = + devm_drm_bridge_alloc(dev->dev, struct msm_dp_mst_bridge, base, + &msm_dp_mst_bridge_ops); + } + + msm_dp_mst->dp_aux = drm_aux; + + ret = drm_dp_mst_topology_mgr_init(&msm_dp_mst->mst_mgr, dev, + drm_aux, + MAX_DPCD_TRANSACTION_BYTES, + max_streams, + conn_base_id); + if (ret) { + DRM_ERROR("DP DRM MST topology manager init failed\n"); + return ret; + } + + dp_display->msm_dp_mst = msm_dp_mst; + + mutex_init(&msm_dp_mst->mst_lock); + return ret; +} diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.h b/drivers/gpu/drm/msm/dp/dp_mst_drm.h new file mode 100644 index 0000000000000..08e145399cfc7 --- /dev/null +++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _DP_MST_DRM_H_ +#define _DP_MST_DRM_H_ + +#include "dp_display.h" + +int msm_dp_mst_init(struct msm_dp *dp_display, u32 max_streams, struct drm_dp_aux *drm_aux); +int msm_dp_mst_display_set_mgr_state(struct msm_dp *dp_display, bool state); +void msm_dp_mst_display_hpd_irq(struct msm_dp *dp_display); + +#endif /* _DP_MST_DRM_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c index ad5d55bf009db..e05d96f33c433 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.c +++ b/drivers/gpu/drm/msm/dp/dp_panel.c @@ -13,6 +13,8 @@ #include #include +#include +#include #define DP_INTF_CONFIG_DATABUS_WIDEN BIT(4) @@ -23,43 +25,70 @@ struct msm_dp_panel_private { struct drm_dp_aux *aux; struct msm_dp_link *link; void __iomem *link_base; - void __iomem *p0_base; + void __iomem *mst2link_base; + void __iomem *mst3link_base; + void __iomem *pixel_base; bool panel_on; }; static inline u32 msm_dp_read_link(struct msm_dp_panel_private *panel, u32 offset) { - return readl_relaxed(panel->link_base + offset); + switch (panel->msm_dp_panel.stream_id) { + case DP_STREAM_0: + case DP_STREAM_1: + return readl_relaxed(panel->link_base + offset); + case DP_STREAM_2: + return readl_relaxed(panel->mst2link_base + offset); + case DP_STREAM_3: + return readl_relaxed(panel->mst3link_base + offset); + default: + DRM_ERROR("error stream_id\n"); + return 0; + } } static inline void msm_dp_write_link(struct msm_dp_panel_private *panel, - u32 offset, u32 data) + u32 offset, u32 data) { /* * To make sure link reg writes happens before any other operation, * this function uses writel() instread of writel_relaxed() */ - writel(data, panel->link_base + offset); + switch (panel->msm_dp_panel.stream_id) { + case DP_STREAM_0: + case DP_STREAM_1: + writel(data, panel->link_base + offset); + break; + case DP_STREAM_2: + writel(data, panel->mst2link_base + offset); + break; + case DP_STREAM_3: + writel(data, panel->mst3link_base + offset); + break; + default: + DRM_ERROR("error stream_id\n"); + break; + } } -static inline void msm_dp_write_p0(struct msm_dp_panel_private *panel, - u32 offset, u32 data) +static inline void msm_dp_write_pn(struct msm_dp_panel_private *panel, + u32 offset, u32 data) { /* * To make sure interface reg writes happens before any other operation, * this function uses writel() instread of writel_relaxed() */ - writel(data, panel->p0_base + offset); + writel(data, panel->pixel_base + offset); } -static inline u32 msm_dp_read_p0(struct msm_dp_panel_private *panel, - u32 offset) +static inline u32 msm_dp_read_pn(struct msm_dp_panel_private *panel, + u32 offset) { /* * To make sure interface reg writes happens before any other operation, * this function uses writel() instread of writel_relaxed() */ - return readl_relaxed(panel->p0_base + offset); + return readl_relaxed(panel->pixel_base + offset); } static void msm_dp_panel_read_psr_cap(struct msm_dp_panel_private *panel) @@ -107,29 +136,98 @@ static int msm_dp_panel_read_dpcd(struct msm_dp_panel *msm_dp_panel) drm_dbg_dp(panel->drm_dev, "max_lanes=%d max_link_rate=%d\n", link->max_dp_lanes, link->max_dp_link_rate); - link_info->rate = drm_dp_max_link_rate(dpcd); + max_lttpr_lanes = drm_dp_lttpr_max_lane_count(link->lttpr_common_caps); + max_lttpr_rate = drm_dp_lttpr_max_link_rate(link->lttpr_common_caps); + + /* eDP sink */ + if (msm_dp_panel->dpcd[DP_EDP_CONFIGURATION_CAP]) { + u8 edp_rev; + + rc = drm_dp_dpcd_read_byte(panel->aux, DP_EDP_DPCD_REV, &edp_rev); + if (rc) + return rc; + + drm_dbg_dp(panel->drm_dev, "edp_rev=0x%x\n", edp_rev); + + /* For eDP v1.4+, parse the SUPPORTED_LINK_RATES table */ + if (edp_rev >= DP_EDP_14) { + __le16 rates[DP_MAX_SUPPORTED_RATES]; + u8 bw_set; + int i; + + rc = drm_dp_dpcd_read_data(panel->aux, DP_SUPPORTED_LINK_RATES, + rates, sizeof(rates)); + if (rc) + return rc; + + rc = drm_dp_dpcd_read_byte(panel->aux, DP_LINK_BW_SET, &bw_set); + if (rc) + return rc; + + /* Find index of max supported link rate that does not exceed dtsi limits */ + for (i = 0; i < ARRAY_SIZE(rates); i++) { + /* + * The value from the DPCD multiplied by 200 gives + * the link rate in kHz. Divide by 10 to convert to + * symbol rate, accounting for 8b/10b encoding. + */ + u32 rate = (le16_to_cpu(rates[i]) * 200) / 10; + + if (!rate) + break; + + drm_dbg_dp(panel->drm_dev, + "SUPPORTED_LINK_RATES[%d]: %d\n", i, rate); + + /* + * Limit link rate from link-frequencies of endpoint + * property of dtsi + */ + if (rate > link->max_dp_link_rate) + break; + + /* Limit link rate from LTTPR capabilities, if any */ + if (max_lttpr_rate && rate > max_lttpr_rate) + break; + + link_info->rate = rate; + link_info->supported_rates[i] = rate; + link_info->rate_set = i; + } + + /* Only use LINK_RATE_SET if LINK_BW_SET hasn't already been written to */ + if (!bw_set && link_info->rate) + link_info->use_rate_set = true; + } + } + + /* Fall back on MAX_LINK_RATE/LINK_BW_SET (DP, eDP <= v1.3) */ + if (!link_info->rate) { + link_info->rate = drm_dp_max_link_rate(dpcd); + + /* Limit link rate from link-frequencies of endpoint property of dtsi */ + if (link_info->rate > link->max_dp_link_rate) + link_info->rate = link->max_dp_link_rate; + + /* Limit link rate from LTTPR capabilities, if any */ + if (max_lttpr_rate && max_lttpr_rate < link_info->rate) + link_info->rate = max_lttpr_rate; + } + link_info->num_lanes = drm_dp_max_lane_count(dpcd); /* Limit data lanes from data-lanes of endpoint property of dtsi */ if (link_info->num_lanes > link->max_dp_lanes) link_info->num_lanes = link->max_dp_lanes; - /* Limit link rate from link-frequencies of endpoint property of dtsi */ - if (link_info->rate > link->max_dp_link_rate) - link_info->rate = link->max_dp_link_rate; - /* Limit data lanes from LTTPR capabilities, if any */ - max_lttpr_lanes = drm_dp_lttpr_max_lane_count(panel->link->lttpr_common_caps); if (max_lttpr_lanes && max_lttpr_lanes < link_info->num_lanes) link_info->num_lanes = max_lttpr_lanes; - /* Limit link rate from LTTPR capabilities, if any */ - max_lttpr_rate = drm_dp_lttpr_max_link_rate(panel->link->lttpr_common_caps); - if (max_lttpr_rate && max_lttpr_rate < link_info->rate) - link_info->rate = max_lttpr_rate; - drm_dbg_dp(panel->drm_dev, "version: %d.%d\n", major, minor); drm_dbg_dp(panel->drm_dev, "link_rate=%d\n", link_info->rate); + drm_dbg_dp(panel->drm_dev, "link_rate_set=%d\n", link_info->rate_set); + drm_dbg_dp(panel->drm_dev, "use_rate_set=%d\n", link_info->use_rate_set); drm_dbg_dp(panel->drm_dev, "lane_count=%d\n", link_info->num_lanes); if (drm_dp_enhanced_frame_cap(dpcd)) @@ -161,8 +259,8 @@ static u32 msm_dp_panel_get_supported_bpp(struct msm_dp_panel *msm_dp_panel, return min_supported_bpp; } -int msm_dp_panel_read_sink_caps(struct msm_dp_panel *msm_dp_panel, - struct drm_connector *connector) +int msm_dp_panel_read_link_caps(struct msm_dp_panel *msm_dp_panel, + struct drm_connector *connector) { int rc, bw_code; int count; @@ -200,25 +298,6 @@ int msm_dp_panel_read_sink_caps(struct msm_dp_panel *msm_dp_panel, rc = drm_dp_read_downstream_info(panel->aux, msm_dp_panel->dpcd, msm_dp_panel->downstream_ports); - if (rc) - return rc; - - drm_edid_free(msm_dp_panel->drm_edid); - - msm_dp_panel->drm_edid = drm_edid_read_ddc(connector, &panel->aux->ddc); - - drm_edid_connector_update(connector, msm_dp_panel->drm_edid); - - if (!msm_dp_panel->drm_edid) { - DRM_ERROR("panel edid read failed\n"); - /* check edid read fail is due to unplug */ - if (!msm_dp_aux_is_link_connected(panel->aux)) { - rc = -ETIMEDOUT; - goto end; - } - } - -end: return rc; } @@ -245,20 +324,6 @@ u32 msm_dp_panel_get_mode_bpp(struct msm_dp_panel *msm_dp_panel, return bpp; } -int msm_dp_panel_get_modes(struct msm_dp_panel *msm_dp_panel, - struct drm_connector *connector) -{ - if (!msm_dp_panel) { - DRM_ERROR("invalid input\n"); - return -EINVAL; - } - - if (msm_dp_panel->drm_edid) - return drm_edid_connector_add_modes(connector); - - return 0; -} - static u8 msm_dp_panel_get_edid_checksum(const struct edid *edid) { edid += edid->extensions; @@ -266,7 +331,8 @@ static u8 msm_dp_panel_get_edid_checksum(const struct edid *edid) return edid->checksum; } -void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel) +void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel, + const struct drm_edid *drm_edid) { struct msm_dp_panel_private *panel; @@ -279,7 +345,7 @@ void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel) if (panel->link->sink_request & DP_TEST_LINK_EDID_READ) { /* FIXME: get rid of drm_edid_raw() */ - const struct edid *edid = drm_edid_raw(msm_dp_panel->drm_edid); + const struct edid *edid = drm_edid_raw(drm_edid); u8 checksum; if (edid) @@ -328,34 +394,34 @@ static void msm_dp_panel_tpg_enable(struct msm_dp_panel *msm_dp_panel, display_hctl = (hsync_end_x << 16) | hsync_start_x; - msm_dp_write_p0(panel, MMSS_DP_INTF_HSYNC_CTL, hsync_ctl); - msm_dp_write_p0(panel, MMSS_DP_INTF_VSYNC_PERIOD_F0, vsync_period * + msm_dp_write_pn(panel, MMSS_DP_INTF_HSYNC_CTL, hsync_ctl); + msm_dp_write_pn(panel, MMSS_DP_INTF_VSYNC_PERIOD_F0, vsync_period * hsync_period); - msm_dp_write_p0(panel, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0, v_sync_width * + msm_dp_write_pn(panel, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0, v_sync_width * hsync_period); - msm_dp_write_p0(panel, MMSS_DP_INTF_VSYNC_PERIOD_F1, 0); - msm_dp_write_p0(panel, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1, 0); - msm_dp_write_p0(panel, MMSS_DP_INTF_DISPLAY_HCTL, display_hctl); - msm_dp_write_p0(panel, MMSS_DP_INTF_ACTIVE_HCTL, 0); - msm_dp_write_p0(panel, MMSS_INTF_DISPLAY_V_START_F0, display_v_start); - msm_dp_write_p0(panel, MMSS_DP_INTF_DISPLAY_V_END_F0, display_v_end); - msm_dp_write_p0(panel, MMSS_INTF_DISPLAY_V_START_F1, 0); - msm_dp_write_p0(panel, MMSS_DP_INTF_DISPLAY_V_END_F1, 0); - msm_dp_write_p0(panel, MMSS_DP_INTF_ACTIVE_V_START_F0, 0); - msm_dp_write_p0(panel, MMSS_DP_INTF_ACTIVE_V_END_F0, 0); - msm_dp_write_p0(panel, MMSS_DP_INTF_ACTIVE_V_START_F1, 0); - msm_dp_write_p0(panel, MMSS_DP_INTF_ACTIVE_V_END_F1, 0); - msm_dp_write_p0(panel, MMSS_DP_INTF_POLARITY_CTL, 0); - - msm_dp_write_p0(panel, MMSS_DP_TPG_MAIN_CONTROL, - DP_TPG_CHECKERED_RECT_PATTERN); - msm_dp_write_p0(panel, MMSS_DP_TPG_VIDEO_CONFIG, - DP_TPG_VIDEO_CONFIG_BPP_8BIT | - DP_TPG_VIDEO_CONFIG_RGB); - msm_dp_write_p0(panel, MMSS_DP_BIST_ENABLE, - DP_BIST_ENABLE_DPBIST_EN); - msm_dp_write_p0(panel, MMSS_DP_TIMING_ENGINE_EN, - DP_TIMING_ENGINE_EN_EN); + msm_dp_write_pn(panel, MMSS_DP_INTF_VSYNC_PERIOD_F1, 0); + msm_dp_write_pn(panel, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1, 0); + msm_dp_write_pn(panel, MMSS_DP_INTF_DISPLAY_HCTL, display_hctl); + msm_dp_write_pn(panel, MMSS_DP_INTF_ACTIVE_HCTL, 0); + msm_dp_write_pn(panel, MMSS_INTF_DISPLAY_V_START_F0, display_v_start); + msm_dp_write_pn(panel, MMSS_DP_INTF_DISPLAY_V_END_F0, display_v_end); + msm_dp_write_pn(panel, MMSS_INTF_DISPLAY_V_START_F1, 0); + msm_dp_write_pn(panel, MMSS_DP_INTF_DISPLAY_V_END_F1, 0); + msm_dp_write_pn(panel, MMSS_DP_INTF_ACTIVE_V_START_F0, 0); + msm_dp_write_pn(panel, MMSS_DP_INTF_ACTIVE_V_END_F0, 0); + msm_dp_write_pn(panel, MMSS_DP_INTF_ACTIVE_V_START_F1, 0); + msm_dp_write_pn(panel, MMSS_DP_INTF_ACTIVE_V_END_F1, 0); + msm_dp_write_pn(panel, MMSS_DP_INTF_POLARITY_CTL, 0); + + msm_dp_write_pn(panel, MMSS_DP_TPG_MAIN_CONTROL, + DP_TPG_CHECKERED_RECT_PATTERN); + msm_dp_write_pn(panel, MMSS_DP_TPG_VIDEO_CONFIG, + DP_TPG_VIDEO_CONFIG_BPP_8BIT | + DP_TPG_VIDEO_CONFIG_RGB); + msm_dp_write_pn(panel, MMSS_DP_BIST_ENABLE, + DP_BIST_ENABLE_DPBIST_EN); + msm_dp_write_pn(panel, MMSS_DP_TIMING_ENGINE_EN, + DP_TIMING_ENGINE_EN_EN); drm_dbg_dp(panel->drm_dev, "%s: enabled tpg\n", __func__); } @@ -364,9 +430,9 @@ static void msm_dp_panel_tpg_disable(struct msm_dp_panel *msm_dp_panel) struct msm_dp_panel_private *panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); - msm_dp_write_p0(panel, MMSS_DP_TPG_MAIN_CONTROL, 0x0); - msm_dp_write_p0(panel, MMSS_DP_BIST_ENABLE, 0x0); - msm_dp_write_p0(panel, MMSS_DP_TIMING_ENGINE_EN, 0x0); + msm_dp_write_pn(panel, MMSS_DP_TPG_MAIN_CONTROL, 0x0); + msm_dp_write_pn(panel, MMSS_DP_BIST_ENABLE, 0x0); + msm_dp_write_pn(panel, MMSS_DP_TIMING_ENGINE_EN, 0x0); } void msm_dp_panel_tpg_config(struct msm_dp_panel *msm_dp_panel, bool enable) @@ -400,35 +466,56 @@ void msm_dp_panel_clear_dsc_dto(struct msm_dp_panel *msm_dp_panel) struct msm_dp_panel_private *panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); - msm_dp_write_p0(panel, MMSS_DP_DSC_DTO, 0x0); + msm_dp_write_pn(panel, MMSS_DP_DSC_DTO, 0x0); } static void msm_dp_panel_send_vsc_sdp(struct msm_dp_panel_private *panel, struct dp_sdp *vsc_sdp) { + u32 id = panel->msm_dp_panel.stream_id; u32 header[2]; u32 val; int i; + u32 offset = 0; + + if (id == DP_STREAM_1) + offset = MMSS_DP1_GENERIC0_0 - MMSS_DP_GENERIC0_0; msm_dp_utils_pack_sdp_header(&vsc_sdp->sdp_header, header); - msm_dp_write_link(panel, MMSS_DP_GENERIC0_0, header[0]); - msm_dp_write_link(panel, MMSS_DP_GENERIC0_1, header[1]); + msm_dp_write_link(panel, id > 1 ? + MMSS_DP_MSTLINK_GENERIC0_0 : MMSS_DP_GENERIC0_0 + offset, + header[0]); + msm_dp_write_link(panel, id > 1 ? + MMSS_DP_MSTLINK_GENERIC0_1 : MMSS_DP_GENERIC0_1 + offset, + header[1]); for (i = 0; i < sizeof(vsc_sdp->db); i += 4) { val = ((vsc_sdp->db[i]) | (vsc_sdp->db[i + 1] << 8) | (vsc_sdp->db[i + 2] << 16) | (vsc_sdp->db[i + 3] << 24)); - msm_dp_write_link(panel, MMSS_DP_GENERIC0_2 + i, val); + + msm_dp_write_link(panel, id > 1 ? + MMSS_DP_MSTLINK_GENERIC0_2 + i : MMSS_DP_GENERIC0_2 + i + offset, + val); } } static void msm_dp_panel_update_sdp(struct msm_dp_panel_private *panel) { + u32 id = panel->msm_dp_panel.stream_id; u32 hw_revision = panel->msm_dp_panel.hw_revision; + u32 offset = 0; + + if (id == DP_STREAM_1) + offset = MMSS_DP1_SDP_CFG3 - MMSS_DP_SDP_CFG3; if (hw_revision >= DP_HW_VERSION_1_0 && hw_revision < DP_HW_VERSION_1_2) { - msm_dp_write_link(panel, MMSS_DP_SDP_CFG3, UPDATE_SDP); - msm_dp_write_link(panel, MMSS_DP_SDP_CFG3, 0x0); + msm_dp_write_link(panel, id > 1 ? + MMSS_DP_MSTLINK_SDP_CFG3 : MMSS_DP_SDP_CFG3 + offset, + UPDATE_SDP); + msm_dp_write_link(panel, id > 1 ? + MMSS_DP_MSTLINK_SDP_CFG3 : MMSS_DP_SDP_CFG3 + offset, + 0x0); } } @@ -436,17 +523,34 @@ void msm_dp_panel_enable_vsc_sdp(struct msm_dp_panel *msm_dp_panel, struct dp_sd { struct msm_dp_panel_private *panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); + u32 id = msm_dp_panel->stream_id; u32 cfg, cfg2, misc; + u32 misc_reg_offset = 0; + u32 sdp_cfg_offset = 0; + u32 sdp_cfg2_offset = 0; + + if (id == DP_STREAM_1) { + misc_reg_offset = REG_DP1_MISC1_MISC0 - REG_DP_MISC1_MISC0; + sdp_cfg_offset = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG; + sdp_cfg2_offset = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2; + } - cfg = msm_dp_read_link(panel, MMSS_DP_SDP_CFG); - cfg2 = msm_dp_read_link(panel, MMSS_DP_SDP_CFG2); - misc = msm_dp_read_link(panel, REG_DP_MISC1_MISC0); + cfg = msm_dp_read_link(panel, id > 1 ? + MMSS_DP_MSTLINK_SDP_CFG : MMSS_DP_SDP_CFG + sdp_cfg_offset); + cfg2 = msm_dp_read_link(panel, id > 1 ? + MMSS_DP_MSTLINK_SDP_CFG2 : MMSS_DP_SDP_CFG2 + sdp_cfg2_offset); + misc = msm_dp_read_link(panel, id > 1 ? + REG_DP_MSTLINK_MISC1_MISC0 : REG_DP_MISC1_MISC0 + misc_reg_offset); cfg |= GEN0_SDP_EN; - msm_dp_write_link(panel, MMSS_DP_SDP_CFG, cfg); - cfg2 |= GENERIC0_SDPSIZE_VALID; - msm_dp_write_link(panel, MMSS_DP_SDP_CFG2, cfg2); + + msm_dp_write_link(panel, id > 1 ? + MMSS_DP_MSTLINK_SDP_CFG : MMSS_DP_SDP_CFG + sdp_cfg_offset, + cfg); + msm_dp_write_link(panel, id > 1 ? + MMSS_DP_MSTLINK_SDP_CFG2 : MMSS_DP_SDP_CFG2 + sdp_cfg2_offset, + cfg2); msm_dp_panel_send_vsc_sdp(panel, vsc_sdp); @@ -456,7 +560,9 @@ void msm_dp_panel_enable_vsc_sdp(struct msm_dp_panel *msm_dp_panel, struct dp_sd drm_dbg_dp(panel->drm_dev, "vsc sdp enable=1\n"); pr_debug("misc settings = 0x%x\n", misc); - msm_dp_write_link(panel, REG_DP_MISC1_MISC0, misc); + msm_dp_write_link(panel, id > 1 ? + REG_DP_MSTLINK_MISC1_MISC0 : REG_DP_MISC1_MISC0 + misc_reg_offset, + misc); msm_dp_panel_update_sdp(panel); } @@ -465,17 +571,34 @@ void msm_dp_panel_disable_vsc_sdp(struct msm_dp_panel *msm_dp_panel) { struct msm_dp_panel_private *panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); + u32 id = msm_dp_panel->stream_id; u32 cfg, cfg2, misc; + u32 misc_reg_offset = 0; + u32 sdp_cfg_offset = 0; + u32 sdp_cfg2_offset = 0; + + if (id == DP_STREAM_1) { + misc_reg_offset = REG_DP1_MISC1_MISC0 - REG_DP_MISC1_MISC0; + sdp_cfg_offset = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG; + sdp_cfg2_offset = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2; + } - cfg = msm_dp_read_link(panel, MMSS_DP_SDP_CFG); - cfg2 = msm_dp_read_link(panel, MMSS_DP_SDP_CFG2); - misc = msm_dp_read_link(panel, REG_DP_MISC1_MISC0); + cfg = msm_dp_read_link(panel, id > 1 ? + MMSS_DP_MSTLINK_SDP_CFG : MMSS_DP_SDP_CFG + sdp_cfg_offset); + cfg2 = msm_dp_read_link(panel, id > 1 ? + MMSS_DP_MSTLINK_SDP_CFG2 : MMSS_DP_SDP_CFG2 + sdp_cfg2_offset); + misc = msm_dp_read_link(panel, id > 1 ? + REG_DP_MSTLINK_MISC1_MISC0 : REG_DP_MISC1_MISC0 + misc_reg_offset); cfg &= ~GEN0_SDP_EN; - msm_dp_write_link(panel, MMSS_DP_SDP_CFG, cfg); - cfg2 &= ~GENERIC0_SDPSIZE_VALID; - msm_dp_write_link(panel, MMSS_DP_SDP_CFG2, cfg2); + + msm_dp_write_link(panel, id > 1 ? + MMSS_DP_MSTLINK_SDP_CFG : MMSS_DP_SDP_CFG + sdp_cfg_offset, + cfg); + msm_dp_write_link(panel, id > 1 ? + MMSS_DP_MSTLINK_SDP_CFG2 : MMSS_DP_SDP_CFG2 + sdp_cfg2_offset, + cfg2); /* switch back to MSA */ misc &= ~DP_MISC1_VSC_SDP; @@ -483,7 +606,9 @@ void msm_dp_panel_disable_vsc_sdp(struct msm_dp_panel *msm_dp_panel) drm_dbg_dp(panel->drm_dev, "vsc sdp enable=0\n"); pr_debug("misc settings = 0x%x\n", misc); - msm_dp_write_link(panel, REG_DP_MISC1_MISC0, misc); + msm_dp_write_link(panel, id > 1 ? + REG_DP_MSTLINK_MISC1_MISC0 : REG_DP_MISC1_MISC0 + misc_reg_offset, + misc); msm_dp_panel_update_sdp(panel); } @@ -533,6 +658,7 @@ static int msm_dp_panel_setup_vsc_sdp_yuv_420(struct msm_dp_panel *msm_dp_panel) int msm_dp_panel_timing_cfg(struct msm_dp_panel *msm_dp_panel, bool wide_bus_en) { + u32 id = msm_dp_panel->stream_id; u32 data, total_ver, total_hor; struct msm_dp_panel_private *panel; struct drm_display_mode *drm_mode; @@ -541,6 +667,7 @@ int msm_dp_panel_timing_cfg(struct msm_dp_panel *msm_dp_panel, bool wide_bus_en) u32 msm_dp_active; u32 total; u32 reg; + u32 offset = 0; panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); drm_mode = &panel->msm_dp_panel.msm_dp_mode.drm_mode; @@ -555,6 +682,9 @@ int msm_dp_panel_timing_cfg(struct msm_dp_panel *msm_dp_panel, bool wide_bus_en) drm_mode->vsync_start - drm_mode->vdisplay, drm_mode->vsync_end - drm_mode->vsync_start); + if (id == DP_STREAM_1) + offset = REG_DP1_TOTAL_HOR_VER - REG_DP_TOTAL_HOR_VER; + total_hor = drm_mode->htotal; total_ver = drm_mode->vtotal; @@ -585,12 +715,20 @@ int msm_dp_panel_timing_cfg(struct msm_dp_panel *msm_dp_panel, bool wide_bus_en) msm_dp_active = data; - msm_dp_write_link(panel, REG_DP_TOTAL_HOR_VER, total); - msm_dp_write_link(panel, REG_DP_START_HOR_VER_FROM_SYNC, sync_start); - msm_dp_write_link(panel, REG_DP_HSYNC_VSYNC_WIDTH_POLARITY, width_blanking); - msm_dp_write_link(panel, REG_DP_ACTIVE_HOR_VER, msm_dp_active); - - reg = msm_dp_read_p0(panel, MMSS_DP_INTF_CONFIG); + msm_dp_write_link(panel, + id > 1 ? REG_DP_MSTLINK_TOTAL_HOR_VER : + REG_DP_TOTAL_HOR_VER + offset, total); + msm_dp_write_link(panel, + id > 1 ? REG_DP_MSTLINK_START_HOR_VER_FROM_SYNC : + REG_DP_START_HOR_VER_FROM_SYNC + offset, sync_start); + msm_dp_write_link(panel, + id > 1 ? REG_DP_MSTLINK_HSYNC_VSYNC_WIDTH_POLARITY : + REG_DP_HSYNC_VSYNC_WIDTH_POLARITY + offset, width_blanking); + msm_dp_write_link(panel, + id > 1 ? REG_DP_MSTLINK_ACTIVE_HOR_VER : + REG_DP_ACTIVE_HOR_VER + offset, msm_dp_active); + + reg = msm_dp_read_pn(panel, MMSS_DP_INTF_CONFIG); if (wide_bus_en) reg |= DP_INTF_CONFIG_DATABUS_WIDEN; else @@ -598,7 +736,7 @@ int msm_dp_panel_timing_cfg(struct msm_dp_panel *msm_dp_panel, bool wide_bus_en) drm_dbg_dp(panel->drm_dev, "wide_bus_en=%d reg=%#x\n", wide_bus_en, reg); - msm_dp_write_p0(panel, MMSS_DP_INTF_CONFIG, reg); + msm_dp_write_pn(panel, MMSS_DP_INTF_CONFIG, reg); if (msm_dp_panel->msm_dp_mode.out_fmt_is_yuv_420) msm_dp_panel_setup_vsc_sdp_yuv_420(msm_dp_panel); @@ -608,6 +746,25 @@ int msm_dp_panel_timing_cfg(struct msm_dp_panel *msm_dp_panel, bool wide_bus_en) return 0; } +void msm_dp_panel_set_pixel_base(struct msm_dp_panel *msm_dp_panel, void __iomem *pixel_base) +{ + struct msm_dp_panel_private *panel = + container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); + panel->pixel_base = pixel_base; +} + +void msm_dp_panel_mst_async_fifo(struct msm_dp_panel *msm_dp_panel, bool mst_en) +{ + struct msm_dp_panel_private *panel; + + panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); + + if (mst_en) + msm_dp_write_pn(panel, MMSS_DP_ASYNC_FIFO_CONFIG, 0x01); + else + msm_dp_write_pn(panel, MMSS_DP_ASYNC_FIFO_CONFIG, 0x00); +} + int msm_dp_panel_init_panel_info(struct msm_dp_panel *msm_dp_panel) { struct drm_display_mode *drm_mode; @@ -650,7 +807,9 @@ int msm_dp_panel_init_panel_info(struct msm_dp_panel *msm_dp_panel) struct msm_dp_panel *msm_dp_panel_get(struct device *dev, struct drm_dp_aux *aux, struct msm_dp_link *link, void __iomem *link_base, - void __iomem *p0_base) + void __iomem *mst2link_base, + void __iomem *mst3link_base, + void __iomem *pixel_base) { struct msm_dp_panel_private *panel; struct msm_dp_panel *msm_dp_panel; @@ -668,7 +827,9 @@ struct msm_dp_panel *msm_dp_panel_get(struct device *dev, struct drm_dp_aux *aux panel->aux = aux; panel->link = link; panel->link_base = link_base; - panel->p0_base = p0_base; + panel->pixel_base = pixel_base; + panel->mst2link_base = mst2link_base; + panel->mst3link_base = mst3link_base; msm_dp_panel = &panel->msm_dp_panel; msm_dp_panel->max_bw_code = DP_LINK_BW_8_1; @@ -676,10 +837,3 @@ struct msm_dp_panel *msm_dp_panel_get(struct device *dev, struct drm_dp_aux *aux return msm_dp_panel; } -void msm_dp_panel_put(struct msm_dp_panel *msm_dp_panel) -{ - if (!msm_dp_panel) - return; - - drm_edid_free(msm_dp_panel->drm_edid); -} diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h index 921a296852d4d..8bab27520439c 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.h +++ b/drivers/gpu/drm/msm/dp/dp_panel.h @@ -27,13 +27,21 @@ struct msm_dp_panel_psr { u8 capabilities; }; +/* stream id */ +enum msm_dp_stream_id { + DP_STREAM_0, + DP_STREAM_1, + DP_STREAM_2, + DP_STREAM_3, + DP_STREAM_MAX, +}; + struct msm_dp_panel { /* dpcd raw data */ u8 dpcd[DP_RECEIVER_CAP_SIZE]; u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; struct msm_dp_link_info link_info; - const struct drm_edid *drm_edid; struct drm_connector *connector; struct msm_dp_display_mode msm_dp_mode; struct msm_dp_panel_psr psr_cap; @@ -41,31 +49,36 @@ struct msm_dp_panel { bool vsc_sdp_supported; u32 hw_revision; + enum msm_dp_stream_id stream_id; + u32 pbn; + u32 max_bw_code; }; int msm_dp_panel_init_panel_info(struct msm_dp_panel *msm_dp_panel); int msm_dp_panel_deinit(struct msm_dp_panel *msm_dp_panel); int msm_dp_panel_timing_cfg(struct msm_dp_panel *msm_dp_panel, bool wide_bus_en); -int msm_dp_panel_read_sink_caps(struct msm_dp_panel *msm_dp_panel, - struct drm_connector *connector); +int msm_dp_panel_read_link_caps(struct msm_dp_panel *msm_dp_panel, + struct drm_connector *connector); u32 msm_dp_panel_get_mode_bpp(struct msm_dp_panel *msm_dp_panel, u32 mode_max_bpp, u32 mode_pclk_khz); -int msm_dp_panel_get_modes(struct msm_dp_panel *msm_dp_panel, - struct drm_connector *connector); -void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel); +void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel, + const struct drm_edid *drm_edid); void msm_dp_panel_tpg_config(struct msm_dp_panel *msm_dp_panel, bool enable); void msm_dp_panel_clear_dsc_dto(struct msm_dp_panel *msm_dp_panel); +void msm_dp_panel_set_pixel_base(struct msm_dp_panel *msm_dp_panel, void __iomem *pixel_base); void msm_dp_panel_enable_vsc_sdp(struct msm_dp_panel *msm_dp_panel, struct dp_sdp *vsc_sdp); void msm_dp_panel_disable_vsc_sdp(struct msm_dp_panel *msm_dp_panel); +void msm_dp_panel_mst_async_fifo(struct msm_dp_panel *msm_dp_panel, bool mst_en); + /** * is_link_rate_valid() - validates the link rate - * @lane_rate: link rate requested by the sink + * @bw_code: link rate requested by the sink * - * Returns true if the requested link rate is supported. + * Returns: true if the requested link rate is supported. */ static inline bool is_link_rate_valid(u32 bw_code) { @@ -76,10 +89,10 @@ static inline bool is_link_rate_valid(u32 bw_code) } /** - * msm_dp_link_is_lane_count_valid() - validates the lane count + * is_lane_count_valid() - validates the lane count * @lane_count: lane count requested by the sink * - * Returns true if the requested lane count is supported. + * Returns: true if the requested lane count is supported. */ static inline bool is_lane_count_valid(u32 lane_count) { @@ -91,6 +104,7 @@ static inline bool is_lane_count_valid(u32 lane_count) struct msm_dp_panel *msm_dp_panel_get(struct device *dev, struct drm_dp_aux *aux, struct msm_dp_link *link, void __iomem *link_base, - void __iomem *p0_base); -void msm_dp_panel_put(struct msm_dp_panel *msm_dp_panel); + void __iomem *mst2link_base, + void __iomem *mst3link_base, + void __iomem *pixel_base); #endif /* _DP_PANEL_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h index 7c44d4e2cf139..65695fcb48d0f 100644 --- a/drivers/gpu/drm/msm/dp/dp_reg.h +++ b/drivers/gpu/drm/msm/dp/dp_reg.h @@ -42,9 +42,13 @@ #define DP_INTR_FRAME_END BIT(6) #define DP_INTR_CRC_UPDATED BIT(9) +#define DP_INTR_DP0_VCPF_SENT BIT(0) +#define DP_INTR_DP1_VCPF_SENT BIT(3) + #define REG_DP_INTR_STATUS3 (0x00000028) #define REG_DP_INTR_STATUS4 (0x0000002C) +#define REG_DP_INTR_STATUS5 (0x00000034) #define PSR_UPDATE_INT (0x00000001) #define PSR_CAPTURE_INT (0x00000004) #define PSR_EXIT_INT (0x00000010) @@ -68,8 +72,8 @@ #define DP_DP_IRQ_HPD_INT_ACK (0x00000002) #define DP_DP_HPD_REPLUG_INT_ACK (0x00000004) #define DP_DP_HPD_UNPLUG_INT_ACK (0x00000008) -#define DP_DP_HPD_STATE_STATUS_BITS_MASK (0x0000000F) -#define DP_DP_HPD_STATE_STATUS_BITS_SHIFT (0x1C) +#define DP_DP_HPD_STATE_STATUS_BITS_MASK (0x00000007) +#define DP_DP_HPD_STATE_STATUS_BITS_SHIFT (0x1D) #define REG_DP_DP_HPD_INT_MASK (0x0000000C) #define DP_DP_HPD_PLUG_INT_MASK (0x00000001) @@ -128,6 +132,10 @@ #define DP_MAINLINK_FLUSH_MODE_UPDATE_SDP FIELD_PREP(DP_MAINLINK_CTRL_FLUSH_MODE_MASK, 1) #define DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE FIELD_PREP(DP_MAINLINK_CTRL_FLUSH_MODE_MASK, 3) #define DP_MAINLINK_FB_BOUNDARY_SEL (0x02000000) +#define DP_MAINLINK_CTRL_ECF_MODE BIT(26) +#define DP_MAINLINK_CTRL_MST_ACTIVE BIT(8) +#define DP_MAINLINK_CTRL_MST_EN (DP_MAINLINK_CTRL_ECF_MODE | \ + DP_MAINLINK_CTRL_MST_ACTIVE) #define REG_DP_STATE_CTRL (0x00000004) #define DP_STATE_CTRL_LINK_TRAINING_PATTERN1 (0x00000001) @@ -156,13 +164,14 @@ #define DP_CONFIGURATION_CTRL_BPC_SHIFT (0x08) #define DP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT (0x0D) +#define REG_DP_MST_ACT (0x00000500) + #define REG_DP_SOFTWARE_MVID (0x00000010) #define REG_DP_SOFTWARE_NVID (0x00000018) #define REG_DP_TOTAL_HOR_VER (0x0000001C) #define REG_DP_START_HOR_VER_FROM_SYNC (0x00000020) #define REG_DP_HSYNC_VSYNC_WIDTH_POLARITY (0x00000024) #define REG_DP_ACTIVE_HOR_VER (0x00000028) - #define REG_DP_MISC1_MISC0 (0x0000002C) #define DP_MISC0_SYNCHRONOUS_CLK (0x00000001) #define DP_MISC0_COLORIMETRY_CFG_SHIFT (0x00000001) @@ -332,6 +341,43 @@ #define DP_TPG_VIDEO_CONFIG_BPP_8BIT (0x00000001) #define DP_TPG_VIDEO_CONFIG_RGB (0x00000004) +/* DP MST registers */ + +#define REG_DP_MSTLINK_DP_RG (0X0000011C) +#define REG_DP1_CONFIGURATION_CTRL (0x00000400) +#define REG_DP_DP0_TIMESLOT_1_32 (0x00000404) +#define REG_DP_DP0_TIMESLOT_33_63 (0x00000408) +#define REG_DP_DP1_TIMESLOT_1_32 (0x0000040C) +#define REG_DP_DP1_TIMESLOT_33_63 (0x00000410) +#define REG_DP1_SOFTWARE_MVID (0x00000414) +#define REG_DP1_SOFTWARE_NVID (0x00000418) +#define REG_DP1_TOTAL_HOR_VER (0x0000041C) +#define REG_DP1_MISC1_MISC0 (0x0000042C) +#define MMSS_DP1_GENERIC0_0 (0x00000490) +#define MMSS_DP1_SDP_CFG (0x000004E0) +#define MMSS_DP1_SDP_CFG2 (0x000004E4) +#define MMSS_DP1_SDP_CFG3 (0x000004E8) +#define REG_DP_DP0_RG (0x000004F8) +#define REG_DP_DP1_RG (0x000004FC) + +#define REG_DP_MSTLINK_STATE_CTRL (0x00000000) +#define REG_DP_MSTLINK_CONFIGURATION_CTRL (0x00000034) +#define REG_DP_MSTLINK_TIMESLOT_1_32 (0x00000038) +#define REG_DP_MSTLINK_TIMESLOT_33_63 (0x0000003C) +#define REG_MSTLINK_SOFTWARE_MVID (0x00000040) +#define REG_MSTLINK_SOFTWARE_NVID (0x00000044) +#define REG_DP_MSTLINK_TOTAL_HOR_VER (0x00000048) +#define REG_DP_MSTLINK_START_HOR_VER_FROM_SYNC (0x0000004C) +#define REG_DP_MSTLINK_HSYNC_VSYNC_WIDTH_POLARITY (0x00000050) +#define REG_DP_MSTLINK_ACTIVE_HOR_VER (0x00000054) +#define REG_DP_MSTLINK_MISC1_MISC0 (0x00000058) +#define MMSS_DP_MSTLINK_GENERIC0_0 (0x000000BC) +#define MMSS_DP_MSTLINK_GENERIC0_1 (0x000000C0) +#define MMSS_DP_MSTLINK_GENERIC0_2 (0x000000C4) +#define MMSS_DP_MSTLINK_SDP_CFG (0x0000010c) +#define MMSS_DP_MSTLINK_SDP_CFG2 (0x0000011c) +#define MMSS_DP_MSTLINK_SDP_CFG3 (0x00000114) + #define MMSS_DP_ASYNC_FIFO_CONFIG (0x00000088) #define REG_DP_PHY_AUX_INTERRUPT_CLEAR (0x0000004C) diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index d8bb40ef820e2..3c9f01ed62713 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -198,6 +198,7 @@ static const struct of_device_id dt_match[] = { { .compatible = "qcom,dsi-ctrl-6g-qcm2290" }, {} }; +MODULE_DEVICE_TABLE(of, dt_match); static const struct dev_pm_ops dsi_pm_ops = { SET_RUNTIME_PM_OPS(msm_dsi_runtime_suspend, msm_dsi_runtime_resume, NULL) diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index fed8e9b67011c..bd3c51c350e73 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -205,6 +205,17 @@ static const struct msm_dsi_config sm8650_dsi_cfg = { }, }; +static const struct msm_dsi_config kaanapali_dsi_cfg = { + .io_offset = DSI_6G_REG_SHIFT, + .regulator_data = sm8650_dsi_regulators, + .num_regulators = ARRAY_SIZE(sm8650_dsi_regulators), + .bus_clk_names = dsi_v2_4_clk_names, + .num_bus_clks = ARRAY_SIZE(dsi_v2_4_clk_names), + .io_start = { + { 0x9ac0000, 0x9ac3000 }, + }, +}; + static const struct regulator_bulk_data sc7280_dsi_regulators[] = { { .supply = "vdda", .init_load_uA = 8350 }, /* 1.2 V */ { .supply = "refgen" }, @@ -332,6 +343,8 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { &sm8650_dsi_cfg, &msm_dsi_6g_v2_host_ops}, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_9_0, &sm8650_dsi_cfg, &msm_dsi_6g_v2_9_host_ops}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_10_0, + &kaanapali_dsi_cfg, &msm_dsi_6g_v2_9_host_ops}, }; const struct msm_dsi_cfg_handler *msm_dsi_cfg_get(u32 major, u32 minor) diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.h b/drivers/gpu/drm/msm/dsi/dsi_cfg.h index 38f303f2ed04c..5dc812028bd54 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h @@ -32,6 +32,7 @@ #define MSM_DSI_6G_VER_MINOR_V2_7_0 0x20070000 #define MSM_DSI_6G_VER_MINOR_V2_8_0 0x20080000 #define MSM_DSI_6G_VER_MINOR_V2_9_0 0x20090000 +#define MSM_DSI_6G_VER_MINOR_V2_10_0 0x200a0000 #define MSM_DSI_V2_VER_MINOR_8064 0x0 diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 4ea681130dbaf..c59375aaae197 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -577,9 +577,12 @@ static const struct of_device_id dsi_phy_dt_match[] = { .data = &dsi_phy_4nm_8650_cfgs }, { .compatible = "qcom,sm8750-dsi-phy-3nm", .data = &dsi_phy_3nm_8750_cfgs }, + { .compatible = "qcom,kaanapali-dsi-phy-3nm", + .data = &dsi_phy_3nm_kaanapali_cfgs }, #endif {} }; +MODULE_DEVICE_TABLE(of, dsi_phy_dt_match); /* * Currently, we only support one SoC for each PHY type. When we have multiple diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index 3cbf082314924..c01784ca38edc 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -64,6 +64,7 @@ extern const struct msm_dsi_phy_cfg dsi_phy_5nm_sar2130p_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_4nm_8550_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_4nm_8650_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_3nm_8750_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_3nm_kaanapali_cfgs; struct msm_dsi_dphy_timing { u32 clk_zero; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c index 4033809ff8237..1cc4061465cd6 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c @@ -1510,3 +1510,26 @@ const struct msm_dsi_phy_cfg dsi_phy_3nm_8750_cfgs = { .num_dsi_phy = 2, .quirks = DSI_PHY_7NM_QUIRK_V7_0, }; + +const struct msm_dsi_phy_cfg dsi_phy_3nm_kaanapali_cfgs = { + .has_phy_lane = true, + .regulator_data = dsi_phy_7nm_98000uA_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_7nm_98000uA_regulators), + .ops = { + .enable = dsi_7nm_phy_enable, + .disable = dsi_7nm_phy_disable, + .pll_init = dsi_pll_7nm_init, + .save_pll_state = dsi_7nm_pll_save_state, + .restore_pll_state = dsi_7nm_pll_restore_state, + .set_continuous_clock = dsi_7nm_set_continuous_clock, + }, + .min_pll_rate = 600000000UL, +#ifdef CONFIG_64BIT + .max_pll_rate = 5000000000UL, +#else + .max_pll_rate = ULONG_MAX, +#endif + .io_start = { 0x9ac1000, 0x9ac4000 }, + .num_dsi_phy = 2, + .quirks = DSI_PHY_7NM_QUIRK_V7_0, +}; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 5afac09c0d334..d5ef5089c9e9c 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -441,6 +441,7 @@ static const struct of_device_id msm_hdmi_dt_match[] = { { .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8960_config }, {} }; +MODULE_DEVICE_TABLE(of, msm_hdmi_dt_match); static struct platform_driver msm_hdmi_driver = { .probe = msm_hdmi_dev_probe, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c index 667573f1db7c6..f726555bb6810 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c @@ -204,6 +204,7 @@ static const struct of_device_id msm_hdmi_phy_dt_match[] = { .data = &msm_hdmi_phy_8998_cfg }, {} }; +MODULE_DEVICE_TABLE(of, msm_hdmi_phy_dt_match); static struct platform_driver msm_hdmi_phy_platform_driver = { .probe = msm_hdmi_phy_probe, diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 87a91148a731d..ea064aa6d8fc1 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -4,6 +4,7 @@ * Author: Rob Clark */ +#include #include #include @@ -207,7 +208,11 @@ int msm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) if (ret) return ret; - return drm_atomic_helper_check(dev, state); + ret = drm_atomic_helper_check(dev, state); + if (ret) + return ret; + + return drm_dp_mst_atomic_check(state); } void msm_atomic_commit_tail(struct drm_atomic_state *state) @@ -221,6 +226,8 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state) trace_msm_atomic_commit_tail_start(async, crtc_mask); + drm_dp_mst_atomic_wait_for_dependencies(state); + kms->funcs->enable_commit(kms); /* diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 44be401444569..111007a241717 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -362,6 +362,9 @@ bool msm_dp_is_yuv_420_enabled(const struct msm_dp *dp_display, bool msm_dp_needs_periph_flush(const struct msm_dp *dp_display, const struct drm_display_mode *mode); bool msm_dp_wide_bus_available(const struct msm_dp *dp_display); +int msm_dp_get_mst_max_stream(struct msm_dp *dp_display); +int msm_dp_mst_register(struct msm_dp *dp_display); +int msm_dp_mst_attach_encoder(struct msm_dp *dp_display, struct drm_encoder *encoder); #else static inline int __init msm_dp_register(void) @@ -379,6 +382,21 @@ static inline int msm_dp_modeset_init(struct msm_dp *dp_display, return -EINVAL; } +static inline int msm_dp_get_mst_max_stream(struct msm_dp *dp_display) +{ + return -EINVAL; +} + +static inline int msm_dp_mst_register(struct msm_dp *dp_display) +{ + return -EINVAL; +} + +static inline int msm_dp_mst_attach_encoder(struct msm_dp *dp_display, struct drm_encoder *encoder) +{ + return -EINVAL; +} + static inline void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_display) { } diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index dd0605fe1243d..995549d0bbbc5 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -197,8 +197,7 @@ static ssize_t msm_gpu_devcoredump_read(char *buffer, loff_t offset, drm_printf(&p, "---\n"); drm_printf(&p, "kernel: " UTS_RELEASE "\n"); drm_printf(&p, "module: " KBUILD_MODNAME "\n"); - drm_printf(&p, "time: %lld.%09ld\n", - state->time.tv_sec, state->time.tv_nsec); + drm_printf(&p, "time: %ptSp\n", &state->time); if (state->comm) drm_printf(&p, "comm: %s\n", state->comm); if (state->cmd) diff --git a/drivers/gpu/drm/msm/msm_kms.c b/drivers/gpu/drm/msm/msm_kms.c index 6e5e94f5c9a74..a4f339db3a754 100644 --- a/drivers/gpu/drm/msm/msm_kms.c +++ b/drivers/gpu/drm/msm/msm_kms.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -29,6 +30,7 @@ static const struct drm_mode_config_funcs mode_config_funcs = { static const struct drm_mode_config_helper_funcs mode_config_helper_funcs = { .atomic_commit_tail = msm_atomic_commit_tail, + .atomic_commit_setup = drm_dp_mst_atomic_setup_commit, }; static irqreturn_t msm_irq(int irq, void *arg) diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c index 6de0e9d796c18..1c09796163b09 100644 --- a/drivers/soc/qcom/ubwc_config.c +++ b/drivers/soc/qcom/ubwc_config.c @@ -16,6 +16,16 @@ static const struct qcom_ubwc_cfg_data no_ubwc_data = { /* no UBWC, no HBB */ }; +static const struct qcom_ubwc_cfg_data kaanapali_data = { + .ubwc_enc_version = UBWC_6_0, + .ubwc_dec_version = UBWC_6_0, + .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | + UBWC_SWIZZLE_ENABLE_LVL3, + .ubwc_bank_spread = true, + .highest_bank_bit = 16, + .macrotile_mode = true, +}; + static const struct qcom_ubwc_cfg_data msm8937_data = { .ubwc_enc_version = UBWC_1_0, .ubwc_dec_version = UBWC_1_0, @@ -218,11 +228,24 @@ static const struct qcom_ubwc_cfg_data x1e80100_data = { .macrotile_mode = true, }; +static const struct qcom_ubwc_cfg_data glymur_data = { + .ubwc_enc_version = UBWC_5_0, + .ubwc_dec_version = UBWC_5_0, + .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | + UBWC_SWIZZLE_ENABLE_LVL3, + .ubwc_bank_spread = true, + /* TODO: highest_bank_bit = 15 for LP_DDR4 */ + .highest_bank_bit = 16, + .macrotile_mode = true, +}; + static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = { { .compatible = "qcom,apq8016", .data = &no_ubwc_data }, { .compatible = "qcom,apq8026", .data = &no_ubwc_data }, { .compatible = "qcom,apq8074", .data = &no_ubwc_data }, { .compatible = "qcom,apq8096", .data = &msm8998_data }, + { .compatible = "qcom,kaanapali", .data = &kaanapali_data, }, + { .compatible = "qcom,glymur", .data = &glymur_data}, { .compatible = "qcom,msm8226", .data = &no_ubwc_data }, { .compatible = "qcom,msm8916", .data = &no_ubwc_data }, { .compatible = "qcom,msm8917", .data = &no_ubwc_data }, diff --git a/include/linux/soc/qcom/ubwc.h b/include/linux/soc/qcom/ubwc.h index d9dfc9edc1b2f..f052e241736c4 100644 --- a/include/linux/soc/qcom/ubwc.h +++ b/include/linux/soc/qcom/ubwc.h @@ -53,6 +53,7 @@ struct qcom_ubwc_cfg_data { #define UBWC_4_0 0x40000000 #define UBWC_4_3 0x40030000 #define UBWC_5_0 0x50000000 +#define UBWC_6_0 0x60000000 #if IS_ENABLED(CONFIG_QCOM_UBWC_CONFIG) const struct qcom_ubwc_cfg_data *qcom_ubwc_config_get_data(void);