1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20
21 #include <assert.h>
22 #include <DA1469xAB.h>
23 #include <da1469x_config.h>
24 #include <da1469x_otp.h>
25
26 #define OTPC_TIM1_REG_2MHz 0x09990001
27 #define OTPC_TIM1_REG_4MHz 0x09990003
28 #define OTPC_TIM1_REG_8MHz 0x09990007
29 #define OTPC_TIM1_REG_16MHz 0x0999000F
30 #define OTPC_TIM1_REG_32MHz 0x0999101F
31 #define OTPC_TIM1_REG_48MHz 0x0999202F
32 #define OTPC_TIM1_REG_96MHz 0x0999515F
33
34 #define OTPC_TIM2_REG_DEFAULT 0xA4040409
35
36 static inline void
da1469x_clock_amba_enable(uint32_t mask)37 da1469x_clock_amba_enable(uint32_t mask)
38 {
39 uint32_t primask;
40
41 primask = DA1469X_IRQ_DISABLE();
42 CRG_TOP->CLK_AMBA_REG |= mask;
43 DA1469X_IRQ_ENABLE(primask);
44 }
45
46 static inline void
da1469x_clock_amba_disable(uint32_t mask)47 da1469x_clock_amba_disable(uint32_t mask)
48 {
49 uint32_t primask;
50
51 primask = DA1469X_IRQ_DISABLE();
52 CRG_TOP->CLK_AMBA_REG &= ~mask;
53 DA1469X_IRQ_ENABLE(primask);
54 }
55
56 static inline void
da1469x_otp_tim1_adjust(int clk_speed)57 da1469x_otp_tim1_adjust(int clk_speed)
58 {
59 switch (clk_speed) {
60 default:
61 /* Unsupported access speed, fall-through to default 32MHz */
62 assert(0);
63 case 32000000:
64 OTPC->OTPC_TIM1_REG = OTPC_TIM1_REG_32MHz;
65 break;
66 /* 48MHz is not supported as PLL is only allowed when HDIV and PDIV are both 0 */
67 case 96000000:
68 OTPC->OTPC_TIM1_REG = OTPC_TIM1_REG_96MHz;
69 break;
70 case 2000000:
71 OTPC->OTPC_TIM1_REG = OTPC_TIM1_REG_2MHz;
72 break;
73 case 4000000:
74 OTPC->OTPC_TIM1_REG = OTPC_TIM1_REG_4MHz;
75 break;
76 case 8000000:
77 OTPC->OTPC_TIM1_REG = OTPC_TIM1_REG_8MHz;
78 break;
79 case 16000000:
80 OTPC->OTPC_TIM1_REG = OTPC_TIM1_REG_16MHz;
81 break;
82 }
83 }
84
85 int
da1469x_otp_read(uint32_t offset,void * dst,uint32_t num_bytes)86 da1469x_otp_read(uint32_t offset, void *dst, uint32_t num_bytes)
87 {
88 uint32_t *src_addr = (uint32_t *)(MCU_OTP_M_BASE + offset);
89 uint32_t *dst_addr = dst;
90
91 if (offset >= MCU_OTPM_SIZE || (offset + num_bytes) > MCU_OTPM_SIZE) {
92 return OTP_ERR_INVALID_ADDRESS;
93 }
94
95 if (num_bytes & 0x3) {
96 return OTP_ERR_INVALID_SIZE_ALIGNMENT;
97 }
98
99 /* Enable OTP clock and set mode to standby */
100 da1469x_clock_amba_enable(CRG_TOP_CLK_AMBA_REG_OTP_ENABLE_Msk);
101
102 da1469x_otp_set_mode(OTPC_MODE_READ);
103
104 for (; num_bytes; dst_addr++, src_addr++, num_bytes -= 4) {
105 *dst_addr = *src_addr;
106 }
107
108 da1469x_otp_set_mode(OTPC_MODE_DSTBY);
109
110 /* Disable OTP clock */
111 da1469x_clock_amba_disable(CRG_TOP_CLK_AMBA_REG_OTP_ENABLE_Msk);
112 return 0;
113 }
114
115 int
da1469x_otp_write(uint32_t offset,const void * src,uint32_t num_bytes)116 da1469x_otp_write(uint32_t offset, const void *src, uint32_t num_bytes)
117 {
118 uint32_t *dst_addr = (uint32_t *)(MCU_OTP_M_BASE + offset);
119 const uint32_t *src_addr = src;
120 int ret = 0;
121
122 if (offset >= MCU_OTPM_SIZE || (offset + num_bytes) > MCU_OTPM_SIZE) {
123 return OTP_ERR_INVALID_ADDRESS;
124 }
125
126 if (num_bytes & 0x3) {
127 return OTP_ERR_INVALID_SIZE_ALIGNMENT;
128 }
129
130 /* Enable OTP clock and set mode to standby */
131 da1469x_clock_amba_enable(CRG_TOP_CLK_AMBA_REG_OTP_ENABLE_Msk);
132
133 do {
134 da1469x_otp_set_mode(OTPC_MODE_PROG);
135
136 /* wait for programming to go idle and data buffer to be empty */
137 while (!(OTPC->OTPC_STAT_REG & OTPC_OTPC_STAT_REG_OTPC_STAT_PRDY_Msk));
138 while (!(OTPC->OTPC_STAT_REG &
139 OTPC_OTPC_STAT_REG_OTPC_STAT_PBUF_EMPTY_Msk));
140
141 /* fill data buffer with a word and trigger via the PADDR reg */
142 OTPC->OTPC_PWORD_REG = *src_addr;
143 OTPC->OTPC_PADDR_REG = ((uint32_t)dst_addr >> 2) &
144 OTPC_OTPC_PADDR_REG_OTPC_PADDR_Msk;
145
146 while (!(OTPC->OTPC_STAT_REG & OTPC_OTPC_STAT_REG_OTPC_STAT_PRDY_Msk));
147
148 /* set mode to verify */
149 da1469x_otp_set_mode(OTPC_MODE_PVFY);
150
151 /* read data and compare to source */
152 if (*dst_addr != *src_addr) {
153 ret = OTP_ERR_PROGRAM_VERIFY_FAILED;
154 goto fail_write;
155 }
156
157 da1469x_otp_set_mode(OTPC_MODE_STBY);
158 num_bytes -= 4;
159 src_addr++;
160 dst_addr++;
161 } while (num_bytes);
162
163 fail_write:
164
165 /* Disable OTP clock */
166 da1469x_clock_amba_disable(CRG_TOP_CLK_AMBA_REG_OTP_ENABLE_Msk);
167
168 return ret;
169 }
170
171 void
da1469x_otp_set_speed(uint32_t clk_speed)172 da1469x_otp_set_speed(uint32_t clk_speed)
173 {
174 /* Enable OTP clock and set mode to standby */
175 da1469x_clock_amba_enable(CRG_TOP_CLK_AMBA_REG_OTP_ENABLE_Msk);
176
177 da1469x_otp_set_mode(OTPC_MODE_DSTBY);
178
179 da1469x_otp_tim1_adjust(clk_speed);
180
181 /* Disable OTP clock */
182 da1469x_clock_amba_disable(CRG_TOP_CLK_AMBA_REG_OTP_ENABLE_Msk);
183 }
184
185
186 void
da1469x_otp_init(void)187 da1469x_otp_init(void)
188 {
189 /* Enable OTP clock and set mode to standby */
190 da1469x_clock_amba_enable(CRG_TOP_CLK_AMBA_REG_OTP_ENABLE_Msk);
191
192 da1469x_otp_set_mode(OTPC_MODE_STBY);
193
194 /* Set clk timing */
195 da1469x_otp_tim1_adjust(SystemCoreClock);
196
197 OTPC->OTPC_TIM2_REG = OTPC_TIM2_REG_DEFAULT;
198
199 /* Disable OTP clock */
200 da1469x_clock_amba_disable(CRG_TOP_CLK_AMBA_REG_OTP_ENABLE_Msk);
201 }
202