1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Power Domain test commands
4  *
5  * Copyright (C) 2020 Texas Instruments Incorporated, <www.ti.com>
6  */
7 
8 #include <command.h>
9 #include <dm.h>
10 #include <k3-dev.h>
11 
12 static const struct udevice_id ti_pd_of_match[] = {
13 	{ .compatible = "ti,sci-pm-domain" },
14 	{ /* sentinel */ }
15 };
16 
ti_pd_find_data(void)17 static struct ti_k3_pd_platdata *ti_pd_find_data(void)
18 {
19 	struct udevice *dev;
20 	int i = 0;
21 
22 	while (1) {
23 		uclass_get_device(UCLASS_POWER_DOMAIN, i++, &dev);
24 		if (!dev)
25 			return NULL;
26 
27 		if (device_is_compatible(dev,
28 					 ti_pd_of_match[0].compatible))
29 			return  dev_get_priv(dev);
30 	}
31 
32 	return NULL;
33 }
34 
dump_lpsc(struct ti_k3_pd_platdata * data,struct ti_pd * pd)35 static void dump_lpsc(struct ti_k3_pd_platdata *data, struct ti_pd *pd)
36 {
37 	int i;
38 	struct ti_lpsc *lpsc;
39 	u8 state;
40 	static const char * const lpsc_states[] = {
41 		"swrstdis", "syncrst", "disable", "enable", "autosleep",
42 		"autowake", "unknown",
43 	};
44 
45 	for (i = 0; i < data->num_lpsc; i++) {
46 		lpsc = &data->lpsc[i];
47 		if (lpsc->pd != pd)
48 			continue;
49 		state = lpsc_get_state(lpsc);
50 		if (state > ARRAY_SIZE(lpsc_states))
51 			state = ARRAY_SIZE(lpsc_states) - 1;
52 		printf("    LPSC%d: state=%s, usecount=%d\n",
53 		       lpsc->id, lpsc_states[state], lpsc->usecount);
54 	}
55 }
56 
dump_pd(struct ti_k3_pd_platdata * data,struct ti_psc * psc)57 static void dump_pd(struct ti_k3_pd_platdata *data, struct ti_psc *psc)
58 {
59 	int i;
60 	struct ti_pd *pd;
61 	u8 state;
62 	static const char * const pd_states[] = {
63 		"off", "on", "unknown"
64 	};
65 
66 	for (i = 0; i < data->num_pd; i++) {
67 		pd = &data->pd[i];
68 		if (pd->psc != psc)
69 			continue;
70 		state = ti_pd_state(pd);
71 		if (state > ARRAY_SIZE(pd_states))
72 			state = ARRAY_SIZE(pd_states) - 1;
73 		printf("  PD%d: state=%s, usecount=%d:\n",
74 		       pd->id, pd_states[state], pd->usecount);
75 		dump_lpsc(data, pd);
76 	}
77 }
78 
dump_psc(struct ti_k3_pd_platdata * data)79 static void dump_psc(struct ti_k3_pd_platdata *data)
80 {
81 	int i;
82 	struct ti_psc *psc;
83 
84 	for (i = 0; i < data->num_psc; i++) {
85 		psc = &data->psc[i];
86 		printf("PSC%d [%p]:\n", psc->id, psc->base);
87 		dump_pd(data, psc);
88 	}
89 }
90 
do_pd_dump(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])91 static int do_pd_dump(struct cmd_tbl *cmdtp, int flag, int argc,
92 		      char *const argv[])
93 {
94 	struct ti_k3_pd_platdata *data;
95 
96 	data = ti_pd_find_data();
97 	if (!data)
98 		return CMD_RET_FAILURE;
99 
100 	dump_psc(data);
101 
102 	return 0;
103 }
104 
do_pd_endis(int argc,char * const argv[],u8 state)105 static int do_pd_endis(int argc, char *const argv[], u8 state)
106 {
107 	u32 psc_id;
108 	u32 lpsc_id;
109 	int i;
110 	struct ti_k3_pd_platdata *data;
111 	struct ti_lpsc *lpsc;
112 	int ret;
113 
114 	if (argc < 3)
115 		return CMD_RET_FAILURE;
116 
117 	data = ti_pd_find_data();
118 	if (!data)
119 		return CMD_RET_FAILURE;
120 
121 	psc_id = dectoul(argv[1], NULL);
122 	lpsc_id = dectoul(argv[2], NULL);
123 
124 	for (i = 0; i < data->num_lpsc; i++) {
125 		lpsc = &data->lpsc[i];
126 		if (lpsc->pd->psc->id != psc_id)
127 			continue;
128 		if (lpsc->id != lpsc_id)
129 			continue;
130 		printf("%s pd [PSC:%d,LPSC:%d]...\n",
131 		       state == MDSTAT_STATE_ENABLE ? "Enabling" : "Disabling",
132 		       psc_id, lpsc_id);
133 		ret = ti_lpsc_transition(lpsc, state);
134 		if (ret)
135 			return CMD_RET_FAILURE;
136 		else
137 			return 0;
138 	}
139 
140 	printf("No matching psc/lpsc found.\n");
141 
142 	return CMD_RET_FAILURE;
143 }
144 
do_pd_enable(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])145 static int do_pd_enable(struct cmd_tbl *cmdtp, int flag, int argc,
146 			char *const argv[])
147 {
148 	return do_pd_endis(argc, argv, MDSTAT_STATE_ENABLE);
149 }
150 
do_pd_disable(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])151 static int do_pd_disable(struct cmd_tbl *cmdtp, int flag, int argc,
152 			 char *const argv[])
153 {
154 	return do_pd_endis(argc, argv, MDSTAT_STATE_SWRSTDISABLE);
155 }
156 
157 static struct cmd_tbl cmd_pd[] = {
158 	U_BOOT_CMD_MKENT(dump, 1, 0, do_pd_dump, "", ""),
159 	U_BOOT_CMD_MKENT(enable, 3, 0, do_pd_enable, "", ""),
160 	U_BOOT_CMD_MKENT(disable, 3, 0, do_pd_disable, "", ""),
161 };
162 
ti_do_pd(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])163 static int ti_do_pd(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
164 {
165 	struct cmd_tbl *c;
166 
167 	argc--;
168 	argv++;
169 
170 	c = find_cmd_tbl(argv[0], cmd_pd, ARRAY_SIZE(cmd_pd));
171 	if (c)
172 		return c->cmd(cmdtp, flag, argc, argv);
173 	else
174 		return CMD_RET_USAGE;
175 }
176 
177 U_BOOT_LONGHELP(pd,
178 	   "dump                 - show power domain status\n"
179 	   "enable [psc] [lpsc]  - enable power domain\n"
180 	   "disable [psc] [lpsc] - disable power domain\n");
181 
182 U_BOOT_CMD(pd, 4, 1, ti_do_pd,
183 	   "TI power domain control", pd_help_text
184 );
185