Bladeren bron

disp: msm: dp: add support to request dp link clk through mmrm

This change adds the support to request the dp link clk rate
through the mmrm driver. In the case the system can not
support the rate, user space is notified of the failure and
dp is diconnected.

Change-Id: I4a074054ce42425ca940d4aec505723724736b44
Signed-off-by: Christina Oliveira <[email protected]>
Christina Oliveira 4 jaren geleden
bovenliggende
commit
6092206a12
8 gewijzigde bestanden met toevoegingen van 129 en 8 verwijderingen
  1. 1 1
      msm/dp/dp_ctrl.c
  2. 49 0
      msm/dp/dp_debug.c
  3. 3 1
      msm/dp/dp_debug.h
  4. 30 0
      msm/dp/dp_display.c
  5. 5 0
      msm/dp/dp_display.h
  6. 10 4
      msm/dp/dp_parser.c
  7. 26 1
      msm/dp/dp_power.c
  8. 5 1
      msm/dp/dp_power.h

+ 1 - 1
msm/dp/dp_ctrl.c

@@ -641,7 +641,7 @@ static int dp_ctrl_enable_link_clock(struct dp_ctrl_private *ctrl)
 
 	DP_DEBUG("rate=%d\n", rate);
 
-	dp_ctrl_set_clock_rate(ctrl, "link_clk", type, rate);
+	dp_ctrl_set_clock_rate(ctrl, "link_clk_src", type, rate);
 
 	if (ctrl->pll->pll_cfg) {
 		ret = ctrl->pll->pll_cfg(ctrl->pll, rate);

+ 49 - 0
msm/dp/dp_debug.c

@@ -43,6 +43,7 @@ struct dp_debug_private {
 	struct dp_parser *parser;
 	struct dp_ctrl *ctrl;
 	struct dp_pll *pll;
+	struct dp_display *display;
 	struct mutex lock;
 };
 
@@ -619,6 +620,41 @@ end:
 	return len;
 }
 
