Loading drivers/media/platform/msm/vidc_3x/governors/msm_vidc_table_gov.c +6 −268 Original line number Diff line number Diff line Loading @@ -24,27 +24,6 @@ #include "../vidc_hfi_api.h" enum bus_profile { VIDC_BUS_PROFILE_NORMAL = BIT(0), VIDC_BUS_PROFILE_LOW = BIT(1), VIDC_BUS_PROFILE_UBWC = BIT(2), }; struct bus_profile_entry { struct { u32 load, freq; } *bus_table; u32 bus_table_size; u32 codec_mask; enum bus_profile profile; }; struct msm_vidc_bus_table_gov { struct bus_profile_entry *bus_prof_entries; u32 count; struct devfreq_governor devfreq_gov; }; static int __get_bus_freq(struct msm_vidc_bus_table_gov *gov, struct vidc_bus_vote_data *data, enum bus_profile profile) Loading Loading @@ -85,31 +64,19 @@ static int __get_bus_freq(struct msm_vidc_bus_table_gov *gov, } static int msm_vidc_table_get_target_freq(struct devfreq *dev, int msm_vidc_table_get_target_freq(struct msm_vidc_bus_table_gov *gov, struct msm_vidc_gov_data *vidc_data, unsigned long *frequency) { struct devfreq_dev_status status = {0}; struct msm_vidc_gov_data *vidc_data = NULL; struct msm_vidc_bus_table_gov *gov = NULL; enum bus_profile profile = 0; int i = 0; if (!dev || !frequency) { dprintk(VIDC_ERR, "%s: Invalid params %pK, %pK\n", __func__, dev, frequency); return -EINVAL; } gov = container_of(dev->governor, struct msm_vidc_bus_table_gov, devfreq_gov); if (!gov) { dprintk(VIDC_ERR, "%s: governor not found\n", __func__); if (!frequency || !gov || !vidc_data) { dprintk(VIDC_ERR, "%s: Invalid params %pK\n", __func__, frequency); return -EINVAL; } dev->profile->get_dev_status(dev->dev.parent, &status); vidc_data = (struct msm_vidc_gov_data *)status.private_data; *frequency = 0; for (i = 0; i < vidc_data->data_count; i++) { struct vidc_bus_vote_data *data = &vidc_data->data[i]; Loading Loading @@ -149,232 +116,3 @@ static int msm_vidc_table_get_target_freq(struct devfreq *dev, 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_free_bus_table(struct platform_device *pdev, struct msm_vidc_bus_table_gov *data) { int rc = 0, i = 0; if (!pdev || !data) { dprintk(VIDC_ERR, "%s: invalid args %pK %pK\n", __func__, pdev, data); return -EINVAL; } for (i = 0; i < data->count; i++) data->bus_prof_entries[i].bus_table = NULL; data->bus_prof_entries = NULL; data->count = 0; return rc; } static int msm_vidc_load_bus_table(struct platform_device *pdev, struct msm_vidc_bus_table_gov *data) { int rc = 0, i = 0, j = 0; const char *name = NULL; struct bus_profile_entry *entry = NULL; struct device_node *parent_node = NULL; struct device_node *child_node = NULL; if (!pdev || !data) { dprintk(VIDC_ERR, "%s: invalid args %pK %pK\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; parent_node = of_find_node_by_name(pdev->dev.of_node, "qcom,bus-freq-table"); if (!parent_node) { dprintk(VIDC_DBG, "Node qcom,bus-freq-table not found.\n"); return 0; } data->count = of_get_child_count(parent_node); if (!data->count) { dprintk(VIDC_DBG, "No child nodes in qcom,bus-freq-table\n"); return 0; } data->bus_prof_entries = devm_kzalloc(&pdev->dev, sizeof(*data->bus_prof_entries) * data->count, GFP_KERNEL); if (!data->bus_prof_entries) { dprintk(VIDC_DBG, "no memory to allocate bus_prof_entries\n"); return -ENOMEM; } for_each_child_of_node(parent_node, child_node) { if (i >= data->count) { dprintk(VIDC_ERR, "qcom,bus-freq-table: invalid child node %d, max is %d\n", i, data->count); break; } entry = &data->bus_prof_entries[i]; if (of_find_property(child_node, "qcom,codec-mask", NULL)) { rc = of_property_read_u32(child_node, "qcom,codec-mask", &entry->codec_mask); if (rc) { dprintk(VIDC_ERR, "qcom,codec-mask not found\n"); break; } } if (of_find_property(child_node, "qcom,low-power-mode", NULL)) entry->profile = VIDC_BUS_PROFILE_LOW; else if (of_find_property(child_node, "qcom,ubwc-mode", NULL)) entry->profile = VIDC_BUS_PROFILE_UBWC; else entry->profile = VIDC_BUS_PROFILE_NORMAL; if (of_find_property(child_node, "qcom,load-busfreq-tbl", NULL)) { rc = msm_vidc_load_u32_table(pdev, child_node, "qcom,load-busfreq-tbl", sizeof(*entry->bus_table), (u32 **)&entry->bus_table, &entry->bus_table_size); if (rc) { dprintk(VIDC_ERR, "qcom,load-busfreq-tbl failed\n"); break; } } else { entry->bus_table = NULL; entry->bus_table_size = 0; } dprintk(VIDC_DBG, "qcom,load-busfreq-tbl: size %d, codec_mask %#x, profile %#x\n", entry->bus_table_size, entry->codec_mask, entry->profile); for (j = 0; j < entry->bus_table_size; j++) dprintk(VIDC_DBG, " load %8d freq %8d\n", entry->bus_table[j].load, entry->bus_table[j].freq); i++; } return rc; } 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 = msm_vidc_free_bus_table(pdev, gov); if (rc) dprintk(VIDC_WARN, "%s: free bus table failed\n", __func__); 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", .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_3x/msm_vidc_res_parse.c +127 −0 Original line number Diff line number Diff line Loading @@ -72,7 +72,23 @@ static inline enum imem_type read_imem_type(struct platform_device *pdev) IMEM_NONE; } static inline void msm_vidc_free_bus_table( struct msm_vidc_platform_resources *res) { int i = 0; struct msm_vidc_bus_table_gov *data = res->gov_data; if (!data) { dprintk(VIDC_ERR, "%s: invalid args %pK\n", __func__, data); } for (i = 0; i < data->count; i++) data->bus_prof_entries[i].bus_table = NULL; data->bus_prof_entries = NULL; data->count = 0; } static inline void msm_vidc_free_allowed_clocks_table( struct msm_vidc_platform_resources *res) { Loading Loading @@ -174,6 +190,7 @@ void msm_vidc_free_platform_resources( struct msm_vidc_platform_resources *res) { msm_vidc_free_clock_table(res); msm_vidc_free_bus_table(res); msm_vidc_free_regulator_table(res); msm_vidc_free_freq_table(res); msm_vidc_free_platform_version_table(res); Loading Loading @@ -1065,7 +1082,108 @@ static int msm_vidc_load_clock_table( err_load_clk_table_fail: return rc; } static int msm_vidc_load_bus_table(struct msm_vidc_platform_resources *res) { int rc = 0, i = 0, j = 0; struct bus_profile_entry *entry = NULL; struct device_node *parent_node = NULL; struct device_node *child_node = NULL; struct msm_vidc_bus_table_gov *gov_data; struct platform_device *pdev = res->pdev; dprintk(VIDC_DBG, "%s\n", __func__); if (!pdev) { dprintk(VIDC_ERR, "%s: invalid args %pK\n", __func__, pdev); return -EINVAL; } res->gov_data = devm_kzalloc(&pdev->dev, sizeof(*gov_data), GFP_KERNEL); if (!res->gov_data) { dprintk(VIDC_ERR, "%s: allocation failed\n", __func__); return -ENOMEM; } gov_data = res->gov_data; parent_node = of_find_node_by_name(pdev->dev.of_node, "qcom,bus-freq-table"); if (!parent_node) { dprintk(VIDC_DBG, "Node qcom,bus-freq-table not found.\n"); return 0; } gov_data->count = of_get_child_count(parent_node); if (!gov_data->count) { dprintk(VIDC_DBG, "No child nodes in qcom,bus-freq-table\n"); return 0; } gov_data->bus_prof_entries = devm_kzalloc(&pdev->dev, sizeof(*gov_data->bus_prof_entries) * gov_data->count, GFP_KERNEL); if (!gov_data->bus_prof_entries) { dprintk(VIDC_DBG, "no memory to allocate bus_prof_entries\n"); return -ENOMEM; } for_each_child_of_node(parent_node, child_node) { if (i >= gov_data->count) { dprintk(VIDC_ERR, "qcom,bus-freq-table: invalid child node %d, max is %d\n", i, gov_data->count); break; } entry = &gov_data->bus_prof_entries[i]; if (of_find_property(child_node, "qcom,codec-mask", NULL)) { rc = of_property_read_u32(child_node, "qcom,codec-mask", &entry->codec_mask); if (rc) { dprintk(VIDC_ERR, "qcom,codec-mask not found\n"); break; } } if (of_find_property(child_node, "qcom,low-power-mode", NULL)) entry->profile = VIDC_BUS_PROFILE_LOW; else if (of_find_property(child_node, "qcom,ubwc-mode", NULL)) entry->profile = VIDC_BUS_PROFILE_UBWC; else entry->profile = VIDC_BUS_PROFILE_NORMAL; if (of_find_property(child_node, "qcom,load-busfreq-tbl", NULL)) { rc = msm_vidc_load_u32_table(pdev, child_node, "qcom,load-busfreq-tbl", sizeof(*entry->bus_table), (u32 **)&entry->bus_table, &entry->bus_table_size); if (rc) { dprintk(VIDC_ERR, "qcom,load-busfreq-tbl failed\n"); break; } } else { entry->bus_table = NULL; entry->bus_table_size = 0; } dprintk(VIDC_DBG, "qcom,load-busfreq-tbl: size %d, codec_mask %#x, profile %#x\n", entry->bus_table_size, entry->codec_mask, entry->profile); for (j = 0; j < entry->bus_table_size; j++) dprintk(VIDC_DBG, " load %8d freq %8d\n", entry->bus_table[j].load, entry->bus_table[j].freq); i++; } return rc; } int read_platform_resources_from_dt( struct msm_vidc_platform_resources *res) { Loading Loading @@ -1185,6 +1303,13 @@ int read_platform_resources_from_dt( goto err_load_allowed_clocks_table; } rc = msm_vidc_load_bus_table(res); if (rc) { dprintk(VIDC_ERR, "Failed to load bus table: %d\n", rc); goto err_load_bus_table; } rc = of_property_read_u32(pdev->dev.of_node, "qcom,max-hw-load", &res->max_load); if (rc) { Loading Loading @@ -1236,6 +1361,8 @@ int read_platform_resources_from_dt( err_setup_legacy_cb: err_load_max_hw_load: msm_vidc_free_allowed_clocks_table(res); err_load_bus_table: msm_vidc_free_bus_table(res); err_load_allowed_clocks_table: msm_vidc_free_cycles_per_mb_table(res); err_load_cycles_per_mb_table: Loading drivers/media/platform/msm/vidc_3x/msm_vidc_resources.h +22 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2021, 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 Loading Loading @@ -149,6 +149,26 @@ struct clock_freq_table { u32 count; }; enum bus_profile { VIDC_BUS_PROFILE_NORMAL = BIT(0), VIDC_BUS_PROFILE_LOW = BIT(1), VIDC_BUS_PROFILE_UBWC = BIT(2), }; struct bus_profile_entry { struct { u32 load, freq; } *bus_table; u32 bus_table_size; u32 codec_mask; enum bus_profile profile; }; struct msm_vidc_bus_table_gov { struct bus_profile_entry *bus_prof_entries; u32 count; }; struct msm_vidc_platform_resources { phys_addr_t firmware_base; phys_addr_t register_base; Loading Loading @@ -176,6 +196,7 @@ struct msm_vidc_platform_resources { struct platform_device *pdev; struct regulator_set regulator_set; struct clock_set clock_set; struct msm_vidc_bus_table_gov *gov_data; struct bus_set bus_set; bool use_non_secure_pil; bool sw_power_collapsible; Loading drivers/media/platform/msm/vidc_3x/venus_hfi.c +20 −6 Original line number Diff line number Diff line Loading @@ -113,7 +113,10 @@ static inline void __strict_check(struct venus_hfi_device *device) WARN_ON(VIDC_DBG_WARN_ENABLE); } } static inline bool is_clock_bus_voted(struct venus_hfi_device *device) { return (device->bus_vote.total_bw_ddr && device->clk_freq); } static inline void __set_state(struct venus_hfi_device *device, enum venus_hfi_state state) { Loading Loading @@ -812,13 +815,18 @@ static int __vote_buses(struct venus_hfi_device *device, venus_hfi_for_each_bus(device, bus) { if (!bus->is_prfm_gov_used) { freq = __calc_bw(bus, &device->bus_vote); rc = __vote_bandwidth(bus, &freq); } else { freq = bus->range[1]; rc = __vote_bandwidth(bus, &freq); rc = msm_vidc_table_get_target_freq( device->res->gov_data, &device->bus_vote, &freq); if (rc) { dprintk(VIDC_ERR, "unable to get freq\n"); return rc; } device->bus_vote.total_bw_ddr = freq; } else freq = bus->range[1]; rc = __vote_bandwidth(bus, &freq); if (rc) return rc; } Loading Loading @@ -1527,6 +1535,12 @@ static int __iface_cmdq_write_relaxed(struct venus_hfi_device *device, goto err_q_write; } if (cmd_packet->packet_type == HFI_CMD_SESSION_EMPTY_BUFFER && !is_clock_bus_voted(device)) dprintk(VIDC_ERR, "%s: bus %llu bps or clock %lu MHz\n", __func__, device->bus_vote.total_bw_ddr, device->clk_freq); if (!__write_queue(q_info, (u8 *)pkt, requires_interrupt)) { if (device->res->sw_power_collapsible) { cancel_delayed_work(&venus_hfi_pm_work); Loading drivers/media/platform/msm/vidc_3x/venus_hfi.h +4 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,10 @@ extern unsigned long __calc_bw(struct bus_info *bus, struct msm_vidc_gov_data *vidc_data); extern int msm_vidc_table_get_target_freq(struct msm_vidc_bus_table_gov *gov, struct msm_vidc_gov_data *vidc_data, unsigned long *frequency); struct hfi_queue_table_header { u32 qtbl_version; u32 qtbl_size; Loading Loading
drivers/media/platform/msm/vidc_3x/governors/msm_vidc_table_gov.c +6 −268 Original line number Diff line number Diff line Loading @@ -24,27 +24,6 @@ #include "../vidc_hfi_api.h" enum bus_profile { VIDC_BUS_PROFILE_NORMAL = BIT(0), VIDC_BUS_PROFILE_LOW = BIT(1), VIDC_BUS_PROFILE_UBWC = BIT(2), }; struct bus_profile_entry { struct { u32 load, freq; } *bus_table; u32 bus_table_size; u32 codec_mask; enum bus_profile profile; }; struct msm_vidc_bus_table_gov { struct bus_profile_entry *bus_prof_entries; u32 count; struct devfreq_governor devfreq_gov; }; static int __get_bus_freq(struct msm_vidc_bus_table_gov *gov, struct vidc_bus_vote_data *data, enum bus_profile profile) Loading Loading @@ -85,31 +64,19 @@ static int __get_bus_freq(struct msm_vidc_bus_table_gov *gov, } static int msm_vidc_table_get_target_freq(struct devfreq *dev, int msm_vidc_table_get_target_freq(struct msm_vidc_bus_table_gov *gov, struct msm_vidc_gov_data *vidc_data, unsigned long *frequency) { struct devfreq_dev_status status = {0}; struct msm_vidc_gov_data *vidc_data = NULL; struct msm_vidc_bus_table_gov *gov = NULL; enum bus_profile profile = 0; int i = 0; if (!dev || !frequency) { dprintk(VIDC_ERR, "%s: Invalid params %pK, %pK\n", __func__, dev, frequency); return -EINVAL; } gov = container_of(dev->governor, struct msm_vidc_bus_table_gov, devfreq_gov); if (!gov) { dprintk(VIDC_ERR, "%s: governor not found\n", __func__); if (!frequency || !gov || !vidc_data) { dprintk(VIDC_ERR, "%s: Invalid params %pK\n", __func__, frequency); return -EINVAL; } dev->profile->get_dev_status(dev->dev.parent, &status); vidc_data = (struct msm_vidc_gov_data *)status.private_data; *frequency = 0; for (i = 0; i < vidc_data->data_count; i++) { struct vidc_bus_vote_data *data = &vidc_data->data[i]; Loading Loading @@ -149,232 +116,3 @@ static int msm_vidc_table_get_target_freq(struct devfreq *dev, 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_free_bus_table(struct platform_device *pdev, struct msm_vidc_bus_table_gov *data) { int rc = 0, i = 0; if (!pdev || !data) { dprintk(VIDC_ERR, "%s: invalid args %pK %pK\n", __func__, pdev, data); return -EINVAL; } for (i = 0; i < data->count; i++) data->bus_prof_entries[i].bus_table = NULL; data->bus_prof_entries = NULL; data->count = 0; return rc; } static int msm_vidc_load_bus_table(struct platform_device *pdev, struct msm_vidc_bus_table_gov *data) { int rc = 0, i = 0, j = 0; const char *name = NULL; struct bus_profile_entry *entry = NULL; struct device_node *parent_node = NULL; struct device_node *child_node = NULL; if (!pdev || !data) { dprintk(VIDC_ERR, "%s: invalid args %pK %pK\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; parent_node = of_find_node_by_name(pdev->dev.of_node, "qcom,bus-freq-table"); if (!parent_node) { dprintk(VIDC_DBG, "Node qcom,bus-freq-table not found.\n"); return 0; } data->count = of_get_child_count(parent_node); if (!data->count) { dprintk(VIDC_DBG, "No child nodes in qcom,bus-freq-table\n"); return 0; } data->bus_prof_entries = devm_kzalloc(&pdev->dev, sizeof(*data->bus_prof_entries) * data->count, GFP_KERNEL); if (!data->bus_prof_entries) { dprintk(VIDC_DBG, "no memory to allocate bus_prof_entries\n"); return -ENOMEM; } for_each_child_of_node(parent_node, child_node) { if (i >= data->count) { dprintk(VIDC_ERR, "qcom,bus-freq-table: invalid child node %d, max is %d\n", i, data->count); break; } entry = &data->bus_prof_entries[i]; if (of_find_property(child_node, "qcom,codec-mask", NULL)) { rc = of_property_read_u32(child_node, "qcom,codec-mask", &entry->codec_mask); if (rc) { dprintk(VIDC_ERR, "qcom,codec-mask not found\n"); break; } } if (of_find_property(child_node, "qcom,low-power-mode", NULL)) entry->profile = VIDC_BUS_PROFILE_LOW; else if (of_find_property(child_node, "qcom,ubwc-mode", NULL)) entry->profile = VIDC_BUS_PROFILE_UBWC; else entry->profile = VIDC_BUS_PROFILE_NORMAL; if (of_find_property(child_node, "qcom,load-busfreq-tbl", NULL)) { rc = msm_vidc_load_u32_table(pdev, child_node, "qcom,load-busfreq-tbl", sizeof(*entry->bus_table), (u32 **)&entry->bus_table, &entry->bus_table_size); if (rc) { dprintk(VIDC_ERR, "qcom,load-busfreq-tbl failed\n"); break; } } else { entry->bus_table = NULL; entry->bus_table_size = 0; } dprintk(VIDC_DBG, "qcom,load-busfreq-tbl: size %d, codec_mask %#x, profile %#x\n", entry->bus_table_size, entry->codec_mask, entry->profile); for (j = 0; j < entry->bus_table_size; j++) dprintk(VIDC_DBG, " load %8d freq %8d\n", entry->bus_table[j].load, entry->bus_table[j].freq); i++; } return rc; } 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 = msm_vidc_free_bus_table(pdev, gov); if (rc) dprintk(VIDC_WARN, "%s: free bus table failed\n", __func__); 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", .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_3x/msm_vidc_res_parse.c +127 −0 Original line number Diff line number Diff line Loading @@ -72,7 +72,23 @@ static inline enum imem_type read_imem_type(struct platform_device *pdev) IMEM_NONE; } static inline void msm_vidc_free_bus_table( struct msm_vidc_platform_resources *res) { int i = 0; struct msm_vidc_bus_table_gov *data = res->gov_data; if (!data) { dprintk(VIDC_ERR, "%s: invalid args %pK\n", __func__, data); } for (i = 0; i < data->count; i++) data->bus_prof_entries[i].bus_table = NULL; data->bus_prof_entries = NULL; data->count = 0; } static inline void msm_vidc_free_allowed_clocks_table( struct msm_vidc_platform_resources *res) { Loading Loading @@ -174,6 +190,7 @@ void msm_vidc_free_platform_resources( struct msm_vidc_platform_resources *res) { msm_vidc_free_clock_table(res); msm_vidc_free_bus_table(res); msm_vidc_free_regulator_table(res); msm_vidc_free_freq_table(res); msm_vidc_free_platform_version_table(res); Loading Loading @@ -1065,7 +1082,108 @@ static int msm_vidc_load_clock_table( err_load_clk_table_fail: return rc; } static int msm_vidc_load_bus_table(struct msm_vidc_platform_resources *res) { int rc = 0, i = 0, j = 0; struct bus_profile_entry *entry = NULL; struct device_node *parent_node = NULL; struct device_node *child_node = NULL; struct msm_vidc_bus_table_gov *gov_data; struct platform_device *pdev = res->pdev; dprintk(VIDC_DBG, "%s\n", __func__); if (!pdev) { dprintk(VIDC_ERR, "%s: invalid args %pK\n", __func__, pdev); return -EINVAL; } res->gov_data = devm_kzalloc(&pdev->dev, sizeof(*gov_data), GFP_KERNEL); if (!res->gov_data) { dprintk(VIDC_ERR, "%s: allocation failed\n", __func__); return -ENOMEM; } gov_data = res->gov_data; parent_node = of_find_node_by_name(pdev->dev.of_node, "qcom,bus-freq-table"); if (!parent_node) { dprintk(VIDC_DBG, "Node qcom,bus-freq-table not found.\n"); return 0; } gov_data->count = of_get_child_count(parent_node); if (!gov_data->count) { dprintk(VIDC_DBG, "No child nodes in qcom,bus-freq-table\n"); return 0; } gov_data->bus_prof_entries = devm_kzalloc(&pdev->dev, sizeof(*gov_data->bus_prof_entries) * gov_data->count, GFP_KERNEL); if (!gov_data->bus_prof_entries) { dprintk(VIDC_DBG, "no memory to allocate bus_prof_entries\n"); return -ENOMEM; } for_each_child_of_node(parent_node, child_node) { if (i >= gov_data->count) { dprintk(VIDC_ERR, "qcom,bus-freq-table: invalid child node %d, max is %d\n", i, gov_data->count); break; } entry = &gov_data->bus_prof_entries[i]; if (of_find_property(child_node, "qcom,codec-mask", NULL)) { rc = of_property_read_u32(child_node, "qcom,codec-mask", &entry->codec_mask); if (rc) { dprintk(VIDC_ERR, "qcom,codec-mask not found\n"); break; } } if (of_find_property(child_node, "qcom,low-power-mode", NULL)) entry->profile = VIDC_BUS_PROFILE_LOW; else if (of_find_property(child_node, "qcom,ubwc-mode", NULL)) entry->profile = VIDC_BUS_PROFILE_UBWC; else entry->profile = VIDC_BUS_PROFILE_NORMAL; if (of_find_property(child_node, "qcom,load-busfreq-tbl", NULL)) { rc = msm_vidc_load_u32_table(pdev, child_node, "qcom,load-busfreq-tbl", sizeof(*entry->bus_table), (u32 **)&entry->bus_table, &entry->bus_table_size); if (rc) { dprintk(VIDC_ERR, "qcom,load-busfreq-tbl failed\n"); break; } } else { entry->bus_table = NULL; entry->bus_table_size = 0; } dprintk(VIDC_DBG, "qcom,load-busfreq-tbl: size %d, codec_mask %#x, profile %#x\n", entry->bus_table_size, entry->codec_mask, entry->profile); for (j = 0; j < entry->bus_table_size; j++) dprintk(VIDC_DBG, " load %8d freq %8d\n", entry->bus_table[j].load, entry->bus_table[j].freq); i++; } return rc; } int read_platform_resources_from_dt( struct msm_vidc_platform_resources *res) { Loading Loading @@ -1185,6 +1303,13 @@ int read_platform_resources_from_dt( goto err_load_allowed_clocks_table; } rc = msm_vidc_load_bus_table(res); if (rc) { dprintk(VIDC_ERR, "Failed to load bus table: %d\n", rc); goto err_load_bus_table; } rc = of_property_read_u32(pdev->dev.of_node, "qcom,max-hw-load", &res->max_load); if (rc) { Loading Loading @@ -1236,6 +1361,8 @@ int read_platform_resources_from_dt( err_setup_legacy_cb: err_load_max_hw_load: msm_vidc_free_allowed_clocks_table(res); err_load_bus_table: msm_vidc_free_bus_table(res); err_load_allowed_clocks_table: msm_vidc_free_cycles_per_mb_table(res); err_load_cycles_per_mb_table: Loading
drivers/media/platform/msm/vidc_3x/msm_vidc_resources.h +22 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2021, 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 Loading Loading @@ -149,6 +149,26 @@ struct clock_freq_table { u32 count; }; enum bus_profile { VIDC_BUS_PROFILE_NORMAL = BIT(0), VIDC_BUS_PROFILE_LOW = BIT(1), VIDC_BUS_PROFILE_UBWC = BIT(2), }; struct bus_profile_entry { struct { u32 load, freq; } *bus_table; u32 bus_table_size; u32 codec_mask; enum bus_profile profile; }; struct msm_vidc_bus_table_gov { struct bus_profile_entry *bus_prof_entries; u32 count; }; struct msm_vidc_platform_resources { phys_addr_t firmware_base; phys_addr_t register_base; Loading Loading @@ -176,6 +196,7 @@ struct msm_vidc_platform_resources { struct platform_device *pdev; struct regulator_set regulator_set; struct clock_set clock_set; struct msm_vidc_bus_table_gov *gov_data; struct bus_set bus_set; bool use_non_secure_pil; bool sw_power_collapsible; Loading
drivers/media/platform/msm/vidc_3x/venus_hfi.c +20 −6 Original line number Diff line number Diff line Loading @@ -113,7 +113,10 @@ static inline void __strict_check(struct venus_hfi_device *device) WARN_ON(VIDC_DBG_WARN_ENABLE); } } static inline bool is_clock_bus_voted(struct venus_hfi_device *device) { return (device->bus_vote.total_bw_ddr && device->clk_freq); } static inline void __set_state(struct venus_hfi_device *device, enum venus_hfi_state state) { Loading Loading @@ -812,13 +815,18 @@ static int __vote_buses(struct venus_hfi_device *device, venus_hfi_for_each_bus(device, bus) { if (!bus->is_prfm_gov_used) { freq = __calc_bw(bus, &device->bus_vote); rc = __vote_bandwidth(bus, &freq); } else { freq = bus->range[1]; rc = __vote_bandwidth(bus, &freq); rc = msm_vidc_table_get_target_freq( device->res->gov_data, &device->bus_vote, &freq); if (rc) { dprintk(VIDC_ERR, "unable to get freq\n"); return rc; } device->bus_vote.total_bw_ddr = freq; } else freq = bus->range[1]; rc = __vote_bandwidth(bus, &freq); if (rc) return rc; } Loading Loading @@ -1527,6 +1535,12 @@ static int __iface_cmdq_write_relaxed(struct venus_hfi_device *device, goto err_q_write; } if (cmd_packet->packet_type == HFI_CMD_SESSION_EMPTY_BUFFER && !is_clock_bus_voted(device)) dprintk(VIDC_ERR, "%s: bus %llu bps or clock %lu MHz\n", __func__, device->bus_vote.total_bw_ddr, device->clk_freq); if (!__write_queue(q_info, (u8 *)pkt, requires_interrupt)) { if (device->res->sw_power_collapsible) { cancel_delayed_work(&venus_hfi_pm_work); Loading
drivers/media/platform/msm/vidc_3x/venus_hfi.h +4 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,10 @@ extern unsigned long __calc_bw(struct bus_info *bus, struct msm_vidc_gov_data *vidc_data); extern int msm_vidc_table_get_target_freq(struct msm_vidc_bus_table_gov *gov, struct msm_vidc_gov_data *vidc_data, unsigned long *frequency); struct hfi_queue_table_header { u32 qtbl_version; u32 qtbl_size; Loading