lkml.org 
[lkml]   [1997]   [Jan]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subjectdiffs to make RTC work on the alpha

following are some diffs which enable the usage of the RTC on the
alpha. all the functionality only gets invoked if CONFIG_RTC=y. what
it does is switch the timer on the alpha to the interval timer (irq 0)
and send RTC interrupts to the rtc driver. to deal with milo and
spurious interrupts at startup, it turns off the RTC at startup and
turns it back on on reboot.

in addition, i've added some space to /proc/interrupts to deal with
the jillions of interrupts that now get reported. they'll also roll
over properly now on the alpha.

finally, i've added a fudge to rtc.c so that ARC time gets reported
correctly. if somebody's not using ARC time on an alpha, let me know,
and i'll make it a config option.

i've tested the diffs on a udb 166. the interval timer gets set a
little faster than the RTC timer (i think the BogoMIPS number goes up
a little). other than that, everything seems to work fine. even
better, i've yet to get the ARC clock confused since applying the
patch and using hwclock. this used to happen fairly regularly using
clock before.

it would be nice if people would test the diffs on other alphas
(expecially eb164 types as the relevant palcode is somewhat
different). if nobody has problems, i'll send the patch off to linus.

at the very least, the patch should apply cleanly to both 2.1.20 and
2.1.21.

---------------------------
# apply with patch -d /usr/src/linux -p2
#
--- ./linux/include/linux/timex.h.save Thu Jan 9 01:37:10 1997
+++ ./linux/include/linux/timex.h Sun Jan 12 19:13:32 1997
@@ -17,6 +17,9 @@
/*
* Modification history timex.h
*
+ * 9 Jan 97 Adrian Sun
+ * Shifted LATCH define to allow access to alpha machines.
+ *
* 26 Sep 94 David L. Mills
* Added defines for hybrid phase/frequency-lock loop.
*
@@ -122,15 +125,17 @@
#define PPS_VALID 120 /* pps signal watchdog max (s) */
#define MAXGLITCH 30 /* pps signal glitch max (s) */

+/* LATCH is used in the interval timer setup. based on the RTC, this
+ * CLOCK_TICK_RATE results in ~1050HZ instead of 1024HZ on the alpha. */
+#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
+#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
+
#ifndef __alpha__
/*
* This definitively is wrong for the Alpha and none of the
* kernel code seems to reference this anymore.
*/
-#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
#define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */
-#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
-
#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
<< (SHIFT_SCALE-SHIFT_HZ)) / HZ)
--- ./linux/drivers/char/rtc.c.save Mon Dec 23 23:56:42 1996
+++ ./linux/drivers/char/rtc.c Sun Jan 12 23:25:38 1997
@@ -35,6 +35,14 @@
#define RTC_IRQ 8 /* Can't see this changing soon. */
#define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */

+/* ARC time has a different starting epoch.
+ * is this always right for alphas? */
+#ifdef __alpha__
+#define ARCFUDGE 20
+#else
+#define ARCFUDGE 0
+#endif
+
/*
* Note that *all* calls to CMOS_READ and CMOS_WRITE are done with
* interrupts disabled. Due to the index-port/data-port (0x70/0x71)
@@ -336,7 +344,7 @@

copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time));

- yrs = rtc_tm.tm_year + 1900;
+ yrs = rtc_tm.tm_year + 1900 + ARCFUDGE;
mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */
day = rtc_tm.tm_mday;
hrs = rtc_tm.tm_hour;
@@ -726,6 +734,9 @@
*/
if (rtc_tm->tm_year <= 69)
rtc_tm->tm_year += 100;
+
+ /* this should get optimized away if ARCFUDGE == 0 */
+ rtc_tm->tm_year -= ARCFUDGE;

rtc_tm->tm_mon--;
}
--- ./linux/arch/alpha/kernel/irq.c.save Thu Nov 21 22:19:35 1996
+++ ./linux/arch/alpha/kernel/irq.c Mon Jan 13 22:09:52 1997
@@ -26,7 +26,12 @@
#include <asm/bitops.h>
#include <asm/dma.h>

-extern void timer_interrupt(struct pt_regs * regs);
+#ifdef CONFIG_RTC
+#define TIMER_IRQ 0
+#define RTC_IRQ 8
+#else
+extern void timer_interrupt(int, void *, struct pt_regs * regs);
+#endif

#if NR_IRQS > 64
# error Unable to handle more than 64 irq levels.
@@ -133,6 +138,9 @@
/*
* Initial irq handlers.
*/
+#ifdef CONFIG_RTC
+static struct irqaction timer_irq = { NULL, 0, 0, NULL, NULL, NULL};
+#endif
static struct irqaction *irq_action[NR_IRQS];

int get_irq_list(char *buf)
@@ -144,7 +152,7 @@
action = irq_action[i];
if (!action)
continue;
- len += sprintf(buf+len, "%2d: %8d %c %s",
+ len += sprintf(buf+len, "%2d: %10u %c %s",
i, kstat.interrupts[i],
(action->flags & SA_INTERRUPT) ? '+' : ' ',
action->name);
@@ -212,7 +220,12 @@
shared = 1;
}

