#include #include #include #include #include #include #include #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; }