# HG changeset patch # User Paul Boddie # Date 1706823690 -3600 # Node ID 8bda1afbc1f5fd4a5d01fba3ce9510b1f277f88f # Parent e0e3ba7f192c9af2b1bb868bc3bf1da4955724d5 Added TCU interrupt support. diff -r e0e3ba7f192c -r 8bda1afbc1f5 pkg/devices/lib/tcu/include/tcu-common.h --- a/pkg/devices/lib/tcu/include/tcu-common.h Thu Feb 01 22:40:19 2024 +0100 +++ b/pkg/devices/lib/tcu/include/tcu-common.h Thu Feb 01 22:41:30 2024 +0100 @@ -36,13 +36,14 @@ { protected: uint8_t _channel; + l4_cap_idx_t _irq; Hw::Register_block<32> _regs; uint32_t get_field(uint32_t reg, uint32_t mask, uint8_t shift); void set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value); public: - explicit Tcu_channel(l4_addr_t start, uint8_t channel); + explicit Tcu_channel(l4_addr_t start, uint8_t channel, l4_cap_idx_t irq); virtual void disable(); virtual void enable(); @@ -59,6 +60,18 @@ virtual void set_full_data_value(uint32_t value); virtual uint32_t get_half_data_value(); virtual void set_half_data_value(uint32_t value); + + // Interrupt-related operations. + + virtual bool get_full_data_mask(); + virtual void set_full_data_mask(bool masked); + virtual bool get_half_data_mask(); + virtual void set_half_data_mask(bool masked); + + virtual void ack_irq(); + virtual bool have_interrupt(); + virtual bool wait_for_irq(); + virtual bool wait_for_irq(unsigned int timeout); }; // TCU device control. @@ -70,12 +83,13 @@ virtual unsigned int num_channels() = 0; - virtual Tcu_channel *_get_channel(l4_addr_t addr, uint8_t channel) = 0; + virtual Tcu_channel *_get_channel(l4_addr_t addr, uint8_t channel, + l4_cap_idx_t irq) = 0; public: explicit Tcu_chip(l4_addr_t start, l4_addr_t end); - Tcu_channel *get_channel(uint8_t channel); + Tcu_channel *get_channel(uint8_t channel, l4_cap_idx_t irq); }; #endif /* __cplusplus */ diff -r e0e3ba7f192c -r 8bda1afbc1f5 pkg/devices/lib/tcu/include/tcu-jz4780.h --- a/pkg/devices/lib/tcu/include/tcu-jz4780.h Thu Feb 01 22:40:19 2024 +0100 +++ b/pkg/devices/lib/tcu/include/tcu-jz4780.h Thu Feb 01 22:41:30 2024 +0100 @@ -34,7 +34,7 @@ class Tcu_jz4780_channel : public Tcu_channel { public: - explicit Tcu_jz4780_channel(l4_addr_t start, uint8_t channel); + explicit Tcu_jz4780_channel(l4_addr_t start, uint8_t channel, l4_cap_idx_t irq); }; @@ -44,7 +44,7 @@ unsigned int num_channels() { return 8; } - Tcu_channel *_get_channel(l4_addr_t addr, uint8_t channel); + Tcu_channel *_get_channel(l4_addr_t addr, uint8_t channel, l4_cap_idx_t irq); public: explicit Tcu_jz4780_chip(l4_addr_t start, l4_addr_t end); @@ -60,7 +60,7 @@ void *jz4780_tcu_init(l4_addr_t tcu_base, l4_addr_t tcu_base_end); -void *jz4780_tcu_get_channel(void *tcu, uint8_t channel); +void *jz4780_tcu_get_channel(void *tcu, uint8_t channel, l4_cap_idx_t irq); void jz4780_tcu_disable(void *tcu_channel); @@ -92,4 +92,16 @@ void jz4780_tcu_set_half_data_value(void *tcu_channel, uint32_t value); +int jz4780_tcu_get_full_data_mask(void *tcu_channel); + +void jz4780_tcu_set_full_data_mask(void *tcu_channel, int masked); + +int jz4780_tcu_get_half_data_mask(void *tcu_channel); + +void jz4780_tcu_set_half_data_mask(void *tcu_channel, int masked); + +int jz4780_tcu_have_interrupt(void *tcu_channel); + +int jz4780_tcu_wait_for_irq(void *tcu_channel, unsigned int timeout); + EXTERN_C_END diff -r e0e3ba7f192c -r 8bda1afbc1f5 pkg/devices/lib/tcu/include/tcu-x1600.h --- a/pkg/devices/lib/tcu/include/tcu-x1600.h Thu Feb 01 22:40:19 2024 +0100 +++ b/pkg/devices/lib/tcu/include/tcu-x1600.h Thu Feb 01 22:41:30 2024 +0100 @@ -34,7 +34,7 @@ class Tcu_x1600_channel : public Tcu_channel { public: - explicit Tcu_x1600_channel(l4_addr_t start, uint8_t channel); + explicit Tcu_x1600_channel(l4_addr_t start, uint8_t channel, l4_cap_idx_t irq); void enable(); uint8_t get_count_mode(); @@ -48,7 +48,7 @@ unsigned int num_channels() { return 8; } - Tcu_channel *_get_channel(l4_addr_t addr, uint8_t channel); + Tcu_channel *_get_channel(l4_addr_t addr, uint8_t channel, l4_cap_idx_t irq); public: explicit Tcu_x1600_chip(l4_addr_t start, l4_addr_t end); @@ -64,7 +64,7 @@ void *x1600_tcu_init(l4_addr_t tcu_base, l4_addr_t tcu_base_end); -void *x1600_tcu_get_channel(void *tcu, uint8_t channel); +void *x1600_tcu_get_channel(void *tcu, uint8_t channel, l4_cap_idx_t irq); void x1600_tcu_disable(void *tcu_channel); @@ -96,4 +96,16 @@ void x1600_tcu_set_half_data_value(void *tcu_channel, uint32_t value); +int x1600_tcu_get_full_data_mask(void *tcu_channel); + +void x1600_tcu_set_full_data_mask(void *tcu_channel, int masked); + +int x1600_tcu_get_half_data_mask(void *tcu_channel); + +void x1600_tcu_set_half_data_mask(void *tcu_channel, int masked); + +int x1600_tcu_have_interrupt(void *tcu_channel); + +int x1600_tcu_wait_for_irq(void *tcu_channel, unsigned int timeout); + EXTERN_C_END diff -r e0e3ba7f192c -r 8bda1afbc1f5 pkg/devices/lib/tcu/src/common.cc --- a/pkg/devices/lib/tcu/src/common.cc Thu Feb 01 22:40:19 2024 +0100 +++ b/pkg/devices/lib/tcu/src/common.cc Thu Feb 01 22:41:30 2024 +0100 @@ -21,8 +21,10 @@ #include #include +#include +#include -#include +#include // log2 #include "tcu-common.h" @@ -78,6 +80,18 @@ Channel_tcu0 = 0, // TCEN0/STOP0/FFLAG0/SFLAG0 }; +// Flag/mask register bits. + +enum Flag_bit_numbers : unsigned +{ + Half_match_wdt = 24, // HFLAGW + + // Flag/mask group bit offsets. + + Half_match_shift = 16, + Full_match_shift = 0, +}; + // Counter data constraints. enum Data_masks : unsigned @@ -102,8 +116,8 @@ // Channel abstraction. -Tcu_channel::Tcu_channel(l4_addr_t addr, uint8_t channel) -: _channel(channel) +Tcu_channel::Tcu_channel(l4_addr_t addr, uint8_t channel, l4_cap_idx_t irq) +: _channel(channel), _irq(irq) { _regs = new Hw::Mmio_register_block<32>(addr); } @@ -226,6 +240,73 @@ _regs[Tcu_half_data_value_base + _channel * Tcu_data_block_offset] = value & Data_mask; } +bool +Tcu_channel::get_full_data_mask() +{ + return _regs[Tcu_mask_status] & (1UL << (_channel + Full_match_shift)); +} + +void +Tcu_channel::set_full_data_mask(bool masked) +{ + _regs[masked ? Tcu_set_mask : Tcu_clear_mask] = (1UL << (_channel + Full_match_shift)); +} + +bool +Tcu_channel::get_half_data_mask() +{ + return _regs[Tcu_mask_status] & (1UL << (_channel + Half_match_shift)); +} + +void +Tcu_channel::set_half_data_mask(bool masked) +{ + _regs[masked ? Tcu_set_mask : Tcu_clear_mask] = (1UL << (_channel + Half_match_shift)); +} + +// Wait indefinitely for an interrupt request, returning true if one was delivered. + +bool +Tcu_channel::wait_for_irq() +{ + bool irq = !l4_error(l4_irq_receive(_irq, L4_IPC_NEVER)) && have_interrupt(); + + if (irq) + ack_irq(); + + return irq; +} + +// Wait up to the given timeout (in microseconds) for an interrupt request, +// returning true if one was delivered. + +bool +Tcu_channel::wait_for_irq(unsigned int timeout) +{ + bool irq = !l4_error(l4_irq_receive(_irq, l4_timeout(L4_IPC_TIMEOUT_NEVER, l4util_micros2l4to(timeout)))) && have_interrupt(); + + if (irq) + ack_irq(); + + return irq; +} + +// Acknowledge an interrupt condition. + +void +Tcu_channel::ack_irq() +{ + _regs[Tcu_clear_flag] = 1UL << _channel; +} + +// Return whether an interrupt is pending on the given channel. + +bool +Tcu_channel::have_interrupt() +{ + return _regs[Tcu_flag_status] & (1UL << _channel) ? true : false; +} + // Peripheral abstraction. @@ -238,10 +319,10 @@ // Obtain a channel object. Tcu_channel * -Tcu_chip::get_channel(uint8_t channel) +Tcu_chip::get_channel(uint8_t channel, l4_cap_idx_t irq) { if (channel < num_channels()) - return _get_channel(_start, channel); + return _get_channel(_start, channel, irq); else throw -L4_EINVAL; } diff -r e0e3ba7f192c -r 8bda1afbc1f5 pkg/devices/lib/tcu/src/jz4780.cc --- a/pkg/devices/lib/tcu/src/jz4780.cc Thu Feb 01 22:40:19 2024 +0100 +++ b/pkg/devices/lib/tcu/src/jz4780.cc Thu Feb 01 22:41:30 2024 +0100 @@ -25,8 +25,9 @@ // Channel abstraction. -Tcu_jz4780_channel::Tcu_jz4780_channel(l4_addr_t addr, uint8_t channel) -: Tcu_channel(addr, channel) +Tcu_jz4780_channel::Tcu_jz4780_channel(l4_addr_t addr, uint8_t channel, + l4_cap_idx_t irq) +: Tcu_channel(addr, channel, irq) { } @@ -39,9 +40,10 @@ { } -Tcu_channel *Tcu_jz4780_chip::_get_channel(l4_addr_t addr, uint8_t channel) +Tcu_channel *Tcu_jz4780_chip::_get_channel(l4_addr_t addr, uint8_t channel, + l4_cap_idx_t irq) { - return new Tcu_jz4780_channel(addr, channel); + return new Tcu_jz4780_channel(addr, channel, irq); } @@ -53,9 +55,9 @@ return (void *) new Tcu_jz4780_chip(tcu_base, tcu_base_end); } -void *jz4780_tcu_get_channel(void *tcu, uint8_t channel) +void *jz4780_tcu_get_channel(void *tcu, uint8_t channel, l4_cap_idx_t irq) { - return static_cast(tcu)->get_channel(channel); + return static_cast(tcu)->get_channel(channel, irq); } void jz4780_tcu_disable(void *tcu_channel) @@ -132,3 +134,33 @@ { static_cast(tcu_channel)->set_full_data_value(value); } + +int jz4780_tcu_get_full_data_mask(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_full_data_mask(); +} + +void jz4780_tcu_set_full_data_mask(void *tcu_channel, int masked) +{ + static_cast(tcu_channel)->set_full_data_mask(masked); +} + +int jz4780_tcu_get_half_data_mask(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_half_data_mask(); +} + +void jz4780_tcu_set_half_data_mask(void *tcu_channel, int masked) +{ + static_cast(tcu_channel)->set_half_data_mask(masked); +} + +int jz4780_tcu_have_interrupt(void *tcu_channel) +{ + return static_cast(tcu_channel)->have_interrupt(); +} + +int jz4780_tcu_wait_for_irq(void *tcu_channel, unsigned int timeout) +{ + return static_cast(tcu_channel)->wait_for_irq(timeout); +} diff -r e0e3ba7f192c -r 8bda1afbc1f5 pkg/devices/lib/tcu/src/x1600.cc --- a/pkg/devices/lib/tcu/src/x1600.cc Thu Feb 01 22:40:19 2024 +0100 +++ b/pkg/devices/lib/tcu/src/x1600.cc Thu Feb 01 22:41:30 2024 +0100 @@ -62,18 +62,6 @@ // Field definitions. -// Flag/mask register bits. - -enum Flag_bit_numbers : unsigned -{ - Half_match_wdt = 24, // HFLAGW - - // Flag/mask group bit offsets. - - Half_match_shift = 16, - Full_match_shift = 0, -}; - // Counter data constraints. enum Data_masks : unsigned @@ -157,8 +145,9 @@ // Channel abstraction. -Tcu_x1600_channel::Tcu_x1600_channel(l4_addr_t addr, uint8_t channel) -: Tcu_channel(addr, channel) +Tcu_x1600_channel::Tcu_x1600_channel(l4_addr_t addr, uint8_t channel, + l4_cap_idx_t irq) +: Tcu_channel(addr, channel, irq) { } @@ -199,9 +188,10 @@ { } -Tcu_channel *Tcu_x1600_chip::_get_channel(l4_addr_t addr, uint8_t channel) +Tcu_channel *Tcu_x1600_chip::_get_channel(l4_addr_t addr, uint8_t channel, + l4_cap_idx_t irq) { - return new Tcu_x1600_channel(addr, channel); + return new Tcu_x1600_channel(addr, channel, irq); } @@ -213,9 +203,9 @@ return (void *) new Tcu_x1600_chip(tcu_base, tcu_base_end); } -void *x1600_tcu_get_channel(void *tcu, uint8_t channel) +void *x1600_tcu_get_channel(void *tcu, uint8_t channel, l4_cap_idx_t irq) { - return static_cast(tcu)->get_channel(channel); + return static_cast(tcu)->get_channel(channel, irq); } void x1600_tcu_disable(void *tcu_channel) @@ -292,3 +282,33 @@ { static_cast(tcu_channel)->set_full_data_value(value); } + +int x1600_tcu_get_full_data_mask(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_full_data_mask(); +} + +void x1600_tcu_set_full_data_mask(void *tcu_channel, int masked) +{ + static_cast(tcu_channel)->set_full_data_mask(masked); +} + +int x1600_tcu_get_half_data_mask(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_half_data_mask(); +} + +void x1600_tcu_set_half_data_mask(void *tcu_channel, int masked) +{ + static_cast(tcu_channel)->set_half_data_mask(masked); +} + +int x1600_tcu_have_interrupt(void *tcu_channel) +{ + return static_cast(tcu_channel)->have_interrupt(); +} + +int x1600_tcu_wait_for_irq(void *tcu_channel, unsigned int timeout) +{ + return static_cast(tcu_channel)->wait_for_irq(timeout); +}