1573a3811SMasahiro Yamada /* 2573a3811SMasahiro Yamada * Copyright (C) 2017 Masahiro Yamada <yamada.masahiro@socionext.com> 3573a3811SMasahiro Yamada * 4573a3811SMasahiro Yamada * Based on drivers/firmware/psci.c from Linux: 5573a3811SMasahiro Yamada * Copyright (C) 2015 ARM Limited 6573a3811SMasahiro Yamada * 7573a3811SMasahiro Yamada * SPDX-License-Identifier: GPL-2.0+ 8573a3811SMasahiro Yamada */ 9573a3811SMasahiro Yamada 10573a3811SMasahiro Yamada #include <common.h> 119d922450SSimon Glass #include <dm.h> 12573a3811SMasahiro Yamada #include <dm/lists.h> 13573a3811SMasahiro Yamada #include <libfdt.h> 14573a3811SMasahiro Yamada #include <linux/arm-smccc.h> 15573a3811SMasahiro Yamada #include <linux/errno.h> 16573a3811SMasahiro Yamada #include <linux/psci.h> 17573a3811SMasahiro Yamada 18573a3811SMasahiro Yamada psci_fn *invoke_psci_fn; 19573a3811SMasahiro Yamada 20573a3811SMasahiro Yamada static unsigned long __invoke_psci_fn_hvc(unsigned long function_id, 21573a3811SMasahiro Yamada unsigned long arg0, unsigned long arg1, 22573a3811SMasahiro Yamada unsigned long arg2) 23573a3811SMasahiro Yamada { 24573a3811SMasahiro Yamada struct arm_smccc_res res; 25573a3811SMasahiro Yamada 26573a3811SMasahiro Yamada arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); 27573a3811SMasahiro Yamada return res.a0; 28573a3811SMasahiro Yamada } 29573a3811SMasahiro Yamada 30573a3811SMasahiro Yamada static unsigned long __invoke_psci_fn_smc(unsigned long function_id, 31573a3811SMasahiro Yamada unsigned long arg0, unsigned long arg1, 32573a3811SMasahiro Yamada unsigned long arg2) 33573a3811SMasahiro Yamada { 34573a3811SMasahiro Yamada struct arm_smccc_res res; 35573a3811SMasahiro Yamada 36573a3811SMasahiro Yamada arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); 37573a3811SMasahiro Yamada return res.a0; 38573a3811SMasahiro Yamada } 39573a3811SMasahiro Yamada 40573a3811SMasahiro Yamada static int psci_bind(struct udevice *dev) 41573a3811SMasahiro Yamada { 42573a3811SMasahiro Yamada /* No SYSTEM_RESET support for PSCI 0.1 */ 43911f3aefSSimon Glass if (device_is_compatible(dev, "arm,psci-0.2") || 44911f3aefSSimon Glass device_is_compatible(dev, "arm,psci-1.0")) { 45573a3811SMasahiro Yamada int ret; 46573a3811SMasahiro Yamada 47573a3811SMasahiro Yamada /* bind psci-sysreset optionally */ 48573a3811SMasahiro Yamada ret = device_bind_driver(dev, "psci-sysreset", "psci-sysreset", 49573a3811SMasahiro Yamada NULL); 50573a3811SMasahiro Yamada if (ret) 51573a3811SMasahiro Yamada debug("PSCI System Reset was not bound.\n"); 52573a3811SMasahiro Yamada } 53573a3811SMasahiro Yamada 54573a3811SMasahiro Yamada return 0; 55573a3811SMasahiro Yamada } 56573a3811SMasahiro Yamada 57573a3811SMasahiro Yamada static int psci_probe(struct udevice *dev) 58573a3811SMasahiro Yamada { 59573a3811SMasahiro Yamada const char *method; 60573a3811SMasahiro Yamada 61*7a484f5fSJoseph Chen method = dev_read_prop(dev, "method", NULL); 62573a3811SMasahiro Yamada if (!method) { 63573a3811SMasahiro Yamada printf("missing \"method\" property\n"); 64573a3811SMasahiro Yamada return -ENXIO; 65573a3811SMasahiro Yamada } 66573a3811SMasahiro Yamada 67573a3811SMasahiro Yamada if (!strcmp("hvc", method)) { 68573a3811SMasahiro Yamada invoke_psci_fn = __invoke_psci_fn_hvc; 69573a3811SMasahiro Yamada } else if (!strcmp("smc", method)) { 70573a3811SMasahiro Yamada invoke_psci_fn = __invoke_psci_fn_smc; 71573a3811SMasahiro Yamada } else { 72573a3811SMasahiro Yamada printf("invalid \"method\" property: %s\n", method); 73573a3811SMasahiro Yamada return -EINVAL; 74573a3811SMasahiro Yamada } 75573a3811SMasahiro Yamada 76573a3811SMasahiro Yamada return 0; 77573a3811SMasahiro Yamada } 78573a3811SMasahiro Yamada 79573a3811SMasahiro Yamada static const struct udevice_id psci_of_match[] = { 80573a3811SMasahiro Yamada { .compatible = "arm,psci" }, 81573a3811SMasahiro Yamada { .compatible = "arm,psci-0.2" }, 82573a3811SMasahiro Yamada { .compatible = "arm,psci-1.0" }, 83573a3811SMasahiro Yamada {}, 84573a3811SMasahiro Yamada }; 85573a3811SMasahiro Yamada 86573a3811SMasahiro Yamada U_BOOT_DRIVER(psci) = { 87573a3811SMasahiro Yamada .name = "psci", 88573a3811SMasahiro Yamada .id = UCLASS_FIRMWARE, 89573a3811SMasahiro Yamada .of_match = psci_of_match, 90573a3811SMasahiro Yamada .bind = psci_bind, 91573a3811SMasahiro Yamada .probe = psci_probe, 92573a3811SMasahiro Yamada }; 93