1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/pkg/devices/lib/rtc/src/common.cc Sat May 04 01:31:54 2024 +0200
1.3 @@ -0,0 +1,198 @@
1.4 +/*
1.5 + * Real-time clock support.
1.6 + *
1.7 + * Copyright (C) 2023, 2024 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This program is free software; you can redistribute it and/or
1.10 + * modify it under the terms of the GNU General Public License as
1.11 + * published by the Free Software Foundation; either version 2 of
1.12 + * the License, or (at your option) any later version.
1.13 + *
1.14 + * This program is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program; if not, write to the Free Software
1.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.22 + * Boston, MA 02110-1301, USA
1.23 + */
1.24 +
1.25 +#include <l4/devices/hw_mmio_register_block.h>
1.26 +#include "rtc-defs.h"
1.27 +#include "rtc-generic.h"
1.28 +
1.29 +
1.30 +
1.31 +// Peripheral abstraction.
1.32 +
1.33 +Rtc_chip::Rtc_chip(l4_addr_t addr, Cpm_chip *cpm)
1.34 +: _cpm(cpm)
1.35 +{
1.36 + _regs = new Hw::Mmio_register_block<32>(addr);
1.37 +
1.38 + // Reset time regulation, in case it is completely scrambled.
1.39 + // NOTE: Using 32768 cycles for a 1Hz signal.
1.40 +
1.41 + set_regulator(32767, 0);
1.42 +}
1.43 +
1.44 +enum Clock_identifiers
1.45 +Rtc_chip::get_clock()
1.46 +{
1.47 + return Clock_rtc;
1.48 +}
1.49 +
1.50 +uint32_t
1.51 +Rtc_chip::read_checked(unsigned reg)
1.52 +{
1.53 + uint32_t last, current;
1.54 +
1.55 + wait();
1.56 + last = _regs[reg];
1.57 +
1.58 + while (1)
1.59 + {
1.60 + wait();
1.61 + current = _regs[reg];
1.62 +
1.63 + if (current == last)
1.64 + return current;
1.65 + else
1.66 + last = current;
1.67 + }
1.68 +}
1.69 +
1.70 +void
1.71 +Rtc_chip::wait()
1.72 +{
1.73 + while (!(_regs[Rtc_control] & Control_write_ready));
1.74 +}
1.75 +
1.76 +void
1.77 +Rtc_chip::write_enable()
1.78 +{
1.79 + wait();
1.80 + _regs[Hibernate_write_enable_pattern] = Write_enable_pattern;
1.81 +
1.82 + while (!(_regs[Hibernate_write_enable_pattern] & Write_enable_status));
1.83 +
1.84 + wait();
1.85 +}
1.86 +
1.87 +void
1.88 +Rtc_chip::disable()
1.89 +{
1.90 + write_enable();
1.91 + _regs[Rtc_control] = _regs[Rtc_control] & ~Control_rtc_enable;
1.92 +}
1.93 +
1.94 +void
1.95 +Rtc_chip::enable()
1.96 +{
1.97 + write_enable();
1.98 + _regs[Rtc_control] = _regs[Rtc_control] | Control_rtc_enable;
1.99 +}
1.100 +
1.101 +void
1.102 +Rtc_chip::alarm_disable()
1.103 +{
1.104 + write_enable();
1.105 + _regs[Rtc_control] = _regs[Rtc_control] & ~Control_alarm_enable;
1.106 +}
1.107 +
1.108 +void
1.109 +Rtc_chip::alarm_enable()
1.110 +{
1.111 + write_enable();
1.112 + _regs[Rtc_control] = (_regs[Rtc_control] & ~Control_alarm) | Control_alarm_enable;
1.113 +}
1.114 +
1.115 +void
1.116 +Rtc_chip::wakeup_alarm_disable()
1.117 +{
1.118 + write_enable();
1.119 + _regs[Hibernate_wakeup_control] = _regs[Hibernate_wakeup_control] & ~Rtc_alarm_wakeup_enable;
1.120 +}
1.121 +
1.122 +void
1.123 +Rtc_chip::wakeup_alarm_enable()
1.124 +{
1.125 + write_enable();
1.126 + _regs[Hibernate_wakeup_control] = _regs[Hibernate_wakeup_control] | Rtc_alarm_wakeup_enable;
1.127 +}
1.128 +
1.129 +uint32_t
1.130 +Rtc_chip::get_seconds()
1.131 +{
1.132 + return read_checked(Rtc_seconds);
1.133 +}
1.134 +
1.135 +void
1.136 +Rtc_chip::set_seconds(uint32_t seconds)
1.137 +{
1.138 + write_enable();
1.139 + _regs[Rtc_seconds] = seconds;
1.140 +}
1.141 +
1.142 +uint32_t
1.143 +Rtc_chip::get_alarm_seconds()
1.144 +{
1.145 + return read_checked(Rtc_alarm_seconds);
1.146 +}
1.147 +
1.148 +void
1.149 +Rtc_chip::set_alarm_seconds(uint32_t seconds)
1.150 +{
1.151 + write_enable();
1.152 + _regs[Rtc_alarm_seconds] = seconds;
1.153 +}
1.154 +
1.155 +void
1.156 +Rtc_chip::set_regulator(uint32_t base, uint32_t adjustment)
1.157 +{
1.158 + base = base ? base - 1 : 0;
1.159 + adjustment = adjustment ? adjustment - 1 : 0;
1.160 +
1.161 + if (base > Regulator_1Hz_cycle_count_limit)
1.162 + base = Regulator_1Hz_cycle_count_limit;
1.163 +
1.164 + if (adjustment > Regulator_adjust_count_limit)
1.165 + adjustment = Regulator_adjust_count_limit;
1.166 +
1.167 + write_enable();
1.168 + _regs[Rtc_regulator] = (base << Regulator_1Hz_cycle_count_shift) |
1.169 + (adjustment << Regulator_adjust_count_shift);
1.170 +}
1.171 +
1.172 +// Device-specific method.
1.173 +
1.174 +void
1.175 +Rtc_chip::_pre_power_down()
1.176 +{
1.177 +}
1.178 +
1.179 +void
1.180 +Rtc_chip::_power_down()
1.181 +{
1.182 + _pre_power_down();
1.183 +
1.184 + write_enable();
1.185 + _regs[Hibernate_control] = _regs[Hibernate_control] | Hibernate_power_down;
1.186 +}
1.187 +
1.188 +void
1.189 +Rtc_chip::hibernate()
1.190 +{
1.191 + alarm_enable();
1.192 + wakeup_alarm_enable();
1.193 + _power_down();
1.194 +}
1.195 +
1.196 +void
1.197 +Rtc_chip::power_down()
1.198 +{
1.199 + wakeup_alarm_disable();
1.200 + _power_down();
1.201 +}