From 8fc5ce902fa661a8db52b71fd2ddcf5c9b698a3c Mon Sep 17 00:00:00 2001 From: Stephan Maka Date: Tue, 13 Aug 2019 02:02:51 +0200 Subject: [PATCH] firmware: let kasli obtain default hardware_addr from i2c_eeprom --- RELEASE_NOTES.rst | 2 + artiq/firmware/libboard_artiq/i2c_eeprom.rs | 65 +++++++++++++++++++++ artiq/firmware/libboard_artiq/lib.rs | 2 + artiq/firmware/runtime/main.rs | 19 +++++- 4 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 artiq/firmware/libboard_artiq/i2c_eeprom.rs diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 56cba97ab..647930883 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -29,6 +29,8 @@ ARTIQ-5 * ``aqctl_corelog`` now filters log messages below the ``WARNING`` level by default. This behavior can be changed using the ``-v`` and ``-q`` options like the other programs. +* On Kasli the firmware now starts with a unique default MAC address + from EEPROM if `mac` is absent from the flash config. ARTIQ-4 diff --git a/artiq/firmware/libboard_artiq/i2c_eeprom.rs b/artiq/firmware/libboard_artiq/i2c_eeprom.rs new file mode 100644 index 000000000..fb89bd4a2 --- /dev/null +++ b/artiq/firmware/libboard_artiq/i2c_eeprom.rs @@ -0,0 +1,65 @@ +use i2c; +use pca9548; + +#[cfg(soc_platform = "kasli")] +const I2C_SWITCH0: u8 = 0x70; +#[cfg(soc_platform = "kasli")] +const I2C_SWITCH1: u8 = 0x71; + +/// [Hardware manual](http://ww1.microchip.com/downloads/en/DeviceDoc/24AA02E48-24AA025E48-24AA02E64-24AA025E64-Data-Sheet-20002124H.pdf) +pub struct EEPROM { + busno: u8, + port: u8, + address: u8, +} + +impl EEPROM { + pub fn kasli_eeprom() -> Self { + EEPROM { + busno: 0, + /// Same port as Si5324 + port: 11, + address: 0xa0, + } + } + + fn select(&self) -> Result<(), &'static str> { + let mask: u16 = 1 << self.port; + pca9548::select(self.busno, I2C_SWITCH0, mask as u8)?; + pca9548::select(self.busno, I2C_SWITCH1, (mask >> 8) as u8) + } + + pub fn read<'a>(&self, addr: u8, buf: &'a mut [u8]) -> Result<(), &'static str> { + self.select()?; + + Ok(()).and_then(|()| { + i2c::start(self.busno)?; + i2c::write(self.busno, self.address)?; + i2c::write(self.busno, addr)?; + Ok(()) + }).map_err(|()| "I2C address write error")?; + + Ok(()).and_then(|()| { + i2c::restart(self.busno)?; + i2c::write(self.busno, self.address | 1)?; + let buf_len = buf.len(); + for (i, byte) in buf.iter_mut().enumerate() { + *byte = i2c::read(self.busno, i < buf_len - 1)?; + } + + i2c::stop(self.busno)?; + Ok(()) + }).map_err(|()| "I2C read error")?; + + Ok(()) + } + + /// > The 24AA02XEXX is programmed at the factory with a + /// > globally unique node address stored in the upper half + /// > of the array and permanently write-protected. + pub fn read_eui48<'a>(&self) -> Result<[u8; 6], &'static str> { + let mut buffer = [0u8; 6]; + self.read(0xFA, &mut buffer)?; + Ok(buffer) + } +} diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 1900719ec..300eed3a6 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -32,6 +32,8 @@ pub mod rpc_queue; mod pca9548; #[cfg(has_si5324)] pub mod si5324; +#[cfg(soc_platform = "kasli")] +pub mod i2c_eeprom; #[cfg(has_slave_fpga_cfg)] pub mod slave_fpga; diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 97b6b88e2..5a96c3336 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -135,21 +135,36 @@ fn startup() { _ => { #[cfg(soc_platform = "kasli")] { - hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x21]); + let eeprom = board_artiq::i2c_eeprom::EEPROM::kasli_eeprom(); + hardware_addr = + eeprom.read_eui48() + .map(|addr_buf| { + let hardware_addr = EthernetAddress(addr_buf); + info!("using MAC address {} from EEPROM", hardware_addr); + hardware_addr + }) + .unwrap_or_else(|e| { + error!("failed to read MAC address from EEPROM: {}", e); + let hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x21]); + warn!("using default MAC address {}; consider changing it", hardware_addr); + hardware_addr + }); } #[cfg(soc_platform = "sayma_amc")] { hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x11]); + warn!("using default MAC address {}; consider changing it", hardware_addr); } #[cfg(soc_platform = "metlino")] { hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x19]); + warn!("using default MAC address {}; consider changing it", hardware_addr); } #[cfg(soc_platform = "kc705")] { hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]); + warn!("using default MAC address {}; consider changing it", hardware_addr); } - warn!("using default MAC address {}; consider changing it", hardware_addr); } }