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