Commit 50083754 authored by Jessica Zhang's avatar Jessica Zhang Committed by Dmitry Baryshkov
Browse files

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: default avatarJessica Zhang <quic_jesszhan@quicinc.com>
Reviewed-by: default avatarDmitry 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: default avatarDmitry Baryshkov <dmitry.baryshkov@linaro.org>
parent f1f0379e
Loading
Loading
Loading
Loading
+30 −4
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
/*
 * Copyright (C) 2013 Red Hat
 * Copyright (c) 2014-2018, 2020-2021 The Linux Foundation. All rights reserved.
 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
 *
 * Author: Rob Clark <robdclark@gmail.com>
 */
@@ -28,6 +28,7 @@
#include "dpu_hw_dsc.h"
#include "dpu_hw_merge3d.h"
#include "dpu_hw_cdm.h"
#include "dpu_hw_cwb.h"
#include "dpu_formats.h"
#include "dpu_encoder_phys.h"
#include "dpu_crtc.h"
@@ -133,6 +134,9 @@ enum dpu_enc_rc_states {
 * @cur_slave:		As above but for the slave encoder.
 * @hw_pp:		Handle to the pingpong blocks used for the display. No.
 *			pingpong blocks can be different than num_phys_encs.
 * @hw_cwb:		Handle to the CWB muxes used for concurrent writeback
 *			display. Number of CWB muxes can be different than
 *			num_phys_encs.
 * @hw_dsc:		Handle to the DSC blocks used for the display.
 * @dsc_mask:		Bitmask of used DSC blocks.
 * @intfs_swapped:	Whether or not the phys_enc interfaces have been swapped
@@ -177,6 +181,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_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];

	unsigned int dsc_mask;
@@ -1149,7 +1154,10 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
	struct dpu_hw_blk *hw_pp[MAX_CHANNELS_PER_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_cwb = 0;
	bool is_cwb_encoder;
	unsigned int dsc_mask = 0;
	int i;

@@ -1163,6 +1171,8 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,

	priv = drm_enc->dev->dev_private;
	dpu_kms = to_dpu_kms(priv->kms);
	is_cwb_encoder = drm_crtc_in_clone_mode(crtc_state) &&
			dpu_enc->disp_info.intf_type == INTF_WB;

	global_state = dpu_kms_get_existing_global_state(dpu_kms);
	if (IS_ERR_OR_NULL(global_state)) {
@@ -1173,9 +1183,25 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
	trace_dpu_enc_mode_set(DRMID(drm_enc));

	/* Query resource that have been reserved in atomic check step. */
	if (is_cwb_encoder) {
		num_pp = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
		drm_enc->crtc, DPU_HW_BLK_PINGPONG, hw_pp,
						       drm_enc->crtc,
						       DPU_HW_BLK_DCWB_PINGPONG,
						       hw_pp, ARRAY_SIZE(hw_pp));
		num_cwb = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
						       drm_enc->crtc,
						       DPU_HW_BLK_CWB,
						       hw_cwb, ARRAY_SIZE(hw_cwb));
	} else {
		num_pp = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
						       drm_enc->crtc,
						       DPU_HW_BLK_PINGPONG, hw_pp,
						       ARRAY_SIZE(hw_pp));
	}

	for (i = 0; i < num_cwb; i++)
		dpu_enc->hw_cwb[i] = to_dpu_hw_cwb(hw_cwb[i]);

	num_ctl = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
		drm_enc->crtc, DPU_HW_BLK_CTL, hw_ctl, ARRAY_SIZE(hw_ctl));

+2 −0
Original line number Diff line number Diff line
@@ -77,12 +77,14 @@ enum dpu_hw_blk_type {
	DPU_HW_BLK_LM,
	DPU_HW_BLK_CTL,
	DPU_HW_BLK_PINGPONG,
	DPU_HW_BLK_DCWB_PINGPONG,
	DPU_HW_BLK_INTF,
	DPU_HW_BLK_WB,
	DPU_HW_BLK_DSPP,
	DPU_HW_BLK_MERGE_3D,
	DPU_HW_BLK_DSC,
	DPU_HW_BLK_CDM,
	DPU_HW_BLK_CWB,
	DPU_HW_BLK_MAX,
};

+1 −0
Original line number Diff line number Diff line
@@ -132,6 +132,7 @@ struct dpu_global_state {
	uint32_t cdm_to_crtc_id;

	uint32_t sspp_to_crtc_id[SSPP_MAX - SSPP_NONE];
	uint32_t cwb_to_crtc_id[CWB_MAX - CWB_0];
};

struct dpu_global_state
+87 −0
Original line number Diff line number Diff line
@@ -233,6 +233,59 @@ static int _dpu_rm_get_lm_peer(struct dpu_rm *rm, int primary_idx)
	return -EINVAL;
}

static int _dpu_rm_reserve_cwb_mux_and_pingpongs(struct dpu_rm *rm,
						 struct dpu_global_state *global_state,
						 uint32_t crtc_id,
						 struct msm_display_topology *topology)
{
	int num_cwb_mux = topology->num_lm, cwb_mux_count = 0;
	int cwb_pp_start_idx = PINGPONG_CWB_0 - PINGPONG_0;
	int cwb_pp_idx[MAX_BLOCKS];
	int cwb_mux_idx[MAX_BLOCKS];

