| #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/pxa182x_freq.h> |
| #include <i2c.h> |
| #include <power/pmic.h> |
| #include <power/marvell88pm_pmic.h> |
| #include "../../board/Marvell/common/mv_cp.h" |
| |
| //#define PXA182X_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 PXA1826_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; |
| |
| #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) |
| |
| core_freq *ca7_value; |
| core_freq ca7_value_832M[] = { |
| /*label pclk,memclk,busclk,pll2,pll2p,dvc,dvcs{profile15..profile0}, dvcsa*/ |
| {"OP0", 416, 208, 104, 0, 0, 0, 0x1111100000000001, 0x0000000000000000}, |
| {"OP1", 312, 156, 156, 0, 0, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP2", 416, 208, 208, 0, 0, 0, 0x1111100000000001, 0x0000000000000000}, |
| {"OP3", 624, 312, 156, 0, 0, 1, 0x1111111111111001, 0x1111111111110001}, |
| {"OP4", 832, 416, 208, 0, 0, 2, 0x2222222222222222, 0x3333333333333333}, |
| }; |
| |
| core_freq ca7_value_1057M[] = { |
| /*label pclk,memclk,busclk,pll2,pll2p,dvc,dvcs{profile15..profile0}, dvcsa*/ |
| {"OP0", 416, 208, 104, 0, 0, 0, 0x1111100000000001, 0x0000000000000000}, |
| {"OP1", 312, 156, 156, 0, 0, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP2", 416, 208, 208, 0, 0, 0, 0x1111100000000001, 0x0000000000000000}, |
| {"OP3", 624, 312, 156, 0, 0, 1, 0x1111111111111001, 0x1111111111110001}, |
| {"OP4", 832, 416, 208, 0, 0, 2, 0x2222222222222222, 0x2222222222222222}, |
| {"OP5", 1057,528, 264, 1057,0, 3, 0x3333333333333333, 0x3333333333333333}, |
| }; |
| |
| core_freq ca7_value_1248M[] = { |
| /*label pclk,memclk,busclk,pll2,pll2p,dvc,dvcs{profile15..profile0}, dvcsa*/ |
| {"OP0", 416, 208, 104, 0, 0, 0, 0x1111100000000001, 0x0000000000000000}, |
| {"OP1", 312, 156, 156, 0, 0, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP2", 416, 208, 208, 0, 0, 0, 0x1111100000000001, 0x0000000000000000}, |
| {"OP3", 624, 312, 156, 0, 0, 1, 0x1111111111111001, 0x1111111111110001}, |
| {"OP4", 832, 416, 208, 0, 0, 2, 0x2222222222222222, 0x2222222222222222}, |
| {"OP5", 1248,624, 312, 0, 0, 3, 0x3333333333333333, 0x3333333333333333}, |
| }; |
| |
| dfc_setting *ca7_reg; |
| /* the ASYNC bits has no use in AP side */ |
| dfc_setting ca7_reg_1248M[] = { |
| /*pll2ref,pll2fb,apb_spare2,fccr[31:29],0x09FC0000|cc_ap[8:0] mc_reg_table*/ |
| {NA , NA , NA , 0x0<<29, 0xC9, NA}, /* OP0 */ |
| {NA , NA , NA , 0x1<<29, 0x4B, NA}, /* OP1 */ |
| {NA , NA , NA , 0x0<<29, 0x49, NA}, /* OP2 */ |
| {NA , NA , NA , 0x1<<29, 0xC9, NA}, /* OP3 */ |
| {NA , NA , NA , 0x0<<29, 0xC8, NA}, /* OP4 */ |
| {NA , NA , NA , 0x1<<29, 0xC8, NA}, /* OP5 */ |
| }; |
| |
| /* the ASYNC bits has no use in AP side */ |
| dfc_setting ca7_reg_1057M[] = { |
| /*pll2ref,pll2fb,apb_spare2,fccr[31:29],0x09FC0000|cc_ap[8:0] mc_reg_table*/ |
| {NA , NA , NA , 0x0<<29, 0xC9, NA}, /* OP0 */ |
| {NA , NA , NA , 0x1<<29, 0x4B, NA}, /* OP1 */ |
| {NA , NA , NA , 0x0<<29, 0x49, NA}, /* OP2 */ |
| {NA , NA , NA , 0x1<<29, 0xC9, NA}, /* OP3 */ |
| {NA , NA , NA , 0x0<<29, 0xC8, NA}, /* OP4 */ |
| {3 , 61 , 0x1010E0EB, 0x2<<29, 0xC8, NA}, /* OP5 */ |
| }; |
| |
| ddr_freq *pxa1826_ddr_value; |
| ddr_freq pxa1826_ddr_value_400op[] = { |
| /* label dclk, pll2,pll2p,dfl_setting,dvc,dvcs{profile15..profile0}, dvcsa*/ |
| {"OP0", 104, 0, 0, 0x00000090, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP1", 156, 0, 0, 0x00000111, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP2", 208, 0, 0, 0x00000180, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP3", 312, 0, 0, 0x00000201, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP4", 398, 797, 0, 0x00000282, 0, 0x0000000000000000, 0x0000000000000000}, |
| }; |
| |
| ddr_freq pxa1826_ddr_value_416op[] = { |
| /* label dclk, pll2,pll2p,dfl_setting, dvc,dvcs{profile15..profile0}, dvcsa*/ |
| {"OP0", 104, 0, 0, 0x00000090, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP1", 156, 0, 0, 0x00000111, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP2", 208, 0, 0, 0x00000180, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP3", 312, 0, 0, 0x00000201, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP4", 416, 0, 0, 0x00000383, 0, 0x0000000000000000, 0x0000000000000000}, |
| }; |
| |
| ddr_freq pxa1826_ddr_value_533op_1057svc[] = { |
| /* label dclk, pll2,pll2p,dfl_setting, dvc,dvcs{profile15..profile0}, dvcsa*/ |
| {"OP0", 104, 0, 0, 0x00000090, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP1", 156, 0, 0, 0x00000111, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP2", 208, 0, 0, 0x00000180, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP3", 312, 0, 0, 0x00000201, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP4", 416, 0, 0, 0x00000383, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP5", 528, 1057,0, 0x00000302, 1, 0x1111111111000001, 0x1111111111000001}, |
| }; |
| |
| ddr_freq pxa1826_ddr_value_533op_non1057svc[] = { |
| /* label dclk, pll2,pll2p,dfl_setting, dvc,dvcs{profile15..profile0}, dvcsa*/ |
| {"OP0", 104, 0, 0, 0x00000090, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP1", 156, 0, 0, 0x00000111, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP2", 208, 0, 0, 0x00000180, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP3", 312, 0, 0, 0x00000201, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP4", 416, 0, 0, 0x00000383, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP5", 528, 1057,0, 0x00000302, 1, 0x1111111111000001, 0x2221111111000002}, |
| }; |
| |
| dfc_setting *pxa1826_ddr_reg; |
| dfc_setting pxa1826_ddr_reg_400op[] = { |
| /*pll2ref,pll2fb,apb_spare2, fccr[27:26], 0x09F80000|cc_cp[8:0] mc_reg_table*/ |
| {NA , NA , NA , 0x0<<23, 0x1<<12, 0x08}, /* OP0 */ |
| {NA , NA , NA , 0x1<<23, 0x1<<12, 0x10}, /* OP1 */ |
| {NA , NA , NA , 0x0<<23, 0x0<<12, 0x18}, /* OP2 */ |
| {NA , NA , NA , 0x1<<23, 0x0<<12, 0x20}, /* OP3 */ |
| {3 , 46, 0x1010D0EB, 0x2<<23, 0x0<<12, 0x28}, /* OP4 */ |
| }; |
| |
| dfc_setting pxa1826_ddr_reg_416op[] = { |
| /*pll2ref,pll2fb,apb_spare2, fccr[27:26], 0x09F80000|cc_cp[8:0] mc_reg_table*/ |
| {NA , NA , NA , 0x0<<23, 0x1<<12, 0x08}, /* OP0 */ |
| {NA , NA , NA , 0x1<<23, 0x1<<12, 0x10}, /* OP1 */ |
| {NA , NA , NA , 0x0<<23, 0x0<<12, 0x18}, /* OP2 */ |
| {NA , NA , NA , 0x1<<23, 0x0<<12, 0x20}, /* OP3 */ |
| {NA , NA, NA , 0x3<<23, 0x0<<12, 0x38}, /* OP4 */ |
| }; |
| |
| dfc_setting pxa1826_ddr_reg_533op[] = { |
| /*pll2ref,pll2fb,apb_spare2, fccr[27:26], 0x09F80000|cc_cp[8:0] mc_reg_table*/ |
| {NA , NA , NA , 0x0<<23, 0x1<<12, 0x08}, /* OP0 */ |
| {NA , NA , NA , 0x1<<23, 0x1<<12, 0x10}, /* OP1 */ |
| {NA , NA , NA , 0x0<<23, 0x0<<12, 0x18}, /* OP2 */ |
| {NA , NA , NA , 0x1<<23, 0x0<<12, 0x20}, /* OP3 */ |
| {NA , NA, NA , 0x3<<23, 0x0<<12, 0x38}, /* OP4 */ |
| {3 , 61, 0x1010E0EB, 0x2<<23, 0x0<<12, 0x30}, /* OP5 */ |
| }; |
| |
| axi_freq aclk_value[] = { |
| /* label aclk, dvc,dvcs{profile15..profile0}, dvcsa*/ |
| {"OP0", 104, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP1", 156, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP2", 208, 0, 0x0000000000000000, 0x0000000000000000}, |
| {"OP3", 312, 1, 0x1111110000000001, 0x1111111000000001}, |
| }; |
| |
| axi_setting aclk_reg[] = { |
| /* fccr[25|19], cc_cp[17:15] */ |
| {0x0<<19, 0x3<<15}, /* OP0 */ |
| {0x1<<19, 0x3<<15}, /* OP1 */ |
| {0x0<<19, 0x1<<15}, /* OP2 */ |
| {0x1<<19, 0x1<<15}, /* OP3 */ |
| }; |
| |
| cs_freq cs_value[] = { |
| /* label atclk, dbg_clk, trace_clk, dvc */ |
| {"OP0", 104, 52, 208, 0, 0x0000000000000000}, |
| {"OP1", 416, 208, 208, 0, 0x0000000000000000}, |
| }; |
| |
| cs_setting cs_reg[] = { |
| /* |trace_config */ |
| {0x00080103}, /* OP0 */ |
| {0x00080100}, /* OP1 */ |
| }; |
| |
| static struct cpmsa_dvc_info cpmsa_dvc_info_182x[] = { |
| [0] = { |
| .cpdvcinfo[0] = {208, VL0}, |
| .cpdvcinfo[1] = {312, VL0}, |
| .cpdvcinfo[2] = {416, VL0}, |
| .cpdvcinfo[3] = {624, VL1}, |
| .cpaxidvcinfo[0] = {104, VL0}, |
| .cpaxidvcinfo[1] = {156, VL0}, |
| .cpaxidvcinfo[2] = {208, VL0}, |
| .lteaxidvcinfo[0] = {104, VL0}, |
| .lteaxidvcinfo[1] = {156, VL0}, |
| .lteaxidvcinfo[2] = {208, VL0}, |
| .lteaxidvcinfo[3] = {312, VL0}, |
| .msadvcvl[0] = {416, VL0}, |
| .msadvcvl[1] = {624, VL2}, |
| }, |
| [1] = { |
| .cpdvcinfo[0] = {208, VL0}, |
| .cpdvcinfo[1] = {312, VL0}, |
| .cpdvcinfo[2] = {416, VL0}, |
| .cpdvcinfo[3] = {624, VL0}, |
| .cpaxidvcinfo[0] = {104, VL0}, |
| .cpaxidvcinfo[1] = {156, VL0}, |
| .cpaxidvcinfo[2] = {208, VL0}, |
| .lteaxidvcinfo[0] = {104, VL0}, |
| .lteaxidvcinfo[1] = {156, VL0}, |
| .lteaxidvcinfo[2] = {208, VL0}, |
| .lteaxidvcinfo[3] = {312, VL0}, |
| .msadvcvl[0] = {416, VL0}, |
| .msadvcvl[1] = {624, VL1}, |
| }, |
| [2] = { |
| .cpdvcinfo[0] = {208, VL0}, |
| .cpdvcinfo[1] = {312, VL0}, |
| .cpdvcinfo[2] = {416, VL0}, |
| .cpdvcinfo[3] = {624, VL0}, |
| .cpaxidvcinfo[0] = {104, VL0}, |
| .cpaxidvcinfo[1] = {156, VL0}, |
| .cpaxidvcinfo[2] = {208, VL0}, |
| .lteaxidvcinfo[0] = {104, VL0}, |
| .lteaxidvcinfo[1] = {156, VL0}, |
| .lteaxidvcinfo[2] = {208, VL0}, |
| .lteaxidvcinfo[3] = {312, VL0}, |
| .msadvcvl[0] = {416, VL0}, |
| .msadvcvl[1] = {624, VL2}, |
| }, |
| [3] = { |
| .cpdvcinfo[0] = {208, VL0}, |
| .cpdvcinfo[1] = {312, VL0}, |
| .cpdvcinfo[2] = {416, VL0}, |
| .cpdvcinfo[3] = {624, VL1}, |
| .cpaxidvcinfo[0] = {104, VL0}, |
| .cpaxidvcinfo[1] = {156, VL0}, |
| .cpaxidvcinfo[2] = {208, VL0}, |
| .lteaxidvcinfo[0] = {104, VL0}, |
| .lteaxidvcinfo[1] = {156, VL0}, |
| .lteaxidvcinfo[2] = {208, VL0}, |
| .lteaxidvcinfo[3] = {312, VL0}, |
| .msadvcvl[0] = {416, VL0}, |
| .msadvcvl[1] = {624, VL2}, |
| }, |
| }; |
| 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 PM801_DVC1 13 |
| #define PM801_DVC2 127 |
| #define PM812_DVC1 79 |
| #define PM812_DVC2 78 |
| |
| static void find_ddr_level(void) |
| { |
| int i; |
| |
| ddrdfcinfo.ddr_idle = 0; |
| for (i = 0; i <= dop_num; i++) { |
| if (ddrdfcinfo.ddr_active == 0) { |
| if (pxa1826_ddr_value[i].dclk >= 312) { |
| ddrdfcinfo.ddr_active = i; |
| } |
| } |
| if (ddrdfcinfo.ddr_high == 0) { |
| if (pxa1826_ddr_value[i].dclk >= 398) { |
| 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); |
| debug("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 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 int pll2_is_enabled(void) |
| { |
| uint32_t val; |
| val = PMUM->PLL2CR; |
| |
| /* ctrl = 0(hw enable) or ctrl = 1&&en = 1(sw enable) */ |
| /* ctrl = 1&&en = 0(sw disable) */ |
| if ((val & (0x1 << 9)) && (!(val & (0x1 << 8)))) |
| return 0; |
| else |
| return 1; |
| } |
| |
| void get_pll2(uint32_t *pll2, uint32_t *pll2p) |
| { |
| volatile uint32_t temp; |
| uint32_t pll2fb, pll2ref, vcodiv_se, vcodiv_diff; |
| uint32_t refclk = 26; |
| |
| temp = PMUM->PLL2CR; |
| |
| if (pll2_is_enabled()) { |
| pll2fb = (temp>>10)&0x1FF; |
| pll2ref= (temp>>19)&0x1F; |
| |
| temp = APBSPARE->PLL2_SW_CTRL; |
| vcodiv_se = (temp>>20)& 0x7; |
| vcodiv_se = 1 << vcodiv_se; |
| *pll2=((pll2fb*refclk*4)/pll2ref)/vcodiv_se; |
| vcodiv_diff = (temp>>17)& 0x7; |
| vcodiv_diff = 1 << vcodiv_diff; |
| *pll2p=((pll2fb*refclk*4)/pll2ref)/vcodiv_diff; |
| } else { |
| *pll2=0; |
| *pll2p=0; |
| } |
| } |
| |
| void hw_setup_pll2(uint32_t pll2ref, uint32_t pll2fb, uint32_t apb_spare2) |
| { |
| uint32_t temp, delaytime = 20; |
| |
| temp = PMUM->PLL2CR; |
| |
| if (pll2_is_enabled() && (((temp&0xF80000)>>19) == pll2ref) |
| && ((temp&0x7FC00)>>10==pll2fb) |
| && (APBSPARE->PLL2_SW_CTRL==apb_spare2)) { |
| printf("PLL2 is already enabled at desired value.\n"); |
| return; |
| } else { |
| if (pll2_is_enabled()) { |
| printf("pll2 is already enabled with not desired value\n"); |
| return; |
| } |
| |
| APBSPARE->PLL2_SW_CTRL = apb_spare2; |
| |
| temp &= (~0xfffc00); |
| temp |= ((pll2ref<<19)|(pll2fb<<10)); |
| PMUM->PLL2CR = temp; |
| |
| temp = PMUM->PLL2CR; |
| temp |= 0x200; /* SW ctrl + en_0 */ |
| PMUM->PLL2CR = temp; |
| temp &= (~0x200); /* hw ctrl + en_0 */ |
| PMUM->PLL2CR = temp; |
| |
| udelay(30); |
| while (!(PMUM->POSR & 0x1 << 29) && delaytime) { |
| udelay(5); |
| delaytime--; |
| } |
| |
| if (!delaytime) { |
| printf("pll2 can't be locked\n"); |
| return; |
| } |
| } |
| } |
| |
| static int pll2_is_inuse(void) |
| { |
| uint32_t fccr; |
| |
| fccr = PMUM->FCCR; |
| if (((fccr & BIT30)==0) && |
| (((fccr & BIT25)!=1)||((fccr & BIT19) !=0))&& |
| ((fccr & BIT27)==0) && |
| ((fccr & BIT24)==0)) |
| return 0; |
| else |
| return 1; |
| } |
| |
| static void sw_turnoff_pll2(void) |
| { |
| uint32_t temp; |
| debug("turning off PLL2\n"); |
| temp = PMUM->PLL2CR; |
| temp |= 0x200; |
| PMUM->PLL2CR = temp; |
| temp &= (~0x100); |
| PMUM->PLL2CR = temp; |
| } |
| |
| |
| 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, pll2 = 0, pll2p = 0; |
| |
| read_reg = PMUA->PLL_SEL_STATUS; |
| pll_dragon = (read_reg & 0xC) >> 2; |
| |
| switch (pll_dragon) { |
| case 0: |
| pll_dragon = 832; |
| break; |
| case 1: |
| pll_dragon = 1248; |
| break; |
| case 2: |
| get_pll2(&pll_dragon, &pll2p); |
| break; |
| case 3: |
| get_pll2(&pll2, &pll_dragon); |
| break; |
| } |
| |
| read_reg = PMUA->DM_CC_AP; |
| PMUA->CC_AP |= BIT31; |
| PMUA->CC_AP &= ~BIT31; |
| |
| temp_reg = read_reg & 7; |
| ap_op->pclk =pll_dragon / (temp_reg + 1) ; |
| |
| temp_reg = (read_reg & 0x00000038) >> 3; |
| ap_op->memclk =ap_op->pclk / (temp_reg + 1) ; |
| |
| temp_reg = (read_reg & 0x000001C0) >> 6; |
| 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" |
| " pll2:%d pll2p:%d dvc:%d\n", |
| md->pclk, md->memclk, md->busclk, |
| md->pll2, md->pll2p, 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; |
| uint32_t i = 0, pll2 = 0, pll2p = 0; |
| |
| read_reg = PMUA->PLL_SEL_STATUS; |
| pll_dp = (read_reg >> 4) & 0x3; |
| |
| switch (pll_dp) { |
| case 0: |
| pll_dp = 416; |
| break; |
| case 1: |
| pll_dp = 624; |
| break; |
| case 2: |
| get_pll2(&pll_dp, &pll2p); |
| break; |
| case 3: |
| pll_dp = 832; |
| break; |
| } |
| |
| /* Read the current status */ |
| read_reg = PMUA->DM_CC_AP; |
| PMUA->CC_AP |= BIT31; |
| PMUA->CC_AP &= ~BIT31; |
| |
| temp_reg = (read_reg >> 12) & 7; |
| d_op->dclk =pll_dp /(temp_reg + 1)/2 ; |
| |
| while (i < dop_num) { |
| if ((abs_diff(pxa1826_ddr_value[i].dclk, d_op->dclk)<5)) { |
| d_op->dvc = pxa1826_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\n",d_op->dclk); |
| 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 = &(pxa1826_ddr_value[op_index]); |
| |
| printf("%d(%s)---", op_index, md->label); |
| printf("dclk:%d pll2:%d pll2p:%d dvc:%d\n", |
| md->dclk,md->pll2, md->pll2p, 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, pll2p = 0; |
| |
| read_reg = PMUA->PLL_SEL_STATUS; |
| pll_aclk = (read_reg & 0xC0) >> 6 ; |
| |
| switch (pll_aclk) { |
| case 0: |
| pll_aclk = 416; |
| break; |
| case 1: |
| pll_aclk = 624; |
| break; |
| case 2: |
| get_pll2(&pll_aclk, &pll2p); |
| break; |
| case 3: |
| pll_aclk = 312; |
| break; |
| } |
| |
| read_reg = PMUA->DM_CC_AP; |
| PMUA->CC_AP |= BIT31; |
| PMUA->CC_AP &= ~BIT31; |
| temp_reg = (read_reg & 0x00038000) >> 15; |
| axi_op->aclk = pll_aclk / (temp_reg + 1) ; |
| |
| 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) |
| { |
| uint32_t read_data; |
| uint32_t FCCR_MASK = ~(0x7 << 29); |
| |
| /* +++Step4: set up correct PMUA_DEBUG value */ |
| read_data = PMUA->DEBUG_REG; |
| |
| read_data |= 0x00660001; |
| |
| |
| if (PMUM->APRR & 0x1) { /* CP is hold in reset */ |
| /* Change the AP freq clk, ignore CP, it is for AP standalone debug */ |
| read_data |= 0x9; |
| } else { |
| /* Need to wait CP's ACK on halt and clock off */ |
| read_data &= ~0x9; |
| } |
| |
| PMUA->DEBUG_REG = read_data; |
| |
| PMUM->FCCR = (PMUM->FCCR & FCCR_MASK)| ca7_reg[top].pmum_fccr; |
| |
| read_data = PMUM->FCCR; |
| |
| PMUA->AP_IMR |= BIT1; /* BIT1=BIT3|BIT4|BIT5@delay */ |
| PMUA->AP_IRWC &= ~BIT1; |
| PMUA->AP_ISR &= ~BIT1; |
| |
| /* +++Step8:Seagull allow freq. change voting */ |
| PMUA->CC_CP |= (0x1 << 27); |
| PMUA->CC_AP |= (0x1 << 27); |
| |
| /* +++Step9: AP set for clock dividers and kick off the sm_fc */ |
| PMUA->CC_AP &= ~0x1ff; |
| PMUA->CC_AP |= ca7_reg[top].pmua_cc_ap_cp; |
| PMUA->CC_AP |= 0x01000000; |
| while (!(BIT1 & PMUA->AP_ISR)); |
| |
| PMUA->AP_ISR &= 0xFFFFFFFD; |
| } |
| |
| static void ddfc_set(uint32_t top) |
| { |
| uint32_t read_data; |
| uint32_t FCCR_MASK = ~(0x3 << 23); |
| |
| /* +++Step4: set up correct PMUA_DEBUG value */ |
| read_data = PMUA->DEBUG_REG; |
| read_data |= 0x00660001; |
| PMUA->DEBUG_REG = read_data; |
| PMUM->FCCR = (PMUM->FCCR & FCCR_MASK)| pxa1826_ddr_reg[top].pmum_fccr; |
| read_data = PMUM->FCCR; |
| |
| PMUA->CC_CP |= (0x1 << 27); |
| PMUA->CC_AP |= (0x1 << 27); |
| |
| PMUA->AP_IMR |= BIT1; /* BIT1=BIT3|BIT4|BIT5@delay */ |
| PMUA->AP_IRWC &= ~BIT1; |
| PMUA->AP_ISR &= ~BIT1; |
| |
| /* +++Step9: AP set for clock dividers and kick off the sm_fc */ |
| PMUA->CC_AP &= ~(0x7 << 12); |
| PMUA->CC_AP |= pxa1826_ddr_reg[top].pmua_cc_ap_cp; |
| PMUA->MC_HW_SLP_TYPE &= ~0xF8; /* BITS[7:3] */ |
| PMUA->MC_HW_SLP_TYPE |= pxa1826_ddr_reg[top].mc_reg_table; |
| |
| PMUA->CC_AP |= 0x02000000; |
| |
| while (!(BIT1 & PMUA->AP_ISR)); |
| PMUA->AP_ISR &= 0xFFFFFFFD; |
| } |
| |
| static void axidfc_set(uint32_t top) |
| { |
| uint32_t read_data; |
| PMUA->DEBUG_REG |= 0x00660001; |
| |
| PMUA->CC_AP |= BIT27; |
| PMUA->CC_CP |= BIT27; |
| PMUM->FCCR &= ~(1<<25); |
| PMUM->FCCR &= ~(1<<19); |
| PMUM->FCCR |= aclk_reg[top].pmum_fccr; |
| read_data = PMUM->FCCR; |
| debug("0x%x.\n", read_data); |
| PMUA->AP_IMR = 0x2; |
| PMUA->AP_IRWC &= ~0x2; |
| PMUA->CC_AP &= ~0x38000; |
| PMUA->CC_AP |= aclk_reg[top].pmua_cc_ap_cp; |
| PMUA->CC_AP |= BIT26; |
| while ((PMUA->AP_ISR & 0x2) == 0); |
| PMUA->AP_ISR &= ~0x2; |
| } |
| |
| /* |
| * You don’t need release CP from reset state. |
| * You can let AP write PMU_CC_CP to trigger CP freq change |
| * Only through this CC_CP dclk can be changed! |
| */ |
| static void get_fc_sm(int is_cp) |
| { |
| if (!is_cp) { |
| while (PMUA->DM_CC_AP & BIT24) { |
| /*if fail to get control once, |
| *clear the flag to avoid deadlock with CP |
| */ |
| PMUA->CC_AP |= (BIT31); |
| PMUA->CC_AP &= ~(BIT31); |
| } |
| } |
| } |
| |
| static void put_fc_sm(int is_cp) |
| { |
| uint32_t read_data, temp_data; |
| if (!is_cp) { |
| read_data = PMUA->CC_AP; |
| temp_data = (read_data & 0x0AFFFFFF) | BIT31; /* RD_ST clear */ |
| PMUA->CC_AP = temp_data; |
| PMUA->CC_AP = temp_data & 0x0AFFFFFF; |
| } |
| } |
| |
| static void update_memory_xtc(uint32_t pclk) |
| { |
| CIU->CA7_CPU_SRAM_CONF_1 = (pclk <= 832)? 0x1088:0x5088; |
| if (pclk <= 416) |
| CIU->CA7_CPU_SRAM_CONF_0 = 0x00111111; |
| else if (pclk <= 624) |
| CIU->CA7_CPU_SRAM_CONF_0 = 0x00555555; |
| else if (pclk <= 1066) |
| CIU->CA7_CPU_SRAM_CONF_0 = 0x00999999; |
| else |
| CIU->CA7_CPU_SRAM_CONF_0 = 0x00AAAAAA; |
| } |
| |
| #define VOL_LEVELS 4 |
| |
| static struct svtrng svtrngtb[] = { |
| {1 , 310, 15}, |
| {311, 322, 14}, |
| {323, 335, 13}, |
| {336, 348, 12}, |
| {349, 360, 11}, |
| {361, 373, 10}, |
| {374, 379, 9}, |
| {380, 386, 8}, |
| {387, 392, 7}, |
| {393, 398, 6}, |
| {399, 405, 5}, |
| {406, 411, 4}, |
| {412, 417, 3}, |
| {418, 424, 2}, |
| {425, 0xfff, 1} |
| }; |
| |
| static unsigned int convert_svtdro2profile(uint32_t uisvtdro) |
| { |
| unsigned int idx; |
| |
| 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 pxa1826_get_profile(void) |
| { |
| uint32_t uiManFuses_95_64 = GEU->BLOCK7_RESERVED_2; |
| uint32_t uiManFuses_127_96 = GEU->BLOCK7_RESERVED_3; |
| uint32_t uiManFuses_63_32, uiblock0_rsv1 = GEU->BLOCK0_RESERVED_1; |
| uint32_t uifuses = 0, uitemp = 3, uitemp2 = 1, profile = 0; |
| int i; |
| |
| uiManFuses_63_32 = GEU->FUSE_MANU_PARA_1; |
| uiManFuses_95_64 = GEU->FUSE_MANU_PARA_2; |
| uidro_svt = ((uiManFuses_95_64 & 0xF) << 6) |
| + ((uiManFuses_63_32 >> 26) & 0x3f); |
| uifuses = (uiblock0_rsv1 >> 16) & 0x0000FFFF; |
| |
| if (uifuses) { |
| for (i = 1; i < PXA1826_NUM_PROFILES; i++) { |
| uitemp |= uitemp2 << i; |
| if (uitemp == uifuses) |
| profile = i; |
| } |
| return profile; |
| } else { |
| return convert_svtdro2profile(uidro_svt); |
| } |
| } |
| |
| static uint32_t soc_init_profile(void) |
| { |
| uint32_t uiprofile; |
| |
| uiprofile = pxa1826_get_profile(); |
| if (uiprofile == 15 && !(cpu_is_pxa1826_a0())) { |
| while(1) |
| printf("!!!!!!profile 15 chip can't support 1.2G!!!!!!\n"); |
| } |
| |
| uiProfile = uiprofile; |
| return uiprofile; |
| } |
| |
| static int (*pxa1826_svc_table_a0)[VOL_LEVELS]; |
| static int pxa1826_svc_table_a0_832M[][VOL_LEVELS] = { |
| {1050, 1075, 1125, 1150}, /* profile 0 */ |
| { 975, 988, 988, 1025}, /* profile 1 */ |
| { 975, 1000, 1000, 1038}, |
| { 975, 1000, 1000, 1038}, |
| { 975, 988, 1013, 1050}, |
| { 975, 988, 1013, 1050}, /* profile 5 */ |
| { 975, 1000, 1025, 1063}, |
| { 975, 1000, 1025, 1063}, |
| { 975, 1013, 1038, 1075}, |
| { 975, 1013, 1050, 1075}, |
| { 988, 1025, 1063, 1088}, /* profile 10 */ |
| {1000, 1038, 1075, 1100}, |
| {1013, 1050, 1088, 1113}, |
| {1025, 1050, 1100, 1125}, |
| {1038, 1063, 1113, 1138}, |
| {1050, 1075, 1125, 1150} /* profile 15 */ |
| }; |
| |
| static int pxa1826_svc_table_a0_1057M[][VOL_LEVELS] = { |
| {1050, 1088, 1150, 1225}, /* profile 0 */ |
| { 975, 988, 1025, 1088}, /* profile 1 */ |
| { 975, 1000, 1038, 1088}, |
| { 975, 1000, 1038, 1100}, |
| { 975, 988, 1050, 1113}, |
| { 975, 988, 1050, 1113}, /* profile 5 */ |
| { 975, 1000, 1063, 1125}, |
| { 975, 1000, 1063, 1125}, |
| { 975, 1013, 1075, 1138}, |
| { 975, 1013, 1075, 1138}, |
| { 988, 1025, 1088, 1163}, /* profile 10 */ |
| {1000, 1038, 1100, 1175}, |
| {1013, 1050, 1113, 1188}, |
| {1025, 1063, 1125, 1200}, |
| {1038, 1075, 1138, 1213}, |
| {1050, 1088, 1150, 1225} /* profile 15 */ |
| }; |
| |
| static int pxa1826_svc_table_a0_1248M[][VOL_LEVELS] = { |
| {1050, 1075, 1150, 1300}, /* profile 0 */ |
| { 975, 988, 1025, 1163}, /* profile 1 */ |
| { 975, 1000, 1038, 1163}, |
| { 975, 1000, 1038, 1175}, |
| { 975, 988, 1050, 1188}, |
| { 975, 988, 1050, 1188}, /* profile 5 */ |
| { 975, 1000, 1063, 1200}, |
| { 975, 1000, 1063, 1200}, |
| { 975, 1013, 1075, 1213}, |
| { 975, 1013, 1075, 1225}, |
| { 988, 1025, 1088, 1238}, /* profile 10 */ |
| {1000, 1038, 1100, 1250}, |
| {1013, 1050, 1113, 1263}, |
| {1025, 1050, 1125, 1275}, |
| {1038, 1063, 1138, 1288}, |
| {1050, 1075, 1150, 1300} /* profile 15 */ |
| }; |
| |
| /* |
| * 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 pxa1826_svc_table_a0[profile][dvc]; |
| } |
| |
| static void soc_dvc_init(void) |
| { |
| uint32_t profile = 0; |
| |
| profile = soc_init_profile(); |
| printf("profile is %d\n", profile); |
| svc_init_table = (uint32_t *)&(pxa1826_svc_table_a0[profile][0]); |
| } |
| |
| /* init hw dvc for cp boot and these values will be overwritten by kernel*/ |
| static void pxa182x_init_hwdvc(void) |
| { |
| int count; |
| |
| 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(0x80, PMU_DVC_APSUB); |
| writel(0x8080, PMU_DVC_APCHIP); |
| |
| writel(0x3, PMU_DVC_DVCR); |
| |
| /* AP self vote dvc*/ |
| writel(0x80 | ((max_dvc & 0x3) << 8), PMU_DVC_AP); |
| writel(((readl(PMU_DVC_AP)) | (0x1 << 15)), PMU_DVC_AP); |
| count = 100000; |
| while((readl(PMU_DVC_AP)) & (0x1 << 15)) |
| count--; |
| if (count == 0) |
| printf("!!!!!!AP-DVC failed\n"); |
| } |
| |
| static void pxa182x_init_hwdfc(void) |
| { |
| int i; |
| |
| for (i = 0; i < dop_num; i++) { |
| writel(pxa1826_ddr_value[i].dvc | pxa1826_ddr_value[i].dfl_setting, |
| PMUA_DFC_LEVEL0 + (i << 2)); |
| } |
| } |
| |
| static int ddr_hwdfc_seq(int level) |
| { |
| u32 status, isr, dfc_ap; |
| uint32_t pll2=0, pll2p=0; |
| int max_delay = 100, timeout = 10000000; |
| |
| |
| if (pxa1826_ddr_value[level].pll2 || pxa1826_ddr_value[level].pll2p) { |
| /* get the current pll2 and pll2p value */ |
| get_pll2(&pll2, &pll2p); |
| if (((abs_diff(pxa1826_ddr_value[level].pll2, pll2)>=5)&& |
| pll2&&pxa1826_ddr_value[level].pll2) || |
| ((abs_diff(pxa1826_ddr_value[level].pll2p, pll2p)>=5)&& |
| pll2p&&pxa1826_ddr_value[level].pll2p)) { |
| printf("FAIL:PLL2 is used at another frequency pll2 =" |
| " %d, pll2p= %d already!\n", pll2,pll2p); |
| 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 -1; |
| } else { |
| debug("Enable PLL2=%d, PLL2P=%d \n" |
| , pxa1826_ddr_value[level].pll2 |
| , pxa1826_ddr_value[level].pll2p); |
| hw_setup_pll2(pxa1826_ddr_reg[level].pll2ref |
| , pxa1826_ddr_reg[level].pll2fb |
| , pxa1826_ddr_reg[level].apb_spare2); |
| } |
| } |
| |
| /* wait for DFC triggered by CP/MSA is done */ |
| status = readl(PMUA_DFC_STATUS); |
| while (max_delay && (status & 0x1)) { |
| udelay(10); |
| max_delay--; |
| status = readl(PMUA_DFC_STATUS); |
| } |
| if (max_delay <= 0) { |
| printf("AP cannot start HWDFC as DFC is in progress!\n"); |
| printf("DFCAP %x, DFCSTATUS %x,\n", |
| readl(PMUA_DFC_AP), |
| readl(PMUA_DFC_STATUS)); |
| return -1; |
| } |
| |
| /* Check if AP ISR is set, if set, clear it */ |
| isr = readl(PMUA_AP_ISR); |
| if (isr & (1 << 1)) { |
| printf("Somebody doesn't clear ISR after FC! ISR: %X\n", isr); |
| writel(isr & ~(1 << 1), PMUA_AP_ISR); |
| } |
| |
| /* trigger AP HWDFC */ |
| dfc_ap = readl(PMUA_DFC_AP); |
| dfc_ap &= ~(0x7 << 1); |
| dfc_ap |= ((level << 1) | 0x1); |
| writel(dfc_ap, PMUA_DFC_AP); |
| |
| /* polling ISR */ |
| while (!((1 << 1) & readl(PMUA_AP_ISR)) && timeout) |
| timeout--; |
| |
| if (timeout <= 0) { |
| printf("AP frequency change timeout!\n"); |
| printf("APMU_ISR %x, DFC_LVL: 0x%x, DFC_AP %x, DFC_STATUS %x\n", |
| readl(PMUA_AP_ISR), |
| readl(PMUA_DFC_LEVEL0 + (level << 2)), |
| readl(PMUA_DFC_AP), |
| readl(PMUA_DFC_STATUS)); |
| } |
| |
| /* clear AP fc done signal */ |
| writel(readl(PMUA_AP_ISR) & ~(1 << 1), PMUA_AP_ISR); |
| return 0; |
| } |
| |
| /*This should be called by PMU_AO init*/ |
| void pxa182x_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; |
| |
| if(max_corefreq_mode==1) { |
| aop_num = sizeof(ca7_value_1248M)/sizeof(core_freq); |
| ca7_value = ca7_value_1248M; |
| } else if(max_corefreq_mode==2) { |
| aop_num = sizeof(ca7_value_1057M)/sizeof(core_freq); |
| ca7_value = ca7_value_1057M; |
| } else { |
| aop_num = sizeof(ca7_value_832M)/sizeof(core_freq); |
| ca7_value = ca7_value_832M; |
| } |
| ca7_reg = (max_corefreq_mode == 2) ? ca7_reg_1057M : ca7_reg_1248M; |
| |
| if(ddr_mode == 0) { |
| pxa1826_ddr_value = pxa1826_ddr_value_400op; |
| pxa1826_ddr_reg = pxa1826_ddr_reg_400op; |
| dop_num = sizeof(pxa1826_ddr_value_400op)/sizeof(ddr_freq); |
| } |
| if(ddr_mode == 2) { |
| pxa1826_ddr_value = pxa1826_ddr_value_416op; |
| pxa1826_ddr_reg = pxa1826_ddr_reg_416op; |
| dop_num = sizeof(pxa1826_ddr_value_416op)/sizeof(ddr_freq); |
| } |
| if(ddr_mode == 1) { |
| pxa1826_ddr_value = (max_corefreq_mode == 2) ? pxa1826_ddr_value_533op_1057svc : pxa1826_ddr_value_533op_non1057svc; |
| pxa1826_ddr_reg = pxa1826_ddr_reg_533op; |
| dop_num = sizeof(pxa1826_ddr_reg_533op)/sizeof(ddr_freq); |
| } |
| debug("aop_num=%d\r\n", aop_num); |
| pxa1826_svc_table_a0 = (max_corefreq_mode == 1) ? pxa1826_svc_table_a0_1248M : |
| (max_corefreq_mode ? pxa1826_svc_table_a0_1057M : pxa1826_svc_table_a0_832M); |
| csop_num = sizeof(cs_value)/sizeof(cs_freq); |
| axiop_num = sizeof(aclk_value)/sizeof(axi_freq); |
| |
| axiop_get_dump(&temp_axi_op); |
| |
| PMUM->SCCR |= 0x1; |
| /* |
| * MC_HW_SLP_TYPE: |
| * for nezha2, |
| * BIT7: enable table-based DDR clock change |
| * BIT8: use 2:1 mode for LPDDR2 |
| * BIT9: enable the lpm exit ddr reg table 0 |
| * |
| * for nezha3, |
| * BIT_10: 0-enable table-based DDR clock change |
| * BIT_11: 0- use 2:1 mode for LPDDR2/3, set in BLF file instead |
| * BIT_8: 0-enable the lpm exit ddr reg table 0 |
| * BIT_9: 0- enable auto DLL update during HW DVC |
| */ |
| if (cpu_is_pxa1826()) { |
| PMUA->MC_HW_SLP_TYPE &= ~(BIT8 | BIT10); |
| 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 = pxa1826_ddr_value[c_dop].dvc; |
| if (max_dvc != 0) { |
| printf("Warning: the boot up PP DVL " |
| "assumption is wrong!\n"); |
| } |
| /* SQU_CTRL_0 */ |
| *(volatile uint32_t *)(0xd42A0000) = 0x10000000; |
| /* CIU->AP_DMA_AXI_XTC */ |
| *(volatile uint32_t *)(0xd4282CF8) = 0x00000010; |
| } |
| |
| /* write initial dvc value */ |
| soc_dvc_init(); |
| |
| if (c_axiop == OP_INVALID) { |
| printf("Note:current AXI OP is not official defined.\n"); |
| axidfc_set(0); |
| c_axiop = 0; |
| } |
| |
| 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; |
| } |
| |
| /*Note: we direclty do the CS change to PP0 for simple*/ |
| PMUA->TRACE_CONFIG &= ~0x003E07C7; |
| PMUA->TRACE_CONFIG |= cs_reg[0].trace_config; |
| PMUA->TRACE_CONFIG |= 0x00008020; |
| debug("Coresight OP changed to OP0\n"); |
| c_csop = 0; |
| |
| GET_CHIP_DVL4OP_Ax(ca7_value, aop_num-1); |
| GET_CHIP_DVL4OP_Ax(aclk_value, axiop_num-1); |
| GET_CHIP_DVL4OP_Ax(pxa1826_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 < cs_value[c_csop].dvc) |
| max_dvc = cs_value[c_csop].dvc; |
| |
| if (max_dvc < pxa1826_ddr_value[c_dop].dvc) |
| max_dvc = pxa1826_ddr_value[c_dop].dvc; |
| |
| if (max_dvc < 1) |
| max_dvc = 1; /* assume CP side boot OP need DVL1 */ |
| |
| *(volatile uint32_t *)(0xd401e2E0) = 0x90C1; /* DVC1, GPIO78 */ |
| *(volatile uint32_t *)(0xd401e2E4) = 0x90C1; /* DVC0, GPIO79 */ |
| |
| mvolt = get_mvolt_by_dvc(max_dvc); |
| set_volt(mvolt); |
| udelay(40); /* 40us(40us *12.5mv/us) should be enough */ |
| pxa182x_init_hwdfc(); |
| adfc(aop_num-1); |
| axidfc(axiop_num-1); |
| ddfc_set(0); |
| ddr_hwdfc_seq(dop_num-1); |
| check_dop(dop_num-1); |
| pxa182x_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 < cs_value[c_csop].dvc) |
| max_dvc_next = cs_value[c_csop].dvc; |
| |
| if (max_dvc_next < pxa1826_ddr_value[c_dop].dvc) |
| max_dvc_next = pxa1826_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 < cs_value[c_csop].dvc) |
| max_dvc_next = cs_value[c_csop].dvc; |
| if (max_dvc_next < pxa1826_ddr_value[c_dop].dvc) |
| max_dvc_next = pxa1826_ddr_value[c_dop].dvc; |
| } else if (3 == initiator) { /* Coresight */ |
| max_dvc_next = cs_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; |
| if (max_dvc_next < pxa1826_ddr_value[c_dop].dvc) |
| max_dvc_next = pxa1826_ddr_value[c_dop].dvc; |
| } else if (5 == initiator) { /* ddr */ |
| max_dvc_next = pxa1826_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; |
| if (max_dvc_next < cs_value[c_csop].dvc) |
| max_dvc_next = cs_value[c_csop].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 < cs_value[c_csop].dvc) |
| max_dvc_next = cs_value[c_csop].dvc; |
| if (max_dvc_next < pxa1826_ddr_value[c_dop].dvc) |
| max_dvc_next = pxa1826_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 < cs_value[c_csop].dvc) |
| max_dvc_next = cs_value[c_csop].dvc; |
| if (max_dvc_next < pxa1826_ddr_value[c_dop].dvc) |
| max_dvc_next = pxa1826_ddr_value[c_dop].dvc; |
| } |
| else if (3 == initiator) { |
| max_dvc_next = cs_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; |
| if (max_dvc_next < pxa1826_ddr_value[c_dop].dvc) |
| max_dvc_next = pxa1826_ddr_value[c_dop].dvc; |
| } else if (5 == initiator) { /* DDR */ |
| max_dvc_next = pxa1826_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; |
| if (max_dvc_next < cs_value[c_csop].dvc) |
| max_dvc_next = cs_value[c_csop].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 pll2=0, pll2p=0; |
| uint32_t flags; |
| |
| if (top == c_aop) { |
| debug("CA7 is already at OP %d!\n", c_aop); |
| dump_cur_aop(); |
| return c_aop; |
| } |
| |
| if (ca7_value[top].pll2 || ca7_value[top].pll2p) { |
| get_pll2(&pll2, &pll2p); |
| if (((abs_diff(ca7_value[top].pll2, pll2)>=5)&& |
| pll2&&ca7_value[top].pll2) || |
| ((abs_diff(ca7_value[top].pll2p, pll2p)>=5)&& |
| pll2p&&ca7_value[top].pll2p)) { |
| printf("FAIL:PLL2 is used at another frequency pll2 =" |
| " %d, pll2p= %d already!\n", pll2,pll2p); |
| 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_aop; |
| } else { |
| debug("Enable PLL2=%d, PLL2P=%d \n" |
| , ca7_value[top].pll2, ca7_value[top].pll2p); |
| hw_setup_pll2(ca7_reg[top].pll2ref |
| , ca7_reg[top].pll2fb, ca7_reg[top].apb_spare2); |
| } |
| } |
| |
| get_fc_sm(0); |
| local_irq_save(flags); |
| if (ca7_value[top].dvc > ca7_value[c_aop].dvc) { |
| update_voltage_dvcl2h(1, top); |
| } |
| if (ca7_value[top].pclk > ca7_value[c_aop].pclk) { |
| update_memory_xtc(ca7_value[top].pclk); |
| } |
| adfc_set(top); |
| if (!pll2_is_inuse()) { |
| sw_turnoff_pll2(); |
| } |
| if (ca7_value[top].pclk < ca7_value[c_aop].pclk) { |
| update_memory_xtc(ca7_value[top].pclk); |
| } |
| |
| if (ca7_value[top].dvc < ca7_value[c_aop].dvc) { |
| update_voltage_dvch2l(1, top); |
| } |
| |
| put_fc_sm(0); |
| local_irq_restore(flags); |
| return (check_aop(top)); |
| } |
| |
| uint32_t ddfc(uint32_t top) |
| { |
| uint32_t pll2=0, pll2p=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 (pxa1826_ddr_value[top].pll2 || pxa1826_ddr_value[top].pll2p) { |
| /* get the current pll2 and pll2p value */ |
| get_pll2(&pll2, &pll2p); |
| if (((abs_diff(pxa1826_ddr_value[top].pll2, pll2)>=5)&& |
| pll2&&pxa1826_ddr_value[top].pll2) || |
| ((abs_diff(pxa1826_ddr_value[top].pll2p, pll2p)>=5)&& |
| pll2p&&pxa1826_ddr_value[top].pll2p)) { |
| printf("FAIL:PLL2 is used at another frequency pll2 =" |
| " %d, pll2p= %d already!\n", pll2,pll2p); |
| 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; |
| } else { |
| debug("Enable PLL2=%d, PLL2P=%d \n" |
| , pxa1826_ddr_value[top].pll2 |
| , pxa1826_ddr_value[top].pll2p); |
| hw_setup_pll2(pxa1826_ddr_reg[top].pll2ref |
| , pxa1826_ddr_reg[top].pll2fb |
| , pxa1826_ddr_reg[top].apb_spare2); |
| } |
| } |
| |
| get_fc_sm(0); |
| local_irq_save(flags); |
| if (pxa1826_ddr_value[top].dvc > pxa1826_ddr_value[c_dop].dvc) { |
| update_voltage_dvcl2h(5, top); |
| } |
| |
| ddfc_set(top); |
| if (!pll2_is_inuse()) { |
| sw_turnoff_pll2(); |
| } |
| |
| if (pxa1826_ddr_value[top].dvc < pxa1826_ddr_value[c_dop].dvc) { |
| update_voltage_dvch2l(5, top); |
| } |
| put_fc_sm(0); |
| 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; |
| } |
| |
| get_fc_sm(0); |
| 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); |
| |
| put_fc_sm(0); |
| 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 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 ((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; |
| } |
| |
| static unsigned int convert_profile2commdvl(unsigned int uiprofile) |
| { |
| unsigned int cmbindex = 0; |
| |
| if (uiprofile >= 1 && uiprofile <= 3) |
| cmbindex = 1; |
| else if (uiprofile == 4) |
| cmbindex = 2; |
| else if (uiprofile >= 5 && uiprofile <= 8) |
| cmbindex = 3; |
| else |
| cmbindex = 0; |
| |
| return cmbindex; |
| } |
| |
| int getcpdvcinfo(struct cpmsa_dvc_info *dvc_info) |
| { |
| if (!dvc_info) { |
| printf("%s: dvc_info NULL\n", __func__); |
| return -1; |
| } |
| memcpy(dvc_info, |
| &cpmsa_dvc_info_182x[convert_profile2commdvl(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", |
| "" |
| ); |
| |