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