/****************************************************************************** * * 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 #include #include #include #include #include "socal/hps.h" #include "socal/socal.h" #include "socal/alt_sysmgr.h" #include "hwlib.h" #include "alt_clock_manager.h" #include "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; /* 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) /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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. */ /****************************************************************************************/ static void inline 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 cnt) { ALT_STATUS_CODE ret = ALT_E_ERROR; uint32_t temp; uint32_t mask = 0; if (pll == ALT_CLK_MAIN_PLL) { mask = ALT_CLKMGR_INTER_MAINPLLLOCKED_SET_MSK; } else if (pll == ALT_CLK_PERIPHERAL_PLL) { mask = ALT_CLKMGR_INTER_PERPLLLOCKED_SET_MSK; } else if (pll == ALT_CLK_SDRAM_PLL) { mask = ALT_CLKMGR_INTER_SDRPLLLOCKED_SET_MSK; } else { return ret; } do { temp = alt_read_word(ALT_CLKMGR_INTER_ADDR); } while (!(temp & mask) && --cnt); if (cnt > 0) { ret = ALT_E_SUCCESS; } return ret; } /* 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) { ALT_STATUS_CODE ret; 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)) { ret = ALT_E_BAD_ARG; } else { alt_setbits_word(ALT_CLKMGR_INTER_ADDR, lock_stat_mask); ret = ALT_E_SUCCESS; } return ret; } /****************************************************************************************/ /* 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 ret = ALT_E_BAD_ARG; if (pll == ALT_CLK_MAIN_PLL) { ret = (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) { ret = (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) { ret = (alt_read_word(ALT_CLKMGR_INTER_ADDR) & ALT_CLKMGR_INTER_SDRPLLLOCKED_SET_MSK) ? ALT_E_TRUE : ALT_E_FALSE; } return ret; } /****************************************************************************************/ /* 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 ret = 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 ret = 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 ret = alt_clk_plls_settle_wait(); #endif return ret; } /****************************************************************************************/ /* 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 ret = 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); ret = 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); ret = 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); ret = alt_clk_plls_settle_wait(); } } else { ret = ALT_E_ERROR; } return ret; } /****************************************************************************************/ /* 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 ret = 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 ret = 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 ret = alt_clk_plls_settle_wait(); #endif ret = ALT_E_SUCCESS; } else { ret = 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 ret = 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); ret = ALT_E_SUCCESS; } return ret; } /****************************************************************************************/ /* 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 ret = ALT_E_BAD_ARG; if (pll == ALT_CLK_MAIN_PLL) { ret = (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) { ret = (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) { ret = (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 ret; } /****************************************************************************************/ /* 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 ret = ALT_E_BAD_ARG; switch (clk) { /* For PLLs, put them in bypass mode */ case (ALT_CLK_MAIN_PLL): case (ALT_CLK_PERIPHERAL_PLL): case (ALT_CLK_SDRAM_PLL): ret = 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); ret = ALT_E_SUCCESS; break; case (ALT_CLK_L3_MP): alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_L3MPCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_L4_MP): alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_L4MPCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_L4_SP): alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_L4SPCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_DBG_AT): alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGATCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_DBG): alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_DBG_TRACE): alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGTRACECLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_DBG_TIMER): alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGTMRCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_CFG): alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_CFGCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_H2F_USER0): alt_clrbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_S2FUSER0CLK_SET_MSK); ret = ALT_E_SUCCESS; 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); ret = ALT_E_SUCCESS; break; case (ALT_CLK_EMAC1): alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_EMAC1CLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_USB_MP): alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_USBCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_SPI_M): alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_SPIMCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_CAN0): alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_CAN0CLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_CAN1): alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_CAN1CLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_GPIO_DB): alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_GPIOCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_H2F_USER1): alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_S2FUSER1CLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_SDMMC): alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_SDMMCCLK_SET_MSK); ret = ALT_E_SUCCESS; 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); ret = ALT_E_SUCCESS; break; case (ALT_CLK_NAND): alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_NANDCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_QSPI): alt_clrbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_QSPICLK_SET_MSK); ret = ALT_E_SUCCESS; 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); ret = ALT_E_SUCCESS; break; case (ALT_CLK_DDR_2X_DQS): alt_clrbits_word(ALT_CLKMGR_SDRPLL_EN_ADDR, ALT_CLKMGR_SDRPLL_EN_DDR2XDQSCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_DDR_DQ): alt_clrbits_word(ALT_CLKMGR_SDRPLL_EN_ADDR, ALT_CLKMGR_SDRPLL_EN_DDRDQCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_H2F_USER2): alt_clrbits_word(ALT_CLKMGR_SDRPLL_EN_ADDR, ALT_CLKMGR_SDRPLL_EN_S2FUSER2CLK_SET_MSK); ret = ALT_E_SUCCESS; break; default: break; } return ret; } /****************************************************************************************/ /* 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 ret = ALT_E_BAD_ARG; 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): ret = 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); ret = ALT_E_SUCCESS; break; case (ALT_CLK_L3_MP): alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_L3MPCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_L4_MP): alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_L4MPCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_L4_SP): alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_L4SPCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_DBG_AT): alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGATCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_DBG): alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_DBG_TRACE): alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGTRACECLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_DBG_TIMER): alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_DBGTMRCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_CFG): alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_CFGCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_H2F_USER0): alt_setbits_word(ALT_CLKMGR_MAINPLL_EN_ADDR, ALT_CLKMGR_MAINPLL_EN_S2FUSER0CLK_SET_MSK); ret = ALT_E_SUCCESS; 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); ret = ALT_E_SUCCESS; break; case (ALT_CLK_EMAC1): alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_EMAC1CLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_USB_MP): alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_USBCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_SPI_M): alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_SPIMCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_CAN0): alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_CAN0CLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_CAN1): alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_CAN1CLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_GPIO_DB): alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_GPIOCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_H2F_USER1): alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_S2FUSER1CLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_SDMMC): alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_SDMMCCLK_SET_MSK); ret = ALT_E_SUCCESS; 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); ret = ALT_E_SUCCESS; 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); ret = ALT_E_SUCCESS; break; case (ALT_CLK_QSPI): alt_setbits_word(ALT_CLKMGR_PERPLL_EN_ADDR, ALT_CLKMGR_PERPLL_EN_QSPICLK_SET_MSK); ret = ALT_E_SUCCESS; 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); ret = ALT_E_SUCCESS; break; case (ALT_CLK_DDR_2X_DQS): alt_setbits_word(ALT_CLKMGR_SDRPLL_EN_ADDR, ALT_CLKMGR_SDRPLL_EN_DDR2XDQSCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_DDR_DQ): alt_setbits_word(ALT_CLKMGR_SDRPLL_EN_ADDR, ALT_CLKMGR_SDRPLL_EN_DDRDQCLK_SET_MSK); ret = ALT_E_SUCCESS; break; case (ALT_CLK_H2F_USER2): alt_setbits_word(ALT_CLKMGR_SDRPLL_EN_ADDR, ALT_CLKMGR_SDRPLL_EN_S2FUSER2CLK_SET_MSK); ret = ALT_E_SUCCESS; break; default: break; } return ret; } /****************************************************************************************/ /* 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 ret = ALT_E_BAD_ARG; switch (clk) // this should be more than enough cases to cause { // the compiler to use a jump table implementation /* 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): ret = (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): ret = ALT_E_BAD_ARG; break; /* Clocks that originate at the Main PLL */ case (ALT_CLK_L4_MAIN): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (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): ret = (ALT_CLKMGR_SDRPLL_EN_S2FUSER2CLK_GET(alt_read_word(ALT_CLKMGR_SDRPLL_EN_ADDR))) ? ALT_E_TRUE : ALT_E_FALSE; break; default: break; } return ret; } /****************************************************************************************/ /* 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 */ 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; // these clock entities are their own source /* 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: break; } /* end big switch/case construct */ 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 ret = ALT_E_BAD_ARG; 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 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); ret = ALT_E_SUCCESS; } 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); ret = ALT_E_SUCCESS; } 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); ret = ALT_E_SUCCESS; } else { ret = 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); ret = ALT_E_SUCCESS; } 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); ret = ALT_E_SUCCESS; } 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); ret = ALT_E_SUCCESS; } else { ret = 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); ret = ALT_E_SUCCESS; } else if (ref_clk == ALT_CLK_PERIPHERAL_PLL_C4) { alt_setbits_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR, ALT_CLKMGR_MAINPLL_L4SRC_L4MP_SET_MSK); ret = ALT_E_SUCCESS; } else { ret = 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); ret = ALT_E_SUCCESS; } else if (ref_clk == ALT_CLK_PERIPHERAL_PLL_C4) { alt_setbits_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR, ALT_CLKMGR_MAINPLL_L4SRC_L4SP_SET_MSK); ret = ALT_E_SUCCESS; } else { ret = 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); ret = ALT_E_SUCCESS; } 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); ret = ALT_E_SUCCESS; } 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); ret = ALT_E_SUCCESS; } else { ret = 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); ret = ALT_E_SUCCESS; } 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); ret = ALT_E_SUCCESS; } 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); ret = ALT_E_SUCCESS; } else { ret = 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); ret = ALT_E_SUCCESS; } 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); ret = ALT_E_SUCCESS; } 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); ret = ALT_E_SUCCESS; } else { ret = ALT_E_INV_OPTION; } } return ret; } /****************************************************************************************/ /* 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 ret = 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; ret = ALT_E_SUCCESS; } else { ret = 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; ret = ALT_E_SUCCESS; } else { ret = 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; ret = ALT_E_SUCCESS; } else { ret = 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; ret = ALT_E_SUCCESS; } else { ret = ALT_E_ARG_RANGE; } } return ret; } /****************************************************************************************/ /* 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) { 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_MAINPLL_MPUCLK_ADDR)); // C0 - mpu_clk pll_cfg->cntrs[1] = ALT_CLKMGR_MAINPLL_MAINCLK_CNT_GET(alt_read_word(ALT_CLKMGR_MAINPLL_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) { ALT_STATUS_CODE ret = ALT_E_ERROR; uint32_t temp; if (pll_cfg != NULL) { if (alt_clk_pll_is_bypassed(pll) == ALT_E_TRUE) // safe to write the PLL registers? { 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_MAINPLL_MPUCLK_ADDR, pll_cfg->cntrs[0]); alt_write_word(ALT_CLKMGR_MAINPLL_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 ret = ALT_E_ERROR; uint32_t temp; if ((mult != NULL) && (div != NULL)) { 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; ret = ALT_E_SUCCESS; } 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; ret = ALT_E_SUCCESS; } 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; ret = ALT_E_SUCCESS; } } return ret; } /****************************************************************************************/ /* 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; #endif 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; if ((mult > 0) && (mult <= ALT_CLK_PLL_MULT_MAX) && (div > 0) && (div <= ALT_CLK_PLL_DIV_MAX)) // check PLL max value limits { // 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); temp = ALT_CLKMGR_PERPLL_VCO_PSRC_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; 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); temp = ALT_CLKMGR_SDRPLL_VCO_SSRC_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; 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; } /****************************************************************************************/ /* 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) { 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) { int32_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) { ALT_STATUS_CODE ret = ALT_E_ERROR; if ((guard_band <= UINT12_MAX) && (guard_band > 0) && (guard_band <= ALT_GUARDBAND_LIMIT)) { 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 ret = ALT_E_SUCCESS; } 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; ret = ALT_E_SUCCESS; } 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; ret = ALT_E_SUCCESS; } } else { ret = ALT_E_ARG_RANGE; } return ret; } /****************************************************************************************/ /* 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 ret = ALT_E_BAD_ARG; uint32_t temp; if (div != NULL) { 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) << 1; // adjust for the additional divide-by-2 internal counter on C0 ret = ALT_E_SUCCESS; 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) << 2; // adjust for the additional divide-by-4 internal counter on C1 ret = ALT_E_SUCCESS; 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) << 2; // adjust for the additional divide-by-4 internal counter on C2 ret = ALT_E_SUCCESS; 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; ret = ALT_E_SUCCESS; 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; ret = ALT_E_SUCCESS; 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; ret = ALT_E_SUCCESS; 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; ret = ALT_E_SUCCESS; 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; ret = ALT_E_SUCCESS; break; case ALT_CLK_PERIPHERAL_PLL_C2: *div = (ALT_CLKMGR_PERPLL_PERQSPICLK_CNT_GET(alt_read_word(ALT_CLKMGR_PERPLL_PERQSPICLK_ADDR))) + 1; ret = ALT_E_SUCCESS; break; case ALT_CLK_PERIPHERAL_PLL_C3: *div = (ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_CNT_GET(alt_read_word(ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_ADDR))) + 1; ret = ALT_E_SUCCESS; break; case ALT_CLK_PERIPHERAL_PLL_C4: *div = (ALT_CLKMGR_PERPLL_PERBASECLK_CNT_GET(alt_read_word(ALT_CLKMGR_PERPLL_PERBASECLK_ADDR))) + 1; ret = ALT_E_SUCCESS; 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; ret = ALT_E_SUCCESS; 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; ret = ALT_E_SUCCESS; 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; ret = ALT_E_SUCCESS; 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; ret = ALT_E_SUCCESS; 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; ret = ALT_E_SUCCESS; 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; ret = ALT_E_SUCCESS; } 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; ret = ALT_E_SUCCESS; } // 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; ret = ALT_E_SUCCESS; } 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; ret = ALT_E_SUCCESS; } 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; ret = ALT_E_SUCCESS; } 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; ret = ALT_E_SUCCESS; } // 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; ret = ALT_E_SUCCESS; } 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; ret = ALT_E_SUCCESS; } 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; ret = ALT_E_SUCCESS; } 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; ret = ALT_E_SUCCESS; } 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; ret = ALT_E_SUCCESS; } break; case ALT_CLK_GPIO_DB: temp = ALT_CLKMGR_PERPLL_GPIODIV_GPIODBCLK_GET(alt_read_word(ALT_CLKMGR_PERPLL_GPIODIV_ADDR)); *div = temp + 1; ret = ALT_E_SUCCESS; break; case ALT_CLK_MPU_PERIPH: *div = 4; // set by hardware ret = ALT_E_SUCCESS; break; case ALT_CLK_MPU_L2_RAM: *div = 2; // set by hardware ret = ALT_E_SUCCESS; break; case ALT_CLK_NAND: *div = 4; // set by hardware ret = ALT_E_SUCCESS; break; default: break; } } return ret; } /****************************************************************************************/ /****************************************************************************************/ #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) { ALT_STATUS_CODE ret = ALT_E_BAD_ARG; uint32_t numer; uint32_t hilimit; uint32_t lolimit; #if ALT_CLK_WITHIN_FREQ_LIMITS_TEST_MODE return ALT_E_TRUE; #endif if (div != 0) { if (!ALT_CLK_WITHIN_FREQ_LIMITS_TEST_MODE) { // Normal mode - do the frequency check /* Counters of the Main PLL */ if (clk == ALT_CLK_MAIN_PLL_C0) { hilimit = alt_pll_cntr_maxfreq.MainPLL_C0; lolimit = alt_ext_clk_paramblok.clkosc1.freqcur; ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &numer); } else if (clk == ALT_CLK_MAIN_PLL_C1) { hilimit = alt_pll_cntr_maxfreq.MainPLL_C1; lolimit = alt_ext_clk_paramblok.clkosc1.freqcur; ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &numer); } else if (clk == ALT_CLK_MAIN_PLL_C2) { hilimit = alt_pll_cntr_maxfreq.MainPLL_C2; lolimit = alt_ext_clk_paramblok.clkosc1.freqcur; ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &numer); } else if (clk == ALT_CLK_MAIN_PLL_C3) { hilimit = alt_pll_cntr_maxfreq.MainPLL_C3; lolimit = 0; ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &numer); } else if (clk == ALT_CLK_MAIN_PLL_C4) { hilimit = alt_pll_cntr_maxfreq.MainPLL_C4; lolimit = alt_ext_clk_paramblok.clkosc1.freqcur; ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &numer); } else if (clk == ALT_CLK_MAIN_PLL_C5) { hilimit = alt_pll_cntr_maxfreq.MainPLL_C5; lolimit = alt_ext_clk_paramblok.clkosc1.freqcur; ret = alt_clk_pll_vco_freq_get(ALT_CLK_MAIN_PLL, &numer); } /* Counters of the Peripheral PLL */ else if (clk == ALT_CLK_PERIPHERAL_PLL_C0) { hilimit = alt_pll_cntr_maxfreq.PeriphPLL_C0; lolimit = 0; ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &numer); } else if (clk == ALT_CLK_PERIPHERAL_PLL_C1) { hilimit = alt_pll_cntr_maxfreq.PeriphPLL_C1; lolimit = 0; ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &numer); } else if (clk == ALT_CLK_PERIPHERAL_PLL_C2) { hilimit = alt_pll_cntr_maxfreq.PeriphPLL_C2; lolimit = 0; ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &numer); } else if (clk == ALT_CLK_PERIPHERAL_PLL_C3) { hilimit = alt_pll_cntr_maxfreq.PeriphPLL_C3; lolimit = 0; ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &numer); } else if (clk == ALT_CLK_PERIPHERAL_PLL_C4) { hilimit = alt_pll_cntr_maxfreq.PeriphPLL_C4; lolimit = 0; ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &numer); } else if (clk == ALT_CLK_PERIPHERAL_PLL_C5) { hilimit = alt_pll_cntr_maxfreq.PeriphPLL_C5; lolimit = alt_ext_clk_paramblok.clkosc1.freqcur; ret = alt_clk_pll_vco_freq_get(ALT_CLK_PERIPHERAL_PLL, &numer); } /* Counters of the SDRAM PLL */ else if (clk == ALT_CLK_SDRAM_PLL_C0) { hilimit = alt_pll_cntr_maxfreq.SDRAMPLL_C0; lolimit = 0; ret = alt_clk_pll_vco_freq_get(ALT_CLK_SDRAM_PLL, &numer); } else if (clk == ALT_CLK_SDRAM_PLL_C1) { hilimit = alt_pll_cntr_maxfreq.SDRAMPLL_C1; lolimit = 0; ret = alt_clk_pll_vco_freq_get(ALT_CLK_SDRAM_PLL, &numer); } else if (clk == ALT_CLK_SDRAM_PLL_C2) { hilimit = alt_pll_cntr_maxfreq.SDRAMPLL_C2; lolimit = 0; ret = alt_clk_pll_vco_freq_get(ALT_CLK_SDRAM_PLL, &numer); } else if (clk == ALT_CLK_SDRAM_PLL_C5) { hilimit = alt_pll_cntr_maxfreq.SDRAMPLL_C5; lolimit = alt_ext_clk_paramblok.clkosc1.freqcur; ret = alt_clk_pll_vco_freq_get(ALT_CLK_SDRAM_PLL, &numer); } else { return ret; } numer = numer / div; if ((numer <= hilimit) && (numer >= lolimit)) { ret = ALT_E_TRUE; } else { ret = ALT_E_FALSE; } } } return ret; } /****************************************************************************************/ /* 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: if ((div <= ((ALT_CLKMGR_MAINPLL_MPUCLK_CNT_SET_MSK << 1) + 1)) && (alt_clk_within_freq_limits(ALT_CLK_MAIN_PLL_C0, div) == ALT_E_TRUE)) { wrval = (div >> 1) + 1; // adjust for the automatic divide-by-two internal counter on C0 // 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. // The counter does have to be reset though, using a request-and-ack method. alt_clk_pllcounter_write( ALT_CLKMGR_MAINPLL_VCO_ADDR, ALT_CLKMGR_MAINPLL_STAT_ADDR, ALT_CLKMGR_MAINPLL_MPUCLK_ADDR, wrval, ALT_CLK_PLL_RST_BIT_C0, ALT_CLKMGR_MAINPLL_VCO_OUTRST_LSB); ret = ALT_E_SUCCESS; } else { ret = ALT_E_ARG_RANGE; } break; case ALT_CLK_MAIN_PLL_C1: case ALT_CLK_L3_MAIN: if ((div <= ((ALT_CLKMGR_MAINPLL_MAINCLK_CNT_SET_MSK << 2) + 1)) && (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 >> 2) + 1; // adjust for the automatic divide-by-four internal counter on C1 #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); } // The counter does have to be reset though, using a request-and-ack method. alt_clk_pllcounter_write( ALT_CLKMGR_MAINPLL_VCO_ADDR, ALT_CLKMGR_MAINPLL_STAT_ADDR, ALT_CLKMGR_MAINPLL_MAINCLK_ADDR, wrval, ALT_CLK_PLL_RST_BIT_C1, ALT_CLKMGR_MAINPLL_VCO_OUTRST_LSB); 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 // The counter does have to be reset though, using a request-and-ack method. alt_clk_pllcounter_write( ALT_CLKMGR_MAINPLL_VCO_ADDR, ALT_CLKMGR_MAINPLL_STAT_ADDR, ALT_CLKMGR_MAINPLL_MAINCLK_ADDR, div >> 2, // adjust for the automatic divide-by-four internal counter on C1 ALT_CLK_PLL_RST_BIT_C1, ALT_CLKMGR_MAINPLL_VCO_OUTRST_LSB); #endif ret = ALT_E_SUCCESS; } else { ret = ALT_E_ARG_RANGE; } break; case ALT_CLK_MAIN_PLL_C2: case ALT_CLK_DBG_BASE: if ((div <= ((ALT_CLKMGR_MAINPLL_DBGATCLK_CNT_SET_MSK << 2) + 1)) && (alt_clk_within_freq_limits(ALT_CLK_MAIN_PLL_C2, div) == ALT_E_TRUE)) { wrval = (div >> 2) + 1; // adjust for the automatic divide-by-four internal counter on C2 // 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. // The counter does have to be reset though, using a request-and-ack method. alt_clk_pllcounter_write( ALT_CLKMGR_MAINPLL_VCO_ADDR, ALT_CLKMGR_MAINPLL_STAT_ADDR, ALT_CLKMGR_MAINPLL_DBGATCLK_ADDR, wrval, ALT_CLK_PLL_RST_BIT_C2, ALT_CLKMGR_MAINPLL_VCO_OUTRST_LSB); 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 (ALT_CLKMGR_PERPLL_SRC_QSPI_GET(alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR)) == ALT_CLKMGR_PERPLL_SRC_QSPI_E_MAIN_QSPI_CLK) // if the main_qspi_clk input is selected for the qspi_clk { restore_0 = alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR) & ALT_CLKMGR_PERPLL_EN_QSPICLK_SET_MSK; if (restore_0) // AND if the QSPI clock is 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; 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 'em 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 <= (ALT_CLKMGR_MAINPLL_MAINDIV_L3SPCLK_E_DIV2 + 1)) { if (div == 1) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L3SPCLK_E_DIV1; } else if (div == 2) { wrval = ALT_CLKMGR_MAINPLL_MAINDIV_L3SPCLK_E_DIV2; } 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; } else { ret = ALT_E_ARG_RANGE; break; } 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; 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 } } else { ret = ALT_E_ARG_RANGE; } ret = ALT_E_SUCCESS; } 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: break; } // end of switch-case construct return ret; } // end of alt_clk_divider_set() - Hallelujah ! /****************************************************************************************/ /* 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; uint64_t numer = 0; uint64_t denom = 1; if (freq != NULL) { 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_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_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; } } 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; } } 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; } } 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: 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) { ALT_STATUS_CODE ret = ALT_E_BAD_ARG; if (!(lock_stat_mask & ALT_CLK_MGR_PLL_LOCK_BITS)) { alt_clrbits_word(ALT_CLKMGR_INTREN_ADDR, lock_stat_mask); ret = ALT_E_SUCCESS; } return ret; } /****************************************************************************************/ /* 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) { ALT_STATUS_CODE ret = ALT_E_BAD_ARG; if (!(lock_stat_mask & ALT_CLK_MGR_PLL_LOCK_BITS)) { alt_setbits_word(ALT_CLKMGR_INTREN_ADDR, lock_stat_mask); ret = ALT_E_SUCCESS; } return ret; } /****************************************************************************************/ /* 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) { ALT_STATUS_CODE ret = ALT_E_BAD_ARG; uint32_t *tmp; if (clk_group_raw_cfg != NULL) { alt_write_word(&clk_group_raw_cfg->verid, alt_read_word(ALT_SYSMGR_SILICONID1_ADDR)); alt_write_word(&clk_group_raw_cfg->siliid2, alt_read_word(ALT_SYSMGR_SILICONID2_ADDR)); alt_indwrite_word(&clk_group_raw_cfg->clkgrpsel, tmp, clk_group); if (clk_group == ALT_MAIN_PLL_CLK_GRP) { /* Main PLL VCO register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.mainpllgrp.vco, uint32_t); // compile-time macro that alt_indwrite_word(&clk_group_raw_cfg->clkgrp.mainpllgrp.vco, tmp, alt_read_word(ALT_CLKMGR_MAINPLL_VCO_ADDR)); /* Main PLL Misc register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.mainpllgrp.misc, uint32_t); // disappears if size is OK alt_indwrite_word(&clk_group_raw_cfg->clkgrp.mainpllgrp.misc, tmp, alt_read_word(ALT_CLKMGR_MAINPLL_MISC_ADDR)); /* Main PLL C0-C5 Counter registers */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.mainpllgrp.mpuclk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.mainpllgrp.mpuclk, tmp, alt_read_word(ALT_CLKMGR_MAINPLL_MPUCLK_ADDR)); // doing these as 32-bit reads and writes avoids unnecessary masking operations alt_check_struct_size(clk_group_raw_cfg->clkgrp.mainpllgrp.mainclk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.mainpllgrp.mainclk, tmp, alt_read_word(ALT_CLKMGR_MAINPLL_MAINCLK_ADDR)); alt_check_struct_size(clk_group_raw_cfg->clkgrp.mainpllgrp.dbgatclk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.mainpllgrp.dbgatclk, tmp, alt_read_word(ALT_CLKMGR_MAINPLL_DBGATCLK_ADDR)); alt_check_struct_size(clk_group_raw_cfg->clkgrp.mainpllgrp.mainqspiclk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.mainpllgrp.mainqspiclk, tmp, alt_read_word(ALT_CLKMGR_MAINPLL_MAINQSPICLK_ADDR)); alt_check_struct_size(clk_group_raw_cfg->clkgrp.mainpllgrp.mainnandsdmmcclk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.mainpllgrp.mainnandsdmmcclk, tmp, alt_read_word(ALT_CLKMGR_MAINPLL_MAINNANDSDMMCCLK_ADDR)); alt_check_struct_size(clk_group_raw_cfg->clkgrp.mainpllgrp.cfgs2fuser0clk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.mainpllgrp.cfgs2fuser0clk, tmp, alt_read_word(ALT_CLKMGR_MAINPLL_CFGS2FUSER0CLK_ADDR)); /* Main PLL Enable register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.mainpllgrp.en, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.mainpllgrp.en, tmp, alt_read_word(ALT_CLKMGR_MAINPLL_EN_ADDR)); /* Main PLL Maindiv register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.mainpllgrp.maindiv, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.mainpllgrp.maindiv, tmp, alt_read_word(ALT_CLKMGR_MAINPLL_MAINDIV_ADDR)); /* Main PLL Debugdiv register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.mainpllgrp.dbgdiv, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.mainpllgrp.dbgdiv, tmp, alt_read_word(ALT_CLKMGR_MAINPLL_DBGDIV_ADDR)); /* Main PLL Tracediv register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.mainpllgrp.tracediv, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.mainpllgrp.tracediv, tmp, alt_read_word(ALT_CLKMGR_MAINPLL_TRACEDIV_ADDR)); /* Main PLL L4 Source register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.mainpllgrp.l4src, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.mainpllgrp.l4src, tmp, alt_read_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR)); /* Main PLL Status register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.mainpllgrp.stat, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.mainpllgrp.stat, tmp, 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._pad_0x38_0x40[0] = 0; clk_group_raw_cfg->clkgrp.mainpllgrp._pad_0x38_0x40[1] = 0; ret = ALT_E_SUCCESS; } else if (clk_group == ALT_PERIPH_PLL_CLK_GRP) { /* Peripheral PLL VCO register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.perpllgrp.vco, uint32_t); // compile-time macro alt_indwrite_word(&clk_group_raw_cfg->clkgrp.perpllgrp.vco, tmp, alt_read_word(ALT_CLKMGR_PERPLL_VCO_ADDR)); /* Peripheral PLL Misc register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.perpllgrp.misc, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.perpllgrp.misc, tmp, alt_read_word(ALT_CLKMGR_PERPLL_MISC_ADDR)); /* Peripheral PLL C0-C5 Counters */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.perpllgrp.emac0clk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.perpllgrp.emac0clk, tmp, alt_read_word(ALT_CLKMGR_PERPLL_EMAC0CLK_ADDR)); // doing these as 32-bit reads and writes avoids unnecessary masking operations alt_check_struct_size(clk_group_raw_cfg->clkgrp.perpllgrp.emac1clk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.perpllgrp.emac1clk, tmp, alt_read_word(ALT_CLKMGR_PERPLL_EMAC1CLK_ADDR)); alt_check_struct_size(clk_group_raw_cfg->clkgrp.perpllgrp.perqspiclk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.perpllgrp.perqspiclk, tmp, alt_read_word(ALT_CLKMGR_PERPLL_PERQSPICLK_ADDR)); alt_check_struct_size(clk_group_raw_cfg->clkgrp.perpllgrp.pernandsdmmcclk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.perpllgrp.pernandsdmmcclk, tmp, alt_read_word(ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_ADDR)); alt_check_struct_size(clk_group_raw_cfg->clkgrp.perpllgrp.perbaseclk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.perpllgrp.perbaseclk, tmp, alt_read_word(ALT_CLKMGR_PERPLL_PERBASECLK_ADDR)); alt_check_struct_size(clk_group_raw_cfg->clkgrp.perpllgrp.s2fuser1clk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.perpllgrp.s2fuser1clk, tmp, alt_read_word(ALT_CLKMGR_PERPLL_S2FUSER1CLK_ADDR)); /* Peripheral PLL Enable register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.perpllgrp.en, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.perpllgrp.en, tmp, alt_read_word(ALT_CLKMGR_PERPLL_EN_ADDR)); /* Peripheral PLL Divider register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.perpllgrp.div, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.perpllgrp.div, tmp, alt_read_word(ALT_CLKMGR_PERPLL_DIV_ADDR)); /* Peripheral PLL GPIO Divider register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.perpllgrp.gpiodiv, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.perpllgrp.gpiodiv, tmp, alt_read_word(ALT_CLKMGR_PERPLL_GPIODIV_ADDR)); /* Peripheral PLL Source register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.perpllgrp.src, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.perpllgrp.src, tmp, alt_read_word(ALT_CLKMGR_PERPLL_SRC_ADDR)); /* Peripheral PLL Status register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.perpllgrp.stat, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.perpllgrp.stat, tmp, alt_read_word(ALT_CLKMGR_PERPLL_STAT_ADDR)); /* padding....... */ clk_group_raw_cfg->clkgrp.perpllgrp._pad_0x34_0x40[0] = 0; clk_group_raw_cfg->clkgrp.perpllgrp._pad_0x34_0x40[1] = 0; clk_group_raw_cfg->clkgrp.perpllgrp._pad_0x34_0x40[2] = 0; ret = ALT_E_SUCCESS; } else if (clk_group == ALT_SDRAM_PLL_CLK_GRP) { /* SDRAM PLL VCO register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.sdrpllgrp.vco, uint32_t); // compile-time macro alt_indwrite_word(&clk_group_raw_cfg->clkgrp.sdrpllgrp.vco, tmp, alt_read_word(ALT_CLKMGR_SDRPLL_VCO_ADDR)); /* SDRAM PLL Control register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.sdrpllgrp.ctrl, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.sdrpllgrp.ctrl, tmp, alt_read_word(ALT_CLKMGR_SDRPLL_CTL_ADDR)); /* SDRAM PLL C0-C2 & C5 Counters */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.sdrpllgrp.ddrdqsclk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.sdrpllgrp.ddrdqsclk, tmp, alt_read_word(ALT_CLKMGR_SDRPLL_DDRDQSCLK_ADDR)); // doing these as 32-bit reads and writes avoids unnecessary masking operations alt_check_struct_size(clk_group_raw_cfg->clkgrp.sdrpllgrp.ddr2xdqsclk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.sdrpllgrp.ddr2xdqsclk, tmp, alt_read_word(ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_ADDR)); alt_check_struct_size(clk_group_raw_cfg->clkgrp.sdrpllgrp.ddrdqclk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.sdrpllgrp.ddrdqclk, tmp, alt_read_word(ALT_CLKMGR_SDRPLL_DDRDQCLK_ADDR)); alt_check_struct_size(clk_group_raw_cfg->clkgrp.sdrpllgrp.s2fuser2clk, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.sdrpllgrp.s2fuser2clk, tmp, alt_read_word(ALT_CLKMGR_SDRPLL_S2FUSER2CLK_ADDR)); /* SDRAM PLL Enable register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.sdrpllgrp.en, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.sdrpllgrp.en, tmp, alt_read_word(ALT_CLKMGR_SDRPLL_EN_ADDR)); /* SDRAM PLL Status register */ alt_check_struct_size(clk_group_raw_cfg->clkgrp.sdrpllgrp.stat, uint32_t); alt_indwrite_word(&clk_group_raw_cfg->clkgrp.sdrpllgrp.stat, tmp, alt_read_word(ALT_CLKMGR_SDRPLL_STAT_ADDR)); ret = ALT_E_SUCCESS; } } return ret; } /****************************************************************************************/ /* 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) { ALT_STATUS_CODE ret = ALT_E_ERROR; ALT_CLK_GRP_t clk_group; ALT_CLK_t pll = ALT_CLK_UNKNOWN; bool byp = false; uint32_t *tmp; if (clk_group_raw_cfg != NULL) { // 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)) { // get the PLL ID clk_group = clk_group_raw_cfg->clkgrpsel; 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 ret; } if (pll == ALT_CLK_UNKNOWN) { return ret; } // if the PLL isn't in bypass mode, put it in bypass mode ret = alt_clk_pll_is_bypassed(pll); if (ret == ALT_E_FALSE) { ret = alt_clk_pll_bypass_enable(pll, false); 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 */ tmp = (uint32_t *) &clk_group_raw_cfg->clkgrp.mainpllgrp.vco; alt_write_word(ALT_CLKMGR_MAINPLL_VCO_ADDR, *tmp & (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_indread_word(ALT_CLKMGR_MAINPLL_MISC_ADDR, tmp, &clk_group_raw_cfg->clkgrp.mainpllgrp.misc); /* Main PLL C0-C5 Counter registers */ alt_indread_word(ALT_CLKMGR_MAINPLL_MPUCLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.mainpllgrp.mpuclk); alt_indread_word(ALT_CLKMGR_MAINPLL_MAINCLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.mainpllgrp.mainclk); alt_indread_word(ALT_CLKMGR_MAINPLL_DBGATCLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.mainpllgrp.dbgatclk); alt_indread_word(ALT_CLKMGR_MAINPLL_MAINQSPICLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.mainpllgrp.mainqspiclk); alt_indread_word(ALT_CLKMGR_MAINPLL_MAINNANDSDMMCCLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.mainpllgrp.mainnandsdmmcclk); alt_indread_word(ALT_CLKMGR_MAINPLL_CFGS2FUSER0CLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.mainpllgrp.cfgs2fuser0clk); /* Main PLL Counter Enable register */ alt_indread_word(ALT_CLKMGR_MAINPLL_EN_ADDR, tmp, &clk_group_raw_cfg->clkgrp.mainpllgrp.en); /* Main PLL Maindiv register */ alt_indread_word(ALT_CLKMGR_MAINPLL_MAINDIV_ADDR, tmp, &clk_group_raw_cfg->clkgrp.mainpllgrp.maindiv); /* Main PLL Debugdiv register */ alt_indread_word(ALT_CLKMGR_MAINPLL_DBGDIV_ADDR, tmp, &clk_group_raw_cfg->clkgrp.mainpllgrp.dbgdiv); /* Main PLL Tracediv register */ alt_indread_word(ALT_CLKMGR_MAINPLL_TRACEDIV_ADDR, tmp, &clk_group_raw_cfg->clkgrp.mainpllgrp.tracediv); /* Main PLL L4 Source register */ alt_indread_word(ALT_CLKMGR_MAINPLL_L4SRC_ADDR, tmp, &clk_group_raw_cfg->clkgrp.mainpllgrp.l4src); // remove bypass ret = ALT_E_SUCCESS; } else if (clk_group == ALT_PERIPH_PLL_CLK_GRP) { /* Peripheral PLL VCO register */ tmp = (uint32_t *) &clk_group_raw_cfg->clkgrp.perpllgrp.vco; alt_write_word(ALT_CLKMGR_PERPLL_VCO_ADDR, *tmp & (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_indread_word(ALT_CLKMGR_PERPLL_MISC_ADDR, tmp, &clk_group_raw_cfg->clkgrp.perpllgrp.misc); /* Peripheral PLL C0-C5 Counters */ alt_indread_word(ALT_CLKMGR_PERPLL_EMAC0CLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.perpllgrp.emac0clk); alt_indread_word(ALT_CLKMGR_PERPLL_EMAC1CLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.perpllgrp.emac1clk); alt_indread_word(ALT_CLKMGR_PERPLL_PERQSPICLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.perpllgrp.perqspiclk); alt_indread_word(ALT_CLKMGR_PERPLL_PERNANDSDMMCCLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.perpllgrp.pernandsdmmcclk); alt_indread_word(ALT_CLKMGR_PERPLL_PERBASECLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.perpllgrp.perbaseclk); alt_indread_word(ALT_CLKMGR_PERPLL_S2FUSER1CLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.perpllgrp.s2fuser1clk); /* Peripheral PLL Counter Enable register */ alt_indread_word(ALT_CLKMGR_PERPLL_EN_ADDR, tmp, &clk_group_raw_cfg->clkgrp.perpllgrp.en); /* Peripheral PLL Divider register */ alt_indread_word(ALT_CLKMGR_PERPLL_DIV_ADDR, tmp, &clk_group_raw_cfg->clkgrp.perpllgrp.div); /* Peripheral PLL GPIO Divider register */ alt_indread_word(ALT_CLKMGR_PERPLL_GPIODIV_ADDR, tmp, &clk_group_raw_cfg->clkgrp.perpllgrp.gpiodiv); /* Peripheral PLL Source register */ alt_indread_word(ALT_CLKMGR_PERPLL_SRC_ADDR, tmp, &clk_group_raw_cfg->clkgrp.perpllgrp.src); ret = ALT_E_SUCCESS; } else if (clk_group == ALT_SDRAM_PLL_CLK_GRP) { /* SDRAM PLL VCO register */ tmp = (uint32_t *) &clk_group_raw_cfg->clkgrp.sdrpllgrp.vco; alt_write_word(ALT_CLKMGR_SDRPLL_VCO_ADDR, *tmp & (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_indread_word(ALT_CLKMGR_SDRPLL_CTL_ADDR, tmp, &clk_group_raw_cfg->clkgrp.sdrpllgrp.ctrl); /* SDRAM PLL C0-C2 & C5 Counters */ alt_indread_word(ALT_CLKMGR_SDRPLL_DDRDQSCLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.sdrpllgrp.ddrdqsclk); alt_indread_word(ALT_CLKMGR_SDRPLL_DDR2XDQSCLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.sdrpllgrp.ddr2xdqsclk); alt_indread_word(ALT_CLKMGR_SDRPLL_DDRDQCLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.sdrpllgrp.ddrdqclk); alt_indread_word(ALT_CLKMGR_SDRPLL_S2FUSER2CLK_ADDR, tmp, &clk_group_raw_cfg->clkgrp.sdrpllgrp.s2fuser2clk); /* SDRAM PLL Counter Enable register */ alt_indread_word(ALT_CLKMGR_SDRPLL_EN_ADDR, tmp, &clk_group_raw_cfg->clkgrp.sdrpllgrp.en); ret = ALT_E_SUCCESS; } else { ret = ALT_E_BAD_ARG; } } else { ret = ALT_E_BAD_VERSION; } } // if PLL was not bypassed before, restore that state if (byp) { ret = alt_clk_pll_bypass_disable(pll); } return ret; } /****************************************************************************************/ /* 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 *s, size_t num) { ALT_STATUS_CODE ret = ALT_E_ERROR; uint32_t num2; char *t = NULL; if (s != NULL) { s[0] = '\0'; switch (clk_id) { case ALT_CLK_IN_PIN_OSC1: t = "ALT_CLK_IN_PIN_OSC1"; break; case ALT_CLK_IN_PIN_OSC2: t = "ALT_CLK_IN_PIN_OSC2"; break; /* FPGA Clock Sources External to HPS */ case ALT_CLK_F2H_PERIPH_REF: t = "ALT_CLK_F2H_PERIPH_REF"; \ break; case ALT_CLK_F2H_SDRAM_REF: t = "ALT_CLK_F2H_SDRAM_REF"; break; /* Other Clock Sources External to HPS */ case ALT_CLK_IN_PIN_JTAG: t = "ALT_CLK_IN_PIN_JTAG"; break; case ALT_CLK_IN_PIN_ULPI0: t = "ALT_CLK_IN_PIN_ULPI0"; break; case ALT_CLK_IN_PIN_ULPI1: t = "ALT_CLK_IN_PIN_ULPI1"; break; case ALT_CLK_IN_PIN_EMAC0_RX: t = "ALT_CLK_IN_PIN_EMAC0_RX"; break; case ALT_CLK_IN_PIN_EMAC1_RX: t = "ALT_CLK_IN_PIN_EMAC1_RX"; break; /* PLLs */ case ALT_CLK_MAIN_PLL: t = "ALT_CLK_MAIN_PLL"; break; case ALT_CLK_PERIPHERAL_PLL: t = "ALT_CLK_PERIPHERAL_PLL"; break; case ALT_CLK_SDRAM_PLL: t = "ALT_CLK_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: t = "ALT_CLK_OSC1"; break; /* Main Clock Group - The following clocks are derived from the Main PLL. */ case ALT_CLK_MAIN_PLL_C0: t = "ALT_CLK_MAIN_PLL_C0"; break; case ALT_CLK_MAIN_PLL_C1: t = "ALT_CLK_MAIN_PLL_C1"; break; case ALT_CLK_MAIN_PLL_C2: t = "ALT_CLK_MAIN_PLL_C2"; break; case ALT_CLK_MAIN_PLL_C3: t = "ALT_CLK_MAIN_PLL_C3"; break; case ALT_CLK_MAIN_PLL_C4: t = "ALT_CLK_MAIN_PLL_C4"; break; case ALT_CLK_MAIN_PLL_C5: t = "ALT_CLK_MAIN_PLL_C5"; break; case ALT_CLK_MPU: t = "ALT_CLK_MPU"; break; case ALT_CLK_MPU_L2_RAM: t = "ALT_CLK_MPU_L2_RAM"; break; case ALT_CLK_MPU_PERIPH: t = "ALT_CLK_MPU_PERIPH"; break; case ALT_CLK_L3_MAIN: t = "ALT_CLK_L3_MAIN"; break; case ALT_CLK_L3_MP: t = "ALT_CLK_L3_MP"; break; case ALT_CLK_L3_SP: t = "ALT_CLK_L3_SP"; break; case ALT_CLK_L4_MAIN: t = "ALT_CLK_L4_MAIN"; break; case ALT_CLK_L4_MP: t = "ALT_CLK_L4_MP"; break; case ALT_CLK_L4_SP: t = "ALT_CLK_L4_SP"; break; case ALT_CLK_DBG_BASE: t = "ALT_CLK_DBG_BASE"; break; case ALT_CLK_DBG_AT: t = "ALT_CLK_DBG_AT\0"; break; case ALT_CLK_DBG_TRACE: t = "ALT_CLK_DBG_TRACE"; break; case ALT_CLK_DBG_TIMER: t = "ALT_CLK_DBG_TIMER"; break; case ALT_CLK_DBG: t = "ALT_CLK_DBG"; break; case ALT_CLK_MAIN_QSPI: t = "ALT_CLK_MAIN_QSPI"; break; case ALT_CLK_MAIN_NAND_SDMMC: t = "ALT_CLK_MAIN_NAND_SDMMC"; break; case ALT_CLK_CFG: t = "ALT_CLK_CFG"; break; case ALT_CLK_H2F_USER0: t = "ALT_CLK_H2F_USER0"; break; /* Peripherals Clock Group - The following clocks are derived from the Peripheral PLL */ case ALT_CLK_PERIPHERAL_PLL_C0: t = "ALT_CLK_PERIPHERAL_PLL_C0"; break; case ALT_CLK_PERIPHERAL_PLL_C1: t = "ALT_CLK_PERIPHERAL_PLL_C1"; break; case ALT_CLK_PERIPHERAL_PLL_C2: t = "ALT_CLK_PERIPHERAL_PLL_C2"; break; case ALT_CLK_PERIPHERAL_PLL_C3: t = "ALT_CLK_PERIPHERAL_PLL_C3"; break; case ALT_CLK_PERIPHERAL_PLL_C4: t = "ALT_CLK_PERIPHERAL_PLL_C4"; break; case ALT_CLK_PERIPHERAL_PLL_C5: t = "ALT_CLK_PERIPHERAL_PLL_C5"; break; case ALT_CLK_USB_MP: t = "ALT_CLK_USB_MP"; break; case ALT_CLK_SPI_M: t = "ALT_CLK_SPI_M"; break; case ALT_CLK_QSPI: t = "ALT_CLK_QSPI"; break; case ALT_CLK_NAND_X: t = "ALT_CLK_NAND_X"; break; case ALT_CLK_NAND: t = "ALT_CLK_NAND"; break; case ALT_CLK_SDMMC: t = "ALT_CLK_SDMMC"; break; case ALT_CLK_EMAC0: t = "ALT_CLK_EMAC0"; break; case ALT_CLK_EMAC1: t = "ALT_CLK_EMAC1"; break; case ALT_CLK_CAN0: t = "ALT_CLK_CAN0"; break; case ALT_CLK_CAN1: t = "ALT_CLK_CAN1"; break; case ALT_CLK_GPIO_DB: t = "ALT_CLK_GPIO_DB"; break; case ALT_CLK_H2F_USER1: t = "ALT_CLK_H2F_USER1"; break; /* SDRAM Clock Group - The following clocks are derived from the SDRAM PLL */ case ALT_CLK_SDRAM_PLL_C0: t = "ALT_CLK_SDRAM_PLL_C0"; break; case ALT_CLK_SDRAM_PLL_C1: t = "ALT_CLK_SDRAM_PLL_C1"; break; case ALT_CLK_SDRAM_PLL_C2: t = "ALT_CLK_SDRAM_PLL_C2"; break; case ALT_CLK_SDRAM_PLL_C3: t = "ALT_CLK_SDRAM_PLL_C3"; break; case ALT_CLK_SDRAM_PLL_C4: t = "ALT_CLK_SDRAM_PLL_C4"; break; case ALT_CLK_SDRAM_PLL_C5: t = "ALT_CLK_SDRAM_PLL_C5"; break; case ALT_CLK_DDR_DQS: t = "ALT_CLK_DDR_DQS"; break; case ALT_CLK_DDR_2X_DQS: t = "ALT_CLK_DDR_2X_DQS"; break; case ALT_CLK_DDR_DQ: t = "ALT_CLK_DDR_DQ"; break; case ALT_CLK_H2F_USER2: t = "ALT_CLK_H2F_USER2"; break; /* Clock Output Pins */ case ALT_CLK_OUT_PIN_EMAC0_TX: t = "ALT_CLK_OUT_PIN_EMAC0_TX"; break; case ALT_CLK_OUT_PIN_EMAC1_TX: t = "ALT_CLK_OUT_PIN_EMAC1_TX"; break; case ALT_CLK_OUT_PIN_SDMMC: t = "ALT_CLK_OUT_PIN_SDMMC"; break; case ALT_CLK_OUT_PIN_I2C0_SCL: t = "ALT_CLK_OUT_PIN_I2C0_SCL"; break; case ALT_CLK_OUT_PIN_I2C1_SCL: t = "ALT_CLK_OUT_PIN_I2C1_SCL"; break; case ALT_CLK_OUT_PIN_I2C2_SCL: t = "ALT_CLK_OUT_PIN_I2C2_SCL"; break; case ALT_CLK_OUT_PIN_I2C3_SCL: t = "ALT_CLK_OUT_PIN_I2C3_SCL"; break; case ALT_CLK_OUT_PIN_SPIM0: t = "ALT_CLK_OUT_PIN_SPIM0"; break; case ALT_CLK_OUT_PIN_SPIM1: t = "ALT_CLK_OUT_PIN_SPIM1"; break; case ALT_CLK_OUT_PIN_QSPI: t = "ALT_CLK_OUT_PIN_QSPI"; break; case ALT_CLK_UNKNOWN: t = "ALT_CLK_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 (t != NULL) { num2 = strlen(t) + 1; if (num2 < num) { num = num2; } strncpy(s, t, num); if (s[0] != '\0') { ret = ALT_E_SUCCESS; } } } return ret; }