Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Xilinx Zynq MPSoC Firmware layer
4 *
5 * Copyright (C) 2014-2020 Xilinx, Inc.
6 *
7 * Michal Simek <michal.simek@xilinx.com>
8 * Davorin Mista <davorin.mista@aggios.com>
9 * Jolly Shah <jollys@xilinx.com>
10 * Rajan Vaja <rajanv@xilinx.com>
11 */
12
13#include <linux/arm-smccc.h>
14#include <linux/compiler.h>
15#include <linux/device.h>
16#include <linux/init.h>
17#include <linux/mfd/core.h>
18#include <linux/module.h>
19#include <linux/of.h>
20#include <linux/of_platform.h>
21#include <linux/slab.h>
22#include <linux/uaccess.h>
23
24#include <linux/firmware/xlnx-zynqmp.h>
25#include "zynqmp-debug.h"
26
27static bool feature_check_enabled;
28static u32 zynqmp_pm_features[PM_API_MAX];
29
30static const struct mfd_cell firmware_devs[] = {
31 {
32 .name = "zynqmp_power_controller",
33 },
34};
35
36/**
37 * zynqmp_pm_ret_code() - Convert PMU-FW error codes to Linux error codes
38 * @ret_status: PMUFW return code
39 *
40 * Return: corresponding Linux error code
41 */
42static int zynqmp_pm_ret_code(u32 ret_status)
43{
44 switch (ret_status) {
45 case XST_PM_SUCCESS:
46 case XST_PM_DOUBLE_REQ:
47 return 0;
48 case XST_PM_NO_FEATURE:
49 return -ENOTSUPP;
50 case XST_PM_NO_ACCESS:
51 return -EACCES;
52 case XST_PM_ABORT_SUSPEND:
53 return -ECANCELED;
54 case XST_PM_MULT_USER:
55 return -EUSERS;
56 case XST_PM_INTERNAL:
57 case XST_PM_CONFLICT:
58 case XST_PM_INVALID_NODE:
59 default:
60 return -EINVAL;
61 }
62}
63
64static noinline int do_fw_call_fail(u64 arg0, u64 arg1, u64 arg2,
65 u32 *ret_payload)
66{
67 return -ENODEV;
68}
69
70/*
71 * PM function call wrapper
72 * Invoke do_fw_call_smc or do_fw_call_hvc, depending on the configuration
73 */
74static int (*do_fw_call)(u64, u64, u64, u32 *ret_payload) = do_fw_call_fail;
75
76/**
77 * do_fw_call_smc() - Call system-level platform management layer (SMC)
78 * @arg0: Argument 0 to SMC call
79 * @arg1: Argument 1 to SMC call
80 * @arg2: Argument 2 to SMC call
81 * @ret_payload: Returned value array
82 *
83 * Invoke platform management function via SMC call (no hypervisor present).
84 *
85 * Return: Returns status, either success or error+reason
86 */
87static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2,
88 u32 *ret_payload)
89{
90 struct arm_smccc_res res;
91
92 arm_smccc_smc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
93
94 if (ret_payload) {
95 ret_payload[0] = lower_32_bits(res.a0);
96 ret_payload[1] = upper_32_bits(res.a0);
97 ret_payload[2] = lower_32_bits(res.a1);
98 ret_payload[3] = upper_32_bits(res.a1);
99 }
100
101 return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
102}
103
104/**
105 * do_fw_call_hvc() - Call system-level platform management layer (HVC)
106 * @arg0: Argument 0 to HVC call
107 * @arg1: Argument 1 to HVC call
108 * @arg2: Argument 2 to HVC call
109 * @ret_payload: Returned value array
110 *
111 * Invoke platform management function via HVC
112 * HVC-based for communication through hypervisor
113 * (no direct communication with ATF).
114 *
115 * Return: Returns status, either success or error+reason
116 */
117static noinline int do_fw_call_hvc(u64 arg0, u64 arg1, u64 arg2,
118 u32 *ret_payload)
119{
120 struct arm_smccc_res res;
121
122 arm_smccc_hvc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
123
124 if (ret_payload) {
125 ret_payload[0] = lower_32_bits(res.a0);
126 ret_payload[1] = upper_32_bits(res.a0);
127 ret_payload[2] = lower_32_bits(res.a1);
128 ret_payload[3] = upper_32_bits(res.a1);
129 }
130
131 return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
132}
133
134/**
135 * zynqmp_pm_feature() - Check weather given feature is supported or not
136 * @api_id: API ID to check
137 *
138 * Return: Returns status, either success or error+reason
139 */
140static int zynqmp_pm_feature(u32 api_id)
141{
142 int ret;
143 u32 ret_payload[PAYLOAD_ARG_CNT];
144 u64 smc_arg[2];
145
146 if (!feature_check_enabled)
147 return 0;
148
149 /* Return value if feature is already checked */
150 if (api_id > ARRAY_SIZE(zynqmp_pm_features))
151 return PM_FEATURE_INVALID;
152
153 if (zynqmp_pm_features[api_id] != PM_FEATURE_UNCHECKED)
154 return zynqmp_pm_features[api_id];
155
156 smc_arg[0] = PM_SIP_SVC | PM_FEATURE_CHECK;
157 smc_arg[1] = api_id;
158
159 ret = do_fw_call(smc_arg[0], smc_arg[1], 0, ret_payload);
160 if (ret) {
161 zynqmp_pm_features[api_id] = PM_FEATURE_INVALID;
162 return PM_FEATURE_INVALID;
163 }
164
165 zynqmp_pm_features[api_id] = ret_payload[1];
166
167 return zynqmp_pm_features[api_id];
168}
169
170/**
171 * zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer
172 * caller function depending on the configuration
173 * @pm_api_id: Requested PM-API call
174 * @arg0: Argument 0 to requested PM-API call
175 * @arg1: Argument 1 to requested PM-API call
176 * @arg2: Argument 2 to requested PM-API call
177 * @arg3: Argument 3 to requested PM-API call
178 * @ret_payload: Returned value array
179 *
180 * Invoke platform management function for SMC or HVC call, depending on
181 * configuration.
182 * Following SMC Calling Convention (SMCCC) for SMC64:
183 * Pm Function Identifier,
184 * PM_SIP_SVC + PM_API_ID =
185 * ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT)
186 * ((SMC_64) << FUNCID_CC_SHIFT)
187 * ((SIP_START) << FUNCID_OEN_SHIFT)
188 * ((PM_API_ID) & FUNCID_NUM_MASK))
189 *
190 * PM_SIP_SVC - Registered ZynqMP SIP Service Call.
191 * PM_API_ID - Platform Management API ID.
192 *
193 * Return: Returns status, either success or error+reason
194 */
195int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1,
196 u32 arg2, u32 arg3, u32 *ret_payload)
197{
198 /*
199 * Added SIP service call Function Identifier
200 * Make sure to stay in x0 register
201 */
202 u64 smc_arg[4];
203
204 if (zynqmp_pm_feature(pm_api_id) == PM_FEATURE_INVALID)
205 return -ENOTSUPP;
206
207 smc_arg[0] = PM_SIP_SVC | pm_api_id;
208 smc_arg[1] = ((u64)arg1 << 32) | arg0;
209 smc_arg[2] = ((u64)arg3 << 32) | arg2;
210
211 return do_fw_call(smc_arg[0], smc_arg[1], smc_arg[2], ret_payload);
212}
213
214static u32 pm_api_version;
215static u32 pm_tz_version;
216
217/**
218 * zynqmp_pm_get_api_version() - Get version number of PMU PM firmware
219 * @version: Returned version value
220 *
221 * Return: Returns status, either success or error+reason
222 */
223int zynqmp_pm_get_api_version(u32 *version)
224{
225 u32 ret_payload[PAYLOAD_ARG_CNT];
226 int ret;
227
228 if (!version)
229 return -EINVAL;
230
231 /* Check is PM API version already verified */
232 if (pm_api_version > 0) {
233 *version = pm_api_version;
234 return 0;
235 }
236 ret = zynqmp_pm_invoke_fn(PM_GET_API_VERSION, 0, 0, 0, 0, ret_payload);
237 *version = ret_payload[1];
238
239 return ret;
240}
241EXPORT_SYMBOL_GPL(zynqmp_pm_get_api_version);
242
243/**
244 * zynqmp_pm_get_chipid - Get silicon ID registers
245 * @idcode: IDCODE register
246 * @version: version register
247 *
248 * Return: Returns the status of the operation and the idcode and version
249 * registers in @idcode and @version.
250 */
251int zynqmp_pm_get_chipid(u32 *idcode, u32 *version)
252{
253 u32 ret_payload[PAYLOAD_ARG_CNT];
254 int ret;
255
256 if (!idcode || !version)
257 return -EINVAL;
258
259 ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload);
260 *idcode = ret_payload[1];
261 *version = ret_payload[2];
262
263 return ret;
264}
265EXPORT_SYMBOL_GPL(zynqmp_pm_get_chipid);
266
267/**
268 * zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version
269 * @version: Returned version value
270 *
271 * Return: Returns status, either success or error+reason
272 */
273static int zynqmp_pm_get_trustzone_version(u32 *version)
274{
275 u32 ret_payload[PAYLOAD_ARG_CNT];
276 int ret;
277
278 if (!version)
279 return -EINVAL;
280
281 /* Check is PM trustzone version already verified */
282 if (pm_tz_version > 0) {
283 *version = pm_tz_version;
284 return 0;
285 }
286 ret = zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION, 0, 0,
287 0, 0, ret_payload);
288 *version = ret_payload[1];
289
290 return ret;
291}
292
293/**
294 * get_set_conduit_method() - Choose SMC or HVC based communication
295 * @np: Pointer to the device_node structure
296 *
297 * Use SMC or HVC-based functions to communicate with EL2/EL3.
298 *
299 * Return: Returns 0 on success or error code
300 */
301static int get_set_conduit_method(struct device_node *np)
302{
303 const char *method;
304
305 if (of_property_read_string(np, "method", &method)) {
306 pr_warn("%s missing \"method\" property\n", __func__);
307 return -ENXIO;
308 }
309
310 if (!strcmp("hvc", method)) {
311 do_fw_call = do_fw_call_hvc;
312 } else if (!strcmp("smc", method)) {
313 do_fw_call = do_fw_call_smc;
314 } else {
315 pr_warn("%s Invalid \"method\" property: %s\n",
316 __func__, method);
317 return -EINVAL;
318 }
319
320 return 0;
321}
322
323/**
324 * zynqmp_pm_query_data() - Get query data from firmware
325 * @qdata: Variable to the zynqmp_pm_query_data structure
326 * @out: Returned output value
327 *
328 * Return: Returns status, either success or error+reason
329 */
330int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out)
331{
332 int ret;
333
334 ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, qdata.qid, qdata.arg1,
335 qdata.arg2, qdata.arg3, out);
336
337 /*
338 * For clock name query, all bytes in SMC response are clock name
339 * characters and return code is always success. For invalid clocks,
340 * clock name bytes would be zeros.
341 */
342 return qdata.qid == PM_QID_CLOCK_GET_NAME ? 0 : ret;
343}
344EXPORT_SYMBOL_GPL(zynqmp_pm_query_data);
345
346/**
347 * zynqmp_pm_clock_enable() - Enable the clock for given id
348 * @clock_id: ID of the clock to be enabled
349 *
350 * This function is used by master to enable the clock
351 * including peripherals and PLL clocks.
352 *
353 * Return: Returns status, either success or error+reason
354 */
355int zynqmp_pm_clock_enable(u32 clock_id)
356{
357 return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, clock_id, 0, 0, 0, NULL);
358}
359EXPORT_SYMBOL_GPL(zynqmp_pm_clock_enable);
360
361/**
362 * zynqmp_pm_clock_disable() - Disable the clock for given id
363 * @clock_id: ID of the clock to be disable
364 *
365 * This function is used by master to disable the clock
366 * including peripherals and PLL clocks.
367 *
368 * Return: Returns status, either success or error+reason
369 */
370int zynqmp_pm_clock_disable(u32 clock_id)
371{
372 return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, clock_id, 0, 0, 0, NULL);
373}
374EXPORT_SYMBOL_GPL(zynqmp_pm_clock_disable);
375
376/**
377 * zynqmp_pm_clock_getstate() - Get the clock state for given id
378 * @clock_id: ID of the clock to be queried
379 * @state: 1/0 (Enabled/Disabled)
380 *
381 * This function is used by master to get the state of clock
382 * including peripherals and PLL clocks.
383 *
384 * Return: Returns status, either success or error+reason
385 */
386int zynqmp_pm_clock_getstate(u32 clock_id, u32 *state)
387{
388 u32 ret_payload[PAYLOAD_ARG_CNT];
389 int ret;
390
391 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, clock_id, 0,
392 0, 0, ret_payload);
393 *state = ret_payload[1];
394
395 return ret;
396}
397EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getstate);
398
399/**
400 * zynqmp_pm_clock_setdivider() - Set the clock divider for given id
401 * @clock_id: ID of the clock
402 * @divider: divider value
403 *
404 * This function is used by master to set divider for any clock
405 * to achieve desired rate.
406 *
407 * Return: Returns status, either success or error+reason
408 */
409int zynqmp_pm_clock_setdivider(u32 clock_id, u32 divider)
410{
411 return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, clock_id, divider,
412 0, 0, NULL);
413}
414EXPORT_SYMBOL_GPL(zynqmp_pm_clock_setdivider);
415
416/**
417 * zynqmp_pm_clock_getdivider() - Get the clock divider for given id
418 * @clock_id: ID of the clock
419 * @divider: divider value
420 *
421 * This function is used by master to get divider values
422 * for any clock.
423 *
424 * Return: Returns status, either success or error+reason
425 */
426int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider)
427{
428 u32 ret_payload[PAYLOAD_ARG_CNT];
429 int ret;
430
431 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, clock_id, 0,
432 0, 0, ret_payload);
433 *divider = ret_payload[1];
434
435 return ret;
436}
437EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getdivider);
438
439/**
440 * zynqmp_pm_clock_setrate() - Set the clock rate for given id
441 * @clock_id: ID of the clock
442 * @rate: rate value in hz
443 *
444 * This function is used by master to set rate for any clock.
445 *
446 * Return: Returns status, either success or error+reason
447 */
448int zynqmp_pm_clock_setrate(u32 clock_id, u64 rate)
449{
450 return zynqmp_pm_invoke_fn(PM_CLOCK_SETRATE, clock_id,
451 lower_32_bits(rate),
452 upper_32_bits(rate),
453 0, NULL);
454}
455EXPORT_SYMBOL_GPL(zynqmp_pm_clock_setrate);
456
457/**
458 * zynqmp_pm_clock_getrate() - Get the clock rate for given id
459 * @clock_id: ID of the clock
460 * @rate: rate value in hz
461 *
462 * This function is used by master to get rate
463 * for any clock.
464 *
465 * Return: Returns status, either success or error+reason
466 */
467int zynqmp_pm_clock_getrate(u32 clock_id, u64 *rate)
468{
469 u32 ret_payload[PAYLOAD_ARG_CNT];
470 int ret;
471
472 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETRATE, clock_id, 0,
473 0, 0, ret_payload);
474 *rate = ((u64)ret_payload[2] << 32) | ret_payload[1];
475
476 return ret;
477}
478EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getrate);
479
480/**
481 * zynqmp_pm_clock_setparent() - Set the clock parent for given id
482 * @clock_id: ID of the clock
483 * @parent_id: parent id
484 *
485 * This function is used by master to set parent for any clock.
486 *
487 * Return: Returns status, either success or error+reason
488 */
489int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id)
490{
491 return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, clock_id,
492 parent_id, 0, 0, NULL);
493}
494EXPORT_SYMBOL_GPL(zynqmp_pm_clock_setparent);
495
496/**
497 * zynqmp_pm_clock_getparent() - Get the clock parent for given id
498 * @clock_id: ID of the clock
499 * @parent_id: parent id
500 *
501 * This function is used by master to get parent index
502 * for any clock.
503 *
504 * Return: Returns status, either success or error+reason
505 */
506int zynqmp_pm_clock_getparent(u32 clock_id, u32 *parent_id)
507{
508 u32 ret_payload[PAYLOAD_ARG_CNT];
509 int ret;
510
511 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, clock_id, 0,
512 0, 0, ret_payload);
513 *parent_id = ret_payload[1];
514
515 return ret;
516}
517EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getparent);
518
519/**
520 * zynqmp_pm_set_pll_frac_mode() - PM API for set PLL mode
521 *
522 * @clk_id: PLL clock ID
523 * @mode: PLL mode (PLL_MODE_FRAC/PLL_MODE_INT)
524 *
525 * This function sets PLL mode
526 *
527 * Return: Returns status, either success or error+reason
528 */
529int zynqmp_pm_set_pll_frac_mode(u32 clk_id, u32 mode)
530{
531 return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_PLL_FRAC_MODE,
532 clk_id, mode, NULL);
533}
534EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_mode);
535
536/**
537 * zynqmp_pm_get_pll_frac_mode() - PM API for get PLL mode
538 *
539 * @clk_id: PLL clock ID
540 * @mode: PLL mode
541 *
542 * This function return current PLL mode
543 *
544 * Return: Returns status, either success or error+reason
545 */
546int zynqmp_pm_get_pll_frac_mode(u32 clk_id, u32 *mode)
547{
548 return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_MODE,
549 clk_id, 0, mode);
550}
551EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_mode);
552
553/**
554 * zynqmp_pm_set_pll_frac_data() - PM API for setting pll fraction data
555 *
556 * @clk_id: PLL clock ID
557 * @data: fraction data
558 *
559 * This function sets fraction data.
560 * It is valid for fraction mode only.
561 *
562 * Return: Returns status, either success or error+reason
563 */
564int zynqmp_pm_set_pll_frac_data(u32 clk_id, u32 data)
565{
566 return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_PLL_FRAC_DATA,
567 clk_id, data, NULL);
568}
569EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_data);
570
571/**
572 * zynqmp_pm_get_pll_frac_data() - PM API for getting pll fraction data
573 *
574 * @clk_id: PLL clock ID
575 * @data: fraction data
576 *
577 * This function returns fraction data value.
578 *
579 * Return: Returns status, either success or error+reason
580 */
581int zynqmp_pm_get_pll_frac_data(u32 clk_id, u32 *data)
582{
583 return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_DATA,
584 clk_id, 0, data);
585}
586EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_data);
587
588/**
589 * zynqmp_pm_set_sd_tapdelay() - Set tap delay for the SD device
590 *
591 * @node_id Node ID of the device
592 * @type Type of tap delay to set (input/output)
593 * @value Value to set fot the tap delay
594 *
595 * This function sets input/output tap delay for the SD device.
596 *
597 * @return Returns status, either success or error+reason
598 */
599int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value)
600{
601 return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, IOCTL_SET_SD_TAPDELAY,
602 type, value, NULL);
603}
604EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay);
605
606/**
607 * zynqmp_pm_sd_dll_reset() - Reset DLL logic
608 *
609 * @node_id Node ID of the device
610 * @type Reset type
611 *
612 * This function resets DLL logic for the SD device.
613 *
614 * @return Returns status, either success or error+reason
615 */
616int zynqmp_pm_sd_dll_reset(u32 node_id, u32 type)
617{
618 return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, IOCTL_SET_SD_TAPDELAY,
619 type, 0, NULL);
620}
621EXPORT_SYMBOL_GPL(zynqmp_pm_sd_dll_reset);
622
623/**
624 * zynqmp_pm_write_ggs() - PM API for writing global general storage (ggs)
625 * @index GGS register index
626 * @value Register value to be written
627 *
628 * This function writes value to GGS register.
629 *
630 * @return Returns status, either success or error+reason
631 */
632int zynqmp_pm_write_ggs(u32 index, u32 value)
633{
634 return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_GGS,
635 index, value, NULL);
636}
637EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs);
638
639/**
640 * zynqmp_pm_write_ggs() - PM API for reading global general storage (ggs)
641 * @index GGS register index
642 * @value Register value to be written
643 *
644 * This function returns GGS register value.
645 *
646 * @return Returns status, either success or error+reason
647 */
648int zynqmp_pm_read_ggs(u32 index, u32 *value)
649{
650 return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_GGS,
651 index, 0, value);
652}
653EXPORT_SYMBOL_GPL(zynqmp_pm_read_ggs);
654
655/**
656 * zynqmp_pm_write_pggs() - PM API for writing persistent global general
657 * storage (pggs)
658 * @index PGGS register index
659 * @value Register value to be written
660 *
661 * This function writes value to PGGS register.
662 *
663 * @return Returns status, either success or error+reason
664 */
665int zynqmp_pm_write_pggs(u32 index, u32 value)
666{
667 return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_PGGS, index, value,
668 NULL);
669}
670EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs);
671
672/**
673 * zynqmp_pm_write_pggs() - PM API for reading persistent global general
674 * storage (pggs)
675 * @index PGGS register index
676 * @value Register value to be written
677 *
678 * This function returns PGGS register value.
679 *
680 * @return Returns status, either success or error+reason
681 */
682int zynqmp_pm_read_pggs(u32 index, u32 *value)
683{
684 return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_PGGS, index, 0,
685 value);
686}
687EXPORT_SYMBOL_GPL(zynqmp_pm_read_pggs);
688
689/**
690 * zynqmp_pm_set_boot_health_status() - PM API for setting healthy boot status
691 * @value Status value to be written
692 *
693 * This function sets healthy bit value to indicate boot health status
694 * to firmware.
695 *
696 * @return Returns status, either success or error+reason
697 */
698int zynqmp_pm_set_boot_health_status(u32 value)
699{
700 return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_BOOT_HEALTH_STATUS,
701 value, 0, NULL);
702}
703
704/**
705 * zynqmp_pm_reset_assert - Request setting of reset (1 - assert, 0 - release)
706 * @reset: Reset to be configured
707 * @assert_flag: Flag stating should reset be asserted (1) or
708 * released (0)
709 *
710 * Return: Returns status, either success or error+reason
711 */
712int zynqmp_pm_reset_assert(const enum zynqmp_pm_reset reset,
713 const enum zynqmp_pm_reset_action assert_flag)
714{
715 return zynqmp_pm_invoke_fn(PM_RESET_ASSERT, reset, assert_flag,
716 0, 0, NULL);
717}
718EXPORT_SYMBOL_GPL(zynqmp_pm_reset_assert);
719
720/**
721 * zynqmp_pm_reset_get_status - Get status of the reset
722 * @reset: Reset whose status should be returned
723 * @status: Returned status
724 *
725 * Return: Returns status, either success or error+reason
726 */
727int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset, u32 *status)
728{
729 u32 ret_payload[PAYLOAD_ARG_CNT];
730 int ret;
731
732 if (!status)
733 return -EINVAL;
734
735 ret = zynqmp_pm_invoke_fn(PM_RESET_GET_STATUS, reset, 0,
736 0, 0, ret_payload);
737 *status = ret_payload[1];
738
739 return ret;
740}
741EXPORT_SYMBOL_GPL(zynqmp_pm_reset_get_status);
742
743/**
744 * zynqmp_pm_fpga_load - Perform the fpga load
745 * @address: Address to write to
746 * @size: pl bitstream size
747 * @flags: Bitstream type
748 * -XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration
749 * -XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration
750 *
751 * This function provides access to pmufw. To transfer
752 * the required bitstream into PL.
753 *
754 * Return: Returns status, either success or error+reason
755 */
756int zynqmp_pm_fpga_load(const u64 address, const u32 size, const u32 flags)
757{
758 return zynqmp_pm_invoke_fn(PM_FPGA_LOAD, lower_32_bits(address),
759 upper_32_bits(address), size, flags, NULL);
760}
761EXPORT_SYMBOL_GPL(zynqmp_pm_fpga_load);
762
763/**
764 * zynqmp_pm_fpga_get_status - Read value from PCAP status register
765 * @value: Value to read
766 *
767 * This function provides access to the pmufw to get the PCAP
768 * status
769 *
770 * Return: Returns status, either success or error+reason
771 */
772int zynqmp_pm_fpga_get_status(u32 *value)
773{
774 u32 ret_payload[PAYLOAD_ARG_CNT];
775 int ret;
776
777 if (!value)
778 return -EINVAL;
779
780 ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload);
781 *value = ret_payload[1];
782
783 return ret;
784}
785EXPORT_SYMBOL_GPL(zynqmp_pm_fpga_get_status);
786
787/**
788 * zynqmp_pm_init_finalize() - PM call to inform firmware that the caller
789 * master has initialized its own power management
790 *
791 * This API function is to be used for notify the power management controller
792 * about the completed power management initialization.
793 *
794 * Return: Returns status, either success or error+reason
795 */
796int zynqmp_pm_init_finalize(void)
797{
798 return zynqmp_pm_invoke_fn(PM_PM_INIT_FINALIZE, 0, 0, 0, 0, NULL);
799}
800EXPORT_SYMBOL_GPL(zynqmp_pm_init_finalize);
801
802/**
803 * zynqmp_pm_set_suspend_mode() - Set system suspend mode
804 * @mode: Mode to set for system suspend
805 *
806 * This API function is used to set mode of system suspend.
807 *
808 * Return: Returns status, either success or error+reason
809 */
810int zynqmp_pm_set_suspend_mode(u32 mode)
811{
812 return zynqmp_pm_invoke_fn(PM_SET_SUSPEND_MODE, mode, 0, 0, 0, NULL);
813}
814EXPORT_SYMBOL_GPL(zynqmp_pm_set_suspend_mode);
815
816/**
817 * zynqmp_pm_request_node() - Request a node with specific capabilities
818 * @node: Node ID of the slave
819 * @capabilities: Requested capabilities of the slave
820 * @qos: Quality of service (not supported)
821 * @ack: Flag to specify whether acknowledge is requested
822 *
823 * This function is used by master to request particular node from firmware.
824 * Every master must request node before using it.
825 *
826 * Return: Returns status, either success or error+reason
827 */
828int zynqmp_pm_request_node(const u32 node, const u32 capabilities,
829 const u32 qos, const enum zynqmp_pm_request_ack ack)
830{
831 return zynqmp_pm_invoke_fn(PM_REQUEST_NODE, node, capabilities,
832 qos, ack, NULL);
833}
834EXPORT_SYMBOL_GPL(zynqmp_pm_request_node);
835
836/**
837 * zynqmp_pm_release_node() - Release a node
838 * @node: Node ID of the slave
839 *
840 * This function is used by master to inform firmware that master
841 * has released node. Once released, master must not use that node
842 * without re-request.
843 *
844 * Return: Returns status, either success or error+reason
845 */
846int zynqmp_pm_release_node(const u32 node)
847{
848 return zynqmp_pm_invoke_fn(PM_RELEASE_NODE, node, 0, 0, 0, NULL);
849}
850EXPORT_SYMBOL_GPL(zynqmp_pm_release_node);
851
852/**
853 * zynqmp_pm_set_requirement() - PM call to set requirement for PM slaves
854 * @node: Node ID of the slave
855 * @capabilities: Requested capabilities of the slave
856 * @qos: Quality of service (not supported)
857 * @ack: Flag to specify whether acknowledge is requested
858 *
859 * This API function is to be used for slaves a PU already has requested
860 * to change its capabilities.
861 *
862 * Return: Returns status, either success or error+reason
863 */
864int zynqmp_pm_set_requirement(const u32 node, const u32 capabilities,
865 const u32 qos,
866 const enum zynqmp_pm_request_ack ack)
867{
868 return zynqmp_pm_invoke_fn(PM_SET_REQUIREMENT, node, capabilities,
869 qos, ack, NULL);
870}
871EXPORT_SYMBOL_GPL(zynqmp_pm_set_requirement);
872
873/**
874 * zynqmp_pm_aes - Access AES hardware to encrypt/decrypt the data using
875 * AES-GCM core.
876 * @address: Address of the AesParams structure.
877 * @out: Returned output value
878 *
879 * Return: Returns status, either success or error code.
880 */
881int zynqmp_pm_aes_engine(const u64 address, u32 *out)
882{
883 u32 ret_payload[PAYLOAD_ARG_CNT];
884 int ret;
885
886 if (!out)
887 return -EINVAL;
888
889 ret = zynqmp_pm_invoke_fn(PM_SECURE_AES, upper_32_bits(address),
890 lower_32_bits(address),
891 0, 0, ret_payload);
892 *out = ret_payload[1];
893
894 return ret;
895}
896EXPORT_SYMBOL_GPL(zynqmp_pm_aes_engine);
897
898/**
899 * zynqmp_pm_system_shutdown - PM call to request a system shutdown or restart
900 * @type: Shutdown or restart? 0 for shutdown, 1 for restart
901 * @subtype: Specifies which system should be restarted or shut down
902 *
903 * Return: Returns status, either success or error+reason
904 */
905int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype)
906{
907 return zynqmp_pm_invoke_fn(PM_SYSTEM_SHUTDOWN, type, subtype,
908 0, 0, NULL);
909}
910
911/**
912 * struct zynqmp_pm_shutdown_scope - Struct for shutdown scope
913 * @subtype: Shutdown subtype
914 * @name: Matching string for scope argument
915 *
916 * This struct encapsulates mapping between shutdown scope ID and string.
917 */
918struct zynqmp_pm_shutdown_scope {
919 const enum zynqmp_pm_shutdown_subtype subtype;
920 const char *name;
921};
922
923static struct zynqmp_pm_shutdown_scope shutdown_scopes[] = {
924 [ZYNQMP_PM_SHUTDOWN_SUBTYPE_SUBSYSTEM] = {
925 .subtype = ZYNQMP_PM_SHUTDOWN_SUBTYPE_SUBSYSTEM,
926 .name = "subsystem",
927 },
928 [ZYNQMP_PM_SHUTDOWN_SUBTYPE_PS_ONLY] = {
929 .subtype = ZYNQMP_PM_SHUTDOWN_SUBTYPE_PS_ONLY,
930 .name = "ps_only",
931 },
932 [ZYNQMP_PM_SHUTDOWN_SUBTYPE_SYSTEM] = {
933 .subtype = ZYNQMP_PM_SHUTDOWN_SUBTYPE_SYSTEM,
934 .name = "system",
935 },
936};
937
938static struct zynqmp_pm_shutdown_scope *selected_scope =
939 &shutdown_scopes[ZYNQMP_PM_SHUTDOWN_SUBTYPE_SYSTEM];
940
941/**
942 * zynqmp_pm_is_shutdown_scope_valid - Check if shutdown scope string is valid
943 * @scope_string: Shutdown scope string
944 *
945 * Return: Return pointer to matching shutdown scope struct from
946 * array of available options in system if string is valid,
947 * otherwise returns NULL.
948 */
949static struct zynqmp_pm_shutdown_scope*
950 zynqmp_pm_is_shutdown_scope_valid(const char *scope_string)
951{
952 int count;
953
954 for (count = 0; count < ARRAY_SIZE(shutdown_scopes); count++)
955 if (sysfs_streq(scope_string, shutdown_scopes[count].name))
956 return &shutdown_scopes[count];
957
958 return NULL;
959}
960
961static ssize_t shutdown_scope_show(struct device *device,
962 struct device_attribute *attr,
963 char *buf)
964{
965 int i;
966
967 for (i = 0; i < ARRAY_SIZE(shutdown_scopes); i++) {
968 if (&shutdown_scopes[i] == selected_scope) {
969 strcat(buf, "[");
970 strcat(buf, shutdown_scopes[i].name);
971 strcat(buf, "]");
972 } else {
973 strcat(buf, shutdown_scopes[i].name);
974 }
975 strcat(buf, " ");
976 }
977 strcat(buf, "\n");
978
979 return strlen(buf);
980}
981
982static ssize_t shutdown_scope_store(struct device *device,
983 struct device_attribute *attr,
984 const char *buf, size_t count)
985{
986 int ret;
987 struct zynqmp_pm_shutdown_scope *scope;
988
989 scope = zynqmp_pm_is_shutdown_scope_valid(buf);
990 if (!scope)
991 return -EINVAL;
992
993 ret = zynqmp_pm_system_shutdown(ZYNQMP_PM_SHUTDOWN_TYPE_SETSCOPE_ONLY,
994 scope->subtype);
995 if (ret) {
996 pr_err("unable to set shutdown scope %s\n", buf);
997 return ret;
998 }
999
1000 selected_scope = scope;
1001
1002 return count;
1003}
1004
1005static DEVICE_ATTR_RW(shutdown_scope);
1006
1007static ssize_t health_status_store(struct device *device,
1008 struct device_attribute *attr,
1009 const char *buf, size_t count)
1010{
1011 int ret;
1012 unsigned int value;
1013
1014 ret = kstrtouint(buf, 10, &value);
1015 if (ret)
1016 return ret;
1017
1018 ret = zynqmp_pm_set_boot_health_status(value);
1019 if (ret) {
1020 dev_err(device, "unable to set healthy bit value to %u\n",
1021 value);
1022 return ret;
1023 }
1024
1025 return count;
1026}
1027
1028static DEVICE_ATTR_WO(health_status);
1029
1030static ssize_t ggs_show(struct device *device,
1031 struct device_attribute *attr,
1032 char *buf,
1033 u32 reg)
1034{
1035 int ret;
1036 u32 ret_payload[PAYLOAD_ARG_CNT];
1037
1038 ret = zynqmp_pm_read_ggs(reg, ret_payload);
1039 if (ret)
1040 return ret;
1041
1042 return sprintf(buf, "0x%x\n", ret_payload[1]);
1043}
1044
1045static ssize_t ggs_store(struct device *device,
1046 struct device_attribute *attr,
1047 const char *buf, size_t count,
1048 u32 reg)
1049{
1050 long value;
1051 int ret;
1052
1053 if (reg >= GSS_NUM_REGS)
1054 return -EINVAL;
1055
1056 ret = kstrtol(buf, 16, &value);
1057 if (ret) {
1058 count = -EFAULT;
1059 goto err;
1060 }
1061
1062 ret = zynqmp_pm_write_ggs(reg, value);
1063 if (ret)
1064 count = -EFAULT;
1065err:
1066 return count;
1067}
1068
1069/* GGS register show functions */
1070#define GGS0_SHOW(N) \
1071 ssize_t ggs##N##_show(struct device *device, \
1072 struct device_attribute *attr, \
1073 char *buf) \
1074 { \
1075 return ggs_show(device, attr, buf, N); \
1076 }
1077
1078static GGS0_SHOW(0);
1079static GGS0_SHOW(1);
1080static GGS0_SHOW(2);
1081static GGS0_SHOW(3);
1082
1083/* GGS register store function */
1084#define GGS0_STORE(N) \
1085 ssize_t ggs##N##_store(struct device *device, \
1086 struct device_attribute *attr, \
1087 const char *buf, \
1088 size_t count) \
1089 { \
1090 return ggs_store(device, attr, buf, count, N); \
1091 }
1092
1093static GGS0_STORE(0);
1094static GGS0_STORE(1);
1095static GGS0_STORE(2);
1096static GGS0_STORE(3);
1097
1098static ssize_t pggs_show(struct device *device,
1099 struct device_attribute *attr,
1100 char *buf,
1101 u32 reg)
1102{
1103 int ret;
1104 u32 ret_payload[PAYLOAD_ARG_CNT];
1105
1106 ret = zynqmp_pm_read_pggs(reg, ret_payload);
1107 if (ret)
1108 return ret;
1109
1110 return sprintf(buf, "0x%x\n", ret_payload[1]);
1111}
1112
1113static ssize_t pggs_store(struct device *device,
1114 struct device_attribute *attr,
1115 const char *buf, size_t count,
1116 u32 reg)
1117{
1118 long value;
1119 int ret;
1120
1121 if (reg >= GSS_NUM_REGS)
1122 return -EINVAL;
1123
1124 ret = kstrtol(buf, 16, &value);
1125 if (ret) {
1126 count = -EFAULT;
1127 goto err;
1128 }
1129
1130 ret = zynqmp_pm_write_pggs(reg, value);
1131 if (ret)
1132 count = -EFAULT;
1133
1134err:
1135 return count;
1136}
1137
1138#define PGGS0_SHOW(N) \
1139 ssize_t pggs##N##_show(struct device *device, \
1140 struct device_attribute *attr, \
1141 char *buf) \
1142 { \
1143 return pggs_show(device, attr, buf, N); \
1144 }
1145
1146#define PGGS0_STORE(N) \
1147 ssize_t pggs##N##_store(struct device *device, \
1148 struct device_attribute *attr, \
1149 const char *buf, \
1150 size_t count) \
1151 { \
1152 return pggs_store(device, attr, buf, count, N); \
1153 }
1154
1155/* PGGS register show functions */
1156static PGGS0_SHOW(0);
1157static PGGS0_SHOW(1);
1158static PGGS0_SHOW(2);
1159static PGGS0_SHOW(3);
1160
1161/* PGGS register store functions */
1162static PGGS0_STORE(0);
1163static PGGS0_STORE(1);
1164static PGGS0_STORE(2);
1165static PGGS0_STORE(3);
1166
1167/* GGS register attributes */
1168static DEVICE_ATTR_RW(ggs0);
1169static DEVICE_ATTR_RW(ggs1);
1170static DEVICE_ATTR_RW(ggs2);
1171static DEVICE_ATTR_RW(ggs3);
1172
1173/* PGGS register attributes */
1174static DEVICE_ATTR_RW(pggs0);
1175static DEVICE_ATTR_RW(pggs1);
1176static DEVICE_ATTR_RW(pggs2);
1177static DEVICE_ATTR_RW(pggs3);
1178
1179static struct attribute *zynqmp_firmware_attrs[] = {
1180 &dev_attr_ggs0.attr,
1181 &dev_attr_ggs1.attr,
1182 &dev_attr_ggs2.attr,
1183 &dev_attr_ggs3.attr,
1184 &dev_attr_pggs0.attr,
1185 &dev_attr_pggs1.attr,
1186 &dev_attr_pggs2.attr,
1187 &dev_attr_pggs3.attr,
1188 &dev_attr_shutdown_scope.attr,
1189 &dev_attr_health_status.attr,
1190 NULL,
1191};
1192
1193ATTRIBUTE_GROUPS(zynqmp_firmware);
1194
1195static int zynqmp_firmware_probe(struct platform_device *pdev)
1196{
1197 struct device *dev = &pdev->dev;
1198 struct device_node *np;
1199 int ret;
1200
1201 np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp");
1202 if (!np) {
1203 np = of_find_compatible_node(NULL, NULL, "xlnx,versal");
1204 if (!np)
1205 return 0;
1206
1207 feature_check_enabled = true;
1208 }
1209 of_node_put(np);
1210
1211 ret = get_set_conduit_method(dev->of_node);
1212 if (ret)
1213 return ret;
1214
1215 /* Check PM API version number */
1216 zynqmp_pm_get_api_version(&pm_api_version);
1217 if (pm_api_version < ZYNQMP_PM_VERSION) {
1218 panic("%s Platform Management API version error. Expected: v%d.%d - Found: v%d.%d\n",
1219 __func__,
1220 ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR,
1221 pm_api_version >> 16, pm_api_version & 0xFFFF);
1222 }
1223
1224 pr_info("%s Platform Management API v%d.%d\n", __func__,
1225 pm_api_version >> 16, pm_api_version & 0xFFFF);
1226
1227 /* Check trustzone version number */
1228 ret = zynqmp_pm_get_trustzone_version(&pm_tz_version);
1229 if (ret)
1230 panic("Legacy trustzone found without version support\n");
1231
1232 if (pm_tz_version < ZYNQMP_TZ_VERSION)
1233 panic("%s Trustzone version error. Expected: v%d.%d - Found: v%d.%d\n",
1234 __func__,
1235 ZYNQMP_TZ_VERSION_MAJOR, ZYNQMP_TZ_VERSION_MINOR,
1236 pm_tz_version >> 16, pm_tz_version & 0xFFFF);
1237
1238 pr_info("%s Trustzone version v%d.%d\n", __func__,
1239 pm_tz_version >> 16, pm_tz_version & 0xFFFF);
1240
1241 ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, firmware_devs,
1242 ARRAY_SIZE(firmware_devs), NULL, 0, NULL);
1243 if (ret) {
1244 dev_err(&pdev->dev, "failed to add MFD devices %d\n", ret);
1245 return ret;
1246 }
1247
1248 zynqmp_pm_api_debugfs_init();
1249
1250 return of_platform_populate(dev->of_node, NULL, NULL, dev);
1251}
1252
1253static int zynqmp_firmware_remove(struct platform_device *pdev)
1254{
1255 mfd_remove_devices(&pdev->dev);
1256 zynqmp_pm_api_debugfs_exit();
1257
1258 return 0;
1259}
1260
1261static const struct of_device_id zynqmp_firmware_of_match[] = {
1262 {.compatible = "xlnx,zynqmp-firmware"},
1263 {.compatible = "xlnx,versal-firmware"},
1264 {},
1265};
1266MODULE_DEVICE_TABLE(of, zynqmp_firmware_of_match);
1267
1268static struct platform_driver zynqmp_firmware_driver = {
1269 .driver = {
1270 .name = "zynqmp_firmware",
1271 .of_match_table = zynqmp_firmware_of_match,
1272 .dev_groups = zynqmp_firmware_groups,
1273 },
1274 .probe = zynqmp_firmware_probe,
1275 .remove = zynqmp_firmware_remove,
1276};
1277module_platform_driver(zynqmp_firmware_driver);