Skip to content

Commit 8bfd4aa

Browse files
committed
plat-rockchip: rk3588: add OTP_S support and HUK
Add OTP_S support for Rockchip rk3588 Add tee_otp_get_hw_unique_key() Signed-off-by: Ed Tubbs <ectubbs@gmail.com> Acked-by: Etienne Carriere <etienne.carriere@foss.st.com>
1 parent 854b7c3 commit 8bfd4aa

File tree

2 files changed

+236
-0
lines changed

2 files changed

+236
-0
lines changed

core/arch/arm/plat-rockchip/platform_config.h

+3
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@
115115
#define TRNG_S_BASE 0xfe398000
116116
#define TRNG_S_SIZE SIZE_K(32)
117117

118+
#define OTP_S_BASE 0xfe3a0000
119+
#define OTP_S_SIZE SIZE_K(64)
120+
118121
#else
119122
#error "Unknown platform flavor"
120123
#endif

core/arch/arm/plat-rockchip/platform_rk3588.c

+233
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88
#include <io.h>
99
#include <kernel/panic.h>
1010
#include <kernel/mutex.h>
11+
#include <kernel/tee_common_otp.h>
1112
#include <mm/core_memprot.h>
1213
#include <platform.h>
1314
#include <platform_config.h>
1415
#include <rng_support.h>
1516
#include <string.h>
17+
#include <string_ext.h>
18+
#include <utee_defines.h>
1619

1720
#define FIREWALL_DDR_RGN(i) ((i) * 0x4)
1821
#define FIREWALL_DDR_CON 0xf0
@@ -46,11 +49,40 @@
4649
#define TRNG_POLL_PERIOD_US 0
4750
#define TRNG_POLL_TIMEOUT_US 1000
4851

52+
#define OTP_S_AUTO_CTRL 0x0004
53+
#define OTP_S_AUTO_EN 0x0008
54+
#define OTP_S_PROG_DATA 0x0010
55+
#define OTP_S_DOUT 0x0020
56+
#define OTP_S_INT_ST 0x0084
57+
58+
#define ADDR_SHIFT 16
59+
#define BURST_SHIFT 8
60+
#define CMD_READ 0
61+
#define CMD_WRITE 2
62+
#define EN_ENABLE 1
63+
#define EN_DISABLE 0
64+
65+
#define MAX_INDEX 0x300
66+
#define BURST_SIZE 8
67+
#define OTP_WORD 1
68+
69+
#define OTP_S_ERROR_BIT BIT32(4)
70+
#define OTP_S_WR_DONE_BIT BIT32(3)
71+
#define OTP_S_VERIFY_BIT BIT32(2)
72+
#define OTP_S_RD_DONE_BIT BIT32(1)
73+
74+
#define OTP_POLL_PERIOD_US 0
75+
#define OTP_POLL_TIMEOUT_US 1000
76+
77+
#define HW_UNIQUE_KEY_INDEX 0x104
78+
4979
register_phys_mem_pgdir(MEM_AREA_IO_SEC, FIREWALL_DDR_BASE, FIREWALL_DDR_SIZE);
5080
register_phys_mem_pgdir(MEM_AREA_IO_SEC, FIREWALL_DSU_BASE, FIREWALL_DSU_SIZE);
5181
register_phys_mem_pgdir(MEM_AREA_IO_SEC, TRNG_S_BASE, TRNG_S_SIZE);
82+
register_phys_mem_pgdir(MEM_AREA_IO_SEC, OTP_S_BASE, OTP_S_SIZE);
5283

5384
static struct mutex trng_mutex = MUTEX_INITIALIZER;
85+
static struct mutex huk_mutex = MUTEX_INITIALIZER;
5486

