diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 3faeb1a102..25cb16d478 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "sde_connector.h" @@ -201,6 +202,8 @@ struct dp_display_private { u32 tot_dsc_blks_in_use; bool process_hpd_connect; + struct dev_pm_qos_request pm_qos_req[NR_CPUS]; + bool pm_qos_requested; struct notifier_block usb_nb; }; @@ -285,6 +288,36 @@ static void dp_audio_enable(struct dp_display_private *dp, bool enable) } } +static void dp_display_qos_request(struct dp_display_private *dp, bool add_vote) +{ + struct device *cpu_dev; + int cpu = 0; + struct cpumask *cpu_mask; + u32 latency = dp->parser->qos_cpu_latency; + unsigned long mask = dp->parser->qos_cpu_mask; + + if (!dp->parser->qos_cpu_mask || (dp->pm_qos_requested == add_vote)) + return; + + cpu_mask = to_cpumask(&mask); + for_each_cpu(cpu, cpu_mask) { + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) { + SDE_DEBUG("%s: failed to get cpu%d device\n", __func__, cpu); + continue; + } + + if (add_vote) + dev_pm_qos_add_request(cpu_dev, &dp->pm_qos_req[cpu], + DEV_PM_QOS_RESUME_LATENCY, latency); + else + dev_pm_qos_remove_request(&dp->pm_qos_req[cpu]); + } + + SDE_EVT32_EXTERNAL(add_vote, mask, latency); + dp->pm_qos_requested = add_vote; +} + static void dp_display_update_hdcp_status(struct dp_display_private *dp, bool reset) { @@ -499,6 +532,11 @@ static void dp_display_hdcp_process_state(struct dp_display_private *dp) dp->debug->force_encryption && ops && ops->force_encryption) ops->force_encryption(data, dp->debug->force_encryption); + if (status->hdcp_state == HDCP_STATE_AUTHENTICATED) + dp_display_qos_request(dp, false); + else + dp_display_qos_request(dp, true); + switch (status->hdcp_state) { case HDCP_STATE_INACTIVE: dp_display_hdcp_register_streams(dp); diff --git a/msm/dp/dp_parser.c b/msm/dp/dp_parser.c index a0bcee0e4f..6efcf30aca 100644 --- a/msm/dp/dp_parser.c +++ b/msm/dp/dp_parser.c @@ -742,6 +742,26 @@ static void dp_parser_dsc(struct dp_parser *parser) parser->dsc_continuous_pps); } +static void dp_parser_qos(struct dp_parser *parser) +{ + struct device *dev = &parser->pdev->dev; + u32 mask, latency; + int rc; + + rc = of_property_read_u32(dev->of_node, "qcom,qos-cpu-latency-us", &latency); + if (rc) + return; + + rc = of_property_read_u32(dev->of_node, "qcom,qos-cpu-mask", &mask); + if (rc) + return; + + parser->qos_cpu_mask = mask; + parser->qos_cpu_latency = latency; + + DP_DEBUG("qos parsing successful. mask:%x latency:%ld\n", mask, latency); +} + static void dp_parser_fec(struct dp_parser *parser) { struct device *dev = &parser->pdev->dev; @@ -817,6 +837,7 @@ static int dp_parser_parse(struct dp_parser *parser) dp_parser_dsc(parser); dp_parser_fec(parser); dp_parser_widebus(parser); + dp_parser_qos(parser); err: return rc; } diff --git a/msm/dp/dp_parser.h b/msm/dp/dp_parser.h index 678185705f..5a4e844ad7 100644 --- a/msm/dp/dp_parser.h +++ b/msm/dp/dp_parser.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_PARSER_H_ @@ -198,6 +198,8 @@ static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type) * @dsc_continuous_pps: PPS sent every frame by HW * @has_widebus: widebus (2PPC) feature eanble status *@mst_fixed_port: mst port_num reserved for fixed topology + * @qos_cpu_mask: CPU mask for QOS + * @qos_cpu_latency: CPU Latency setting for QOS * @parse: function to be called by client to parse device tree. * @get_io: function to be called by client to get io data. * @get_io_buf: function to be called by client to get io buffers. @@ -227,6 +229,8 @@ struct dp_parser { bool gpio_aux_switch; bool lphw_hpd; u32 mst_fixed_port[MAX_DP_MST_STREAMS]; + u32 qos_cpu_mask; + unsigned long qos_cpu_latency; int (*parse)(struct dp_parser *parser); struct dp_io_data *(*get_io)(struct dp_parser *parser, char *name);