abcrtc.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /*
  2. * abcrtc.c
  3. *
  4. * ABC-bus interface to the real-time clock
  5. * Very loosely based on the virtual RTC in abc80sim.
  6. */
  7. #include "fw.h"
  8. #include "io.h"
  9. #include "abcio.h"
  10. #include "systime.h"
  11. #include "console.h"
  12. #define RTC_DEVSEL 54
  13. #define RTC_CALLBACK_MASK ((1 << 8)|(1 << 2)|(1 << 0))
  14. #define RTC_MAGIC 211
  15. /* Command and status register bits */
  16. enum rtc_cmd_status {
  17. RTC_READY = 0x01,
  18. RTC_ID = 0x02, /* INP(0) shows magic number */
  19. RTC_PROGRAM = 0x04, /* (Ready to) program RTC */
  20. RTC_START_WRITE = 0x40,
  21. RTC_START_READ = 0x80
  22. };
  23. static uint8_t rdbuf[8];
  24. static uint8_t wrbuf[8];
  25. static bool need_program; /* Programming is handled at non-IRQ prio */
  26. static void rtc_latch_time(void)
  27. {
  28. struct tms tms = get_systime();
  29. rdbuf[0] = 20; /* Only 20xx years supported */
  30. rdbuf[1] = tms.tm_year - 20;
  31. rdbuf[2] = tms.tm_mon;
  32. rdbuf[3] = tms.tm_mday;
  33. rdbuf[4] = tms.tm_hour;
  34. rdbuf[5] = tms.tm_min;
  35. rdbuf[6] = tms_sec(tms);
  36. rdbuf[7] = (tms.hold.tm_tick * ((100ULL << 32) >> 15)) >> 32; /* 1/100 s */
  37. }
  38. static void rtc_store_time(void)
  39. {
  40. struct tms tms;
  41. /* XXX: should probably do data validation here, even an error bit */
  42. memset(&tms, 0, sizeof tms);
  43. tms.tm_year = wrbuf[1] + 20;
  44. tms.tm_mon = wrbuf[2];
  45. tms.tm_mday = wrbuf[3];
  46. tms.tm_hour = wrbuf[4];
  47. tms.tm_min = wrbuf[5];
  48. tms.tm_2sec = wrbuf[6] >> 1;
  49. tms.hold.tm_1sec = wrbuf[6] & 1;
  50. tms.hold.tm_tick = (wrbuf[7] * ((1ULL << (15+32))/100)) >> 32;
  51. set_systime(tms);
  52. do_write_rtc = true;
  53. }
  54. static ABC_CALLBACK(rtc_do_program_ready)
  55. {
  56. dev->inp_data[1] |= RTC_PROGRAM;
  57. ABC_INP1_DATA = dev->inp_data[1];
  58. }
  59. static ABC_CALLBACK(rtc_do_id)
  60. {
  61. /* Called on end of data read */
  62. dev->inp_data[1] |= RTC_ID;
  63. ABC_INP1_DATA = dev->inp_data[1];
  64. }
  65. static ABC_CALLBACK(rtc_do_command)
  66. {
  67. if (data & RTC_PROGRAM) {
  68. dev->inp_data[1] &= ~RTC_PROGRAM;
  69. ABC_INP1_DATA = dev->inp_data[1];
  70. rtc_store_time();
  71. }
  72. if (data & RTC_START_WRITE) {
  73. abc_setup_out_queue(dev, &wrbuf, 8, dev->inp_data[1]|RTC_START_WRITE);
  74. }
  75. if (data & RTC_START_READ) {
  76. dev->inp_data[1] &= ~RTC_ID;
  77. ABC_INP1_DATA = dev->inp_data[1];
  78. rtc_latch_time();
  79. abc_setup_inp_queue(dev, &rdbuf, 8, dev->inp_data[1]|RTC_START_READ);
  80. }
  81. }
  82. static struct abc_dev rtc_iodev = {
  83. .callback_mask = RTC_CALLBACK_MASK,
  84. .status_first_inp_mask = (uint8_t)~RTC_START_READ,
  85. .status_first_out_mask = (uint8_t)~RTC_START_WRITE,
  86. .inp_en = 3,
  87. .inp_data_def = RTC_MAGIC,
  88. .inp_data[1] = RTC_READY|RTC_ID,
  89. .callback_out[0] = rtc_do_program_ready,
  90. .callback_out[2] = rtc_do_command,
  91. .callback_inp[0] = rtc_do_id
  92. };
  93. void rtc_abc_init(void)
  94. {
  95. abc_register(&rtc_iodev, RTC_DEVSEL);
  96. }