1*d2c909e8SMichael Tretter // SPDX-License-Identifier: BSD-3-Clause
2*d2c909e8SMichael Tretter /*
3*d2c909e8SMichael Tretter * Copyright (C) 2019, Theobroma Systems Design und Consulting GmbH
4*d2c909e8SMichael Tretter * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
5*d2c909e8SMichael Tretter * Copyright (C) 2025, Pengutronix, Michael Tretter <m.tretter@pengutronix.de>
6*d2c909e8SMichael Tretter */
7*d2c909e8SMichael Tretter
8*d2c909e8SMichael Tretter #include <common.h>
9*d2c909e8SMichael Tretter #include <drivers/rockchip_otp.h>
10*d2c909e8SMichael Tretter #include <io.h>
11*d2c909e8SMichael Tretter #include <kernel/panic.h>
12*d2c909e8SMichael Tretter #include <kernel/tee_common_otp.h>
13*d2c909e8SMichael Tretter #include <mm/core_memprot.h>
14*d2c909e8SMichael Tretter #include <utee_defines.h>
15*d2c909e8SMichael Tretter
16*d2c909e8SMichael Tretter #define OTP_S_AUTO_CTRL 0x0004
17*d2c909e8SMichael Tretter #define OTP_S_AUTO_EN 0x0008
18*d2c909e8SMichael Tretter #define OTP_S_PROG_DATA 0x0010
19*d2c909e8SMichael Tretter #define OTP_S_DOUT 0x0020
20*d2c909e8SMichael Tretter #define OTP_S_INT_ST 0x0084
21*d2c909e8SMichael Tretter
22*d2c909e8SMichael Tretter #define ADDR_SHIFT 16
23*d2c909e8SMichael Tretter #define BURST_SHIFT 8
24*d2c909e8SMichael Tretter #define CMD_READ 0
25*d2c909e8SMichael Tretter #define CMD_WRITE 2
26*d2c909e8SMichael Tretter #define EN_ENABLE 1
27*d2c909e8SMichael Tretter #define EN_DISABLE 0
28*d2c909e8SMichael Tretter
29*d2c909e8SMichael Tretter #define MAX_INDEX 0x300
30*d2c909e8SMichael Tretter #define BURST_SIZE 8
31*d2c909e8SMichael Tretter #define OTP_WORD 1
32*d2c909e8SMichael Tretter
33*d2c909e8SMichael Tretter #define OTP_S_ERROR_BIT BIT32(4)
34*d2c909e8SMichael Tretter #define OTP_S_WR_DONE_BIT BIT32(3)
35*d2c909e8SMichael Tretter #define OTP_S_VERIFY_BIT BIT32(2)
36*d2c909e8SMichael Tretter #define OTP_S_RD_DONE_BIT BIT32(1)
37*d2c909e8SMichael Tretter
38*d2c909e8SMichael Tretter #define OTP_POLL_PERIOD_US 0
39*d2c909e8SMichael Tretter #define OTP_POLL_TIMEOUT_US 1000
40*d2c909e8SMichael Tretter
41*d2c909e8SMichael Tretter register_phys_mem_pgdir(MEM_AREA_IO_SEC, OTP_S_BASE, OTP_S_SIZE);
42*d2c909e8SMichael Tretter
rockchip_otp_read_secure(uint32_t * value,uint32_t index,uint32_t count)43*d2c909e8SMichael Tretter TEE_Result rockchip_otp_read_secure(uint32_t *value, uint32_t index,
44*d2c909e8SMichael Tretter uint32_t count)
45*d2c909e8SMichael Tretter {
46*d2c909e8SMichael Tretter vaddr_t base = (vaddr_t)phys_to_virt(OTP_S_BASE, MEM_AREA_IO_SEC,
47*d2c909e8SMichael Tretter OTP_S_SIZE);
48*d2c909e8SMichael Tretter uint32_t int_status = 0;
49*d2c909e8SMichael Tretter uint32_t i = 0;
50*d2c909e8SMichael Tretter uint32_t val = 0;
51*d2c909e8SMichael Tretter uint32_t auto_ctrl_val = 0;
52*d2c909e8SMichael Tretter TEE_Result res = TEE_SUCCESS;
53*d2c909e8SMichael Tretter
54*d2c909e8SMichael Tretter if (!base)
55*d2c909e8SMichael Tretter panic("OTP_S base not mapped");
56*d2c909e8SMichael Tretter
57*d2c909e8SMichael Tretter /* Check for invalid parameters or exceeding hardware burst limit */
58*d2c909e8SMichael Tretter if (!value || !count || count > BURST_SIZE ||
59*d2c909e8SMichael Tretter (index + count > MAX_INDEX))
60*d2c909e8SMichael Tretter return TEE_ERROR_BAD_PARAMETERS;
61*d2c909e8SMichael Tretter
62*d2c909e8SMichael Tretter /* Setup read: index, count, command = READ */
63*d2c909e8SMichael Tretter auto_ctrl_val = SHIFT_U32(index, ADDR_SHIFT) |
64*d2c909e8SMichael Tretter SHIFT_U32(count, BURST_SHIFT) |
65*d2c909e8SMichael Tretter CMD_READ;
66*d2c909e8SMichael Tretter
67*d2c909e8SMichael Tretter /* Clear any pending interrupts by reading & writing back INT_ST */
68*d2c909e8SMichael Tretter io_write32(base + OTP_S_INT_ST, io_read32(base + OTP_S_INT_ST));
69*d2c909e8SMichael Tretter
70*d2c909e8SMichael Tretter /* Set read command */
71*d2c909e8SMichael Tretter io_write32(base + OTP_S_AUTO_CTRL, auto_ctrl_val);
72*d2c909e8SMichael Tretter
73*d2c909e8SMichael Tretter /* Enable read */
74*d2c909e8SMichael Tretter io_write32(base + OTP_S_AUTO_EN, EN_ENABLE);
75*d2c909e8SMichael Tretter
76*d2c909e8SMichael Tretter /* Wait for RD_DONE or ERROR bits */
77*d2c909e8SMichael Tretter res = IO_READ32_POLL_TIMEOUT(base + OTP_S_INT_ST,
78*d2c909e8SMichael Tretter int_status,
79*d2c909e8SMichael Tretter (int_status & OTP_S_RD_DONE_BIT) ||
80*d2c909e8SMichael Tretter (int_status & OTP_S_ERROR_BIT),
81*d2c909e8SMichael Tretter OTP_POLL_PERIOD_US,
82*d2c909e8SMichael Tretter OTP_POLL_TIMEOUT_US);
83*d2c909e8SMichael Tretter
84*d2c909e8SMichael Tretter /* Clear the interrupt again */
85*d2c909e8SMichael Tretter io_write32(base + OTP_S_INT_ST, io_read32(base + OTP_S_INT_ST));
86*d2c909e8SMichael Tretter
87*d2c909e8SMichael Tretter if (int_status & OTP_S_ERROR_BIT) {
88*d2c909e8SMichael Tretter EMSG("OTP_S Error");
89*d2c909e8SMichael Tretter return TEE_ERROR_GENERIC;
90*d2c909e8SMichael Tretter }
91*d2c909e8SMichael Tretter if (res) {
92*d2c909e8SMichael Tretter EMSG("OTP_S Timeout");
93*d2c909e8SMichael Tretter return TEE_ERROR_BUSY;
94*d2c909e8SMichael Tretter }
95*d2c909e8SMichael Tretter
96*d2c909e8SMichael Tretter /* Read out the data */
97*d2c909e8SMichael Tretter for (i = 0; i < count; i++) {
98*d2c909e8SMichael Tretter val = io_read32(base + OTP_S_DOUT +
99*d2c909e8SMichael Tretter (i * sizeof(uint32_t)));
100*d2c909e8SMichael Tretter value[i] = val;
101*d2c909e8SMichael Tretter }
102*d2c909e8SMichael Tretter
103*d2c909e8SMichael Tretter return TEE_SUCCESS;
104*d2c909e8SMichael Tretter }
105*d2c909e8SMichael Tretter
rockchip_otp_write_secure(const uint32_t * value,uint32_t index,uint32_t count)106*d2c909e8SMichael Tretter TEE_Result rockchip_otp_write_secure(const uint32_t *value, uint32_t index,
107*d2c909e8SMichael Tretter uint32_t count)
108*d2c909e8SMichael Tretter {
109*d2c909e8SMichael Tretter vaddr_t base = (vaddr_t)phys_to_virt(OTP_S_BASE, MEM_AREA_IO_SEC,
110*d2c909e8SMichael Tretter OTP_S_SIZE);
111*d2c909e8SMichael Tretter uint32_t int_status = 0;
112*d2c909e8SMichael Tretter uint32_t i = 0;
113*d2c909e8SMichael Tretter
114*d2c909e8SMichael Tretter if (!base)
115*d2c909e8SMichael Tretter panic("OTP_S base not mapped");
116*d2c909e8SMichael Tretter
117*d2c909e8SMichael Tretter /* Check for invalid parameters or exceeding hardware limits */
118*d2c909e8SMichael Tretter if (!value || !count || count > BURST_SIZE ||
119*d2c909e8SMichael Tretter (index + count > MAX_INDEX))
120*d2c909e8SMichael Tretter return TEE_ERROR_BAD_PARAMETERS;
121*d2c909e8SMichael Tretter
122*d2c909e8SMichael Tretter /* Program OTP words */
123*d2c909e8SMichael Tretter for (i = 0; i < count; i++) {
124*d2c909e8SMichael Tretter uint32_t old_val = 0;
125*d2c909e8SMichael Tretter uint32_t new_val = 0;
126*d2c909e8SMichael Tretter uint32_t curr_idx = index + i;
127*d2c909e8SMichael Tretter TEE_Result res = TEE_SUCCESS;
128*d2c909e8SMichael Tretter
129*d2c909e8SMichael Tretter /* Setup write: curr_idx, command = WRITE */
130*d2c909e8SMichael Tretter uint32_t auto_ctrl_val = SHIFT_U32(curr_idx, ADDR_SHIFT) |
131*d2c909e8SMichael Tretter CMD_WRITE;
132*d2c909e8SMichael Tretter
133*d2c909e8SMichael Tretter /* Read existing OTP word to see which bits can be set */
134*d2c909e8SMichael Tretter res = rockchip_otp_read_secure(&old_val, curr_idx, OTP_WORD);
135*d2c909e8SMichael Tretter if (res != TEE_SUCCESS)
136*d2c909e8SMichael Tretter return res;
137*d2c909e8SMichael Tretter
138*d2c909e8SMichael Tretter /* Check if bits in value conflict with old_val */
139*d2c909e8SMichael Tretter if (~*value & old_val) {
140*d2c909e8SMichael Tretter EMSG("OTP_S Program fail");
141*d2c909e8SMichael Tretter return TEE_ERROR_GENERIC;
142*d2c909e8SMichael Tretter }
143*d2c909e8SMichael Tretter
144*d2c909e8SMichael Tretter /* Only program bits that are currently 0 (0->1) */
145*d2c909e8SMichael Tretter new_val = *value & ~old_val;
146*d2c909e8SMichael Tretter value++;
147*d2c909e8SMichael Tretter if (!new_val)
148*d2c909e8SMichael Tretter continue;
149*d2c909e8SMichael Tretter
150*d2c909e8SMichael Tretter /* Clear any pending interrupts */
151*d2c909e8SMichael Tretter io_write32(base + OTP_S_INT_ST, io_read32(base + OTP_S_INT_ST));
152*d2c909e8SMichael Tretter
153*d2c909e8SMichael Tretter /* Set write command */
154*d2c909e8SMichael Tretter io_write32(base + OTP_S_AUTO_CTRL, auto_ctrl_val);
155*d2c909e8SMichael Tretter
156*d2c909e8SMichael Tretter /* Write the new bits into PROG_DATA register */
157*d2c909e8SMichael Tretter io_write32(base + OTP_S_PROG_DATA, new_val);
158*d2c909e8SMichael Tretter
159*d2c909e8SMichael Tretter /* Enable the write */
160*d2c909e8SMichael Tretter io_write32(base + OTP_S_AUTO_EN, EN_ENABLE);
161*d2c909e8SMichael Tretter
162*d2c909e8SMichael Tretter /* Poll for WR_DONE or verify/error bits */
163*d2c909e8SMichael Tretter res = IO_READ32_POLL_TIMEOUT(base + OTP_S_INT_ST,
164*d2c909e8SMichael Tretter int_status,
165*d2c909e8SMichael Tretter (int_status & OTP_S_WR_DONE_BIT) ||
166*d2c909e8SMichael Tretter (int_status & OTP_S_VERIFY_BIT) ||
167*d2c909e8SMichael Tretter (int_status & OTP_S_ERROR_BIT),
168*d2c909e8SMichael Tretter OTP_POLL_PERIOD_US,
169*d2c909e8SMichael Tretter OTP_POLL_TIMEOUT_US);
170*d2c909e8SMichael Tretter
171*d2c909e8SMichael Tretter /* Clear INT status bits */
172*d2c909e8SMichael Tretter io_write32(base + OTP_S_INT_ST, int_status);
173*d2c909e8SMichael Tretter
174*d2c909e8SMichael Tretter /* Check for VERIFY_FAIL, ERROR or timeout */
175*d2c909e8SMichael Tretter if (int_status & OTP_S_VERIFY_BIT) {
176*d2c909e8SMichael Tretter EMSG("OTP_S Verification fail");
177*d2c909e8SMichael Tretter return TEE_ERROR_GENERIC;
178*d2c909e8SMichael Tretter }
179*d2c909e8SMichael Tretter if (int_status & OTP_S_ERROR_BIT) {
180*d2c909e8SMichael Tretter EMSG("OTP_S Error");
181*d2c909e8SMichael Tretter return TEE_ERROR_GENERIC;
182*d2c909e8SMichael Tretter }
183*d2c909e8SMichael Tretter if (res) {
184*d2c909e8SMichael Tretter EMSG("OTP_S Timeout");
185*d2c909e8SMichael Tretter return TEE_ERROR_BUSY;
186*d2c909e8SMichael Tretter }
187*d2c909e8SMichael Tretter }
188*d2c909e8SMichael Tretter
189*d2c909e8SMichael Tretter return TEE_SUCCESS;
190*d2c909e8SMichael Tretter }
191