lineage_kernel_xcoverpro/drivers/soc/samsung/cal-if/fvmap.c

363 lines
7.8 KiB
C
Executable File

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <soc/samsung/cal-if.h>
#include "fvmap.h"
#include "cmucal.h"
#include "vclk.h"
#include "ra.h"
#define FVMAP_SIZE (SZ_8K)
#define STEP_UV (6250)
void __iomem *fvmap_base;
void __iomem *sram_fvmap_base;
static int init_margin_table[MAX_MARGIN_ID];
static int volt_offset_percent = 0;
static int __init get_mif_volt(char *str)
{
int volt;
get_option(&str, &volt);
init_margin_table[MARGIN_MIF] = volt;
return 0;
}
early_param("mif", get_mif_volt);
static int __init get_int_volt(char *str)
{
int volt;
get_option(&str, &volt);
init_margin_table[MARGIN_INT] = volt;
return 0;
}
early_param("int", get_int_volt);
static int __init get_big_volt(char *str)
{
int volt;
get_option(&str, &volt);
init_margin_table[MARGIN_BIG] = volt;
return 0;
}
early_param("big", get_big_volt);
static int __init get_lit_volt(char *str)
{
int volt;
get_option(&str, &volt);
init_margin_table[MARGIN_LIT] = volt;
return 0;
}
early_param("lit", get_lit_volt);
static int __init get_g3d_volt(char *str)
{
int volt;
get_option(&str, &volt);
init_margin_table[MARGIN_G3D] = volt;
return 0;
}
early_param("g3d", get_g3d_volt);
static int __init get_intcam_volt(char *str)
{
int volt;
get_option(&str, &volt);
init_margin_table[MARGIN_INTCAM] = volt;
return 0;
}
early_param("intcam", get_intcam_volt);
static int __init get_cam_volt(char *str)
{
int volt;
get_option(&str, &volt);
init_margin_table[MARGIN_CAM] = volt;
return 0;
}
early_param("cam", get_cam_volt);
static int __init get_disp_volt(char *str)
{
int volt;
get_option(&str, &volt);
init_margin_table[MARGIN_DISP] = volt;
return 0;
}
early_param("disp", get_disp_volt);
static int __init get_g3dm_volt(char *str)
{
int volt;
get_option(&str, &volt);
init_margin_table[MARGIN_G3DM] = volt;
return 0;
}
early_param("g3dm", get_g3dm_volt);
static int __init get_cp_volt(char *str)
{
int volt;
get_option(&str, &volt);
init_margin_table[MARGIN_CP] = volt;
return 0;
}
early_param("cp", get_cp_volt);
static int __init get_fsys0_volt(char *str)
{
int volt;
get_option(&str, &volt);
init_margin_table[MARGIN_FSYS0] = volt;
return 0;
}
early_param("fsys0", get_fsys0_volt);
static int __init get_aud_volt(char *str)
{
int volt;
get_option(&str, &volt);
init_margin_table[MARGIN_AUD] = volt;
return 0;
}
early_param("aud", get_aud_volt);
static int __init get_iva_volt(char *str)
{
int volt;
get_option(&str, &volt);
init_margin_table[MARGIN_IVA] = volt;
return 0;
}
early_param("iva", get_iva_volt);
static int __init get_score_volt(char *str)
{
int volt;
get_option(&str, &volt);
init_margin_table[MARGIN_SCORE] = volt;
return 0;
}
early_param("score", get_score_volt);
static int __init get_percent_margin_volt(char *str)
{
int percent;
get_option(&str, &percent);
volt_offset_percent = percent;
return 0;
}
early_param("volt_offset_percent", get_percent_margin_volt);
int fvmap_set_raw_voltage_table(unsigned int id, int uV)
{
struct fvmap_header *fvmap_header;
struct rate_volt_header *fv_table;
int num_of_lv;
int idx, i;
idx = GET_IDX(id);
fvmap_header = sram_fvmap_base;
fv_table = sram_fvmap_base + fvmap_header[idx].o_ratevolt;
num_of_lv = fvmap_header[idx].num_of_lv;
for (i = 0; i < num_of_lv; i++)
fv_table->table[i].volt += uV;
return 0;
}
int fvmap_get_voltage_table(unsigned int id, unsigned int *table)
{
struct fvmap_header *fvmap_header = fvmap_base;
struct rate_volt_header *fv_table;
int idx, i;
int num_of_lv;
if (!IS_ACPM_VCLK(id))
return 0;
idx = GET_IDX(id);
fvmap_header = fvmap_base;
fv_table = fvmap_base + fvmap_header[idx].o_ratevolt;
num_of_lv = fvmap_header[idx].num_of_lv;
for (i = 0; i < num_of_lv; i++)
table[i] = fv_table->table[i].volt;
return num_of_lv;
}
int fvmap_get_raw_voltage_table(unsigned int id)
{
struct fvmap_header *fvmap_header;
struct rate_volt_header *fv_table;
int idx, i;
int num_of_lv;
unsigned int table[20];
idx = GET_IDX(id);
fvmap_header = sram_fvmap_base;
fv_table = sram_fvmap_base + fvmap_header[idx].o_ratevolt;
num_of_lv = fvmap_header[idx].num_of_lv;
for (i = 0; i < num_of_lv; i++)
table[i] = fv_table->table[i].volt;
for (i = 0; i < num_of_lv; i++)
printk("dvfs id : %d %d Khz : %d uv\n", ACPM_VCLK_TYPE | id, fv_table->table[i].rate, table[i]);
return 0;
}
static void check_percent_margin(struct rate_volt_header *head, unsigned int num_of_lv)
{
int org_volt;
int percent_volt;
int i;
if (!volt_offset_percent)
return;
for (i = 0; i < num_of_lv; i++) {
org_volt = head->table[i].volt;
percent_volt = org_volt * volt_offset_percent / 100;
head->table[i].volt = org_volt + rounddown(percent_volt, STEP_UV);
}
}
static void fvmap_copy_from_sram(void __iomem *map_base, void __iomem *sram_base)
{
struct fvmap_header *fvmap_header, *header;
struct rate_volt_header *old, *new;
struct clocks *clks;
struct pll_header *plls;
struct vclk *vclk;
struct cmucal_clk *clk_node;
unsigned int paddr_offset, fvaddr_offset;
int size, margin;
int i, j;
fvmap_header = map_base;
header = sram_base;
size = cmucal_get_list_size(ACPM_VCLK_TYPE);
for (i = 0; i < size; i++) {
/* load fvmap info */
fvmap_header[i].dvfs_type = header[i].dvfs_type;
fvmap_header[i].num_of_lv = header[i].num_of_lv;
fvmap_header[i].num_of_members = header[i].num_of_members;
fvmap_header[i].num_of_pll = header[i].num_of_pll;
fvmap_header[i].num_of_mux = header[i].num_of_mux;
fvmap_header[i].num_of_div = header[i].num_of_div;
fvmap_header[i].gearratio = header[i].gearratio;
fvmap_header[i].init_lv = header[i].init_lv;
fvmap_header[i].num_of_gate = header[i].num_of_gate;
fvmap_header[i].reserved[0] = header[i].reserved[0];
fvmap_header[i].reserved[1] = header[i].reserved[1];
fvmap_header[i].block_addr[0] = header[i].block_addr[0];
fvmap_header[i].block_addr[1] = header[i].block_addr[1];
fvmap_header[i].block_addr[2] = header[i].block_addr[2];
fvmap_header[i].o_members = header[i].o_members;
fvmap_header[i].o_ratevolt = header[i].o_ratevolt;
fvmap_header[i].o_tables = header[i].o_tables;
vclk = cmucal_get_node(ACPM_VCLK_TYPE | i);
if (vclk == NULL)
continue;
pr_info("dvfs_type : %s - id : %x\n",
vclk->name, fvmap_header[i].dvfs_type);
pr_info(" num_of_lv : %d\n", fvmap_header[i].num_of_lv);
pr_info(" num_of_members : %d\n", fvmap_header[i].num_of_members);
old = sram_base + fvmap_header[i].o_ratevolt;
new = map_base + fvmap_header[i].o_ratevolt;
check_percent_margin(old, fvmap_header[i].num_of_lv);
margin = init_margin_table[vclk->margin_id];
if (margin)
cal_dfs_set_volt_margin(i | ACPM_VCLK_TYPE, margin);
for (j = 0; j < fvmap_header[i].num_of_lv; j++) {
new->table[j].rate = old->table[j].rate;
new->table[j].volt = old->table[j].volt;
pr_info(" lv : [%7d], volt = %d uV (%d %%) \n",
new->table[j].rate, new->table[j].volt,
volt_offset_percent);
}
for (j = 0; j < fvmap_header[i].num_of_pll; j++) {
clks = sram_base + fvmap_header[i].o_members;
plls = sram_base + clks->addr[j];
clk_node = cmucal_get_node(vclk->list[j]);
if (clk_node == NULL)
continue;
paddr_offset = clk_node->paddr & 0xFFFF;
fvaddr_offset = plls->addr & 0xFFFF;
if (paddr_offset == fvaddr_offset)
continue;
clk_node->paddr += fvaddr_offset - paddr_offset;
clk_node->pll_con0 += fvaddr_offset - paddr_offset;
if (clk_node->pll_con1)
clk_node->pll_con1 += fvaddr_offset - paddr_offset;
}
}
}
int fvmap_init(void __iomem *sram_base)
{
void __iomem *map_base;
map_base = kzalloc(FVMAP_SIZE, GFP_KERNEL);
fvmap_base = map_base;
sram_fvmap_base = sram_base;
pr_info("%s:fvmap initialize %p\n", __func__, sram_base);
fvmap_copy_from_sram(map_base, sram_base);
return 0;
}