]> Git Repo - J-linux.git/blob - drivers/firmware/xilinx/zynqmp-debug.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / firmware / xilinx / zynqmp-debug.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Xilinx Zynq MPSoC Firmware layer for debugfs APIs
4  *
5  *  Copyright (C) 2014-2018 Xilinx, Inc.
6  *
7  *  Michal Simek <[email protected]>
8  *  Davorin Mista <[email protected]>
9  *  Jolly Shah <[email protected]>
10  *  Rajan Vaja <[email protected]>
11  */
12
13 #include <linux/compiler.h>
14 #include <linux/module.h>
15 #include <linux/slab.h>
16 #include <linux/debugfs.h>
17 #include <linux/uaccess.h>
18
19 #include <linux/firmware/xlnx-zynqmp.h>
20 #include "zynqmp-debug.h"
21
22 #define PM_API_NAME_LEN                 50
23
24 struct pm_api_info {
25         u32 api_id;
26         char api_name[PM_API_NAME_LEN];
27         char api_name_len;
28 };
29
30 static char debugfs_buf[PAGE_SIZE];
31
32 #define PM_API(id)               {id, #id, strlen(#id)}
33 static struct pm_api_info pm_api_list[] = {
34         PM_API(PM_FORCE_POWERDOWN),
35         PM_API(PM_REQUEST_WAKEUP),
36         PM_API(PM_SYSTEM_SHUTDOWN),
37         PM_API(PM_REQUEST_NODE),
38         PM_API(PM_RELEASE_NODE),
39         PM_API(PM_SET_REQUIREMENT),
40         PM_API(PM_GET_API_VERSION),
41         PM_API(PM_REGISTER_NOTIFIER),
42         PM_API(PM_RESET_ASSERT),
43         PM_API(PM_RESET_GET_STATUS),
44         PM_API(PM_GET_CHIPID),
45         PM_API(PM_PINCTRL_SET_FUNCTION),
46         PM_API(PM_PINCTRL_CONFIG_PARAM_GET),
47         PM_API(PM_PINCTRL_CONFIG_PARAM_SET),
48         PM_API(PM_IOCTL),
49         PM_API(PM_CLOCK_ENABLE),
50         PM_API(PM_CLOCK_DISABLE),
51         PM_API(PM_CLOCK_GETSTATE),
52         PM_API(PM_CLOCK_SETDIVIDER),
53         PM_API(PM_CLOCK_GETDIVIDER),
54         PM_API(PM_CLOCK_SETPARENT),
55         PM_API(PM_CLOCK_GETPARENT),
56         PM_API(PM_QUERY_DATA),
57 };
58
59 static struct dentry *firmware_debugfs_root;
60
61 /**
62  * zynqmp_pm_ioctl - PM IOCTL for device control and configs
63  * @node:       Node ID of the device
64  * @ioctl:      ID of the requested IOCTL
65  * @arg1:       Argument 1 of requested IOCTL call
66  * @arg2:       Argument 2 of requested IOCTL call
67  * @arg3:       Argument 3 of requested IOCTL call
68  * @out:        Returned output value
69  *
70  * Return:      Returns status, either success or error+reason
71  */
72 static int zynqmp_pm_ioctl(const u32 node, const u32 ioctl, const u32 arg1,
73                            const u32 arg2, const u32 arg3, u32 *out)
74 {
75         return zynqmp_pm_invoke_fn(PM_IOCTL, out, 5, node, ioctl, arg1, arg2, arg3);
76 }
77
78 /**
79  * zynqmp_pm_argument_value() - Extract argument value from a PM-API request
80  * @arg:        Entered PM-API argument in string format
81  *
82  * Return: Argument value in unsigned integer format on success
83  *         0 otherwise
84  */
85 static u64 zynqmp_pm_argument_value(char *arg)
86 {
87         u64 value;
88
89         if (!arg)
90                 return 0;
91
92         if (!kstrtou64(arg, 0, &value))
93                 return value;
94
95         return 0;
96 }
97
98 /**
99  * get_pm_api_id() - Extract API-ID from a PM-API request
100  * @pm_api_req:         Entered PM-API argument in string format
101  * @pm_id:              API-ID
102  *
103  * Return: 0 on success else error code
104  */
105 static int get_pm_api_id(char *pm_api_req, u32 *pm_id)
106 {
107         int i;
108
109         for (i = 0; i < ARRAY_SIZE(pm_api_list) ; i++) {
110                 if (!strncasecmp(pm_api_req, pm_api_list[i].api_name,
111                                  pm_api_list[i].api_name_len)) {
112                         *pm_id = pm_api_list[i].api_id;
113                         break;
114                 }
115         }
116
117         /* If no name was entered look for PM-API ID instead */
118         if (i == ARRAY_SIZE(pm_api_list) && kstrtouint(pm_api_req, 10, pm_id))
119                 return -EINVAL;
120
121         return 0;
122 }
123
124 static int process_api_request(u32 pm_id, u64 *pm_api_arg, u32 *pm_api_ret)
125 {
126         u32 pm_api_version;
127         int ret;
128         struct zynqmp_pm_query_data qdata = {0};
129
130         switch (pm_id) {
131         case PM_GET_API_VERSION:
132                 ret = zynqmp_pm_get_api_version(&pm_api_version);
133                 sprintf(debugfs_buf, "PM-API Version = %d.%d\n",
134                         pm_api_version >> 16, pm_api_version & 0xffff);
135                 break;
136         case PM_FORCE_POWERDOWN:
137                 ret = zynqmp_pm_force_pwrdwn(pm_api_arg[0],
138                                              pm_api_arg[1] ? pm_api_arg[1] :
139                                              ZYNQMP_PM_REQUEST_ACK_NO);
140                 break;
141         case PM_REQUEST_WAKEUP:
142                 ret = zynqmp_pm_request_wake(pm_api_arg[0],
143                                              pm_api_arg[1], pm_api_arg[2],
144                                              pm_api_arg[3] ? pm_api_arg[3] :
145                                              ZYNQMP_PM_REQUEST_ACK_NO);
146                 break;
147         case PM_SYSTEM_SHUTDOWN:
148                 ret = zynqmp_pm_system_shutdown(pm_api_arg[0], pm_api_arg[1]);
149                 break;
150         case PM_REQUEST_NODE:
151                 ret = zynqmp_pm_request_node(pm_api_arg[0],
152                                              pm_api_arg[1] ? pm_api_arg[1] :
153                                              ZYNQMP_PM_CAPABILITY_ACCESS,
154                                              pm_api_arg[2] ? pm_api_arg[2] : 0,
155                                              pm_api_arg[3] ? pm_api_arg[3] :
156                                              ZYNQMP_PM_REQUEST_ACK_BLOCKING);
157                 break;
158         case PM_RELEASE_NODE:
159                 ret = zynqmp_pm_release_node(pm_api_arg[0]);
160                 break;
161         case PM_SET_REQUIREMENT:
162                 ret = zynqmp_pm_set_requirement(pm_api_arg[0],
163                                                 pm_api_arg[1] ? pm_api_arg[1] :
164                                                 ZYNQMP_PM_CAPABILITY_CONTEXT,
165                                                 pm_api_arg[2] ?
166                                                 pm_api_arg[2] : 0,
167                                                 pm_api_arg[3] ? pm_api_arg[3] :
168                                                 ZYNQMP_PM_REQUEST_ACK_BLOCKING);
169                 break;
170         case PM_REGISTER_NOTIFIER:
171                 ret = zynqmp_pm_register_notifier(pm_api_arg[0],
172                                                   pm_api_arg[1] ?
173                                                   pm_api_arg[1] : 0,
174                                                   pm_api_arg[2] ?
175                                                   pm_api_arg[2] : 0,
176                                                   pm_api_arg[3] ?
177                                                   pm_api_arg[3] : 0);
178                 break;
179         case PM_RESET_ASSERT:
180                 ret = zynqmp_pm_reset_assert(pm_api_arg[0], pm_api_arg[1]);
181                 break;
182         case PM_RESET_GET_STATUS:
183                 ret = zynqmp_pm_reset_get_status(pm_api_arg[0], &pm_api_ret[0]);
184                 if (!ret)
185                         sprintf(debugfs_buf, "Reset status: %u\n",
186                                 pm_api_ret[0]);
187                 break;
188         case PM_GET_CHIPID:
189                 ret = zynqmp_pm_get_chipid(&pm_api_ret[0], &pm_api_ret[1]);
190                 if (!ret)
191                         sprintf(debugfs_buf, "Idcode: %#x, Version:%#x\n",
192                                 pm_api_ret[0], pm_api_ret[1]);
193                 break;
194         case PM_PINCTRL_SET_FUNCTION:
195                 ret = zynqmp_pm_pinctrl_set_function(pm_api_arg[0],
196                                                      pm_api_arg[1]);
197                 break;
198         case PM_PINCTRL_CONFIG_PARAM_GET:
199                 ret = zynqmp_pm_pinctrl_get_config(pm_api_arg[0], pm_api_arg[1],
200                                                    &pm_api_ret[0]);
201                 if (!ret)
202                         sprintf(debugfs_buf,
203                                 "Pin: %llu, Param: %llu, Value: %u\n",
204                                 pm_api_arg[0], pm_api_arg[1],
205                                 pm_api_ret[0]);
206                 break;
207         case PM_PINCTRL_CONFIG_PARAM_SET:
208                 ret = zynqmp_pm_pinctrl_set_config(pm_api_arg[0],
209                                                    pm_api_arg[1],
210                                                    pm_api_arg[2]);
211                 break;
212         case PM_IOCTL:
213                 ret = zynqmp_pm_ioctl(pm_api_arg[0], pm_api_arg[1],
214                                       pm_api_arg[2], pm_api_arg[3],
215                                       pm_api_arg[4], &pm_api_ret[0]);
216                 if (!ret && (pm_api_arg[1] == IOCTL_GET_RPU_OPER_MODE ||
217                              pm_api_arg[1] == IOCTL_GET_PLL_FRAC_MODE ||
218                              pm_api_arg[1] == IOCTL_GET_PLL_FRAC_DATA ||
219                              pm_api_arg[1] == IOCTL_READ_GGS ||
220                              pm_api_arg[1] == IOCTL_READ_PGGS ||
221                              pm_api_arg[1] == IOCTL_READ_REG))
222                         sprintf(debugfs_buf, "IOCTL return value: %u\n",
223                                 pm_api_ret[1]);
224                 if (!ret && pm_api_arg[1] == IOCTL_GET_QOS)
225                         sprintf(debugfs_buf, "Default QoS: %u\nCurrent QoS: %u\n",
226                                 pm_api_ret[1], pm_api_ret[2]);
227                 break;
228         case PM_CLOCK_ENABLE:
229                 ret = zynqmp_pm_clock_enable(pm_api_arg[0]);
230                 break;
231         case PM_CLOCK_DISABLE:
232                 ret = zynqmp_pm_clock_disable(pm_api_arg[0]);
233                 break;
234         case PM_CLOCK_GETSTATE:
235                 ret = zynqmp_pm_clock_getstate(pm_api_arg[0], &pm_api_ret[0]);
236                 if (!ret)
237                         sprintf(debugfs_buf, "Clock state: %u\n",
238                                 pm_api_ret[0]);
239                 break;
240         case PM_CLOCK_SETDIVIDER:
241                 ret = zynqmp_pm_clock_setdivider(pm_api_arg[0], pm_api_arg[1]);
242                 break;
243         case PM_CLOCK_GETDIVIDER:
244                 ret = zynqmp_pm_clock_getdivider(pm_api_arg[0], &pm_api_ret[0]);
245                 if (!ret)
246                         sprintf(debugfs_buf, "Divider Value: %d\n",
247                                 pm_api_ret[0]);
248                 break;
249         case PM_CLOCK_SETPARENT:
250                 ret = zynqmp_pm_clock_setparent(pm_api_arg[0], pm_api_arg[1]);
251                 break;
252         case PM_CLOCK_GETPARENT:
253                 ret = zynqmp_pm_clock_getparent(pm_api_arg[0], &pm_api_ret[0]);
254                 if (!ret)
255                         sprintf(debugfs_buf,
256                                 "Clock parent Index: %u\n", pm_api_ret[0]);
257                 break;
258         case PM_QUERY_DATA:
259                 qdata.qid = pm_api_arg[0];
260                 qdata.arg1 = pm_api_arg[1];
261                 qdata.arg2 = pm_api_arg[2];
262                 qdata.arg3 = pm_api_arg[3];
263
264                 ret = zynqmp_pm_query_data(qdata, pm_api_ret);
265                 if (ret)
266                         break;
267
268                 switch (qdata.qid) {
269                 case PM_QID_CLOCK_GET_NAME:
270                         sprintf(debugfs_buf, "Clock name = %s\n",
271                                 (char *)pm_api_ret);
272                         break;
273                 case PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS:
274                         sprintf(debugfs_buf, "Multiplier = %d, Divider = %d\n",
275                                 pm_api_ret[1], pm_api_ret[2]);
276                         break;
277                 default:
278                         sprintf(debugfs_buf,
279                                 "data[0] = 0x%08x\ndata[1] = 0x%08x\n data[2] = 0x%08x\ndata[3] = 0x%08x\n",
280                                 pm_api_ret[0], pm_api_ret[1],
281                                 pm_api_ret[2], pm_api_ret[3]);
282                 }
283                 break;
284         default:
285                 sprintf(debugfs_buf, "Unsupported PM-API request\n");
286                 ret = -EINVAL;
287         }
288
289         return ret;
290 }
291
292 /**
293  * zynqmp_pm_debugfs_api_write() - debugfs write function
294  * @file:       User file
295  * @ptr:        User entered PM-API string
296  * @len:        Length of the userspace buffer
297  * @off:        Offset within the file
298  *
299  * Used for triggering pm api functions by writing
300  * echo <pm_api_id>     > /sys/kernel/debug/zynqmp_pm/power or
301  * echo <pm_api_name>   > /sys/kernel/debug/zynqmp_pm/power
302  *
303  * Return: Number of bytes copied if PM-API request succeeds,
304  *         the corresponding error code otherwise
305  */
306 static ssize_t zynqmp_pm_debugfs_api_write(struct file *file,
307                                            const char __user *ptr, size_t len,
308                                            loff_t *off)
309 {
310         char *kern_buff, *tmp_buff;
311         char *pm_api_req;
312         u32 pm_id = 0;
313         u64 pm_api_arg[5] = {0, 0, 0, 0, 0};
314         /* Return values from PM APIs calls */
315         u32 pm_api_ret[4] = {0, 0, 0, 0};
316
317         int ret;
318         int i = 0;
319
320         strcpy(debugfs_buf, "");
321
322         if (*off != 0 || len <= 1 || len > PAGE_SIZE - 1)
323                 return -EINVAL;
324
325         kern_buff = memdup_user_nul(ptr, len);
326         if (IS_ERR(kern_buff))
327                 return PTR_ERR(kern_buff);
328         tmp_buff = kern_buff;
329
330         /* Read the API name from a user request */
331         pm_api_req = strsep(&kern_buff, " ");
332
333         ret = get_pm_api_id(pm_api_req, &pm_id);
334         if (ret < 0)
335                 goto err;
336
337         /* Read node_id and arguments from the PM-API request */
338         pm_api_req = strsep(&kern_buff, " ");
339         while ((i < ARRAY_SIZE(pm_api_arg)) && pm_api_req) {
340                 pm_api_arg[i++] = zynqmp_pm_argument_value(pm_api_req);
341                 pm_api_req = strsep(&kern_buff, " ");
342         }
343
344         ret = process_api_request(pm_id, pm_api_arg, pm_api_ret);
345
346 err:
347         kfree(tmp_buff);
348         if (ret)
349                 return ret;
350
351         return len;
352 }
353
354 /**
355  * zynqmp_pm_debugfs_api_read() - debugfs read function
356  * @file:       User file
357  * @ptr:        Requested pm_api_version string
358  * @len:        Length of the userspace buffer
359  * @off:        Offset within the file
360  *
361  * Return: Length of the version string on success
362  *         else error code
363  */
364 static ssize_t zynqmp_pm_debugfs_api_read(struct file *file, char __user *ptr,
365                                           size_t len, loff_t *off)
366 {
367         return simple_read_from_buffer(ptr, len, off, debugfs_buf,
368                                        strlen(debugfs_buf));
369 }
370
371 /* Setup debugfs fops */
372 static const struct file_operations fops_zynqmp_pm_dbgfs = {
373         .owner = THIS_MODULE,
374         .write = zynqmp_pm_debugfs_api_write,
375         .read = zynqmp_pm_debugfs_api_read,
376 };
377
378 /**
379  * zynqmp_pm_api_debugfs_init - Initialize debugfs interface
380  *
381  * Return:      None
382  */
383 void zynqmp_pm_api_debugfs_init(void)
384 {
385         /* Initialize debugfs interface */
386         firmware_debugfs_root = debugfs_create_dir("zynqmp-firmware", NULL);
387         debugfs_create_file("pm", 0660, firmware_debugfs_root, NULL,
388                             &fops_zynqmp_pm_dbgfs);
389 }
390
391 /**
392  * zynqmp_pm_api_debugfs_exit - Remove debugfs interface
393  *
394  * Return:      None
395  */
396 void zynqmp_pm_api_debugfs_exit(void)
397 {
398         debugfs_remove_recursive(firmware_debugfs_root);
399 }
This page took 0.050416 seconds and 4 git commands to generate.