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