blob: 0e1db8234da1503b2725c211c434782656fa8ea1 [file] [log] [blame]
/******************************************************************************
*
* Copyright 2013 Altera Corporation. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
******************************************************************************/
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include "socal/hps.h"
#include "socal/socal.h"
#include "socal/alt_sysmgr.h"
#include "hwlib.h"
#include "alt_clock_manager.h"
#include "alt_mpu_registers.h"
#define UINT12_MAX (4096)
#define printf( ... )
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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;
}