blob: 4a987bf622ff3f5fa45155f996d11e3cd4841d59 [file] [log] [blame]
/*
* NDA AND NEED-TO-KNOW REQUIRED
*
* Copyright © 2013-2018 Synaptics Incorporated. All rights reserved.
*
* This file contains information that is proprietary to Synaptics
* Incorporated ("Synaptics"). The holder of this file shall treat all
* information contained herein as confidential, shall use the
* information only for its intended purpose, and shall not duplicate,
* disclose, or disseminate any of this information in any manner
* unless Synaptics has otherwise provided express, written
* permission.
*
* Use of the materials may require a license of intellectual property
* from a third party or from Synaptics. This file conveys no express
* or implied licenses to any intellectual property rights belonging
* to Synaptics.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND
* SYNAPTICS EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE, AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY
* INTELLECTUAL PROPERTY RIGHTS. IN NO EVENT SHALL SYNAPTICS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE, OR
* CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION WITH THE USE
* OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED AND
* BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF
* COMPETENT JURISDICTION DOES NOT PERMIT THE DISCLAIMER OF DIRECT
* DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' TOTAL CUMULATIVE LIABILITY
* TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. DOLLARS.
*/
#include <io.h>
#include "util.h"
#include "debug.h"
#include "chip_voltage_info.h"
#include "pmic_select.h"
#include "lgpl_printf.h"
#include "pv_comp.h"
#define UNUSED(var) do { (void)(var); } while(0)
const dvfs_ops_t * dvfs_ops = NULL;
static int find_dvfs_group(struct freq_leakage_table *flt, int pll, int leakage)
{
struct leakage_table *p = NULL;
while(flt->freq != 0) {
if(flt->freq >= pll) {
p = flt->lt;
if(p == NULL) {
break;
}
while(1) {
if(leakage <= p->info)
break;
p++;
}
return p->volt;
}
flt++;
}
return -1;
}
static int get_vcpu_volt_from_dvfs(int cpu_pll, int leakage)
{
struct freq_leakage_table *flt = get_vcpu_leakage_table();
int ret = 0;
if(flt == NULL) {
lgpl_printf("No vcpu PV table found!!!!\n");
return -1;
}
ret = find_dvfs_group(flt, cpu_pll, leakage);
if(ret == -1)
lgpl_printf("No leakage group in vcpu PV table found!!!!\n");
return ret;
}
#ifdef CORE_VOLT_VALUE
int get_vcore_volt_from_dvfs(int gpu_pll, int leakage)
{
struct freq_leakage_table *flt = get_vcore_leakage_table();
int ret = 0;
if(flt == NULL) {
lgpl_printf("No vcore PV table found!!!!\n");
return -1;
}
ret = find_dvfs_group(flt, gpu_pll, leakage);
if(ret == -1)
lgpl_printf("No leakage group in vcore PV table found!!!!\n");
return ret;
}
#endif
void get_vcpu_vh_vl(unsigned int *opp)
{
int leakage = 0;
int volt = 0;
unsigned int count = 0;
struct freq_leakage_table *flt = NULL;
leakage = get_leakage_info();
flt = get_vcpu_leakage_table();
if(flt == NULL) {
lgpl_printf("No vcpu PV table found!!!!\n");
goto error;
}
//vl
if(flt->freq != 0) {
volt = get_vcpu_volt_from_dvfs(flt->freq, leakage);
if(volt > 0) {
opp[count++] = volt * 1000;
lgpl_printf("vl = %d\n", (volt * 1000));
}
flt++;
//vh
if(flt->freq != 0) {
volt = get_vcpu_volt_from_dvfs(flt->freq, leakage);
if(volt > 0) {
opp[count++] = volt * 1000;
lgpl_printf("vh = %d\n", (volt * 1000));
}
}
}
if(count > 1) {
lgpl_printf("Got %d value for vcpu vl and vh\n", count);
return;
}
error:
lgpl_printf("###### wrong value for vcpu vl and vh!!!!!!!!\n");
return;
}
#ifdef CORE_VOLT_VALUE
void get_vcore_vh_vl(unsigned int *opp)
{
int leakage = 0;
int volt = 0;
unsigned int count = 0;
struct freq_leakage_table *flt = NULL;
leakage = get_leakage_info();
flt = get_vcore_leakage_table();
if(NULL == flt) {
lgpl_printf("No vcore PV table found!!!!\n");
goto error;
}
//vl
if(0 != flt->freq) {
volt = get_vcore_volt_from_dvfs(flt->freq, leakage);
if(volt > 0) {
opp[count++] = volt * 1000;
lgpl_printf("vcore vl = %d\n", (volt * 1000));
}
flt++;
//vh
if(0 != flt->freq) {
volt = get_vcore_volt_from_dvfs(flt->freq, leakage);
if(volt > 0) {
opp[count++] = volt * 1000;
lgpl_printf("vcore vh = %d\n", (volt * 1000));
}
}
}
if(count > 1) {
lgpl_printf("Got %d value for vcore vl and vh\n", count);
return;
}
error:
lgpl_printf("###### wrong value for vcore vl and vh!!!!!!!!\n");
return;
}
#endif
extern const dvfs_ops_t m88pg86x_ops;
extern const dvfs_ops_t sy8824b_ops;
extern const dvfs_ops_t ncp6335d_ops;
extern const dvfs_ops_t sy20276_ops;
extern const dvfs_ops_t sy20278_ops;
void pv_comp(int cpu_pll, int gpu_pll)
{
int leakage_info = 0;
int volt = 0, final_volt = 0, default_cpu_volt = 0;;
int ret = 0;
unsigned int pmic_id = get_pmic_id();
if(M88PG86X == pmic_id) {
lgpl_printf("PMIC: Marvell 88PG86X selected!\n");
dvfs_ops = &m88pg86x_ops;
}
else if(SY8824B == pmic_id) {
lgpl_printf("PMIC: SY8824B selected!\n");
dvfs_ops = &sy8824b_ops;
}
else if(SY20276 == pmic_id) {
lgpl_printf("PMIC: SY20276 is selected!\n");
dvfs_ops = &sy20276_ops;
}
else if(SY20278 == pmic_id) {
lgpl_printf("PMIC: SY20278 is selected!\n");
dvfs_ops = &sy20278_ops;
}
else if(NCP6335D == pmic_id) {
lgpl_printf("PMIC: NCP6335D selected!\n");
dvfs_ops = &ncp6335d_ops;
}
if(NULL == dvfs_ops)
lgpl_printf("WARN: unsupported PMIC for pv_comp!\n");
leakage_info = get_leakage_info();
if(!leakage_info) {
lgpl_printf("leakage is not present!!!!\n");
return;
}
lgpl_printf("leakage info %d.\n", leakage_info);
// start to set vcpu
volt = get_vcpu_volt_from_dvfs(cpu_pll, leakage_info);
if(volt != -1)
final_volt = volt * 1000; //change to uv to handle 12.5mv case
else {
lgpl_printf("Failed to parse valid vcpu from opp table !\n");
#ifdef CORE_VOLT_VALUE
goto set_vcore;
#else
UNUSED(gpu_pll);
return ;
#endif
}
default_cpu_volt = dvfs_ops->get_vcpu_volt();
if(default_cpu_volt < 0) {
lgpl_printf("Failed to get current Vcpu! \n");
return ;
}
volt = default_cpu_volt;
if(volt == final_volt) {
lgpl_printf("Vcpu is %duV, default setting by hardware. \n",volt);
} else {
ret = dvfs_ops->set_vcpu_volt(default_cpu_volt, final_volt);
if(ret)
lgpl_printf("Failed to set Vcpu from %duv to %duv\n", default_cpu_volt, final_volt);
else
lgpl_printf("set Vcpu from %duv to %duv\n", default_cpu_volt, final_volt);
}
#ifdef CORE_VOLT_VALUE
set_vcore:
{
int default_core_volt = 0;
// start to set vcore if has
volt = get_vcore_volt_from_dvfs(gpu_pll, leakage_info);
if(volt != -1)
final_volt = volt * 1000; //change to uv to handle 12.5mv case
else {
lgpl_printf("Failed to parse valid vcore from opp table !\n");
return;
}
default_core_volt = dvfs_ops->get_vcore_volt();
if(default_core_volt < 0) {
lgpl_printf("Failed to get current Vcore! \n");
return;
}
volt = default_core_volt;
if(volt == final_volt) {
lgpl_printf("Vcore is %duV, default setting by hardware. \n",volt);
} else {
ret = dvfs_ops->set_vcore_volt(final_volt, default_core_volt);
if(ret) {
lgpl_printf("Failed to set Vcore from %duv to %duv\n", default_core_volt, final_volt);
} else {
lgpl_printf("set Vcore from %duv to %duv\n", default_cpu_volt, final_volt);
}
}
}
#endif
return ;
}