diff options
Diffstat (limited to 'bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_clock_manager.c')
-rw-r--r-- | bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_clock_manager.c | 5554 |
1 files changed, 5554 insertions, 0 deletions
diff --git a/bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_clock_manager.c b/bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_clock_manager.c new file mode 100644 index 0000000000..95404c1c13 --- /dev/null +++ b/bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_clock_manager.c @@ -0,0 +1,5554 @@ +/****************************************************************************** + * + * Copyright 2013 Altera Corporation. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + ******************************************************************************/ + +#include <stdint.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdio.h> + +#include <bsp/socal/hps.h> +#include <bsp/socal/socal.h> +#include <bsp/socal/alt_sysmgr.h> +#include <bsp/hwlib.h> +#include <bsp/alt_clock_manager.h> +#include <bsp/alt_mpu_registers.h> + +#define UINT12_MAX (4096) + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Useful Structures ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + + + /* General structure used to hold parameters of various clock entities, */ +typedef struct ALT_CLK_PARAMS_s +{ + alt_freq_t freqcur; // current frequency of the clock + alt_freq_t freqmin; // minimum allowed frequency for this clock + alt_freq_t freqmax; // maximum allowed frequency for this clock + uint32_t guardband : 7; // guardband percentage (0-100) if this clock + // is a PLL, ignored otherwise + uint32_t active : 1; // current state of activity of this clock +} ALT_CLK_PARAMS_t; + + +typedef struct ALT_EXT_CLK_PARAMBLOK_s +{ + ALT_CLK_PARAMS_t clkosc1; // ALT_CLK_OSC1 + ALT_CLK_PARAMS_t clkosc2; // ALT_CLK_OSC2 + ALT_CLK_PARAMS_t periph; // ALT_CLK_F2H_PERIPH_REF + ALT_CLK_PARAMS_t sdram; // ALT_CLK_F2H_SDRAM_REF +} ALT_EXT_CLK_PARAMBLOK_t; + + + /* Initializes the External Clock Frequency Limits block */ + /* The first field is the current external clock frequency, and can be set by */ + /* alt_clk_ext_clk_freq_set(), the second and third fields are the minimum and */ + /* maximum frequencies, the fourth field is ignored, and the fifth field */ + /* contains the current activity state of the clock, 1=active, 0=inactive. */ + /* Values taken from Section 2.3 and Section 2.7.1 of the HHP HPS-Clocking */ + /* NPP specification. */ +static ALT_EXT_CLK_PARAMBLOK_t alt_ext_clk_paramblok = +{ + { 25000000, 10000000, 50000000, 0, 1 }, + { 25000000, 10000000, 50000000, 0, 1 }, + { 0, 10000000, 50000000, 0, 1 }, + { 0, 10000000, 50000000, 0, 1 } +}; + + + /* PLL frequency limits */ +typedef struct ALT_PLL_CLK_PARAMBLOK_s +{ + ALT_CLK_PARAMS_t MainPLL_600; // Main PLL values for 600 MHz SoC + ALT_CLK_PARAMS_t PeriphPLL_600; // Peripheral PLL values for 600 MHz SoC + ALT_CLK_PARAMS_t SDRAMPLL_600; // SDRAM PLL values for 600 MHz SoC + ALT_CLK_PARAMS_t MainPLL_800; // Main PLL values for 800 MHz SoC + ALT_CLK_PARAMS_t PeriphPLL_800; // Peripheral PLL values for 800 MHz SoC + ALT_CLK_PARAMS_t SDRAMPLL_800; // SDRAM PLL values for 800 MHz SoC +} ALT_PLL_CLK_PARAMBLOK_t; + + + /* Initializes the PLL frequency limits block */ + /* The first field is the current frequency, the second and third fields */ + /* are the design limits of the PLLs as listed in Section 3.2.1.2 of the */ + /* HHP HPS-Clocking NPP document. The fourth field of each line is the */ + /* guardband percentage, and the fifth field of each line is the current */ + /* state of the PLL, 1=active, 0=inactive. */ +#define ALT_ORIGINAL_GUARDBAND_VAL 20 +#define ALT_GUARDBAND_LIMIT 20 + +static ALT_PLL_CLK_PARAMBLOK_t alt_pll_clk_paramblok = +{ + { 0, 320000000, 1200000000, ALT_ORIGINAL_GUARDBAND_VAL, 0 }, + { 0, 320000000, 900000000, ALT_ORIGINAL_GUARDBAND_VAL, 0 }, + { 0, 320000000, 800000000, ALT_ORIGINAL_GUARDBAND_VAL, 0 }, + { 0, 320000000, 1600000000, ALT_ORIGINAL_GUARDBAND_VAL, 1 }, + { 0, 320000000, 1250000000, ALT_ORIGINAL_GUARDBAND_VAL, 1 }, + { 0, 320000000, 1066000000, ALT_ORIGINAL_GUARDBAND_VAL, 1 } +}; + + + /* PLL counter frequency limits */ +typedef struct ALT_PLL_CNTR_FREQMAX_s +{ + alt_freq_t MainPLL_C0; // Main PLL Counter 0 parameter block + alt_freq_t MainPLL_C1; // Main PLL Counter 1 parameter block + alt_freq_t MainPLL_C2; // Main PLL Counter 2 parameter block + alt_freq_t MainPLL_C3; // Main PLL Counter 3 parameter block + alt_freq_t MainPLL_C4; // Main PLL Counter 4 parameter block + alt_freq_t MainPLL_C5; // Main PLL Counter 5 parameter block + alt_freq_t PeriphPLL_C0; // Peripheral PLL Counter 0 parameter block + alt_freq_t PeriphPLL_C1; // Peripheral PLL Counter 1 parameter block + alt_freq_t PeriphPLL_C2; // Peripheral PLL Counter 2 parameter block + alt_freq_t PeriphPLL_C3; // Peripheral PLL Counter 3 parameter block + alt_freq_t PeriphPLL_C4; // Peripheral PLL Counter 4 parameter block + alt_freq_t PeriphPLL_C5; // Peripheral PLL Counter 5 parameter block + alt_freq_t SDRAMPLL_C0; // SDRAM PLL Counter 0 parameter block + alt_freq_t SDRAMPLL_C1; // SDRAM PLL Counter 1 parameter block + alt_freq_t SDRAMPLL_C2; // SDRAM PLL Counter 2 parameter block + alt_freq_t SDRAMPLL_C5; // SDRAM PLL Counter 5 parameter block +} ALT_PLL_CNTR_FREQMAX_t; + +// +// The following pll max frequency array statically defined must be recalculated each time +// when powering up, by calling alt_clk_clkmgr_init() +// +// for 14.1 uboot preloader, the following values are calculated dynamically. +// +// Arrial 5 +// alt_pll_cntr_maxfreq.MainPLL_C0 = 1050000000 +// alt_pll_cntr_maxfreq.MainPLL_C1 = 350000000 +// alt_pll_cntr_maxfreq.MainPLL_C2 = 262500000 +// alt_pll_cntr_maxfreq.MainPLL_C3 = 350000000 +// alt_pll_cntr_maxfreq.MainPLL_C4 = 2050781 +// alt_pll_cntr_maxfreq.MainPLL_C5 = 116666666 +// alt_pll_cntr_maxfreq.PeriphPLL_C0 = 1953125 +// alt_pll_cntr_maxfreq.PeriphPLL_C1 = 250000000 +// alt_pll_cntr_maxfreq.PeriphPLL_C2 = 1953125 +// alt_pll_cntr_maxfreq.PeriphPLL_C3 = 200000000 +// alt_pll_cntr_maxfreq.PeriphPLL_C4 = 200000000 +// alt_pll_cntr_maxfreq.PeriphPLL_C5 = 1953125 +// alt_pll_cntr_maxfreq.SDRAMPLL_C0 = 533333333 +// alt_pll_cntr_maxfreq.SDRAMPLL_C1 = 1066666666 +// alt_pll_cntr_maxfreq.SDRAMPLL_C2 = 533333333 +// alt_pll_cntr_maxfreq.SDRAMPLL_C5 = 177777777 + +// Cyclone V +// alt_pll_cntr_maxfreq.MainPLL_C0 = 925000000 +// alt_pll_cntr_maxfreq.MainPLL_C1 = 370000000 +// alt_pll_cntr_maxfreq.MainPLL_C2 = 462500000 +// alt_pll_cntr_maxfreq.MainPLL_C3 = 370000000 +// alt_pll_cntr_maxfreq.MainPLL_C4 = 3613281 +// alt_pll_cntr_maxfreq.MainPLL_C5 = 123333333 +// alt_pll_cntr_maxfreq.PeriphPLL_C0 = 1953125 +// alt_pll_cntr_maxfreq.PeriphPLL_C1 = 250000000 +// alt_pll_cntr_maxfreq.PeriphPLL_C2 = 1953125 +// alt_pll_cntr_maxfreq.PeriphPLL_C3 = 200000000 +// alt_pll_cntr_maxfreq.PeriphPLL_C4 = 200000000 +// alt_pll_cntr_maxfreq.PeriphPLL_C5 = 1953125 +// alt_pll_cntr_maxfreq.SDRAMPLL_C0 = 400000000 +// alt_pll_cntr_maxfreq.SDRAMPLL_C1 = 800000000 +// alt_pll_cntr_maxfreq.SDRAMPLL_C2 = 400000000 +// alt_pll_cntr_maxfreq.SDRAMPLL_C5 = 133333333 + + +/* Initializes the PLL Counter output maximum frequency block */ +static ALT_PLL_CNTR_FREQMAX_t alt_pll_cntr_maxfreq = +{ + 800000000, /* Main PLL Outputs */ + 400000000, + 400000000, + 432000000, + 250000000, + 125000000, + 250000000, /* Peripheral PLL Outputs */ + 250000000, + 432000000, + 250000000, + 200000000, + 100000000, /* SDRAM PLL Outputs */ + 533000000, + 1066000000, + 533000000, + 200000000 +}; + + + + /* Maximum multiply, divide, and counter divisor values for each PLL */ +#define ALT_CLK_PLL_MULT_MAX 4095 +#define ALT_CLK_PLL_DIV_MAX 63 +#define ALT_CLK_PLL_CNTR_MAX 511 + + + /* Definitions for the reset request and reset acknowledge bits */ + /* for each of the output counters for each of the PLLS */ +#define ALT_CLK_PLL_RST_BIT_C0 0x00000001 +#define ALT_CLK_PLL_RST_BIT_C1 0x00000002 +#define ALT_CLK_PLL_RST_BIT_C2 0x00000004 +#define ALT_CLK_PLL_RST_BIT_C3 0x00000008 +#define ALT_CLK_PLL_RST_BIT_C4 0x00000010 +#define ALT_CLK_PLL_RST_BIT_C5 0x00000020 + + + /* These are the bits that deal with PLL lock and this macro */ + /* defines a mask to test for bits outside of these */ +#define ALT_CLK_MGR_PLL_LOCK_BITS (ALT_CLKMGR_INTREN_MAINPLLACHIEVED_CLR_MSK \ + & ALT_CLKMGR_INTREN_PERPLLACHIEVED_CLR_MSK \ + & ALT_CLKMGR_INTREN_SDRPLLACHIEVED_CLR_MSK \ + & ALT_CLKMGR_INTREN_MAINPLLLOST_CLR_MSK \ + & ALT_CLKMGR_INTREN_PERPLLLOST_CLR_MSK \ + & ALT_CLKMGR_INTREN_SDRPLLLOST_CLR_MSK) + + +// Undocumented register which determines clock dividers for main PLL C0, C1, and C2. These should be considered RO. +#define ALT_CLKMGR_ALTERA_OFST 0xe0 +#define ALT_CLKMGR_ALTERA_MPUCLK_OFST 0x0 +#define ALT_CLKMGR_ALTERA_MAINCLK_OFST 0x4 +#define ALT_CLKMGR_ALTERA_DBGATCLK_OFST 0x8 +#define ALT_CLKMGR_ALTERA_ADDR ALT_CAST(void *, (ALT_CAST(char *, ALT_CLKMGR_ADDR) + ALT_CLKMGR_ALTERA_OFST)) +#define ALT_CLKMGR_ALTERA_MPUCLK_ADDR ALT_CAST(void *, (ALT_CAST(char *, ALT_CLKMGR_ALTERA_ADDR) + ALT_CLKMGR_ALTERA_MPUCLK_OFST)) +#define ALT_CLKMGR_ALTERA_MAINCLK_ADDR ALT_CAST(void *, (ALT_CAST(char *, ALT_CLKMGR_ALTERA_ADDR) + ALT_CLKMGR_ALTERA_MAINCLK_OFST)) +#define ALT_CLKMGR_ALTERA_DBGATCLK_ADDR ALT_CAST(void *, (ALT_CAST(char *, ALT_CLKMGR_ALTERA_ADDR) + ALT_CLKMGR_ALTERA_DBGATCLK_OFST)) +#define ALT_CLKMGR_ALTERA_MPUCLK_CNT_GET(value) (((value) & 0x000001ff) >> 0) +#define ALT_CLKMGR_ALTERA_MAINCLK_CNT_GET(value) (((value) & 0x000001ff) >> 0) +#define ALT_CLKMGR_ALTERA_DBGATCLK_CNT_GET(value) (((value) & 0x000001ff) >> 0) + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Utility functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + + +/****************************************************************************************/ +/* alt_clk_mgr_wait() introduces a delay, not very exact, but very light in */ +/* implementation. Depending upon the optinization level, it will wait at least the */ +/* number of clock cycles specified in the cnt parameter, sometimes many more. The */ +/* reg parameter is set to a register or a memory location that was recently used (so */ +/* as to avoid accidently evicting a register and a recently-used cache line in favor */ +/* of one whose values are not actually needed.). The cnt parameter sets the number of */ +/* repeated volatile memory reads and so sets a minimum time delay measured in */ +/* mpu_clk cycles. If mpu_clk = osc1 clock (as in bypass mode), then this gives a */ +/* minimum osc1 clock cycle delay. */ +/****************************************************************************************/ + +inline static void alt_clk_mgr_wait(void* reg, uint32_t cnt) +{ + for (; cnt ; cnt--) + { + (void) alt_read_word(reg); + } +} + + /* Wait time constants */ + /* These values came from Section 4.9.4 of the HHP HPS-Clocking NPP document */ +#define ALT_SW_MANAGED_CLK_WAIT_CTRDIV 30 /* 30 or more MPU clock cycles */ +#define ALT_SW_MANAGED_CLK_WAIT_HWCTRDIV 40 +#define ALT_SW_MANAGED_CLK_WAIT_BYPASS 30 +#define ALT_SW_MANAGED_CLK_WAIT_SAFEREQ 30 +#define ALT_SW_MANAGED_CLK_WAIT_SAFEEXIT 30 +#define ALT_SW_MANAGED_CLK_WAIT_NANDCLK 8 /* 8 or more MPU clock cycles */ + + +#define ALT_BYPASS_TIMEOUT_CNT 50 + // arbitrary number until i find more info +#define ALT_TIMEOUT_PHASE_SYNC 300 + // how many loops to wait for the SDRAM clock to come around + // to zero and allow for writing a new divisor ratio to it + +ALT_STATUS_CODE alt_clk_plls_settle_wait(void) +{ + int32_t i = ALT_BYPASS_TIMEOUT_CNT; + bool nofini; + + do + { + nofini = alt_read_word(ALT_CLKMGR_STAT_ADDR) & ALT_CLKMGR_STAT_BUSY_SET_MSK; + } while (nofini && i--); + // wait until clocks finish transitioning and become stable again + return (i > 0) ? ALT_E_SUCCESS : ALT_E_ERROR; +} + +static ALT_STATUS_CODE alt_clk_pll_lock_wait(ALT_CLK_t pll, uint32_t timeout) +{ + uint32_t locked_mask = 0; + + if (pll == ALT_CLK_MAIN_PLL) { locked_mask = ALT_CLKMGR_INTER_MAINPLLLOCKED_SET_MSK; } + else if (pll == ALT_CLK_PERIPHERAL_PLL) { locked_mask = ALT_CLKMGR_INTER_PERPLLLOCKED_SET_MSK; } + else if (pll == ALT_CLK_SDRAM_PLL) { locked_mask = ALT_CLKMGR_INTER_SDRPLLLOCKED_SET_MSK; } + else + { + return ALT_E_BAD_ARG; + } + + do + { + uint32_t int_status = alt_read_word(ALT_CLKMGR_INTER_ADDR); + if (int_status & locked_mask) + { + return ALT_E_SUCCESS; + } + + } while (timeout--); + + return ALT_E_TMO; +} + + /* Useful utility macro for checking if two values */ + /* are within a certain percentage of each other */ +#define alt_within_delta(ref, neu, prcnt) (((((neu) * 100)/(ref)) < (100 + (prcnt))) \ + && ((((neu) * 100)/(ref)) > (100 - (prcnt)))) + + + /* Flags to include or omit code sections */ +// There are four cases where there is a small possibility of producing clock +// glitches. Code has been added from an abundance of caution to prevent +// these glitches. If further testing shows that this extra code is not necessary +// under any conditions, it may be easily eliminated by clearing these flags. + +#define ALT_PREVENT_GLITCH_BYP true +// for PLL entering or leaving bypass +#define ALT_PREVENT_GLITCH_EXSAFE true +// for PLL exiting safe mode +#define ALT_PREVENT_GLITCH_CNTRRST true +// resets counter phase +#define ALT_PREVENT_GLITCH_CHGC1 true +// for changing Main PLL C1 counter + + + +/****************************************************************************************/ +/* Bare-bones utility function used to make the somewhat complex writes to the PLL */ +/* counter registers (the clock dividers) easier. No parameter-checking or */ +/* error-checking, this is a static to this file and invisible to Doxygen. */ +/****************************************************************************************/ + +static void alt_clk_pllcounter_write(void* vcoaddr, void* stataddr, void* cntraddr, + uint32_t val, uint32_t msk, uint32_t shift) +{ +#if ALT_PREVENT_GLITCH_CNTRRST + // this is here from an abundance of caution and it may not be necessary + // to put the counter in reset for this write + volatile uint32_t temp; + + alt_setbits_word(vcoaddr, msk << shift); // put the counter in reset + do + { + temp = alt_read_word(stataddr); + } while (!(temp & msk)); + + alt_write_word(cntraddr, val); + alt_clrbits_word(vcoaddr, msk << shift); // release counter reset + +#else // should we find out that resetting the counters as above is unnecessary + alt_write_word(cntraddr, val); +#endif +} + + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Main Functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + + +/****************************************************************************************/ +/* alt_clk_lock_status_clear() clears assertions of one or more of the PLL lock status */ +/* conditions. */ +/****************************************************************************************/ + +ALT_STATUS_CODE alt_clk_lock_status_clear(ALT_CLK_PLL_LOCK_STATUS_t lock_stat_mask) +{ + if (lock_stat_mask & ( ALT_CLKMGR_INTER_MAINPLLACHIEVED_CLR_MSK + & ALT_CLKMGR_INTER_PERPLLACHIEVED_CLR_MSK + & ALT_CLKMGR_INTER_SDRPLLACHIEVED_CLR_MSK + & ALT_CLKMGR_INTER_MAINPLLLOST_CLR_MSK + & ALT_CLKMGR_INTER_PERPLLLOST_CLR_MSK + & ALT_CLKMGR_INTER_SDRPLLLOST_CLR_MSK) + ) + { + return ALT_E_BAD_ARG; + } + else + { + alt_setbits_word(ALT_CLKMGR_INTER_ADDR, lock_stat_mask); + return ALT_E_SUCCESS; + } +} + + +/****************************************************************************************/ +/* alt_clk_lock_status_get() returns the value of the PLL lock status conditions. */ +/****************************************************************************************/ + +uint32_t alt_clk_lock_status_get(void) +{ + return alt_read_word(ALT_CLKMGR_INTER_ADDR) & ( ALT_CLKMGR_INTER_MAINPLLACHIEVED_SET_MSK + | ALT_CLKMGR_INTER_PERPLLACHIEVED_SET_MSK + | ALT_CLKMGR_INTER_SDRPLLACHIEVED_SET_MSK + | ALT_CLKMGR_INTER_MAINPLLLOST_SET_MSK + | ALT_CLKMGR_INTER_PERPLLLOST_SET_MSK + | ALT_CLKMGR_INTER_SDRPLLLOST_SET_MSK + | ALT_CLKMGR_INTER_MAINPLLLOCKED_SET_MSK + | ALT_CLKMGR_INTER_PERPLLLOCKED_SET_MSK + | ALT_CLKMGR_INTER_SDRPLLLOCKED_SET_MSK ); +} + + +/****************************************************************************************/ +/* alt_clk_pll_is_locked() returns ALT_E_TRUE if the designated PLL is currently */ +/* locked and ALT_E_FALSE if not. */ +/****************************************************************************************/ + +ALT_STATUS_CODE alt_clk_pll_is_locked(ALT_CLK_t pll) +{ + ALT_STATUS_CODE status = ALT_E_BAD_ARG; + + if (pll == ALT_CLK_MAIN_PLL) + { + status = (alt_read_word(ALT_CLKMGR_INTER_ADDR) & ALT_CLKMGR_INTER_MAINPLLLOCKED_SET_MSK) + ? ALT_E_TRUE : ALT_E_FALSE; + } + else if (pll == ALT_CLK_PERIPHERAL_PLL) + { + status = (alt_read_word(ALT_CLKMGR_INTER_ADDR) & ALT_CLKMGR_INTER_PERPLLLOCKED_SET_MSK) + ? ALT_E_TRUE : ALT_E_FALSE; + } + else if (pll == ALT_CLK_SDRAM_PLL) + { + status = (alt_read_word(ALT_CLKMGR_INTER_ADDR) & ALT_CLKMGR_INTER_SDRPLLLOCKED_SET_MSK) + ? ALT_E_TRUE : ALT_E_FALSE; + } + return status; +} + + +/****************************************************************************************/ +/* alt_clk_safe_mode_clear() clears the safe mode status of the Clock Manager following */ +/* a reset. */ +/****************************************************************************************/ + +ALT_STATUS_CODE alt_clk_safe_mode_clear(void) +{ + ALT_STATUS_CODE status = ALT_E_ERROR; +#if ALT_PREVENT_GLITCH_EXSAFE + uint32_t temp; + + temp = alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR); + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp & + (ALT_CLKMGR_MAINPLL_EN_L4MPCLK_CLR_MSK & ALT_CLKMGR_MAINPLL_EN_L4SPCLK_CLR_MSK)); + // gate off l4MP and L4SP clocks (no matter their source) + + alt_setbits_word(ALT_CLKMGR_CTL_ADDR, ALT_CLKMGR_CTL_SAFEMOD_SET_MSK); + // clear safe mode bit + status = alt_clk_plls_settle_wait(); + alt_replbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, + ALT_CLKMGR_MAINPLL_EN_L4MPCLK_SET_MSK | ALT_CLKMGR_MAINPLL_EN_L4SPCLK_SET_MSK, + temp); + // gate l4MP and L4SP clocks back on if they were on previously + +#else + alt_setbits_word(ALT_CLKMGR_CTL_ADDR, ALT_CLKMGR_CTL_SAFEMOD_SET_MSK); + // clear safe mode bit + status = alt_clk_plls_settle_wait(); + +#endif + return status; +} + + +/****************************************************************************************/ +/* alt_clk_is_in_safe_mode() returns whether the specified safe mode clock domain is in */ +/* safe mode or not. */ +/****************************************************************************************/ + +bool alt_clk_is_in_safe_mode(ALT_CLK_SAFE_DOMAIN_t clk_domain) +{ + bool ret = false; + uint32_t temp; + + if (clk_domain == ALT_CLK_DOMAIN_NORMAL) + { + ret = alt_read_word(ALT_CLKMGR_CTL_ADDR) & ALT_CLKMGR_CTL_SAFEMOD_SET_MSK; + // is the main clock domain in safe mode? + } + else if (clk_domain == ALT_CLK_DOMAIN_DEBUG) + { + temp = alt_read_word(ALT_CLKMGR_DBCTL_ADDR); + if (temp & ALT_CLKMGR_DBCTL_STAYOSC1_SET_MSK) + { + ret = true; // is the debug clock domain in safe mode? + } + else if (temp & ALT_CLKMGR_DBCTL_ENSFMDWR_SET_MSK) + { + ret = alt_read_word(ALT_CLKMGR_CTL_ADDR) & ALT_CLKMGR_CTL_SAFEMOD_SET_MSK; + // is the debug clock domain following the main clock domain + // AND is the main clock domain in safe mode? + } + } + return ret; +} + +/****************************************************************************************/ +/* alt_clk_pll_bypass_disable() disables bypass mode for the specified PLL, removing */ +/* it from bypass mode and allowing it to provide the output of the PLL to drive the */ +/* six main clocks. */ +/****************************************************************************************/ + +ALT_STATUS_CODE alt_clk_pll_bypass_disable(ALT_CLK_t pll) +{ + ALT_STATUS_CODE status = ALT_E_BAD_ARG; + uint32_t temp; +#if ALT_PREVENT_GLITCH_BYP + uint32_t temp1; + bool restore_0 = false; + bool restore_1 = false; +#endif + + // this function should only be called after the selected PLL is locked + if (alt_clk_pll_is_locked(pll) == ALT_E_TRUE) + { + if (pll == ALT_CLK_MAIN_PLL) + { +#if ALT_PREVENT_GLITCH_BYP + // if L4MP or L4SP source is set to Main PLL C1, gate it off before changing + // bypass state, then gate clock back on. FogBugz #63778 + temp = alt_read_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR); + temp1 = alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR); + + if ((temp1 & ALT_CLKMGR_MAINPLL_EN_L4MPCLK_SET_MSK) && (!(temp & ALT_CLKMGR_MAINPLL_L4SRC_L4MP_SET_MSK))) + { + restore_0 = true; + } + if ((temp1 & ALT_CLKMGR_MAINPLL_EN_L4SPCLK_SET_MSK) && (!(temp & ALT_CLKMGR_MAINPLL_L4SRC_L4SP_SET_MSK))) + { + restore_1 = true; + } + temp = temp1; + if (restore_0) { temp &= ALT_CLKMGR_MAINPLL_EN_L4MPCLK_CLR_MSK; } + if (restore_1) { temp &= ALT_CLKMGR_MAINPLL_EN_L4SPCLK_CLR_MSK; } + if (restore_0 || restore_1) { alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp); } +#endif + + // assert outresetall of main PLL + temp = alt_read_word(ALT_CLKMGR_MAINPLL_VCO_ADDR); + alt_write_word(ALT_CLKMGR_MAINPLL_VCO_ADDR, temp | ALT_CLKMGR_MAINPLL_VCO_OUTRSTALL_SET_MSK); + + // deassert outresetall of main PLL + alt_write_word(ALT_CLKMGR_MAINPLL_VCO_ADDR, temp & ALT_CLKMGR_MAINPLL_VCO_OUTRSTALL_CLR_MSK); + + alt_clk_plls_settle_wait(); + + // remove bypass + alt_clrbits_word(ALT_CLKMGR_BYPASS_ADDR, ALT_CLKMGR_BYPASS_MAINPLL_SET_MSK); + status = alt_clk_plls_settle_wait(); + +#if ALT_PREVENT_GLITCH_BYP + if (restore_0 || restore_1) + { + alt_clk_mgr_wait(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + // wait a bit more before reenabling the L4MP and L4SP clocks + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp1); + } +#endif + } + + else if (pll == ALT_CLK_PERIPHERAL_PLL) + { +#if ALT_PREVENT_GLITCH_BYP + // if L4MP or L4SP source is set to Main PLL C1, gate it off before changing + // bypass state, then gate clock back on. FogBugz #63778 + temp = alt_read_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR); + temp1 = alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR); + + if ((temp1 & ALT_CLKMGR_MAINPLL_EN_L4MPCLK_SET_MSK) && (temp & ALT_CLKMGR_MAINPLL_L4SRC_L4MP_SET_MSK)) + { + restore_0 = true; + } + if ((temp1 & ALT_CLKMGR_MAINPLL_EN_L4SPCLK_SET_MSK) && (temp & ALT_CLKMGR_MAINPLL_L4SRC_L4SP_SET_MSK)) + { + restore_1 = true; + } + temp = temp1; + if (restore_0) { temp &= ALT_CLKMGR_MAINPLL_EN_L4MPCLK_CLR_MSK; } + if (restore_1) { temp &= ALT_CLKMGR_MAINPLL_EN_L4SPCLK_CLR_MSK; } + if (restore_0 || restore_1) { alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp); } +#endif + + // assert outresetall of Peripheral PLL + temp = alt_read_word(ALT_CLKMGR_PERPLL_VCO_ADDR); + alt_write_word(ALT_CLKMGR_PERPLL_VCO_ADDR, temp | ALT_CLKMGR_PERPLL_VCO_OUTRSTALL_SET_MSK); + alt_clk_plls_settle_wait(); + + // deassert outresetall of main PLL + alt_write_word(ALT_CLKMGR_PERPLL_VCO_ADDR, temp & ALT_CLKMGR_PERPLL_VCO_OUTRSTALL_CLR_MSK); + + // remove bypass - don't think that there's any need to touch the bypass clock source + alt_clrbits_word(ALT_CLKMGR_BYPASS_ADDR, ALT_CLKMGR_BYPASS_PERPLL_SET_MSK); + status = alt_clk_plls_settle_wait(); + +#if ALT_PREVENT_GLITCH_BYP + if (restore_0 || restore_1) + { + alt_clk_mgr_wait(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + // wait a bit more before reenabling the L4MP and L4SP clocks + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp1); + } +#endif + } + + else if (pll == ALT_CLK_SDRAM_PLL) + { + // assert outresetall of SDRAM PLL + temp = alt_read_word(ALT_CLKMGR_SDRPLL_VCO_ADDR); + alt_write_word(ALT_CLKMGR_SDRPLL_VCO_ADDR, temp | ALT_CLKMGR_SDRPLL_VCO_OUTRSTALL_SET_MSK); + + // deassert outresetall of main PLL + alt_write_word(ALT_CLKMGR_SDRPLL_VCO_ADDR, temp & ALT_CLKMGR_SDRPLL_VCO_OUTRSTALL_CLR_MSK); + alt_clk_plls_settle_wait(); + + // remove bypass - don't think that there's any need to touch the bypass clock source + alt_clrbits_word(ALT_CLKMGR_BYPASS_ADDR, ALT_CLKMGR_BYPASS_SDRPLLSRC_SET_MSK); + status = alt_clk_plls_settle_wait(); + } + } + else + { + status = ALT_E_ERROR; + } + + return status; +} + + +/****************************************************************************************/ +/* alt_clk_pll_bypass_enable() enable bypass mode for the specified PLL. */ +/****************************************************************************************/ + +ALT_STATUS_CODE alt_clk_pll_bypass_enable(ALT_CLK_t pll, bool use_input_mux) +{ + ALT_STATUS_CODE status = ALT_E_BAD_ARG; + uint32_t temp; +#ifdef ALT_PREVENT_GLITCH_BYP + uint32_t temp1; + bool restore_0 = false; + bool restore_1 = false; +#endif + + if (pll == ALT_CLK_MAIN_PLL) + { + if (!use_input_mux) + { +#ifdef ALT_PREVENT_GLITCH_BYP + // if L4MP or L4SP source is set to Main PLL C1, gate it off before changing + // bypass state, then gate clock back on. FogBugz #63778 + temp = alt_read_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR); + temp1 = alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR); + + if ((temp1 & ALT_CLKMGR_MAINPLL_EN_L4MPCLK_SET_MSK) && (!(temp & ALT_CLKMGR_MAINPLL_L4SRC_L4MP_SET_MSK))) + { + restore_0 = true; + } + if ((temp1 & ALT_CLKMGR_MAINPLL_EN_L4SPCLK_SET_MSK) && (!(temp & ALT_CLKMGR_MAINPLL_L4SRC_L4SP_SET_MSK))) + { + restore_1 = true; + } + temp = temp1; + if (restore_0) { temp &= ALT_CLKMGR_MAINPLL_EN_L4MPCLK_CLR_MSK; } + if (restore_1) { temp &= ALT_CLKMGR_MAINPLL_EN_L4SPCLK_CLR_MSK; } + if (restore_0 || restore_1) { alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp); } + + alt_setbits_word(ALT_CLKMGR_BYPASS_ADDR, ALT_CLKMGR_BYPASS_MAINPLL_SET_MSK); + // no input mux select on main PLL + + status = alt_clk_plls_settle_wait(); + // wait before reenabling the L4MP and L4SP clocks + if (restore_0 || restore_1) { alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp1); } + +#else + alt_setbits_word(ALT_CLKMGR_BYPASS_ADDR, ALT_CLKMGR_BYPASS_MAINPLL_SET_MSK); + // no input mux select on main PLL + status = alt_clk_plls_settle_wait(); + +#endif + status = ALT_E_SUCCESS; + } + else + { + status = ALT_E_BAD_ARG; + } + } + else if (pll == ALT_CLK_PERIPHERAL_PLL) + { +#ifdef ALT_PREVENT_GLITCH_BYP + // if L4MP or L4SP source is set to Peripheral PLL C1, gate it off before changing + // bypass state, then gate clock back on. FogBugz #63778 + temp = alt_read_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR); + temp1 = alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR); + + if ((temp1 & ALT_CLKMGR_MAINPLL_EN_L4MPCLK_SET_MSK) && (temp & ALT_CLKMGR_MAINPLL_L4SRC_L4MP_SET_MSK)) + { + restore_0 = true; + } + if ((temp1 & ALT_CLKMGR_MAINPLL_EN_L4SPCLK_SET_MSK) && (temp & ALT_CLKMGR_MAINPLL_L4SRC_L4SP_SET_MSK)) + { + restore_1 = true; + } + temp = temp1; + if (restore_0) { temp &= ALT_CLKMGR_MAINPLL_EN_L4MPCLK_CLR_MSK; } + if (restore_1) { temp &= ALT_CLKMGR_MAINPLL_EN_L4SPCLK_CLR_MSK; } + if (restore_0 || restore_1) { alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp); } + + temp = alt_read_word(ALT_CLKMGR_BYPASS_ADDR) & + (ALT_CLKMGR_BYPASS_PERPLL_CLR_MSK & ALT_CLKMGR_BYPASS_PERPLLSRC_CLR_MSK); + temp |= (use_input_mux) ? ALT_CLKMGR_BYPASS_PERPLL_SET_MSK | + ALT_CLKMGR_BYPASS_PERPLLSRC_SET_MSK : ALT_CLKMGR_BYPASS_PERPLL_SET_MSK; + // set bypass bit and optionally the source select bit + + alt_write_word(ALT_CLKMGR_BYPASS_ADDR, temp); + alt_clk_mgr_wait(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + // wait a bit before reenabling the L4MP and L4SP clocks + if (restore_0 || restore_1) { alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp1); } + +#else + temp = alt_read_word(ALT_CLKMGR_BYPASS_ADDR) & + (ALT_CLKMGR_BYPASS_PERPLL_CLR_MSK & ALT_CLKMGR_BYPASS_PERPLLSRC_CLR_MSK); + temp |= (use_input_mux) ? ALT_CLKMGR_BYPASS_PERPLL_SET_MSK | + ALT_CLKMGR_BYPASS_PERPLLSRC_SET_MSK : ALT_CLKMGR_BYPASS_PERPLL_SET_MSK; + // set bypass bit and optionally the source select bit +#endif + status = ALT_E_SUCCESS; + } + + else if (pll == ALT_CLK_SDRAM_PLL) + { + temp = alt_read_word(ALT_CLKMGR_BYPASS_ADDR) & + (ALT_CLKMGR_BYPASS_SDRPLL_CLR_MSK & ALT_CLKMGR_BYPASS_SDRPLLSRC_CLR_MSK); + temp |= (use_input_mux) ? ALT_CLKMGR_BYPASS_SDRPLL_SET_MSK | + ALT_CLKMGR_BYPASS_SDRPLLSRC_SET_MSK : ALT_CLKMGR_BYPASS_SDRPLL_SET_MSK; + // set bypass bit and optionally the source select bit + alt_write_word(ALT_CLKMGR_BYPASS_ADDR, temp); + status = ALT_E_SUCCESS; + } + return status; +} + + +/****************************************************************************************/ +/* alt_clk_pll_is_bypassed() returns whether the specified PLL is in bypass or not. */ +/* Bypass is a special state where the PLL VCO and the C0-C5 counters are bypassed */ +/* and not in the circuit. Either the Osc1 clock input or the input chosen by the */ +/* input mux may be selected to be operational in the bypass state. All changes to */ +/* the PLL VCO must be made in bypass mode to avoid the potential of producing clock */ +/* glitches which may affect downstream clock dividers and peripherals. */ +/****************************************************************************************/ + +ALT_STATUS_CODE alt_clk_pll_is_bypassed(ALT_CLK_t pll) +{ + ALT_STATUS_CODE status = ALT_E_BAD_ARG; + + if (pll == ALT_CLK_MAIN_PLL) + { + status = (ALT_CLKMGR_CTL_SAFEMOD_GET(alt_read_word(ALT_CLKMGR_CTL_ADDR)) + || ALT_CLKMGR_BYPASS_MAINPLL_GET(alt_read_word(ALT_CLKMGR_BYPASS_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + } + else if (pll == ALT_CLK_PERIPHERAL_PLL) + { + status = (ALT_CLKMGR_CTL_SAFEMOD_GET(alt_read_word(ALT_CLKMGR_CTL_ADDR)) + || ALT_CLKMGR_BYPASS_PERPLL_GET(alt_read_word(ALT_CLKMGR_BYPASS_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + } + else if (pll == ALT_CLK_SDRAM_PLL) + { + status = (ALT_CLKMGR_CTL_SAFEMOD_GET(alt_read_word(ALT_CLKMGR_CTL_ADDR)) + || ALT_CLKMGR_BYPASS_SDRPLL_GET(alt_read_word(ALT_CLKMGR_BYPASS_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + } + return status; +} + + +/****************************************************************************************/ +/* alt_clk_pll_source_get() returns the current input of the specified PLL. */ +/****************************************************************************************/ + +ALT_CLK_t alt_clk_pll_source_get(ALT_CLK_t pll) +{ + ALT_CLK_t ret = ALT_CLK_UNKNOWN; + uint32_t temp; + + + if (pll == ALT_CLK_MAIN_PLL) + { + ret = ALT_CLK_IN_PIN_OSC1; + } + else if (pll == ALT_CLK_PERIPHERAL_PLL) + { + // three possible clock sources for the peripheral PLL + temp = ALT_CLKMGR_PERPLL_VCO_PSRC_GET(alt_read_word(ALT_CLKMGR_PERPLL_VCO_ADDR)); + if (temp == ALT_CLKMGR_PERPLL_VCO_PSRC_E_EOSC1) + { + ret = ALT_CLK_IN_PIN_OSC1; + } + else if (temp == ALT_CLKMGR_PERPLL_VCO_PSRC_E_EOSC2) + { + ret = ALT_CLK_IN_PIN_OSC2; + } + else if (temp == ALT_CLKMGR_PERPLL_VCO_PSRC_E_F2S_PERIPH_REF) + { + ret = ALT_CLK_F2H_PERIPH_REF; + } + } + else if (pll == ALT_CLK_SDRAM_PLL) + { + // three possible clock sources for the SDRAM PLL + temp = ALT_CLKMGR_SDRPLL_VCO_SSRC_GET(alt_read_word(ALT_CLKMGR_SDRPLL_VCO_ADDR)); + if (temp == ALT_CLKMGR_SDRPLL_VCO_SSRC_E_EOSC1) + { + ret = ALT_CLK_IN_PIN_OSC1; + } + else if (temp == ALT_CLKMGR_SDRPLL_VCO_SSRC_E_EOSC2) + { + ret = ALT_CLK_IN_PIN_OSC2; + } + else if (temp == ALT_CLKMGR_SDRPLL_VCO_SSRC_E_F2S_SDRAM_REF) + { + ret = ALT_CLK_F2H_SDRAM_REF; + } + } + return ret; +} + +// +// alt_clk_clock_disable() disables the specified clock. Once the clock is disabled, +// its clock signal does not propagate to its clocked elements. +// +ALT_STATUS_CODE alt_clk_clock_disable(ALT_CLK_t clk) +{ + ALT_STATUS_CODE status = ALT_E_SUCCESS; + + switch (clk) + { + // For PLLs, put them in bypass mode. + case ALT_CLK_MAIN_PLL: + case ALT_CLK_PERIPHERAL_PLL: + case ALT_CLK_SDRAM_PLL: + status = alt_clk_pll_bypass_enable(clk, false); + break; + + // Clocks that originate at the Main PLL. + case ALT_CLK_L4_MAIN: + alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_L4MAINCLK_SET_MSK); + break; + case ALT_CLK_L3_MP: + alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_L3MPCLK_SET_MSK); + break; + case ALT_CLK_L4_MP: + alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_L4MPCLK_SET_MSK); + break; + case ALT_CLK_L4_SP: + alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_L4SPCLK_SET_MSK); + break; + case ALT_CLK_DBG_AT: + alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGATCLK_SET_MSK); + break; + case ALT_CLK_DBG: + alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGCLK_SET_MSK); + break; + case ALT_CLK_DBG_TRACE: + alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGTRACECLK_SET_MSK); + break; + case ALT_CLK_DBG_TIMER: + alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGTMRCLK_SET_MSK); + break; + case ALT_CLK_CFG: + alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_CFGCLK_SET_MSK); + break; + case ALT_CLK_H2F_USER0: + alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_S2FUSER0CLK_SET_MSK); + break; + + // Clocks that originate at the Peripheral PLL. + case ALT_CLK_EMAC0: + alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_EMAC0CLK_SET_MSK); + break; + case ALT_CLK_EMAC1: + alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_EMAC1CLK_SET_MSK); + break; + case ALT_CLK_USB_MP: + alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_USBCLK_SET_MSK); + break; + case ALT_CLK_SPI_M: + alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_SPIMCLK_SET_MSK); + break; + case ALT_CLK_CAN0: + alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_CAN0CLK_SET_MSK); + break; + case ALT_CLK_CAN1: + alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_CAN1CLK_SET_MSK); + break; + case ALT_CLK_GPIO_DB: + alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_GPIOCLK_SET_MSK); + break; + case ALT_CLK_H2F_USER1: + alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_S2FUSER1CLK_SET_MSK); + break; + case ALT_CLK_SDMMC: + alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_SDMMCCLK_SET_MSK); + break; + case ALT_CLK_NAND_X: + alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_NANDCLK_SET_MSK); + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_SW_MANAGED_CLK_WAIT_NANDCLK); + // gate nand_clk off before nand_x_clk. + alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_NANDXCLK_SET_MSK); + break; + case ALT_CLK_NAND: + alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_NANDCLK_SET_MSK); + break; + case ALT_CLK_QSPI: + alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_QSPICLK_SET_MSK); + break; + + // Clocks that originate at the SDRAM PLL. + case ALT_CLK_DDR_DQS: + alt_clrbits_word(ALT_CLKMGR_SDRPLL_EN_ADDR, ALT_CLKMGR_SDRPLL_EN_DDRDQSCLK_SET_MSK); + break; + case ALT_CLK_DDR_2X_DQS: + alt_clrbits_word(ALT_CLKMGR_SDRPLL_EN_ADDR, ALT_CLKMGR_SDRPLL_EN_DDR2XDQSCLK_SET_MSK); + break; + case ALT_CLK_DDR_DQ: + alt_clrbits_word(ALT_CLKMGR_SDRPLL_EN_ADDR, ALT_CLKMGR_SDRPLL_EN_DDRDQCLK_SET_MSK); + break; + case ALT_CLK_H2F_USER2: + alt_clrbits_word(ALT_CLKMGR_SDRPLL_EN_ADDR, ALT_CLKMGR_SDRPLL_EN_S2FUSER2CLK_SET_MSK); + break; + + default: + status = ALT_E_BAD_ARG; + break; + } + + return status; +} + + +// +// alt_clk_clock_enable() enables the specified clock. Once the clock is enabled, its +// clock signal propagates to its elements. +// +ALT_STATUS_CODE alt_clk_clock_enable(ALT_CLK_t clk) +{ + ALT_STATUS_CODE status = ALT_E_SUCCESS; + + switch (clk) + { + // For PLLs, take them out of bypass mode. + case ALT_CLK_MAIN_PLL: + case ALT_CLK_PERIPHERAL_PLL: + case ALT_CLK_SDRAM_PLL: + status = alt_clk_pll_bypass_disable(clk); + break; + + // Clocks that originate at the Main PLL. + case ALT_CLK_L4_MAIN: + alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_L4MAINCLK_SET_MSK); + break; + case ALT_CLK_L3_MP: + alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_L3MPCLK_SET_MSK); + break; + case ALT_CLK_L4_MP: + alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_L4MPCLK_SET_MSK); + break; + case ALT_CLK_L4_SP: + alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_L4SPCLK_SET_MSK); + break; + case ALT_CLK_DBG_AT: + alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGATCLK_SET_MSK); + break; + case ALT_CLK_DBG: + alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGCLK_SET_MSK); + break; + case ALT_CLK_DBG_TRACE: + alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGTRACECLK_SET_MSK); + break; + case ALT_CLK_DBG_TIMER: + alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGTMRCLK_SET_MSK); + break; + case ALT_CLK_CFG: + alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_CFGCLK_SET_MSK); + break; + case ALT_CLK_H2F_USER0: + alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_S2FUSER0CLK_SET_MSK); + break; + + // Clocks that originate at the Peripheral PLL. + case ALT_CLK_EMAC0: + alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_EMAC0CLK_SET_MSK); + break; + case ALT_CLK_EMAC1: + alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_EMAC1CLK_SET_MSK); + break; + case ALT_CLK_USB_MP: + alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_USBCLK_SET_MSK); + break; + case ALT_CLK_SPI_M: + alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_SPIMCLK_SET_MSK); + break; + case ALT_CLK_CAN0: + alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_CAN0CLK_SET_MSK); + break; + case ALT_CLK_CAN1: + alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_CAN1CLK_SET_MSK); + break; + case ALT_CLK_GPIO_DB: + alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_GPIOCLK_SET_MSK); + break; + case ALT_CLK_H2F_USER1: + alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_S2FUSER1CLK_SET_MSK); + break; + case ALT_CLK_SDMMC: + alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_SDMMCCLK_SET_MSK); + break; + case ALT_CLK_NAND_X: + // implementation detail - should ALK_CLK_NAND be gated off here before enabling ALT_CLK_NAND_X? + alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_NANDXCLK_SET_MSK); + // implementation detail - should this wait be enforced here? + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_SW_MANAGED_CLK_WAIT_NANDCLK); + break; + case ALT_CLK_NAND: + // enabling ALT_CLK_NAND always implies enabling ALT_CLK_NAND_X first + alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_NANDXCLK_SET_MSK); + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_SW_MANAGED_CLK_WAIT_NANDCLK); + // gate nand_x_clk on at least 8 MCU clocks before nand_clk + alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_NANDCLK_SET_MSK); + break; + case ALT_CLK_QSPI: + alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_QSPICLK_SET_MSK); + break; + + // Clocks that originate at the SDRAM PLL. + case ALT_CLK_DDR_DQS: + alt_setbits_word(ALT_CLKMGR_SDRPLL_EN_ADDR, ALT_CLKMGR_SDRPLL_EN_DDRDQSCLK_SET_MSK); + break; + case ALT_CLK_DDR_2X_DQS: + alt_setbits_word(ALT_CLKMGR_SDRPLL_EN_ADDR, ALT_CLKMGR_SDRPLL_EN_DDR2XDQSCLK_SET_MSK); + break; + case ALT_CLK_DDR_DQ: + alt_setbits_word(ALT_CLKMGR_SDRPLL_EN_ADDR, ALT_CLKMGR_SDRPLL_EN_DDRDQCLK_SET_MSK); + break; + case ALT_CLK_H2F_USER2: + alt_setbits_word(ALT_CLKMGR_SDRPLL_EN_ADDR, ALT_CLKMGR_SDRPLL_EN_S2FUSER2CLK_SET_MSK); + break; + + default: + status = ALT_E_BAD_ARG; + break; + } + + return status; +} + +// +// alt_clk_is_enabled() returns whether the specified clock is enabled or not. +// +ALT_STATUS_CODE alt_clk_is_enabled(ALT_CLK_t clk) +{ + ALT_STATUS_CODE status = ALT_E_BAD_ARG; + + switch (clk) + { + // For PLLs, this function checks if the PLL is bypassed or not. + case ALT_CLK_MAIN_PLL: + case ALT_CLK_PERIPHERAL_PLL: + case ALT_CLK_SDRAM_PLL: + status = (alt_clk_pll_is_bypassed(clk) != ALT_E_TRUE); + break; + + // These clocks are not gated, so must return a ALT_E_BAD_ARG type error. + case ALT_CLK_MAIN_PLL_C0: + case ALT_CLK_MAIN_PLL_C1: + case ALT_CLK_MAIN_PLL_C2: + case ALT_CLK_MAIN_PLL_C3: + case ALT_CLK_MAIN_PLL_C4: + case ALT_CLK_MAIN_PLL_C5: + case ALT_CLK_MPU: + case ALT_CLK_MPU_L2_RAM: + case ALT_CLK_MPU_PERIPH: + case ALT_CLK_L3_MAIN: + case ALT_CLK_L3_SP: + case ALT_CLK_DBG_BASE: + case ALT_CLK_MAIN_QSPI: + case ALT_CLK_MAIN_NAND_SDMMC: + case ALT_CLK_PERIPHERAL_PLL_C0: + case ALT_CLK_PERIPHERAL_PLL_C1: + case ALT_CLK_PERIPHERAL_PLL_C2: + case ALT_CLK_PERIPHERAL_PLL_C3: + case ALT_CLK_PERIPHERAL_PLL_C4: + case ALT_CLK_PERIPHERAL_PLL_C5: + case ALT_CLK_SDRAM_PLL_C0: + case ALT_CLK_SDRAM_PLL_C1: + case ALT_CLK_SDRAM_PLL_C2: + case ALT_CLK_SDRAM_PLL_C5: + status = ALT_E_BAD_ARG; + break; + + // Clocks that originate at the Main PLL. + case ALT_CLK_L4_MAIN: + status = (ALT_CLKMGR_MAINPLL_EN_L4MAINCLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_L3_MP: + status = (ALT_CLKMGR_MAINPLL_EN_L3MPCLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_L4_MP: + status = (ALT_CLKMGR_MAINPLL_EN_L4MPCLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_L4_SP: + status = (ALT_CLKMGR_MAINPLL_EN_L4SPCLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_DBG_AT: + status = (ALT_CLKMGR_MAINPLL_EN_DBGATCLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_DBG: + status = (ALT_CLKMGR_MAINPLL_EN_DBGCLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_DBG_TRACE: + status = (ALT_CLKMGR_MAINPLL_EN_DBGTRACECLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_DBG_TIMER: + status = (ALT_CLKMGR_MAINPLL_EN_DBGTMRCLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_CFG: + status = (ALT_CLKMGR_MAINPLL_EN_CFGCLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_H2F_USER0: + status = (ALT_CLKMGR_MAINPLL_EN_S2FUSER0CLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + + // Clocks that originate at the Peripheral PLL. + case ALT_CLK_EMAC0: + status = (ALT_CLKMGR_PERPLL_EN_EMAC0CLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_EMAC1: + status = (ALT_CLKMGR_PERPLL_EN_EMAC1CLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_USB_MP: + status = (ALT_CLKMGR_PERPLL_EN_USBCLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_SPI_M: + status = (ALT_CLKMGR_PERPLL_EN_SPIMCLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_CAN0: + status = (ALT_CLKMGR_PERPLL_EN_CAN0CLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_CAN1: + status = (ALT_CLKMGR_PERPLL_EN_CAN1CLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_GPIO_DB: + status = (ALT_CLKMGR_PERPLL_EN_GPIOCLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_H2F_USER1: + status = (ALT_CLKMGR_PERPLL_EN_S2FUSER1CLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + + // Clocks that may originate at the Main PLL, the Peripheral PLL, or the FPGA. + case ALT_CLK_SDMMC: + status = (ALT_CLKMGR_PERPLL_EN_SDMMCCLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_NAND_X: + status = (ALT_CLKMGR_PERPLL_EN_NANDXCLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_NAND: + status = (ALT_CLKMGR_PERPLL_EN_NANDCLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_QSPI: + status = (ALT_CLKMGR_PERPLL_EN_QSPICLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + + // Clocks that originate at the SDRAM PLL. + case ALT_CLK_DDR_DQS: + status = (ALT_CLKMGR_SDRPLL_EN_DDRDQSCLK_GET(alt_read_word(ALT_CLKMGR_SDRPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_DDR_2X_DQS: + status = (ALT_CLKMGR_SDRPLL_EN_DDR2XDQSCLK_GET(alt_read_word(ALT_CLKMGR_SDRPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_DDR_DQ: + status = (ALT_CLKMGR_SDRPLL_EN_DDRDQCLK_GET(alt_read_word(ALT_CLKMGR_SDRPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + case ALT_CLK_H2F_USER2: + status = (ALT_CLKMGR_SDRPLL_EN_S2FUSER2CLK_GET(alt_read_word(ALT_CLKMGR_SDRPLL_EN_ADDR))) + ? ALT_E_TRUE : ALT_E_FALSE; + break; + + default: + status = ALT_E_BAD_ARG; + break; + + } + + return status; +} + +// +// alt_clk_source_get() gets the input reference clock source selection value for the +// specified clock or PLL. +// +ALT_CLK_t alt_clk_source_get(ALT_CLK_t clk) +{ + ALT_CLK_t ret = ALT_CLK_UNKNOWN; + uint32_t temp; + + switch (clk) + { + // Potential external clock sources. + // these clock entities are their own source + case ALT_CLK_IN_PIN_OSC1: + case ALT_CLK_IN_PIN_OSC2: + case ALT_CLK_F2H_PERIPH_REF: + case ALT_CLK_F2H_SDRAM_REF: + case ALT_CLK_IN_PIN_JTAG: + case ALT_CLK_IN_PIN_ULPI0: + case ALT_CLK_IN_PIN_ULPI1: + case ALT_CLK_IN_PIN_EMAC0_RX: + case ALT_CLK_IN_PIN_EMAC1_RX: + ret = clk; + break; + + // Phase-Locked Loops. + case ALT_CLK_MAIN_PLL: + case ALT_CLK_OSC1: + ret = ALT_CLK_IN_PIN_OSC1; + break; + case ALT_CLK_PERIPHERAL_PLL: + ret = alt_clk_pll_source_get(ALT_CLK_PERIPHERAL_PLL); + break; + case ALT_CLK_SDRAM_PLL: + ret = alt_clk_pll_source_get(ALT_CLK_SDRAM_PLL); + break; + + // Main Clock Group. + case ALT_CLK_MAIN_PLL_C0: + case ALT_CLK_MAIN_PLL_C1: + case ALT_CLK_MAIN_PLL_C2: + case ALT_CLK_MAIN_PLL_C3: + case ALT_CLK_MAIN_PLL_C4: + case ALT_CLK_MAIN_PLL_C5: + // check bypass, return either osc1 or PLL ID + ret = (alt_clk_pll_is_bypassed(ALT_CLK_MAIN_PLL) == ALT_E_TRUE) ? + ALT_CLK_IN_PIN_OSC1 : ALT_CLK_MAIN_PLL; + break; + + case ALT_CLK_MPU_PERIPH: + case ALT_CLK_MPU_L2_RAM: + case ALT_CLK_MPU: + ret = (alt_clk_pll_is_bypassed(ALT_CLK_MAIN_PLL) == ALT_E_TRUE) ? + ALT_CLK_IN_PIN_OSC1 : ALT_CLK_MAIN_PLL_C0; + break; + + case ALT_CLK_L4_MAIN: + case ALT_CLK_L3_MAIN: + case ALT_CLK_L3_MP: + case ALT_CLK_L3_SP: + ret = (alt_clk_pll_is_bypassed(ALT_CLK_MAIN_PLL) == ALT_E_TRUE) ? + ALT_CLK_IN_PIN_OSC1 : ALT_CLK_MAIN_PLL_C1; + break; + + case ALT_CLK_L4_MP: + // read the state of the L4_mp source bit + if ((ALT_CLKMGR_MAINPLL_L4SRC_L4MP_GET(alt_read_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR))) + == ALT_CLKMGR_MAINPLL_L4SRC_L4MP_E_MAINPLL) + { + ret = (alt_clk_pll_is_bypassed(ALT_CLK_MAIN_PLL) == ALT_E_TRUE) ? + ALT_CLK_IN_PIN_OSC1 : ALT_CLK_MAIN_PLL_C1; + } + else + { + // if the clock comes from periph_base_clk + ret = (alt_clk_pll_is_bypassed(ALT_CLK_PERIPHERAL_PLL) == ALT_E_TRUE) ? + alt_clk_pll_source_get(ALT_CLK_PERIPHERAL_PLL) : ALT_CLK_PERIPHERAL_PLL_C4; + } + break; + + case ALT_CLK_L4_SP: + // read the state of the source bit + if ((ALT_CLKMGR_MAINPLL_L4SRC_L4SP_GET(alt_read_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR))) + == ALT_CLKMGR_MAINPLL_L4SRC_L4SP_E_MAINPLL) + { + ret = (alt_clk_pll_is_bypassed(ALT_CLK_MAIN_PLL) == ALT_E_TRUE) ? + ALT_CLK_IN_PIN_OSC1 : ALT_CLK_MAIN_PLL_C1; + } + else + { + // if the clock comes from periph_base_clk + ret = (alt_clk_pll_is_bypassed(ALT_CLK_PERIPHERAL_PLL) == ALT_E_TRUE) ? + alt_clk_pll_source_get(ALT_CLK_PERIPHERAL_PLL) : ALT_CLK_PERIPHERAL_PLL_C4; + } + break; + + case ALT_CLK_DBG_BASE: + case ALT_CLK_DBG_AT: + case ALT_CLK_DBG_TRACE: + case ALT_CLK_DBG_TIMER: + case ALT_CLK_DBG: + ret = (alt_clk_pll_is_bypassed(ALT_CLK_MAIN_PLL) == ALT_E_TRUE) ? + ALT_CLK_OSC1 : ALT_CLK_MAIN_PLL_C2; + break; + case ALT_CLK_MAIN_QSPI: + ret = (alt_clk_pll_is_bypassed(ALT_CLK_MAIN_PLL) == ALT_E_TRUE) ? + ALT_CLK_OSC1 : ALT_CLK_MAIN_PLL_C3; + break; + case ALT_CLK_MAIN_NAND_SDMMC: + ret = (alt_clk_pll_is_bypassed(ALT_CLK_MAIN_PLL) == ALT_E_TRUE) ? + ALT_CLK_OSC1 : ALT_CLK_MAIN_PLL_C4; + break; + case ALT_CLK_CFG: + case ALT_CLK_H2F_USER0: + ret = (alt_clk_pll_is_bypassed(ALT_CLK_MAIN_PLL) == ALT_E_TRUE) ? + ALT_CLK_OSC1 : ALT_CLK_MAIN_PLL_C5; + break; + + // Peripherals Clock Group + case ALT_CLK_PERIPHERAL_PLL_C0: + case ALT_CLK_PERIPHERAL_PLL_C1: + case ALT_CLK_PERIPHERAL_PLL_C2: + case ALT_CLK_PERIPHERAL_PLL_C3: + case ALT_CLK_PERIPHERAL_PLL_C4: + case ALT_CLK_PERIPHERAL_PLL_C5: + // if the clock comes from periph_base_clk + ret = (alt_clk_pll_is_bypassed(ALT_CLK_PERIPHERAL_PLL) == ALT_E_TRUE) ? + alt_clk_pll_source_get(ALT_CLK_PERIPHERAL_PLL) : ALT_CLK_PERIPHERAL_PLL; + break; + + case ALT_CLK_EMAC0: + ret = (alt_clk_pll_is_bypassed(ALT_CLK_PERIPHERAL_PLL) == ALT_E_TRUE) ? + alt_clk_pll_source_get(ALT_CLK_PERIPHERAL_PLL) : ALT_CLK_PERIPHERAL_PLL_C0; + break; + + case ALT_CLK_EMAC1: + ret = (alt_clk_pll_is_bypassed(ALT_CLK_PERIPHERAL_PLL) == ALT_E_TRUE) ? + alt_clk_pll_source_get(ALT_CLK_PERIPHERAL_PLL) : ALT_CLK_PERIPHERAL_PLL_C1; + break; + + case ALT_CLK_USB_MP: + case ALT_CLK_SPI_M: + case ALT_CLK_CAN0: + case ALT_CLK_CAN1: + case ALT_CLK_GPIO_DB: + ret = (alt_clk_pll_is_bypassed(ALT_CLK_PERIPHERAL_PLL) == ALT_E_TRUE) ? + alt_clk_pll_source_get(ALT_CLK_PERIPHERAL_PLL) : ALT_CLK_PERIPHERAL_PLL_C4; + break; + + case ALT_CLK_H2F_USER1: + ret = (alt_clk_pll_is_bypassed(ALT_CLK_PERIPHERAL_PLL) == ALT_E_TRUE) ? + alt_clk_pll_source_get(ALT_CLK_PERIPHERAL_PLL) : ALT_CLK_PERIPHERAL_PLL_C5; + break; + + case ALT_CLK_SDMMC: + temp = ALT_CLKMGR_PERPLL_SRC_SDMMC_GET(alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR)); + if (temp == ALT_CLKMGR_PERPLL_SRC_SDMMC_E_F2S_PERIPH_REF_CLK) + { + ret = ALT_CLK_F2H_PERIPH_REF; + } + else if (temp == ALT_CLKMGR_PERPLL_SRC_SDMMC_E_MAIN_NAND_CLK) + { + ret = (alt_clk_pll_is_bypassed(ALT_CLK_MAIN_PLL) == ALT_E_TRUE) ? + ALT_CLK_IN_PIN_OSC1 : ALT_CLK_MAIN_PLL_C4; + } + else if (temp == ALT_CLKMGR_PERPLL_SRC_SDMMC_E_PERIPH_NAND_CLK) + { + ret = (alt_clk_pll_is_bypassed(ALT_CLK_PERIPHERAL_PLL) == ALT_E_TRUE) ? + alt_clk_pll_source_get(ALT_CLK_PERIPHERAL_PLL) : ALT_CLK_PERIPHERAL_PLL_C3; + } + break; + + case ALT_CLK_NAND_X: + case ALT_CLK_NAND: + temp = ALT_CLKMGR_PERPLL_SRC_NAND_GET(alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR)); + if (temp == ALT_CLKMGR_PERPLL_SRC_NAND_E_F2S_PERIPH_REF_CLK) + { + ret = ALT_CLK_F2H_PERIPH_REF; + } + else if (temp == ALT_CLKMGR_PERPLL_SRC_NAND_E_MAIN_NAND_CLK) + { + ret = (alt_clk_pll_is_bypassed(ALT_CLK_MAIN_PLL) == ALT_E_TRUE) ? + ALT_CLK_IN_PIN_OSC1 : ALT_CLK_MAIN_PLL_C4; + } + else if (temp == ALT_CLKMGR_PERPLL_SRC_NAND_E_PERIPH_NAND_CLK) + { + ret = (alt_clk_pll_is_bypassed(ALT_CLK_PERIPHERAL_PLL) == ALT_E_TRUE) ? + alt_clk_pll_source_get(ALT_CLK_PERIPHERAL_PLL) : ALT_CLK_PERIPHERAL_PLL_C3; + } + break; + + case ALT_CLK_QSPI: + temp = ALT_CLKMGR_PERPLL_SRC_QSPI_GET(alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR)); + if (temp == ALT_CLKMGR_PERPLL_SRC_QSPI_E_F2S_PERIPH_REF_CLK) + { + ret = ALT_CLK_F2H_PERIPH_REF; + } + else if (temp == ALT_CLKMGR_PERPLL_SRC_QSPI_E_MAIN_QSPI_CLK) + { + ret = (alt_clk_pll_is_bypassed(ALT_CLK_MAIN_PLL) == ALT_E_TRUE) ? + ALT_CLK_IN_PIN_OSC1 : ALT_CLK_MAIN_PLL_C3; + } + else if (temp == ALT_CLKMGR_PERPLL_SRC_QSPI_E_PERIPH_QSPI_CLK) + { + ret = (alt_clk_pll_is_bypassed(ALT_CLK_PERIPHERAL_PLL) == ALT_E_TRUE) ? + alt_clk_pll_source_get(ALT_CLK_PERIPHERAL_PLL) : ALT_CLK_PERIPHERAL_PLL_C2; + } + break; + + // SDRAM Clock Group + case ALT_CLK_SDRAM_PLL_C0: + case ALT_CLK_SDRAM_PLL_C1: + case ALT_CLK_SDRAM_PLL_C2: + case ALT_CLK_SDRAM_PLL_C3: + case ALT_CLK_SDRAM_PLL_C4: + case ALT_CLK_SDRAM_PLL_C5: + ret = (alt_clk_pll_is_bypassed(ALT_CLK_SDRAM_PLL) == ALT_E_TRUE) ? + alt_clk_pll_source_get(ALT_CLK_SDRAM_PLL) : ALT_CLK_SDRAM_PLL; + break; + case ALT_CLK_DDR_DQS: + ret = (alt_clk_pll_is_bypassed(ALT_CLK_SDRAM_PLL) == ALT_E_TRUE) ? + alt_clk_pll_source_get(ALT_CLK_SDRAM_PLL) : ALT_CLK_SDRAM_PLL_C0; + break; + case ALT_CLK_DDR_2X_DQS: + ret = (alt_clk_pll_is_bypassed(ALT_CLK_SDRAM_PLL) == ALT_E_TRUE) ? + alt_clk_pll_source_get(ALT_CLK_SDRAM_PLL) : ALT_CLK_SDRAM_PLL_C1; + break; + case ALT_CLK_DDR_DQ: + ret = (alt_clk_pll_is_bypassed(ALT_CLK_SDRAM_PLL) == ALT_E_TRUE) ? + alt_clk_pll_source_get(ALT_CLK_SDRAM_PLL) : ALT_CLK_SDRAM_PLL_C2; + break; + case ALT_CLK_H2F_USER2: + ret = (alt_clk_pll_is_bypassed(ALT_CLK_SDRAM_PLL) == ALT_E_TRUE) ? + alt_clk_pll_source_get(ALT_CLK_SDRAM_PLL) : ALT_CLK_SDRAM_PLL_C5; + break; + + // Clock Output Pins + case ALT_CLK_OUT_PIN_EMAC0_TX: + case ALT_CLK_OUT_PIN_EMAC1_TX: + case ALT_CLK_OUT_PIN_SDMMC: + case ALT_CLK_OUT_PIN_I2C0_SCL: + case ALT_CLK_OUT_PIN_I2C1_SCL: + case ALT_CLK_OUT_PIN_I2C2_SCL: + case ALT_CLK_OUT_PIN_I2C3_SCL: + case ALT_CLK_OUT_PIN_SPIM0: + case ALT_CLK_OUT_PIN_SPIM1: + case ALT_CLK_OUT_PIN_QSPI: + ret = ALT_CLK_UNKNOWN; + break; + + default: + ret = ALT_CLK_UNKNOWN; + break; + } + + return ret; +} + +// +// alt_clk_source_set() sets the specified clock's input reference clock source +// selection to the specified input. It does not handle gating the specified clock +// off and back on, those are covered in other functions in this API, but it does +// verify that the clock is off before changing the divider or PLL. Note that the PLL +// must have regained phase-lock before being the bypass is disabled. +// +ALT_STATUS_CODE alt_clk_source_set(ALT_CLK_t clk, ALT_CLK_t ref_clk) +{ + ALT_STATUS_CODE status = ALT_E_SUCCESS; + uint32_t temp; + + if (ALT_CLK_MAIN_PLL == clk) + { + if ((ref_clk == ALT_CLK_IN_PIN_OSC1) || (ref_clk == ALT_CLK_OSC1)) + { + // ret = ALT_E_SUCCESS; + } + else + { + status = ALT_E_BAD_ARG; + } + } + else if (ALT_CLK_PERIPHERAL_PLL == clk) + { + // the PLL must be bypassed before getting here + temp = alt_read_word(ALT_CLKMGR_PERPLL_VCO_ADDR); + temp &= ALT_CLKMGR_PERPLL_VCO_PSRC_CLR_MSK; + + if ((ref_clk == ALT_CLK_IN_PIN_OSC1) || (ref_clk == ALT_CLK_OSC1)) + { + temp |= ALT_CLKMGR_PERPLL_VCO_PSRC_SET(ALT_CLKMGR_PERPLL_VCO_PSRC_E_EOSC1); + alt_write_word(ALT_CLKMGR_PERPLL_VCO_ADDR, temp); + } + else if (ref_clk == ALT_CLK_IN_PIN_OSC2) + { + temp |= ALT_CLKMGR_PERPLL_VCO_PSRC_SET(ALT_CLKMGR_PERPLL_VCO_PSRC_E_EOSC2); + alt_write_word(ALT_CLKMGR_PERPLL_VCO_ADDR, temp); + } + else if (ref_clk == ALT_CLK_F2H_PERIPH_REF) + { + temp |= ALT_CLKMGR_PERPLL_VCO_PSRC_SET(ALT_CLKMGR_PERPLL_VCO_PSRC_E_F2S_PERIPH_REF); + alt_write_word(ALT_CLKMGR_PERPLL_VCO_ADDR, temp); + } + else + { + status = ALT_E_INV_OPTION; + } + } + else if (ALT_CLK_SDRAM_PLL == clk) + { + temp = alt_read_word(ALT_CLKMGR_SDRPLL_VCO_ADDR); + temp &= ALT_CLKMGR_SDRPLL_VCO_SSRC_CLR_MSK; + + if ((ref_clk == ALT_CLK_IN_PIN_OSC1) || (ref_clk == ALT_CLK_OSC1)) + { + temp |= ALT_CLKMGR_SDRPLL_VCO_SSRC_SET(ALT_CLKMGR_SDRPLL_VCO_SSRC_E_EOSC1); + alt_write_word(ALT_CLKMGR_SDRPLL_VCO_ADDR, temp); + } + else if (ref_clk == ALT_CLK_IN_PIN_OSC2) + { + temp |= ALT_CLKMGR_SDRPLL_VCO_SSRC_SET(ALT_CLKMGR_SDRPLL_VCO_SSRC_E_EOSC2); + alt_write_word(ALT_CLKMGR_SDRPLL_VCO_ADDR, temp); + } + else if (ref_clk == ALT_CLK_F2H_SDRAM_REF) + { + temp |= ALT_CLKMGR_SDRPLL_VCO_SSRC_SET(ALT_CLKMGR_SDRPLL_VCO_SSRC_E_F2S_SDRAM_REF); + alt_write_word(ALT_CLKMGR_SDRPLL_VCO_ADDR, temp); + } + else + { + status = ALT_E_INV_OPTION; + } + } + else if ( ALT_CLK_L4_MP == clk) + { + // clock is gated off + if (ref_clk == ALT_CLK_MAIN_PLL_C1) + { + alt_clrbits_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR, ALT_CLKMGR_MAINPLL_L4SRC_L4MP_SET_MSK); + } + else if (ref_clk == ALT_CLK_PERIPHERAL_PLL_C4) + { + alt_setbits_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR, ALT_CLKMGR_MAINPLL_L4SRC_L4MP_SET_MSK); + } + else + { + status = ALT_E_INV_OPTION; + } + } + else if ( ALT_CLK_L4_SP == clk) + { + if (ref_clk == ALT_CLK_MAIN_PLL_C1) + { + alt_clrbits_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR, ALT_CLKMGR_MAINPLL_L4SRC_L4SP_SET_MSK); + } + else if (ref_clk == ALT_CLK_PERIPHERAL_PLL_C4) + { + alt_setbits_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR, ALT_CLKMGR_MAINPLL_L4SRC_L4SP_SET_MSK); + } + else + { + status = ALT_E_INV_OPTION; + } + } + else if (ALT_CLK_SDMMC == clk) + { + temp = alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR); + temp &= ALT_CLKMGR_PERPLL_SRC_SDMMC_CLR_MSK; + + if (ref_clk == ALT_CLK_F2H_PERIPH_REF) + { + temp |= ALT_CLKMGR_PERPLL_SRC_SDMMC_SET(ALT_CLKMGR_PERPLL_SRC_SDMMC_E_F2S_PERIPH_REF_CLK); + alt_write_word(ALT_CLKMGR_PERPLL_SRC_ADDR, temp); + } + else if ((ref_clk == ALT_CLK_MAIN_PLL_C4) || (ref_clk == ALT_CLK_MAIN_NAND_SDMMC)) + { + temp |= ALT_CLKMGR_PERPLL_SRC_SDMMC_SET(ALT_CLKMGR_PERPLL_SRC_SDMMC_E_MAIN_NAND_CLK); + alt_write_word(ALT_CLKMGR_PERPLL_SRC_ADDR, temp); + } + else if (ref_clk == ALT_CLK_PERIPHERAL_PLL_C3) + { + temp |= ALT_CLKMGR_PERPLL_SRC_SDMMC_SET(ALT_CLKMGR_PERPLL_SRC_SDMMC_E_PERIPH_NAND_CLK); + alt_write_word(ALT_CLKMGR_PERPLL_SRC_ADDR, temp); + } + else + { + status = ALT_E_INV_OPTION; + } + } + else if ((ALT_CLK_NAND_X == clk) || ( ALT_CLK_NAND == clk)) + { + temp = alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR); + temp &= ALT_CLKMGR_PERPLL_SRC_NAND_CLR_MSK; + + if (ref_clk == ALT_CLK_F2H_PERIPH_REF) + { + temp |= ALT_CLKMGR_PERPLL_SRC_NAND_SET(ALT_CLKMGR_PERPLL_SRC_NAND_E_F2S_PERIPH_REF_CLK); + alt_write_word(ALT_CLKMGR_PERPLL_SRC_ADDR, temp); + } + else if ((ref_clk == ALT_CLK_MAIN_PLL_C4) || (ref_clk == ALT_CLK_MAIN_NAND_SDMMC)) + { + temp |= ALT_CLKMGR_PERPLL_SRC_NAND_SET(ALT_CLKMGR_PERPLL_SRC_NAND_E_MAIN_NAND_CLK); + alt_write_word(ALT_CLKMGR_PERPLL_SRC_ADDR, temp); + } + else if (ref_clk == ALT_CLK_PERIPHERAL_PLL_C3) + { + temp |= ALT_CLKMGR_PERPLL_SRC_NAND_SET(ALT_CLKMGR_PERPLL_SRC_NAND_E_PERIPH_NAND_CLK); + alt_write_word(ALT_CLKMGR_PERPLL_SRC_ADDR, temp); + } + else + { + status = ALT_E_INV_OPTION; + } + } + else if (ALT_CLK_QSPI == clk) + { + temp = alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR); + temp &= ALT_CLKMGR_PERPLL_SRC_QSPI_CLR_MSK; + + if (ref_clk == ALT_CLK_F2H_PERIPH_REF) + { + temp |= ALT_CLKMGR_PERPLL_SRC_QSPI_SET(ALT_CLKMGR_PERPLL_SRC_QSPI_E_F2S_PERIPH_REF_CLK); + alt_write_word(ALT_CLKMGR_PERPLL_SRC_ADDR, temp); + } + else if ((ref_clk == ALT_CLK_MAIN_PLL_C3) || (ref_clk == ALT_CLK_MAIN_QSPI)) + { + temp |= ALT_CLKMGR_PERPLL_SRC_QSPI_SET(ALT_CLKMGR_PERPLL_SRC_QSPI_E_MAIN_QSPI_CLK); + alt_write_word(ALT_CLKMGR_PERPLL_SRC_ADDR, temp); + } + else if (ref_clk == ALT_CLK_PERIPHERAL_PLL_C2) + { + temp |= ALT_CLKMGR_PERPLL_SRC_QSPI_SET(ALT_CLKMGR_PERPLL_SRC_QSPI_E_PERIPH_QSPI_CLK); + alt_write_word(ALT_CLKMGR_PERPLL_SRC_ADDR, temp); + } + else + { + status = ALT_E_INV_OPTION; + } + } + + return status; +} + +// +// alt_clk_ext_clk_freq_set() specifies the frequency of the external clock source as +// a measure of Hz. This value is stored in a static array and used for calculations. +// The supplied frequency should be within the Fmin and Fmax values allowed for the +// external clock source. +// +ALT_STATUS_CODE alt_clk_ext_clk_freq_set(ALT_CLK_t clk, alt_freq_t freq) +{ + ALT_STATUS_CODE status = ALT_E_BAD_ARG; + + if ((clk == ALT_CLK_IN_PIN_OSC1) || (clk == ALT_CLK_OSC1)) // two names for one input + { + if ((freq >= alt_ext_clk_paramblok.clkosc1.freqmin) && (freq <= alt_ext_clk_paramblok.clkosc1.freqmax)) + { + alt_ext_clk_paramblok.clkosc1.freqcur = freq; + status = ALT_E_SUCCESS; + } + else + { + status = ALT_E_ARG_RANGE; + } + } + else if (clk == ALT_CLK_IN_PIN_OSC2) // the other clock input pin + { + if ((freq >= alt_ext_clk_paramblok.clkosc2.freqmin) && (freq <= alt_ext_clk_paramblok.clkosc2.freqmax)) + { + alt_ext_clk_paramblok.clkosc2.freqcur = freq; + status = ALT_E_SUCCESS; + } + else + { + status = ALT_E_ARG_RANGE; + } + } + else if (clk == ALT_CLK_F2H_PERIPH_REF) // clock from the FPGA + { + if ((freq >= alt_ext_clk_paramblok.periph.freqmin) && (freq <= alt_ext_clk_paramblok.periph.freqmax)) + { + alt_ext_clk_paramblok.periph.freqcur = freq; + status = ALT_E_SUCCESS; + } + else + { + status = ALT_E_ARG_RANGE; + } + } + else if (clk == ALT_CLK_F2H_SDRAM_REF) // clock from the FPGA SDRAM + { + if ((freq >= alt_ext_clk_paramblok.sdram.freqmin) && (freq <= alt_ext_clk_paramblok.sdram.freqmax)) + { + alt_ext_clk_paramblok.sdram.freqcur = freq; + status = ALT_E_SUCCESS; + } + else + { + status = ALT_E_ARG_RANGE; + } + } + else + { + status = ALT_E_BAD_ARG; + } + + return status; +} + + +// +// alt_clk_ext_clk_freq_get returns the frequency of the external clock source as +// a measure of Hz. This value is stored in a static array. +// +alt_freq_t alt_clk_ext_clk_freq_get(ALT_CLK_t clk) +{ + uint32_t ret = 0; + + if ((clk == ALT_CLK_IN_PIN_OSC1) || (clk == ALT_CLK_OSC1)) // two names for one input + { + ret = alt_ext_clk_paramblok.clkosc1.freqcur; + } + else if (clk == ALT_CLK_IN_PIN_OSC2) + { + ret = alt_ext_clk_paramblok.clkosc2.freqcur; + } + else if (clk == ALT_CLK_F2H_PERIPH_REF) // clock from the FPGA + { + ret = alt_ext_clk_paramblok.periph.freqcur; + } + else if (clk == ALT_CLK_F2H_SDRAM_REF) // clock from the FPGA + { + ret = alt_ext_clk_paramblok.sdram.freqcur; + } + return ret; +} + + +// +// alt_clk_pll_cfg_get() returns the current PLL configuration. +// +ALT_STATUS_CODE alt_clk_pll_cfg_get(ALT_CLK_t pll, ALT_CLK_PLL_CFG_t * pll_cfg) +{ + ALT_STATUS_CODE ret = ALT_E_ERROR; // return value + uint32_t temp; // temp variable + + if (pll_cfg == NULL) + { + ret = ALT_E_BAD_ARG; + return ret; + } + + if (pll == ALT_CLK_MAIN_PLL) + { + temp = alt_read_word(ALT_CLKMGR_MAINPLL_VCO_ADDR); + pll_cfg->ref_clk = ALT_CLK_IN_PIN_OSC1; + pll_cfg->mult = ALT_CLKMGR_MAINPLL_VCO_NUMER_GET(temp); + pll_cfg->div = ALT_CLKMGR_MAINPLL_VCO_DENOM_GET(temp); + + // Get the C0-C5 divider values: + pll_cfg->cntrs[0] = ALT_CLKMGR_MAINPLL_MPUCLK_CNT_GET(alt_read_word(ALT_CLKMGR_ALTERA_MPUCLK_ADDR)); + // C0 - mpu_clk + + pll_cfg->cntrs[1] = ALT_CLKMGR_MAINPLL_MAINCLK_CNT_GET(alt_read_word(ALT_CLKMGR_ALTERA_MAINCLK_ADDR)); + // C1 - main_clk + + pll_cfg->cntrs[2] = ALT_CLKMGR_MAINPLL_DBGATCLK_CNT_GET(alt_read_word(ALT_CLKMGR_MAINPLL_DBGATCLK_ADDR)); + // C2 - dbg_base_clk + + pll_cfg->cntrs[3] = ALT_CLKMGR_MAINPLL_MAINQSPICLK_CNT_GET(alt_read_word(ALT_CLKMGR_MAINPLL_MAINQSPICLK_ADDR)); + // C3 - main_qspi_clk + + pll_cfg->cntrs[4] = ALT_CLKMGR_MAINPLL_MAINNANDSDMMCCLK_CNT_GET(alt_read_word(ALT_CLKMGR_MAINPLL_MAINNANDSDMMCCLK_ADDR)); + // C4 - main_nand_sdmmc_clk + + pll_cfg->cntrs[5] = ALT_CLKMGR_MAINPLL_CFGS2FUSER0CLK_CNT_GET(alt_read_word(ALT_CLKMGR_MAINPLL_CFGS2FUSER0CLK_ADDR)); + // C5 - cfg_s2f_user0_clk aka cfg_h2f_user0_clk + + // The Main PLL C0-C5 outputs have no phase shift capabilities : + pll_cfg->pshift[0] = pll_cfg->pshift[1] = pll_cfg->pshift[2] = + pll_cfg->pshift[3] = pll_cfg->pshift[4] = pll_cfg->pshift[5] = 0; + ret = ALT_E_SUCCESS; + } + else if (pll == ALT_CLK_PERIPHERAL_PLL) + { + temp = ALT_CLKMGR_PERPLL_VCO_PSRC_GET(alt_read_word(ALT_CLKMGR_PERPLL_VCO_ADDR)); + if (temp <= 2) + { + if (temp == ALT_CLKMGR_PERPLL_VCO_PSRC_E_EOSC1) + { + pll_cfg->ref_clk = ALT_CLK_IN_PIN_OSC1; + } + else if (temp == ALT_CLKMGR_PERPLL_VCO_PSRC_E_EOSC2) + { + pll_cfg->ref_clk = ALT_CLK_IN_PIN_OSC2; + } + else if (temp == ALT_CLKMGR_PERPLL_VCO_PSRC_E_F2S_PERIPH_REF) + { + pll_cfg->ref_clk = ALT_CLK_F2H_PERIPH_REF; + } + + temp = alt_read_word(ALT_CLKMGR_PERPLL_VCO_ADDR); + pll_cfg->mult = ALT_CLKMGR_PERPLL_VCO_NUMER_GET(temp); + pll_cfg->div = ALT_CLKMGR_PERPLL_VCO_DENOM_GET(temp); + + // Get the C0-C5 divider values: + pll_cfg->cntrs[0] = ALT_CLKMGR_PERPLL_EMAC0CLK_CNT_GET(alt_read_word(ALT_CLKMGR_PERPLL_EMAC0CLK_ADDR)); + // C0 - emac0_clk + + pll_cfg->cntrs[1] = ALT_CLKMGR_PERPLL_EMAC1CLK_CNT_GET(alt_read_word(ALT_CLKMGR_PERPLL_EMAC1CLK_ADDR)); + // C1 - emac1_clk + + pll_cfg->cntrs[2] = ALT_CLKMGR_PERPLL_PERQSPICLK_CNT_GET(alt_read_word(ALT_CLKMGR_PERPLL_PERQSPICLK_ADDR)); + // C2 - periph_qspi_clk + + pll_cfg->cntrs[3] = ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_CNT_GET(alt_read_word(ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_ADDR)); + // C3 - periph_nand_sdmmc_clk + + pll_cfg->cntrs[4] = ALT_CLKMGR_PERPLL_PERBASECLK_CNT_GET(alt_read_word(ALT_CLKMGR_PERPLL_PERBASECLK_ADDR)); + // C4 - periph_base_clk + + pll_cfg->cntrs[5] = ALT_CLKMGR_PERPLL_S2FUSER1CLK_CNT_GET(alt_read_word(ALT_CLKMGR_PERPLL_S2FUSER1CLK_ADDR)); + // C5 - s2f_user1_clk + + // The Peripheral PLL C0-C5 outputs have no phase shift capabilities : + pll_cfg->pshift[0] = pll_cfg->pshift[1] = pll_cfg->pshift[2] = + pll_cfg->pshift[3] = pll_cfg->pshift[4] = pll_cfg->pshift[5] = 0; + ret = ALT_E_SUCCESS; + } + } + else if (pll == ALT_CLK_SDRAM_PLL) + { + temp = ALT_CLKMGR_SDRPLL_VCO_SSRC_GET(alt_read_word(ALT_CLKMGR_SDRPLL_VCO_ADDR)); + if (temp <= 2) + { + if (temp == ALT_CLKMGR_SDRPLL_VCO_SSRC_E_EOSC1) + { + pll_cfg->ref_clk = ALT_CLK_IN_PIN_OSC1; + } + else if (temp == ALT_CLKMGR_SDRPLL_VCO_SSRC_E_EOSC2) + { + pll_cfg->ref_clk = ALT_CLK_IN_PIN_OSC2; + } + else if (temp == ALT_CLKMGR_SDRPLL_VCO_SSRC_E_F2S_SDRAM_REF) + { + pll_cfg->ref_clk = ALT_CLK_F2H_SDRAM_REF; + } + + pll_cfg->mult = ALT_CLKMGR_SDRPLL_VCO_NUMER_GET(alt_read_word(ALT_CLKMGR_SDRPLL_VCO_ADDR)); + pll_cfg->div = ALT_CLKMGR_SDRPLL_VCO_DENOM_GET(alt_read_word(ALT_CLKMGR_SDRPLL_VCO_ADDR)); + + // Get the C0-C5 divider values: + pll_cfg->cntrs[0] = ALT_CLKMGR_SDRPLL_DDRDQSCLK_CNT_GET(alt_read_word(ALT_CLKMGR_SDRPLL_DDRDQSCLK_ADDR)); + pll_cfg->pshift[0] = ALT_CLKMGR_SDRPLL_DDRDQSCLK_PHASE_GET(alt_read_word(ALT_CLKMGR_SDRPLL_DDRDQSCLK_ADDR)); + // C0 - ddr_dqs_clk + + pll_cfg->cntrs[1] = ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_CNT_GET(alt_read_word(ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_ADDR)); + pll_cfg->pshift[1] = ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_PHASE_GET(alt_read_word(ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_ADDR)); + // C1 - ddr_2x_dqs_clk + + pll_cfg->cntrs[2] = ALT_CLKMGR_SDRPLL_DDRDQCLK_CNT_GET(alt_read_word(ALT_CLKMGR_SDRPLL_DDRDQCLK_ADDR)); + pll_cfg->pshift[2] = ALT_CLKMGR_SDRPLL_DDRDQCLK_PHASE_GET(alt_read_word(ALT_CLKMGR_SDRPLL_DDRDQCLK_ADDR)); + // C2 - ddr_dq_clk + + pll_cfg->cntrs[3] = pll_cfg->cntrs[4] = pll_cfg->pshift[3] = pll_cfg->pshift[4] = 0; + // C3 & C4 outputs don't exist on the SDRAM PLL + + pll_cfg->cntrs[5] = ALT_CLKMGR_SDRPLL_S2FUSER2CLK_CNT_GET(alt_read_word(ALT_CLKMGR_SDRPLL_S2FUSER2CLK_ADDR)); + pll_cfg->pshift[5] = ALT_CLKMGR_SDRPLL_S2FUSER2CLK_PHASE_GET(alt_read_word(ALT_CLKMGR_SDRPLL_S2FUSER2CLK_ADDR)); + // C5 - s2f_user2_clk or h2f_user2_clk + + ret = ALT_E_SUCCESS; + } + } + + return ret; +} + + +// +// alt_clk_pll_cfg_set() sets the PLL configuration using the configuration parameters +// specified in pll_cfg. +// +ALT_STATUS_CODE alt_clk_pll_cfg_set(ALT_CLK_t pll, const ALT_CLK_PLL_CFG_t * pll_cfg) +{ + if (pll_cfg == NULL) + { + return ALT_E_BAD_ARG; + } + + if (alt_clk_pll_is_bypassed(pll) != ALT_E_TRUE) // safe to write the PLL registers? + { + return ALT_E_ERROR; + } + + ALT_STATUS_CODE ret = ALT_E_ERROR; + uint32_t temp; + + if (pll == ALT_CLK_MAIN_PLL) + { + temp = (ALT_CLKMGR_MAINPLL_VCO_NUMER_CLR_MSK & ALT_CLKMGR_MAINPLL_VCO_DENOM_CLR_MSK) + & alt_read_word(ALT_CLKMGR_MAINPLL_VCO_ADDR); + temp |= ALT_CLKMGR_MAINPLL_VCO_NUMER_SET(pll_cfg->mult) | + ALT_CLKMGR_MAINPLL_VCO_DENOM_SET(pll_cfg->div); + + alt_write_word(ALT_CLKMGR_MAINPLL_VCO_ADDR, temp); + alt_write_word(ALT_CLKMGR_ALTERA_MPUCLK_ADDR, pll_cfg->cntrs[0]); + alt_write_word(ALT_CLKMGR_ALTERA_MAINCLK_ADDR, pll_cfg->cntrs[1]); + alt_write_word(ALT_CLKMGR_MAINPLL_DBGATCLK_ADDR, pll_cfg->cntrs[2]); + alt_write_word(ALT_CLKMGR_MAINPLL_MAINQSPICLK_ADDR, pll_cfg->cntrs[3]); + alt_write_word(ALT_CLKMGR_MAINPLL_MAINNANDSDMMCCLK_ADDR, pll_cfg->cntrs[4]); + alt_write_word(ALT_CLKMGR_MAINPLL_CFGS2FUSER0CLK_ADDR, pll_cfg->cntrs[5]); + ret = ALT_E_SUCCESS; + } + else if (pll == ALT_CLK_PERIPHERAL_PLL) + { + temp = ALT_CLKMGR_PERPLL_VCO_NUMER_CLR_MSK & ALT_CLKMGR_PERPLL_VCO_DENOM_CLR_MSK + & ALT_CLKMGR_PERPLL_VCO_PSRC_CLR_MSK; + temp &= alt_read_word(ALT_CLKMGR_PERPLL_VCO_ADDR); + temp |= ALT_CLKMGR_PERPLL_VCO_NUMER_SET(pll_cfg->mult) + | ALT_CLKMGR_PERPLL_VCO_DENOM_SET(pll_cfg->div); + + if ((pll_cfg->ref_clk == ALT_CLK_IN_PIN_OSC1) || (pll_cfg->ref_clk == ALT_CLK_OSC1)) + { + temp |= ALT_CLKMGR_PERPLL_VCO_PSRC_SET(ALT_CLKMGR_PERPLL_VCO_PSRC_E_EOSC1); + } + else if (pll_cfg->ref_clk == ALT_CLK_IN_PIN_OSC2) + { + temp |= ALT_CLKMGR_PERPLL_VCO_PSRC_SET(ALT_CLKMGR_PERPLL_VCO_PSRC_E_EOSC2); + } + else if (pll_cfg->ref_clk == ALT_CLK_F2H_PERIPH_REF) + { + temp |= ALT_CLKMGR_PERPLL_VCO_PSRC_SET(ALT_CLKMGR_PERPLL_VCO_PSRC_E_F2S_PERIPH_REF); + } + else + { + return ret; + } + + alt_write_word(ALT_CLKMGR_PERPLL_VCO_ADDR, temp); + alt_write_word(ALT_CLKMGR_PERPLL_EMAC0CLK_ADDR, pll_cfg->cntrs[0]); + alt_write_word(ALT_CLKMGR_PERPLL_EMAC1CLK_ADDR, pll_cfg->cntrs[1]); + alt_write_word(ALT_CLKMGR_PERPLL_PERQSPICLK_ADDR, pll_cfg->cntrs[2]); + alt_write_word(ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_ADDR, pll_cfg->cntrs[3]); + alt_write_word(ALT_CLKMGR_PERPLL_PERBASECLK_ADDR, pll_cfg->cntrs[4]); + alt_write_word(ALT_CLKMGR_PERPLL_S2FUSER1CLK_ADDR, pll_cfg->cntrs[5]); + ret = ALT_E_SUCCESS; + } + else if (pll == ALT_CLK_SDRAM_PLL) + { + // write the SDRAM PLL VCO Counter ----------------------------- + temp = ALT_CLKMGR_SDRPLL_VCO_NUMER_CLR_MSK & ALT_CLKMGR_SDRPLL_VCO_DENOM_CLR_MSK + & ALT_CLKMGR_SDRPLL_VCO_SSRC_CLR_MSK; // make a mask + temp &= alt_read_word(ALT_CLKMGR_SDRPLL_VCO_ADDR); + temp |= ALT_CLKMGR_SDRPLL_VCO_NUMER_SET(pll_cfg->mult) + | ALT_CLKMGR_SDRPLL_VCO_DENOM_SET(pll_cfg->div) + | ALT_CLKMGR_SDRPLL_VCO_OUTRSTALL_SET_MSK; + // setting this bit aligns the output phase of the counters and prevents + // glitches and too-short clock periods when restarting. + // this bit is cleared at the end of this routine + + if ((pll_cfg->ref_clk == ALT_CLK_IN_PIN_OSC1) || (pll_cfg->ref_clk == ALT_CLK_OSC1)) + { + temp |= ALT_CLKMGR_SDRPLL_VCO_SSRC_SET(ALT_CLKMGR_SDRPLL_VCO_SSRC_E_EOSC1); + } + else if (pll_cfg->ref_clk == ALT_CLK_IN_PIN_OSC2) + { + temp |= ALT_CLKMGR_SDRPLL_VCO_SSRC_SET(ALT_CLKMGR_SDRPLL_VCO_SSRC_E_EOSC2); + } + else if (pll_cfg->ref_clk == ALT_CLK_F2H_PERIPH_REF) + { + temp |= ALT_CLKMGR_SDRPLL_VCO_SSRC_SET(ALT_CLKMGR_SDRPLL_VCO_SSRC_E_F2S_SDRAM_REF); + } + else + { + return ret; + } + + alt_write_word(ALT_CLKMGR_SDRPLL_VCO_ADDR, temp); + + // write the SDRAM PLL C0 Divide Counter ----------------------------- + temp = ALT_CLKMGR_SDRPLL_DDRDQSCLK_CNT_SET(pll_cfg->cntrs[0]) + | ALT_CLKMGR_SDRPLL_DDRDQSCLK_PHASE_SET(pll_cfg->pshift[0]); + + alt_clk_pllcounter_write(ALT_CLKMGR_SDRPLL_VCO_ADDR, ALT_CLKMGR_STAT_ADDR, + ALT_CLKMGR_SDRPLL_DDRDQSCLK_ADDR, temp, + ALT_CLKMGR_SDRPLL_DDRDQSCLK_CNT_SET_MSK | ALT_CLKMGR_SDRPLL_DDRDQSCLK_PHASE_SET_MSK, + ALT_CLKMGR_SDRPLL_DDRDQSCLK_CNT_LSB); + + // write the SDRAM PLL C1 Divide Counter ----------------------------- + if (ret == ALT_E_SUCCESS) + { + temp = ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_CNT_SET(pll_cfg->cntrs[1]) + | ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_PHASE_SET(pll_cfg->pshift[1]); + alt_clk_pllcounter_write(ALT_CLKMGR_SDRPLL_VCO_ADDR, ALT_CLKMGR_STAT_ADDR, + ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_ADDR, temp, + ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_CNT_SET_MSK | ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_PHASE_SET_MSK, + ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_CNT_LSB); + } + + // write the SDRAM PLL C2 Divide Counter ----------------------------- + if (ret == ALT_E_SUCCESS) + { + temp = ALT_CLKMGR_SDRPLL_DDRDQCLK_CNT_SET(pll_cfg->cntrs[2]) + | ALT_CLKMGR_SDRPLL_DDRDQCLK_PHASE_SET(pll_cfg->pshift[2]); + alt_clk_pllcounter_write(ALT_CLKMGR_SDRPLL_VCO_ADDR, ALT_CLKMGR_STAT_ADDR, + ALT_CLKMGR_SDRPLL_DDRDQCLK_ADDR, temp, + ALT_CLKMGR_SDRPLL_DDRDQCLK_CNT_SET_MSK | ALT_CLKMGR_SDRPLL_DDRDQCLK_PHASE_SET_MSK, + ALT_CLKMGR_SDRPLL_DDRDQCLK_CNT_LSB); + } + + // write the SDRAM PLL C5 Divide Counter ----------------------------- + if (ret == ALT_E_SUCCESS) + { + temp = ALT_CLKMGR_SDRPLL_S2FUSER2CLK_CNT_SET(pll_cfg->cntrs[2]) + | ALT_CLKMGR_SDRPLL_S2FUSER2CLK_PHASE_SET(pll_cfg->pshift[2]); + alt_clk_pllcounter_write(ALT_CLKMGR_SDRPLL_VCO_ADDR, ALT_CLKMGR_STAT_ADDR, + ALT_CLKMGR_SDRPLL_S2FUSER2CLK_ADDR, temp, + ALT_CLKMGR_SDRPLL_S2FUSER2CLK_CNT_SET_MSK | ALT_CLKMGR_SDRPLL_S2FUSER2CLK_PHASE_SET_MSK, + ALT_CLKMGR_SDRPLL_S2FUSER2CLK_CNT_LSB); + } + + if (ret == ALT_E_SUCCESS) + { + alt_clrbits_word(ALT_CLKMGR_SDRPLL_VCO_ADDR, ALT_CLKMGR_SDRPLL_VCO_OUTRSTALL_SET_MSK); + // allow the phase multiplexer and output counter to leave reset + } + } + + return ret; +} + + +// +// alt_clk_pll_vco_cfg_get() returns the current PLL VCO frequency configuration. +// +ALT_STATUS_CODE alt_clk_pll_vco_cfg_get(ALT_CLK_t pll, uint32_t * mult, uint32_t * div) +{ + ALT_STATUS_CODE status = ALT_E_SUCCESS; + uint32_t temp; + + if ( (mult == NULL) || (div == NULL) ) + { + return ALT_E_BAD_ARG; + } + + if (pll == ALT_CLK_MAIN_PLL) + { + temp = alt_read_word(ALT_CLKMGR_MAINPLL_VCO_ADDR); + *mult = ALT_CLKMGR_MAINPLL_VCO_NUMER_GET(temp) + 1; + *div = ALT_CLKMGR_MAINPLL_VCO_DENOM_GET(temp) + 1; + } + else if (pll == ALT_CLK_PERIPHERAL_PLL) + { + temp = alt_read_word(ALT_CLKMGR_PERPLL_VCO_ADDR); + *mult = ALT_CLKMGR_PERPLL_VCO_NUMER_GET(temp) + 1; + *div = ALT_CLKMGR_PERPLL_VCO_DENOM_GET(temp) + 1; + } + else if (pll == ALT_CLK_SDRAM_PLL) + { + temp = alt_read_word(ALT_CLKMGR_SDRPLL_VCO_ADDR); + *mult = ALT_CLKMGR_SDRPLL_VCO_NUMER_GET(temp) + 1; + *div = ALT_CLKMGR_SDRPLL_VCO_DENOM_GET(temp) + 1; + } + else + { + status = ALT_E_ERROR; + } + + return status; +} + + +/****************************************************************************************/ +/* This enum enumerates a set of possible change methods that are available for use by */ +/* alt_clk_pll_vco_cfg_set() to change VCO parameter settings. */ +/****************************************************************************************/ + +typedef enum ALT_CLK_PLL_VCO_CHG_METHOD_e +{ + ALT_VCO_CHG_NONE_VALID = 0, /* No valid method to change PLL + * VCO was found */ + ALT_VCO_CHG_NOCHANGE = 0x00000001, /* Proposed new VCO values are the + * same as the old values */ + ALT_VCO_CHG_NUM = 0x00000002, /* Can change the VCO multiplier + * alone */ + ALT_VCO_CHG_NUM_BYP = 0x00000004, /* A VCO multiplier-only change will + * require putting the PLL in bypass */ + ALT_VCO_CHG_DENOM = 0x00000008, /* Can change the VCO divider + * alone */ + ALT_VCO_CHG_DENOM_BYP = 0x00000010, /* A VCO divider-only change will + * require putting the PLL in bypass */ + ALT_VCO_CHG_NUM_DENOM = 0x00000020, /* Can change the clock multiplier + * first. then the clock divider */ + ALT_VCO_CHG_NUM_DENOM_BYP = 0x00000040, /* Changing the clock multiplier first. + * then the clock divider will + * require putting the PLL in bypass */ + ALT_VCO_CHG_DENOM_NUM = 0x00000080, /* Can change the clock divider first. + * then the clock multiplier */ + ALT_VCO_CHG_DENOM_NUM_BYP = 0x00000100 /* Changing the clock divider first. + * then the clock multiplier will + * require putting the PLL in bypass */ +} ALT_CLK_PLL_VCO_CHG_METHOD_t; + + + +/****************************************************************************************/ +/* alt_clk_pll_vco_chg_methods_get() determines which possible methods to change the */ +/* VCO are allowed within the limits set by the maximum PLL multiplier and divider */ +/* values and by the upper and lower frequency limits of the PLL, and also determines */ +/* whether each of these changes can be made without the PLL losing lock, which */ +/* requires the PLL to be bypassed before making changes, and removed from bypass state */ +/* afterwards. */ +/****************************************************************************************/ + + +#define ALT_CLK_PLL_VCO_CHG_METHOD_TEST_MODE false + // used for testing writes to the PLL VCOs + + + +static ALT_CLK_PLL_VCO_CHG_METHOD_t alt_clk_pll_vco_chg_methods_get(ALT_CLK_t pll, + uint32_t mult, uint32_t div ) +{ +#if ALT_CLK_PLL_VCO_CHG_METHOD_TEST_MODE + + // used for testing + return ALT_VCO_CHG_NOCHANGE; + +#else + + // check PLL max value limits + if ( (mult == 0) || (mult > ALT_CLK_PLL_MULT_MAX) + || (div == 0) || (div > ALT_CLK_PLL_DIV_MAX) + ) + { + return ALT_VCO_CHG_NONE_VALID; + } + + ALT_CLK_PLL_VCO_CHG_METHOD_t ret = ALT_VCO_CHG_NONE_VALID; + uint32_t temp; + uint32_t numer; + uint32_t denom; + uint32_t freqmax; + uint32_t freqmin; + uint32_t inputfreq; + uint32_t guardband; + bool numerchg = false; + bool denomchg = false; + bool within_gb; + + // gather data values according to PLL + if (pll == ALT_CLK_MAIN_PLL) + { + temp = alt_read_word(ALT_CLKMGR_MAINPLL_VCO_ADDR); + + numer = ALT_CLKMGR_MAINPLL_VCO_NUMER_GET(temp); + denom = ALT_CLKMGR_MAINPLL_VCO_DENOM_GET(temp); + + freqmax = alt_pll_clk_paramblok.MainPLL_800.freqmax; + freqmin = alt_pll_clk_paramblok.MainPLL_800.freqmin; + guardband = alt_pll_clk_paramblok.MainPLL_800.guardband; + + inputfreq = alt_ext_clk_paramblok.clkosc1.freqcur; + } + + else if (pll == ALT_CLK_PERIPHERAL_PLL) + { + temp = alt_read_word(ALT_CLKMGR_PERPLL_VCO_ADDR); + + numer = ALT_CLKMGR_PERPLL_VCO_NUMER_GET(temp); + denom = ALT_CLKMGR_PERPLL_VCO_DENOM_GET(temp); + + freqmax = alt_pll_clk_paramblok.PeriphPLL_800.freqmax; + freqmin = alt_pll_clk_paramblok.PeriphPLL_800.freqmin; + guardband = alt_pll_clk_paramblok.PeriphPLL_800.guardband; + + temp = ALT_CLKMGR_PERPLL_VCO_PSRC_GET(temp); + if (temp == ALT_CLKMGR_PERPLL_VCO_PSRC_E_EOSC1) + { + inputfreq = alt_ext_clk_paramblok.clkosc1.freqcur; + } + else if (temp == ALT_CLKMGR_PERPLL_VCO_PSRC_E_EOSC2) + { + inputfreq = alt_ext_clk_paramblok.clkosc2.freqcur; + } + else if (temp == ALT_CLKMGR_PERPLL_VCO_PSRC_E_F2S_PERIPH_REF) + { + inputfreq = alt_ext_clk_paramblok.periph.freqcur; + } + else + { + return ret; + } + } + + else if (pll == ALT_CLK_SDRAM_PLL) + { + temp = alt_read_word(ALT_CLKMGR_SDRPLL_VCO_ADDR); + + numer = ALT_CLKMGR_SDRPLL_VCO_NUMER_GET(temp); + denom = ALT_CLKMGR_SDRPLL_VCO_DENOM_GET(temp); + + freqmax = alt_pll_clk_paramblok.SDRAMPLL_800.freqmax; + freqmin = alt_pll_clk_paramblok.SDRAMPLL_800.freqmin; + guardband = alt_pll_clk_paramblok.SDRAMPLL_800.guardband; + + temp = ALT_CLKMGR_SDRPLL_VCO_SSRC_GET(temp); + if (temp == ALT_CLKMGR_SDRPLL_VCO_SSRC_E_EOSC1) + { + inputfreq = alt_ext_clk_paramblok.clkosc1.freqcur; + } + else if (temp == ALT_CLKMGR_SDRPLL_VCO_SSRC_E_EOSC2) + { + inputfreq = alt_ext_clk_paramblok.clkosc2.freqcur; + } + else if (temp == ALT_CLKMGR_SDRPLL_VCO_SSRC_E_F2S_SDRAM_REF) + { + inputfreq = alt_ext_clk_paramblok.sdram.freqcur; + } + else + { + return ret; + } + } + else + { + return ret; + } + + temp = mult * (inputfreq / div); + if ((temp <= freqmax) && (temp >= freqmin)) // are the final values within frequency limits? + { + numer++; + denom++; + numerchg = (mult != numer); + denomchg = (div != denom); + + if (!numerchg && !denomchg) + { + ret = ALT_VCO_CHG_NOCHANGE; + } + else if (numerchg && !denomchg) + { + within_gb = alt_within_delta(numer, mult, guardband); + // check if change is within the guardband limits + temp = mult * (inputfreq / denom); + if ((temp <= freqmax) && (temp >= freqmin)) + { + ret = ALT_VCO_CHG_NUM; + if (!within_gb) ret |= ALT_VCO_CHG_NUM_BYP; + } + } + else if (!numerchg && denomchg) + { + within_gb = alt_within_delta(denom, div, guardband); + temp = numer * (inputfreq / div); + if ((temp <= freqmax) && (temp >= freqmin)) + { + ret = ALT_VCO_CHG_DENOM; + if (!within_gb) + { + ret |= ALT_VCO_CHG_DENOM_BYP; + } + } + } + else //numerchg && denomchg + { + within_gb = alt_within_delta(numer, mult, guardband); + temp = mult * (inputfreq / denom); + if ((temp <= freqmax) && (temp >= freqmin)) + { + ret = ALT_VCO_CHG_NUM_DENOM; + if (!within_gb) + { + ret |= ALT_VCO_CHG_NUM_DENOM_BYP; + } + } + within_gb = alt_within_delta(denom, div, guardband); + temp = numer * (inputfreq / div); + if ((temp <= freqmax) && (temp >= freqmin)) + { + ret = ALT_VCO_CHG_DENOM_NUM; + if (!within_gb) + { + ret |= ALT_VCO_CHG_DENOM_NUM_BYP; + } + } + } + } + + return ret; +#endif +} + + +/****************************************************************************************/ +/* alt_clk_pll_vco_cfg_set() sets the PLL VCO frequency configuration using the */ +/* supplied multiplier and divider arguments. alt_clk_pll_vco_chg_methods_get() */ +/* determines which methods are allowed by the limits set by the maximum multiplier */ +/* and divider values and by the upper and lower frequency limits of the PLL, and also */ +/* determines whether these changes can be made without requiring the PLL to be */ +/* bypassed. alt_clk_pll_vco_cfg_set() then carries out the actions required to effect */ +/* the method chosen to change the VCO settings. */ +/****************************************************************************************/ + +ALT_STATUS_CODE alt_clk_pll_vco_cfg_set(ALT_CLK_t pll, uint32_t mult, uint32_t div) +{ + ALT_STATUS_CODE ret = ALT_E_ERROR; + ALT_CLK_PLL_VCO_CHG_METHOD_t method; + bool byp = false; + void *vaddr; + uint32_t numermask, denommask; + uint32_t numershift, denomshift; + + + method = alt_clk_pll_vco_chg_methods_get(pll, mult, div); + + if (method == ALT_VCO_CHG_NONE_VALID) + { + ret = ALT_E_BAD_CLK; + } + else if (method == ALT_VCO_CHG_NOCHANGE) + { + ret = ALT_E_INV_OPTION; + } + else + { + if (pll == ALT_CLK_MAIN_PLL) + { + vaddr = ALT_CLKMGR_MAINPLL_VCO_ADDR; + numermask = ALT_CLKMGR_MAINPLL_VCO_NUMER_SET_MSK; + denommask = ALT_CLKMGR_MAINPLL_VCO_DENOM_SET_MSK; + numershift = ALT_CLKMGR_MAINPLL_VCO_NUMER_LSB; + denomshift = ALT_CLKMGR_MAINPLL_VCO_DENOM_LSB; + } + else if (pll == ALT_CLK_PERIPHERAL_PLL) + { + vaddr = ALT_CLKMGR_PERPLL_VCO_ADDR; + numermask = ALT_CLKMGR_PERPLL_VCO_NUMER_SET_MSK; + denommask = ALT_CLKMGR_PERPLL_VCO_DENOM_SET_MSK; + numershift = ALT_CLKMGR_PERPLL_VCO_NUMER_LSB; + denomshift = ALT_CLKMGR_PERPLL_VCO_DENOM_LSB; + } + else if (pll == ALT_CLK_SDRAM_PLL) + { + vaddr = ALT_CLKMGR_SDRPLL_VCO_ADDR; + numermask = ALT_CLKMGR_SDRPLL_VCO_NUMER_SET_MSK; + denommask = ALT_CLKMGR_SDRPLL_VCO_DENOM_SET_MSK; + numershift = ALT_CLKMGR_SDRPLL_VCO_NUMER_LSB; + denomshift = ALT_CLKMGR_SDRPLL_VCO_DENOM_LSB; + } + else { return ALT_E_BAD_ARG; } + + mult--; + div--; + + if (method & ALT_VCO_CHG_NUM) + { + if (method & ALT_VCO_CHG_NUM_BYP) + { + alt_clk_pll_bypass_enable(pll, 0); + byp = true; + alt_clk_mgr_wait(vaddr, ALT_SW_MANAGED_CLK_WAIT_BYPASS); + } + alt_replbits_word(vaddr, numermask, mult << numershift); + } + + else if (method & ALT_VCO_CHG_DENOM) + { + if (method & ALT_VCO_CHG_DENOM_BYP) + { + alt_clk_pll_bypass_enable(pll, 0); + byp = true; + } + alt_replbits_word(vaddr, denommask, div << denomshift); + } + + else if (method & ALT_VCO_CHG_NUM_DENOM) + { + if (method & ALT_VCO_CHG_NUM_DENOM_BYP) + { + alt_clk_pll_bypass_enable(pll, 0); + byp = true; + } + alt_replbits_word(vaddr, numermask, mult << numershift); + if (!byp) // if PLL is not bypassed + { + ret = alt_clk_pll_lock_wait(ALT_CLK_MAIN_PLL, 1000); + // verify PLL is still locked or wait for it to lock again + } + alt_replbits_word(vaddr, denommask, div << denomshift); + } + + else if (method & ALT_VCO_CHG_DENOM_NUM) + { + if (method & ALT_VCO_CHG_DENOM_NUM_BYP) + { + alt_clk_pll_bypass_enable(pll, 0); + byp = true; + } + alt_replbits_word(vaddr, numermask, mult << numershift); + if (!byp) // if PLL is not bypassed + { + ret = alt_clk_pll_lock_wait(ALT_CLK_MAIN_PLL, 1000); + // verify PLL is still locked or wait for it to lock again + } + alt_replbits_word(vaddr, denommask, div << denomshift); + } + + ret = alt_clk_pll_lock_wait(ALT_CLK_MAIN_PLL, 1000); + // verify PLL is still locked or wait for it to lock again + if (byp) + { + alt_clk_pll_bypass_disable(pll); + alt_clk_mgr_wait(vaddr, ALT_SW_MANAGED_CLK_WAIT_BYPASS); + // wait for PLL to come out of bypass mode completely + } + } + return ret; +} + + +// +// alt_clk_pll_vco_freq_get() gets the VCO frequency of the specified PLL. +// Note that since there is at present no known way for software to obtain the speed +// bin of the SoC or MPU that it is running on, the function below only deals with the +// 800 MHz part. This may need to be revised in the future. +// +ALT_STATUS_CODE alt_clk_pll_vco_freq_get(ALT_CLK_t pll, alt_freq_t * freq) +{ + uint64_t temp1 = 0; + uint32_t temp; + uint32_t numer; + uint32_t denom; + ALT_STATUS_CODE ret = ALT_E_BAD_ARG; + + if (freq == NULL) + { + return ret; + } + + if (pll == ALT_CLK_MAIN_PLL) + { + temp = alt_read_word(ALT_CLKMGR_MAINPLL_VCO_ADDR); + numer = ALT_CLKMGR_MAINPLL_VCO_NUMER_GET(temp); + denom = ALT_CLKMGR_MAINPLL_VCO_DENOM_GET(temp); + temp1 = (uint64_t) alt_ext_clk_paramblok.clkosc1.freqcur; + temp1 *= (numer + 1); + temp1 /= (denom + 1); + + if (temp1 <= UINT32_MAX) + { + temp = (alt_freq_t) temp1; + alt_pll_clk_paramblok.MainPLL_800.freqcur = temp; + // store this value in the parameter block table + *freq = temp; + // should NOT check value against PLL frequency limits + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ERROR; + } + } + else if (pll == ALT_CLK_PERIPHERAL_PLL) + { + temp = alt_read_word(ALT_CLKMGR_PERPLL_VCO_ADDR); + numer = ALT_CLKMGR_PERPLL_VCO_NUMER_GET(temp); + denom = ALT_CLKMGR_PERPLL_VCO_DENOM_GET(temp); + temp = ALT_CLKMGR_PERPLL_VCO_PSRC_GET(temp); + if (temp == ALT_CLKMGR_PERPLL_VCO_PSRC_E_EOSC1) + { + temp1 = (uint64_t) alt_ext_clk_paramblok.clkosc1.freqcur; + } + else if (temp == ALT_CLKMGR_PERPLL_VCO_PSRC_E_EOSC2) + { + temp1 = (uint64_t) alt_ext_clk_paramblok.clkosc2.freqcur; + } + else if (temp == ALT_CLKMGR_PERPLL_VCO_PSRC_E_F2S_PERIPH_REF) + { + temp1 = (uint64_t) alt_ext_clk_paramblok.periph.freqcur; + } + + if (temp1 != 0) + { + temp1 *= (numer + 1); + temp1 /= (denom + 1); + if (temp1 <= UINT32_MAX) + { + temp = (alt_freq_t) temp1; + alt_pll_clk_paramblok.PeriphPLL_800.freqcur = temp; + // store this value in the parameter block table + + *freq = temp; + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ERROR; + } + } // this returns ALT_BAD_ARG if the source isn't known + } + else if (pll == ALT_CLK_SDRAM_PLL) + { + temp = alt_read_word(ALT_CLKMGR_SDRPLL_VCO_ADDR); + numer = ALT_CLKMGR_SDRPLL_VCO_NUMER_GET(temp); + denom = ALT_CLKMGR_SDRPLL_VCO_DENOM_GET(temp); + temp = ALT_CLKMGR_SDRPLL_VCO_SSRC_GET(temp); + if (temp == ALT_CLKMGR_SDRPLL_VCO_SSRC_E_EOSC1) + { + temp1 = (uint64_t) alt_ext_clk_paramblok.clkosc1.freqcur; + } + else if (temp == ALT_CLKMGR_SDRPLL_VCO_SSRC_E_EOSC2) + { + temp1 = (uint64_t) alt_ext_clk_paramblok.clkosc2.freqcur; + } + else if (temp == ALT_CLKMGR_SDRPLL_VCO_SSRC_E_F2S_SDRAM_REF) + { + temp1 = (uint64_t) alt_ext_clk_paramblok.sdram.freqcur; + } + + if (temp1 != 0) + { + temp1 *= (numer + 1); + temp1 /= (denom + 1); + if (temp1 <= UINT32_MAX) + { + temp = (alt_freq_t) temp1; + alt_pll_clk_paramblok.SDRAMPLL_800.freqcur = temp; + // store this value in the parameter block table + + *freq = temp; + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ERROR; + } + } + } // which returns ALT_BAD_ARG if the source isn't known + + return ret; +} + +// +// Returns the current guard band range in effect for the PLL. +// +uint32_t alt_clk_pll_guard_band_get(ALT_CLK_t pll) +{ + uint32_t ret = 0; + + if (pll == ALT_CLK_MAIN_PLL) + { + ret = alt_pll_clk_paramblok.MainPLL_800.guardband; + } + else if (pll == ALT_CLK_PERIPHERAL_PLL) + { + ret = alt_pll_clk_paramblok.PeriphPLL_800.guardband; + } + else if (pll == ALT_CLK_SDRAM_PLL) + { + ret = alt_pll_clk_paramblok.SDRAMPLL_800.guardband; + } + return ret; +} + +// +// clk_mgr_pll_guard_band_set() changes the guard band from its current value to permit +// a more lenient or stringent policy to be in effect for the implementation of the +// functions configuring PLL VCO frequency. +// +ALT_STATUS_CODE alt_clk_pll_guard_band_set(ALT_CLK_t pll, uint32_t guard_band) +{ + if ( (guard_band > UINT12_MAX) || (guard_band <= 0) + || (guard_band > ALT_GUARDBAND_LIMIT) + ) + { + return ALT_E_ARG_RANGE; + } + + ALT_STATUS_CODE status = ALT_E_SUCCESS; + + if (pll == ALT_CLK_MAIN_PLL) + { + alt_pll_clk_paramblok.MainPLL_800.guardband = guard_band; + //alt_pll_clk_paramblok.MainPLL_600.guardband = guard_band; + // ??? Don't know how to check the MPU speed bin yet, so only 800 MHz struct is used + } + else if (pll == ALT_CLK_PERIPHERAL_PLL) + { + alt_pll_clk_paramblok.PeriphPLL_800.guardband = guard_band; + //alt_pll_clk_paramblok.PeriphPLL_600.guardband = guard_band; + } + else if (pll == ALT_CLK_SDRAM_PLL) + { + alt_pll_clk_paramblok.SDRAMPLL_800.guardband = guard_band; + //alt_pll_clk_paramblok.SDRAMPLL_600.guardband = guard_band; + } + else + { + status = ALT_E_ERROR; + } + + return status; +} + +// +// alt_clk_divider_get() gets configured divider value for the specified clock. +// +ALT_STATUS_CODE alt_clk_divider_get(ALT_CLK_t clk, uint32_t * div) +{ + ALT_STATUS_CODE status = ALT_E_SUCCESS; + uint32_t temp; + + if (div == NULL) + { + return ALT_E_BAD_ARG; + } + + switch (clk) + { + // Main PLL outputs + case ALT_CLK_MAIN_PLL_C0: + case ALT_CLK_MPU: + *div = (ALT_CLKMGR_MAINPLL_MPUCLK_CNT_GET(alt_read_word(ALT_CLKMGR_MAINPLL_MPUCLK_ADDR)) + 1) * + (ALT_CLKMGR_ALTERA_MPUCLK_CNT_GET(alt_read_word(ALT_CLKMGR_ALTERA_MPUCLK_ADDR)) + 1); + break; + + case ALT_CLK_MAIN_PLL_C1: + case ALT_CLK_L4_MAIN: + case ALT_CLK_L3_MAIN: + *div = (ALT_CLKMGR_MAINPLL_MAINCLK_CNT_GET(alt_read_word(ALT_CLKMGR_MAINPLL_MAINCLK_ADDR)) + 1) * + (ALT_CLKMGR_ALTERA_MAINCLK_CNT_GET(alt_read_word(ALT_CLKMGR_ALTERA_MAINCLK_ADDR)) + 1); + break; + + case ALT_CLK_MAIN_PLL_C2: + case ALT_CLK_DBG_BASE: + case ALT_CLK_DBG_TIMER: + *div = (ALT_CLKMGR_MAINPLL_DBGATCLK_CNT_GET(alt_read_word(ALT_CLKMGR_MAINPLL_DBGATCLK_ADDR)) + 1) * + (ALT_CLKMGR_ALTERA_DBGATCLK_CNT_GET(alt_read_word(ALT_CLKMGR_ALTERA_DBGATCLK_ADDR)) + 1); + break; + + case ALT_CLK_MAIN_PLL_C3: + case ALT_CLK_MAIN_QSPI: + *div = (ALT_CLKMGR_MAINPLL_MAINQSPICLK_CNT_GET(alt_read_word(ALT_CLKMGR_MAINPLL_MAINQSPICLK_ADDR))) + 1; + break; + + case ALT_CLK_MAIN_PLL_C4: + case ALT_CLK_MAIN_NAND_SDMMC: + *div = (ALT_CLKMGR_MAINPLL_MAINNANDSDMMCCLK_CNT_GET(alt_read_word(ALT_CLKMGR_MAINPLL_MAINNANDSDMMCCLK_ADDR))) + 1; + break; + + case ALT_CLK_MAIN_PLL_C5: + case ALT_CLK_CFG: + case ALT_CLK_H2F_USER0: + *div = (ALT_CLKMGR_MAINPLL_CFGS2FUSER0CLK_CNT_GET(alt_read_word(ALT_CLKMGR_MAINPLL_CFGS2FUSER0CLK_ADDR))) + 1; + break; + + ///// + + // Peripheral PLL outputs + case ALT_CLK_PERIPHERAL_PLL_C0: + case ALT_CLK_EMAC0: + *div = (ALT_CLKMGR_PERPLL_EMAC0CLK_CNT_GET(alt_read_word(ALT_CLKMGR_PERPLL_EMAC0CLK_ADDR))) + 1; + break; + + case ALT_CLK_PERIPHERAL_PLL_C1: + case ALT_CLK_EMAC1: + *div = (ALT_CLKMGR_PERPLL_EMAC1CLK_CNT_GET(alt_read_word(ALT_CLKMGR_PERPLL_EMAC1CLK_ADDR))) + 1; + break; + + case ALT_CLK_PERIPHERAL_PLL_C2: + *div = (ALT_CLKMGR_PERPLL_PERQSPICLK_CNT_GET(alt_read_word(ALT_CLKMGR_PERPLL_PERQSPICLK_ADDR))) + 1; + break; + + case ALT_CLK_PERIPHERAL_PLL_C3: + *div = (ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_CNT_GET(alt_read_word(ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_ADDR))) + 1; + break; + + case ALT_CLK_PERIPHERAL_PLL_C4: + *div = (ALT_CLKMGR_PERPLL_PERBASECLK_CNT_GET(alt_read_word(ALT_CLKMGR_PERPLL_PERBASECLK_ADDR))) + 1; + break; + + case ALT_CLK_PERIPHERAL_PLL_C5: + case ALT_CLK_H2F_USER1: + *div = (ALT_CLKMGR_PERPLL_S2FUSER1CLK_CNT_GET(alt_read_word(ALT_CLKMGR_PERPLL_S2FUSER1CLK_ADDR))) + 1; + break; + + ///// + + // SDRAM PLL outputs + case ALT_CLK_SDRAM_PLL_C0: + case ALT_CLK_DDR_DQS: + *div = (ALT_CLKMGR_SDRPLL_DDRDQSCLK_CNT_GET(alt_read_word(ALT_CLKMGR_SDRPLL_DDRDQSCLK_ADDR))) + 1; + break; + + case ALT_CLK_SDRAM_PLL_C1: + case ALT_CLK_DDR_2X_DQS: + *div = (ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_CNT_GET(alt_read_word(ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_ADDR))) + 1; + break; + + case ALT_CLK_SDRAM_PLL_C2: + case ALT_CLK_DDR_DQ: + *div = (ALT_CLKMGR_SDRPLL_DDRDQCLK_CNT_GET(alt_read_word(ALT_CLKMGR_SDRPLL_DDRDQCLK_ADDR))) + 1; + break; + + case ALT_CLK_SDRAM_PLL_C5: + case ALT_CLK_H2F_USER2: + *div = (ALT_CLKMGR_SDRPLL_S2FUSER2CLK_CNT_GET(alt_read_word(ALT_CLKMGR_SDRPLL_S2FUSER2CLK_ADDR))) + 1; + break; + + ///// + + // Other clock dividers + case ALT_CLK_L3_MP: + temp = ALT_CLKMGR_MAINPLL_MAINDIV_L3MPCLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_MAINDIV_ADDR)); + if (temp <= ALT_CLKMGR_MAINPLL_MAINDIV_L3MPCLK_E_DIV2) + { + *div = temp + 1; + } + else + { + status = ALT_E_ERROR; + } + break; + + case ALT_CLK_L3_SP: + temp = ALT_CLKMGR_MAINPLL_MAINDIV_L3SPCLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_MAINDIV_ADDR)); + if (temp <= ALT_CLKMGR_MAINPLL_MAINDIV_L3SPCLK_E_DIV2) + { + *div = temp + 1; + } + else + { + status = ALT_E_ERROR; + } + // note that this value does not include the additional effect + // of the L3_MP divider that is upchain from this one + break; + + case ALT_CLK_L4_MP: + temp = ALT_CLKMGR_MAINPLL_MAINDIV_L4MPCLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_MAINDIV_ADDR)); + if (temp <= ALT_CLKMGR_MAINPLL_MAINDIV_L4MPCLK_E_DIV16) + { + *div = 1 << temp; + } + else + { + status = ALT_E_ERROR; + } + break; + + case ALT_CLK_L4_SP: + temp = ALT_CLKMGR_MAINPLL_MAINDIV_L4SPCLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_MAINDIV_ADDR)); + if (temp <= ALT_CLKMGR_MAINPLL_MAINDIV_L4SPCLK_E_DIV16) + { + *div = 1 << temp; + } + else + { + status = ALT_E_ERROR; + } + break; + + case ALT_CLK_DBG_AT: + temp = ALT_CLKMGR_MAINPLL_DBGDIV_DBGATCLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_DBGDIV_ADDR)); + if (temp <= ALT_CLKMGR_MAINPLL_DBGDIV_DBGATCLK_E_DIV4) + { + *div = 1 << temp; + } + else + { + status = ALT_E_ERROR; + } + break; + + case ALT_CLK_DBG: + temp = ALT_CLKMGR_MAINPLL_DBGDIV_DBGCLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_DBGDIV_ADDR)); + if (temp <= ALT_CLKMGR_MAINPLL_DBGDIV_DBGCLK_E_DIV4) + { + *div = 1 << temp; + } + else + { + status = ALT_E_ERROR; + } + // note that this value does not include the value of the upstream dbg_at_clk divder + break; + + case ALT_CLK_DBG_TRACE: + temp = ALT_CLKMGR_MAINPLL_TRACEDIV_TRACECLK_GET(alt_read_word(ALT_CLKMGR_MAINPLL_TRACEDIV_ADDR)); + if (temp <= ALT_CLKMGR_MAINPLL_TRACEDIV_TRACECLK_E_DIV16) + { + *div = 1 << temp; + } + else + { + status = ALT_E_ERROR; + } + break; + + case ALT_CLK_USB_MP: + temp = ALT_CLKMGR_PERPLL_DIV_USBCLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_DIV_ADDR)); + if (temp <= ALT_CLKMGR_PERPLL_DIV_USBCLK_E_DIV16) + { + *div = 1 << temp; + } + else + { + status = ALT_E_ERROR; + } + break; + + case ALT_CLK_SPI_M: + temp = ALT_CLKMGR_PERPLL_DIV_SPIMCLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_DIV_ADDR)); + if (temp <= ALT_CLKMGR_PERPLL_DIV_SPIMCLK_E_DIV16) + { + *div = 1 << temp; + } + else + { + status = ALT_E_ERROR; + } + break; + + case ALT_CLK_CAN0: + temp = ALT_CLKMGR_PERPLL_DIV_CAN0CLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_DIV_ADDR)); + if (temp <= ALT_CLKMGR_PERPLL_DIV_CAN0CLK_E_DIV16) + { + *div = 1 << temp; + } + else + { + status = ALT_E_ERROR; + } + break; + + case ALT_CLK_CAN1: + temp = ALT_CLKMGR_PERPLL_DIV_CAN1CLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_DIV_ADDR)); + if (temp <= ALT_CLKMGR_PERPLL_DIV_CAN1CLK_E_DIV16) + { + *div = 1 << temp; + } + else + { + status = ALT_E_ERROR; + } + break; + + case ALT_CLK_GPIO_DB: + temp = ALT_CLKMGR_PERPLL_GPIODIV_GPIODBCLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_GPIODIV_ADDR)); + *div = temp + 1; + break; + + case ALT_CLK_MPU_PERIPH: + *div = 4; // set by hardware + break; + + case ALT_CLK_MPU_L2_RAM: + *div = 2; // set by hardware + break; + + case ALT_CLK_NAND: + *div = 4; // set by hardware + break; + + default: + status = ALT_E_BAD_ARG; + break; + } + + return status; +} + +///// + +#define ALT_CLK_WITHIN_FREQ_LIMITS_TEST_MODE false + // used for testing writes to the the full range of counters without + // regard to the usual output frequency upper and lower limits + + +static ALT_STATUS_CODE alt_clk_within_freq_limits(ALT_CLK_t clk, uint32_t div) +{ +#if ALT_CLK_WITHIN_FREQ_LIMITS_TEST_MODE + return ALT_E_TRUE; +#else + + if (div == 0) + { + return ALT_E_BAD_ARG; + } + + ALT_STATUS_CODE status = ALT_E_SUCCESS; + uint32_t numer = 0; + uint32_t hilimit; + uint32_t lolimit; + + switch (clk) + { + // Counters of the Main PLL + case ALT_CLK_MAIN_PLL_C0: + hilimit = alt_pll_cntr_maxfreq.MainPLL_C0; + lolimit = alt_ext_clk_paramblok.clkosc1.freqcur; + status = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &numer); + break; + case ALT_CLK_MAIN_PLL_C1: + hilimit = alt_pll_cntr_maxfreq.MainPLL_C1; + lolimit = alt_ext_clk_paramblok.clkosc1.freqcur; + status = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &numer); + break; + case ALT_CLK_MAIN_PLL_C2: + hilimit = alt_pll_cntr_maxfreq.MainPLL_C2; + lolimit = alt_ext_clk_paramblok.clkosc1.freqcur; + status = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &numer); + break; + case ALT_CLK_MAIN_PLL_C3: + hilimit = alt_pll_cntr_maxfreq.MainPLL_C3; + lolimit = 0; + status = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &numer); + break; + case ALT_CLK_MAIN_PLL_C4: + hilimit = alt_pll_cntr_maxfreq.MainPLL_C4; + lolimit = alt_ext_clk_paramblok.clkosc1.freqcur; + status = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &numer); + break; + case ALT_CLK_MAIN_PLL_C5: + hilimit = alt_pll_cntr_maxfreq.MainPLL_C5; + lolimit = alt_ext_clk_paramblok.clkosc1.freqcur; + status = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &numer); + break; + + // Counters of the Peripheral PLL + case ALT_CLK_PERIPHERAL_PLL_C0: + hilimit = alt_pll_cntr_maxfreq.PeriphPLL_C0; + lolimit = 0; + status = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &numer); + break; + case ALT_CLK_PERIPHERAL_PLL_C1: + hilimit = alt_pll_cntr_maxfreq.PeriphPLL_C1; + lolimit = 0; + status = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &numer); + break; + case ALT_CLK_PERIPHERAL_PLL_C2: + hilimit = alt_pll_cntr_maxfreq.PeriphPLL_C2; + lolimit = 0; + status = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &numer); + break; + case ALT_CLK_PERIPHERAL_PLL_C3: + hilimit = alt_pll_cntr_maxfreq.PeriphPLL_C3; + lolimit = 0; + status = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &numer); + break; + case ALT_CLK_PERIPHERAL_PLL_C4: + hilimit = alt_pll_cntr_maxfreq.PeriphPLL_C4; + lolimit = 0; + status = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &numer); + break; + case ALT_CLK_PERIPHERAL_PLL_C5: + hilimit = alt_pll_cntr_maxfreq.PeriphPLL_C5; + lolimit = alt_ext_clk_paramblok.clkosc1.freqcur; + status = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &numer); + break; + + // Counters of the SDRAM PLL + case ALT_CLK_SDRAM_PLL_C0: + hilimit = alt_pll_cntr_maxfreq.SDRAMPLL_C0; + lolimit = 0; + status = alt_clk_pll_vco_freq_get(ALT_CLK_SDRAM_PLL, &numer); + break; + case ALT_CLK_SDRAM_PLL_C1: + hilimit = alt_pll_cntr_maxfreq.SDRAMPLL_C1; + lolimit = 0; + status = alt_clk_pll_vco_freq_get(ALT_CLK_SDRAM_PLL, &numer); + break; + case ALT_CLK_SDRAM_PLL_C2: + hilimit = alt_pll_cntr_maxfreq.SDRAMPLL_C2; + lolimit = 0; + status = alt_clk_pll_vco_freq_get(ALT_CLK_SDRAM_PLL, &numer); + break; + case ALT_CLK_SDRAM_PLL_C5: + hilimit = alt_pll_cntr_maxfreq.SDRAMPLL_C5; + lolimit = alt_ext_clk_paramblok.clkosc1.freqcur; + status = alt_clk_pll_vco_freq_get(ALT_CLK_SDRAM_PLL, &numer); + break; + + default: + status = ALT_E_BAD_ARG; + break; + } + + if (status == ALT_E_SUCCESS) + { + numer = numer / div; + if ((numer <= hilimit) && (numer >= lolimit)) + { + status = ALT_E_TRUE; + } + else + { + status = ALT_E_FALSE; + } + } + + return status; +#endif +} + +static bool alt_clkmgr_is_val_modulo_n(uint32_t div, uint32_t mod) +{ + if (mod == 1) + { + return true; + } + else if (mod == 2) + { + return (div & 0x1) == 0; + } + else if (mod == 4) + { + return (div & 0x3) == 0; + } + else + { + return (div % mod) == 0; + } +} + +// +// alt_clk_divider_set() sets the divider value for the specified clock. +// +// See pages 38, 44, 45, and 46 of the HPS-Clocking NPP for a map of the +// HPS clocking architecture and hierarchy of connections. +// +ALT_STATUS_CODE alt_clk_divider_set(ALT_CLK_t clk, uint32_t div) +{ + ALT_STATUS_CODE ret = ALT_E_BAD_ARG; + volatile uint32_t temp, temp1; + uint32_t wrval = UINT32_MAX; // value to be written + bool restore_0 = false; + bool restore_1 = false; + bool restore_2 = false; + + switch (clk) + { + // Main PLL outputs + case ALT_CLK_MAIN_PLL_C0: + case ALT_CLK_MPU: + { + uint32_t prediv = (ALT_CLKMGR_ALTERA_MPUCLK_CNT_GET(alt_read_word(ALT_CLKMGR_ALTERA_MPUCLK_ADDR)) + 1); + + if ( (div <= ((ALT_CLKMGR_MAINPLL_MPUCLK_CNT_SET_MSK + 1) * prediv)) + && alt_clkmgr_is_val_modulo_n(div, prediv) + && (alt_clk_within_freq_limits(ALT_CLK_MAIN_PLL_C0, div) == ALT_E_TRUE) ) + { + wrval = (div / prediv) - 1; + + // HW managed clock, change by writing to the external counter, no need to gate clock + // or match phase or wait for transistion time. No other field in the register to mask off either. + alt_write_word(ALT_CLKMGR_MAINPLL_MPUCLK_ADDR, wrval); + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + } + break; + + case ALT_CLK_MAIN_PLL_C1: + case ALT_CLK_L3_MAIN: + { + uint32_t prediv = (ALT_CLKMGR_ALTERA_MAINCLK_CNT_GET(alt_read_word(ALT_CLKMGR_ALTERA_MAINCLK_ADDR)) + 1); + + if ( (div <= ((ALT_CLKMGR_MAINPLL_MAINCLK_CNT_SET_MSK + 1) * prediv)) + && alt_clkmgr_is_val_modulo_n(div, prediv) + && (alt_clk_within_freq_limits(ALT_CLK_MAIN_PLL_C1, div) == ALT_E_TRUE) ) + { + // HW managed clock, change by writing to the external counter, no need to gate clock + // or match phase or wait for transistion time. No other field in the register to mask off either. + + wrval = (div / prediv) - 1; + +#if ALT_PREVENT_GLITCH_CHGC1 + // if L4MP or L4SP source is set to Main PLL C1, gate it off before changing + // bypass state, then gate clock back on. FogBugz #63778 + temp = alt_read_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR); + temp1 = alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR); + + if ((temp1 & ALT_CLKMGR_MAINPLL_EN_L4MPCLK_SET_MSK) && (!(temp & ALT_CLKMGR_MAINPLL_L4SRC_L4MP_SET_MSK))) + { + restore_0 = true; + } + if ((temp1 & ALT_CLKMGR_MAINPLL_EN_L4SPCLK_SET_MSK) && (!(temp & ALT_CLKMGR_MAINPLL_L4SRC_L4SP_SET_MSK))) + { + restore_1 = true; + } + temp = temp1; + if (restore_0) { temp &= ALT_CLKMGR_MAINPLL_EN_L4MPCLK_CLR_MSK; } + if (restore_1) { temp &= ALT_CLKMGR_MAINPLL_EN_L4SPCLK_CLR_MSK; } + if (restore_0 || restore_1) { alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp); } + + alt_write_word(ALT_CLKMGR_MAINPLL_MAINCLK_ADDR, wrval); + + alt_clk_mgr_wait(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + // wait a bit before reenabling the L4MP and L4SP clocks + if (restore_0 || restore_1) { alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp1); } +#else + alt_write_word(ALT_CLKMGR_MAINPLL_MAINCLK_ADDR, wrval); +#endif + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + } + break; + + case ALT_CLK_MAIN_PLL_C2: + case ALT_CLK_DBG_BASE: + { + uint32_t prediv = (ALT_CLKMGR_ALTERA_DBGATCLK_CNT_GET(alt_read_word(ALT_CLKMGR_ALTERA_DBGATCLK_ADDR)) + 1); + + if ( (div <= ((ALT_CLKMGR_MAINPLL_DBGATCLK_CNT_SET_MSK + 1) * prediv)) + && alt_clkmgr_is_val_modulo_n(div, prediv) + && (alt_clk_within_freq_limits(ALT_CLK_MAIN_PLL_C2, div) == ALT_E_TRUE) ) + { + wrval = (div / prediv) - 1; + // HW managed clock, change by writing to the external counter, no need to gate clock + // or match phase or wait for transistion time. No other field in the register to mask off either. + alt_write_word(ALT_CLKMGR_MAINPLL_DBGATCLK_ADDR, wrval); + + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + } + break; + + case ALT_CLK_MAIN_PLL_C3: + // The rest of the PLL outputs do not have external counters, but + // their internal counters are programmable rather than fixed + if ( (div <= (ALT_CLKMGR_MAINPLL_MAINQSPICLK_CNT_SET_MSK + 1)) + && (alt_clk_within_freq_limits(ALT_CLK_MAIN_PLL_C3, div) == ALT_E_TRUE) ) + { + // if the main_qspi_clk input is selected for the qspi_clk + if (ALT_CLKMGR_PERPLL_SRC_QSPI_GET(alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR)) == + ALT_CLKMGR_PERPLL_SRC_QSPI_E_MAIN_QSPI_CLK) + { + restore_0 = (temp = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR)) & ALT_CLKMGR_PERPLL_EN_QSPICLK_SET_MSK; + if (restore_0) // AND if the QSPI clock is currently enabled + { + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp & ALT_CLKMGR_PERPLL_EN_QSPICLK_CLR_MSK); + // gate off the QSPI clock + } + + wrval = div - 1; + // the rest are software-managed clocks and require a reset sequence to write to + alt_clk_pllcounter_write(ALT_CLKMGR_MAINPLL_VCO_ADDR, + ALT_CLKMGR_MAINPLL_STAT_ADDR, + ALT_CLKMGR_MAINPLL_MAINQSPICLK_ADDR, + wrval, + ALT_CLK_PLL_RST_BIT_C3, + ALT_CLKMGR_MAINPLL_VCO_OUTRST_LSB); + + alt_clk_mgr_wait(ALT_CLKMGR_MAINPLL_MAINQSPICLK_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp); + // if the QSPI clock was gated on (enabled) before, return it to that state + } + ret = ALT_E_SUCCESS; + } + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_MAIN_PLL_C4: + case ALT_CLK_MAIN_NAND_SDMMC: + if ( (div <= (ALT_CLKMGR_MAINPLL_MAINNANDSDMMCCLK_CNT_SET_MSK + 1)) + && (alt_clk_within_freq_limits(ALT_CLK_MAIN_PLL_C4, div) == ALT_E_TRUE) ) + { + temp = alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR); + temp1 = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR); + + // do we need to gate off the SDMMC clock ? + if (ALT_CLKMGR_PERPLL_SRC_SDMMC_GET(temp) == ALT_CLKMGR_PERPLL_SRC_SDMMC_E_MAIN_NAND_CLK) + { + if (temp1 & ALT_CLKMGR_PERPLL_EN_SDMMCCLK_SET_MSK) { restore_0 = true; } + } + + // do we need to gate off the NAND clock and/or the NANDX clock? + if (ALT_CLKMGR_PERPLL_SRC_NAND_GET(temp) == ALT_CLKMGR_PERPLL_SRC_NAND_E_MAIN_NAND_CLK) + { + if (temp1 & ALT_CLKMGR_PERPLL_EN_NANDXCLK_SET_MSK) { restore_1 = true; } + if (temp1 & ALT_CLKMGR_PERPLL_EN_NANDCLK_SET_MSK) { restore_2 = true; } + } + + temp = temp1; + if (restore_1 && restore_2) + { + temp &= ALT_CLKMGR_PERPLL_EN_NANDCLK_CLR_MSK; + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp); + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_SW_MANAGED_CLK_WAIT_NANDCLK); + // gate nand_clk off at least 8 MPU clock cycles before before nand_x_clk + } + + if (restore_0 || restore_1) + { + if (restore_0) { temp &= ALT_CLKMGR_PERPLL_EN_SDMMCCLK_CLR_MSK; } + if (restore_1) { temp &= ALT_CLKMGR_PERPLL_EN_NANDXCLK_CLR_MSK; } + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp); + // gate off sdmmc_clk and/or nand_x_clk + } + + // now write the new divisor ratio + wrval = div - 1; + alt_clk_pllcounter_write(ALT_CLKMGR_MAINPLL_VCO_ADDR, + ALT_CLKMGR_MAINPLL_STAT_ADDR, + ALT_CLKMGR_MAINPLL_MAINNANDSDMMCCLK_ADDR, + wrval, + ALT_CLK_PLL_RST_BIT_C4, + ALT_CLKMGR_MAINPLL_VCO_OUTRST_LSB); + alt_clk_mgr_wait(ALT_CLKMGR_MAINPLL_MAINNANDSDMMCCLK_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + + if (restore_0 || restore_1) + { + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp1 & ALT_CLKMGR_PERPLL_EN_NANDCLK_CLR_MSK); + // if the NANDX and/or SDMMC clock was gated on (enabled) before, return it to that state + if (restore_1 && restore_2) + { + // wait at least 8 clock cycles to turn the nand_clk on + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_SW_MANAGED_CLK_WAIT_NANDCLK); + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp1); + } + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_MAIN_PLL_C5: + case ALT_CLK_CFG: + case ALT_CLK_H2F_USER0: + if ( (div <= (ALT_CLKMGR_MAINPLL_CFGS2FUSER0CLK_CNT_SET_MSK + 1)) + && (alt_clk_within_freq_limits(ALT_CLK_MAIN_PLL_C5, div) == ALT_E_TRUE) ) + { + temp = alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR); + restore_0 = ((temp & ALT_CLKMGR_MAINPLL_EN_CFGCLK_SET_MSK) || + (temp & ALT_CLKMGR_MAINPLL_EN_S2FUSER0CLK_SET_MSK)); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp & (ALT_CLKMGR_MAINPLL_EN_CFGCLK_CLR_MSK & + ALT_CLKMGR_MAINPLL_EN_S2FUSER0CLK_CLR_MSK)); // clear both + } + + // now write the new divisor ratio + wrval = div - 1; + alt_clk_pllcounter_write(ALT_CLKMGR_MAINPLL_VCO_ADDR, + ALT_CLKMGR_MAINPLL_STAT_ADDR, + ALT_CLKMGR_MAINPLL_CFGS2FUSER0CLK_ADDR, + wrval, + ALT_CLK_PLL_RST_BIT_C5, + ALT_CLKMGR_MAINPLL_VCO_OUTRST_LSB); + + alt_clk_mgr_wait(ALT_CLKMGR_MAINPLL_CFGS2FUSER0CLK_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + + if (restore_0) + { + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp); + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + ///// + + // Peripheral PLL outputs + case ALT_CLK_PERIPHERAL_PLL_C0: + case ALT_CLK_EMAC0: + if ( (div <= (ALT_CLKMGR_PERPLL_EMAC0CLK_CNT_SET_MSK + 1)) + && (alt_clk_within_freq_limits(ALT_CLK_PERIPHERAL_PLL_C0, div) == ALT_E_TRUE) ) + { + temp = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR); + restore_0 = temp & ALT_CLKMGR_PERPLL_EN_EMAC0CLK_SET_MSK; + + if (restore_0) + { + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp & ALT_CLKMGR_PERPLL_EN_EMAC0CLK_CLR_MSK); + } + + // now write the new divisor ratio + wrval = div - 1; + alt_clk_pllcounter_write(ALT_CLKMGR_PERPLL_VCO_ADDR, + ALT_CLKMGR_PERPLL_STAT_ADDR, + ALT_CLKMGR_PERPLL_EMAC0CLK_ADDR, + wrval, + ALT_CLK_PLL_RST_BIT_C0, + ALT_CLKMGR_PERPLL_VCO_OUTRST_LSB); + + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_EMAC0CLK_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp); + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_PERIPHERAL_PLL_C1: + case ALT_CLK_EMAC1: + if ( (div <= (ALT_CLKMGR_PERPLL_EMAC1CLK_CNT_SET_MSK + 1)) + && (alt_clk_within_freq_limits(ALT_CLK_PERIPHERAL_PLL_C1, div) == ALT_E_TRUE) ) + { + temp = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR); + restore_0 = temp & ALT_CLKMGR_PERPLL_EN_EMAC1CLK_SET_MSK; + + if (restore_0) + { + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp & ALT_CLKMGR_PERPLL_EN_EMAC1CLK_CLR_MSK); + } + // now write the new divisor ratio + wrval = div - 1; + alt_clk_pllcounter_write(ALT_CLKMGR_PERPLL_VCO_ADDR, + ALT_CLKMGR_PERPLL_STAT_ADDR, + ALT_CLKMGR_PERPLL_EMAC1CLK_ADDR, + wrval, + ALT_CLK_PLL_RST_BIT_C1, + ALT_CLKMGR_PERPLL_VCO_OUTRST_LSB); + + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_EMAC1CLK_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp); + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_PERIPHERAL_PLL_C2: + if ( (div <= (ALT_CLKMGR_PERPLL_PERQSPICLK_CNT_SET_MSK + 1)) + && (alt_clk_within_freq_limits(ALT_CLK_PERIPHERAL_PLL_C2, div) == ALT_E_TRUE) ) + { + temp = ALT_CLKMGR_PERPLL_SRC_QSPI_GET(alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR)); + if (temp == ALT_CLKMGR_PERPLL_SRC_QSPI_E_PERIPH_QSPI_CLK) + { + // if qspi source is set to Peripheral PLL C2 + temp = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR); + // and if qspi_clk is enabled + restore_0 = temp & ALT_CLKMGR_PERPLL_EN_QSPICLK_SET_MSK; + if (restore_0) + { + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp & ALT_CLKMGR_PERPLL_EN_QSPICLK_CLR_MSK); + // gate it off + } + } + + // now write the new divisor ratio + wrval = div - 1; + alt_clk_pllcounter_write(ALT_CLKMGR_PERPLL_VCO_ADDR, + ALT_CLKMGR_PERPLL_STAT_ADDR, + ALT_CLKMGR_PERPLL_PERQSPICLK_ADDR, + wrval, + ALT_CLK_PLL_RST_BIT_C2, + ALT_CLKMGR_PERPLL_VCO_OUTRST_LSB); + + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_PERQSPICLK_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp); + // if the clock was gated on (enabled) before, return it to that state + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_PERIPHERAL_PLL_C3: + if ( (div <= (ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_CNT_SET_MSK + 1)) + && (alt_clk_within_freq_limits(ALT_CLK_PERIPHERAL_PLL_C3, div) == ALT_E_TRUE) ) + { + // first, are the clock MUX input selections currently set to use the clock we want to change? + temp = alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR); + restore_0 = (ALT_CLKMGR_PERPLL_SRC_SDMMC_GET(temp) == ALT_CLKMGR_PERPLL_SRC_SDMMC_E_PERIPH_NAND_CLK); + restore_1 = restore_2 = (ALT_CLKMGR_PERPLL_SRC_NAND_GET(temp) == ALT_CLKMGR_PERPLL_SRC_NAND_E_PERIPH_NAND_CLK); + + // now AND those with the current state of the three gate enables + // to get the clocks which must be gated off and then back on + temp1 = temp = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR); + restore_0 = restore_0 && (temp & ALT_CLKMGR_PERPLL_EN_SDMMCCLK_SET_MSK); + restore_1 = restore_1 && (temp & ALT_CLKMGR_PERPLL_EN_NANDXCLK_SET_MSK); + restore_2 = restore_2 && (temp & ALT_CLKMGR_PERPLL_EN_NANDCLK_SET_MSK); + + // gate off the clocks that depend on the clock divider that we want to change + if (restore_2) { temp &= ALT_CLKMGR_PERPLL_EN_NANDCLK_CLR_MSK; } + if (restore_0) { temp &= ALT_CLKMGR_PERPLL_EN_SDMMCCLK_CLR_MSK; } + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp); + + // the NAND clock must be gated off before the NANDX clock, + if (restore_1) + { + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_ADDR, ALT_SW_MANAGED_CLK_WAIT_NANDCLK); + temp &= ALT_CLKMGR_PERPLL_EN_NANDXCLK_CLR_MSK; + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp); + } + + // now write the new divisor ratio + wrval = div - 1; + alt_clk_pllcounter_write(ALT_CLKMGR_PERPLL_VCO_ADDR, + ALT_CLKMGR_PERPLL_STAT_ADDR, + ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_ADDR, + wrval, + ALT_CLK_PLL_RST_BIT_C3, + ALT_CLKMGR_PERPLL_VCO_OUTRST_LSB); + + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV ); + + // NAND clock and NAND_X clock cannot be written together, must be a set sequence with a delay + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp1 & ALT_CLKMGR_PERPLL_EN_NANDCLK_CLR_MSK); + if (restore_2) + { + // the NANDX clock must be gated on before the NAND clock. + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_ADDR, ALT_SW_MANAGED_CLK_WAIT_NANDCLK ); + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp1); + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_PERIPHERAL_PLL_C4: + if ( (div <= (ALT_CLKMGR_PERPLL_PERBASECLK_CNT_SET_MSK + 1)) + && (alt_clk_within_freq_limits(ALT_CLK_PERIPHERAL_PLL_C4, div) == ALT_E_TRUE) ) + { + // look at the L4 set of clock gates first + temp1 = alt_read_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR); + restore_0 = (ALT_CLKMGR_MAINPLL_L4SRC_L4MP_GET(temp1) == ALT_CLKMGR_MAINPLL_L4SRC_L4MP_E_PERIPHPLL); + restore_1 = (ALT_CLKMGR_MAINPLL_L4SRC_L4SP_GET(temp1) == ALT_CLKMGR_MAINPLL_L4SRC_L4SP_E_PERIPHPLL); + temp1 = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR); + restore_0 = restore_0 && (temp1 & ALT_CLKMGR_MAINPLL_EN_L4MPCLK_SET_MSK); + restore_1 = restore_1 && (temp1 & ALT_CLKMGR_MAINPLL_EN_L4SPCLK_SET_MSK); + + // if the l4_sp and l4_mp clocks are not set to use the periph_base_clk + // from the Peripheral PLL C4 clock divider output, or if they are + // not currently gated on, don't change their gates + temp = alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR); + if (restore_0) { temp &= ALT_CLKMGR_MAINPLL_EN_L4MPCLK_CLR_MSK; } + if (restore_1) { temp &= ALT_CLKMGR_MAINPLL_EN_L4SPCLK_CLR_MSK; } + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp); + + // now look at the C4 direct set of clock gates + // first, create a mask of the C4 direct set of clock gate enables + temp = ( ALT_CLKMGR_PERPLL_EN_USBCLK_SET_MSK + | ALT_CLKMGR_PERPLL_EN_SPIMCLK_SET_MSK + | ALT_CLKMGR_PERPLL_EN_CAN0CLK_SET_MSK + | ALT_CLKMGR_PERPLL_EN_CAN1CLK_SET_MSK + | ALT_CLKMGR_PERPLL_EN_GPIOCLK_SET_MSK ); + + // gate off all the C4 Direct set of clocks + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp1 & ~temp); + + // change the clock divider ratio - the reason we're here + wrval = div - 1; + alt_clk_pllcounter_write(ALT_CLKMGR_PERPLL_VCO_ADDR, + ALT_CLKMGR_PERPLL_STAT_ADDR, + ALT_CLKMGR_PERPLL_PERBASECLK_ADDR, + wrval, + ALT_CLK_PLL_RST_BIT_C4, + ALT_CLKMGR_PERPLL_VCO_OUTRST_LSB); + + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_PERBASECLK_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV ); + + // gate the affected clocks that were on before back on - both sets of gates + temp = (restore_0) ? ALT_CLKMGR_MAINPLL_EN_L4MPCLK_SET_MSK : 0; + if (restore_1) { temp |= ALT_CLKMGR_MAINPLL_EN_L4SPCLK_SET_MSK; } + alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp); + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp1); + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_PERIPHERAL_PLL_C5: + case ALT_CLK_H2F_USER1: + if ( (div <= (ALT_CLKMGR_PERPLL_S2FUSER1CLK_CNT_SET_MSK + 1)) + && (alt_clk_within_freq_limits(ALT_CLK_PERIPHERAL_PLL_C5, div) == ALT_E_TRUE) ) + { + temp = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR); + restore_0 = temp & ALT_CLKMGR_PERPLL_EN_S2FUSER1CLK_SET_MSK; + if (restore_0) + { + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp & ALT_CLKMGR_PERPLL_EN_S2FUSER1CLK_CLR_MSK); + } + + // now write the new divisor ratio + wrval = div - 1; + alt_clk_pllcounter_write(ALT_CLKMGR_PERPLL_VCO_ADDR, + ALT_CLKMGR_PERPLL_STAT_ADDR, + ALT_CLKMGR_PERPLL_S2FUSER1CLK_ADDR, + wrval, + ALT_CLK_PLL_RST_BIT_C5, + ALT_CLKMGR_PERPLL_VCO_OUTRST_LSB); + + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV ); + if (restore_0) { alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp); } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + ///// + + // SDRAM PLL outputs + case ALT_CLK_SDRAM_PLL_C0: + case ALT_CLK_DDR_DQS: + if ( (div <= (ALT_CLKMGR_SDRPLL_DDRDQSCLK_CNT_SET_MSK + 1)) + && (alt_clk_within_freq_limits(ALT_CLK_SDRAM_PLL_C0, div) == ALT_E_TRUE) ) + { + wrval = div - 1; + temp = alt_read_word(ALT_CLKMGR_SDRPLL_EN_ADDR); + if (temp & ALT_CLKMGR_SDRPLL_EN_DDRDQSCLK_SET_MSK) + { + // if clock is currently on, gate it off + alt_write_word(ALT_CLKMGR_SDRPLL_EN_ADDR, temp & ALT_CLKMGR_SDRPLL_EN_DDRDQSCLK_CLR_MSK); + restore_0 = true; + } + + alt_clk_pllcounter_write(ALT_CLKMGR_SDRPLL_VCO_ADDR, + ALT_CLKMGR_SDRPLL_STAT_ADDR, + ALT_CLKMGR_SDRPLL_DDRDQSCLK_ADDR, + wrval, + ALT_CLK_PLL_RST_BIT_C0, + ALT_CLKMGR_SDRPLL_DDRDQSCLK_CNT_LSB); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_SDRPLL_EN_ADDR, temp); // which has the enable bit set + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_SDRAM_PLL_C1: + case ALT_CLK_DDR_2X_DQS: + if ( (div <= (ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_CNT_SET_MSK + 1)) + && (alt_clk_within_freq_limits(ALT_CLK_SDRAM_PLL_C1, div) == ALT_E_TRUE) ) + { + wrval = div - 1; + temp = alt_read_word(ALT_CLKMGR_SDRPLL_EN_ADDR); + if (temp & ALT_CLKMGR_SDRPLL_EN_DDR2XDQSCLK_SET_MSK) + { + // if clock is currently on, gate it off + alt_write_word(ALT_CLKMGR_SDRPLL_EN_ADDR, temp & ALT_CLKMGR_SDRPLL_EN_DDR2XDQSCLK_CLR_MSK); + restore_0 = true; + } + + alt_clk_pllcounter_write(ALT_CLKMGR_SDRPLL_VCO_ADDR, + ALT_CLKMGR_SDRPLL_STAT_ADDR, + ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_ADDR, + wrval, + ALT_CLK_PLL_RST_BIT_C1, + ALT_CLKMGR_SDRPLL_VCO_OUTRST_LSB); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_SDRPLL_EN_ADDR, temp); // which has the enable bit set + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_SDRAM_PLL_C2: + case ALT_CLK_DDR_DQ: + if ( (div <= (ALT_CLKMGR_SDRPLL_DDRDQCLK_CNT_SET_MSK + 1)) + && (alt_clk_within_freq_limits(ALT_CLK_SDRAM_PLL_C2, div) == ALT_E_TRUE) ) + { + wrval = div - 1; + temp = alt_read_word(ALT_CLKMGR_SDRPLL_EN_ADDR); + if (temp & ALT_CLKMGR_SDRPLL_EN_DDRDQCLK_SET_MSK) + { + // if clock is currently on, gate it off + alt_write_word(ALT_CLKMGR_SDRPLL_EN_ADDR, temp & ALT_CLKMGR_SDRPLL_EN_DDRDQCLK_CLR_MSK); + restore_0 = true; + } + + alt_clk_pllcounter_write(ALT_CLKMGR_SDRPLL_VCO_ADDR, + ALT_CLKMGR_SDRPLL_STAT_ADDR, + ALT_CLKMGR_SDRPLL_DDRDQCLK_ADDR, + wrval, + ALT_CLK_PLL_RST_BIT_C2, + ALT_CLKMGR_SDRPLL_VCO_OUTRST_LSB); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_SDRPLL_EN_ADDR, temp); // which has the enable bit set + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_SDRAM_PLL_C5: + case ALT_CLK_H2F_USER2: + if ( (div <= (ALT_CLKMGR_SDRPLL_S2FUSER2CLK_CNT_SET_MSK + 1)) + && (alt_clk_within_freq_limits(ALT_CLK_SDRAM_PLL_C5, div) == ALT_E_TRUE) ) + { + wrval = div - 1; + temp = alt_read_word(ALT_CLKMGR_SDRPLL_EN_ADDR); + if (temp & ALT_CLKMGR_SDRPLL_EN_S2FUSER2CLK_SET_MSK) + { + // if clock is currently on, gate it off + alt_write_word(ALT_CLKMGR_SDRPLL_EN_ADDR, temp & ALT_CLKMGR_SDRPLL_EN_S2FUSER2CLK_CLR_MSK); + restore_0 = true; + } + + alt_clk_pllcounter_write(ALT_CLKMGR_SDRPLL_VCO_ADDR, + ALT_CLKMGR_SDRPLL_STAT_ADDR, + ALT_CLKMGR_SDRPLL_S2FUSER2CLK_ADDR, + wrval, + ALT_CLK_PLL_RST_BIT_C5, + ALT_CLKMGR_SDRPLL_VCO_OUTRST_LSB); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_SDRPLL_EN_ADDR, temp); // which has the enable bit set + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + ///// + + // Other clock dividers + case ALT_CLK_L3_MP: + if (div == 1) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L3MPCLK_E_DIV1; } + else if (div == 2) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L3MPCLK_E_DIV2; } + + if (wrval != UINT32_MAX) + { + temp = alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR); + if (temp & ALT_CLKMGR_MAINPLL_EN_L3MPCLK_SET_MSK) + { + // if clock is currently on, gate it off + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp & ALT_CLKMGR_MAINPLL_EN_L3MPCLK_CLR_MSK); + restore_0 = true; + } + alt_replbits_word(ALT_CLKMGR_MAINPLL_MAINDIV_ADDR, ALT_CLKMGR_MAINPLL_MAINDIV_L3MPCLK_SET_MSK, + wrval << ALT_CLKMGR_MAINPLL_MAINDIV_L3MPCLK_LSB); + alt_clk_mgr_wait(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV ); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp); // which has the enable bit set + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_L3_SP: + // note that the L3MP divider is upstream from the L3SP divider + // and any changes to the former will affect the output of both + if (div == 1) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L3SPCLK_E_DIV1; } + else if (div == 2) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L3SPCLK_E_DIV2; } + + if (wrval != UINT32_MAX) + { + alt_replbits_word(ALT_CLKMGR_MAINPLL_MAINDIV_ADDR, ALT_CLKMGR_MAINPLL_MAINDIV_L3SPCLK_SET_MSK, + wrval << ALT_CLKMGR_MAINPLL_MAINDIV_L3SPCLK_LSB); + // no clock gate to close and reopen + alt_clk_mgr_wait(ALT_CLKMGR_MAINPLL_MAINDIV_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV ); + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_L4_MP: + if (div == 1) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L4MPCLK_E_DIV1; } + else if (div == 2) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L4MPCLK_E_DIV2; } + else if (div == 4) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L4MPCLK_E_DIV4; } + else if (div == 8) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L4MPCLK_E_DIV8; } + else if (div == 16) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L4MPCLK_E_DIV16; } + + if (wrval != UINT32_MAX) + { + temp = alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR); + if (temp & ALT_CLKMGR_MAINPLL_EN_L4MPCLK_SET_MSK) + { + // if clock is currently on, gate it off + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp & ALT_CLKMGR_MAINPLL_EN_L4MPCLK_CLR_MSK); + restore_0 = true; + } + alt_replbits_word(ALT_CLKMGR_MAINPLL_MAINDIV_ADDR, ALT_CLKMGR_MAINPLL_MAINDIV_L4MPCLK_SET_MSK, + wrval << ALT_CLKMGR_MAINPLL_MAINDIV_L4MPCLK_LSB); + alt_clk_mgr_wait(ALT_CLKMGR_MAINPLL_MAINDIV_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp); // which has the enable bit set + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_L4_SP: + if (div == 1) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L4SPCLK_E_DIV1; } + else if (div == 2) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L4SPCLK_E_DIV2; } + else if (div == 4) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L4SPCLK_E_DIV4; } + else if (div == 8) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L4SPCLK_E_DIV8; } + else if (div == 16) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L4SPCLK_E_DIV16; } + + if (wrval != UINT32_MAX) + { + temp = alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR); + if (temp & ALT_CLKMGR_MAINPLL_EN_L4SPCLK_SET_MSK) + { + // if clock is currently on, gate it off + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp & ALT_CLKMGR_MAINPLL_EN_L4SPCLK_CLR_MSK); + restore_0 = true; + } + alt_replbits_word(ALT_CLKMGR_MAINPLL_MAINDIV_ADDR, ALT_CLKMGR_MAINPLL_MAINDIV_L4SPCLK_SET_MSK, + wrval << ALT_CLKMGR_MAINPLL_MAINDIV_L4SPCLK_LSB); + alt_clk_mgr_wait(ALT_CLKMGR_MAINPLL_MAINDIV_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp); + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_DBG_AT: + if (div == 1) { wrval = ALT_CLKMGR_MAINPLL_DBGDIV_DBGATCLK_E_DIV1; } + else if (div == 2) { wrval = ALT_CLKMGR_MAINPLL_DBGDIV_DBGATCLK_E_DIV2; } + else if (div == 4) { wrval = ALT_CLKMGR_MAINPLL_DBGDIV_DBGATCLK_E_DIV4; } + + if (wrval != UINT32_MAX) + { + temp = alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR); + if (temp & ALT_CLKMGR_MAINPLL_EN_DBGATCLK_SET_MSK) + { + // if clock is currently on, gate it off + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp & ALT_CLKMGR_MAINPLL_EN_DBGATCLK_CLR_MSK); + restore_0 = true; + } + alt_replbits_word(ALT_CLKMGR_MAINPLL_DBGDIV_ADDR, ALT_CLKMGR_MAINPLL_DBGDIV_DBGATCLK_SET_MSK, + wrval << ALT_CLKMGR_MAINPLL_DBGDIV_DBGATCLK_LSB); + alt_clk_mgr_wait(ALT_CLKMGR_MAINPLL_DBGDIV_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp); + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_DBG: + if (div == 2) { wrval = ALT_CLKMGR_MAINPLL_DBGDIV_DBGCLK_E_DIV2; } + else if (div == 4) { wrval = ALT_CLKMGR_MAINPLL_DBGDIV_DBGCLK_E_DIV4; } + + if (wrval != UINT32_MAX) + { + temp = alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR); + if (temp & ALT_CLKMGR_MAINPLL_EN_DBGCLK_SET_MSK) + { + // if clock is currently on, gate it off + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp & ALT_CLKMGR_MAINPLL_EN_DBGCLK_CLR_MSK); + restore_0 = true; + } + alt_replbits_word(ALT_CLKMGR_MAINPLL_DBGDIV_ADDR, ALT_CLKMGR_MAINPLL_DBGDIV_DBGCLK_SET_MSK, + wrval << (ALT_CLKMGR_MAINPLL_DBGDIV_DBGCLK_LSB - 1)); + // account for the fact that the divisor ratios are 2x the value + alt_clk_mgr_wait(ALT_CLKMGR_MAINPLL_DBGDIV_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp); + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_DBG_TRACE: + if (div == 1) { wrval = ALT_CLKMGR_MAINPLL_TRACEDIV_TRACECLK_E_DIV1; } + else if (div == 2) { wrval = ALT_CLKMGR_MAINPLL_TRACEDIV_TRACECLK_E_DIV2; } + else if (div == 4) { wrval = ALT_CLKMGR_MAINPLL_TRACEDIV_TRACECLK_E_DIV4; } + else if (div == 8) { wrval = ALT_CLKMGR_MAINPLL_TRACEDIV_TRACECLK_E_DIV8; } + else if (div == 16) { wrval = ALT_CLKMGR_MAINPLL_TRACEDIV_TRACECLK_E_DIV16; } + + if (wrval != UINT32_MAX) + { + temp = alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR); + if (temp & ALT_CLKMGR_MAINPLL_EN_DBGTRACECLK_SET_MSK) + { + // if clock is currently on, gate it off + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp & ALT_CLKMGR_MAINPLL_EN_DBGTRACECLK_CLR_MSK); + restore_0 = true; + } + alt_replbits_word(ALT_CLKMGR_MAINPLL_TRACEDIV_ADDR, ALT_CLKMGR_MAINPLL_TRACEDIV_TRACECLK_SET_MSK, + wrval << ALT_CLKMGR_MAINPLL_TRACEDIV_TRACECLK_LSB); + alt_clk_mgr_wait(ALT_CLKMGR_MAINPLL_TRACEDIV_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, temp); + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_USB_MP: + if (div == 1) { wrval = ALT_CLKMGR_PERPLL_DIV_USBCLK_E_DIV1; } + else if (div == 2) { wrval = ALT_CLKMGR_PERPLL_DIV_USBCLK_E_DIV2; } + else if (div == 4) { wrval = ALT_CLKMGR_PERPLL_DIV_USBCLK_E_DIV4; } + else if (div == 8) { wrval = ALT_CLKMGR_PERPLL_DIV_USBCLK_E_DIV8; } + else if (div == 16) { wrval = ALT_CLKMGR_PERPLL_DIV_USBCLK_E_DIV16; } + + if (wrval != UINT32_MAX) + { + temp = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR); + if (temp & ALT_CLKMGR_PERPLL_EN_USBCLK_SET_MSK) + { + // if clock is currently on, gate it off + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp & ALT_CLKMGR_PERPLL_EN_USBCLK_CLR_MSK); + restore_0 = true; + } + alt_replbits_word(ALT_CLKMGR_PERPLL_DIV_ADDR, ALT_CLKMGR_PERPLL_DIV_USBCLK_SET_MSK, + wrval << ALT_CLKMGR_PERPLL_DIV_USBCLK_LSB); + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_DIV_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp); + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_SPI_M: + if (div == 1) { wrval = ALT_CLKMGR_PERPLL_DIV_SPIMCLK_E_DIV1; } + else if (div == 2) { wrval = ALT_CLKMGR_PERPLL_DIV_SPIMCLK_E_DIV2; } + else if (div == 4) { wrval = ALT_CLKMGR_PERPLL_DIV_SPIMCLK_E_DIV4; } + else if (div == 8) { wrval = ALT_CLKMGR_PERPLL_DIV_SPIMCLK_E_DIV8; } + else if (div == 16) { wrval = ALT_CLKMGR_PERPLL_DIV_SPIMCLK_E_DIV16; } + + if (wrval != UINT32_MAX) + { + temp = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR); + if (temp & ALT_CLKMGR_PERPLL_EN_SPIMCLK_SET_MSK) + { + // if clock is currently on, gate it off + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp & ALT_CLKMGR_PERPLL_EN_SPIMCLK_CLR_MSK); + restore_0 = true; + } + alt_replbits_word(ALT_CLKMGR_PERPLL_DIV_ADDR, ALT_CLKMGR_PERPLL_DIV_SPIMCLK_SET_MSK, + wrval << ALT_CLKMGR_PERPLL_DIV_SPIMCLK_LSB); + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_DIV_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp); + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_CAN0: + if (div == 1) { wrval = ALT_CLKMGR_PERPLL_DIV_CAN0CLK_E_DIV1; } + else if (div == 2) { wrval = ALT_CLKMGR_PERPLL_DIV_CAN0CLK_E_DIV2; } + else if (div == 4) { wrval = ALT_CLKMGR_PERPLL_DIV_CAN0CLK_E_DIV4; } + else if (div == 8) { wrval = ALT_CLKMGR_PERPLL_DIV_CAN0CLK_E_DIV8; } + else if (div == 16) { wrval = ALT_CLKMGR_PERPLL_DIV_CAN0CLK_E_DIV16; } + + if (wrval != UINT32_MAX) + { + temp = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR); + if (temp & ALT_CLKMGR_PERPLL_EN_CAN0CLK_SET_MSK) + { + // if clock is currently on, gate it off + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp & ALT_CLKMGR_PERPLL_EN_CAN0CLK_CLR_MSK); + restore_0 = true; + } + alt_replbits_word(ALT_CLKMGR_PERPLL_DIV_ADDR, ALT_CLKMGR_PERPLL_DIV_CAN0CLK_SET_MSK, + wrval << ALT_CLKMGR_PERPLL_DIV_CAN0CLK_LSB); + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_DIV_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp); + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_CAN1: + if (div == 1) { wrval = ALT_CLKMGR_PERPLL_DIV_CAN1CLK_E_DIV1; } + else if (div == 2) { wrval = ALT_CLKMGR_PERPLL_DIV_CAN1CLK_E_DIV2; } + else if (div == 4) { wrval = ALT_CLKMGR_PERPLL_DIV_CAN1CLK_E_DIV4; } + else if (div == 8) { wrval = ALT_CLKMGR_PERPLL_DIV_CAN1CLK_E_DIV8; } + else if (div == 16) { wrval = ALT_CLKMGR_PERPLL_DIV_CAN1CLK_E_DIV16; } + + if (wrval != UINT32_MAX) + { + temp = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR); + if (temp & ALT_CLKMGR_PERPLL_EN_CAN1CLK_SET_MSK) + { + // if clock is currently on, gate it off + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp & ALT_CLKMGR_PERPLL_EN_CAN1CLK_CLR_MSK); + restore_0 = true; + } + alt_replbits_word(ALT_CLKMGR_PERPLL_DIV_ADDR, ALT_CLKMGR_PERPLL_DIV_CAN1CLK_SET_MSK, + wrval << ALT_CLKMGR_PERPLL_DIV_CAN1CLK_LSB); + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_DIV_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp); + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_GPIO_DB: // GPIO debounce clock + if (div <= ALT_CLKMGR_PERPLL_GPIODIV_GPIODBCLK_SET_MSK) + { + temp = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR); + if (temp & ALT_CLKMGR_PERPLL_EN_GPIOCLK_SET_MSK) + { + // if clock is currently on, gate it off + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp & ALT_CLKMGR_PERPLL_EN_GPIOCLK_CLR_MSK); + restore_0 = true; + } + wrval = div - 1; + alt_replbits_word(ALT_CLKMGR_PERPLL_GPIODIV_ADDR, ALT_CLKMGR_PERPLL_GPIODIV_GPIODBCLK_SET_MSK, + wrval << ALT_CLKMGR_PERPLL_GPIODIV_GPIODBCLK_LSB); + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_GPIODIV_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, temp); + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + break; + + case ALT_CLK_MAIN_QSPI: + temp = ALT_CLKMGR_PERPLL_SRC_QSPI_GET(alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR)); + // get the QSPI clock source + restore_0 = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR) & ALT_CLKMGR_PERPLL_EN_QSPICLK_SET_MSK; + // and the current enable state + wrval = div - 1; + + if (temp == ALT_CLKMGR_PERPLL_SRC_QSPI_E_MAIN_QSPI_CLK) + { // if the main_qspi_clk (Main PLL C3 Ouput) input is selected + if (div <= ALT_CLKMGR_MAINPLL_MAINQSPICLK_CNT_SET_MSK) + { + if (restore_0) + { + alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_QSPICLK_SET_MSK); + } // gate off the QSPI clock + + alt_clk_pllcounter_write(ALT_CLKMGR_MAINPLL_VCO_ADDR, + ALT_CLKMGR_MAINPLL_STAT_ADDR, + ALT_CLKMGR_MAINPLL_MAINQSPICLK_ADDR, + wrval, + ALT_CLK_PLL_RST_BIT_C3, + ALT_CLKMGR_MAINPLL_VCO_OUTRST_LSB); + + alt_clk_mgr_wait(ALT_CLKMGR_MAINPLL_MAINQSPICLK_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_QSPICLK_SET_MSK); + // if the QSPI clock was gated on (enabled) before, return it to that state + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + } + else if (temp == ALT_CLKMGR_PERPLL_SRC_QSPI_E_PERIPH_QSPI_CLK) + { + if (div <= ALT_CLKMGR_PERPLL_PERQSPICLK_CNT_SET_MSK) + { + if (restore_0) + { + alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_QSPICLK_SET_MSK); + } // gate off the QSPI clock + + alt_clk_pllcounter_write(ALT_CLKMGR_PERPLL_VCO_ADDR, + ALT_CLKMGR_PERPLL_STAT_ADDR, + ALT_CLKMGR_PERPLL_PERQSPICLK_ADDR, + wrval, + ALT_CLK_PLL_RST_BIT_C2, + ALT_CLKMGR_PERPLL_VCO_OUTRST_LSB); + + alt_clk_mgr_wait(ALT_CLKMGR_PERPLL_PERQSPICLK_ADDR, ALT_SW_MANAGED_CLK_WAIT_CTRDIV); + if (restore_0) + { + alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_QSPICLK_SET_MSK); + // if the QSPI clock was gated on (enabled) before, return it to that state + } + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ARG_RANGE; + } + } + break; + + ///// + + default: + ret = ALT_E_BAD_ARG; + break; + } + + return ret; +} + +// +// alt_clk_freq_get() returns the output frequency of the specified clock. +// +ALT_STATUS_CODE alt_clk_freq_get(ALT_CLK_t clk, alt_freq_t* freq) +{ + ALT_STATUS_CODE ret = ALT_E_BAD_ARG; + uint32_t temp = 0; + uint64_t numer = 0; + uint64_t denom = 1; + + if (freq == NULL) + { + return ret; + } + + switch (clk) + { + // External Inputs + case ALT_CLK_IN_PIN_OSC1: + case ALT_CLK_OSC1: + numer = alt_ext_clk_paramblok.clkosc1.freqcur; + // denom = 1 by default + ret = ALT_E_SUCCESS; + break; + + case ALT_CLK_IN_PIN_OSC2: + numer = alt_ext_clk_paramblok.clkosc2.freqcur; + // denom = 1 by default + ret = ALT_E_SUCCESS; + break; + + case ALT_CLK_F2H_PERIPH_REF: + numer = alt_ext_clk_paramblok.periph.freqcur; + // denom = 1 by default + ret = ALT_E_SUCCESS; + break; + + case ALT_CLK_F2H_SDRAM_REF: + numer = alt_ext_clk_paramblok.sdram.freqcur; + // denom = 1 by default + ret = ALT_E_SUCCESS; + break; + + ///// + + // PLLs + case ALT_CLK_MAIN_PLL: + if (alt_clk_pll_is_bypassed(ALT_CLK_MAIN_PLL) == ALT_E_TRUE) + { + temp = alt_ext_clk_paramblok.clkosc1.freqcur; + ret = ALT_E_SUCCESS; + } + else + { + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + } + numer = (uint64_t) temp; + // denom = 1 by default + break; + + case ALT_CLK_PERIPHERAL_PLL: + if (alt_clk_pll_is_bypassed(ALT_CLK_PERIPHERAL_PLL) == ALT_E_TRUE) + { + temp = ALT_CLKMGR_PERPLL_VCO_PSRC_GET(alt_read_word(ALT_CLKMGR_PERPLL_VCO_ADDR)); + if (temp == ALT_CLKMGR_PERPLL_VCO_PSRC_E_EOSC1) + { + temp = alt_ext_clk_paramblok.clkosc1.freqcur; + ret = ALT_E_SUCCESS; + } + else if (temp == ALT_CLKMGR_PERPLL_VCO_PSRC_E_EOSC2) + { + temp = alt_ext_clk_paramblok.clkosc2.freqcur; + ret = ALT_E_SUCCESS; + } + else if (temp == ALT_CLKMGR_PERPLL_VCO_PSRC_E_F2S_PERIPH_REF) + { + temp = alt_ext_clk_paramblok.periph.freqcur; + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ERROR; + } + } + else + { + ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &temp); + } + numer = (uint64_t) temp; + // denom = 1 by default + break; + + case ALT_CLK_SDRAM_PLL: + if (alt_clk_pll_is_bypassed(ALT_CLK_SDRAM_PLL) == ALT_E_TRUE) + { + temp = ALT_CLKMGR_SDRPLL_VCO_SSRC_GET(alt_read_word(ALT_CLKMGR_SDRPLL_VCO_ADDR)); + if (temp == ALT_CLKMGR_SDRPLL_VCO_SSRC_E_EOSC1) + { + temp = alt_ext_clk_paramblok.clkosc1.freqcur; + ret = ALT_E_SUCCESS; + } + else if (temp == ALT_CLKMGR_SDRPLL_VCO_SSRC_E_EOSC2) + { + temp = alt_ext_clk_paramblok.clkosc2.freqcur; + ret = ALT_E_SUCCESS; + } + else if (temp == ALT_CLKMGR_SDRPLL_VCO_SSRC_E_F2S_SDRAM_REF) + { + temp = alt_ext_clk_paramblok.sdram.freqcur; + ret = ALT_E_SUCCESS; + } + else + { + ret = ALT_E_ERROR; + } + } + else + { + ret = alt_clk_pll_vco_freq_get(ALT_CLK_SDRAM_PLL, &temp); + } + numer = (uint64_t) temp; + // denom = 1 by default + break; + + ///// + + // Main Clock Group + case ALT_CLK_MAIN_PLL_C0: + case ALT_CLK_MAIN_PLL_C1: + case ALT_CLK_MAIN_PLL_C2: + case ALT_CLK_MAIN_PLL_C3: + case ALT_CLK_MAIN_PLL_C4: + case ALT_CLK_MAIN_PLL_C5: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(clk, &temp); + denom = (uint64_t) temp; + } + break; + + case ALT_CLK_MPU: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C0, &temp); + denom = (uint64_t) temp; + } + break; + + case ALT_CLK_MPU_PERIPH: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C0, &temp); + } + if (ret == ALT_E_SUCCESS) + { + denom = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MPU_PERIPH, &temp); + denom = denom * (uint64_t) temp; + } + break; + + case ALT_CLK_MPU_L2_RAM: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C0, &temp); + } + if (ret == ALT_E_SUCCESS) + { + denom = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MPU_L2_RAM, &temp); + denom = denom * (uint64_t) temp; + } + break; + + case ALT_CLK_L4_MAIN: + case ALT_CLK_L3_MAIN: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C1, &temp); + denom = (uint64_t) temp; + } + break; + + case ALT_CLK_L3_MP: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C1, &temp); + } + if (ret == ALT_E_SUCCESS) + { + denom = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_L3_MP, &temp); + denom = denom * (uint64_t) temp; + } + break; + + case ALT_CLK_L3_SP: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C1, &temp); + } + if (ret == ALT_E_SUCCESS) + { + denom = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_L3_MP, &temp); + } + if (ret == ALT_E_SUCCESS) + { + denom = denom * (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_L3_SP, &temp); + denom = denom * (uint64_t) temp; + } + break; + + case ALT_CLK_L4_MP: + ret = alt_clk_divider_get(ALT_CLK_L4_MP, &temp); + if (ret == ALT_E_SUCCESS) + { + denom = (uint64_t) temp; + temp = ALT_CLKMGR_MAINPLL_L4SRC_L4MP_GET(alt_read_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR)); + if (temp == ALT_CLKMGR_MAINPLL_L4SRC_L4MP_E_MAINPLL) + { + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C1, &temp); + denom = denom * (uint64_t) temp; // no real harm if temp is garbage data + } + } + else if (temp == ALT_CLKMGR_MAINPLL_L4SRC_L4MP_E_PERIPHPLL) + { + ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_PERIPHERAL_PLL_C4, &temp); + denom = denom * (uint64_t) temp; + } + } + } + break; + + case ALT_CLK_L4_SP: + ret = alt_clk_divider_get(ALT_CLK_L4_SP, &temp); + if (ret == ALT_E_SUCCESS) + { + denom = (uint64_t) temp; + temp = ALT_CLKMGR_MAINPLL_L4SRC_L4SP_GET(alt_read_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR)); + if (temp == ALT_CLKMGR_MAINPLL_L4SRC_L4SP_E_MAINPLL) + { + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C1, &temp); + denom = denom * (uint64_t) temp; + } + } + else if (temp == ALT_CLKMGR_MAINPLL_L4SRC_L4SP_E_PERIPHPLL) // periph_base_clk + { + ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_PERIPHERAL_PLL_C4, &temp); + denom = denom * (uint64_t) temp; + } + } + } + break; + + case ALT_CLK_DBG_BASE: + case ALT_CLK_DBG_TIMER: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C2, &temp); + denom = (uint64_t) temp; + } + break; + + case ALT_CLK_DBG_AT: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C2, &temp); + } + if (ret == ALT_E_SUCCESS) + { + denom = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_DBG_AT, &temp); + denom = denom * (uint64_t) temp; + } + break; + + case ALT_CLK_DBG: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C2, &temp); + } + if (ret == ALT_E_SUCCESS) + { + denom = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_DBG_AT, &temp); + } + if (ret == ALT_E_SUCCESS) + { + denom = denom * (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_DBG, &temp); + denom = denom * (uint64_t) temp; + } + break; + + case ALT_CLK_DBG_TRACE: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C2, &temp); + } + if (ret == ALT_E_SUCCESS) + { + denom = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_DBG_TRACE, &temp); + denom = denom * (uint64_t) temp; + } + break; + + case ALT_CLK_MAIN_QSPI: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C3, &temp); + denom = (uint64_t) temp; + } + break; + + case ALT_CLK_MAIN_NAND_SDMMC: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C4, &temp); + denom = (uint64_t) temp; + } + break; + + case ALT_CLK_CFG: + case ALT_CLK_H2F_USER0: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C5, &temp); + denom = (uint64_t) temp; + } + break; + + ///// + + // Peripheral Clock Group + case ALT_CLK_PERIPHERAL_PLL_C0: + case ALT_CLK_PERIPHERAL_PLL_C1: + case ALT_CLK_PERIPHERAL_PLL_C2: + case ALT_CLK_PERIPHERAL_PLL_C3: + case ALT_CLK_PERIPHERAL_PLL_C4: + case ALT_CLK_PERIPHERAL_PLL_C5: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(clk, &temp); + denom = (uint64_t) temp; + } + break; + + case ALT_CLK_EMAC0: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_PERIPHERAL_PLL_C0, &temp); + denom = (uint64_t) temp; + } + break; + + case ALT_CLK_EMAC1: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_PERIPHERAL_PLL_C1, &temp); + denom = (uint64_t) temp; + } + break; + + case ALT_CLK_USB_MP: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_PERIPHERAL_PLL_C4, &temp); + if (ret == ALT_E_SUCCESS) + { + denom = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_USB_MP, &temp); + denom = denom * (uint64_t) temp; + } + } + break; + + case ALT_CLK_SPI_M: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_PERIPHERAL_PLL_C4, &temp); + } + if (ret == ALT_E_SUCCESS) + { + denom = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_SPI_M, &temp); + denom = denom * (uint64_t) temp; + } + break; + + case ALT_CLK_CAN0: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_PERIPHERAL_PLL_C4, &temp); + } + if (ret == ALT_E_SUCCESS) + { + denom = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_CAN0, &temp); + denom = denom * (uint64_t) temp; + } + break; + + case ALT_CLK_CAN1: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_PERIPHERAL_PLL_C4, &temp); + } + if (ret == ALT_E_SUCCESS) + { + denom = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_CAN1, &temp); + denom = denom * (uint64_t) temp; + } + break; + + case ALT_CLK_GPIO_DB: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_PERIPHERAL_PLL_C4, &temp); + } + if (ret == ALT_E_SUCCESS) + { + denom = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_GPIO_DB, &temp); + denom = denom * (uint64_t) temp; + } + break; + + case ALT_CLK_H2F_USER1: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_PERIPHERAL_PLL_C5, &temp); + denom = (uint64_t) temp; + } + break; + + /* Clocks That Can Switch Between Different Clock Groups */ + case ALT_CLK_SDMMC: + temp = ALT_CLKMGR_PERPLL_SRC_SDMMC_GET(alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR)); + if (temp == ALT_CLKMGR_PERPLL_SRC_SDMMC_E_F2S_PERIPH_REF_CLK) + { + numer = (uint64_t) alt_ext_clk_paramblok.periph.freqcur; + // denom = 1 by default + ret = ALT_E_SUCCESS; + } + else if (temp == ALT_CLKMGR_PERPLL_SRC_SDMMC_E_MAIN_NAND_CLK) + { + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C4, &temp); + denom = (uint64_t) temp; + } + } + else if (temp == ALT_CLKMGR_PERPLL_SRC_SDMMC_E_PERIPH_NAND_CLK) + { + ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_PERIPHERAL_PLL_C3, &temp); + denom = (uint64_t) temp; + } + } + else + { + ret = ALT_E_ERROR; + } + break; + + case ALT_CLK_NAND: + denom = 4; + // the absence of a break statement here is not a mistake + case ALT_CLK_NAND_X: + temp = ALT_CLKMGR_PERPLL_SRC_NAND_GET(alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR)); + if (temp == ALT_CLKMGR_PERPLL_SRC_NAND_E_F2S_PERIPH_REF_CLK) + { + numer = (uint64_t) alt_ext_clk_paramblok.periph.freqcur; + // denom = 1 or 4 by default; + ret = ALT_E_SUCCESS; + } + else if (temp == ALT_CLKMGR_PERPLL_SRC_NAND_E_MAIN_NAND_CLK) + { + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C4, &temp); + denom = denom * (uint64_t) temp; + } + } + else if (temp == ALT_CLKMGR_PERPLL_SRC_NAND_E_PERIPH_NAND_CLK) + { + ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_PERIPHERAL_PLL_C3, &temp); + denom = denom * (uint64_t) temp; + } + } + else + { + ret = ALT_E_ERROR; + } + break; + + case ALT_CLK_QSPI: + temp = ALT_CLKMGR_PERPLL_SRC_QSPI_GET(alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR)); + if (temp == ALT_CLKMGR_PERPLL_SRC_QSPI_E_F2S_PERIPH_REF_CLK) + { + numer = (uint64_t) alt_ext_clk_paramblok.periph.freqcur; + // denom = 1 by default; + ret = ALT_E_SUCCESS; + } + else if (temp == ALT_CLKMGR_PERPLL_SRC_QSPI_E_MAIN_QSPI_CLK) + { + ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_MAIN_PLL_C3, &temp); + denom = (uint64_t) temp; + } + } + else if (temp == ALT_CLKMGR_PERPLL_SRC_QSPI_E_PERIPH_QSPI_CLK) + { + ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_PERIPHERAL_PLL_C2, &temp); + denom = (uint64_t) temp; + } + } + else + { + ret = ALT_E_ERROR; + } + break; + + ///// + + // SDRAM Clock Group + case ALT_CLK_SDRAM_PLL_C0: + case ALT_CLK_DDR_DQS: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_SDRAM_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_SDRAM_PLL_C0, &temp); + denom = (uint64_t) temp; + } + break; + + case ALT_CLK_SDRAM_PLL_C1: + case ALT_CLK_DDR_2X_DQS: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_SDRAM_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_SDRAM_PLL_C1, &temp); + denom = (uint64_t) temp; + } + break; + + case ALT_CLK_SDRAM_PLL_C2: + case ALT_CLK_DDR_DQ: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_SDRAM_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_SDRAM_PLL_C2, &temp); + denom = (uint64_t) temp; + } + break; + + case ALT_CLK_SDRAM_PLL_C5: + case ALT_CLK_H2F_USER2: + ret = alt_clk_pll_vco_freq_get(ALT_CLK_SDRAM_PLL, &temp); + if (ret == ALT_E_SUCCESS) + { + numer = (uint64_t) temp; + ret = alt_clk_divider_get(ALT_CLK_SDRAM_PLL_C5, &temp); + denom = (uint64_t) temp; + } + break; + + default: + ret = ALT_E_BAD_ARG; + break; + + } // end of switch-case construct + + if (ret == ALT_E_SUCCESS) + { + // will not get here if none of above cases match + if (denom > 0) + { + numer /= denom; + if (numer <= UINT32_MAX) + { + *freq = (uint32_t) numer; + } + else + { + ret = ALT_E_ERROR; + } + } + else + { + ret = ALT_E_ERROR; + } + } + + return ret; +} + +// +// alt_clk_irq_disable() disables one or more of the lock status conditions as +// contributors to the clkmgr_IRQ interrupt signal state. +// +ALT_STATUS_CODE alt_clk_irq_disable(ALT_CLK_PLL_LOCK_STATUS_t lock_stat_mask) +{ + if (!(lock_stat_mask & ALT_CLK_MGR_PLL_LOCK_BITS)) + { + alt_clrbits_word(ALT_CLKMGR_INTREN_ADDR, lock_stat_mask); + return ALT_E_SUCCESS; + } + else + { + return ALT_E_BAD_ARG; + } +} + +// +// alt_clk_irq_enable() enables one or more of the lock status conditions as +// contributors to the clkmgr_IRQ interrupt signal state. +// +ALT_STATUS_CODE alt_clk_irq_enable(ALT_CLK_PLL_LOCK_STATUS_t lock_stat_mask) +{ + if (!(lock_stat_mask & ALT_CLK_MGR_PLL_LOCK_BITS)) + { + alt_setbits_word(ALT_CLKMGR_INTREN_ADDR, lock_stat_mask); + return ALT_E_SUCCESS; + } + else + { + return ALT_E_BAD_ARG; + } +} + +///// + +// +// alt_clk_group_cfg_raw_get() gets the raw configuration state of the designated +// clock group. +// +ALT_STATUS_CODE alt_clk_group_cfg_raw_get(ALT_CLK_GRP_t clk_group, + ALT_CLK_GROUP_RAW_CFG_t * clk_group_raw_cfg) +{ + clk_group_raw_cfg->verid = alt_read_word(ALT_SYSMGR_SILICONID1_ADDR); + clk_group_raw_cfg->siliid2 = alt_read_word(ALT_SYSMGR_SILICONID2_ADDR); + clk_group_raw_cfg->clkgrpsel = clk_group; + + if (clk_group == ALT_MAIN_PLL_CLK_GRP) + { + // Main PLL VCO register + clk_group_raw_cfg->clkgrp.mainpllgrp.raw.vco = alt_read_word(ALT_CLKMGR_MAINPLL_VCO_ADDR); + + // Main PLL Misc register + clk_group_raw_cfg->clkgrp.mainpllgrp.raw.misc = alt_read_word(ALT_CLKMGR_MAINPLL_MISC_ADDR); + + // Main PLL C0-C5 Counter registers + clk_group_raw_cfg->clkgrp.mainpllgrp.raw.mpuclk = alt_read_word(ALT_CLKMGR_MAINPLL_MPUCLK_ADDR); + // doing these as 32-bit reads and writes avoids unnecessary masking operations + + clk_group_raw_cfg->clkgrp.mainpllgrp.raw.mainclk = alt_read_word(ALT_CLKMGR_MAINPLL_MAINCLK_ADDR); + clk_group_raw_cfg->clkgrp.mainpllgrp.raw.dbgatclk = alt_read_word(ALT_CLKMGR_MAINPLL_DBGATCLK_ADDR); + clk_group_raw_cfg->clkgrp.mainpllgrp.raw.mainqspiclk = alt_read_word(ALT_CLKMGR_MAINPLL_MAINQSPICLK_ADDR); + clk_group_raw_cfg->clkgrp.mainpllgrp.raw.mainnandsdmmcclk = alt_read_word(ALT_CLKMGR_MAINPLL_MAINNANDSDMMCCLK_ADDR); + clk_group_raw_cfg->clkgrp.mainpllgrp.raw.cfgs2fuser0clk = alt_read_word(ALT_CLKMGR_MAINPLL_CFGS2FUSER0CLK_ADDR); + + // Main PLL Enable register + clk_group_raw_cfg->clkgrp.mainpllgrp.raw.en = alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR); + + // Main PLL Maindiv register + clk_group_raw_cfg->clkgrp.mainpllgrp.raw.maindiv = alt_read_word(ALT_CLKMGR_MAINPLL_MAINDIV_ADDR); + + // Main PLL Debugdiv register + clk_group_raw_cfg->clkgrp.mainpllgrp.raw.dbgdiv = alt_read_word(ALT_CLKMGR_MAINPLL_DBGDIV_ADDR); + + // Main PLL Tracediv register + clk_group_raw_cfg->clkgrp.mainpllgrp.raw.tracediv = alt_read_word(ALT_CLKMGR_MAINPLL_TRACEDIV_ADDR); + + // Main PLL L4 Source register + clk_group_raw_cfg->clkgrp.mainpllgrp.raw.l4src = alt_read_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR); + + // Main PLL Status register + clk_group_raw_cfg->clkgrp.mainpllgrp.raw.stat = alt_read_word(ALT_CLKMGR_MAINPLL_STAT_ADDR); + // clkgrp.mainpllgrp.stat.outresetack is defined in the ALT_CLKMGR_MAINPLL_STAT_s declaration + // as a const but alt_indwrite_word() overrides that restriction. + + // padding ... + clk_group_raw_cfg->clkgrp.mainpllgrp.raw._pad_0x38_0x40[0] = 0; + clk_group_raw_cfg->clkgrp.mainpllgrp.raw._pad_0x38_0x40[1] = 0; + + return ALT_E_SUCCESS; + } + else if (clk_group == ALT_PERIPH_PLL_CLK_GRP) + { + // Peripheral PLL VCO register + clk_group_raw_cfg->clkgrp.perpllgrp.raw.vco = alt_read_word(ALT_CLKMGR_PERPLL_VCO_ADDR); + + // Peripheral PLL Misc register + clk_group_raw_cfg->clkgrp.perpllgrp.raw.misc = alt_read_word(ALT_CLKMGR_PERPLL_MISC_ADDR); + + // Peripheral PLL C0-C5 Counters + clk_group_raw_cfg->clkgrp.perpllgrp.raw.emac0clk = alt_read_word(ALT_CLKMGR_PERPLL_EMAC0CLK_ADDR); + // doing these as 32-bit reads and writes avoids unnecessary masking operations + + clk_group_raw_cfg->clkgrp.perpllgrp.raw.emac1clk = alt_read_word(ALT_CLKMGR_PERPLL_EMAC1CLK_ADDR); + clk_group_raw_cfg->clkgrp.perpllgrp.raw.perqspiclk = alt_read_word(ALT_CLKMGR_PERPLL_PERQSPICLK_ADDR); + clk_group_raw_cfg->clkgrp.perpllgrp.raw.pernandsdmmcclk = alt_read_word(ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_ADDR); + clk_group_raw_cfg->clkgrp.perpllgrp.raw.perbaseclk = alt_read_word(ALT_CLKMGR_PERPLL_PERBASECLK_ADDR); + clk_group_raw_cfg->clkgrp.perpllgrp.raw.s2fuser1clk = alt_read_word(ALT_CLKMGR_PERPLL_S2FUSER1CLK_ADDR); + + // Peripheral PLL Enable register + clk_group_raw_cfg->clkgrp.perpllgrp.raw.en = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR); + + // Peripheral PLL Divider register + clk_group_raw_cfg->clkgrp.perpllgrp.raw.div = alt_read_word(ALT_CLKMGR_PERPLL_DIV_ADDR); + + // Peripheral PLL GPIO Divider register + clk_group_raw_cfg->clkgrp.perpllgrp.raw.gpiodiv = alt_read_word(ALT_CLKMGR_PERPLL_GPIODIV_ADDR); + + // Peripheral PLL Source register + clk_group_raw_cfg->clkgrp.perpllgrp.raw.src = alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR); + + // Peripheral PLL Status register + clk_group_raw_cfg->clkgrp.perpllgrp.raw.stat = alt_read_word(ALT_CLKMGR_PERPLL_STAT_ADDR); + + // padding ... + clk_group_raw_cfg->clkgrp.perpllgrp.raw._pad_0x34_0x40[0] = 0; + clk_group_raw_cfg->clkgrp.perpllgrp.raw._pad_0x34_0x40[1] = 0; + clk_group_raw_cfg->clkgrp.perpllgrp.raw._pad_0x34_0x40[2] = 0; + + return ALT_E_SUCCESS; + } + else if (clk_group == ALT_SDRAM_PLL_CLK_GRP) + { + // SDRAM PLL VCO register + clk_group_raw_cfg->clkgrp.sdrpllgrp.raw.vco = alt_read_word(ALT_CLKMGR_SDRPLL_VCO_ADDR); + + // SDRAM PLL Control register + clk_group_raw_cfg->clkgrp.sdrpllgrp.raw.ctrl = alt_read_word(ALT_CLKMGR_SDRPLL_CTL_ADDR); + + // SDRAM PLL C0-C2 & C5 Counters + clk_group_raw_cfg->clkgrp.sdrpllgrp.raw.ddrdqsclk = alt_read_word(ALT_CLKMGR_SDRPLL_DDRDQSCLK_ADDR); + // doing these as 32-bit reads and writes avoids unnecessary masking operations + + clk_group_raw_cfg->clkgrp.sdrpllgrp.raw.ddr2xdqsclk = alt_read_word(ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_ADDR); + clk_group_raw_cfg->clkgrp.sdrpllgrp.raw.ddrdqclk = alt_read_word(ALT_CLKMGR_SDRPLL_DDRDQCLK_ADDR); + clk_group_raw_cfg->clkgrp.sdrpllgrp.raw.s2fuser2clk = alt_read_word(ALT_CLKMGR_SDRPLL_S2FUSER2CLK_ADDR); + + // SDRAM PLL Enable register + clk_group_raw_cfg->clkgrp.sdrpllgrp.raw.en = alt_read_word(ALT_CLKMGR_SDRPLL_EN_ADDR); + + // SDRAM PLL Status register + clk_group_raw_cfg->clkgrp.sdrpllgrp.raw.stat = alt_read_word(ALT_CLKMGR_SDRPLL_STAT_ADDR); + + return ALT_E_SUCCESS; + } + else + { + return ALT_E_BAD_ARG; + } +} + +// +// alt_clk_group_cfg_raw_set() sets the clock group configuration. +// +ALT_STATUS_CODE alt_clk_group_cfg_raw_set(const ALT_CLK_GROUP_RAW_CFG_t * clk_group_raw_cfg) +{ + // test for matching silicon ID, but not for matching silicon revision number + if (ALT_SYSMGR_SILICONID1_ID_GET(alt_read_word(ALT_SYSMGR_SILICONID1_ADDR)) != + ALT_SYSMGR_SILICONID1_ID_GET(clk_group_raw_cfg->verid)) + { + return ALT_E_BAD_VERSION; + } + + // get the PLL ID + ALT_CLK_GRP_t clk_group = clk_group_raw_cfg->clkgrpsel; + ALT_CLK_t pll; + + if (clk_group == ALT_MAIN_PLL_CLK_GRP) { pll = ALT_CLK_MAIN_PLL; } + else if (clk_group == ALT_PERIPH_PLL_CLK_GRP) { pll = ALT_CLK_PERIPHERAL_PLL; } + else if (clk_group == ALT_SDRAM_PLL_CLK_GRP) { pll = ALT_CLK_SDRAM_PLL; } + else + { + return ALT_E_ERROR; + } + + ALT_STATUS_CODE status = ALT_E_SUCCESS; + + // if the PLL isn't in bypass mode, put it in bypass mode + bool byp = false; + if (alt_clk_pll_is_bypassed(pll) == ALT_E_FALSE) + { + status = alt_clk_pll_bypass_enable(pll, false); + if (status != ALT_E_SUCCESS) + { + return status; + } + + byp = true; + } + + // now write the values in the ALT_CLK_GROUP_RAW_CFG_t structure to the registers + if (clk_group == ALT_MAIN_PLL_CLK_GRP) + { + // Main PLL VCO register + alt_write_word(ALT_CLKMGR_MAINPLL_VCO_ADDR, clk_group_raw_cfg->clkgrp.mainpllgrp.raw.vco & + ALT_CLKMGR_MAINPLL_VCO_OUTRSTALL_CLR_MSK & ALT_CLKMGR_MAINPLL_VCO_OUTRST_CLR_MSK); + // the outreset and outresetall bits were probably clear when the + // state was saved, but make sure they're clear now + + // Main PLL Misc register + alt_write_word(ALT_CLKMGR_MAINPLL_MISC_ADDR, clk_group_raw_cfg->clkgrp.mainpllgrp.raw.misc); + + // Main PLL C0-C5 Counter registers + alt_write_word(ALT_CLKMGR_MAINPLL_MPUCLK_ADDR, clk_group_raw_cfg->clkgrp.mainpllgrp.raw.mpuclk); + alt_write_word(ALT_CLKMGR_MAINPLL_MAINCLK_ADDR, clk_group_raw_cfg->clkgrp.mainpllgrp.raw.mainclk); + alt_write_word(ALT_CLKMGR_MAINPLL_DBGATCLK_ADDR, clk_group_raw_cfg->clkgrp.mainpllgrp.raw.dbgatclk); + alt_write_word(ALT_CLKMGR_MAINPLL_MAINQSPICLK_ADDR, clk_group_raw_cfg->clkgrp.mainpllgrp.raw.mainqspiclk); + alt_write_word(ALT_CLKMGR_MAINPLL_MAINNANDSDMMCCLK_ADDR, clk_group_raw_cfg->clkgrp.mainpllgrp.raw.mainnandsdmmcclk); + alt_write_word(ALT_CLKMGR_MAINPLL_CFGS2FUSER0CLK_ADDR, clk_group_raw_cfg->clkgrp.mainpllgrp.raw.cfgs2fuser0clk); + + // Main PLL Counter Enable register + alt_write_word(ALT_CLKMGR_MAINPLL_EN_ADDR, clk_group_raw_cfg->clkgrp.mainpllgrp.raw.en); + + // Main PLL Maindiv register + alt_write_word(ALT_CLKMGR_MAINPLL_MAINDIV_ADDR, clk_group_raw_cfg->clkgrp.mainpllgrp.raw.maindiv); + + // Main PLL Debugdiv register + alt_write_word(ALT_CLKMGR_MAINPLL_DBGDIV_ADDR, clk_group_raw_cfg->clkgrp.mainpllgrp.raw.dbgdiv); + + // Main PLL Tracediv register + alt_write_word(ALT_CLKMGR_MAINPLL_TRACEDIV_ADDR, clk_group_raw_cfg->clkgrp.mainpllgrp.raw.tracediv); + + // Main PLL L4 Source register + alt_write_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR, clk_group_raw_cfg->clkgrp.mainpllgrp.raw.l4src); + } + else if (clk_group == ALT_PERIPH_PLL_CLK_GRP) + { + // Peripheral PLL VCO register + alt_write_word(ALT_CLKMGR_PERPLL_VCO_ADDR, clk_group_raw_cfg->clkgrp.perpllgrp.raw.vco & + ALT_CLKMGR_PERPLL_VCO_OUTRST_CLR_MSK & ALT_CLKMGR_PERPLL_VCO_OUTRSTALL_CLR_MSK); + // the outreset and outresetall bits were probably clear when the + // state was saved, but make sure they're clear now + + // Peripheral PLL Misc register + alt_write_word(ALT_CLKMGR_PERPLL_MISC_ADDR, clk_group_raw_cfg->clkgrp.perpllgrp.raw.misc); + + // Peripheral PLL C0-C5 Counters + alt_write_word(ALT_CLKMGR_PERPLL_EMAC0CLK_ADDR, clk_group_raw_cfg->clkgrp.perpllgrp.raw.emac0clk); + alt_write_word(ALT_CLKMGR_PERPLL_EMAC1CLK_ADDR, clk_group_raw_cfg->clkgrp.perpllgrp.raw.emac1clk); + alt_write_word(ALT_CLKMGR_PERPLL_PERQSPICLK_ADDR, clk_group_raw_cfg->clkgrp.perpllgrp.raw.perqspiclk); + alt_write_word(ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_ADDR, clk_group_raw_cfg->clkgrp.perpllgrp.raw.pernandsdmmcclk); + alt_write_word(ALT_CLKMGR_PERPLL_PERBASECLK_ADDR, clk_group_raw_cfg->clkgrp.perpllgrp.raw.perbaseclk); + alt_write_word(ALT_CLKMGR_PERPLL_S2FUSER1CLK_ADDR, clk_group_raw_cfg->clkgrp.perpllgrp.raw.s2fuser1clk); + + // Peripheral PLL Counter Enable register + alt_write_word(ALT_CLKMGR_PERPLL_EN_ADDR, clk_group_raw_cfg->clkgrp.perpllgrp.raw.en); + + // Peripheral PLL Divider register + alt_write_word(ALT_CLKMGR_PERPLL_DIV_ADDR, clk_group_raw_cfg->clkgrp.perpllgrp.raw.div); + + // Peripheral PLL GPIO Divider register + alt_write_word(ALT_CLKMGR_PERPLL_GPIODIV_ADDR, clk_group_raw_cfg->clkgrp.perpllgrp.raw.gpiodiv); + + // Peripheral PLL Source register + alt_write_word(ALT_CLKMGR_PERPLL_SRC_ADDR, clk_group_raw_cfg->clkgrp.perpllgrp.raw.src); + } + else if (clk_group == ALT_SDRAM_PLL_CLK_GRP) + { + // SDRAM PLL VCO register + alt_write_word(ALT_CLKMGR_SDRPLL_VCO_ADDR, clk_group_raw_cfg->clkgrp.sdrpllgrp.raw.vco & + ALT_CLKMGR_SDRPLL_VCO_OUTRST_CLR_MSK & ALT_CLKMGR_SDRPLL_VCO_OUTRSTALL_CLR_MSK); + // the outreset and outresetall bits were probably clear when the + // state was saved, but make sure they're clear now + + // SDRAM PLL Control register + alt_write_word(ALT_CLKMGR_SDRPLL_CTL_ADDR, clk_group_raw_cfg->clkgrp.sdrpllgrp.raw.ctrl); + + // SDRAM PLL C0-C2 & C5 Counters + alt_write_word(ALT_CLKMGR_SDRPLL_DDRDQSCLK_ADDR, clk_group_raw_cfg->clkgrp.sdrpllgrp.raw.ddrdqsclk); + alt_write_word(ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_ADDR, clk_group_raw_cfg->clkgrp.sdrpllgrp.raw.ddr2xdqsclk); + alt_write_word(ALT_CLKMGR_SDRPLL_DDRDQCLK_ADDR, clk_group_raw_cfg->clkgrp.sdrpllgrp.raw.ddrdqclk); + alt_write_word(ALT_CLKMGR_SDRPLL_S2FUSER2CLK_ADDR, clk_group_raw_cfg->clkgrp.sdrpllgrp.raw.s2fuser2clk); + + // SDRAM PLL Counter Enable register + alt_write_word(ALT_CLKMGR_SDRPLL_EN_ADDR, clk_group_raw_cfg->clkgrp.sdrpllgrp.raw.en); + } + + // if PLL was not bypassed before, restore that state + if (byp) + { + status = alt_clk_pll_bypass_disable(pll); + } + + return status; +} + +// +// alt_clk_id_to_string() converts a clock ID to a text string. +// +ALT_STATUS_CODE alt_clk_id_to_string(ALT_CLK_t clk_id, char * output, size_t size) +{ + char * name = NULL; + + switch (clk_id) + { + case ALT_CLK_IN_PIN_OSC1: + name = "IN_PIN_OSC1"; + break; + case ALT_CLK_IN_PIN_OSC2: + name = "IN_PIN_OSC2"; + break; + + // FPGA Clock Sources External to HPS + case ALT_CLK_F2H_PERIPH_REF: + name = "F2H_PERIPH_REF"; + break; + case ALT_CLK_F2H_SDRAM_REF: + name = "F2H_SDRAM_REF"; + break; + + // Other Clock Sources External to HPS + case ALT_CLK_IN_PIN_JTAG: + name = "IN_PIN_JTAG"; + break; + case ALT_CLK_IN_PIN_ULPI0: + name = "IN_PIN_ULPI0"; + break; + case ALT_CLK_IN_PIN_ULPI1: + name = "IN_PIN_ULPI1"; + break; + case ALT_CLK_IN_PIN_EMAC0_RX: + name = "IN_PIN_EMAC0_RX"; + break; + case ALT_CLK_IN_PIN_EMAC1_RX: + name = "IN_PIN_EMAC1_RX"; + break; + + // PLLs + case ALT_CLK_MAIN_PLL: + name = "MAIN_PLL"; + break; + case ALT_CLK_PERIPHERAL_PLL: + name = "PERIPHERAL_PLL"; + break; + case ALT_CLK_SDRAM_PLL: + name = "SDRAM_PLL"; + break; + + // OSC1 Clock Group - The OSC1 clock group contains those clocks which are derived + // directly from the osc_clk_1_HPS pin + case ALT_CLK_OSC1: + name = "OSC1"; + break; + + // Main Clock Group - The following clocks are derived from the Main PLL. + case ALT_CLK_MAIN_PLL_C0: + name = "MAIN_PLL_C0"; + break; + case ALT_CLK_MAIN_PLL_C1: + name = "MAIN_PLL_C1"; + break; + case ALT_CLK_MAIN_PLL_C2: + name = "MAIN_PLL_C2"; + break; + case ALT_CLK_MAIN_PLL_C3: + name = "MAIN_PLL_C3"; + break; + case ALT_CLK_MAIN_PLL_C4: + name = "MAIN_PLL_C4"; + break; + case ALT_CLK_MAIN_PLL_C5: + name = "MAIN_PLL_C5"; + break; + case ALT_CLK_MPU: + name = "MPU"; + break; + case ALT_CLK_MPU_L2_RAM: + name = "MPU_L2_RAM"; + break; + case ALT_CLK_MPU_PERIPH: + name = "MPU_PERIPH"; + break; + case ALT_CLK_L3_MAIN: + name = "L3_MAIN"; + break; + case ALT_CLK_L3_MP: + name = "L3_MP"; + break; + case ALT_CLK_L3_SP: + name = "L3_SP"; + break; + case ALT_CLK_L4_MAIN: + name = "L4_MAIN"; + break; + case ALT_CLK_L4_MP: + name = "L4_MP"; + break; + case ALT_CLK_L4_SP: + name = "L4_SP"; + break; + case ALT_CLK_DBG_BASE: + name = "DBG_BASE"; + break; + case ALT_CLK_DBG_AT: + name = "DBG_AT"; + break; + case ALT_CLK_DBG_TRACE: + name = "DBG_TRACE"; + break; + case ALT_CLK_DBG_TIMER: + name = "DBG_TIMER"; + break; + case ALT_CLK_DBG: + name = "DBG"; + break; + case ALT_CLK_MAIN_QSPI: + name = "MAIN_QSPI"; + break; + case ALT_CLK_MAIN_NAND_SDMMC: + name = "MAIN_NAND_SDMMC"; + break; + case ALT_CLK_CFG: + name = "CFG"; + break; + case ALT_CLK_H2F_USER0: + name = "H2F_USER0"; + break; + + // Peripherals Clock Group - The following clocks are derived from the Peripheral PLL. + case ALT_CLK_PERIPHERAL_PLL_C0: + name = "PERIPHERAL_PLL_C0"; + break; + case ALT_CLK_PERIPHERAL_PLL_C1: + name = "PERIPHERAL_PLL_C1"; + break; + case ALT_CLK_PERIPHERAL_PLL_C2: + name = "PERIPHERAL_PLL_C2"; + break; + case ALT_CLK_PERIPHERAL_PLL_C3: + name = "PERIPHERAL_PLL_C3"; + break; + case ALT_CLK_PERIPHERAL_PLL_C4: + name = "PERIPHERAL_PLL_C4"; + break; + case ALT_CLK_PERIPHERAL_PLL_C5: + name = "PERIPHERAL_PLL_C5"; + break; + case ALT_CLK_USB_MP: + name = "USB_MP"; + break; + case ALT_CLK_SPI_M: + name = "SPI_M"; + break; + case ALT_CLK_QSPI: + name = "QSPI"; + break; + case ALT_CLK_NAND_X: + name = "NAND_X"; + break; + case ALT_CLK_NAND: + name = "NAND"; + break; + case ALT_CLK_SDMMC: + name = "SDMMC"; + break; + case ALT_CLK_EMAC0: + name = "EMAC0"; + break; + case ALT_CLK_EMAC1: + name = "EMAC1"; + break; + case ALT_CLK_CAN0: + name = "CAN0"; + break; + case ALT_CLK_CAN1: + name = "CAN1"; + break; + case ALT_CLK_GPIO_DB: + name = "GPIO_DB"; + break; + case ALT_CLK_H2F_USER1: + name = "H2F_USER1"; + break; + + // SDRAM Clock Group - The following clocks are derived from the SDRAM PLL. + case ALT_CLK_SDRAM_PLL_C0: + name = "SDRAM_PLL_C0"; + break; + case ALT_CLK_SDRAM_PLL_C1: + name = "SDRAM_PLL_C1"; + break; + case ALT_CLK_SDRAM_PLL_C2: + name = "SDRAM_PLL_C2"; + break; + case ALT_CLK_SDRAM_PLL_C3: + name = "SDRAM_PLL_C3"; + break; + case ALT_CLK_SDRAM_PLL_C4: + name = "SDRAM_PLL_C4"; + break; + case ALT_CLK_SDRAM_PLL_C5: + name = "SDRAM_PLL_C5"; + break; + case ALT_CLK_DDR_DQS: + name = "DDR_DQS"; + break; + case ALT_CLK_DDR_2X_DQS: + name = "DDR_2X_DQS"; + break; + case ALT_CLK_DDR_DQ: + name = "DDR_DQ"; + break; + case ALT_CLK_H2F_USER2: + name = "H2F_USER2"; + break; + + // Clock Output Pins + case ALT_CLK_OUT_PIN_EMAC0_TX: + name = "OUT_PIN_EMAC0_TX"; + break; + case ALT_CLK_OUT_PIN_EMAC1_TX: + name = "OUT_PIN_EMAC1_TX"; + break; + case ALT_CLK_OUT_PIN_SDMMC: + name = "OUT_PIN_SDMMC"; + break; + case ALT_CLK_OUT_PIN_I2C0_SCL: + name = "OUT_PIN_I2C0_SCL"; + break; + case ALT_CLK_OUT_PIN_I2C1_SCL: + name = "OUT_PIN_I2C1_SCL"; + break; + case ALT_CLK_OUT_PIN_I2C2_SCL: + name = "OUT_PIN_I2C2_SCL"; + break; + case ALT_CLK_OUT_PIN_I2C3_SCL: + name = "OUT_PIN_I2C3_SCL"; + break; + case ALT_CLK_OUT_PIN_SPIM0: + name = "OUT_PIN_SPIM0"; + break; + case ALT_CLK_OUT_PIN_SPIM1: + name = "OUT_PIN_SPIM1"; + break; + case ALT_CLK_OUT_PIN_QSPI: + name = "OUT_PIN_QSPI"; + break; + case ALT_CLK_UNKNOWN: + name = "UNKNOWN"; + break; + + // do *not* put a 'default' statement here. Then the compiler will throw + // an error if another clock id enum is added if the corresponding + // string is not added to this function. + } + + if (name != NULL) + { + snprintf(output, size, "ALT_CLK_%s", name); + return ALT_E_SUCCESS; + } + else + { + return ALT_E_BAD_ARG; + } +} + + +// +// alt_clk_pll_cntr_maxfreq_recalc() recalculate the maxmum frequency of the specified clock. +// +ALT_STATUS_CODE alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_t clk, ALT_PLL_CNTR_FREQMAX_t * maxfreq) +{ + ALT_STATUS_CODE ret = ALT_E_BAD_ARG; + alt_freq_t freq; + + ret = alt_clk_freq_get(clk, &freq); + + if (ret == ALT_E_SUCCESS) + { + + switch (clk) + { + // Main Clock Group + case ALT_CLK_MAIN_PLL_C0: + maxfreq->MainPLL_C0 = freq; + printf("alt_pll_cntr_maxfreq.MainPLL_C0 = %10d\n", (unsigned int)freq); + break; + case ALT_CLK_MAIN_PLL_C1: + maxfreq->MainPLL_C1 = freq; + printf("alt_pll_cntr_maxfreq.MainPLL_C1 = %10d\n", (unsigned int)freq); + break; + case ALT_CLK_MAIN_PLL_C2: + maxfreq->MainPLL_C2 = freq; + printf("alt_pll_cntr_maxfreq.MainPLL_C2 = %10d\n", (unsigned int)freq); + break; + case ALT_CLK_MAIN_PLL_C3: + maxfreq->MainPLL_C3 = freq; + printf("alt_pll_cntr_maxfreq.MainPLL_C3 = %10d\n", (unsigned int)freq); + break; + case ALT_CLK_MAIN_PLL_C4: + maxfreq->MainPLL_C4 = freq; + printf("alt_pll_cntr_maxfreq.MainPLL_C4 = %10d\n", (unsigned int)freq); + break; + case ALT_CLK_MAIN_PLL_C5: + maxfreq->MainPLL_C5 = freq; + printf("alt_pll_cntr_maxfreq.MainPLL_C5 = %10d\n", (unsigned int)freq); + break; + + // Peripheral Clock Group + case ALT_CLK_PERIPHERAL_PLL_C0: + maxfreq->PeriphPLL_C0 = freq; + printf("alt_pll_cntr_maxfreq.PeriphPLL_C0 = %10d\n", (unsigned int)freq); + break; + case ALT_CLK_PERIPHERAL_PLL_C1: + maxfreq->PeriphPLL_C1 = freq; + printf("alt_pll_cntr_maxfreq.PeriphPLL_C1 = %10d\n", (unsigned int)freq); + break; + case ALT_CLK_PERIPHERAL_PLL_C2: + maxfreq->PeriphPLL_C2 = freq; + printf("alt_pll_cntr_maxfreq.PeriphPLL_C2 = %10d\n", (unsigned int)freq); + break; + case ALT_CLK_PERIPHERAL_PLL_C3: + maxfreq->PeriphPLL_C3 = freq; + printf("alt_pll_cntr_maxfreq.PeriphPLL_C3 = %10d\n", (unsigned int)freq); + break; + case ALT_CLK_PERIPHERAL_PLL_C4: + maxfreq->PeriphPLL_C4 = freq; + printf("alt_pll_cntr_maxfreq.PeriphPLL_C4 = %10d\n", (unsigned int)freq); + break; + case ALT_CLK_PERIPHERAL_PLL_C5: + maxfreq->PeriphPLL_C5 = freq; + printf("alt_pll_cntr_maxfreq.PeriphPLL_C5 = %10d\n", (unsigned int)freq); + break; + + // SDRAM Clock Group + case ALT_CLK_SDRAM_PLL_C0: + maxfreq->SDRAMPLL_C0 = freq; + printf("alt_pll_cntr_maxfreq.SDRAMPLL_C0 = %10d\n", (unsigned int)freq); + break; + case ALT_CLK_SDRAM_PLL_C1: + maxfreq->SDRAMPLL_C1 = freq; + printf("alt_pll_cntr_maxfreq.SDRAMPLL_C1 = %10d\n", (unsigned int)freq); + break; + case ALT_CLK_SDRAM_PLL_C2: + maxfreq->SDRAMPLL_C2 = freq; + printf("alt_pll_cntr_maxfreq.SDRAMPLL_C2 = %10d\n", (unsigned int)freq); + break; + case ALT_CLK_SDRAM_PLL_C5: + maxfreq->SDRAMPLL_C5 = freq; + printf("alt_pll_cntr_maxfreq.SDRAMPLL_C5 = %10d\n", (unsigned int)freq); + break; + default: + ret = ALT_E_BAD_ARG; + printf("bad max frequency parameter\n"); + break; + } // end of switch-case construct + } + + return ret; +} + +// +// u-boot preloader actually initialize clock manager circuitry +// +// alt_clk_clkmgr_init() attempt to fix the pll counter max frequencies, since +// thses frequencies are not known in advance until u-boot programmed clock manager. +// +ALT_STATUS_CODE alt_clk_clkmgr_init(void) +{ + ALT_STATUS_CODE ret = ALT_E_SUCCESS; + ALT_STATUS_CODE status ; + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_MAIN_PLL_C0,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_MAIN_PLL_C1,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_MAIN_PLL_C2,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_MAIN_PLL_C3,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_MAIN_PLL_C4,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_MAIN_PLL_C5,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_PERIPHERAL_PLL_C0,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_PERIPHERAL_PLL_C1,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_PERIPHERAL_PLL_C2,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_PERIPHERAL_PLL_C3,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_PERIPHERAL_PLL_C4,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_PERIPHERAL_PLL_C5,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_SDRAM_PLL_C0,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_SDRAM_PLL_C1,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_SDRAM_PLL_C2,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + status = alt_clk_pll_cntr_maxfreq_recalc(ALT_CLK_SDRAM_PLL_C5,&alt_pll_cntr_maxfreq ); + if (status != ALT_E_SUCCESS) ret = ALT_E_ERROR; + + + return ret; +} + |