1 /* 2 * Real-time clock support. 3 * 4 * Copyright (C) 2023 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <l4/devices/hw_mmio_register_block.h> 23 #include "rtc-x1600.h" 24 25 26 27 // Register locations. 28 29 enum Regs : unsigned 30 { 31 Rtc_control = 0x000, // RTCCR 32 Rtc_seconds = 0x004, // RTCSR 33 Rtc_alarm_seconds = 0x008, // RTCSAR 34 Rtc_regulator = 0x00c, // RTCGR 35 36 Hibernate_control = 0x020, // HCR 37 Hibernate_wakeup_filter_counter = 0x024, // HWFCR 38 Hibernate_reset_counter = 0x028, // HRCR 39 Hibernate_wakeup_control = 0x02c, // HWCR 40 Hibernate_wakeup_status = 0x030, // HWRSR 41 Hibernate_scratch_pattern = 0x034, // HSPR 42 Hibernate_write_enable_pattern = 0x03c, // WENR 43 Hibernate_wakeup_pin_configure = 0x048, // WKUPPINCR 44 }; 45 46 // Field definitions. 47 48 enum Control_bits : unsigned 49 { 50 Control_write_ready = 0x80, // WRDY 51 Control_1Hz = 0x40, // 1HZ 52 Control_1Hz_irq_enable = 0x20, // 1HZIE 53 Control_alarm = 0x10, // AF 54 Control_alarm_irq_enable = 0x08, // AIE 55 Control_alarm_enable = 0x04, // AE 56 Control_rtc_enable = 0x01, // RTCE 57 }; 58 59 enum Regulator_bits : unsigned 60 { 61 Regulator_lock = 0x80000000, // LOCK 62 Regulator_adjust_count_mask = 0x03ff0000, // ADJC 63 Regulator_1Hz_cycle_count_mask = 0x0000ffff, // NC1HZ 64 }; 65 66 enum Regulator_limits : unsigned 67 { 68 Regulator_adjust_count_limit = 0x03ff, // ADJC 69 Regulator_1Hz_cycle_count_limit = 0xffff, // NC1HZ 70 }; 71 72 enum Regulator_shifts : unsigned 73 { 74 Regulator_adjust_count_shift = 16, // ADJC 75 Regulator_1Hz_cycle_count_shift = 0, // NC1HZ 76 }; 77 78 enum Hibernate_control_bits : unsigned 79 { 80 Hibernate_power_down = 0x01, // PD 81 }; 82 83 enum Hibernate_wakeup_filter_counter_bits : unsigned 84 { 85 Wakeup_minimum_time_mask = 0xffe0, // HWFCR 86 }; 87 88 enum Hibernate_reset_counter_bits : unsigned 89 { 90 Reset_assert_time_mask = 0x7800, // HRCR 91 }; 92 93 enum Hibernate_wakeup_control_bits : unsigned 94 { 95 Power_detect_enable_mask = 0xfffffff8, // EPDET 96 Rtc_alarm_wakeup_enable = 0x00000001, // EALM 97 }; 98 99 enum Hibernate_wakeup_status_bits : unsigned 100 { 101 Accident_power_down = 0x0100, // APD 102 Hibernate_reset = 0x0020, // HR 103 Pad_pin_reset = 0x0010, // PPR 104 Wakeup_pin_status = 0x0002, // PIN 105 Rtc_alarm_status = 0x0001, // ALM 106 }; 107 108 enum Hibernate_write_enable_pattern_bits : unsigned 109 { 110 Write_enable_status = 0x80000000, // WEN 111 Write_enable_pattern_mask = 0x0000ffff, // WENPAT 112 Write_enable_pattern = 0x0000a55a, // WENPAT 113 }; 114 115 enum Hibernate_wakeup_pin_configure_bits : unsigned 116 { 117 Rtc_oscillator_test_enable = 0x00080000, // OSC_TE 118 Oscillator_xtclk_rtclk = 0x00040000, // OSC_RETON 119 Oscillator_xtclk_low = 0x00000000, // OSC_RETON 120 Rtc_internal_oscillator_enable = 0x00010000, // OSC_EN 121 Wakeup_pin_extended_press_mask = 0x000000f0, // P_JUD_LEN 122 Wakeup_pin_extended_press_enable = 0x0000000f, // P_RST_LEN 123 }; 124 125 126 127 // Peripheral abstraction. 128 129 Rtc_x1600_chip::Rtc_x1600_chip(l4_addr_t addr) 130 { 131 _regs = new Hw::Mmio_register_block<32>(addr); 132 } 133 134 uint32_t 135 Rtc_x1600_chip::read_checked(unsigned reg) 136 { 137 uint32_t last, current; 138 139 wait(); 140 last = _regs[reg]; 141 142 while (1) 143 { 144 wait(); 145 current = _regs[reg]; 146 147 if (current == last) 148 return current; 149 else 150 last = current; 151 } 152 } 153 154 void 155 Rtc_x1600_chip::wait() 156 { 157 while (!(_regs[Rtc_control] & Control_write_ready)); 158 } 159 160 void 161 Rtc_x1600_chip::write_enable() 162 { 163 wait(); 164 _regs[Hibernate_write_enable_pattern] = Write_enable_pattern; 165 166 while (!(_regs[Hibernate_write_enable_pattern] & Write_enable_status)); 167 168 wait(); 169 } 170 171 void 172 Rtc_x1600_chip::disable() 173 { 174 write_enable(); 175 _regs[Rtc_control] = _regs[Rtc_control] & ~Control_rtc_enable; 176 } 177 178 void 179 Rtc_x1600_chip::enable() 180 { 181 write_enable(); 182 _regs[Rtc_control] = _regs[Rtc_control] | Control_rtc_enable; 183 } 184 185 void 186 Rtc_x1600_chip::alarm_disable() 187 { 188 write_enable(); 189 _regs[Rtc_control] = _regs[Rtc_control] & ~Control_alarm_enable; 190 } 191 192 void 193 Rtc_x1600_chip::alarm_enable() 194 { 195 write_enable(); 196 _regs[Rtc_control] = (_regs[Rtc_control] & ~Control_alarm) | Control_alarm_enable; 197 } 198 199 void 200 Rtc_x1600_chip::wakeup_alarm_disable() 201 { 202 write_enable(); 203 _regs[Hibernate_wakeup_control] = _regs[Hibernate_wakeup_control] & ~Rtc_alarm_wakeup_enable; 204 } 205 206 void 207 Rtc_x1600_chip::wakeup_alarm_enable() 208 { 209 write_enable(); 210 _regs[Hibernate_wakeup_control] = _regs[Hibernate_wakeup_control] | Rtc_alarm_wakeup_enable; 211 } 212 213 uint32_t 214 Rtc_x1600_chip::get_seconds() 215 { 216 return read_checked(Rtc_seconds); 217 } 218 219 void 220 Rtc_x1600_chip::set_seconds(uint32_t seconds) 221 { 222 write_enable(); 223 _regs[Rtc_seconds] = seconds; 224 } 225 226 uint32_t 227 Rtc_x1600_chip::get_alarm_seconds() 228 { 229 return read_checked(Rtc_alarm_seconds); 230 } 231 232 void 233 Rtc_x1600_chip::set_alarm_seconds(uint32_t seconds) 234 { 235 write_enable(); 236 _regs[Rtc_alarm_seconds] = seconds; 237 } 238 239 void 240 Rtc_x1600_chip::set_regulator(uint32_t base, uint32_t adjustment) 241 { 242 base = base ? base - 1 : 0; 243 adjustment = adjustment ? adjustment - 1 : 0; 244 245 if (base > Regulator_1Hz_cycle_count_limit) 246 base = Regulator_1Hz_cycle_count_limit; 247 248 if (adjustment > Regulator_adjust_count_limit) 249 adjustment = Regulator_adjust_count_limit; 250 251 write_enable(); 252 _regs[Rtc_regulator] = (base << Regulator_1Hz_cycle_count_shift) | 253 (adjustment << Regulator_adjust_count_shift); 254 } 255 256 void 257 Rtc_x1600_chip::hibernate() 258 { 259 alarm_enable(); 260 wakeup_alarm_enable(); 261 power_down(); 262 } 263 264 void 265 Rtc_x1600_chip::power_down() 266 { 267 write_enable(); 268 _regs[Hibernate_control] = _regs[Hibernate_control] | Hibernate_power_down; 269 } 270 271 272 273 // C language interface functions. 274 275 void 276 *x1600_rtc_init(l4_addr_t rtc_base) 277 { 278 return (void *) new Rtc_x1600_chip(rtc_base); 279 } 280 281 void x1600_rtc_disable(void *rtc) 282 { 283 static_cast<Rtc_x1600_chip *>(rtc)->disable(); 284 } 285 286 void x1600_rtc_enable(void *rtc) 287 { 288 static_cast<Rtc_x1600_chip *>(rtc)->enable(); 289 } 290 291 void x1600_rtc_alarm_disable(void *rtc) 292 { 293 static_cast<Rtc_x1600_chip *>(rtc)->alarm_disable(); 294 } 295 296 void x1600_rtc_alarm_enable(void *rtc) 297 { 298 static_cast<Rtc_x1600_chip *>(rtc)->alarm_enable(); 299 } 300 301 uint32_t x1600_rtc_get_seconds(void *rtc) 302 { 303 return static_cast<Rtc_x1600_chip *>(rtc)->get_seconds(); 304 } 305 306 void x1600_rtc_set_seconds(void *rtc, uint32_t seconds) 307 { 308 static_cast<Rtc_x1600_chip *>(rtc)->set_seconds(seconds); 309 } 310 311 uint32_t x1600_rtc_get_alarm_seconds(void *rtc) 312 { 313 return static_cast<Rtc_x1600_chip *>(rtc)->get_alarm_seconds(); 314 } 315 316 void x1600_rtc_set_alarm_seconds(void *rtc, uint32_t seconds) 317 { 318 static_cast<Rtc_x1600_chip *>(rtc)->set_alarm_seconds(seconds); 319 } 320 321 void x1600_rtc_set_regulator(void *rtc, uint32_t base, uint32_t adjustment) 322 { 323 static_cast<Rtc_x1600_chip *>(rtc)->set_regulator(base, adjustment); 324 } 325 326 void x1600_rtc_hibernate(void *rtc) 327 { 328 static_cast<Rtc_x1600_chip *>(rtc)->hibernate(); 329 } 330 331 void x1600_rtc_power_down(void *rtc) 332 { 333 static_cast<Rtc_x1600_chip *>(rtc)->power_down(); 334 }