1use core::cell::Cell;
11use core::mem;
12use kernel::hil;
13use kernel::utilities::cells::MapCell;
14use kernel::utilities::StaticRef;
15
16use crate::event_manager::LiteXEventManager;
17use crate::litex_registers::{LiteXSoCRegisterConfiguration, Read, Write};
18
19type LiteXGPIOEV<'a, R> = LiteXEventManager<
23    'a,
24    u32,
25    <R as LiteXSoCRegisterConfiguration>::ReadOnly32,
26    <R as LiteXSoCRegisterConfiguration>::ReadWrite32,
27    <R as LiteXSoCRegisterConfiguration>::ReadWrite32,
28>;
29
30#[repr(C)]
32pub struct LiteXGPIORegisters<R: LiteXSoCRegisterConfiguration> {
33    gpio_output_enable: R::ReadWrite32,
34    gpio_input: R::ReadOnly32,
35    gpio_output: R::ReadWrite32,
36    gpio_mode: R::ReadWrite32,
37    gpio_edge: R::ReadWrite32,
38    gpio_ev_status: R::ReadOnly32,
39    gpio_ev_pending: R::ReadWrite32,
40    gpio_ev_enable: R::ReadWrite32,
41}
42
43impl<R: LiteXSoCRegisterConfiguration> LiteXGPIORegisters<R> {
44    fn ev(&self) -> LiteXGPIOEV<'_, R> {
45        LiteXGPIOEV::<R>::new(
46            &self.gpio_ev_status,
47            &self.gpio_ev_pending,
48            &self.gpio_ev_enable,
49        )
50    }
51}
52
53pub struct LiteXGPIOController<'client, R: LiteXSoCRegisterConfiguration> {
55    regs: StaticRef<LiteXGPIORegisters<R>>,
56    gpio_count: usize,
57    gpio_references: Cell<u32>,
58    gpio_clients: MapCell<[Option<&'client dyn hil::gpio::Client>; 32]>,
63}
64
65impl<'client, R: LiteXSoCRegisterConfiguration> LiteXGPIOController<'client, R> {
66    pub fn new(
67        base: StaticRef<LiteXGPIORegisters<R>>,
68        gpio_count: usize,
69    ) -> LiteXGPIOController<'client, R> {
70        assert!(
75            gpio_count <= 32,
76            "LiteXGPIOController register width insufficient to support the requested GPIO count"
77        );
78
79        LiteXGPIOController {
80            regs: base,
81            gpio_count,
82            gpio_references: Cell::new(0),
83            gpio_clients: MapCell::new([None; 32]),
84        }
85    }
86
87    pub fn initialize(&self) {
91        self.regs.gpio_output_enable.set(0);
92        self.regs.ev().disable_all();
93        self.regs.ev().clear_all();
94    }
95
96    pub fn gpio_count(&self) -> usize {
99        self.gpio_count
100    }
101
102    pub fn get_gpio_pin<'controller>(
109        &'controller self,
110        index: usize,
111    ) -> Option<LiteXGPIOPin<'controller, 'client, R>> {
112        if index < self.gpio_count() && (self.gpio_references.get() & (1 << index)) == 0 {
113            self.gpio_references
114                .set(self.gpio_references.get() | (1 << index));
115            Some(LiteXGPIOPin::new(self, index))
116        } else {
117            None
118        }
119    }
120
121    pub(self) fn destroy_gpio_pin(&self, index: usize) {
123        self.gpio_clients.map(|clients| clients[index] = None);
124        self.gpio_references
125            .set(self.gpio_references.get() & !(1 << index));
126    }
127
128    pub(self) fn set_gpio_output_enable(&self, index: usize, oe: bool) {
130        if oe {
131            self.regs
132                .gpio_output_enable
133                .set(self.regs.gpio_output_enable.get() | (1 << index));
134        } else {
135            self.regs
136                .gpio_output_enable
137                .set(self.regs.gpio_output_enable.get() & !(1 << index));
138        }
139    }
140
141    pub(self) fn set_gpio_output(&self, index: usize, output: bool) {
143        if output {
144            self.regs
145                .gpio_output
146                .set(self.regs.gpio_output.get() | (1 << index));
147        } else {
148            self.regs
149                .gpio_output
150                .set(self.regs.gpio_output.get() & !(1 << index));
151        }
152    }
153
154    pub(self) fn read_gpio(&self, index: usize) -> (bool, bool, bool) {
158        (
159            (self.regs.gpio_output_enable.get() & (1 << index)) != 0,
160            (self.regs.gpio_output.get() & (1 << index)) != 0,
161            (self.regs.gpio_input.get() & (1 << index)) != 0,
162        )
163    }
164
165    fn set_gpio_client(&self, index: usize, client: &'client dyn hil::gpio::Client) {
167        self.gpio_clients
168            .map(|clients| clients[index] = Some(client));
169    }
170
171    pub(self) fn gpio_interrupt_pending(&self, index: usize) -> bool {
177        self.regs.ev().event_asserted(index)
178    }
179
180    pub(self) fn configure_gpio_interrupt(
183        &self,
184        index: usize,
185        edge: Option<hil::gpio::InterruptEdge>,
186    ) {
187        if let Some(e) = edge {
188            self.regs.ev().disable_event(index);
191
192            match e {
197                hil::gpio::InterruptEdge::RisingEdge => {
198                    self.regs
199                        .gpio_mode
200                        .set(self.regs.gpio_mode.get() & !(1 << index));
201                    self.regs
202                        .gpio_edge
203                        .set(self.regs.gpio_edge.get() & !(1 << index));
204                }
205                hil::gpio::InterruptEdge::FallingEdge => {
206                    self.regs
207                        .gpio_mode
208                        .set(self.regs.gpio_mode.get() & !(1 << index));
209                    self.regs
210                        .gpio_edge
211                        .set(self.regs.gpio_edge.get() & !(1 << index));
212                }
213                hil::gpio::InterruptEdge::EitherEdge => {
214                    self.regs
215                        .gpio_mode
216                        .set(self.regs.gpio_mode.get() & !(1 << index));
217                }
218            }
219
220            self.regs.ev().enable_event(index);
222        } else {
223            self.regs.ev().disable_event(index);
227        }
228    }
229
230    pub fn service_interrupt(&self) {
231        while let Some(event_index) = self.regs.ev().next_asserted() {
232            self.regs.ev().clear_event(event_index);
233            self.gpio_clients
234                .map(|clients| clients[event_index].map(|client| client.fired()));
235        }
236    }
237}
238
239pub struct LiteXGPIOPin<'controller, 'client, R: LiteXSoCRegisterConfiguration> {
246    controller: &'controller LiteXGPIOController<'client, R>,
247    index: usize,
248}
249
250impl<'controller, 'client, R: LiteXSoCRegisterConfiguration> LiteXGPIOPin<'controller, 'client, R> {
251    fn new(
252        controller: &'controller LiteXGPIOController<'client, R>,
253        index: usize,
254    ) -> LiteXGPIOPin<'controller, 'client, R> {
255        LiteXGPIOPin { controller, index }
256    }
257
258    pub fn index(&self) -> usize {
260        self.index
261    }
262
263    pub fn controller(&self) -> &'controller LiteXGPIOController<'client, R> {
265        self.controller
266    }
267
268    pub fn destroy(self) {
270        mem::drop(self);
271    }
272}
273
274impl<R: LiteXSoCRegisterConfiguration> hil::gpio::Configure for LiteXGPIOPin<'_, '_, R> {
275    fn configuration(&self) -> hil::gpio::Configuration {
276        let (output_enable, _, _) = self.controller.read_gpio(self.index);
277        if output_enable {
278            hil::gpio::Configuration::Output
279        } else {
280            hil::gpio::Configuration::Input
281        }
282    }
283
284    fn make_output(&self) -> hil::gpio::Configuration {
285        self.controller.set_gpio_output_enable(self.index, true);
286        hil::gpio::Configuration::Output
287    }
288
289    fn disable_output(&self) -> hil::gpio::Configuration {
290        self.make_input()
293    }
294
295    fn make_input(&self) -> hil::gpio::Configuration {
296        self.controller.set_gpio_output_enable(self.index, false);
297        hil::gpio::Configuration::Input
298    }
299
300    fn disable_input(&self) -> hil::gpio::Configuration {
301        self.configuration()
308    }
309
310    fn deactivate_to_low_power(&self) {
311        self.make_input();
312    }
313
314    fn set_floating_state(&self, _state: hil::gpio::FloatingState) {
315        }
318
319    fn floating_state(&self) -> hil::gpio::FloatingState {
320        hil::gpio::FloatingState::PullNone
321    }
322}
323
324impl<R: LiteXSoCRegisterConfiguration> hil::gpio::Output for LiteXGPIOPin<'_, '_, R> {
325    fn set(&self) {
326        self.controller.set_gpio_output(self.index, true);
327    }
328
329    fn clear(&self) {
330        self.controller.set_gpio_output(self.index, false);
331    }
332
333    fn toggle(&self) -> bool {
334        let (_, current, _) = self.controller.read_gpio(self.index);
335        self.controller.set_gpio_output(self.index, !current);
336        !current
337    }
338}
339
340impl<R: LiteXSoCRegisterConfiguration> hil::gpio::Input for LiteXGPIOPin<'_, '_, R> {
341    fn read(&self) -> bool {
342        let (output_enable, output, input) = self.controller.read_gpio(self.index);
348        if output_enable {
349            output
350        } else {
351            input
352        }
353    }
354}
355
356impl<'client, R: LiteXSoCRegisterConfiguration> hil::gpio::Interrupt<'client>
357    for LiteXGPIOPin<'_, 'client, R>
358{
359    fn set_client(&self, client: &'client dyn hil::gpio::Client) {
360        self.controller.set_gpio_client(self.index, client);
361    }
362
363    fn is_pending(&self) -> bool {
364        self.controller.gpio_interrupt_pending(self.index)
365    }
366
367    fn enable_interrupts(&self, mode: hil::gpio::InterruptEdge) {
368        self.controller
369            .configure_gpio_interrupt(self.index, Some(mode));
370    }
371
372    fn disable_interrupts(&self) {
373        self.controller.configure_gpio_interrupt(self.index, None);
374    }
375}
376
377impl<R: LiteXSoCRegisterConfiguration> Drop for LiteXGPIOPin<'_, '_, R> {
378    fn drop(&mut self) {
380        self.controller.destroy_gpio_pin(self.index);
381    }
382}