From 6092206a1214013095777a45aad40db588b4eab2 Mon Sep 17 00:00:00 2001 From: Christina Oliveira Date: Mon, 8 Feb 2021 12:55:12 -0800 Subject: [PATCH] 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 --- msm/dp/dp_ctrl.c | 2 +- msm/dp/dp_debug.c | 49 +++++++++++++++++++++++++++++++++++++++++++++ msm/dp/dp_debug.h | 4 +++- msm/dp/dp_display.c | 30 +++++++++++++++++++++++++++ msm/dp/dp_display.h | 5 +++++ msm/dp/dp_parser.c | 14 +++++++++---- msm/dp/dp_power.c | 27 ++++++++++++++++++++++++- msm/dp/dp_power.h | 6 +++++- 8 files changed, 129 insertions(+), 8 deletions(-) diff --git a/msm/dp/dp_ctrl.c b/msm/dp/dp_ctrl.c index ae3aca628b..170ddce7a5 100644 --- a/msm/dp/dp_ctrl.c +++ b/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); diff --git a/msm/dp/dp_debug.c b/msm/dp/dp_debug.c index f5862980ed..930094fdcc 100644 --- a/msm/dp/dp_debug.c +++ b/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(¬ifier_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; diff --git a/msm/dp/dp_debug.h b/msm/dp/dp_debug.h index 67e9eceb7f..4a1cdf7dc3 100644 --- a/msm/dp/dp_debug.h +++ b/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; }; /** diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 5faf36ce42..d87cd89b2c 100644 --- a/msm/dp/dp_display.c +++ b/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)) { diff --git a/msm/dp/dp_display.h b/msm/dp/dp_display.h index 0417fa7c83..d4091933bf 100644 --- a/msm/dp/dp_display.h +++ b/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_ */ diff --git a/msm/dp/dp_parser.c b/msm/dp/dp_parser.c index b94133b5e0..9d935dfe60 100644 --- a/msm/dp/dp_parser.c +++ b/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 @@ -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 = diff --git a/msm/dp/dp_power.c b/msm/dp/dp_power.c index 1ece48e2fb..583381c1da 100644 --- a/msm/dp/dp_power.c +++ b/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 @@ -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: diff --git a/msm/dp/dp_power.h b/msm/dp/dp_power.h index 7a0302356d..0f0a728bb4 100644 --- a/msm/dp/dp_power.h +++ b/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)); }; /**