| // SPDX-License-Identifier: GPL-2.0+ | |
| /* | |
| * Power Domain test commands | |
| * | |
| * Copyright (C) 2020 Texas Instruments Incorporated, <www.ti.com> | |
| */ | |
| #include <command.h> | |
| #include <dm.h> | |
| #include <k3-dev.h> | |
| static const struct udevice_id ti_pd_of_match[] = { | |
| { .compatible = "ti,sci-pm-domain" }, | |
| { /* sentinel */ } | |
| }; | |
| static struct ti_k3_pd_platdata *ti_pd_find_data(void) | |
| { | |
| struct udevice *dev; | |
| int i = 0; | |
| while (1) { | |
| uclass_get_device(UCLASS_POWER_DOMAIN, i++, &dev); | |
| if (!dev) | |
| return NULL; | |
| if (device_is_compatible(dev, | |
| ti_pd_of_match[0].compatible)) | |
| return dev_get_priv(dev); | |
| } | |
| return NULL; | |
| } | |
| static void dump_lpsc(struct ti_k3_pd_platdata *data, struct ti_pd *pd) | |
| { | |
| int i; | |
| struct ti_lpsc *lpsc; | |
| u8 state; | |
| static const char * const lpsc_states[] = { | |
| "swrstdis", "syncrst", "disable", "enable", "autosleep", | |
| "autowake", "unknown", | |
| }; | |
| for (i = 0; i < data->num_lpsc; i++) { | |
| lpsc = &data->lpsc[i]; | |
| if (lpsc->pd != pd) | |
| continue; | |
| state = lpsc_get_state(lpsc); | |
| if (state > ARRAY_SIZE(lpsc_states)) | |
| state = ARRAY_SIZE(lpsc_states) - 1; | |
| printf(" LPSC%d: state=%s, usecount=%d\n", | |
| lpsc->id, lpsc_states[state], lpsc->usecount); | |
| } | |
| } | |
| static void dump_pd(struct ti_k3_pd_platdata *data, struct ti_psc *psc) | |
| { | |
| int i; | |
| struct ti_pd *pd; | |
| u8 state; | |
| static const char * const pd_states[] = { | |
| "off", "on", "unknown" | |
| }; | |
| for (i = 0; i < data->num_pd; i++) { | |
| pd = &data->pd[i]; | |
| if (pd->psc != psc) | |
| continue; | |
| state = ti_pd_state(pd); | |
| if (state > ARRAY_SIZE(pd_states)) | |
| state = ARRAY_SIZE(pd_states) - 1; | |
| printf(" PD%d: state=%s, usecount=%d:\n", | |
| pd->id, pd_states[state], pd->usecount); | |
| dump_lpsc(data, pd); | |
| } | |
| } | |
| static void dump_psc(struct ti_k3_pd_platdata *data) | |
| { | |
| int i; | |
| struct ti_psc *psc; | |
| for (i = 0; i < data->num_psc; i++) { | |
| psc = &data->psc[i]; | |
| printf("PSC%d [%p]:\n", psc->id, psc->base); | |
| dump_pd(data, psc); | |
| } | |
| } | |
| static int do_pd_dump(struct cmd_tbl *cmdtp, int flag, int argc, | |
| char *const argv[]) | |
| { | |
| struct ti_k3_pd_platdata *data; | |
| data = ti_pd_find_data(); | |
| if (!data) | |
| return CMD_RET_FAILURE; | |
| dump_psc(data); | |
| return 0; | |
| } | |
| static int do_pd_endis(int argc, char *const argv[], u8 state) | |
| { | |
| u32 psc_id; | |
| u32 lpsc_id; | |
| int i; | |
| struct ti_k3_pd_platdata *data; | |
| struct ti_lpsc *lpsc; | |
| int ret; | |
| if (argc < 3) | |
| return CMD_RET_FAILURE; | |
| data = ti_pd_find_data(); | |
| if (!data) | |
| return CMD_RET_FAILURE; | |
| psc_id = dectoul(argv[1], NULL); | |
| lpsc_id = dectoul(argv[2], NULL); | |
| for (i = 0; i < data->num_lpsc; i++) { | |
| lpsc = &data->lpsc[i]; | |
| if (lpsc->pd->psc->id != psc_id) | |
| continue; | |
| if (lpsc->id != lpsc_id) | |
| continue; | |
| printf("%s pd [PSC:%d,LPSC:%d]...\n", | |
| state == MDSTAT_STATE_ENABLE ? "Enabling" : "Disabling", | |
| psc_id, lpsc_id); | |
| ret = ti_lpsc_transition(lpsc, state); | |
| if (ret) | |
| return CMD_RET_FAILURE; | |
| else | |
| return 0; | |
| } | |
| printf("No matching psc/lpsc found.\n"); | |
| return CMD_RET_FAILURE; | |
| } | |
| static int do_pd_enable(struct cmd_tbl *cmdtp, int flag, int argc, | |
| char *const argv[]) | |
| { | |
| return do_pd_endis(argc, argv, MDSTAT_STATE_ENABLE); | |
| } | |
| static int do_pd_disable(struct cmd_tbl *cmdtp, int flag, int argc, | |
| char *const argv[]) | |
| { | |
| return do_pd_endis(argc, argv, MDSTAT_STATE_SWRSTDISABLE); | |
| } | |
| static struct cmd_tbl cmd_pd[] = { | |
| U_BOOT_CMD_MKENT(dump, 1, 0, do_pd_dump, "", ""), | |
| U_BOOT_CMD_MKENT(enable, 3, 0, do_pd_enable, "", ""), | |
| U_BOOT_CMD_MKENT(disable, 3, 0, do_pd_disable, "", ""), | |
| }; | |
| static int ti_do_pd(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) | |
| { | |
| struct cmd_tbl *c; | |
| argc--; | |
| argv++; | |
| c = find_cmd_tbl(argv[0], cmd_pd, ARRAY_SIZE(cmd_pd)); | |
| if (c) | |
| return c->cmd(cmdtp, flag, argc, argv); | |
| else | |
| return CMD_RET_USAGE; | |
| } | |
| U_BOOT_LONGHELP(pd, | |
| "dump - show power domain status\n" | |
| "enable [psc] [lpsc] - enable power domain\n" | |
| "disable [psc] [lpsc] - disable power domain\n"); | |
| U_BOOT_CMD(pd, 4, 1, ti_do_pd, | |
| "TI power domain control", pd_help_text | |
| ); |