Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a62eeb84 authored by Alan Kwong's avatar Alan Kwong
Browse files

drm/msm/sde: add vbif qos remapper for display



QoS remapper is used to translate DPU priority to chip-level
priority. Add vbif qos remapper function to provide proper
translation to chip-level QoS request.

CRs-Fixed: 2037879
Change-Id: Ia34664d0a15dcb9056991d5a88b37a2fbc3bc285
Signed-off-by: default avatarAlan Kwong <akwong@codeaurora.org>
parent ea5149e3
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -297,6 +297,10 @@ Optional properties:
- qcom,sde-downscaling-prefill-lines:	A u32 value indicates the latency of downscaling in lines.
- qcom,sde-max-per-pipe-bw-kbps:	Array of u32 value indicates the max per pipe bandwidth in Kbps.
- qcom,sde-amortizable-threshold:	This value indicates the min for traffic shaping in lines.
- qcom,sde-vbif-qos-rt-remap:	This array is used to program vbif qos remapper register
				priority for realtime clients.
- qcom,sde-vbif-qos-nrt-remap:	This array is used to program vbif qos remapper register
				priority for non-realtime clients.

Bus Scaling Subnodes:
- qcom,sde-reg-bus:		Property to provide Bus scaling for register access for
@@ -500,6 +504,9 @@ Example:
        2400000 2400000 2400000 2400000>;
    qcom,sde-amortizable-threshold = <11>;

    qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>;
    qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>;

    qcom,sde-sspp-vig-blocks {
        qcom,sde-vig-csc-off = <0x320>;
        qcom,sde-vig-qseed-off = <0x200>;
+45 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "sde_core_irq.h"
#include "sde_wb.h"
#include "sde_vbif.h"
#include "sde_crtc.h"

#define to_sde_encoder_phys_wb(x) \
	container_of(x, struct sde_encoder_phys_wb, base)
@@ -103,6 +104,48 @@ static void sde_encoder_phys_wb_set_traffic_shaper(
	wb_cfg->ts_cfg.en = false;
}

/**
 * sde_encoder_phys_wb_set_qos_remap - set QoS remapper for writeback
 * @phys_enc:	Pointer to physical encoder
 */
static void sde_encoder_phys_wb_set_qos_remap(
		struct sde_encoder_phys *phys_enc)
{
	struct sde_encoder_phys_wb *wb_enc;
	struct sde_hw_wb *hw_wb;
	struct drm_crtc *crtc;
	struct sde_vbif_set_qos_params qos_params;

	if (!phys_enc || !phys_enc->parent || !phys_enc->parent->crtc) {
		SDE_ERROR("invalid arguments\n");
		return;
	}

	wb_enc = to_sde_encoder_phys_wb(phys_enc);
	crtc = phys_enc->parent->crtc;

	if (!wb_enc->hw_wb || !wb_enc->hw_wb->caps) {
		SDE_ERROR("invalid writeback hardware\n");
		return;
	}

	hw_wb = wb_enc->hw_wb;

	memset(&qos_params, 0, sizeof(qos_params));
	qos_params.vbif_idx = hw_wb->caps->vbif_idx;
	qos_params.xin_id = hw_wb->caps->xin_id;
	qos_params.clk_ctrl = hw_wb->caps->clk_ctrl;
	qos_params.num = hw_wb->idx - WB_0;
	qos_params.is_rt = sde_crtc_get_client_type(crtc) != NRT_CLIENT;

	SDE_DEBUG("[qos_remap] wb:%d vbif:%d xin:%d rt:%d\n",
			qos_params.num,
			qos_params.vbif_idx,
			qos_params.xin_id, qos_params.is_rt);

	sde_vbif_set_qos_remap(phys_enc->sde_kms, &qos_params);
}

/**
 * sde_encoder_phys_setup_cdm - setup chroma down block
 * @phys_enc:	Pointer to physical encoder
@@ -528,6 +571,8 @@ static void sde_encoder_phys_wb_setup(

	sde_encoder_phys_wb_set_traffic_shaper(phys_enc);

	sde_encoder_phys_wb_set_qos_remap(phys_enc);

	sde_encoder_phys_setup_cdm(phys_enc, fb, wb_enc->wb_fmt, wb_roi);

	sde_encoder_phys_wb_setup_fb(phys_enc, fb, wb_roi);
+81 −4
Original line number Diff line number Diff line
@@ -285,6 +285,8 @@ enum {
	VBIF_DEFAULT_OT_WR_LIMIT,
	VBIF_DYNAMIC_OT_RD_LIMIT,
	VBIF_DYNAMIC_OT_WR_LIMIT,
	VBIF_QOS_RT_REMAP,
	VBIF_QOS_NRT_REMAP,
	VBIF_PROP_MAX,
};

@@ -512,6 +514,10 @@ static struct sde_prop_type vbif_prop[] = {
		PROP_TYPE_U32_ARRAY},
	{VBIF_DYNAMIC_OT_WR_LIMIT, "qcom,sde-vbif-dynamic-ot-wr-limit", false,
		PROP_TYPE_U32_ARRAY},
	{VBIF_QOS_RT_REMAP, "qcom,sde-vbif-qos-rt-remap", false,
		PROP_TYPE_U32_ARRAY},
	{VBIF_QOS_NRT_REMAP, "qcom,sde-vbif-qos-nrt-remap", false,
		PROP_TYPE_U32_ARRAY},
};

static struct sde_prop_type reg_dma_prop[REG_DMA_PROP_MAX] = {
@@ -1926,7 +1932,7 @@ static int sde_vbif_parse_dt(struct device_node *np,
	int rc, prop_count[VBIF_PROP_MAX], i, j, k;
	struct sde_prop_value *prop_value = NULL;
	bool prop_exists[VBIF_PROP_MAX];
	u32 off_count, vbif_len, rd_len = 0, wr_len = 0;
	u32 off_count, vbif_len;
	struct sde_vbif_cfg *vbif;

	if (!sde_cfg) {
@@ -1948,12 +1954,22 @@ static int sde_vbif_parse_dt(struct device_node *np,
		goto end;

	rc = _validate_dt_entry(np, &vbif_prop[VBIF_DYNAMIC_OT_RD_LIMIT], 1,
			&prop_count[VBIF_DYNAMIC_OT_RD_LIMIT], &rd_len);
			&prop_count[VBIF_DYNAMIC_OT_RD_LIMIT], NULL);
	if (rc)
		goto end;

	rc = _validate_dt_entry(np, &vbif_prop[VBIF_DYNAMIC_OT_WR_LIMIT], 1,
			&prop_count[VBIF_DYNAMIC_OT_WR_LIMIT], &wr_len);
			&prop_count[VBIF_DYNAMIC_OT_WR_LIMIT], NULL);
	if (rc)
		goto end;

	rc = _validate_dt_entry(np, &vbif_prop[VBIF_QOS_RT_REMAP], 1,
			&prop_count[VBIF_QOS_RT_REMAP], NULL);
	if (rc)
		goto end;

	rc = _validate_dt_entry(np, &vbif_prop[VBIF_QOS_NRT_REMAP], 1,
			&prop_count[VBIF_QOS_NRT_REMAP], NULL);
	if (rc)
		goto end;

@@ -2048,6 +2064,63 @@ static int sde_vbif_parse_dt(struct device_node *np,
				vbif->dynamic_ot_rd_tbl.count ||
				vbif->dynamic_ot_wr_tbl.count)
			set_bit(SDE_VBIF_QOS_OTLIM, &vbif->features);

		vbif->qos_rt_tbl.npriority_lvl =
				prop_count[VBIF_QOS_RT_REMAP];
		SDE_DEBUG("qos_rt_tbl.npriority_lvl=%u\n",
				vbif->qos_rt_tbl.npriority_lvl);
		if (vbif->qos_rt_tbl.npriority_lvl == sde_cfg->vbif_qos_nlvl) {
			vbif->qos_rt_tbl.priority_lvl = kcalloc(
				vbif->qos_rt_tbl.npriority_lvl, sizeof(u32),
				GFP_KERNEL);
			if (!vbif->qos_rt_tbl.priority_lvl) {
				rc = -ENOMEM;
				goto end;
			}
		} else if (vbif->qos_rt_tbl.npriority_lvl) {
			vbif->qos_rt_tbl.npriority_lvl = 0;
			vbif->qos_rt_tbl.priority_lvl = NULL;
			SDE_ERROR("invalid qos rt table\n");
		}

		for (j = 0; j < vbif->qos_rt_tbl.npriority_lvl; j++) {
			vbif->qos_rt_tbl.priority_lvl[j] =
				PROP_VALUE_ACCESS(prop_value,
						VBIF_QOS_RT_REMAP, j);
			SDE_DEBUG("lvl[%d]=%u\n", j,
					vbif->qos_rt_tbl.priority_lvl[j]);
		}

		vbif->qos_nrt_tbl.npriority_lvl =
				prop_count[VBIF_QOS_NRT_REMAP];
		SDE_DEBUG("qos_nrt_tbl.npriority_lvl=%u\n",
				vbif->qos_nrt_tbl.npriority_lvl);

		if (vbif->qos_nrt_tbl.npriority_lvl == sde_cfg->vbif_qos_nlvl) {
			vbif->qos_nrt_tbl.priority_lvl = kcalloc(
				vbif->qos_nrt_tbl.npriority_lvl, sizeof(u32),
				GFP_KERNEL);
			if (!vbif->qos_nrt_tbl.priority_lvl) {
				rc = -ENOMEM;
				goto end;
			}
		} else if (vbif->qos_nrt_tbl.npriority_lvl) {
			vbif->qos_nrt_tbl.npriority_lvl = 0;
			vbif->qos_nrt_tbl.priority_lvl = NULL;
			SDE_ERROR("invalid qos nrt table\n");
		}

		for (j = 0; j < vbif->qos_nrt_tbl.npriority_lvl; j++) {
			vbif->qos_nrt_tbl.priority_lvl[j] =
				PROP_VALUE_ACCESS(prop_value,
						VBIF_QOS_NRT_REMAP, j);
			SDE_DEBUG("lvl[%d]=%u\n", j,
					vbif->qos_nrt_tbl.priority_lvl[j]);
		}

		if (vbif->qos_rt_tbl.npriority_lvl ||
				vbif->qos_nrt_tbl.npriority_lvl)
			set_bit(SDE_VBIF_QOS_REMAP, &vbif->features);
	}

end:
@@ -2510,11 +2583,13 @@ static int _sde_hardware_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
		/* update msm8998 target here */
		sde_cfg->has_wb_ubwc = true;
		sde_cfg->perf.min_prefill_lines = 25;
		sde_cfg->vbif_qos_nlvl = 4;
		break;
	case SDE_HW_VER_400:
		/* update msm8998 and sdm845 target here */
		/* update sdm845 target here */
		sde_cfg->has_wb_ubwc = true;
		sde_cfg->perf.min_prefill_lines = 24;
		sde_cfg->vbif_qos_nlvl = 8;
		break;
	default:
		sde_cfg->perf.min_prefill_lines = 0xffff;
@@ -2549,6 +2624,8 @@ void sde_hw_catalog_deinit(struct sde_mdss_cfg *sde_cfg)
	for (i = 0; i < sde_cfg->vbif_count; i++) {
		kfree(sde_cfg->vbif[i].dynamic_ot_rd_tbl.cfg);
		kfree(sde_cfg->vbif[i].dynamic_ot_wr_tbl.cfg);
		kfree(sde_cfg->vbif[i].qos_rt_tbl.priority_lvl);
		kfree(sde_cfg->vbif[i].qos_nrt_tbl.priority_lvl);
	}

	kfree(sde_cfg->dma_formats);
+18 −0
Original line number Diff line number Diff line
@@ -258,10 +258,12 @@ enum {
/**
 * VBIF sub-blocks and features
 * @SDE_VBIF_QOS_OTLIM        VBIF supports OT Limit
 * @SDE_VBIF_QOS_REMAP        VBIF supports QoS priority remap
 * @SDE_VBIF_MAX              maximum value
 */
enum {
	SDE_VBIF_QOS_OTLIM = 0x1,
	SDE_VBIF_QOS_REMAP,
	SDE_VBIF_MAX
};

@@ -652,6 +654,16 @@ struct sde_vbif_dynamic_ot_tbl {
	struct sde_vbif_dynamic_ot_cfg *cfg;
};

/**
 * struct sde_vbif_qos_tbl - QoS priority table
 * @npriority_lvl      num of priority level
 * @priority_lvl       pointer to array of priority level in ascending order
 */
struct sde_vbif_qos_tbl {
	u32 npriority_lvl;
	u32 *priority_lvl;
};

/**
 * struct sde_vbif_cfg - information of VBIF blocks
 * @id                 enum identifying this block
@@ -662,6 +674,8 @@ struct sde_vbif_dynamic_ot_tbl {
 * @xin_halt_timeout   maximum time (in usec) for xin to halt
 * @dynamic_ot_rd_tbl  dynamic OT read configuration table
 * @dynamic_ot_wr_tbl  dynamic OT write configuration table
 * @qos_rt_tbl         real-time QoS priority table
 * @qos_nrt_tbl        non-real-time QoS priority table
 */
struct sde_vbif_cfg {
	SDE_HW_BLK_INFO;
@@ -670,6 +684,8 @@ struct sde_vbif_cfg {
	u32 xin_halt_timeout;
	struct sde_vbif_dynamic_ot_tbl dynamic_ot_rd_tbl;
	struct sde_vbif_dynamic_ot_tbl dynamic_ot_wr_tbl;
	struct sde_vbif_qos_tbl qos_rt_tbl;
	struct sde_vbif_qos_tbl qos_nrt_tbl;
};
/**
 * struct sde_reg_dma_cfg - information of lut dma blocks
@@ -746,6 +762,7 @@ struct sde_perf_cfg {
 * @cursor_formats     Supported formats for cursor pipe
 * @vig_formats        Supported formats for vig pipe
 * @wb_formats         Supported formats for wb
 * @vbif_qos_nlvl      number of vbif QoS priority level
 */
struct sde_mdss_cfg {
	u32 hwversion;
@@ -765,6 +782,7 @@ struct sde_mdss_cfg {
	bool has_sbuf;
	u32 sbuf_headroom;
	bool has_idle_pc;
	u32 vbif_qos_nlvl;

	u32 mdss_count;
	struct sde_mdss_base_cfg mdss[MAX_BLOCKS];
+33 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@
#define VBIF_OUT_WR_LIM_CONF0		0x00D4
#define VBIF_XIN_HALT_CTRL0		0x0200
#define VBIF_XIN_HALT_CTRL1		0x0204
#define VBIF_XINL_QOS_RP_REMAP_000	0x0550
#define VBIF_XINL_QOS_LVL_REMAP_000	0x0590

static void sde_hw_set_limit_conf(struct sde_hw_vbif *vbif,
		u32 xin_id, bool rd, u32 limit)
@@ -104,6 +106,35 @@ static bool sde_hw_get_halt_ctrl(struct sde_hw_vbif *vbif,
	return (reg_val & BIT(xin_id)) ? true : false;
}

static void sde_hw_set_qos_remap(struct sde_hw_vbif *vbif,
		u32 xin_id, u32 level, u32 remap_level)
{
	struct sde_hw_blk_reg_map *c;
	u32 reg_val, reg_val_lvl, mask, reg_high, reg_shift;

	if (!vbif)
		return;

	c = &vbif->hw;

	reg_high = ((xin_id & 0x8) >> 3) * 4 + (level * 8);
	reg_shift = (xin_id & 0x7) * 4;

	reg_val = SDE_REG_READ(c, VBIF_XINL_QOS_RP_REMAP_000 + reg_high);
	reg_val_lvl = SDE_REG_READ(c, VBIF_XINL_QOS_LVL_REMAP_000 + reg_high);

	mask = 0x7 << reg_shift;

	reg_val &= ~mask;
	reg_val |= (remap_level << reg_shift) & mask;

	reg_val_lvl &= ~mask;
	reg_val_lvl |= (remap_level << reg_shift) & mask;

	SDE_REG_WRITE(c, VBIF_XINL_QOS_RP_REMAP_000 + reg_high, reg_val);
	SDE_REG_WRITE(c, VBIF_XINL_QOS_LVL_REMAP_000 + reg_high, reg_val_lvl);
}

static void _setup_vbif_ops(struct sde_hw_vbif_ops *ops,
		unsigned long cap)
{
@@ -111,6 +142,8 @@ static void _setup_vbif_ops(struct sde_hw_vbif_ops *ops,
	ops->get_limit_conf = sde_hw_get_limit_conf;
	ops->set_halt_ctrl = sde_hw_set_halt_ctrl;
	ops->get_halt_ctrl = sde_hw_get_halt_ctrl;
	if (test_bit(SDE_VBIF_QOS_REMAP, &cap))
		ops->set_qos_remap = sde_hw_set_qos_remap;
}

static const struct sde_vbif_cfg *_top_offset(enum sde_vbif vbif,
Loading