# HG changeset patch # User Paul Boddie # Date 1714779114 -7200 # Node ID 16d7ccdedcf0d309db64954c5d006e24d84e00e4 # Parent 672a2ee47bfde0c38fc1dd36f708fe06b2b0ae38 Introduced specialisations of the RTC peripheral functionality along with the mechanism providing generic access to such functionality. diff -r 672a2ee47bfd -r 16d7ccdedcf0 pkg/devices/lib/rtc/include/rtc-defs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/rtc/include/rtc-defs.h Sat May 04 01:31:54 2024 +0200 @@ -0,0 +1,125 @@ +/* + * RTC (real-time clock) support for various devices. + * + * Copyright (C) 2023, 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 + +#ifdef __cplusplus + +// Register locations. + +enum Regs : unsigned +{ + Rtc_control = 0x000, // RTCCR + Rtc_seconds = 0x004, // RTCSR + Rtc_alarm_seconds = 0x008, // RTCSAR + Rtc_regulator = 0x00c, // RTCGR + + Hibernate_control = 0x020, // HCR + Hibernate_wakeup_filter_counter = 0x024, // HWFCR + Hibernate_reset_counter = 0x028, // HRCR + Hibernate_wakeup_control = 0x02c, // HWCR + Hibernate_wakeup_status = 0x030, // HWRSR + Hibernate_scratch_pattern = 0x034, // HSPR + Hibernate_write_enable_pattern = 0x03c, // WENR + Hibernate_wakeup_pin_configure = 0x048, // WKUPPINCR +}; + +// Field definitions. + +enum Control_bits : unsigned +{ + Control_write_ready = 0x80, // WRDY + Control_1Hz = 0x40, // 1HZ + Control_1Hz_irq_enable = 0x20, // 1HZIE + Control_alarm = 0x10, // AF + Control_alarm_irq_enable = 0x08, // AIE + Control_alarm_enable = 0x04, // AE + Control_external_divided = 0x02, // SELEXC (JZ4780) + Control_rtc_enable = 0x01, // RTCE +}; + +enum Regulator_bits : unsigned +{ + Regulator_lock = 0x80000000, // LOCK + Regulator_adjust_count_mask = 0x03ff0000, // ADJC + Regulator_1Hz_cycle_count_mask = 0x0000ffff, // NC1HZ +}; + +enum Regulator_limits : unsigned +{ + Regulator_adjust_count_limit = 0x03ff, // ADJC + Regulator_1Hz_cycle_count_limit = 0xffff, // NC1HZ +}; + +enum Regulator_shifts : unsigned +{ + Regulator_adjust_count_shift = 16, // ADJC + Regulator_1Hz_cycle_count_shift = 0, // NC1HZ +}; + +enum Hibernate_control_bits : unsigned +{ + Hibernate_power_down = 0x01, // PD +}; + +enum Hibernate_wakeup_filter_counter_bits : unsigned +{ + Wakeup_minimum_time_mask = 0xffe0, // HWFCR +}; + +enum Hibernate_reset_counter_bits : unsigned +{ + Reset_assert_time_mask = 0x7800, // HRCR +}; + +enum Hibernate_wakeup_control_bits : unsigned +{ + Power_detect_enable_mask = 0xfffffff8, // EPDET + Rtc_alarm_wakeup_enable = 0x00000001, // EALM +}; + +enum Hibernate_wakeup_status_bits : unsigned +{ + Accident_power_down = 0x0100, // APD + Hibernate_reset = 0x0020, // HR + Pad_pin_reset = 0x0010, // PPR + Wakeup_pin_status = 0x0002, // PIN + Rtc_alarm_status = 0x0001, // ALM +}; + +enum Hibernate_write_enable_pattern_bits : unsigned +{ + Write_enable_status = 0x80000000, // WEN + Write_enable_pattern_mask = 0x0000ffff, // WENPAT + Write_enable_pattern = 0x0000a55a, // WENPAT +}; + +enum Hibernate_wakeup_pin_configure_bits : unsigned +{ + Rtc_oscillator_test_enable = 0x00080000, // OSC_TE + Oscillator_xtclk_rtclk = 0x00040000, // OSC_RETON + Oscillator_xtclk_low = 0x00000000, // OSC_RETON + Rtc_internal_oscillator_enable = 0x00010000, // OSC_EN + Wakeup_pin_extended_press_mask = 0x000000f0, // P_JUD_LEN + Wakeup_pin_extended_press_enable = 0x0000000f, // P_RST_LEN +}; + +#endif /* __cplusplus */ diff -r 672a2ee47bfd -r 16d7ccdedcf0 pkg/devices/lib/rtc/include/rtc-generic.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/rtc/include/rtc-generic.h Sat May 04 01:31:54 2024 +0200 @@ -0,0 +1,88 @@ +/* + * RTC (real-time clock) support for various devices. + * + * Copyright (C) 2023, 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 +#include +#include + +class Rtc_chip +{ +protected: + Cpm_chip *_cpm; + Hw::Register_block<32> _regs; + + /* Utility methods. */ + + uint32_t read_checked(unsigned reg); + void wait(); + void write_enable(); + void _power_down(); + + /* Device-specific methods. */ + + virtual void _pre_power_down(); + +public: + explicit Rtc_chip(l4_addr_t addr, Cpm_chip *cpm); + + virtual enum Clock_identifiers get_clock(); + + void disable(); + + void enable(); + + void alarm_disable(); + + void alarm_enable(); + + void wakeup_alarm_disable(); + + void wakeup_alarm_enable(); + + uint32_t get_seconds(); + + void set_seconds(uint32_t seconds); + + uint32_t get_alarm_seconds(); + + void set_alarm_seconds(uint32_t seconds); + + void set_regulator(uint32_t base, uint32_t adjustment); + + void hibernate(); + + void power_down(); +}; + +// Generic access to the RTC abstraction. + +Rtc_chip *new_rtc_chip(const char *name, l4_addr_t start, Cpm_chip *cpm); + +#endif /* __cplusplus */ diff -r 672a2ee47bfd -r 16d7ccdedcf0 pkg/devices/lib/rtc/include/rtc-jz4780.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/rtc/include/rtc-jz4780.h Sat May 04 01:31:54 2024 +0200 @@ -0,0 +1,79 @@ +/* + * RTC (real-time clock) support for the JZ4780. + * + * Copyright (C) 2023, 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 Rtc_jz4780_chip : public Rtc_chip +{ +public: + explicit Rtc_jz4780_chip(l4_addr_t addr, Cpm_chip *cpm); +}; + +Rtc_chip *jz4780_rtc_chip(l4_addr_t rtc_base, Cpm_chip *cpm); + +#endif /* __cplusplus */ + + + +/* C language interface. */ + +EXTERN_C_BEGIN + +void *jz4780_rtc_init(l4_addr_t rtc_base, void *cpm); + +enum Clock_identifiers jz4780_rtc_get_clock(void *rtc); + +void jz4780_rtc_disable(void *rtc); + +void jz4780_rtc_enable(void *rtc); + +void jz4780_rtc_alarm_disable(void *rtc); + +void jz4780_rtc_alarm_enable(void *rtc); + +void jz4780_rtc_wakeup_alarm_disable(void *rtc); + +void jz4780_rtc_wakeup_alarm_enable(void *rtc); + +uint32_t jz4780_rtc_get_seconds(void *rtc); + +void jz4780_rtc_set_seconds(void *rtc, uint32_t seconds); + +uint32_t jz4780_rtc_get_alarm_seconds(void *rtc); + +void jz4780_rtc_set_alarm_seconds(void *rtc, uint32_t seconds); + +void jz4780_rtc_set_regulator(void *rtc, uint32_t base, uint32_t adjustment); + +void jz4780_rtc_hibernate(void *rtc); + +void jz4780_rtc_power_down(void *rtc); + +EXTERN_C_END diff -r 672a2ee47bfd -r 16d7ccdedcf0 pkg/devices/lib/rtc/include/rtc-x1600.h --- a/pkg/devices/lib/rtc/include/rtc-x1600.h Sat May 04 01:30:06 2024 +0200 +++ b/pkg/devices/lib/rtc/include/rtc-x1600.h Sat May 04 01:31:54 2024 +0200 @@ -1,7 +1,7 @@ /* * RTC (real-time clock) support for the X1600. * - * Copyright (C) 2023 Paul Boddie + * Copyright (C) 2023, 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 @@ -28,53 +28,18 @@ #ifdef __cplusplus -#include -#include +#include -class Rtc_x1600_chip +class Rtc_x1600_chip : public Rtc_chip { protected: - /* Only use the CPM for the X1600, not other chips. */ - - Cpm_x1600_chip *_cpm; - Hw::Register_block<32> _regs; - - /* Utility methods. */ - - uint32_t read_checked(unsigned reg); - void wait(); - void write_enable(); - void _power_down(); + void _pre_power_down(); public: - explicit Rtc_x1600_chip(l4_addr_t addr, Cpm_x1600_chip *cpm = NULL); - - void disable(); - - void enable(); - - void alarm_disable(); - - void alarm_enable(); - - void wakeup_alarm_disable(); - - void wakeup_alarm_enable(); + explicit Rtc_x1600_chip(l4_addr_t addr, Cpm_chip *cpm = NULL); +}; - uint32_t get_seconds(); - - void set_seconds(uint32_t seconds); - - uint32_t get_alarm_seconds(); - - void set_alarm_seconds(uint32_t seconds); - - void set_regulator(uint32_t base, uint32_t adjustment); - - void hibernate(); - - void power_down(); -}; +Rtc_chip *x1600_rtc_chip(l4_addr_t rtc_base, Cpm_chip *cpm); #endif /* __cplusplus */ @@ -86,6 +51,8 @@ void *x1600_rtc_init(l4_addr_t rtc_base, void *cpm); +enum Clock_identifiers x1600_rtc_get_clock(void *rtc); + void x1600_rtc_disable(void *rtc); void x1600_rtc_enable(void *rtc); diff -r 672a2ee47bfd -r 16d7ccdedcf0 pkg/devices/lib/rtc/src/Makefile --- a/pkg/devices/lib/rtc/src/Makefile Sat May 04 01:30:06 2024 +0200 +++ b/pkg/devices/lib/rtc/src/Makefile Sat May 04 01:31:54 2024 +0200 @@ -4,7 +4,7 @@ TARGET = librtc.o.a librtc.o.so PC_FILENAME := libdrivers-rtc -SRC_CC := x1600.cc +SRC_CC := common.cc generic.cc jz4780.cc x1600.cc PRIVATE_INCDIR += $(PKGDIR)/lib/rtc/include diff -r 672a2ee47bfd -r 16d7ccdedcf0 pkg/devices/lib/rtc/src/common.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/rtc/src/common.cc Sat May 04 01:31:54 2024 +0200 @@ -0,0 +1,198 @@ +/* + * Real-time clock support. + * + * Copyright (C) 2023, 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 "rtc-defs.h" +#include "rtc-generic.h" + + + +// Peripheral abstraction. + +Rtc_chip::Rtc_chip(l4_addr_t addr, Cpm_chip *cpm) +: _cpm(cpm) +{ + _regs = new Hw::Mmio_register_block<32>(addr); + + // Reset time regulation, in case it is completely scrambled. + // NOTE: Using 32768 cycles for a 1Hz signal. + + set_regulator(32767, 0); +} + +enum Clock_identifiers +Rtc_chip::get_clock() +{ + return Clock_rtc; +} + +uint32_t +Rtc_chip::read_checked(unsigned reg) +{ + uint32_t last, current; + + wait(); + last = _regs[reg]; + + while (1) + { + wait(); + current = _regs[reg]; + + if (current == last) + return current; + else + last = current; + } +} + +void +Rtc_chip::wait() +{ + while (!(_regs[Rtc_control] & Control_write_ready)); +} + +void +Rtc_chip::write_enable() +{ + wait(); + _regs[Hibernate_write_enable_pattern] = Write_enable_pattern; + + while (!(_regs[Hibernate_write_enable_pattern] & Write_enable_status)); + + wait(); +} + +void +Rtc_chip::disable() +{ + write_enable(); + _regs[Rtc_control] = _regs[Rtc_control] & ~Control_rtc_enable; +} + +void +Rtc_chip::enable() +{ + write_enable(); + _regs[Rtc_control] = _regs[Rtc_control] | Control_rtc_enable; +} + +void +Rtc_chip::alarm_disable() +{ + write_enable(); + _regs[Rtc_control] = _regs[Rtc_control] & ~Control_alarm_enable; +} + +void +Rtc_chip::alarm_enable() +{ + write_enable(); + _regs[Rtc_control] = (_regs[Rtc_control] & ~Control_alarm) | Control_alarm_enable; +} + +void +Rtc_chip::wakeup_alarm_disable() +{ + write_enable(); + _regs[Hibernate_wakeup_control] = _regs[Hibernate_wakeup_control] & ~Rtc_alarm_wakeup_enable; +} + +void +Rtc_chip::wakeup_alarm_enable() +{ + write_enable(); + _regs[Hibernate_wakeup_control] = _regs[Hibernate_wakeup_control] | Rtc_alarm_wakeup_enable; +} + +uint32_t +Rtc_chip::get_seconds() +{ + return read_checked(Rtc_seconds); +} + +void +Rtc_chip::set_seconds(uint32_t seconds) +{ + write_enable(); + _regs[Rtc_seconds] = seconds; +} + +uint32_t +Rtc_chip::get_alarm_seconds() +{ + return read_checked(Rtc_alarm_seconds); +} + +void +Rtc_chip::set_alarm_seconds(uint32_t seconds) +{ + write_enable(); + _regs[Rtc_alarm_seconds] = seconds; +} + +void +Rtc_chip::set_regulator(uint32_t base, uint32_t adjustment) +{ + base = base ? base - 1 : 0; + adjustment = adjustment ? adjustment - 1 : 0; + + if (base > Regulator_1Hz_cycle_count_limit) + base = Regulator_1Hz_cycle_count_limit; + + if (adjustment > Regulator_adjust_count_limit) + adjustment = Regulator_adjust_count_limit; + + write_enable(); + _regs[Rtc_regulator] = (base << Regulator_1Hz_cycle_count_shift) | + (adjustment << Regulator_adjust_count_shift); +} + +// Device-specific method. + +void +Rtc_chip::_pre_power_down() +{ +} + +void +Rtc_chip::_power_down() +{ + _pre_power_down(); + + write_enable(); + _regs[Hibernate_control] = _regs[Hibernate_control] | Hibernate_power_down; +} + +void +Rtc_chip::hibernate() +{ + alarm_enable(); + wakeup_alarm_enable(); + _power_down(); +} + +void +Rtc_chip::power_down() +{ + wakeup_alarm_disable(); + _power_down(); +} diff -r 672a2ee47bfd -r 16d7ccdedcf0 pkg/devices/lib/rtc/src/generic.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/rtc/src/generic.cc Sat May 04 01:31:54 2024 +0200 @@ -0,0 +1,56 @@ +/* + * Generic access to real-time clock functionality. + * + * 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 "rtc-generic.h" + +/* Function declarations reproduced here to avoid clock identifier conflicts in + the chip-specific headers. */ + +//extern Rtc_chip *jz4730_rtc_chip(l4_addr_t, Cpm_chip *); +//extern Rtc_chip *jz4740_rtc_chip(l4_addr_t, Cpm_chip *); +extern Rtc_chip *jz4780_rtc_chip(l4_addr_t, Cpm_chip *); +extern Rtc_chip *x1600_rtc_chip(l4_addr_t, Cpm_chip *); + +struct rtc_function +{ + const char *name; + Rtc_chip *(*function)(l4_addr_t, Cpm_chip *); +}; + +static struct rtc_function functions[] = { + //{"jz4730", jz4730_rtc_chip}, + //{"jz4740", jz4740_rtc_chip}, + {"jz4780", jz4780_rtc_chip}, + {"x1600", x1600_rtc_chip}, + {NULL, NULL} +}; + +Rtc_chip *new_rtc_chip(const char *name, l4_addr_t start, Cpm_chip *cpm) +{ + for (struct rtc_function *f = functions; f->name != NULL; f++) + { + if (!strcmp(name, f->name)) + return f->function(start, cpm); + } + + return NULL; +} diff -r 672a2ee47bfd -r 16d7ccdedcf0 pkg/devices/lib/rtc/src/jz4780.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/devices/lib/rtc/src/jz4780.cc Sat May 04 01:31:54 2024 +0200 @@ -0,0 +1,107 @@ +/* + * Real-time clock support. + * + * Copyright (C) 2023, 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 "rtc-jz4780.h" +#include "rtc-defs.h" + + + +// Peripheral abstraction. + +Rtc_jz4780_chip::Rtc_jz4780_chip(l4_addr_t addr, Cpm_chip *cpm) +: Rtc_chip(addr, cpm) +{ +} + +Rtc_chip *jz4780_rtc_chip(l4_addr_t rtc_base, Cpm_chip *cpm) +{ + return new Rtc_jz4780_chip(rtc_base, cpm); +} + + + +// C language interface functions. + +void +*jz4780_rtc_init(l4_addr_t rtc_base, void *cpm) +{ + return (void *) jz4780_rtc_chip(rtc_base, static_cast(cpm)); +} + +enum Clock_identifiers jz4780_rtc_get_clock(void *rtc) +{ + return static_cast(rtc)->get_clock(); +} + +void jz4780_rtc_disable(void *rtc) +{ + static_cast(rtc)->disable(); +} + +void jz4780_rtc_enable(void *rtc) +{ + static_cast(rtc)->enable(); +} + +void jz4780_rtc_alarm_disable(void *rtc) +{ + static_cast(rtc)->alarm_disable(); +} + +void jz4780_rtc_alarm_enable(void *rtc) +{ + static_cast(rtc)->alarm_enable(); +} + +uint32_t jz4780_rtc_get_seconds(void *rtc) +{ + return static_cast(rtc)->get_seconds(); +} + +void jz4780_rtc_set_seconds(void *rtc, uint32_t seconds) +{ + static_cast(rtc)->set_seconds(seconds); +} + +uint32_t jz4780_rtc_get_alarm_seconds(void *rtc) +{ + return static_cast(rtc)->get_alarm_seconds(); +} + +void jz4780_rtc_set_alarm_seconds(void *rtc, uint32_t seconds) +{ + static_cast(rtc)->set_alarm_seconds(seconds); +} + +void jz4780_rtc_set_regulator(void *rtc, uint32_t base, uint32_t adjustment) +{ + static_cast(rtc)->set_regulator(base, adjustment); +} + +void jz4780_rtc_hibernate(void *rtc) +{ + static_cast(rtc)->hibernate(); +} + +void jz4780_rtc_power_down(void *rtc) +{ + static_cast(rtc)->power_down(); +} diff -r 672a2ee47bfd -r 16d7ccdedcf0 pkg/devices/lib/rtc/src/x1600.cc --- a/pkg/devices/lib/rtc/src/x1600.cc Sat May 04 01:30:06 2024 +0200 +++ b/pkg/devices/lib/rtc/src/x1600.cc Sat May 04 01:31:54 2024 +0200 @@ -1,7 +1,7 @@ /* * Real-time clock support. * - * Copyright (C) 2023 Paul Boddie + * Copyright (C) 2023, 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 @@ -19,267 +19,31 @@ * Boston, MA 02110-1301, USA */ -#include #include "rtc-x1600.h" - - - -// Register locations. - -enum Regs : unsigned -{ - Rtc_control = 0x000, // RTCCR - Rtc_seconds = 0x004, // RTCSR - Rtc_alarm_seconds = 0x008, // RTCSAR - Rtc_regulator = 0x00c, // RTCGR - - Hibernate_control = 0x020, // HCR - Hibernate_wakeup_filter_counter = 0x024, // HWFCR - Hibernate_reset_counter = 0x028, // HRCR - Hibernate_wakeup_control = 0x02c, // HWCR - Hibernate_wakeup_status = 0x030, // HWRSR - Hibernate_scratch_pattern = 0x034, // HSPR - Hibernate_write_enable_pattern = 0x03c, // WENR - Hibernate_wakeup_pin_configure = 0x048, // WKUPPINCR -}; - -// Field definitions. - -enum Control_bits : unsigned -{ - Control_write_ready = 0x80, // WRDY - Control_1Hz = 0x40, // 1HZ - Control_1Hz_irq_enable = 0x20, // 1HZIE - Control_alarm = 0x10, // AF - Control_alarm_irq_enable = 0x08, // AIE - Control_alarm_enable = 0x04, // AE - Control_rtc_enable = 0x01, // RTCE -}; - -enum Regulator_bits : unsigned -{ - Regulator_lock = 0x80000000, // LOCK - Regulator_adjust_count_mask = 0x03ff0000, // ADJC - Regulator_1Hz_cycle_count_mask = 0x0000ffff, // NC1HZ -}; - -enum Regulator_limits : unsigned -{ - Regulator_adjust_count_limit = 0x03ff, // ADJC - Regulator_1Hz_cycle_count_limit = 0xffff, // NC1HZ -}; - -enum Regulator_shifts : unsigned -{ - Regulator_adjust_count_shift = 16, // ADJC - Regulator_1Hz_cycle_count_shift = 0, // NC1HZ -}; - -enum Hibernate_control_bits : unsigned -{ - Hibernate_power_down = 0x01, // PD -}; - -enum Hibernate_wakeup_filter_counter_bits : unsigned -{ - Wakeup_minimum_time_mask = 0xffe0, // HWFCR -}; - -enum Hibernate_reset_counter_bits : unsigned -{ - Reset_assert_time_mask = 0x7800, // HRCR -}; - -enum Hibernate_wakeup_control_bits : unsigned -{ - Power_detect_enable_mask = 0xfffffff8, // EPDET - Rtc_alarm_wakeup_enable = 0x00000001, // EALM -}; - -enum Hibernate_wakeup_status_bits : unsigned -{ - Accident_power_down = 0x0100, // APD - Hibernate_reset = 0x0020, // HR - Pad_pin_reset = 0x0010, // PPR - Wakeup_pin_status = 0x0002, // PIN - Rtc_alarm_status = 0x0001, // ALM -}; - -enum Hibernate_write_enable_pattern_bits : unsigned -{ - Write_enable_status = 0x80000000, // WEN - Write_enable_pattern_mask = 0x0000ffff, // WENPAT - Write_enable_pattern = 0x0000a55a, // WENPAT -}; - -enum Hibernate_wakeup_pin_configure_bits : unsigned -{ - Rtc_oscillator_test_enable = 0x00080000, // OSC_TE - Oscillator_xtclk_rtclk = 0x00040000, // OSC_RETON - Oscillator_xtclk_low = 0x00000000, // OSC_RETON - Rtc_internal_oscillator_enable = 0x00010000, // OSC_EN - Wakeup_pin_extended_press_mask = 0x000000f0, // P_JUD_LEN - Wakeup_pin_extended_press_enable = 0x0000000f, // P_RST_LEN -}; +#include "rtc-defs.h" // Peripheral abstraction. -Rtc_x1600_chip::Rtc_x1600_chip(l4_addr_t addr, Cpm_x1600_chip *cpm) -: _cpm(cpm) -{ - _regs = new Hw::Mmio_register_block<32>(addr); -} - -uint32_t -Rtc_x1600_chip::read_checked(unsigned reg) -{ - uint32_t last, current; - - wait(); - last = _regs[reg]; - - while (1) - { - wait(); - current = _regs[reg]; - - if (current == last) - return current; - else - last = current; - } -} - -void -Rtc_x1600_chip::wait() +Rtc_x1600_chip::Rtc_x1600_chip(l4_addr_t addr, Cpm_chip *cpm) +: Rtc_chip(addr, cpm) { - while (!(_regs[Rtc_control] & Control_write_ready)); -} - -void -Rtc_x1600_chip::write_enable() -{ - wait(); - _regs[Hibernate_write_enable_pattern] = Write_enable_pattern; - - while (!(_regs[Hibernate_write_enable_pattern] & Write_enable_status)); - - wait(); -} - -void -Rtc_x1600_chip::disable() -{ - write_enable(); - _regs[Rtc_control] = _regs[Rtc_control] & ~Control_rtc_enable; -} - -void -Rtc_x1600_chip::enable() -{ - write_enable(); - _regs[Rtc_control] = _regs[Rtc_control] | Control_rtc_enable; -} - -void -Rtc_x1600_chip::alarm_disable() -{ - write_enable(); - _regs[Rtc_control] = _regs[Rtc_control] & ~Control_alarm_enable; } void -Rtc_x1600_chip::alarm_enable() -{ - write_enable(); - _regs[Rtc_control] = (_regs[Rtc_control] & ~Control_alarm) | Control_alarm_enable; -} - -void -Rtc_x1600_chip::wakeup_alarm_disable() -{ - write_enable(); - _regs[Hibernate_wakeup_control] = _regs[Hibernate_wakeup_control] & ~Rtc_alarm_wakeup_enable; -} - -void -Rtc_x1600_chip::wakeup_alarm_enable() -{ - write_enable(); - _regs[Hibernate_wakeup_control] = _regs[Hibernate_wakeup_control] | Rtc_alarm_wakeup_enable; -} - -uint32_t -Rtc_x1600_chip::get_seconds() -{ - return read_checked(Rtc_seconds); -} - -void -Rtc_x1600_chip::set_seconds(uint32_t seconds) -{ - write_enable(); - _regs[Rtc_seconds] = seconds; -} - -uint32_t -Rtc_x1600_chip::get_alarm_seconds() -{ - return read_checked(Rtc_alarm_seconds); -} - -void -Rtc_x1600_chip::set_alarm_seconds(uint32_t seconds) -{ - write_enable(); - _regs[Rtc_alarm_seconds] = seconds; -} - -void -Rtc_x1600_chip::set_regulator(uint32_t base, uint32_t adjustment) -{ - base = base ? base - 1 : 0; - adjustment = adjustment ? adjustment - 1 : 0; - - if (base > Regulator_1Hz_cycle_count_limit) - base = Regulator_1Hz_cycle_count_limit; - - if (adjustment > Regulator_adjust_count_limit) - adjustment = Regulator_adjust_count_limit; - - write_enable(); - _regs[Rtc_regulator] = (base << Regulator_1Hz_cycle_count_shift) | - (adjustment << Regulator_adjust_count_shift); -} - -void -Rtc_x1600_chip::_power_down() +Rtc_x1600_chip::_pre_power_down() { /* Set CPU frequency to L2 cache frequency before powering down. This is apparently necessary according to the X1600 manual. */ if (_cpm != NULL) _cpm->set_frequency(Clock_cpu, _cpm->get_frequency(Clock_l2cache)); - - write_enable(); - _regs[Hibernate_control] = _regs[Hibernate_control] | Hibernate_power_down; } -void -Rtc_x1600_chip::hibernate() +Rtc_chip *x1600_rtc_chip(l4_addr_t rtc_base, Cpm_chip *cpm) { - alarm_enable(); - wakeup_alarm_enable(); - _power_down(); -} - -void -Rtc_x1600_chip::power_down() -{ - wakeup_alarm_disable(); - _power_down(); + return new Rtc_x1600_chip(rtc_base, cpm); } @@ -289,60 +53,65 @@ void *x1600_rtc_init(l4_addr_t rtc_base, void *cpm) { - return (void *) new Rtc_x1600_chip(rtc_base, static_cast(cpm)); + return (void *) x1600_rtc_chip(rtc_base, static_cast(cpm)); +} + +enum Clock_identifiers x1600_rtc_get_clock(void *rtc) +{ + return static_cast(rtc)->get_clock(); } void x1600_rtc_disable(void *rtc) { - static_cast(rtc)->disable(); + static_cast(rtc)->disable(); } void x1600_rtc_enable(void *rtc) { - static_cast(rtc)->enable(); + static_cast(rtc)->enable(); } void x1600_rtc_alarm_disable(void *rtc) { - static_cast(rtc)->alarm_disable(); + static_cast(rtc)->alarm_disable(); } void x1600_rtc_alarm_enable(void *rtc) { - static_cast(rtc)->alarm_enable(); + static_cast(rtc)->alarm_enable(); } uint32_t x1600_rtc_get_seconds(void *rtc) { - return static_cast(rtc)->get_seconds(); + return static_cast(rtc)->get_seconds(); } void x1600_rtc_set_seconds(void *rtc, uint32_t seconds) { - static_cast(rtc)->set_seconds(seconds); + static_cast(rtc)->set_seconds(seconds); } uint32_t x1600_rtc_get_alarm_seconds(void *rtc) { - return static_cast(rtc)->get_alarm_seconds(); + return static_cast(rtc)->get_alarm_seconds(); } void x1600_rtc_set_alarm_seconds(void *rtc, uint32_t seconds) { - static_cast(rtc)->set_alarm_seconds(seconds); + static_cast(rtc)->set_alarm_seconds(seconds); } void x1600_rtc_set_regulator(void *rtc, uint32_t base, uint32_t adjustment) { - static_cast(rtc)->set_regulator(base, adjustment); + static_cast(rtc)->set_regulator(base, adjustment); } void x1600_rtc_hibernate(void *rtc) { - static_cast(rtc)->hibernate(); + static_cast(rtc)->hibernate(); } void x1600_rtc_power_down(void *rtc) { - static_cast(rtc)->power_down(); + static_cast(rtc)->power_down(); } diff -r 672a2ee47bfd -r 16d7ccdedcf0 pkg/landfall-examples/hw_info/common.h --- a/pkg/landfall-examples/hw_info/common.h Sat May 04 01:30:06 2024 +0200 +++ b/pkg/landfall-examples/hw_info/common.h Sat May 04 01:31:54 2024 +0200 @@ -189,6 +189,8 @@ void *rtc_init(l4_addr_t start, void *cpm); +enum Clock_identifiers rtc_get_clock(void *rtc); + void rtc_disable(void *rtc); void rtc_enable(void *rtc); diff -r 672a2ee47bfd -r 16d7ccdedcf0 pkg/landfall-examples/hw_info/hw_info.c --- a/pkg/landfall-examples/hw_info/hw_info.c Sat May 04 01:30:06 2024 +0200 +++ b/pkg/landfall-examples/hw_info/hw_info.c Sat May 04 01:31:54 2024 +0200 @@ -356,7 +356,7 @@ const char *source_id = clock_id(cpm_get_source_clock(cpm, clocks[i].clock)); int num_parameters = cpm_get_parameters(cpm, clocks[i].clock, parameters); - for (int p = 0, pos = 0; p < num_parameters; p++) + for (int p = 0, pos = 0; (p < num_parameters) && (p < 4); p++) { int result = sprintf(parameter_str + pos, "%-7d ", parameters[p]); if (result < 0) @@ -1326,6 +1326,13 @@ /* RTC operations. */ +static void rtc_clock_frequency(void *rtc, void *cpm) +{ + enum Clock_identifiers clock = rtc_get_clock(rtc); + + printf("RTC frequency: %lld\n", cpm_get_frequency(cpm, clock)); +} + static void rtc_reset(void *rtc, void *cpm) { unsigned int seconds; @@ -1333,10 +1340,9 @@ if (!read_number("Seconds", &seconds)) return; - /* NOTE: Assuming EXCLK/512 as RTC source. */ - + enum Clock_identifiers clock = rtc_get_clock(rtc); uint32_t rtc_seconds = rtc_get_seconds(rtc); - uint32_t value = seconds * cpm_get_frequency(cpm, Clock_external) / 512; + uint32_t value = seconds * cpm_get_frequency(cpm, clock); rtc_alarm_disable(rtc); rtc_set_alarm_seconds(rtc, rtc_seconds + value); @@ -1871,7 +1877,9 @@ if ((token = read_token(NULL)) != NULL) { - if (!strcmp(token, "d") || !strcmp(token, "disable")) + if (!strcmp(token, "c") || !strcmp(token, "clock-frequency")) + rtc_clock_frequency(rtc, cpm); + else if (!strcmp(token, "d") || !strcmp(token, "disable")) rtc_disable(rtc); else if (!strcmp(token, "e") || !strcmp(token, "enable")) rtc_enable(rtc); @@ -1888,10 +1896,10 @@ else if (!strcmp(token, "sa") || !strcmp(token, "set-alarm")) _rtc_set_seconds(rtc, 1); else - printf("rtc disable | enable | get | get-alarm | power-down | reset | set | set-alarm\n"); + printf("rtc clock-frequency | disable | enable | get | get-alarm | power-down | reset | set | set-alarm\n"); } else - printf("rtc disable | enable | get | get-alarm | power-down | reset | set | set-alarm\n"); + printf("rtc clock-frequency | disable | enable | get | get-alarm | power-down | reset | set | set-alarm\n"); } static void handle_spi(void *spi, void *gpio[]) diff -r 672a2ee47bfd -r 16d7ccdedcf0 pkg/landfall-examples/hw_info/jz4780.c --- a/pkg/landfall-examples/hw_info/jz4780.c Sat May 04 01:30:06 2024 +0200 +++ b/pkg/landfall-examples/hw_info/jz4780.c Sat May 04 01:31:54 2024 +0200 @@ -29,10 +29,7 @@ #include #include #include - -/* The X1600 RTC functionality is a subset of that in the JZ4780. */ - -#include +#include /* GPIO-based SPI can use arbitrary pins, whereas on the CI20 only the secondary header provides pins like GPC. */ @@ -382,65 +379,67 @@ void *rtc_init(l4_addr_t start, void *cpm) { - /* Ignore the CPM requirement for the JZ4780. */ + return jz4780_rtc_init(start, cpm); +} - (void) cpm; - return x1600_rtc_init(start, NULL); +enum Clock_identifiers rtc_get_clock(void *rtc) +{ + return jz4780_rtc_get_clock(rtc); } void rtc_disable(void *rtc) { - x1600_rtc_disable(rtc); + jz4780_rtc_disable(rtc); } void rtc_enable(void *rtc) { - x1600_rtc_enable(rtc); + jz4780_rtc_enable(rtc); } void rtc_alarm_disable(void *rtc) { - x1600_rtc_alarm_disable(rtc); + jz4780_rtc_alarm_disable(rtc); } void rtc_alarm_enable(void *rtc) { - x1600_rtc_alarm_enable(rtc); + jz4780_rtc_alarm_enable(rtc); } uint32_t rtc_get_seconds(void *rtc) { - return x1600_rtc_get_seconds(rtc); + return jz4780_rtc_get_seconds(rtc); } void rtc_set_seconds(void *rtc, uint32_t seconds) { - x1600_rtc_set_seconds(rtc, seconds); + jz4780_rtc_set_seconds(rtc, seconds); } uint32_t rtc_get_alarm_seconds(void *rtc) { - return x1600_rtc_get_alarm_seconds(rtc); + return jz4780_rtc_get_alarm_seconds(rtc); } void rtc_set_alarm_seconds(void *rtc, uint32_t seconds) { - x1600_rtc_set_alarm_seconds(rtc, seconds); + jz4780_rtc_set_alarm_seconds(rtc, seconds); } void rtc_hibernate(void *rtc) { - x1600_rtc_hibernate(rtc); + jz4780_rtc_hibernate(rtc); } void rtc_power_down(void *rtc) { - x1600_rtc_power_down(rtc); + jz4780_rtc_power_down(rtc); } void rtc_set_regulator(void *rtc, uint32_t base, uint32_t adjustment) { - x1600_rtc_set_regulator(rtc, base, adjustment); + jz4780_rtc_set_regulator(rtc, base, adjustment); } diff -r 672a2ee47bfd -r 16d7ccdedcf0 pkg/landfall-examples/hw_info/x1600.c --- a/pkg/landfall-examples/hw_info/x1600.c Sat May 04 01:30:06 2024 +0200 +++ b/pkg/landfall-examples/hw_info/x1600.c Sat May 04 01:31:54 2024 +0200 @@ -374,6 +374,11 @@ return x1600_rtc_init(start, cpm); } +enum Clock_identifiers rtc_get_clock(void *rtc) +{ + return x1600_rtc_get_clock(rtc); +} + void rtc_disable(void *rtc) { x1600_rtc_disable(rtc);