1 /*
2  * Copyright (c) 2016 Linaro Limited.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT arm_beetle_syscon
8 
9 /**
10  * @file
11  * @brief Driver for Clock Control of Beetle MCUs.
12  *
13  * This file contains the Clock Control driver implementation for the
14  * Beetle MCUs.
15  */
16 
17 #include <soc.h>
18 #include <zephyr/drivers/clock_control.h>
19 #include <zephyr/irq.h>
20 #include <zephyr/sys/util.h>
21 #include <zephyr/drivers/clock_control/arm_clock_control.h>
22 
23 #define MAINCLK_BASE_FREQ 24000000
24 
25 struct beetle_clock_control_cfg_t {
26 	/* Clock Control ID */
27 	uint32_t clock_control_id;
28 	/* Clock control freq */
29 	uint32_t freq;
30 };
31 
beetle_set_clock(volatile uint32_t * base,uint8_t bit,enum arm_soc_state_t state)32 static inline void beetle_set_clock(volatile uint32_t *base,
33 				    uint8_t bit, enum arm_soc_state_t state)
34 {
35 	uint32_t key;
36 
37 	key = irq_lock();
38 
39 	switch (state) {
40 	case SOC_ACTIVE:
41 		base[0] |= (1 << bit);
42 		break;
43 	case SOC_SLEEP:
44 		base[2] |= (1 << bit);
45 		break;
46 	case SOC_DEEPSLEEP:
47 		base[4] |= (1 << bit);
48 		break;
49 	default:
50 		break;
51 	}
52 
53 	irq_unlock(key);
54 }
55 
beetle_ahb_set_clock_on(uint8_t bit,enum arm_soc_state_t state)56 static inline void beetle_ahb_set_clock_on(uint8_t bit,
57 					   enum arm_soc_state_t state)
58 {
59 	beetle_set_clock((volatile uint32_t *)&(__BEETLE_SYSCON->ahbclkcfg0set),
60 			 bit, state);
61 }
62 
beetle_ahb_set_clock_off(uint8_t bit,enum arm_soc_state_t state)63 static inline void beetle_ahb_set_clock_off(uint8_t bit,
64 					    enum arm_soc_state_t state)
65 {
66 	beetle_set_clock((volatile uint32_t *)&(__BEETLE_SYSCON->ahbclkcfg0clr),
67 			 bit, state);
68 }
69 
beetle_apb_set_clock_on(uint8_t bit,enum arm_soc_state_t state)70 static inline void beetle_apb_set_clock_on(uint8_t bit,
71 					   enum arm_soc_state_t state)
72 {
73 	beetle_set_clock((volatile uint32_t *)&(__BEETLE_SYSCON->apbclkcfg0set),
74 			 bit, state);
75 }
76 
beetle_apb_set_clock_off(uint8_t bit,enum arm_soc_state_t state)77 static inline void beetle_apb_set_clock_off(uint8_t bit,
78 					    enum arm_soc_state_t state)
79 {
80 	beetle_set_clock((volatile uint32_t *)&(__BEETLE_SYSCON->apbclkcfg0clr),
81 			 bit, state);
82 }
83 
beetle_clock_control_on(const struct device * dev,clock_control_subsys_t sub_system)84 static inline int beetle_clock_control_on(const struct device *dev,
85 					  clock_control_subsys_t sub_system)
86 {
87 	struct arm_clock_control_t *beetle_cc =
88 				(struct arm_clock_control_t *)(sub_system);
89 
90 	uint8_t bit = 0U;
91 
92 	switch (beetle_cc->bus) {
93 	case CMSDK_AHB:
94 		bit = (beetle_cc->device - _BEETLE_AHB_BASE) >> 12;
95 		beetle_ahb_set_clock_on(bit, beetle_cc->state);
96 		break;
97 	case CMSDK_APB:
98 		bit = (beetle_cc->device - _BEETLE_APB_BASE) >> 12;
99 		beetle_apb_set_clock_on(bit, beetle_cc->state);
100 		break;
101 	default:
102 		break;
103 	}
104 
105 	return 0;
106 }
107 
beetle_clock_control_off(const struct device * dev,clock_control_subsys_t sub_system)108 static inline int beetle_clock_control_off(const struct device *dev,
109 					   clock_control_subsys_t sub_system)
110 {
111 	struct arm_clock_control_t *beetle_cc =
112 				(struct arm_clock_control_t *)(sub_system);
113 
114 	uint8_t bit = 0U;
115 
116 	switch (beetle_cc->bus) {
117 	case CMSDK_AHB:
118 		bit = (beetle_cc->device - _BEETLE_AHB_BASE) >> 12;
119 		beetle_ahb_set_clock_off(bit, beetle_cc->state);
120 		break;
121 	case CMSDK_APB:
122 		bit = (beetle_cc->device - _BEETLE_APB_BASE) >> 12;
123 		beetle_apb_set_clock_off(bit, beetle_cc->state);
124 		break;
125 	default:
126 		break;
127 	}
128 	return 0;
129 }
130 
beetle_clock_control_get_subsys_rate(const struct device * clock,clock_control_subsys_t sub_system,uint32_t * rate)131 static int beetle_clock_control_get_subsys_rate(const struct device *clock,
132 						clock_control_subsys_t sub_system,
133 						uint32_t *rate)
134 {
135 #ifdef CONFIG_CLOCK_CONTROL_BEETLE_ENABLE_PLL
136 	const struct beetle_clock_control_cfg_t * const cfg =
137 						clock->config;
138 	uint32_t nc_mainclk = beetle_round_freq(cfg->freq);
139 
140 	*rate = nc_mainclk;
141 #else
142 	ARG_UNUSED(clock);
143 	ARG_UNUSED(sub_system);
144 
145 	*rate = MAINCLK_BASE_FREQ;
146 #endif /* CONFIG_CLOCK_CONTROL_BEETLE_ENABLE_PLL */
147 
148 	return 0;
149 }
150 
151 static const struct clock_control_driver_api beetle_clock_control_api = {
152 	.on = beetle_clock_control_on,
153 	.off = beetle_clock_control_off,
154 	.get_rate = beetle_clock_control_get_subsys_rate,
155 };
156 
157 #ifdef CONFIG_CLOCK_CONTROL_BEETLE_ENABLE_PLL
beetle_round_freq(uint32_t mainclk)158 static uint32_t beetle_round_freq(uint32_t mainclk)
159 {
160 	uint32_t nc_mainclk = 0U;
161 
162 	/*
163 	 * Verify that the frequency is in the supported range otherwise
164 	 * round it to the next closer one.
165 	 */
166 	if (mainclk <= BEETLE_PLL_FREQUENCY_12MHZ) {
167 		nc_mainclk = BEETLE_PLL_FREQUENCY_12MHZ;
168 	} else if (mainclk <= BEETLE_PLL_FREQUENCY_24MHZ) {
169 		nc_mainclk = BEETLE_PLL_FREQUENCY_24MHZ;
170 	} else if (mainclk <= BEETLE_PLL_FREQUENCY_36MHZ) {
171 		nc_mainclk = BEETLE_PLL_FREQUENCY_36MHZ;
172 	} else {
173 		nc_mainclk = BEETLE_PLL_FREQUENCY_48MHZ;
174 	}
175 
176 	return nc_mainclk;
177 }
178 
beetle_get_prescaler(uint32_t mainclk)179 static uint32_t beetle_get_prescaler(uint32_t mainclk)
180 {
181 	uint32_t pre_mainclk = 0U;
182 
183 	/*
184 	 * Verify that the frequency is in the supported range otherwise
185 	 * round it to the next closer one.
186 	 */
187 	if (mainclk <= BEETLE_PLL_FREQUENCY_12MHZ) {
188 		pre_mainclk = BEETLE_PLL_PRESCALER_12MHZ;
189 	} else if (mainclk <= BEETLE_PLL_FREQUENCY_24MHZ) {
190 		pre_mainclk = BEETLE_PLL_PRESCALER_24MHZ;
191 	} else if (mainclk <= BEETLE_PLL_FREQUENCY_36MHZ) {
192 		pre_mainclk = BEETLE_PLL_PRESCALER_36MHZ;
193 	} else {
194 		pre_mainclk = BEETLE_PLL_PRESCALER_48MHZ;
195 	}
196 
197 	return pre_mainclk;
198 }
199 
beetle_pll_enable(uint32_t mainclk)200 static int beetle_pll_enable(uint32_t mainclk)
201 {
202 
203 	uint32_t pre_mainclk = beetle_get_prescaler(mainclk);
204 
205 	/* Set PLLCTRL Register */
206 	__BEETLE_SYSCON->pllctrl = BEETLE_PLL_CONFIGURATION;
207 
208 	/* Switch the the Main clock to PLL and set prescaler */
209 	__BEETLE_SYSCON->mainclk = pre_mainclk;
210 
211 	while (!__BEETLE_SYSCON->pllstatus) {
212 		/* Wait for PLL to lock */
213 	}
214 
215 	return 0;
216 }
217 #endif /* CONFIG_CLOCK_CONTROL_BEETLE_ENABLE_PLL */
218 
beetle_clock_control_init(const struct device * dev)219 static int beetle_clock_control_init(const struct device *dev)
220 {
221 #ifdef CONFIG_CLOCK_CONTROL_BEETLE_ENABLE_PLL
222 	const struct beetle_clock_control_cfg_t * const cfg =
223 						dev->config;
224 
225 	/*
226 	 * Enable PLL if Beetle is configured to run at a different
227 	 * frequency than 24Mhz.
228 	 */
229 	if (cfg->freq != MAINCLK_BASE_FREQ) {
230 		beetle_pll_enable(cfg->freq);
231 	}
232 #endif /* CONFIG_CLOCK_CONTROL_BEETLE_ENABLE_PLL */
233 
234 	return 0;
235 }
236 
237 static const struct beetle_clock_control_cfg_t beetle_cc_cfg = {
238 	.clock_control_id = 0,
239 	.freq = DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency),
240 };
241 
242 /**
243  * @brief Clock Control device init
244  *
245  */
246 DEVICE_DT_INST_DEFINE(0, &beetle_clock_control_init, NULL,
247 		      NULL, &beetle_cc_cfg, PRE_KERNEL_1,
248 		      CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
249 		      &beetle_clock_control_api);
250