|
7 | 7 | //! Generally, Tock peripherals are modeled by two structures, such as:
|
8 | 8 | //!
|
9 | 9 | //! ```rust
|
| 10 | +//! # use kernel::common::cells::VolatileCell; |
| 11 | +//! # use kernel::common::StaticRef; |
| 12 | +//! # struct ChipSpecificPeripheralClock {}; |
10 | 13 | //! /// The MMIO Structure.
|
11 | 14 | //! #[repr(C)]
|
12 | 15 | //! #[allow(dead_code)]
|
|
16 | 19 | //! }
|
17 | 20 | //!
|
18 | 21 | //! /// The Tock object that holds all information for this peripheral.
|
19 |
| -//! pub struct PeripheralHardware { |
| 22 | +//! pub struct PeripheralHardware<'a> { |
20 | 23 | //! mmio_address: StaticRef<PeripheralRegisters>,
|
21 |
| -//! clock: &ChipSpecificPeripheralClock, |
| 24 | +//! clock: &'a ChipSpecificPeripheralClock, |
22 | 25 | //! }
|
23 | 26 | //! ```
|
24 | 27 | //!
|
|
29 | 32 | //! MMIO pointer safely, Tock provides the PeripheralManager interface:
|
30 | 33 | //!
|
31 | 34 | //! ```rust
|
| 35 | +//! # use kernel::common::cells::VolatileCell; |
| 36 | +//! # use kernel::common::peripherals::PeripheralManager; |
| 37 | +//! # use kernel::common::StaticRef; |
| 38 | +//! # use kernel::hil; |
| 39 | +//! # use kernel::ReturnCode; |
| 40 | +//! # struct PeripheralRegisters { control: VolatileCell<u32> }; |
| 41 | +//! # struct PeripheralHardware { mmio_address: StaticRef<PeripheralRegisters> }; |
32 | 42 | //! impl hil::uart::UART for PeripheralHardware {
|
33 |
| -//! fn init(&self, params: hil::uart::UARTParams) { |
34 |
| -//! let peripheral = &PeripheralManager::new(self); |
35 |
| -//! peripheral.registers.control.set(0x0); |
36 |
| -//! // ^^^^^^^^^-- This is type &PeripheralRegisters |
| 43 | +//! fn configure(&self, params: hil::uart::UARTParameters) -> ReturnCode { |
| 44 | +//! let peripheral = &PeripheralManager::new(self); |
| 45 | +//! peripheral.registers.control.set(0x0); |
| 46 | +//! // ^^^^^^^^^-- This is type &PeripheralRegisters |
| 47 | +//! ReturnCode::SUCCESS |
| 48 | +//! } |
| 49 | +//! # fn set_client(&self, _client: &'static hil::uart::Client) {} |
| 50 | +//! # fn transmit(&self, _tx_data: &'static mut [u8], _tx_len: usize) {} |
| 51 | +//! # fn receive(&self, _rx_buffer: &'static mut [u8], _rx_len: usize) {} |
| 52 | +//! # fn abort_receive(&self) {} |
| 53 | +//! } |
| 54 | +//! # use kernel::common::peripherals::PeripheralManagement; |
| 55 | +//! # use kernel::NoClockControl; |
| 56 | +//! # impl PeripheralManagement<NoClockControl> for PeripheralHardware { |
| 57 | +//! # type RegisterType = PeripheralRegisters; |
| 58 | +//! |
| 59 | +//! # fn get_registers(&self) -> &PeripheralRegisters { |
| 60 | +//! # &*self.mmio_address |
| 61 | +//! # } |
| 62 | +//! # fn get_clock(&self) -> &NoClockControl { unsafe { &kernel::NO_CLOCK_CONTROL } } |
| 63 | +//! # fn before_peripheral_access(&self, _c: &NoClockControl, _r: &Self::RegisterType) {} |
| 64 | +//! # fn after_peripheral_access(&self, _c: &NoClockControl, _r: &Self::RegisterType) {} |
| 65 | +//! # } |
37 | 66 | //! ```
|
38 | 67 | //!
|
39 | 68 | //! Each peripheral must tell the kernel where its registers live in memory:
|
40 | 69 | //!
|
41 | 70 | //! ```rust
|
| 71 | +//! # use kernel::common::peripherals::PeripheralManagement; |
| 72 | +//! # use kernel::common::StaticRef; |
| 73 | +//! # pub struct PeripheralRegisters {}; |
| 74 | +//! # pub struct PeripheralHardware { mmio_address: StaticRef<PeripheralRegisters> }; |
42 | 75 | //! /// Teaching the kernel how to create PeripheralRegisters.
|
43 |
| -//! impl PeripheralManagement<pm::Clock> for PeripheralHardware { |
| 76 | +//! use kernel::NoClockControl; |
| 77 | +//! impl PeripheralManagement<NoClockControl> for PeripheralHardware { |
44 | 78 | //! type RegisterType = PeripheralRegisters;
|
45 | 79 | //!
|
46 | 80 | //! fn get_registers(&self) -> &PeripheralRegisters {
|
47 | 81 | //! &*self.mmio_address
|
48 | 82 | //! }
|
| 83 | +//! # fn get_clock(&self) -> &NoClockControl { unsafe { &kernel::NO_CLOCK_CONTROL } } |
| 84 | +//! # fn before_peripheral_access(&self, _c: &NoClockControl, _r: &Self::RegisterType) {} |
| 85 | +//! # fn after_peripheral_access(&self, _c: &NoClockControl, _r: &Self::RegisterType) {} |
49 | 86 | //! }
|
50 | 87 | //! ```
|
51 | 88 | //!
|
|
68 | 105 | //! without enabling clocks if needed if they use hardware for bookkeeping.
|
69 | 106 | //!
|
70 | 107 | //! ```rust
|
| 108 | +//! use kernel::common::peripherals::PeripheralManagement; |
| 109 | +//! use kernel::common::StaticRef; |
| 110 | +//! use kernel::ClockInterface; |
| 111 | +//! // A dummy clock for this example. |
| 112 | +//! // Real peripherals that do not have clocks should use NoClockControl from this module. |
| 113 | +//! struct ExampleClock {}; |
| 114 | +//! impl ClockInterface for ExampleClock { |
| 115 | +//! fn is_enabled(&self) -> bool { true } |
| 116 | +//! fn enable(&self) { } |
| 117 | +//! fn disable(&self) { } |
| 118 | +//! } |
| 119 | +//! |
| 120 | +//! // Dummy hardware for this example. |
| 121 | +//! struct SpiRegisters {}; |
| 122 | +//! struct SpiHw<'a> { |
| 123 | +//! mmio_address: StaticRef<SpiRegisters>, |
| 124 | +//! clock: &'a ExampleClock, |
| 125 | +//! busy: bool, |
| 126 | +//! }; |
| 127 | +//! |
71 | 128 | //! /// Teaching the kernel which clock controls SpiHw.
|
72 |
| -//! impl PeripheralManagement<pm::Clock> for SpiHw { |
73 |
| -//! fn get_clock(&self) -> &pm::Clock { |
74 |
| -//! &pm::Clock::PBA(pm::PBAClock::SPI) |
75 |
| -//! } |
| 129 | +//! impl<'a> PeripheralManagement<ExampleClock> for SpiHw<'a> { |
| 130 | +//! type RegisterType = SpiRegisters; |
| 131 | +//! |
| 132 | +//! fn get_registers(&self) -> &SpiRegisters { &*self.mmio_address } |
| 133 | +//! |
| 134 | +//! fn get_clock(&self) -> &ExampleClock { self.clock } |
76 | 135 | //!
|
77 |
| -//! fn before_mmio_access(&self, clock: &pm::Clock, _registers: &SpiRegisters) { |
| 136 | +//! fn before_peripheral_access(&self, clock: &ExampleClock, _registers: &SpiRegisters) { |
78 | 137 | //! clock.enable();
|
79 | 138 | //! }
|
80 | 139 | //!
|
81 |
| -//! fn after_mmio_access(&self, clock: &pm::Clock, _registers: &SpiRegisters) { |
82 |
| -//! if !self.is_busy() { |
| 140 | +//! fn after_peripheral_access(&self, clock: &ExampleClock, _registers: &SpiRegisters) { |
| 141 | +//! if !self.busy { |
83 | 142 | //! clock.disable();
|
84 | 143 | //! }
|
85 | 144 | //! }
|
@@ -120,9 +179,30 @@ where
|
120 | 179 | /// PeripheralManagement trait) should instantiate an instance of this
|
121 | 180 | /// method to accesss memory mapped registers.
|
122 | 181 | ///
|
123 |
| -/// ```rust |
124 |
| -/// let peripheral = &PeripheralManager::new(self); |
125 |
| -/// peripheral.registers.control.set(0x1); |
| 182 | +/// ``` |
| 183 | +/// # use kernel::common::cells::VolatileCell; |
| 184 | +/// # use kernel::common::peripherals::PeripheralManager; |
| 185 | +/// # use kernel::common::StaticRef; |
| 186 | +/// # pub struct PeripheralRegisters { control: VolatileCell<u32> }; |
| 187 | +/// # pub struct PeripheralHardware { mmio_address: StaticRef<PeripheralRegisters> }; |
| 188 | +/// impl PeripheralHardware { |
| 189 | +/// fn example(&self) { |
| 190 | +/// let peripheral = &PeripheralManager::new(self); |
| 191 | +/// peripheral.registers.control.set(0x1); |
| 192 | +/// } |
| 193 | +/// } |
| 194 | +/// # use kernel::common::peripherals::PeripheralManagement; |
| 195 | +/// # use kernel::NoClockControl; |
| 196 | +/// # impl PeripheralManagement<NoClockControl> for PeripheralHardware { |
| 197 | +/// # type RegisterType = PeripheralRegisters; |
| 198 | +/// |
| 199 | +/// # fn get_registers(&self) -> &PeripheralRegisters { |
| 200 | +/// # &*self.mmio_address |
| 201 | +/// # } |
| 202 | +/// # fn get_clock(&self) -> &NoClockControl { unsafe { &kernel::NO_CLOCK_CONTROL } } |
| 203 | +/// # fn before_peripheral_access(&self, _c: &NoClockControl, _r: &Self::RegisterType) {} |
| 204 | +/// # fn after_peripheral_access(&self, _c: &NoClockControl, _r: &Self::RegisterType) {} |
| 205 | +/// # } |
126 | 206 | /// ```
|
127 | 207 | pub struct PeripheralManager<'a, H, C>
|
128 | 208 | where
|
|
0 commit comments