Merge "msm: vidc: Add support for Cx ipeak limitation"

This commit is contained in:
Linux Build Service Account 2017-03-02 08:27:02 -08:00 committed by Gerrit - the friendly Code Review server
commit 2caf0b2fcd
4 changed files with 84 additions and 16 deletions

View file

@ -135,6 +135,12 @@ value is typically max(latencies of every cluster at all power levels) + 1
- qcom,power-conf = Indicates the value at which or beyond, a video session - qcom,power-conf = Indicates the value at which or beyond, a video session
is configured in low power mode to have power benefits. Value is defined is configured in low power mode to have power benefits. Value is defined
interms of HxW of the video session beyond which power benefit is desired. interms of HxW of the video session beyond which power benefit is desired.
- qcom,cx-ipeak-data : phandle of cx_ipeak device node and bit position on
the cx register where venus is supposed to vote
- qcom,clock-freq-threshold : Operating threshold frequency of venus which
video driver uses to check against the frequency voted. Whenever venus
clock frequency crosses this mark, driver intimates cx ipeak driver on
supported targets.
[Second level nodes] [Second level nodes]
Context Banks Context Banks

View file

@ -22,6 +22,7 @@
#include "msm_vidc_res_parse.h" #include "msm_vidc_res_parse.h"
#include "venus_boot.h" #include "venus_boot.h"
#include "soc/qcom/secure_buffer.h" #include "soc/qcom/secure_buffer.h"
#include "soc/qcom/cx_ipeak.h"
enum clock_properties { enum clock_properties {
CLOCK_PROP_HAS_SCALING = 1 << 0, CLOCK_PROP_HAS_SCALING = 1 << 0,
@ -171,6 +172,8 @@ void msm_vidc_free_platform_resources(
msm_vidc_free_qdss_addr_table(res); msm_vidc_free_qdss_addr_table(res);
msm_vidc_free_bus_vectors(res); msm_vidc_free_bus_vectors(res);
msm_vidc_free_buffer_usage_table(res); msm_vidc_free_buffer_usage_table(res);
cx_ipeak_unregister(res->cx_ipeak_context);
res->cx_ipeak_context = NULL;
} }
static int msm_vidc_load_reg_table(struct msm_vidc_platform_resources *res) static int msm_vidc_load_reg_table(struct msm_vidc_platform_resources *res)
@ -1133,8 +1136,36 @@ int read_platform_resources_from_dt(
of_property_read_u32(pdev->dev.of_node, of_property_read_u32(pdev->dev.of_node,
"qcom,max-secure-instances", "qcom,max-secure-instances",
&res->max_secure_inst_count); &res->max_secure_inst_count);
res->cx_ipeak_context = cx_ipeak_register(pdev->dev.of_node,
"qcom,cx-ipeak-data");
if (IS_ERR(res->cx_ipeak_context)) {
rc = PTR_ERR(res->cx_ipeak_context);
if (rc == -EPROBE_DEFER)
dprintk(VIDC_INFO,
"cx-ipeak register failed. Deferring probe!");
else
dprintk(VIDC_ERR,
"cx-ipeak register failed. rc: %d", rc);
res->cx_ipeak_context = NULL;
goto err_register_cx_ipeak;
} else if (res->cx_ipeak_context) {
dprintk(VIDC_INFO, "cx-ipeak register successful");
} else {
dprintk(VIDC_INFO, "cx-ipeak register not implemented");
}
of_property_read_u32(pdev->dev.of_node,
"qcom,clock-freq-threshold",
&res->clk_freq_threshold);
dprintk(VIDC_DBG, "cx ipeak threshold frequency = %u\n",
res->clk_freq_threshold);
return rc; return rc;
err_register_cx_ipeak:
err_setup_legacy_cb: err_setup_legacy_cb:
err_load_max_hw_load: err_load_max_hw_load:
msm_vidc_free_allowed_clocks_table(res); msm_vidc_free_allowed_clocks_table(res);

View file

@ -17,6 +17,7 @@
#include <linux/devfreq.h> #include <linux/devfreq.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <media/msm_vidc.h> #include <media/msm_vidc.h>
#include "soc/qcom/cx_ipeak.h"
#define MAX_BUFFER_TYPES 32 #define MAX_BUFFER_TYPES 32
struct platform_version_table { struct platform_version_table {
@ -191,6 +192,8 @@ struct msm_vidc_platform_resources {
uint32_t pm_qos_latency_us; uint32_t pm_qos_latency_us;
uint32_t max_inst_count; uint32_t max_inst_count;
uint32_t max_secure_inst_count; uint32_t max_secure_inst_count;
uint32_t clk_freq_threshold;
struct cx_ipeak_client *cx_ipeak_context;
}; };
static inline bool is_iommu_present(struct msm_vidc_platform_resources *res) static inline bool is_iommu_present(struct msm_vidc_platform_resources *res)

View file

@ -27,6 +27,7 @@
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <soc/qcom/cx_ipeak.h>
#include <soc/qcom/scm.h> #include <soc/qcom/scm.h>
#include <soc/qcom/smem.h> #include <soc/qcom/smem.h>
#include <soc/qcom/subsystem_restart.h> #include <soc/qcom/subsystem_restart.h>
@ -1385,6 +1386,39 @@ static int __halt_axi(struct venus_hfi_device *device)
return rc; return rc;
} }
static int __set_clk_rate(struct venus_hfi_device *device,
struct clock_info *cl, u64 rate) {
int rc = 0, rc1 = 0;
u64 toggle_freq = device->res->clk_freq_threshold;
struct cx_ipeak_client *ipeak = device->res->cx_ipeak_context;
struct clk *clk = cl->clk;
if (device->clk_freq < toggle_freq && rate >= toggle_freq) {
rc1 = cx_ipeak_update(ipeak, true);
dprintk(VIDC_PROF, "Voting up: %d\n", rc);
}
rc = clk_set_rate(clk, rate);
if (rc)
dprintk(VIDC_ERR,
"%s: Failed to set clock rate %llu %s: %d\n",
__func__, rate, cl->name, rc);
if (device->clk_freq >= toggle_freq && rate < toggle_freq) {
rc1 = cx_ipeak_update(ipeak, false);
dprintk(VIDC_PROF, "Voting down: %d\n", rc);
}
if (rc1)
dprintk(VIDC_ERR,
"cx_ipeak_update failed! ipeak %pK\n", ipeak);
if (!rc)
device->clk_freq = rate;
return rc;
}
static int __scale_clocks_cycles_per_mb(struct venus_hfi_device *device, static int __scale_clocks_cycles_per_mb(struct venus_hfi_device *device,
struct vidc_clk_scale_data *data, unsigned long instant_bitrate) struct vidc_clk_scale_data *data, unsigned long instant_bitrate)
{ {
@ -1458,14 +1492,10 @@ get_clock_freq:
if (!cl->has_scaling) if (!cl->has_scaling)
continue; continue;
device->clk_freq = rate; rc = __set_clk_rate(device, cl, rate);
rc = clk_set_rate(cl->clk, rate); if (rc)
if (rc) {
dprintk(VIDC_ERR,
"%s: Failed to set clock rate %llu %s: %d\n",
__func__, rate, cl->name, rc);
return rc; return rc;
}
if (!strcmp(cl->name, "core_clk")) if (!strcmp(cl->name, "core_clk"))
device->scaled_rate = rate; device->scaled_rate = rate;
@ -1506,14 +1536,11 @@ static int __scale_clocks_load(struct venus_hfi_device *device, int load,
load, data, load, data,
instant_bitrate); instant_bitrate);
} }
device->clk_freq = rate;
rc = clk_set_rate(cl->clk, rate); rc = __set_clk_rate(device, cl, rate);
if (rc) { if (rc)
dprintk(VIDC_ERR,
"Failed to set clock rate %lu %s: %d\n",
rate, cl->name, rc);
return rc; return rc;
}
if (!strcmp(cl->name, "core_clk")) if (!strcmp(cl->name, "core_clk"))
device->scaled_rate = rate; device->scaled_rate = rate;
@ -3794,7 +3821,8 @@ static inline int __prepare_enable_clks(struct venus_hfi_device *device)
* it to the lowest frequency possible * it to the lowest frequency possible
*/ */
if (cl->has_scaling) if (cl->has_scaling)
clk_set_rate(cl->clk, clk_round_rate(cl->clk, 0)); __set_clk_rate(device, cl,
clk_round_rate(cl->clk, 0));
if (cl->has_mem_retention) { if (cl->has_mem_retention) {
rc = clk_set_flags(cl->clk, CLKFLAG_NORETAIN_PERIPH); rc = clk_set_flags(cl->clk, CLKFLAG_NORETAIN_PERIPH);