1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2020 Arm Limited |
4 | */ |
5 | |
6 | #define pr_fmt(fmt) "smccc: " fmt |
7 | |
8 | #include <linux/cache.h> |
9 | #include <linux/init.h> |
10 | #include <linux/arm-smccc.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/platform_device.h> |
13 | #include <asm/archrandom.h> |
14 | |
15 | static u32 smccc_version = ARM_SMCCC_VERSION_1_0; |
16 | static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE; |
17 | |
18 | bool __ro_after_init smccc_trng_available = false; |
19 | u64 __ro_after_init smccc_has_sve_hint = false; |
20 | s32 __ro_after_init smccc_soc_id_version = SMCCC_RET_NOT_SUPPORTED; |
21 | s32 __ro_after_init smccc_soc_id_revision = SMCCC_RET_NOT_SUPPORTED; |
22 | |
23 | void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit) |
24 | { |
25 | struct arm_smccc_res res; |
26 | |
27 | smccc_version = version; |
28 | smccc_conduit = conduit; |
29 | |
30 | smccc_trng_available = smccc_probe_trng(); |
31 | if (IS_ENABLED(CONFIG_ARM64_SVE) && |
32 | smccc_version >= ARM_SMCCC_VERSION_1_3) |
33 | smccc_has_sve_hint = true; |
34 | |
35 | if ((smccc_version >= ARM_SMCCC_VERSION_1_2) && |
36 | (smccc_conduit != SMCCC_CONDUIT_NONE)) { |
37 | arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, |
38 | ARM_SMCCC_ARCH_SOC_ID, &res); |
39 | if ((s32)res.a0 >= 0) { |
40 | arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 0, &res); |
41 | smccc_soc_id_version = (s32)res.a0; |
42 | arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 1, &res); |
43 | smccc_soc_id_revision = (s32)res.a0; |
44 | } |
45 | } |
46 | } |
47 | |
48 | enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void) |
49 | { |
50 | if (smccc_version < ARM_SMCCC_VERSION_1_1) |
51 | return SMCCC_CONDUIT_NONE; |
52 | |
53 | return smccc_conduit; |
54 | } |
55 | EXPORT_SYMBOL_GPL(arm_smccc_1_1_get_conduit); |
56 | |
57 | u32 arm_smccc_get_version(void) |
58 | { |
59 | return smccc_version; |
60 | } |
61 | EXPORT_SYMBOL_GPL(arm_smccc_get_version); |
62 | |
63 | s32 arm_smccc_get_soc_id_version(void) |
64 | { |
65 | return smccc_soc_id_version; |
66 | } |
67 | |
68 | s32 arm_smccc_get_soc_id_revision(void) |
69 | { |
70 | return smccc_soc_id_revision; |
71 | } |
72 | |
73 | static int __init smccc_devices_init(void) |
74 | { |
75 | struct platform_device *pdev; |
76 | |
77 | if (smccc_trng_available) { |
78 | pdev = platform_device_register_simple(name: "smccc_trng" , id: -1, |
79 | NULL, num: 0); |
80 | if (IS_ERR(ptr: pdev)) |
81 | pr_err("smccc_trng: could not register device: %ld\n" , |
82 | PTR_ERR(pdev)); |
83 | } |
84 | |
85 | return 0; |
86 | } |
87 | device_initcall(smccc_devices_init); |
88 | |