- action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
+#ifdef CONFIG_RTC
+ if (irq == TIMER_IRQ)
+ action = &timer_irq;
+ else
+#endif
+ action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
GFP_KERNEL);
if (!action)
return -ENOMEM;
@@ -646,7 +659,9 @@
{
int i;

- irqs &= irq_mask & ~1; /* always mask out irq 0---it's the unused timer */
+ /* as irq 0 & 8 handling don't use this function, i'm not altering the
+ * following if CONFIG_RTC=y */
+ irqs &= irq_mask & ~1; /* always mask out irq 0---it's the unused timer */
#ifdef CONFIG_ALPHA_P2K
irqs &= ~(1 << 8); /* mask out irq 8 since that's the unused RTC input to PIC */
#endif
@@ -686,7 +701,11 @@
printk("Interprocessor interrupt? You must be kidding\n");
break;
case 1:
- timer_interrupt(&regs);
+#ifdef CONFIG_RTC /* re-route IRQ 8 to RTC handler */
+ handle_irq(RTC_IRQ, &regs);
+#else
+ timer_interrupt(0, NULL, &regs);
+#endif
return;
case 2:
machine_check(vector, la_ptr, &regs);
--- ./linux/arch/alpha/kernel/time.c.save Wed Jan 8 23:56:02 1997
+++ ./linux/arch/alpha/kernel/time.c Sun Jan 12 01:43:58 1997
@@ -10,6 +10,8 @@
* 1995-03-26 Markus Kuhn
* fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
* precision CMOS clock update
+ * 1997-01-09 Adrian Sun
+ * use interval timer if CONFIG_RTC=y
*/
#include <linux/errno.h>
#include <linux/sched.h>
@@ -61,7 +63,7 @@
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
-void timer_interrupt(struct pt_regs * regs)
+void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
{
__u32 delta, now;

@@ -125,6 +127,10 @@

void time_init(void)
{
+#ifdef CONFIG_RTC
+ unsigned char save_control;
+ void (*irq_handler)(int, void *, struct pt_regs *);
+#endif
unsigned int year, mon, day, hour, min, sec;
int i;

@@ -178,6 +184,21 @@
state.scaled_ticks_per_cycle = ((unsigned long) HZ << FIX_SHIFT) / hwrpb->cycle_freq;
state.max_cycles_per_tick = (2 * hwrpb->cycle_freq) / HZ;
state.last_rtc_update = 0;
+
+#ifdef CONFIG_RTC
+ /* turn off RTC interrupts before /dev/rtc is initialized */
+ save_control = CMOS_READ(RTC_CONTROL);
+ save_control &= ~RTC_PIE;
+ save_control &= ~RTC_AIE;
+ save_control &= ~RTC_UIE;
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_READ(RTC_INTR_FLAGS);
+
+ /* setup interval timer */
+ irq_handler = timer_interrupt;
+ if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL))
+ panic("Could not allocate timer IRQ!");
+#endif
}

/*
--- ./linux/arch/alpha/kernel/process.c.save Sun Jan 12 01:09:58 1997
+++ ./linux/arch/alpha/kernel/process.c Sun Jan 12 18:17:42 1997
@@ -26,6 +26,10 @@
#include <linux/mman.h>
#include <linux/elfcore.h>

+#ifdef CONFIG_RTC
+#include <linux/mc146818rtc.h>
+#endif
+
#include <asm/reg.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -53,6 +57,24 @@

void hard_reset_now(void)
{
+#ifdef CONFIG_RTC /* reset rtc to defaults */
+ unsigned char control;
+ unsigned long flags;
+
+ /* i'm not sure if i really need to disable interrupts here */
+ save_flags(flags);
+ cli();
+ /* reset periodic interrupt frequency */
+ CMOS_WRITE(0x26, RTC_FREQ_SELECT);
+
+ /* turn on periodic interrupts */
+ control = CMOS_READ(RTC_CONTROL);
+ control |= RTC_PIE;
+ CMOS_WRITE(control, RTC_CONTROL);
+ CMOS_READ(RTC_INTR_FLAGS);
+ restore_flags(flags);
+#endif
+
#if defined(CONFIG_ALPHA_SRM) && defined(CONFIG_ALPHA_ALCOR)
/* who said DEC engineer's have no sense of humor? ;-)) */
*(int *) GRU_RESET = 0x0000dead;
--- ./linux/arch/alpha/kernel/setup.c.save Thu Jan 9 09:24:55 1997
+++ ./linux/arch/alpha/kernel/setup.c Fri Jan 10 00:17:15 1997
@@ -22,6 +22,11 @@
#include <linux/delay.h>
#include <linux/config.h> /* CONFIG_ALPHA_LCA etc */

+#ifdef CONFIG_RTC
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#endif
+
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
@@ -83,9 +88,16 @@
outb(0x18, 0x41);
#endif

+#ifdef CONFIG_RTC /* setup interval timer if /dev/rtc is being used */
+ outb(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */
+ outb(LATCH & 0xff, 0x40); /* LSB */
+ outb(LATCH >> 8, 0x40); /* MSB */
+ request_region(0x40, 0x20, "timer");
+#else
outb(0x36, 0x43); /* counter 0: system timer */
outb(0x00, 0x40);
outb(0x00, 0x40);
+#endif

outb(0xb6, 0x43); /* counter 2: speaker */
outb(0x31, 0x42);


\
 
 \ /
  Last update: 2005-03-22 13:38    [W:0.036 / U:1.044 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site