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