1 /*
2  * Copyright (c) 2024 Nuvoton Technology Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nuvoton_npcm_pcc
8 
9 #include <soc.h>
10 #include <zephyr/drivers/clock_control.h>
11 #include <zephyr/dt-bindings/clock/npcm_clock.h>
12 
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(clock_control_npcm, LOG_LEVEL_ERR);
15 
16 /* Driver config */
17 struct npcm_pcc_config {
18 	/* cdcg device base address */
19 	uintptr_t base_cdcg;
20 	/* pmc device base address */
21 	uintptr_t base_pmc;
22 };
23 
24 /*
25  * Core Domain Clock Generator (CDCG) device registers
26  */
27 struct cdcg_reg {
28 	/* High Frequency Clock Generator (HFCG) registers */
29 	/* 0x000: HFCG Control */
30 	volatile uint8_t hfcgctrl;
31 	volatile uint8_t reserved1;
32 	/* 0x002: HFCG M Low Byte Value */
33 	volatile uint8_t hfcgml;
34 	volatile uint8_t reserved2;
35 	/* 0x004: HFCG M High Byte Value */
36 	volatile uint8_t hfcgmh;
37 	volatile uint8_t reserved3;
38 	/* 0x006: HFCG N Value */
39 	volatile uint8_t hfcgn;
40 	volatile uint8_t reserved4;
41 	/* 0x008: HFCG Prescaler */
42 	volatile uint8_t hfcgp;
43 	volatile uint8_t reserved5[7];
44 	/* 0x010: HFCG Bus Clock Dividers */
45 	volatile uint8_t hfcbcd;
46 	volatile uint8_t reserved6;
47 	/* 0x012: HFCG Bus Clock Dividers */
48 	volatile uint8_t hfcbcd1;
49 	volatile uint8_t reserved7;
50 	/* 0x014: HFCG Bus Clock Dividers */
51 	volatile uint8_t hfcbcd2;
52 	volatile uint8_t reserved12[8];
53 	/* 0x01d: HFCG Bus Clock Dividers */
54 	volatile uint8_t hfcbcd3;
55 };
56 
57 /* clock bus references */
58 #define NPCM_CLOCK_BUS_LFCLK     0
59 #define NPCM_CLOCK_BUS_OSC       1
60 #define NPCM_CLOCK_BUS_FIU       2
61 #define NPCM_CLOCK_BUS_I3C       3
62 #define NPCM_CLOCK_BUS_CORE      4
63 #define NPCM_CLOCK_BUS_APB1      5
64 #define NPCM_CLOCK_BUS_APB2      6
65 #define NPCM_CLOCK_BUS_APB3      7
66 #define NPCM_CLOCK_BUS_APB4      8
67 #define NPCM_CLOCK_BUS_AHB6      9
68 #define NPCM_CLOCK_BUS_FMCLK     10
69 #define NPCM_CLOCK_BUS_USB20_CLK 11
70 #define NPCM_CLOCK_BUS_SIO_CLK   12
71 
72 /* clock enable/disable references */
73 #define NPCM_PWDWN_CTL0 0
74 #define NPCM_PWDWN_CTL1 1
75 #define NPCM_PWDWN_CTL2 2
76 #define NPCM_PWDWN_CTL3 3
77 #define NPCM_PWDWN_CTL4 4
78 #define NPCM_PWDWN_CTL5 5
79 #define NPCM_PWDWN_CTL6 6
80 #define NPCM_PWDWN_CTL7 7
81 
82 /* CDCG register fields */
83 #define NPCM_HFCGCTRL_LOAD     0
84 #define NPCM_HFCGCTRL_LOCK     2
85 #define NPCM_HFCGCTRL_CLK_CHNG 7
86 
87 /* Clock settings from pcc node */
88 /* Target OFMCLK freq */
89 #define OFMCLK      DT_PROP(DT_NODELABEL(pcc), clock_frequency)
90 /* Core clock prescaler */
91 #define FPRED_VAL   (DT_PROP(DT_NODELABEL(pcc), core_prescaler) - 1)
92 /* APB1 clock divider */
93 #define APB1DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb1_prescaler) - 1)
94 /* APB2 clock divider */
95 #define APB2DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb2_prescaler) - 1)
96 /* APB3 clock divider */
97 #define APB3DIV_VAL (DT_PROP(DT_NODELABEL(pcc), apb3_prescaler) - 1)
98 /* AHB6 clock divider*/
99 #define AHB6DIV_VAL (DT_PROP(DT_NODELABEL(pcc), ahb6_prescaler) - 1)
100 /* FIU clock divider */
101 #define FIUDIV_VAL  (DT_PROP(DT_NODELABEL(pcc), fiu_prescaler) - 1)
102 /* I3C clock divider */
103 #define I3CDIV_VAL  (DT_PROP(DT_NODELABEL(pcc), i3c_prescaler) - 1)
104 
105 /* Core domain clock */
106 #define CORE_CLK           (OFMCLK / DT_PROP(DT_NODELABEL(pcc), core_prescaler))
107 /* Low Frequency clock */
108 #define LFCLK              32768
109 /* FMUL clock */
110 #define FMCLK              OFMCLK /* FMUL clock = OFMCLK */
111 /* APBs source clock */
112 #define APBSRC_CLK         OFMCLK
113 /* USB2.0 clock */
114 #define USB20_CLK          12000000
115 /* SIO clock */
116 #define SIO_CLK            48000000
117 /* Get APB clock freq */
118 #define NPCM_APB_CLOCK(no) (APBSRC_CLK / (APB##no##DIV_VAL + 1))
119 
120 struct freq_multiplier_t {
121 	uint32_t ofmclk;
122 	uint8_t hfcgn;
123 	uint8_t hfcgmh;
124 	uint8_t hfcgml;
125 };
126 
127 static struct freq_multiplier_t freq_multiplier[] = {
128 	{.ofmclk = 100000000, .hfcgn = 0x82, .hfcgmh = 0x0B, .hfcgml = 0xEC},
129 	{.ofmclk = 96000000, .hfcgn = 0x82, .hfcgmh = 0x0B, .hfcgml = 0x72},
130 	{.ofmclk = 80000000, .hfcgn = 0x82, .hfcgmh = 0x09, .hfcgml = 0x89},
131 	{.ofmclk = 66000000, .hfcgn = 0x82, .hfcgmh = 0x07, .hfcgml = 0xDE},
132 	{.ofmclk = 50000000, .hfcgn = 0x02, .hfcgmh = 0x0B, .hfcgml = 0xEC},
133 	{.ofmclk = 48000000, .hfcgn = 0x02, .hfcgmh = 0x0B, .hfcgml = 0x72},
134 	{.ofmclk = 40000000, .hfcgn = 0x02, .hfcgmh = 0x09, .hfcgml = 0x89},
135 	{.ofmclk = 33000000, .hfcgn = 0x02, .hfcgmh = 0x07, .hfcgml = 0xDE}};
136 
137 struct clk_cfg_t {
138 	uint32_t clock_id;
139 	uint16_t bus;
140 };
141 
142 static struct clk_cfg_t clk_cfg[] = {
143 	{.clock_id = NPCM_CLOCK_PWM_I, .bus = NPCM_CLOCK_BUS_LFCLK},
144 	{.clock_id = NPCM_CLOCK_PWM_J, .bus = NPCM_CLOCK_BUS_LFCLK},
145 	{.clock_id = NPCM_CLOCK_I3CI, .bus = NPCM_CLOCK_BUS_APB3},
146 	{.clock_id = NPCM_CLOCK_UART3, .bus = NPCM_CLOCK_BUS_APB2},
147 	{.clock_id = NPCM_CLOCK_UART2, .bus = NPCM_CLOCK_BUS_APB2},
148 
149 	{.clock_id = NPCM_CLOCK_FIU, .bus = NPCM_CLOCK_BUS_FIU},
150 	{.clock_id = NPCM_CLOCK_USB20, .bus = NPCM_CLOCK_BUS_USB20_CLK},
151 	{.clock_id = NPCM_CLOCK_UART, .bus = NPCM_CLOCK_BUS_APB2},
152 
153 	{.clock_id = NPCM_CLOCK_PWM_A, .bus = NPCM_CLOCK_BUS_LFCLK},
154 	{.clock_id = NPCM_CLOCK_PWM_B, .bus = NPCM_CLOCK_BUS_LFCLK},
155 	{.clock_id = NPCM_CLOCK_PWM_C, .bus = NPCM_CLOCK_BUS_LFCLK},
156 	{.clock_id = NPCM_CLOCK_PWM_D, .bus = NPCM_CLOCK_BUS_LFCLK},
157 	{.clock_id = NPCM_CLOCK_PWM_E, .bus = NPCM_CLOCK_BUS_LFCLK},
158 	{.clock_id = NPCM_CLOCK_PWM_F, .bus = NPCM_CLOCK_BUS_LFCLK},
159 	{.clock_id = NPCM_CLOCK_PWM_G, .bus = NPCM_CLOCK_BUS_LFCLK},
160 	{.clock_id = NPCM_CLOCK_PWM_H, .bus = NPCM_CLOCK_BUS_LFCLK},
161 
162 	{.clock_id = NPCM_CLOCK_SMB1, .bus = NPCM_CLOCK_BUS_APB3},
163 	{.clock_id = NPCM_CLOCK_SMB2, .bus = NPCM_CLOCK_BUS_APB3},
164 	{.clock_id = NPCM_CLOCK_SMB3, .bus = NPCM_CLOCK_BUS_APB3},
165 	{.clock_id = NPCM_CLOCK_SMB4, .bus = NPCM_CLOCK_BUS_APB3},
166 	{.clock_id = NPCM_CLOCK_SMB5, .bus = NPCM_CLOCK_BUS_APB3},
167 	{.clock_id = NPCM_CLOCK_SMB6, .bus = NPCM_CLOCK_BUS_APB3},
168 
169 	{.clock_id = NPCM_CLOCK_ITIM1, .bus = NPCM_CLOCK_BUS_LFCLK},
170 	{.clock_id = NPCM_CLOCK_ITIM2, .bus = NPCM_CLOCK_BUS_LFCLK},
171 	{.clock_id = NPCM_CLOCK_ITIM3, .bus = NPCM_CLOCK_BUS_LFCLK},
172 	{.clock_id = NPCM_CLOCK_ADC, .bus = NPCM_CLOCK_BUS_APB1},
173 	{.clock_id = NPCM_CLOCK_PECI, .bus = NPCM_CLOCK_BUS_FMCLK},
174 
175 	{.clock_id = NPCM_CLOCK_UART4, .bus = NPCM_CLOCK_BUS_APB2},
176 
177 	{.clock_id = NPCM_CLOCK_ESPI, .bus = NPCM_CLOCK_BUS_APB3},
178 
179 	{.clock_id = NPCM_CLOCK_SMB7, .bus = NPCM_CLOCK_BUS_APB3},
180 	{.clock_id = NPCM_CLOCK_SMB8, .bus = NPCM_CLOCK_BUS_APB3},
181 	{.clock_id = NPCM_CLOCK_SMB9, .bus = NPCM_CLOCK_BUS_APB3},
182 	{.clock_id = NPCM_CLOCK_SMB10, .bus = NPCM_CLOCK_BUS_APB3},
183 	{.clock_id = NPCM_CLOCK_SMB11, .bus = NPCM_CLOCK_BUS_APB3},
184 	{.clock_id = NPCM_CLOCK_SMB12, .bus = NPCM_CLOCK_BUS_APB3},
185 };
186 
187 /* PMC multi-registers */
188 #define NPCM_PWDWN_CTL_OFFSET(n)     (((n) < 7) ? (0x07 + n) : (0x15 + (n - 7)))
189 #define NPCM_PWDWN_CTL(base, n)      (*(volatile uint8_t *)(base + NPCM_PWDWN_CTL_OFFSET(n)))
190 #define NPCM_CLOCK_REG_OFFSET(n)     ((n) >> 3)
191 #define NPCM_CLOCK_REG_BIT_OFFSET(n) ((n) & 0x7)
192 
193 #define DRV_CONFIG(dev) ((const struct npcm_pcc_config *)(dev)->config)
194 
195 /* Clock controller local functions */
npcm_get_cfg(clock_control_subsys_t sub_system)196 static struct clk_cfg_t *npcm_get_cfg(clock_control_subsys_t sub_system)
197 {
198 	uint32_t clk_id = (uint32_t)sub_system;
199 	uint32_t i;
200 
201 	for (i = 0; i < ARRAY_SIZE(clk_cfg); i++) {
202 		if (clk_cfg[i].clock_id == clk_id) {
203 			return &clk_cfg[i];
204 		}
205 	}
206 
207 	return NULL;
208 }
209 
npcm_clock_control_on(const struct device * dev,clock_control_subsys_t sub_system)210 static inline int npcm_clock_control_on(const struct device *dev, clock_control_subsys_t sub_system)
211 {
212 	uint32_t clk_id = (uint32_t)sub_system;
213 	struct clk_cfg_t *priv;
214 	const uint32_t pmc_base = DRV_CONFIG(dev)->base_pmc;
215 
216 	priv = npcm_get_cfg(sub_system);
217 	if (!priv) {
218 		LOG_ERR("Unsupported clock id %d", clk_id);
219 		return -EINVAL;
220 	}
221 
222 	/* Clear related PD (Power-Down) bit of module to turn on clock */
223 	NPCM_PWDWN_CTL(pmc_base, NPCM_CLOCK_REG_OFFSET(priv->clock_id)) &=
224 		~(BIT(NPCM_CLOCK_REG_BIT_OFFSET(priv->clock_id)));
225 	return 0;
226 }
227 
npcm_clock_control_off(const struct device * dev,clock_control_subsys_t sub_system)228 static inline int npcm_clock_control_off(const struct device *dev,
229 					 clock_control_subsys_t sub_system)
230 {
231 	uint32_t clk_id = (uint32_t)sub_system;
232 	struct clk_cfg_t *priv;
233 	const uint32_t pmc_base = DRV_CONFIG(dev)->base_pmc;
234 
235 	priv = npcm_get_cfg(sub_system);
236 	if (!priv) {
237 		LOG_ERR("Unsupported clock id %d", clk_id);
238 		return -EINVAL;
239 	}
240 
241 	/* Set related PD (Power-Down) bit of module to turn off clock */
242 	NPCM_PWDWN_CTL(pmc_base, NPCM_CLOCK_REG_OFFSET(priv->clock_id)) |=
243 		~(BIT(NPCM_CLOCK_REG_BIT_OFFSET(priv->clock_id)));
244 	return 0;
245 }
246 
npcm_clock_control_get_subsys_rate(const struct device * dev,clock_control_subsys_t sub_system,uint32_t * rate)247 static int npcm_clock_control_get_subsys_rate(const struct device *dev,
248 					      clock_control_subsys_t sub_system, uint32_t *rate)
249 {
250 	ARG_UNUSED(dev);
251 	uint32_t clk_id = (uint32_t)sub_system;
252 	struct clk_cfg_t *priv;
253 
254 	priv = npcm_get_cfg(sub_system);
255 	if (!priv) {
256 		LOG_ERR("Unsupported clock id %d", clk_id);
257 		return -EINVAL;
258 	}
259 
260 	switch (priv->bus) {
261 	case NPCM_CLOCK_BUS_APB1:
262 		*rate = NPCM_APB_CLOCK(1);
263 		break;
264 	case NPCM_CLOCK_BUS_APB2:
265 		*rate = NPCM_APB_CLOCK(2);
266 		break;
267 	case NPCM_CLOCK_BUS_APB3:
268 		*rate = NPCM_APB_CLOCK(3);
269 		break;
270 	case NPCM_CLOCK_BUS_AHB6:
271 		*rate = CORE_CLK / (AHB6DIV_VAL + 1);
272 		break;
273 	case NPCM_CLOCK_BUS_FIU:
274 		*rate = CORE_CLK / (FIUDIV_VAL + 1);
275 		break;
276 	case NPCM_CLOCK_BUS_I3C:
277 		*rate = CORE_CLK / (I3CDIV_VAL + 1);
278 		break;
279 	case NPCM_CLOCK_BUS_CORE:
280 		*rate = CORE_CLK;
281 		break;
282 	case NPCM_CLOCK_BUS_LFCLK:
283 		*rate = LFCLK;
284 		break;
285 	case NPCM_CLOCK_BUS_FMCLK:
286 		*rate = FMCLK;
287 		break;
288 	case NPCM_CLOCK_BUS_USB20_CLK:
289 		*rate = USB20_CLK;
290 		break;
291 	case NPCM_CLOCK_BUS_SIO_CLK:
292 		*rate = SIO_CLK;
293 		break;
294 	default:
295 		*rate = 0U;
296 		/* Invalid parameters */
297 		return -EINVAL;
298 	}
299 
300 	return 0;
301 }
302 
303 /* Clock controller driver registration */
304 static DEVICE_API(clock_control, npcm_clock_control_api) = {
305 	.on = npcm_clock_control_on,
306 	.off = npcm_clock_control_off,
307 	.get_rate = npcm_clock_control_get_subsys_rate,
308 };
309 
npcm_clock_control_init(const struct device * dev)310 static int npcm_clock_control_init(const struct device *dev)
311 {
312 	struct cdcg_reg *const priv = (struct cdcg_reg *)(DRV_CONFIG(dev)->base_cdcg);
313 	struct freq_multiplier_t *freq_p;
314 	int i;
315 
316 	for (i = 0; i < ARRAY_SIZE(freq_multiplier); i++) {
317 		if (freq_multiplier[i].ofmclk == OFMCLK) {
318 			freq_p = &freq_multiplier[i];
319 			break;
320 		}
321 	}
322 
323 	if (i >= ARRAY_SIZE(freq_multiplier)) {
324 		LOG_ERR("Unsupported OFMCLK frequency %d", OFMCLK);
325 		return -EINVAL;
326 	}
327 
328 	/*
329 	 * Resetting the OFMCLK (even to the same value) will make the clock
330 	 * unstable for a little which can affect peripheral communication like
331 	 * eSPI. Skip this if not needed.
332 	 */
333 	if (priv->hfcgn != freq_p->hfcgn || priv->hfcgml != freq_p->hfcgml ||
334 	    priv->hfcgmh != freq_p->hfcgmh) {
335 		/*
336 		 * Configure frequency multiplier M/N values according to
337 		 * the requested OFMCLK (Unit:Hz).
338 		 */
339 		priv->hfcgn = freq_p->hfcgn;
340 		priv->hfcgml = freq_p->hfcgml;
341 		priv->hfcgmh = freq_p->hfcgmh;
342 
343 		/* Load M and N values into the frequency multiplier */
344 		priv->hfcgctrl |= BIT(NPCM_HFCGCTRL_LOAD);
345 		/* Wait for stable */
346 		while (sys_test_bit(priv->hfcgctrl, NPCM_HFCGCTRL_CLK_CHNG))
347 			;
348 	}
349 
350 	/* Set all clock prescalers of core and peripherals. */
351 	priv->hfcgp = (FPRED_VAL << 4) | AHB6DIV_VAL;
352 	priv->hfcbcd = APB1DIV_VAL | (APB2DIV_VAL << 4);
353 	priv->hfcbcd1 = (I3CDIV_VAL << 2) | FIUDIV_VAL;
354 	priv->hfcbcd2 = APB3DIV_VAL;
355 
356 	return 0;
357 }
358 
359 const struct npcm_pcc_config pcc_config = {
360 	.base_cdcg = DT_INST_REG_ADDR_BY_NAME(0, cdcg),
361 	.base_pmc = DT_INST_REG_ADDR_BY_NAME(0, pmc),
362 };
363 
364 DEVICE_DT_INST_DEFINE(0, &npcm_clock_control_init, NULL, NULL, &pcc_config, PRE_KERNEL_1,
365 		      CONFIG_KERNEL_INIT_PRIORITY_OBJECTS, &npcm_clock_control_api);
366