diff options
Diffstat (limited to 'plat/intel/soc/agilex/soc/agilex_clock_manager.c')
-rw-r--r-- | plat/intel/soc/agilex/soc/agilex_clock_manager.c | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/plat/intel/soc/agilex/soc/agilex_clock_manager.c b/plat/intel/soc/agilex/soc/agilex_clock_manager.c new file mode 100644 index 0000000..76b9937 --- /dev/null +++ b/plat/intel/soc/agilex/soc/agilex_clock_manager.c @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2019-2022, Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <errno.h> +#include <lib/mmio.h> + +#include "agilex_clock_manager.h" +#include "socfpga_handoff.h" +#include "socfpga_system_manager.h" + + +uint32_t wait_pll_lock(void) +{ + uint32_t data; + uint32_t count = 0; + + do { + data = mmio_read_32(CLKMGR_OFFSET + CLKMGR_STAT); + count++; + if (count >= 1000) + return -ETIMEDOUT; + + } while ((CLKMGR_STAT_MAINPLLLOCKED(data) == 0) || + (CLKMGR_STAT_PERPLLLOCKED(data) == 0)); + return 0; +} + +uint32_t wait_fsm(void) +{ + uint32_t data; + uint32_t count = 0; + + do { + data = mmio_read_32(CLKMGR_OFFSET + CLKMGR_STAT); + count++; + if (count >= 1000) + return -ETIMEDOUT; + + } while (CLKMGR_STAT_BUSY(data) == CLKMGR_STAT_BUSY_E_BUSY); + + return 0; +} + +uint32_t pll_source_sync_config(uint32_t pll_mem_offset, uint32_t data) +{ + uint32_t val = 0; + uint32_t count = 0; + uint32_t req_status = 0; + + val = (CLKMGR_MEM_WR | CLKMGR_MEM_REQ | + (data << CLKMGR_MEM_WDAT_OFFSET) | CLKMGR_MEM_ADDR); + mmio_write_32(pll_mem_offset, val); + + do { + req_status = mmio_read_32(pll_mem_offset); + count++; + } while ((req_status & CLKMGR_MEM_REQ) && (count < 10)); + + if (count >= 100) + return -ETIMEDOUT; + + return 0; +} + +uint32_t pll_source_sync_read(uint32_t pll_mem_offset) +{ + uint32_t val = 0; + uint32_t rdata = 0; + uint32_t count = 0; + uint32_t req_status = 0; + + val = (CLKMGR_MEM_REQ | CLKMGR_MEM_ADDR); + mmio_write_32(pll_mem_offset, val); + + do { + req_status = mmio_read_32(pll_mem_offset); + count++; + } while ((req_status & CLKMGR_MEM_REQ) && (count < 10)); + + if (count >= 100) + return -ETIMEDOUT; + + rdata = mmio_read_32(pll_mem_offset + 0x4); + INFO("rdata (%x) = %x\n", pll_mem_offset + 0x4, rdata); + + return rdata; +} + +void config_clkmgr_handoff(handoff *hoff_ptr) +{ + uint32_t mdiv, mscnt, hscnt; + uint32_t drefclk_div, refclk_div, rdata; + + /* Set clock maanger into boot mode before running configuration */ + mmio_setbits_32(CLKMGR_OFFSET + CLKMGR_CTRL, + CLKMGR_CTRL_BOOTMODE_SET_MSK); + /* Bypass all mainpllgrp's clocks */ + mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_BYPASS, 0x7); + wait_fsm(); + + /* Bypass all perpllgrp's clocks */ + mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_BYPASS, 0x7f); + wait_fsm(); + + /* Put both PLL in reset and power down */ + mmio_clrbits_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB, + CLKMGR_PLLGLOB_PD_SET_MSK | + CLKMGR_PLLGLOB_RST_SET_MSK); + mmio_clrbits_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB, + CLKMGR_PLLGLOB_PD_SET_MSK | + CLKMGR_PLLGLOB_RST_SET_MSK); + + /* Setup main PLL dividers */ + mdiv = CLKMGR_PLLM_MDIV(hoff_ptr->main_pll_pllm); + + drefclk_div = CLKMGR_PLLGLOB_DREFCLKDIV( + hoff_ptr->main_pll_pllglob); + refclk_div = CLKMGR_PLLGLOB_REFCLKDIV( + hoff_ptr->main_pll_pllglob); + + mscnt = 100 / (mdiv * BIT(drefclk_div)); + if (!mscnt) + mscnt = 1; + hscnt = (mdiv * mscnt * BIT(drefclk_div) / refclk_div) - 4; + + mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB, + hoff_ptr->main_pll_pllglob & + ~CLKMGR_PLLGLOB_RST_SET_MSK); + mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_FDBCK, + hoff_ptr->main_pll_fdbck); + mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_VCOCALIB, + CLKMGR_VCOCALIB_HSCNT_SET(hscnt) | + CLKMGR_VCOCALIB_MSCNT_SET(mscnt)); + mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLC0, + hoff_ptr->main_pll_pllc0); + mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLC1, + hoff_ptr->main_pll_pllc1); + mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLC2, + hoff_ptr->main_pll_pllc2); + mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLC3, + hoff_ptr->main_pll_pllc3); + mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLM, + hoff_ptr->main_pll_pllm); + mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_MPUCLK, + hoff_ptr->main_pll_mpuclk); + mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_NOCCLK, + hoff_ptr->main_pll_nocclk); + mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_NOCDIV, + hoff_ptr->main_pll_nocdiv); + + /* Setup peripheral PLL dividers */ + mdiv = CLKMGR_PLLM_MDIV(hoff_ptr->per_pll_pllm); + + drefclk_div = CLKMGR_PLLGLOB_DREFCLKDIV( + hoff_ptr->per_pll_pllglob); + refclk_div = CLKMGR_PLLGLOB_REFCLKDIV( + hoff_ptr->per_pll_pllglob); + + + mscnt = 100 / (mdiv * BIT(drefclk_div)); + if (!mscnt) + mscnt = 1; + hscnt = (mdiv * mscnt * BIT(drefclk_div) / refclk_div) - 4; + + mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB, + hoff_ptr->per_pll_pllglob & + ~CLKMGR_PLLGLOB_RST_SET_MSK); + mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_FDBCK, + hoff_ptr->per_pll_fdbck); + + mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_VCOCALIB, + CLKMGR_VCOCALIB_HSCNT_SET(hscnt) | + CLKMGR_VCOCALIB_MSCNT_SET(mscnt)); + + mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLC0, + hoff_ptr->per_pll_pllc0); + mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLC1, + hoff_ptr->per_pll_pllc1); + mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLC2, + hoff_ptr->per_pll_pllc2); + mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLC3, + hoff_ptr->per_pll_pllc3); + mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLM, + hoff_ptr->per_pll_pllm); + mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_EMACCTL, + hoff_ptr->per_pll_emacctl); + mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_GPIODIV, + hoff_ptr->per_pll_gpiodiv); + + /* Take both PLL out of reset and power up */ + mmio_setbits_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB, + CLKMGR_PLLGLOB_PD_SET_MSK | + CLKMGR_PLLGLOB_RST_SET_MSK); + mmio_setbits_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB, + CLKMGR_PLLGLOB_PD_SET_MSK | + CLKMGR_PLLGLOB_RST_SET_MSK); + + rdata = pll_source_sync_read(CLKMGR_MAINPLL + + CLKMGR_MAINPLL_MEM); + pll_source_sync_config(CLKMGR_MAINPLL + CLKMGR_MAINPLL_MEM, + rdata | 0x80); + + rdata = pll_source_sync_read(CLKMGR_PERPLL + CLKMGR_PERPLL_MEM); + pll_source_sync_config(CLKMGR_PERPLL + CLKMGR_PERPLL_MEM, + rdata | 0x80); + + wait_pll_lock(); + + /*Configure Ping Pong counters in altera group */ + mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_EMACACTR, + hoff_ptr->alt_emacactr); + mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_EMACBCTR, + hoff_ptr->alt_emacbctr); + mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_EMACPTPCTR, + hoff_ptr->alt_emacptpctr); + mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_GPIODBCTR, + hoff_ptr->alt_gpiodbctr); + mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_SDMMCCTR, + hoff_ptr->alt_sdmmcctr); + mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_S2FUSER0CTR, + hoff_ptr->alt_s2fuser0ctr); + mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_S2FUSER1CTR, + hoff_ptr->alt_s2fuser1ctr); + mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_PSIREFCTR, + hoff_ptr->alt_psirefctr); + + /* Clear lost lock bypass mode */ + mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_LOSTLOCK, 0x1); + mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_LOSTLOCK, 0x1); + + mmio_setbits_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB, + CLKMGR_CLR_LOSTLOCK_BYPASS); + + mmio_setbits_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB, + CLKMGR_CLR_LOSTLOCK_BYPASS); + + /* Take all PLLs out of bypass */ + mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_BYPASS, 0); + wait_fsm(); + + mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_BYPASS, 0); + wait_fsm(); + + /* Clear loss lock interrupt status register that */ + /* might be set during configuration */ + mmio_clrbits_32(CLKMGR_OFFSET + CLKMGR_INTRCLR, + CLKMGR_INTRCLR_MAINLOCKLOST_SET_MSK | + CLKMGR_INTRCLR_PERLOCKLOST_SET_MSK); + + /* Take all ping pong counters out of reset */ + mmio_clrbits_32(CLKMGR_ALTERA + CLKMGR_ALTERA_EXTCNTRST, + CLKMGR_ALTERA_EXTCNTRST_RESET); + + /* Set safe mode / out of boot mode */ + mmio_clrbits_32(CLKMGR_OFFSET + CLKMGR_CTRL, + CLKMGR_CTRL_BOOTMODE_SET_MSK); + wait_fsm(); + + /* Enable mainpllgrp's software-managed clock */ + mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_EN, + CLKMGR_MAINPLL_EN_RESET); + mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_EN, + CLKMGR_PERPLL_EN_RESET); + + /* Pass clock source frequency into scratch register */ + mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_1), + hoff_ptr->hps_osc_clk_h); + mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_2), + hoff_ptr->fpga_clk_hz); +} + +/* Extract reference clock from platform clock source */ +uint32_t get_ref_clk(uint32_t pllglob) +{ + uint32_t arefclkdiv, ref_clk; + uint32_t scr_reg; + + switch (CLKMGR_PSRC(pllglob)) { + case CLKMGR_PLLGLOB_PSRC_EOSC1: + scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_1); + ref_clk = mmio_read_32(scr_reg); + break; + case CLKMGR_PLLGLOB_PSRC_INTOSC: + ref_clk = CLKMGR_INTOSC_HZ; + break; + case CLKMGR_PLLGLOB_PSRC_F2S: + scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_2); + ref_clk = mmio_read_32(scr_reg); + break; + default: + ref_clk = 0; + assert(0); + break; + } + + arefclkdiv = CLKMGR_PLLGLOB_AREFCLKDIV(pllglob); + ref_clk /= arefclkdiv; + + return ref_clk; +} + +/* Calculate clock frequency based on parameter */ +uint32_t get_clk_freq(uint32_t psrc_reg, uint32_t main_pllc, uint32_t per_pllc) +{ + uint32_t clk_psrc, mdiv, ref_clk; + uint32_t pllm_reg, pllc_reg, pllc_div, pllglob_reg; + + clk_psrc = mmio_read_32(CLKMGR_MAINPLL + psrc_reg); + + switch (CLKMGR_PSRC(clk_psrc)) { + case CLKMGR_PSRC_MAIN: + pllm_reg = CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLM; + pllc_reg = CLKMGR_MAINPLL + main_pllc; + pllglob_reg = CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB; + break; + case CLKMGR_PSRC_PER: + pllm_reg = CLKMGR_PERPLL + CLKMGR_PERPLL_PLLM; + pllc_reg = CLKMGR_PERPLL + per_pllc; + pllglob_reg = CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB; + break; + default: + return 0; + } + + ref_clk = get_ref_clk(mmio_read_32(pllglob_reg)); + mdiv = CLKMGR_PLLM_MDIV(mmio_read_32(pllm_reg)); + ref_clk *= mdiv; + + pllc_div = mmio_read_32(pllc_reg) & 0x7ff; + + return ref_clk / pllc_div; +} + +/* Return L3 interconnect clock */ +uint32_t get_l3_clk(void) +{ + uint32_t l3_clk; + + l3_clk = get_clk_freq(CLKMGR_MAINPLL_NOCCLK, CLKMGR_MAINPLL_PLLC1, + CLKMGR_PERPLL_PLLC1); + return l3_clk; +} + +/* Calculate clock frequency to be used for watchdog timer */ +uint32_t get_wdt_clk(void) +{ + uint32_t l3_clk, l4_sys_clk; + + l3_clk = get_l3_clk(); + l4_sys_clk = l3_clk / 4; + + return l4_sys_clk; +} + +/* Calculate clock frequency to be used for UART driver */ +uint32_t get_uart_clk(void) +{ + uint32_t data32, l3_clk, l4_sp_clk; + + l3_clk = get_l3_clk(); + + data32 = mmio_read_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_NOCDIV); + data32 = (data32 >> 16) & 0x3; + + l4_sp_clk = l3_clk >> data32; + + return l4_sp_clk; +} + +/* Calculate clock frequency to be used for SDMMC driver */ +uint32_t get_mmc_clk(void) +{ + uint32_t data32, mmc_clk; + + mmc_clk = get_clk_freq(CLKMGR_ALTERA_SDMMCCTR, + CLKMGR_MAINPLL_PLLC3, CLKMGR_PERPLL_PLLC3); + + data32 = mmio_read_32(CLKMGR_ALTERA + CLKMGR_ALTERA_SDMMCCTR); + data32 = (data32 & 0x7ff) + 1; + mmc_clk = (mmc_clk / data32) / 4; + + return mmc_clk; +} + +/* Get cpu freq clock */ +uint32_t get_cpu_clk(void) +{ + uint32_t cpu_clk; + + cpu_clk = get_l3_clk()/PLAT_SYS_COUNTER_CONVERT_TO_MHZ; + + return cpu_clk; +} |