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