diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-08-05 20:58:04 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2024-08-05 21:07:42 +0200 |
| commit | 4f7ac1946a43379306aa432961fb97bba1139a6e (patch) | |
| tree | 2589e67baa770acf244dfdea355e16585d683d16 /cyw43/src/runner.rs | |
| parent | afc8e684dd16c3bc947b365ca293f0f37d95b342 (diff) | |
cyw43: add Bluetooth support.
Co-Authored-By: Brandon Ros <[email protected]>
Diffstat (limited to 'cyw43/src/runner.rs')
| -rw-r--r-- | cyw43/src/runner.rs | 120 |
1 files changed, 96 insertions, 24 deletions
diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs index e90316302..6522d40fa 100644 --- a/cyw43/src/runner.rs +++ b/cyw43/src/runner.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | use embassy_futures::select::{select3, Either3}; | 1 | use embassy_futures::select::{select4, Either4}; |
| 2 | use embassy_net_driver_channel as ch; | 2 | use embassy_net_driver_channel as ch; |
| 3 | use embassy_time::{block_for, Duration, Timer}; | 3 | use embassy_time::{block_for, Duration, Timer}; |
| 4 | use embedded_hal_1::digital::OutputPin; | 4 | use embedded_hal_1::digital::OutputPin; |
| @@ -11,7 +11,8 @@ use crate::fmt::Bytes; | |||
| 11 | use crate::ioctl::{IoctlState, IoctlType, PendingIoctl}; | 11 | use crate::ioctl::{IoctlState, IoctlType, PendingIoctl}; |
| 12 | use crate::nvram::NVRAM; | 12 | use crate::nvram::NVRAM; |
| 13 | use crate::structs::*; | 13 | use crate::structs::*; |
| 14 | use crate::{events, slice8_mut, Core, CHIP, MTU}; | 14 | use crate::util::slice8_mut; |
| 15 | use crate::{events, Core, CHIP, MTU}; | ||
| 15 | 16 | ||
| 16 | #[cfg(feature = "firmware-logs")] | 17 | #[cfg(feature = "firmware-logs")] |
| 17 | struct LogState { | 18 | struct LogState { |
| @@ -36,7 +37,7 @@ impl Default for LogState { | |||
| 36 | /// Driver communicating with the WiFi chip. | 37 | /// Driver communicating with the WiFi chip. |
| 37 | pub struct Runner<'a, PWR, SPI> { | 38 | pub struct Runner<'a, PWR, SPI> { |
| 38 | ch: ch::Runner<'a, MTU>, | 39 | ch: ch::Runner<'a, MTU>, |
| 39 | bus: Bus<PWR, SPI>, | 40 | pub(crate) bus: Bus<PWR, SPI>, |
| 40 | 41 | ||
| 41 | ioctl_state: &'a IoctlState, | 42 | ioctl_state: &'a IoctlState, |
| 42 | ioctl_id: u16, | 43 | ioctl_id: u16, |
| @@ -47,6 +48,9 @@ pub struct Runner<'a, PWR, SPI> { | |||
| 47 | 48 | ||
| 48 | #[cfg(feature = "firmware-logs")] | 49 | #[cfg(feature = "firmware-logs")] |
| 49 | log: LogState, | 50 | log: LogState, |
| 51 | |||
| 52 | #[cfg(feature = "bluetooth")] | ||
| 53 | pub(crate) bt: Option<crate::bluetooth::BtRunner<'a>>, | ||
| 50 | } | 54 | } |
| 51 | 55 | ||
| 52 | impl<'a, PWR, SPI> Runner<'a, PWR, SPI> | 56 | impl<'a, PWR, SPI> Runner<'a, PWR, SPI> |
| @@ -59,6 +63,7 @@ where | |||
| 59 | bus: Bus<PWR, SPI>, | 63 | bus: Bus<PWR, SPI>, |
| 60 | ioctl_state: &'a IoctlState, | 64 | ioctl_state: &'a IoctlState, |
| 61 | events: &'a Events, | 65 | events: &'a Events, |
| 66 | #[cfg(feature = "bluetooth")] bt: Option<crate::bluetooth::BtRunner<'a>>, | ||
| 62 | ) -> Self { | 67 | ) -> Self { |
| 63 | Self { | 68 | Self { |
| 64 | ch, | 69 | ch, |
| @@ -70,33 +75,52 @@ where | |||
| 70 | events, | 75 | events, |
| 71 | #[cfg(feature = "firmware-logs")] | 76 | #[cfg(feature = "firmware-logs")] |
| 72 | log: LogState::default(), | 77 | log: LogState::default(), |
| 78 | #[cfg(feature = "bluetooth")] | ||
| 79 | bt, | ||
| 73 | } | 80 | } |
| 74 | } | 81 | } |
| 75 | 82 | ||
| 76 | pub(crate) async fn init(&mut self, firmware: &[u8]) { | 83 | pub(crate) async fn init(&mut self, wifi_fw: &[u8], bt_fw: Option<&[u8]>) { |
| 77 | self.bus.init().await; | 84 | self.bus.init(bt_fw.is_some()).await; |
| 78 | 85 | ||
| 79 | // Init ALP (Active Low Power) clock | 86 | // Init ALP (Active Low Power) clock |
| 87 | debug!("init alp"); | ||
| 80 | self.bus | 88 | self.bus |
| 81 | .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ) | 89 | .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ) |
| 82 | .await; | 90 | .await; |
| 91 | |||
| 92 | debug!("set f2 watermark"); | ||
| 93 | self.bus | ||
| 94 | .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 0x10) | ||
| 95 | .await; | ||
| 96 | let watermark = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK).await; | ||
| 97 | debug!("watermark = {:02x}", watermark); | ||
| 98 | assert!(watermark == 0x10); | ||
| 99 | |||
| 83 | debug!("waiting for clock..."); | 100 | debug!("waiting for clock..."); |
| 84 | while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {} | 101 | while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {} |
| 85 | debug!("clock ok"); | 102 | debug!("clock ok"); |
| 86 | 103 | ||
| 104 | // clear request for ALP | ||
| 105 | debug!("clear request for ALP"); | ||
| 106 | self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0).await; | ||
| 107 | |||
| 87 | let chip_id = self.bus.bp_read16(0x1800_0000).await; | 108 | let chip_id = self.bus.bp_read16(0x1800_0000).await; |
| 88 | debug!("chip ID: {}", chip_id); | 109 | debug!("chip ID: {}", chip_id); |
| 89 | 110 | ||
| 90 | // Upload firmware. | 111 | // Upload firmware. |
| 91 | self.core_disable(Core::WLAN).await; | 112 | self.core_disable(Core::WLAN).await; |
| 113 | self.core_disable(Core::SOCSRAM).await; // TODO: is this needed if we reset right after? | ||
| 92 | self.core_reset(Core::SOCSRAM).await; | 114 | self.core_reset(Core::SOCSRAM).await; |
| 115 | |||
| 116 | // this is 4343x specific stuff: Disable remap for SRAM_3 | ||
| 93 | self.bus.bp_write32(CHIP.socsram_base_address + 0x10, 3).await; | 117 | self.bus.bp_write32(CHIP.socsram_base_address + 0x10, 3).await; |
| 94 | self.bus.bp_write32(CHIP.socsram_base_address + 0x44, 0).await; | 118 | self.bus.bp_write32(CHIP.socsram_base_address + 0x44, 0).await; |
| 95 | 119 | ||
| 96 | let ram_addr = CHIP.atcm_ram_base_address; | 120 | let ram_addr = CHIP.atcm_ram_base_address; |
| 97 | 121 | ||
| 98 | debug!("loading fw"); | 122 | debug!("loading fw"); |
| 99 | self.bus.bp_write(ram_addr, firmware).await; | 123 | self.bus.bp_write(ram_addr, wifi_fw).await; |
| 100 | 124 | ||
| 101 | debug!("loading nvram"); | 125 | debug!("loading nvram"); |
| 102 | // Round up to 4 bytes. | 126 | // Round up to 4 bytes. |
| @@ -116,10 +140,23 @@ where | |||
| 116 | self.core_reset(Core::WLAN).await; | 140 | self.core_reset(Core::WLAN).await; |
| 117 | assert!(self.core_is_up(Core::WLAN).await); | 141 | assert!(self.core_is_up(Core::WLAN).await); |
| 118 | 142 | ||
| 143 | // wait until HT clock is available; takes about 29ms | ||
| 144 | debug!("wait for HT clock"); | ||
| 119 | while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} | 145 | while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} |
| 120 | 146 | ||
| 121 | // "Set up the interrupt mask and enable interrupts" | 147 | // "Set up the interrupt mask and enable interrupts" |
| 122 | // self.bus.bp_write32(CHIP.sdiod_core_base_address + 0x24, 0xF0).await; | 148 | debug!("setup interrupt mask"); |
| 149 | self.bus | ||
| 150 | .bp_write32(CHIP.sdiod_core_base_address + SDIO_INT_HOST_MASK, I_HMB_SW_MASK) | ||
| 151 | .await; | ||
| 152 | |||
| 153 | // Set up the interrupt mask and enable interrupts | ||
| 154 | if bt_fw.is_some() { | ||
| 155 | debug!("bluetooth setup interrupt mask"); | ||
| 156 | self.bus | ||
| 157 | .bp_write32(CHIP.sdiod_core_base_address + SDIO_INT_HOST_MASK, I_HMB_FC_CHANGE) | ||
| 158 | .await; | ||
| 159 | } | ||
| 123 | 160 | ||
| 124 | self.bus | 161 | self.bus |
| 125 | .write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, IRQ_F2_PACKET_AVAILABLE) | 162 | .write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, IRQ_F2_PACKET_AVAILABLE) |
| @@ -128,11 +165,11 @@ where | |||
| 128 | // "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped." | 165 | // "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped." |
| 129 | // Sounds scary... | 166 | // Sounds scary... |
| 130 | self.bus | 167 | self.bus |
| 131 | .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 32) | 168 | .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, SPI_F2_WATERMARK) |
| 132 | .await; | 169 | .await; |
| 133 | 170 | ||
| 134 | // wait for wifi startup | 171 | // wait for F2 to be ready |
| 135 | debug!("waiting for wifi init..."); | 172 | debug!("waiting for F2 to be ready..."); |
| 136 | while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {} | 173 | while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {} |
| 137 | 174 | ||
| 138 | // Some random configs related to sleep. | 175 | // Some random configs related to sleep. |
| @@ -153,19 +190,27 @@ where | |||
| 153 | */ | 190 | */ |
| 154 | 191 | ||
| 155 | // clear pulls | 192 | // clear pulls |
| 193 | debug!("clear pad pulls"); | ||
| 156 | self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await; | 194 | self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await; |
| 157 | let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await; | 195 | let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await; |
| 158 | 196 | ||
| 159 | // start HT clock | 197 | // start HT clock |
| 160 | //self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10).await; | 198 | self.bus |
| 161 | //debug!("waiting for HT clock..."); | 199 | .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10) |
| 162 | //while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} | 200 | .await; // SBSDIO_HT_AVAIL_REQ |
| 163 | //debug!("clock ok"); | 201 | debug!("waiting for HT clock..."); |
| 202 | while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} | ||
| 203 | debug!("clock ok"); | ||
| 164 | 204 | ||
| 165 | #[cfg(feature = "firmware-logs")] | 205 | #[cfg(feature = "firmware-logs")] |
| 166 | self.log_init().await; | 206 | self.log_init().await; |
| 167 | 207 | ||
| 168 | debug!("wifi init done"); | 208 | #[cfg(feature = "bluetooth")] |
| 209 | if let Some(bt_fw) = bt_fw { | ||
| 210 | self.bt.as_mut().unwrap().init_bluetooth(&mut self.bus, bt_fw).await; | ||
| 211 | } | ||
| 212 | |||
| 213 | debug!("cyw43 runner init done"); | ||
| 169 | } | 214 | } |
| 170 | 215 | ||
| 171 | #[cfg(feature = "firmware-logs")] | 216 | #[cfg(feature = "firmware-logs")] |
| @@ -222,7 +267,7 @@ where | |||
| 222 | } | 267 | } |
| 223 | } | 268 | } |
| 224 | 269 | ||
| 225 | /// Run the | 270 | /// Run the CYW43 event handling loop. |
| 226 | pub async fn run(mut self) -> ! { | 271 | pub async fn run(mut self) -> ! { |
| 227 | let mut buf = [0; 512]; | 272 | let mut buf = [0; 512]; |
| 228 | loop { | 273 | loop { |
| @@ -231,11 +276,27 @@ where | |||
| 231 | 276 | ||
| 232 | if self.has_credit() { | 277 | if self.has_credit() { |
| 233 | let ioctl = self.ioctl_state.wait_pending(); | 278 | let ioctl = self.ioctl_state.wait_pending(); |
| 234 | let tx = self.ch.tx_buf(); | 279 | let wifi_tx = self.ch.tx_buf(); |
| 280 | #[cfg(feature = "bluetooth")] | ||
| 281 | let bt_tx = async { | ||
| 282 | match &mut self.bt { | ||
| 283 | Some(bt) => bt.tx_chan.receive().await, | ||
| 284 | None => core::future::pending().await, | ||
| 285 | } | ||
| 286 | }; | ||
| 287 | #[cfg(not(feature = "bluetooth"))] | ||
| 288 | let bt_tx = core::future::pending::<()>(); | ||
| 289 | |||
| 290 | // interrupts aren't working yet for bluetooth. Do busy-polling instead. | ||
| 291 | // Note for this to work `ev` has to go last in the `select()`. It prefers | ||
| 292 | // first futures if they're ready, so other select branches don't get starved.` | ||
| 293 | #[cfg(feature = "bluetooth")] | ||
| 294 | let ev = core::future::ready(()); | ||
| 295 | #[cfg(not(feature = "bluetooth"))] | ||
| 235 | let ev = self.bus.wait_for_event(); | 296 | let ev = self.bus.wait_for_event(); |
| 236 | 297 | ||
| 237 | match select3(ioctl, tx, ev).await { | 298 | match select4(ioctl, wifi_tx, bt_tx, ev).await { |
| 238 | Either3::First(PendingIoctl { | 299 | Either4::First(PendingIoctl { |
| 239 | buf: iobuf, | 300 | buf: iobuf, |
| 240 | kind, | 301 | kind, |
| 241 | cmd, | 302 | cmd, |
| @@ -244,7 +305,7 @@ where | |||
| 244 | self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }, &mut buf).await; | 305 | self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }, &mut buf).await; |
| 245 | self.check_status(&mut buf).await; | 306 | self.check_status(&mut buf).await; |
| 246 | } | 307 | } |
| 247 | Either3::Second(packet) => { | 308 | Either4::Second(packet) => { |
| 248 | trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); | 309 | trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); |
| 249 | 310 | ||
| 250 | let buf8 = slice8_mut(&mut buf); | 311 | let buf8 = slice8_mut(&mut buf); |
| @@ -298,7 +359,11 @@ where | |||
| 298 | self.ch.tx_done(); | 359 | self.ch.tx_done(); |
| 299 | self.check_status(&mut buf).await; | 360 | self.check_status(&mut buf).await; |
| 300 | } | 361 | } |
| 301 | Either3::Third(()) => { | 362 | Either4::Third(_) => { |
| 363 | #[cfg(feature = "bluetooth")] | ||
| 364 | self.bt.as_mut().unwrap().hci_write(&mut self.bus).await; | ||
| 365 | } | ||
| 366 | Either4::Fourth(()) => { | ||
| 302 | self.handle_irq(&mut buf).await; | 367 | self.handle_irq(&mut buf).await; |
| 303 | } | 368 | } |
| 304 | } | 369 | } |
| @@ -314,17 +379,24 @@ where | |||
| 314 | async fn handle_irq(&mut self, buf: &mut [u32; 512]) { | 379 | async fn handle_irq(&mut self, buf: &mut [u32; 512]) { |
| 315 | // Receive stuff | 380 | // Receive stuff |
| 316 | let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await; | 381 | let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await; |
| 317 | trace!("irq{}", FormatInterrupt(irq)); | 382 | if irq != 0 { |
| 383 | trace!("irq{}", FormatInterrupt(irq)); | ||
| 384 | } | ||
| 318 | 385 | ||
| 319 | if irq & IRQ_F2_PACKET_AVAILABLE != 0 { | 386 | if irq & IRQ_F2_PACKET_AVAILABLE != 0 { |
| 320 | self.check_status(buf).await; | 387 | self.check_status(buf).await; |
| 321 | } | 388 | } |
| 322 | 389 | ||
| 323 | if irq & IRQ_DATA_UNAVAILABLE != 0 { | 390 | if irq & IRQ_DATA_UNAVAILABLE != 0 { |
| 324 | // TODO what should we do here? | 391 | // this seems to be ignorable with no ill effects. |
| 325 | warn!("IRQ DATA_UNAVAILABLE, clearing..."); | 392 | trace!("IRQ DATA_UNAVAILABLE, clearing..."); |
| 326 | self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await; | 393 | self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await; |
| 327 | } | 394 | } |
| 395 | |||
| 396 | #[cfg(feature = "bluetooth")] | ||
| 397 | if let Some(bt) = &mut self.bt { | ||
| 398 | bt.handle_irq(&mut self.bus).await; | ||
| 399 | } | ||
| 328 | } | 400 | } |
| 329 | 401 | ||
| 330 | /// Handle F2 events while status register is set | 402 | /// Handle F2 events while status register is set |
