xref: /optee_os/core/arch/arm/plat-k3/drivers/sa2ul.c (revision 2f4d97e7664270c92f4fd9d35fcddcfa4fd5f667)
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 
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 	/* Power on the SA2UL device */
56 	ret = ti_sci_device_get(SA2UL_TI_SCI_DEV_ID);
57 	if (ret) {
58 		EMSG("Failed to get SA2UL device");
59 		return TEE_ERROR_GENERIC;
60 	}
61 
62 	IMSG("Activated SA2UL device");
63 
64 	/* Try to claim the SA2UL firewall for ourselves */
65 	ret = ti_sci_change_fwl_owner(fwl_id, sa2ul_region, owner_index,
66 				      &owner_privid, &owner_permission_bits);
67 	if (ret) {
68 		/*
69 		 * This is not fatal, it just means we are on an HS device
70 		 * where the DMSC already owns the SA2UL. On GP we need
71 		 * to do additional setup for access permissions below.
72 		 */
73 		DMSG("Could not change SA2UL firewall owner");
74 	} else {
75 		IMSG("Fixing SA2UL firewall owner for GP device");
76 
77 		/* Get current SA2UL firewall configuration */
78 		ret = ti_sci_get_fwl_region(fwl_id, sa2ul_region, 1,
79 					    &control, permissions,
80 					    &start_address, &end_address);
81 		if (ret) {
82 			EMSG("Could not get firewall region information");
83 			return TEE_ERROR_GENERIC;
84 		}
85 
86 		/* Modify SA2UL firewall to allow all others access*/
87 		control = FW_BACKGROUND_REGION | FW_ENABLE_REGION;
88 		permissions[0] = (FW_WILDCARD_PRIVID << 16) | FW_NON_SECURE;
89 		ret = ti_sci_set_fwl_region(fwl_id, sa2ul_region, 1,
90 					    control, permissions,
91 					    0x0, UINT32_MAX);
92 		if (ret) {
93 			EMSG("Could not set firewall region information");
94 			return TEE_ERROR_GENERIC;
95 		}
96 	}
97 
98 	/* Claim the TRNG firewall for ourselves */
99 	ret = ti_sci_change_fwl_owner(fwl_id, rng_region, owner_index,
100 				      &owner_privid, &owner_permission_bits);
101 	if (ret) {
102 		EMSG("Could not change TRNG firewall owner");
103 		return TEE_ERROR_GENERIC;
104 	}
105 
106 	/* Get current TRNG firewall configuration */
107 	ret = ti_sci_get_fwl_region(fwl_id, rng_region, 1,
108 				    &control, permissions,
109 				    &start_address, &end_address);
110 	if (ret) {
111 		EMSG("Could not get firewall region information");
112 		return TEE_ERROR_GENERIC;
113 	}
114 
115 	/* Modify TRNG firewall to block all others access */
116 	control = FW_ENABLE_REGION;
117 	permissions[0] = (FW_BIG_ARM_PRIVID << 16) | FW_SECURE_ONLY;
118 	start_address = RNG_BASE;
119 	end_address = RNG_BASE + RNG_REG_SIZE - 1;
120 	ret = ti_sci_set_fwl_region(fwl_id, rng_region, 1,
121 				    control, permissions,
122 				    start_address, end_address);
123 	if (ret) {
124 		EMSG("Could not set firewall region information");
125 		return TEE_ERROR_GENERIC;
126 	}
127 
128 	IMSG("Enabled firewalls for SA2UL TRNG device");
129 
130 	/* Enable RNG engine in SA2UL if not already enabled */
131 	val = io_read32(sa2ul + SA2UL_ES);
132 	if (!(val & SA2UL_ES_TRNG)) {
133 		IMSG("Enabling SA2UL TRNG engine");
134 		io_setbits32(sa2ul + SA2UL_EEC, SA2UL_EEC_TRNG);
135 	}
136 
137 	/* Initialize the RNG Module */
138 	result = sa2ul_rng_init();
139 	if (result != TEE_SUCCESS)
140 		return result;
141 
142 	IMSG("SA2UL Drivers initialized");
143 
144 	return TEE_SUCCESS;
145 }
146 driver_init(sa2ul_init);
147