Procházet zdrojové kódy

disp: msm: reserve core clock rate during display disable

Userspace module may not trigger the atomic check and it
can cause the commit failure. In such case, always reserve
the minimum core clock rate on mmrm module for built-in
displays to avoid the power ON failure.

Change-Id: Iafd92a7b7d1b35befe70b041cbedaec2add40de4
Signed-off-by: Dhaval Patel <[email protected]>
Dhaval Patel před 3 roky
rodič
revize
c281b3a879

+ 25 - 0
msm/sde/sde_core_perf.c

@@ -829,6 +829,31 @@ void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc)
 	}
 }
 
+void sde_core_perf_crtc_reserve_res(struct drm_crtc *crtc, u64 reserve_rate)
+{
+	struct sde_crtc *sde_crtc;
+	struct sde_kms *kms;
+	struct msm_drm_private *priv;
+
+	if (!crtc) {
+		SDE_ERROR("invalid crtc\n");
+		return;
+	}
+
+	/* use current perf, which are the values voted */
+	sde_crtc = to_sde_crtc(crtc);
+	kms = _sde_crtc_get_kms(crtc);
+	priv = kms->dev->dev_private;
+
+	kms->perf.core_clk_reserve_rate = max(kms->perf.core_clk_reserve_rate, reserve_rate);
+	kms->perf.core_clk_reserve_rate = min(kms->perf.core_clk_reserve_rate,
+			kms->perf.max_core_clk_rate);
+	sde_power_clk_reserve_rate(&priv->phandle, kms->perf.clk_name,
+			kms->perf.core_clk_reserve_rate);
+
+	SDE_DEBUG("reserve clk:%llu\n", kms->perf.core_clk_reserve_rate);
+}
+
 static u64 _sde_core_perf_get_core_clk_rate(struct sde_kms *kms)
 {
 	u64 clk_rate = kms->perf.perf_tune.min_core_clk;

+ 10 - 1
msm/sde/sde_core_perf.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_CORE_PERF_H_
@@ -78,6 +78,7 @@ struct sde_core_perf_tune {
  * @uidle_enabled: indicates if uidle is already enabled
  * @idle_sys_cache_enabled: override system cache enable state
  *                          for idle usecase
+ * @core_clk_reserve_rate: reserve core clk rate for built-in display
  */
 struct sde_core_perf {
 	struct drm_device *dev;
@@ -99,6 +100,7 @@ struct sde_core_perf {
 	bool llcc_active[SDE_SYS_CACHE_MAX];
 	bool uidle_enabled;
 	bool idle_sys_cache_enabled;
+	u64 core_clk_reserve_rate;
 };
 
 /**
@@ -131,6 +133,13 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc,
  */
 void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc);
 
+/**
+ * sde_core_perf_reserve_res - reserve core clock resource for built-in displays.
+ * @crtc: Pointer to crtc
+ * @reserve_rate: core clock rate for built-in display
+ */
+void sde_core_perf_crtc_reserve_res(struct drm_crtc *crtc, u64 reserve_rate);
+
 /**
  * sde_core_perf_crtc_update_uidle - attempts to enable uidle of the given crtc
  * @crtc: Pointer to crtc

+ 40 - 1
msm/sde/sde_crtc.c

@@ -4160,6 +4160,43 @@ static int _sde_crtc_vblank_enable(
 	return 0;
 }
 
+static void _sde_crtc_reserve_resource(struct drm_crtc *crtc, struct drm_connector *conn)
+{
+	u32 min_transfer_time = 0, lm_count = 1;
+	u64 mode_clock_hz = 0, updated_fps = 0, topology_id;
+	struct drm_encoder *encoder;
+
+	if (!crtc || !conn)
+		return;
+
+	encoder = conn->state->best_encoder;
+	if (!sde_encoder_is_built_in_display(encoder))
+		return;
+
+	if (sde_encoder_check_curr_mode(encoder, MSM_DISPLAY_CMD_MODE))
+		sde_encoder_get_transfer_time(encoder, &min_transfer_time);
+
+	if (min_transfer_time)
+		updated_fps = DIV_ROUND_UP(1000000, min_transfer_time);
+	else
+		updated_fps = drm_mode_vrefresh(&crtc->mode);
+
+	topology_id = sde_connector_get_topology_name(conn);
+	if (TOPOLOGY_DUALPIPE_MODE(topology_id))
+		lm_count = 2;
+	else if (TOPOLOGY_QUADPIPE_MODE(topology_id))
+		lm_count = 4;
+
+	/* mode clock = [(h * v * fps * 1.05) / (num_lm)] */
+	mode_clock_hz = mult_frac(crtc->mode.htotal * crtc->mode.vtotal * updated_fps, 105, 100);
+	mode_clock_hz = div_u64(mode_clock_hz, lm_count);
+	SDE_DEBUG("[%s] h=%d v=%d fps=%d lm=%d mode_clk=%u\n",
+			crtc->mode.name, crtc->mode.htotal, crtc->mode.vtotal,
+			updated_fps, lm_count, mode_clock_hz);
+
+	sde_core_perf_crtc_reserve_res(crtc, mode_clock_hz);
+}
+
 /**
  * sde_crtc_duplicate_state - state duplicate hook
  * @crtc: Pointer to drm crtc structure
@@ -4666,8 +4703,10 @@ static void sde_crtc_enable(struct drm_crtc *crtc,
 		sde_crtc_handle_power_event, crtc, sde_crtc->name);
 
 	/* Enable ESD thread */
-	for (i = 0; i < cstate->num_connectors; i++)
+	for (i = 0; i < cstate->num_connectors; i++) {
 		sde_connector_schedule_status_work(cstate->connectors[i], true);
+		_sde_crtc_reserve_resource(crtc, cstate->connectors[i]);
+	}
 }
 
 /* no input validation - caller API has all the checks */

