Loading Documentation/devicetree/bindings/media/video/msm-vidc-bus.txt 0 → 100644 +25 −0 Original line number Diff line number Diff line * Qualcomm Technologies Inc MSM VIDC BUS Required properties: - compatible : "qcom,msm-vidc,governor,table" - name : name of the governor. - qcom,bus-table : the table comprised of load (macro blocks per second), frequency (KBps) and codec type (u32) to select appropriate bus frequency for a given load and codec type. Example: venus-ddr-gov { compatible = "qcom,msm-vidc,governor,table"; name = "qcom,venus-gov"; qcom,bus-table = /* Encoders */ <244800 787456 0x55555555>, /* 1080p30E */ <108000 350208 0x55555555>, /* 720p30E */ <0 0 0x55555555>, /* Decoders */ <244800 618496 0xffffffff>, /* 1080p30D */ <108000 314368 0xffffffff>, /* 720p30D */ <0 0 0xffffffff>; }; drivers/media/platform/msm/vidc/governors/Makefile +2 −1 Original line number Diff line number Diff line ccflags-y := -I$(srctree)/drivers/devfreq/ \ -I$(srctree)/drivers/media/platform/msm/vidc/ obj-$(CONFIG_MSM_VIDC_GOVERNORS) := msm_vidc_bw_gov.o obj-$(CONFIG_MSM_VIDC_GOVERNORS) := msm_vidc_dyn_gov.o \ msm_vidc_table_gov.o drivers/media/platform/msm/vidc/governors/msm_vidc_bw_gov.c→drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c +1 −0 Original line number Diff line number Diff line Loading @@ -860,6 +860,7 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, vmem.dpb_read = temp; } else if (scenario != SCENARIO_AVERAGE) { fp_t temp = fp_mult(one_frame_bw_dpb, FP_INT(2)); temp = fp_mult(temp, FP_INT(search_window_factor_bw_b * available_vmem_b)); temp = fp_div(temp, FP_INT(6)); Loading drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c 0 → 100644 +241 −0 Original line number Diff line number Diff line /* Copyright (c) 2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <linux/module.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/string.h> #include "governor.h" #include "msm_vidc_debug.h" #include "msm_vidc_internal.h" #include "venus_hfi.h" struct msm_vidc_bus_table_gov { struct { u32 load, freq, codecs; } *bus_table; int bus_table_size; struct devfreq_governor devfreq_gov; }; int msm_vidc_table_get_target_freq(struct devfreq *dev, unsigned long *freq, u32 *flag) { struct devfreq_dev_status status = {0}; struct msm_vidc_gov_data *vidc_data = NULL; struct msm_vidc_bus_table_gov *gov = NULL; enum vidc_vote_data_session sess_type = 0; u32 load = 0, i = 0, j = 0; if (!dev || !freq || !flag) { dprintk(VIDC_ERR, "%s: Invalid params %p, %p, %p\n", __func__, dev, freq, flag); return -EINVAL; } gov = container_of(dev->governor, struct msm_vidc_bus_table_gov, devfreq_gov); dev->profile->get_dev_status(dev->dev.parent, &status); vidc_data = (struct msm_vidc_gov_data *)status.private_data; *freq = 0; for (i = 0; i < vidc_data->data_count; ++i) { struct vidc_bus_vote_data *curr = &vidc_data->data[i]; u32 frequency = 0; load = NUM_MBS_PER_SEC(curr->width, curr->height, curr->fps); sess_type = VIDC_VOTE_DATA_SESSION_VAL( curr->codec, curr->domain); if (curr->power_mode == VIDC_POWER_TURBO) { dprintk(VIDC_DBG, "found turbo session[%d] %#x\n", i, sess_type); *freq = INT_MAX; goto exit; } /* * loop over bus table and select frequency of * matching session and appropriate load */ for (j = gov->bus_table_size - 1; j >= 0; --j) { bool matches = venus_hfi_is_session_supported( gov->bus_table[j].codecs, sess_type); if (!matches) continue; frequency = gov->bus_table[j].freq; if (load <= gov->bus_table[j].load) break; } *freq += frequency; dprintk(VIDC_DBG, "session[%d] %#x, wxh %dx%d, fps %d, load %d, freq %d, total_freq %ld\n", i, sess_type, curr->width, curr->height, curr->fps, load, frequency, *freq); } exit: return 0; } int msm_vidc_table_event_handler(struct devfreq *devfreq, unsigned int event, void *data) { int rc = 0; if (!devfreq) { dprintk(VIDC_ERR, "%s: NULL devfreq\n", __func__); return -EINVAL; } switch (event) { case DEVFREQ_GOV_START: case DEVFREQ_GOV_RESUME: mutex_lock(&devfreq->lock); rc = update_devfreq(devfreq); mutex_unlock(&devfreq->lock); break; } return rc; } static int msm_vidc_load_bus_table(struct platform_device *pdev, struct msm_vidc_bus_table_gov *data) { int c = 0; const char *name = NULL; if (!pdev || !data) { dprintk(VIDC_ERR, "%s: invalid args %p %p\n", __func__, pdev, data); return -EINVAL; } of_property_read_string(pdev->dev.of_node, "name", &name); if (strlen(name) > ARRAY_SIZE(data->devfreq_gov.name) - 1) { dprintk(VIDC_ERR, "%s: name is too long, max should be %zu chars\n", __func__, ARRAY_SIZE(data->devfreq_gov.name) - 1); return -EINVAL; } strlcpy((char *)data->devfreq_gov.name, name, ARRAY_SIZE(data->devfreq_gov.name)); data->devfreq_gov.get_target_freq = msm_vidc_table_get_target_freq; data->devfreq_gov.event_handler = msm_vidc_table_event_handler; data->bus_table_size = of_property_count_elems_of_size( pdev->dev.of_node, "qcom,bus-table", sizeof(*data->bus_table)); if (data->bus_table_size <= 0) { dprintk(VIDC_ERR, "%s: invalid bus table size %d\n", __func__, data->bus_table_size); return -EINVAL; } data->bus_table = devm_kcalloc(&pdev->dev, data->bus_table_size, sizeof(*data->bus_table), GFP_KERNEL); if (!data->bus_table) { dprintk(VIDC_ERR, "%s: allocation failed\n", __func__); return -ENOMEM; } of_property_read_u32_array(pdev->dev.of_node, "qcom,bus-table", (u32 *)data->bus_table, sizeof(*data->bus_table) / sizeof(u32) * data->bus_table_size); dprintk(VIDC_DBG, "%s: bus table:\n", __func__); for (c = 0; c < data->bus_table_size; ++c) dprintk(VIDC_DBG, "%8d %8d %#x\n", data->bus_table[c].load, data->bus_table[c].freq, data->bus_table[c].codecs); return 0; } static int msm_vidc_bus_table_probe(struct platform_device *pdev) { int rc = 0; struct msm_vidc_bus_table_gov *gov = NULL; dprintk(VIDC_DBG, "%s\n", __func__); gov = devm_kzalloc(&pdev->dev, sizeof(*gov), GFP_KERNEL); if (!gov) { dprintk(VIDC_ERR, "%s: allocation failed\n", __func__); return -ENOMEM; } platform_set_drvdata(pdev, gov); rc = msm_vidc_load_bus_table(pdev, gov); if (rc) return rc; rc = devfreq_add_governor(&gov->devfreq_gov); if (rc) dprintk(VIDC_ERR, "%s: add governor failed\n", __func__); return rc; } static int msm_vidc_bus_table_remove(struct platform_device *pdev) { int rc = 0; struct msm_vidc_bus_table_gov *gov = NULL; dprintk(VIDC_DBG, "%s\n", __func__); gov = platform_get_drvdata(pdev); if (IS_ERR_OR_NULL(gov)) return PTR_ERR(gov); rc = devfreq_remove_governor(&gov->devfreq_gov); return rc; } static const struct of_device_id device_id[] = { {.compatible = "qcom,msm-vidc,governor,table"}, {} }; static struct platform_driver msm_vidc_bus_table_driver = { .probe = msm_vidc_bus_table_probe, .remove = msm_vidc_bus_table_remove, .driver = { .name = "msm_vidc_bus_table_governor", .owner = THIS_MODULE, .of_match_table = device_id, }, }; static int __init msm_vidc_bus_table_init(void) { dprintk(VIDC_DBG, "%s\n", __func__); return platform_driver_register(&msm_vidc_bus_table_driver); } module_init(msm_vidc_bus_table_init); static void __exit msm_vidc_bus_table_exit(void) { dprintk(VIDC_DBG, "%s\n", __func__); platform_driver_unregister(&msm_vidc_bus_table_driver); } module_exit(msm_vidc_bus_table_exit); MODULE_LICENSE("GPL v2"); drivers/media/platform/msm/vidc/venus_hfi.c +6 −0 Original line number Diff line number Diff line Loading @@ -733,6 +733,12 @@ static bool __is_session_supported(unsigned long sessions_supported, return same_codec && same_session_type; } bool venus_hfi_is_session_supported(unsigned long sessions_supported, enum vidc_vote_data_session session_type) { return __is_session_supported(sessions_supported, session_type); } static int __devfreq_target(struct device *devfreq_dev, unsigned long *freq, u32 flags) { Loading Loading
Documentation/devicetree/bindings/media/video/msm-vidc-bus.txt 0 → 100644 +25 −0 Original line number Diff line number Diff line * Qualcomm Technologies Inc MSM VIDC BUS Required properties: - compatible : "qcom,msm-vidc,governor,table" - name : name of the governor. - qcom,bus-table : the table comprised of load (macro blocks per second), frequency (KBps) and codec type (u32) to select appropriate bus frequency for a given load and codec type. Example: venus-ddr-gov { compatible = "qcom,msm-vidc,governor,table"; name = "qcom,venus-gov"; qcom,bus-table = /* Encoders */ <244800 787456 0x55555555>, /* 1080p30E */ <108000 350208 0x55555555>, /* 720p30E */ <0 0 0x55555555>, /* Decoders */ <244800 618496 0xffffffff>, /* 1080p30D */ <108000 314368 0xffffffff>, /* 720p30D */ <0 0 0xffffffff>; };
drivers/media/platform/msm/vidc/governors/Makefile +2 −1 Original line number Diff line number Diff line ccflags-y := -I$(srctree)/drivers/devfreq/ \ -I$(srctree)/drivers/media/platform/msm/vidc/ obj-$(CONFIG_MSM_VIDC_GOVERNORS) := msm_vidc_bw_gov.o obj-$(CONFIG_MSM_VIDC_GOVERNORS) := msm_vidc_dyn_gov.o \ msm_vidc_table_gov.o
drivers/media/platform/msm/vidc/governors/msm_vidc_bw_gov.c→drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c +1 −0 Original line number Diff line number Diff line Loading @@ -860,6 +860,7 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, vmem.dpb_read = temp; } else if (scenario != SCENARIO_AVERAGE) { fp_t temp = fp_mult(one_frame_bw_dpb, FP_INT(2)); temp = fp_mult(temp, FP_INT(search_window_factor_bw_b * available_vmem_b)); temp = fp_div(temp, FP_INT(6)); Loading
drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c 0 → 100644 +241 −0 Original line number Diff line number Diff line /* Copyright (c) 2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <linux/module.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/string.h> #include "governor.h" #include "msm_vidc_debug.h" #include "msm_vidc_internal.h" #include "venus_hfi.h" struct msm_vidc_bus_table_gov { struct { u32 load, freq, codecs; } *bus_table; int bus_table_size; struct devfreq_governor devfreq_gov; }; int msm_vidc_table_get_target_freq(struct devfreq *dev, unsigned long *freq, u32 *flag) { struct devfreq_dev_status status = {0}; struct msm_vidc_gov_data *vidc_data = NULL; struct msm_vidc_bus_table_gov *gov = NULL; enum vidc_vote_data_session sess_type = 0; u32 load = 0, i = 0, j = 0; if (!dev || !freq || !flag) { dprintk(VIDC_ERR, "%s: Invalid params %p, %p, %p\n", __func__, dev, freq, flag); return -EINVAL; } gov = container_of(dev->governor, struct msm_vidc_bus_table_gov, devfreq_gov); dev->profile->get_dev_status(dev->dev.parent, &status); vidc_data = (struct msm_vidc_gov_data *)status.private_data; *freq = 0; for (i = 0; i < vidc_data->data_count; ++i) { struct vidc_bus_vote_data *curr = &vidc_data->data[i]; u32 frequency = 0; load = NUM_MBS_PER_SEC(curr->width, curr->height, curr->fps); sess_type = VIDC_VOTE_DATA_SESSION_VAL( curr->codec, curr->domain); if (curr->power_mode == VIDC_POWER_TURBO) { dprintk(VIDC_DBG, "found turbo session[%d] %#x\n", i, sess_type); *freq = INT_MAX; goto exit; } /* * loop over bus table and select frequency of * matching session and appropriate load */ for (j = gov->bus_table_size - 1; j >= 0; --j) { bool matches = venus_hfi_is_session_supported( gov->bus_table[j].codecs, sess_type); if (!matches) continue; frequency = gov->bus_table[j].freq; if (load <= gov->bus_table[j].load) break; } *freq += frequency; dprintk(VIDC_DBG, "session[%d] %#x, wxh %dx%d, fps %d, load %d, freq %d, total_freq %ld\n", i, sess_type, curr->width, curr->height, curr->fps, load, frequency, *freq); } exit: return 0; } int msm_vidc_table_event_handler(struct devfreq *devfreq, unsigned int event, void *data) { int rc = 0; if (!devfreq) { dprintk(VIDC_ERR, "%s: NULL devfreq\n", __func__); return -EINVAL; } switch (event) { case DEVFREQ_GOV_START: case DEVFREQ_GOV_RESUME: mutex_lock(&devfreq->lock); rc = update_devfreq(devfreq); mutex_unlock(&devfreq->lock); break; } return rc; } static int msm_vidc_load_bus_table(struct platform_device *pdev, struct msm_vidc_bus_table_gov *data) { int c = 0; const char *name = NULL; if (!pdev || !data) { dprintk(VIDC_ERR, "%s: invalid args %p %p\n", __func__, pdev, data); return -EINVAL; } of_property_read_string(pdev->dev.of_node, "name", &name); if (strlen(name) > ARRAY_SIZE(data->devfreq_gov.name) - 1) { dprintk(VIDC_ERR, "%s: name is too long, max should be %zu chars\n", __func__, ARRAY_SIZE(data->devfreq_gov.name) - 1); return -EINVAL; } strlcpy((char *)data->devfreq_gov.name, name, ARRAY_SIZE(data->devfreq_gov.name)); data->devfreq_gov.get_target_freq = msm_vidc_table_get_target_freq; data->devfreq_gov.event_handler = msm_vidc_table_event_handler; data->bus_table_size = of_property_count_elems_of_size( pdev->dev.of_node, "qcom,bus-table", sizeof(*data->bus_table)); if (data->bus_table_size <= 0) { dprintk(VIDC_ERR, "%s: invalid bus table size %d\n", __func__, data->bus_table_size); return -EINVAL; } data->bus_table = devm_kcalloc(&pdev->dev, data->bus_table_size, sizeof(*data->bus_table), GFP_KERNEL); if (!data->bus_table) { dprintk(VIDC_ERR, "%s: allocation failed\n", __func__); return -ENOMEM; } of_property_read_u32_array(pdev->dev.of_node, "qcom,bus-table", (u32 *)data->bus_table, sizeof(*data->bus_table) / sizeof(u32) * data->bus_table_size); dprintk(VIDC_DBG, "%s: bus table:\n", __func__); for (c = 0; c < data->bus_table_size; ++c) dprintk(VIDC_DBG, "%8d %8d %#x\n", data->bus_table[c].load, data->bus_table[c].freq, data->bus_table[c].codecs); return 0; } static int msm_vidc_bus_table_probe(struct platform_device *pdev) { int rc = 0; struct msm_vidc_bus_table_gov *gov = NULL; dprintk(VIDC_DBG, "%s\n", __func__); gov = devm_kzalloc(&pdev->dev, sizeof(*gov), GFP_KERNEL); if (!gov) { dprintk(VIDC_ERR, "%s: allocation failed\n", __func__); return -ENOMEM; } platform_set_drvdata(pdev, gov); rc = msm_vidc_load_bus_table(pdev, gov); if (rc) return rc; rc = devfreq_add_governor(&gov->devfreq_gov); if (rc) dprintk(VIDC_ERR, "%s: add governor failed\n", __func__); return rc; } static int msm_vidc_bus_table_remove(struct platform_device *pdev) { int rc = 0; struct msm_vidc_bus_table_gov *gov = NULL; dprintk(VIDC_DBG, "%s\n", __func__); gov = platform_get_drvdata(pdev); if (IS_ERR_OR_NULL(gov)) return PTR_ERR(gov); rc = devfreq_remove_governor(&gov->devfreq_gov); return rc; } static const struct of_device_id device_id[] = { {.compatible = "qcom,msm-vidc,governor,table"}, {} }; static struct platform_driver msm_vidc_bus_table_driver = { .probe = msm_vidc_bus_table_probe, .remove = msm_vidc_bus_table_remove, .driver = { .name = "msm_vidc_bus_table_governor", .owner = THIS_MODULE, .of_match_table = device_id, }, }; static int __init msm_vidc_bus_table_init(void) { dprintk(VIDC_DBG, "%s\n", __func__); return platform_driver_register(&msm_vidc_bus_table_driver); } module_init(msm_vidc_bus_table_init); static void __exit msm_vidc_bus_table_exit(void) { dprintk(VIDC_DBG, "%s\n", __func__); platform_driver_unregister(&msm_vidc_bus_table_driver); } module_exit(msm_vidc_bus_table_exit); MODULE_LICENSE("GPL v2");
drivers/media/platform/msm/vidc/venus_hfi.c +6 −0 Original line number Diff line number Diff line Loading @@ -733,6 +733,12 @@ static bool __is_session_supported(unsigned long sessions_supported, return same_codec && same_session_type; } bool venus_hfi_is_session_supported(unsigned long sessions_supported, enum vidc_vote_data_session session_type) { return __is_session_supported(sessions_supported, session_type); } static int __devfreq_target(struct device *devfreq_dev, unsigned long *freq, u32 flags) { Loading