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