sam4l/
gloc.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Implementation of the SAM4L glue logic controller (GLOC).
6//!
7//! GLOC input and output pins must be selected appropriately from table 3-1 in
8//! the SAM4l manual.
9
10use crate::pm::{self, Clock, PBAClock};
11use crate::scif::{self, ClockSource, GenericClock};
12use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
13use kernel::utilities::registers::{register_bitfields, ReadWrite};
14use kernel::utilities::StaticRef;
15
16#[repr(C)]
17pub struct GlocRegisters {
18    cr: ReadWrite<u32, Control::Register>,
19    truth: ReadWrite<u32, Truth::Register>,
20}
21
22register_bitfields![u32,
23    Control [
24        /// Filter Enable
25        FILTEN OFFSET(31) NUMBITS(1) [
26            NoGlitchFilter = 0,
27            GlitchFilter = 1
28        ],
29        /// Enable IN Inputs
30        AEN OFFSET(0) NUMBITS(4) []
31    ],
32
33    Truth [
34        /// Truth table values
35        TRUTH OFFSET(0) NUMBITS(16) []
36    ]
37];
38
39/// The GLOC's base addresses in memory (Section 7.1 of manual).
40const GLOC_BASE_ADDR: usize = 0x40060000;
41
42/// The number of bytes between each memory mapped GLOC LUT (Section 36.7).
43const GLOC_LUT_SIZE: usize = 0x8;
44
45/// Bitmasks for selecting the four GLOC inputs.
46pub const IN_0_4: u8 = 0b0001; // IN0/IN4
47pub const IN_1_5: u8 = 0b0010; // IN1/IN5
48pub const IN_2_6: u8 = 0b0100; // IN2/IN6
49pub const IN_3_7: u8 = 0b1000; // IN3/IN7
50
51/// Available look up tables.
52pub enum Lut {
53    Lut0 = 0,
54    Lut1 = 1,
55}
56
57pub struct Gloc {
58    lut_regs: [StaticRef<GlocRegisters>; 2],
59}
60
61impl Gloc {
62    pub const fn new() -> Self {
63        Self {
64            lut_regs: [get_lut_reg(Lut::Lut0), get_lut_reg(Lut::Lut1)],
65        }
66    }
67}
68
69/// Gets the memory location of the memory-mapped registers of a LUT.
70const fn get_lut_reg(lut: Lut) -> StaticRef<GlocRegisters> {
71    unsafe {
72        StaticRef::new((GLOC_BASE_ADDR + (lut as usize) * GLOC_LUT_SIZE) as *const GlocRegisters)
73    }
74}
75
76impl Gloc {
77    /// Enables the GLOC by enabling its clock.
78    pub fn enable(&self) {
79        pm::enable_clock(Clock::PBA(PBAClock::GLOC));
80    }
81
82    /// Disables the GLOC by resetting the registers and disabling the clocks.
83    pub fn disable(&self) {
84        self.disable_lut(Lut::Lut0);
85        self.disable_lut(Lut::Lut1);
86        scif::generic_clock_disable(GenericClock::GCLK5);
87        pm::disable_clock(Clock::PBA(PBAClock::GLOC));
88    }
89
90    /// Gets the memory-mapped registers associated with a LUT.
91    fn lut_registers(&self, lut: Lut) -> &GlocRegisters {
92        &self.lut_regs[lut as usize]
93    }
94
95    /// Set the truth table values.
96    pub fn configure_lut(&self, lut: Lut, config: u16) {
97        let registers = self.lut_registers(lut);
98        registers.truth.write(Truth::TRUTH.val(config as u32));
99    }
100
101    /// Enable selected LUT inputs.
102    pub fn enable_lut_inputs(&self, lut: Lut, inputs: u8) {
103        let registers = self.lut_registers(lut);
104        let aen: u32 = registers.cr.read(Control::AEN) | (inputs as u32);
105        registers.cr.modify(Control::AEN.val(aen));
106    }
107
108    /// Disable selected LUT inputs.
109    pub fn disable_lut_inputs(&self, lut: Lut, inputs: u8) {
110        let registers = self.lut_registers(lut);
111        let aen: u32 = registers.cr.read(Control::AEN) & !(inputs as u32);
112        registers.cr.modify(Control::AEN.val(aen));
113    }
114
115    /// Disable LUT by resetting registers.
116    pub fn disable_lut(&self, lut: Lut) {
117        let registers = self.lut_registers(lut);
118        registers.truth.write(Truth::TRUTH.val(0));
119        registers.cr.modify(Control::AEN.val(0));
120    }
121
122    /// Enable filter on output to prevent glitches.  This will delay the given
123    /// LUT's output by 3-4 GCLK cycles.
124    pub fn enable_lut_filter(&self, lut: Lut) {
125        scif::generic_clock_enable(GenericClock::GCLK5, ClockSource::CLK_CPU);
126        let registers = self.lut_registers(lut);
127        registers.cr.modify(Control::FILTEN::GlitchFilter);
128    }
129
130    /// Disable output filter.
131    pub fn disable_lut_filter(&self, lut: Lut) {
132        let registers = self.lut_registers(lut);
133        registers.cr.modify(Control::FILTEN::NoGlitchFilter);
134    }
135}