1.1 --- a/pkg/devices/lib/tcu/src/common.cc Thu Feb 01 22:40:19 2024 +0100
1.2 +++ b/pkg/devices/lib/tcu/src/common.cc Thu Feb 01 22:41:30 2024 +0100
1.3 @@ -21,8 +21,10 @@
1.4
1.5 #include <l4/devices/hw_mmio_register_block.h>
1.6 #include <l4/sys/err.h>
1.7 +#include <l4/sys/irq.h>
1.8 +#include <l4/util/util.h>
1.9
1.10 -#include <math.h>
1.11 +#include <math.h> // log2
1.12
1.13 #include "tcu-common.h"
1.14
1.15 @@ -78,6 +80,18 @@
1.16 Channel_tcu0 = 0, // TCEN0/STOP0/FFLAG0/SFLAG0
1.17 };
1.18
1.19 +// Flag/mask register bits.
1.20 +
1.21 +enum Flag_bit_numbers : unsigned
1.22 +{
1.23 + Half_match_wdt = 24, // HFLAGW
1.24 +
1.25 + // Flag/mask group bit offsets.
1.26 +
1.27 + Half_match_shift = 16,
1.28 + Full_match_shift = 0,
1.29 +};
1.30 +
1.31 // Counter data constraints.
1.32
1.33 enum Data_masks : unsigned
1.34 @@ -102,8 +116,8 @@
1.35
1.36 // Channel abstraction.
1.37
1.38 -Tcu_channel::Tcu_channel(l4_addr_t addr, uint8_t channel)
1.39 -: _channel(channel)
1.40 +Tcu_channel::Tcu_channel(l4_addr_t addr, uint8_t channel, l4_cap_idx_t irq)
1.41 +: _channel(channel), _irq(irq)
1.42 {
1.43 _regs = new Hw::Mmio_register_block<32>(addr);
1.44 }
1.45 @@ -226,6 +240,73 @@
1.46 _regs[Tcu_half_data_value_base + _channel * Tcu_data_block_offset] = value & Data_mask;
1.47 }
1.48
1.49 +bool
1.50 +Tcu_channel::get_full_data_mask()
1.51 +{
1.52 + return _regs[Tcu_mask_status] & (1UL << (_channel + Full_match_shift));
1.53 +}
1.54 +
1.55 +void
1.56 +Tcu_channel::set_full_data_mask(bool masked)
1.57 +{
1.58 + _regs[masked ? Tcu_set_mask : Tcu_clear_mask] = (1UL << (_channel + Full_match_shift));
1.59 +}
1.60 +
1.61 +bool
1.62 +Tcu_channel::get_half_data_mask()
1.63 +{
1.64 + return _regs[Tcu_mask_status] & (1UL << (_channel + Half_match_shift));
1.65 +}
1.66 +
1.67 +void
1.68 +Tcu_channel::set_half_data_mask(bool masked)
1.69 +{
1.70 + _regs[masked ? Tcu_set_mask : Tcu_clear_mask] = (1UL << (_channel + Half_match_shift));
1.71 +}
1.72 +
1.73 +// Wait indefinitely for an interrupt request, returning true if one was delivered.
1.74 +
1.75 +bool
1.76 +Tcu_channel::wait_for_irq()
1.77 +{
1.78 + bool irq = !l4_error(l4_irq_receive(_irq, L4_IPC_NEVER)) && have_interrupt();
1.79 +
1.80 + if (irq)
1.81 + ack_irq();
1.82 +
1.83 + return irq;
1.84 +}
1.85 +
1.86 +// Wait up to the given timeout (in microseconds) for an interrupt request,
1.87 +// returning true if one was delivered.
1.88 +
1.89 +bool
1.90 +Tcu_channel::wait_for_irq(unsigned int timeout)
1.91 +{
1.92 + bool irq = !l4_error(l4_irq_receive(_irq, l4_timeout(L4_IPC_TIMEOUT_NEVER, l4util_micros2l4to(timeout)))) && have_interrupt();
1.93 +
1.94 + if (irq)
1.95 + ack_irq();
1.96 +
1.97 + return irq;
1.98 +}
1.99 +
1.100 +// Acknowledge an interrupt condition.
1.101 +
1.102 +void
1.103 +Tcu_channel::ack_irq()
1.104 +{
1.105 + _regs[Tcu_clear_flag] = 1UL << _channel;
1.106 +}
1.107 +
1.108 +// Return whether an interrupt is pending on the given channel.
1.109 +
1.110 +bool
1.111 +Tcu_channel::have_interrupt()
1.112 +{
1.113 + return _regs[Tcu_flag_status] & (1UL << _channel) ? true : false;
1.114 +}
1.115 +
1.116
1.117
1.118 // Peripheral abstraction.
1.119 @@ -238,10 +319,10 @@
1.120 // Obtain a channel object.
1.121
1.122 Tcu_channel *
1.123 -Tcu_chip::get_channel(uint8_t channel)
1.124 +Tcu_chip::get_channel(uint8_t channel, l4_cap_idx_t irq)
1.125 {
1.126 if (channel < num_channels())
1.127 - return _get_channel(_start, channel);
1.128 + return _get_channel(_start, channel, irq);
1.129 else
1.130 throw -L4_EINVAL;
1.131 }