summaryrefslogtreecommitdiffstats
path: root/sys/mips
diff options
context:
space:
mode:
authorjchandra <jchandra@FreeBSD.org>2010-08-25 13:37:55 +0000
committerjchandra <jchandra@FreeBSD.org>2010-08-25 13:37:55 +0000
commitd2b87ab5767b4dd49984883d979dd28c459b7968 (patch)
treeec1cb3bf62bf5621b0da8c0886c2fdee2a301c4c /sys/mips
parent90304603520c92ca0b6224d4b717754045be3bd1 (diff)
downloadFreeBSD-src-d2b87ab5767b4dd49984883d979dd28c459b7968.zip
FreeBSD-src-d2b87ab5767b4dd49984883d979dd28c459b7968.tar.gz
Provide timecounter based on XLR PIC timer.
- Use timer 7 in XLR PIC as a 32 counter - provide pic_init_timer(), pic_set_timer(), pic_timer_count32() and pic_timer_count() PIC timer operations. - register this timer as platform_timecounter on rmi platform.
Diffstat (limited to 'sys/mips')
-rw-r--r--sys/mips/rmi/pic.h52
-rw-r--r--sys/mips/rmi/xlr_machdep.c22
2 files changed, 74 insertions, 0 deletions
diff --git a/sys/mips/rmi/pic.h b/sys/mips/rmi/pic.h
index 35a8cd1..d8860c5 100644
--- a/sys/mips/rmi/pic.h
+++ b/sys/mips/rmi/pic.h
@@ -100,6 +100,8 @@
#define PIC_TIMER_MAXVAL_1(i) (PIC_TIMER_MAXVAL_1_BASE + (i))
#define PIC_TIMER_COUNT_0(i) (PIC_TIMER_COUNT_0_BASE + (i))
#define PIC_TIMER_COUNT_1(i) (PIC_TIMER_COUNT_0_BASE + (i))
+#define PIC_TIMER_HZ 66000000U
+
/*
* We use a simple mapping form PIC interrupts to CPU IRQs.
@@ -241,4 +243,54 @@ void pic_setup_intr(int picintr, int irq, uint32_t cpumask)
mtx_unlock_spin(&xlr_pic_lock);
}
+static __inline void
+pic_init_timer(int timer)
+{
+ xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
+ uint32_t val;
+
+ mtx_lock_spin(&xlr_pic_lock);
+ val = xlr_read_reg(mmio, PIC_CTRL);
+ val |= (1 << (8 + timer));
+ xlr_write_reg(mmio, PIC_CTRL, val);
+ mtx_unlock_spin(&xlr_pic_lock);
+}
+
+static __inline void
+pic_set_timer(int timer, uint64_t maxval)
+{
+ xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
+
+ xlr_write_reg(mmio, PIC_TIMER_MAXVAL_0(timer),
+ (maxval & 0xffffffff));
+ xlr_write_reg(mmio, PIC_TIMER_MAXVAL_1(timer),
+ (maxval >> 32) & 0xffffffff);
+}
+
+static __inline uint32_t
+pic_timer_count32(int timer)
+ {
+ xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
+
+ return (xlr_read_reg(mmio, PIC_TIMER_COUNT_0(timer)));
+}
+
+/*
+ * The timer can wrap 32 bits between the two reads, so we
+ * need additional logic to detect that.
+ */
+static __inline uint64_t
+pic_timer_count(int timer)
+{
+ xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
+ uint32_t tu1, tu2, tl;
+
+ tu1 = xlr_read_reg(mmio, PIC_TIMER_COUNT_1(timer));
+ tl = xlr_read_reg(mmio, PIC_TIMER_COUNT_0(timer));
+ tu2 = xlr_read_reg(mmio, PIC_TIMER_COUNT_1(timer));
+ if (tu2 != tu1)
+ tl = xlr_read_reg(mmio, PIC_TIMER_COUNT_0(timer));
+ return (((uint64_t)tu2 << 32) | tl);
+}
+
#endif /* _RMI_PIC_H_ */
diff --git a/sys/mips/rmi/xlr_machdep.c b/sys/mips/rmi/xlr_machdep.c
index f3f380e..dd50b92 100644
--- a/sys/mips/rmi/xlr_machdep.c
+++ b/sys/mips/rmi/xlr_machdep.c
@@ -278,14 +278,31 @@ mips_init(void)
mutex_init();
}
+u_int
+platform_get_timecount(struct timecounter *tc __unused)
+{
+
+ return (0xffffffffU - pic_timer_count32(PIC_CLOCK_TIMER));
+}
+
static void
xlr_pic_init(void)
{
+ struct timecounter pic_timecounter = {
+ platform_get_timecount, /* get_timecount */
+ 0, /* no poll_pps */
+ ~0U, /* counter_mask */
+ PIC_TIMER_HZ, /* frequency */
+ "XLRPIC", /* name */
+ 2000, /* quality (adjusted in code) */
+ };
xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET);
int i, level, irq;
mtx_init(&xlr_pic_lock, "pic", NULL, MTX_SPIN);
xlr_write_reg(mmio, PIC_CTRL, 0);
+
+ /* Initialize all IRT entries */
for (i = 0; i < PIC_NUM_IRTS; i++) {
irq = PIC_INTR_TO_IRQ(i);
level = PIC_IRQ_IS_EDGE_TRIGGERED(irq);
@@ -300,6 +317,11 @@ xlr_pic_init(void)
xlr_write_reg(mmio, PIC_IRT_1(i), (level << 30) | (1 << 6) |
irq);
}
+
+ /* Setup timer 7 of PIC as a timestamp, no interrupts */
+ pic_init_timer(PIC_CLOCK_TIMER);
+ pic_set_timer(PIC_CLOCK_TIMER, ~UINT64_C(0));
+ platform_timecounter = &pic_timecounter;
}
static void
OpenPOWER on IntegriCloud