15406fe9e9
This reverts commit bc2b96f62c
.
325 lines
10 KiB
C
Executable file
325 lines
10 KiB
C
Executable file
/* SPDX-License-Identifier: GPL-2.0 */
|
|
|
|
/*
|
|
* (C) COPYRIGHT 2021 Samsung Electronics Inc. All rights reserved.
|
|
*
|
|
* This program is free software and is provided to you under the terms of the
|
|
* GNU General Public License version 2 as published by the Free Software
|
|
* Foundation, and any use by you of this program is subject to the terms
|
|
* of such GNU licence.
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, you can access it online at
|
|
* http://www.gnu.org/licenses/gpl-2.0.html.
|
|
*/
|
|
|
|
#include <linux/device.h>
|
|
#include <linux/of.h>
|
|
#include <linux/sysfs.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include <gpex_utils.h>
|
|
#include <gpexbe_devicetree.h>
|
|
|
|
#define CPU_MAX INT_MAX
|
|
static gpu_dt dt_info;
|
|
static struct _dt_clock_item *clock_table;
|
|
static struct _dt_clqos_item *clqos_table;
|
|
|
|
static int gpexbe_devicetree_read_u32(const char *of_string, u32 *of_data)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (!of_string || !of_data) {
|
|
GPU_LOG(MALI_EXYNOS_ERROR, "NULL: failed to get item from dt\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = of_property_read_u32(dt_info.dev->of_node, of_string, of_data);
|
|
|
|
if (ret) {
|
|
GPU_LOG(MALI_EXYNOS_ERROR,
|
|
"%s: failed to get item from dt. Data will be set to 0.\n", of_string);
|
|
*of_data = 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* TODO: document in the interface header. Return value same as of_property_read_string */
|
|
static int gpexbe_devicetree_read_string(const char *of_string, const char **of_data)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (!of_string || !of_data) {
|
|
GPU_LOG(MALI_EXYNOS_ERROR, "NULL: failed to get item from dt\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = of_property_read_string(dt_info.dev->of_node, of_string, of_data);
|
|
if (ret) {
|
|
GPU_LOG(MALI_EXYNOS_ERROR,
|
|
"%s: failed to get item from dt. Data will be set to NULL.\n", of_string);
|
|
*of_data = NULL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int gpexbe_devicetree_read_u32_array(const char *of_string, int *of_data, int sz)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (!of_string || !of_data || sz < 0) {
|
|
GPU_LOG(MALI_EXYNOS_ERROR, "NULL: failed to get item from dt. Invalid params\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = of_property_read_u32_array(dt_info.dev->of_node, of_string, of_data, sz);
|
|
|
|
if (ret)
|
|
GPU_LOG(MALI_EXYNOS_ERROR, "%s: failed to get item from dt (u32 array)\n",
|
|
of_string);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int read_interactive_info_array(void)
|
|
{
|
|
int interactive_info[3] = { 0, 0, 0 };
|
|
|
|
gpexbe_devicetree_read_u32_array("interactive_info", interactive_info, 3);
|
|
|
|
/* TODO: change default value to something more sensible */
|
|
dt_info.interactive_info.highspeed_clock =
|
|
interactive_info[0] == 0 ? 500 : (u32)interactive_info[0];
|
|
dt_info.interactive_info.highspeed_load =
|
|
interactive_info[1] == 0 ? 100 : (u32)interactive_info[1];
|
|
dt_info.interactive_info.highspeed_delay =
|
|
interactive_info[2] == 0 ? 0 : (u32)interactive_info[2];
|
|
|
|
return 0;
|
|
}
|
|
|
|
unsigned int custom_clock[] = {1209000, 1105000, 1001000, 897000, 806000, 702000, 611000, 507000, 403000, 312000, 208000, 104000};
|
|
unsigned int custom_min_threshold[] = {90, 87, 85, 82, 80, 79, 78, 70, 60, 50, 30, 0};
|
|
unsigned int custom_max_threshold[] = {100, 96 ,95, 95, 95, 95, 95, 90, 80, 70, 60, 40};
|
|
unsigned int custom_staycount[] = {5, 5, 5, 5, 5, 5, 5, 3, 3, 2, 2, 1};
|
|
unsigned int custom_mem_freq[] = {2093000, 1794000, 1794000, 1794000, 1539000, 1352000, 1352000, 1014000, 1014000, 845000, 676000, 676000};
|
|
unsigned int custom_lit[] = {1536000, 1440000, 1248000, 1056000, 1056000, 1056000, 1056000, 1056000, 0, 0, 0, 0};
|
|
unsigned int custom_mid = 0;
|
|
unsigned int custom_big = CPU_MAX;
|
|
int custom_array_size = sizeof(custom_clock) / sizeof(custom_clock[0]);
|
|
|
|
static int build_clk_table(void)
|
|
{
|
|
int array_size = custom_array_size;
|
|
int i = 0;
|
|
|
|
if (array_size <= 0) {
|
|
return -EINVAL;
|
|
}
|
|
clock_table = kcalloc(array_size, sizeof(*clock_table), GFP_KERNEL);
|
|
|
|
for (i = 0; i < array_size; i++) {
|
|
clock_table[i].clock = custom_clock[i];
|
|
clock_table[i].min_threshold = custom_min_threshold[i];
|
|
clock_table[i].max_threshold = custom_max_threshold[i];
|
|
clock_table[i].down_staycount = custom_staycount[i];
|
|
clock_table[i].mem_freq = custom_mem_freq[i];
|
|
clock_table[i].cpu_little_min_freq = custom_lit[i];
|
|
|
|
if (dt_info.gpu_pmqos_cpu_cluster_num == 3) {
|
|
clock_table[i].cpu_middle_min_freq = custom_mid;
|
|
clock_table[i].cpu_big_max_freq = custom_big;
|
|
|
|
GPU_LOG(MALI_EXYNOS_INFO,
|
|
"up [%d] down [%d] staycnt [%d] mif [%d] lit [%d] mid [%d] big [%d]\n",
|
|
clock_table[i].max_threshold, clock_table[i].min_threshold,
|
|
clock_table[i].down_staycount, clock_table[i].mem_freq,
|
|
clock_table[i].cpu_little_min_freq,
|
|
clock_table[i].cpu_middle_min_freq,
|
|
clock_table[i].cpu_big_max_freq);
|
|
} else {
|
|
// Assuming cpu cluster number is 2
|
|
clock_table[i].cpu_big_max_freq = custom_big;
|
|
|
|
GPU_LOG(MALI_EXYNOS_INFO,
|
|
"up [%d] down [%d] staycnt [%d] mif [%d] lit [%d] big [%d]\n",
|
|
clock_table[i].max_threshold, clock_table[i].min_threshold,
|
|
clock_table[i].down_staycount, clock_table[i].mem_freq,
|
|
clock_table[i].cpu_little_min_freq,
|
|
clock_table[i].cpu_big_max_freq);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int build_cl_pmqos_table(void)
|
|
{
|
|
int array_size = dt_info.gpu_cl_pmqos_table_size.row * dt_info.gpu_cl_pmqos_table_size.col;
|
|
u32 *raw_table;
|
|
int row = 0;
|
|
|
|
if (array_size <= 0) {
|
|
int num_rows = dt_info.gpu_dvfs_table_size.row;
|
|
|
|
clqos_table = kcalloc(num_rows, sizeof(*clqos_table), GFP_KERNEL);
|
|
|
|
for (row = 0; row < num_rows; row++)
|
|
clqos_table[row].clock = clock_table[row].clock;
|
|
|
|
dt_info.gpu_cl_pmqos_table_size.row = num_rows;
|
|
dt_info.gpu_cl_pmqos_table_size.col = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
raw_table = kcalloc(array_size, sizeof(*raw_table), GFP_KERNEL);
|
|
|
|
if (!raw_table)
|
|
return -ENOMEM;
|
|
|
|
gpexbe_devicetree_read_u32_array("gpu_cl_pmqos_table", raw_table, array_size);
|
|
|
|
clqos_table =
|
|
kcalloc(dt_info.gpu_cl_pmqos_table_size.row, sizeof(*clqos_table), GFP_KERNEL);
|
|
|
|
for (row = 0; row < dt_info.gpu_cl_pmqos_table_size.row; row++) {
|
|
int table_idx = row * dt_info.gpu_cl_pmqos_table_size.col;
|
|
|
|
clqos_table[row].clock = raw_table[table_idx];
|
|
clqos_table[row].mif_min = raw_table[table_idx + 1];
|
|
clqos_table[row].little_min = raw_table[table_idx + 2];
|
|
clqos_table[row].middle_min = raw_table[table_idx + 3];
|
|
clqos_table[row].big_max = raw_table[table_idx + 4];
|
|
}
|
|
|
|
kfree(raw_table);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void read_from_dt(void)
|
|
{
|
|
/* clock backend */
|
|
gpexbe_devicetree_read_u32("g3d_cmu_cal_id", &dt_info.g3d_cmu_cal_id);
|
|
|
|
/* PM backend */
|
|
gpexbe_devicetree_read_string("g3d_genpd_name", &dt_info.g3d_genpd_name);
|
|
|
|
/* CLOCK */
|
|
dt_info.gpu_max_clock = custom_clock[0];
|
|
dt_info.gpu_min_clock = custom_clock[custom_array_size - 1];
|
|
gpexbe_devicetree_read_u32("gpu_pmqos_cpu_cluster_num", &dt_info.gpu_pmqos_cpu_cluster_num);
|
|
|
|
dt_info.gpu_dvfs_table_size.col = 8; // 8 values for each freq
|
|
dt_info.gpu_dvfs_table_size.row = custom_array_size;
|
|
|
|
gpexbe_devicetree_read_u32_array("gpu_cl_pmqos_table_size",
|
|
(int *)&dt_info.gpu_cl_pmqos_table_size, 2);
|
|
|
|
/* DEBUG_BACKEND */
|
|
gpexbe_devicetree_read_u32("gpu_ess_id_type", &dt_info.gpu_ess_id_type);
|
|
|
|
/* LEGACY DVFS */
|
|
gpexbe_devicetree_read_string("governor", &dt_info.governor);
|
|
gpexbe_devicetree_read_u32("gpu_dvfs_bl_config_clock", &dt_info.gpu_dvfs_bl_config_clock);
|
|
gpexbe_devicetree_read_u32("gpu_dvfs_polling_time", &dt_info.gpu_dvfs_polling_time);
|
|
|
|
/* IFPO */
|
|
gpexbe_devicetree_read_u32("gpu_inter_frame_pm", &dt_info.gpu_inter_frame_pm);
|
|
|
|
/* PM BACKEND */
|
|
gpexbe_devicetree_read_u32("gpu_pmu_status_reg_offset", &dt_info.gpu_pmu_status_reg_offset);
|
|
gpexbe_devicetree_read_u32("gpu_pmu_status_local_pwr_mask",
|
|
&dt_info.gpu_pmu_status_local_pwr_mask);
|
|
|
|
/* PM */
|
|
gpexbe_devicetree_read_u32("gpu_runtime_pm_delay_time", &dt_info.gpu_runtime_pm_delay_time);
|
|
|
|
/* QOS */
|
|
gpexbe_devicetree_read_u32("gpu_bts_support", &dt_info.gpu_bts_support);
|
|
gpexbe_devicetree_read_u32("gpu_mo_min_clock", &dt_info.gpu_mo_min_clock);
|
|
|
|
/* UTILS */
|
|
gpexbe_devicetree_read_u32("gpu_debug_level", &dt_info.gpu_debug_level);
|
|
|
|
/* HCM */
|
|
gpexbe_devicetree_read_u32("gpu_heavy_compute_cpu0_min_clock;",
|
|
&dt_info.gpu_heavy_compute_cpu0_min_clock);
|
|
gpexbe_devicetree_read_u32("gpu_heavy_compute_vk_cpu0_min_clock;",
|
|
&dt_info.gpu_heavy_compute_vk_cpu0_min_clock);
|
|
|
|
/* TSG */
|
|
gpexbe_devicetree_read_u32("gpu_weight_table_idx_0", &dt_info.gpu_weight_table_idx_0);
|
|
gpexbe_devicetree_read_u32("gpu_weight_table_idx_1", &dt_info.gpu_weight_table_idx_1);
|
|
}
|
|
|
|
/******************
|
|
* GETTERS
|
|
* ***************/
|
|
dt_clock_item *gpexbe_devicetree_get_clock_table(void)
|
|
{
|
|
return clock_table;
|
|
}
|
|
|
|
/********************************************
|
|
* Helper Functions. (Must remain non static)
|
|
* ******************************************/
|
|
int gpexbe_devicetree_get_int_internal(size_t offset, const char *str)
|
|
{
|
|
//pr_warn("mali: %s %s %d\n", __func__, str, *(int*)((u8*)&dt_info + offset));
|
|
//GPU_LOG(MALI_EXYNOS_INFO, "%s: %s\n", of_string, *of_data);
|
|
return *(int *)((u8 *)&dt_info + offset);
|
|
}
|
|
|
|
char *gpexbe_devicetree_get_str_internal(size_t offset, const char *str)
|
|
{
|
|
//pr_warn("mali: %s %s %s\n", __func__, str, *(char**)((u8*)&dt_info + offset));
|
|
//GPU_LOG(MALI_EXYNOS_INFO, "%s: %s\n", of_string, *of_data);
|
|
return *(char **)((u8 *)&dt_info + offset);
|
|
}
|
|
|
|
gpu_dt *gpexbe_devicetree_get_gpu_dt(void)
|
|
{
|
|
return &dt_info;
|
|
}
|
|
|
|
/************************************************************************
|
|
* INIT and TERM functions
|
|
************************************************************************/
|
|
|
|
int gpexbe_devicetree_init(struct device *dev)
|
|
{
|
|
dt_info.dev = dev;
|
|
read_from_dt();
|
|
build_clk_table();
|
|
build_cl_pmqos_table();
|
|
read_interactive_info_array();
|
|
|
|
dt_info.gpu_dvfs_table = clock_table;
|
|
dt_info.gpu_cl_pmqos_table = clqos_table;
|
|
|
|
dt_info.initialized = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void gpexbe_devicetree_term(void)
|
|
{
|
|
kfree(clock_table);
|
|
kfree(clqos_table);
|
|
|
|
clock_table = NULL;
|
|
clqos_table = NULL;
|
|
|
|
memset(&dt_info, 0, sizeof(gpu_dt));
|
|
|
|
return;
|
|
}
|