nuttx/arch/arm/src/sam34/sam4l_clockconfig.c

1435 lines
43 KiB
C

/****************************************************************************
* arch/avr/src/sam34/sam4l_clockconfig.c
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* This file is derived from nuttx/arch/avr/src/at32uc3/at32uc3_clkinit.c
*
* 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. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "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
* COPYRIGHT OWNER OR CONTRIBUTORS 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <arch/irq.h>
#include <arch/board/board.h>
#include "up_arch.h"
#include "up_internal.h"
#include "chip/sam4l_pm.h"
#include "chip/sam4l_scif.h"
#include "chip/sam4l_bpm.h"
#include "chip/sam4l_bscif.h"
#include "chip/sam4l_flashcalw.h"
#include "sam4l_periphclks.h"
#include "sam_clockconfig.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
#ifndef CONFIG_ARCH_RAMFUNCS
# error "CONFIG_ARCH_RAMFUNCS must be defined"
#endif
/* Board/Clock Setup *******************************************************/
/* Verify dividers */
#if ((BOARD_CPU_SHIFT > BOARD_PBA_SHIFT) || (BOARD_CPU_SHIFT > BOARD_PBB_SHIFT) || \
(BOARD_CPU_SHIFT > BOARD_PBC_SHIFT) || (BOARD_CPU_SHIFT > BOARD_PBD_SHIFT))
# error BOARD_PBx_SHIFT must be greater than or equal to BOARD_CPU_SHIFT
#endif
/* Nominal frequencies in on-chip RC oscillators. These may frequencies
* may vary with temperature changes.
*/
#define SAM_RCSYS_FREQUENCY 115000 /* Nominal frequency of RCSYS (Hz) */
#define SAM_RC32K_FREQUENCY 32768 /* Nominal frequency of RC32K (Hz) */
#define SAM_RC80M_FREQUENCY 80000000 /* Nominal frequency of RC80M (Hz) */
#define SAM_RCFAST4M_FREQUENCY 4000000 /* Nominal frequency of RCFAST4M (Hz) */
#define SAM_RCFAST8M_FREQUENCY 8000000 /* Nominal frequency of RCFAST8M (Hz) */
#define SAM_RCFAST12M_FREQUENCY 12000000 /* Nominal frequency of RCFAST12M (Hz) */
#define SAM_RC1M_FREQUENCY 1000000 /* Nominal frequency of RC1M (Hz) */
/* Oscillator 0. This might be the system clock or the source clock for
* either PLL0 or DFPLL. It might also be needed if OSC0 is the source
* clock for GCLK9.
*
* By selecting CONFIG_SAM34_OSC0, you can also force the clock to be enabled
* at boot time.
*/
#if defined(CONFIG_SAM34_OSC0) || defined(BOARD_SYSCLK_SOURCE_OSC0) || \
defined(BOARD_DFLL0_SOURCE_OSC0) || defined(BOARD_PLL0_SOURCE_OSC0) || \
defined(BOARD_GLCK9_SOURCE_OSC0)
# define NEED_OSC0 1
#endif
#ifdef NEED_OSC0
# if !defined(BOARD_OSC0_STARTUP_US)
# error BOARD_OSC0_STARTUP_US is not defined
# elif BOARD_OSC0_STARTUP_US == 0
# define SAM_OSC0_STARTUP_VALUE SCIF_OSCCTRL0_STARTUP_0
# define SAM_OSC0_STARTUP_TIMEOUT 8
# elif BOARD_OSC0_STARTUP_US <= 557
# define SAM_OSC0_STARTUP_VALUE SCIF_OSCCTRL0_STARTUP_64
# define SAM_OSC0_STARTUP_TIMEOUT 80
# elif BOARD_OSC0_STARTUP_US <= 1100
# define SAM_OSC0_STARTUP_VALUE SCIF_OSCCTRL0_STARTUP_128
# define SAM_OSC0_STARTUP_TIMEOUT 160
# elif BOARD_OSC0_STARTUP_US <= 18000
# define SAM_OSC0_STARTUP_VALUE SCIF_OSCCTRL0_STARTUP_2K
# define SAM_OSC0_STARTUP_TIMEOUT 2560
# elif BOARD_OSC0_STARTUP_US <= 36000
# define SAM_OSC0_STARTUP_VALUE SCIF_OSCCTRL0_STARTUP_4K
# define SAM_OSC0_STARTUP_TIMEOUT 5120
# elif BOARD_OSC0_STARTUP_US <= 71000
# define SAM_OSC0_STARTUP_VALUE SCIF_OSCCTRL0_STARTUP_8K
# define SAM_OSC0_STARTUP_TIMEOUT 10240
# elif BOARD_OSC0_STARTUP_US <= 143000
# define SAM_OSC0_STARTUP_VALUE SCIF_OSCCTRL0_STARTUP_16K
# define SAM_OSC0_STARTUP_TIMEOUT 20480
# elif BOARD_OSC0_STARTUP_US <= 285000
# define SAM_OSC0_STARTUP_VALUE SCIF_OSCCTRL0_STARTUP_32K
# define SAM_OSC0_STARTUP_TIMEOUT 40960
# else
# error BOARD_OSC0_STARTUP_US is out of range
# endif
# ifdef BOARD_OSC0_ISXTAL
# define SAM_OSC0_MODE_VALUE SCIF_OSCCTRL0_MODE
# if BOARD_OSC0_FREQUENCY < 2000000
# define SAM_OSC0_GAIN_VALUE SCIF_OSCCTRL0_GAIN(0)
# elif BOARD_OSC0_FREQUENCY < 4000000
# define SAM_OSC0_GAIN_VALUE SCIF_OSCCTRL0_GAIN(1)
# elif BOARD_OSC0_FREQUENCY < 8000000
# define SAM_OSC0_GAIN_VALUE SCIF_OSCCTRL0_GAIN(2)
# elif BOARD_OSC0_FREQUENCY < 16000000
# define SAM_OSC0_GAIN_VALUE SCIF_OSCCTRL0_GAIN(3)
# else
# define SAM_OSC0_GAIN_VALUE ((0x1u << 4) | SCIF_OSCCTRL0_GAIN(0))
# endif
# else
# define SAM_OSC0_MODE_VALUE 0
# define SAM_OSC0_GAIN_VALUE 0
# endif
#endif
/* OSC32. The 32K oscillator may be the source clock for DFPLL0 or
* the source clock for GLK9 that might be used to driver PLL0.
*
* By selecting CONFIG_SAM34_OSC32K, you can also force the clock to be
* enabled at boot time. OSC32 may needed by other devices as well
* (AST, WDT, PICUART, RTC).
*/
#if defined(CONFIG_SAM34_OSC32K) || defined(BOARD_DFLL0_SOURCE_OSC32K) || \
defined(BOARD_GLCK9_SOURCE_OSC32K)
# define NEED_OSC32K 1
#endif
#ifdef NEED_OSC32K
# if !defined(BOARD_OSC32_STARTUP_US)
# error BOARD_OSC32_STARTUP_US is not defined
# elif BOARD_OSC32_STARTUP_US == 0
# define SAM_OSC32_STARTUP_VALUE BSCIF_OSCCTRL32_STARTUP_0
# elif BOARD_OSC32_STARTUP_US <= 1100
# define SAM_OSC32_STARTUP_VALUE BSCIF_OSCCTRL32_STARTUP_128
# elif BOARD_OSC32_STARTUP_US <= 72300
# define SAM_OSC32_STARTUP_VALUE BSCIF_OSCCTRL32_STARTUP_8K
# elif BOARD_OSC32_STARTUP_US <= 143000
# define SAM_OSC32_STARTUP_VALUE BSCIF_OSCCTRL32_STARTUP_16K
# elif BOARD_OSC32_STARTUP_US <= 570000
# define SAM_OSC32_STARTUP_VALUE BSCIF_OSCCTRL32_STARTUP_64K
# elif BOARD_OSC32_STARTUP_US <= 1100000
# define SAM_OSC32_STARTUP_VALUE BSCIF_OSCCTRL32_STARTUP_128K
# elif BOARD_OSC32_STARTUP_US <= 2300000
# define SAM_OSC32_STARTUP_VALUE BSCIF_OSCCTRL32_STARTUP_256K
# elif BOARD_OSC32_STARTUP_US <= 4600000
# define SAM_OSC32_STARTUP_VALUE BSCIF_OSCCTRL32_STARTUP_512K
# else
# error BOARD_OSC32_STARTUP_US is out of range
# endif
# ifdef BOARD_OSC32_ISXTAL
# define SAM_OSC32_MODE_VALUE BSCIF_OSCCTRL32_MODE_XTAL
# else
# define SAM_OSC32_MODE_VALUE BSCIF_OSCCTRL32_MODE_EXTCLK
# endif
# ifndef BOARD_OSC32_SELCURR
# define BOARD_OSC32_SELCURR BSCIF_OSCCTRL32_SELCURR_300
# endif
#endif
/* RC80M. This might be the system clock or the source clock for the DFPLL
* or it could be the source for GCLK9 that drives PLL0.
*
* By selecting CONFIG_SAM34_RC80M, you can also force the clock to be enabled
* at boot time.
*/
#if defined(CONFIG_SAM34_RC80M) || defined(BOARD_SYSCLK_SOURCE_RC80M) || \
defined(BOARD_DFLL0_SOURCE_RC80M) || BOARD_GLCK9_SOURCE_RC80M
# define NEED_RC80M 1
#endif
/* RCFAST. The 12/8/4 fast RC oscillator may be used as the system clock
* or as the source for GLCK9 that drives PLL0.
* If not then, it may be enabled by setting the CONFIG_SAM34_RCFASTxM
* configuration variable.
*/
#if defined(CONFIG_SAM34_RCFAST12M)
# undef CONFIG_SAM34_RCFAST8M
# undef CONFIG_SAM34_RCFAST4M
#elif defined(CONFIG_SAM34_RCFAST8M)
# undef CONFIG_SAM34_RCFAST4M
#endif
#if defined(BOARD_SYSCLK_SOURCE_FCFAST12M)
# if defined(CONFIG_SAM34_RCFAST8M) || defined(CONFIG_SAM34_RCFAST4M)
# error BOARD_SYSCLK_SOURCE_FCFAST12M inconsistent with CONFIG_SAM34_RCFAST8/4M
# endif
# define NEED_RCFAST 1
# define SAM_RCFAST_RANGE SCIF_RCFASTCFG_FRANGE_12MHZ
# define SAM_RCFAST_FREQUENCY SAM_RCFAST12M_FREQUENCY
#elif defined(BOARD_SYSCLK_SOURCE_FCFAST8M)
# if defined(CONFIG_SAM34_RCFAST12M) || defined(CONFIG_SAM34_RCFAST4M)
# error BOARD_SYSCLK_SOURCE_FCFAST8M inconsistent with CONFIG_SAM34_RCFAST12/4M
# endif
# define NEED_RCFAST 1
# define SAM_RCFAST_RANGE SCIF_RCFASTCFG_FRANGE_8MHZ
# define SAM_RCFAST_FREQUENCY SAM_RCFAST8M_FREQUENCY
#elif defined(BOARD_SYSCLK_SOURCE_FCFAST4M)
# if defined(CONFIG_SAM34_RCFAST12M) || defined(CONFIG_SAM34_RCFAST8M)
# error BOARD_SYSCLK_SOURCE_FCFAST4M inconsistent with CONFIG_SAM34_RCFAST12/8M
# endif
# define NEED_RCFAST 1
# define SAM_RCFAST_RANGE SCIF_RCFASTCFG_FRANGE_4MHZ
# define SAM_RCFAST_FREQUENCY SAM_RCFAST4M_FREQUENCY
#elif defined(CONFIG_SAM34_RCFAST12M)
# define NEED_RCFAST 1
# define SAM_RCFAST_RANGE SCIF_RCFASTCFG_FRANGE_12MHZ
# define SAM_RCFAST_FREQUENCY SAM_RCFAST12M_FREQUENCY
#elif defined(CONFIG_SAM34_RCFAST8M)
# define NEED_RCFAST 1
# define SAM_RCFAST_RANGE SCIF_RCFASTCFG_FRANGE_8MHZ
# define SAM_RCFAST_FREQUENCY SAM_RCFAST8M_FREQUENCY
#elif defined(CONFIG_SAM34_RCFAST4M)
# define NEED_RCFAST 1
# define SAM_RCFAST_RANGE SCIF_RCFASTCFG_FRANGE_4MHZ
# define SAM_RCFAST_FREQUENCY SAM_RCFAST4M_FREQUENCY
#endif
/* RC1M. The 1M RC oscillator may be used as the system block or
* may be the source clock for GLCK9 that drives PLL0
*
* By selecting CONFIG_SAM34_RC1M, you can also force the clock to be
* enabled at boot time.
*/
#if defined(CONFIG_SAM34_RC1M) || defined(BOARD_SYSCLK_SOURCE_RC1M) || \
defined(BOARD_GLCK9_SOURCE_RC1M)
# define NEED_RC1M 1
#endif
/* RC32K. The 32KHz RC oscillator may be used as the input to DFLL0
* or as the input to GCLK9 that drives PLL0.
*
* By selecting CONFIG_SAM34_RC32K, you can also force the clock to be
* enabled at boot time.
*/
#if defined(CONFIG_SAM34_RC32K) || defined(BOARD_DFLL0_SOURCE_RC32K) || \
defined(BOARD_GLCK9_SOURCE_RC32K)
# define NEED_RC32K 1
#endif
/* GCLK9. May used as a source clock for PLL0 */
#ifdef BOARD_PLL0_SOURCE_GCLK9
# define NEED_GLCK9 1
#endif
#ifdef NEED_GLCK9
# if defined(BOARD_GLCK9_SOURCE_RCSYS)
# define SAM_GCLK9_SOURCE_VALUE SCIF_GCCTRL_OSCSEL_RCSYS
# define SAM_GCLK9_FREQUENCY SAM_RCSYS_FREQUENCY
# elif defined(BOARD_GLCK9_SOURCE_OSC32K)
# define SAM_GCLK9_SOURCE_VALUE SCIF_GCCTRL_OSCSEL_OSC32K
# define SAM_GCLK9_FREQUENCY BOARD_OSC32_FREQUENCY
# elif defined(BOARD_GLCK9_SOURCE_DFLL0)
# error BOARD_GLCK9_SOURCE_DFLL0 is not supported
# elif defined(BOARD_GLCK9_SOURCE_OSC0)
# define SAM_GCLK9_SOURCE_VALUE SCIF_GCCTRL_OSCSEL_OSC0
# define SAM_GCLK9_FREQUENCY BOARD_OSC0_FREQUENCY
# elif defined(BOARD_GLCK9_SOURCE_RC80M)
# define SAM_GCLK9_SOURCE_VALUE SCIF_GCCTRL_OSCSEL_RC80M
# define SAM_GCLK9_FREQUENCY SAM_RC80M_FREQUENCY
# elif defined(BOARD_GLCK9_SOURCE_RCFAST)
# error BOARD_GLCK9_SOURCE_RCFAST is not supported (needs RCFAST configuration)
# elif defined(BOARD_GLCK9_SOURCE_RC1M)
# define SAM_GCLK9_SOURCE_VALUE SCIF_GCCTRL_OSCSEL_RC1M
# define SAM_GCLK9_FREQUENCY SAM_RCFAST_FREQUENCY
# elif defined(BOARD_GLCK9_SOURCE_CPUCLK)
# define SAM_GCLK9_SOURCE_VALUE SCIF_GCCTRL_OSCSEL_CPUCLK
# define SAM_GCLK9_FREQUENCY BOARD_CPU_FREQUENCY
# elif defined(BOARD_GLCK9_SOURCE_HSBCLK)
# error BOARD_GLCK9_SOURCE_HSBCLK is not supported (REVISIT)
# elif defined(BOARD_GLCK9_SOURCE_PBACLK)
# define SAM_GCLK9_SOURCE_VALUE SCIF_GCCTRL_OSCSEL_PBACLK
# define SAM_GCLK9_FREQUENCY BOARD_PBA_FREQUENCY
# elif defined(BOARD_GLCK9_SOURCE_PBBCLK)
# define SAM_GCLK9_SOURCE_VALUE SCIF_GCCTRL_OSCSEL_PBBCLK
# define SAM_GCLK9_FREQUENCY BOARD_PBB_FREQUENCY
# elif defined(BOARD_GLCK9_SOURCE_PBCCLK)
# define SAM_GCLK9_SOURCE_VALUE SCIF_GCCTRL_OSCSEL_PBCCLK
# define SAM_GCLK9_FREQUENCY BOARD_PBC_FREQUENCY
# elif defined(BOARD_GLCK9_SOURCE_PBDCLK)
# define SAM_GCLK9_SOURCE_VALUE SCIF_GCCTRL_OSCSEL_PBDCLK
# define SAM_GCLK9_FREQUENCY BOARD_PBD_FREQUENCY
# elif defined(BOARD_GLCK9_SOURCE_RC32K)
# define SAM_GCLK9_SOURCE_VALUE SCIF_GCCTRL_OSCSEL_RC32K
# define SAM_GCLK9_FREQUENCY SAM_RC32K_FREQUENCY
# else
# error Missing GCLK9 source
# endif
#endif
/* PLL0 */
#ifdef BOARD_SYSCLK_SOURCE_PLL0
/* PLL0 source */
# if defined(BOARD_PLL0_SOURCE_OSC0)
# define SAM_PLL0_SOURCE SCIF_PLL0_PLLOSC_OSC0
# define SAM_PLL0_SOURCE_FREQUENCY BOARD_OSC0_FREQUENCY
# elif defined(BOARD_PLL0_SOURCE_GCLK9)
# define SAM_PLL0_SOURCE SCIF_PLL0_PLLOSC_GCLK9
# define SAM_PLL0_SOURCE_FREQUENCY SAM_GCLK9_FREQUENCY
# else
# error Missing PLL0 source
# endif
/* PLL0 Multipler and Divider */
# if !defined(BOARD_PLL0_MUL)
# error BOARD_PLL0_MUL is not defined
# elif BOARD_PLL0_MUL <= 2 || BOARD_PLL0_MUL > 16
# error BOARD_PLL0_MUL is out of range
# endif
# if !defined(BOARD_PLL0_DIV)
# error BOARD_PLL0_DIV is not defined
# elif BOARD_PLL0_DIV < 1 || BOARD_PLL0_DIV > 15
# error BOARD_PLL0_DIV is out of range
# endif
/* PLL0 frequency ranges */
# define SAM_PLL0_MIN_FREQUENCY 40000000
# define SAM_PLL0_MAX_FREQUENCY 240000000
/* PLL0 VCO frequency */
# define SAM_PLL0_VCO_DIV1_FREQUENCY \
(SAM_PLL0_SOURCE_FREQUENCY * BOARD_PLL0_MUL / BOARD_PLL0_DIV)
# if (SAM_PLL0_VCO_DIV1_FREQUENCY < SAM_PLL0_MIN_FREQUENCY) || \
(SAM_PLL0_VCO_DIV1_FREQUENCY > SAM_PLL0_MAX_FREQUENCY)
# error PLL0 VCO frequency is out of range
# endif
/* PLL0 Options:
*
* PLL0 supports an option to divide the frequency output by 2. We
* will do this division to bring the internal VCO frequency up to the
* minimum value
*
* PLL0 operates in two frequency ranges as determined by
* SCIF_PLL0_PLLOPT_FVO:
*
* 0: 80MHz < fvco < 180MHz
* 1: 160MHz < fvco < 240MHz
*
* Select the correct frequncy range using the recommended threshold
* value.
*/
# if SAM_PLL0_VCO_DIV1_FREQUENCY < (2*SAM_PLL0_MIN_FREQUENCY) && BOARD_PLL0_MUL <= 8
# define SAM_PLL0_VCO_FREQUENCY (2 * SAM_PLL0_VCO_DIV1_FREQUENCY)
# define SAM_PLL0_MUL (2 * BOARD_PLL0_MUL)
# if SAM_PLL0_VCO_FREQUENCY > (SAM_PLL0_VCO_RANGE_THRESHOLD / 2)
# define SAM_PLL0_OPTIONS (SCIF_PLL0_PLLOPT_DIV2 | SCIF_PLL0_PLLOPT_FVO)
# else
# define SAM_PLL0_OPTIONS SCIF_PLL0_PLLOPT_DIV2
# endif
# else
# define SAM_PLL0_VCO_FREQUENCY SAM_PLL0_VCO_DIV1_FREQUENCY
# define SAM_PLL0_MUL BOARD_PLL0_MUL
# if SAM_PLL0_VCO_FREQUENCY > SAM_PLL0_VCO_RANGE_THRESHOLD
# define SAM_PLL0_OPTIONS SCIF_PLL0_PLLOPT_FVO
# else
# define SAM_PLL0_OPTIONS 0
# endif
# endif
#endif
/* DFLL0 */
#ifdef BOARD_SYSCLK_SOURCE_DFLL0
/* DFLL0 reference clock */
# if defined(BOARD_DFLL0_SOURCE_RCSYS)
# define SAM_DFLLO_REFCLK SCIF_GCCTRL_OSCSEL_RCSYS
# elif defined(BOARD_DFLL0_SOURCE_OSC32K)
# define SAM_DFLLO_REFCLK SCIF_GCCTRL_OSCSEL_OSC32K
# elif defined(BOARD_DFLL0_SOURCE_OSC0)
# define SAM_DFLLO_REFCLK SCIF_GCCTRL_OSCSEL_OSC0
# elif defined(BOARD_DFLL0_SOURCE_RC80M)
# define SAM_DFLLO_REFCLK SCIF_GCCTRL_OSCSEL_RC80M
# elif defined(BOARD_DFLL0_SOURCE_RC32K)
# define SAM_DFLLO_REFCLK SCIF_GCCTRL_OSCSEL_RC32K
# else
# error No DFLL0 source for reference clock defined
# endif
#endif
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Global Variables
****************************************************************************/
/****************************************************************************
* Private Variables
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: sam_picocache
*
* Description:
* Initialiaze the PICOCACHE.
*
****************************************************************************/
#ifdef CONFIG_SAM34_PICOCACHE
static inline void sam_picocache(void)
{
/* Enable clocking to the PICOCACHE */
sam_hsb_enableperipheral(PM_HSBMASK_HRAMC1);
sam_pbb_enableperipheral(PM_PBBMASK_HRAMC1);
/* Enable the PICOCACHE and wait for it to become ready */
putreg32(PICOCACHE_CTRL_CEN, SAM_PICOCACHE_CTRL);
while ((getreg32(SAM_PICOCACHE_SR) & PICOCACHE_SR_CSTS) == 0);
}
#else
# define sam_picocache()
#endif
/****************************************************************************
* Name: sam_enableosc0
*
* Description:
* Initialiaze OSC0 settings per the definitions in the board.h file.
*
****************************************************************************/
#ifdef NEED_OSC0
static inline void sam_enableosc0(void)
{
uint32_t regval;
/* Enable and configure OSC0 */
regval = SAM_OSC0_STARTUP_VALUE | SAM_OSC0_GAIN_VALUE | SAM_OSC0_MODE_VALUE |
SCIF_OSCCTRL0_OSCEN;
putreg32(SCIF_UNLOCK_KEY(0xaa) | SCIF_UNLOCK_ADDR(SAM_SCIF_OSCCTRL0_OFFSET),
SAM_SCIF_UNLOCK);
putreg32(regval, SAM_SCIF_OSCCTRL0);
/* Wait for OSC0 to be ready */
while (getreg32(SAM_SCIF_PCLKSR) & SCIF_INT_OSC0RDY) == 0);
}
#endif
/****************************************************************************
* Name: sam_enableosc32
*
* Description:
* Initialiaze the 32KHz oscillator per settings in the board.h header
* file.
*
****************************************************************************/
#ifdef NEED_OSC32K
static inline void sam_enableosc32(void)
{
uint32_t regval;
/* Set up the OSCCTRL32 register using settings from the board.h file.
* Also enable the oscillator and provide bother the 32KHz and 1KHz output.
*/
regval = SAM_OSC32_STARTUP_VALUE | BOARD_OSC32_SELCURR | SAM_OSC32_MODE_VALUE |
BSCIF_OSCCTRL32_EN1K | BSCIF_OSCCTRL32_EN32K |
BSCIF_OSCCTRL32_OSC32EN;
putreg32(BSCIF_UNLOCK_KEY(0xaa) | BSCIF_UNLOCK_ADDR(SAM_BSCIF_OSCCTRL32_OFFSET),
SAM_BSCIF_UNLOCK);
putreg32(regval, SAM_BSCIF_OSCCTRL32);
/* Wait for OSC32 to be ready */
while ((getreg32(SAM_BSCIF_PCLKSR) & BSCIF_INT_OSC32RDY) == 0);
}
#endif
/****************************************************************************
* Name: sam_enablerc80m
*
* Description:
* Initialiaze the 80 MHz RC oscillator per settings in the board.h header
* file.
*
****************************************************************************/
#ifdef NEED_RC80M
static inline void sam_enablerc80m(void)
{
uint32_t regval;
/* Configure and enable RC80M */
regval = getreg32(SAM_SCIF_RC80MCR);
putreg32(SCIF_UNLOCK_KEY(0xaa) | SCIF_UNLOCK_ADDR(SAM_SCIF_RC80MCR_OFFSET),
SAM_SCIF_UNLOCK);
putreg32(regval | SCIF_RC80MCR_EN, SAM_SCIF_RC80MCR);
/* Wait for OSC32 to be ready */
while (getreg32(SAM_SCIF_RC80MCR) & SCIF_RC80MCR_EN) == 0);
}
#endif
/****************************************************************************
* Name: sam_enablerc80m
*
* Description:
* Initialiaze the 12/8/4 RC fast oscillator per settings in the board.h
* header file.
*
****************************************************************************/
#ifdef NEED_RCFAST
static inline void sam_enablercfast(void)
{
uint32_t regval;
/* Configure and enable RCFAST */
regval = getreg32(SAM_SCIF_RCFASTCFG);
regval &= ~SCIF_RCFASTCFG_FRANGE_MASK;
regval |= (SAM_RCFAST_RANGE | SCIF_RCFASTCFG_EN);
putreg32(SCIF_UNLOCK_KEY(0xaa) | SCIF_UNLOCK_ADDR(SAM_SCIF_RCFASTCFG_OFFSET),
SAM_SCIF_UNLOCK);
putreg32(regval, SAM_SCIF_RCFASTCFG);
/* Wait for RCFAST to be ready */
while (getreg32(SAM_SCIF_RCFASTCFG) & SCIF_RCFASTCFG_EN) == 0);
}
#endif
/****************************************************************************
* Name: sam_enablerc1m
*
* Description:
* Initialiaze the 1M RC oscillator per settings in the board.h header
* file.
*
****************************************************************************/
#ifdef NEED_RC1M
static inline void sam_enablerc1m(void)
{
uint32_t regval;
/* Configure and enable RC1M */
regval = getreg32(SAM_BSCIF_RC1MCR);
regval &= ~BSCIF_RCFASTCFG_FRANGE_MASK;
regval |= (SAM_RCFAST_RANGE | BSCIF_RCFASTCFG_EN);
putreg32(BSCIF_UNLOCK_KEY(0xaa) | BSCIF_UNLOCK_ADDR(SAM_BSCIF_RC1MCR_OFFSET),
SAM_BSCIF_UNLOCK);
putreg32(regval | BSCIF_RC1MCR_CLKOEN, SAM_BSCIF_RC1MCR);
/* Wait for RCFAST to be ready */
while (getreg32(SAM_BSCIF_RC1MCR) & BSCIF_RC1MCR_CLKOEN) == 0);
}
#endif
/****************************************************************************
* Name: sam_enablerc32k
*
* Description:
* Initialiaze the 23KHz RC oscillator per settings in the board.h header
* file.
*
****************************************************************************/
#ifdef NEED_RC32K
static inline void sam_enablerc32k(void)
{
uint32_t regval;
/* Configure and enable RC32K */
regval = getreg32(SAM_BSCIF_RC32KCR);
putreg32(BSCIF_UNLOCK_KEY(0xaa) | BSCIF_UNLOCK_ADDR(SAM_BSCIF_RC32KCR_OFFSET),
SAM_BSCIF_UNLOCK);
putreg32(regval | BSCIF_RC32KCR_EN32K | BSCIF_RC32KCR_EN, SAM_BSCIF_RC32KCR);
/* Wait for RCFAST to be ready */
while (getreg32(SAM_BSCIF_RC32KCR) & BSCIF_RC32KCR_EN) == 0);
}
#endif
/****************************************************************************
* Name: sam_enableglck9
*
* Description:
* Enable GLCK9.
*
****************************************************************************/
#ifdef NEED_GLCK9
static inline void sam_enableglck9(void)
{
/* Enable the generic clock using the source specified in the board.h
* file. No division is used so that the GCLK9 frequency is the same
* as the source frequency.
*/
putreg32(SAM_GCLK9_SOURCE_VALUE | SCIF_GCCTRL_CEN, SAM_SCIF_GCCTRL9);
}
#endif
/****************************************************************************
* Name: sam_enablepll0 (and its helper sam_pll0putreg())
*
* Description:
* Initialiaze PLL0 settings per the definitions in the board.h file.
*
****************************************************************************/
#ifdef BOARD_SYSCLK_SOURCE_PLL0
static inline void sam_pll0putreg(uint32_t regval, uint32_t regaddr,
uint32_t regoffset)
{
putreg32(SCIF_UNLOCK_KEY(0xaa) | SCIF_UNLOCK_ADDR(regoffset),
SAM_SCIF_UNLOCK);
putreg32(regval, regaddr);
}
static inline void sam_enablepll0(void)
{
uint32_t regval;
/* Clear the PLL0 control register */
sam_pll0putreg(0, SAM_SCIF_PLL0, SAM_SCIF_PLL0_OFFSET);
/* Write the selected options */
regval = getreg32(SAM_SCIF_PLL0);
regval &= SCIF_PLL0_PLLOPT_MASK;
regval |= SAM_PLL0_OPTIONS;
sam_pll0putreg(regval, SAM_SCIF_PLL0, SAM_SCIF_PLL0_OFFSET);
/* Set up the multiers and dividers */
regval = getreg32(SAM_SCIF_PLL0);
regval &= ~(SCIF_PLL0_PLLOSC_MASK | SCIF_PLL0_PLLDIV_MASK | SCIF_PLL0_PLLMUL_MASK);
regval |= ((SAM_PLL0_MUL - 1) << SCIF_PLL0_PLLMUL_SHIFT) |
(BOARD_DFLL0_DIV << SCIF_PLL0_PLLDIV_SHIFT) |
SCIF_PLL0_PLLCOUNT_MAX | SAM_PLL0_SOURCE;
sam_pll0putreg(regval, SAM_SCIF_PLL0, SAM_SCIF_PLL0_OFFSET);
/* And, finally, enable PLL0 */
regval = getreg32(SAM_SCIF_PLL0);
regval |= SCIF_PLL_PLLEN;
sam_pll0putreg(regval, SAM_SCIF_PLL0, SAM_SCIF_PLL0_OFFSET);
/* Wait for PLL0 to become locked */
while ((getreg32(SAM_SCIF_PCLKSR) & SCIF_INT_PLL0LOCK) == 0);
}
#endif
/****************************************************************************
* Name: sam_enabledfll0 (and its helper sam_dfll0_putreg32())
*
* Description:
* Initialiaze DFLL0 settings per the definitions in the board.h file.
*
****************************************************************************/
#ifdef BOARD_SYSCLK_SOURCE_DFLL0
static inline void sam_dfll0_putreg32(uint32_t regval, uint32_t regaddr,
uint32_t regoffset)
{
/* Wait until DFLL0 is completes the last setting */
while ((getreg32(SAM_SCIF_PCLKSR) & SCIF_INT_DFLL0RDY) == 0);
/* Then unlock the register and write the next value */
putreg32(SCIF_UNLOCK_KEY(0xaa) | SCIF_UNLOCK_ADDR(regoffset),
SAM_SCIF_UNLOCK);
putreg32(regval, regaddr);
}
static inline void sam_enabledfll0(void)
{
uint32_t regval;
uint32_t conf;
/* Set up generic clock source with specified reference clock
* and divider.
*/
putreg32(0, SAM_SCIF_GCCTRL0);
/* Set the generic clock 0 source */
regval = getreg32(SAM_SCIF_GCCTRL0);
regval &= ~SCIF_GCCTRL_OSCSEL_MASK;
regval |= SAM_DFLLO_REFCLK;
putreg32(regval, SAM_SCIF_GCCTRL0);
/* Get the generic clock 0 divider */
regval = getreg32(SAM_SCIF_GCCTRL0);
regval &= ~(SCIF_GCCTRL_DIVEN | SCIF_GCCTRL_DIV_MASK);
#if BOARD_DFLL0_DIV > 1
regval |= SCIF_GCCTRL_DIVEN;
regval |= SCIF_GCCTRL_DIV(((BOARD_DFLL0_DIV + 1) / 2) - 1);
#endif
putreg32(regval, SAM_SCIF_GCCTRL0);
/* Sync before reading a dfll conf register */
putreg32(SCIF_DFLL0SYNC_SYNC, SAM_SCIF_DFLL0SYNC);
while ((getreg32(SAM_SCIF_PCLKSR) & SCIF_INT_DFLL0RDY) == 0);
/* Select Closed Loop Mode */
conf = getreg32(SAM_SCIF_DFLL0CONF);
conf &= ~SCIF_DFLL0CONF_RANGE_MASK;
conf |= SCIF_DFLL0CONF_MODE;
/* Select the DFLL0 Frequency Range */
#if BOARD_DFLL0_FREQUENCY < SCIF_DFLL0CONF_MAX_RANGE3
conf |= SCIF_DFLL0CONF_RANGE3;
#elif BOARD_DFLL0_FREQUENCY < SCIF_DFLL0CONF_MAX_RANGE2
conf |= SCIF_DFLL0CONF_RANGE2;
#elif BOARD_DFLL0_FREQUENCY < SCIF_DFLL0CONF_MAX_RANGE1
conf |= SCIF_DFLL0CONF_RANGE1;
#else
conf |= SCIF_DFLL0CONF_RANGE0;
#endif
/* Enable the reference generic clock 0 */
regval = getreg32(SAM_SCIF_GCCTRL0);
regval |= SCIF_GCCTRL_CEN;
putreg32(regval, SAM_SCIF_GCCTRL0);
/* Enable DFLL0. Here we assume DFLL0RDY because the DFLL was disabled
* before this function was called.
*/
putreg32(SCIF_UNLOCK_KEY(0xaa) | SCIF_UNLOCK_ADDR(SAM_SCIF_DFLL0CONF_OFFSET),
SAM_SCIF_UNLOCK);
putreg32(SCIF_DFLL0CONF_EN, SAM_SCIF_DFLL0CONF);
/* Configure DFLL0. Note that now we do have to wait for DFLL0RDY before
* every write.
*
* Set the initial coarse and fine step lengths to 4. If this is set
* too high, DFLL0 may fail to lock.
*/
sam_dfll0_putreg32(SCIF_DFLL0STEP_CSTEP(4) | SCIF_DFLL0STEP_FSTEP(4),
SAM_SCIF_DFLL0STEP,
SAM_SCIF_DFLL0STEP_OFFSET);
/* Set the DFLL0 multipler register */
sam_dfll0_putreg32(BOARD_DFLL0_MUL, SAM_SCIF_DFLL0MUL,
SAM_SCIF_DFLL0MUL_OFFSET);
/* Set the multipler and spread spectrum generator control registers */
sam_dfll0_putreg32(0, SAM_SCIF_DFLL0SSG, SAM_SCIF_DFLL0SSG_OFFSET);
/* Finally, set the DFLL0 configuration */
sam_dfll0_putreg32(conf | SCIF_DFLL0CONF_EN,
SAM_SCIF_DFLL0CONF, SAM_SCIF_DFLL0CONF_OFFSET);
/* Wait until we are locked on the fine value */
while ((getreg32(SAM_SCIF_PCLKSR) & SCIF_INT_DFLL0LOCKF) == 0);
}
#endif
/****************************************************************************
* Name: sam_setdividers
*
* Description:
* Configure derived clocks.
*
****************************************************************************/
static inline void sam_setdividers(void)
{
uint32_t cpusel;
uint32_t pbasel;
uint32_t pbbsel;
uint32_t pbcsel;
uint32_t pbdsel;
/* Get the register setting for each divider value */
#if BOARD_CPU_SHIFT > 0
cpusel = (PM_CPUSEL(BOARD_CPU_SHIFT - 1)) | PM_CPUSEL_DIV;
#else
cpusel = 0;
#endif
#if BOARD_PBA_SHIFT > 0
pbasel = (PM_PBSEL(BOARD_PBA_SHIFT - 1)) | PM_PBSEL_DIV;
#else
pbasel = 0;
#endif
#if BOARD_PBB_SHIFT >0
pbbsel = (PM_PBSEL(BOARD_PBB_SHIFT - 1)) | PM_PBSEL_DIV;
#else
pbbsel = 0;
#endif
#if BOARD_PBC_SHIFT > 0
pbcsel = (PM_PBSEL(BOARD_PBC_SHIFT - 1)) | PM_PBSEL_DIV;
#else
pbcsel = 0;
#endif
#if BOARD_PBD_SHIFT > 0
pbdsel = (PM_PBSEL(BOARD_PBD_SHIFT - 1)) | PM_PBSEL_DIV;
#else
pbdsel = 0;
#endif
/* Then set the divider values. */
putreg32(PM_UNLOCK_KEY(0xaa) | PM_UNLOCK_ADDR(SAM_PM_CPUSEL_OFFSET), SAM_PM_UNLOCK);
putreg32(cpusel, SAM_PM_CPUSEL);
putreg32(PM_UNLOCK_KEY(0xaa) | PM_UNLOCK_ADDR(SAM_PM_PBASEL_OFFSET), SAM_PM_UNLOCK);
putreg32(pbasel, SAM_PM_PBASEL);
putreg32(PM_UNLOCK_KEY(0xaa) | PM_UNLOCK_ADDR(SAM_PM_PBBSEL_OFFSET), SAM_PM_UNLOCK);
putreg32(pbbsel, SAM_PM_PBBSEL);
putreg32(PM_UNLOCK_KEY(0xaa) | PM_UNLOCK_ADDR(SAM_PM_PBCSEL_OFFSET), SAM_PM_UNLOCK);
putreg32(pbcsel, SAM_PM_PBCSEL);
putreg32(PM_UNLOCK_KEY(0xaa) | PM_UNLOCK_ADDR(SAM_PM_PBDSEL_OFFSET), SAM_PM_UNLOCK);
putreg32(pbdsel, SAM_PM_PBDSEL);
}
/****************************************************************************
* Name: sam_enable_fastwakeup
*
* Description:
* Enable FLASH fast wakeup mode.
*
****************************************************************************/
static inline void sam_enable_fastwakeup(void)
{
uint32_t regval;
regval = getreg32(SAM_BPM_PMCON);
regval |= BPM_PMCON_FASTWKUP;
putreg32(BPM_UNLOCK_KEY(0xaa) | BPM_UNLOCK_ADDR(SAM_BPM_PMCON_OFFSET),
SAM_BPM_UNLOCK);
putreg32(regval, SAM_BPM_PMCON);
}
/****************************************************************************
* Name: set_flash_waitstate
*
* Description:
* Setup one or two FLASH wait states.
*
****************************************************************************/
static inline void set_flash_waitstate(bool waitstate)
{
uint32_t regval;
/* Set or clear the FLASH wait state (FWS) bit in the FLASH control
* register (FCR).
*/
regval = getreg32(SAM_FLASHCALW_FCR);
if (waitstate)
{
regval |= FLASHCALW_FCR_FWS;
}
else
{
regval &= ~FLASHCALW_FCR_FWS;
}
putreg32(regval, SAM_FLASHCALW_FCR);
}
/****************************************************************************
* Name: sam_flash_readmode
*
* Description:
* Send a FLASH command to enable to disable high speed FLASH read mode.
*
****************************************************************************/
static inline void sam_flash_readmode(uint32_t command)
{
uint32_t regval;
/* Make sure that any previous FLASH operation is completed */
while ((getreg32(SAM_FLASHCALW_FSR) & FLASHCALW_FSR_FRDY) == 0);
/* Write the specified FLASH command to the FCMD register */
regval = getreg32(SAM_FLASHCALW_FCMD);
regval &= ~FLASHCALW_FCMD_CMD_MASK;
regval |= (FLASHCALW_FCMD_KEY | command);
putreg32(regval, SAM_FLASHCALW_FCMD);
/* Wait for this FLASH operation to complete */
while ((getreg32(SAM_FLASHCALW_FSR) & FLASHCALW_FSR_FRDY) == 0);
}
/****************************************************************************
* Name: sam_flash_config
*
* Description:
* Configure FLASH read mode and wait states.
*
* Maximum CPU frequency for 0 and 1 FLASH wait states (FWS) in various modes
* (Table 42-30 in the big data sheet).
*
* ------- ------------------- ---------- ----------
* Power Flash Read Mode Flash Maximum
* Sclaing Wait Operating
* Mode HSEN HSDIS FASTWKUP States Frequency
* ------- ---- ----- -------- ---------- ----------
* PS0 X X 1 12MHz
* " " X 0 18MHz
* " " X 1 36MHz
* PS1 X X 1 12MHz
* " " X 0 8MHz
* " " X 1 12MHz
* PS2 X 0 24Mhz
* " " X 1 48MHz
* ------- ---- ----- -------- ---------- ----------
*
****************************************************************************/
static inline void sam_flash_config(uint32_t cpuclock, uint32_t psm, bool fastwkup)
{
bool waitstate;
uint32_t command;
#ifdef CONFIG_SAM34_FLASH_HSEN
/* High speed flash read mode (with power scaling mode == 2). Set one
* wait state if the CPU clock frequency exceeds the threshold value
* and enable high speed read mode.
*/
waitstate = (cpuclock > FLASH_MAXFREQ_PS2_HSEN_FWS0);
command = FLASHCALW_FCMD_CMD_HSEN;
#else
/* Assume that we will select no wait states and that we will disable high-
* speed read mode.
*/
waitstate = false;
command = FLASHCALW_FCMD_CMD_HSDIS;
/* Handle power scaling mode == 0 FLASH configuration */
if (psm == 0)
{
/* Power scaling mode 0. We need to set wait state the CPU clock if
* the CPU frequency exceeds a threshold.
*/
if (cpuclock > FLASH_MAXFREQ_PS0_HSDIS_FWS0)
{
/* Set one wait state */
waitstate = true;
/* Enable high speed read mode if the frequency exceed the maximum
* for the low speed configuration. This mode is not documented
* in the data sheet, but I see that they do this in some Atmel
* code examples.
*/
if (cpuclock > FLASH_MAXFREQ_PS0_HSDIS_FWS1)
{
/* Enable high speed read mode. */
command = FLASHCALW_FCMD_CMD_HSEN;
}
}
/* The is below the threshold that requires one wait state. But we
* have to check a few more things.
*/
else
{
/* If FLASH wake-up mode is selected and the we are in the lower
* operating frequency for this mode, then set 1 waitate and
* disable high speed read mode.
*/
if ((fastwkup == true) &&
(cpuclock <= FLASH_MAXFREQ_PS1_HSDIS_FASTWKUP_FWS1))
{
/* Set one wait state */
waitstate = true;
}
}
}
/* Otherwise, this is power scaling mode 1 */
else /* if (psm == 1) */
{
/* If we are in the lower operating frequency range, then select
* zero wait states. Otherwise, select one wait state.
*/
if (cpuclock > FLASH_MAXFREQ_PS1_HSDIS_FWS0)
{
/* Set one wait state */
waitstate = true;
}
}
#endif
/* Set 0 or 1 waitstates */
set_flash_waitstate(waitstate);
/* Enable/disable the high-speed read mode. */
sam_flash_readmode(command);
}
/****************************************************************************
* Name: sam_mainclk
*
* Description:
* Select the main clock.
*
****************************************************************************/
static inline void sam_mainclk(uint32_t mcsel)
{
uint32_t regval;
regval = getreg32(SAM_PM_MCCTRL);
regval &= ~PM_MCCTRL_MCSEL_MASK;
regval |= mcsel;
putreg32(PM_UNLOCK_KEY(0xaa) | PM_UNLOCK_ADDR(SAM_PM_MCCTRL_OFFSET),
SAM_PM_UNLOCK);
putreg32(regval, SAM_PM_MCCTRL);
}
/****************************************************************************
* Name: sam_setpsm (and its helper, sam_instantiatepsm())
*
* Description:
* Switch to the selected power scaling mode.
*
****************************************************************************/
static __ramfunc__ void sam_instantiatepsm(uint32_t regval)
{
/* Set the BMP PCOM register (containing the new power scaling mode) */
putreg32(BPM_UNLOCK_KEY(0xaa) | BPM_UNLOCK_ADDR(SAM_BPM_PMCON_OFFSET),
SAM_BPM_UNLOCK);
putreg32(regval, SAM_BPM_PMCON);
/* Wait for new power scaling mode to become active. There should be
* timeout on this wait.
*/
while ((getreg32(SAM_BPM_SR) & BPM_INT_PSOK) == 0);
}
static inline void sam_setpsm(uint32_t psm)
{
uint32_t regval;
/* Setup the PMCON register content fo the new power scaling mode */
regval = getreg32(SAM_BPM_PMCON);
regval &= ~BPM_PMCON_PS_MASK;
regval |= (psm | BPM_PMCON_PSCM | BPM_PMCON_PSCREQ);
/* Then call the RAMFUNC sam_setpsm() to set the new power scaling mode */
sam_instantiatepsm(regval);
}
/****************************************************************************
* Name: sam_usbclock
*
* Description:
* Setup the USBB GCLK.
*
****************************************************************************/
#ifdef CONFIG_USBDEV
static inline void sam_usbclock(void)
{
uint32_t regval = 0;
#if defined(SAM_CLOCK_USB_PLL0) || defined(SAM_CLOCK_USB_PLL1)
regval |= PM_GCCTRL_PLLSEL;
#endif
#if defined(SAM_CLOCK_USB_OSC1) || defined(SAM_CLOCK_USB_PLL1)
regval |= PM_GCCTRL_OSCSEL;
#endif
#if SAM_CLOCK_USB_DIV > 0
u_avr32_pm_gcctrl.GCCTRL.diven = diven;
u_avr32_pm_gcctrl.GCCTRL.div = div;
#endif
putreg32(regval, SAM_PM_GCCTRL(SAM_PM_GCLK_USBB))
/* Enable USB GCLK */
regval = getreg32(SAM_PM_GCCTRL(SAM_PM_GCLK_USBB))
regval |= PM_GCCTRL_CEN;
putreg32(regval, SAM_PM_GCCTRL(SAM_PM_GCLK_USBB))
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sam_clockconfig
*
* Description:
* Called to initialize the SAM3/4. This does whatever setup is needed to
* put the SoC in a usable state. This includes the initialization of
* clocking using the settings in board.h.
*
****************************************************************************/
void sam_clockconfig(void)
{
uint32_t psm;
bool fastwkup;
/* Enable clocking to the PICOCACHE */
sam_picocache();
/* Configure dividers for derived clocks. These divider definitions must
* be provided in the board.h header file.
*/
sam_setdividers();
/* Select a power scaling mode and possible fast wakeup so that we get the
* best possible flash performance. The following table shows the maximum
* CPU frequency for 0 and 1 FLASH wait states (FWS) in various modes
* (Table 42-30 in the big data sheet).
*
* ------- ------------------- ---------- ----------
* Power Flash Read Mode Flash Maximum
* Sclaing Wait Operating
* Mode HSEN HSDIS FASTWKUP States Frequency
* ------- ---- ----- -------- ---------- ----------
* PS0 X X 1 12MHz
* " " X 0 18MHz
* " " X 1 36MHz
* PS1 X X 1 12MHz
* " " X 0 8MHz
* " " X 1 12MHz
* PS2 X 0 24Mhz
* " " X 1 48MHz
* ------- ---- ----- -------- ---------- ----------
*/
#ifdef CONFIG_SAM34_FLASH_HSEN
/* The high speed FLASH mode has been enabled. Select power scaling
* mode 2, no fast wakeup.
*/
psm = BPM_PMCON_PS2;
fastwkup = false;
#elif BOARD_CPU_FREQUENCY <= FLASH_MAXFREQ_PS1_HSDIS_FWS1
/* Not high speed mode and frequency is below the thrshold. We can go to
* power scaling mode 1.
*/
psm = BPM_PMCON_PS1;
# if BOARD_CPU_FREQUENCY > FLASH_MAXFREQ_PS1_HSDIS_FWS0
/* We need to enable fast wakeup */
sam_enable_fastwakeup()
fastwkup = true;
# endif
#else
/* Power scaling mode 0, disable high speed mode, no fast wakeup */
psm = BPM_PMCON_PS0;
fastwkup = false;
#endif
/* Enable clock sources:
*
* OSC0: Might by the system clock or the source clock for PLL0 or DFLL0
* OSC32: Might be source clock for DFLL0
*/
#if NEED_OSC0
/* Enable OSC0 using the settings in board.h */
sam_enableosc0();
#endif
#ifdef NEED_OSC32K
/* Enable the 32KHz oscillator using the settings in board.h */
sam_enableosc32();
#endif
#ifdef NEED_RC80M
/* Enable the 32KHz oscillator using the settings in board.h */
sam_enablerc80m();
#endif
#ifdef NEED_RCFAST
/* Enable the 12/8/4MHz RC fast oscillator using the settings in board.h */
sam_enablercrcfast();
#endif
#ifdef NEED_RC1M
/* Enable the 1MHz RC oscillator using the settings in board.h */
sam_enablerc1m();
#endif
#ifdef NEED_RC32K
/* Enable the 32KHz RC oscillator using the settings in board.h */
sam_enablerc32k();
#endif
#ifdef NEED_GLCK9
/* Enable the GLCK9 */
sam_enableglck9();
#endif
/* Switch to the system clock selected by the settings in the board.h
* header file.
*/
#if defined(BOARD_SYSCLK_SOURCE_RCSYS)
/* Since this function only executes at power up, we know that we are
* already running from RCSYS.
*/
// sam_mainclk(PM_MCCTRL_MCSEL_RCSYS);
#elif defined(BOARD_SYSCLK_SOURCE_OSC0)
/* Configure FLASH read mode and wait states */
sam_flash_config(BOARD_CPU_FREQUENCY, psm, fastwkup);
/* Then switch the main clock to OSC0 */
sam_mainclk(PM_MCCTRL_MCSEL_OSC0);
#elif defined(BOARD_SYSCLK_SOURCE_PLL0)
/* Enable PLL0 using the settings in board.h */
sam_enablepll0();
/* Configure FLASH read mode and wait states */
sam_flash_config(BOARD_CPU_FREQUENCY, psm, fastwkup);
/* Then switch the main clock to PLL0 */
sam_mainclk(PM_MCCTRL_MCSEL_PLL);
#elif defined(BOARD_SYSCLK_SOURCE_DFLL0)
/* Enable PLL0 using the settings in board.h */
sam_enabledfll0();
/* Configure FLASH read mode and wait states */
sam_flash_config(BOARD_CPU_FREQUENCY, psm, fastwkup);
/* Then switch the main clock to DFLL0 */
sam_mainclk(PM_MCCTRL_MCSEL_DFLL);
#elif defined(BOARD_SYSCLK_SOURCE_RC80M)
/* Configure FLASH read mode and wait states */
sam_flash_config(BOARD_CPU_FREQUENCY, psm, fastwkup);
/* Then switch the main clock to RCM80 */
sam_mainclk(PM_MCCTRL_MCSEL_RC80M);
#elif defined(BOARD_SYSCLK_SOURCE_FCFAST12M) || defined(BOARD_SYSCLK_SOURCE_FCFAST8M) || \
defined(BOARD_SYSCLK_SOURCE_FCFAST4M)
/* Configure FLASH read mode and wait states */
sam_flash_config(BOARD_CPU_FREQUENCY, psm, fastwkup);
/* Then switch the main clock to RCFAST */
sam_mainclk(PM_MCCTRL_MCSEL_RCFAST);
#elif defined(BOARD_SYSCLK_SOURCE_RC1M)
/* Configure FLASH read mode and wait states */
sam_flash_config(BOARD_CPU_FREQUENCY, psm, fastwkup);
/* Then switch the main clock to RC1M */
sam_mainclk(PM_MCCTRL_MCSEL_RC1M);
#else
# error "No SYSCLK source provided"
#endif
/* Switch to the selected power scaling mode */
sam_setpsm(psm);
/* Enable all selected peripheral cloks */
sam_init_periphclks();
/* Configure clocking to the USB controller */
#ifdef CONFIG_USBDEV
sam_usbc_enableclk();
#endif
}