1 /*
2  * Copyright (c) 2019-2021, Intel Corporation. All rights reserved.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/arch/cpu.h>
8 #include <zephyr/arch/common/sys_bitops.h>
9 #include <zephyr/drivers/clock_control/clock_agilex_ll.h>
10 #include <socfpga_system_manager.h>
11 
12 /*
13  * Intel SoC re-use Arm Trusted Firmware (ATF) driver code in Zephyr.
14  * The migrated ATF driver code uses mmio_X macro to access the register.
15  * The following macros map mmio_X to Zephyr compatible function for
16  * register access. This allow Zephyr to re-use the ATF driver codes
17  * without massive changes.
18  */
19 #define mmio_write_32(addr, data)	sys_write32((data), (addr))
20 #define mmio_read_32(addr)		sys_read32((addr))
21 #define mmio_setbits_32(addr, mask)	sys_set_bits((addr), (mask))
22 #define mmio_clrbits_32(addr, mask)	sys_clear_bits((addr), (mask))
23 
24 /* Extract reference clock from platform clock source */
get_ref_clk(uint32_t pllglob)25 uint32_t get_ref_clk(uint32_t pllglob)
26 {
27 	uint32_t arefclkdiv, ref_clk;
28 	uint32_t scr_reg;
29 
30 	switch (CLKMGR_PSRC(pllglob)) {
31 	case CLKMGR_PLLGLOB_PSRC_EOSC1:
32 		scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_1);
33 		ref_clk = mmio_read_32(scr_reg);
34 		break;
35 	case CLKMGR_PLLGLOB_PSRC_INTOSC:
36 		ref_clk = CLKMGR_INTOSC_HZ;
37 		break;
38 	case CLKMGR_PLLGLOB_PSRC_F2S:
39 		scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_2);
40 		ref_clk = mmio_read_32(scr_reg);
41 		break;
42 	default:
43 		ref_clk = 0;
44 		break;
45 	}
46 
47 	arefclkdiv = CLKMGR_PLLGLOB_AREFCLKDIV(pllglob);
48 	ref_clk /= arefclkdiv;
49 
50 	return ref_clk;
51 }
52 
53 /* Calculate clock frequency based on parameter */
get_clk_freq(uint32_t psrc_reg,uint32_t main_pllc,uint32_t per_pllc)54 uint32_t get_clk_freq(uint32_t psrc_reg, uint32_t main_pllc, uint32_t per_pllc)
55 {
56 	uint32_t clk_psrc, mdiv, ref_clk;
57 	uint32_t pllm_reg, pllc_reg, pllc_div, pllglob_reg;
58 
59 	clk_psrc = mmio_read_32(CLKMGR_MAINPLL + psrc_reg);
60 
61 	switch (CLKMGR_PSRC(clk_psrc)) {
62 	case CLKMGR_PSRC_MAIN:
63 		pllm_reg = CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLM;
64 		pllc_reg = CLKMGR_MAINPLL + main_pllc;
65 		pllglob_reg = CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB;
66 		break;
67 	case CLKMGR_PSRC_PER:
68 		pllm_reg = CLKMGR_PERPLL + CLKMGR_PERPLL_PLLM;
69 		pllc_reg = CLKMGR_PERPLL + per_pllc;
70 		pllglob_reg = CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB;
71 		break;
72 	default:
73 		return 0;
74 	}
75 
76 	ref_clk = get_ref_clk(mmio_read_32(pllglob_reg));
77 	mdiv = CLKMGR_PLLM_MDIV(mmio_read_32(pllm_reg));
78 	ref_clk *= mdiv;
79 
80 	pllc_div = mmio_read_32(pllc_reg) & 0x7ff;
81 
82 	return ref_clk / pllc_div;
83 }
84 
85 /* Return L3 interconnect clock */
get_l3_clk(void)86 uint32_t get_l3_clk(void)
87 {
88 	uint32_t l3_clk;
89 
90 	l3_clk = get_clk_freq(CLKMGR_MAINPLL_NOCCLK, CLKMGR_MAINPLL_PLLC1,
91 				CLKMGR_PERPLL_PLLC1);
92 	return l3_clk;
93 }
94 
95 /* Calculate clock frequency to be used for mpu */
get_mpu_clk(void)96 uint32_t get_mpu_clk(void)
97 {
98 	uint32_t mpu_clk = 0;
99 
100 	mpu_clk = get_clk_freq(CLKMGR_MAINPLL_MPUCLK, CLKMGR_MAINPLL_PLLC0,
101 				CLKMGR_PERPLL_PLLC0);
102 	return mpu_clk;
103 }
104 
105 /* Calculate clock frequency to be used for watchdog timer */
get_wdt_clk(void)106 uint32_t get_wdt_clk(void)
107 {
108 	uint32_t l3_clk, l4_sys_clk;
109 
110 	l3_clk = get_l3_clk();
111 	l4_sys_clk = l3_clk / 4;
112 
113 	return l4_sys_clk;
114 }
115 
116 /* Calculate clock frequency to be used for UART driver */
get_uart_clk(void)117 uint32_t get_uart_clk(void)
118 {
119 	uint32_t data32, l3_clk, l4_sp_clk;
120 
121 	l3_clk = get_l3_clk();
122 
123 	data32 = mmio_read_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_NOCDIV);
124 	data32 = (data32 >> 16) & 0x3;
125 
126 	l4_sp_clk = l3_clk >> data32;
127 
128 	return l4_sp_clk;
129 }
130 
131 /* Calculate clock frequency to be used for SDMMC driver */
get_mmc_clk(void)132 uint32_t get_mmc_clk(void)
133 {
134 	uint32_t data32, mmc_clk;
135 
136 	mmc_clk = get_clk_freq(CLKMGR_ALTERA_SDMMCCTR,
137 		CLKMGR_MAINPLL_PLLC3, CLKMGR_PERPLL_PLLC3);
138 
139 	data32 = mmio_read_32(CLKMGR_ALTERA + CLKMGR_ALTERA_SDMMCCTR);
140 	data32 = (data32 & 0x7ff) + 1;
141 	mmc_clk = (mmc_clk / data32) / 4;
142 
143 	return mmc_clk;
144 }
145