1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2019 Broadcom.
4  */
5 
6 #include <assert.h>
7 #include <drivers/bcm_sotp.h>
8 #include <initcall.h>
9 #include <io.h>
10 #include <kernel/delay.h>
11 #include <mm/core_memprot.h>
12 #include <platform_config.h>
13 #include <util.h>
14 
15 #define SOTP_PROG_CONTROL			0x0
16 #define SOTP_PROG_CONTROL__OTP_CPU_MODE_EN	BIT(15)
17 #define SOTP_PROG_CONTROL__OTP_DISABLE_ECC	BIT(9)
18 #define SOTP_ADDR__OTP_ROW_ADDR_R		6
19 
20 #define SOTP_ADDR				0xc
21 
22 #define SOTP_CTRL_0				0x10
23 #define SOTP_CTRL_0__START			1
24 #define SOTP_READ				0
25 
26 #define SOTP_STAT_0				0x18
27 #define SOTP_STATUS_0__FDONE			BIT(3)
28 
29 #define SOTP_STATUS_1				0x1c
30 #define SOTP_STATUS_1__CMD_DONE			BIT(1)
31 #define SOTP_STATUS_1__ECC_DET			BIT(17)
32 
33 #define SOTP_RDDATA_0				0x20
34 #define SOTP_RDDATA_1				0x24
35 #define SOTP_ADDR_MASK				0x3ff
36 
37 #define SOTP_ECC_ERR_DETECT			BIT64(63)
38 
39 #define SOTP_TIMEOUT_US				300
40 
41 static vaddr_t bcm_sotp_base;
42 
otp_status_done_wait(vaddr_t addr,uint32_t bit)43 static TEE_Result otp_status_done_wait(vaddr_t addr, uint32_t bit)
44 {
45 	uint64_t timeout = timeout_init_us(SOTP_TIMEOUT_US);
46 
47 	while (!(io_read32(addr) & bit))
48 		if (timeout_elapsed(timeout))
49 			return TEE_ERROR_BUSY;
50 	return TEE_SUCCESS;
51 }
52 
bcm_iproc_sotp_mem_read(uint32_t row_addr,uint32_t sotp_add_ecc,uint64_t * rdata)53 TEE_Result bcm_iproc_sotp_mem_read(uint32_t row_addr, uint32_t sotp_add_ecc,
54 				uint64_t *rdata)
55 {
56 	uint64_t read_data = 0;
57 	uint32_t reg_val = 0;
58 	TEE_Result ret = TEE_SUCCESS;
59 
60 	assert(bcm_sotp_base);
61 	/* Check for FDONE status */
62 	ret = otp_status_done_wait((bcm_sotp_base + SOTP_STAT_0),
63 				   SOTP_STATUS_0__FDONE);
64 	if (ret) {
65 		EMSG("FDONE status done wait failed");
66 		return ret;
67 	}
68 
69 	/* Enable OTP access by CPU */
70 	io_setbits32((bcm_sotp_base + SOTP_PROG_CONTROL),
71 		     SOTP_PROG_CONTROL__OTP_CPU_MODE_EN);
72 
73 	/* ROWS does not support ECC */
74 	if (row_addr <= SOTP_NO_ECC_ROWS)
75 		sotp_add_ecc = 0;
76 
77 	if (sotp_add_ecc == 1) {
78 		io_clrbits32((bcm_sotp_base + SOTP_PROG_CONTROL),
79 			     SOTP_PROG_CONTROL__OTP_DISABLE_ECC);
80 	} else {
81 		io_setbits32((bcm_sotp_base + SOTP_PROG_CONTROL),
82 			     SOTP_PROG_CONTROL__OTP_DISABLE_ECC);
83 	}
84 
85 	/* 10 bit row address */
86 	reg_val = (row_addr & SOTP_ADDR_MASK) << SOTP_ADDR__OTP_ROW_ADDR_R;
87 	io_write32((bcm_sotp_base + SOTP_ADDR), reg_val);
88 	reg_val = SOTP_READ;
89 	io_write32((bcm_sotp_base + SOTP_CTRL_0), reg_val);
90 
91 	/* Start bit to tell SOTP to send command to the OTP controller */
92 	io_setbits32((bcm_sotp_base + SOTP_CTRL_0), SOTP_CTRL_0__START);
93 
94 	/* Wait for SOTP command done to be set */
95 	ret = otp_status_done_wait((bcm_sotp_base + SOTP_STAT_0),
96 				   SOTP_STATUS_1__CMD_DONE);
97 	if (ret) {
98 		EMSG("FDONE cmd done wait failed\n");
99 		return ret;
100 	}
101 
102 	DMSG("CMD Done\n");
103 
104 	/* Clr Start bit after command done */
105 	io_clrbits32((bcm_sotp_base + SOTP_CTRL_0), SOTP_CTRL_0__START);
106 	read_data = io_read32(bcm_sotp_base + SOTP_RDDATA_1);
107 	read_data = ((read_data & 0x1ff) << 32);
108 	read_data |= io_read32(bcm_sotp_base + SOTP_RDDATA_0);
109 
110 	reg_val = io_read32(bcm_sotp_base + SOTP_STATUS_1);
111 	/* No ECC check till SOTP_NO_ECC_ROWS */
112 	if (row_addr > SOTP_NO_ECC_ROWS &&
113 	    reg_val & SOTP_STATUS_1__ECC_DET) {
114 		EMSG("SOTP ECC ERROR Detected ROW %d\n", row_addr);
115 		read_data = SOTP_ECC_ERR_DETECT;
116 	}
117 
118 	/* Command done is cleared */
119 	io_setbits32((bcm_sotp_base + SOTP_STATUS_1), SOTP_STATUS_1__CMD_DONE);
120 	io_clrbits32((bcm_sotp_base + SOTP_PROG_CONTROL),
121 		     SOTP_PROG_CONTROL__OTP_CPU_MODE_EN);
122 	DMSG("read done\n");
123 
124 	*rdata = read_data;
125 	return ret;
126 }
127 
bcm_sotp_init(void)128 static TEE_Result bcm_sotp_init(void)
129 {
130 	bcm_sotp_base = (vaddr_t)phys_to_virt(SOTP_BASE, MEM_AREA_IO_SEC, 1);
131 
132 	DMSG("bcm_sotp init done\n");
133 	return TEE_SUCCESS;
134 }
135 
136 service_init(bcm_sotp_init);
137