1 /*
2  * Copyright (c) 2022 Teslabs Engineering S.L.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT gd_gd32_cctl
8 
9 #include <stdint.h>
10 
11 #include <zephyr/arch/cpu.h>
12 #include <zephyr/device.h>
13 #include <zephyr/devicetree.h>
14 #include <zephyr/drivers/clock_control.h>
15 #include <zephyr/drivers/clock_control/gd32.h>
16 
17 #include <gd32_regs.h>
18 
19 /** RCU offset (from id cell) */
20 #define GD32_CLOCK_ID_OFFSET(id) (((id) >> 6U) & 0xFFU)
21 /** RCU configuration bit (from id cell) */
22 #define GD32_CLOCK_ID_BIT(id)	 ((id)&0x1FU)
23 
24 #define CPU_FREQ DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency)
25 
26 /** AHB prescaler exponents */
27 static const uint8_t ahb_exp[16] = {
28 	0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U, 6U, 7U, 8U, 9U,
29 };
30 /** APB1 prescaler exponents */
31 static const uint8_t apb1_exp[8] = {
32 	0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U,
33 };
34 /** APB2 prescaler exponents */
35 static const uint8_t apb2_exp[8] = {
36 	0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U,
37 };
38 
39 struct clock_control_gd32_config {
40 	uint32_t base;
41 };
42 
43 #if DT_HAS_COMPAT_STATUS_OKAY(gd_gd32_timer)
44 /* timer identifiers */
45 #define TIMER_ID_OR_NONE(nodelabel)                                            \
46 	COND_CODE_1(DT_NODE_HAS_STATUS(DT_NODELABEL(nodelabel), okay),         \
47 		    (DT_CLOCKS_CELL(DT_NODELABEL(nodelabel), id),), ())
48 
49 static const uint16_t timer_ids[] = {
50 	TIMER_ID_OR_NONE(timer0)  /* */
51 	TIMER_ID_OR_NONE(timer1)  /* */
52 	TIMER_ID_OR_NONE(timer2)  /* */
53 	TIMER_ID_OR_NONE(timer3)  /* */
54 	TIMER_ID_OR_NONE(timer4)  /* */
55 	TIMER_ID_OR_NONE(timer5)  /* */
56 	TIMER_ID_OR_NONE(timer6)  /* */
57 	TIMER_ID_OR_NONE(timer7)  /* */
58 	TIMER_ID_OR_NONE(timer8)  /* */
59 	TIMER_ID_OR_NONE(timer9)  /* */
60 	TIMER_ID_OR_NONE(timer10) /* */
61 	TIMER_ID_OR_NONE(timer11) /* */
62 	TIMER_ID_OR_NONE(timer12) /* */
63 	TIMER_ID_OR_NONE(timer13) /* */
64 	TIMER_ID_OR_NONE(timer14) /* */
65 	TIMER_ID_OR_NONE(timer15) /* */
66 	TIMER_ID_OR_NONE(timer16) /* */
67 };
68 #endif /* DT_HAS_COMPAT_STATUS_OKAY(gd_gd32_timer) */
69 
clock_control_gd32_on(const struct device * dev,clock_control_subsys_t sys)70 static int clock_control_gd32_on(const struct device *dev,
71 				 clock_control_subsys_t sys)
72 {
73 	const struct clock_control_gd32_config *config = dev->config;
74 	uint16_t id = *(uint16_t *)sys;
75 
76 	sys_set_bit(config->base + GD32_CLOCK_ID_OFFSET(id),
77 		    GD32_CLOCK_ID_BIT(id));
78 
79 	return 0;
80 }
81 
clock_control_gd32_off(const struct device * dev,clock_control_subsys_t sys)82 static int clock_control_gd32_off(const struct device *dev,
83 				  clock_control_subsys_t sys)
84 {
85 	const struct clock_control_gd32_config *config = dev->config;
86 	uint16_t id = *(uint16_t *)sys;
87 
88 	sys_clear_bit(config->base + GD32_CLOCK_ID_OFFSET(id),
89 		      GD32_CLOCK_ID_BIT(id));
90 
91 	return 0;
92 }
93 
clock_control_gd32_get_rate(const struct device * dev,clock_control_subsys_t sys,uint32_t * rate)94 static int clock_control_gd32_get_rate(const struct device *dev,
95 				       clock_control_subsys_t sys,
96 				       uint32_t *rate)
97 {
98 	const struct clock_control_gd32_config *config = dev->config;
99 	uint16_t id = *(uint16_t *)sys;
100 	uint32_t cfg;
101 	uint8_t psc;
102 
103 	cfg = sys_read32(config->base + RCU_CFG0_OFFSET);
104 
105 	switch (GD32_CLOCK_ID_OFFSET(id)) {
106 #if defined(CONFIG_SOC_SERIES_GD32F4XX)
107 	case RCU_AHB1EN_OFFSET:
108 	case RCU_AHB2EN_OFFSET:
109 	case RCU_AHB3EN_OFFSET:
110 #else
111 	case RCU_AHBEN_OFFSET:
112 #endif
113 		psc = (cfg & RCU_CFG0_AHBPSC_MSK) >> RCU_CFG0_AHBPSC_POS;
114 		*rate = CPU_FREQ >> ahb_exp[psc];
115 		break;
116 	case RCU_APB1EN_OFFSET:
117 #if !defined(CONFIG_SOC_SERIES_GD32VF103) && \
118 	!defined(CONFIG_SOC_SERIES_GD32A50X) && \
119 	!defined(CONFIG_SOC_SERIES_GD32L23X)
120 	case RCU_ADDAPB1EN_OFFSET:
121 #endif
122 		psc = (cfg & RCU_CFG0_APB1PSC_MSK) >> RCU_CFG0_APB1PSC_POS;
123 		*rate = CPU_FREQ >> apb1_exp[psc];
124 		break;
125 	case RCU_APB2EN_OFFSET:
126 		psc = (cfg & RCU_CFG0_APB2PSC_MSK) >> RCU_CFG0_APB2PSC_POS;
127 		*rate = CPU_FREQ >> apb2_exp[psc];
128 		break;
129 	default:
130 		return -ENOTSUP;
131 	}
132 
133 #if DT_HAS_COMPAT_STATUS_OKAY(gd_gd32_timer)
134 	/* handle timer clocks */
135 	for (size_t i = 0U; i < ARRAY_SIZE(timer_ids); i++) {
136 		if (id != timer_ids[i]) {
137 			continue;
138 		}
139 
140 #if defined(CONFIG_SOC_SERIES_GD32F4XX)
141 		uint32_t cfg1 = sys_read32(config->base + RCU_CFG1_OFFSET);
142 
143 		/*
144 		 * The TIMERSEL bit in RCU_CFG1 controls the clock frequency of
145 		 * all the timers connected to the APB1 and APB2 domains.
146 		 *
147 		 * Up to a certain threshold value of APB{1,2} prescaler, timer
148 		 * clock equals to CK_AHB. This threshold value depends on
149 		 * TIMERSEL setting (2 if TIMERSEL=0, 4 if TIMERSEL=1). Above
150 		 * threshold, timer clock is set to a multiple of the APB
151 		 * domain clock CK_APB{1,2} (2 if TIMERSEL=0, 4 if TIMERSEL=1).
152 		 */
153 
154 		/* TIMERSEL = 0 */
155 		if ((cfg1 & RCU_CFG1_TIMERSEL_MSK) == 0U) {
156 			if (psc <= 2U) {
157 				*rate = CPU_FREQ;
158 			} else {
159 				*rate *= 2U;
160 			}
161 		/* TIMERSEL = 1 */
162 		} else {
163 			if (psc <= 4U) {
164 				*rate = CPU_FREQ;
165 			} else {
166 				*rate *= 4U;
167 			}
168 		}
169 #else
170 		/*
171 		 * If the APB prescaler equals 1, the timer clock frequencies
172 		 * are set to the same frequency as that of the APB domain.
173 		 * Otherwise, they are set to twice the frequency of the APB
174 		 * domain.
175 		 */
176 		if (psc != 1U) {
177 			*rate *= 2U;
178 		}
179 #endif /* CONFIG_SOC_SERIES_GD32F4XX */
180 	}
181 #endif /* DT_HAS_COMPAT_STATUS_OKAY(gd_gd32_timer) */
182 
183 	return 0;
184 }
185 
186 static enum clock_control_status
clock_control_gd32_get_status(const struct device * dev,clock_control_subsys_t sys)187 clock_control_gd32_get_status(const struct device *dev,
188 			      clock_control_subsys_t sys)
189 {
190 	const struct clock_control_gd32_config *config = dev->config;
191 	uint16_t id = *(uint16_t *)sys;
192 
193 	if (sys_test_bit(config->base + GD32_CLOCK_ID_OFFSET(id),
194 			 GD32_CLOCK_ID_BIT(id)) != 0) {
195 		return CLOCK_CONTROL_STATUS_ON;
196 	}
197 
198 	return CLOCK_CONTROL_STATUS_OFF;
199 }
200 
201 static struct clock_control_driver_api clock_control_gd32_api = {
202 	.on = clock_control_gd32_on,
203 	.off = clock_control_gd32_off,
204 	.get_rate = clock_control_gd32_get_rate,
205 	.get_status = clock_control_gd32_get_status,
206 };
207 
208 static const struct clock_control_gd32_config config = {
209 	.base = DT_REG_ADDR(DT_INST_PARENT(0)),
210 };
211 
212 DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, &config, PRE_KERNEL_1,
213 		      CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
214 		      &clock_control_gd32_api);
215