+ 46 - 0
msm/sde_power_handle.c

@@ -800,6 +800,32 @@ void sde_power_resource_deinit(struct platform_device *pdev,
 		sde_rsc_client_destroy(phandle->rsc_client);
 }
 
+static void sde_power_mmrm_reserve(struct sde_power_handle *phandle)
+{
+	int i;
+	struct dss_module_power *mp = &phandle->mp;
+	u64 rate = phandle->mmrm_reserve.clk_rate;
+
+	if (!phandle->mmrm_enable)
+		return;
+
+	for (i = 0; i < mp->num_clk; i++) {
+		if (!strcmp(mp->clk_config[i].clk_name, phandle->mmrm_reserve.clk_name)) {
+			if (mp->clk_config[i].max_rate)
+				rate = min(rate, (u64)mp->clk_config[i].max_rate);
+
+			mp->clk_config[i].rate = rate;
+			mp->clk_config[i].mmrm.flags =
+				MMRM_CLIENT_DATA_FLAG_RESERVE_ONLY;
+
+			SDE_ATRACE_BEGIN("sde_clk_set_rate");
+			msm_dss_single_clk_set_rate(&mp->clk_config[i]);
+			SDE_ATRACE_END("sde_clk_set_rate");
+			break;
+		}
+	}
+}
+
 int sde_power_scale_reg_bus(struct sde_power_handle *phandle,
 	u32 usecase_ndx, bool skip_lock)
 {
@@ -897,6 +923,7 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, bool enable)
 		SDE_EVT32_VERBOSE(enable, SDE_EVTLOG_FUNC_CASE2);
 		sde_power_rsc_update(phandle, false);
 
+		sde_power_mmrm_reserve(phandle);
 		msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
 
 		sde_power_scale_reg_bus(phandle, VOTE_INDEX_DISABLE, true);
@@ -936,6 +963,25 @@ vreg_err:
 	return rc;
 }
 
+int sde_power_clk_reserve_rate(struct sde_power_handle *phandle, char *clock_name, u64 rate)
+{
+	if (!phandle) {
+		pr_err("invalid input power handle\n");
+		return -EINVAL;
+	} else if (!phandle->mmrm_enable) {
+		pr_debug("mmrm disabled, return early\n");
+		return 0;
+	}
+
+	mutex_lock(&phandle->phandle_lock);
+	phandle->mmrm_reserve.clk_rate = rate;
+	strlcpy(phandle->mmrm_reserve.clk_name, clock_name,
+			sizeof(phandle->mmrm_reserve.clk_name));
+	mutex_unlock(&phandle->phandle_lock);
+
+	return 0;
+}
+
 int sde_power_clk_set_rate(struct sde_power_handle *phandle, char *clock_name,
 	u64 rate, u32 flags)
 {

+ 23 - 0
msm/sde_power_handle.h

@@ -147,6 +147,16 @@ struct sde_power_event {
 	bool active;
 };
 
+/*
+ * struct sde_power_mmrm_reserve - mmrm resource reservation for clk and bw
+ * @clk_name: name of resource reservation clock
+ * @clk_rate: resource reservation clock rate
+ */
+struct sde_power_mmrm_reserve {
+	char clk_name[32];
+	u64 clk_rate;
+};
+
 /**
  * struct sde_power_handle: power handle main struct
  * @mp:		module power for clock and regulator
@@ -159,6 +169,7 @@ struct sde_power_event {
  * @rsc_client_init: boolean to control rsc client create
  * @mmrm_enable: boolean to indicate if mmrm is enabled
  * @ib_quota: ib quota of the given bus
+ * @mmrm_reserve: mmrm resource reservation
  */
 struct sde_power_handle {
 	struct dss_module_power mp;
@@ -173,6 +184,8 @@ struct sde_power_handle {
 	bool rsc_client_init;
 	bool mmrm_enable;
 	u64 ib_quota[SDE_POWER_HANDLE_DBUS_ID_MAX];
+
+	struct sde_power_mmrm_reserve mmrm_reserve;
 };
 
 /**
@@ -226,6 +239,16 @@ int sde_power_scale_reg_bus(struct sde_power_handle *phandle,
 int sde_power_data_bus_state_update(struct sde_power_handle *phandle,
 							bool enable);
 
+/**
+ * sde_power_clk_reserve_rate() - reserve the clock rate with mmrm
+ * @pdata:  power handle containing the resources
+ * @clock_name: clock name which needs rate update.
+ * @rate:       Requested rate.
+ *
+ * Return: error code.
+ */
+int sde_power_clk_reserve_rate(struct sde_power_handle *pdata, char *clock_name, u64 rate);
+
 /**
  * sde_power_clk_set_rate() - set the clock rate
  * @pdata:  power handle containing the resources