1 /*
2  * Copyright 2024 Microchip Technology Inc. and its subsidiaries.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <stdbool.h>
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <device_mec5.h>
11 #include "mec_pcfg.h"
12 #include "mec_defs.h"
13 #include "mec_ecs_api.h"
14 #include "mec_gpio_api.h"
15 #include "mec_pcr_api.h"
16 #include "mec_vbat_api.h"
17 #include "mec_retval.h"
18 
19 #define MEC_PCR_PLL_FAST_FREQ_HZ 96000000
20 #define MEC_PCR_PLL_FREQ_HZ      48000000
21 #define MEC_PCR_PLL_MAX_CLK_DIV  48
22 
23 #define MEC_PCR_RSTEN_UNLOCK 0xa6382d4cu
24 #define MEC_PCR_RSTEN_LOCK   0xa6382d4du
25 
26 #define MEC_PCR_PRIV_UNLOCK 0xa6382d4cu
27 #define MEC_PCR_PRIV_LOCK   0xa6382d4du
28 
29 /* PCR Power Reset Status register RESET_VCC bit is RESET_HOST
30  * 0 = reset active
31  * 1 = reset inactive
32  */
mec_hal_pcr_is_host_reset(void)33 int mec_hal_pcr_is_host_reset(void)
34 {
35     if (MEC_PCR->PRS & MEC_BIT(MEC_PCR_PRS_RESET_VCC_Pos)) {
36         return 0;
37     }
38     return 1;
39 }
40 
mec_hal_pcr_is_vcc_pwrgd(void)41 int mec_hal_pcr_is_vcc_pwrgd(void)
42 {
43     if (MEC_PCR->PRS & MEC_BIT(MEC_PCR_PRS_VCC_PWRGD_Pos)) {
44         return 1;
45     }
46     return 0;
47 }
48 
49 /* Return state of VCC_PWRGD in bit 0 and VCC_PWRGD2 in bit 1 */
mec_hal_pcr_vcc_power_good_state(void)50 uint32_t mec_hal_pcr_vcc_power_good_state(void)
51 {
52     return (MEC_PCR->PRS >> 1) & 0x03u;
53 }
54 
mec_hal_pcr_is_turbo_clock(void)55 int mec_hal_pcr_is_turbo_clock(void)
56 {
57 #ifdef MEC5_FAM2_ID
58     if (MEC_PCR->TURBO_CLK & MEC_BIT(MEC_PCR_TURBO_CLK_FAST_CLK_Pos)) {
59         return 1;
60     }
61 
62     return 0;
63 #else
64     if (MEC_ECS->FEAT_LOCK & MEC_BIT(MEC_ECS_FEAT_LOCK_TURBO_FREQ_Pos)) {
65         return 0;
66     }
67 
68     return 1;
69 #endif
70 }
71 
72 /* Get maximum input clock frequency in Hz supplied by the PCR module to the ARM Cortex-M4 core */
mec_hal_pcr_cpu_max_freq(void)73 uint32_t mec_hal_pcr_cpu_max_freq(void)
74 {
75 #ifdef MEC5_FAM2_ID
76     uint32_t fhz = MEC_PCR_PLL_FREQ_HZ;
77 
78     if (MEC_PCR->TURBO_CLK & MEC_BIT(MEC_PCR_TURBO_CLK_FAST_CLK_Pos)) {
79         fhz = MEC_PCR_PLL_FAST_FREQ_HZ;
80     }
81 #else
82     uint32_t fhz = MEC_PCR_PLL_FAST_FREQ_HZ;
83 
84     if (MEC_ECS->FEAT_LOCK & MEC_BIT(MEC_ECS_FEAT_LOCK_TURBO_FREQ_Pos)) {
85         fhz = MEC_PCR_PLL_FREQ_HZ;
86     }
87 #endif
88 
89     return fhz;
90 }
91 
92 /* Get current clock frequency in Hz divided down from maximum */
mec_hal_pcr_cpu_clk_speed(void)93 uint32_t mec_hal_pcr_cpu_clk_speed(void)
94 {
95     uint32_t max_freq = mec_hal_pcr_cpu_max_freq();
96     uint32_t freq = max_freq;
97     uint32_t clkdiv = MEC_PCR->PCC;
98 
99     if (clkdiv) {
100         freq = max_freq / clkdiv;
101     }
102 
103     return freq;
104 }
105 
set_pcr_cpu_clk_div(uint32_t clkdiv)106 static void set_pcr_cpu_clk_div(uint32_t clkdiv)
107 {
108     uint32_t isave;
109 
110     isave = __get_PRIMASK();
111     __disable_irq();
112 
113     MEC_PCR->PCC = clkdiv;
114     __ISB();
115     __DSB();
116     __NOP();
117     __NOP();
118     __NOP();
119     __NOP();
120     __NOP();
121     __NOP();
122     __NOP();
123     __NOP();
124     __NOP();
125 
126     if (isave) {
127         __enable_irq();
128     }
129 }
130 
131 /* Change clock speed PCR provides to ARM Cortex-M4 core
132  * @param fhz requested clock in Hz
133  * @return 0 (success), < 0 error
134  * @note this routine include a critical section around write to
135  * frequency divider register and necessary instruction sequence
136  * to re-align clock and processor.
137  */
mec_hal_pcr_cpu_clk_speed_set(uint32_t fhz)138 int mec_hal_pcr_cpu_clk_speed_set(uint32_t fhz)
139 {
140     uint32_t fdiv, max_freq;
141 
142     if (fhz == 0) {
143         return MEC_RET_ERR_INVAL;
144     }
145 
146     max_freq = mec_hal_pcr_cpu_max_freq();
147     fdiv = max_freq / fhz;
148 
149     if (fdiv == 0) {
150         fdiv = 1u;
151     } else {
152         if (fdiv > MEC_PCR_PLL_MAX_CLK_DIV) {
153             fdiv = MEC_PCR_PLL_MAX_CLK_DIV;
154         }
155     }
156 
157     set_pcr_cpu_clk_div(fdiv);
158 
159     return 0;
160 }
161 
mec_hal_pcr_cpu_clock_divider(void)162 uint32_t mec_hal_pcr_cpu_clock_divider(void)
163 {
164     return MEC_PCR->PCC;
165 }
166 
mec_hal_pcr_cpu_clock_divider_set(enum mec_pcr_cpu_clk_div clk_div)167 int mec_hal_pcr_cpu_clock_divider_set(enum mec_pcr_cpu_clk_div clk_div)
168 {
169     if (!clk_div) {
170         return MEC_RET_ERR_INVAL;
171     }
172 
173     set_pcr_cpu_clk_div((uint32_t)clk_div);
174 
175     return 0;
176 }
177 
mec_hal_pcr_is_pll_locked(void)178 bool mec_hal_pcr_is_pll_locked(void)
179 {
180     if (MEC_PCR->OID & MEC_BIT(MEC_PCR_OID_PLL_LOCK_Pos)) {
181         return true;
182     }
183 
184     return false;
185 }
186 
187 /* PCR sleep enables */
188 /* pid = zero based PCR bit position of the peripheral.
189  * Sleep enable register index 0 contains bits 0:31, ...,
190  * Sleep enable register index 4 contains bits 128:159
191  */
mec_hal_pcr_set_blk_slp_en(uint16_t pid)192 void mec_hal_pcr_set_blk_slp_en(uint16_t pid)
193 {
194     if (pid >= MEC_PCR_MAX_ID) {
195         return;
196     }
197 
198     uint32_t idx = pid / 32u;
199     uint32_t bpos = pid % 32u;
200 
201     MEC_PCR->SLP_EN[idx] |= MEC_BIT(bpos);
202 }
203 
mec_hal_pcr_clr_blk_slp_en(uint16_t pid)204 void mec_hal_pcr_clr_blk_slp_en(uint16_t pid)
205 {
206     if (pid >= MEC_PCR_MAX_ID) {
207         return;
208     }
209 
210     uint32_t idx = pid / 32u;
211     uint32_t bpos = pid % 32u;
212 
213     MEC_PCR->SLP_EN[idx] &= ~MEC_BIT(bpos);
214 }
215 
mec_hal_pcr_is_blk_slp_en(uint16_t pid)216 uint8_t mec_hal_pcr_is_blk_slp_en(uint16_t pid)
217 {
218     uint32_t idx;
219     uint32_t bpos;
220 
221     if (pid < MEC_PCR_MAX_ID) {
222         idx = pid / 32u;
223         bpos = pid % 32u;
224 
225         if (MEC_PCR->SLP_EN[idx] & MEC_BIT(bpos)) {
226             return 1;
227         }
228     }
229 
230     return 0;
231 }
232 
mec_hal_pcr_blk_slp_en(uint16_t pid,uint8_t enable)233 void mec_hal_pcr_blk_slp_en(uint16_t pid, uint8_t enable)
234 {
235     if (enable) {
236         mec_hal_pcr_set_blk_slp_en(pid);
237     } else {
238         mec_hal_pcr_clr_blk_slp_en(pid);
239     }
240 }
241 
mec_hal_pcr_slp_en_set(uint8_t regid,uint32_t val)242 int mec_hal_pcr_slp_en_set(uint8_t regid, uint32_t val)
243 {
244     if (regid >= MEC_MAX_PCR_SCR_REGS) {
245         return MEC_RET_ERR_INVAL;
246     }
247 
248     MEC_PCR->SLP_EN[regid] = val;
249 
250     return MEC_RET_OK;
251 }
252 
mec_hal_pcr_slp_en_mask(uint8_t regid,uint32_t val,uint32_t mask)253 int mec_hal_pcr_slp_en_mask(uint8_t regid, uint32_t val, uint32_t mask)
254 {
255     if (regid >= MEC_MAX_PCR_SCR_REGS) {
256         return MEC_RET_ERR_INVAL;
257     }
258 
259     MEC_PCR->SLP_EN[regid] = (MEC_PCR->SLP_EN[regid] & ~mask) | (val & mask);
260 
261     return MEC_RET_OK;
262 }
263 
mec_hal_pcr_slp_en_por(void)264 void mec_hal_pcr_slp_en_por(void)
265 {
266     for (uint32_t i = 0; i < MEC_MAX_PCR_SCR_REGS; i++) {
267         MEC_PCR->SLP_EN[i] = 0;
268     }
269 
270     MEC_PCR->SLP_EN[3] = MEC_BIT(MEC_PCR_CRYPTO_ALL % 32u);
271 }
272 
mec_hal_pcr_slp_en_set_all(void)273 void mec_hal_pcr_slp_en_set_all(void)
274 {
275     for (uint32_t i = 0; i < MEC_MAX_PCR_SCR_REGS; i++) {
276         MEC_PCR->SLP_EN[i] = UINT32_MAX;
277     }
278 }
279 
280 /* Reset specified peripheral block using PCR peripheral block reset
281  * This reset is similar to the reset a peripheral block resets during
282  * chip reset.
283  * @param pid, an enum mec_pcr_scr_id specifying peripheral block.
284  * @return value written to PCR reset enable[n] register.
285  * @note enum mec_pcr_scr_id encodes the peripheral's PCR reset register
286  * index and bit position. Return value has no purpose other than providing
287  * a way to force a read-back of the write to the reset enable register.
288  * Yes, this is overkill. AHB with this CPU preserved ordering of register
289  * writes.
290  */
mec_hal_pcr_blk_reset(uint16_t pid)291 uint32_t mec_hal_pcr_blk_reset(uint16_t pid)
292 {
293     uint32_t bpos, idx, temp;
294 
295     if (pid >= MEC_PCR_MAX_ID) {
296         return 0;
297     }
298 
299     idx = pid / 32u;
300     bpos = pid % 32u;
301 
302     MEC_PCR->RENLK = MEC_PCR_RSTEN_UNLOCK;
303     MEC_PCR->RST_EN[idx] = MEC_BIT(bpos);
304     temp = MEC_PCR->RST_EN[idx];
305     MEC_PCR->RENLK = MEC_PCR_RSTEN_LOCK;
306 
307     return temp;
308 }
309 
mec_hal_pcr_blk_reset_critical(uint16_t pid)310 uint32_t mec_hal_pcr_blk_reset_critical(uint16_t pid)
311 {
312     uint32_t isave, rval;
313 
314     isave = __get_PRIMASK();
315     __disable_irq();
316     rval = mec_hal_pcr_blk_reset(pid);
317     if (isave) {
318         __enable_irq();
319     }
320     return rval;
321 }
322 
mec_pcr_reset_system(void)323 void __attribute__((__noreturn__)) mec_pcr_reset_system(void)
324 {
325     MEC_PCR->SRST |= MEC_BIT(MEC_PCR_SRST_SYS_RST_Pos);
326 
327     while (1) {
328         __NOP();
329         __NOP();
330         __NOP();
331     }
332 }
333 
334 /* Release firmware control override (assertion) of RESET_VCC internal signal.
335  * release == 0 configure HW to force assertion of internal RESET_VCC signal.
336  * release != 0 configure HW to disable forced assertion of internal RESET_VCC
337  *              signal. RESET_VCC state is controlled by its other inputs.
338  * Note1: RESET_VCC internal signal is affected by
339  * RESET_SYS high || VCC_PWRGD2 low || PCR PWR_INV bit high
340  * Note2: PWROK(_ALT) pins is inverted RESET_VCC. If PWROK(_ALT) pin(s) are
341  * used the application must configura the respective GPIO(s).
342  */
mec_hal_pcr_release_reset_vcc(uint8_t release)343 void mec_hal_pcr_release_reset_vcc(uint8_t release)
344 {
345     if (release) {
346         MEC_PCR->PRC &= ~MEC_BIT(MEC_PCR_PRC_PWR_INV_Pos);
347     } else {
348         MEC_PCR->PRC |= MEC_BIT(MEC_PCR_PRC_PWR_INV_Pos);
349     }
350 }
351 
mec_hal_pcr_host_reset_select(uint8_t use_espi_platform_reset)352 void mec_hal_pcr_host_reset_select(uint8_t use_espi_platform_reset)
353 {
354     if (use_espi_platform_reset) {
355         MEC_PCR->PRC &= ~MEC_BIT(MEC_PCR_PRC_HOST_RSEL_Pos);
356     } else {
357         MEC_PCR->PRC |= MEC_BIT(MEC_PCR_PRC_HOST_RSEL_Pos);
358     }
359 }
360 
361 /* ---- PCR slow clock (100 kHz domain) ----
362  * PCR block derives a 100 KHz clock from the 48MHz PLL outout.
363  * This clock is used by certain peripherals such as the PWMs.
364  * PCR implements a 10 bit clock divider of its 48MHz PLL output.
365  * The programmable divider defaults to 480 (0x1E0) to produce 100 KHz.
366  */
mec_hal_pcr_slow_clock_freq_get(void)367 uint32_t mec_hal_pcr_slow_clock_freq_get(void)
368 {
369     uint32_t sdiv = MEC_PCR->SCC & MEC_PCR_SCC_SLOW_CLK_DIV_Msk;
370 
371     if (sdiv) {
372         return (48000000U / sdiv);
373     }
374 
375     return 0; /* slow clock is off */
376 }
377 
mec_hal_pcr_slow_clock_freq_set(uint32_t freqhz)378 void mec_hal_pcr_slow_clock_freq_set(uint32_t freqhz)
379 {
380     uint32_t sdiv = 1u;
381 
382     if (!freqhz) {
383         MEC_PCR->SCC = 0; /* turn off slow clock */
384         return;
385     }
386 
387     if (freqhz < 48000000U) {
388         sdiv = 48000000U / freqhz;
389     }
390 
391     if (sdiv > MEC_PCR_SCC_SLOW_CLK_DIV_Msk) {
392         sdiv = MEC_PCR_SCC_SLOW_CLK_DIV_Msk;
393     }
394 
395     MEC_PCR->SCC = (MEC_PCR->SCC & (uint32_t)~MEC_PCR_SCC_SLOW_CLK_DIV_Msk) | sdiv;
396 }
397 
398 /* ---- 32KHz clock configuration ----
399  * !!! WARNING - Requires more testing !!!
400  */
401 
mec_hal_pll_get_clk32k_source(void)402 enum mec_pll_clk32k_src mec_hal_pll_get_clk32k_source(void)
403 {
404     switch (MEC_PCR->SS32K & MEC_PCR_SS32K_PLL_REF_SRC_Msk) {
405         case MEC_PCR_SS32K_PLL_REF_SRC_INTERNAL_OSC:
406             return MEC_PLL_CLK32K_SRC_SI;
407         case MEC_PCR_SS32K_PLL_REF_SRC_CRYSTAL:
408             return MEC_PLL_CLK32K_SRC_XTAL;
409         case MEC_PCR_SS32K_PLL_REF_SRC_PIN_32K_IN:
410             return MEC_PLL_CLK32K_SRC_PIN;
411         default:
412             return MEC_PLL_CLK32K_SRC_NONE;
413     }
414 }
415 
mec_hal_vbr_get_periph_clk32_source(void)416 enum mec_periph_clk32k_src mec_hal_vbr_get_periph_clk32_source(void)
417 {
418     uint32_t cs;
419 
420     cs = (MEC_VBATR->CLK32K_SRC & MEC_VBATR_CLK32K_SRC_PSSEL_Msk) >> MEC_VBATR_CLK32K_SRC_PSSEL_Pos;
421     switch (cs) {
422         case MEC_VBATR_CLK32K_SRC_PSSEL_XTAL:
423             return MEC_PERIPH_CLK32K_SRC_XTAL_XTAL;
424         case MEC_VBATR_CLK32K_SRC_PSSEL_PIN_SIL:
425             return MEC_PERIPH_CLK32K_SRC_PIN_SI;
426         case MEC_VBATR_CLK32K_SRC_PSSEL_PIN_XTAL:
427             return MEC_PERIPH_CLK32K_SRC_PIN_XTAL;
428         default:
429             return MEC_PERIPH_CLK32K_SRC_SI_SI;
430     }
431 }
432 
433 /* Are PLL and Peripheral 32KHz clock source selected and enabled?
434  * return True (non-zero)
435  *        False (zero)
436  */
mec_hal_pcr_clk32k_is_config(enum mec_pll_clk32k_src pll_src,enum mec_periph_clk32k_src periph_src,uint32_t flags)437 int mec_hal_pcr_clk32k_is_config(enum mec_pll_clk32k_src pll_src,
438                              enum mec_periph_clk32k_src periph_src,
439                              uint32_t flags)
440 {
441     uint32_t cs = MEC_VBATR->CLK32K_SRC;
442     enum mec_pll_clk32k_src pll = mec_hal_pll_get_clk32k_source();
443     enum mec_periph_clk32k_src periph = mec_hal_vbr_get_periph_clk32_source();
444     uint32_t temp = 0;
445 
446     if ((pll != pll_src) || (periph != periph_src)) {
447         return 0;
448     }
449 
450     /* is silicon OSC required? */
451     if ((pll == MEC_PLL_CLK32K_SRC_SI) || (periph == MEC_PERIPH_CLK32K_SRC_SI_SI)
452         || (periph == MEC_PERIPH_CLK32K_SRC_PIN_SI)) {
453         /* is Silicon OSC enabled? */
454         if (!(cs & MEC_BIT(MEC_VBATR_CLK32K_SRC_SILOSC_Pos))) {
455             return 0;
456         }
457     }
458 
459     /* is crystal required? */
460     if ((pll_src == MEC_PLL_CLK32K_SRC_XTAL)
461             || (periph_src == MEC_PERIPH_CLK32K_SRC_XTAL_XTAL)
462             || (periph_src == MEC_PERIPH_CLK32K_SRC_PIN_XTAL)) {
463         if (flags & MEC_BIT(MEC_CLK32K_FLAG_XTAL_SE_POS)) {
464             if (!(cs & MEC_BIT(MEC_VBATR_CLK32K_SRC_XTAL_XOSEL_Pos))) {
465                 return 0;
466             }
467         } else {
468             if (cs & MEC_BIT(MEC_VBATR_CLK32K_SRC_XTAL_XOSEL_Pos)) {
469                 return 0;
470             }
471         }
472         /* is crystal enabled? */
473         if (!(cs & MEC_BIT(MEC_VBATR_CLK32K_SRC_XTAL_Pos))) {
474             return 0;
475         }
476     }
477 
478     /* is PIN_32KHZ_IN required? */
479     if ((pll_src == MEC_PLL_CLK32K_SRC_PIN) || (periph_src == MEC_PERIPH_CLK32K_SRC_PIN_SI)
480         || (periph_src == MEC_PERIPH_CLK32K_SRC_PIN_XTAL)) {
481         /* is pin configured? GPIO 0165 Func 1 */
482         mec_hal_gpio_get_property(MEC_PIN_0165, MEC_GPIO_MUX_PROP_ID, (uint8_t *)&temp);
483         if (temp != MEC_GPIO_PROP_MUX_FUNC1) {
484             return 0;
485         }
486     }
487 
488     return 1;
489 }
490 
491 /* Use PCR CLK32 monitor HW to measure crystal input */
492 
check_crystal(struct mec_pcr_clkmon_cfg * cmcfg)493 static int check_crystal(struct mec_pcr_clkmon_cfg *cmcfg)
494 {
495     uint32_t temp = 0;
496     int ret = 0;
497 
498     if (!cmcfg) {
499         return MEC_RET_ERR_INVAL;
500     }
501 
502     /* disable and clear counters */
503     MEC_PCR->CTRL32K = MEC_BIT(MEC_PCR_CTRL32K_CLRCNT_Pos);
504 
505     /* Min and Max period counts */
506     MEC_PCR->PERMINC = cmcfg->period_min;
507     MEC_PCR->PERMAXC = cmcfg->period_max;
508 
509     /* Duty cycle variation maximum count */
510     MEC_PCR->DCVMX = (uint32_t)(cmcfg->duty_var);
511     /* Valid minimum count */
512     MEC_PCR->VCMIN = (uint32_t)(cmcfg->valid_min);
513 
514     /* Start monitor */
515     MEC_PCR->SIS32K = 0xffffffffu;
516     MEC_PCR->CTRL32K = (MEC_BIT(MEC_PCR_CTRL32K_PERIOD_CNT_Pos)
517                         | MEC_BIT(MEC_PCR_CTRL32K_DCNT_EN_Pos)
518                         | MEC_BIT(MEC_PCR_CTRL32K_VALCNT_EN_Pos));
519 
520     do {
521         temp = MEC_PCR->SIS32K;
522     } while ((temp & (MEC_BIT(MEC_PCR_SIS32K_PD_FAIL_Pos)
523                       | MEC_BIT(MEC_PCR_SIS32K_VALID_Pos))) == 0);
524 
525     /* disable and clear counters */
526     MEC_PCR->CTRL32K = MEC_BIT(MEC_PCR_CTRL32K_CLRCNT_Pos);
527     MEC_PCR->SIS32K = 0xffffffffu;
528 
529     if (temp & MEC_BIT(MEC_PCR_SIS32K_PD_FAIL_Pos)) {
530         ret = MEC_RET_ERR_HW;
531     }
532 
533     return ret;
534 }
535 
spin_delay(uint32_t loops)536 static void spin_delay(uint32_t loops)
537 {
538     while (loops--) {
539         __NOP();
540         __NOP();
541         __NOP();
542     }
543 }
544 
pll_clk_src_val(enum mec_pll_clk32k_src pll_src)545 static uint32_t pll_clk_src_val(enum mec_pll_clk32k_src pll_src)
546 {
547     uint32_t regval = 0;
548 
549     switch (pll_src) {
550         case MEC_PLL_CLK32K_SRC_NONE: /* PLL disabled. SoC uses ring oscillator */
551             regval = MEC_PCR_SS32K_PLL_REF_SRC_NONE;
552             break;
553         case MEC_PLL_CLK32K_SRC_SI:
554             regval = MEC_PCR_SS32K_PLL_REF_SRC_INTERNAL_OSC;
555             break;
556         case MEC_PLL_CLK32K_SRC_XTAL:
557             regval = MEC_PCR_SS32K_PLL_REF_SRC_CRYSTAL;
558             break;
559         case MEC_PLL_CLK32K_SRC_PIN:
560             regval = MEC_PCR_SS32K_PLL_REF_SRC_PIN_32K_IN;
561             break;
562         default: /* failsafe bad function argument */
563             regval = MEC_PCR_SS32K_PLL_REF_SRC_INTERNAL_OSC;
564     }
565 
566     return (regval << MEC_PCR_SS32K_PLL_REF_SRC_Pos) & MEC_PCR_SS32K_PLL_REF_SRC_Msk;
567 }
568 
periph_clk_src_val(enum mec_periph_clk32k_src periph_src)569 static uint32_t periph_clk_src_val(enum mec_periph_clk32k_src periph_src)
570 {
571     uint32_t regval = 0;
572 
573     switch (periph_src) {
574         case MEC_PERIPH_CLK32K_SRC_SI_SI:
575             regval = MEC_VBATR_CLK32K_SRC_PSSEL_SILOSC;
576             break;
577         case MEC_PERIPH_CLK32K_SRC_XTAL_XTAL:
578             regval = MEC_VBATR_CLK32K_SRC_PSSEL_XTAL;
579             break;
580         case MEC_PERIPH_CLK32K_SRC_PIN_SI:
581             regval = MEC_VBATR_CLK32K_SRC_PSSEL_PIN_SIL;
582             break;
583         case MEC_PERIPH_CLK32K_SRC_PIN_XTAL:
584             regval = MEC_VBATR_CLK32K_SRC_PSSEL_PIN_XTAL;
585             break;
586         default: /* failsafe for bad function parameter */
587             regval = MEC_VBATR_CLK32K_SRC_PSSEL_SILOSC;
588     }
589 
590     return (regval << MEC_VBATR_CLK32K_SRC_PSSEL_Pos) & MEC_VBATR_CLK32K_SRC_PSSEL_Msk;
591 }
592 
mec_hal_pcr_clk32k_init(enum mec_pll_clk32k_src pll_src,enum mec_periph_clk32k_src periph_src,struct mec_pcr_clkmon_cfg * cfg,uint32_t flags,uint32_t lock_wait)593 int mec_hal_pcr_clk32k_init(enum mec_pll_clk32k_src pll_src,
594                             enum mec_periph_clk32k_src periph_src,
595                             struct mec_pcr_clkmon_cfg *cfg,
596                             uint32_t flags,
597                             uint32_t lock_wait)
598 {
599     uint32_t temp = 0;
600     int ret = 0;
601 
602     if (!cfg) {
603         return MEC_RET_ERR_INVAL;
604     }
605 
606     /* disable and clear counters */
607     MEC_PCR->CTRL32K = MEC_BIT(MEC_PCR_CTRL32K_CLRCNT_Pos);
608 
609     /* HW config matches requested config? */
610     if (mec_hal_pcr_clk32k_is_config(pll_src, periph_src, flags)) {
611         return MEC_RET_OK;
612     }
613 
614     /* enable silicon oscillator */
615     MEC_VBATR->CLK32K_SRC |= MEC_BIT(MEC_VBATR_CLK32K_SRC_SILOSC_Pos);
616     spin_delay(256u);
617 
618     /* configure Peripherals to use silicon oscillator */
619     temp = MEC_VBATR->CLK32K_SRC & (uint32_t)~MEC_VBATR_CLK32K_SRC_PSSEL_Msk;
620     temp |= (MEC_VBATR_CLK32K_SRC_PSSEL_SILOSC << MEC_VBATR_CLK32K_SRC_PSSEL_Pos);
621     MEC_VBATR->CLK32K_SRC = temp;
622 
623     /* configure PLL to use silicon oscillator */
624     temp = MEC_PCR->SS32K & (uint32_t)~MEC_PCR_SS32K_PLL_REF_SRC_Msk;
625     temp |= (MEC_PCR_SS32K_PLL_REF_SRC_INTERNAL_OSC << MEC_PCR_SS32K_PLL_REF_SRC_Pos);
626     MEC_PCR->SS32K = temp;
627     spin_delay(256u);
628 
629     /* If crystal requested configure and enable */
630     if ((pll_src == MEC_PLL_CLK32K_SRC_XTAL)
631             || (periph_src == MEC_PERIPH_CLK32K_SRC_XTAL_XTAL)
632             || (periph_src == MEC_PERIPH_CLK32K_SRC_PIN_XTAL)) {
633 
634         if (flags & MEC_BIT(MEC_CLK32K_FLAG_XTAL_SE_POS)) {
635             MEC_VBATR->CLK32K_SRC |= MEC_BIT(MEC_VBATR_CLK32K_SRC_XTAL_XOSEL_Pos);
636         }
637 
638         /* enable crystal high startup current */
639         MEC_VBATR->CLK32K_SRC |= MEC_BIT(MEC_VBATR_CLK32K_SRC_XTAL_XOSEL_Pos);
640 
641         /* start crystal */
642         MEC_VBATR->CLK32K_SRC |= MEC_BIT(MEC_VBATR_CLK32K_SRC_XTAL_XOSEL_Pos);
643         spin_delay(1000u);
644 
645         /* disable crystal high startup current */
646         MEC_VBATR->CLK32K_SRC |= ~MEC_BIT(MEC_VBATR_CLK32K_SRC_XTAL_XOSEL_Pos);
647 
648         ret = check_crystal(cfg);
649         if (ret) {
650             return ret;
651         }
652     }
653 
654     /* Using 32KHZ_IN pin? */
655     if ((pll_src == MEC_PLL_CLK32K_SRC_PIN)
656             || (periph_src == MEC_PERIPH_CLK32K_SRC_PIN_SI)
657             || (periph_src == MEC_PERIPH_CLK32K_SRC_PIN_XTAL)) {
658         /* configure pin */
659         mec_hal_gpio_set_property(MEC_PIN_0165, MEC_GPIO_INPAD_DIS_PROP_ID, 0);
660         mec_hal_gpio_set_property(MEC_PIN_0165, MEC_GPIO_MUX_PROP_ID,
661                                   MEC_GPIO_PROP_MUX_FUNC1);
662     }
663 
664     /* switch peripherals to new source */
665     temp = MEC_VBATR->CLK32K_SRC & (uint32_t)~MEC_VBATR_CLK32K_SRC_PSSEL_Msk;
666     temp |= periph_clk_src_val(periph_src);
667     MEC_VBATR->CLK32K_SRC = temp;
668 
669     /* switch PLL to new source */
670     temp = MEC_PCR->SS32K & (uint32_t)~MEC_PCR_SS32K_PLL_REF_SRC_Msk;
671     temp |= pll_clk_src_val(pll_src);
672     MEC_PCR->SS32K = temp;
673 
674     /* spin for PLL lock */
675     while (!mec_hal_pcr_is_pll_locked()) {
676         if (lock_wait == 0) {
677             return MEC_RET_ERR_TIMEOUT;
678         }
679         lock_wait--;
680         __NOP();
681         __NOP();
682     }
683 
684     return MEC_RET_OK;
685 }
686 
687 #ifdef MEC5_HAS_PERIPH_PRIVILEGE
688 
mec_hal_pcr_blk_privilege_enable(uint8_t pid,uint8_t enable)689 uint32_t mec_hal_pcr_blk_privilege_enable(uint8_t pid, uint8_t enable)
690 {
691     uint32_t bpos, idx, temp;
692 
693     if (pid >= MEC_PCR_MAX_ID) {
694         return 0;
695     }
696 
697     idx = pid / 32u;
698     bpos = pid % 32u;
699 
700     MEC_PCR->PP_LOCK = MEC_PCR_PRIV_UNLOCK;
701     if (enable) {
702         MEC_PCR->EC_PRIV_EN[idx] |= MEC_BIT(bpos);
703     } else {
704         MEC_PCR->EC_PRIV_EN[idx] &= ~MEC_BIT(bpos);
705     }
706     temp = MEC_PCR->EC_PRIV_EN[idx];
707     MEC_PCR->PP_LOCK = MEC_PCR_PRIV_LOCK;
708 
709     return temp;
710 }
711 
mec_hal_pcr_blk_privilege_mask(uint8_t priv_idx,uint32_t en_mask,uint32_t dis_mask)712 uint32_t mec_hal_pcr_blk_privilege_mask(uint8_t priv_idx, uint32_t en_mask, uint32_t dis_mask)
713 {
714     uint32_t temp;
715 
716     if (priv_idx >= PCR_SLP_EN_IDX_MAX) {
717         return 0;
718     }
719 
720     MEC_PCR->PP_LOCK = MEC_PCR_PRIV_UNLOCK;
721     MEC_PCR->EC_PRIV_EN[priv_idx] = (MEC_PCR->EC_PRIV_EN[priv_idx] & ~dis_mask) | en_mask;
722     temp = MEC_PCR->EC_PRIV_EN[priv_idx];
723     MEC_PCR->PP_LOCK = MEC_PCR_PRIV_LOCK;
724 
725     return temp;
726 }
727 
mec_hal_pcr_save_clk_req_to_vbatm(uint16_t vbatm_byte_ofs)728 void mec_hal_pcr_save_clk_req_to_vbatm(uint16_t vbatm_byte_ofs)
729 {
730     uint32_t rval;
731 
732     for (int i = 0; i < 5; i++) {
733         rval = MEC_PCR->CLK_REQ[i];
734         mec_hal_bbram_wr32(vbatm_byte_ofs, rval);
735         vbatm_byte_ofs += 4u;
736     }
737 
738     rval = MEC_ECS->SSSMR;
739     mec_hal_bbram_wr32(vbatm_byte_ofs, rval);
740 
741     vbatm_byte_ofs += 4u;
742     rval = CoreDebug->DHCSR;
743     mec_hal_bbram_wr32(vbatm_byte_ofs, rval);
744 
745     vbatm_byte_ofs += 4u;
746     rval = CoreDebug->DEMCR;
747     mec_hal_bbram_wr32(vbatm_byte_ofs, rval);
748 }
749 
750 #endif /* MEC5_HAS_PERIPH_PRIVILEGE */
751 /* end mec_pcr.c */
752