stm32/usb: add support for 32bit usbram.
This commit is contained in:
		| @@ -60,7 +60,7 @@ sdio-host = "0.5.0" | ||||
| embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true } | ||||
| critical-section = "1.1" | ||||
| atomic-polyfill = "1.0.1" | ||||
| stm32-metapac = "3" | ||||
| stm32-metapac = "4" | ||||
| vcell = "0.1.3" | ||||
| bxcan = "0.7.0" | ||||
| nb = "1.0.0" | ||||
| @@ -75,7 +75,7 @@ critical-section = { version = "1.1", features = ["std"] } | ||||
| [build-dependencies] | ||||
| proc-macro2 = "1.0.36" | ||||
| quote = "1.0.15" | ||||
| stm32-metapac = { version = "3", default-features = false, features = ["metadata"]} | ||||
| stm32-metapac = { version = "4", default-features = false, features = ["metadata"]} | ||||
|  | ||||
| [features] | ||||
| default = ["stm32-metapac/rt"] | ||||
|   | ||||
| @@ -12,22 +12,29 @@ use embassy_usb_driver as driver; | ||||
| use embassy_usb_driver::{ | ||||
|     Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, | ||||
| }; | ||||
| use pac::common::{Reg, RW}; | ||||
| use pac::usb::vals::{EpType, Stat}; | ||||
|  | ||||
| use super::{DmPin, DpPin, Instance}; | ||||
| use crate::gpio::sealed::AFType; | ||||
| use crate::interrupt::InterruptExt; | ||||
| use crate::pac::usb::regs; | ||||
| use crate::pac::usb::vals::{EpType, Stat}; | ||||
| use crate::pac::USBRAM; | ||||
| use crate::rcc::sealed::RccPeripheral; | ||||
| use crate::{pac, Peripheral}; | ||||
| use crate::Peripheral; | ||||
|  | ||||
| const EP_COUNT: usize = 8; | ||||
|  | ||||
| #[cfg(any(usb_v1_x1, usb_v1_x2))] | ||||
| const EP_MEMORY_SIZE: usize = 512; | ||||
| #[cfg(not(any(usb_v1_x1, usb_v1_x2)))] | ||||
| const EP_MEMORY_SIZE: usize = 1024; | ||||
| #[cfg(any(usbram_16x1_512, usbram_16x2_512))] | ||||
| const USBRAM_SIZE: usize = 512; | ||||
| #[cfg(usbram_16x2_1024)] | ||||
| const USBRAM_SIZE: usize = 1024; | ||||
| #[cfg(usbram_32_2048)] | ||||
| const USBRAM_SIZE: usize = 2048; | ||||
|  | ||||
| #[cfg(not(usbram_32_2048))] | ||||
| const USBRAM_ALIGN: usize = 2; | ||||
| #[cfg(usbram_32_2048)] | ||||
| const USBRAM_ALIGN: usize = 4; | ||||
|  | ||||
| const NEW_AW: AtomicWaker = AtomicWaker::new(); | ||||
| static BUS_WAKER: AtomicWaker = NEW_AW; | ||||
| @@ -57,25 +64,60 @@ fn invariant(mut r: regs::Epr) -> regs::Epr { | ||||
|     r | ||||
| } | ||||
|  | ||||
| fn align_len_up(len: u16) -> u16 { | ||||
|     ((len as usize + USBRAM_ALIGN - 1) / USBRAM_ALIGN * USBRAM_ALIGN) as u16 | ||||
| } | ||||
|  | ||||
| // Returns (actual_len, len_bits) | ||||
| fn calc_out_len(len: u16) -> (u16, u16) { | ||||
|     match len { | ||||
|         2..=62 => ((len + 1) / 2 * 2, ((len + 1) / 2) << 10), | ||||
|         63..=480 => ((len + 31) / 32 * 32, (((len + 31) / 32 - 1) << 10) | 0x8000), | ||||
|         // NOTE: this could be 2..=62 with 16bit USBRAM, but not with 32bit. Limit it to 60 for simplicity. | ||||
|         2..=60 => (align_len_up(len), align_len_up(len) / 2 << 10), | ||||
|         61..=1024 => ((len + 31) / 32 * 32, (((len + 31) / 32 - 1) << 10) | 0x8000), | ||||
|         _ => panic!("invalid OUT length {}", len), | ||||
|     } | ||||
| } | ||||
| fn ep_in_addr<T: Instance>(index: usize) -> Reg<u16, RW> { | ||||
|     T::regs().ep_mem(index * 4 + 0) | ||||
|  | ||||
| #[cfg(not(usbram_32_2048))] | ||||
| mod btable { | ||||
|     use super::*; | ||||
|  | ||||
|     pub(super) unsafe fn write_in<T: Instance>(index: usize, addr: u16) { | ||||
|         USBRAM.mem(index * 4 + 0).write_value(addr); | ||||
|     } | ||||
|  | ||||
|     pub(super) unsafe fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) { | ||||
|         USBRAM.mem(index * 4 + 1).write_value(len); | ||||
|     } | ||||
|  | ||||
|     pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { | ||||
|         USBRAM.mem(index * 4 + 2).write_value(addr); | ||||
|         USBRAM.mem(index * 4 + 3).write_value(max_len_bits); | ||||
|     } | ||||
|  | ||||
|     pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 { | ||||
|         USBRAM.mem(index * 4 + 3).read() | ||||
|     } | ||||
| } | ||||
| fn ep_in_len<T: Instance>(index: usize) -> Reg<u16, RW> { | ||||
|     T::regs().ep_mem(index * 4 + 1) | ||||
| } | ||||
| fn ep_out_addr<T: Instance>(index: usize) -> Reg<u16, RW> { | ||||
|     T::regs().ep_mem(index * 4 + 2) | ||||
| } | ||||
| fn ep_out_len<T: Instance>(index: usize) -> Reg<u16, RW> { | ||||
|     T::regs().ep_mem(index * 4 + 3) | ||||
| #[cfg(usbram_32_2048)] | ||||
| mod btable { | ||||
|     use super::*; | ||||
|  | ||||
|     pub(super) unsafe fn write_in<T: Instance>(_index: usize, _addr: u16) {} | ||||
|  | ||||
|     pub(super) unsafe fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) { | ||||
|         USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); | ||||
|     } | ||||
|  | ||||
|     pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { | ||||
|         USBRAM | ||||
|             .mem(index * 2 + 1) | ||||
|             .write_value((addr as u32) | ((max_len_bits as u32) << 16)); | ||||
|     } | ||||
|  | ||||
|     pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 { | ||||
|         (USBRAM.mem(index * 2 + 1).read() >> 16) as u16 | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct EndpointBuffer<T: Instance> { | ||||
| @@ -87,23 +129,25 @@ struct EndpointBuffer<T: Instance> { | ||||
| impl<T: Instance> EndpointBuffer<T> { | ||||
|     fn read(&mut self, buf: &mut [u8]) { | ||||
|         assert!(buf.len() <= self.len as usize); | ||||
|         for i in 0..((buf.len() + 1) / 2) { | ||||
|             let val = unsafe { T::regs().ep_mem(self.addr as usize / 2 + i).read() }; | ||||
|             buf[i * 2] = val as u8; | ||||
|             if i * 2 + 1 < buf.len() { | ||||
|                 buf[i * 2 + 1] = (val >> 8) as u8; | ||||
|             } | ||||
|         for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN { | ||||
|             let val = unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read() }; | ||||
|             let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); | ||||
|             buf[i * USBRAM_ALIGN..][..n].copy_from_slice(&val.to_le_bytes()[..n]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn write(&mut self, buf: &[u8]) { | ||||
|         assert!(buf.len() <= self.len as usize); | ||||
|         for i in 0..((buf.len() + 1) / 2) { | ||||
|             let mut val = buf[i * 2] as u16; | ||||
|             if i * 2 + 1 < buf.len() { | ||||
|                 val |= (buf[i * 2 + 1] as u16) << 8; | ||||
|             } | ||||
|             unsafe { T::regs().ep_mem(self.addr as usize / 2 + i).write_value(val) }; | ||||
|         for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN { | ||||
|             let mut val = [0u8; USBRAM_ALIGN]; | ||||
|             let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN); | ||||
|             val[..n].copy_from_slice(&buf[i * USBRAM_ALIGN..][..n]); | ||||
|  | ||||
|             #[cfg(not(usbram_32_2048))] | ||||
|             let val = u16::from_le_bytes(val); | ||||
|             #[cfg(usbram_32_2048)] | ||||
|             let val = u32::from_le_bytes(val); | ||||
|             unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val) }; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -139,8 +183,7 @@ impl<'d, T: Instance> Driver<'d, T> { | ||||
|         #[cfg(stm32l5)] | ||||
|         unsafe { | ||||
|             crate::peripherals::PWR::enable(); | ||||
|  | ||||
|             pac::PWR.cr2().modify(|w| w.set_usv(true)); | ||||
|             crate::pac::PWR.cr2().modify(|w| w.set_usv(true)); | ||||
|         } | ||||
|  | ||||
|         unsafe { | ||||
| @@ -256,8 +299,9 @@ impl<'d, T: Instance> Driver<'d, T> { | ||||
|     } | ||||
|  | ||||
|     fn alloc_ep_mem(&mut self, len: u16) -> u16 { | ||||
|         assert!(len as usize % USBRAM_ALIGN == 0); | ||||
|         let addr = self.ep_mem_free; | ||||
|         if addr + len > EP_MEMORY_SIZE as _ { | ||||
|         if addr + len > USBRAM_SIZE as _ { | ||||
|             panic!("Endpoint memory full"); | ||||
|         } | ||||
|         self.ep_mem_free += len; | ||||
| @@ -306,10 +350,7 @@ impl<'d, T: Instance> Driver<'d, T> { | ||||
|                 let addr = self.alloc_ep_mem(len); | ||||
|  | ||||
|                 trace!("  len_bits = {:04x}", len_bits); | ||||
|                 unsafe { | ||||
|                     ep_out_addr::<T>(index).write_value(addr); | ||||
|                     ep_out_len::<T>(index).write_value(len_bits); | ||||
|                 } | ||||
|                 unsafe { btable::write_out::<T>(index, addr, len_bits) } | ||||
|  | ||||
|                 EndpointBuffer { | ||||
|                     addr, | ||||
| @@ -321,13 +362,11 @@ impl<'d, T: Instance> Driver<'d, T> { | ||||
|                 assert!(!ep.used_in); | ||||
|                 ep.used_in = true; | ||||
|  | ||||
|                 let len = (max_packet_size + 1) / 2 * 2; | ||||
|                 let len = align_len_up(max_packet_size); | ||||
|                 let addr = self.alloc_ep_mem(len); | ||||
|  | ||||
|                 unsafe { | ||||
|                     ep_in_addr::<T>(index).write_value(addr); | ||||
|                     // ep_in_len is written when actually TXing packets. | ||||
|                 } | ||||
|                 // ep_in_len is written when actually TXing packets. | ||||
|                 unsafe { btable::write_in::<T>(index, addr) } | ||||
|  | ||||
|                 EndpointBuffer { | ||||
|                     addr, | ||||
| @@ -398,7 +437,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { | ||||
|                 w.set_ctrm(true); | ||||
|             }); | ||||
|  | ||||
|             #[cfg(usb_v3)] | ||||
|             #[cfg(any(usb_v3, usb_v4))] | ||||
|             regs.bcdr().write(|w| w.set_dppu(true)) | ||||
|         } | ||||
|  | ||||
| @@ -633,12 +672,12 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> { | ||||
|     fn write_data(&mut self, buf: &[u8]) { | ||||
|         let index = self.info.addr.index(); | ||||
|         self.buf.write(buf); | ||||
|         unsafe { ep_in_len::<T>(index).write_value(buf.len() as _) }; | ||||
|         unsafe { btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _) } | ||||
|     } | ||||
|  | ||||
|     fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { | ||||
|         let index = self.info.addr.index(); | ||||
|         let rx_len = unsafe { ep_out_len::<T>(index).read() as usize } & 0x3FF; | ||||
|         let rx_len = unsafe { btable::read_out_len::<T>(index) as usize } & 0x3FF; | ||||
|         trace!("READ DONE, rx_len = {}", rx_len); | ||||
|         if rx_len > buf.len() { | ||||
|             return Err(EndpointError::BufferOverflow); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user