浏览代码

disp: msm: sde: add support for split VBIF clock access

From Kalama onwards, the VBIF CLK_CTRL register has been moved from TOP block
to individual hardware block memory range.

This change is adding a backward compatible solution to support
per block VBIF CLK_CTRL access by allowing each HW block to register
set of callback ops. Additionally, it adds DMA and IPCC/MSI VBIF CLK_CTRL
block type.

Change-Id: Ia82ced34cfa1636b57cd1c03b327faf923be482a
Signed-off-by: Amine Najahi <[email protected]>
Amine Najahi 3 年之前
父节点
当前提交
ca4acd5270
共有 5 个文件被更改,包括 219 次插入20 次删除
  1. 42 0
      msm/sde/sde_hw_catalog.h
  2. 35 1
      msm/sde/sde_hw_vbif.h
  3. 2 0
      msm/sde/sde_kms.h
  4. 131 18
      msm/sde/sde_vbif.c
  5. 9 1
      msm/sde/sde_vbif.h

+ 42 - 0
msm/sde/sde_hw_catalog.h

@@ -657,6 +657,7 @@ enum {
  * @SDE_FEATURE_SUI_NS_ALLOWED SecureUI allowed to access non-secure context banks
  * @SDE_FEATURE_TRUSTED_VM     Trusted VM supported
  * @SDE_FEATURE_UBWC_STATS     UBWC statistics supported
+ * @SDE_FEATURE_VBIF_CLK_SPLIT VBIF clock split supported
  * @SDE_FEATURE_MAX:             MAX features value
  */
 enum sde_mdss_features {
@@ -696,6 +697,7 @@ enum sde_mdss_features {
 	SDE_FEATURE_SUI_NS_ALLOWED,
 	SDE_FEATURE_TRUSTED_VM,
 	SDE_FEATURE_UBWC_STATS,
+	SDE_FEATURE_VBIF_CLK_SPLIT,
 	SDE_FEATURE_MAX
 };
 
@@ -1025,15 +1027,55 @@ enum sde_clk_ctrl_type {
 	SDE_CLK_CTRL_RGB3,
 	SDE_CLK_CTRL_DMA0,
 	SDE_CLK_CTRL_DMA1,
+	SDE_CLK_CTRL_DMA2,
+	SDE_CLK_CTRL_DMA3,
+	SDE_CLK_CTRL_DMA4,
+	SDE_CLK_CTRL_DMA5,
 	SDE_CLK_CTRL_CURSOR0,
 	SDE_CLK_CTRL_CURSOR1,
 	SDE_CLK_CTRL_WB0,
 	SDE_CLK_CTRL_WB1,
 	SDE_CLK_CTRL_WB2,
 	SDE_CLK_CTRL_LUTDMA,
+	SDE_CLK_CTRL_IPCC_MSI,
 	SDE_CLK_CTRL_MAX,
 };
 
+#define SDE_CLK_CTRL_VALID(x) (x > SDE_CLK_CTRL_NONE && x < SDE_CLK_CTRL_MAX)
+#define SDE_CLK_CTRL_SSPP_VALID(x) (x >= SDE_CLK_CTRL_VIG0 && x <= SDE_CLK_CTRL_CURSOR1)
+#define SDE_CLK_CTRL_WB_VALID(x) (x >= SDE_CLK_CTRL_WB0 && x <= SDE_CLK_CTRL_WB2)
+#define SDE_CLK_CTRL_LUTDMA_VALID(x) (x == SDE_CLK_CTRL_LUTDMA)
+#define SDE_CLK_CTRL_IPCC_MSI_VALID(x) (x == SDE_CLK_CTRL_IPCC_MSI)
+
+/**
+ * sde_clk_ctrl_type - String of top level clock control signals
+ */
+static const char *sde_clk_ctrl_type_s[SDE_CLK_CTRL_MAX] = {
+	[SDE_CLK_CTRL_NONE] = "NONE",
+	[SDE_CLK_CTRL_VIG0] = "VIG0",
+	[SDE_CLK_CTRL_VIG1] = "VIG1",
+	[SDE_CLK_CTRL_VIG2] = "VIG2",
+	[SDE_CLK_CTRL_VIG3] = "VIG3",
+	[SDE_CLK_CTRL_VIG4] = "VIG4",
+	[SDE_CLK_CTRL_RGB0] = "RGB0",
+	[SDE_CLK_CTRL_RGB1] = "RGB1",
+	[SDE_CLK_CTRL_RGB2] = "RGB2",
+	[SDE_CLK_CTRL_RGB3] = "RGB3",
+	[SDE_CLK_CTRL_DMA0] = "DMA0",
+	[SDE_CLK_CTRL_DMA1] = "DMA1",
+	[SDE_CLK_CTRL_DMA2] = "DMA2",
+	[SDE_CLK_CTRL_DMA3] = "DMA3",
+	[SDE_CLK_CTRL_DMA4] = "DMA4",
+	[SDE_CLK_CTRL_DMA5] = "DMA5",
+	[SDE_CLK_CTRL_CURSOR0] = "CURSOR0",
+	[SDE_CLK_CTRL_CURSOR1] = "CURSOR1",
+	[SDE_CLK_CTRL_WB0] = "WB0",
+	[SDE_CLK_CTRL_WB1] = "WB1",
+	[SDE_CLK_CTRL_WB2] = "WB2",
+	[SDE_CLK_CTRL_LUTDMA] = "LUTDMA",
+	[SDE_CLK_CTRL_IPCC_MSI] = "IPCC_MSI",
+};
+
 /* struct sde_clk_ctrl_reg : Clock control register
  * @reg_off:           register offset
  * @bit_off:           bit offset

+ 35 - 1
msm/sde/sde_hw_vbif.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _SDE_HW_VBIF_H
@@ -124,6 +124,40 @@ struct sde_hw_vbif {
 	struct mutex mutex;
 };
 
+struct sde_vbif_clk_ops {
+	/**
+	 * setup_clk_force_ctrl - set clock force control
+	 * @hw:		hw block object
+	 * @clk_ctrl:	clock to be controlled
+	 * @enable:	force on enable
+	 * @return:	if the clock is forced-on by this function
+	 */
+	bool (*setup_clk_force_ctrl)(struct sde_hw_blk_reg_map *hw,
+			enum sde_clk_ctrl_type clk_ctrl, bool enable);
+
+	/**
+	 * get_clk_ctrl_status - get clock control status
+	 * @hw:		hw block object
+	 * @clk_ctrl:	clock to be controlled
+	 * @status:	returns true if clock is on
+	 * @return:	0 if success, otherwise return error code
+	 */
+	int (*get_clk_ctrl_status)(struct sde_hw_blk_reg_map *hw,
+			enum sde_clk_ctrl_type clk_ctrl, bool *status);
+};
+
+/**
+ * sde_vbif_clk_client - vbif client info
+ * @hw:		hw block object
+ * @clk_ctrl:	clock to be controlled
+ * @ops:	VBIF client ops
+ */
+struct sde_vbif_clk_client {
+	struct sde_hw_blk_reg_map *hw;
+	enum sde_clk_ctrl_type clk_ctrl;
+	struct sde_vbif_clk_ops ops;
+};
+
 /**
  * sde_hw_vbif_init - initializes the vbif driver for the passed interface idx
  * @idx:  Interface index for which driver object is required

+ 2 - 0
msm/sde/sde_kms.h

@@ -35,6 +35,7 @@
 #include "sde_hw_wb.h"
 #include "sde_hw_top.h"
 #include "sde_hw_uidle.h"
+#include "sde_hw_vbif.h"
 #include "sde_rm.h"
 #include "sde_power_handle.h"
 #include "sde_irq.h"
@@ -283,6 +284,7 @@ struct sde_kms {
 	struct sde_rm rm;
 	bool rm_init;
 	struct sde_splash_data splash_data;
+	struct sde_vbif_clk_client vbif_clk_clients[SDE_CLK_CTRL_MAX];
 	struct sde_hw_vbif *hw_vbif[VBIF_MAX];
 	struct sde_hw_mdp *hw_mdp;
 	struct sde_hw_uidle *hw_uidle;

+ 131 - 18
msm/sde/sde_vbif.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
@@ -14,6 +14,121 @@
 
 #define MAX_XIN_CLIENT	16
 
+#define VBIF_CLK_CLIENT(x) sde_kms->vbif_clk_clients[x]
+#define VBIF_CLK_CLIENT_NAME(x) sde_clk_ctrl_type_s[x]
+
+int sde_vbif_clk_register(struct sde_kms *sde_kms, struct sde_vbif_clk_client *client)
+{
+	enum sde_clk_ctrl_type clk_ctrl;
+
+	if (!sde_kms || !client)
+		return -EINVAL;
+
+	clk_ctrl = client->clk_ctrl;
+	if (!SDE_CLK_CTRL_VALID(clk_ctrl))
+		return -EINVAL;
+
+	VBIF_CLK_CLIENT(clk_ctrl).hw = client->hw;
+	VBIF_CLK_CLIENT(clk_ctrl).clk_ctrl = clk_ctrl;
+	memcpy(&VBIF_CLK_CLIENT(clk_ctrl).ops, &client->ops, sizeof(struct sde_vbif_clk_ops));
+
+	SDE_DEBUG("registering hw:%pK clk_ctrl:%s\n", client->hw, VBIF_CLK_CLIENT_NAME(clk_ctrl));
+
+	return 0;
+}
+
+/**
+ * _sde_vbif_setup_clk_supported - check if VBIF setup_clk_force_ctrl API is supported
+ * @sde_kms:	Pointer to sde_kms object
+ * @clk_ctrl:	clock to be controlled
+ * @return:	true if client is supported, otherwise false
+ */
+static bool _sde_vbif_setup_clk_supported(struct sde_kms *sde_kms, enum sde_clk_ctrl_type clk_ctrl)
+{
+	bool supported = false;
+	bool has_split_vbif = test_bit(SDE_FEATURE_VBIF_CLK_SPLIT, sde_kms->catalog->features);
+
+	if ((has_split_vbif && VBIF_CLK_CLIENT(clk_ctrl).ops.setup_clk_force_ctrl) ||
+			(!has_split_vbif && sde_kms->hw_mdp->ops.setup_clk_force_ctrl))
+		supported = true;
+
+	SDE_DEBUG("split_vbif:%d type:%s supported:%d\n", has_split_vbif,
+			VBIF_CLK_CLIENT_NAME(clk_ctrl), supported);
+
+	return supported;
+}
+
+/**
+ * _sde_vbif_get_clk_supported - check if VBIF get_clk_ctrl_status API is supported
+ * @sde_kms:	Pointer to sde_kms object
+ * @clk_ctrl:	clock to be controlled
+ * @return:	true if client is supported, otherwise false
+ */
+static bool _sde_vbif_get_clk_supported(struct sde_kms *sde_kms, enum sde_clk_ctrl_type clk_ctrl)
+{
+	bool supported = false;
+	bool has_split_vbif = test_bit(SDE_FEATURE_VBIF_CLK_SPLIT, sde_kms->catalog->features);
+
+	if ((has_split_vbif && VBIF_CLK_CLIENT(clk_ctrl).ops.get_clk_ctrl_status) ||
+			(!has_split_vbif && sde_kms->hw_mdp->ops.get_clk_ctrl_status))
+		supported = true;
+
+	SDE_DEBUG("split_vbif:%d type:%s supported:%d\n", has_split_vbif,
+			VBIF_CLK_CLIENT_NAME(clk_ctrl), supported);
+
+	return supported;
+}
+
+/**
+ * _sde_vbif_setup_clk_force_ctrl - set clock force control
+ * @sde_kms:	Pointer to sde_kms object
+ * @clk_ctrl:	clock to be controlled
+ * @enable:	force on enable
+ * @return:	if the clock is forced-on by this function
+ */
+static int _sde_vbif_setup_clk_force_ctrl(struct sde_kms *sde_kms, enum sde_clk_ctrl_type clk_ctrl,
+		bool enable)
+{
+	int rc = 0;
+	struct sde_hw_blk_reg_map *hw = VBIF_CLK_CLIENT(clk_ctrl).hw;
+	bool has_split_vbif = test_bit(SDE_FEATURE_VBIF_CLK_SPLIT, sde_kms->catalog->features);
+
+	if (has_split_vbif)
+		rc = VBIF_CLK_CLIENT(clk_ctrl).ops.setup_clk_force_ctrl(hw, clk_ctrl, enable);
+	else
+		rc = sde_kms->hw_mdp->ops.setup_clk_force_ctrl(sde_kms->hw_mdp, clk_ctrl, enable);
+
+	SDE_DEBUG("split_vbif:%d type:%s en:%d rc:%d\n", has_split_vbif,
+			VBIF_CLK_CLIENT_NAME(clk_ctrl), enable, rc);
+
+	return rc;
+}
+
+/**
+ * _sde_vbif_get_clk_ctrl_status - get clock control status
+ * @sde_kms:	Pointer to sde_kms object
+ * @clk_ctrl:	clock to be controlled
+ * @status:	returns true if clock is on
+ * @return:	0 if success, otherwise return error code
+ */
+static int _sde_vbif_get_clk_ctrl_status(struct sde_kms *sde_kms, enum sde_clk_ctrl_type clk_ctrl,
+		bool *status)
+{
+	int rc = 0;
+	struct sde_hw_blk_reg_map *hw = VBIF_CLK_CLIENT(clk_ctrl).hw;
+	bool has_split_vbif = test_bit(SDE_FEATURE_VBIF_CLK_SPLIT, sde_kms->catalog->features);
+
+	if (has_split_vbif)
+		rc = VBIF_CLK_CLIENT(clk_ctrl).ops.get_clk_ctrl_status(hw, clk_ctrl, status);
+	else
+		rc = sde_kms->hw_mdp->ops.get_clk_ctrl_status(sde_kms->hw_mdp, clk_ctrl, status);
+
+	SDE_DEBUG("split_vbif:%d type:%s status:%d rc:%d\n", has_split_vbif,
+			VBIF_CLK_CLIENT_NAME(clk_ctrl), *status, rc);
+
+	return rc;
+}
+
 /**
  * _sde_vbif_wait_for_xin_halt - wait for the xin to halt
  * @vbif:	Pointer to hardware vbif driver
@@ -98,7 +213,7 @@ int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl)
 	mdp = sde_kms->hw_mdp;
 	if (!vbif || !mdp || !vbif->ops.get_xin_halt_status ||
 		       !vbif->ops.set_xin_halt ||
-		       !mdp->ops.setup_clk_force_ctrl) {
+		       !_sde_vbif_setup_clk_supported(sde_kms, clk_ctrl)) {
 		SDE_ERROR("invalid vbif or mdp arguments\n");
 		return -EINVAL;
 	}
@@ -118,7 +233,7 @@ int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl)
 		return 0;
 	}
 
-	forced_on = mdp->ops.setup_clk_force_ctrl(mdp, clk_ctrl, true);
+	forced_on = _sde_vbif_setup_clk_force_ctrl(sde_kms, clk_ctrl, true);
 
 	/* send halt request for unused plane's xin client */
 	vbif->ops.set_xin_halt(vbif, xin_id, true);
@@ -134,7 +249,7 @@ int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl)
 	/* open xin client to enable transactions */
 	vbif->ops.set_xin_halt(vbif, xin_id, false);
 	if (forced_on)
