363 lines
7.8 KiB
C
Executable File
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;
|
|
}
|