diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-07-11 00:25:35 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-07-11 00:25:35 +0200 |
| commit | 069a57fcf85c725d000e03163716edb4ae3922ca (patch) | |
| tree | e0b672124cdfc0c8d4a58896d887496f5dec7d1d /src | |
| parent | e560415fde967483573d42f628e52501768584e0 (diff) | |
async ioctls working.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 192 | ||||
| -rw-r--r-- | src/structs.rs | 71 |
2 files changed, 175 insertions, 88 deletions
diff --git a/src/lib.rs b/src/lib.rs index 5caf19267..3609ecaeb 100644 --- a/src/lib.rs +++ b/src/lib.rs | |||
| @@ -1,16 +1,20 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait, concat_bytes)] | 3 | #![feature(type_alias_impl_trait, concat_bytes, const_slice_from_raw_parts)] |
| 4 | |||
| 5 | // This mod MUST go first, so that the others see its macros. | 4 | // This mod MUST go first, so that the others see its macros. |
| 6 | pub(crate) mod fmt; | 5 | pub(crate) mod fmt; |
| 7 | 6 | ||
| 7 | mod structs; | ||
| 8 | |||
| 9 | use core::cell::Cell; | ||
| 8 | use core::slice; | 10 | use core::slice; |
| 9 | 11 | ||
| 10 | use embassy::time::{block_for, Duration, Timer}; | 12 | use embassy::time::{block_for, Duration, Timer}; |
| 11 | use embassy::util::yield_now; | 13 | use embassy::util::yield_now; |
| 12 | use embassy_rp::gpio::{Flex, Output, Pin}; | 14 | use embassy_rp::gpio::{Flex, Output, Pin}; |
| 13 | 15 | ||
| 16 | use self::structs::*; | ||
| 17 | |||
| 14 | fn swap16(x: u32) -> u32 { | 18 | fn swap16(x: u32) -> u32 { |
| 15 | (x & 0xFF00FF00) >> 8 | (x & 0x00FF00FF) << 8 | 19 | (x & 0xFF00FF00) >> 8 | (x & 0x00FF00FF) << 8 |
| 16 | } | 20 | } |
| @@ -169,68 +173,73 @@ const CHIP: Chip = Chip { | |||
| 169 | }; | 173 | }; |
| 170 | 174 | ||
| 171 | #[derive(Clone, Copy)] | 175 | #[derive(Clone, Copy)] |
| 172 | #[repr(C)] | 176 | enum IoctlState { |
| 173 | struct SdpcmHeader { | 177 | Idle, |
| 174 | len: u16, | 178 | |
| 175 | len_inv: u16, | 179 | Pending { |
| 176 | /// Rx/Tx sequence number | 180 | kind: u32, |
| 177 | sequence: u8, | 181 | cmd: u32, |
| 178 | /// 4 MSB Channel number, 4 LSB arbitrary flag | 182 | iface: u32, |
| 179 | channel_and_flags: u8, | 183 | buf: *const [u8], |
| 180 | /// Length of next data frame, reserved for Tx | 184 | }, |
| 181 | next_length: u8, | 185 | Sent, |
| 182 | /// Data offset | 186 | Done, |
| 183 | header_length: u8, | ||
| 184 | /// Flow control bits, reserved for Tx | ||
| 185 | wireless_flow_control: u8, | ||
| 186 | /// Maximum Sequence number allowed by firmware for Tx | ||
| 187 | bus_data_credit: u8, | ||
| 188 | /// Reserved | ||
| 189 | reserved: [u8; 2], | ||
| 190 | } | 187 | } |
| 191 | 188 | ||
| 192 | #[derive(Clone, Copy)] | 189 | pub struct State { |
| 193 | #[repr(C)] | 190 | ioctl_id: Cell<u16>, |
| 194 | struct CdcHeader { | 191 | ioctl_state: Cell<IoctlState>, |
| 195 | cmd: u32, | ||
| 196 | out_len: u16, | ||
| 197 | in_len: u16, | ||
| 198 | flags: u16, | ||
| 199 | id: u16, | ||
| 200 | status: u32, | ||
| 201 | } | 192 | } |
| 202 | 193 | ||
| 203 | #[derive(Clone, Copy)] | 194 | impl State { |
| 204 | #[repr(C)] | 195 | pub fn new() -> Self { |
| 205 | struct BdcHeader { | 196 | Self { |
| 206 | flags: u8, | 197 | ioctl_id: Cell::new(0), |
| 207 | /// 802.1d Priority (low 3 bits) | 198 | ioctl_state: Cell::new(IoctlState::Idle), |
| 208 | priority: u8, | 199 | } |
| 209 | flags2: u8, | 200 | } |
| 210 | /// Offset from end of BDC header to packet data, in 4-uint8_t words. Leaves room for optional headers. | ||
| 211 | data_offset: u8, | ||
| 212 | } | 201 | } |
| 213 | 202 | ||
| 214 | macro_rules! impl_bytes { | 203 | pub struct Control<'a> { |
| 215 | ($t:ident) => { | 204 | state: &'a State, |
| 216 | impl $t { | 205 | } |
| 217 | const SIZE: usize = core::mem::size_of::<Self>(); | ||
| 218 | 206 | ||
| 219 | pub fn to_bytes(&self) -> [u8; Self::SIZE] { | 207 | impl<'a> Control<'a> { |
| 220 | unsafe { core::mem::transmute(*self) } | 208 | pub async fn init(&mut self) { |
| 221 | } | 209 | let clm = unsafe { slice::from_raw_parts(0x10140000 as *const u8, 4752) }; |
| 222 | 210 | ||
| 223 | pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> Self { | 211 | let mut buf = [0; 8 + 12 + 1024]; |
| 224 | unsafe { core::mem::transmute(*bytes) } | 212 | buf[0..8].copy_from_slice(b"clmload\x00"); |
| 225 | } | 213 | buf[8..20].copy_from_slice(b"\x02\x10\x02\x00\x00\x04\x00\x00\x00\x00\x00\x00"); |
| 214 | buf[20..].copy_from_slice(&clm[..1024]); | ||
| 215 | self.ioctl(2, 263, 0, &buf).await; | ||
| 216 | info!("IOCTL done"); | ||
| 217 | } | ||
| 218 | |||
| 219 | async fn ioctl(&mut self, kind: u32, cmd: u32, iface: u32, buf: &[u8]) { | ||
| 220 | // TODO cancel ioctl on future drop. | ||
| 221 | |||
| 222 | while !matches!(self.state.ioctl_state.get(), IoctlState::Idle) { | ||
| 223 | yield_now().await; | ||
| 226 | } | 224 | } |
| 227 | }; | 225 | |
| 226 | self.state.ioctl_id.set(self.state.ioctl_id.get().wrapping_add(1)); | ||
| 227 | |||
| 228 | self.state | ||
| 229 | .ioctl_state | ||
| 230 | .set(IoctlState::Pending { kind, cmd, iface, buf }); | ||
| 231 | |||
| 232 | while !matches!(self.state.ioctl_state.get(), IoctlState::Done) { | ||
| 233 | yield_now().await; | ||
| 234 | } | ||
| 235 | |||
| 236 | self.state.ioctl_state.set(IoctlState::Idle); | ||
| 237 | } | ||
| 228 | } | 238 | } |
| 229 | impl_bytes!(SdpcmHeader); | ||
| 230 | impl_bytes!(CdcHeader); | ||
| 231 | impl_bytes!(BdcHeader); | ||
| 232 | 239 | ||
| 233 | pub struct Driver<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> { | 240 | pub struct Runner<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> { |
| 241 | state: &'a State, | ||
| 242 | |||
| 234 | pwr: Output<'a, PWR>, | 243 | pwr: Output<'a, PWR>, |
| 235 | 244 | ||
| 236 | /// SPI chip-select. | 245 | /// SPI chip-select. |
| @@ -249,18 +258,29 @@ pub struct Driver<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> { | |||
| 249 | backplane_window: u32, | 258 | backplane_window: u32, |
| 250 | } | 259 | } |
| 251 | 260 | ||
| 252 | impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | 261 | pub async fn new<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin>( |
| 253 | pub fn new(pwr: Output<'a, PWR>, cs: Output<'a, CS>, clk: Output<'a, CLK>, dio: Flex<'a, DIO>) -> Self { | 262 | state: &'a State, |
| 254 | Self { | 263 | pwr: Output<'a, PWR>, |
| 255 | pwr, | 264 | cs: Output<'a, CS>, |
| 256 | cs, | 265 | clk: Output<'a, CLK>, |
| 257 | clk, | 266 | dio: Flex<'a, DIO>, |
| 258 | dio, | 267 | ) -> (Control<'a>, Runner<'a, PWR, CS, CLK, DIO>) { |
| 259 | backplane_window: 0xAAAA_AAAA, | 268 | let mut runner = Runner { |
| 260 | } | 269 | state, |
| 261 | } | 270 | pwr, |
| 271 | cs, | ||
| 272 | clk, | ||
| 273 | dio, | ||
| 274 | backplane_window: 0xAAAA_AAAA, | ||
| 275 | }; | ||
| 262 | 276 | ||
| 263 | pub async fn init(&mut self) { | 277 | runner.init().await; |
| 278 | |||
| 279 | (Control { state }, runner) | ||
| 280 | } | ||
| 281 | |||
| 282 | impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Runner<'a, PWR, CS, CLK, DIO> { | ||
| 283 | async fn init(&mut self) { | ||
| 264 | // Set strap to select gSPI mode. | 284 | // Set strap to select gSPI mode. |
| 265 | self.dio.set_as_output(); | 285 | self.dio.set_as_output(); |
| 266 | self.dio.set_low(); | 286 | self.dio.set_low(); |
| @@ -306,6 +326,8 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | |||
| 306 | self.bp_write32(CHIP.socsram_base_address + 0x10, 3); | 326 | self.bp_write32(CHIP.socsram_base_address + 0x10, 3); |
| 307 | self.bp_write32(CHIP.socsram_base_address + 0x44, 0); | 327 | self.bp_write32(CHIP.socsram_base_address + 0x44, 0); |
| 308 | 328 | ||
| 329 | let ram_addr = CHIP.atcm_ram_base_address; | ||
| 330 | |||
| 309 | // I'm flashing the firmwares independently at hardcoded addresses, instead of baking them | 331 | // I'm flashing the firmwares independently at hardcoded addresses, instead of baking them |
| 310 | // into the program with `include_bytes!` or similar, so that flashing the program stays fast. | 332 | // into the program with `include_bytes!` or similar, so that flashing the program stays fast. |
| 311 | // | 333 | // |
| @@ -314,9 +336,6 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | |||
| 314 | // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 | 336 | // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 |
| 315 | // probe-rs-cli download 43439A0.clm_blob --format bin --chip RP2040 --base-address 0x10140000 | 337 | // probe-rs-cli download 43439A0.clm_blob --format bin --chip RP2040 --base-address 0x10140000 |
| 316 | let fw = unsafe { slice::from_raw_parts(0x10100000 as *const u8, 224190) }; | 338 | let fw = unsafe { slice::from_raw_parts(0x10100000 as *const u8, 224190) }; |
| 317 | let clm = unsafe { slice::from_raw_parts(0x10140000 as *const u8, 4752) }; | ||
| 318 | |||
| 319 | let ram_addr = CHIP.atcm_ram_base_address; | ||
| 320 | 339 | ||
| 321 | info!("loading fw"); | 340 | info!("loading fw"); |
| 322 | self.bp_write(ram_addr, fw); | 341 | self.bp_write(ram_addr, fw); |
| @@ -374,17 +393,20 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | |||
| 374 | let _ = self.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP); | 393 | let _ = self.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP); |
| 375 | */ | 394 | */ |
| 376 | 395 | ||
| 377 | let mut buf = [0; 8 + 12 + 1024]; | ||
| 378 | buf[0..8].copy_from_slice(b"clmload\x00"); | ||
| 379 | buf[8..20].copy_from_slice(b"\x02\x10\x02\x00\x00\x04\x00\x00\x00\x00\x00\x00"); | ||
| 380 | buf[20..].copy_from_slice(&clm[..1024]); | ||
| 381 | self.send_ioctl(2, 263, 0, &buf); | ||
| 382 | |||
| 383 | info!("init done "); | 396 | info!("init done "); |
| 397 | } | ||
| 384 | 398 | ||
| 399 | pub async fn run(mut self) -> ! { | ||
| 385 | let mut old_irq = 0; | 400 | let mut old_irq = 0; |
| 386 | let mut buf = [0; 2048]; | 401 | let mut buf = [0; 2048]; |
| 387 | loop { | 402 | loop { |
| 403 | // Send stuff | ||
| 404 | if let IoctlState::Pending { kind, cmd, iface, buf } = self.state.ioctl_state.get() { | ||
| 405 | self.send_ioctl(kind, cmd, iface, unsafe { &*buf }, self.state.ioctl_id.get()); | ||
| 406 | self.state.ioctl_state.set(IoctlState::Sent); | ||
| 407 | } | ||
| 408 | |||
| 409 | // Receive stuff | ||
| 388 | let irq = self.read16(FUNC_BUS, REG_BUS_INTERRUPT); | 410 | let irq = self.read16(FUNC_BUS, REG_BUS_INTERRUPT); |
| 389 | if irq != old_irq { | 411 | if irq != old_irq { |
| 390 | info!("irq: {:04x}", irq); | 412 | info!("irq: {:04x}", irq); |
| @@ -419,6 +441,7 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | |||
| 419 | } | 441 | } |
| 420 | } | 442 | } |
| 421 | 443 | ||
| 444 | // TODO use IRQs | ||
| 422 | yield_now().await; | 445 | yield_now().await; |
| 423 | } | 446 | } |
| 424 | } | 447 | } |
| @@ -453,14 +476,16 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | |||
| 453 | let cdc_header = | 476 | let cdc_header = |
| 454 | CdcHeader::from_bytes(packet[SdpcmHeader::SIZE..][..CdcHeader::SIZE].try_into().unwrap()); | 477 | CdcHeader::from_bytes(packet[SdpcmHeader::SIZE..][..CdcHeader::SIZE].try_into().unwrap()); |
| 455 | 478 | ||
| 456 | // TODO check cdc_header.id matches | 479 | if cdc_header.id == self.state.ioctl_id.get() { |
| 457 | // TODO check status | 480 | assert_eq!(cdc_header.status, 0); // todo propagate error |
| 481 | self.state.ioctl_state.set(IoctlState::Done); | ||
| 482 | } | ||
| 458 | } | 483 | } |
| 459 | _ => {} | 484 | _ => {} |
| 460 | } | 485 | } |
| 461 | } | 486 | } |
| 462 | 487 | ||
| 463 | fn send_ioctl(&mut self, kind: u32, cmd: u32, iface: u32, data: &[u8]) { | 488 | fn send_ioctl(&mut self, kind: u32, cmd: u32, iface: u32, data: &[u8], id: u16) { |
| 464 | let mut buf = [0; 2048]; | 489 | let mut buf = [0; 2048]; |
| 465 | 490 | ||
| 466 | let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len(); | 491 | let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len(); |
| @@ -469,7 +494,7 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | |||
| 469 | len: total_len as u16, | 494 | len: total_len as u16, |
| 470 | len_inv: !total_len as u16, | 495 | len_inv: !total_len as u16, |
| 471 | sequence: 0x02, // todo | 496 | sequence: 0x02, // todo |
| 472 | channel_and_flags: 0, // control channle | 497 | channel_and_flags: 0, // control channel |
| 473 | next_length: 0, | 498 | next_length: 0, |
| 474 | header_length: SdpcmHeader::SIZE as _, | 499 | header_length: SdpcmHeader::SIZE as _, |
| 475 | wireless_flow_control: 0, | 500 | wireless_flow_control: 0, |
| @@ -482,7 +507,7 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | |||
| 482 | out_len: data.len() as _, | 507 | out_len: data.len() as _, |
| 483 | in_len: 0, | 508 | in_len: 0, |
| 484 | flags: kind as u16 | (iface as u16) << 12, | 509 | flags: kind as u16 | (iface as u16) << 12, |
| 485 | id: 1, // todo | 510 | id, |
| 486 | status: 0, | 511 | status: 0, |
| 487 | }; | 512 | }; |
| 488 | 513 | ||
| @@ -780,16 +805,13 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | |||
| 780 | w |= 0x01; | 805 | w |= 0x01; |
| 781 | } | 806 | } |
| 782 | self.clk.set_high(); | 807 | self.clk.set_high(); |
| 783 | delay(); | ||
| 784 | 808 | ||
| 785 | // falling edge | 809 | // falling edge |
| 786 | self.clk.set_low(); | 810 | self.clk.set_low(); |
| 787 | delay(); | ||
| 788 | } | 811 | } |
| 789 | *word = w | 812 | *word = w |
| 790 | } | 813 | } |
| 791 | self.clk.set_low(); | 814 | self.clk.set_low(); |
| 792 | delay(); | ||
| 793 | } | 815 | } |
| 794 | 816 | ||
| 795 | fn spi_write(&mut self, words: &[u8]) { | 817 | fn spi_write(&mut self, words: &[u8]) { |
| @@ -804,25 +826,19 @@ impl<'a, PWR: Pin, CS: Pin, CLK: Pin, DIO: Pin> Driver<'a, PWR, CS, CLK, DIO> { | |||
| 804 | } else { | 826 | } else { |
| 805 | self.dio.set_high(); | 827 | self.dio.set_high(); |
| 806 | } | 828 | } |
| 807 | delay(); | ||
| 808 | 829 | ||
| 809 | // rising edge | 830 | // rising edge |
| 810 | self.clk.set_high(); | 831 | self.clk.set_high(); |
| 811 | delay(); | ||
| 812 | 832 | ||
| 813 | word = word << 1; | 833 | word = word << 1; |
| 814 | } | 834 | } |
| 815 | } | 835 | } |
| 816 | self.clk.set_low(); | 836 | self.clk.set_low(); |
| 817 | delay(); | 837 | |
| 818 | self.dio.set_as_input(); | 838 | self.dio.set_as_input(); |
| 819 | } | 839 | } |
| 820 | } | 840 | } |
| 821 | 841 | ||
| 822 | fn delay() { | ||
| 823 | //cortex_m::asm::delay(5); | ||
| 824 | } | ||
| 825 | |||
| 826 | macro_rules! nvram { | 842 | macro_rules! nvram { |
| 827 | ($($s:literal,)*) => { | 843 | ($($s:literal,)*) => { |
| 828 | concat_bytes!($($s, b"\x00",)* b"\x00\x00") | 844 | concat_bytes!($($s, b"\x00",)* b"\x00\x00") |
diff --git a/src/structs.rs b/src/structs.rs new file mode 100644 index 000000000..fe5e89a37 --- /dev/null +++ b/src/structs.rs | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | #[derive(Clone, Copy)] | ||
| 2 | #[repr(C)] | ||
| 3 | pub struct SdpcmHeader { | ||
| 4 | pub len: u16, | ||
| 5 | pub len_inv: u16, | ||
| 6 | /// Rx/Tx sequence number | ||
| 7 | pub sequence: u8, | ||
| 8 | /// 4 MSB Channel number, 4 LSB arbitrary flag | ||
| 9 | pub channel_and_flags: u8, | ||
| 10 | /// Length of next data frame, reserved for Tx | ||
| 11 | pub next_length: u8, | ||
| 12 | /// Data offset | ||
| 13 | pub header_length: u8, | ||
| 14 | /// Flow control bits, reserved for Tx | ||
| 15 | pub wireless_flow_control: u8, | ||
| 16 | /// Maximum Sequence number allowed by firmware for Tx | ||
| 17 | pub bus_data_credit: u8, | ||
| 18 | /// Reserved | ||
| 19 | pub reserved: [u8; 2], | ||
| 20 | } | ||
| 21 | |||
| 22 | #[derive(Clone, Copy)] | ||
| 23 | #[repr(C)] | ||
| 24 | pub struct CdcHeader { | ||
| 25 | pub cmd: u32, | ||
| 26 | pub out_len: u16, | ||
| 27 | pub in_len: u16, | ||
| 28 | pub flags: u16, | ||
| 29 | pub id: u16, | ||
| 30 | pub status: u32, | ||
| 31 | } | ||
| 32 | |||
| 33 | #[derive(Clone, Copy)] | ||
| 34 | #[repr(C)] | ||
| 35 | pub struct BdcHeader { | ||
| 36 | pub flags: u8, | ||
| 37 | /// 802.1d Priority (low 3 bits) | ||
| 38 | pub priority: u8, | ||
| 39 | pub flags2: u8, | ||
| 40 | /// Offset from end of BDC header to packet data, in 4-uint8_t words. Leaves room for optional headers. | ||
| 41 | pub data_offset: u8, | ||
| 42 | } | ||
| 43 | |||
| 44 | #[derive(Clone, Copy)] | ||
| 45 | #[repr(C)] | ||
| 46 | pub struct DownloadHeader { | ||
| 47 | pub flag: u16, | ||
| 48 | pub dload_type: u16, | ||
| 49 | pub len: u32, | ||
| 50 | pub crc: u32, | ||
| 51 | } | ||
| 52 | |||
| 53 | macro_rules! impl_bytes { | ||
| 54 | ($t:ident) => { | ||
| 55 | impl $t { | ||
| 56 | pub const SIZE: usize = core::mem::size_of::<Self>(); | ||
| 57 | |||
| 58 | pub fn to_bytes(&self) -> [u8; Self::SIZE] { | ||
| 59 | unsafe { core::mem::transmute(*self) } | ||
| 60 | } | ||
| 61 | |||
| 62 | pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> Self { | ||
| 63 | unsafe { core::mem::transmute(*bytes) } | ||
| 64 | } | ||
| 65 | } | ||
| 66 | }; | ||
| 67 | } | ||
| 68 | impl_bytes!(SdpcmHeader); | ||
| 69 | impl_bytes!(CdcHeader); | ||
| 70 | impl_bytes!(BdcHeader); | ||
| 71 | impl_bytes!(DownloadHeader); | ||
