|
@@ -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);
|
|
|
}
|