123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- /*
- * abcrtc.c
- *
- * ABC-bus interface to the real-time clock
- * Very loosely based on the virtual RTC in abc80sim.
- */
- #include "common.h"
- #include "io.h"
- #include "abcio.h"
- #include "systime.h"
- #include "console.h"
- #define RTC_DEVSEL 54
- #define RTC_CALLBACK_MASK ((1 << 8)|(1 << 2)|(1 << 0))
- #define RTC_MAGIC 211
- /* Command and status register bits */
- enum rtc_cmd_status {
- RTC_READY = 0x01,
- RTC_ID = 0x02, /* INP(0) shows magic number */
- RTC_PROGRAM = 0x04, /* (Ready to) program RTC */
- RTC_START_WRITE = 0x40,
- RTC_START_READ = 0x80
- };
- static uint8_t rdbuf[8];
- static uint8_t wrbuf[8];
- static bool need_program; /* Programming is handled at non-IRQ prio */
- static void rtc_latch_time(void)
- {
- struct tms tms = get_systime();
- rdbuf[0] = 20; /* Only 20xx years supported */
- rdbuf[1] = tms.tm_year - 20;
- rdbuf[2] = tms.tm_mon;
- rdbuf[3] = tms.tm_mday;
- rdbuf[4] = tms.tm_hour;
- rdbuf[5] = tms.tm_min;
- rdbuf[6] = tms_sec(tms);
- rdbuf[7] = (tms.hold.tm_tick * ((100ULL << 32) >> 15)) >> 32; /* 1/100 s */
- }
- static void rtc_store_time(void)
- {
- struct tms tms;
- /* XXX: should probably do data validation here, even an error bit */
- memset(&tms, 0, sizeof tms);
- tms.tm_year = wrbuf[1] + 20;
- tms.tm_mon = wrbuf[2];
- tms.tm_mday = wrbuf[3];
- tms.tm_hour = wrbuf[4];
- tms.tm_min = wrbuf[5];
- tms.tm_2sec = wrbuf[6] >> 1;
- tms.hold.tm_1sec = wrbuf[6] & 1;
- tms.hold.tm_tick = (wrbuf[7] * ((1ULL << (15+32))/100)) >> 32;
- set_systime(tms);
- do_write_rtc = true;
- }
- static ABC_CALLBACK(rtc_do_program_ready)
- {
- dev->inp_data[1] |= RTC_PROGRAM;
- ABC_INP1_DATA = dev->inp_data[1];
- }
- static ABC_CALLBACK(rtc_do_id)
- {
- /* Called on end of data read */
- dev->inp_data[1] |= RTC_ID;
- ABC_INP1_DATA = dev->inp_data[1];
- }
- static ABC_CALLBACK(rtc_do_command)
- {
- if (data & RTC_PROGRAM) {
- dev->inp_data[1] &= ~RTC_PROGRAM;
- ABC_INP1_DATA = dev->inp_data[1];
- rtc_store_time();
- }
- if (data & RTC_START_WRITE) {
- abc_setup_out_queue(dev, &wrbuf, 8, dev->inp_data[1]|RTC_START_WRITE);
- }
- if (data & RTC_START_READ) {
- dev->inp_data[1] &= ~RTC_ID;
- ABC_INP1_DATA = dev->inp_data[1];
- rtc_latch_time();
- abc_setup_inp_queue(dev, &rdbuf, 8, dev->inp_data[1]|RTC_START_READ);
- }
- }
- static struct abc_dev rtc_iodev = {
- .callback_mask = RTC_CALLBACK_MASK,
- .status_first_inp_mask = (uint8_t)~RTC_START_READ,
- .status_first_out_mask = (uint8_t)~RTC_START_WRITE,
- .inp_en = 3,
- .inp_data_def = RTC_MAGIC,
- .inp_data[1] = RTC_READY|RTC_ID,
- .callback_out[0] = rtc_do_program_ready,
- .callback_out[2] = rtc_do_command,
- .callback_inp[0] = rtc_do_id
- };
- void rtc_abc_init(void)
- {
- abc_register(&rtc_iodev, RTC_DEVSEL);
- }
|