| /* |
| * (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", |
| "" |
| ); |
| |