Masahiro Yamada | 573a381 | 2017-04-14 11:10:24 +0900 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 Masahiro Yamada <yamada.masahiro@socionext.com> |
| 3 | * |
| 4 | * Based on drivers/firmware/psci.c from Linux: |
| 5 | * Copyright (C) 2015 ARM Limited |
| 6 | * |
| 7 | * SPDX-License-Identifier: GPL-2.0+ |
| 8 | */ |
| 9 | |
| 10 | #include <common.h> |
Simon Glass | 9d92245 | 2017-05-17 17:18:03 -0600 | [diff] [blame] | 11 | #include <dm.h> |
Masahiro Yamada | 573a381 | 2017-04-14 11:10:24 +0900 | [diff] [blame] | 12 | #include <dm/lists.h> |
Masahiro Yamada | b08c8c4 | 2018-03-05 01:20:11 +0900 | [diff] [blame] | 13 | #include <linux/libfdt.h> |
Masahiro Yamada | 573a381 | 2017-04-14 11:10:24 +0900 | [diff] [blame] | 14 | #include <linux/arm-smccc.h> |
| 15 | #include <linux/errno.h> |
Masahiro Yamada | af4e6d3 | 2017-11-29 15:04:40 +0900 | [diff] [blame] | 16 | #include <linux/printk.h> |
Masahiro Yamada | 573a381 | 2017-04-14 11:10:24 +0900 | [diff] [blame] | 17 | #include <linux/psci.h> |
| 18 | |
| 19 | psci_fn *invoke_psci_fn; |
| 20 | |
| 21 | static unsigned long __invoke_psci_fn_hvc(unsigned long function_id, |
| 22 | unsigned long arg0, unsigned long arg1, |
| 23 | unsigned long arg2) |
| 24 | { |
| 25 | struct arm_smccc_res res; |
| 26 | |
| 27 | arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); |
| 28 | return res.a0; |
| 29 | } |
| 30 | |
| 31 | static unsigned long __invoke_psci_fn_smc(unsigned long function_id, |
| 32 | unsigned long arg0, unsigned long arg1, |
| 33 | unsigned long arg2) |
| 34 | { |
| 35 | struct arm_smccc_res res; |
| 36 | |
| 37 | arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); |
| 38 | return res.a0; |
| 39 | } |
| 40 | |
| 41 | static int psci_bind(struct udevice *dev) |
| 42 | { |
| 43 | /* No SYSTEM_RESET support for PSCI 0.1 */ |
Simon Glass | 911f3ae | 2017-05-18 20:08:57 -0600 | [diff] [blame] | 44 | if (device_is_compatible(dev, "arm,psci-0.2") || |
| 45 | device_is_compatible(dev, "arm,psci-1.0")) { |
Masahiro Yamada | 573a381 | 2017-04-14 11:10:24 +0900 | [diff] [blame] | 46 | int ret; |
| 47 | |
| 48 | /* bind psci-sysreset optionally */ |
| 49 | ret = device_bind_driver(dev, "psci-sysreset", "psci-sysreset", |
| 50 | NULL); |
| 51 | if (ret) |
Masahiro Yamada | af4e6d3 | 2017-11-29 15:04:40 +0900 | [diff] [blame] | 52 | pr_debug("PSCI System Reset was not bound.\n"); |
Masahiro Yamada | 573a381 | 2017-04-14 11:10:24 +0900 | [diff] [blame] | 53 | } |
| 54 | |
| 55 | return 0; |
| 56 | } |
| 57 | |
| 58 | static int psci_probe(struct udevice *dev) |
| 59 | { |
| 60 | DECLARE_GLOBAL_DATA_PTR; |
| 61 | const char *method; |
| 62 | |
Simon Glass | da409cc | 2017-05-17 17:18:09 -0600 | [diff] [blame] | 63 | method = fdt_stringlist_get(gd->fdt_blob, dev_of_offset(dev), "method", |
| 64 | 0, NULL); |
Masahiro Yamada | 573a381 | 2017-04-14 11:10:24 +0900 | [diff] [blame] | 65 | if (!method) { |
Masahiro Yamada | af4e6d3 | 2017-11-29 15:04:40 +0900 | [diff] [blame] | 66 | pr_warn("missing \"method\" property\n"); |
Masahiro Yamada | 573a381 | 2017-04-14 11:10:24 +0900 | [diff] [blame] | 67 | return -ENXIO; |
| 68 | } |
| 69 | |
| 70 | if (!strcmp("hvc", method)) { |
| 71 | invoke_psci_fn = __invoke_psci_fn_hvc; |
| 72 | } else if (!strcmp("smc", method)) { |
| 73 | invoke_psci_fn = __invoke_psci_fn_smc; |
| 74 | } else { |
Masahiro Yamada | af4e6d3 | 2017-11-29 15:04:40 +0900 | [diff] [blame] | 75 | pr_warn("invalid \"method\" property: %s\n", method); |
Masahiro Yamada | 573a381 | 2017-04-14 11:10:24 +0900 | [diff] [blame] | 76 | return -EINVAL; |
| 77 | } |
| 78 | |
| 79 | return 0; |
| 80 | } |
| 81 | |
| 82 | static const struct udevice_id psci_of_match[] = { |
| 83 | { .compatible = "arm,psci" }, |
| 84 | { .compatible = "arm,psci-0.2" }, |
| 85 | { .compatible = "arm,psci-1.0" }, |
| 86 | {}, |
| 87 | }; |
| 88 | |
| 89 | U_BOOT_DRIVER(psci) = { |
| 90 | .name = "psci", |
| 91 | .id = UCLASS_FIRMWARE, |
| 92 | .of_match = psci_of_match, |
| 93 | .bind = psci_bind, |
| 94 | .probe = psci_probe, |
| 95 | }; |