# HG changeset patch # User Paul Boddie # Date 1706746564 -3600 # Node ID 8e43685cd49b0201cdc5bd27302be138174cab02 # Parent 8a4ce6e2f4df8244ff735141ee8c774b9422944e Added initial TCU support. diff -r 8a4ce6e2f4df -r 8e43685cd49b conf/landfall-examples/mips-jz4780-info.io --- a/conf/landfall-examples/mips-jz4780-info.io Thu Feb 01 01:09:29 2024 +0100 +++ b/conf/landfall-examples/mips-jz4780-info.io Thu Feb 01 01:16:04 2024 +0100 @@ -12,6 +12,7 @@ I2C = wrap(hw:match("jz4780-i2c")); RTC = wrap(hw:match("jz4780-rtc")); SSI = wrap(hw:match("jz4780-ssi")); + TCU = wrap(hw:match("jz4780-tcu")); } Io.add_vbus("common", bus) diff -r 8a4ce6e2f4df -r 8e43685cd49b conf/landfall-examples/mips-x1600-info.io --- a/conf/landfall-examples/mips-x1600-info.io Thu Feb 01 01:09:29 2024 +0100 +++ b/conf/landfall-examples/mips-x1600-info.io Thu Feb 01 01:16:04 2024 +0100 @@ -12,6 +12,7 @@ I2C = wrap(hw:match("x1600-i2c")); RTC = wrap(hw:match("x1600-rtc")); SSI = wrap(hw:match("x1600-ssi")); + TCU = wrap(hw:match("x1600-tcu")); } Io.add_vbus("common", bus) diff -r 8a4ce6e2f4df -r 8e43685cd49b pkg/devices/Control --- a/pkg/devices/Control Thu Feb 01 01:09:29 2024 +0100 +++ b/pkg/devices/Control Thu Feb 01 01:16:04 2024 +0100 @@ -42,5 +42,6 @@ provides: libdrivers-pwm provides: libdrivers-rtc provides: libdrivers-spi +provides: libdrivers-tcu requires: libc libc_be_l4re libdl l4re_c libio libipc Maintainer: paul@boddie.org.uk diff -r 8a4ce6e2f4df -r 8e43685cd49b pkg/devices/lib/Makefile --- a/pkg/devices/lib/Makefile Thu Feb 01 01:09:29 2024 +0100 +++ b/pkg/devices/lib/Makefile Thu Feb 01 01:16:04 2024 +0100 @@ -1,7 +1,7 @@ PKGDIR ?= .. L4DIR ?= $(PKGDIR)/../.. -TARGET := aic common cpm dma gpio hdmi i2c keypad lcd panel pwm rtc spi +TARGET := aic common cpm dma gpio hdmi i2c keypad lcd panel pwm rtc spi tcu include $(L4DIR)/mk/subdir.mk @@ -17,3 +17,4 @@ pwm: common rtc: common spi: cpm dma gpio +tcu: common diff -r 8a4ce6e2f4df -r 8e43685cd49b pkg/devices/lib/tcu/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/tcu/Makefile Thu Feb 01 01:16:04 2024 +0100 @@ -0,0 +1,8 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET := include src + +include $(L4DIR)/mk/subdir.mk + +src: include diff -r 8a4ce6e2f4df -r 8e43685cd49b pkg/devices/lib/tcu/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/tcu/include/Makefile Thu Feb 01 01:16:04 2024 +0100 @@ -0,0 +1,4 @@ +PKGDIR = ../../.. +L4DIR ?= $(PKGDIR)/../.. + +include $(L4DIR)/mk/include.mk diff -r 8a4ce6e2f4df -r 8e43685cd49b pkg/devices/lib/tcu/include/tcu-common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/tcu/include/tcu-common.h Thu Feb 01 01:16:04 2024 +0100 @@ -0,0 +1,81 @@ +/* + * TCU support for various chips. + * + * Copyright (C) 2024 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + + + +#ifdef __cplusplus + +#include + +// TCU channel. + +class Tcu_channel +{ +protected: + uint8_t _channel; + 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); + + virtual void disable(); + virtual void enable(); + virtual bool is_enabled(); + virtual uint8_t get_clock(); + virtual void set_clock(uint8_t clock); + virtual uint32_t get_prescale(); + virtual void set_prescale(uint32_t prescale); + virtual uint32_t get_counter(); + virtual void set_counter(uint32_t value); + virtual uint8_t get_count_mode(); + virtual void set_count_mode(uint8_t mode); + virtual uint32_t get_full_data_value(); + 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); +}; + +// TCU device control. + +class Tcu_chip +{ +protected: + l4_addr_t _start, _end; + + virtual unsigned int num_channels() = 0; + + virtual Tcu_channel *_get_channel(l4_addr_t addr, uint8_t channel) = 0; + +public: + explicit Tcu_chip(l4_addr_t start, l4_addr_t end); + + Tcu_channel *get_channel(uint8_t channel); +}; + +#endif /* __cplusplus */ diff -r 8a4ce6e2f4df -r 8e43685cd49b pkg/devices/lib/tcu/include/tcu-jz4780.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/tcu/include/tcu-jz4780.h Thu Feb 01 01:16:04 2024 +0100 @@ -0,0 +1,95 @@ +/* + * TCU (timer/counter unit) support for the JZ4780. + * + * Copyright (C) 2024 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + + + +#ifdef __cplusplus + +#include + + +class Tcu_jz4780_channel : public Tcu_channel +{ +public: + explicit Tcu_jz4780_channel(l4_addr_t start, uint8_t channel); +}; + + +class Tcu_jz4780_chip : public Tcu_chip +{ +protected: + unsigned int num_channels() + { return 8; } + + Tcu_channel *_get_channel(l4_addr_t addr, uint8_t channel); + +public: + explicit Tcu_jz4780_chip(l4_addr_t start, l4_addr_t end); +}; + +#endif /* __cplusplus */ + + + +/* C language interface. */ + +EXTERN_C_BEGIN + +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_disable(void *tcu_channel); + +void jz4780_tcu_enable(void *tcu_channel); + +int jz4780_tcu_is_enabled(void *tcu_channel); + +uint8_t jz4780_tcu_get_clock(void *tcu_channel); + +void jz4780_tcu_set_clock(void *tcu_channel, uint8_t clock); + +uint32_t jz4780_tcu_get_prescale(void *tcu_channel); + +void jz4780_tcu_set_prescale(void *tcu_channel, uint32_t prescale); + +uint32_t jz4780_tcu_get_counter(void *tcu_channel); + +void jz4780_tcu_set_counter(void *tcu_channel, uint32_t value); + +uint8_t jz4780_tcu_get_count_mode(void *tcu_channel); + +void jz4780_tcu_set_count_mode(void *tcu_channel, uint8_t mode); + +uint32_t jz4780_tcu_get_full_data_value(void *tcu_channel); + +void jz4780_tcu_set_full_data_value(void *tcu_channel, uint32_t value); + +uint32_t jz4780_tcu_get_half_data_value(void *tcu_channel); + +void jz4780_tcu_set_half_data_value(void *tcu_channel, uint32_t value); + +EXTERN_C_END diff -r 8a4ce6e2f4df -r 8e43685cd49b pkg/devices/lib/tcu/include/tcu-x1600.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/tcu/include/tcu-x1600.h Thu Feb 01 01:16:04 2024 +0100 @@ -0,0 +1,99 @@ +/* + * TCU (timer/counter unit) support for the X1600. + * + * Copyright (C) 2024 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + + + +#ifdef __cplusplus + +#include + + +class Tcu_x1600_channel : public Tcu_channel +{ +public: + explicit Tcu_x1600_channel(l4_addr_t start, uint8_t channel); + + void enable(); + uint8_t get_count_mode(); + void set_count_mode(uint8_t mode); +}; + + +class Tcu_x1600_chip : public Tcu_chip +{ +protected: + unsigned int num_channels() + { return 8; } + + Tcu_channel *_get_channel(l4_addr_t addr, uint8_t channel); + +public: + explicit Tcu_x1600_chip(l4_addr_t start, l4_addr_t end); +}; + +#endif /* __cplusplus */ + + + +/* C language interface. */ + +EXTERN_C_BEGIN + +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_disable(void *tcu_channel); + +void x1600_tcu_enable(void *tcu_channel); + +int x1600_tcu_is_enabled(void *tcu_channel); + +uint8_t x1600_tcu_get_clock(void *tcu_channel); + +void x1600_tcu_set_clock(void *tcu_channel, uint8_t clock); + +uint32_t x1600_tcu_get_prescale(void *tcu_channel); + +void x1600_tcu_set_prescale(void *tcu_channel, uint32_t prescale); + +uint32_t x1600_tcu_get_counter(void *tcu_channel); + +void x1600_tcu_set_counter(void *tcu_channel, uint32_t value); + +uint8_t x1600_tcu_get_count_mode(void *tcu_channel); + +void x1600_tcu_set_count_mode(void *tcu_channel, uint8_t mode); + +uint32_t x1600_tcu_get_full_data_value(void *tcu_channel); + +void x1600_tcu_set_full_data_value(void *tcu_channel, uint32_t value); + +uint32_t x1600_tcu_get_half_data_value(void *tcu_channel); + +void x1600_tcu_set_half_data_value(void *tcu_channel, uint32_t value); + +EXTERN_C_END diff -r 8a4ce6e2f4df -r 8e43685cd49b pkg/devices/lib/tcu/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/tcu/src/Makefile Thu Feb 01 01:16:04 2024 +0100 @@ -0,0 +1,13 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. + +TARGET = libtcu.o.a libtcu.o.so +PC_FILENAME := libdrivers-tcu + +SRC_CC := common.cc jz4780.cc x1600.cc + +PRIVATE_INCDIR += $(PKGDIR)/lib/tcu/include + +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-common + +include $(L4DIR)/mk/lib.mk diff -r 8a4ce6e2f4df -r 8e43685cd49b pkg/devices/lib/tcu/src/common.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/tcu/src/common.cc Thu Feb 01 01:16:04 2024 +0100 @@ -0,0 +1,247 @@ +/* + * Timer/counter unit support. + * + * Copyright (C) 2024 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include + +#include "tcu-common.h" + + + +// Register locations. + +enum Regs : unsigned +{ + Tcu_enable_status = 0x010, // TER + Tcu_set_enable = 0x014, // TESR + Tcu_clear_enable = 0x018, // TECR + Tcu_stop_status = 0x01c, // TSR + Tcu_set_stop = 0x02c, // TSSR + Tcu_clear_stop = 0x03c, // TSCR + Tcu_flag_status = 0x020, // TFR + Tcu_set_flag = 0x024, // TFSR + Tcu_clear_flag = 0x028, // TFCR + Tcu_mask_status = 0x030, // TMR + Tcu_set_mask = 0x034, // TMSR + Tcu_clear_mask = 0x038, // TMCR + + // Channel-related locations. + + Tcu_full_data_value_base = 0x040, // TDFRn + Tcu_half_data_value_base = 0x044, // TDHRn + Tcu_counter_base = 0x048, // TCNTn + Tcu_control_base = 0x04c, // TCRn + + // Block size/step/offset for the above register set. + + Tcu_data_block_offset = 0x010, +}; + +// Field definitions. + +// Enable/stop register bits. + +enum Channel_bit_numbers : unsigned +{ + Channel_wdt = 16, // WDTS only + + // Enable/stop/flag/mask bit numbers. + + Channel_ost = 15, // OSTEN/OSTS/OSTFLAG + Channel_tcu7 = 7, // TCEN7/STOP7/FFLAG7/SFLAG7 + Channel_tcu6 = 6, // TCEN6/STOP6/FFLAG6/SFLAG6 + Channel_tcu5 = 5, // TCEN5/STOP5/FFLAG5/SFLAG5 + Channel_tcu4 = 4, // TCEN4/STOP4/FFLAG4/SFLAG4 + Channel_tcu3 = 3, // TCEN3/STOP3/FFLAG3/SFLAG3 + Channel_tcu2 = 2, // TCEN2/STOP2/FFLAG2/SFLAG2 + Channel_tcu1 = 1, // TCEN1/STOP1/FFLAG1/SFLAG1 + Channel_tcu0 = 0, // TCEN0/STOP0/FFLAG0/SFLAG0 +}; + +// Counter data constraints. + +enum Data_masks : unsigned +{ + Data_mask = 0xffff, +}; + +enum Control_bits : unsigned +{ + Count_prescale_field_mask = 0x7, // PRESCALE + Count_prescale_max = 5, // CLK/1024 + Count_prescale_field_shift = 3, + + Count_clock_field_mask = 0x7, + Count_clock_exclk = 4, // EXT_EN + Count_clock_rtclk = 2, // RTC_EN + Count_clock_pclk = 1, // PCK_EN + Count_clock_field_shift = 0, +}; + + + +// Channel abstraction. + +Tcu_channel::Tcu_channel(l4_addr_t addr, uint8_t channel) +: _channel(channel) +{ + _regs = new Hw::Mmio_register_block<32>(addr); +} + +// Utility methods. +// NOTE: Also defined in the CPM abstraction, should be consolidated. + +uint32_t +Tcu_channel::get_field(uint32_t reg, uint32_t mask, uint8_t shift) +{ + return (_regs[reg] & (mask << shift)) >> shift; +} + +void +Tcu_channel::set_field(uint32_t reg, uint32_t mask, uint8_t shift, uint32_t value) +{ + _regs[reg] = (_regs[reg] & (~(mask << shift))) | ((mask & value) << shift); +} + +// Operation methods. + +uint8_t +Tcu_channel::get_clock() +{ + return (uint8_t) get_field(Tcu_control_base + _channel * Tcu_data_block_offset, + Count_clock_field_mask, Count_clock_field_shift); +} + +void +Tcu_channel::set_clock(uint8_t clock) +{ + + set_field(Tcu_control_base + _channel * Tcu_data_block_offset, + Count_clock_field_mask, Count_clock_field_shift, clock); +} + +uint32_t +Tcu_channel::get_prescale() +{ + return 1UL << (2 * get_field(Tcu_control_base + _channel * Tcu_data_block_offset, + Count_prescale_field_mask, Count_prescale_field_shift)); +} + +void +Tcu_channel::set_prescale(uint32_t prescale) +{ + // Obtain the log4 value for prescale. + + uint32_t value = (uint32_t) log2(prescale) / 2; + + set_field(Tcu_control_base + _channel * Tcu_data_block_offset, + Count_prescale_field_mask, Count_prescale_field_shift, + value > Count_prescale_max ? Count_prescale_max : value); +} + +void +Tcu_channel::disable() +{ + _regs[Tcu_clear_enable] = 1UL << _channel; +} + +void +Tcu_channel::enable() +{ + _regs[Tcu_set_enable] = 1UL << _channel; +} + +bool +Tcu_channel::is_enabled() +{ + return _regs[Tcu_enable_status] & (1UL << _channel); +} + +uint32_t +Tcu_channel::get_counter() +{ + return _regs[Tcu_counter_base + _channel * Tcu_data_block_offset] & Data_mask; +} + +void +Tcu_channel::set_counter(uint32_t value) +{ + _regs[Tcu_counter_base + _channel * Tcu_data_block_offset] = value & Data_mask; +} + +uint8_t +Tcu_channel::get_count_mode() +{ + return 0; +} + +void +Tcu_channel::set_count_mode(uint8_t mode) +{ + if (mode != 0) + throw -L4_EINVAL; +} + +uint32_t +Tcu_channel::get_full_data_value() +{ + return _regs[Tcu_full_data_value_base + _channel * Tcu_data_block_offset] & Data_mask; +} + +void +Tcu_channel::set_full_data_value(uint32_t value) +{ + _regs[Tcu_full_data_value_base + _channel * Tcu_data_block_offset] = value & Data_mask; +} + +uint32_t +Tcu_channel::get_half_data_value() +{ + return _regs[Tcu_half_data_value_base + _channel * Tcu_data_block_offset] & Data_mask; +} + +void +Tcu_channel::set_half_data_value(uint32_t value) +{ + _regs[Tcu_half_data_value_base + _channel * Tcu_data_block_offset] = value & Data_mask; +} + + + +// Peripheral abstraction. + +Tcu_chip::Tcu_chip(l4_addr_t start, l4_addr_t end) +: _start(start), _end(end) +{ +} + +// Obtain a channel object. + +Tcu_channel * +Tcu_chip::get_channel(uint8_t channel) +{ + if (channel < num_channels()) + return _get_channel(_start, channel); + else + throw -L4_EINVAL; +} diff -r 8a4ce6e2f4df -r 8e43685cd49b pkg/devices/lib/tcu/src/jz4780.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/tcu/src/jz4780.cc Thu Feb 01 01:16:04 2024 +0100 @@ -0,0 +1,134 @@ +/* + * Timer/counter unit support for the JZ4780. + * + * Copyright (C) 2024 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "tcu-jz4780.h" + + + +// Channel abstraction. + +Tcu_jz4780_channel::Tcu_jz4780_channel(l4_addr_t addr, uint8_t channel) +: Tcu_channel(addr, channel) +{ +} + + + +// Peripheral abstraction. + +Tcu_jz4780_chip::Tcu_jz4780_chip(l4_addr_t start, l4_addr_t end) +: Tcu_chip(start, end) +{ +} + +Tcu_channel *Tcu_jz4780_chip::_get_channel(l4_addr_t addr, uint8_t channel) +{ + return new Tcu_jz4780_channel(addr, channel); +} + + + +// C language interface functions. + +void *jz4780_tcu_init(l4_addr_t tcu_base, l4_addr_t tcu_base_end) +{ + return (void *) new Tcu_jz4780_chip(tcu_base, tcu_base_end); +} + +void *jz4780_tcu_get_channel(void *tcu, uint8_t channel) +{ + return static_cast(tcu)->get_channel(channel); +} + +void jz4780_tcu_disable(void *tcu_channel) +{ + static_cast(tcu_channel)->disable(); +} + +void jz4780_tcu_enable(void *tcu_channel) +{ + static_cast(tcu_channel)->enable(); +} + +int jz4780_tcu_is_enabled(void *tcu_channel) +{ + return static_cast(tcu_channel)->is_enabled(); +} + +uint8_t jz4780_tcu_get_clock(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_clock(); +} + +void jz4780_tcu_set_clock(void *tcu_channel, uint8_t clock) +{ + static_cast(tcu_channel)->set_clock(clock); +} + +uint32_t jz4780_tcu_get_prescale(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_prescale(); +} + +void jz4780_tcu_set_prescale(void *tcu_channel, uint32_t prescale) +{ + static_cast(tcu_channel)->set_prescale(prescale); +} + +uint32_t jz4780_tcu_get_counter(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_counter(); +} + +void jz4780_tcu_set_counter(void *tcu_channel, uint32_t value) +{ + static_cast(tcu_channel)->set_counter(value); +} + +uint8_t jz4780_tcu_get_count_mode(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_count_mode(); +} + +void jz4780_tcu_set_count_mode(void *tcu_channel, uint8_t mode) +{ + static_cast(tcu_channel)->set_count_mode(mode); +} + +uint32_t jz4780_tcu_get_full_data_value(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_full_data_value(); +} + +void jz4780_tcu_set_full_data_value(void *tcu_channel, uint32_t value) +{ + static_cast(tcu_channel)->set_full_data_value(value); +} + +uint32_t jz4780_tcu_get_half_data_value(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_half_data_value(); +} + +void jz4780_tcu_set_half_data_value(void *tcu_channel, uint32_t value) +{ + static_cast(tcu_channel)->set_full_data_value(value); +} diff -r 8a4ce6e2f4df -r 8e43685cd49b pkg/devices/lib/tcu/src/x1600.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/tcu/src/x1600.cc Thu Feb 01 01:16:04 2024 +0100 @@ -0,0 +1,294 @@ +/* + * Timer/counter unit support. + * + * Copyright (C) 2024 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "tcu-x1600.h" + + + +// Register locations. + +enum Regs : unsigned +{ + Tcu_control_base = 0x04c, // TCRn + + // Block size/step/offset for the above register set. + + Tcu_data_block_offset = 0x010, +}; + +enum Regs_x1600 : unsigned +{ + // X1600 channel-related locations. + + Tcu_store_flag_status = 0x200, // TSFR + Tcu_store_set_flag = 0x204, // TSFSR + Tcu_store_clear_flag = 0x208, // TSFCR + Tcu_store_mask_status = 0x210, // TSMR + Tcu_store_set_mask = 0x214, // TSMSR + Tcu_store_clear_mask = 0x218, // TSMCR + + Tcu_capture_control_base = 0x0c0, // TCRn + Tcu_capture_counter_base = 0x0e0, // CAPVRn + Tcu_filter_value_base = 0x1a0, // FIRVRn + Tcu_stored_counter_base = 0x220, // TSVRn + Tcu_stored_filter_counter_base = 0x240, // TSFVRn + + // Block size/step/offset for the above register set. + + Tcu_capture_block_offset = 0x004, + + // Limits. + + Tcu_capture_channel_max = 3, +}; + +// 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 +{ + Data_mask = 0xffff, +}; + +enum Control_bits_x1600 : unsigned +{ + Store_negative_edge_enable = 0x04000000, // STORE_NEG_EN + Store_positive_edge_enable = 0x02000000, // STORE_POS_EN + Store_enable = 0x01000000, // STORE_EN + + Count_mode_field_mask = 0x3, // COUNT_MODE + Count_mode_wrap_at_full_data = 0, + Count_mode_wrap_at_field_limit = 1, + Count_mode_stop_at_field_limit = 2, + Count_mode_field_shift = 22, + + Count_source_field_mask = 0x3f, + Count_gpio1_negative_edge_enable = 0x20, // GPIO1_NEG_EN + Count_gpio1_positive_edge_enable = 0x10, // GPIO1_POS_EN + Count_gpio0_negative_edge_enable = 0x08, // GPIO0_NEG_EN + Count_gpio0_positive_edge_enable = 0x04, // GPIO0_POS_EN + Count_clock_negative_edge_enable = 0x02, // CLK_NEG_EN + Count_clock_positive_edge_enable = 0x01, // CLK_POS_EN + Count_source_field_shift = 16, + + Count_shutdown = 0x00008000, // SHUTDOWN + Count_gate_polarity_low = 0x00000000, // GATE_POLA = 0 + Count_gate_polarity_high = 0x00004000, // GATE_POLA = 1 + Count_direction_polarity_low = 0x00000000, // DIRECTION_POLA = 0 + Count_direction_polarity_high = 0x00002000, // DIRECTION_POLA = 1 + + Count_gate_select_field_mask = 0x3, // GATE_SEL + Count_gate_select_none = 0, + Count_gate_select_clock = 1, + Count_gate_select_gpio0 = 2, + Count_gate_select_gpio1 = 3, + Count_gate_select_field_shift = 11, + + Count_direction_select_field_mask = 0x7, // DIRECTION_SEL + Count_direction_select_none = 0, + Count_direction_select_clock = 1, + Count_direction_select_gpio0 = 2, + Count_direction_select_gpio1 = 3, + Count_direction_select_gpio01 = 4, + Count_direction_select_field_shift = 8, + + Count_gpio1_enable = 0x00000080, // GPIO1_EN + Count_gpio0_enable = 0x00000040, // GPIO0_EN +}; + +enum Capture_bits : unsigned +{ + Capture_select_mask = 0x00070000, // CAPTURE_SEL + Capture_select_clock = 0x00000000, // CAPTURE_SEL = 0 + Capture_select_gpio0 = 0x00010000, // CAPTURE_SEL = 1 + Capture_select_gpio1 = 0x00020000, // CAPTURE_SEL = 2 + Capture_count_mask = 0x000000ff, // CAPTURE_NUM +}; + +enum Capture_value_bits : unsigned +{ + Capture_time_all_mask = 0xffff0000, // CAPTURE_ALL + Capture_time_high_mask = 0x0000ffff, // CAPTURE_HEIGHT (sic) +}; + +enum Filter_value_bits : unsigned +{ + Filter_gpio1_value_mask = 0x03ff0000, // FIL_B + Filter_gpio0_value_mask = 0x000003ff, // FIL_A +}; + +enum Store_filter_bits : unsigned +{ + Store_filter_value_mask = 0x3ff, // STR_FIL +}; + + + +// Channel abstraction. + +Tcu_x1600_channel::Tcu_x1600_channel(l4_addr_t addr, uint8_t channel) +: Tcu_channel(addr, channel) +{ +} + +// Operation methods. + +void +Tcu_x1600_channel::enable() +{ + // NOTE: Use a positive clock edge for the timer event by default. + + set_field(Tcu_control_base + _channel * Tcu_data_block_offset, + Count_source_field_mask, Count_source_field_shift, + Count_clock_positive_edge_enable); + + Tcu_channel::enable(); +} + +uint8_t +Tcu_x1600_channel::get_count_mode() +{ + return get_field(Tcu_control_base + _channel * Tcu_data_block_offset, + Count_mode_field_mask, Count_mode_field_shift); +} + +void +Tcu_x1600_channel::set_count_mode(uint8_t mode) +{ + set_field(Tcu_control_base + _channel * Tcu_data_block_offset, + Count_mode_field_mask, Count_mode_field_shift, mode); +} + + + +// Peripheral abstraction. + +Tcu_x1600_chip::Tcu_x1600_chip(l4_addr_t start, l4_addr_t end) +: Tcu_chip(start, end) +{ +} + +Tcu_channel *Tcu_x1600_chip::_get_channel(l4_addr_t addr, uint8_t channel) +{ + return new Tcu_x1600_channel(addr, channel); +} + + + +// C language interface functions. + +void *x1600_tcu_init(l4_addr_t tcu_base, l4_addr_t tcu_base_end) +{ + return (void *) new Tcu_x1600_chip(tcu_base, tcu_base_end); +} + +void *x1600_tcu_get_channel(void *tcu, uint8_t channel) +{ + return static_cast(tcu)->get_channel(channel); +} + +void x1600_tcu_disable(void *tcu_channel) +{ + static_cast(tcu_channel)->disable(); +} + +void x1600_tcu_enable(void *tcu_channel) +{ + static_cast(tcu_channel)->enable(); +} + +int x1600_tcu_is_enabled(void *tcu_channel) +{ + return static_cast(tcu_channel)->is_enabled(); +} + +uint8_t x1600_tcu_get_clock(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_clock(); +} + +void x1600_tcu_set_clock(void *tcu_channel, uint8_t clock) +{ + static_cast(tcu_channel)->set_clock(clock); +} + +uint32_t x1600_tcu_get_prescale(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_prescale(); +} + +void x1600_tcu_set_prescale(void *tcu_channel, uint32_t prescale) +{ + static_cast(tcu_channel)->set_prescale(prescale); +} + +uint32_t x1600_tcu_get_counter(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_counter(); +} + +void x1600_tcu_set_counter(void *tcu_channel, uint32_t value) +{ + static_cast(tcu_channel)->set_counter(value); +} + +uint8_t x1600_tcu_get_count_mode(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_count_mode(); +} + +void x1600_tcu_set_count_mode(void *tcu_channel, uint8_t mode) +{ + static_cast(tcu_channel)->set_count_mode(mode); +} + +uint32_t x1600_tcu_get_full_data_value(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_full_data_value(); +} + +void x1600_tcu_set_full_data_value(void *tcu_channel, uint32_t value) +{ + static_cast(tcu_channel)->set_full_data_value(value); +} + +uint32_t x1600_tcu_get_half_data_value(void *tcu_channel) +{ + return static_cast(tcu_channel)->get_half_data_value(); +} + +void x1600_tcu_set_half_data_value(void *tcu_channel, uint32_t value) +{ + static_cast(tcu_channel)->set_full_data_value(value); +}