split bus, consts into separate mods.
This commit is contained in:
parent
076ada4c02
commit
1b6799d93f
321
src/bus.rs
Normal file
321
src/bus.rs
Normal file
@ -0,0 +1,321 @@
|
||||
use core::slice;
|
||||
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embedded_hal_1::digital::OutputPin;
|
||||
use embedded_hal_async::spi::{transaction, SpiBusRead, SpiBusWrite, SpiDevice};
|
||||
|
||||
use crate::consts::*;
|
||||
|
||||
pub(crate) struct Bus<PWR, SPI> {
|
||||
backplane_window: u32,
|
||||
pwr: PWR,
|
||||
spi: SPI,
|
||||
}
|
||||
|
||||
impl<PWR, SPI> Bus<PWR, SPI>
|
||||
where
|
||||
PWR: OutputPin,
|
||||
SPI: SpiDevice,
|
||||
SPI::Bus: SpiBusRead<u32> + SpiBusWrite<u32>,
|
||||
{
|
||||
pub(crate) fn new(pwr: PWR, spi: SPI) -> Self {
|
||||
Self {
|
||||
backplane_window: 0xAAAA_AAAA,
|
||||
pwr,
|
||||
spi,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn init(&mut self) {
|
||||
// Reset
|
||||
self.pwr.set_low().unwrap();
|
||||
Timer::after(Duration::from_millis(20)).await;
|
||||
self.pwr.set_high().unwrap();
|
||||
Timer::after(Duration::from_millis(250)).await;
|
||||
|
||||
while self.read32_swapped(REG_BUS_TEST_RO).await != FEEDBEAD {}
|
||||
|
||||
self.write32_swapped(REG_BUS_TEST_RW, TEST_PATTERN).await;
|
||||
let val = self.read32_swapped(REG_BUS_TEST_RW).await;
|
||||
assert_eq!(val, TEST_PATTERN);
|
||||
|
||||
// 32-bit word length, little endian (which is the default endianess).
|
||||
self.write32_swapped(REG_BUS_CTRL, WORD_LENGTH_32 | HIGH_SPEED).await;
|
||||
|
||||
let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await;
|
||||
assert_eq!(val, FEEDBEAD);
|
||||
let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await;
|
||||
assert_eq!(val, TEST_PATTERN);
|
||||
}
|
||||
|
||||
pub async fn wlan_read(&mut self, buf: &mut [u32]) {
|
||||
let cmd = cmd_word(READ, INC_ADDR, FUNC_WLAN, 0, buf.len() as u32 * 4);
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[cmd]).await?;
|
||||
bus.read(buf).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub async fn wlan_write(&mut self, buf: &[u32]) {
|
||||
let cmd = cmd_word(WRITE, INC_ADDR, FUNC_WLAN, 0, buf.len() as u32 * 4);
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[cmd]).await?;
|
||||
bus.write(buf).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub async fn bp_read(&mut self, mut addr: u32, mut data: &mut [u8]) {
|
||||
// It seems the HW force-aligns the addr
|
||||
// to 2 if data.len() >= 2
|
||||
// to 4 if data.len() >= 4
|
||||
// To simplify, enforce 4-align for now.
|
||||
assert!(addr % 4 == 0);
|
||||
|
||||
let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4];
|
||||
|
||||
while !data.is_empty() {
|
||||
// Ensure transfer doesn't cross a window boundary.
|
||||
let window_offs = addr & BACKPLANE_ADDRESS_MASK;
|
||||
let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize;
|
||||
|
||||
let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining);
|
||||
|
||||
self.backplane_set_window(addr).await;
|
||||
|
||||
let cmd = cmd_word(READ, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32);
|
||||
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[cmd]).await?;
|
||||
|
||||
// 4-byte response delay.
|
||||
let mut junk = [0; 1];
|
||||
bus.read(&mut junk).await?;
|
||||
|
||||
// Read data
|
||||
bus.read(&mut buf[..(len + 3) / 4]).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
data[..len].copy_from_slice(&slice8_mut(&mut buf)[..len]);
|
||||
|
||||
// Advance ptr.
|
||||
addr += len as u32;
|
||||
data = &mut data[len..];
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn bp_write(&mut self, mut addr: u32, mut data: &[u8]) {
|
||||
// It seems the HW force-aligns the addr
|
||||
// to 2 if data.len() >= 2
|
||||
// to 4 if data.len() >= 4
|
||||
// To simplify, enforce 4-align for now.
|
||||
assert!(addr % 4 == 0);
|
||||
|
||||
let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4];
|
||||
|
||||
while !data.is_empty() {
|
||||
// Ensure transfer doesn't cross a window boundary.
|
||||
let window_offs = addr & BACKPLANE_ADDRESS_MASK;
|
||||
let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize;
|
||||
|
||||
let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining);
|
||||
slice8_mut(&mut buf)[..len].copy_from_slice(&data[..len]);
|
||||
|
||||
self.backplane_set_window(addr).await;
|
||||
|
||||
let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32);
|
||||
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[cmd]).await?;
|
||||
bus.write(&buf[..(len + 3) / 4]).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Advance ptr.
|
||||
addr += len as u32;
|
||||
data = &data[len..];
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn bp_read8(&mut self, addr: u32) -> u8 {
|
||||
self.backplane_readn(addr, 1).await as u8
|
||||
}
|
||||
|
||||
pub async fn bp_write8(&mut self, addr: u32, val: u8) {
|
||||
self.backplane_writen(addr, val as u32, 1).await
|
||||
}
|
||||
|
||||
pub async fn bp_read16(&mut self, addr: u32) -> u16 {
|
||||
self.backplane_readn(addr, 2).await as u16
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub async fn bp_write16(&mut self, addr: u32, val: u16) {
|
||||
self.backplane_writen(addr, val as u32, 2).await
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub async fn bp_read32(&mut self, addr: u32) -> u32 {
|
||||
self.backplane_readn(addr, 4).await
|
||||
}
|
||||
|
||||
pub async fn bp_write32(&mut self, addr: u32, val: u32) {
|
||||
self.backplane_writen(addr, val, 4).await
|
||||
}
|
||||
|
||||
async fn backplane_readn(&mut self, addr: u32, len: u32) -> u32 {
|
||||
self.backplane_set_window(addr).await;
|
||||
|
||||
let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK;
|
||||
if len == 4 {
|
||||
bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG
|
||||
}
|
||||
self.readn(FUNC_BACKPLANE, bus_addr, len).await
|
||||
}
|
||||
|
||||
async fn backplane_writen(&mut self, addr: u32, val: u32, len: u32) {
|
||||
self.backplane_set_window(addr).await;
|
||||
|
||||
let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK;
|
||||
if len == 4 {
|
||||
bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG
|
||||
}
|
||||
self.writen(FUNC_BACKPLANE, bus_addr, val, len).await
|
||||
}
|
||||
|
||||
async fn backplane_set_window(&mut self, addr: u32) {
|
||||
let new_window = addr & !BACKPLANE_ADDRESS_MASK;
|
||||
|
||||
if (new_window >> 24) as u8 != (self.backplane_window >> 24) as u8 {
|
||||
self.write8(
|
||||
FUNC_BACKPLANE,
|
||||
REG_BACKPLANE_BACKPLANE_ADDRESS_HIGH,
|
||||
(new_window >> 24) as u8,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
if (new_window >> 16) as u8 != (self.backplane_window >> 16) as u8 {
|
||||
self.write8(
|
||||
FUNC_BACKPLANE,
|
||||
REG_BACKPLANE_BACKPLANE_ADDRESS_MID,
|
||||
(new_window >> 16) as u8,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
if (new_window >> 8) as u8 != (self.backplane_window >> 8) as u8 {
|
||||
self.write8(
|
||||
FUNC_BACKPLANE,
|
||||
REG_BACKPLANE_BACKPLANE_ADDRESS_LOW,
|
||||
(new_window >> 8) as u8,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
self.backplane_window = new_window;
|
||||
}
|
||||
|
||||
pub async fn read8(&mut self, func: u32, addr: u32) -> u8 {
|
||||
self.readn(func, addr, 1).await as u8
|
||||
}
|
||||
|
||||
pub async fn write8(&mut self, func: u32, addr: u32, val: u8) {
|
||||
self.writen(func, addr, val as u32, 1).await
|
||||
}
|
||||
|
||||
pub async fn read16(&mut self, func: u32, addr: u32) -> u16 {
|
||||
self.readn(func, addr, 2).await as u16
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub async fn write16(&mut self, func: u32, addr: u32, val: u16) {
|
||||
self.writen(func, addr, val as u32, 2).await
|
||||
}
|
||||
|
||||
pub async fn read32(&mut self, func: u32, addr: u32) -> u32 {
|
||||
self.readn(func, addr, 4).await
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub async fn write32(&mut self, func: u32, addr: u32, val: u32) {
|
||||
self.writen(func, addr, val, 4).await
|
||||
}
|
||||
|
||||
async fn readn(&mut self, func: u32, addr: u32, len: u32) -> u32 {
|
||||
let cmd = cmd_word(READ, INC_ADDR, func, addr, len);
|
||||
let mut buf = [0; 1];
|
||||
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[cmd]).await?;
|
||||
if func == FUNC_BACKPLANE {
|
||||
// 4-byte response delay.
|
||||
bus.read(&mut buf).await?;
|
||||
}
|
||||
bus.read(&mut buf).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
buf[0]
|
||||
}
|
||||
|
||||
async fn writen(&mut self, func: u32, addr: u32, val: u32, len: u32) {
|
||||
let cmd = cmd_word(WRITE, INC_ADDR, func, addr, len);
|
||||
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[cmd, val]).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn read32_swapped(&mut self, addr: u32) -> u32 {
|
||||
let cmd = cmd_word(READ, INC_ADDR, FUNC_BUS, addr, 4);
|
||||
let mut buf = [0; 1];
|
||||
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[swap16(cmd)]).await?;
|
||||
bus.read(&mut buf).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
swap16(buf[0])
|
||||
}
|
||||
|
||||
async fn write32_swapped(&mut self, addr: u32, val: u32) {
|
||||
let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4);
|
||||
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[swap16(cmd), swap16(val)]).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn swap16(x: u32) -> u32 {
|
||||
x.rotate_left(16)
|
||||
}
|
||||
|
||||
fn cmd_word(write: bool, incr: bool, func: u32, addr: u32, len: u32) -> u32 {
|
||||
(write as u32) << 31 | (incr as u32) << 30 | (func & 0b11) << 28 | (addr & 0x1FFFF) << 11 | (len & 0x7FF)
|
||||
}
|
||||
|
||||
fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
|
||||
let len = x.len() * 4;
|
||||
unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
|
||||
}
|
105
src/consts.rs
Normal file
105
src/consts.rs
Normal file
@ -0,0 +1,105 @@
|
||||
#![allow(unused)]
|
||||
pub(crate) const FUNC_BUS: u32 = 0;
|
||||
pub(crate) const FUNC_BACKPLANE: u32 = 1;
|
||||
pub(crate) const FUNC_WLAN: u32 = 2;
|
||||
pub(crate) const FUNC_BT: u32 = 3;
|
||||
|
||||
pub(crate) const REG_BUS_CTRL: u32 = 0x0;
|
||||
pub(crate) const REG_BUS_INTERRUPT: u32 = 0x04; // 16 bits - Interrupt status
|
||||
pub(crate) const REG_BUS_INTERRUPT_ENABLE: u32 = 0x06; // 16 bits - Interrupt mask
|
||||
pub(crate) const REG_BUS_STATUS: u32 = 0x8;
|
||||
pub(crate) const REG_BUS_TEST_RO: u32 = 0x14;
|
||||
pub(crate) const REG_BUS_TEST_RW: u32 = 0x18;
|
||||
pub(crate) const REG_BUS_RESP_DELAY: u32 = 0x1c;
|
||||
pub(crate) const WORD_LENGTH_32: u32 = 0x1;
|
||||
pub(crate) const HIGH_SPEED: u32 = 0x10;
|
||||
|
||||
// SPI_STATUS_REGISTER bits
|
||||
pub(crate) const STATUS_DATA_NOT_AVAILABLE: u32 = 0x00000001;
|
||||
pub(crate) const STATUS_UNDERFLOW: u32 = 0x00000002;
|
||||
pub(crate) const STATUS_OVERFLOW: u32 = 0x00000004;
|
||||
pub(crate) const STATUS_F2_INTR: u32 = 0x00000008;
|
||||
pub(crate) const STATUS_F3_INTR: u32 = 0x00000010;
|
||||
pub(crate) const STATUS_F2_RX_READY: u32 = 0x00000020;
|
||||
pub(crate) const STATUS_F3_RX_READY: u32 = 0x00000040;
|
||||
pub(crate) const STATUS_HOST_CMD_DATA_ERR: u32 = 0x00000080;
|
||||
pub(crate) const STATUS_F2_PKT_AVAILABLE: u32 = 0x00000100;
|
||||
pub(crate) const STATUS_F2_PKT_LEN_MASK: u32 = 0x000FFE00;
|
||||
pub(crate) const STATUS_F2_PKT_LEN_SHIFT: u32 = 9;
|
||||
pub(crate) const STATUS_F3_PKT_AVAILABLE: u32 = 0x00100000;
|
||||
pub(crate) const STATUS_F3_PKT_LEN_MASK: u32 = 0xFFE00000;
|
||||
pub(crate) const STATUS_F3_PKT_LEN_SHIFT: u32 = 21;
|
||||
|
||||
pub(crate) const REG_BACKPLANE_GPIO_SELECT: u32 = 0x10005;
|
||||
pub(crate) const REG_BACKPLANE_GPIO_OUTPUT: u32 = 0x10006;
|
||||
pub(crate) const REG_BACKPLANE_GPIO_ENABLE: u32 = 0x10007;
|
||||
pub(crate) const REG_BACKPLANE_FUNCTION2_WATERMARK: u32 = 0x10008;
|
||||
pub(crate) const REG_BACKPLANE_DEVICE_CONTROL: u32 = 0x10009;
|
||||
pub(crate) const REG_BACKPLANE_BACKPLANE_ADDRESS_LOW: u32 = 0x1000A;
|
||||
pub(crate) const REG_BACKPLANE_BACKPLANE_ADDRESS_MID: u32 = 0x1000B;
|
||||
pub(crate) const REG_BACKPLANE_BACKPLANE_ADDRESS_HIGH: u32 = 0x1000C;
|
||||
pub(crate) const REG_BACKPLANE_FRAME_CONTROL: u32 = 0x1000D;
|
||||
pub(crate) const REG_BACKPLANE_CHIP_CLOCK_CSR: u32 = 0x1000E;
|
||||
pub(crate) const REG_BACKPLANE_PULL_UP: u32 = 0x1000F;
|
||||
pub(crate) const REG_BACKPLANE_READ_FRAME_BC_LOW: u32 = 0x1001B;
|
||||
pub(crate) const REG_BACKPLANE_READ_FRAME_BC_HIGH: u32 = 0x1001C;
|
||||
pub(crate) const REG_BACKPLANE_WAKEUP_CTRL: u32 = 0x1001E;
|
||||
pub(crate) const REG_BACKPLANE_SLEEP_CSR: u32 = 0x1001F;
|
||||
|
||||
pub(crate) const BACKPLANE_WINDOW_SIZE: usize = 0x8000;
|
||||
pub(crate) const BACKPLANE_ADDRESS_MASK: u32 = 0x7FFF;
|
||||
pub(crate) const BACKPLANE_ADDRESS_32BIT_FLAG: u32 = 0x08000;
|
||||
pub(crate) const BACKPLANE_MAX_TRANSFER_SIZE: usize = 64;
|
||||
// Active Low Power (ALP) clock constants
|
||||
pub(crate) const BACKPLANE_ALP_AVAIL_REQ: u8 = 0x08;
|
||||
pub(crate) const BACKPLANE_ALP_AVAIL: u8 = 0x40;
|
||||
|
||||
// Broadcom AMBA (Advanced Microcontroller Bus Architecture) Interconnect
|
||||
// (AI) pub (crate) constants
|
||||
pub(crate) const AI_IOCTRL_OFFSET: u32 = 0x408;
|
||||
pub(crate) const AI_IOCTRL_BIT_FGC: u8 = 0x0002;
|
||||
pub(crate) const AI_IOCTRL_BIT_CLOCK_EN: u8 = 0x0001;
|
||||
pub(crate) const AI_IOCTRL_BIT_CPUHALT: u8 = 0x0020;
|
||||
|
||||
pub(crate) const AI_RESETCTRL_OFFSET: u32 = 0x800;
|
||||
pub(crate) const AI_RESETCTRL_BIT_RESET: u8 = 1;
|
||||
|
||||
pub(crate) const AI_RESETSTATUS_OFFSET: u32 = 0x804;
|
||||
|
||||
pub(crate) const TEST_PATTERN: u32 = 0x12345678;
|
||||
pub(crate) const FEEDBEAD: u32 = 0xFEEDBEAD;
|
||||
|
||||
// SPI_INTERRUPT_REGISTER and SPI_INTERRUPT_ENABLE_REGISTER Bits
|
||||
pub(crate) const IRQ_DATA_UNAVAILABLE: u16 = 0x0001; // Requested data not available; Clear by writing a "1"
|
||||
pub(crate) const IRQ_F2_F3_FIFO_RD_UNDERFLOW: u16 = 0x0002;
|
||||
pub(crate) const IRQ_F2_F3_FIFO_WR_OVERFLOW: u16 = 0x0004;
|
||||
pub(crate) const IRQ_COMMAND_ERROR: u16 = 0x0008; // Cleared by writing 1
|
||||
pub(crate) const IRQ_DATA_ERROR: u16 = 0x0010; // Cleared by writing 1
|
||||
pub(crate) const IRQ_F2_PACKET_AVAILABLE: u16 = 0x0020;
|
||||
pub(crate) const IRQ_F3_PACKET_AVAILABLE: u16 = 0x0040;
|
||||
pub(crate) const IRQ_F1_OVERFLOW: u16 = 0x0080; // Due to last write. Bkplane has pending write requests
|
||||
pub(crate) const IRQ_MISC_INTR0: u16 = 0x0100;
|
||||
pub(crate) const IRQ_MISC_INTR1: u16 = 0x0200;
|
||||
pub(crate) const IRQ_MISC_INTR2: u16 = 0x0400;
|
||||
pub(crate) const IRQ_MISC_INTR3: u16 = 0x0800;
|
||||
pub(crate) const IRQ_MISC_INTR4: u16 = 0x1000;
|
||||
pub(crate) const IRQ_F1_INTR: u16 = 0x2000;
|
||||
pub(crate) const IRQ_F2_INTR: u16 = 0x4000;
|
||||
pub(crate) const IRQ_F3_INTR: u16 = 0x8000;
|
||||
|
||||
pub(crate) const IOCTL_CMD_UP: u32 = 2;
|
||||
pub(crate) const IOCTL_CMD_SET_SSID: u32 = 26;
|
||||
pub(crate) const IOCTL_CMD_ANTDIV: u32 = 64;
|
||||
pub(crate) const IOCTL_CMD_SET_VAR: u32 = 263;
|
||||
pub(crate) const IOCTL_CMD_GET_VAR: u32 = 262;
|
||||
pub(crate) const IOCTL_CMD_SET_PASSPHRASE: u32 = 268;
|
||||
|
||||
pub(crate) const CHANNEL_TYPE_CONTROL: u8 = 0;
|
||||
pub(crate) const CHANNEL_TYPE_EVENT: u8 = 1;
|
||||
pub(crate) const CHANNEL_TYPE_DATA: u8 = 2;
|
||||
|
||||
// CYW_SPID command structure constants.
|
||||
pub(crate) const WRITE: bool = true;
|
||||
pub(crate) const READ: bool = false;
|
||||
pub(crate) const INC_ADDR: bool = true;
|
||||
pub(crate) const FIXED_ADDR: bool = false;
|
536
src/lib.rs
536
src/lib.rs
@ -6,6 +6,8 @@
|
||||
// This mod MUST go first, so that the others see its macros.
|
||||
pub(crate) mod fmt;
|
||||
|
||||
mod bus;
|
||||
mod consts;
|
||||
mod countries;
|
||||
mod events;
|
||||
mod structs;
|
||||
@ -23,132 +25,12 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||
use embassy_sync::channel::Channel;
|
||||
use embassy_time::{block_for, Duration, Timer};
|
||||
use embedded_hal_1::digital::OutputPin;
|
||||
use embedded_hal_async::spi::{transaction, SpiBusRead, SpiBusWrite, SpiDevice};
|
||||
use embedded_hal_async::spi::{SpiBusRead, SpiBusWrite, SpiDevice};
|
||||
|
||||
use self::structs::*;
|
||||
use crate::bus::Bus;
|
||||
use crate::consts::*;
|
||||
use crate::events::Event;
|
||||
|
||||
fn swap16(x: u32) -> u32 {
|
||||
x.rotate_left(16)
|
||||
}
|
||||
|
||||
fn cmd_word(write: bool, incr: bool, func: u32, addr: u32, len: u32) -> u32 {
|
||||
(write as u32) << 31 | (incr as u32) << 30 | (func & 0b11) << 28 | (addr & 0x1FFFF) << 11 | (len & 0x7FF)
|
||||
}
|
||||
|
||||
fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
|
||||
let len = x.len() * 4;
|
||||
unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
|
||||
}
|
||||
|
||||
mod constants {
|
||||
#![allow(unused)]
|
||||
pub(crate) const FUNC_BUS: u32 = 0;
|
||||
pub(crate) const FUNC_BACKPLANE: u32 = 1;
|
||||
pub(crate) const FUNC_WLAN: u32 = 2;
|
||||
pub(crate) const FUNC_BT: u32 = 3;
|
||||
|
||||
pub(crate) const REG_BUS_CTRL: u32 = 0x0;
|
||||
pub(crate) const REG_BUS_INTERRUPT: u32 = 0x04; // 16 bits - Interrupt status
|
||||
pub(crate) const REG_BUS_INTERRUPT_ENABLE: u32 = 0x06; // 16 bits - Interrupt mask
|
||||
pub(crate) const REG_BUS_STATUS: u32 = 0x8;
|
||||
pub(crate) const REG_BUS_TEST_RO: u32 = 0x14;
|
||||
pub(crate) const REG_BUS_TEST_RW: u32 = 0x18;
|
||||
pub(crate) const REG_BUS_RESP_DELAY: u32 = 0x1c;
|
||||
pub(crate) const WORD_LENGTH_32: u32 = 0x1;
|
||||
pub(crate) const HIGH_SPEED: u32 = 0x10;
|
||||
|
||||
// SPI_STATUS_REGISTER bits
|
||||
pub(crate) const STATUS_DATA_NOT_AVAILABLE: u32 = 0x00000001;
|
||||
pub(crate) const STATUS_UNDERFLOW: u32 = 0x00000002;
|
||||
pub(crate) const STATUS_OVERFLOW: u32 = 0x00000004;
|
||||
pub(crate) const STATUS_F2_INTR: u32 = 0x00000008;
|
||||
pub(crate) const STATUS_F3_INTR: u32 = 0x00000010;
|
||||
pub(crate) const STATUS_F2_RX_READY: u32 = 0x00000020;
|
||||
pub(crate) const STATUS_F3_RX_READY: u32 = 0x00000040;
|
||||
pub(crate) const STATUS_HOST_CMD_DATA_ERR: u32 = 0x00000080;
|
||||
pub(crate) const STATUS_F2_PKT_AVAILABLE: u32 = 0x00000100;
|
||||
pub(crate) const STATUS_F2_PKT_LEN_MASK: u32 = 0x000FFE00;
|
||||
pub(crate) const STATUS_F2_PKT_LEN_SHIFT: u32 = 9;
|
||||
pub(crate) const STATUS_F3_PKT_AVAILABLE: u32 = 0x00100000;
|
||||
pub(crate) const STATUS_F3_PKT_LEN_MASK: u32 = 0xFFE00000;
|
||||
pub(crate) const STATUS_F3_PKT_LEN_SHIFT: u32 = 21;
|
||||
|
||||
pub(crate) const REG_BACKPLANE_GPIO_SELECT: u32 = 0x10005;
|
||||
pub(crate) const REG_BACKPLANE_GPIO_OUTPUT: u32 = 0x10006;
|
||||
pub(crate) const REG_BACKPLANE_GPIO_ENABLE: u32 = 0x10007;
|
||||
pub(crate) const REG_BACKPLANE_FUNCTION2_WATERMARK: u32 = 0x10008;
|
||||
pub(crate) const REG_BACKPLANE_DEVICE_CONTROL: u32 = 0x10009;
|
||||
pub(crate) const REG_BACKPLANE_BACKPLANE_ADDRESS_LOW: u32 = 0x1000A;
|
||||
pub(crate) const REG_BACKPLANE_BACKPLANE_ADDRESS_MID: u32 = 0x1000B;
|
||||
pub(crate) const REG_BACKPLANE_BACKPLANE_ADDRESS_HIGH: u32 = 0x1000C;
|
||||
pub(crate) const REG_BACKPLANE_FRAME_CONTROL: u32 = 0x1000D;
|
||||
pub(crate) const REG_BACKPLANE_CHIP_CLOCK_CSR: u32 = 0x1000E;
|
||||
pub(crate) const REG_BACKPLANE_PULL_UP: u32 = 0x1000F;
|
||||
pub(crate) const REG_BACKPLANE_READ_FRAME_BC_LOW: u32 = 0x1001B;
|
||||
pub(crate) const REG_BACKPLANE_READ_FRAME_BC_HIGH: u32 = 0x1001C;
|
||||
pub(crate) const REG_BACKPLANE_WAKEUP_CTRL: u32 = 0x1001E;
|
||||
pub(crate) const REG_BACKPLANE_SLEEP_CSR: u32 = 0x1001F;
|
||||
|
||||
pub(crate) const BACKPLANE_WINDOW_SIZE: usize = 0x8000;
|
||||
pub(crate) const BACKPLANE_ADDRESS_MASK: u32 = 0x7FFF;
|
||||
pub(crate) const BACKPLANE_ADDRESS_32BIT_FLAG: u32 = 0x08000;
|
||||
pub(crate) const BACKPLANE_MAX_TRANSFER_SIZE: usize = 64;
|
||||
// Active Low Power (ALP) clock constants
|
||||
pub(crate) const BACKPLANE_ALP_AVAIL_REQ: u8 = 0x08;
|
||||
pub(crate) const BACKPLANE_ALP_AVAIL: u8 = 0x40;
|
||||
|
||||
// Broadcom AMBA (Advanced Microcontroller Bus Architecture) Interconnect
|
||||
// (AI) pub (crate) constants
|
||||
pub(crate) const AI_IOCTRL_OFFSET: u32 = 0x408;
|
||||
pub(crate) const AI_IOCTRL_BIT_FGC: u8 = 0x0002;
|
||||
pub(crate) const AI_IOCTRL_BIT_CLOCK_EN: u8 = 0x0001;
|
||||
pub(crate) const AI_IOCTRL_BIT_CPUHALT: u8 = 0x0020;
|
||||
|
||||
pub(crate) const AI_RESETCTRL_OFFSET: u32 = 0x800;
|
||||
pub(crate) const AI_RESETCTRL_BIT_RESET: u8 = 1;
|
||||
|
||||
pub(crate) const AI_RESETSTATUS_OFFSET: u32 = 0x804;
|
||||
|
||||
pub(crate) const TEST_PATTERN: u32 = 0x12345678;
|
||||
pub(crate) const FEEDBEAD: u32 = 0xFEEDBEAD;
|
||||
|
||||
// SPI_INTERRUPT_REGISTER and SPI_INTERRUPT_ENABLE_REGISTER Bits
|
||||
pub(crate) const IRQ_DATA_UNAVAILABLE: u16 = 0x0001; // Requested data not available; Clear by writing a "1"
|
||||
pub(crate) const IRQ_F2_F3_FIFO_RD_UNDERFLOW: u16 = 0x0002;
|
||||
pub(crate) const IRQ_F2_F3_FIFO_WR_OVERFLOW: u16 = 0x0004;
|
||||
pub(crate) const IRQ_COMMAND_ERROR: u16 = 0x0008; // Cleared by writing 1
|
||||
pub(crate) const IRQ_DATA_ERROR: u16 = 0x0010; // Cleared by writing 1
|
||||
pub(crate) const IRQ_F2_PACKET_AVAILABLE: u16 = 0x0020;
|
||||
pub(crate) const IRQ_F3_PACKET_AVAILABLE: u16 = 0x0040;
|
||||
pub(crate) const IRQ_F1_OVERFLOW: u16 = 0x0080; // Due to last write. Bkplane has pending write requests
|
||||
pub(crate) const IRQ_MISC_INTR0: u16 = 0x0100;
|
||||
pub(crate) const IRQ_MISC_INTR1: u16 = 0x0200;
|
||||
pub(crate) const IRQ_MISC_INTR2: u16 = 0x0400;
|
||||
pub(crate) const IRQ_MISC_INTR3: u16 = 0x0800;
|
||||
pub(crate) const IRQ_MISC_INTR4: u16 = 0x1000;
|
||||
pub(crate) const IRQ_F1_INTR: u16 = 0x2000;
|
||||
pub(crate) const IRQ_F2_INTR: u16 = 0x4000;
|
||||
pub(crate) const IRQ_F3_INTR: u16 = 0x8000;
|
||||
|
||||
pub(crate) const IOCTL_CMD_UP: u32 = 2;
|
||||
pub(crate) const IOCTL_CMD_SET_SSID: u32 = 26;
|
||||
pub(crate) const IOCTL_CMD_ANTDIV: u32 = 64;
|
||||
pub(crate) const IOCTL_CMD_SET_VAR: u32 = 263;
|
||||
pub(crate) const IOCTL_CMD_GET_VAR: u32 = 262;
|
||||
pub(crate) const IOCTL_CMD_SET_PASSPHRASE: u32 = 268;
|
||||
|
||||
pub(crate) const CHANNEL_TYPE_CONTROL: u8 = 0;
|
||||
pub(crate) const CHANNEL_TYPE_EVENT: u8 = 1;
|
||||
pub(crate) const CHANNEL_TYPE_DATA: u8 = 2;
|
||||
|
||||
// CYW_SPID command structure constants.
|
||||
pub(crate) const WRITE: bool = true;
|
||||
pub(crate) const READ: bool = false;
|
||||
pub(crate) const INC_ADDR: bool = true;
|
||||
pub(crate) const FIXED_ADDR: bool = false;
|
||||
}
|
||||
use crate::constants::*;
|
||||
use crate::structs::*;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum IoctlType {
|
||||
@ -565,15 +447,11 @@ impl<'a> embassy_net::Device for NetDevice<'a> {
|
||||
}
|
||||
|
||||
pub struct Runner<'a, PWR, SPI> {
|
||||
bus: Bus<PWR, SPI>,
|
||||
|
||||
state: &'a State,
|
||||
|
||||
pwr: PWR,
|
||||
spi: SPI,
|
||||
|
||||
ioctl_id: u16,
|
||||
sdpcm_seq: u8,
|
||||
backplane_window: u32,
|
||||
|
||||
sdpcm_seq_max: u8,
|
||||
|
||||
#[cfg(feature = "firmware-logs")]
|
||||
@ -600,14 +478,11 @@ where
|
||||
SPI::Bus: SpiBusRead<u32> + SpiBusWrite<u32>,
|
||||
{
|
||||
let mut runner = Runner {
|
||||
state,
|
||||
pwr,
|
||||
spi,
|
||||
bus: Bus::new(pwr, spi),
|
||||
|
||||
state,
|
||||
ioctl_id: 0,
|
||||
sdpcm_seq: 0,
|
||||
backplane_window: 0xAAAA_AAAA,
|
||||
|
||||
sdpcm_seq_max: 1,
|
||||
|
||||
#[cfg(feature = "firmware-logs")]
|
||||
@ -631,62 +506,41 @@ where
|
||||
SPI::Bus: SpiBusRead<u32> + SpiBusWrite<u32>,
|
||||
{
|
||||
async fn init(&mut self, firmware: &[u8]) {
|
||||
// Reset
|
||||
self.pwr.set_low().unwrap();
|
||||
Timer::after(Duration::from_millis(20)).await;
|
||||
self.pwr.set_high().unwrap();
|
||||
Timer::after(Duration::from_millis(250)).await;
|
||||
|
||||
info!("waiting for ping...");
|
||||
while self.read32_swapped(REG_BUS_TEST_RO).await != FEEDBEAD {}
|
||||
info!("ping ok");
|
||||
|
||||
self.write32_swapped(REG_BUS_TEST_RW, TEST_PATTERN).await;
|
||||
let val = self.read32_swapped(REG_BUS_TEST_RW).await;
|
||||
assert_eq!(val, TEST_PATTERN);
|
||||
|
||||
// 32-bit word length, little endian (which is the default endianess).
|
||||
self.write32_swapped(REG_BUS_CTRL, WORD_LENGTH_32 | HIGH_SPEED).await;
|
||||
|
||||
let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await;
|
||||
assert_eq!(val, FEEDBEAD);
|
||||
let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await;
|
||||
assert_eq!(val, TEST_PATTERN);
|
||||
|
||||
// No response delay in any of the funcs.
|
||||
// seems to break backplane??? eat the 4-byte delay instead, that's what the vendor drivers do...
|
||||
//self.write32(FUNC_BUS, REG_BUS_RESP_DELAY, 0).await;
|
||||
self.bus.init().await;
|
||||
|
||||
// Init ALP (Active Low Power) clock
|
||||
self.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ)
|
||||
self.bus
|
||||
.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ)
|
||||
.await;
|
||||
info!("waiting for clock...");
|
||||
while self.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {}
|
||||
while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {}
|
||||
info!("clock ok");
|
||||
|
||||
let chip_id = self.bp_read16(0x1800_0000).await;
|
||||
let chip_id = self.bus.bp_read16(0x1800_0000).await;
|
||||
info!("chip ID: {}", chip_id);
|
||||
|
||||
// Upload firmware.
|
||||
self.core_disable(Core::WLAN).await;
|
||||
self.core_reset(Core::SOCSRAM).await;
|
||||
self.bp_write32(CHIP.socsram_base_address + 0x10, 3).await;
|
||||
self.bp_write32(CHIP.socsram_base_address + 0x44, 0).await;
|
||||
self.bus.bp_write32(CHIP.socsram_base_address + 0x10, 3).await;
|
||||
self.bus.bp_write32(CHIP.socsram_base_address + 0x44, 0).await;
|
||||
|
||||
let ram_addr = CHIP.atcm_ram_base_address;
|
||||
|
||||
info!("loading fw");
|
||||
self.bp_write(ram_addr, firmware).await;
|
||||
self.bus.bp_write(ram_addr, firmware).await;
|
||||
|
||||
info!("loading nvram");
|
||||
// Round up to 4 bytes.
|
||||
let nvram_len = (NVRAM.len() + 3) / 4 * 4;
|
||||
self.bp_write(ram_addr + CHIP.chip_ram_size - 4 - nvram_len as u32, NVRAM)
|
||||
self.bus
|
||||
.bp_write(ram_addr + CHIP.chip_ram_size - 4 - nvram_len as u32, NVRAM)
|
||||
.await;
|
||||
|
||||
let nvram_len_words = nvram_len as u32 / 4;
|
||||
let nvram_len_magic = (!nvram_len_words << 16) | nvram_len_words;
|
||||
self.bp_write32(ram_addr + CHIP.chip_ram_size - 4, nvram_len_magic)
|
||||
self.bus
|
||||
.bp_write32(ram_addr + CHIP.chip_ram_size - 4, nvram_len_magic)
|
||||
.await;
|
||||
|
||||
// Start core!
|
||||
@ -694,18 +548,20 @@ where
|
||||
self.core_reset(Core::WLAN).await;
|
||||
assert!(self.core_is_up(Core::WLAN).await);
|
||||
|
||||
while self.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
|
||||
while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
|
||||
|
||||
// "Set up the interrupt mask and enable interrupts"
|
||||
self.bp_write32(CHIP.sdiod_core_base_address + 0x24, 0xF0).await;
|
||||
self.bus.bp_write32(CHIP.sdiod_core_base_address + 0x24, 0xF0).await;
|
||||
|
||||
// "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped."
|
||||
// Sounds scary...
|
||||
self.write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 32).await;
|
||||
self.bus
|
||||
.write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 32)
|
||||
.await;
|
||||
|
||||
// wait for wifi startup
|
||||
info!("waiting for wifi init...");
|
||||
while self.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {}
|
||||
while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {}
|
||||
|
||||
// Some random configs related to sleep.
|
||||
// These aren't needed if we don't want to sleep the bus.
|
||||
@ -713,25 +569,25 @@ where
|
||||
// being on the same pin as MOSI/MISO?
|
||||
|
||||
/*
|
||||
let mut val = self.read8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL).await;
|
||||
let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL).await;
|
||||
val |= 0x02; // WAKE_TILL_HT_AVAIL
|
||||
self.write8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL, val).await;
|
||||
self.write8(FUNC_BUS, 0xF0, 0x08).await; // SDIOD_CCCR_BRCM_CARDCAP.CMD_NODEC = 1
|
||||
self.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x02).await; // SBSDIO_FORCE_HT
|
||||
self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL, val).await;
|
||||
self.bus.write8(FUNC_BUS, 0xF0, 0x08).await; // SDIOD_CCCR_BRCM_CARDCAP.CMD_NODEC = 1
|
||||
self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x02).await; // SBSDIO_FORCE_HT
|
||||
|
||||
let mut val = self.read8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR).await;
|
||||
let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR).await;
|
||||
val |= 0x01; // SBSDIO_SLPCSR_KEEP_SDIO_ON
|
||||
self.write8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR, val).await;
|
||||
self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR, val).await;
|
||||
*/
|
||||
|
||||
// clear pulls
|
||||
self.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await;
|
||||
let _ = self.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await;
|
||||
self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await;
|
||||
let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await;
|
||||
|
||||
// start HT clock
|
||||
//self.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10).await;
|
||||
//self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10).await;
|
||||
//info!("waiting for HT clock...");
|
||||
//while self.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
|
||||
//while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
|
||||
//info!("clock ok");
|
||||
|
||||
#[cfg(feature = "firmware-logs")]
|
||||
@ -744,13 +600,12 @@ where
|
||||
async fn log_init(&mut self) {
|
||||
// Initialize shared memory for logging.
|
||||
|
||||
let shared_addr = self
|
||||
.bp_read32(CHIP.atcm_ram_base_address + CHIP.chip_ram_size - 4 - CHIP.socram_srmem_size)
|
||||
.await;
|
||||
let addr = CHIP.atcm_ram_base_address + CHIP.chip_ram_size - 4 - CHIP.socram_srmem_size;
|
||||
let shared_addr = self.bus.bp_read32(addr).await;
|
||||
info!("shared_addr {:08x}", shared_addr);
|
||||
|
||||
let mut shared = [0; SharedMemData::SIZE];
|
||||
self.bp_read(shared_addr, &mut shared).await;
|
||||
self.bus.bp_read(shared_addr, &mut shared).await;
|
||||
let shared = SharedMemData::from_bytes(&shared);
|
||||
info!("shared: {:08x}", shared);
|
||||
|
||||
@ -761,7 +616,7 @@ where
|
||||
async fn log_read(&mut self) {
|
||||
// Read log struct
|
||||
let mut log = [0; SharedMemLog::SIZE];
|
||||
self.bp_read(self.log.addr, &mut log).await;
|
||||
self.bus.bp_read(self.log.addr, &mut log).await;
|
||||
let log = SharedMemLog::from_bytes(&log);
|
||||
|
||||
let idx = log.idx as usize;
|
||||
@ -774,7 +629,7 @@ where
|
||||
// Read entire buf for now. We could read only what we need, but then we
|
||||
// run into annoying alignment issues in `bp_read`.
|
||||
let mut buf = [0; 0x400];
|
||||
self.bp_read(log.buf, &mut buf).await;
|
||||
self.bus.bp_read(log.buf, &mut buf).await;
|
||||
|
||||
while self.log.last_idx != idx as usize {
|
||||
let b = buf[self.log.last_idx];
|
||||
@ -821,29 +676,19 @@ where
|
||||
}
|
||||
|
||||
// Receive stuff
|
||||
let irq = self.read16(FUNC_BUS, REG_BUS_INTERRUPT).await;
|
||||
let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await;
|
||||
|
||||
if irq & IRQ_F2_PACKET_AVAILABLE != 0 {
|
||||
let mut status = 0xFFFF_FFFF;
|
||||
while status == 0xFFFF_FFFF {
|
||||
status = self.read32(FUNC_BUS, REG_BUS_STATUS).await;
|
||||
status = self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await;
|
||||
}
|
||||
|
||||
if status & STATUS_F2_PKT_AVAILABLE != 0 {
|
||||
let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT;
|
||||
|
||||
let cmd = cmd_word(READ, INC_ADDR, FUNC_WLAN, 0, len);
|
||||
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[cmd]).await?;
|
||||
bus.read(&mut buf[..(len as usize + 3) / 4]).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
self.bus.wlan_read(&mut buf[..(len as usize + 3) / 4]).await;
|
||||
trace!("rx {:02x}", &slice8_mut(&mut buf)[..(len as usize).min(48)]);
|
||||
|
||||
self.rx(&slice8_mut(&mut buf)[..len as usize]);
|
||||
}
|
||||
}
|
||||
@ -893,14 +738,7 @@ where
|
||||
|
||||
trace!(" {:02x}", &buf8[..total_len.min(48)]);
|
||||
|
||||
let cmd = cmd_word(WRITE, INC_ADDR, FUNC_WLAN, 0, total_len as _);
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[cmd]).await?;
|
||||
bus.write(&buf[..(total_len / 4)]).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
self.bus.wlan_write(&buf[..(total_len / 4)]).await;
|
||||
}
|
||||
|
||||
fn rx(&mut self, packet: &[u8]) {
|
||||
@ -1086,52 +924,49 @@ where
|
||||
|
||||
trace!(" {:02x}", &buf8[..total_len.min(48)]);
|
||||
|
||||
let cmd = cmd_word(WRITE, INC_ADDR, FUNC_WLAN, 0, total_len as _);
|
||||
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[cmd]).await?;
|
||||
bus.write(&buf[..total_len / 4]).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
self.bus.wlan_write(&buf[..total_len / 4]).await;
|
||||
}
|
||||
|
||||
async fn core_disable(&mut self, core: Core) {
|
||||
let base = core.base_addr();
|
||||
|
||||
// Dummy read?
|
||||
let _ = self.bp_read8(base + AI_RESETCTRL_OFFSET).await;
|
||||
let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
|
||||
|
||||
// Check it isn't already reset
|
||||
let r = self.bp_read8(base + AI_RESETCTRL_OFFSET).await;
|
||||
let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
|
||||
if r & AI_RESETCTRL_BIT_RESET != 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.bp_write8(base + AI_IOCTRL_OFFSET, 0).await;
|
||||
let _ = self.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
||||
self.bus.bp_write8(base + AI_IOCTRL_OFFSET, 0).await;
|
||||
let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
||||
|
||||
block_for(Duration::from_millis(1));
|
||||
|
||||
self.bp_write8(base + AI_RESETCTRL_OFFSET, AI_RESETCTRL_BIT_RESET).await;
|
||||
let _ = self.bp_read8(base + AI_RESETCTRL_OFFSET).await;
|
||||
self.bus
|
||||
.bp_write8(base + AI_RESETCTRL_OFFSET, AI_RESETCTRL_BIT_RESET)
|
||||
.await;
|
||||
let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
|
||||
}
|
||||
|
||||
async fn core_reset(&mut self, core: Core) {
|
||||
self.core_disable(core).await;
|
||||
|
||||
let base = core.base_addr();
|
||||
self.bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN)
|
||||
self.bus
|
||||
.bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN)
|
||||
.await;
|
||||
let _ = self.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
||||
let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
||||
|
||||
self.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await;
|
||||
self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await;
|
||||
|
||||
Timer::after(Duration::from_millis(1)).await;
|
||||
|
||||
self.bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN).await;
|
||||
let _ = self.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
||||
self.bus
|
||||
.bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN)
|
||||
.await;
|
||||
let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
||||
|
||||
Timer::after(Duration::from_millis(1)).await;
|
||||
}
|
||||
@ -1139,13 +974,13 @@ where
|
||||
async fn core_is_up(&mut self, core: Core) -> bool {
|
||||
let base = core.base_addr();
|
||||
|
||||
let io = self.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
||||
let io = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
||||
if io & (AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN) != AI_IOCTRL_BIT_CLOCK_EN {
|
||||
debug!("core_is_up: returning false due to bad ioctrl {:02x}", io);
|
||||
return false;
|
||||
}
|
||||
|
||||
let r = self.bp_read8(base + AI_RESETCTRL_OFFSET).await;
|
||||
let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await;
|
||||
if r & (AI_RESETCTRL_BIT_RESET) != 0 {
|
||||
debug!("core_is_up: returning false due to bad resetctrl {:02x}", r);
|
||||
return false;
|
||||
@ -1153,242 +988,11 @@ where
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
async fn bp_read(&mut self, mut addr: u32, mut data: &mut [u8]) {
|
||||
// It seems the HW force-aligns the addr
|
||||
// to 2 if data.len() >= 2
|
||||
// to 4 if data.len() >= 4
|
||||
// To simplify, enforce 4-align for now.
|
||||
assert!(addr % 4 == 0);
|
||||
|
||||
let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4];
|
||||
|
||||
while !data.is_empty() {
|
||||
// Ensure transfer doesn't cross a window boundary.
|
||||
let window_offs = addr & BACKPLANE_ADDRESS_MASK;
|
||||
let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize;
|
||||
|
||||
let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining);
|
||||
|
||||
self.backplane_set_window(addr).await;
|
||||
|
||||
let cmd = cmd_word(READ, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32);
|
||||
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[cmd]).await?;
|
||||
|
||||
// 4-byte response delay.
|
||||
let mut junk = [0; 1];
|
||||
bus.read(&mut junk).await?;
|
||||
|
||||
// Read data
|
||||
bus.read(&mut buf[..(len + 3) / 4]).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
data[..len].copy_from_slice(&slice8_mut(&mut buf)[..len]);
|
||||
|
||||
// Advance ptr.
|
||||
addr += len as u32;
|
||||
data = &mut data[len..];
|
||||
}
|
||||
}
|
||||
|
||||
async fn bp_write(&mut self, mut addr: u32, mut data: &[u8]) {
|
||||
// It seems the HW force-aligns the addr
|
||||
// to 2 if data.len() >= 2
|
||||
// to 4 if data.len() >= 4
|
||||
// To simplify, enforce 4-align for now.
|
||||
assert!(addr % 4 == 0);
|
||||
|
||||
let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4];
|
||||
|
||||
while !data.is_empty() {
|
||||
// Ensure transfer doesn't cross a window boundary.
|
||||
let window_offs = addr & BACKPLANE_ADDRESS_MASK;
|
||||
let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize;
|
||||
|
||||
let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining);
|
||||
slice8_mut(&mut buf)[..len].copy_from_slice(&data[..len]);
|
||||
|
||||
self.backplane_set_window(addr).await;
|
||||
|
||||
let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32);
|
||||
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[cmd]).await?;
|
||||
bus.write(&buf[..(len + 3) / 4]).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Advance ptr.
|
||||
addr += len as u32;
|
||||
data = &data[len..];
|
||||
}
|
||||
}
|
||||
|
||||
async fn bp_read8(&mut self, addr: u32) -> u8 {
|
||||
self.backplane_readn(addr, 1).await as u8
|
||||
}
|
||||
|
||||
async fn bp_write8(&mut self, addr: u32, val: u8) {
|
||||
self.backplane_writen(addr, val as u32, 1).await
|
||||
}
|
||||
|
||||
async fn bp_read16(&mut self, addr: u32) -> u16 {
|
||||
self.backplane_readn(addr, 2).await as u16
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
async fn bp_write16(&mut self, addr: u32, val: u16) {
|
||||
self.backplane_writen(addr, val as u32, 2).await
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
async fn bp_read32(&mut self, addr: u32) -> u32 {
|
||||
self.backplane_readn(addr, 4).await
|
||||
}
|
||||
|
||||
async fn bp_write32(&mut self, addr: u32, val: u32) {
|
||||
self.backplane_writen(addr, val, 4).await
|
||||
}
|
||||
|
||||
async fn backplane_readn(&mut self, addr: u32, len: u32) -> u32 {
|
||||
self.backplane_set_window(addr).await;
|
||||
|
||||
let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK;
|
||||
if len == 4 {
|
||||
bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG
|
||||
}
|
||||
self.readn(FUNC_BACKPLANE, bus_addr, len).await
|
||||
}
|
||||
|
||||
async fn backplane_writen(&mut self, addr: u32, val: u32, len: u32) {
|
||||
self.backplane_set_window(addr).await;
|
||||
|
||||
let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK;
|
||||
if len == 4 {
|
||||
bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG
|
||||
}
|
||||
self.writen(FUNC_BACKPLANE, bus_addr, val, len).await
|
||||
}
|
||||
|
||||
async fn backplane_set_window(&mut self, addr: u32) {
|
||||
let new_window = addr & !BACKPLANE_ADDRESS_MASK;
|
||||
|
||||
if (new_window >> 24) as u8 != (self.backplane_window >> 24) as u8 {
|
||||
self.write8(
|
||||
FUNC_BACKPLANE,
|
||||
REG_BACKPLANE_BACKPLANE_ADDRESS_HIGH,
|
||||
(new_window >> 24) as u8,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
if (new_window >> 16) as u8 != (self.backplane_window >> 16) as u8 {
|
||||
self.write8(
|
||||
FUNC_BACKPLANE,
|
||||
REG_BACKPLANE_BACKPLANE_ADDRESS_MID,
|
||||
(new_window >> 16) as u8,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
if (new_window >> 8) as u8 != (self.backplane_window >> 8) as u8 {
|
||||
self.write8(
|
||||
FUNC_BACKPLANE,
|
||||
REG_BACKPLANE_BACKPLANE_ADDRESS_LOW,
|
||||
(new_window >> 8) as u8,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
self.backplane_window = new_window;
|
||||
}
|
||||
|
||||
async fn read8(&mut self, func: u32, addr: u32) -> u8 {
|
||||
self.readn(func, addr, 1).await as u8
|
||||
}
|
||||
|
||||
async fn write8(&mut self, func: u32, addr: u32, val: u8) {
|
||||
self.writen(func, addr, val as u32, 1).await
|
||||
}
|
||||
|
||||
async fn read16(&mut self, func: u32, addr: u32) -> u16 {
|
||||
self.readn(func, addr, 2).await as u16
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
async fn write16(&mut self, func: u32, addr: u32, val: u16) {
|
||||
self.writen(func, addr, val as u32, 2).await
|
||||
}
|
||||
|
||||
async fn read32(&mut self, func: u32, addr: u32) -> u32 {
|
||||
self.readn(func, addr, 4).await
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
async fn write32(&mut self, func: u32, addr: u32, val: u32) {
|
||||
self.writen(func, addr, val, 4).await
|
||||
}
|
||||
|
||||
async fn readn(&mut self, func: u32, addr: u32, len: u32) -> u32 {
|
||||
let cmd = cmd_word(READ, INC_ADDR, func, addr, len);
|
||||
let mut buf = [0; 1];
|
||||
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[cmd]).await?;
|
||||
if func == FUNC_BACKPLANE {
|
||||
// 4-byte response delay.
|
||||
bus.read(&mut buf).await?;
|
||||
}
|
||||
bus.read(&mut buf).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
buf[0]
|
||||
}
|
||||
|
||||
async fn writen(&mut self, func: u32, addr: u32, val: u32, len: u32) {
|
||||
let cmd = cmd_word(WRITE, INC_ADDR, func, addr, len);
|
||||
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[cmd, val]).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn read32_swapped(&mut self, addr: u32) -> u32 {
|
||||
let cmd = cmd_word(READ, INC_ADDR, FUNC_BUS, addr, 4);
|
||||
let mut buf = [0; 1];
|
||||
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[swap16(cmd)]).await?;
|
||||
bus.read(&mut buf).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
swap16(buf[0])
|
||||
}
|
||||
|
||||
async fn write32_swapped(&mut self, addr: u32, val: u32) {
|
||||
let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4);
|
||||
|
||||
transaction!(&mut self.spi, |bus| async {
|
||||
bus.write(&[swap16(cmd), swap16(val)]).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
|
||||
let len = x.len() * 4;
|
||||
unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
|
||||
}
|
||||
|
||||
macro_rules! nvram {
|
||||
|
Loading…
Reference in New Issue
Block a user