@@ -7,4 +7,12 @@ config CMD_DDR3
supports memory verification, memory comapre and ecc
verification if supported.
+config CMD_PD
+ bool "command for verifying power domains"
+ depends on TI_POWER_DOMAIN
+ help
+ Debug command for K3 power domains. For this to work, the
+ K3 power domain driver must be enabled for the u-boot; by
+ default it is only enabled for SPL.
+
endmenu
@@ -5,4 +5,5 @@ obj- += dummy.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_CMD_DDR3) += ddr3.o
+obj-$(CONFIG_CMD_PD) += pd.o
endif
new file mode 100644
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Power Domain test commands
+ *
+ * Copyright (C) 2020 Texas Instruments Incorporated, <www.ti.com>
+ */
+
+#include <common.h>
+#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 = simple_strtoul(argv[1], NULL, 10);
+ lpsc_id = simple_strtoul(argv[2], NULL, 10);
+
+ 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_CMD(pd, 4, 1, ti_do_pd,
+ "TI power domain control",
+#if CONFIG_IS_ENABLED(SYS_LONGHELP)
+ "dump - show power domain status\n"
+ "enable [psc] [lpsc] - enable power domain\n"
+ "disable [psc] [lpsc] - disable power domain\n"
+#endif
+);
@@ -132,7 +132,7 @@ static void ti_pd_transition(struct ti_pd *pd)
psc_write(BIT(pd->id), pd->psc, PSC_PTCMD);
}
-static u8 ti_pd_state(struct ti_pd *pd)
+u8 ti_pd_state(struct ti_pd *pd)
{
return pd_read(pd, PSC_PDCTL) & PDCTL_STATE_MASK;
}
@@ -227,12 +227,12 @@ static int ti_lpsc_wait(struct ti_lpsc *lpsc)
return ret;
}
-static u8 lpsc_get_state(struct ti_lpsc *lpsc)
+u8 lpsc_get_state(struct ti_lpsc *lpsc)
{
return lpsc_read(lpsc, PSC_MDCTL) & MDSTAT_STATE_MASK;
}
-static int ti_lpsc_transition(struct ti_lpsc *lpsc, u8 state)
+int ti_lpsc_transition(struct ti_lpsc *lpsc, u8 state)
{
struct ti_pd *psc_pd;
int ret;
@@ -22,6 +22,11 @@
#define PSC_PD_ALWAYSON BIT(1)
#define PSC_PD_DEPENDS BIT(2)
+#define MDSTAT_STATE_MASK 0x3f
+#define MDSTAT_BUSY_MASK 0x30
+#define MDSTAT_STATE_SWRSTDISABLE 0x0
+#define MDSTAT_STATE_ENABLE 0x3
+
struct ti_psc {
int id;
void __iomem *base;
@@ -73,4 +78,8 @@ struct ti_k3_pd_platdata {
extern const struct ti_k3_pd_platdata j721e_pd_platdata;
extern const struct ti_k3_pd_platdata j7200_pd_platdata;
+u8 ti_pd_state(struct ti_pd *pd);
+u8 lpsc_get_state(struct ti_lpsc *lpsc);
+int ti_lpsc_transition(struct ti_lpsc *lpsc, u8 state);
+
#endif