blob: 1fe008b78cc319ddcc17e4f711b6dbf69a57bd4b [file] [log] [blame]
/****************************************************************************
* arch/avr/src/at32uc3/at32uc3_clkinit.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <arch/board/board.h>
#include "at32uc3_config.h"
#include "avr_internal.h"
#include "at32uc3.h"
#include "at32uc3_pm.h"
#include "at32uc3_flashc.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#if defined(AVR32_CLOCK_OSC0) || \
(defined (AVR32_CLOCK_PLL0) && defined(AVR32_CLOCK_PLL0_OSC0)) || \
(defined (AVR32_CLOCK_PLL1) && defined(AVR32_CLOCK_PLL1_OSC0))
# define NEED_OSC0
#endif
#if defined(AVR32_CLOCK_OSC1) || \
(defined (AVR32_CLOCK_PLL0) && defined(AVR32_CLOCK_PLL0_OSC1)) || \
(defined (AVR32_CLOCK_PLL1) && defined(AVR32_CLOCK_PLL1_OSC1))
# define NEED_OSC1
#endif
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: up_enableosc32
*
* Description:
* Initialize the 32KHz oscillaor. This oscillaor is used by the RTC
* logic to provide the system timer.
*
****************************************************************************/
#ifdef AVR32_CLOCK_OSC32
static inline void up_enableosc32(void)
{
uint32_t regval;
/* Select the 32KHz oscillator crystal */
regval = getreg32(AVR32_PM_OSCCTRL32);
regval &= ~PM_OSCCTRL32_MODE_MASK;
regval |= PM_OSCCTRL32_MODE_XTAL;
putreg32(regval, AVR32_PM_OSCCTRL32);
/* Enable the 32-kHz clock */
regval = getreg32(AVR32_PM_OSCCTRL32);
regval &= ~PM_OSCCTRL32_STARTUP_MASK;
regval |= PM_OSCCTRL32_EN |
(AVR32_OSC32STARTUP << PM_OSCCTRL32_STARTUP_SHIFT);
putreg32(regval, AVR32_PM_OSCCTRL32);
}
#endif
/****************************************************************************
* Name: up_enableosc0
*
* Description:
* Initialize OSC0 settings per the definitions in the board.h file.
*
****************************************************************************/
#ifdef NEED_OSC0
static inline void up_enableosc0(void)
{
uint32_t regval;
/* Enable OSC0 in the correct crystal mode by setting the mode value in
* OSCCTRL0
*/
regval = getreg32(AVR32_PM_OSCCTRL0);
regval &= ~PM_OSCCTRL_MODE_MASK;
#if AVR32_FOSC0 < 900000
regval |= PM_OSCCTRL_MODE_XTALP9; /* Crystal XIN 0.4-0.9MHz */
#elif AVR32_FOSC0 < 3000000
regval |= PM_OSCCTRL_MODE_XTAL3; /* Crystal XIN 0.9-3.0MHz */
#elif AVR32_FOSC0 < 8000000
regval |= PM_OSCCTRL_MODE_XTAL8; /* Crystal XIN 3.0-8.0MHz */
#else
regval |= PM_OSCCTRL_MODE_XTALHI; /* Crystal XIN above 8.0MHz */
#endif
putreg32(regval, AVR32_PM_OSCCTRL0);
/* Enable OSC0 using the startup time provided in board.h. This startup
* time is critical and depends on the characteristics of the crystal.
*/
regval = getreg32(AVR32_PM_OSCCTRL0);
regval &= ~PM_OSCCTRL_STARTUP_MASK;
regval |= (AVR32_OSC0STARTUP << PM_OSCCTRL_STARTUP_SHIFT);
putreg32(regval, AVR32_PM_OSCCTRL0);
/* Enable OSC0 */
regval = getreg32(AVR32_PM_MCCTRL);
regval |= PM_MCCTRL_OSC0EN;
putreg32(regval, AVR32_PM_MCCTRL);
/* Wait for OSC0 to be ready */
while ((getreg32(AVR32_PM_POSCSR) & PM_POSCSR_OSC0RDY) == 0);
}
#endif
/****************************************************************************
* Name: up_enableosc1
*
* Description:
* Initialize OSC0 settings per the definitions in the board.h file.
*
****************************************************************************/
#ifdef NEED_OSC1
static inline void up_enableosc1(void)
{
uint32_t regval;
/* Enable OSC1 in the correct crystal mode by setting the mode value in
* OSCCTRL1
*/
regval = getreg32(AVR32_PM_OSCCTRL1);
regval &= ~PM_OSCCTRL_MODE_MASK;
#if AVR32_FOSC1 < 900000
regval |= PM_OSCCTRL_MODE_XTALP9; /* Crystal XIN 0.4-0.9MHz */
#elif AVR32_FOSC1 < 3000000
regval |= PM_OSCCTRL_MODE_XTAL3; /* Crystal XIN 0.9-3.0MHz */
#elif AVR32_FOSC1 < 8000000
regval |= PM_OSCCTRL_MODE_XTAL8; /* Crystal XIN 3.0-8.0MHz */
#else
regval |= PM_OSCCTRL_MODE_XTALHI; /* Crystal XIN above 8.0MHz */
#endif
putreg32(regval, AVR32_PM_OSCCTRL1);
/* Enable OSC1 using the startup time provided in board.h. This startup
* time is critical and depends on the characteristics of the crystal.
*/
regval = getreg32(AVR32_PM_OSCCTRL1);
regval &= ~PM_OSCCTRL_STARTUP_MASK;
regval |= (AVR32_OSC1STARTUP << PM_OSCCTRL_STARTUP_SHIFT);
putreg32(regval, AVR32_PM_OSCCTRL1);
/* Enable OSC1 */
regval = getreg32(AVR32_PM_MCCTRL);
regval |= PM_MCCTRL_OSC1EN;
putreg32(regval, AVR32_PM_MCCTRL);
/* Wait for OSC1 to be ready */
while ((getreg32(AVR32_PM_POSCSR) & PM_POSCSR_OSC1RDY) == 0);
}
#endif
/****************************************************************************
* Name: up_enablepll0
*
* Description:
* Initialize PLL0 settings per the definitions in the board.h file.
*
****************************************************************************/
#ifdef AVR32_CLOCK_PLL0
static inline void up_enablepll0(void)
{
uint32_t regval;
/* Setup PLL0 */
regval = (AVR32_PLL0_DIV << PM_PLL_PLLDIV_SHIFT) |
(AVR32_PLL0_MUL << PM_PLL_PLLMUL_SHIFT) |
(16 << PM_PLL_PLLCOUNT_SHIFT);
/* Select PLL0/1 oscillator */
#ifdef AVR32_CLOCK_PLL0_OSC1
regval |= PM_PLL_PLLOSC;
#endif
putreg32(regval, AVR32_PM_PLL0);
/* Set PLL0 options */
regval = getreg32(AVR32_PM_PLL0);
regval &= ~PM_PLL_PLLOPT_MASK;
#if AVR32_PLL0_FREQ < 160000000
regval |= PM_PLL_PLLOPT_VCO;
#endif
#if AVR32_PLL0_DIV2 != 0
regval |= PM_PLL_PLLOPT_XTRADIV;
#endif
#if AVR32_PLL0_WBWM != 0
regval |= PM_PLL_PLLOPT_WBWDIS;
#endif
putreg32(regval, AVR32_PM_PLL0);
/* Enable PLL0 */
regval = getreg32(AVR32_PM_PLL0);
regval |= PM_PLL_PLLEN;
putreg32(regval, AVR32_PM_PLL0);
/* Wait for PLL0 locked. */
while ((getreg32(AVR32_PM_POSCSR) & PM_POSCSR_LOCK0) == 0);
}
#endif
/****************************************************************************
* Name: up_enablepll1
*
* Description:
* Initialize PLL1 settings per the definitions in the board.h file.
*
****************************************************************************/
#ifdef AVR32_CLOCK_PLL1
static inline void up_enablepll1(void)
{
/* Setup PLL1 */
regval = (AVR32_PLL1_DIV << PM_PLL_PLLDIV_SHIFT) |
(AVR32_PLL1_MUL << PM_PLL_PLLMUL_SHIFT) |
(16 << PM_PLL_PLLCOUNT_SHIFT);
/* Select PLL0/1 oscillator */
#ifdef AVR32_CLOCK_PLL1_OSC1
regval |= PM_PLL_PLLOSC;
#endif
putreg32(regval, AVR32_PM_PLL1);
/* Set PLL1 options */
regval = getreg32(AVR32_PM_PLL1);
regval &= ~PM_PLL_PLLOPT_MASK;
#if AVR32_PLL1_FREQ < 160000000
regval |= PM_PLL_PLLOPT_VCO;
#endif
#if AVR32_PLL1_DIV2 != 0
regval |= PM_PLL_PLLOPT_XTRADIV;
#endif
#if AVR32_PLL1_WBWM != 0
regval |= PM_PLL_PLLOPT_WBWDIS;
#endif
putreg32(regval, AVR32_PM_PLL1);
/* Enable PLL1 */
regval = getreg32(AVR32_PM_PLL1);
regval |= PM_PLL_PLLEN;
putreg32(regval, AVR32_PM_PLL1);
/* Wait for PLL1 locked. */
while ((getreg32(AVR32_PM_POSCSR) & PM_POSCSR_LOCK1) == 0);
}
#endif
/****************************************************************************
* Name: up_clksel
*
* Description:
* Configure derived clocks.
*
****************************************************************************/
static inline void up_clksel(void)
{
uint32_t regval = 0;
#if AVR32_CKSEL_CPUDIV != 0
regval |= PM_CKSEL_CPUDIV;
regval |= (AVR32_CKSEL_CPUDIV << PM_CKSEL_CPUSEL_SHIFT);
#endif
#if AVR32_CKSEL_HSBDIV != 0
regval |= PM_CKSEL_HSBDIV;
regval |= (AVR32_CKSEL_HSBDIV << PM_CKSEL_HSBSEL_SHIFT);
#endif
#if AVR32_CKSEL_PBADIV != 0
regval |= PM_CKSEL_PBADIV;
regval |= (AVR32_CKSEL_PBADIV << PM_CKSEL_PBASEL_SHIFT);
#endif
#if AVR32_CKSEL_PBBDIV != 0
regval |= PM_CKSEL_PBBDIV;
regval |= (AVR32_CKSEL_PBBDIV << PM_CKSEL_PBBSEL_SHIFT);
#endif
putreg32(regval, AVR32_PM_CKSEL);
/* Wait for CLKRDY */
while ((getreg32(AVR32_PM_POSCSR) & PM_POSCSR_CKRDY) == 0);
}
/****************************************************************************
* Name: up_fws
*
* Description:
* Setup FLASH wait states.
*
****************************************************************************/
static void up_fws(uint32_t cpuclock)
{
uint32_t regval;
regval = getreg32(AVR32_FLASHC_FCR);
if (cpuclock > AVR32_FLASHC_FWS0_MAXFREQ)
{
regval |= FLASHC_FCR_FWS;
}
else
{
regval &= ~FLASHC_FCR_FWS;
}
putreg32(regval, AVR32_FLASHC_FCR);
}
/****************************************************************************
* Name: up_mainclk
*
* Description:
* Select the main clock.
*
****************************************************************************/
static inline void up_mainclk(uint32_t mcsel)
{
uint32_t regval;
regval = getreg32(AVR32_PM_MCCTRL);
regval &= ~PM_MCCTRL_MCSEL_MASK;
regval |= mcsel;
putreg32(regval, AVR32_PM_MCCTRL);
}
/****************************************************************************
* Name: up_usbclock
*
* Description:
* Setup the USBB GCLK.
*
****************************************************************************/
#ifdef CONFIG_USBDEV
static inline void up_usbclock(void)
{
uint32_t regval = 0;
#if defined(AVR32_CLOCK_USB_PLL0) || defined(AVR32_CLOCK_USB_PLL1)
regval |= PM_GCCTRL_PLLSEL;
#endif
#if defined(AVR32_CLOCK_USB_OSC1) || defined(AVR32_CLOCK_USB_PLL1)
regval |= PM_GCCTRL_OSCSEL;
#endif
#if AVR32_CLOCK_USB_DIV > 0
u_avr32_pm_gcctrl.GCCTRL.diven = diven;
u_avr32_pm_gcctrl.GCCTRL.div = div;
#endif
putreg32(regval, AVR32_PM_GCCTRL(AVR32_PM_GCLK_USBB));
/* Enable USB GCLK */
regval = getreg32(AVR32_PM_GCCTRL(AVR32_PM_GCLK_USBB));
regval |= PM_GCCTRL_CEN;
putreg32(regval, AVR32_PM_GCCTRL(AVR32_PM_GCLK_USBB));
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: up_clkinit
*
* Description:
* Initialize clock/PLL settings per the definitions in the board.h
* file.
*
****************************************************************************/
void up_clkinitialize(void)
{
#ifdef AVR32_CLOCK_OSC32
/* Enable the 32KHz oscillator (need by the RTC module) */
up_enableosc32();
#endif
#ifdef NEED_OSC0
/* Enable OSC0 using the settings in board.h */
up_enableosc0();
/* Set up FLASH wait states */
up_fws(AVR32_FOSC0);
/* Then switch the main clock to OSC0 */
up_mainclk(PM_MCCTRL_MCSEL_OSC0);
#endif
#ifdef NEED_OSC1
/* Enable OSC1 using the settings in board.h */
up_enableosc1();
#endif
#ifdef AVR32_CLOCK_PLL0
/* Enable PLL0 using the settings in board.h */
up_enablepll0();
/* Set up FLASH wait states */
up_fws(AVR32_CPU_CLOCK);
/* Then switch the main clock to PLL0 */
up_mainclk(PM_MCCTRL_MCSEL_PLL0);
#endif
#ifdef AVR32_CLOCK_PLL1
/* Enable PLL1 using the settings in board.h */
up_enablepll1();
#endif
/* Configure derived clocks */
up_clksel();
/* Set up the USBB GCLK */
#ifdef CONFIG_USBDEV
void up_usbclock();
#endif
}