Skip to main content

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