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 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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