From 1c190045b3e549ee70cc0d1723acde6df1e20f4a Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 4 Jan 2024 14:33:17 +0100 Subject: [PATCH] soc: arm: atmel_sam: samv71: Rework clock_init Update clock_init for the Atmel SAMV71 SoC using the new PMC API. Signed-off-by: Pieter De Gendt --- soc/arm/atmel_sam/samv71/soc.c | 225 ++++++++------------------------- 1 file changed, 51 insertions(+), 174 deletions(-) diff --git a/soc/arm/atmel_sam/samv71/soc.c b/soc/arm/atmel_sam/samv71/soc.c index f88a3cb440..6e82b9fe2f 100644 --- a/soc/arm/atmel_sam/samv71/soc.c +++ b/soc/arm/atmel_sam/samv71/soc.c @@ -23,35 +23,6 @@ #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL LOG_MODULE_REGISTER(soc); -/* Power Manager Controller */ - -/* - * PLL clock = Main * (MULA + 1) / DIVA - * - * By default, MULA == 24, DIVA == 1. - * With main crystal running at 12 MHz, - * PLL = 12 * (24 + 1) / 1 = 300 MHz - * - * With Processor Clock prescaler at 1 - * Processor Clock (HCLK)=300 MHz. - */ -#define PMC_CKGR_PLLAR_MULA \ - (CKGR_PLLAR_MULA(CONFIG_SOC_ATMEL_SAMV71_PLLA_MULA)) -#define PMC_CKGR_PLLAR_DIVA \ - (CKGR_PLLAR_DIVA(CONFIG_SOC_ATMEL_SAMV71_PLLA_DIVA)) - -#if CONFIG_SOC_ATMEL_SAMV71_MDIV == 1 -#define SOC_ATMEL_SAMV71_MDIV PMC_MCKR_MDIV_EQ_PCK -#elif CONFIG_SOC_ATMEL_SAMV71_MDIV == 2 -#define SOC_ATMEL_SAMV71_MDIV PMC_MCKR_MDIV_PCK_DIV2 -#elif CONFIG_SOC_ATMEL_SAMV71_MDIV == 3 -#define SOC_ATMEL_SAMV71_MDIV PMC_MCKR_MDIV_PCK_DIV3 -#elif CONFIG_SOC_ATMEL_SAMV71_MDIV == 4 -#define SOC_ATMEL_SAMV71_MDIV PMC_MCKR_MDIV_PCK_DIV4 -#else -#error "Invalid CONFIG_SOC_ATMEL_SAMV71_MDIV define value" -#endif - /** * @brief Setup various clocks on SoC at boot time. * @@ -60,174 +31,88 @@ LOG_MODULE_REGISTER(soc); */ static ALWAYS_INLINE void clock_init(void) { - uint32_t reg_val; + /* Switch the main clock to the internal OSC with 12MHz */ + soc_pmc_switch_mainck_to_fastrc(SOC_PMC_FAST_RC_FREQ_12MHZ); -#ifdef CONFIG_SOC_ATMEL_SAMV71_EXT_SLCK - /* Switch slow clock to the external 32 kHz crystal oscillator */ - SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL; + /* Switch MCK (Master Clock) to the main clock */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_MAIN_CLK); - /* Wait for oscillator to be stabilized */ - while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAMV71_EXT_SLCK */ + EFC->EEFC_FMR = EEFC_FMR_FWS(0) | EEFC_FMR_CLOE; -#ifdef CONFIG_SOC_ATMEL_SAMV71_EXT_MAINCK - /* - * Setup main external crystal oscillator if not already done - * by a previous program i.e. bootloader - */ + soc_pmc_enable_clock_failure_detector(); - if (!(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL_Msk)) { - /* Start the external crystal oscillator */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - /* We select maximum setup time. - * While start up time could be shortened - * this optimization is not deemed - * critical now. - */ - | CKGR_MOR_MOSCXTST(0xFFu) - /* RC OSC must stay on */ - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; - - /* Wait for oscillator to be stabilized */ - while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { - ; - } - - /* Select the external crystal oscillator as main clock */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; - - /* Wait for external oscillator to be selected */ - while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) { - ; - } + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAMV71_EXT_SLCK)) { + soc_supc_slow_clock_select_crystal_osc(); } - /* Turn off RC OSC, not used any longer, to save power */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCXTEN; - /* Wait for RC OSC to be turned off */ - while (PMC->PMC_SR & PMC_SR_MOSCRCS) { - ; + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAMV71_EXT_MAINCK)) { + /* + * Setup main external crystal oscillator. + */ + + /* We select maximum setup time. + * While start up time could be shortened + * this optimization is not deemed + * critical now. + */ + soc_pmc_switch_mainck_to_xtal(false, 0xff); } -#ifdef CONFIG_SOC_ATMEL_SAMV71_WAIT_MODE - /* - * Instruct CPU to enter Wait mode instead of Sleep mode to - * keep Processor Clock (HCLK) and thus be able to debug - * CPU using JTAG - */ - PMC->PMC_FSMR |= PMC_FSMR_LPM; -#endif -#else - /* Attempt to change main fast RC oscillator frequency */ - /* - * NOTE: MOSCRCF must be changed only if MOSCRCS is set in the PMC_SR - * register, should normally be the case here + * Set FWS (Flash Wait State) value before increasing Master Clock + * (MCK) frequency. + * TODO: set FWS based on the actual MCK frequency and VDDIO value + * rather than maximum supported 150 MHz at standard VDDIO=2.7V */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } - - /* Set main fast RC oscillator to 12 MHz */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_12_MHz - | CKGR_MOR_MOSCRCEN; - - /* Wait for oscillator to be stabilized */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAMV71_EXT_MAINCK */ + EFC->EEFC_FMR = EEFC_FMR_FWS(5) | EEFC_FMR_CLOE; /* * Setup PLLA */ - /* Switch MCK (Master Clock) to the main clock first */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_MAIN_CLK; - - /* Wait for clock selection to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Setup PLLA */ - PMC->CKGR_PLLAR = CKGR_PLLAR_ONE - | PMC_CKGR_PLLAR_MULA - | CKGR_PLLAR_PLLACOUNT(0x3Fu) - | PMC_CKGR_PLLAR_DIVA; - /* - * NOTE: Both MULA and DIVA must be set to a value greater than 0 or - * otherwise PLL will be disabled. In this case we would get stuck in - * the following loop. + * PLL clock = Main * (MULA + 1) / DIVA + * + * By default, MULA == 24, DIVA == 1. + * With main crystal running at 12 MHz, + * PLL = 12 * (24 + 1) / 1 = 300 MHz + * + * With Processor Clock prescaler at 1 + * Processor Clock (HCLK)=300 MHz. */ + soc_pmc_enable_pllack(CONFIG_SOC_ATMEL_SAMV71_PLLA_MULA, 0x3Fu, + CONFIG_SOC_ATMEL_SAMV71_PLLA_DIVA); - /* Wait for PLL lock */ - while (!(PMC->PMC_SR & PMC_SR_LOCKA)) { - ; - } - /* Setup UPLL */ - PMC->CKGR_UCKR = CKGR_UCKR_UPLLCOUNT(0x3Fu) | CKGR_UCKR_UPLLEN; - - /* Wait for PLL lock */ - while (!(PMC->PMC_SR & PMC_SR_LOCKU)) { - ; - } + soc_pmc_enable_upllck(0x3Fu); /* * Final setup of the Master Clock */ - /* - * NOTE: PMC_MCKR must not be programmed in a single write operation. - * If CSS, MDIV or PRES are modified we must wait for MCKRDY bit to be - * set again. - */ + /* Setting PLLA as MCK, first prescaler, then divider and source last */ + soc_pmc_mck_set_prescaler(1); + soc_pmc_mck_set_divider(CONFIG_SOC_ATMEL_SAMV71_MDIV); + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_PLLA_CLK); - /* Setup prescaler - PLLA Clock / Processor Clock (HCLK) */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_PRES_CLK_1; - - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Setup divider - Processor Clock (HCLK) / Master Clock (MCK) */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_MDIV_Msk; - PMC->PMC_MCKR = reg_val | SOC_ATMEL_SAMV71_MDIV; - - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Finally select PLL as Master Clock source */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_PLLA_CLK; - - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; + /* Disable internal fast RC if we have an external crystal oscillator */ + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAMV71_EXT_MAINCK)) { + soc_pmc_osc_disable_fastrc(); } } void z_arm_platform_init(void) { + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAMV71_WAIT_MODE)) { + /* + * Instruct CPU to enter Wait mode instead of Sleep mode to + * keep Processor Clock (HCLK) and thus be able to debug + * CPU using JTAG. + */ + soc_pmc_enable_waitmode(); + } + /* * DTCM is enabled by default at reset, therefore we have to disable * it first to get the caches into a state where then the @@ -242,14 +127,6 @@ void z_arm_platform_init(void) sys_cache_instr_enable(); sys_cache_data_enable(); - /* - * Set FWS (Flash Wait State) value before increasing Master Clock - * (MCK) frequency. - * TODO: set FWS based on the actual MCK frequency and VDDIO value - * rather than maximum supported 150 MHz at standard VDDIO=2.7V - */ - EFC->EEFC_FMR = EEFC_FMR_FWS(5) | EEFC_FMR_CLOE; - /* Setup system clocks */ clock_init(); }