kopia lustrzana https://github.com/majbthrd/pico-debug
93 wiersze
4.4 KiB
C
93 wiersze
4.4 KiB
C
/* this function was salvaged from pico-bootrom/bootrom/bootrom_main.c */
|
|
|
|
/**
|
|
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <rp2040.h>
|
|
|
|
// USB bootloader requires clk_sys and clk_usb at 48 MHz. For this to work,
|
|
// xosc must be running at 12 MHz. It is possible that:
|
|
//
|
|
// - No crystal is present (and XI may not be properly grounded)
|
|
// - xosc output is much greater than 12 MHz
|
|
//
|
|
// In this case we *must* leave clk_sys in a safe state, and ideally, never
|
|
// return from this function. This is because boards which are not designed to
|
|
// use USB will still enter the USB bootcode when booted with a blank flash.
|
|
|
|
void _usb_clock_setup(void) {
|
|
// First make absolutely sure clk_ref is running: needed for resuscitate,
|
|
// and to run clk_sys while configuring sys PLL. Assume that rosc is not
|
|
// configured to run faster than clk_sys max (as this is officially out of
|
|
// spec)
|
|
// If user previously configured clk_ref to a different source (e.g.
|
|
// GPINx), then halted that source, the glitchless mux can't switch away
|
|
// from the dead source-- nothing we can do about this here.
|
|
rosc_hw->ctrl = ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB;
|
|
hw_clear_bits(&clocks_hw->clk[clk_ref].ctrl, CLOCKS_CLK_REF_CTRL_SRC_BITS);
|
|
|
|
// Resuscitate logic will switch clk_sys to clk_ref if it is inadvertently stopped
|
|
clocks_hw->resus.ctrl =
|
|
CLOCKS_CLK_SYS_RESUS_CTRL_ENABLE_BITS |
|
|
(CLOCKS_CLK_SYS_RESUS_CTRL_TIMEOUT_RESET
|
|
<< CLOCKS_CLK_SYS_RESUS_CTRL_TIMEOUT_LSB);
|
|
|
|
// Resetting PLL regs or changing XOSC range can glitch output, so switch
|
|
// clk_sys away before touching. Not worried about clk_usb as USB is held
|
|
// in reset.
|
|
hw_clear_bits(&clocks_hw->clk[clk_sys].ctrl, CLOCKS_CLK_SYS_CTRL_SRC_BITS);
|
|
while (!(clocks_hw->clk[clk_sys].selected & 1u));
|
|
// rosc can not (while following spec) run faster than clk_sys max, so
|
|
// it's safe now to clear dividers in clkslices.
|
|
clocks_hw->clk[clk_sys].div = 0x100; // int 1 frac 0
|
|
clocks_hw->clk[clk_usb].div = 0x100;
|
|
|
|
// Try to get the crystal running. If no crystal is present, XI should be
|
|
// grounded, so STABLE counter will never complete. Poor designs might
|
|
// leave XI floating, in which case we may eventually drop through... in
|
|
// this case we rely on PLL not locking, and/or resuscitate counter.
|
|
//
|
|
// Don't touch range setting: user would only have changed if crystal
|
|
// needs it, and running crystal out of range can produce glitchy output.
|
|
// Note writing a "bad" value (non-aax) to RANGE has no effect.
|
|
xosc_hw->ctrl = XOSC_CTRL_ENABLE_VALUE_ENABLE << XOSC_CTRL_ENABLE_LSB;
|
|
while (!(xosc_hw->status & XOSC_STATUS_STABLE_BITS));
|
|
|
|
// Sys PLL setup:
|
|
// - VCO freq 1200 MHz, so feedback divisor of 100. Range is 400 MHz to 1.6 GHz
|
|
// - Postdiv1 of 5, down to 240 MHz (appnote recommends postdiv1 >= postdiv2)
|
|
// - Postdiv2 of 5, down to 48 MHz
|
|
//
|
|
// Total postdiv of 25 means that too-fast xtal will push VCO out of
|
|
// lockable range *before* clk_sys goes out of closure (factor of 1.88)
|
|
hw_set_bits(&resets_hw->reset, RESETS_RESET_PLL_SYS_BITS);
|
|
hw_clear_bits(&resets_hw->reset, RESETS_RESET_PLL_SYS_BITS);
|
|
while (!(resets_hw->reset_done & RESETS_RESET_DONE_PLL_SYS_BITS));
|
|
pll_sys_hw->cs = 1u << PLL_CS_REFDIV_LSB;
|
|
pll_sys_hw->fbdiv_int = 100;
|
|
pll_sys_hw->prim =
|
|
(5u << PLL_PRIM_POSTDIV1_LSB) |
|
|
(5u << PLL_PRIM_POSTDIV2_LSB);
|
|
|
|
// Power up VCO, wait for lock
|
|
hw_clear_bits(&pll_sys_hw->pwr, PLL_PWR_PD_BITS | PLL_PWR_VCOPD_BITS);
|
|
while (!(pll_sys_hw->cs & PLL_CS_LOCK_BITS));
|
|
|
|
// Power up post-dividers, which ungates PLL final output
|
|
hw_clear_bits(&pll_sys_hw->pwr, PLL_PWR_POSTDIVPD_BITS);
|
|
|
|
// Glitchy switch of clk_usb, clk_sys aux to sys PLL output.
|
|
clocks_hw->clk[clk_sys].ctrl = 0;
|
|
clocks_hw->clk[clk_usb].ctrl =
|
|
CLOCKS_CLK_USB_CTRL_ENABLE_BITS |
|
|
(CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS
|
|
<< CLOCKS_CLK_USB_CTRL_AUXSRC_LSB);
|
|
|
|
// Glitchless switch of clk_sys to aux source (sys PLL)
|
|
hw_set_bits(&clocks_hw->clk[clk_sys].ctrl, CLOCKS_CLK_SYS_CTRL_SRC_BITS);
|
|
while (!(clocks_hw->clk[clk_sys].selected & 0x2u));
|
|
}
|