2021-04-15 22:06:38 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2019-2021, Intel Corporation. All rights reserved.
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
2022-05-06 16:25:46 +08:00
|
|
|
#include <zephyr/arch/cpu.h>
|
|
|
|
#include <zephyr/arch/common/sys_bitops.h>
|
|
|
|
#include <zephyr/drivers/clock_control/clock_agilex_ll.h>
|
2021-04-15 22:06:38 +08:00
|
|
|
#include <socfpga_system_manager.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Intel SoC re-use Arm Trusted Firmware (ATF) driver code in Zephyr.
|
|
|
|
* The migrated ATF driver code uses mmio_X macro to access the register.
|
|
|
|
* The following macros map mmio_X to Zephyr compatible function for
|
|
|
|
* register access. This allow Zephyr to re-use the ATF driver codes
|
|
|
|
* without massive changes.
|
|
|
|
*/
|
|
|
|
#define mmio_write_32(addr, data) sys_write32((data), (addr))
|
|
|
|
#define mmio_read_32(addr) sys_read32((addr))
|
|
|
|
#define mmio_setbits_32(addr, mask) sys_set_bits((addr), (mask))
|
|
|
|
#define mmio_clrbits_32(addr, mask) sys_clear_bits((addr), (mask))
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
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 mpu */
|
|
|
|
uint32_t get_mpu_clk(void)
|
|
|
|
{
|
|
|
|
uint32_t mpu_clk = 0;
|
|
|
|
|
|
|
|
mpu_clk = get_clk_freq(CLKMGR_MAINPLL_MPUCLK, CLKMGR_MAINPLL_PLLC0,
|
|
|
|
CLKMGR_PERPLL_PLLC0);
|
|
|
|
return mpu_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;
|
|
|
|
}
|