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 <zephyr/arch/common/sys_io.h>
21 #include <assert.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <DA1469xAB.h>
25 #include <da1469x_config.h>
26 #include <da1469x_pd.h>
27 #include <da1469x_trimv.h>
28
29 #define PD_COUNT (sizeof(g_da1469x_pd_desc) / sizeof(g_da1469x_pd_desc[0]))
30
31 #define REG_TO_PTR(_reg) ((uintptr_t)&(_reg))
32
33 struct da1469x_pd_desc {
34 uint8_t pmu_sleep_bit;
35 uint8_t stat_down_bit; /* up is +1 */
36 };
37
38 static uint32_t trimv_words_buf[16];
39 static uint32_t trimv_words_idx = 0;
40
41 struct da1469x_pd_data {
42 uint8_t refcnt;
43 uint8_t trimv_count;
44 uint32_t *trimv_words;
45 };
46
47 enum chip_variant {
48 CHIP_VARIANT_TSMC,
49 CHIP_VARIANT_GF,
50 CHIP_VARIANT_UNKNOWN
51 };
52
53 static int g_device_id = CHIP_VARIANT_UNKNOWN;
54
55 /* Only include controllable power domains here */
56 static const struct da1469x_pd_desc g_da1469x_pd_desc[] = {
57 [MCU_PD_DOMAIN_SYS] = { CRG_TOP_PMU_CTRL_REG_SYS_SLEEP_Pos,
58 CRG_TOP_SYS_STAT_REG_SYS_IS_DOWN_Pos },
59 [MCU_PD_DOMAIN_PER] = { CRG_TOP_PMU_CTRL_REG_PERIPH_SLEEP_Pos,
60 CRG_TOP_SYS_STAT_REG_PER_IS_DOWN_Pos },
61 [MCU_PD_DOMAIN_TIM] = { CRG_TOP_PMU_CTRL_REG_TIM_SLEEP_Pos,
62 CRG_TOP_SYS_STAT_REG_TIM_IS_DOWN_Pos },
63 [MCU_PD_DOMAIN_COM] = { CRG_TOP_PMU_CTRL_REG_COM_SLEEP_Pos,
64 CRG_TOP_SYS_STAT_REG_COM_IS_DOWN_Pos},
65 };
66
67 static struct da1469x_pd_data g_da1469x_pd_data[PD_COUNT];
68
69 static inline void
write32_mask(uint32_t mask,uint32_t data,mem_addr_t addr)70 write32_mask(uint32_t mask, uint32_t data, mem_addr_t addr)
71 {
72 uint32_t val = sys_read32(addr);
73
74 sys_write32((val & (~mask)) | (data & mask), addr);
75 }
76
77 static void
da1469x_pd_load_trimv(uint8_t pd,uint8_t group)78 da1469x_pd_load_trimv(uint8_t pd, uint8_t group)
79 {
80 struct da1469x_pd_data *pdd;
81
82 assert(pd < PD_COUNT);
83
84 pdd = &g_da1469x_pd_data[pd];
85 pdd->trimv_count = da1469x_trimv_group_num_words_get(group);
86 if (pdd->trimv_count == 0) {
87 return;
88 }
89
90 if (trimv_words_idx + pdd->trimv_count <= ARRAY_SIZE(trimv_words_buf)) {
91 pdd->trimv_words = &trimv_words_buf[trimv_words_idx];
92 trimv_words_idx += pdd->trimv_count;
93 } else {
94 pdd->trimv_count = 0;
95 assert(0);
96 return;
97 }
98
99 pdd->trimv_count = da1469x_trimv_group_read(group, pdd->trimv_words,
100 pdd->trimv_count);
101 pdd->trimv_count /= 2;
102 }
103
104 static void
da1469x_pd_apply_trimv(uint8_t pd)105 da1469x_pd_apply_trimv(uint8_t pd)
106 {
107 struct da1469x_pd_data *pdd;
108 volatile uint32_t *reg;
109 uint32_t val;
110 int idx;
111
112 assert(pd < PD_COUNT);
113
114 pdd = &g_da1469x_pd_data[pd];
115 if (pdd->trimv_count == 0) {
116 return;
117 }
118
119 for (idx = 0; idx < pdd->trimv_count; idx++) {
120 reg = (uint32_t *) pdd->trimv_words[idx * 2];
121 val = pdd->trimv_words[idx * 2 + 1];
122 *reg = val;
123 }
124 }
125
126 static int
read_device_id(void)127 read_device_id(void)
128 {
129 union {
130 uint8_t array[4];
131 uint32_t value;
132 } chip_id;
133
134 chip_id.array[3] = CHIP_VERSION->CHIP_ID1_REG & CHIP_VERSION_CHIP_ID1_REG_CHIP_ID1_Msk;
135 chip_id.array[2] = CHIP_VERSION->CHIP_ID2_REG & CHIP_VERSION_CHIP_ID2_REG_CHIP_ID2_Msk;
136 chip_id.array[1] = CHIP_VERSION->CHIP_ID3_REG & CHIP_VERSION_CHIP_ID3_REG_CHIP_ID3_Msk;
137 chip_id.array[0] = CHIP_VERSION->CHIP_ID4_REG & CHIP_VERSION_CHIP_ID4_REG_CHIP_ID4_Msk;
138
139 if (chip_id.value == 0x32353232) {
140 return CHIP_VARIANT_TSMC;
141 } else if (chip_id.value == 0x33303830) {
142 return CHIP_VARIANT_GF;
143 } else {
144 return CHIP_VARIANT_UNKNOWN;
145 }
146 }
147
148 static void
da1469x_TSMC_pd_apply_preferred(uint8_t pd)149 da1469x_TSMC_pd_apply_preferred(uint8_t pd)
150 {
151 switch (pd) {
152 case MCU_PD_DOMAIN_AON:
153 /* Apply if no user-defined value has been applied */
154 if (sys_read32(REG_TO_PTR(CRG_TOP->PMU_TRIM_REG)) == 0x00008800) {
155 sys_write32(0x00007700, REG_TO_PTR(CRG_TOP->PMU_TRIM_REG));
156 }
157 write32_mask(0x00001000, 0x00001020, REG_TO_PTR(CRG_TOP->BANDGAP_REG));
158 sys_write32(0x000000ca, REG_TO_PTR(CRG_TOP->BIAS_VREF_SEL_REG));
159 write32_mask(0x0003ffff, 0x041e6ef4, REG_TO_PTR(CRG_TOP->BOD_LVL_CTRL0_REG));
160 break;
161 case MCU_PD_DOMAIN_SYS:
162 write32_mask(0x00000c00, 0x003f6a78, REG_TO_PTR(CHARGER->CHARGER_CTRL_REG));
163 write32_mask(0x000003ff, 0x00000002, REG_TO_PTR(CHARGER->CHARGER_PWR_UP_TIMER_REG));
164 break;
165 case MCU_PD_DOMAIN_TIM:
166 write32_mask(0x3ff00000, 0x000afd70, REG_TO_PTR(CRG_XTAL->CLK_FREQ_TRIM_REG));
167 write32_mask(0x000000c0, 0x00000562, REG_TO_PTR(CRG_XTAL->TRIM_CTRL_REG));
168 write32_mask(0x03c38002, 0x0801e6b6, REG_TO_PTR(CRG_XTAL->XTAL32M_CTRL0_REG));
169 write32_mask(0x007fff00, 0x7500a1a4, REG_TO_PTR(CRG_XTAL->XTAL32M_CTRL1_REG));
170 write32_mask(0x00000fff, 0x001e45c4, REG_TO_PTR(CRG_XTAL->XTAL32M_CTRL2_REG));
171 write32_mask(0x40000000, 0x40096255, REG_TO_PTR(CRG_XTAL->XTAL32M_CTRL3_REG));
172 write32_mask(0x00c00000, 0x00c00000, 0x50010040);
173 write32_mask(0x000000ff, 0x00000180, REG_TO_PTR(CRG_XTAL->XTALRDY_CTRL_REG));
174 break;
175 }
176 }
177
178 static void
da1469x_GF_pd_apply_preferred(uint8_t pd)179 da1469x_GF_pd_apply_preferred(uint8_t pd)
180 {
181 switch (pd) {
182 case MCU_PD_DOMAIN_AON:
183 write32_mask(0x00001000, 0x00001020, REG_TO_PTR(CRG_TOP->BANDGAP_REG));
184 sys_write32(0x000000ca, REG_TO_PTR(CRG_TOP->BIAS_VREF_SEL_REG));
185 write32_mask(0x0003ffff, 0x041e6ef4, REG_TO_PTR(CRG_TOP->BOD_LVL_CTRL0_REG));
186 write32_mask(0x00000f00, 0x00000dfc, REG_TO_PTR(CRG_TOP->CLK_RCX_REG));
187 write32_mask(0x0000007e, 0x00000024, REG_TO_PTR(CRG_TOP->CLK_XTAL32K_REG));
188 break;
189 case MCU_PD_DOMAIN_SYS:
190 write32_mask(0x00000c00, 0x003f6a78, REG_TO_PTR(CHARGER->CHARGER_CTRL_REG));
191 write32_mask(0x000003ff, 0x00000002, REG_TO_PTR(CHARGER->CHARGER_PWR_UP_TIMER_REG));
192 break;
193 case MCU_PD_DOMAIN_TIM:
194 write32_mask(0x3ff00000, 0x000afd70, REG_TO_PTR(CRG_XTAL->CLK_FREQ_TRIM_REG));
195 write32_mask(0x000000c0, 0x00000562, REG_TO_PTR(CRG_XTAL->TRIM_CTRL_REG));
196 write32_mask(0x1fc38002, 0x0c01e6b6, REG_TO_PTR(CRG_XTAL->XTAL32M_CTRL0_REG));
197 write32_mask(0x707fff00, 0x0500a1a4, REG_TO_PTR(CRG_XTAL->XTAL32M_CTRL1_REG));
198 write32_mask(0x00000fff, 0x001e45c4, REG_TO_PTR(CRG_XTAL->XTAL32M_CTRL2_REG));
199 write32_mask(0x40000000, 0x40096255, REG_TO_PTR(CRG_XTAL->XTAL32M_CTRL3_REG));
200 write32_mask(0x00c00000, 0x00c00000, 0x50010040);
201 write32_mask(0x000000ff, 0x00000180, REG_TO_PTR(CRG_XTAL->XTALRDY_CTRL_REG));
202 break;
203 }
204 }
205
206 __weak void
da1469x_pd_apply_preferred(uint8_t pd)207 da1469x_pd_apply_preferred(uint8_t pd)
208 {
209 if (g_device_id == CHIP_VARIANT_TSMC) {
210 da1469x_TSMC_pd_apply_preferred(pd);
211 } else {
212 da1469x_GF_pd_apply_preferred(pd);
213 }
214 }
215
216
217 int
da1469x_pd_init(void)218 da1469x_pd_init(void)
219 {
220 /* Get the chip ID before initilizating any PD */
221 g_device_id = read_device_id();
222 assert(g_device_id != CHIP_VARIANT_UNKNOWN);
223
224 /*
225 * Apply now for always-on domain which, as name suggests, is always on so
226 * need to do this only once.
227 */
228 da1469x_pd_apply_preferred(MCU_PD_DOMAIN_AON);
229
230 da1469x_pd_load_trimv(MCU_PD_DOMAIN_SYS, 1);
231 da1469x_pd_load_trimv(MCU_PD_DOMAIN_COM, 2);
232 da1469x_pd_load_trimv(MCU_PD_DOMAIN_TIM, 4);
233 da1469x_pd_load_trimv(MCU_PD_DOMAIN_PER, 5);
234
235 return 0;
236 }
237
238 int
da1469x_pd_get_ref_cnt(uint8_t pd)239 da1469x_pd_get_ref_cnt(uint8_t pd)
240 {
241 struct da1469x_pd_data *pdd;
242
243 assert(pd < PD_COUNT);
244
245 pdd = &g_da1469x_pd_data[pd];
246
247 return pdd->refcnt;
248 }
249
250 static int
da1469x_pd_acquire_internal(uint8_t pd,bool load)251 da1469x_pd_acquire_internal(uint8_t pd, bool load)
252 {
253 struct da1469x_pd_data *pdd;
254 uint32_t primask;
255 uint32_t bitmask;
256 int ret = 0;
257
258 assert(pd < PD_COUNT);
259
260 pdd = &g_da1469x_pd_data[pd];
261
262 primask = DA1469X_IRQ_DISABLE();
263
264 assert(pdd->refcnt < UINT8_MAX);
265
266 if (pdd->refcnt++ == 0) {
267 bitmask = 1 << g_da1469x_pd_desc[pd].pmu_sleep_bit;
268 CRG_TOP->PMU_CTRL_REG &= ~bitmask;
269
270 bitmask = 1 << (g_da1469x_pd_desc[pd].stat_down_bit + 1);
271 while ((CRG_TOP->SYS_STAT_REG & bitmask) == 0);
272
273 if (load) {
274 da1469x_pd_apply_trimv(pd);
275 da1469x_pd_apply_preferred(pd);
276 }
277
278 ret = 1;
279 }
280
281 DA1469X_IRQ_ENABLE(primask);
282
283 return ret;
284 }
285
286 int
da1469x_pd_acquire(uint8_t pd)287 da1469x_pd_acquire(uint8_t pd)
288 {
289 return da1469x_pd_acquire_internal(pd, true);
290 }
291
292 int
da1469x_pd_acquire_noconf(uint8_t pd)293 da1469x_pd_acquire_noconf(uint8_t pd)
294 {
295 return da1469x_pd_acquire_internal(pd, false);
296 }
297
298 static int
da1469x_pd_release_internal(uint8_t pd,bool wait)299 da1469x_pd_release_internal(uint8_t pd, bool wait)
300 {
301 struct da1469x_pd_data *pdd;
302 uint32_t primask;
303 uint32_t bitmask;
304 int ret = 0;
305
306 assert(pd < PD_COUNT);
307
308 pdd = &g_da1469x_pd_data[pd];
309
310 primask = DA1469X_IRQ_DISABLE();
311
312 assert(pdd->refcnt > 0);
313
314 if (--pdd->refcnt == 0) {
315 bitmask = 1 << g_da1469x_pd_desc[pd].pmu_sleep_bit;
316 CRG_TOP->PMU_CTRL_REG |= bitmask;
317
318 if (wait) {
319 bitmask = 1 << g_da1469x_pd_desc[pd].stat_down_bit;
320 while ((CRG_TOP->SYS_STAT_REG & bitmask) == 0);
321 }
322
323 ret = 1;
324 }
325
326 DA1469X_IRQ_ENABLE(primask);;
327
328 return ret;
329 }
330
331 int
da1469x_pd_release(uint8_t pd)332 da1469x_pd_release(uint8_t pd)
333 {
334 return da1469x_pd_release_internal(pd, true);
335 }
336
337 int
da1469x_pd_release_nowait(uint8_t pd)338 da1469x_pd_release_nowait(uint8_t pd)
339 {
340 return da1469x_pd_release_internal(pd, false);
341 }
342