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, Cpm_x1600_chip *cpm) 130 : _cpm(cpm) 131 { 132 _regs = new Hw::Mmio_register_block<32>(addr); 133 } 134 135 uint32_t 136 Rtc_x1600_chip::read_checked(unsigned reg) 137 { 138 uint32_t last, current; 139 140 wait(); 141 last = _regs[reg]; 142 143 while (1) 144 { 145 wait(); 146 current = _regs[reg]; 147 148 if (current == last) 149 return current; 150 else 151 last = current; 152 } 153 } 154 155 void 156 Rtc_x1600_chip::wait() 157 { 158 while (!(_regs[Rtc_control] & Control_write_ready)); 159 } 160 161 void 162 Rtc_x1600_chip::write_enable() 163 { 164 wait(); 165 _regs[Hibernate_write_enable_pattern] = Write_enable_pattern; 166 167 while (!(_regs[Hibernate_write_enable_pattern] & Write_enable_status)); 168 169 wait(); 170 } 171 172 void 173 Rtc_x1600_chip::disable() 174 { 175 write_enable(); 176 _regs[Rtc_control] = _regs[Rtc_control] & ~Control_rtc_enable; 177 } 178 179 void 180 Rtc_x1600_chip::enable() 181 { 182 write_enable(); 183 _regs[Rtc_control] = _regs[Rtc_control] | Control_rtc_enable; 184 } 185 186 void 187 Rtc_x1600_chip::alarm_disable() 188 { 189 write_enable(); 190 _regs[Rtc_control] = _regs[Rtc_control] & ~Control_alarm_enable; 191 } 192 193 void 194 Rtc_x1600_chip::alarm_enable() 195 { 196 write_enable(); 197 _regs[Rtc_control] = (_regs[Rtc_control] & ~Control_alarm) | Control_alarm_enable; 198 } 199 200 void 201 Rtc_x1600_chip::wakeup_alarm_disable() 202 { 203 write_enable(); 204 _regs[Hibernate_wakeup_control] = _regs[Hibernate_wakeup_control] & ~Rtc_alarm_wakeup_enable; 205 } 206 207 void 208 Rtc_x1600_chip::wakeup_alarm_enable() 209 { 210 write_enable(); 211 _regs[Hibernate_wakeup_control] = _regs[Hibernate_wakeup_control] | Rtc_alarm_wakeup_enable; 212 } 213 214 uint32_t 215 Rtc_x1600_chip::get_seconds() 216 { 217 return read_checked(Rtc_seconds); 218 } 219 220 void 221 Rtc_x1600_chip::set_seconds(uint32_t seconds) 222 { 223 write_enable(); 224 _regs[Rtc_seconds] = seconds; 225 } 226 227 uint32_t 228 Rtc_x1600_chip::get_alarm_seconds() 229 { 230 return read_checked(Rtc_alarm_seconds); 231 } 232 233 void 234 Rtc_x1600_chip::set_alarm_seconds(uint32_t seconds) 235 { 236 write_enable(); 237 _regs[Rtc_alarm_seconds] = seconds; 238 } 239 240 void 241 Rtc_x1600_chip::set_regulator(uint32_t base, uint32_t adjustment) 242 { 243 base = base ? base - 1 : 0; 244 adjustment = adjustment ? adjustment - 1 : 0; 245 246 if (base > Regulator_1Hz_cycle_count_limit) 247 base = Regulator_1Hz_cycle_count_limit; 248 249 if (adjustment > Regulator_adjust_count_limit) 250 adjustment = Regulator_adjust_count_limit; 251 252 write_enable(); 253 _regs[Rtc_regulator] = (base << Regulator_1Hz_cycle_count_shift) | 254 (adjustment << Regulator_adjust_count_shift); 255 } 256 257 void 258 Rtc_x1600_chip::_power_down() 259 { 260 /* Set CPU frequency to L2 cache frequency before powering down. This is 261 apparently necessary according to the X1600 manual. */ 262 263 if (_cpm != NULL) 264 _cpm->set_frequency(Clock_cpu, _cpm->get_frequency(Clock_l2cache)); 265 266 write_enable(); 267 _regs[Hibernate_control] = _regs[Hibernate_control] | Hibernate_power_down; 268 } 269 270 void 271 Rtc_x1600_chip::hibernate() 272 { 273 alarm_enable(); 274 wakeup_alarm_enable(); 275 _power_down(); 276 } 277 278 void 279 Rtc_x1600_chip::power_down() 280 { 281 wakeup_alarm_disable(); 282 _power_down(); 283 } 284 285 286 287 // C language interface functions. 288 289 void 290 *x1600_rtc_init(l4_addr_t rtc_base, void *cpm) 291 { 292 return (void *) new Rtc_x1600_chip(rtc_base, static_cast<Cpm_x1600_chip *>(cpm)); 293 } 294 295 void x1600_rtc_disable(void *rtc) 296 { 297 static_cast<Rtc_x1600_chip *>(rtc)->disable(); 298 } 299 300 void x1600_rtc_enable(void *rtc) 301 { 302 static_cast<Rtc_x1600_chip *>(rtc)->enable(); 303 } 304 305 void x1600_rtc_alarm_disable(void *rtc) 306 { 307 static_cast<Rtc_x1600_chip *>(rtc)->alarm_disable(); 308 } 309 310 void x1600_rtc_alarm_enable(void *rtc) 311 { 312 static_cast<Rtc_x1600_chip *>(rtc)->alarm_enable(); 313 } 314 315 uint32_t x1600_rtc_get_seconds(void *rtc) 316 { 317 return static_cast<Rtc_x1600_chip *>(rtc)->get_seconds(); 318 } 319 320 void x1600_rtc_set_seconds(void *rtc, uint32_t seconds) 321 { 322 static_cast<Rtc_x1600_chip *>(rtc)->set_seconds(seconds); 323 } 324 325 uint32_t x1600_rtc_get_alarm_seconds(void *rtc) 326 { 327 return static_cast<Rtc_x1600_chip *>(rtc)->get_alarm_seconds(); 328 } 329 330 void x1600_rtc_set_alarm_seconds(void *rtc, uint32_t seconds) 331 { 332 static_cast<Rtc_x1600_chip *>(rtc)->set_alarm_seconds(seconds); 333 } 334 335 void x1600_rtc_set_regulator(void *rtc, uint32_t base, uint32_t adjustment) 336 { 337 static_cast<Rtc_x1600_chip *>(rtc)->set_regulator(base, adjustment); 338 } 339 340 void x1600_rtc_hibernate(void *rtc) 341 { 342 static_cast<Rtc_x1600_chip *>(rtc)->hibernate(); 343 } 344 345 void x1600_rtc_power_down(void *rtc) 346 { 347 static_cast<Rtc_x1600_chip *>(rtc)->power_down(); 348 }