msm_mmrm: Add support of new low voltage corners in mmrm driver

Add support of low priority voltage corners lowsvs and
svs in mmrm driver.
This logic maintains a list of clients which are to be
proritize to be throtlled to low power in order to satisfy
high priority client's power requiretment.

Change-Id: Ia7f912e41bbcff057c0732cc7c2b16e327c59fd8
Signed-off-by: Mahesh Kumar Sharma <smahesh@codeaurora.org>
This commit is contained in:
Mahesh Kumar Sharma
2021-07-06 14:34:12 -07:00
parent 3b8eae3aa1
commit af00e1b7ca
11 changed files with 123 additions and 50 deletions

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (c) 2020, The Linux Foundation. All rights reserved. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*/ */
#include "mmrm_clk_rsrc_mgr.h" #include "mmrm_clk_rsrc_mgr.h"

View File

@@ -10,6 +10,7 @@
#include <linux/soc/qcom/msm_mmrm.h> #include <linux/soc/qcom/msm_mmrm.h>
#include "mmrm_internal.h" #include "mmrm_internal.h"
#define MMRM_MAX_THROTTLE_CLIENTS 5
enum mmrm_clk_mgr_scheme { enum mmrm_clk_mgr_scheme {
CLK_MGR_SCHEME_SW, CLK_MGR_SCHEME_SW,
@@ -17,6 +18,8 @@ enum mmrm_clk_mgr_scheme {
}; };
enum mmrm_sw_vdd_levels { enum mmrm_sw_vdd_levels {
MMRM_VDD_LEVEL_LOW_SVS,
MMRM_VDD_LEVEL_SVS,
MMRM_VDD_LEVEL_SVS_L1, MMRM_VDD_LEVEL_SVS_L1,
MMRM_VDD_LEVEL_NOM, MMRM_VDD_LEVEL_NOM,
MMRM_VDD_LEVEL_TURBO, MMRM_VDD_LEVEL_TURBO,
@@ -24,6 +27,8 @@ enum mmrm_sw_vdd_levels {
}; };
static int mmrm_sw_vdd_corner[] = { static int mmrm_sw_vdd_corner[] = {
[MMRM_VDD_LEVEL_LOW_SVS] = RPMH_REGULATOR_LEVEL_LOW_SVS,
[MMRM_VDD_LEVEL_SVS] = RPMH_REGULATOR_LEVEL_SVS,
[MMRM_VDD_LEVEL_SVS_L1] = RPMH_REGULATOR_LEVEL_SVS_L1, [MMRM_VDD_LEVEL_SVS_L1] = RPMH_REGULATOR_LEVEL_SVS_L1,
[MMRM_VDD_LEVEL_NOM] = RPMH_REGULATOR_LEVEL_NOM, [MMRM_VDD_LEVEL_NOM] = RPMH_REGULATOR_LEVEL_NOM,
[MMRM_VDD_LEVEL_TURBO] = RPMH_REGULATOR_LEVEL_TURBO [MMRM_VDD_LEVEL_TURBO] = RPMH_REGULATOR_LEVEL_TURBO
@@ -70,6 +75,11 @@ struct mmrm_sw_peak_current_data {
u32 aggreg_level; u32 aggreg_level;
}; };
struct mmrm_throttle_info {
u32 csid_throttle_client;
u16 tbl_entry_id;
};
struct mmrm_sw_clk_mgr_info { struct mmrm_sw_clk_mgr_info {
void *driver_data; void *driver_data;
@@ -77,6 +87,8 @@ struct mmrm_sw_clk_mgr_info {
struct mmrm_sw_clk_client_tbl_entry *clk_client_tbl; struct mmrm_sw_clk_client_tbl_entry *clk_client_tbl;
u32 tot_clk_clients; u32 tot_clk_clients;
u32 enabled_clk_clients; u32 enabled_clk_clients;
struct mmrm_throttle_info throttle_clients_info[MMRM_MAX_THROTTLE_CLIENTS];
u16 throttle_clients_data_length;
/* peak current data */ /* peak current data */
struct mmrm_sw_peak_current_data peak_cur_data; struct mmrm_sw_peak_current_data peak_cur_data;

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (c) 2020, The Linux Foundation. All rights reserved. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*/ */
struct mmrm_client *mmrm_cxipeak_clk_client_register( struct mmrm_client *mmrm_cxipeak_clk_client_register(

View File

@@ -55,9 +55,8 @@ static int mmrm_sw_update_freq(
} }
/* voltage corner is below svsl1 */ /* voltage corner is below svsl1 */
if (voltage_corner < mmrm_sw_vdd_corner[MMRM_VDD_LEVEL_SVS_L1]) { if (voltage_corner < mmrm_sw_vdd_corner[MMRM_VDD_LEVEL_LOW_SVS])
voltage_corner = mmrm_sw_vdd_corner[MMRM_VDD_LEVEL_SVS_L1]; voltage_corner = mmrm_sw_vdd_corner[MMRM_VDD_LEVEL_LOW_SVS];
}
/* match vdd level */ /* match vdd level */
for (i = 0; i < MMRM_VDD_LEVEL_MAX; i++) { for (i = 0; i < MMRM_VDD_LEVEL_MAX; i++) {
@@ -340,7 +339,8 @@ static int mmrm_sw_clk_client_deregister(struct mmrm_clk_mgr *sw_clk_mgr,
if (tbl_entry->ref_count == 0) { if (tbl_entry->ref_count == 0) {
kfree(tbl_entry->client); kfree(tbl_entry->client);
tbl_entry->vdd_level = 0;
tbl_entry->clk_rate = 0;
tbl_entry->client = NULL; tbl_entry->client = NULL;
tbl_entry->clk = NULL; tbl_entry->clk = NULL;
tbl_entry->pri = 0x0; tbl_entry->pri = 0x0;
@@ -378,13 +378,13 @@ static int mmrm_sw_get_req_level(
goto err_invalid_corner; goto err_invalid_corner;
} }
/* voltage corner is below svsl1 */ /* voltage corner is below low svs */
if (voltage_corner < mmrm_sw_vdd_corner[MMRM_VDD_LEVEL_SVS_L1]) { if (voltage_corner < mmrm_sw_vdd_corner[MMRM_VDD_LEVEL_LOW_SVS]) {
d_mpr_h("%s: csid(0x%x): lower voltage corner(%d)\n", d_mpr_h("%s: csid(0x%x): lower voltage corner(%d)\n",
__func__, __func__,
tbl_entry->clk_src_id, tbl_entry->clk_src_id,
voltage_corner); voltage_corner);
*req_level = MMRM_VDD_LEVEL_SVS_L1; *req_level = MMRM_VDD_LEVEL_LOW_SVS;
goto exit_no_err; goto exit_no_err;
} }
@@ -489,41 +489,44 @@ err_invalid_level:
static int mmrm_sw_throttle_low_priority_client( static int mmrm_sw_throttle_low_priority_client(
struct mmrm_sw_clk_mgr_info *sinfo, u32 *delta_cur) struct mmrm_sw_clk_mgr_info *sinfo, u32 *delta_cur)
{ {
int rc = 0, c = 0; int rc = 0, i;
bool found_client_throttle = false; bool found_client_throttle = false;
struct mmrm_sw_clk_client_tbl_entry *tbl_entry_throttle_client; struct mmrm_sw_clk_client_tbl_entry *tbl_entry_throttle_client;
struct mmrm_client_notifier_data notifier_data; struct mmrm_client_notifier_data notifier_data;
struct completion timeout; struct completion timeout;
struct mmrm_sw_peak_current_data *peak_data = &sinfo->peak_cur_data; struct mmrm_sw_peak_current_data *peak_data = &sinfo->peak_cur_data;
u32 now_cur_ma, min_cur_ma; u32 now_cur_ma, min_cur_ma;
long clk_min_level = MMRM_VDD_LEVEL_SVS_L1; long clk_min_level = MMRM_VDD_LEVEL_LOW_SVS;
d_mpr_h("%s: entering\n", __func__); d_mpr_h("%s: entering\n", __func__);
init_completion(&timeout); init_completion(&timeout);
for (c = 0; c < sinfo->tot_clk_clients; c++) {
tbl_entry_throttle_client = &sinfo->clk_client_tbl[c];
now_cur_ma = tbl_entry_throttle_client->current_ma
[tbl_entry_throttle_client->vdd_level][peak_data->aggreg_level];
min_cur_ma = tbl_entry_throttle_client->current_ma[clk_min_level]
[peak_data->aggreg_level];
d_mpr_h("%s:csid(0x%x) name(%s) now_cur_ma(%llu) min_cur_ma(%llu) delta_cur(%d)\n", for (i = 0; i < sinfo->throttle_clients_data_length ; i++) {
tbl_entry_throttle_client =
&sinfo->clk_client_tbl[sinfo->throttle_clients_info[i].tbl_entry_id];
now_cur_ma = tbl_entry_throttle_client->current_ma
[tbl_entry_throttle_client->vdd_level]
[peak_data->aggreg_level];
min_cur_ma = tbl_entry_throttle_client->current_ma[clk_min_level]
[peak_data->aggreg_level];
d_mpr_h("%s:csid(0x%x) name(%s)\n",
__func__, tbl_entry_throttle_client->clk_src_id, __func__, tbl_entry_throttle_client->clk_src_id,
tbl_entry_throttle_client->name, now_cur_ma, min_cur_ma, tbl_entry_throttle_client->name);
*delta_cur); d_mpr_h("%s:now_cur_ma(%llu) min_cur_ma(%llu) delta_cur(%d)\n",
__func__, now_cur_ma, min_cur_ma, *delta_cur);
if (tbl_entry_throttle_client if (tbl_entry_throttle_client
&& (tbl_entry_throttle_client->pri == MMRM_CLIENT_PRIOR_LOW) && (now_cur_ma > min_cur_ma)
&& (now_cur_ma > min_cur_ma) && (now_cur_ma - min_cur_ma > *delta_cur)) { && (now_cur_ma - min_cur_ma > *delta_cur)) {
found_client_throttle = true; found_client_throttle = true;
d_mpr_h("%s: Throttle client csid(0x%x) name(%s)\n", __func__, d_mpr_h("%s: Throttle client csid(0x%x) name(%s)\n",
tbl_entry_throttle_client->clk_src_id, __func__, tbl_entry_throttle_client->clk_src_id,
tbl_entry_throttle_client->name); tbl_entry_throttle_client->name);
d_mpr_h("%s: now_cur_ma(%llu) - min_cur_ma(%llu) > delta_cur(%d)\n", d_mpr_h("%s:now_cur_ma %llu-min_cur_ma %llu>delta_cur %d\n",
__func__, now_cur_ma, min_cur_ma, *delta_cur); __func__, now_cur_ma, min_cur_ma, *delta_cur);
/* found client to throttle, break from here. */
/* found client to throttle, break from here. */ break;
break;
} }
} }
@@ -536,14 +539,11 @@ static int mmrm_sw_throttle_low_priority_client(
tbl_entry_throttle_client->freq[tbl_entry_throttle_client->vdd_level]; tbl_entry_throttle_client->freq[tbl_entry_throttle_client->vdd_level];
notifier_data.cb_data.val_chng.new_val = notifier_data.cb_data.val_chng.new_val =
tbl_entry_throttle_client->freq[clk_min_level]; tbl_entry_throttle_client->freq[clk_min_level];
notifier_data.pvt_data = NULL; notifier_data.pvt_data = tbl_entry_throttle_client->pvt_data;
if (tbl_entry_throttle_client->notifier_cb_fn) if (tbl_entry_throttle_client->notifier_cb_fn)
rc = tbl_entry_throttle_client->notifier_cb_fn(&notifier_data); rc = tbl_entry_throttle_client->notifier_cb_fn(&notifier_data);
if (!wait_for_completion_timeout(&timeout, CLIENT_CB_TIMEOUT))
d_mpr_h("Intentionally added to wait for 100ms\n", __func__);
if (rc) { if (rc) {
d_mpr_e("%s: Client failed to send SUCCESS in callback(%d)\n", d_mpr_e("%s: Client failed to send SUCCESS in callback(%d)\n",
__func__, tbl_entry_throttle_client->clk_src_id); __func__, tbl_entry_throttle_client->clk_src_id);
@@ -559,6 +559,9 @@ static int mmrm_sw_throttle_low_priority_client(
rc = -EINVAL; rc = -EINVAL;
goto err_clk_set_fail; goto err_clk_set_fail;
} else { } else {
d_mpr_h("%s: %s throttled to %llu\n",
__func__, tbl_entry_throttle_client->name,
tbl_entry_throttle_client->freq[clk_min_level]);
*delta_cur = now_cur_ma - min_cur_ma; *delta_cur = now_cur_ma - min_cur_ma;
} }
/* Store the throttled clock rate of client */ /* Store the throttled clock rate of client */
@@ -570,6 +573,7 @@ static int mmrm_sw_throttle_low_priority_client(
/* Clearing the reserve flag */ /* Clearing the reserve flag */
tbl_entry_throttle_client->reserve = tbl_entry_throttle_client->reserve & 0; tbl_entry_throttle_client->reserve = tbl_entry_throttle_client->reserve & 0;
d_mpr_h("%s: exiting\n", __func__);
} }
err_clk_set_fail: err_clk_set_fail:
return rc; return rc;
@@ -664,8 +668,6 @@ static int mmrm_sw_clk_client_setval(struct mmrm_clk_mgr *sw_clk_mgr,
bool req_reserve; bool req_reserve;
u32 req_level; u32 req_level;
d_mpr_h("%s: entering\n", __func__);
/* validate input params */ /* validate input params */
if (!client) { if (!client) {
d_mpr_e("%s: invalid client\n"); d_mpr_e("%s: invalid client\n");
@@ -693,6 +695,8 @@ static int mmrm_sw_clk_client_setval(struct mmrm_clk_mgr *sw_clk_mgr,
rc = -EINVAL; rc = -EINVAL;
goto err_invalid_client; goto err_invalid_client;
} }
d_mpr_h("%s: csid(0x%x) clk rate %llu\n",
__func__, tbl_entry->clk_src_id, clk_val);
/* Check if the requested clk rate is the same as the current clk rate. /* Check if the requested clk rate is the same as the current clk rate.
* When clk rates are the same, compare this with the current state. * When clk rates are the same, compare this with the current state.
@@ -777,7 +781,8 @@ set_clk_rate:
} }
exit_no_err: exit_no_err:
d_mpr_h("%s: exiting with success\n", __func__); d_mpr_h("%s: clk rate %llu set successfully for %s\n",
__func__, clk_val, tbl_entry->name);
return rc; return rc;
err_invalid_client: err_invalid_client:
@@ -889,7 +894,7 @@ static int mmrm_sw_prepare_table(struct mmrm_clk_platform_resources *cres,
int mmrm_init_sw_clk_mgr(void *driver_data) int mmrm_init_sw_clk_mgr(void *driver_data)
{ {
int rc = 0; int rc = 0, i, j;
struct mmrm_driver_data *drv_data = struct mmrm_driver_data *drv_data =
(struct mmrm_driver_data *)driver_data; (struct mmrm_driver_data *)driver_data;
struct mmrm_clk_platform_resources *cres = &drv_data->clk_res; struct mmrm_clk_platform_resources *cres = &drv_data->clk_res;
@@ -936,7 +941,19 @@ int mmrm_init_sw_clk_mgr(void *driver_data)
/* update the peak current threshold */ /* update the peak current threshold */
sinfo->peak_cur_data.threshold = cres->threshold; sinfo->peak_cur_data.threshold = cres->threshold;
sinfo->peak_cur_data.aggreg_val = 0; sinfo->peak_cur_data.aggreg_val = 0;
sinfo->peak_cur_data.aggreg_level = MMRM_VDD_LEVEL_SVS_L1; sinfo->peak_cur_data.aggreg_level = 0;
sinfo->throttle_clients_data_length = cres->throttle_clients_data_length;
for (i = 0; i < sinfo->throttle_clients_data_length; i++) {
for (j = 0; j < sinfo->tot_clk_clients; j++) {
if (sinfo->clk_client_tbl[j].clk_src_id
== cres->clsid_threshold_clients[i]) {
sinfo->throttle_clients_info[i].csid_throttle_client
= cres->clsid_threshold_clients[i];
sinfo->throttle_clients_info[i].tbl_entry_id = j;
break;
}
}
}
/* initialize mutex for sw clk mgr */ /* initialize mutex for sw clk mgr */
mutex_init(&sw_clk_mgr->lock); mutex_init(&sw_clk_mgr->lock);

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* Copyright (c) 2020, The Linux Foundation. All rights reserved. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*/ */
#ifndef __MMRM_DEBUG__ #ifndef __MMRM_DEBUG__

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* Copyright (c) 2020, The Linux Foundation. All rights reserved. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*/ */
#ifdef _FIXP_ARITH_H #ifdef _FIXP_ARITH_H

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (c) 2020, The Linux Foundation. All rights reserved. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*/ */
#include <linux/types.h> #include <linux/types.h>
@@ -20,9 +20,36 @@ static struct mmrm_common_data waipio_common_data[] = {
}, },
}; };
/*throttle client list is as per fdd & resource availability*/
static struct mmrm_throttle_clients_data waipio_throttle_clients_data[] = {
{
.domain = MMRM_CLIENT_DOMAIN_DISPLAY,
.id = 0x3d,
},
{
.domain = MMRM_CLIENT_DOMAIN_VIDEO,
.id = 0x03,
},
{
.domain = MMRM_CLIENT_DOMAIN_CAMERA,
.id = 0x46,
},
{
.domain = MMRM_CLIENT_DOMAIN_CVP,
.id = 0x08,
},
{
.domain = MMRM_CLIENT_DOMAIN_CAMERA,
.id = 0x02,
},
};
static struct mmrm_platform_data waipio_data = { static struct mmrm_platform_data waipio_data = {
.common_data = waipio_common_data, .common_data = waipio_common_data,
.common_data_length = ARRAY_SIZE(waipio_common_data), .common_data_length = ARRAY_SIZE(waipio_common_data),
.throttle_clk_clients_data = waipio_throttle_clients_data,
.throttle_clk_clients_data_length = ARRAY_SIZE(waipio_throttle_clients_data),
}; };
static const struct of_device_id mmrm_dt_match[] = { static const struct of_device_id mmrm_dt_match[] = {

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* Copyright (c) 2020, The Linux Foundation. All rights reserved. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*/ */
#ifndef _MMRM_INTERNAL_H_ #ifndef _MMRM_INTERNAL_H_
@@ -17,9 +17,16 @@ struct mmrm_common_data {
int value; int value;
}; };
struct mmrm_throttle_clients_data {
u32 domain;
u32 id;
};
struct mmrm_platform_data { struct mmrm_platform_data {
struct mmrm_common_data *common_data; struct mmrm_common_data *common_data;
struct mmrm_throttle_clients_data *throttle_clk_clients_data;
u32 common_data_length; u32 common_data_length;
u16 throttle_clk_clients_data_length;
u32 scheme; u32 scheme;
}; };

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (c) 2020, The Linux Foundation. All rights reserved. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*/ */
#include <linux/types.h> #include <linux/types.h>
@@ -30,7 +30,7 @@ static int mmrm_read_clk_pltfrm_rsrc_frm_drv_data(
{ {
struct mmrm_platform_data *pdata; struct mmrm_platform_data *pdata;
struct mmrm_clk_platform_resources *cres; struct mmrm_clk_platform_resources *cres;
int rc = 0; int i = 0;
pdata = ddata->platform_data; pdata = ddata->platform_data;
cres = &ddata->clk_res; cres = &ddata->clk_res;
@@ -44,8 +44,15 @@ static int mmrm_read_clk_pltfrm_rsrc_frm_drv_data(
"qcom,mmrm_clk_mgr_scheme"); "qcom,mmrm_clk_mgr_scheme");
d_mpr_h("%s: configured mmrm scheme %d\n", d_mpr_h("%s: configured mmrm scheme %d\n",
__func__, cres->scheme); __func__, cres->scheme);
cres->throttle_clients_data_length = pdata->throttle_clk_clients_data_length;
return rc; for (i = 0; i < pdata->throttle_clk_clients_data_length; i++) {
cres->clsid_threshold_clients[i] =
(pdata->throttle_clk_clients_data[i].domain << 16
| pdata->throttle_clk_clients_data[i].id);
}
return 0;
} }
static void mmrm_free_rail_corner_table( static void mmrm_free_rail_corner_table(

View File

@@ -1,12 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* Copyright (c) 2020, The Linux Foundation. All rights reserved. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*/ */
#ifndef _MMRM_RESOURCES_H_ #ifndef _MMRM_RESOURCES_H_
#define _MMRM_RESOURCES_H_ #define _MMRM_RESOURCES_H_
#include <linux/platform_device.h> #include <linux/platform_device.h>
#define MMRM_MAX_THROTTLE_CLIENTS 5
struct corner_info { struct corner_info {
const char *name; const char *name;
@@ -36,6 +37,8 @@ struct mmrm_clk_platform_resources {
struct platform_device *pdev; struct platform_device *pdev;
u32 threshold; u32 threshold;
u32 scheme; u32 scheme;
u32 clsid_threshold_clients[MMRM_MAX_THROTTLE_CLIENTS];
u16 throttle_clients_data_length;
struct voltage_corner_set corner_set; struct voltage_corner_set corner_set;
struct nom_clk_src_set nom_clk_set; struct nom_clk_src_set nom_clk_set;
}; };

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (c) 2020, The Linux Foundation. All rights reserved. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*/ */
#include <linux/module.h> #include <linux/module.h>