The following enables the DS1337 RTC clock found on octeon boards.

I've tested it on my DSR-500 and would love to hear about tests on other
machines.

Comments? Okays?


Index: conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/arch/octeon/conf/GENERIC,v
retrieving revision 1.11
diff -u -p -r1.11 GENERIC
--- conf/GENERIC        24 Oct 2013 20:47:08 -0000      1.11
+++ conf/GENERIC        30 Dec 2013 12:42:02 -0000
@@ -31,6 +31,8 @@ clock0                at mainbus0
 iobus0         at mainbus0
 uartbus0       at mainbus0
 
+octrtc0                at mainbus0
+
 octcf0         at iobus0
 octrng0                at iobus0
 
Index: conf/files.octeon
===================================================================
RCS file: /cvs/src/sys/arch/octeon/conf/files.octeon,v
retrieving revision 1.16
diff -u -p -r1.16 files.octeon
--- conf/files.octeon   4 Nov 2013 14:07:16 -0000       1.16
+++ conf/files.octeon   30 Dec 2013 12:42:02 -0000
@@ -48,6 +48,11 @@ attach       cpu at mainbus
 device clock
 attach clock at mainbus
 
+# TOD cloc 
+device octrtc
+attach octrtc at mainbus
+file   arch/octeon/dev/octrtc.c                        octrtc
+
 define iobus {[base = -1]}
 device iobus
 attach iobus at mainbus
