1use arbitrary_int::{prelude::*, u6};
2use zynq7000::{
3 eth::{InterruptControl, NetworkControl, RxStatus, TxStatus},
4 slcr::reset::EthernetReset,
5};
6
7use crate::{clocks::IoClocks, enable_amba_peripheral_clock, slcr::Slcr, time::Hertz};
8
9use super::{EthernetId, PsEthernet as _};
10
11pub struct EthernetLowLevel {
12 id: EthernetId,
13 pub regs: zynq7000::eth::MmioEthernet<'static>,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum Speed {
18 Mbps10,
19 Mbps100,
20 Mbps1000,
21}
22
23impl Speed {
24 pub const fn rgmii_clk_rate(&self) -> Hertz {
25 match self {
26 Speed::Mbps10 => Hertz::from_raw(2_500_000),
27 Speed::Mbps100 => Hertz::from_raw(25_000_000),
28 Speed::Mbps1000 => Hertz::from_raw(125_000_000),
29 }
30 }
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum Duplex {
35 Half,
36 Full,
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub struct ClockDivisors {
41 pub divisor_0: u6,
42 pub divisor_1: u6,
43}
44
45impl ClockDivisors {
46 pub const fn new(divisor_0: u6, divisor_1: u6) -> Self {
47 Self {
48 divisor_0,
49 divisor_1,
50 }
51 }
52
53 pub fn calculate_for_rgmii_and_io_clock(io_clks: IoClocks, target_speed: Speed) -> (Self, u32) {
56 Self::calculate_for_rgmii(io_clks.ref_clk(), target_speed)
57 }
58
59 pub fn calculate_for_rgmii(ref_clk: Hertz, target_speed: Speed) -> (Self, u32) {
68 let mut smallest_diff = u32::MAX;
69 let target_speed = target_speed.rgmii_clk_rate();
70 let mut best_div_0 = u6::new(0);
71 let mut best_div_1 = u6::new(0);
72 for div_1 in 1..=u6::MAX.as_usize() {
73 for div_0 in 1..=u6::MAX.as_usize() {
74 let clk_rate = ref_clk.raw() / div_0 as u32 / div_1 as u32;
75 let diff = (target_speed.raw() as i64 - clk_rate as i64).unsigned_abs() as u32;
76 if diff < smallest_diff {
77 smallest_diff = diff;
78 best_div_0 = u6::new(div_0 as u8);
79 best_div_1 = u6::new(div_1 as u8);
80 }
81 if diff == 0 {
83 break;
84 }
85 }
86 }
87 (Self::new(best_div_0, best_div_1), smallest_diff)
88 }
89}
90
91#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93pub struct ClockConfig {
94 pub src_sel: zynq7000::slcr::clocks::SrcSelIo,
95 pub use_emio_tx_clk: bool,
96 pub divs: ClockDivisors,
97 pub enable: bool,
99}
100
101impl ClockConfig {
102 pub const fn new(divs: ClockDivisors) -> Self {
103 Self {
104 src_sel: zynq7000::slcr::clocks::SrcSelIo::IoPll,
105 use_emio_tx_clk: false,
106 divs,
107 enable: true,
108 }
109 }
110}
111
112#[derive(Debug, Clone, Copy)]
118pub struct ClockDivSet {
119 pub cfg_10_mbps: ClockDivisors,
120 pub cfg_100_mbps: ClockDivisors,
121 pub cfg_1000_mbps: ClockDivisors,
122}
123
124impl ClockDivSet {
125 pub const fn new(
126 cfg_10_mbps: ClockDivisors,
127 cfg_100_mbps: ClockDivisors,
128 cfg_1000_mbps: ClockDivisors,
129 ) -> Self {
130 Self {
131 cfg_10_mbps,
132 cfg_100_mbps,
133 cfg_1000_mbps,
134 }
135 }
136
137 #[inline]
138 pub fn clk_divs_for_speed(&self, speed: Speed) -> &ClockDivisors {
139 match speed {
140 Speed::Mbps10 => &self.cfg_10_mbps,
141 Speed::Mbps100 => &self.cfg_100_mbps,
142 Speed::Mbps1000 => &self.cfg_1000_mbps,
143 }
144 }
145
146 pub fn calculate_for_rgmii_and_io_clock(io_clks: &IoClocks) -> (Self, [u32; 3]) {
149 Self::calculate_for_rgmii(io_clks.ref_clk())
150 }
151
152 pub fn calculate_for_rgmii(ref_clk: Hertz) -> (Self, [u32; 3]) {
161 let (cfg_10_mbps, error_10_mbps) =
162 ClockDivisors::calculate_for_rgmii(ref_clk, Speed::Mbps10);
163 let (cfg_100_mbps, error_100_mbps) =
164 ClockDivisors::calculate_for_rgmii(ref_clk, Speed::Mbps100);
165 let (cfg_1000_mbps, error_1000_mbps) =
166 ClockDivisors::calculate_for_rgmii(ref_clk, Speed::Mbps1000);
167 (
168 Self::new(cfg_10_mbps, cfg_100_mbps, cfg_1000_mbps),
169 [error_10_mbps, error_100_mbps, error_1000_mbps],
170 )
171 }
172}
173
174impl EthernetLowLevel {
178 #[inline]
180 pub fn new(regs: zynq7000::eth::MmioEthernet<'static>) -> Option<Self> {
181 regs.id()?;
182 Some(EthernetLowLevel {
183 id: regs.id().unwrap(),
184 regs,
185 })
186 }
187
188 #[inline]
194 pub const unsafe fn steal(id: EthernetId) -> Self {
195 Self {
196 id,
197 regs: unsafe {
198 match id {
199 EthernetId::Eth0 => zynq7000::eth::Ethernet::new_mmio_fixed_0(),
200 EthernetId::Eth1 => zynq7000::eth::Ethernet::new_mmio_fixed_1(),
201 }
202 },
203 }
204 }
205
206 pub fn reset(&mut self, cycles: usize) {
207 let assert_reset = match self.id {
208 EthernetId::Eth0 => EthernetReset::builder()
209 .with_gem1_ref_rst(false)
210 .with_gem0_ref_rst(true)
211 .with_gem1_rx_rst(false)
212 .with_gem0_rx_rst(true)
213 .with_gem1_cpu1x_rst(false)
214 .with_gem0_cpu1x_rst(true)
215 .build(),
216 EthernetId::Eth1 => EthernetReset::builder()
217 .with_gem1_ref_rst(true)
218 .with_gem0_ref_rst(false)
219 .with_gem1_rx_rst(true)
220 .with_gem0_rx_rst(false)
221 .with_gem1_cpu1x_rst(true)
222 .with_gem0_cpu1x_rst(false)
223 .build(),
224 };
225 unsafe {
226 Slcr::with(|regs| {
227 regs.reset_ctrl().write_eth(assert_reset);
228 for _ in 0..cycles {
229 cortex_ar::asm::nop();
230 }
231 regs.reset_ctrl().write_eth(EthernetReset::DEFAULT);
232 });
233 }
234 }
235
236 #[inline]
237 pub fn enable_peripheral_clock(&mut self) {
238 let periph_sel = match self.id {
239 EthernetId::Eth0 => crate::PeriphSelect::Gem0,
240 EthernetId::Eth1 => crate::PeriphSelect::Gem1,
241 };
242 enable_amba_peripheral_clock(periph_sel);
243 }
244
245 pub fn configure_clock(&mut self, cfg: ClockConfig, enable_rx_clock: bool) {
249 unsafe {
250 Slcr::with(|regs| {
251 let (ptr_gig_eth_clk_ctrl, ptr_gig_eth_rclk_ctrl) = self.id().clk_config_regs(regs);
252 let mut gig_eth_clk_ctrl_val = core::ptr::read_volatile(ptr_gig_eth_clk_ctrl);
253 gig_eth_clk_ctrl_val.set_srcsel(cfg.src_sel);
254 gig_eth_clk_ctrl_val.set_divisor_0(cfg.divs.divisor_0);
255 gig_eth_clk_ctrl_val.set_divisor_1(cfg.divs.divisor_1);
256 gig_eth_clk_ctrl_val.set_use_emio_tx_clk(cfg.use_emio_tx_clk);
257 gig_eth_clk_ctrl_val.set_clk_act(cfg.enable);
258 core::ptr::write_volatile(ptr_gig_eth_clk_ctrl, gig_eth_clk_ctrl_val);
259
260 if enable_rx_clock {
261 let mut gig_eth_rclk_ctrl_val = core::ptr::read_volatile(ptr_gig_eth_rclk_ctrl);
262 gig_eth_rclk_ctrl_val.set_clk_enable(true);
263 core::ptr::write_volatile(ptr_gig_eth_rclk_ctrl, gig_eth_rclk_ctrl_val);
264 }
265 })
266 }
267 }
268
269 pub fn configure_clock_divs(&mut self, cfg: ClockDivisors) {
273 unsafe {
274 Slcr::with(|regs| {
275 let (ptr_gig_eth_clk_ctrl, _ptr_gig_eth_rclk_ctrl) =
276 self.id().clk_config_regs(regs);
277 let mut gig_eth_clk_ctrl_val = core::ptr::read_volatile(ptr_gig_eth_clk_ctrl);
278 gig_eth_clk_ctrl_val.set_divisor_0(cfg.divisor_0);
279 gig_eth_clk_ctrl_val.set_divisor_1(cfg.divisor_1);
280 core::ptr::write_volatile(ptr_gig_eth_clk_ctrl, gig_eth_clk_ctrl_val);
281 })
282 }
283 }
284
285 pub fn configure_clock_and_speed_duplex(
291 &mut self,
292 speed: Speed,
293 duplex: Duplex,
294 clk_collection: &ClockDivSet,
295 ) {
296 self.configure_clock_for_speed(speed, clk_collection);
297 self.set_speed_and_duplex(speed, duplex);
298 }
299
300 pub fn configure_clock_for_speed(&mut self, speed: Speed, clk_collection: &ClockDivSet) {
301 match speed {
302 Speed::Mbps10 => self.configure_clock_divs(clk_collection.cfg_10_mbps),
303 Speed::Mbps100 => self.configure_clock_divs(clk_collection.cfg_100_mbps),
304 Speed::Mbps1000 => self.configure_clock_divs(clk_collection.cfg_1000_mbps),
305 }
306 }
307
308 #[inline]
309 pub fn set_promiscous_mode(&mut self, enable: bool) {
310 self.regs.modify_net_cfg(|mut val| {
311 val.set_copy_all_frames(enable);
312 val
313 });
314 }
315
316 #[inline]
317 pub fn set_rx_buf_descriptor_base_address(&mut self, addr: u32) {
318 self.regs.write_rx_buf_queue_base_addr(addr);
319 }
320
321 #[inline]
322 pub fn set_tx_buf_descriptor_base_address(&mut self, addr: u32) {
323 self.regs.write_tx_buf_queue_base_addr(addr);
324 }
325
326 pub fn set_speed_and_duplex(&mut self, speed: Speed, duplex: Duplex) {
331 self.regs.modify_net_cfg(|mut val| {
332 val.set_full_duplex(duplex == Duplex::Full);
333 match speed {
334 Speed::Mbps10 => {
335 val.set_speed_mode(zynq7000::eth::SpeedMode::Low10Mbps);
336 val.set_gigabit_enable(false);
337 val
338 }
339 Speed::Mbps100 => {
340 val.set_speed_mode(zynq7000::eth::SpeedMode::High100Mbps);
341 val.set_gigabit_enable(false);
342 val
343 }
344 Speed::Mbps1000 => {
345 val.set_gigabit_enable(true);
346 val
347 }
348 }
349 });
350 }
351
352 #[inline]
354 pub fn set_tx_rx_enable(&mut self, tx_enable: bool, rx_enable: bool) {
355 self.regs.modify_net_ctrl(|mut val| {
356 val.set_rx_enable(rx_enable);
357 val.set_tx_enable(tx_enable);
358 val
359 });
360 }
361
362 pub fn initialize(&mut self, reset_rx_tx_queue_base_addr: bool) {
366 let mut ctrl_val = NetworkControl::new_with_raw_value(0);
367 self.regs.write_net_ctrl(ctrl_val);
368 ctrl_val.set_clear_statistics(true);
370 self.regs.write_net_ctrl(ctrl_val);
371 self.regs.write_tx_status(TxStatus::new_clear_all());
372 self.regs.write_rx_status(RxStatus::new_clear_all());
373 self.regs
374 .write_interrupt_disable(InterruptControl::new_clear_all());
375 if reset_rx_tx_queue_base_addr {
376 self.regs.write_rx_buf_queue_base_addr(0);
377 self.regs.write_tx_buf_queue_base_addr(0);
378 }
379 }
380
381 #[inline]
382 pub const fn id(&self) -> EthernetId {
383 self.id
384 }
385}