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