macros.rs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. // SPDX-License-Identifier: GPL-2.0
  2. //! `register!` macro to define register layout and accessors.
  3. //!
  4. //! A single register typically includes several fields, which are accessed through a combination
  5. //! of bit-shift and mask operations that introduce a class of potential mistakes, notably because
  6. //! not all possible field values are necessarily valid.
  7. //!
  8. //! The `register!` macro in this module provides an intuitive and readable syntax for defining a
  9. //! dedicated type for each register. Each such type comes with its own field accessors that can
  10. //! return an error if a field's value is invalid. Please look at the [`bitfield`] macro for the
  11. //! complete syntax of fields definitions.
  12. /// Trait providing a base address to be added to the offset of a relative register to obtain
  13. /// its actual offset.
  14. ///
  15. /// The `T` generic argument is used to distinguish which base to use, in case a type provides
  16. /// several bases. It is given to the `register!` macro to restrict the use of the register to
  17. /// implementors of this particular variant.
  18. pub(crate) trait RegisterBase<T> {
  19. const BASE: usize;
  20. }
  21. /// Defines a dedicated type for a register with an absolute offset, including getter and setter
  22. /// methods for its fields and methods to read and write it from an `Io` region.
  23. ///
  24. /// Example:
  25. ///
  26. /// ```no_run
  27. /// register!(BOOT_0 @ 0x00000100, "Basic revision information about the GPU" {
  28. /// 3:0 minor_revision as u8, "Minor revision of the chip";
  29. /// 7:4 major_revision as u8, "Major revision of the chip";
  30. /// 28:20 chipset as u32 ?=> Chipset, "Chipset model";
  31. /// });
  32. /// ```
  33. ///
  34. /// This defines a `BOOT_0` type which can be read or written from offset `0x100` of an `Io`
  35. /// region. It is composed of 3 fields, for instance `minor_revision` is made of the 4 least
  36. /// significant bits of the register. Each field can be accessed and modified using accessor
  37. /// methods:
  38. ///
  39. /// ```no_run
  40. /// // Read from the register's defined offset (0x100).
  41. /// let boot0 = BOOT_0::read(&bar);
  42. /// pr_info!("chip revision: {}.{}", boot0.major_revision(), boot0.minor_revision());
  43. ///
  44. /// // `Chipset::try_from` is called with the value of the `chipset` field and returns an
  45. /// // error if it is invalid.
  46. /// let chipset = boot0.chipset()?;
  47. ///
  48. /// // Update some fields and write the value back.
  49. /// boot0.set_major_revision(3).set_minor_revision(10).write(&bar);
  50. ///
  51. /// // Or, just read and update the register in a single step:
  52. /// BOOT_0::update(&bar, |r| r.set_major_revision(3).set_minor_revision(10));
  53. /// ```
  54. ///
  55. /// The documentation strings are optional. If present, they will be added to the type's
  56. /// definition, or the field getter and setter methods they are attached to.
  57. ///
  58. /// It is also possible to create a alias register by using the `=> ALIAS` syntax. This is useful
  59. /// for cases where a register's interpretation depends on the context:
  60. ///
  61. /// ```no_run
  62. /// register!(SCRATCH @ 0x00000200, "Scratch register" {
  63. /// 31:0 value as u32, "Raw value";
  64. /// });
  65. ///
  66. /// register!(SCRATCH_BOOT_STATUS => SCRATCH, "Boot status of the firmware" {
  67. /// 0:0 completed as bool, "Whether the firmware has completed booting";
  68. /// });
  69. /// ```
  70. ///
  71. /// In this example, `SCRATCH_0_BOOT_STATUS` uses the same I/O address as `SCRATCH`, while also
  72. /// providing its own `completed` field.
  73. ///
  74. /// ## Relative registers
  75. ///
  76. /// A register can be defined as being accessible from a fixed offset of a provided base. For
  77. /// instance, imagine the following I/O space:
  78. ///
  79. /// ```text
  80. /// +-----------------------------+
  81. /// | ... |
  82. /// | |
  83. /// 0x100--->+------------CPU0-------------+
  84. /// | |
  85. /// 0x110--->+-----------------------------+
  86. /// | CPU_CTL |
  87. /// +-----------------------------+
  88. /// | ... |
  89. /// | |
  90. /// | |
  91. /// 0x200--->+------------CPU1-------------+
  92. /// | |
  93. /// 0x210--->+-----------------------------+
  94. /// | CPU_CTL |
  95. /// +-----------------------------+
  96. /// | ... |
  97. /// +-----------------------------+
  98. /// ```
  99. ///
  100. /// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset `0x10` of their I/O
  101. /// space segment. Since both instances of `CPU_CTL` share the same layout, we don't want to define
  102. /// them twice and would prefer a way to select which one to use from a single definition
  103. ///
  104. /// This can be done using the `Base[Offset]` syntax when specifying the register's address.
  105. ///
  106. /// `Base` is an arbitrary type (typically a ZST) to be used as a generic parameter of the
  107. /// [`RegisterBase`] trait to provide the base as a constant, i.e. each type providing a base for
  108. /// this register needs to implement `RegisterBase<Base>`. Here is the above example translated
  109. /// into code:
  110. ///
  111. /// ```no_run
  112. /// // Type used to identify the base.
  113. /// pub(crate) struct CpuCtlBase;
  114. ///
  115. /// // ZST describing `CPU0`.
  116. /// struct Cpu0;
  117. /// impl RegisterBase<CpuCtlBase> for Cpu0 {
  118. /// const BASE: usize = 0x100;
  119. /// }
  120. /// // Singleton of `CPU0` used to identify it.
  121. /// const CPU0: Cpu0 = Cpu0;
  122. ///
  123. /// // ZST describing `CPU1`.
  124. /// struct Cpu1;
  125. /// impl RegisterBase<CpuCtlBase> for Cpu1 {
  126. /// const BASE: usize = 0x200;
  127. /// }
  128. /// // Singleton of `CPU1` used to identify it.
  129. /// const CPU1: Cpu1 = Cpu1;
  130. ///
  131. /// // This makes `CPU_CTL` accessible from all implementors of `RegisterBase<CpuCtlBase>`.
  132. /// register!(CPU_CTL @ CpuCtlBase[0x10], "CPU core control" {
  133. /// 0:0 start as bool, "Start the CPU core";
  134. /// });
  135. ///
  136. /// // The `read`, `write` and `update` methods of relative registers take an extra `base` argument
  137. /// // that is used to resolve its final address by adding its `BASE` to the offset of the
  138. /// // register.
  139. ///
  140. /// // Start `CPU0`.
  141. /// CPU_CTL::update(bar, &CPU0, |r| r.set_start(true));
  142. ///
  143. /// // Start `CPU1`.
  144. /// CPU_CTL::update(bar, &CPU1, |r| r.set_start(true));
  145. ///
  146. /// // Aliases can also be defined for relative register.
  147. /// register!(CPU_CTL_ALIAS => CpuCtlBase[CPU_CTL], "Alias to CPU core control" {
  148. /// 1:1 alias_start as bool, "Start the aliased CPU core";
  149. /// });
  150. ///
  151. /// // Start the aliased `CPU0`.
  152. /// CPU_CTL_ALIAS::update(bar, &CPU0, |r| r.set_alias_start(true));
  153. /// ```
  154. ///
  155. /// ## Arrays of registers
  156. ///
  157. /// Some I/O areas contain consecutive values that can be interpreted in the same way. These areas
  158. /// can be defined as an array of identical registers, allowing them to be accessed by index with
  159. /// compile-time or runtime bound checking. Simply define their address as `Address[Size]`, and add
  160. /// an `idx` parameter to their `read`, `write` and `update` methods:
  161. ///
  162. /// ```no_run
  163. /// # fn no_run() -> Result<(), Error> {
  164. /// # fn get_scratch_idx() -> usize {
  165. /// # 0x15
  166. /// # }
  167. /// // Array of 64 consecutive registers with the same layout starting at offset `0x80`.
  168. /// register!(SCRATCH @ 0x00000080[64], "Scratch registers" {
  169. /// 31:0 value as u32;
  170. /// });
  171. ///
  172. /// // Read scratch register 0, i.e. I/O address `0x80`.
  173. /// let scratch_0 = SCRATCH::read(bar, 0).value();
  174. /// // Read scratch register 15, i.e. I/O address `0x80 + (15 * 4)`.
  175. /// let scratch_15 = SCRATCH::read(bar, 15).value();
  176. ///
  177. /// // This is out of bounds and won't build.
  178. /// // let scratch_128 = SCRATCH::read(bar, 128).value();
  179. ///
  180. /// // Runtime-obtained array index.
  181. /// let scratch_idx = get_scratch_idx();
  182. /// // Access on a runtime index returns an error if it is out-of-bounds.
  183. /// let some_scratch = SCRATCH::try_read(bar, scratch_idx)?.value();
  184. ///
  185. /// // Alias to a particular register in an array.
  186. /// // Here `SCRATCH[8]` is used to convey the firmware exit code.
  187. /// register!(FIRMWARE_STATUS => SCRATCH[8], "Firmware exit status code" {
  188. /// 7:0 status as u8;
  189. /// });
  190. ///
  191. /// let status = FIRMWARE_STATUS::read(bar).status();
  192. ///
  193. /// // Non-contiguous register arrays can be defined by adding a stride parameter.
  194. /// // Here, each of the 16 registers of the array are separated by 8 bytes, meaning that the
  195. /// // registers of the two declarations below are interleaved.
  196. /// register!(SCRATCH_INTERLEAVED_0 @ 0x000000c0[16 ; 8], "Scratch registers bank 0" {
  197. /// 31:0 value as u32;
  198. /// });
  199. /// register!(SCRATCH_INTERLEAVED_1 @ 0x000000c4[16 ; 8], "Scratch registers bank 1" {
  200. /// 31:0 value as u32;
  201. /// });
  202. /// # Ok(())
  203. /// # }
  204. /// ```
  205. ///
  206. /// ## Relative arrays of registers
  207. ///
  208. /// Combining the two features described in the sections above, arrays of registers accessible from
  209. /// a base can also be defined:
  210. ///
  211. /// ```no_run
  212. /// # fn no_run() -> Result<(), Error> {
  213. /// # fn get_scratch_idx() -> usize {
  214. /// # 0x15
  215. /// # }
  216. /// // Type used as parameter of `RegisterBase` to specify the base.
  217. /// pub(crate) struct CpuCtlBase;
  218. ///
  219. /// // ZST describing `CPU0`.
  220. /// struct Cpu0;
  221. /// impl RegisterBase<CpuCtlBase> for Cpu0 {
  222. /// const BASE: usize = 0x100;
  223. /// }
  224. /// // Singleton of `CPU0` used to identify it.
  225. /// const CPU0: Cpu0 = Cpu0;
  226. ///
  227. /// // ZST describing `CPU1`.
  228. /// struct Cpu1;
  229. /// impl RegisterBase<CpuCtlBase> for Cpu1 {
  230. /// const BASE: usize = 0x200;
  231. /// }
  232. /// // Singleton of `CPU1` used to identify it.
  233. /// const CPU1: Cpu1 = Cpu1;
  234. ///
  235. /// // 64 per-cpu scratch registers, arranged as an contiguous array.
  236. /// register!(CPU_SCRATCH @ CpuCtlBase[0x00000080[64]], "Per-CPU scratch registers" {
  237. /// 31:0 value as u32;
  238. /// });
  239. ///
  240. /// let cpu0_scratch_0 = CPU_SCRATCH::read(bar, &Cpu0, 0).value();
  241. /// let cpu1_scratch_15 = CPU_SCRATCH::read(bar, &Cpu1, 15).value();
  242. ///
  243. /// // This won't build.
  244. /// // let cpu0_scratch_128 = CPU_SCRATCH::read(bar, &Cpu0, 128).value();
  245. ///
  246. /// // Runtime-obtained array index.
  247. /// let scratch_idx = get_scratch_idx();
  248. /// // Access on a runtime value returns an error if it is out-of-bounds.
  249. /// let cpu0_some_scratch = CPU_SCRATCH::try_read(bar, &Cpu0, scratch_idx)?.value();
  250. ///
  251. /// // `SCRATCH[8]` is used to convey the firmware exit code.
  252. /// register!(CPU_FIRMWARE_STATUS => CpuCtlBase[CPU_SCRATCH[8]],
  253. /// "Per-CPU firmware exit status code" {
  254. /// 7:0 status as u8;
  255. /// });
  256. ///
  257. /// let cpu0_status = CPU_FIRMWARE_STATUS::read(bar, &Cpu0).status();
  258. ///
  259. /// // Non-contiguous register arrays can be defined by adding a stride parameter.
  260. /// // Here, each of the 16 registers of the array are separated by 8 bytes, meaning that the
  261. /// // registers of the two declarations below are interleaved.
  262. /// register!(CPU_SCRATCH_INTERLEAVED_0 @ CpuCtlBase[0x00000d00[16 ; 8]],
  263. /// "Scratch registers bank 0" {
  264. /// 31:0 value as u32;
  265. /// });
  266. /// register!(CPU_SCRATCH_INTERLEAVED_1 @ CpuCtlBase[0x00000d04[16 ; 8]],
  267. /// "Scratch registers bank 1" {
  268. /// 31:0 value as u32;
  269. /// });
  270. /// # Ok(())
  271. /// # }
  272. /// ```
  273. macro_rules! register {
  274. // Creates a register at a fixed offset of the MMIO space.
  275. ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => {
  276. bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } );
  277. register!(@io_fixed $name @ $offset);
  278. };
  279. // Creates an alias register of fixed offset register `alias` with its own fields.
  280. ($name:ident => $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => {
  281. bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } );
  282. register!(@io_fixed $name @ $alias::OFFSET);
  283. };
  284. // Creates a register at a relative offset from a base address provider.
  285. ($name:ident @ $base:ty [ $offset:literal ] $(, $comment:literal)? { $($fields:tt)* } ) => {
  286. bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } );
  287. register!(@io_relative $name @ $base [ $offset ]);
  288. };
  289. // Creates an alias register of relative offset register `alias` with its own fields.
  290. ($name:ident => $base:ty [ $alias:ident ] $(, $comment:literal)? { $($fields:tt)* }) => {
  291. bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } );
  292. register!(@io_relative $name @ $base [ $alias::OFFSET ]);
  293. };
  294. // Creates an array of registers at a fixed offset of the MMIO space.
  295. (
  296. $name:ident @ $offset:literal [ $size:expr ; $stride:expr ] $(, $comment:literal)? {
  297. $($fields:tt)*
  298. }
  299. ) => {
  300. static_assert!(::core::mem::size_of::<u32>() <= $stride);
  301. bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } );
  302. register!(@io_array $name @ $offset [ $size ; $stride ]);
  303. };
  304. // Shortcut for contiguous array of registers (stride == size of element).
  305. (
  306. $name:ident @ $offset:literal [ $size:expr ] $(, $comment:literal)? {
  307. $($fields:tt)*
  308. }
  309. ) => {
  310. register!($name @ $offset [ $size ; ::core::mem::size_of::<u32>() ] $(, $comment)? {
  311. $($fields)*
  312. } );
  313. };
  314. // Creates an array of registers at a relative offset from a base address provider.
  315. (
  316. $name:ident @ $base:ty [ $offset:literal [ $size:expr ; $stride:expr ] ]
  317. $(, $comment:literal)? { $($fields:tt)* }
  318. ) => {
  319. static_assert!(::core::mem::size_of::<u32>() <= $stride);
  320. bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } );
  321. register!(@io_relative_array $name @ $base [ $offset [ $size ; $stride ] ]);
  322. };
  323. // Shortcut for contiguous array of relative registers (stride == size of element).
  324. (
  325. $name:ident @ $base:ty [ $offset:literal [ $size:expr ] ] $(, $comment:literal)? {
  326. $($fields:tt)*
  327. }
  328. ) => {
  329. register!($name @ $base [ $offset [ $size ; ::core::mem::size_of::<u32>() ] ]
  330. $(, $comment)? { $($fields)* } );
  331. };
  332. // Creates an alias of register `idx` of relative array of registers `alias` with its own
  333. // fields.
  334. (
  335. $name:ident => $base:ty [ $alias:ident [ $idx:expr ] ] $(, $comment:literal)? {
  336. $($fields:tt)*
  337. }
  338. ) => {
  339. static_assert!($idx < $alias::SIZE);
  340. bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } );
  341. register!(@io_relative $name @ $base [ $alias::OFFSET + $idx * $alias::STRIDE ] );
  342. };
  343. // Creates an alias of register `idx` of array of registers `alias` with its own fields.
  344. // This rule belongs to the (non-relative) register arrays set, but needs to be put last
  345. // to avoid it being interpreted in place of the relative register array alias rule.
  346. ($name:ident => $alias:ident [ $idx:expr ] $(, $comment:literal)? { $($fields:tt)* }) => {
  347. static_assert!($idx < $alias::SIZE);
  348. bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } );
  349. register!(@io_fixed $name @ $alias::OFFSET + $idx * $alias::STRIDE );
  350. };
  351. // Generates the IO accessors for a fixed offset register.
  352. (@io_fixed $name:ident @ $offset:expr) => {
  353. #[allow(dead_code)]
  354. impl $name {
  355. pub(crate) const OFFSET: usize = $offset;
  356. /// Read the register from its address in `io`.
  357. #[inline(always)]
  358. pub(crate) fn read<T, I>(io: &T) -> Self where
  359. T: ::core::ops::Deref<Target = I>,
  360. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  361. {
  362. Self(io.read32($offset))
  363. }
  364. /// Write the value contained in `self` to the register address in `io`.
  365. #[inline(always)]
  366. pub(crate) fn write<T, I>(self, io: &T) where
  367. T: ::core::ops::Deref<Target = I>,
  368. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  369. {
  370. io.write32(self.0, $offset)
  371. }
  372. /// Read the register from its address in `io` and run `f` on its value to obtain a new
  373. /// value to write back.
  374. #[inline(always)]
  375. pub(crate) fn update<T, I, F>(
  376. io: &T,
  377. f: F,
  378. ) where
  379. T: ::core::ops::Deref<Target = I>,
  380. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  381. F: ::core::ops::FnOnce(Self) -> Self,
  382. {
  383. let reg = f(Self::read(io));
  384. reg.write(io);
  385. }
  386. }
  387. };
  388. // Generates the IO accessors for a relative offset register.
  389. (@io_relative $name:ident @ $base:ty [ $offset:expr ]) => {
  390. #[allow(dead_code)]
  391. impl $name {
  392. pub(crate) const OFFSET: usize = $offset;
  393. /// Read the register from `io`, using the base address provided by `base` and adding
  394. /// the register's offset to it.
  395. #[inline(always)]
  396. pub(crate) fn read<T, I, B>(
  397. io: &T,
  398. #[allow(unused_variables)]
  399. base: &B,
  400. ) -> Self where
  401. T: ::core::ops::Deref<Target = I>,
  402. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  403. B: crate::regs::macros::RegisterBase<$base>,
  404. {
  405. const OFFSET: usize = $name::OFFSET;
  406. let value = io.read32(
  407. <B as crate::regs::macros::RegisterBase<$base>>::BASE + OFFSET
  408. );
  409. Self(value)
  410. }
  411. /// Write the value contained in `self` to `io`, using the base address provided by
  412. /// `base` and adding the register's offset to it.
  413. #[inline(always)]
  414. pub(crate) fn write<T, I, B>(
  415. self,
  416. io: &T,
  417. #[allow(unused_variables)]
  418. base: &B,
  419. ) where
  420. T: ::core::ops::Deref<Target = I>,
  421. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  422. B: crate::regs::macros::RegisterBase<$base>,
  423. {
  424. const OFFSET: usize = $name::OFFSET;
  425. io.write32(
  426. self.0,
  427. <B as crate::regs::macros::RegisterBase<$base>>::BASE + OFFSET
  428. );
  429. }
  430. /// Read the register from `io`, using the base address provided by `base` and adding
  431. /// the register's offset to it, then run `f` on its value to obtain a new value to
  432. /// write back.
  433. #[inline(always)]
  434. pub(crate) fn update<T, I, B, F>(
  435. io: &T,
  436. base: &B,
  437. f: F,
  438. ) where
  439. T: ::core::ops::Deref<Target = I>,
  440. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  441. B: crate::regs::macros::RegisterBase<$base>,
  442. F: ::core::ops::FnOnce(Self) -> Self,
  443. {
  444. let reg = f(Self::read(io, base));
  445. reg.write(io, base);
  446. }
  447. }
  448. };
  449. // Generates the IO accessors for an array of registers.
  450. (@io_array $name:ident @ $offset:literal [ $size:expr ; $stride:expr ]) => {
  451. #[allow(dead_code)]
  452. impl $name {
  453. pub(crate) const OFFSET: usize = $offset;
  454. pub(crate) const SIZE: usize = $size;
  455. pub(crate) const STRIDE: usize = $stride;
  456. /// Read the array register at index `idx` from its address in `io`.
  457. #[inline(always)]
  458. pub(crate) fn read<T, I>(
  459. io: &T,
  460. idx: usize,
  461. ) -> Self where
  462. T: ::core::ops::Deref<Target = I>,
  463. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  464. {
  465. build_assert!(idx < Self::SIZE);
  466. let offset = Self::OFFSET + (idx * Self::STRIDE);
  467. let value = io.read32(offset);
  468. Self(value)
  469. }
  470. /// Write the value contained in `self` to the array register with index `idx` in `io`.
  471. #[inline(always)]
  472. pub(crate) fn write<T, I>(
  473. self,
  474. io: &T,
  475. idx: usize
  476. ) where
  477. T: ::core::ops::Deref<Target = I>,
  478. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  479. {
  480. build_assert!(idx < Self::SIZE);
  481. let offset = Self::OFFSET + (idx * Self::STRIDE);
  482. io.write32(self.0, offset);
  483. }
  484. /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a
  485. /// new value to write back.
  486. #[inline(always)]
  487. pub(crate) fn update<T, I, F>(
  488. io: &T,
  489. idx: usize,
  490. f: F,
  491. ) where
  492. T: ::core::ops::Deref<Target = I>,
  493. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  494. F: ::core::ops::FnOnce(Self) -> Self,
  495. {
  496. let reg = f(Self::read(io, idx));
  497. reg.write(io, idx);
  498. }
  499. /// Read the array register at index `idx` from its address in `io`.
  500. ///
  501. /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
  502. /// access was out-of-bounds.
  503. #[inline(always)]
  504. pub(crate) fn try_read<T, I>(
  505. io: &T,
  506. idx: usize,
  507. ) -> ::kernel::error::Result<Self> where
  508. T: ::core::ops::Deref<Target = I>,
  509. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  510. {
  511. if idx < Self::SIZE {
  512. Ok(Self::read(io, idx))
  513. } else {
  514. Err(EINVAL)
  515. }
  516. }
  517. /// Write the value contained in `self` to the array register with index `idx` in `io`.
  518. ///
  519. /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
  520. /// access was out-of-bounds.
  521. #[inline(always)]
  522. pub(crate) fn try_write<T, I>(
  523. self,
  524. io: &T,
  525. idx: usize,
  526. ) -> ::kernel::error::Result where
  527. T: ::core::ops::Deref<Target = I>,
  528. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  529. {
  530. if idx < Self::SIZE {
  531. Ok(self.write(io, idx))
  532. } else {
  533. Err(EINVAL)
  534. }
  535. }
  536. /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a
  537. /// new value to write back.
  538. ///
  539. /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
  540. /// access was out-of-bounds.
  541. #[inline(always)]
  542. pub(crate) fn try_update<T, I, F>(
  543. io: &T,
  544. idx: usize,
  545. f: F,
  546. ) -> ::kernel::error::Result where
  547. T: ::core::ops::Deref<Target = I>,
  548. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  549. F: ::core::ops::FnOnce(Self) -> Self,
  550. {
  551. if idx < Self::SIZE {
  552. Ok(Self::update(io, idx, f))
  553. } else {
  554. Err(EINVAL)
  555. }
  556. }
  557. }
  558. };
  559. // Generates the IO accessors for an array of relative registers.
  560. (
  561. @io_relative_array $name:ident @ $base:ty
  562. [ $offset:literal [ $size:expr ; $stride:expr ] ]
  563. ) => {
  564. #[allow(dead_code)]
  565. impl $name {
  566. pub(crate) const OFFSET: usize = $offset;
  567. pub(crate) const SIZE: usize = $size;
  568. pub(crate) const STRIDE: usize = $stride;
  569. /// Read the array register at index `idx` from `io`, using the base address provided
  570. /// by `base` and adding the register's offset to it.
  571. #[inline(always)]
  572. pub(crate) fn read<T, I, B>(
  573. io: &T,
  574. #[allow(unused_variables)]
  575. base: &B,
  576. idx: usize,
  577. ) -> Self where
  578. T: ::core::ops::Deref<Target = I>,
  579. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  580. B: crate::regs::macros::RegisterBase<$base>,
  581. {
  582. build_assert!(idx < Self::SIZE);
  583. let offset = <B as crate::regs::macros::RegisterBase<$base>>::BASE +
  584. Self::OFFSET + (idx * Self::STRIDE);
  585. let value = io.read32(offset);
  586. Self(value)
  587. }
  588. /// Write the value contained in `self` to `io`, using the base address provided by
  589. /// `base` and adding the offset of array register `idx` to it.
  590. #[inline(always)]
  591. pub(crate) fn write<T, I, B>(
  592. self,
  593. io: &T,
  594. #[allow(unused_variables)]
  595. base: &B,
  596. idx: usize
  597. ) where
  598. T: ::core::ops::Deref<Target = I>,
  599. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  600. B: crate::regs::macros::RegisterBase<$base>,
  601. {
  602. build_assert!(idx < Self::SIZE);
  603. let offset = <B as crate::regs::macros::RegisterBase<$base>>::BASE +
  604. Self::OFFSET + (idx * Self::STRIDE);
  605. io.write32(self.0, offset);
  606. }
  607. /// Read the array register at index `idx` from `io`, using the base address provided
  608. /// by `base` and adding the register's offset to it, then run `f` on its value to
  609. /// obtain a new value to write back.
  610. #[inline(always)]
  611. pub(crate) fn update<T, I, B, F>(
  612. io: &T,
  613. base: &B,
  614. idx: usize,
  615. f: F,
  616. ) where
  617. T: ::core::ops::Deref<Target = I>,
  618. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  619. B: crate::regs::macros::RegisterBase<$base>,
  620. F: ::core::ops::FnOnce(Self) -> Self,
  621. {
  622. let reg = f(Self::read(io, base, idx));
  623. reg.write(io, base, idx);
  624. }
  625. /// Read the array register at index `idx` from `io`, using the base address provided
  626. /// by `base` and adding the register's offset to it.
  627. ///
  628. /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
  629. /// access was out-of-bounds.
  630. #[inline(always)]
  631. pub(crate) fn try_read<T, I, B>(
  632. io: &T,
  633. base: &B,
  634. idx: usize,
  635. ) -> ::kernel::error::Result<Self> where
  636. T: ::core::ops::Deref<Target = I>,
  637. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  638. B: crate::regs::macros::RegisterBase<$base>,
  639. {
  640. if idx < Self::SIZE {
  641. Ok(Self::read(io, base, idx))
  642. } else {
  643. Err(EINVAL)
  644. }
  645. }
  646. /// Write the value contained in `self` to `io`, using the base address provided by
  647. /// `base` and adding the offset of array register `idx` to it.
  648. ///
  649. /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
  650. /// access was out-of-bounds.
  651. #[inline(always)]
  652. pub(crate) fn try_write<T, I, B>(
  653. self,
  654. io: &T,
  655. base: &B,
  656. idx: usize,
  657. ) -> ::kernel::error::Result where
  658. T: ::core::ops::Deref<Target = I>,
  659. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  660. B: crate::regs::macros::RegisterBase<$base>,
  661. {
  662. if idx < Self::SIZE {
  663. Ok(self.write(io, base, idx))
  664. } else {
  665. Err(EINVAL)
  666. }
  667. }
  668. /// Read the array register at index `idx` from `io`, using the base address provided
  669. /// by `base` and adding the register's offset to it, then run `f` on its value to
  670. /// obtain a new value to write back.
  671. ///
  672. /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
  673. /// access was out-of-bounds.
  674. #[inline(always)]
  675. pub(crate) fn try_update<T, I, B, F>(
  676. io: &T,
  677. base: &B,
  678. idx: usize,
  679. f: F,
  680. ) -> ::kernel::error::Result where
  681. T: ::core::ops::Deref<Target = I>,
  682. I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
  683. B: crate::regs::macros::RegisterBase<$base>,
  684. F: ::core::ops::FnOnce(Self) -> Self,
  685. {
  686. if idx < Self::SIZE {
  687. Ok(Self::update(io, base, idx, f))
  688. } else {
  689. Err(EINVAL)
  690. }
  691. }
  692. }
  693. };
  694. }