1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2021 Foundries.io Ltd.
4  *
5  * Jorge Ramirez-Ortiz <jorge@foundries.io>
6  */
7 #include <drivers/zynqmp_csu.h>
8 #include <drivers/zynqmp_csu_aes.h>
9 #include <drivers/zynqmp_csu_puf.h>
10 #include <initcall.h>
11 #include <io.h>
12 #include <kernel/delay.h>
13 #include <mm/core_memprot.h>
14 
15 #define PUF_CMD_OFFSET			0x00
16 #define PUF_CFG0_OFFSET			0x04
17 #define PUF_CFG1_OFFSET			0x08
18 #define PUF_SHUT_OFFSET			0x0C
19 #define PUF_STATUS_OFFSET		0x10
20 #define PUF_WORD_OFFSET			0x18
21 
22 #define PUF_REGENERATION		4
23 #define PUF_RESET			6
24 
25 #define PUF_CFG0_DEFAULT		0x02
26 #define PUF_SHUT_DEFAULT		0x01000100
27 #define PUF_REGEN_TIME_MS		3
28 
zynqmp_csu_puf_regenerate(void)29 TEE_Result zynqmp_csu_puf_regenerate(void)
30 {
31 	vaddr_t puf = core_mmu_get_va(ZYNQMP_CSU_PUF_BASE, MEM_AREA_IO_SEC,
32 				      ZYNQMP_CSU_PUF_SIZE);
33 	vaddr_t csu = core_mmu_get_va(CSU_BASE, MEM_AREA_IO_SEC, CSU_SIZE);
34 	uint32_t status = 0;
35 
36 	if (!puf || !csu)
37 		return TEE_ERROR_GENERIC;
38 
39 	io_write32(puf + PUF_CFG0_OFFSET, PUF_CFG0_DEFAULT);
40 	io_write32(puf + PUF_SHUT_OFFSET, PUF_SHUT_DEFAULT);
41 	io_write32(puf + PUF_CMD_OFFSET, PUF_REGENERATION);
42 	mdelay(PUF_REGEN_TIME_MS);
43 
44 	status = io_read32(csu + ZYNQMP_CSU_ISR_OFFSET);
45 	if (status & ZYNQMP_CSU_ISR_PUF_ACC_ERROR_MASK) {
46 		EMSG("regeneration failed");
47 		return TEE_ERROR_GENERIC;
48 	}
49 
50 	return TEE_SUCCESS;
51 }
52 
zynqmp_csu_puf_reset(void)53 void zynqmp_csu_puf_reset(void)
54 {
55 	vaddr_t puf = core_mmu_get_va(ZYNQMP_CSU_PUF_BASE, MEM_AREA_IO_SEC,
56 				      ZYNQMP_CSU_PUF_SIZE);
57 
58 	io_write32(puf + PUF_CMD_OFFSET, PUF_RESET);
59 }
60 
zynqmp_csu_puf_init(void)61 static TEE_Result zynqmp_csu_puf_init(void)
62 {
63 	vaddr_t csu = core_mmu_get_va(CSU_BASE, MEM_AREA_IO_SEC, CSU_SIZE);
64 	uint32_t status = 0;
65 
66 	/* if the bootloader has been authenticated, reserve the PUF */
67 	status = io_read32(csu + ZYNQMP_CSU_STATUS_OFFSET);
68 	if (status & ZYNQMP_CSU_STATUS_AUTH)
69 		return zynqmp_csu_aes_dt_enable_secure_status();
70 
71 	return TEE_SUCCESS;
72 }
73 
74 driver_init(zynqmp_csu_puf_init);
75