5587
int platform_secure_ddr_region(int rgn, paddr_t st, size_t sz)
5688
{
@@ -160,3 +192,204 @@ TEE_Result hw_get_random_bytes(void *buf, size_t blen)
160192

161193
return TEE_SUCCESS;
162194
}
195+
196+
static TEE_Result tee_otp_read_secure(uint32_t *value, uint32_t index,
197+
uint32_t count)
198+
{
199+
vaddr_t base = (vaddr_t)phys_to_virt(OTP_S_BASE, MEM_AREA_IO_SEC,
200+
OTP_S_SIZE);
201+
uint32_t int_status = 0;
202+
uint32_t i = 0;
203+
uint32_t val = 0;
204+
uint32_t auto_ctrl_val = 0;
205+
TEE_Result res = TEE_SUCCESS;
206+
207+
if (!base)
208+
panic("OTP_S base not mapped");
209+
210+
/* Check for invalid parameters or exceeding hardware burst limit */
211+
if (!value || !count || count > BURST_SIZE ||
212+
(index + count > MAX_INDEX))
213+
return TEE_ERROR_BAD_PARAMETERS;
214+
215+
/* Setup read: index, count, command = READ */
216+
auto_ctrl_val = SHIFT_U32(index, ADDR_SHIFT) |
217+
SHIFT_U32(count, BURST_SHIFT) |
218+
CMD_READ;
219+
220+
/* Clear any pending interrupts by reading & writing back INT_ST */
221+
io_write32(base + OTP_S_INT_ST, io_read32(base + OTP_S_INT_ST));
222+
223+
/* Set read command */
224+
io_write32(base + OTP_S_AUTO_CTRL, auto_ctrl_val);
225+
226+
/* Enable read */
227+
io_write32(base + OTP_S_AUTO_EN, EN_ENABLE);
228+
229+
/* Wait for RD_DONE or ERROR bits */
230+
res = IO_READ32_POLL_TIMEOUT(base + OTP_S_INT_ST,
231+
int_status,
232+
(int_status & OTP_S_RD_DONE_BIT) ||
233+
(int_status & OTP_S_ERROR_BIT),
234+
OTP_POLL_PERIOD_US,
235+
OTP_POLL_TIMEOUT_US);
236+
237+
/* Clear the interrupt again */
238+
io_write32(base + OTP_S_INT_ST, io_read32(base + OTP_S_INT_ST));
239+
240+
if (int_status & OTP_S_ERROR_BIT) {
241+
EMSG("OTP_S Error");
242+
return TEE_ERROR_GENERIC;
243+
}
244+
if (res) {
245+
EMSG("OTP_S Timeout");
246+
return TEE_ERROR_BUSY;
247+
}
248+
249+
/* Read out the data */
250+
for (i = 0; i < count; i++) {
251+
val = io_read32(base + OTP_S_DOUT +
252+
(i * sizeof(uint32_t)));
253+
value[i] = val;
254+
}
255+
256+
return TEE_SUCCESS;
257+
}
258+
259+
static TEE_Result tee_otp_write_secure(const uint32_t *value, uint32_t index,
260+
uint32_t count)
261+
{
262+
vaddr_t base = (vaddr_t)phys_to_virt(OTP_S_BASE, MEM_AREA_IO_SEC,
263+
OTP_S_SIZE);
264+
uint32_t int_status = 0;
265+
uint32_t i = 0;
266+
267+
if (!base)
268+
panic("OTP_S base not mapped");
269+
270+
/* Check for invalid parameters or exceeding hardware limits */
271+
if (!value || !count || count > BURST_SIZE ||
272+
(index + count > MAX_INDEX))
273+
return TEE_ERROR_BAD_PARAMETERS;
274+
275+
/* Program OTP words */
276+
for (i = 0; i < count; i++) {
277+
uint32_t old_val = 0;
278+
uint32_t new_val = 0;
279+
uint32_t curr_idx = index + i;
280+
TEE_Result res = TEE_SUCCESS;
281+
282+
/* Setup write: curr_idx, command = WRITE */
283+
uint32_t auto_ctrl_val = SHIFT_U32(curr_idx, ADDR_SHIFT) |
284+
CMD_WRITE;
285+
286+
/* Read existing OTP word to see which bits can be set */
287+
res = tee_otp_read_secure(&old_val, curr_idx, OTP_WORD);
288+
if (res != TEE_SUCCESS)
289+
return res;
290+
291+
/* Check if bits in value conflict with old_val */
292+
if (~*value & old_val) {
293+
EMSG("OTP_S Program fail");
294+
return TEE_ERROR_GENERIC;
295+
}
296+
297+
/* Only program bits that are currently 0 (0->1) */
298+
new_val = *value & ~old_val;
299+
value++;
300+
if (!new_val)
301+
continue;
302+
303+
/* Clear any pending interrupts */
304+
io_write32(base + OTP_S_INT_ST, io_read32(base + OTP_S_INT_ST));
305+
306+
/* Set write command */
307+
io_write32(base + OTP_S_AUTO_CTRL, auto_ctrl_val);
308+
309+
/* Write the new bits into PROG_DATA register */
310+
io_write32(base + OTP_S_PROG_DATA, new_val);
311+
312+
/* Enable the write */
313+
io_write32(base + OTP_S_AUTO_EN, EN_ENABLE);
314+
315+
/* Poll for WR_DONE or verify/error bits */
316+
res = IO_READ32_POLL_TIMEOUT(base + OTP_S_INT_ST,
317+
int_status,
318+
(int_status & OTP_S_WR_DONE_BIT) ||
319+
(int_status & OTP_S_VERIFY_BIT) ||
320+
(int_status & OTP_S_ERROR_BIT),
321+
OTP_POLL_PERIOD_US,
322+
OTP_POLL_TIMEOUT_US);
323+
324+
/* Clear INT status bits */
325+
io_write32(base + OTP_S_INT_ST, int_status);
326+
327+
/* Check for VERIFY_FAIL, ERROR or timeout */
328+
if (int_status & OTP_S_VERIFY_BIT) {
329+
EMSG("OTP_S Verification fail");
330+
return TEE_ERROR_GENERIC;
331+
}
332+
if (int_status & OTP_S_ERROR_BIT) {
333+
EMSG("OTP_S Error");
334+
return TEE_ERROR_GENERIC;
335+
}
336+
if (res) {
337+
EMSG("OTP_S Timeout");
338+
return TEE_ERROR_BUSY;
339+
}
340+
}
341+
342+
return TEE_SUCCESS;
343+
}
344+
345+
TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey)
346+
{
347+
TEE_Result res = TEE_SUCCESS;
348+
uint32_t buffer[HW_UNIQUE_KEY_LENGTH / sizeof(uint32_t)] = { };
349+
bool key_is_empty = true;
350+
size_t i = 0;
351+
352+
if (!hwkey)
353+
return TEE_ERROR_BAD_PARAMETERS;
354+
355+
mutex_lock(&huk_mutex);
356+
357+
/* Read 4 words (16 bytes) from OTP at HW_UNIQUE_KEY_INDEX */
358+
res = tee_otp_read_secure(buffer,
359+
HW_UNIQUE_KEY_INDEX,
360+
HW_UNIQUE_KEY_LENGTH / sizeof(uint32_t));
361+
if (res)
362+
goto out;
363+
364+
/* Check if the buffer is all zero => HUK not present */
365+
for (i = 0; i < ARRAY_SIZE(buffer); i++) {
366+
if (buffer[i] != 0)
367+
key_is_empty = false;
368+
}
369+
370+
if (key_is_empty) {
371+
/* Generate random 128-bit key from TRNG */
372+
res = hw_get_random_bytes(buffer, sizeof(buffer));
373+
if (res)
374+
goto out;
375+
376+
/* Write the new HUK into OTP at HW_UNIQUE_KEY_INDEX */
377+
res = tee_otp_write_secure(buffer,
378+
HW_UNIQUE_KEY_INDEX,
379+
HW_UNIQUE_KEY_LENGTH /
380+
sizeof(uint32_t));
381+
if (res)
382+
goto out;
383+
}
384+
385+
/* Copy HUK into hwkey->data */
386+
memcpy(hwkey->data, buffer, HW_UNIQUE_KEY_LENGTH);
387+
388+
out:
389+
/* Clear buffer memory */
390+
memzero_explicit(buffer, sizeof(buffer));
391+
392+
mutex_unlock(&huk_mutex);
393+
394+
return res;
395+
}

0 commit comments

Comments
 (0)