1 /* 2 * Copyright (c) 2019-2022, Intel Corporation. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <errno.h> 9 #include <common/debug.h> 10 #include <drivers/delay_timer.h> 11 #include <lib/mmio.h> 12 13 #include "n5x_clock_manager.h" 14 #include "n5x_system_manager.h" 15 #include "socfpga_handoff.h" 16 clk_get_pll_output_hz(void)17uint64_t clk_get_pll_output_hz(void) 18 { 19 uint32_t clksrc; 20 uint32_t scr_reg; 21 uint32_t divf; 22 uint32_t divr; 23 uint32_t divq; 24 uint32_t power = 1; 25 uint64_t clock = 0; 26 27 clksrc = ((get_clk_freq(CLKMGR_PERPLL_PLLGLOB)) & 28 CLKMGR_PLLGLOB_VCO_PSRC_MASK) >> CLKMGR_PLLGLOB_VCO_PSRC_OFFSET; 29 30 switch (clksrc) { 31 case CLKMGR_VCO_PSRC_EOSC1: 32 scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_1); 33 clock = mmio_read_32(scr_reg); 34 break; 35 36 case CLKMGR_VCO_PSRC_INTOSC: 37 clock = CLKMGR_INTOSC_HZ; 38 break; 39 40 case CLKMGR_VCO_PSRC_F2S: 41 scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_2); 42 clock = mmio_read_32(scr_reg); 43 break; 44 } 45 46 divf = ((get_clk_freq(CLKMGR_PERPLL_PLLDIV)) & 47 CLKMGR_PLLDIV_FDIV_MASK) >> CLKMGR_PLLDIV_FDIV_OFFSET; 48 divr = ((get_clk_freq(CLKMGR_PERPLL_PLLDIV)) & 49 CLKMGR_PLLDIV_REFCLKDIV_MASK) >> CLKMGR_PLLDIV_REFCLKDIV_OFFSET; 50 divq = ((get_clk_freq(CLKMGR_PERPLL_PLLDIV)) & 51 CLKMGR_PLLDIV_OUTDIV_QDIV_MASK) >> CLKMGR_PLLDIV_OUTDIV_QDIV_OFFSET; 52 53 while (divq) { 54 power *= 2; 55 divq--; 56 } 57 58 return ((clock * 2 * (divf + 1)) / ((divr + 1) * power)); 59 } 60 get_l4_clk(void)61uint64_t get_l4_clk(void) 62 { 63 uint32_t clock = 0; 64 uint32_t mainpll_c1cnt; 65 uint32_t perpll_c1cnt; 66 uint32_t clksrc; 67 68 mainpll_c1cnt = ((get_clk_freq(CLKMGR_MAINPLL_PLLOUTDIV)) & 69 CLKMGR_PLLOUTDIV_C1CNT_MASK) >> CLKMGR_PLLOUTDIV_C1CNT_OFFSET; 70 71 perpll_c1cnt = ((get_clk_freq(CLKMGR_PERPLL_PLLOUTDIV)) & 72 CLKMGR_PLLOUTDIV_C1CNT_MASK) >> CLKMGR_PLLOUTDIV_C1CNT_OFFSET; 73 74 clksrc = ((get_clk_freq(CLKMGR_MAINPLL_NOCCLK)) & CLKMGR_CLKSRC_MASK) >> 75 CLKMGR_CLKSRC_OFFSET; 76 77 switch (clksrc) { 78 case CLKMGR_CLKSRC_MAIN: 79 clock = clk_get_pll_output_hz(); 80 clock /= 1 + mainpll_c1cnt; 81 break; 82 83 case CLKMGR_CLKSRC_PER: 84 clock = clk_get_pll_output_hz(); 85 clock /= 1 + perpll_c1cnt; 86 break; 87 88 default: 89 return 0; 90 break; 91 } 92 93 clock /= BIT(((get_clk_freq(CLKMGR_MAINPLL_NOCDIV)) >> 94 CLKMGR_NOCDIV_L4MAIN_OFFSET) & CLKMGR_NOCDIV_DIVIDER_MASK); 95 96 return clock; 97 } 98 99 /* Return MPU clock */ get_mpu_clk(void)100uint32_t get_mpu_clk(void) 101 { 102 uint32_t clock = 0; 103 uint32_t mainpll_c0cnt; 104 uint32_t perpll_c0cnt; 105 uint32_t clksrc; 106 107 mainpll_c0cnt = ((get_clk_freq(CLKMGR_MAINPLL_PLLOUTDIV)) & 108 CLKMGR_PLLOUTDIV_C0CNT_MASK) >> CLKMGR_PLLOUTDIV_C0CNT_OFFSET; 109 110 perpll_c0cnt = ((get_clk_freq(CLKMGR_PERPLL_PLLOUTDIV)) & 111 CLKMGR_PLLOUTDIV_C0CNT_MASK) >> CLKMGR_PLLOUTDIV_C0CNT_OFFSET; 112 113 clksrc = ((get_clk_freq(CLKMGR_MAINPLL_NOCCLK)) & CLKMGR_CLKSRC_MASK) >> 114 CLKMGR_CLKSRC_OFFSET; 115 116 switch (clksrc) { 117 case CLKMGR_CLKSRC_MAIN: 118 clock = clk_get_pll_output_hz(); 119 clock /= 1 + mainpll_c0cnt; 120 break; 121 122 case CLKMGR_CLKSRC_PER: 123 clock = clk_get_pll_output_hz(); 124 clock /= 1 + perpll_c0cnt; 125 break; 126 127 default: 128 return 0; 129 break; 130 } 131 132 clock /= BIT(((get_clk_freq(CLKMGR_MAINPLL_NOCDIV)) >> 133 CLKMGR_NOCDIV_L4MAIN_OFFSET) & CLKMGR_NOCDIV_DIVIDER_MASK); 134 135 return clock; 136 } 137 138 /* Calculate clock frequency based on parameter */ get_clk_freq(uint32_t psrc_reg)139uint32_t get_clk_freq(uint32_t psrc_reg) 140 { 141 uint32_t clk_psrc; 142 143 clk_psrc = mmio_read_32(CLKMGR_N5X_BASE + psrc_reg); 144 145 return clk_psrc; 146 } 147 148 /* Get cpu freq clock */ get_cpu_clk(void)149uint32_t get_cpu_clk(void) 150 { 151 uint32_t cpu_clk = 0; 152 153 cpu_clk = get_l4_clk()/PLAT_HZ_CONVERT_TO_MHZ; 154 155 return cpu_clk; 156 } 157 158 /* Return mpu_periph_clk clock frequency */ get_mpu_periph_clk(void)159uint32_t get_mpu_periph_clk(void) 160 { 161 uint32_t mpu_periph_clk = 0; 162 /* mpu_periph_clk is mpu_clk, via a static /4 divider */ 163 mpu_periph_clk = (get_mpu_clk()/4)/PLAT_HZ_CONVERT_TO_MHZ; 164 return mpu_periph_clk; 165 } 166 167 /* Return mpu_periph_clk tick */ plat_get_syscnt_freq2(void)168unsigned int plat_get_syscnt_freq2(void) 169 { 170 return PLAT_SYS_COUNTER_FREQ_IN_TICKS; 171 } 172