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