1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Texas Instruments K3 SA2UL Driver
4 *
5 * Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
6 * Andrew Davis <afd@ti.com>
7 */
8
9 #include <drivers/ti_sci.h>
10 #include <initcall.h>
11 #include <io.h>
12 #include <keep.h>
13 #include <kernel/interrupt.h>
14 #include <kernel/misc.h>
15 #include <kernel/spinlock.h>
16 #include <mm/core_memprot.h>
17 #include <mm/core_mmu.h>
18 #include <platform_config.h>
19 #include <rng_support.h>
20
21 #include "sa2ul.h"
22
23 #define SA2UL_ES 0x0008
24 #define SA2UL_ES_TRNG BIT(3)
25 #define SA2UL_EEC 0x1000
26 #define SA2UL_EEC_TRNG BIT(3)
27
28 #define FW_ENABLE_REGION 0x0a
29 #define FW_BACKGROUND_REGION BIT(8)
30 #define FW_BIG_ARM_PRIVID 0x01
31 #define FW_WILDCARD_PRIVID 0xc3
32 #define FW_SECURE_ONLY GENMASK_32(8, 0)
33 #define FW_NON_SECURE GENMASK_32(16, 0)
34
35 register_phys_mem_pgdir(MEM_AREA_IO_SEC, SA2UL_BASE, SA2UL_REG_SIZE);
36
sa2ul_init(void)37 static TEE_Result sa2ul_init(void)
38 {
39 vaddr_t sa2ul = (vaddr_t)phys_to_virt(SA2UL_BASE, MEM_AREA_IO_SEC,
40 RNG_REG_SIZE);
41 uint16_t fwl_id = SA2UL_TI_SCI_FW_ID;
42 uint16_t sa2ul_region = SA2UL_TI_SCI_FW_RGN_ID;
43 uint16_t rng_region = RNG_TI_SCI_FW_RGN_ID;
44 uint8_t owner_index = OPTEE_HOST_ID;
45 uint8_t owner_privid = 0;
46 uint16_t owner_permission_bits = 0;
47 uint32_t control = 0;
48 uint32_t permissions[FWL_MAX_PRIVID_SLOTS] = { };
49 uint64_t start_address = 0;
50 uint64_t end_address = 0;
51 uint32_t val = 0;
52 TEE_Result result = TEE_SUCCESS;
53 int ret = 0;
54
55 if (SA2UL_TI_SCI_DEV_ID != -1) {
56 /* Power on the SA2UL device */
57 ret = ti_sci_device_get(SA2UL_TI_SCI_DEV_ID);
58 if (ret) {
59 EMSG("Failed to get SA2UL device");
60 return TEE_ERROR_GENERIC;
61 }
62 }
63
64 IMSG("Activated SA2UL device");
65
66 /* Try to claim the SA2UL firewall for ourselves */
67 ret = ti_sci_change_fwl_owner(fwl_id, sa2ul_region, owner_index,
68 &owner_privid, &owner_permission_bits);
69 if (ret) {
70 /*
71 * This is not fatal, it just means we are on an HS device
72 * where the DMSC already owns the SA2UL. On GP we need
73 * to do additional setup for access permissions below.
74 */
75 DMSG("Could not change SA2UL firewall owner");
76 } else {
77 IMSG("Fixing SA2UL firewall owner for GP device");
78
79 /* Get current SA2UL firewall configuration */
80 ret = ti_sci_get_fwl_region(fwl_id, sa2ul_region, 1,
81 &control, permissions,
82 &start_address, &end_address);
83 if (ret) {
84 EMSG("Could not get firewall region information");
85 return TEE_ERROR_GENERIC;
86 }
87
88 /* Modify SA2UL firewall to allow all others access*/
89 control = FW_BACKGROUND_REGION | FW_ENABLE_REGION;
90 permissions[0] = (FW_WILDCARD_PRIVID << 16) | FW_NON_SECURE;
91 ret = ti_sci_set_fwl_region(fwl_id, sa2ul_region, 1,
92 control, permissions,
93 0x0, UINT32_MAX);
94 if (ret) {
95 EMSG("Could not set firewall region information");
96 return TEE_ERROR_GENERIC;
97 }
98 }
99
100 /* Claim the TRNG firewall for ourselves */
101 ret = ti_sci_change_fwl_owner(fwl_id, rng_region, owner_index,
102 &owner_privid, &owner_permission_bits);
103 if (ret) {
104 EMSG("Could not change TRNG firewall owner");
105 return TEE_ERROR_GENERIC;
106 }
107
108 /* Get current TRNG firewall configuration */
109 ret = ti_sci_get_fwl_region(fwl_id, rng_region, 1,
110 &control, permissions,
111 &start_address, &end_address);
112 if (ret) {
113 EMSG("Could not get firewall region information");
114 return TEE_ERROR_GENERIC;
115 }
116
117 /* Modify TRNG firewall to block all others access */
118 control = FW_ENABLE_REGION;
119 permissions[0] = (FW_BIG_ARM_PRIVID << 16) | FW_SECURE_ONLY;
120 start_address = RNG_BASE;
121 end_address = RNG_BASE + RNG_REG_SIZE - 1;
122 ret = ti_sci_set_fwl_region(fwl_id, rng_region, 1,
123 control, permissions,
124 start_address, end_address);
125 if (ret) {
126 EMSG("Could not set firewall region information");
127 return TEE_ERROR_GENERIC;
128 }
129
130 IMSG("Enabled firewalls for SA2UL TRNG device");
131
132 /* Enable RNG engine in SA2UL if not already enabled */
133 val = io_read32(sa2ul + SA2UL_ES);
134 if (!(val & SA2UL_ES_TRNG)) {
135 IMSG("Enabling SA2UL TRNG engine");
136 io_setbits32(sa2ul + SA2UL_EEC, SA2UL_EEC_TRNG);
137 }
138
139 /* Initialize the RNG Module */
140 result = sa2ul_rng_init();
141 if (result != TEE_SUCCESS)
142 return result;
143
144 IMSG("SA2UL Drivers initialized");
145
146 return TEE_SUCCESS;
147 }
148 driver_init(sa2ul_init);
149