blob: bb46f1074ffbab323313275fd4217a91b19afd04 [file] [log] [blame]
/*
* (C) Copyright 2018
* ASR Microelectronics (Shanghai) Co., Ltd.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <errno.h>
#include <common.h>
#include <command.h>
#include "../../board/Marvell/include/core.h"
#include <asm/io.h>
#include <asm/gpio.h>
#include <asm/arch/cpu.h>
#include <asm/arch/features.h>
#include <asm/gpio.h>
#include <linux/types.h>
#include <power/asr1901_freq.h>
#include <i2c.h>
#include <power/pmic.h>
#include <power/marvell88pm_pmic.h>
#include "../../board/Marvell/common/mv_cp.h"
//#define ASR180X_FREQ_DEBUG 1
/*
* !!!!!!!!!!!!!!!!!!!!!Note: AP and CP has different copy of the below variables
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!
* Which means AP only has real time value of c_aop,
* need to update/get the c_axiop value when CP not changing them.
* and vice-versa.
*/
#define ASR180X_NUM_PROFILES 16
uint32_t aop_num = 0, axiop_num = 0, csop_num = 0, dop_num = 0;
op_index c_aop=OP_INVALID, c_csop = OP_INVALID, c_dop = OP_INVALID;
op_index c_axiop = OP_INVALID;
uint32_t max_dvc = 0; /* The current max requested DVC level at AP or CP side*/
uint32_t uidro_svt = 0;
uint32_t uiProfile = 0;
int local_max_corefreq_mode;
#define GET_CHIP_DVL4OP_Ax(p, n) \
do {\
uint32_t j = 0; \
for (j = 0; j <= n; j++) \
(p[j].dvc) = (((p[j].dvcsa) >> (4*uiProfile))&0xF); \
} while(0)
#define AP_CLK_CTRL_MASK (0xfff)
#define CKPHY_FC_CTRL_MASK (0xf)
#define MC_HW_SLP_TYPE_MASK (0x3 << 5)
#define ACLK_CTRL_MASK (0xf)
#define CP_CORE_MAX_FREQ (416)
#define DP_CORE_MAX_FREQ (416)
core_freq *ca7_value;
core_freq ca7_value_832M[] = {
/*label pclk,memclk,busclk,pll2,pll2p,dvc,dvcs{profile15..profile0}, dvcsa*/
{"OP0", 312, 156, 156, 0, 0, 0, 0x0000000000000000, 0x0000000000000000},
{"OP1", 416, 208, 208, 0, 0, 0, 0x0000000000000000, 0x0000000000000000},
{"OP2", 624, 312, 156, 0, 0, 1, 0x0000000000000000, 0x0000000000000000},
{"OP3", 832, 416, 208, 0, 0, 2, 0x2222222221221002, 0x2222222221111002},
};
core_freq ca7_value_1248M[] = {
/*label pclk,memclk,busclk,pll2,pll2p,dvc,dvcs{profile15..profile0}, dvcsa*/
{"OP0", 312, 156, 156, 0, 0, 0, 0x0000000000000000, 0x0000000000000000},
{"OP1", 416, 208, 208, 0, 0, 0, 0x0000000000000000, 0x0000000000000000},
{"OP2", 624, 312, 156, 0, 0, 1, 0x0000000000000000, 0x0000000000000000},
{"OP3", 832, 416, 208, 0, 0, 2, 0x1111111110000001, 0x1111111110000001},
{"OP4", 1248,624, 312, 0, 0, 3, 0x3333333333332223, 0x3333333333332223},
};
/* the ASYNC bits has no use in AP side */
dfc_setting ca7_reg[] = {
/*pll2ref,pll2fb,apb_spare2,fccr[31:29],0x09FC0000|cc_ap[8:0] mc_reg_table*/
{NA , NA , NA , NA, (0x1 << 9)|(0x1 << 6)|(0x0 << 3)|(0x1 << 0), NA}, /* OP0 */
{NA , NA , NA , NA, (0x1 << 9)|(0x1 << 6)|(0x0 << 3)|(0x2 << 0), NA}, /* OP1 */
{NA , NA , NA , NA, (0x3 << 9)|(0x1 << 6)|(0x0 << 3)|(0x0 << 0), NA}, /* OP2 */
{NA , NA , NA , NA, (0x3 << 9)|(0x1 << 6)|(0x0 << 3)|(0x4 << 0), NA}, /* OP3 */
{NA , NA , NA , NA, (0x3 << 9)|(0x1 << 6)|(0x0 << 3)|(0x5 << 0), NA}, /* OP4 */
};
ddr_freq asr1901_ddr_value[] = {
/* label dclk, memclk/dclk_1x,busclk,pll2,pll2p,dvc,dvcs{profile15..profile0}, dvcsa*/
{"OP0", 266, 1066, 0, 0, 0x0000000000000000, 0x0000000000000000},
{"OP1", 533, 1066, 0, 0, 0x3333333333333333, 0x3333333333333333},
};
dfc_setting asr1901_ddr_reg[] = {
/*pll2ref,pll2fb,apb_spare2, fccr[27:26], 0x09F80000|cc_cp[8:0] mc_reg_table*/
{NA , NA , NA , NA, 0x4<<0, (0x0 << 5)}, /* OP0 */
{NA , NA , NA , NA, 0x0<<0, (0x1 << 5)}, /* OP2 */
};
axi_freq asr1901_aclk_value[] = {
/* label aclk,dvc,dvcs{profile15..profile0}, dvcsa*/
{"OP0", 156, 0, 0x0000000000000000, 0x0000000000000000},
{"OP1", 208, 0, 0x0000000000000000, 0x0000000000000000},
};
axi_freq *aclk_value;
axi_setting asr1901_aclk_reg[] = {
/* fccr[25|19], cc_cp[17:15] */
{NA, 0x0<<0}, /* OP0 */
{NA, 0x1<<0}, /* OP1 */
};
static struct cpmsa_dvc_info cpmsa_dvc_info_1901_832svc[] = {
[0] = {
.cpdvcinfo[0] = {312, VL0},
.cpdvcinfo[1] = {416, VL0},
.cpdvcinfo[2] = {624, VL2},
.msadvcvl[0] = {416, VL2},
},
[1] = {
.cpdvcinfo[0] = {312, VL0},
.cpdvcinfo[1] = {416, VL0},
.cpdvcinfo[2] = {624, VL0},
.msadvcvl[0] = {416, VL0},
},
[2] = {
.cpdvcinfo[0] = {312, VL0},
.cpdvcinfo[1] = {416, VL0},
.cpdvcinfo[2] = {624, VL0},
.msadvcvl[0] = {416, VL1},
},
[3] = {
.cpdvcinfo[0] = {312, VL0},
.cpdvcinfo[1] = {416, VL0},
.cpdvcinfo[2] = {624, VL1},
.msadvcvl[0] = {416, VL1},
},
[4] = {
.cpdvcinfo[0] = {312, VL0},
.cpdvcinfo[1] = {416, VL0},
.cpdvcinfo[2] = {624, VL1},
.msadvcvl[0] = {416, VL2},
},
};
static struct cpmsa_dvc_info cpmsa_dvc_info_1901_1248svc[] = {
[0] = {
.cpdvcinfo[0] = {312, VL0},
.cpdvcinfo[1] = {416, VL0},
.cpdvcinfo[2] = {624, VL1},
.msadvcvl[0] = {416, VL1},
},
[1] = {
.cpdvcinfo[0] = {312, VL0},
.cpdvcinfo[1] = {416, VL0},
.cpdvcinfo[2] = {624, VL0},
.msadvcvl[0] = {416, VL0},
},
[2] = {
.cpdvcinfo[0] = {312, VL0},
.cpdvcinfo[1] = {416, VL0},
.cpdvcinfo[2] = {624, VL0},
.msadvcvl[0] = {416, VL1},
},
};
static struct ddr_dfc_info ddrdfcinfo;
#define PM801_SLAVE_ADDR 0x31
#define PM801_VBUCK1_SET0_REG 0x3c /* dvc[1:0] = 0x0 */
#define VOL_BASE 600000
#define VOL_STEP 12500
#define VOL_HIGH 1400000
#define PM812_DVC1 67
#define PM812_DVC2 68
static void find_ddr_level(void)
{
int i;
ddrdfcinfo.ddr_idle = 0;
for (i = 0; i <= dop_num; i++) {
if (ddrdfcinfo.ddr_active == 0) {
/* is 266 ok ? */
if (asr1901_ddr_value[i].dclk >= 266) {
ddrdfcinfo.ddr_active = i;
}
}
if (ddrdfcinfo.ddr_high == 0) {
if (asr1901_ddr_value[i].dclk >= 400) {
ddrdfcinfo.ddr_high = i;
}
}
if (ddrdfcinfo.ddr_active && ddrdfcinfo.ddr_high)
break;
}
return;
}
static int set_volt(u32 vol)
{
int ret = 0;
unsigned gpio_dvc2, gpio_dvc1;
struct pmic *p_power;
struct pmic_chip_desc *board_pmic_chip;
vol *= 1000;
if ((vol < VOL_BASE) || (vol > VOL_HIGH)) {
printf("out of range when set voltage!\n");
return -1;
}
board_pmic_chip = get_marvell_pmic();
if (!board_pmic_chip)
return -1;
p_power = pmic_get(board_pmic_chip->power_name);
if (!p_power)
return -1;
if (pmic_probe(p_power))
return -1;
ret = marvell88pm_set_buck_vol(p_power, 1, vol, 0);
ret = marvell88pm_set_buck_vol(p_power, 1, vol, 1);
ret = marvell88pm_set_buck_vol(p_power, 1, vol, 2);
ret = marvell88pm_set_buck_vol(p_power, 1, vol, 3);
printf("Set VBUCK1 to %4dmV\n", vol / 1000);
gpio_dvc2 = PM812_DVC2;
gpio_dvc1 = PM812_DVC1;
/* always use DVC[1:0] = 0 in uboot */
/* TODO : make sure DVC pins' function is GPIO */
gpio_direction_output(gpio_dvc1, 0);
gpio_direction_output(gpio_dvc2, 0);
return ret;
}
static u32 get_volt(int buck_num, int level)
{
u32 vol = 0;
struct pmic *p_power;
struct pmic_chip_desc *board_pmic_chip;
board_pmic_chip = get_marvell_pmic();
if (!board_pmic_chip)
return -1;
p_power = pmic_get(board_pmic_chip->power_name);
if (!p_power)
return -1;
if (pmic_probe(p_power))
return -1;
vol = marvell88pm_get_buck_vol(p_power, buck_num, level);
if (vol < 0)
return -1;
return vol / 1000;
}
int do_setvolt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
ulong vol, buck_num = 1, dvl = 0;
int res = 0;
struct pmic *p_power;
struct pmic_chip_desc *board_pmic_chip;
if ((argc < 1) || (argc > 4))
return -1;
board_pmic_chip = get_marvell_pmic();
if (!board_pmic_chip)
return -1;
p_power = pmic_get(board_pmic_chip->power_name);
if (!p_power)
return -1;
if (pmic_probe(p_power))
return -1;
if (argc == 1) {
printf("usage: setvolt x xxxx(unit mV)\n"
"for PM80X, x can be 1 2 ... 5\n"
"for PM80X, xxxx can be 600..1300 for buck1,"
"step 13 or 21\n"
);
goto out;
} else if (argc == 2) {
res |= strict_strtoul(argv[1], 0, &buck_num);
goto out;
} else if (argc == 3) {
res |= strict_strtoul(argv[1], 0, &buck_num);
res |= strict_strtoul(argv[2], 0, &vol);
res |= marvell88pm_set_buck_vol(p_power, buck_num, vol*1000, 0);
res |= marvell88pm_set_buck_vol(p_power, buck_num, vol*1000, 1);
res |= marvell88pm_set_buck_vol(p_power, buck_num, vol*1000, 2);
res |= marvell88pm_set_buck_vol(p_power, buck_num, vol*1000, 3);
} else if (argc == 4) {
res |= strict_strtoul(argv[1], 0, &buck_num);
res |= strict_strtoul(argv[2], 0, &vol);
res |= strict_strtoul(argv[3], 0, &dvl);
res |= marvell88pm_set_buck_vol(p_power, buck_num, vol*1000, dvl);
}
if (res == 0)
printf("Voltage change was successful\n");
else
printf("Voltage change was unsuccessful\n");
out:
if (buck_num == 1 || buck_num == 4) {
printf("DVL00 -- BUCK%ld is %dmV\n",
buck_num, get_volt(buck_num, 0));
printf("DVL01 -- BUCK%ld is %dmV\n",
buck_num, get_volt(buck_num, 1));
printf("DVL10 -- BUCK%ld is %dmV\n",
buck_num, get_volt(buck_num, 2));
printf("DVL11 -- BUCK%ld is %dmV\n",
buck_num, get_volt(buck_num, 3));
} else
printf("BUCK%ld is %dmV in active mode\n",
buck_num, get_volt(buck_num, 0));
return 0;
}
U_BOOT_CMD(
setvolt, 6, 1, do_setvolt,
"Setting voltages",
""
);
static void BBU_REG_DUMP(char *sptr, uint32_t *reg_addr, uint32_t hexvalue)
{
printf("%s(%x) = %x \n", sptr, (uint32_t)reg_addr, (uint32_t)hexvalue);
}
static int check_help(char *help_argu)
{
if ((strcmp((const char*)help_argu, "/h") == 0) ||
(strcmp((const char*)help_argu, "--help") == 0))
return 1;
return 0;
}
static uint32_t pp_check_reg(char *reg_argu)
{
if ((strcmp((const char*)reg_argu, "/r") == 0) ||
(strcmp((const char*)reg_argu, "--regdump") == 0)) {
return 1;
}
return 0;
}
void get_ddr_pll(uint32_t *ddrpll)
{
volatile uint32_t temp;
uint32_t refclk = 26;
temp = PMUA->DDR_CKPHY_PLL1_CTRL2;
if (temp & (BIT7))
*ddrpll = refclk * (temp & 0x7f) * 2;
else
*ddrpll = refclk * (temp & 0x7f);
}
void hw_setup_ddr_pll(uint32_t pll2ref, uint32_t pll2fb, uint32_t apb_spare2)
{
printf("ddr pll should not be set in ddr running mode\n");
}
static uint32_t abs_diff(uint32_t value1, uint32_t value2)
{
if (value1 < value2) {
return (value2 - value1);
} else {
return (value1 - value2);
}
}
/*
* Collect all the AP and CP freqs and print out the infos, not include MSA.
*/
op_index aop_get_dump(core_freq *ap_op)
{
uint32_t pll_dragon, read_reg, temp_reg;
uint32_t i = 0;
read_reg = PMUA->AP_CLK_CTRL;
pll_dragon = (read_reg & 0x7) >> 0;
switch (pll_dragon) {
case 0:
pll_dragon = 624;
break;
case 1:
pll_dragon = 312;
break;
case 2:
pll_dragon = 416;
break;
case 3:
pll_dragon = 499;
break;
case 4:
pll_dragon = 832;
break;
case 5:
pll_dragon = 1248;
break;
}
temp_reg = (read_reg >> 3) & 0x7;
ap_op->pclk = pll_dragon / (temp_reg + 1) ;
temp_reg = (read_reg >> 6) & 0x7;
ap_op->memclk =ap_op->pclk / (temp_reg + 1) ;
temp_reg = (read_reg >> 9) & 0x7;
ap_op->busclk =ap_op->pclk / (temp_reg + 1) ;
while (i<aop_num) {
if ((abs_diff(ca7_value[i].pclk, ap_op->pclk)<5)&&
(abs_diff(ca7_value[i].memclk, ap_op->memclk)<5)&&
(abs_diff(ca7_value[i].busclk, ap_op->busclk)<5)) {
ap_op->dvc = ca7_value[i].dvc;
c_aop = (op_index)i;
break;
} else {
i++;
c_aop = OP_INVALID;
}
}
debug("CA7 pclk = %d, memclk= %d, busclk = %d\n",
ap_op->pclk,ap_op->memclk,ap_op->busclk);
return c_aop;
}
static uint32_t check_aop(int32_t top)
{
int32_t aop;
core_freq temp;
aop = aop_get_dump(&temp);
if (aop == OP_INVALID) {
printf("Warning: CA7 freqs are INVALID OP\n");
return OP_INVALID;
}
if (aop == top) {
printf("CA7 OP%d,DVL:%d\n", aop,max_dvc);
c_aop = top;
return MV_OK;
} else {
printf("Warning: CA7 OP changed but freqs are not expected.\n");
c_aop = aop;
return MV_FAIL;
}
}
static void dump_aop( unsigned int op_index)
{
core_freq *md = &(ca7_value[op_index]);
printf("%d(%s)---", op_index, md->label);
printf("pclk:%d memclk:%d busclk:%d dvc:%d\n",
md->pclk, md->memclk, md->busclk, md->dvc);
}
void dump_aop_list(void)
{
unsigned int i;
printf("AP core OP list \n");
for (i = 0; i < aop_num; i++) {
dump_aop(i);
}
}
void dump_cur_aop(void)
{
printf("CA7 @OP%d\n", c_aop);
dump_aop(c_aop);
}
op_index dop_get_dump(ddr_freq *d_op)
{
uint32_t pll_dp, read_reg, temp_reg, div_val;
uint32_t i = 0;
read_reg = PMUA->CKPHY_FC_CTRL;
get_ddr_pll(&pll_dp);
temp_reg = read_reg & 0xf;
if (temp_reg == 0)
div_val = 0x1;
else if (temp_reg == 0x4)
div_val = 0x2;
else if (temp_reg == 0x8)
div_val = 0x3;
else
div_val = 0x4;
d_op->dclk =pll_dp /(div_val)/2 ;
while (i < dop_num) {
if ((abs_diff(asr1901_ddr_value[i].dclk, d_op->dclk)<15)) {
d_op->dvc = asr1901_ddr_value[i].dvc;
c_dop = (op_index)i;
CIU->SW_SCRATCH = c_dop;
break;
} else {
i++;
c_dop = OP_INVALID;
CIU->SW_SCRATCH = c_dop;
}
}
debug("DDR dclk = %d, c_dop: %d\n",d_op->dclk, c_dop);
return c_dop;
}
static uint32_t check_dop(int32_t top)
{
int32_t dop;
ddr_freq temp;
dop = dop_get_dump(&temp);
if (dop == OP_INVALID) {
printf("Warning: DDR freqs are INVALID OP\n");
return OP_INVALID;
}
if (dop == top) {
printf("DDR OP%d,DVL:%d\n", dop,max_dvc);
c_dop = top;
CIU->SW_SCRATCH = c_dop;
return MV_OK;
} else {
printf("ERR: the DDR OP changed but freq is not expected\n");
c_dop = dop;
CIU->SW_SCRATCH = c_dop;
return MV_FAIL;
}
}
static void dump_dop( unsigned int op_index)
{
ddr_freq *md = &(asr1901_ddr_value[op_index]);
printf("%d(%s)---", op_index, md->label);
printf("dclk:%d ddr_pll:%d dvc:%d\n",
md->dclk,md->pll2, md->dvc);
}
void dump_dop_list(void)
{
unsigned int i;
printf("DDR OP list \n");
for (i=0; i < dop_num; i++) {
dump_dop(i);
}
}
void dump_cur_dop(void)
{
printf("DDR @OP%d\n", c_dop);
dump_dop(c_dop);
}
op_index axiop_get_dump(axi_freq *axi_op)
{
uint32_t pll_aclk, read_reg, temp_reg;
uint32_t i = 0;
read_reg = PMUA->ACLK_CTRL;
pll_aclk = (read_reg & 0x1);
switch (pll_aclk) {
case 0:
axi_op->aclk = 156;
break;
case 1:
axi_op->aclk = 208;
break;
}
while (i<axiop_num) {
if (abs_diff(aclk_value[i].aclk, axi_op->aclk)<5) {
axi_op->dvc = aclk_value[i].dvc;
c_axiop = (op_index)i;
break;
} else {
i++;
c_axiop = OP_INVALID;
}
}
debug("AXI aclk = %d\n",axi_op->aclk);
return c_axiop;
}
static uint32_t check_axiop(int32_t top)
{
int32_t axiop;
axi_freq temp;
axiop = axiop_get_dump(&temp);
if (axiop == OP_INVALID) {
printf("Warning: AXI freq is INVALID OP\n");
return OP_INVALID;
}
if (axiop == top) {
printf("AXI OP%d,DVL:%d\n", axiop,max_dvc);
c_axiop = top;
return MV_OK;
} else {
printf("ERROR: the AXI freq changed but the values"
" are not expected.\n");
c_axiop = axiop;
return MV_FAIL;
}
}
static void dump_axiop( unsigned int op_index)
{
axi_freq *md = &(aclk_value[op_index]);
printf("%d(%s)---", op_index, md->label);
printf("aclk:%d dvc:%d\n", md->aclk, md->dvc);
}
void dump_axiop_list(void)
{
unsigned int i;
printf("AXI OP list \n");
for (i=0; i < axiop_num; i++) {
dump_axiop(i);
}
}
void dump_cur_axiop(void)
{
printf("AXI @OP%d\n", c_axiop);
dump_axiop(c_axiop);
}
/*AP core freq change function*/
static void adfc_set(uint32_t top)
{
PMUA->AP_CLK_CTRL &= ~(AP_CLK_CTRL_MASK);
PMUA->AP_CLK_CTRL |= ca7_reg[top].pmua_cc_ap_cp;
PMUA->AP_CLK_CTRL |= BIT12;
while (BIT12 & PMUA->AP_CLK_CTRL);
}
static void ddfc_set(uint32_t top)
{
PMUA->CKPHY_FC_CTRL &= ~(CKPHY_FC_CTRL_MASK);
PMUA->CKPHY_FC_CTRL |= asr1901_ddr_reg[top].pmua_cc_ap_cp;
PMUA->MC_HW_SLP_TYPE &= ~(MC_HW_SLP_TYPE_MASK);
PMUA->MC_HW_SLP_TYPE |= asr1901_ddr_reg[top].mc_reg_table;
PMUA->MC_HW_SLP_TYPE |= BIT24;
while (BIT24 & PMUA->MC_HW_SLP_TYPE);
}
static void axidfc_set(uint32_t top)
{
PMUA->ACLK_CTRL &= ~(ACLK_CTRL_MASK);
PMUA->ACLK_CTRL |= asr1901_aclk_reg[top].pmua_cc_ap_cp;
PMUA->ACLK_CTRL |= BIT4;
while (BIT4 & PMUA->ACLK_CTRL);
}
#define VOL_LEVELS 4
static struct svtrng svtrngtb[] = {
{178, 184, 15},
{185, 191, 14},
{192, 198, 13},
{199, 205, 12},
{206, 212, 11},
{213, 219, 10},
{220, 226, 9},
{227, 233, 8},
{234, 240, 7},
{241, 247, 6},
{248, 254, 5},
{255, 261, 4},
{262, 268, 3},
{269, 275, 2},
{276, 282, 1}
};
static unsigned int convert_profile2comm1248dvl(unsigned int uiprofile)
{
unsigned int cmbindex = 0;
if (uiprofile >= 1 && uiprofile <= 5)
cmbindex = 1;
else if (uiprofile >= 6 && uiprofile <= 7)
cmbindex = 2;
else
cmbindex = 0;
return cmbindex;
}
static unsigned int convert_profile2comm832dvl(unsigned int uiprofile)
{
unsigned int cmbindex = 0;
if (uiprofile >= 1 && uiprofile <= 2)
cmbindex = 1;
else if (uiprofile == 3)
cmbindex = 2;
else if (uiprofile >= 4 && uiprofile <= 5)
cmbindex = 3;
else if (uiprofile >= 6 && uiprofile <= 7)
cmbindex = 4;
else
cmbindex = 0;
return cmbindex;
}
static unsigned int convert_svtdro2profile(uint32_t uisvtdro)
{
unsigned int idx;
uiProfile = 0;
for (idx = 0; idx < ARRAY_SIZE(svtrngtb); idx++) {
if (uisvtdro >= svtrngtb[idx].min
&& uisvtdro <= svtrngtb[idx].max) {
uiProfile = svtrngtb[idx].profile;
break;
}
}
return uiProfile;
}
static uint32_t asr1901_get_profile(void)
{
uint32_t uiManFuses_159_128 = GEU->BLOCK3_RESERVED[4];
uidro_svt = ((uiManFuses_159_128 >> (133 - 128)) & 0x3ff);
return convert_svtdro2profile(uidro_svt);
}
static uint32_t soc_init_profile(void)
{
uint32_t uiprofile;
uiprofile = asr1901_get_profile();
uiProfile = uiprofile;
return uiprofile;
}
static int (*asr1901_svc_table_a0)[VOL_LEVELS];
#if 0
static int asr1901_svc_table_832M[][VOL_LEVELS] = {
{813, 825, 888, 950}, /* profile 0 */
{788, 800, 800, 875}, /* profile 1 */
{788, 800, 800, 875},
{788, 800, 800, 888},
{788, 813, 813, 888},
{788, 813, 813, 900}, /* profile 5 */
{788, 813, 825, 900},
{800, 813, 825, 913},
{800, 813, 838, 913},
{800, 813, 850, 925},
{800, 813, 850, 925}, /* profile 10 */
{800, 813, 863, 925},
{800, 813, 875, 938},
{800, 825, 875, 938},
{800, 825, 888, 950},
{813, 825, 888, 950} /* profile 15 */
};
static int asr1901_svc_table_1248M[][VOL_LEVELS] = {
{825, 888, 950, 1050}, /* profile 0 */
{788, 800, 875, 875}, /* profile 1 */
{788, 800, 875, 875},
{800, 800, 888, 888},
{800, 813, 888, 900},
{813, 813, 900, 925}, /* profile 5 */
{813, 825, 900, 938},
{813, 825, 913, 950},
{813, 838, 913, 963},
{813, 850, 925, 975},
{813, 850, 925, 988}, /* profile 10 */
{813, 863, 925, 1000},
{813, 875, 938, 1013},
{825, 875, 938, 1025},
{825, 888, 950, 1038},
{825, 888, 950, 1050} /* profile 15 */
};
#else
static int asr1901_svc_table_832M[][VOL_LEVELS] = {
{950, 950, 950, 950}, /* profile 0 */
{950, 950, 950, 950}, /* profile 1 */
{950, 950, 950, 950},
{950, 950, 950, 950},
{950, 950, 950, 950},
{950, 950, 950, 950}, /* profile 5 */
{950, 950, 950, 950},
{950, 950, 950, 950},
{950, 950, 950, 950},
{950, 950, 950, 950},
{950, 950, 950, 950}, /* profile 10 */
{950, 950, 950, 950},
{950, 950, 950, 950},
{950, 950, 950, 950},
{950, 950, 950, 950},
{950, 950, 950, 950} /* profile 15 */
};
static int asr1901_svc_table_1248M[][VOL_LEVELS] = {
{950, 950, 950, 1050}, /* profile 0 */
{950, 950, 950, 1050}, /* profile 1 */
{950, 950, 950, 1050},
{950, 950, 950, 1050},
{950, 950, 950, 1050},
{950, 950, 950, 1050}, /* profile 5 */
{950, 950, 950, 1050},
{950, 950, 950, 1050},
{950, 950, 950, 1050},
{950, 950, 950, 1050},
{950, 950, 950, 1050}, /* profile 10 */
{950, 950, 950, 1050},
{950, 950, 950, 1050},
{950, 950, 950, 1050},
{950, 950, 950, 1050},
{950, 950, 950, 1050} /* profile 15 */
};
#endif
/*
* In case SW DVC case, CP can't adjust the voltage and AP is the owner
* And even the DVL0 should be higher enough to cover all CP/DP PPs.
* That's why we need HW-DVC!!!!
*/
uint32_t * svc_init_table;
u32 get_mvolt_by_dvc(int dvc)
{
u32 profile = uiProfile;
return asr1901_svc_table_a0[profile][dvc];
}
static void soc_dvc_init(void)
{
uint32_t profile = 0;
profile = soc_init_profile();
printf("SVC profile is %d\n", profile);
svc_init_table = (uint32_t *)&(asr1901_svc_table_a0[profile][0]);
}
/* init hw dvc for cp boot and these values will be overwritten by kernel*/
static void asr1901_init_hwdvc(void)
{
int count;
u32 cpvl, dpvl;
struct cpmsa_dvc_info *dvc_info;
writel(0x200, PMU_DVC_VL01STR_A0);
writel(0x200, PMU_DVC_VL12STR_A0);
writel(0x200, PMU_DVC_VL23STR_A0);
writel(0x1a0, PMU_DVC_EXRA_STR);
writel(0x8, PMU_DVC_AP);
writel(0x8, PMU_DVC_APSUB);
writel(0x88, PMU_DVC_APCHIP);
writel(0x3, PMU_DVC_DVCR);
if (local_max_corefreq_mode)
dvc_info = &cpmsa_dvc_info_1901_1248svc[convert_profile2comm1248dvl(uiProfile)];
else
dvc_info = &cpmsa_dvc_info_1901_832svc[convert_profile2comm832dvl(uiProfile)];
cpvl = 3;
for (count = 0; count < MAX_CP_PPNUM; count++) {
if (CP_CORE_MAX_FREQ <= dvc_info->cpdvcinfo[count].cpfreq) {
cpvl = dvc_info->cpdvcinfo[count].cpvl;
printf("cpvl: 0x%x\n", cpvl);
break;
}
}
dpvl = 3;
for (count = 0; count < MAX_CP_PPNUM; count++) {
if (DP_CORE_MAX_FREQ <= dvc_info->msadvcvl[count].cpfreq) {
dpvl = dvc_info->msadvcvl[count].cpvl;
printf("dpvl: 0x%x\n", dpvl);
break;
}
}
/* AP vote dvc for CP */
writel(0x8 | ((cpvl & 0x3) << 4), PMU_DVC_CP);
writel(((readl(PMU_DVC_CP)) | (0x1 << 7)), PMU_DVC_CP);
count = 100000;
while((readl(PMU_DVC_CP)) & (0x1 << 7)){
count--;
if (count == 0){
printf("!!!!!!CP-DVC failed\n");
break;
}
}
/* AP vote dvc for DSP */
writel(0x8 | ((dpvl & 0x3) << 4), PMU_DVC_DP);
writel(((readl(PMU_DVC_DP)) | (0x1 << 7)), PMU_DVC_DP);
count = 100000;
while((readl(PMU_DVC_DP)) & (0x1 << 7)){
count--;
if (count == 0){
printf("!!!!!!DP-DVC failed\n");
break;
}
}
/* AP self vote dvc*/
writel(0x8 | ((max_dvc & 0x3) << 4), PMU_DVC_AP);
writel(((readl(PMU_DVC_AP)) | (0x1 << 7)), PMU_DVC_AP);
count = 100000;
while((readl(PMU_DVC_AP)) & (0x1 << 7)){
count--;
if (count == 0){
printf("!!!!!!AP-DVC failed\n");
break;
}
}
}
/*This should be called by PMU_AO init*/
void asr1901_fc_init(int ddr_mode, int max_corefreq_mode)
{
core_freq temp_aop;
ddr_freq temp_dop;
axi_freq temp_axi_op;
u32 mvolt;
int i;
local_max_corefreq_mode = max_corefreq_mode;
if(max_corefreq_mode) {
aop_num = sizeof(ca7_value_1248M)/sizeof(core_freq);
ca7_value = ca7_value_1248M;
/* enable pll1_1248_en bit */
writel((0x8 | readl(0xd4090104)), 0xd4090104);
} else {
aop_num = sizeof(ca7_value_832M)/sizeof(core_freq);
ca7_value = ca7_value_832M;
}
debug("aop_num=%d\r\n", aop_num);
asr1901_svc_table_a0 = max_corefreq_mode ? asr1901_svc_table_1248M : asr1901_svc_table_832M;
dop_num = sizeof(asr1901_ddr_value)/sizeof(ddr_freq);
axiop_num = sizeof(asr1901_aclk_value)/sizeof(axi_freq);
aclk_value = &asr1901_aclk_value[0];
axiop_get_dump(&temp_axi_op);
/* sccr */
PMUM->SCCR |= 0x1;
PMUA->AP_CLK_CTRL |= (0x1 << 10); /* set clksrc to 312MHZ */
dop_get_dump(&temp_dop);
if (c_dop == OP_INVALID) {
printf("Note:current DDR OP is not official defined\n");
ddfc_set(0);
c_dop = 0;
}
CIU->SW_SCRATCH = c_dop;
max_dvc = asr1901_ddr_value[c_dop].dvc;
if (max_dvc != 0) {
printf("Warning: the boot up PP DVL "
"assumption is wrong!\n");
}
/* write initial dvc value */
soc_dvc_init();
if (c_axiop == OP_INVALID) {
printf("Note:current AXI OP is not official defined.\n");
axidfc_set(1);
c_axiop = 1;
}
aop_get_dump(&temp_aop);
if (c_aop == OP_INVALID) {
printf("Note:current CA7 OP is not official defined.\n");
adfc_set(0); /* should not use adfc invoking DVC here */
c_aop = 0;
}
GET_CHIP_DVL4OP_Ax(ca7_value, aop_num-1);
GET_CHIP_DVL4OP_Ax(aclk_value, axiop_num-1);
GET_CHIP_DVL4OP_Ax(asr1901_ddr_value, dop_num-1);
/* Prepare the DVC settings before enable the DVC mechanism.*/
max_dvc = ca7_value[c_aop].dvc;
if (max_dvc < aclk_value[c_axiop].dvc)
max_dvc = aclk_value[c_axiop].dvc;
if (max_dvc < asr1901_ddr_value[c_dop].dvc)
max_dvc = asr1901_ddr_value[c_dop].dvc;
if (max_dvc < 1)
max_dvc = 1; /* assume CP side boot OP need DVL1 */
*(volatile uint32_t *)(0xd401e2b8) = 0x9041;
*(volatile uint32_t *)(0xd401e2b4) = 0x9041;
mvolt = get_mvolt_by_dvc(max_dvc);
set_volt(mvolt);
udelay(40); /* 40us(40us *12.5mv/us) should be enough */
adfc(aop_num-1);
axidfc(OP1);
ddfc(OP1);
asr1901_init_hwdvc();
find_ddr_level();
}
void update_voltage_dvcl2h(uint32_t initiator, uint32_t top)
{
uint32_t max_dvc_next, mvolt;
if (1 == initiator) { /* ap core */
max_dvc_next = ca7_value[top].dvc;
if (max_dvc_next < aclk_value[c_axiop].dvc)
max_dvc_next = aclk_value[c_axiop].dvc;
if (max_dvc_next < asr1901_ddr_value[c_dop].dvc)
max_dvc_next = asr1901_ddr_value[c_dop].dvc;
} else if (2 == initiator) { /* AXI */
max_dvc_next = aclk_value[top].dvc;
if (max_dvc_next < ca7_value[c_aop].dvc)
max_dvc_next = ca7_value[c_aop].dvc;
if (max_dvc_next < asr1901_ddr_value[c_dop].dvc)
max_dvc_next = asr1901_ddr_value[c_dop].dvc;
} else if (5 == initiator) { /* ddr */
max_dvc_next = asr1901_ddr_value[top].dvc;
if (max_dvc_next < ca7_value[c_aop].dvc)
max_dvc_next = ca7_value[c_aop].dvc;
if (max_dvc_next < aclk_value[c_axiop].dvc)
max_dvc_next = aclk_value[c_axiop].dvc;
} else {
printf("Warning: unsuppoted DVC initiator!\n");
max_dvc_next = 3;
}
debug("l2h:The max_dvc_next = %d\n", max_dvc_next);
if (max_dvc_next > (uint32_t) DVC11) {
printf("ERROR:invalid dvc_next\n");
} else if (max_dvc_next < max_dvc) {
printf("ERROR: wrong voltage direction\n");
} else {
mvolt = get_mvolt_by_dvc(max_dvc_next);
set_volt(mvolt);
udelay(20);
max_dvc = max_dvc_next;
}
}
void update_voltage_dvch2l(uint32_t initiator, uint32_t top)
{
uint32_t max_dvc_next, mvolt;
if (1 == initiator) {
max_dvc_next = ca7_value[top].dvc;
if (max_dvc_next < aclk_value[c_axiop].dvc)
max_dvc_next = aclk_value[c_axiop].dvc;
if (max_dvc_next < asr1901_ddr_value[c_dop].dvc)
max_dvc_next = asr1901_ddr_value[c_dop].dvc;
} else if (2 == initiator) {
max_dvc_next = aclk_value[top].dvc;
if (max_dvc_next < ca7_value[c_aop].dvc)
max_dvc_next = ca7_value[c_aop].dvc;
if (max_dvc_next < asr1901_ddr_value[c_dop].dvc)
max_dvc_next = asr1901_ddr_value[c_dop].dvc;
} else if (5 == initiator) { /* DDR */
max_dvc_next = asr1901_ddr_value[top].dvc;
if (max_dvc_next < ca7_value[c_aop].dvc)
max_dvc_next = ca7_value[c_aop].dvc;
if (max_dvc_next < aclk_value[c_axiop].dvc)
max_dvc_next = aclk_value[c_axiop].dvc;
} else {
printf("Warning: unsuppoted DVC initiator!\n");
max_dvc_next = 3;
}
debug("h2l:The max_dvc_next = %d\n ", max_dvc_next);
if (max_dvc_next > (uint32_t) DVC11) {
printf("ERROR:invalid dvc_next\n");
} else if (max_dvc_next > max_dvc) {
printf("ERROR: wrong voltage direction\n");
} else {
mvolt = get_mvolt_by_dvc(max_dvc_next);
set_volt(mvolt);
udelay(20);
/* With SW-DVC, we need to make sure CP can work at the lowest DVL */
max_dvc = max_dvc_next;
}
}
/*
*Must make sure there is only one entity of this function is in executing at
*any time,better to be in critial section, return value is OP_INVALID or MV_OK
*/
uint32_t adfc(uint32_t top)
{
uint32_t flags;
if (top == c_aop) {
debug("CA7 is already at OP %d!\n", c_aop);
dump_cur_aop();
return c_aop;
}
local_irq_save(flags);
if (ca7_value[top].dvc > ca7_value[c_aop].dvc) {
update_voltage_dvcl2h(1, top);
}
adfc_set(top);
if (ca7_value[top].dvc < ca7_value[c_aop].dvc) {
update_voltage_dvch2l(1, top);
}
local_irq_restore(flags);
return (check_aop(top));
}
uint32_t ddfc(uint32_t top)
{
uint32_t ddrpll = 0;
uint32_t flags;
if (top == c_dop) {
debug("DDR is already at OP %d!\n", c_dop);
dump_cur_dop();
return c_dop;
}
if (asr1901_ddr_value[top].pll2) {
/* get the current pll2 value */
get_ddr_pll(&ddrpll);
if (((abs_diff(asr1901_ddr_value[top].pll2, ddrpll)>=30)&&
ddrpll&&asr1901_ddr_value[top].pll2)) {
printf("FAIL:PLL2 is used at another frequency pll2 ="
" %d already!\n", ddrpll);
printf("In decoupled DFC solution, PLLs shoud take"
" fixed values, avoid MFC.\n");
printf("For test purpose, please switch all clock"
" to PLL1 based first\n");
return c_dop;
}
}
local_irq_save(flags);
if (asr1901_ddr_value[top].dvc > asr1901_ddr_value[c_dop].dvc) {
update_voltage_dvcl2h(5, top);
}
ddfc_set(top);
if (asr1901_ddr_value[top].dvc < asr1901_ddr_value[c_dop].dvc) {
update_voltage_dvch2l(5, top);
}
local_irq_restore(flags);
return (check_dop(top));
}
uint32_t axidfc(uint32_t top)
{
uint32_t flags;
axi_freq temp;
c_axiop = axiop_get_dump(&temp);
if (top == c_axiop) {
debug("ACLK is already at OP %d!\n", c_axiop);
dump_cur_axiop();
return c_axiop;
}
local_irq_save(flags);
if (aclk_value[top].dvc > aclk_value[c_axiop].dvc)
update_voltage_dvcl2h(2, top);
axidfc_set(top);
if (aclk_value[top].dvc < aclk_value[c_axiop].dvc)
update_voltage_dvch2l(2, top);
local_irq_restore(flags);
return (check_axiop(top));
}
uint32_t aop_test(uint32_t argc, char * const argv[])
{
uint32_t test_mode;
(void)argc;
if ((strcmp((const char*)argv[2], "/c") == 0) ||
(strcmp((const char*)argv[2], "--check") == 0)){
dump_cur_aop();
return MV_OK;
}
test_mode = simple_strtol((char*)argv[2],NULL,10);
if (test_mode < aop_num) {
adfc(test_mode);
return MV_OK;
} else {
printf("unsupported core op\n");
}
return MV_OK;
}
uint32_t dop_test(uint32_t argc, char * const argv[])
{
uint32_t test_mode;
(void)argc;
if ((strcmp((const char*)argv[2], "/c") == 0) ||
(strcmp((const char*)argv[2], "--check") == 0)){
dump_cur_dop();
return MV_OK;
}
test_mode = simple_strtol((char*)argv[2],NULL,10);
if (test_mode < dop_num) {
ddfc(test_mode);
return MV_OK;
} else {
printf("unsupported ddr op\n");
}
return MV_OK;
}
uint32_t axiop_test(uint32_t argc, char * const argv[])
{
uint32_t test_mode;
(void)argc;
if ((strcmp((const char*)argv[2], "/c") == 0) ||
(strcmp((const char*)argv[2], "--check") == 0)) {
dump_cur_axiop();
return MV_OK;
}
test_mode = simple_strtol((char*)argv[2],NULL,10);
if (test_mode < axiop_num) {
axidfc(test_mode);
return MV_OK;
} else {
printf("unsupported axi op\n");
}
return MV_OK;
}
void dump_app_pmureg()
{
#if 0
printf("\n*************Dragon : APP PMU Register Dump Begin ************\n");
BBU_REG_DUMP("CC_CP ", (uint32_t*)&PMUA->CC_CP , PMUA->CC_CP );
BBU_REG_DUMP("CC_AP ", (uint32_t*)&PMUA->CC_AP , PMUA->CC_AP );
BBU_REG_DUMP("FC_TIMER ", (uint32_t*)&PMUA->FC_TIMER , PMUA->FC_TIMER );
BBU_REG_DUMP("CP_IDLE_CFG ", (uint32_t*)&PMUA->CP_IDLE_CFG , PMUA->CP_IDLE_CFG );
BBU_REG_DUMP("AP_IDLE_CFG ", (uint32_t*)&PMUA->AP_IDLE_CFG , PMUA->AP_IDLE_CFG );
BBU_REG_DUMP("SQU_CLK_GATE_CTRL ", (uint32_t*)&PMUA->SQU_CLK_GATE_CTRL , PMUA->SQU_CLK_GATE_CTRL );
BBU_REG_DUMP("IRE_CLK_GATE_CTRL ", (uint32_t*)&PMUA->IRE_CLK_GATE_CTRL , PMUA->IRE_CLK_GATE_CTRL );
BBU_REG_DUMP("CCIC_CLK_GATE_CTRL ", (uint32_t*)&PMUA->CCIC_CLK_GATE_CTRL , PMUA->CCIC_CLK_GATE_CTRL );
BBU_REG_DUMP("FBRC0_CLK_GATE_CTRL", (uint32_t*)&PMUA->FBRC0_CLK_GATE_CTRL, PMUA->FBRC0_CLK_GATE_CTRL);
BBU_REG_DUMP("FBRC1_CLK_GATE_CTRL", (uint32_t*)&PMUA->FBRC1_CLK_GATE_CTRL, PMUA->FBRC1_CLK_GATE_CTRL);
BBU_REG_DUMP("USB_CLK_GATE_CTRL ", (uint32_t*)&PMUA->USB_CLK_GATE_CTRL , PMUA->USB_CLK_GATE_CTRL );
BBU_REG_DUMP("PMU_CLK_GATE_CTRL ", (uint32_t*)&PMUA->PMU_CLK_GATE_CTRL , PMUA->PMU_CLK_GATE_CTRL );
BBU_REG_DUMP("HSI_CLK_RES_CTRL ", (uint32_t*)&PMUA->HSI_CLK_RES_CTRL , PMUA->HSI_CLK_RES_CTRL );
BBU_REG_DUMP("CCIC_CLK_RES_CTRL ", (uint32_t*)&PMUA->CCIC_CLK_RES_CTRL , PMUA->CCIC_CLK_RES_CTRL );
BBU_REG_DUMP("SDH0_CLK_RES_CTRL ", (uint32_t*)&PMUA->SDH0_CLK_RES_CTRL , PMUA->SDH0_CLK_RES_CTRL );
BBU_REG_DUMP("SDH1_CLK_RES_CTRL ", (uint32_t*)&PMUA->SDH1_CLK_RES_CTRL , PMUA->SDH1_CLK_RES_CTRL );
BBU_REG_DUMP("USB_CLK_RES_CTRL ", (uint32_t*)&PMUA->USB_CLK_RES_CTRL , PMUA->USB_CLK_RES_CTRL );
BBU_REG_DUMP("NF_CLK_RES_CTRL ", (uint32_t*)&PMUA->NF_CLK_RES_CTRL , PMUA->NF_CLK_RES_CTRL );
BBU_REG_DUMP("DMA_CLK_RES_CTRL ", (uint32_t*)&PMUA->DMA_CLK_RES_CTRL , PMUA->DMA_CLK_RES_CTRL );
BBU_REG_DUMP("AES_CLK_RES_CTRL ", (uint32_t*)&PMUA->AES_CLK_RES_CTRL , PMUA->AES_CLK_RES_CTRL );
BBU_REG_DUMP("MCB_CLK_RES_CTRL ", (uint32_t*)&PMUA->MCB_CLK_RES_CTRL , PMUA->MCB_CLK_RES_CTRL );
BBU_REG_DUMP("PMU_CP_IMR ", (uint32_t*)&PMUA->CP_IMR , PMUA->CP_IMR );
BBU_REG_DUMP("PMU_CP_IRWC ", (uint32_t*)&PMUA->CP_IRWC , PMUA->CP_IRWC );
BBU_REG_DUMP("PMU_CP_ISR ", (uint32_t*)&PMUA->CP_ISR , PMUA->CP_ISR );
BBU_REG_DUMP("SD_ROT_WAKE_CLR ", (uint32_t*)&PMUA->SD_ROT_WAKE_CLR , PMUA->SD_ROT_WAKE_CLR );
BBU_REG_DUMP("PMU_FBRC_CLK ", (uint32_t*)&PMUA->PMU_FBRC_CLK , PMUA->PMU_FBRC_CLK );
BBU_REG_DUMP("PWR_STBL_TIMER ", (uint32_t*)&PMUA->PWR_STBL_TIMER , PMUA->PWR_STBL_TIMER );
BBU_REG_DUMP("DEBUG_REG ", (uint32_t*)&PMUA->DEBUG_REG , PMUA->DEBUG_REG );
BBU_REG_DUMP("SRAM_PWR_DWN ", (uint32_t*)&PMUA->SRAM_PWR_DWN , PMUA->SRAM_PWR_DWN );
BBU_REG_DUMP("CORE_STATUS ", (uint32_t*)&PMUA->CORE_STATUS , PMUA->CORE_STATUS );
BBU_REG_DUMP("RES_FRM_SLP_CLR ", (uint32_t*)&PMUA->RES_FRM_SLP_CLR , PMUA->RES_FRM_SLP_CLR );
BBU_REG_DUMP("AP_IMR ", (uint32_t*)&PMUA->AP_IMR , PMUA->AP_IMR );
BBU_REG_DUMP("AP_IRWC ", (uint32_t*)&PMUA->AP_IRWC , PMUA->AP_IRWC );
BBU_REG_DUMP("AP_ISR ", (uint32_t*)&PMUA->AP_ISR , PMUA->AP_ISR );
BBU_REG_DUMP("DTC_CLK_RES_CTRL ", (uint32_t*)&PMUA->DTC_CLK_RES_CTRL , PMUA->DTC_CLK_RES_CTRL );
BBU_REG_DUMP("MC_HW_SLP_TYPE ", (uint32_t*)&PMUA->MC_HW_SLP_TYPE , PMUA->MC_HW_SLP_TYPE );
BBU_REG_DUMP("MC_SLP_REQ_AP ", (uint32_t*)&PMUA->MC_SLP_REQ_AP , PMUA->MC_SLP_REQ_AP );
BBU_REG_DUMP("MC_SLP_REQ_CP ", (uint32_t*)&PMUA->MC_SLP_REQ_CP , PMUA->MC_SLP_REQ_CP );
BBU_REG_DUMP("MC_SLP_REQ_MSA ", (uint32_t*)&PMUA->MC_SLP_REQ_MSA , PMUA->MC_SLP_REQ_MSA );
BBU_REG_DUMP("MC_MC_SLP_TYPE ", (uint32_t*)&PMUA->MC_MC_SLP_TYPE , PMUA->MC_MC_SLP_TYPE );
BBU_REG_DUMP("PLL_SEL_STATUS ", (uint32_t*)&PMUA->PLL_SEL_STATUS , PMUA->PLL_SEL_STATUS );
BBU_REG_DUMP("SYNC_MODE_BYPASS ", (uint32_t*)&PMUA->SYNC_MODE_BYPASS , PMUA->SYNC_MODE_BYPASS );
BBU_REG_DUMP("GC_CLK_RES_CTRL ", (uint32_t*)&PMUA->GC_CLK_RES_CTRL , PMUA->GC_CLK_RES_CTRL );
BBU_REG_DUMP("SMC_CLK_RES_CTRL ", (uint32_t*)&PMUA->SMC_CLK_RES_CTRL , PMUA->SMC_CLK_RES_CTRL );
BBU_REG_DUMP("PWR_CTRL_REG ", (uint32_t*)&PMUA->PWR_CTRL_REG , PMUA->PWR_CTRL_REG );
BBU_REG_DUMP("PWR_BLK_TMR_REG ", (uint32_t*)&PMUA->PWR_BLK_TMR_REG , PMUA->PWR_BLK_TMR_REG );
BBU_REG_DUMP("SDH2_CLK_RES_CTRL ", (uint32_t*)&PMUA->SDH2_CLK_RES_CTRL , PMUA->SDH2_CLK_RES_CTRL );
BBU_REG_DUMP("MCK4_CTRL ", (uint32_t*)&PMUA->MCK4_CTRL , PMUA->MCK4_CTRL );
BBU_REG_DUMP("PWR_STATUS_REG ", (uint32_t*)&PMUA->PWR_STATUS_REG , PMUA->PWR_STATUS_REG );
BBU_REG_DUMP("CC2_AP ", (uint32_t*)&PMUA->CC2_AP , PMUA->CC2_AP );
BBU_REG_DUMP("TRACE_CONFIG ", (uint32_t*)&PMUA->TRACE_CONFIG , PMUA->TRACE_CONFIG );
BBU_REG_DUMP("CA7MP_IDLE_CFG0 ", (uint32_t*)&PMUA->CA7MP_IDLE_CFG0 , PMUA->CA7MP_IDLE_CFG0 );
BBU_REG_DUMP("CA7_CORE0_IDLE_CFG ", (uint32_t*)&PMUA->CA7_CORE0_IDLE_CFG , PMUA->CA7_CORE0_IDLE_CFG );
BBU_REG_DUMP("DVC_DEBUG ", (uint32_t*)&PMUA->DVC_DEBUG , PMUA->DVC_DEBUG );
BBU_REG_DUMP("CA7_PWR_MISC ", (uint32_t*)&PMUA->CA7_PWR_MISC , PMUA->CA7_PWR_MISC );
printf("************Dragon : APP PMU Register Dump End ************\n");
#endif
}
void dump_main_pmureg()
{
#if 0
printf("*********Dragon : MAIN PMU Register Dump Begin ************\n");
BBU_REG_DUMP("CPCR ", (uint32_t*)&PMUM->CPCR , PMUM->CPCR );
BBU_REG_DUMP("CPSR ", (uint32_t*)&PMUM->CPSR , PMUM->CPSR );
BBU_REG_DUMP("FCCR ", (uint32_t*)&PMUM->FCCR , PMUM->FCCR );
BBU_REG_DUMP("POCR ", (uint32_t*)&PMUM->POCR , PMUM->POCR );
BBU_REG_DUMP("POSR ", (uint32_t*)&PMUM->POSR , PMUM->POSR );
BBU_REG_DUMP("SUCCR ", (uint32_t*)&PMUM->SUCCR , PMUM->SUCCR );
BBU_REG_DUMP("VRCR ", (uint32_t*)&PMUM->VRCR , PMUM->VRCR );
BBU_REG_DUMP("CPRR ", (uint32_t*)&PMUM->CPRR , PMUM->CPRR );
BBU_REG_DUMP("CCGR ", (uint32_t*)&PMUM->CCGR , PMUM->CCGR );
BBU_REG_DUMP("CRSR ", (uint32_t*)&PMUM->CRSR , PMUM->CRSR );
BBU_REG_DUMP("XDCR ", (uint32_t*)&PMUM->XDCR , PMUM->XDCR );
BBU_REG_DUMP("GPCR ", (uint32_t*)&PMUM->GPCR , PMUM->GPCR );
BBU_REG_DUMP("PLL2CR ", (uint32_t*)&PMUM->PLL2CR , PMUM->PLL2CR );
BBU_REG_DUMP("SCCR ", (uint32_t*)&PMUM->SCCR , PMUM->SCCR );
BBU_REG_DUMP("MCCR ", (uint32_t*)&PMUM->MCCR , PMUM->MCCR );
BBU_REG_DUMP("ISCCRX[0]", (uint32_t*)&PMUM->ISCCRX[0], PMUM->ISCCRX[0]);
BBU_REG_DUMP("ISCCRX[1]", (uint32_t*)&PMUM->ISCCRX[1], PMUM->ISCCRX[1]);
BBU_REG_DUMP("CWUCRS ", (uint32_t*)&PMUM->CWUCRS , PMUM->CWUCRS );
BBU_REG_DUMP("CWUCRM ", (uint32_t*)&PMUM->CWUCRM , PMUM->CWUCRM );
BBU_REG_DUMP("DSOC ", (uint32_t*)&PMUM->DSOC , PMUM->DSOC );
BBU_REG_DUMP("WDTPCR ", (uint32_t*)&PMUM->WDTPCR , PMUM->WDTPCR );
BBU_REG_DUMP("CMPRX[0] ", (uint32_t*)&PMUM->CMPRX[0] , PMUM->CMPRX[0] );
BBU_REG_DUMP("CMPRX[1] ", (uint32_t*)&PMUM->CMPRX[1] , PMUM->CMPRX[1] );
BBU_REG_DUMP("CMPRX[2] ", (uint32_t*)&PMUM->CMPRX[2] , PMUM->CMPRX[2] );
BBU_REG_DUMP("CMPRX[3] ", (uint32_t*)&PMUM->CMPRX[3] , PMUM->CMPRX[3] );
BBU_REG_DUMP("CMPRX[4] ", (uint32_t*)&PMUM->CMPRX[4] , PMUM->CMPRX[4] );
BBU_REG_DUMP("APCR ", (uint32_t*)&PMUM->APCR , PMUM->APCR );
BBU_REG_DUMP("APSR ", (uint32_t*)&PMUM->APSR , PMUM->APSR );
BBU_REG_DUMP("APRR ", (uint32_t*)&PMUM->APRR , PMUM->APRR );
BBU_REG_DUMP("ACGR ", (uint32_t*)&PMUM->ACGR , PMUM->ACGR );
BBU_REG_DUMP("ARSR ", (uint32_t*)&PMUM->ARSR , PMUM->ARSR );
BBU_REG_DUMP("AWUCRS ", (uint32_t*)&PMUM->AWUCRS , PMUM->AWUCRS );
BBU_REG_DUMP("AWUCRM ", (uint32_t*)&PMUM->AWUCRM , PMUM->AWUCRM );
printf("***********Dragon : MAIN PMU Register Dump End ************\n");
#endif
}
void dump_pmu_reg(void)
{
dump_main_pmureg();
dump_app_pmureg();
}
void ppset_help(void)
{
printf(" ppset - change the device OP to defined one.\n");
printf(" ppset /r or ppset --regdump: dump pmu register.\n");
printf(" ppset /h or ppset --help: print the help information\n");
printf(" ==========================================================\n");
printf(" Syntax: ppset OPdevice OPmode <op_count>\n");
printf(" OP_device: core, ddr, axi\n");
printf(" OP_mode: if it's < OP_NUM, then just change OP to OP_mode\n");
return;
}
/*
* ppset <OP_device> <OP_index>
* OP_device: core/axi/cs
* OP_index: 0..n, "/c", "help", "/h"
*/
static int do_ppset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
printf("\n");
switch (argc) {
case 1:
printf("ppset--> No PP specified.\n");
ppset_help();
break;
default:
if (check_help(argv[1])) {
ppset_help();
dump_aop_list();
dump_axiop_list();
dump_dop_list();
} else if (pp_check_reg(argv[1])) {
dump_pmu_reg();
} else if ((strcmp((const char*)argv[1], "/c") == 0)) {
dump_cur_aop();
dump_cur_dop();
dump_cur_axiop();
} else {
if ((strcmp((char *)argv[1], "core") == 0)) {
if (MV_OK == aop_test(argc, argv))
return 1;
else
return 0;
} else if ((strcmp((char*)argv[1], "ddr") == 0)) {
if (MV_OK == dop_test(argc, argv))
return 1;
else
return 0;
} else if ((strcmp((char*)argv[1], "axi") == 0)) {
if (MV_OK == axiop_test(argc, argv))
return 1;
else
return 0;
}
}
}
return 0;
}
int getcpdvcinfo(struct cpmsa_dvc_info *dvc_info)
{
if (!dvc_info) {
printf("%s: dvc_info NULL\n", __func__);
return -1;
}
if (local_max_corefreq_mode)
memcpy(dvc_info,
&cpmsa_dvc_info_1901_1248svc[convert_profile2comm1248dvl(uiProfile)],
sizeof(struct cpmsa_dvc_info));
else
memcpy(dvc_info,
&cpmsa_dvc_info_1901_832svc[convert_profile2comm832dvl(uiProfile)],
sizeof(struct cpmsa_dvc_info));
return 0;
}
int getddrdfcinfo(struct ddr_dfc_info *dfc_info)
{
if (!dfc_info) {
printf("%s: dvc_info NULL\n", __func__);
return -1;
}
memcpy(dfc_info, &ddrdfcinfo, sizeof(struct ddr_dfc_info));
return 0;
}
U_BOOT_CMD(
ppset, 6, 1, do_ppset,
"change core/ddr/axi op\n",
""
);