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 #include <assert.h>
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <string.h>
24
25 #include <zephyr/random/rand32.h>
26
27 #include <DA1469xAB.h>
28 #include <da1469x_pdc.h>
29 #include <da1469x_trimv.h>
30 #include <mbox.h>
31 #include <rand.h>
32 #include <shm.h>
33
34 extern char _binary_cmac_img_bin_start[];
35 extern char _binary_cmac_img_bin_end;
36 extern char _binary_cmac_ram_bin_start[];
37 extern char _binary_cmac_ram_bin_end;
38
39 struct cmac_img_info {
40 uint32_t magic;
41 uint32_t img_size;
42 uint32_t ram_size;
43 uint32_t data_offset;
44 uint32_t shared_offset;
45 uint32_t shared_addr;
46 };
47
48 struct cmac_img_hdr {
49 uint32_t isr[32];
50 struct cmac_img_info ii;
51 struct cmac_shm_config *shm_config;
52 struct cmac_shm_ctrl *shm_ctrl;
53 struct cmac_shm_mbox *shm_mbox_s2c;
54 struct cmac_shm_mbox *shm_mbox_c2s;
55 struct cmac_shm_trim *shm_trim;
56 struct cmac_shm_rand *shm_rand;
57 struct cmac_shm_dcdc *shm_dcdc;
58 struct cmac_shm_crashinfo *shm_crashinfo;
59 struct cmac_shm_debugdata *shm_debugdata;
60 };
61
62 #define CMAC_IMG_HDR ((struct cmac_img_hdr *)_binary_cmac_img_bin_start)
63
64 #define CMAC_CODE_PTR(_ptr) ((void *)((uint32_t)(_ptr) + \
65 0x20000000 + \
66 MEMCTRL->CMI_CODE_BASE_REG))
67 #define CMAC_SHARED_PTR(_ptr) ((void *)((uint32_t)(_ptr) - \
68 CMAC_IMG_HDR->ii.shared_addr + \
69 0x20000000 + \
70 MEMCTRL->CMI_SHARED_BASE_REG))
71
72 struct cmac_shm g_cmac_shm;
73
74 /* PDC entry for waking up CMAC */
75 static int8_t g_cmac_host_pdc_sys2cmac;
76 /* PDC entry for waking up M33 */
77 static int8_t g_cmac_host_pdc_cmac2sys;
78
79 static void cmac_host_rand_chk_fill(void);
80
81 void
cmac_cmac2sys_isr(void)82 cmac_cmac2sys_isr(void)
83 {
84 /* Clear CMAC2SYS interrupt */
85 *(volatile uint32_t *)0x40002000 = 2;
86
87 if (cmac_mbox_has_data()) {
88 cmac_read_req();
89 }
90
91 if (*(volatile uint32_t *)0x40002000 & 0x1c00) {
92 return;
93 }
94
95 cmac_host_rand_chk_fill();
96 }
97
98 static void
cmac_host_rand_chk_fill(void)99 cmac_host_rand_chk_fill(void)
100 {
101 uint32_t word;
102
103 while (cmac_rand_is_active() && !cmac_rand_is_full()) {
104 word = sys_rand32_get();
105 cmac_rand_fill(&word, 1);
106 }
107
108 cmac_signal();
109 }
110
111 static void
resolve_shm_ptrs(void)112 resolve_shm_ptrs(void)
113 {
114 g_cmac_shm.config = CMAC_CODE_PTR(CMAC_IMG_HDR->shm_config);
115 g_cmac_shm.ctrl = CMAC_SHARED_PTR(CMAC_IMG_HDR->shm_ctrl);
116 g_cmac_shm.mbox_s2c = CMAC_SHARED_PTR(CMAC_IMG_HDR->shm_mbox_s2c);
117 g_cmac_shm.mbox_c2s = CMAC_SHARED_PTR(CMAC_IMG_HDR->shm_mbox_c2s);
118 g_cmac_shm.trim = CMAC_SHARED_PTR(CMAC_IMG_HDR->shm_trim);
119 g_cmac_shm.rand = CMAC_SHARED_PTR(CMAC_IMG_HDR->shm_rand);
120 g_cmac_shm.dcdc = CMAC_SHARED_PTR(CMAC_IMG_HDR->shm_dcdc);
121 g_cmac_shm.crashinfo = CMAC_SHARED_PTR(CMAC_IMG_HDR->shm_crashinfo);
122 g_cmac_shm.debugdata = CMAC_SHARED_PTR(CMAC_IMG_HDR->shm_debugdata);
123 }
124
125 static void
shm_configure_trim(void)126 shm_configure_trim(void)
127 {
128 struct cmac_shm_config *config;
129 struct cmac_shm_trim *trim;
130 uint32_t *trim_data;
131
132 config = g_cmac_shm.config;
133 trim = g_cmac_shm.trim;
134 trim_data = trim->data;
135
136 trim->rfcu_len =
137 da1469x_trimv_group_read(6, trim_data, config->trim_rfcu_size);
138 trim_data += config->trim_rfcu_size;
139 trim->rfcu_mode1_len =
140 da1469x_trimv_group_read(8, trim_data, config->trim_rfcu_mode1_size);
141 trim_data += config->trim_rfcu_mode1_size;
142 trim->rfcu_mode2_len =
143 da1469x_trimv_group_read(10, trim_data, config->trim_rfcu_mode2_size);
144 trim_data += config->trim_rfcu_mode2_size;
145 trim->synth_len =
146 da1469x_trimv_group_read(7, trim_data, config->trim_synth_size);
147 }
148
149 static void
shm_configure_dcdc(void)150 shm_configure_dcdc(void)
151 {
152 struct cmac_shm_dcdc *dcdc;
153
154 dcdc = g_cmac_shm.dcdc;
155
156 dcdc->enabled = !!(DCDC->DCDC_CTRL1_REG & DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk);
157 if (dcdc->enabled) {
158 dcdc->v18 = DCDC->DCDC_V18_REG;
159 dcdc->v18p = DCDC->DCDC_V18P_REG;
160 dcdc->vdd = DCDC->DCDC_VDD_REG;
161 dcdc->v14 = DCDC->DCDC_V14_REG;
162 dcdc->ctrl1 = DCDC->DCDC_CTRL1_REG;
163 }
164 }
165
166 void
cmac_configure_shm(void)167 cmac_configure_shm(void)
168 {
169 resolve_shm_ptrs();
170
171 /* TODO: make this configurable */
172 g_cmac_shm.ctrl->xtal32m_settle_us = 1000;
173
174 shm_configure_trim();
175 shm_configure_dcdc();
176 }
177
178 void
cmac_load_image(void)179 cmac_load_image(void)
180 {
181 struct cmac_img_info *ii;
182 uint32_t img_size;
183 uint32_t ram_size;
184
185 /* Calculate size of image and RAM area */
186 img_size = &_binary_cmac_img_bin_end - &_binary_cmac_img_bin_start[0];
187 ram_size = &_binary_cmac_ram_bin_end - &_binary_cmac_ram_bin_start[0];
188
189 ii = &CMAC_IMG_HDR->ii;
190 assert(ii->magic == 0xC3AC0001);
191 assert(ii->img_size == img_size);
192 assert(ii->ram_size <= ram_size);
193
194 /* Setup CMAC memory addresses */
195 MEMCTRL->CMI_CODE_BASE_REG = (uint32_t)&_binary_cmac_ram_bin_start;
196 MEMCTRL->CMI_DATA_BASE_REG = MEMCTRL->CMI_CODE_BASE_REG + ii->data_offset;
197 MEMCTRL->CMI_SHARED_BASE_REG = MEMCTRL->CMI_CODE_BASE_REG + ii->shared_offset;
198 MEMCTRL->CMI_END_REG = MEMCTRL->CMI_CODE_BASE_REG + ii->ram_size - 1;
199
200 /* Clear RAM area then copy image */
201 memset(&_binary_cmac_ram_bin_start, 0, ram_size);
202 memcpy(&_binary_cmac_ram_bin_start, &_binary_cmac_img_bin_start, img_size);
203 }
204
205 void
cmac_configure_pdc(void)206 cmac_configure_pdc(void)
207 {
208 /* Add PDC entry to wake up CMAC from M33 */
209 g_cmac_host_pdc_sys2cmac = da1469x_pdc_add(MCU_PDC_TRIGGER_MAC_TIMER,
210 MCU_PDC_MASTER_CMAC,
211 MCU_PDC_EN_XTAL);
212 da1469x_pdc_set(g_cmac_host_pdc_sys2cmac);
213 da1469x_pdc_ack(g_cmac_host_pdc_sys2cmac);
214
215 /* Add PDC entry to wake up M33 from CMAC, if does not exist yet */
216 g_cmac_host_pdc_cmac2sys = da1469x_pdc_find(MCU_PDC_TRIGGER_COMBO,
217 MCU_PDC_MASTER_M33, 0);
218 if (g_cmac_host_pdc_cmac2sys < 0) {
219 g_cmac_host_pdc_cmac2sys = da1469x_pdc_add(MCU_PDC_TRIGGER_COMBO,
220 MCU_PDC_MASTER_M33,
221 MCU_PDC_EN_XTAL);
222 da1469x_pdc_set(g_cmac_host_pdc_cmac2sys);
223 da1469x_pdc_ack(g_cmac_host_pdc_cmac2sys);
224 }
225 }
226
227 void
cmac_enable(void)228 cmac_enable(void)
229 {
230 /* Enable Radio LDO */
231 CRG_TOP->POWER_CTRL_REG |= CRG_TOP_POWER_CTRL_REG_LDO_RADIO_ENABLE_Msk;
232
233 /* Enable CMAC, but keep it in reset */
234 CRG_TOP->CLK_RADIO_REG = (1 << CRG_TOP_CLK_RADIO_REG_RFCU_ENABLE_Pos) |
235 (1 << CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Pos) |
236 (0 << CRG_TOP_CLK_RADIO_REG_CMAC_CLK_SEL_Pos) |
237 (1 << CRG_TOP_CLK_RADIO_REG_CMAC_CLK_ENABLE_Pos) |
238 (0 << CRG_TOP_CLK_RADIO_REG_CMAC_DIV_Pos);
239
240 /* Release CMAC from reset and sync */
241 CRG_TOP->CLK_RADIO_REG &= ~CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Msk;
242
243 while (g_cmac_shm.ctrl->magic != CMAC_SHM_CB_MAGIC) {
244 /* Wait for CMAC to initialize */
245 };
246 }
247
248 void
cmac_disable(void)249 cmac_disable(void)
250 {
251 CRG_TOP->CLK_RADIO_REG = CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Msk;
252 }
253
254 void
cmac_signal(void)255 cmac_signal(void)
256 {
257 da1469x_pdc_set(g_cmac_host_pdc_sys2cmac);
258 }
259
260 void
cmac_request_lp_clock_freq_set(uint32_t freq)261 cmac_request_lp_clock_freq_set(uint32_t freq)
262 {
263 /* No need to wakeup CMAC if LP clock frequency did not change */
264 if (g_cmac_shm.ctrl->lp_clock_freq == freq) {
265 return;
266 }
267
268 cmac_shm_lock();
269 g_cmac_shm.ctrl->lp_clock_freq = freq;
270 g_cmac_shm.ctrl->pending_ops |= CMAC_SHM_CB_PENDING_OP_LP_CLK;
271 cmac_shm_unlock();
272
273 cmac_signal();
274 }
275
276 void
cmac_request_rf_calibrate(void)277 cmac_request_rf_calibrate(void)
278 {
279 cmac_shm_lock();
280 g_cmac_shm.ctrl->pending_ops |= CMAC_SHM_CB_PENDING_OP_RF_CAL;
281 cmac_shm_unlock();
282
283 cmac_signal();
284 }
285