1#![no_std]
16#![cfg_attr(docsrs, feature(doc_cfg))]
17
18#[cfg(feature = "alloc")]
19extern crate alloc;
20
21use slcr::Slcr;
22use zynq7000::{
23 SpiClockPhase, SpiClockPolarity,
24 slcr::{BootModeRegister, BootPllConfig, LevelShifterRegister},
25};
26
27pub mod cache;
28pub mod clocks;
29pub mod ddr;
30pub mod devcfg;
31pub mod eth;
32pub mod gic;
33pub mod gpio;
34pub mod gtc;
35pub mod i2c;
36pub mod l2_cache;
37pub mod log;
38pub mod prelude;
39pub mod priv_tim;
40pub mod qspi;
41pub mod slcr;
42pub mod spi;
43pub mod time;
44pub mod ttc;
45pub mod uart;
46
47pub use zynq7000 as pac;
48pub use zynq7000::slcr::LevelShifterConfig;
49
50#[derive(Debug, thiserror::Error)]
51pub enum InitError {
52 #[error("peripheral singleton was already taken")]
53 PeripheralsAlreadyTaken,
54}
55
56#[derive(Debug)]
57pub enum InteruptConfig {
58 AllInterruptsToCpu0,
61}
62
63#[derive(Debug)]
64pub struct Config {
65 pub init_l2_cache: bool,
66 pub level_shifter_config: Option<LevelShifterConfig>,
68 pub interrupt_config: Option<InteruptConfig>,
70}
71
72pub fn init(config: Config) -> Result<zynq7000::Peripherals, InitError> {
74 let mut periphs = zynq7000::Peripherals::take().ok_or(InitError::PeripheralsAlreadyTaken)?;
75 if config.init_l2_cache {
76 l2_cache::init_with_defaults(&mut periphs.l2c);
77 }
78 if let Some(config) = config.level_shifter_config {
79 configure_level_shifter(config);
80 }
81 if let Some(interrupt_config) = config.interrupt_config {
82 let mut gic = gic::GicConfigurator::new_with_init(periphs.gicc, periphs.gicd);
83 match interrupt_config {
84 InteruptConfig::AllInterruptsToCpu0 => {
85 gic.enable_all_interrupts();
86 gic.set_all_spi_interrupt_targets_cpu0();
87 }
88 }
89 gic.enable();
90 unsafe {
91 gic.enable_interrupts();
92 }
93 }
94
95 Ok(unsafe { zynq7000::Peripherals::steal() })
96}
97
98#[derive(Debug, Copy, Clone)]
100pub enum BootDevice {
101 JtagCascaded,
102 JtagIndependent,
103 Nor,
104 Nand,
105 Qspi,
106 SdCard,
107}
108
109#[derive(Debug, Copy, Clone)]
110pub struct BootMode {
111 boot_mode: Option<BootDevice>,
112 pll_config: BootPllConfig,
113}
114
115impl BootMode {
116 pub fn new_from_regs() -> Self {
119 Self::new_with_reg(unsafe { zynq7000::slcr::Slcr::new_mmio_fixed() }.read_boot_mode())
121 }
122
123 fn new_with_reg(boot_mode_reg: BootModeRegister) -> Self {
124 let boot_dev = boot_mode_reg.boot_mode();
125 let msb_three_bits = (boot_dev.value() >> 1) & 0b111;
126
127 let boot_mode = match msb_three_bits {
128 0b000 => {
129 if boot_dev.value() & 0b1 == 0 {
130 Some(BootDevice::JtagCascaded)
131 } else {
132 Some(BootDevice::JtagIndependent)
133 }
134 }
135 0b001 => Some(BootDevice::Nor),
136 0b010 => Some(BootDevice::Nand),
137 0b100 => Some(BootDevice::Qspi),
138 0b110 => Some(BootDevice::SdCard),
139 _ => None,
140 };
141 Self {
142 boot_mode,
143 pll_config: boot_mode_reg.pll_config(),
144 }
145 }
146
147 pub const fn boot_device(&self) -> Option<BootDevice> {
148 self.boot_mode
149 }
150
151 pub const fn pll_config(&self) -> BootPllConfig {
152 self.pll_config
153 }
154}
155
156pub fn configure_level_shifter(config: LevelShifterConfig) {
161 unsafe {
163 Slcr::with(|slcr_unlocked| {
164 slcr_unlocked
165 .write_lvl_shftr_en(LevelShifterRegister::new_with_raw_value(config as u32));
166 });
167 }
168}
169
170#[derive(Debug, PartialEq, Eq, Clone, Copy)]
171pub enum PeriphSelect {
172 Smc = 24,
173 Lqspi = 23,
174 Gpio = 22,
175 Uart1 = 21,
176 Uart0 = 20,
177 I2c1 = 19,
178 I2c0 = 18,
179 Can1 = 17,
180 Can0 = 16,
181 Spi1 = 15,
182 Spi0 = 14,
183 Sdio1 = 11,
184 Sdio0 = 10,
185 Gem1 = 7,
186 Gem0 = 6,
187 Usb1 = 3,
188 Usb0 = 2,
189 Dma = 0,
190}
191
192#[inline]
195pub fn enable_amba_peripheral_clock(select: PeriphSelect) {
196 unsafe {
197 Slcr::with(|regs| {
198 regs.clk_ctrl().modify_aper_clk_ctrl(|mut val| {
199 match select {
200 PeriphSelect::Smc => val.set_smc_1x_clk_act(true),
201 PeriphSelect::Lqspi => val.set_lqspi_1x_clk_act(true),
202 PeriphSelect::Gpio => val.set_gpio_1x_clk_act(true),
203 PeriphSelect::Uart1 => val.set_uart_1_1x_clk_act(true),
204 PeriphSelect::Uart0 => val.set_uart_0_1x_clk_act(true),
205 PeriphSelect::I2c1 => val.set_i2c_1_1x_clk_act(true),
206 PeriphSelect::I2c0 => val.set_i2c_0_1x_clk_act(true),
207 PeriphSelect::Can1 => val.set_can_1_1x_clk_act(true),
208 PeriphSelect::Can0 => val.set_can_0_1x_clk_act(true),
209 PeriphSelect::Spi1 => val.set_spi_1_1x_clk_act(true),
210 PeriphSelect::Spi0 => val.set_spi_1_1x_clk_act(true),
211 PeriphSelect::Sdio1 => val.set_sdio_1_1x_clk_act(true),
212 PeriphSelect::Sdio0 => val.set_sdio_0_1x_clk_act(true),
213 PeriphSelect::Gem1 => val.set_gem_1_1x_clk_act(true),
214 PeriphSelect::Gem0 => val.set_gem_0_1x_clk_act(true),
215 PeriphSelect::Usb1 => val.set_usb_1_cpu_1x_clk_act(true),
216 PeriphSelect::Usb0 => val.set_usb_0_cpu_1x_clk_act(true),
217 PeriphSelect::Dma => val.set_dma_cpu_2x_clk_act(true),
218 }
219 val
220 })
221 });
222 }
223}
224
225#[inline]
228pub fn disable_amba_periph_clk(select: PeriphSelect) {
229 unsafe {
230 Slcr::with(|regs| {
231 regs.clk_ctrl().modify_aper_clk_ctrl(|mut val| {
232 match select {
233 PeriphSelect::Smc => val.set_smc_1x_clk_act(false),
234 PeriphSelect::Lqspi => val.set_lqspi_1x_clk_act(false),
235 PeriphSelect::Gpio => val.set_gpio_1x_clk_act(false),
236 PeriphSelect::Uart1 => val.set_uart_1_1x_clk_act(false),
237 PeriphSelect::Uart0 => val.set_uart_0_1x_clk_act(false),
238 PeriphSelect::I2c1 => val.set_i2c_1_1x_clk_act(false),
239 PeriphSelect::I2c0 => val.set_i2c_0_1x_clk_act(false),
240 PeriphSelect::Can1 => val.set_can_1_1x_clk_act(false),
241 PeriphSelect::Can0 => val.set_can_0_1x_clk_act(false),
242 PeriphSelect::Spi1 => val.set_spi_1_1x_clk_act(false),
243 PeriphSelect::Spi0 => val.set_spi_1_1x_clk_act(false),
244 PeriphSelect::Sdio1 => val.set_sdio_1_1x_clk_act(false),
245 PeriphSelect::Sdio0 => val.set_sdio_0_1x_clk_act(false),
246 PeriphSelect::Gem1 => val.set_gem_1_1x_clk_act(false),
247 PeriphSelect::Gem0 => val.set_gem_0_1x_clk_act(false),
248 PeriphSelect::Usb1 => val.set_usb_1_cpu_1x_clk_act(false),
249 PeriphSelect::Usb0 => val.set_usb_0_cpu_1x_clk_act(false),
250 PeriphSelect::Dma => val.set_dma_cpu_2x_clk_act(false),
251 }
252 val
253 })
254 });
255 }
256}
257
258#[inline]
259const fn spi_mode_const_to_cpol_cpha(
260 mode: embedded_hal::spi::Mode,
261) -> (SpiClockPolarity, SpiClockPhase) {
262 match mode {
263 embedded_hal::spi::MODE_0 => (
264 SpiClockPolarity::QuiescentLow,
265 SpiClockPhase::ActiveOutsideOfWord,
266 ),
267 embedded_hal::spi::MODE_1 => (
268 SpiClockPolarity::QuiescentLow,
269 SpiClockPhase::InactiveOutsideOfWord,
270 ),
271 embedded_hal::spi::MODE_2 => (
272 SpiClockPolarity::QuiescentHigh,
273 SpiClockPhase::ActiveOutsideOfWord,
274 ),
275 embedded_hal::spi::MODE_3 => (
276 SpiClockPolarity::QuiescentHigh,
277 SpiClockPhase::InactiveOutsideOfWord,
278 ),
279 }
280}
281
282pub(crate) mod sealed {
283 pub trait Sealed {}
284}