-		mdp->ops.setup_clk_force_ctrl(mdp, clk_ctrl, false);
+		_sde_vbif_setup_clk_force_ctrl(sde_kms, clk_ctrl, false);
 
 	mutex_unlock(&vbif->mutex);
 
@@ -268,7 +383,7 @@ void sde_vbif_set_ot_limit(struct sde_kms *sde_kms,
 		return;
 	}
 
-	if (!mdp->ops.setup_clk_force_ctrl ||
+	if (!_sde_vbif_setup_clk_supported(sde_kms, params->clk_ctrl) ||
 			!vbif->ops.set_limit_conf ||
 			!vbif->ops.set_xin_halt)
 		return;
@@ -289,7 +404,7 @@ void sde_vbif_set_ot_limit(struct sde_kms *sde_kms,
 	trace_sde_perf_set_ot(params->num, params->xin_id, ot_lim,
 		params->vbif_idx);
 
-	forced_on = mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, true);
+	forced_on = _sde_vbif_setup_clk_force_ctrl(sde_kms, params->clk_ctrl, true);
 
 	vbif->ops.set_limit_conf(vbif, params->xin_id, params->rd, ot_lim);
 
@@ -302,7 +417,8 @@ void sde_vbif_set_ot_limit(struct sde_kms *sde_kms,
 	vbif->ops.set_xin_halt(vbif, params->xin_id, false);
 
 	if (forced_on)
-		mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false);
+		_sde_vbif_setup_clk_force_ctrl(sde_kms, params->clk_ctrl, false);
+
 exit:
 	mutex_unlock(&vbif->mutex);
 }
