1 /*
2  * Copyright (c) 2022 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 
9 #include <zephyr/device.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/spinlock.h>
12 
13 #include <adsp_clk.h>
14 #include <adsp_shim.h>
15 
16 static struct adsp_clock_info platform_clocks[CONFIG_MP_MAX_NUM_CPUS];
17 static struct k_spinlock lock;
18 
19 int adsp_clock_freq_enc[] = ADSP_CLOCK_FREQ_ENC;
20 int adsp_clock_freq_mask[] = ADSP_CLOCK_FREQ_MASK;
21 
select_cpu_clock_hw(uint32_t freq_idx)22 static void select_cpu_clock_hw(uint32_t freq_idx)
23 {
24 	uint32_t enc = adsp_clock_freq_enc[freq_idx];
25 	uint32_t status_mask = adsp_clock_freq_mask[freq_idx];
26 
27 	/* Request clock */
28 	ADSP_CLKCTL |= enc;
29 
30 	/* Wait for requested clock to be on */
31 	while ((ADSP_CLKCTL & status_mask) != status_mask) {
32 		k_busy_wait(10);
33 	}
34 
35 	/* Switch to requested clock */
36 	ADSP_CLKCTL = (ADSP_CLKCTL & ~ADSP_CLKCTL_OSC_SOURCE_MASK) |
37 			    enc;
38 
39 	/* Release other clocks */
40 	ADSP_CLKCTL &= ~ADSP_CLKCTL_OSC_REQUEST_MASK | enc;
41 }
42 
adsp_clock_set_freq(uint32_t freq_idx)43 int adsp_clock_set_freq(uint32_t freq_idx)
44 {
45 	k_spinlock_key_t k;
46 	int i;
47 
48 	if (freq_idx >= ADSP_CLOCK_FREQ_LEN) {
49 		return -EINVAL;
50 	}
51 
52 	k = k_spin_lock(&lock);
53 
54 	select_cpu_clock_hw(freq_idx);
55 
56 	unsigned int num_cpus = arch_num_cpus();
57 
58 	for (i = 0; i < num_cpus; i++) {
59 		platform_clocks[i].current_freq = freq_idx;
60 	}
61 
62 	k_spin_unlock(&lock, k);
63 
64 	return 0;
65 }
66 
adsp_clocks_get(void)67 struct adsp_clock_info *adsp_clocks_get(void)
68 {
69 	return platform_clocks;
70 }
71 
adsp_clock_init(void)72 void adsp_clock_init(void)
73 {
74 	uint32_t platform_lowest_freq_idx = ADSP_CLOCK_FREQ_LOWEST;
75 	int i;
76 
77 #ifdef ADSP_CLOCK_HAS_WOVCRO
78 #ifdef CONFIG_SOC_SERIES_INTEL_ACE
79 	ACE_DfPMCCU.dfclkctl |= ACE_CLKCTL_WOVCRO;
80 	if (ACE_DfPMCCU.dfclkctl & ACE_CLKCTL_WOVCRO) {
81 		ACE_DfPMCCU.dfclkctl = ACE_DfPMCCU.dfclkctl & ~ACE_CLKCTL_WOVCRO;
82 	} else {
83 		platform_lowest_freq_idx = ADSP_CLOCK_FREQ_LPRO;
84 	}
85 #else
86 	CAVS_SHIM.clkctl |= CAVS_CLKCTL_WOVCRO;
87 	if (CAVS_SHIM.clkctl & CAVS_CLKCTL_WOVCRO) {
88 		CAVS_SHIM.clkctl = CAVS_SHIM.clkctl & ~CAVS_CLKCTL_WOVCRO;
89 	} else {
90 		platform_lowest_freq_idx = ADSP_CLOCK_FREQ_LPRO;
91 	}
92 #endif /* CONFIG_SOC_SERIES_INTEL_ACE */
93 #endif /* ADSP_CLOCK_HAS_WOVCRO */
94 
95 	unsigned int num_cpus = arch_num_cpus();
96 
97 	for (i = 0; i < num_cpus; i++) {
98 		platform_clocks[i].default_freq = ADSP_CLOCK_FREQ_DEFAULT;
99 		platform_clocks[i].current_freq = ADSP_CLOCK_FREQ_DEFAULT;
100 		platform_clocks[i].lowest_freq = platform_lowest_freq_idx;
101 	}
102 }
103