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