Files
android_kernel_samsung_sm86…/driver/src/mmrm_res_parse.c
Sebastian Dang 7657a22ccf mmrm: Resolve for invalid voltage corner values
- When qcom_clk_get_voltage encounters an error,
return the error.
- When qcom_clk_get_voltage returns a level higher
than supported, return an error.
- Added warning debug level.
- Minor formatting changes.

Change-Id: I6d7147f6af83bff2d84ef40c3a11cfef7faca391
2020-12-01 10:38:41 -08:00

260 lines
6.4 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include <linux/types.h>
#include <linux/of_platform.h>
#include "mmrm_internal.h"
#include "mmrm_debug.h"
#include "mmrm_clk_rsrc_mgr.h"
static int mmrm_find_key_value(
struct mmrm_platform_data *pdata, const char *key)
{
int i = 0;
struct mmrm_common_data *cdata = pdata->common_data;
int size = pdata->common_data_length;
for (i = 0; i < size; i++) {
if (!strcmp(cdata[i].key, key))
return cdata[i].value;
}
return 0;
}
static int mmrm_read_clk_pltfrm_rsrc_frm_drv_data(
struct mmrm_driver_data *ddata)
{
struct mmrm_platform_data *pdata;
struct mmrm_clk_platform_resources *cres;
int rc = 0;
pdata = ddata->platform_data;
cres = &ddata->clk_res;
cres->threshold = mmrm_find_key_value(pdata,
"qcom,mmrm_clk_threshold");
d_mpr_e("%s: configured mmrm clk threshold %d\n",
__func__, cres->threshold);
cres->scheme = mmrm_find_key_value(pdata,
"qcom,mmrm_clk_mgr_scheme");
d_mpr_e("%s: configured mmrm scheme %d\n",
__func__, cres->scheme);
return rc;
}
static void mmrm_free_rail_corner_table(
struct mmrm_clk_platform_resources *cres)
{
cres->corner_set.corner_tbl = NULL;
cres->corner_set.count = 0;
}
static int mmrm_load_mm_rail_corner_table(
struct mmrm_clk_platform_resources *cres)
{
int rc = 0, num_corners = 0, c = 0;
struct voltage_corner_set *corners = &cres->corner_set;
struct platform_device *pdev = cres->pdev;
num_corners = of_property_count_strings(pdev->dev.of_node,
"mm-rail-corners");
if (num_corners <= 0) {
d_mpr_e("%s: no mm rail corners found\n",
__func__);
corners->count = 0;
goto err_load_corner_tbl;
}
corners->corner_tbl = devm_kzalloc(&pdev->dev,
sizeof(*corners->corner_tbl) * num_corners, GFP_KERNEL);
if (!corners->corner_tbl) {
d_mpr_e("%s: failed to allocate memory for corner_tbl\n",
__func__);
rc = -ENOMEM;
goto err_load_corner_tbl;
}
corners->count = num_corners;
d_mpr_h("%s: found %d corners\n",
__func__, num_corners);
for (c = 0; c < num_corners; c++) {
struct corner_info *ci = &corners->corner_tbl[c];
of_property_read_string_index(pdev->dev.of_node,
"mm-rail-corners", c, &ci->name);
of_property_read_u32_index(pdev->dev.of_node,
"mm-rail-fact-volt", c, &ci->volt_factor);
of_property_read_u32_index(pdev->dev.of_node,
"scaling-fact-dyn", c, &ci->scaling_factor_dyn);
of_property_read_u32_index(pdev->dev.of_node,
"scaling-fact-leak", c, &ci->scaling_factor_leak);
}
/* print corner tables */
for (c = 0; c < num_corners; c++) {
struct corner_info *ci = &corners->corner_tbl[c];
d_mpr_e(
"%s: corner_name:%s volt_factor: %d sc_dyn: %d sc_leak: %d\n",
__func__, ci->name, ci->volt_factor,
ci->scaling_factor_dyn, ci->scaling_factor_leak);
}
return 0;
err_load_corner_tbl:
return rc;
}
static void mmrm_free_nom_clk_src_table(
struct mmrm_clk_platform_resources *cres)
{
cres->nom_clk_set.clk_src_tbl = NULL;
cres->nom_clk_set.count = 0;
}
static int mmrm_load_nom_clk_src_table(
struct mmrm_clk_platform_resources *cres)
{
int rc = 0, num_clk_src = 0, c = 0, size_clk_src = 0, entry_offset = 4;
struct platform_device *pdev = cres->pdev;
struct nom_clk_src_set *clk_srcs = &cres->nom_clk_set;
of_find_property(pdev->dev.of_node, "mmrm-client-info", &size_clk_src);
if ((size_clk_src < sizeof(*clk_srcs->clk_src_tbl)) ||
(size_clk_src % sizeof(*clk_srcs->clk_src_tbl))) {
d_mpr_e("%s: invalid size(%d) of clk src table\n",
__func__, size_clk_src);
clk_srcs->count = 0;
goto err_load_clk_src_tbl;
}
clk_srcs->clk_src_tbl = devm_kzalloc(&pdev->dev,
size_clk_src, GFP_KERNEL);
if (!clk_srcs->clk_src_tbl) {
d_mpr_e("%s: failed to allocate memory for clk_src_tbl\n",
__func__);
rc = -ENOMEM;
goto err_load_clk_src_tbl;
}
num_clk_src = size_clk_src / sizeof(struct nom_clk_src_info);
clk_srcs->count = num_clk_src;
d_mpr_h("%s: found %d clk_srcs size %d\n",
__func__, num_clk_src, size_clk_src);
for (c = 0; c < num_clk_src; c++) {
struct nom_clk_src_info *ci = &clk_srcs->clk_src_tbl[c];
of_property_read_u32_index(pdev->dev.of_node,
"mmrm-client-info", (c*entry_offset), &ci->domain);
of_property_read_u32_index(pdev->dev.of_node,
"mmrm-client-info", (c*entry_offset+1), &ci->clk_src_id);
of_property_read_u32_index(pdev->dev.of_node,
"mmrm-client-info", (c*entry_offset+2),
&ci->nom_dyn_pwr);
of_property_read_u32_index(pdev->dev.of_node,
"mmrm-client-info", (c*entry_offset+3),
&ci->nom_leak_pwr);
}
/* print corner tables */
for (c = 0; c < num_clk_src; c++) {
struct nom_clk_src_info *ci = &clk_srcs->clk_src_tbl[c];
d_mpr_e("%s: domain: %d clk_src: %d dyn_pwr: %d leak_pwr: %d\n",
__func__, ci->domain, ci->clk_src_id, ci->nom_dyn_pwr,
ci->nom_leak_pwr);
}
return 0;
err_load_clk_src_tbl:
return rc;
}
static int mmrm_read_clk_pltfrm_rsrc_frm_dt(
struct mmrm_clk_platform_resources *cres)
{
int rc = 0;
rc = mmrm_load_mm_rail_corner_table(cres);
if (rc) {
d_mpr_e("%s: failed to load mm rail corner table\n",
__func__);
goto err_load_mmrm_rail_table;
}
if (cres->scheme == CLK_MGR_SCHEME_SW) {
rc = mmrm_load_nom_clk_src_table(cres);
if (rc) {
d_mpr_e("%s: failed to load nom clk src table\n",
__func__);
goto err_load_nom_clk_src_table;
}
} else if (cres->scheme == CLK_MGR_SCHEME_CXIPEAK) {
d_mpr_e("%s: cxipeak is not supported with mmrm\n",
__func__);
rc = -EINVAL;
goto err_load_mmrm_rail_table;
}
return rc;
err_load_nom_clk_src_table:
mmrm_free_nom_clk_src_table(cres);
err_load_mmrm_rail_table:
mmrm_free_rail_corner_table(cres);
return rc;
}
int mmrm_read_platform_resources(struct platform_device *pdev,
struct mmrm_driver_data *drv_data)
{
int rc = 0;
if (pdev->dev.of_node) {
/* clk resources */
drv_data->clk_res.pdev = pdev;
rc = mmrm_read_clk_pltfrm_rsrc_frm_drv_data(drv_data);
if (rc) {
d_mpr_e(
"%s: failed to read clk platform res from driver\n",
__func__);
goto exit;
}
rc = mmrm_read_clk_pltfrm_rsrc_frm_dt(&drv_data->clk_res);
if (rc) {
d_mpr_e("%s: failed to read clk platform res from dt\n",
__func__);
goto exit;
}
} else {
d_mpr_e("%s: of node is null\n", __func__);
rc = -EINVAL;
goto exit;
}
exit:
return rc;
}
int mmrm_free_platform_resources(struct mmrm_driver_data *drv_data)
{
int rc = 0;
/* free clk resources */
mmrm_free_nom_clk_src_table(&drv_data->clk_res);
mmrm_free_rail_corner_table(&drv_data->clk_res);
return rc;
}