extern crate alloc;
pub mod chip;
pub mod config;
pub mod firmware;
pub mod protocol;
pub use chip::{ChipRevision, ChipVariant};
use config::*;
pub use firmware::FirmwareSet;
use firmware::{
get_firmware_set, init_aic8800d80_firmware, init_aic8800dc_firmware, init_aic8801_firmware,
};
use protocol::{IpcTransport, ipc_mem_write}; use sdio_host::{SdioHost, error::SdioError};
pub use crate::common;
use crate::common::{SDIOWIFI_V3_WAKEUP_VALUE, SDIOWIFI_WAKEUP_REG_V3};
pub fn sdio_func_setup<H: SdioHost>(host: &mut H, is_v3: bool) -> Result<(), SdioError> {
if !is_v3 {
host.write_byte(1, SDIOWIFI_REGISTER_BLOCK, 0x01)?;
host.write_byte(1, SDIOWIFI_BYTEMODE_ENABLE_REG, 0x01)?;
crate::runtime::runtime().sleep_ms(10);
} else {
host.write_byte(0, 0xF2, 0x7F)?;
host.write_byte(1, SDIOWIFI_BYTEMODE_ENABLE_REG_V3, 0x01)?;
host.write_byte(1, SDIOWIFI_WAKEUP_REG_V3, SDIOWIFI_V3_WAKEUP_VALUE)?;
crate::runtime::runtime().sleep_ms(5);
let sleep_val = host.read_byte(1, SDIOWIFI_SLEEP_REG_V3)?;
if sleep_val & SDIOWIFI_V3_SLEEP_READY_BIT == 0 {
log::error!("[aic8800] V3 wakeup failed, sleep_reg=0x{:02x}", sleep_val);
return Err(SdioError::Timeout);
}
log::info!("[aic8800] V3 SDIO ready (sleep_reg=0x{:02x})", sleep_val);
}
log::debug!("[aic8800] SDIO func setup done (v3={})", is_v3);
Ok(())
}
fn aicbsp_system_config<H: SdioHost>(ipc: &mut IpcTransport<H>) -> Result<(), SdioError> {
for &(addr, data) in config::SYSCFG_TBL {
ipc_mem_write(ipc, addr, data)?;
}
log::debug!("[aic8800] aicbsp_system_config done");
Ok(())
}
pub fn firmware_init<H: SdioHost>(host: &mut H, chip: ChipVariant) -> Result<(), SdioError> {
log::info!("[aic8800] firmware_init: chip={:?}", chip);
let is_v3 = matches!(chip, ChipVariant::Aic8800D80 | ChipVariant::Aic8800D80X2);
sdio_func_setup(host, is_v3)?;
if matches!(chip, ChipVariant::Aic8801) {
host.set_clock(DEFAULT_CLOCK_FREQ)?;
log::debug!("[aic8800] SDIO clock set to 25MHz for AIC8801");
}
let mut ipc = IpcTransport::new(host, chip);
let chip_rev = chip::read_chip_revision(&mut ipc, chip)?;
log::debug!("[aic8800] chip_rev={}", chip_rev.rev);
chip::validate_chip_revision(chip, &chip_rev)?;
if matches!(chip, ChipVariant::Aic8801) {
aicbsp_system_config(&mut ipc)?;
}
let fw_set = get_firmware_set(chip, &chip_rev).unwrap();
log::debug!(
"[aic8800] firmware: {} (fw={} bytes, patch={} bytes)",
fw_set.desc,
fw_set.wl_fw.len(),
fw_set.wl_patch.len(),
);
if fw_set.wl_fw.is_empty() {
log::error!("[aic8800] WiFi firmware data is empty");
return Err(SdioError::Unsupported);
}
match chip {
ChipVariant::Aic8801 => init_aic8801_firmware(&mut ipc, &fw_set)?,
ChipVariant::Aic8800DC | ChipVariant::Aic8800DW => {
init_aic8800dc_firmware(&mut ipc, &fw_set, &chip_rev)?
}
ChipVariant::Aic8800D80 | ChipVariant::Aic8800D80X2 => {
init_aic8800d80_firmware(&mut ipc, &fw_set)?
}
ChipVariant::Unknown => {
log::error!("[aic8800] Unknown chip, cannot init firmware");
return Err(SdioError::Unsupported);
}
}
if is_v3 {
host.write_byte(1, SDIOWIFI_WAKEUP_REG_V3, 0x04)?;
log::debug!("[aic8800] D80 post-init wakeup_reg=0x04 written");
}
log::info!("[aic8800] Firmware init complete");
Ok(())
}