Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/msm/dpu: Reserve resources for CWB

Add support for RM to reserve dedicated CWB PINGPONGs and CWB muxes

For concurrent writeback, even-indexed CWB muxes must be assigned to
even-indexed LMs and odd-indexed CWB muxes for odd-indexed LMs. The same
even/odd rule applies for dedicated CWB PINGPONGs.

Track the CWB muxes in the global state and add a CWB-specific helper to
reserve the correct CWB muxes and dedicated PINGPONGs following the
even/odd rule.

Signed-off-by: Jessica Zhang <quic_jesszhan@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Patchwork: https://patchwork.freedesktop.org/patch/637495/
Link: https://lore.kernel.org/r/20250214-concurrent-wb-v6-7-a44c293cf422@quicinc.com
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>

authored by

Jessica Zhang and committed by
Dmitry Baryshkov
50083754 f1f0379e

+120 -4
+30 -4
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
··· 2 2 /* 3 3 * Copyright (C) 2013 Red Hat 4 4 * Copyright (c) 2014-2018, 2020-2021 The Linux Foundation. All rights reserved. 5 - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 5 + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. 6 6 * 7 7 * Author: Rob Clark <robdclark@gmail.com> 8 8 */ ··· 28 28 #include "dpu_hw_dsc.h" 29 29 #include "dpu_hw_merge3d.h" 30 30 #include "dpu_hw_cdm.h" 31 + #include "dpu_hw_cwb.h" 31 32 #include "dpu_formats.h" 32 33 #include "dpu_encoder_phys.h" 33 34 #include "dpu_crtc.h" ··· 134 133 * @cur_slave: As above but for the slave encoder. 135 134 * @hw_pp: Handle to the pingpong blocks used for the display. No. 136 135 * pingpong blocks can be different than num_phys_encs. 136 + * @hw_cwb: Handle to the CWB muxes used for concurrent writeback 137 + * display. Number of CWB muxes can be different than 138 + * num_phys_encs. 137 139 * @hw_dsc: Handle to the DSC blocks used for the display. 138 140 * @dsc_mask: Bitmask of used DSC blocks. 139 141 * @intfs_swapped: Whether or not the phys_enc interfaces have been swapped ··· 181 177 struct dpu_encoder_phys *cur_master; 182 178 struct dpu_encoder_phys *cur_slave; 183 179 struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC]; 180 + struct dpu_hw_cwb *hw_cwb[MAX_CHANNELS_PER_ENC]; 184 181 struct dpu_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC]; 185 182 186 183 unsigned int dsc_mask; ··· 1154 1149 struct dpu_hw_blk *hw_pp[MAX_CHANNELS_PER_ENC]; 1155 1150 struct dpu_hw_blk *hw_ctl[MAX_CHANNELS_PER_ENC]; 1156 1151 struct dpu_hw_blk *hw_dsc[MAX_CHANNELS_PER_ENC]; 1152 + struct dpu_hw_blk *hw_cwb[MAX_CHANNELS_PER_ENC]; 1157 1153 int num_ctl, num_pp, num_dsc; 1154 + int num_cwb = 0; 1155 + bool is_cwb_encoder; 1158 1156 unsigned int dsc_mask = 0; 1159 1157 int i; 1160 1158 ··· 1171 1163 1172 1164 priv = drm_enc->dev->dev_private; 1173 1165 dpu_kms = to_dpu_kms(priv->kms); 1166 + is_cwb_encoder = drm_crtc_in_clone_mode(crtc_state) && 1167 + dpu_enc->disp_info.intf_type == INTF_WB; 1174 1168 1175 1169 global_state = dpu_kms_get_existing_global_state(dpu_kms); 1176 1170 if (IS_ERR_OR_NULL(global_state)) { ··· 1183 1173 trace_dpu_enc_mode_set(DRMID(drm_enc)); 1184 1174 1185 1175 /* Query resource that have been reserved in atomic check step. */ 1186 - num_pp = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, 1187 - drm_enc->crtc, DPU_HW_BLK_PINGPONG, hw_pp, 1188 - ARRAY_SIZE(hw_pp)); 1176 + if (is_cwb_encoder) { 1177 + num_pp = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, 1178 + drm_enc->crtc, 1179 + DPU_HW_BLK_DCWB_PINGPONG, 1180 + hw_pp, ARRAY_SIZE(hw_pp)); 1181 + num_cwb = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, 1182 + drm_enc->crtc, 1183 + DPU_HW_BLK_CWB, 1184 + hw_cwb, ARRAY_SIZE(hw_cwb)); 1185 + } else { 1186 + num_pp = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, 1187 + drm_enc->crtc, 1188 + DPU_HW_BLK_PINGPONG, hw_pp, 1189 + ARRAY_SIZE(hw_pp)); 1190 + } 1191 + 1192 + for (i = 0; i < num_cwb; i++) 1193 + dpu_enc->hw_cwb[i] = to_dpu_hw_cwb(hw_cwb[i]); 1194 + 1189 1195 num_ctl = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, 1190 1196 drm_enc->crtc, DPU_HW_BLK_CTL, hw_ctl, ARRAY_SIZE(hw_ctl)); 1191 1197
+2
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
··· 77 77 DPU_HW_BLK_LM, 78 78 DPU_HW_BLK_CTL, 79 79 DPU_HW_BLK_PINGPONG, 80 + DPU_HW_BLK_DCWB_PINGPONG, 80 81 DPU_HW_BLK_INTF, 81 82 DPU_HW_BLK_WB, 82 83 DPU_HW_BLK_DSPP, 83 84 DPU_HW_BLK_MERGE_3D, 84 85 DPU_HW_BLK_DSC, 85 86 DPU_HW_BLK_CDM, 87 + DPU_HW_BLK_CWB, 86 88 DPU_HW_BLK_MAX, 87 89 }; 88 90
+1
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
··· 132 132 uint32_t cdm_to_crtc_id; 133 133 134 134 uint32_t sspp_to_crtc_id[SSPP_MAX - SSPP_NONE]; 135 + uint32_t cwb_to_crtc_id[CWB_MAX - CWB_0]; 135 136 }; 136 137 137 138 struct dpu_global_state
+87
drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
··· 233 233 return -EINVAL; 234 234 } 235 235 236 + static int _dpu_rm_reserve_cwb_mux_and_pingpongs(struct dpu_rm *rm, 237 + struct dpu_global_state *global_state, 238 + uint32_t crtc_id, 239 + struct msm_display_topology *topology) 240 + { 241 + int num_cwb_mux = topology->num_lm, cwb_mux_count = 0; 242 + int cwb_pp_start_idx = PINGPONG_CWB_0 - PINGPONG_0; 243 + int cwb_pp_idx[MAX_BLOCKS]; 244 + int cwb_mux_idx[MAX_BLOCKS]; 245 + 246 + /* 247 + * Reserve additional dedicated CWB PINGPONG blocks and muxes for each 248 + * mixer 249 + * 250 + * TODO: add support reserving resources for platforms with no 251 + * PINGPONG_CWB 252 + */ 253 + for (int i = 0; i < ARRAY_SIZE(rm->mixer_blks) && 254 + cwb_mux_count < num_cwb_mux; i++) { 255 + for (int j = 0; j < ARRAY_SIZE(rm->cwb_blks); j++) { 256 + /* 257 + * Odd LMs must be assigned to odd CWB muxes and even 258 + * LMs with even CWB muxes. 259 + * 260 + * Since the RM HW block array index is based on the HW 261 + * block ids, we can also use the array index to enforce 262 + * the odd/even rule. See dpu_rm_init() for more 263 + * information 264 + */ 265 + if (reserved_by_other(global_state->cwb_to_crtc_id, j, crtc_id) || 266 + i % 2 != j % 2) 267 + continue; 268 + 269 + cwb_mux_idx[cwb_mux_count] = j; 270 + cwb_pp_idx[cwb_mux_count] = j + cwb_pp_start_idx; 271 + cwb_mux_count++; 272 + break; 273 + } 274 + } 275 + 276 + if (cwb_mux_count != num_cwb_mux) { 277 + DPU_ERROR("Unable to reserve all CWB PINGPONGs\n"); 278 + return -ENAVAIL; 279 + } 280 + 281 + for (int i = 0; i < cwb_mux_count; i++) { 282 + global_state->pingpong_to_crtc_id[cwb_pp_idx[i]] = crtc_id; 283 + global_state->cwb_to_crtc_id[cwb_mux_idx[i]] = crtc_id; 284 + } 285 + 286 + return 0; 287 + } 288 + 236 289 /** 237 290 * _dpu_rm_check_lm_and_get_connected_blks - check if proposed layer mixer meets 238 291 * proposed use case requirements, incl. hardwired dependent blocks like ··· 676 623 return ret; 677 624 } 678 625 626 + if (topology->cwb_enabled) { 627 + ret = _dpu_rm_reserve_cwb_mux_and_pingpongs(rm, global_state, 628 + crtc_id, topology); 629 + if (ret) 630 + return ret; 631 + } 679 632 680 633 ret = _dpu_rm_reserve_ctls(rm, global_state, crtc_id, 681 634 topology); ··· 739 680 _dpu_rm_clear_mapping(global_state->dspp_to_crtc_id, 740 681 ARRAY_SIZE(global_state->dspp_to_crtc_id), crtc_id); 741 682 _dpu_rm_clear_mapping(&global_state->cdm_to_crtc_id, 1, crtc_id); 683 + _dpu_rm_clear_mapping(global_state->cwb_to_crtc_id, 684 + ARRAY_SIZE(global_state->cwb_to_crtc_id), crtc_id); 742 685 } 743 686 744 687 /** ··· 885 824 886 825 switch (type) { 887 826 case DPU_HW_BLK_PINGPONG: 827 + case DPU_HW_BLK_DCWB_PINGPONG: 888 828 hw_blks = rm->pingpong_blks; 889 829 hw_to_crtc_id = global_state->pingpong_to_crtc_id; 890 830 max_blks = ARRAY_SIZE(rm->pingpong_blks); ··· 915 853 hw_to_crtc_id = &global_state->cdm_to_crtc_id; 916 854 max_blks = 1; 917 855 break; 856 + case DPU_HW_BLK_CWB: 857 + hw_blks = rm->cwb_blks; 858 + hw_to_crtc_id = global_state->cwb_to_crtc_id; 859 + max_blks = ARRAY_SIZE(rm->cwb_blks); 860 + break; 918 861 default: 919 862 DPU_ERROR("blk type %d not managed by rm\n", type); 920 863 return 0; ··· 929 862 for (i = 0; i < max_blks; i++) { 930 863 if (hw_to_crtc_id[i] != crtc_id) 931 864 continue; 865 + 866 + if (type == DPU_HW_BLK_PINGPONG) { 867 + struct dpu_hw_pingpong *pp = to_dpu_hw_pingpong(hw_blks[i]); 868 + 869 + if (pp->idx >= PINGPONG_CWB_0) 870 + continue; 871 + } 872 + 873 + if (type == DPU_HW_BLK_DCWB_PINGPONG) { 874 + struct dpu_hw_pingpong *pp = to_dpu_hw_pingpong(hw_blks[i]); 875 + 876 + if (pp->idx < PINGPONG_CWB_0) 877 + continue; 878 + } 932 879 933 880 if (num_blks == blks_size) { 934 881 DPU_ERROR("More than %d resources assigned to crtc %d\n", ··· 1025 944 for (i = SSPP_NONE + 1; i < ARRAY_SIZE(global_state->sspp_to_crtc_id); i++) 1026 945 dpu_rm_print_state_helper(p, rm->hw_sspp[i] ? &rm->hw_sspp[i]->base : NULL, 1027 946 global_state->sspp_to_crtc_id[i]); 947 + drm_puts(p, "\n"); 948 + 949 + drm_puts(p, "\tcwb="); 950 + for (i = 0; i < ARRAY_SIZE(global_state->cwb_to_crtc_id); i++) 951 + dpu_rm_print_state_helper(p, rm->cwb_blks[i], 952 + global_state->cwb_to_crtc_id[i]); 1028 953 drm_puts(p, "\n"); 1029 954 }