283 lines
7.0 KiB
C
283 lines
7.0 KiB
C
|
/* linux/drivers/soc/samsung/cal-if/pmucal_asv.c
|
||
|
*
|
||
|
* Copyright (c) 2016 Samsung Electronics Co., Ltd.
|
||
|
* http://www.samsung.com/
|
||
|
*
|
||
|
* ASV common driver for Exynos
|
||
|
* Author: Hyunju Kang <hjtop.kang@samsung.com>
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License version 2 as
|
||
|
* published by the Free Software Foundation.
|
||
|
*/
|
||
|
|
||
|
#include "fvmap_asv.h"
|
||
|
#include "pwrcal.h"
|
||
|
#include "vclk.h"
|
||
|
#include <soc/samsung/ect_parser.h>
|
||
|
#include "cmucal.h"
|
||
|
|
||
|
static void asv_set_grp(unsigned int id, unsigned int asvgrp)
|
||
|
{
|
||
|
if (exynos_cal_asv_ops.set_grp)
|
||
|
exynos_cal_asv_ops.set_grp(id, asvgrp);
|
||
|
}
|
||
|
|
||
|
static void asv_set_tablever(unsigned int version)
|
||
|
{
|
||
|
asv_table_ver = version;
|
||
|
}
|
||
|
|
||
|
static void asv_set_ssa0(unsigned int id, unsigned int ssa0)
|
||
|
{
|
||
|
if (exynos_cal_asv_ops.set_ssa0)
|
||
|
exynos_cal_asv_ops.set_ssa0(id, ssa0);
|
||
|
}
|
||
|
|
||
|
static void asv_get_asvinfo(void)
|
||
|
{
|
||
|
if (exynos_cal_asv_ops.asv_get_asvinfo)
|
||
|
exynos_cal_asv_ops.asv_get_asvinfo();
|
||
|
}
|
||
|
|
||
|
static int get_asv_table(unsigned int *table, unsigned int id)
|
||
|
{
|
||
|
int max_lv = 0;
|
||
|
|
||
|
if (exynos_cal_asv_ops.get_asv_table)
|
||
|
max_lv = exynos_cal_asv_ops.get_asv_table(table, id);
|
||
|
|
||
|
return max_lv;
|
||
|
}
|
||
|
|
||
|
static int asv_rcc_set_table(void)
|
||
|
{
|
||
|
int result = 0;
|
||
|
|
||
|
if (exynos_cal_asv_ops.set_rcc_table)
|
||
|
result = exynos_cal_asv_ops.set_rcc_table();
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static void asv_voltage_init_table(struct asv_table_list **asv_table, char *name)
|
||
|
{
|
||
|
struct ect_voltage_domain *domain = NULL;
|
||
|
struct ect_voltage_table *table = NULL;
|
||
|
struct asv_table_entry *asv_entry = NULL;
|
||
|
struct ect_margin_domain *margin_domain = NULL;
|
||
|
void *asv_block = NULL, *margin_block = NULL;
|
||
|
int i =0, j = 0, k = 0;
|
||
|
|
||
|
asv_block = ect_get_block("ASV");
|
||
|
if (asv_block == NULL)
|
||
|
return;
|
||
|
|
||
|
margin_block = ect_get_block("MARGIN");
|
||
|
|
||
|
domain = ect_asv_get_domain(asv_block, name);
|
||
|
if (domain == NULL)
|
||
|
return;
|
||
|
|
||
|
if (margin_block)
|
||
|
margin_domain = ect_margin_get_domain(margin_block, name);
|
||
|
|
||
|
*asv_table = kzalloc(sizeof(struct asv_table_list) * domain->num_of_table, GFP_KERNEL);
|
||
|
if (*asv_table == NULL)
|
||
|
return;
|
||
|
|
||
|
for (i = 0; i < domain->num_of_table; ++i) {
|
||
|
table = &domain->table_list[i];
|
||
|
|
||
|
(*asv_table)[i].table_size = domain->num_of_table;
|
||
|
(*asv_table)[i].table = kzalloc(sizeof(struct asv_table_entry) * domain->num_of_level, GFP_KERNEL);
|
||
|
if ((*asv_table)[i].table == NULL)
|
||
|
return;
|
||
|
|
||
|
for (j = 0; j < domain->num_of_level; ++j) {
|
||
|
asv_entry = &(*asv_table)[i].table[j];
|
||
|
|
||
|
asv_entry->index = domain->level_list[j];
|
||
|
asv_entry->voltage = kzalloc(sizeof(unsigned int) * domain->num_of_group, GFP_KERNEL);
|
||
|
|
||
|
for (k = 0; k < domain->num_of_group; ++k) {
|
||
|
if (table->voltages != NULL)
|
||
|
asv_entry->voltage[k] = table->voltages[j * domain->num_of_group + k];
|
||
|
else if (table->voltages_step != NULL)
|
||
|
asv_entry->voltage[k] = table->voltages_step[j * domain->num_of_group + k] * table->volt_step;
|
||
|
|
||
|
if (margin_domain != NULL) {
|
||
|
if (margin_domain->offset != NULL)
|
||
|
asv_entry->voltage[k] += margin_domain->offset[j * margin_domain->num_of_group + k];
|
||
|
else
|
||
|
asv_entry->voltage[k] += margin_domain->offset_compact[j * margin_domain->num_of_group + k] * margin_domain->volt_step;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void asv_rcc_init_table(struct asv_table_list **rcc_table, char *name)
|
||
|
{
|
||
|
struct ect_rcc_domain *domain = NULL;
|
||
|
struct ect_rcc_table *table = NULL;
|
||
|
struct asv_table_entry *rcc_entry = NULL;
|
||
|
void *rcc_block = NULL;
|
||
|
int i = 0, j = 0, k = 0;
|
||
|
|
||
|
rcc_block = ect_get_block("RCC");
|
||
|
if (rcc_block == NULL)
|
||
|
return;
|
||
|
|
||
|
domain = ect_rcc_get_domain(rcc_block, name);
|
||
|
if (domain == NULL)
|
||
|
return;
|
||
|
|
||
|
*rcc_table = kzalloc(sizeof(struct asv_table_list) * domain->num_of_table, GFP_KERNEL);
|
||
|
if (*rcc_table == NULL)
|
||
|
return;
|
||
|
|
||
|
for (i = 0; i < domain->num_of_table; ++i) {
|
||
|
table = &domain->table_list[i];
|
||
|
|
||
|
(*rcc_table)[i].table_size = domain->num_of_table;
|
||
|
(*rcc_table)[i].table = kzalloc(sizeof(struct asv_table_entry) * domain->num_of_level, GFP_KERNEL);
|
||
|
if ((*rcc_table)[i].table == NULL)
|
||
|
return;
|
||
|
|
||
|
for (j = 0; j < domain->num_of_level; ++j) {
|
||
|
rcc_entry = &(*rcc_table)[i].table[j];
|
||
|
|
||
|
rcc_entry->index = domain->level_list[j];
|
||
|
rcc_entry->voltage = kzalloc(sizeof(unsigned int) * domain->num_of_group, GFP_KERNEL);
|
||
|
|
||
|
for (k = 0; k < domain->num_of_group; ++k) {
|
||
|
if (table->rcc != NULL)
|
||
|
rcc_entry->voltage[k] = table->rcc[j * domain->num_of_group + k];
|
||
|
else
|
||
|
rcc_entry->voltage[k] = table->rcc_compact[j * domain->num_of_group + k];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void asv_voltage_table_init(void)
|
||
|
{
|
||
|
int i = 0;
|
||
|
|
||
|
for (i = 0; i < NUM_OF_DVFS; i++)
|
||
|
asv_voltage_init_table(&(asv_table[i]), dvfs_names[i]);
|
||
|
}
|
||
|
|
||
|
static void asv_rcc_table_init(void)
|
||
|
{
|
||
|
int i = 0;
|
||
|
|
||
|
for (i = 0; i < NUM_OF_DVFS; i++)
|
||
|
asv_rcc_init_table(&(rcc_table[i]), dvfs_names[i]);
|
||
|
}
|
||
|
|
||
|
static void asv_ssa_init(void)
|
||
|
{
|
||
|
void *gen_block = 0;
|
||
|
struct ect_gen_param_table *param = NULL;
|
||
|
unsigned int asv_table_version = asv_table_ver;
|
||
|
int i = 0, j = 0;
|
||
|
|
||
|
gen_block = ect_get_block("GEN");
|
||
|
if (gen_block == NULL)
|
||
|
return;
|
||
|
|
||
|
for (i = 0; i < NUM_OF_DVFS; i++) {
|
||
|
param = ect_gen_param_get_table(gen_block, ssa_names[i]);
|
||
|
if (param) {
|
||
|
subgrp_table[i] = param->parameter[asv_table_version * param->num_of_col + SUB_GROUP_INDEX];
|
||
|
ssa_info_table[i].ssa0_base = param->parameter[asv_table_version * param->num_of_col + SSA0_BASE_INDEX];
|
||
|
ssa_info_table[i].ssa0_offset = param->parameter[asv_table_version * param->num_of_col + SSA0_OFFSET_INDEX];
|
||
|
for (j = 0; j < size_of_ssa1_table; j++)
|
||
|
ssa_info_table[i].ssa1_table[j] = param->parameter[asv_table_version * param->num_of_col + 4 + j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void asv_ema_init(void)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
static void asv_print_info(void)
|
||
|
{
|
||
|
int i = 0;
|
||
|
|
||
|
pr_info("asv_table_ver : %d\n", asv_table_ver);
|
||
|
pr_info("fused_grp : %d\n", fused_grp);
|
||
|
|
||
|
for (i = 0; i < NUM_OF_DVFS; i++)
|
||
|
pr_info("%s_asv_group : %u\n", dvfs_names[i], fused_table[i].asv_group);
|
||
|
}
|
||
|
|
||
|
static void rcc_print_info(void)
|
||
|
{
|
||
|
if (exynos_cal_asv_ops.print_rcc_info)
|
||
|
exynos_cal_asv_ops.print_rcc_info();
|
||
|
}
|
||
|
|
||
|
static int asv_set_ema(unsigned int id, unsigned int volt)
|
||
|
{
|
||
|
int result = 0;
|
||
|
|
||
|
if(exynos_cal_asv_ops.set_ema)
|
||
|
result = exynos_cal_asv_ops.set_ema(id, volt);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static int asv_get_grp(unsigned int id, unsigned int lv)
|
||
|
{
|
||
|
int result = 0;
|
||
|
|
||
|
if (exynos_cal_asv_ops.get_grp)
|
||
|
result = exynos_cal_asv_ops.get_grp(id, lv);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static int asv_get_tablever(void)
|
||
|
{
|
||
|
return (int)(asv_table_ver);
|
||
|
}
|
||
|
|
||
|
int cal_asv_init(void)
|
||
|
{
|
||
|
int i = 0;
|
||
|
|
||
|
for (i = 0; i < NUM_OF_DVFS; i++) {
|
||
|
asv_table[i] = NULL;
|
||
|
rcc_table[i] = NULL;
|
||
|
}
|
||
|
|
||
|
asv_get_asvinfo();
|
||
|
asv_voltage_table_init();
|
||
|
asv_rcc_table_init();
|
||
|
asv_ssa_init();
|
||
|
asv_ema_init();
|
||
|
|
||
|
if (exynos_cal_asv_ops.asv_init)
|
||
|
exynos_cal_asv_ops.asv_init();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
struct cal_asv_ops cal_asv_ops = {
|
||
|
.print_asv_info = asv_print_info,
|
||
|
.print_rcc_info = rcc_print_info,
|
||
|
.asv_init = cal_asv_init,
|
||
|
.set_grp = asv_set_grp,
|
||
|
.get_grp = asv_get_grp,
|
||
|
.get_asv_table = get_asv_table,
|
||
|
.set_tablever = asv_set_tablever,
|
||
|
.get_tablever = asv_get_tablever,
|
||
|
.set_rcc_table = asv_rcc_set_table,
|
||
|
.set_ssa0 = asv_set_ssa0,
|
||
|
.set_ema = asv_set_ema,
|
||
|
};
|