blob: d54c9fbac4f485dbca750945b4bae1a99a8d635f [file] [log] [blame]
/*
* Copyright (c) 2021 Katsuhiro Suzuki
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/init.h>
#include <zephyr/devicetree.h>
#include <zephyr/sys/util.h>
#include "fu740_prci.h"
BUILD_ASSERT(MHZ(1000) == DT_PROP(DT_NODELABEL(coreclk), clock_frequency),
"Unsupported CORECLK frequency");
BUILD_ASSERT(KHZ(125125) == DT_PROP(DT_NODELABEL(pclk), clock_frequency),
"Unsupported PCLK frequency");
/*
* Switch the clock source
* - core: to 1GHz PLL (CORE_PLL) from 26MHz oscillator (HFCLK)
* - peri: to 250MHz PLL (HFPCLKPLL) from HFCLK
* on the HiFive Unmatched board.
*
* Note: Valid PLL VCO range is 2400MHz to 4800MHz
*/
static int fu740_clock_init(const struct device *dev)
{
ARG_UNUSED(dev);
PRCI_REG(PRCI_COREPLLCFG) =
PLL_R(0) | /* input divider: Fin / (0 + 1) = 26MHz */
PLL_F(76) | /* VCO: 2 x (76 + 1) = 154 = 4004MHz */
PLL_Q(2) | /* output divider: VCO / 2^2 = 1001MHz */
PLL_RANGE(PLL_RANGE_18MHZ) | /* 18MHz <= post divr(= 26MHz) < 30MHz */
PLL_BYPASS(PLL_BYPASS_DISABLE) |
PLL_FSE(PLL_FSE_INTERNAL);
while ((PRCI_REG(PRCI_COREPLLCFG) & PLL_LOCK(1)) == 0)
;
/* Switch CORE_CLK to CORE_PLL from HFCLK */
PRCI_REG(PRCI_COREPLLSEL) = COREPLLSEL_SEL(COREPLLSEL_COREPLL);
PRCI_REG(PRCI_CORECLKSEL) = CLKSEL_SEL(CLKSEL_PLL);
PRCI_REG(PRCI_HFPCLKPLLCFG) =
PLL_R(0) | /* input divider: Fin / (0 + 1) = 26MHz */
PLL_F(76) | /* VCO: 2 x (76 + 1) = 154 = 4004MHz */
PLL_Q(4) | /* output divider: VCO / 2^4 = 250.25MHz */
PLL_RANGE(PLL_RANGE_18MHZ) | /* 18MHz <= post divr(= 26MHz) < 30MHz */
PLL_BYPASS(PLL_BYPASS_DISABLE) |
PLL_FSE(PLL_FSE_INTERNAL);
while ((PRCI_REG(PRCI_HFPCLKPLLCFG) & PLL_LOCK(1)) == 0)
;
/* Switch PCLK to HFPCLKPLL/2 from HFCLK/2 */
PRCI_REG(PRCI_HFPCLKPLLOUTDIV) = OUTDIV_PLLCKE(OUTDIV_PLLCKE_ENA);
PRCI_REG(PRCI_HFPCLKPLLSEL) = CLKSEL_SEL(CLKSEL_PLL);
return 0;
}
SYS_INIT(fu740_clock_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);