//! Clock tree initialization for {{ ir.board.name }}.
//!
//! Peripheral clock gating on {{ ir.chip.name }} is **two-step** per
//! CHIPS-MICROCHIP-00 §6 INV-MC1 — the SAM D-class clock controller
//! splits responsibility between MCLK and GCLK:
//!
//! 1. `MCLK.APBxMASK` ungates the bus clock for the peripheral. The
//! `apba` / `apbb` / `apbc` / `apbd` mask register is named per
//! peripheral in the chip yaml's `clock_tree.mclk_gates:` table.
//! The pinned `atsamd51j19a 0.7.1` PAC exposes these as direct
//! register-block fields (`p.MCLK.apbamask`), not method accessors.
//! 2. `GCLK.PCHCTRL[n]` selects the generic-clock generator and enables
//! the functional clock. The channel index `n` comes from the chip
//! yaml's `peripherals.<name>.gclk_pchctrl_id:` field; the default
//! generator comes from `clock_tree.pchctrl_channels`. `pchctrl` is
//! a fixed-size array (`[PCHCTRL; 48]`) on this PAC era, so we
//! index it directly rather than via a `pchctrl(N)` method.
//!
//! AHB-only peripherals (USB on D5x) carry `mclk_field: null` in the
//! chip yaml and emit only the PCHCTRL write — their AHB clock is
//! always-on at reset.
//!
//! CPU frequency selection (XOSC0/XOSC1, DFLL48M, FDPLL0/1) is handled
//! by the bootloader / cortex-m-rt reset path; this code does not
//! reprogram the oscillators. See `board.rs` for the configured
//! frequencies.
use {{ ir.chip.pac_crate }} as pac;
/// Enable every peripheral used by this board.
///
/// Called by [`crate::pac::init`] as the first bring-up step, before PORT
/// PMUX configuration so that peripheral registers are writable. Each
/// used peripheral's `mclk_field:` and `gclk_pchctrl_id:` in the chip
/// yaml are looked up against `clock_tree.mclk_gates:` and
/// `clock_tree.pchctrl_channels:` respectively.
pub fn init() {
let p = unsafe { pac::Peripherals::steal() };
{% for name in peripherals_used %}
{% set periph = ir.chip.peripherals[name] %}
{% if periph %}
// {{ name }} — class {{ periph.class }}
{% if periph.mclk_field %}
{% set gate = ir.chip.clock_tree.mclk_gates[name] %}
{% if gate %}
// Step 1: MCLK {{ gate.reg }} {{ gate.field }} bit (APB bus-clock gate)
p.MCLK.{{ gate.reg }}.modify(|_, w| w.{{ gate.field }}().set_bit());
{% else %}
// {{ name }}: mclk_field set on peripheral but no entry in clock_tree.mclk_gates (TODO)
{% endif %}
{% else %}
// {{ name }}: AHB-only (no APB gate write)
{% endif %}
{% if periph.gclk_pchctrl_id is not none %}
// Step 2: GCLK PCHCTRL channel {{ periph.gclk_pchctrl_id }} — enable + select generator
// (default generator from clock_tree.pchctrl_channels; override via board kernels map)
p.GCLK.pchctrl[{{ periph.gclk_pchctrl_id }}].modify(|_, w| unsafe {
w.gen().bits(0).chen().set_bit()
});
while p.GCLK.pchctrl[{{ periph.gclk_pchctrl_id }}].read().chen().bit_is_clear() {}
{% else %}
// {{ name }}: no functional GCLK (AHB-only or self-clocked)
{% endif %}
{% else %}
// {{ name }}: not in chip IR peripherals map (TODO)
{% endif %}
{% endfor %}
}