blob: 82109386098ab234fab9193fcd778de76475287d [file] [log] [blame]
Kévin Redon93717e42018-07-08 13:26:15 +02001/* ----------------------------------------------------------------------------
2 * ATMEL Microcontroller Software Support
3 * ----------------------------------------------------------------------------
4 * Copyright (c) 2009, Atmel Corporation
Kévin Redonad0958e2018-09-06 22:49:56 +02005 * Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
Kévin Redon93717e42018-07-08 13:26:15 +02006 *
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * - Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the disclaimer below.
14 *
15 * Atmel's name may not be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
21 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * ----------------------------------------------------------------------------
29 */
30
31/**
32 * \file
33 *
34 * Provides the low-level initialization function that called on chip startup.
35 */
36
37/*----------------------------------------------------------------------------
38 * Headers
39 *----------------------------------------------------------------------------*/
40
41#include "board.h"
42
43/*----------------------------------------------------------------------------
44 * Local definitions
45 *----------------------------------------------------------------------------*/
46
47#define BOARD_OSCOUNT (CKGR_MOR_MOSCXTST(0x8))
48#define BOARD_MCKR (PMC_MCKR_PRES_CLK | PMC_MCKR_CSS_PLLA_CLK)
49
Kévin Redone2b0f972018-08-28 19:13:06 +020050/** configure PLL to generate main clock based on main oscillator frequency */
51#if (BOARD_MAINOSC == 12000000) && (BOARD_MCK == 48000000)
Kévin Redon93717e42018-07-08 13:26:15 +020052#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
Kévin Redon33d1eb72018-07-08 13:58:12 +020053 | CKGR_PLLAR_MULA(8-1) \
54 | CKGR_PLLAR_PLLACOUNT(0x1) \
55 | CKGR_PLLAR_DIVA(2))
Kévin Redone2b0f972018-08-28 19:13:06 +020056#elif (BOARD_MAINOSC == 12000000) && (BOARD_MCK == 58000000)
Kévin Redon93717e42018-07-08 13:26:15 +020057#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
Kévin Redone2b0f972018-08-28 19:13:06 +020058 | CKGR_PLLAR_MULA(29-1) \
Kévin Redon33d1eb72018-07-08 13:58:12 +020059 | CKGR_PLLAR_PLLACOUNT(0x1) \
Kévin Redone2b0f972018-08-28 19:13:06 +020060 | CKGR_PLLAR_DIVA(6))
61#elif (BOARD_MAINOSC == 12000000) && (BOARD_MCK == 60000000)
Kévin Redon93717e42018-07-08 13:26:15 +020062#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
Kévin Redon33d1eb72018-07-08 13:58:12 +020063 | CKGR_PLLAR_MULA(10-1) \
64 | CKGR_PLLAR_PLLACOUNT(0x1) \
65 | CKGR_PLLAR_DIVA(2))
Kévin Redone2b0f972018-08-28 19:13:06 +020066#elif (BOARD_MAINOSC == 18432000) && (BOARD_MCK == 47923200)
67#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
68 | CKGR_PLLAR_MULA(13-1) \
69 | CKGR_PLLAR_PLLACOUNT(0x1) \
70 | CKGR_PLLAR_DIVA(5))
71#elif (BOARD_MAINOSC == 18432000) && (BOARD_MCK == 58982400)
72#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
73 | CKGR_PLLAR_MULA(16-1) \
74 | CKGR_PLLAR_PLLACOUNT(0x1) \
75 | CKGR_PLLAR_DIVA(5))
76#elif (BOARD_MAINOSC == 18432000) && (BOARD_MCK == 64512000)
77#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
78 | CKGR_PLLAR_MULA(7-1) \
79 | CKGR_PLLAR_PLLACOUNT(0x1) \
80 | CKGR_PLLAR_DIVA(2))
Kévin Redon93717e42018-07-08 13:26:15 +020081#else
Kévin Redone2b0f972018-08-28 19:13:06 +020082 #error "Please define PLLA config for your BOARD_MCK/MAINOSC frequency"
Kévin Redon93717e42018-07-08 13:26:15 +020083#endif
84
85#if (BOARD_MAINOSC == 12000000)
86#define PLLB_CFG (CKGR_PLLBR_DIVB(2)|CKGR_PLLBR_MULB(8-1)|CKGR_PLLBR_PLLBCOUNT_Msk)
87#elif (BOARD_MAINOSC == 18432000)
88#define PLLB_CFG (CKGR_PLLBR_DIVB(5)|CKGR_PLLBR_MULB(13-1)|CKGR_PLLBR_PLLBCOUNT_Msk)
89#else
90#error "Please configure PLLB for your MAINOSC freq"
91#endif
92
93/* Define clock timeout */
94#define CLOCK_TIMEOUT 0xFFFFFFFF
95
96/**
97 * \brief Configure 48MHz Clock for USB
98 */
99static void _ConfigureUsbClock(void)
100{
101 /* Enable PLLB for USB */
102 PMC->CKGR_PLLBR = PLLB_CFG;
103 while ((PMC->PMC_SR & PMC_SR_LOCKB) == 0) ;
104
105 /* USB Clock uses PLLB */
106 PMC->PMC_USB = PMC_USB_USBDIV(0) /* /1 (no divider) */
107 | PMC_USB_USBS; /* PLLB */
108}
109
110/*----------------------------------------------------------------------------
111 * Exported functions
112 *----------------------------------------------------------------------------*/
113
114/**
115 * \brief Performs the low-level initialization of the chip.
116 * This includes EFC and master clock configuration.
117 * It also enable a low level on the pin NRST triggers a user reset.
118 */
119extern WEAK void LowLevelInit( void )
120{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200121 uint32_t timeout = 0;
Kévin Redon93717e42018-07-08 13:26:15 +0200122
Kévin Redon33d1eb72018-07-08 13:58:12 +0200123 /* Configure the Supply Monitor to reset the CPU in case VDDIO is
124 * lower than 3.0V. As we run the board on 3.3V, any lower voltage
125 * might be some kind of leakage that creeps in some way, but is not
126 * the "official" power supply */
127 SUPC->SUPC_SMMR = SUPC_SMMR_SMTH_3_0V | SUPC_SMMR_SMSMPL_CSM |
Kévin Redon93717e42018-07-08 13:26:15 +0200128 SUPC_SMMR_SMRSTEN_ENABLE;
129
Kévin Redon33d1eb72018-07-08 13:58:12 +0200130 /* enable both LED and green LED */
131 PIOA->PIO_PER |= PIO_LED_RED | PIO_LED_GREEN;
132 PIOA->PIO_OER |= PIO_LED_RED | PIO_LED_GREEN;
133 PIOA->PIO_CODR |= PIO_LED_RED | PIO_LED_GREEN;
Kévin Redon93717e42018-07-08 13:26:15 +0200134
Kévin Redon33d1eb72018-07-08 13:58:12 +0200135 /* Set 3 FWS for Embedded Flash Access */
136 EFC->EEFC_FMR = EEFC_FMR_FWS(3);
Kévin Redon93717e42018-07-08 13:26:15 +0200137
Kévin Redon33d1eb72018-07-08 13:58:12 +0200138 /* Select external slow clock */
Kévin Redon93717e42018-07-08 13:26:15 +0200139/* if ((SUPC->SUPC_SR & SUPC_SR_OSCSEL) != SUPC_SR_OSCSEL_CRYST)
Kévin Redon33d1eb72018-07-08 13:58:12 +0200140 {
141 SUPC->SUPC_CR = (uint32_t)(SUPC_CR_XTALSEL_CRYSTAL_SEL | SUPC_CR_KEY(0xA5));
142 timeout = 0;
143 while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL_CRYST) );
144 }
Kévin Redon93717e42018-07-08 13:26:15 +0200145*/
146
147#ifndef qmod
Kévin Redon33d1eb72018-07-08 13:58:12 +0200148 /* Initialize main oscillator */
149 if ( !(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) )
150 {
151 PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN;
152 timeout = 0;
153 while (!(PMC->PMC_SR & PMC_SR_MOSCXTS) && (timeout++ < CLOCK_TIMEOUT));
154 }
Kévin Redon93717e42018-07-08 13:26:15 +0200155
Kévin Redon33d1eb72018-07-08 13:58:12 +0200156 /* Switch to 3-20MHz Xtal oscillator */
157 PIOB->PIO_PDR = (1 << 8) | (1 << 9);
158 PIOB->PIO_PUDR = (1 << 8) | (1 << 9);
159 PIOB->PIO_PPDDR = (1 << 8) | (1 << 9);
160 PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL;
161 /* wait for Main XTAL oscillator stabilization */
162 timeout = 0;
163 while (!(PMC->PMC_SR & PMC_SR_MOSCSELS) && (timeout++ < CLOCK_TIMEOUT));
Kévin Redon93717e42018-07-08 13:26:15 +0200164#else
Kévin Redon33d1eb72018-07-08 13:58:12 +0200165 /* QMOD has external 12MHz clock source */
166 PIOB->PIO_PDR = (1 << 9);
167 PIOB->PIO_PUDR = (1 << 9);
168 PIOB->PIO_PPDDR = (1 << 9);
169 PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTBY| CKGR_MOR_MOSCSEL;
Kévin Redon93717e42018-07-08 13:26:15 +0200170#endif
171
Kévin Redon33d1eb72018-07-08 13:58:12 +0200172 /* disable the red LED after main clock initialization */
173 PIOA->PIO_SODR = PIO_LED_RED;
Kévin Redon93717e42018-07-08 13:26:15 +0200174
Kévin Redon33d1eb72018-07-08 13:58:12 +0200175 /* "switch" to main clock as master clock source (should already be the case */
176 PMC->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK;
177 /* wait for master clock to be ready */
178 for ( timeout = 0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT) ; );
Kévin Redon93717e42018-07-08 13:26:15 +0200179
Kévin Redon33d1eb72018-07-08 13:58:12 +0200180 /* Initialize PLLA */
181 PMC->CKGR_PLLAR = BOARD_PLLAR;
182 /* Wait for PLLA to lock */
183 timeout = 0;
184 while (!(PMC->PMC_SR & PMC_SR_LOCKA) && (timeout++ < CLOCK_TIMEOUT));
Kévin Redon93717e42018-07-08 13:26:15 +0200185
Kévin Redon33d1eb72018-07-08 13:58:12 +0200186 /* Switch to main clock (again ?!?) */
187 PMC->PMC_MCKR = (BOARD_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK;
188 /* wait for master clock to be ready */
189 for ( timeout = 0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT) ; );
Kévin Redon93717e42018-07-08 13:26:15 +0200190
Kévin Redon33d1eb72018-07-08 13:58:12 +0200191 /* switch to PLLA as master clock source */
192 PMC->PMC_MCKR = BOARD_MCKR ;
193 /* wait for master clock to be ready */
194 for ( timeout = 0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT) ; );
Kévin Redon93717e42018-07-08 13:26:15 +0200195
Kévin Redon33d1eb72018-07-08 13:58:12 +0200196 /* Configure SysTick for 1ms */
197 SysTick_Config(BOARD_MCK/1000);
Kévin Redon93717e42018-07-08 13:26:15 +0200198
Kévin Redon33d1eb72018-07-08 13:58:12 +0200199 _ConfigureUsbClock();
Kévin Redon93717e42018-07-08 13:26:15 +0200200}
201
202/* SysTick based delay function */
203
204volatile uint32_t jiffies;
205
206/* Interrupt handler for SysTick interrupt */
207void SysTick_Handler(void)
208{
209 jiffies++;
210}
211
212void mdelay(unsigned int msecs)
213{
214 uint32_t jiffies_start = jiffies;
215 do {
216 } while ((jiffies - jiffies_start) < msecs);
217}