Index: dev/octrtc.c
===================================================================
RCS file: dev/octrtc.c
diff -N dev/octrtc.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ dev/octrtc.c        30 Dec 2013 12:42:03 -0000
@@ -0,0 +1,218 @@
+/*     $OpenBSD$       */
+
+/*
+ * Copyright (c) 2013 Paul Irofti.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/timetc.h>
+
+#include <machine/bus.h>
+#include <machine/autoconf.h>
+#include <machine/octeonvar.h>
+
+#ifdef OCTRTC_DEBUG    /* VERY VERBOSE */
+#define DPRINTF(x)     printf x
+#else
+#define DPRINTF(x)
+#endif
+
+#define MIO_TWS_SW_TWSI        0x0001180000001000ULL
+#define OCTRTC_REG     0x68
+
+struct octrtc_softc {
+       struct device           sc_dev;
+};
+
+struct cfdriver octrtc_cd = {
+       NULL, "octrtc", DV_DULL
+};
+
+int    octrtc_match(struct device *, void *, void *);
+void   octrtc_attach(struct device *, struct device *, void *);
+
+u_int  octrtc_gettime(struct timecounter *);
+int    octrtc_read(uint8_t *, char);
+
+struct cfattach octrtc_ca = {
+       sizeof(struct octrtc_softc), octrtc_match, octrtc_attach,
+};
+
+
+static struct timecounter octrtc_timecounter = {
+       octrtc_gettime,         /* get_timecount */
+       0,                      /* no poll_pps */
+       0xffffffff,             /* counter_mask */
+       100000,                 /* frequency */
+       "DS1337",               /* name */
+       1000,                   /* quality */
+};
+
+
+union mio_tws_sw_twsi_reg {
+       uint64_t reg;
+       struct cvmx_mio_twsx_sw_twsi_s {
+               uint64_t v:1;           /* Valid bit */
+               uint64_t slonly:1;      /* Slave Only Mode */
+               uint64_t eia:1;         /* Extended Internal Address */
+               uint64_t op:4;          /* Opcode field */
+               uint64_t r:1;           /* Read bit or result */
+               uint64_t sovr:1;        /* Size Override */
+               uint64_t size:3;        /* Size in bytes */
+               uint64_t scr:2;         /* Scratch, unused */
+               uint64_t a:10;          /* Address field */
+               uint64_t ia:5;          /* Internal Address */
+               uint64_t eop_ia:3;      /* Extra opcode */
+               uint64_t d:32;          /* Data Field */
+       } field;
+};
+
+
+static inline int bcd2bin(int);
+static inline int
+bcd2bin(int datum)
+{
+       return (datum >> 4) * 10 + (datum & 0x0f);
+}
+
+int
+octrtc_match(struct device *parent, void *match, void *aux)
+{
+       return 1;
+}
+
+void
+octrtc_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct octrtc_softc *sc = (struct octrtc_softc *)self;
+
+       octrtc_timecounter.tc_priv = sc;
+       tc_init(&octrtc_timecounter);
+
+       printf(": DS1337\n");
+}
+
+u_int
+octrtc_gettime(struct timecounter *tc)
+{
+       uint8_t tod[8];
+       uint8_t check;
+       int i, rc;
+
+       int nretries = 2;
+
+       struct clock_ymdhms dt;
+
+       DPRINTF(("\nTOD: "));
+       while (nretries--)
+       {
+               rc = octrtc_read(&tod[0], 1);   /* ia read */
+               if (rc) {
+                       DPRINTF(("octrtc_read(0) failed %d", rc));
+                       return rc;
+               }
+
+               for (i = 1; i < 8; i++) {
+                       rc = octrtc_read(&tod[i], 0);   /* current address */
+                       if (rc) {
+                               DPRINTF(("octrtc_read(%d) failed %d", i, rc));
+                               return rc;
+                       }
+                       DPRINTF(("%#X ", tod[i]));
+               }
+
+               /* Check against time-wrap */
+               rc = octrtc_read(&check, 1);    /* ia read */
+               if (rc) {
+                       DPRINTF(("octrtc_read(check) failed %d", i, rc));
+                       return rc;
+               }
+               if ((check & 0xf) == (tod[0] & 0xf))
+                       break;
+       }
+       DPRINTF(("\n"));
+
+       DPRINTF(("Time: %d %d %d (%d) %02d:%02d:%02d\n",
+           ((tod[5] & 0x80) ? 2000 : 1900) + bcd2bin(tod[6]),  /* year */
+           bcd2bin(tod[5] & 0x1f),     /* month */
+           bcd2bin(tod[4] & 0x3f),     /* day */
+           (tod[3] & 0x7),             /* day of the week */
+           bcd2bin(tod[2] & 0x3f),     /* hour */
+           bcd2bin(tod[1] & 0x7f),     /* minute */
+           bcd2bin(tod[0] & 0x7f)));   /* second */
+
+       dt.dt_year = ((tod[5] & 0x80) ? 2000 : 1900) + bcd2bin(tod[6]);
+       dt.dt_mon = bcd2bin(tod[5] & 0x1f);
+       dt.dt_day = bcd2bin(tod[4] & 0x3f);
+        dt.dt_wday = (tod[3] & 0x7);
+       dt.dt_hour = bcd2bin(tod[2] & 0x3f);
+       if ((tod[2] & 0x40) && (tod[2] & 0x20)) /* adjust AM/PM format */
+               dt.dt_hour = (dt.dt_hour + 12) % 24;
+       dt.dt_min = bcd2bin(tod[1] & 0x7f);
+       dt.dt_sec = bcd2bin(tod[0] & 0x7f);
+
+       return clock_ymdhms_to_secs(&dt);
+}
+
+int
+octrtc_read(uint8_t *data, char ia)
+{
+       int nretries = 5;
+       union mio_tws_sw_twsi_reg twsi;
+
+again:
+       twsi.reg = 0;
+       twsi.field.v = 1;
+       twsi.field.r = 1;
+       twsi.field.sovr = 1;
+       twsi.field.a = OCTRTC_REG;
+       if (ia) {
+               twsi.field.op = 1;
+       }
+
+       octeon_xkphys_write_8(MIO_TWS_SW_TWSI, twsi.reg);
+       /* The 1st bit is cleared when the operation is complete */
+       do {
+               delay(1000);
+               twsi.reg = octeon_xkphys_read_8(MIO_TWS_SW_TWSI);
+       } while (twsi.field.v);
+       DPRINTF(("%#llX ", twsi.reg));
+
+       /* 
+        * The data field is in the upper 32 bits and we're only
+        * interested in the first byte.
+        */
+       *data = twsi.field.d & 0xff;
+
+       /* 8th bit is the read result: 1 = success, 0 = failure */
+       if (twsi.field.r == 0) {
+               /*
+                * Lost arbitration : 0x38, 0x68, 0xB0, 0x78
+                * Core busy as slave: 0x80, 0x88, 0xA0, 0xA8, 0xB8, 0xC0, 0xC8
+                */
+               if (*data == 0x38 || *data == 0x68 || *data == 0xB0 ||
+                   *data == 0x78 || *data == 0x80 || *data == 0x88 ||
+                   *data == 0xA0 || *data == 0xA8 || *data == 0xB8 ||
+                   *data == 0xC0 || *data == 0xC8)
+                       if (nretries--)
+                               goto again;
+               return EIO;
+       }
+
+       return 0;
+}

Reply via email to