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(LS7ARtcState *s, uint64_t val, struct tm *tm) 152 { 153 qemu_get_timedate(tm, s->offset_toy); 154 tm->tm_sec = FIELD_EX32(val, TOY_MATCH, SEC); 155 tm->tm_min = FIELD_EX32(val, TOY_MATCH, MIN); 156 tm->tm_hour = FIELD_EX32(val, TOY_MATCH, HOUR); 157 tm->tm_mday = FIELD_EX32(val, TOY_MATCH, DAY); 158 tm->tm_mon = FIELD_EX32(val, TOY_MATCH, MON) - 1; 159 tm->tm_year += (FIELD_EX32(val, TOY_MATCH, YEAR) - (tm->tm_year & 0x3f)); 160 } 161 162 static void toymatch_write(LS7ARtcState *s, uint64_t val, int num) 163 { 164 int64_t now, expire_time; 165 struct tm tm = {}; 166 167 /* it do not support write when toy disabled */ 168 if (toy_enabled(s)) { 169 s->toymatch[num] = val; 170 /* caculate expire time */ 171 now = qemu_clock_get_ms(rtc_clock); 172 toymatch_val_to_time(s, val, &tm); 173 expire_time = now + (qemu_timedate_diff(&tm) - s->offset_toy) * 1000; 174 timer_mod(s->toy_timer[num], expire_time); 175 } 176 } 177 178 static void rtcmatch_write(LS7ARtcState *s, uint64_t val, int num) 179 { 180 uint64_t expire_ns; 181 182 /* it do not support write when toy disabled */ 183 if (rtc_enabled(s)) { 184 s->rtcmatch[num] = val; 185 /* caculate expire time */ 186 expire_ns = ticks_to_ns(val) - ticks_to_ns(s->offset_rtc); 187 timer_mod_ns(s->rtc_timer[num], expire_ns); 188 } 189 } 190 191 static void ls7a_toy_stop(LS7ARtcState *s) 192 { 193 int i; 194 struct tm tm; 195 /* 196 * save time when disabled toy, 197 * because toy time not add counters. 198 */ 199 qemu_get_timedate(&tm, s->offset_toy); 200 s->save_toy_mon = toy_time_to_val_mon(tm); 201 s->save_toy_year = toy_time_to_val_year(tm); 202 203 /* delete timers, and when re-enabled, recaculate expire time */ 204 for (i = 0; i < TIMER_NUMS; i++) { 205 timer_del(s->toy_timer[i]); 206 } 207 } 208 209 static void ls7a_rtc_stop(LS7ARtcState *s) 210 { 211 int i; 212 uint64_t time; 213 214 /* save rtc time */ 215 time = ls7a_rtc_ticks() + s->offset_rtc; 216 s->save_rtc = time; 217 218 /* delete timers, and when re-enabled, recaculate expire time */ 219 for (i = 0; i < TIMER_NUMS; i++) { 220 timer_del(s->rtc_timer[i]); 221 } 222 } 223 224 static void ls7a_toy_start(LS7ARtcState *s) 225 { 226 int i; 227 uint64_t expire_time, now; 228 struct tm tm = {}; 229 /* 230 * need to recaculate toy offset 231 * and expire time when enable it. 232 */ 233 toy_val_to_time_mon(s->save_toy_mon, &tm); 234 toy_val_to_time_year(s->save_toy_year, &tm); 235 236 s->offset_toy = qemu_timedate_diff(&tm); 237 now = qemu_clock_get_ms(rtc_clock); 238 239 /* recaculate expire time and enable timer */ 240 for (i = 0; i < TIMER_NUMS; i++) { 241 toymatch_val_to_time(s, s->toymatch[i], &tm); 242 expire_time = now + (qemu_timedate_diff(&tm) - s->offset_toy) * 1000; 243 timer_mod(s->toy_timer[i], expire_time); 244 } 245 } 246 247 static void ls7a_rtc_start(LS7ARtcState *s) 248 { 249 int i; 250 uint64_t expire_time, now; 251 252 /* 253 * need to recaculate rtc offset 254 * and expire time when enable it. 255 */ 256 now = ls7a_rtc_ticks(); 257 s->offset_rtc = s->save_rtc - now; 258 259 /* recaculate expire time and enable timer */ 260 for (i = 0; i < TIMER_NUMS; i++) { 261 expire_time = ticks_to_ns(s->rtcmatch[i]) - ticks_to_ns(s->offset_rtc); 262 timer_mod_ns(s->rtc_timer[i], expire_time); 263 } 264 } 265 266 static uint64_t ls7a_rtc_read(void *opaque, hwaddr addr, unsigned size) 267 { 268 LS7ARtcState *s = LS7A_RTC(opaque); 269 struct tm tm; 270 int val = 0; 271 272 switch (addr) { 273 case SYS_TOYREAD0: 274 /* if toy disabled, read save toy time */ 275 if (toy_enabled(s)) { 276 qemu_get_timedate(&tm, s->offset_toy); 277 val = toy_time_to_val_mon(tm); 278 } else { 279 /* read save mon val */ 280 val = s->save_toy_mon; 281 } 282 break; 283 case SYS_TOYREAD1: 284 /* if toy disabled, read save toy time */ 285 if (toy_enabled(s)) { 286 qemu_get_timedate(&tm, s->offset_toy); 287 val = tm.tm_year; 288 } else { 289 /* read save year val */ 290 val = s->save_toy_year; 291 } 292 break; 293 case SYS_TOYMATCH0: 294 val = s->toymatch[0]; 295 break; 296 case SYS_TOYMATCH1: 297 val = s->toymatch[1]; 298 break; 299 case SYS_TOYMATCH2: 300 val = s->toymatch[2]; 301 break; 302 case SYS_RTCCTRL: 303 val = s->cntrctl; 304 break; 305 case SYS_RTCREAD0: 306 /* if rtc disabled, read save rtc time */ 307 if (rtc_enabled(s)) { 308 val = ls7a_rtc_ticks() + s->offset_rtc; 309 } else { 310 val = s->save_rtc; 311 } 312 break; 313 case SYS_RTCMATCH0: 314 val = s->rtcmatch[0]; 315 break; 316 case SYS_RTCMATCH1: 317 val = s->rtcmatch[1]; 318 break; 319 case SYS_RTCMATCH2: 320 val = s->rtcmatch[2]; 321 break; 322 default: 323 val = 0; 324 break; 325 } 326 return val; 327 } 328 329 static void ls7a_rtc_write(void *opaque, hwaddr addr, 330 uint64_t val, unsigned size) 331 { 332 int old_toyen, old_rtcen, new_toyen, new_rtcen; 333 LS7ARtcState *s = LS7A_RTC(opaque); 334 struct tm tm; 335 336 switch (addr) { 337 case SYS_TOYWRITE0: 338 /* it do not support write when toy disabled */ 339 if (toy_enabled(s)) { 340 qemu_get_timedate(&tm, s->offset_toy); 341 tm.tm_sec = FIELD_EX32(val, TOY, SEC); 342 tm.tm_min = FIELD_EX32(val, TOY, MIN); 343 tm.tm_hour = FIELD_EX32(val, TOY, HOUR); 344 tm.tm_mday = FIELD_EX32(val, TOY, DAY); 345 tm.tm_mon = FIELD_EX32(val, TOY, MON) - 1; 346 s->offset_toy = qemu_timedate_diff(&tm); 347 } 348 break; 349 case SYS_TOYWRITE1: 350 if (toy_enabled(s)) { 351 qemu_get_timedate(&tm, s->offset_toy); 352 tm.tm_year = val; 353 s->offset_toy = qemu_timedate_diff(&tm); 354 } 355 break; 356 case SYS_TOYMATCH0: 357 toymatch_write(s, val, 0); 358 break; 359 case SYS_TOYMATCH1: 360 toymatch_write(s, val, 1); 361 break; 362 case SYS_TOYMATCH2: 363 toymatch_write(s, val, 2); 364 break; 365 case SYS_RTCCTRL: 366 /* get old ctrl */ 367 old_toyen = toy_enabled(s); 368 old_rtcen = rtc_enabled(s); 369 370 s->cntrctl = val; 371 /* get new ctrl */ 372 new_toyen = toy_enabled(s); 373 new_rtcen = rtc_enabled(s); 374 375 /* 376 * we do not consider if EO changed, as it always set at most time. 377 * toy or rtc enabled should start timer. otherwise, stop timer 378 */ 379 if (old_toyen != new_toyen) { 380 if (new_toyen) { 381 ls7a_toy_start(s); 382 } else { 383 ls7a_toy_stop(s); 384 } 385 } 386 if (old_rtcen != new_rtcen) { 387 if (new_rtcen) { 388 ls7a_rtc_start(s); 389 } else { 390 ls7a_rtc_stop(s); 391 } 392 } 393 break; 394 case SYS_RTCWRTIE0: 395 if (rtc_enabled(s)) { 396 s->offset_rtc = val - ls7a_rtc_ticks(); 397 } 398 break; 399 case SYS_RTCMATCH0: 400 rtcmatch_write(s, val, 0); 401 break; 402 case SYS_RTCMATCH1: 403 rtcmatch_write(s, val, 1); 404 break; 405 case SYS_RTCMATCH2: 406 rtcmatch_write(s, val, 2); 407 break; 408 default: 409 break; 410 } 411 } 412 413 static const MemoryRegionOps ls7a_rtc_ops = { 414 .read = ls7a_rtc_read, 415 .write = ls7a_rtc_write, 416 .endianness = DEVICE_LITTLE_ENDIAN, 417 .valid = { 418 .min_access_size = 4, 419 .max_access_size = 4, 420 }, 421 }; 422 423 static void toy_timer_cb(void *opaque) 424 { 425 LS7ARtcState *s = opaque; 426 427 if (toy_enabled(s)) { 428 qemu_irq_raise(s->irq); 429 } 430 } 431 432 static void rtc_timer_cb(void *opaque) 433 { 434 LS7ARtcState *s = opaque; 435 436 if (rtc_enabled(s)) { 437 qemu_irq_raise(s->irq); 438 } 439 } 440 441 static void ls7a_rtc_realize(DeviceState *dev, Error **errp) 442 { 443 int i; 444 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 445 LS7ARtcState *d = LS7A_RTC(sbd); 446 memory_region_init_io(&d->iomem, NULL, &ls7a_rtc_ops, 447 (void *)d, "ls7a_rtc", 0x100); 448 449 sysbus_init_irq(sbd, &d->irq); 450 451 sysbus_init_mmio(sbd, &d->iomem); 452 for (i = 0; i < TIMER_NUMS; i++) { 453 d->toymatch[i] = 0; 454 d->rtcmatch[i] = 0; 455 d->toy_timer[i] = timer_new_ms(rtc_clock, toy_timer_cb, d); 456 d->rtc_timer[i] = timer_new_ms(rtc_clock, rtc_timer_cb, d); 457 } 458 d->offset_toy = 0; 459 d->offset_rtc = 0; 460 d->save_toy_mon = 0; 461 d->save_toy_year = 0; 462 d->save_rtc = 0; 463 464 } 465 466 static int ls7a_rtc_pre_save(void *opaque) 467 { 468 LS7ARtcState *s = LS7A_RTC(opaque); 469 470 ls7a_toy_stop(s); 471 ls7a_rtc_stop(s); 472 473 return 0; 474 } 475 476 static int ls7a_rtc_post_load(void *opaque, int version_id) 477 { 478 LS7ARtcState *s = LS7A_RTC(opaque); 479 if (toy_enabled(s)) { 480 ls7a_toy_start(s); 481 } 482 483 if (rtc_enabled(s)) { 484 ls7a_rtc_start(s); 485 } 486 487 return 0; 488 } 489 490 static const VMStateDescription vmstate_ls7a_rtc = { 491 .name = "ls7a_rtc", 492 .version_id = 1, 493 .minimum_version_id = 1, 494 .pre_save = ls7a_rtc_pre_save, 495 .post_load = ls7a_rtc_post_load, 496 .fields = (VMStateField[]) { 497 VMSTATE_INT64(offset_toy, LS7ARtcState), 498 VMSTATE_INT64(offset_rtc, LS7ARtcState), 499 VMSTATE_UINT64(save_toy_mon, LS7ARtcState), 500 VMSTATE_UINT64(save_toy_year, LS7ARtcState), 501 VMSTATE_UINT64(save_rtc, LS7ARtcState), 502 VMSTATE_UINT32_ARRAY(toymatch, LS7ARtcState, TIMER_NUMS), 503 VMSTATE_UINT32_ARRAY(rtcmatch, LS7ARtcState, TIMER_NUMS), 504 VMSTATE_UINT32(cntrctl, LS7ARtcState), 505 VMSTATE_END_OF_LIST() 506 } 507 }; 508 509 static void ls7a_rtc_class_init(ObjectClass *klass, void *data) 510 { 511 DeviceClass *dc = DEVICE_CLASS(klass); 512 dc->vmsd = &vmstate_ls7a_rtc; 513 dc->realize = ls7a_rtc_realize; 514 dc->desc = "ls7a rtc"; 515 } 516 517 static const TypeInfo ls7a_rtc_info = { 518 .name = TYPE_LS7A_RTC, 519 .parent = TYPE_SYS_BUS_DEVICE, 520 .instance_size = sizeof(LS7ARtcState), 521 .class_init = ls7a_rtc_class_init, 522 }; 523 524 static void ls7a_rtc_register_types(void) 525 { 526 type_register_static(&ls7a_rtc_info); 527 } 528 529 type_init(ls7a_rtc_register_types) 530