|
@@ -0,0 +1,82 @@
|
|
|
+/*
|
|
|
+ * abcrtc.c
|
|
|
+ *
|
|
|
+ * ABC-bus interface to the real-time clock
|
|
|
+ * Very loosely based on the virtual RTC in abc80sim.
|
|
|
+ */
|
|
|
+
|
|
|
+#include "fw.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))
|
|
|
+
|
|
|
+#define RTC_MAGIC 0xd3
|
|
|
+
|
|
|
+/* Command and status register bits */
|
|
|
+enum rtc_cmd_status {
|
|
|
+ RTC_READY = 0x01,
|
|
|
+ RTC_ID = 0x02, /* INP(0) shows magic number */
|
|
|
+ RTC_PROGRAM = 0x04,
|
|
|
+ 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 ABC_CALLBACK(rtc_do_id)
|
|
|
+{
|
|
|
+ /* Called on end of data read */
|
|
|
+ ABC_INP1_DATA = dev->inp_data[1] |= RTC_ID;
|
|
|
+}
|
|
|
+
|
|
|
+static ABC_CALLBACK(rtc_do_command)
|
|
|
+{
|
|
|
+ if (data & RTC_PROGRAM) {
|
|
|
+ need_program = true;
|
|
|
+ ABC_INP1_DATA = dev->inp_data[1] &= ~RTC_READY;
|
|
|
+ }
|
|
|
+ if (data & RTC_START_WRITE) {
|
|
|
+ abc_setup_out_queue(dev, &wrbuf, 8, dev->inp_data[1]|RTC_START_WRITE);
|
|
|
+ }
|
|
|
+ if (data & RTC_START_READ) {
|
|
|
+ rtc_latch_time();
|
|
|
+ abc_setup_inp_queue(dev, &rdbuf, 8,
|
|
|
+ (dev->inp_data[1] & ~RTC_ID)|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[2] = rtc_do_command,
|
|
|
+ .callback_inp[0] = rtc_do_id
|
|
|
+};
|
|
|
+
|
|
|
+void rtc_abc_init(void)
|
|
|
+{
|
|
|
+ abc_register(&rtc_iodev, RTC_DEVSEL);
|
|
|
+}
|