/* * Copyright (c) 2016 Intel Corporation. * Copyright (c) 2013-2015 Wind River Systems, Inc. * * Licensed 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. */ /** * @file * @brief System/hardware module for Atmel SAM3 family processor * * This module provides routines to initialize and support board-level hardware * for the Atmel SAM3 family processor. */ #include #include #include #include #include /** * @brief Setup various clock on SoC. * * Setup the SoC clocks according to section 28.12 in datasheet. * * Assumption: * SLCK = 32.768kHz */ static ALWAYS_INLINE void clock_init(void) { uint32_t tmp; /* Note: * Magic numbers below are obtained by reading the registers * when the SoC was running the SAM-BA bootloader * (with reserved bits set to 0). */ #ifdef CONFIG_SOC_ATMEL_SAM3_EXT_SLCK /* This part is to switch the slow clock to using * the external 32 kHz crystal oscillator. */ /* Select external crystal */ __SUPC->cr = SUPC_CR_KEY | SUPC_CR_XTALSEL; /* Wait for oscillator to be stablized */ while (!(__SUPC->sr & SUPC_SR_OSCSEL)) ; #endif /* CONFIG_SOC_ATMEL_SAM3_EXT_SLCK */ #ifdef CONFIG_SOC_ATMEL_SAM3_EXT_MAINCK /* Start the external main oscillator */ __PMC->ckgr_mor = PMC_CKGR_MOR_KEY | PMC_CKGR_MOR_MOSCRCF_4MHZ | PMC_CKGR_MOR_MOSCRCEN | PMC_CKGR_MOR_MOSCXTEN | PMC_CKGR_MOR_MOSCXTST; /* Wait for main oscillator to be stablized */ while (!(__PMC->sr & PMC_INT_MOSCXTS)) ; /* Select main oscillator as source since it is more accurate * according to datasheet. */ __PMC->ckgr_mor = PMC_CKGR_MOR_KEY | PMC_CKGR_MOR_MOSCRCF_4MHZ | PMC_CKGR_MOR_MOSCRCEN | PMC_CKGR_MOR_MOSCXTEN | PMC_CKGR_MOR_MOSCXTST | PMC_CKGR_MOR_MOSCSEL; /* Wait for main oscillator to be selected */ while (!(__PMC->sr & PMC_INT_MOSCSELS)) ; #else /* Set main fast RC oscillator to 12 MHz */ __PMC->ckgr_mor = PMC_CKGR_MOR_KEY | PMC_CKGR_MOR_MOSCRCF_12MHZ | PMC_CKGR_MOR_MOSCRCEN; /* Wait for main fast RC oscillator to be stablized */ while (!(__PMC->sr & PMC_INT_MOSCRCS)) ; #endif /* CONFIG_SOC_ATMEL_SAM3_EXT_MAINCK */ /* Use PLLA as master clock. * According to datasheet, PMC_MCKR must not be programmed in * a single write operation. So it seems the safe way is to * get the system to use main clock (by setting CSS). Then set * the prescaler (PRES). Finally setting it back to using PLL. */ /* Switch to main clock first so we can setup PLL */ tmp = __PMC->mckr & ~PMC_MCKR_CSS_MASK; __PMC->mckr = tmp | PMC_MCKR_CSS_MAIN; /* Wait for clock selection complete */ while (!(__PMC->sr & PMC_INT_MCKRDY)) ; /* Setup PLLA */ __PMC->ckgr_pllar = PMC_CKGR_PLLAR_DIVA | PMC_CKGR_PLLAR_ONE | PMC_CKGR_PLLAR_MULA | PMC_CKGR_PLLAR_PLLACOUNT; /* Wait for PLL lock */ while (!(__PMC->sr & PMC_INT_LOCKA)) ; /* Setup prescaler */ tmp = __PMC->mckr & ~PMC_MCKR_PRES_MASK; __PMC->mckr = tmp | PMC_MCKR_PRES_CLK; /* Wait for main clock setup complete */ while (!(__PMC->sr & PMC_INT_MCKRDY)) ; /* Finally select PLL as clock source */ tmp = __PMC->mckr & ~PMC_MCKR_CSS_MASK; __PMC->mckr = tmp | PMC_MCKR_CSS_PLLA; /* Wait for main clock setup complete */ while (!(__PMC->sr & PMC_INT_MCKRDY)) ; } /** * @brief Perform basic hardware initialization at boot. * * This needs to be run from the very beginning. * So the init priority has to be 0 (zero). * * @return 0 */ static int atmel_sam3_init(struct device *arg) { uint32_t key; ARG_UNUSED(arg); /* Note: * Magic numbers below are obtained by reading the registers * when the SoC was running the SAM-BA bootloader * (with reserved bits set to 0). */ key = irq_lock(); /* Setup the vector table offset register (VTOR), * which is located at the beginning of flash area. */ _scs_relocate_vector_table((void *)CONFIG_FLASH_BASE_ADDRESS); /* Setup the flash controller. * The bootloader is running @ 48 MHz with * FWS == 2. * When running at 84 MHz, FWS == 4 seems * to be more stable, and allows the board * to boot. */ __EEFC0->fmr = 0x00000400; __EEFC1->fmr = 0x00000400; /* Clear all faults */ _ScbMemFaultAllFaultsReset(); _ScbBusFaultAllFaultsReset(); _ScbUsageFaultAllFaultsReset(); _ScbHardFaultAllFaultsReset(); /* Setup master clock */ clock_init(); /* Install default handler that simply resets the CPU * if configured in the kernel, NOP otherwise */ NMI_INIT(); irq_unlock(key); return 0; } SYS_INIT(atmel_sam3_init, PRIMARY, 0);