// SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2019 * Broadcom Corp */ #include #include #include #include "spl_env.h" #include "pmc_drv.h" #ifdef PMC_ON_HOSTCPU #define PMCcmd(...) -1 #else extern int PMCcmd(int arg[4]); #endif DECLARE_GLOBAL_DATA_PTR; enum { PMCFW_CODE, PMCFW_DATA, PMCFW_TYPES }; static int is_pmcfw_loaded(int type) { const char *path[PMCFW_TYPES] = { "/fit-images/pmcfw_code", "/fit-images/pmcfw_data" }; int offset = fdt_path_offset(gd->fdt_blob, path[type]); const uint32_t *load_addr, *size; if (offset < 0) return 0; load_addr = fdt_getprop(gd->fdt_blob, offset, "load-addr", NULL); if (!load_addr) return 0; size = fdt_getprop(gd->fdt_blob, offset, "size", NULL); if (!size) return 0; printf("pmc firmware %s has been loaded to 0x%x, size=%uB\n", (type ? "data" : "code"), be32_to_cpu(*load_addr), be32_to_cpu(*size)); return 1; } int is_pmcfw_code_loaded(void) { return is_pmcfw_loaded(PMCFW_CODE); } int is_pmcfw_data_loaded(void) { return is_pmcfw_loaded(PMCFW_DATA); } // return 1 if the environment variable avs_disable=1 int getAVSConfig(void) { char *disable = NULL; int offset = fdt_path_offset(gd->fdt_blob, "/chosen"); if (offset < 0) return 0; disable = fdt_getprop(gd->fdt_blob, offset, ENV_AVS_DISABLE, NULL); if (!disable) return 0; return *disable == '1'; } static void setAVSConfig(int new) { int old = getAVSConfig(); if (old == new) return; if (!env_set(ENV_AVS_DISABLE, new ? "1" : NULL) && !env_save()) printf("Reboot to use new " ENV_AVS_DISABLE "=%d\n", new); } static int do_pmc_sc_avs(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]) { #if IS_BCMCHIP(4908) || IS_BCMCHIP(63158) || IS_BCMCHIP(63178) || \ IS_BCMCHIP(47622) || IS_BCMCHIP(63146) || IS_BCMCHIP(4912) || \ IS_BCMCHIP(6756) int pmc[4]; static const char *disables[] = {"0", "disable", "false", "off"}; int res, i; if (argc < 2) { res = getAVSConfig(); printf("AVS %sdisabled by environment\n", res ? "" : "not "); return CMD_RET_SUCCESS; } if (!strcmp(argv[1], "show")) { memset((void*)pmc, 0, sizeof(pmc)); /* Try to know the AVS disable state */ pmc[0] = 20; // cmdGetAvsDisableState defined in pmc/command.h res = PMCcmd(pmc); if (!res) printf("AVS %s\n", pmc[2] ? "Disabled" : "Enabled"); else printf("failed to get AVS state, res=%d\n", res); return CMD_RET_SUCCESS; } res = 0; for (i = 0; i < sizeof disables / sizeof disables[0]; i++) if (!strcmp(argv[1], disables[i])) { res = 1; break; } setAVSConfig(res); #else printf("not supported\n"); #endif return CMD_RET_SUCCESS; } static int do_pmc_sc_closeavs(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]) { #if IS_BCMCHIP(63138) || IS_BCMCHIP(63148) || IS_BCMCHIP(4908) || \ IS_BCMCHIP(63158) || defined(PMC_IMPL_3_X) int res; uint32_t island = 0; uint16_t margin_mv_slow; uint16_t margin_mv_fast; uint16_t maximum_mv = 0; uint16_t minimum_mv = 0; if (!(argc == 4 || argc == 3 #if IS_BCMCHIP(63158) || defined(PMC_IMPL_3_X) || argc == 6 || argc == 5 #endif )) { printf("invalid number of parameters\n"); return CMD_RET_SUCCESS; } switch (argc) { case 3: case 5: margin_mv_slow = (uint16_t)simple_strtol(argv[1], NULL, 0); margin_mv_fast = (uint16_t)simple_strtol(argv[2], NULL, 0); if (argc == 3) break; maximum_mv = (uint16_t)simple_strtol(argv[3], NULL, 0); minimum_mv = (uint16_t)simple_strtol(argv[4], NULL, 0); break; case 4: case 6: island = (uint32_t)simple_strtol(argv[1], NULL, 0); margin_mv_slow = (uint16_t)simple_strtol(argv[2], NULL, 0); margin_mv_fast = (uint16_t)simple_strtol(argv[3], NULL, 0); if (argc == 4) break; maximum_mv = (uint16_t)simple_strtol(argv[4], NULL, 0); minimum_mv = (uint16_t)simple_strtol(argv[5], NULL, 0); break; } if (minimum_mv && maximum_mv && (minimum_mv > maximum_mv)) { printf("invalid parameters: min %d > max %d " "and not firmware default\n", minimum_mv, maximum_mv); return CMD_RET_SUCCESS; } printf("closeavs with [island %d] margin_mv slow %d fast %d" #if IS_BCMCHIP(63158) || defined(PMC_IMPL_3_X) "\n [max_mv %d min_mv %d (0 means using firmware default)]" #endif " ...\n", island, (short) margin_mv_slow, (short) margin_mv_fast #if IS_BCMCHIP(63158) || defined(PMC_IMPL_3_X) , maximum_mv, minimum_mv #endif ); res = CloseAVS(island, margin_mv_slow, margin_mv_fast, maximum_mv, minimum_mv); printf("%sed, res=%d\n", res ? "fail" : "succeed", res); #else printf("not supported\n"); #endif return CMD_RET_SUCCESS; } static int do_pmc_sc_cmd(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]) { int i, res, cmd[4] = { 0 }; for (i = 0; (i < sizeof(cmd)/sizeof(cmd[0])) && (i+1 < argc); i++) cmd[i] = simple_strtol(argv[i+1], NULL, 0); res = PMCcmd(cmd); printf("res=%d rsp=[%08x %08x %08x %08x]\n", res, cmd[0], cmd[1], cmd[2], cmd[3]); return CMD_RET_SUCCESS; } static int do_pmc_sc_log(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]) { #if defined(PMC_RAM_BOOT) && (defined(PMC_SHARED_MEMORY) || defined(PMC_IMPL_3_X)) int log_type = 0; if (argc > 1) log_type = simple_strtol(argv[1], NULL, 0); pmc_log(log_type); #endif return CMD_RET_SUCCESS; } static int get_pvtmon_result(int select, int island, int * val) { int res, adc = -1; res = GetPVT(select, island, &adc); if (!res) *val = pmc_convert_pvtmon(select, adc); return res; } static int do_pmc_sc_pvtmon(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]) { int select = 0; int island = 0; int res, val; if (argc > 1) select = simple_strtol(argv[1], NULL, 0); if (select < 0 || select > 7) { printf("invalid value for select, must be in 0 ~ 7\n"); return CMD_RET_SUCCESS; } if (argc > 2) island = simple_strtol(argv[2], NULL, 0); printf("get pvtmon select %d island %d ... ", select, island); res = get_pvtmon_result(select, island, &val); if (res) printf("failed, res=%d\n", res); else printf("value %d.%03d %c\n", val/1000, (val > 0 ? val : -val)%1000, select ? 'V' : 'C'); return CMD_RET_SUCCESS; } static int do_pmc_sc_tracktemp(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]) { char *p = argc > 1 ? argv[1] : NULL; int res, status = 1; if (!p || !strcmp(p, "status")) { res = pmc_get_tracktemp(&status); if (res) printf("failed to get tracktemp status, res=%d\n", res); else printf("tracktemp is %s\n", status ? "on" : "off"); return CMD_RET_SUCCESS; } if (!strcmp(p, "off")) status = 0; res = pmc_set_tracktemp(status); if (res) printf("failed to set tracktemp %s, res=%d\n", status ? "on" : "off", res); return CMD_RET_SUCCESS; } static char pmc_usage[] = "{avs | closeavs | cmd | log | pvtmon | tracktemp}\n" " - avs [enable | disable | show]\n" " - closeavs [] " #if IS_BCMCHIP(63158) || defined(PMC_IMPL_3_X) " [ ]" #endif "\n" " - cmd [ [ []]]\n" " - log []\n" " - pvtmon [