1 /*
2 * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8 #include <errno.h>
9
10 #include <common/debug.h>
11 #include <drivers/delay_timer.h>
12 #include <lib/mmio.h>
13
14 #include "agilex5_clock_manager.h"
15 #include "agilex5_system_manager.h"
16 #include "socfpga_handoff.h"
17 #include "socfpga_system_manager.h"
18
wait_pll_lock(void)19 uint32_t wait_pll_lock(void)
20 {
21 uint32_t data;
22 uint32_t count = 0;
23
24 do {
25 data = mmio_read_32(CLKMGR_OFFSET + CLKMGR_STAT);
26 count++;
27 if (count >= 1000)
28 return -ETIMEDOUT;
29
30 } while ((CLKMGR_STAT_MAINPLLLOCKED(data) == 0) ||
31 (CLKMGR_STAT_PERPLLLOCKED(data) == 0));
32 return 0;
33 }
34
wait_fsm(void)35 uint32_t wait_fsm(void)
36 {
37 uint32_t data;
38 uint32_t count = 0;
39
40 do {
41 data = mmio_read_32(CLKMGR_OFFSET + CLKMGR_STAT);
42 count++;
43 if (count >= 1000)
44 return -ETIMEDOUT;
45
46 } while (CLKMGR_STAT_BUSY(data) == CLKMGR_STAT_BUSY_E_BUSY);
47
48 return 0;
49 }
50
pll_source_sync_config(uint32_t pll_mem_offset,uint32_t data)51 uint32_t pll_source_sync_config(uint32_t pll_mem_offset, uint32_t data)
52 {
53 uint32_t val = 0;
54 uint32_t count = 0;
55 uint32_t req_status = 0;
56
57 val = (CLKMGR_MEM_WR | CLKMGR_MEM_REQ |
58 (data << CLKMGR_MEM_WDAT_OFFSET) | CLKMGR_MEM_ADDR);
59 mmio_write_32(pll_mem_offset, val);
60
61 do {
62 req_status = mmio_read_32(pll_mem_offset);
63 count++;
64 } while ((req_status & CLKMGR_MEM_REQ) && (count < 10));
65
66 if (count >= 10)
67 return -ETIMEDOUT;
68
69 return 0;
70 }
71
pll_source_sync_read(uint32_t pll_mem_offset)72 uint32_t pll_source_sync_read(uint32_t pll_mem_offset)
73 {
74 uint32_t val = 0;
75 uint32_t rdata = 0;
76 uint32_t count = 0;
77 uint32_t req_status = 0;
78
79 val = (CLKMGR_MEM_REQ | CLKMGR_MEM_ADDR);
80 mmio_write_32(pll_mem_offset, val);
81
82 do {
83 req_status = mmio_read_32(pll_mem_offset);
84 count++;
85 } while ((req_status & CLKMGR_MEM_REQ) && (count < 10));
86
87 if (count >= 10)
88 return -ETIMEDOUT;
89
90 rdata = mmio_read_32(pll_mem_offset + 0x4);
91 INFO("rdata (%x) = %x\n", pll_mem_offset + 0x4, rdata);
92
93 return rdata;
94 }
95
config_clkmgr_handoff(handoff * hoff_ptr)96 void config_clkmgr_handoff(handoff *hoff_ptr)
97 {
98 /* Take both PLL out of reset and power up */
99
100 mmio_setbits_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB,
101 CLKMGR_PLLGLOB_PD_SET_MSK |
102 CLKMGR_PLLGLOB_RST_SET_MSK);
103 mmio_setbits_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB,
104 CLKMGR_PLLGLOB_PD_SET_MSK |
105 CLKMGR_PLLGLOB_RST_SET_MSK);
106
107 /* PLL lock */
108 wait_pll_lock();
109
110 /* Bypass all mainpllgrp's clocks to input clock ref */
111 mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_BYPASSS, 0xff);
112 /* Bypass all perpllgrp's clocks to input clock ref */
113 mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_BYPASS, 0xff);
114
115 /* Pass clock source frequency into scratch register */
116 mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_1),
117 hoff_ptr->hps_osc_clk_hz);
118 mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_2),
119 hoff_ptr->fpga_clk_hz);
120
121 /* Take all PLLs out of bypass */
122 mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_BYPASS, 0);
123 wait_fsm();
124 mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_BYPASS, 0);
125 wait_fsm();
126
127 /* Enable mainpllgrp's software-managed clock */
128 mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_EN,
129 CLKMGR_MAINPLL_EN_RESET);
130 mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_EN,
131 CLKMGR_PERPLL_EN_RESET);
132 }
133
134 /* Extract reference clock from platform clock source */
get_ref_clk(uint32_t pllglob)135 uint32_t get_ref_clk(uint32_t pllglob)
136 {
137 uint32_t arefclkdiv, ref_clk;
138 uint32_t scr_reg;
139
140 switch (CLKMGR_PSRC(pllglob)) {
141 case CLKMGR_PLLGLOB_PSRC_EOSC1:
142 scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_1);
143 ref_clk = mmio_read_32(scr_reg);
144 break;
145 case CLKMGR_PLLGLOB_PSRC_INTOSC:
146 ref_clk = CLKMGR_INTOSC_HZ;
147 break;
148 case CLKMGR_PLLGLOB_PSRC_F2S:
149 scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_2);
150 ref_clk = mmio_read_32(scr_reg);
151 break;
152 default:
153 ref_clk = 0;
154 assert(0);
155 break;
156 }
157
158 arefclkdiv = CLKMGR_PLLGLOB_AREFCLKDIV(pllglob);
159 ref_clk /= arefclkdiv;
160
161 return ref_clk;
162 }
163
164 /* Calculate clock frequency based on parameter */
get_clk_freq(uint32_t psrc_reg,uint32_t main_pllc,uint32_t per_pllc)165 uint32_t get_clk_freq(uint32_t psrc_reg, uint32_t main_pllc, uint32_t per_pllc)
166 {
167 uint32_t ref_clk = 0;
168
169 uint32_t clk_psrc, mdiv;
170 uint32_t pllm_reg, pllc_reg, pllc_div, pllglob_reg;
171
172
173 clk_psrc = mmio_read_32(CLKMGR_MAINPLL + psrc_reg);
174 clk_psrc = 0;
175
176 switch (clk_psrc) {
177 case 0:
178 pllm_reg = CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLM;
179 pllc_reg = CLKMGR_MAINPLL + main_pllc;
180 pllglob_reg = CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB;
181 break;
182 }
183
184 ref_clk = get_ref_clk(mmio_read_32(pllglob_reg));
185 mdiv = CLKMGR_PLLM_MDIV(mmio_read_32(pllm_reg));
186 ref_clk *= mdiv;
187
188 pllc_div = mmio_read_32(pllc_reg) & 0x7ff;
189 NOTICE("return = %d Hz\n", (ref_clk / pllc_div));
190
191 ref_clk = 200000000;
192 return (uint32_t) ref_clk;
193
194 }
195
196 /* Return L3 interconnect clock */
get_l3_clk(void)197 uint32_t get_l3_clk(void)
198 {
199 uint32_t l3_clk;
200
201 l3_clk = get_clk_freq(CLKMGR_MAINPLL_NOCCLK, CLKMGR_MAINPLL_PLLC1,
202 CLKMGR_PERPLL_PLLC1);
203 return l3_clk;
204 }
205
206 /* Calculate clock frequency to be used for watchdog timer */
get_wdt_clk(void)207 uint32_t get_wdt_clk(void)
208 {
209 uint32_t l3_clk, l4_sys_clk;
210
211 l3_clk = get_l3_clk();
212 l4_sys_clk = l3_clk / 4;
213
214 return l4_sys_clk;
215 }
216
217 /* Calculate clock frequency to be used for UART driver */
get_uart_clk(void)218 uint32_t get_uart_clk(void)
219 {
220 uint32_t data32, l3_clk, l4_sp_clk;
221
222 l3_clk = get_l3_clk();
223
224 data32 = mmio_read_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_NOCDIV);
225 data32 = (data32 >> 16) & 0x3;
226
227 l4_sp_clk = l3_clk >> data32;
228
229 return l4_sp_clk;
230 }
231
232 /* Calculate clock frequency to be used for SDMMC driver */
get_mmc_clk(void)233 uint32_t get_mmc_clk(void)
234 {
235 uint32_t mmc_clk;
236
237 //TODO: To update when handoff data is ready
238 //uint32_t data32;
239
240 //mmc_clk = get_clk_freq(CLKMGR_ALTERA_SDMMCCTR, CLKMGR_MAINPLL_PLLC3, CLKMGR_PERPLL_PLLC3);
241
242 //data32 = mmio_read_32(CLKMGR_ALTERA + CLKMGR_ALTERA_SDMMCCTR);
243 //data32 = (data32 & 0x7ff) + 1;
244 //mmc_clk = (mmc_clk / data32) / 4;
245
246
247 mmc_clk = get_clk_freq(CLKMGR_MAINPLL_NOCCLK, CLKMGR_MAINPLL_PLLC3,
248 CLKMGR_PERPLL_PLLC3);
249
250 // TODO: To update when handoff data is ready
251 NOTICE("mmc_clk = %d Hz\n", mmc_clk);
252
253 return mmc_clk;
254 }
255
256 /* Return mpu_periph_clk tick */
plat_get_syscnt_freq2(void)257 unsigned int plat_get_syscnt_freq2(void)
258 {
259 return PLAT_SYS_COUNTER_FREQ_IN_TICKS;
260 }
261