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