+static ssize_t dp_debug_mmrm_clk_cb_write(struct file *file,
+		 const char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char buf[SZ_8];
+	size_t len = 0;
+	struct dss_clk_mmrm_cb mmrm_cb_data;
+	struct mmrm_client_notifier_data notifier_data;
+	struct dp_display *dp_display = debug->display;
+	int cb_type;
+
+	if (!debug)
+		return -ENODEV;
+	if (*ppos)
+		return 0;
+	len = min_t(size_t, count, SZ_8 - 1);
+	if (copy_from_user(buf, user_buff, len))
+		return 0;
+
+	buf[len] = '\0';
+
+	if (kstrtoint(buf, 10, &cb_type) != 0)
+		return 0;
+	if (cb_type != MMRM_CLIENT_RESOURCE_VALUE_CHANGE)
+		return 0;
+
+	notifier_data.cb_type = MMRM_CLIENT_RESOURCE_VALUE_CHANGE;
+	mmrm_cb_data.phandle = (void *)dp_display;
+	notifier_data.pvt_data = (void *)&mmrm_cb_data;
+
+	dp_display_mmrm_callback(&notifier_data);
+
+	return len;
+}
+
 static ssize_t dp_debug_bw_code_write(struct file *file,
 		const char __user *user_buff, size_t count, loff_t *ppos)
 {
@@ -1889,6 +1925,11 @@ static const struct file_operations hdcp_fops = {
 	.read = dp_debug_read_hdcp,
 };
 
+static const struct file_operations mmrm_clk_cb_fops = {
+	.open = simple_open,
+	.write = dp_debug_mmrm_clk_cb_write,
+};
+
 static int dp_debug_init_mst(struct dp_debug_private *debug, struct dentry *dir)
 {
 	int rc = 0;
@@ -1981,6 +2022,13 @@ static int dp_debug_init_link(struct dp_debug_private *debug,
 
 	debugfs_create_u32("link_bw_code", 0644, dir, &debug->panel->link_bw_code);
 
+	file = debugfs_create_file("mmrm_clk_cb", 0644, dir, debug, &mmrm_clk_cb_fops);
+	if (IS_ERR_OR_NULL(file)) {
+		rc = PTR_ERR(file);
+		DP_ERR("[%s] debugfs mmrm_clk_cb failed, rc=%d\n", DEBUG_NAME, rc);
+		return rc;
+	}
+
 	return rc;
 }
 
@@ -2429,6 +2477,7 @@ struct dp_debug *dp_debug_get(struct dp_debug_in *in)
 	debug->parser = in->parser;
 	debug->ctrl = in->ctrl;
 	debug->pll = in->pll;
+	debug->display = in->display;
 
 	dp_debug = &debug->dp_debug;
 	dp_debug->vdisplay = 0;

+ 3 - 1
msm/dp/dp_debug.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _DP_DEBUG_H_
@@ -115,6 +115,7 @@ struct dp_debug {
  * @parser: instance of parser module
  * @ctrl: instance of controller module
  * @pll: instance of pll module
+ * @display: instance of display module
  */
 struct dp_debug_in {
 	struct device *dev;
@@ -127,6 +128,7 @@ struct dp_debug_in {
 	struct dp_parser *parser;
 	struct dp_ctrl *ctrl;
 	struct dp_pll *pll;
+	struct dp_display *display;
 };
 
 /**

+ 30 - 0
msm/dp/dp_display.c

@@ -1836,6 +1836,28 @@ static void dp_display_register_usb_notifier(struct dp_display_private *dp)
 		DP_DEBUG("failed to register for usb event: %d\n", rc);
 }
 
+int dp_display_mmrm_callback(struct mmrm_client_notifier_data *notifier_data)
+{
+	struct dss_clk_mmrm_cb *mmrm_cb_data = (struct dss_clk_mmrm_cb *)notifier_data->pvt_data;
+	struct dp_display *dp_display = (struct dp_display *)mmrm_cb_data->phandle;
+	struct dp_display_private *dp =
+		container_of(dp_display, struct dp_display_private, dp_display);
+	int ret = 0;
+
+	SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state, notifier_data->cb_type);
+	if (notifier_data->cb_type == MMRM_CLIENT_RESOURCE_VALUE_CHANGE
+				&& dp_display_state_is(DP_STATE_ENABLED)
+				&& !dp_display_state_is(DP_STATE_ABORTED)) {
+		ret = dp_display_handle_disconnect(dp);
+		if (ret)
+			DP_ERR("mmrm callback error reducing clk, ret:%d\n", ret);
+	}
+
+	DP_DEBUG("mmrm callback handled, state: 0x%x rc:%d\n", dp->state, ret);
+	SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state, notifier_data->cb_type);
+	return ret;
+}
+
 static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
 {
 	dp_debug_put(dp->debug);
@@ -1940,6 +1962,13 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
 		goto error_link;
 	}
 
+	rc = dp->power->power_mmrm_init(dp->power, &dp->priv->phandle,
+		(void *)&dp->dp_display, dp_display_mmrm_callback);
+	if (rc) {
+		DP_ERR("failed to initialize mmrm, rc = %d\n", rc);
+		goto error_link;
+	}
+
 	dp->link = dp_link_get(dev, dp->aux);
 	if (IS_ERR(dp->link)) {
 		rc = PTR_ERR(dp->link);
@@ -2014,6 +2043,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
 	debug_in.parser = dp->parser;
 	debug_in.ctrl = dp->ctrl;
 	debug_in.pll = dp->pll;
+	debug_in.display = &dp->dp_display;
 
 	dp->debug = dp_debug_get(&debug_in);
 	if (IS_ERR(dp->debug)) {

+ 5 - 0
msm/dp/dp_display.h

@@ -137,6 +137,7 @@ struct dp_display {
 int dp_display_get_num_of_displays(void);
 int dp_display_get_displays(void **displays, int count);
 int dp_display_get_num_of_streams(void);
+int dp_display_mmrm_callback(struct mmrm_client_notifier_data *notifier_data);
 #else
 static inline int dp_display_get_num_of_displays(void)
 {
@@ -155,5 +156,9 @@ static inline int dp_connector_update_pps(struct drm_connector *connector,
 {
 	return 0;
 }
+static inline int dp_display_mmrm_callback(struct mmrm_client_notifier_data *notifier_data)
+{
+	return 0;
+}
 #endif /* CONFIG_DRM_MSM_DP */
 #endif /* _DP_DISPLAY_H_ */

+ 10 - 4
msm/dp/dp_parser.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/of_gpio.h>
@@ -609,6 +609,7 @@ static int dp_parser_clock(struct dp_parser *parser)
 	int core_clk_count = 0, link_clk_count = 0;
 	int strm0_clk_index = 0, strm1_clk_index = 0;
 	int strm0_clk_count = 0, strm1_clk_count = 0;
+	int clock_mmrm = 0;
 	const char *clk_name;
 	const char *core_clk = "core";
 	const char *strm0_clk = "strm0";
@@ -656,11 +657,16 @@ static int dp_parser_clock(struct dp_parser *parser)
 				&link_power->clk_config[link_clk_index];
 			strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
 			link_clk_index++;
-
-			if (!strcmp(clk_name, "link_clk"))
+			clock_mmrm = 0;
+			of_property_read_u32_index(dev->of_node, "clock-mmrm", i, &clock_mmrm);
+			if (clock_mmrm) {
+				clk->type = DSS_CLK_MMRM;
+				clk->mmrm.clk_id = clock_mmrm;
+			} else if (!strcmp(clk_name, "link_clk")) {
 				clk->type = DSS_CLK_PCLK;
-			else
+			} else {
 				clk->type = DSS_CLK_AHB;
+			}
 		} else if (dp_parser_check_prefix(strm0_clk, clk_name) &&
 			   strm0_clk_index < strm0_clk_count) {
 			struct dss_clk *clk =

+ 26 - 1
msm/dp/dp_power.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/clk.h>
@@ -172,6 +172,8 @@ static void dp_power_clk_put(struct dp_power_private *power)
 		if (!pm->num_clk)
 			continue;
 
+		msm_dss_mmrm_deregister(&power->pdev->dev, pm);
+
 		msm_dss_put_clk(pm->clk_config, pm->num_clk);
 	}
 }
@@ -482,6 +484,28 @@ static int dp_power_config_gpios(struct dp_power_private *power, bool flip,
 	return 0;
 }
 
+static int dp_power_mmrm_init(struct dp_power *dp_power, struct sde_power_handle *phandle, void *dp,
+	int (*dp_display_mmrm_callback)(struct mmrm_client_notifier_data *notifier_data))
+{
+	int rc = 0;
+	enum dp_pm_type module;
+	struct dp_power_private *power = container_of(dp_power, struct dp_power_private, dp_power);
+	struct device *dev = &power->pdev->dev;
+
+	for (module = DP_CORE_PM; module < DP_MAX_PM; module++) {
+		struct dss_module_power *pm = &power->parser->mp[module];
+		if (!pm->num_clk)
+			continue;
+
+		rc = msm_dss_mmrm_register(dev, pm, dp_display_mmrm_callback,
+					dp, &phandle->mmrm_enable);
+		if (rc)
+			DP_ERR("mmrm register failed rc=%d\n", rc);
+	}
+
+	return rc;
+}
+
 static int dp_power_client_init(struct dp_power *dp_power,
 	struct sde_power_handle *phandle, struct drm_device *drm_dev)
 {
@@ -717,6 +741,7 @@ struct dp_power *dp_power_get(struct dp_parser *parser, struct dp_pll *pll)
 	dp_power->clk_get_rate = dp_power_clk_get_rate;
 	dp_power->power_client_init = dp_power_client_init;
 	dp_power->power_client_deinit = dp_power_client_deinit;
+	dp_power->power_mmrm_init = dp_power_mmrm_init;
 
 	return dp_power;
 error:

+ 5 - 1
msm/dp/dp_power.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _DP_POWER_H_
@@ -20,6 +20,7 @@
  * @clk_get_rate: get the current rate for provided clk_name
  * @power_client_init: configures clocks and regulators
  * @power_client_deinit: frees clock and regulator resources
+ * @power_mmrm_init: configures mmrm client registration
  */
 struct dp_power {
 	struct drm_device *drm_dev;
@@ -34,6 +35,9 @@ struct dp_power {
 		struct sde_power_handle *phandle,
 		struct drm_device *drm_dev);
 	void (*power_client_deinit)(struct dp_power *power);
+	int (*power_mmrm_init)(struct dp_power *power,
+                struct sde_power_handle *phandle, void *dp,
+		int (*dp_display_mmrm_callback)(struct mmrm_client_notifier_data *notifier_data));
 };
 
 /**