]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_pll.c
Rename RISC-V_RV32_SiFive_HiFive1-FreedomStudio directory to RISC-V_RV32_SiFive_HiFiv...
[freertos] / FreeRTOS / Demo / RISC-V_RV32_SiFive_HiFive1_FreedomStudio / freedom-metal / src / drivers / sifive_fe310-g000_pll.c
diff --git a/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_pll.c b/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_fe310-g000_pll.c
deleted file mode 100644 (file)
index 2ca468f..0000000
+++ /dev/null
@@ -1,360 +0,0 @@
-/* Copyright 2018 SiFive, Inc */
-/* SPDX-License-Identifier: Apache-2.0 */
-
-#include <metal/machine/platform.h>
-
-#ifdef METAL_SIFIVE_FE310_G000_PLL
-
-#include <stdio.h>
-#include <limits.h>
-
-#include <metal/machine.h>
-#include <metal/drivers/sifive_fe310-g000_pll.h>
-#include <stdlib.h>
-
-#define PLL_R        0x00000007UL
-#define PLL_F        0x000003F0UL
-#define PLL_Q        0x00000C00UL
-#define PLL_SEL      0x00010000UL
-#define PLL_REFSEL   0x00020000UL
-#define PLL_BYPASS   0x00040000UL
-#define PLL_LOCK     0x80000000UL
-
-#define DIV_DIV      0x0000003FUL
-#define DIV_1        0x00000100UL
-
-#define PLL_R_SHIFT(r)  ((r << 0) & PLL_R)
-#define PLL_F_SHIFT(f)  ((f << 4) & PLL_F) 
-#define PLL_Q_SHIFT(q)  ((q << 10) & PLL_Q)
-#define PLL_DIV_SHIFT(d)    ((d << 0) & DIV_DIV)
-
-struct pll_config_t {
-    unsigned long multiplier;
-    unsigned long divisor;
-    unsigned long min_input_rate;
-    unsigned long max_input_rate;
-    unsigned long r;
-    unsigned long f;
-    unsigned long q;
-    long d; /* < 0 if disabled */
-};
-
-static const struct pll_config_t pll_configs[] = {
-    /*
-     * multiplier
-     * ^  divisor
-     * |  ^      min_input_rate
-     * |  |      ^        max_input_rate
-     * |  |      |        ^      r
-     * |  |      |        |      ^   f
-     * |  |      |        |      |   ^  q
-     * |  |      |        |      |   |  ^   d
-     * |  |      |        |      |   |  |   ^
-     * |  |      |        |      |   |  |   | */
-    { 1, 32, 12000000, 24000000, 1, 31, 3, 63}, 
-    { 1, 32, 24000000, 48000000, 3, 31, 2, 63}, 
-    { 1, 16,  6000000, 12000000, 0, 31, 3, 63}, 
-    { 1, 16, 12000000, 24000000, 1, 31, 2, 63}, 
-    { 1, 16, 24000000, 48000000, 3, 31, 2, 31}, 
-    { 1,  8,  6000000, 12000000, 0, 31, 3, 31}, 
-    { 1,  8, 12000000, 24000000, 1, 31, 2, 31}, 
-    { 1,  8, 24000000, 48000000, 3, 31, 2, 15}, 
-    { 1,  4,  6000000, 12000000, 0, 31, 3, 15}, 
-    { 1,  4, 12000000, 24000000, 1, 31, 2, 15}, 
-    { 1,  4, 24000000, 48000000, 3, 31, 2,  7}, 
-    { 1,  2,  6000000, 12000000, 0, 31, 2, 15}, 
-    { 1,  2, 12000000, 24000000, 1, 31, 1, 15}, 
-    { 1,  2, 24000000, 48000000, 3, 31, 1,  7}, 
-    { 2,  1,  6000000, 12000000, 0, 31, 1,  7}, 
-    { 2,  1, 12000000, 24000000, 1, 31, 1,  3}, 
-    { 2,  1, 24000000, 48000000, 3, 31, 3, -1}, 
-    { 4,  1,  6000000, 12000000, 0, 31, 3,  0}, 
-    { 4,  1, 12000000, 24000000, 1, 31, 3, -1}, 
-    { 4,  1, 24000000, 48000000, 3, 31, 2, -1}, 
-    { 6,  1,  6000000, 10666666, 0, 35, 1,  2}, 
-    { 6,  1, 10666666, 12000000, 0, 23, 3, -1}, 
-    { 6,  1, 12000000, 16000000, 1, 47, 3, -1}, 
-    { 6,  1, 16000000, 18000000, 1, 23, 2, -1}, 
-    { 6,  1, 18000000, 21333333, 2, 35, 2, -1}, 
-    { 8,  1,  6000000, 12000000, 0, 31, 3, -1}, 
-    { 8,  1, 12000000, 24000000, 1, 31, 2, -1}, 
-    { 8,  1, 24000000, 48000000, 3, 31, 1, -1}, 
-    {10,  1,  6000000,  9600000, 0, 39, 3, -1}, 
-    {10,  1,  9600000, 12000000, 0, 19, 2, -1}, 
-    {10,  1, 12000000, 19200000, 1, 39, 2, -1}, 
-    {10,  1, 19200000, 24000000, 1, 19, 1, -1}, 
-    {10,  1, 24000000, 38400000, 3, 39, 1, -1}, 
-    {12,  1,  6000000,  8000000, 0, 47, 3, -1}, 
-    {12,  1,  8000000, 12000000, 0, 23, 2, -1}, 
-    {12,  1, 12000000, 16000000, 1, 47, 2, -1}, 
-    {12,  1, 16000000, 24000000, 1, 23, 1, -1}, 
-    {12,  1, 24000000, 30000000, 3, 47, 1, -1}, 
-    {12,  1, 30000000, 32000000, 3, 47, 1, -1}, 
-    {14,  1,  6000000,  6857142, 0, 55, 3, -1}, 
-    {14,  1,  6857143, 12000000, 0, 27, 2, -1}, 
-    {14,  1, 12000000, 13714285, 1, 55, 2, -1}, 
-    {14,  1, 13714286, 24000000, 1, 27, 1, -1}, 
-    {14,  1, 24000000, 27428571, 3, 55, 1, -1}, 
-    {16,  1,  6000000, 12000000, 0, 31, 2, -1}, 
-    {16,  1, 12000000, 24000000, 1, 31, 1, -1}, 
-    {18,  1,  6000000, 10666666, 0, 35, 2, -1}, 
-    {18,  1, 10666667, 12000000, 0, 17, 1, -1}, 
-    {18,  1, 12000000, 21333333, 1, 35, 1, -1}, 
-    {20,  1,  6000000,  9600000, 0, 39, 2, -1}, 
-    {20,  1,  9600000, 12000000, 0, 19, 1, -1}, 
-    {20,  1, 12000000, 19200000, 1, 39, 1, -1}, 
-    {22,  1,  6000000,  8727272, 0, 43, 2, -1}, 
-    {22,  1,  8727273, 12000000, 0, 21, 1, -1}, 
-    {22,  1, 12000000, 17454545, 1, 43, 1, -1}, 
-    {24,  1,  6000000,  8000000, 0, 47, 2, -1}, 
-    {24,  1,  8000000, 12000000, 0, 23, 1, -1}, 
-    {24,  1, 12000000, 16000000, 1, 47, 1, -1}, 
-    {26,  1,  6000000,  7384615, 0, 51, 2, -1}, 
-    {26,  1,  7384616, 12000000, 0, 25, 1, -1}, 
-    {26,  1, 12000000, 14768230, 1, 51, 1, -1}, 
-    {28,  1,  6000000,  6857142, 0, 55, 2, -1}, 
-    {28,  1,  6857143, 12000000, 0, 27, 1, -1}, 
-    {28,  1, 12000000, 13714285, 1, 55, 1, -1}, 
-    {30,  1,  6000000,  6400000, 0, 59, 2, -1}, 
-    {30,  1,  6400000, 12000000, 0, 29, 1, -1}, 
-    {30,  1, 12000000, 12800000, 1, 59, 1, -1}, 
-    {32,  1,  6000000, 12000000, 0, 31, 1, -1}
-};
-
-#define PLL_CONFIG_NOT_VALID -1
-
-void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe310_g000_pll *pll);
-
-/* Given the rate of the PLL input frequency and a PLL configuration, what
- * will the resulting PLL output frequency be?
- * Arguments:
- *  - pll_input_rate the PLL input frequency in hertz
- *  - config the PLL configuration
- * Returns:
- *  - PLL_CONFIG_NOT_VALID if the configuration is not valid for the input frequency
- *  - the output frequency, in hertz */
-static long get_pll_config_freq(unsigned long pll_input_rate, const struct pll_config_t *config)
-{
-    if(pll_input_rate < config->min_input_rate || pll_input_rate > config->max_input_rate)
-        return PLL_CONFIG_NOT_VALID;
-
-    return pll_input_rate * config->multiplier / config->divisor;
-}
-
-#ifdef __METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE
-
-static void metal_sifive_fe310_g000_pll_init(void) __attribute__((constructor));
-static void metal_sifive_fe310_g000_pll_init(void) {
-    long init_rate = __metal_driver_sifive_fe310_g000_pll_init_rate();
-    /* If the PLL init_rate is zero, don't initialize the PLL */
-    if(init_rate != 0)
-        __metal_driver_sifive_fe310_g000_pll_init(__METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE);
-}
-
-#endif /* __METAL_DT_SIFIVE_FE310_G000__PLL_HANDLE */
-
-void __metal_driver_sifive_fe310_g000_pll_init(struct __metal_driver_sifive_fe310_g000_pll *pll) {
-    struct metal_clock *pllref = __metal_driver_sifive_fe310_g000_pll_pllref(&(pll->clock));
-    long init_rate = __metal_driver_sifive_fe310_g000_pll_init_rate();
-    long config_offset = __metal_driver_sifive_fe310_g000_pll_config_offset();
-    long base = __metal_driver_sifive_fe310_g000_prci_base();
-
-    __metal_io_u32 *pllcfg = (__metal_io_u32 *) (base + config_offset);
-
-    /* If the PLL clock has had a _pre_rate_change_callback configured, call it */
-    _metal_clock_call_all_callbacks(pll->clock._pre_rate_change_callback);
-
-    /* If we're running off of the PLL, switch off before we start configuring it*/
-    if((__METAL_ACCESS_ONCE(pllcfg) & PLL_SEL) == 0)
-        __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_SEL);
-
-    /* Make sure we're running off of the external oscillator for stability */
-    if(pllref != NULL)
-        __METAL_ACCESS_ONCE(pllcfg) |= PLL_REFSEL;
-
-    /* Configure the PLL to run at the requested init frequency.
-     * Using the vtable instead of the user API because we want to control
-     * when the callbacks occur. */
-    pll->clock.vtable->set_rate_hz(&(pll->clock), init_rate);
-
-    /* If the PLL clock has had a rate_change_callback configured, call it */
-    _metal_clock_call_all_callbacks(pll->clock._post_rate_change_callback);
-}
-
-long __metal_driver_sifive_fe310_g000_pll_get_rate_hz(const struct metal_clock *clock)
-{
-    struct metal_clock *pllref = __metal_driver_sifive_fe310_g000_pll_pllref(clock);
-    struct metal_clock *pllsel0 = __metal_driver_sifive_fe310_g000_pll_pllsel0(clock);
-    long config_offset = __metal_driver_sifive_fe310_g000_pll_config_offset(clock);
-    struct __metal_driver_sifive_fe310_g000_prci *config_base =
-      __metal_driver_sifive_fe310_g000_pll_config_base(clock);
-    long divider_offset = __metal_driver_sifive_fe310_g000_pll_divider_offset(clock);
-    struct __metal_driver_sifive_fe310_g000_prci *divider_base =
-      __metal_driver_sifive_fe310_g000_pll_divider_base(clock);
-    const struct __metal_driver_vtable_sifive_fe310_g000_prci *vtable =
-      __metal_driver_sifive_fe310_g000_prci_vtable();
-
-    long cfg = vtable->get_reg(config_base, config_offset);
-    long div = vtable->get_reg(divider_base, divider_offset);
-
-    /* At the end of the PLL there's one big mux: it either selects the HFROSC
-     * (bypassing the PLL entirely) or uses the PLL. */
-    if (__METAL_GET_FIELD(cfg, PLL_SEL) == 0)
-        return metal_clock_get_rate_hz(pllsel0);
-
-    /* There's a clock mux before the PLL that selects between the HFROSC adn
-     * the HFXOSC as the PLL's input clock. */
-    long ref_hz = metal_clock_get_rate_hz(__METAL_GET_FIELD(cfg, PLL_REFSEL) ? pllref : pllsel0);
-
-    /* It's possible to bypass the PLL, which is an internal bpyass.  This
-     * still obays the PLL's input clock mu. */
-    if (__METAL_GET_FIELD(cfg, PLL_BYPASS))
-        return ref_hz;
-
-    /* Logically the PLL is a three stage div-mul-div. */
-    long div_r = __METAL_GET_FIELD(cfg, PLL_R) + 1;
-    long mul_f = 2 * (__METAL_GET_FIELD(cfg, PLL_F) + 1);
-    if (__METAL_GET_FIELD(cfg, PLL_Q) == 0)
-        return -1;
-    long div_q = 1 << __METAL_GET_FIELD(cfg, PLL_Q);
-
-    /* In addition to the dividers inherent in the PLL, there's an additional
-     * clock divider that lives after the PLL and lets us pick a more
-     * interesting range of frequencies. */
-    long pllout = (((ref_hz / div_r) * mul_f) / div_q);
-    if (__METAL_GET_FIELD(div, DIV_1))
-        return pllout;
-
-    return pllout / (2 * (__METAL_GET_FIELD(div, DIV_DIV) + 1));
-}
-
-/* Find a valid configuration for the PLL which is closest to the desired
- * output frequency.
- * Arguments:
- *  - ref_hz PLL input frequency
- *  - rate desired PLL output frequency
- * Returns:
- *  -1 if no valid configuration is available
- *  the index into pll_configs of a valid configuration */
-static int find_closest_config(long ref_hz, long rate)
-{
-    int closest_index = -1;
-    long closest_diff = LONG_MAX;
-
-    /* We're probably trying for a fast output frequency, so start from
-     * the high end of the configs. */
-    for(int i = (sizeof(pll_configs) / sizeof(pll_configs[0])) - 1; i >= 0; i--)
-    {
-        long config_freq = get_pll_config_freq(ref_hz, &(pll_configs[i]));
-        if(config_freq != PLL_CONFIG_NOT_VALID)
-        {
-            long freq_diff = abs(config_freq - rate);
-            if(freq_diff < closest_diff)
-            {
-                closest_index = i;
-                closest_diff = freq_diff;
-            }
-        }
-    }
-
-    return closest_index;
-}
-
-/* Configure the PLL and wait for it to lock */
-static void configure_pll(__metal_io_u32 *pllcfg, __metal_io_u32 *plloutdiv, const struct pll_config_t *config)
-{
-    __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_R);
-    __METAL_ACCESS_ONCE(pllcfg) |= PLL_R_SHIFT(config->r);
-
-    __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_F);
-    __METAL_ACCESS_ONCE(pllcfg) |= PLL_F_SHIFT(config->f);
-
-    __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_Q);
-    __METAL_ACCESS_ONCE(pllcfg) |= PLL_Q_SHIFT(config->q);
-
-    if(config->d < 0)
-    {
-        /* disable final divider */
-        __METAL_ACCESS_ONCE(plloutdiv) |= DIV_1;
-
-        __METAL_ACCESS_ONCE(plloutdiv) &= ~(DIV_DIV);
-        __METAL_ACCESS_ONCE(plloutdiv) |= PLL_DIV_SHIFT(1);
-    }
-    else
-    {
-        __METAL_ACCESS_ONCE(plloutdiv) &= ~(DIV_1);
-
-        __METAL_ACCESS_ONCE(plloutdiv) &= ~(DIV_DIV);
-        __METAL_ACCESS_ONCE(plloutdiv) |= PLL_DIV_SHIFT(config->d);
-    }
-
-    __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_BYPASS);
-
-    /* Wait for PLL to lock */
-    while((__METAL_ACCESS_ONCE(pllcfg) & PLL_LOCK) == 0) ;
-}
-
-long __metal_driver_sifive_fe310_g000_pll_set_rate_hz(struct metal_clock *clock, long rate)
-{
-    struct metal_clock *pllref = __metal_driver_sifive_fe310_g000_pll_pllref(clock);
-    struct metal_clock *pllsel0 = __metal_driver_sifive_fe310_g000_pll_pllsel0(clock);
-    long config_offset = __metal_driver_sifive_fe310_g000_pll_config_offset(clock);
-    long divider_offset = __metal_driver_sifive_fe310_g000_pll_divider_offset(clock);
-    long base = __metal_driver_sifive_fe310_g000_prci_base();
-
-    __metal_io_u32 *pllcfg = (__metal_io_u32 *) (base + config_offset);
-    __metal_io_u32 *plloutdiv = (__metal_io_u32 *) (base + divider_offset);
-
-    /* We can't modify the PLL if coreclk is driven by it, so switch it off */
-    if (__METAL_ACCESS_ONCE(pllcfg) & PLL_SEL)
-        __METAL_ACCESS_ONCE(pllcfg) &= ~(PLL_SEL);
-
-    /* There's a clock mux before the PLL that selects between the HFROSC and
-     * the HFXOSC as the PLL's input clock. */
-    long ref_hz = metal_clock_get_rate_hz(__METAL_ACCESS_ONCE(pllcfg) & PLL_REFSEL ? pllref : pllsel0);
-
-    /* if the desired rate is within 75%-125% of the input clock, bypass the PLL */
-    if((ref_hz * 3 / 4) <= rate && (ref_hz * 5 / 4) >= rate)
-    {
-        __METAL_ACCESS_ONCE(pllcfg) |= PLL_BYPASS;
-    }
-    else
-    {
-        int config_index = find_closest_config(ref_hz, rate);
-        if(config_index != -1)
-        {
-            configure_pll(pllcfg, plloutdiv, &(pll_configs[config_index]));
-        }
-        else
-        {
-            /* unable to find a valid configuration */
-            __METAL_ACCESS_ONCE(pllcfg) |= PLL_BYPASS;
-        }
-    }
-
-    /* Enable the PLL */
-    __METAL_ACCESS_ONCE(pllcfg) |= PLL_SEL;
-
-    return __metal_driver_sifive_fe310_g000_pll_get_rate_hz(clock);
-}
-
-#ifdef __METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE
-static void use_hfxosc(void) __attribute__((constructor));
-static void use_hfxosc(void)
-{
-    long init_rate = __metal_driver_sifive_fe310_g000_pll_init_rate();
-    metal_clock_set_rate_hz(
-        &__METAL_DT_SIFIVE_FE310_G000_PLL_HANDLE->clock, init_rate
-    );
-}
-#endif
-
-__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fe310_g000_pll) = {
-    .init = __metal_driver_sifive_fe310_g000_pll_init,
-    .clock.get_rate_hz = __metal_driver_sifive_fe310_g000_pll_get_rate_hz,
-    .clock.set_rate_hz = __metal_driver_sifive_fe310_g000_pll_set_rate_hz,
-};
-
-#endif /* METAL_SIFIVE_FE310_G000_PLL */
-
-typedef int no_empty_translation_units;