Skip to content

Commit 08df288

Browse files
committed
cpu/samd5x: support for using ext_osc + xosc + fdpll
1 parent a73e9bf commit 08df288

File tree

1 file changed

+46
-8
lines changed

1 file changed

+46
-8
lines changed

cpu/samd5x/cpu.c

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ the CPU frequency can't exceed it's frequency.
7474
/* Main clock > 48 MHz -> use DPLL, otherwise use DFLL */
7575
# define USE_DPLL (CLOCK_CORECLOCK > SAM0_DFLL_FREQ_HZ)
7676
# define USE_DFLL 1
77+
#ifndef USE_XOSC
7778
# define USE_XOSC 0
79+
#endif
7880

7981
# ifndef GCLK_TIMER_HZ
8082
# define GCLK_TIMER_HZ MHZ(8)
@@ -115,9 +117,18 @@ static void xosc32k_init(void)
115117
while (!(OSC32KCTRL->STATUS.reg & OSC32KCTRL_STATUS_XOSC32KRDY)) {}
116118
}
117119

120+
#ifndef XOSC0_EXT_OSC
121+
# define XOSC0_EXT_OSC (0)
122+
#endif
123+
124+
#ifndef XOSC1_EXT_OSC
125+
# define XOSC1_EXT_OSC (0)
126+
#endif
127+
118128
static void xosc_init(uint8_t idx)
119129
{
120130
uint32_t freq;
131+
bool xtal;
121132

122133
if (!USE_XOSC ||
123134
(idx == 0 && XOSC0_FREQUENCY == 0) ||
@@ -130,9 +141,17 @@ static void xosc_init(uint8_t idx)
130141

131142
if (idx == 0) {
132143
freq = XOSC0_FREQUENCY;
144+
xtal = !XOSC0_EXT_OSC;
133145
}
134146
else if (idx == 1) {
135147
freq = XOSC1_FREQUENCY;
148+
xtal = !XOSC1_EXT_OSC;
149+
}
150+
151+
if (xtal) {
152+
OSCCTRL->XOSCCTRL[idx].reg = OSCCTRL_XOSCCTRL_ENABLE;
153+
while (!(OSCCTRL->STATUS.vec.XOSCRDY & (idx + 1))) {}
154+
return;
136155
}
137156

138157
uint32_t reg = OSCCTRL_XOSCCTRL_XTALEN
@@ -204,6 +223,10 @@ static void fdpll_init_nolock(uint8_t idx, uint32_t f_cpu, uint8_t flags)
204223
OSCCTRL->Dpll[idx].DPLLCTRLA.reg = 0;
205224
while (OSCCTRL->Dpll[idx].DPLLSYNCBUSY.reg) {}
206225

226+
/* holds LDR 13 bit integer and 5 bit fractional part:
227+
* - integer part: ldr13_5 >> 5
228+
* - fractional part: ldr13_5 & 0x1f */
229+
uint32_t ldr13_5;
207230
uint32_t ctrlb = 0;
208231

209232
/* HW revision before F (A and D) might false unlock -> LBYPASS and WUF */
@@ -217,12 +240,25 @@ static void fdpll_init_nolock(uint8_t idx, uint32_t f_cpu, uint8_t flags)
217240
* (critical for some application not so much for other)*/
218241
if (EXTERNAL_OSC32_SOURCE) {
219242
/* Source the DPLL from 32kHz XOSC32 ( equivalent to ((f_cpu << 5) / 32768) ) */
220-
const uint32_t LDR = (f_cpu >> 10);
221-
OSCCTRL->Dpll[idx].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(LDR & 0x1F)
222-
| OSCCTRL_DPLLRATIO_LDR((LDR >> 5) - 1);
223-
243+
ldr13_5 = (f_cpu >> 10);
224244
ctrlb |= OSCCTRL_DPLLCTRLB_REFCLK_XOSC32;
225-
OSCCTRL->Dpll[idx].DPLLCTRLB.reg = ctrlb;
245+
}
246+
else if (XOSC1_FREQUENCY) {
247+
/* Source the DPLL from XOSC1 equivalent to ((f_cpu << 5) / 32768) ) */
248+
/* fCLK_DPLLn = fCKR × (LDR + 1 + LDRFRAC/32)*/
249+
/* fDIV = fXOSC / 2 * ( DIV + 1) */
250+
/* divide to 1 MHz then multiply to fcpu */
251+
const uint32_t div = (XOSC1_FREQUENCY / MHZ(1) / 2) -1;
252+
ldr13_5 = (f_cpu / MHZ(1)) << 5;
253+
ctrlb |= OSCCTRL_DPLLCTRLB_DIV(DIV) | OSCCTRL_DPLLCTRLB_REFCLK_XOSC1;
254+
}
255+
else if (XOSC0_FREQUENCY) {
256+
/* Source the DPLL from XOSC0 /* divide to 1 MHz then multiply to fcpu */
257+
/* fCLK_DPLLn = fCKR × (LDR + 1 + LDRFRAC/32)*/
258+
/* fDIV = fXOSC / 2 * ( DIV + 1) */
259+
const uint32_t div = (XOSC0_FREQUENCY / MHZ(1) / 2) -1;
260+
ldr13_5 = (f_cpu / MHZ(1)) << 5;
261+
ctrlb |= OSCCTRL_DPLLCTRLB_DIV(div) | OSCCTRL_DPLLCTRLB_REFCLK_XOSC0;
226262
}
227263
else {
228264
/* TODO find a better fallback source (eg 48MCLK routed though gclk divided down to 1MHz)
@@ -232,11 +268,13 @@ static void fdpll_init_nolock(uint8_t idx, uint32_t f_cpu, uint8_t flags)
232268
while (!(GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0 + idx].reg & GCLK_PCHCTRL_CHEN)) {}
233269
/* Source the DPLL from 32kHz GCLK1 ( equivalent to ((f_cpu << 5) / 32768) )
234270
* avoid the routing through gclk when XOSC32 is the source */
235-
const uint32_t LDR = (f_cpu >> 10);
236-
OSCCTRL->Dpll[idx].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(LDR & 0x1F)
237-
| OSCCTRL_DPLLRATIO_LDR((LDR >> 5) - 1);
271+
ldr13_5 = (f_cpu >> 10);
238272
ctrlb |= OSCCTRL_DPLLCTRLB_REFCLK_GCLK;
239273
}
274+
275+
OSCCTRL->Dpll[idx].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(ldr13_5 & 0x1F)
276+
| OSCCTRL_DPLLRATIO_LDR((ldr13_5 >> 5) - 1);
277+
240278
OSCCTRL->Dpll[idx].DPLLCTRLB.reg = ctrlb;
241279
OSCCTRL->Dpll[idx].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_ENABLE | flags;
242280

0 commit comments

Comments
 (0)