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