@@ -376,7 +492,7 @@ bool sde_vbif_set_xin_halt(struct sde_kms *sde_kms,
 		return false;
 	}
 
-	if (!mdp->ops.setup_clk_force_ctrl ||
+	if (!_sde_vbif_setup_clk_supported(sde_kms, params->clk_ctrl) ||
 			!vbif->ops.set_xin_halt)
 		return false;
 
@@ -385,8 +501,7 @@ bool sde_vbif_set_xin_halt(struct sde_kms *sde_kms,
 	SDE_EVT32_VERBOSE(vbif->idx, params->xin_id);
 
 	if (params->enable) {
-		forced_on = mdp->ops.setup_clk_force_ctrl(mdp,
-				params->clk_ctrl, true);
+		forced_on = _sde_vbif_setup_clk_force_ctrl(sde_kms, params->clk_ctrl, true);
 
 		vbif->ops.set_xin_halt(vbif, params->xin_id, true);
 
@@ -397,8 +512,7 @@ bool sde_vbif_set_xin_halt(struct sde_kms *sde_kms,
 		vbif->ops.set_xin_halt(vbif, params->xin_id, false);
 
 		if (params->forced_on)
-			mdp->ops.setup_clk_force_ctrl(mdp,
-					params->clk_ctrl, false);
+			_sde_vbif_setup_clk_force_ctrl(sde_kms, params->clk_ctrl, false);
 	}
 
 	mutex_unlock(&vbif->mutex);
@@ -440,7 +554,7 @@ bool sde_vbif_get_xin_status(struct sde_kms *sde_kms,
 		return false;
 	}
 
-	if (!mdp->ops.get_clk_ctrl_status ||
+	if (!_sde_vbif_get_clk_supported(sde_kms, params->clk_ctrl) ||
 			!vbif->ops.get_xin_halt_status)
 		return false;
 
@@ -448,8 +562,7 @@ bool sde_vbif_get_xin_status(struct sde_kms *sde_kms,
 	SDE_EVT32_VERBOSE(vbif->idx, params->xin_id);
 	status = vbif->ops.get_xin_halt_status(vbif, params->xin_id);
 	if (status) {
-		rc = !mdp->ops.get_clk_ctrl_status(mdp, params->clk_ctrl,
-				&status);
+		rc = _sde_vbif_get_clk_ctrl_status(sde_kms, params->clk_ctrl, &status);
 		if (rc)
 			status = false;
 	}
@@ -492,7 +605,7 @@ void sde_vbif_set_qos_remap(struct sde_kms *sde_kms,
 		return;
 	}
 
-	if (!vbif->ops.set_qos_remap || !mdp->ops.setup_clk_force_ctrl) {
+	if (!vbif->ops.set_qos_remap || !_sde_vbif_setup_clk_supported(sde_kms, params->clk_ctrl)) {
 		SDE_DEBUG("qos remap not supported\n");
 		return;
 	}
@@ -510,7 +623,7 @@ void sde_vbif_set_qos_remap(struct sde_kms *sde_kms,
 
 	mutex_lock(&vbif->mutex);
 
-	forced_on = mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, true);
+	forced_on = _sde_vbif_setup_clk_force_ctrl(sde_kms, params->clk_ctrl, true);
 
 	for (i = 0; i < qos_tbl->npriority_lvl; i++) {
 		SDE_DEBUG("vbif:%d xin:%d lvl:%d/%d\n",
@@ -521,7 +634,7 @@ void sde_vbif_set_qos_remap(struct sde_kms *sde_kms,
 	}
 
 	if (forced_on)
-		mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false);
+		_sde_vbif_setup_clk_force_ctrl(sde_kms, params->clk_ctrl, false);
 
 	mutex_unlock(&vbif->mutex);
 }

+ 9 - 1
msm/sde/sde_vbif.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef __SDE_VBIF_H__
@@ -72,6 +72,14 @@ struct sde_vbif_set_qos_params {
 	enum sde_vbif_client_type client_type;
 };
 
+/**
+ * sde_vbif_clk_register - register vbif clk client
+ * @sde_kms:	SDE handler
+ * @client:	pointer to VBIF clk client info
+ * Returns:	0 on success, error code otherwise
+ */
+int sde_vbif_clk_register(struct sde_kms *sde_kms, struct sde_vbif_clk_client *client);
+
 /**
  * sde_vbif_set_ot_limit - set OT limit for vbif client
  * @sde_kms:	SDE handler