1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * Loongarch LS7A Real Time Clock emulation 4 * 5 * Copyright (C) 2021 Loongson Technology Corporation Limited 6 */ 7 8 #include "qemu/osdep.h" 9 #include "hw/sysbus.h" 10 #include "hw/irq.h" 11 #include "include/hw/register.h" 12 #include "qemu/timer.h" 13 #include "sysemu/sysemu.h" 14 #include "qemu/cutils.h" 15 #include "qemu/log.h" 16 #include "migration/vmstate.h" 17 #include "hw/misc/unimp.h" 18 #include "sysemu/rtc.h" 19 #include "hw/registerfields.h" 20 21 #define SYS_TOYTRIM 0x20 22 #define SYS_TOYWRITE0 0x24 23 #define SYS_TOYWRITE1 0x28 24 #define SYS_TOYREAD0 0x2C 25 #define SYS_TOYREAD1 0x30 26 #define SYS_TOYMATCH0 0x34 27 #define SYS_TOYMATCH1 0x38 28 #define SYS_TOYMATCH2 0x3C 29 #define SYS_RTCCTRL 0x40 30 #define SYS_RTCTRIM 0x60 31 #define SYS_RTCWRTIE0 0x64 32 #define SYS_RTCREAD0 0x68 33 #define SYS_RTCMATCH0 0x6C 34 #define SYS_RTCMATCH1 0x70 35 #define SYS_RTCMATCH2 0x74 36 37 #define LS7A_RTC_FREQ 32768 38 #define TIMER_NUMS 3 39 /* 40 * Shift bits and filed mask 41 */ 42 43 FIELD(TOY, MON, 26, 6) 44 FIELD(TOY, DAY, 21, 5) 45 FIELD(TOY, HOUR, 16, 5) 46 FIELD(TOY, MIN, 10, 6) 47 FIELD(TOY, SEC, 4, 6) 48 FIELD(TOY, MSEC, 0, 4) 49 50 FIELD(TOY_MATCH, YEAR, 26, 6) 51 FIELD(TOY_MATCH, MON, 22, 4) 52 FIELD(TOY_MATCH, DAY, 17, 5) 53 FIELD(TOY_MATCH, HOUR, 12, 5) 54 FIELD(TOY_MATCH, MIN, 6, 6) 55 FIELD(TOY_MATCH, SEC, 0, 6) 56 57 FIELD(RTC_CTRL, RTCEN, 13, 1) 58 FIELD(RTC_CTRL, TOYEN, 11, 1) 59 FIELD(RTC_CTRL, EO, 8, 1) 60 61 #define TYPE_LS7A_RTC "ls7a_rtc" 62 OBJECT_DECLARE_SIMPLE_TYPE(LS7ARtcState, LS7A_RTC) 63 64 struct LS7ARtcState { 65 SysBusDevice parent_obj; 66 67 MemoryRegion iomem; 68 /* 69 * Needed to preserve the tick_count across migration, even if the 70 * absolute value of the rtc_clock is different on the source and 71 * destination. 72 */ 73 int64_t offset_toy; 74 int64_t offset_rtc; 75 uint64_t save_toy_mon; 76 uint64_t save_toy_year; 77 uint64_t save_rtc; 78 int64_t data; 79 int tidx; 80 uint32_t toymatch[3]; 81 uint32_t toytrim; 82 uint32_t cntrctl; 83 uint32_t rtctrim; 84 uint32_t rtccount; 85 uint32_t rtcmatch[3]; 86 QEMUTimer *toy_timer[TIMER_NUMS]; 87 QEMUTimer *rtc_timer[TIMER_NUMS]; 88 qemu_irq irq; 89 }; 90 91 /* switch nanoseconds time to rtc ticks */ 92 static inline uint64_t ls7a_rtc_ticks(void) 93 { 94 return qemu_clock_get_ns(rtc_clock) * LS7A_RTC_FREQ / NANOSECONDS_PER_SECOND; 95 } 96 97 /* switch rtc ticks to nanoseconds */ 98 static inline uint64_t ticks_to_ns(uint64_t ticks) 99 { 100 return ticks * NANOSECONDS_PER_SECOND / LS7A_RTC_FREQ; 101 } 102 103 static inline bool toy_enabled(LS7ARtcState *s) 104 { 105 return FIELD_EX32(s->cntrctl, RTC_CTRL, TOYEN) && 106 FIELD_EX32(s->cntrctl, RTC_CTRL, EO); 107 } 108 109 static inline bool rtc_enabled(LS7ARtcState *s) 110 { 111 return FIELD_EX32(s->cntrctl, RTC_CTRL, RTCEN) && 112 FIELD_EX32(s->cntrctl, RTC_CTRL, EO); 113 } 114 115 /* parse toy value to struct tm */ 116 static inline void toy_val_to_time_mon(uint64_t toy_val, struct tm *tm) 117 { 118 tm->tm_sec = FIELD_EX32(toy_val, TOY, SEC); 119 tm->tm_min = FIELD_EX32(toy_val, TOY, MIN); 120 tm->tm_hour = FIELD_EX32(toy_val, TOY, HOUR); 121 tm->tm_mday = FIELD_EX32(toy_val, TOY, DAY); 122 tm->tm_mon = FIELD_EX32(toy_val, TOY, MON) - 1; 123 } 124 125 static inline void toy_val_to_time_year(uint64_t toy_year, struct tm *tm) 126 { 127 tm->tm_year = toy_year; 128 } 129 130 /* parse struct tm to toy value */ 131 static inline uint64_t toy_time_to_val_mon(struct tm tm) 132 { 133 uint64_t val = 0; 134 135 val = FIELD_DP32(val, TOY, MON, tm.tm_mon + 1); 136 val = FIELD_DP32(val, TOY, DAY, tm.tm_mday); 137 val = FIELD_DP32(val, TOY, HOUR, tm.tm_hour); 138 val = FIELD_DP32(val, TOY, MIN, tm.tm_min); 139 val = FIELD_DP32(val, TOY, SEC, tm.tm_sec); 140 return val; 141 } 142 143 static inline uint64_t toy_time_to_val_year(struct tm tm) 144 { 145 uint64_t year; 146 147 year = tm.tm_year; 148 return year; 149 } 150 151 static inline void toymatch_val_to_time(uint64_t val, struct tm *tm) 152 { 153 tm->tm_sec = FIELD_EX32(val, TOY_MATCH, SEC); 154 tm->tm_min = FIELD_EX32(val, TOY_MATCH, MIN); 155 tm->tm_hour = FIELD_EX32(val, TOY_MATCH, HOUR); 156 tm->tm_mday = FIELD_EX32(val, TOY_MATCH, DAY); 157 tm->tm_mon = FIELD_EX32(val, TOY_MATCH, MON) - 1; 158 tm->tm_year += (FIELD_EX32(val, TOY_MATCH, YEAR) - (tm->tm_year & 0x3f)); 159 } 160 161 static void toymatch_write(LS7ARtcState *s, struct tm *tm, uint64_t val, int num) 162 { 163 int64_t now, expire_time; 164 165 /* it do not support write when toy disabled */ 166 if (toy_enabled(s)) { 167 s->toymatch[num] = val; 168 /* caculate expire time */ 169 now = qemu_clock_get_ms(rtc_clock); 170 toymatch_val_to_time(val, tm); 171 expire_time = now + (qemu_timedate_diff(tm) - s->offset_toy) * 1000; 172 timer_mod(s->toy_timer[num], expire_time); 173 } 174 } 175 176 static void rtcmatch_write(LS7ARtcState *s, uint64_t val, int num) 177 { 178 uint64_t expire_ns; 179 180 /* it do not support write when toy disabled */ 181 if (rtc_enabled(s)) { 182 s->rtcmatch[num] = val; 183 /* caculate expire time */ 184 expire_ns = ticks_to_ns(val) - ticks_to_ns(s->offset_rtc); 185 timer_mod_ns(s->rtc_timer[num], expire_ns); 186 } 187 } 188 189 static void ls7a_toy_stop(LS7ARtcState *s) 190 { 191 int i; 192 struct tm tm; 193 /* 194 * save time when disabled toy, 195 * because toy time not add counters. 196 */ 197 qemu_get_timedate(&tm, s->offset_toy); 198 s->save_toy_mon = toy_time_to_val_mon(tm); 199 s->save_toy_year = toy_time_to_val_year(tm); 200 201 /* delete timers, and when re-enabled, recaculate expire time */ 202 for (i = 0; i < TIMER_NUMS; i++) { 203 timer_del(s->toy_timer[i]); 204 } 205 } 206 207 static void ls7a_rtc_stop(LS7ARtcState *s) 208 { 209 int i; 210 uint64_t time; 211 212 /* save rtc time */ 213 time = ls7a_rtc_ticks() + s->offset_rtc; 214 s->save_rtc = time; 215 216 /* delete timers, and when re-enabled, recaculate expire time */ 217 for (i = 0; i < TIMER_NUMS; i++) { 218 timer_del(s->rtc_timer[i]); 219 } 220 } 221 222 static void ls7a_toy_start(LS7ARtcState *s) 223 { 224 int i; 225 uint64_t expire_time, now; 226 struct tm tm; 227 /* 228 * need to recaculate toy offset 229 * and expire time when enable it. 230 */ 231 toy_val_to_time_mon(s->save_toy_mon, &tm); 232 toy_val_to_time_year(s->save_toy_year, &tm); 233 234 s->offset_toy = qemu_timedate_diff(&tm); 235 now = qemu_clock_get_ms(rtc_clock); 236 237 /* recaculate expire time and enable timer */ 238 for (i = 0; i < TIMER_NUMS; i++) { 239 toymatch_val_to_time(s->toymatch[i], &tm); 240 expire_time = now + (qemu_timedate_diff(&tm) - s->offset_toy) * 1000; 241 timer_mod(s->toy_timer[i], expire_time); 242 } 243 } 244 245 static void ls7a_rtc_start(LS7ARtcState *s) 246 { 247 int i; 248 uint64_t expire_time, now; 249 250 /* 251 * need to recaculate rtc offset 252 * and expire time when enable it. 253 */ 254 now = ls7a_rtc_ticks(); 255 s->offset_rtc = s->save_rtc - now; 256 257 /* recaculate expire time and enable timer */ 258 for (i = 0; i < TIMER_NUMS; i++) { 259 expire_time = ticks_to_ns(s->rtcmatch[i]) - ticks_to_ns(s->offset_rtc); 260 timer_mod_ns(s->rtc_timer[i], expire_time); 261 } 262 } 263 264 static uint64_t ls7a_rtc_read(void *opaque, hwaddr addr, unsigned size) 265 { 266 LS7ARtcState *s = LS7A_RTC(opaque); 267 struct tm tm; 268 int val = 0; 269 270 switch (addr) { 271 case SYS_TOYREAD0: 272 /* if toy disabled, read save toy time */ 273 if (toy_enabled(s)) { 274 qemu_get_timedate(&tm, s->offset_toy); 275 val = toy_time_to_val_mon(tm); 276 } else { 277 /* read save mon val */ 278 val = s->save_toy_mon; 279 } 280 break; 281 case SYS_TOYREAD1: 282 /* if toy disabled, read save toy time */ 283 if (toy_enabled(s)) { 284 qemu_get_timedate(&tm, s->offset_toy); 285 val = tm.tm_year; 286 } else { 287 /* read save year val */ 288 val = s->save_toy_year; 289 } 290 break; 291 case SYS_TOYMATCH0: 292 val = s->toymatch[0]; 293 break; 294 case SYS_TOYMATCH1: 295 val = s->toymatch[1]; 296 break; 297 case SYS_TOYMATCH2: 298 val = s->toymatch[2]; 299 break; 300 case SYS_RTCCTRL: 301 val = s->cntrctl; 302 break; 303 case SYS_RTCREAD0: 304 /* if rtc disabled, read save rtc time */ 305 if (rtc_enabled(s)) { 306 val = ls7a_rtc_ticks() + s->offset_rtc; 307 } else { 308 val = s->save_rtc; 309 } 310 break; 311 case SYS_RTCMATCH0: 312 val = s->rtcmatch[0]; 313 break; 314 case SYS_RTCMATCH1: 315 val = s->rtcmatch[1]; 316 break; 317 case SYS_RTCMATCH2: 318 val = s->rtcmatch[2]; 319 break; 320 default: 321 val = 0; 322 break; 323 } 324 return val; 325 } 326 327 static void ls7a_rtc_write(void *opaque, hwaddr addr, 328 uint64_t val, unsigned size) 329 { 330 int old_toyen, old_rtcen, new_toyen, new_rtcen; 331 LS7ARtcState *s = LS7A_RTC(opaque); 332 struct tm tm; 333 334 switch (addr) { 335 case SYS_TOYWRITE0: 336 /* it do not support write when toy disabled */ 337 if (toy_enabled(s)) { 338 qemu_get_timedate(&tm, s->offset_toy); 339 tm.tm_sec = FIELD_EX32(val, TOY, SEC); 340 tm.tm_min = FIELD_EX32(val, TOY, MIN); 341 tm.tm_hour = FIELD_EX32(val, TOY, HOUR); 342 tm.tm_mday = FIELD_EX32(val, TOY, DAY); 343 tm.tm_mon = FIELD_EX32(val, TOY, MON) - 1; 344 s->offset_toy = qemu_timedate_diff(&tm); 345 } 346 break; 347 case SYS_TOYWRITE1: 348 if (toy_enabled(s)) { 349 qemu_get_timedate(&tm, s->offset_toy); 350 tm.tm_year = val; 351 s->offset_toy = qemu_timedate_diff(&tm); 352 } 353 break; 354 case SYS_TOYMATCH0: 355 toymatch_write(s, &tm, val, 0); 356 break; 357 case SYS_TOYMATCH1: 358 toymatch_write(s, &tm, val, 1); 359 break; 360 case SYS_TOYMATCH2: 361 toymatch_write(s, &tm, val, 2); 362 break; 363 case SYS_RTCCTRL: 364 /* get old ctrl */ 365 old_toyen = toy_enabled(s); 366 old_rtcen = rtc_enabled(s); 367 368 s->cntrctl = val; 369 /* get new ctrl */ 370 new_toyen = toy_enabled(s); 371 new_rtcen = rtc_enabled(s); 372 373 /* 374 * we do not consider if EO changed, as it always set at most time. 375 * toy or rtc enabled should start timer. otherwise, stop timer 376 */ 377 if (old_toyen != new_toyen) { 378 if (new_toyen) { 379 ls7a_toy_start(s); 380 } else { 381 ls7a_toy_stop(s); 382 } 383 } 384 if (old_rtcen != new_rtcen) { 385 if (new_rtcen) { 386 ls7a_rtc_start(s); 387 } else { 388 ls7a_rtc_stop(s); 389 } 390 } 391 break; 392 case SYS_RTCWRTIE0: 393 if (rtc_enabled(s)) { 394 s->offset_rtc = val - ls7a_rtc_ticks(); 395 } 396 break; 397 case SYS_RTCMATCH0: 398 rtcmatch_write(s, val, 0); 399 break; 400 case SYS_RTCMATCH1: 401 rtcmatch_write(s, val, 1); 402 break; 403 case SYS_RTCMATCH2: 404 rtcmatch_write(s, val, 2); 405 break; 406 default: 407 break; 408 } 409 } 410 411 static const MemoryRegionOps ls7a_rtc_ops = { 412 .read = ls7a_rtc_read, 413 .write = ls7a_rtc_write, 414 .endianness = DEVICE_LITTLE_ENDIAN, 415 .valid = { 416 .min_access_size = 4, 417 .max_access_size = 4, 418 }, 419 }; 420 421 static void toy_timer_cb(void *opaque) 422 { 423 LS7ARtcState *s = opaque; 424 425 if (toy_enabled(s)) { 426 qemu_irq_pulse(s->irq); 427 } 428 } 429 430 static void rtc_timer_cb(void *opaque) 431 { 432 LS7ARtcState *s = opaque; 433 434 if (rtc_enabled(s)) { 435 qemu_irq_pulse(s->irq); 436 } 437 } 438 439 static void ls7a_rtc_realize(DeviceState *dev, Error **errp) 440 { 441 int i; 442 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 443 LS7ARtcState *d = LS7A_RTC(sbd); 444 memory_region_init_io(&d->iomem, NULL, &ls7a_rtc_ops, 445 (void *)d, "ls7a_rtc", 0x100); 446 447 sysbus_init_irq(sbd, &d->irq); 448 449 sysbus_init_mmio(sbd, &d->iomem); 450 for (i = 0; i < TIMER_NUMS; i++) { 451 d->toymatch[i] = 0; 452 d->rtcmatch[i] = 0; 453 d->toy_timer[i] = timer_new_ms(rtc_clock, toy_timer_cb, d); 454 d->rtc_timer[i] = timer_new_ms(rtc_clock, rtc_timer_cb, d); 455 } 456 d->offset_toy = 0; 457 d->offset_rtc = 0; 458 d->save_toy_mon = 0; 459 d->save_toy_year = 0; 460 d->save_rtc = 0; 461 462 create_unimplemented_device("mmio fallback 1", 0x10013ffc, 0x4); 463 } 464 465 static int ls7a_rtc_pre_save(void *opaque) 466 { 467 LS7ARtcState *s = LS7A_RTC(opaque); 468 469 ls7a_toy_stop(s); 470 ls7a_rtc_stop(s); 471 472 return 0; 473 } 474 475 static int ls7a_rtc_post_load(void *opaque, int version_id) 476 { 477 LS7ARtcState *s = LS7A_RTC(opaque); 478 if (toy_enabled(s)) { 479 ls7a_toy_start(s); 480 } 481 482 if (rtc_enabled(s)) { 483 ls7a_rtc_start(s); 484 } 485 486 return 0; 487 } 488 489 static const VMStateDescription vmstate_ls7a_rtc = { 490 .name = "ls7a_rtc", 491 .version_id = 1, 492 .minimum_version_id = 1, 493 .pre_save = ls7a_rtc_pre_save, 494 .post_load = ls7a_rtc_post_load, 495 .fields = (VMStateField[]) { 496 VMSTATE_INT64(offset_toy, LS7ARtcState), 497 VMSTATE_INT64(offset_rtc, LS7ARtcState), 498 VMSTATE_UINT64(save_toy_mon, LS7ARtcState), 499 VMSTATE_UINT64(save_toy_year, LS7ARtcState), 500 VMSTATE_UINT64(save_rtc, LS7ARtcState), 501 VMSTATE_UINT32_ARRAY(toymatch, LS7ARtcState, TIMER_NUMS), 502 VMSTATE_UINT32_ARRAY(rtcmatch, LS7ARtcState, TIMER_NUMS), 503 VMSTATE_UINT32(cntrctl, LS7ARtcState), 504 VMSTATE_END_OF_LIST() 505 } 506 }; 507 508 static void ls7a_rtc_class_init(ObjectClass *klass, void *data) 509 { 510 DeviceClass *dc = DEVICE_CLASS(klass); 511 dc->vmsd = &vmstate_ls7a_rtc; 512 dc->realize = ls7a_rtc_realize; 513 dc->desc = "ls7a rtc"; 514 } 515 516 static const TypeInfo ls7a_rtc_info = { 517 .name = TYPE_LS7A_RTC, 518 .parent = TYPE_SYS_BUS_DEVICE, 519 .instance_size = sizeof(LS7ARtcState), 520 .class_init = ls7a_rtc_class_init, 521 }; 522 523 static void ls7a_rtc_register_types(void) 524 { 525 type_register_static(&ls7a_rtc_info); 526 } 527 528 type_init(ls7a_rtc_register_types) 529