#![allow(non_snake_case)]

use core::time::Duration;

use libk::{error::Error, task::runtime::pwait};
use mac::{MACMDIOAR, MACMDIODR};
use tock_registers::{
    interfaces::{Readable, Writeable},
    register_structs,
};
use ygg_driver_net_core::ephy::MdioBus;

pub mod dma;
pub mod mac;
pub mod mtl;

register_structs! {
    pub Regs {
        (0x0000 => pub MAC: mac::MacRegs),
        (0x0C00 => pub MTL: mtl::MtlRegs),
        (0x1000 => pub DMA: dma::DmaRegs),
        (0x1200 => @END),
    }
}

impl Regs {
    fn mdio_wait_busy(&self) -> Result<(), Error> {
        pwait(Duration::from_millis(50), Duration::from_millis(1), || {
            self.MAC.MACMDIOAR.matches_all(MACMDIOAR::GB::CLEAR)
        })
    }
}

impl MdioBus for Regs {
    fn mii_read(&self, phyaddr: u8, regaddr: u8) -> Result<u16, Error> {
        self.mdio_wait_busy()?;
        self.MAC.MACMDIOAR.write(
            MACMDIOAR::GOC::Read
                + MACMDIOAR::CR.val(1)
                + MACMDIOAR::PA.val(phyaddr as u32)
                + MACMDIOAR::RDA.val(regaddr as u32)
                + MACMDIOAR::GB::SET,
        );
        self.mdio_wait_busy()?;
        Ok(self.MAC.MACMDIODR.read(MACMDIODR::GD) as u16)
    }

    fn mii_write(&self, phyaddr: u8, regaddr: u8, value: u16) -> Result<(), Error> {
        self.mdio_wait_busy()?;
        self.MAC.MACMDIODR.write(MACMDIODR::GD.val(value as u32));
        self.MAC.MACMDIOAR.write(
            MACMDIOAR::GOC::Write
                + MACMDIOAR::CR.val(1)
                + MACMDIOAR::PA.val(phyaddr as u32)
                + MACMDIOAR::RDA.val(regaddr as u32)
                + MACMDIOAR::GB::SET,
        );
        self.mdio_wait_busy()?;
        Ok(())
    }
}
