Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cpu/samd5x: enable FDPLL1 at 200MHz #19581

Merged
merged 4 commits into from
May 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 32 additions & 27 deletions cpu/samd5x/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,6 @@
#define USE_VREG_BUCK (0)
#endif

/*
* An external inductor needs to be present on the board,
* so the feature can only be enabled by the board configuration.
*/
#ifndef USE_VREG_BUCK
#define USE_VREG_BUCK (0)
#endif

#if CLOCK_CORECLOCK == 0
#error Please select CLOCK_CORECLOCK
#endif
Expand Down Expand Up @@ -191,37 +183,43 @@ static void dfll_init(void)
while (!OSCCTRL->STATUS.bit.DFLLRDY) {}
}

static void fdpll0_init(uint32_t f_cpu)
static void fdpll_init_nolock(uint8_t idx, uint32_t f_cpu, uint8_t flags)
{
/* Trigger assertion if not using FDPLL0 or FDPLL1 */
assert(idx == 0 || idx == 1);

if (!USE_DPLL) {
OSCCTRL->Dpll[0].DPLLCTRLA.reg = 0;
OSCCTRL->Dpll[idx].DPLLCTRLA.reg = 0;
return;
}

/* We source the DPLL from 32kHz GCLK1 */
const uint32_t LDR = ((f_cpu << 5) / 32768);
/* Source the DPLL from 32kHz GCLK1 ( equivalent to ((f_cpu << 5) / 32768) ) */
const uint32_t LDR = (f_cpu >> 10);

/* disable the DPLL before changing the configuration */
OSCCTRL->Dpll[0].DPLLCTRLA.bit.ENABLE = 0;
while (OSCCTRL->Dpll[0].DPLLSYNCBUSY.reg) {}
OSCCTRL->Dpll[idx].DPLLCTRLA.bit.ENABLE = 0;
while (OSCCTRL->Dpll[idx].DPLLSYNCBUSY.reg) {}

/* set DPLL clock source */
GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0].reg = GCLK_PCHCTRL_GEN(1) | GCLK_PCHCTRL_CHEN;
while (!(GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0].reg & GCLK_PCHCTRL_CHEN)) {}
GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0 + idx].reg = GCLK_PCHCTRL_GEN(1) | GCLK_PCHCTRL_CHEN;
while (!(GCLK->PCHCTRL[OSCCTRL_GCLK_ID_FDPLL0 + idx].reg & GCLK_PCHCTRL_CHEN)) {}

OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(LDR & 0x1F)
| OSCCTRL_DPLLRATIO_LDR((LDR >> 5) - 1);
OSCCTRL->Dpll[idx].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(LDR & 0x1F)
| OSCCTRL_DPLLRATIO_LDR((LDR >> 5) - 1);

/* Without LBYPASS, startup takes very long, see errata section 2.13. */
OSCCTRL->Dpll[0].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_REFCLK_GCLK
| OSCCTRL_DPLLCTRLB_WUF
| OSCCTRL_DPLLCTRLB_LBYPASS;
OSCCTRL->Dpll[idx].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_REFCLK_GCLK
| OSCCTRL_DPLLCTRLB_WUF
| OSCCTRL_DPLLCTRLB_LBYPASS;

OSCCTRL->Dpll[0].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_ENABLE;
OSCCTRL->Dpll[idx].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_ENABLE | flags;

while (OSCCTRL->Dpll[0].DPLLSYNCBUSY.reg) {}
while (!(OSCCTRL->Dpll[0].DPLLSTATUS.bit.CLKRDY &&
OSCCTRL->Dpll[0].DPLLSTATUS.bit.LOCK)) {}
while (OSCCTRL->Dpll[idx].DPLLSYNCBUSY.reg) {}
}

static void fdpll_lock(uint8_t idx) {
while (!(OSCCTRL->Dpll[idx].DPLLSTATUS.bit.CLKRDY &&
OSCCTRL->Dpll[idx].DPLLSTATUS.bit.LOCK)) {}
}

static void gclk_connect(uint8_t id, uint8_t src, uint32_t flags) {
Expand Down Expand Up @@ -256,7 +254,11 @@ void sam0_gclk_enable(uint8_t id)
} else if (USE_XOSC) {
gclk_connect(SAM0_GCLK_PERIPH, GCLK_SOURCE_ACTIVE_XOSC, 0);
}

break;
dylad marked this conversation as resolved.
Show resolved Hide resolved
case SAM0_GCLK_200MHZ:
fdpll_init_nolock(1, MHZ(200), OSCCTRL_DPLLCTRLA_ONDEMAND);
gclk_connect(SAM0_GCLK_200MHZ, GCLK_SOURCE_DPLL1, 0);
fdpll_lock(1);
break;
}
}
Expand All @@ -279,6 +281,8 @@ uint32_t sam0_gclk_freq(uint8_t id)
assert(0);
return 0;
}
case SAM0_GCLK_200MHZ:
return MHZ(200);
default:
return 0;
}
Expand Down Expand Up @@ -354,12 +358,13 @@ void cpu_init(void)

xosc_init(0);
xosc_init(1);
fdpll0_init(CLOCK_CORECLOCK * DPLL_DIV);

/* select the source of the main clock */
if (USE_DPLL) {
fdpll_init_nolock(0, CLOCK_CORECLOCK * DPLL_DIV, OSCCTRL_DPLLCTRLA_ONDEMAND);
gclk_connect(SAM0_GCLK_MAIN, GCLK_SOURCE_DPLL0,
GCLK_GENCTRL_DIV(DPLL_DIV));
fdpll_lock(0);
} else if (USE_DFLL) {
gclk_connect(SAM0_GCLK_MAIN, GCLK_SOURCE_DFLL,
GCLK_GENCTRL_DIV(SAM0_DFLL_FREQ_HZ / CLOCK_CORECLOCK));
Expand Down
3 changes: 2 additions & 1 deletion cpu/samd5x/include/periph_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ extern "C" {
/**
* @brief DPLL frequency must not exceed 200 MHz
*/
#define SAM0_DPLL_FREQ_MAX_HZ MHZ(20)
#define SAM0_DPLL_FREQ_MAX_HZ MHZ(200)

/**
* @name Power mode configuration
Expand All @@ -65,6 +65,7 @@ enum {
SAM0_GCLK_32KHZ, /**< 32 kHz clock */
SAM0_GCLK_TIMER, /**< 4-8 MHz clock for xTimer */
SAM0_GCLK_PERIPH, /**< 12-48 MHz (DFLL) clock */
SAM0_GCLK_200MHZ, /**< 200MHz FDPLL clock */
};
/** @} */

Expand Down