	/*
	 * Reserve additional dedicated CWB PINGPONG blocks and muxes for each
	 * mixer
	 *
	 * TODO: add support reserving resources for platforms with no
	 *       PINGPONG_CWB
	 */
	for (int i = 0; i < ARRAY_SIZE(rm->mixer_blks) &&
	     cwb_mux_count < num_cwb_mux; i++) {
		for (int j = 0; j < ARRAY_SIZE(rm->cwb_blks); j++) {
			/*
			 * Odd LMs must be assigned to odd CWB muxes and even
			 * LMs with even CWB muxes.
			 *
			 * Since the RM HW block array index is based on the HW
			 * block ids, we can also use the array index to enforce
			 * the odd/even rule. See dpu_rm_init() for more
			 * information
			 */
			if (reserved_by_other(global_state->cwb_to_crtc_id, j, crtc_id) ||
			    i % 2 != j % 2)
				continue;

			cwb_mux_idx[cwb_mux_count] = j;
			cwb_pp_idx[cwb_mux_count] = j + cwb_pp_start_idx;
			cwb_mux_count++;
			break;
		}
	}

	if (cwb_mux_count != num_cwb_mux) {
		DPU_ERROR("Unable to reserve all CWB PINGPONGs\n");
		return -ENAVAIL;
	}

	for (int i = 0; i < cwb_mux_count; i++) {
		global_state->pingpong_to_crtc_id[cwb_pp_idx[i]] = crtc_id;
		global_state->cwb_to_crtc_id[cwb_mux_idx[i]] = crtc_id;
	}

	return 0;
}

/**
 * _dpu_rm_check_lm_and_get_connected_blks - check if proposed layer mixer meets
 *	proposed use case requirements, incl. hardwired dependent blocks like
@@ -623,6 +676,12 @@ static int _dpu_rm_make_reservation(
		return ret;
	}

	if (topology->cwb_enabled) {
		ret = _dpu_rm_reserve_cwb_mux_and_pingpongs(rm, global_state,
							    crtc_id, topology);
		if (ret)
			return ret;
	}

	ret = _dpu_rm_reserve_ctls(rm, global_state, crtc_id,
			topology);
@@ -680,6 +739,8 @@ void dpu_rm_release(struct dpu_global_state *global_state,
	_dpu_rm_clear_mapping(global_state->dspp_to_crtc_id,
			ARRAY_SIZE(global_state->dspp_to_crtc_id), crtc_id);
	_dpu_rm_clear_mapping(&global_state->cdm_to_crtc_id, 1, crtc_id);
	_dpu_rm_clear_mapping(global_state->cwb_to_crtc_id,
			ARRAY_SIZE(global_state->cwb_to_crtc_id), crtc_id);
}

/**
@@ -824,6 +885,7 @@ int dpu_rm_get_assigned_resources(struct dpu_rm *rm,

	switch (type) {
	case DPU_HW_BLK_PINGPONG:
	case DPU_HW_BLK_DCWB_PINGPONG:
		hw_blks = rm->pingpong_blks;
		hw_to_crtc_id = global_state->pingpong_to_crtc_id;
		max_blks = ARRAY_SIZE(rm->pingpong_blks);
@@ -853,6 +915,11 @@ int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
		hw_to_crtc_id = &global_state->cdm_to_crtc_id;
		max_blks = 1;
		break;
	case DPU_HW_BLK_CWB:
		hw_blks = rm->cwb_blks;
		hw_to_crtc_id = global_state->cwb_to_crtc_id;
		max_blks = ARRAY_SIZE(rm->cwb_blks);
		break;
	default:
		DPU_ERROR("blk type %d not managed by rm\n", type);
		return 0;
@@ -863,6 +930,20 @@ int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
		if (hw_to_crtc_id[i] != crtc_id)
			continue;

		if (type == DPU_HW_BLK_PINGPONG) {
			struct dpu_hw_pingpong *pp = to_dpu_hw_pingpong(hw_blks[i]);

			if (pp->idx >= PINGPONG_CWB_0)
				continue;
		}

		if (type == DPU_HW_BLK_DCWB_PINGPONG) {
			struct dpu_hw_pingpong *pp = to_dpu_hw_pingpong(hw_blks[i]);

			if (pp->idx < PINGPONG_CWB_0)
				continue;
		}

		if (num_blks == blks_size) {
			DPU_ERROR("More than %d resources assigned to crtc %d\n",
				  blks_size, crtc_id);
@@ -945,4 +1026,10 @@ void dpu_rm_print_state(struct drm_printer *p,
		dpu_rm_print_state_helper(p, rm->hw_sspp[i] ? &rm->hw_sspp[i]->base : NULL,
					  global_state->sspp_to_crtc_id[i]);
	drm_puts(p, "\n");

	drm_puts(p, "\tcwb=");
	for (i = 0; i < ARRAY_SIZE(global_state->cwb_to_crtc_id); i++)
		dpu_rm_print_state_helper(p, rm->cwb_blks[i],
					  global_state->cwb_to_crtc_id[i]);
	drm_puts(p, "\n");
}