diff -Nru linux/arch/mips/sgi/kernel/setup.c.orig linux/arch/mips/sgi/kernel/setup.c --- linux/arch/mips/sgi/kernel/setup.c.orig Wed May 16 16:51:30 2001 +++ linux/arch/mips/sgi/kernel/setup.c Fri Jun 8 16:58:14 2001 @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -25,6 +24,7 @@ #include #include #include +#include #ifdef CONFIG_REMOTE_DEBUG extern void rs_kgdb_hook(int); @@ -36,9 +36,6 @@ extern void console_setup(char *); #endif -extern unsigned long r4k_interval; /* Cycle counter ticks per 1/HZ seconds */ - -extern struct rtc_ops indy_rtc_ops; void indy_reboot_setup(void); void sgi_volume_set(unsigned char); @@ -117,8 +114,6 @@ sgi_read_status }; -void (*board_time_init)(struct irqaction *irq); - static unsigned long dosample(volatile unsigned char *tcwp, volatile unsigned char *tc2p) { @@ -155,6 +150,7 @@ #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) +extern void rtc_ds1386_init(unsigned long base); void sgi_time_init (struct irqaction *irq) { /* Here we need to calibrate the cycle counter to at least be close. * We don't need to actually register the irq handler because that's @@ -163,7 +159,8 @@ struct sgi_ioc_timers *p; volatile unsigned char *tcwp, *tc2p; unsigned long r4k_ticks[3]; - unsigned long r4k_next; + unsigned long r4k_interval; /* Cycle counter ticks per 1/HZ seconds */ + /* Figure out the r4k offset, the algorithm is very simple * and works in _all_ cases as long as the 8254 counter @@ -207,8 +204,19 @@ printk("%d [%d.%02d MHz CPU]\n", (int) r4k_interval, (int) (r4k_interval / 5000), (int) (r4k_interval % 5000) / 50); - /* Set ourselves up for future interrupts */ - r4k_next = (read_32bit_cp0_register(CP0_COUNT) + r4k_interval); + /* set up the counter frequency */ + mips_counter_frequency = r4k_interval * HZ; + + /* set the base addr for RTC ops */ + rtc_ds1386_init(INDY_CLOCK_REGS); +} + +static void __init sgi_timer_setup(struct irqaction *irq) +{ + unsigned r4k_next; + + r4k_next = (read_32bit_cp0_register(CP0_COUNT) + + mips_counter_frequency / HZ); write_32bit_cp0_register(CP0_COMPARE, r4k_next); change_cp0_status(ST0_IM, ALLINTS); sti (); @@ -224,6 +232,7 @@ #endif board_time_init = sgi_time_init; + board_timer_setup = sgi_timer_setup; /* Init the INDY HPC I/O controller. Need to call this before * fucking with the memory controller because it needs to know the @@ -298,7 +307,6 @@ #endif #endif - rtc_ops = &indy_rtc_ops; kbd_ops = &sgi_kbd_ops; #ifdef CONFIG_PSMOUSE aux_device_present = 0xaa; diff -Nru linux/arch/mips/sgi/kernel/indy_rtc.c.orig linux/arch/mips/sgi/kernel/indy_rtc.c --- linux/arch/mips/sgi/kernel/indy_rtc.c.orig Mon Mar 19 21:17:02 2001 +++ linux/arch/mips/sgi/kernel/indy_rtc.c Fri Jun 8 13:47:45 2001 @@ -1,36 +1,292 @@ /* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. + * Modified for Indy RTC, which is DS-1286. [jsun] + */ + +/*********************************************************************** + * + * Copyright 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + * + * arch/mips/ddb5xxx/common/rtc_ds1386.c + * low-level RTC hookups for s for Dallas 1386 chip. * - * RTC routines for Indy style attached Dallas chip. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. * - * Copyright (C) 1998, 2001 by Ralf Baechle + *********************************************************************** */ -#include -#include -static unsigned char indy_rtc_read_data(unsigned long addr) -{ - volatile unsigned int *rtcregs = (void *)INDY_CLOCK_REGS; - return rtcregs[addr]; +/* + * This file exports a function, rtc_ds1386_init(), which expects an + * uncached base address as the argument. It will set the two function + * pointers expected by the MIPS generic timer code. + */ + +#include +#include +#include + +#include +#include + +#include + +/* + * macro for catching spurious errors. Eable to LL_DEBUG in kernel hacking + * config menu. + */ +#ifdef CONFIG_LL_DEBUG + +#include + +#define MIPS_ASSERT(x) if (!(x)) { panic("MIPS_ASSERT failed at %s:%d\n", __FILE__, __LINE__); } +#define MIPS_VERIFY(x, y) MIPS_ASSERT(x y) +#define MIPS_DEBUG(x) do { x; } while (0) + +#else + +#define MIPS_ASSERT(x) +#define MIPS_VERIFY(x, y) x +#define MIPS_DEBUG(x) + +#endif + + +#define EPOCH 2000 + +#undef BCD_TO_BIN +#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10) + +#undef BIN_TO_BCD +#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10) + +#define READ_RTC(x) *(volatile unsigned char*)(rtc_base+x) +#define WRITE_RTC(x, y) *(volatile unsigned char*)(rtc_base+x) = y + +static unsigned long rtc_base; + +static unsigned long +rtc_ds1386_get_time(void) +{ + u8 byte; + u8 temp; + unsigned int year, month, day, hour, minute, second; + + /* let us freeze external registers */ + byte = READ_RTC(0xB); + byte &= 0x3f; + WRITE_RTC(0xB, byte); + + /* read time data */ + year = BCD_TO_BIN(READ_RTC(0xA)) + EPOCH; + month = BCD_TO_BIN(READ_RTC(0x9) & 0x1f); + day = BCD_TO_BIN(READ_RTC(0x8)); + minute = BCD_TO_BIN(READ_RTC(0x2)); + second = BCD_TO_BIN(READ_RTC(0x1)); + + /* hour is special - deal with it later */ + temp = READ_RTC(0x4); + + /* enable time transfer */ + byte |= 0x80; + WRITE_RTC(0xB, byte); + + /* calc hour */ + if (temp & 0x40) { + /* 12 hour format */ + hour = BCD_TO_BIN(temp & 0x1f); + if (temp & 0x20) hour += 12; /* PM */ + } else { + /* 24 hour format */ + hour = BCD_TO_BIN(temp & 0x3f); + } + + return mktime(year, month, day, hour, minute, second); } -static void indy_rtc_write_data(unsigned char data, unsigned long addr) +void to_tm(unsigned long tim, struct rtc_time * tm); +static int +rtc_ds1386_set_time(unsigned long t) { - volatile unsigned int *rtcregs = (void *)INDY_CLOCK_REGS; + struct rtc_time tm; + u8 byte; + u8 temp; + u8 year, month, day, hour, minute, second; + + /* let us freeze external registers */ + byte = READ_RTC(0xB); + byte &= 0x3f; + WRITE_RTC(0xB, byte); + + /* convert */ + to_tm(t, &tm); - rtcregs[addr] = data; + /* check each field one by one */ + year = BIN_TO_BCD(tm.tm_year - EPOCH); + if (year != READ_RTC(0xA)) { + WRITE_RTC(0xA, year); + } + + temp = READ_RTC(0x9); + month = BIN_TO_BCD(tm.tm_mon); + if (month != (temp & 0x1f)) { + WRITE_RTC( 0x9, + (month & 0x1f) | (temp & ~0x1f) ); + } + + day = BIN_TO_BCD(tm.tm_mday); + if (day != READ_RTC(0x8)) { + WRITE_RTC(0x8, day); + } + + temp = READ_RTC(0x4); + if (temp & 0x40) { + /* 12 hour format */ + hour = 0x40; + if (tm.tm_hour > 12) { + hour |= 0x20 | (BIN_TO_BCD(hour-12) & 0x1f); + } else { + hour |= BIN_TO_BCD(tm.tm_hour); + } + } else { + /* 24 hour format */ + hour = BIN_TO_BCD(tm.tm_hour) & 0x3f; + } + if (hour != temp) WRITE_RTC(0x4, hour); + + minute = BIN_TO_BCD(tm.tm_min); + if (minute != READ_RTC(0x2)) { + WRITE_RTC(0x2, minute); + } + + second = BIN_TO_BCD(tm.tm_sec); + if (second != READ_RTC(0x1)) { + WRITE_RTC(0x1, second); + } + + return 0; } -static int indy_rtc_bcd_mode(void) +void +rtc_ds1386_init(unsigned long base) { - return 0; + unsigned char byte; + + /* remember the base */ + rtc_base = base; + MIPS_ASSERT((rtc_base & 0xe0000000) == KSEG1); + + /* turn on RTC if it is not on */ + byte = READ_RTC(0x9); + if (byte & 0x80) { + byte &= 0x7f; + WRITE_RTC(0x9, byte); + } + + /* enable time transfer */ + byte = READ_RTC(0xB); + byte |= 0x80; + WRITE_RTC(0xB, byte); + + /* set the function pointers */ + rtc_get_time = rtc_ds1386_get_time; + rtc_set_time = rtc_ds1386_set_time; } -struct rtc_ops indy_rtc_ops = { - &indy_rtc_read_data, - &indy_rtc_write_data, - &indy_rtc_bcd_mode + +/* ================================================== */ +#define TICK_SIZE tick +#define FEBRUARY 2 +#define STARTOFTIME 1970 +#define SECDAY 86400L +#define SECYR (SECDAY * 365) +#define leapyear(year) ((year) % 4 == 0) +#define days_in_year(a) (leapyear(a) ? 366 : 365) +#define days_in_month(a) (month_days[(a) - 1]) + +static int month_days[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +/* + * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) + */ +static void +GregorianDay(struct rtc_time * tm) +{ + int leapsToDate; + int lastYear; + int day; + int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + + lastYear=tm->tm_year-1; + + /* + * Number of leap corrections to apply up to end of last year + */ + leapsToDate = lastYear/4 - lastYear/100 + lastYear/400; + + /* + * This year is a leap year if it is divisible by 4 except when it is + * divisible by 100 unless it is divisible by 400 + * + * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be + */ + if((tm->tm_year%4==0) && + ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) && + (tm->tm_mon>2)) + { + /* + * We are past Feb. 29 in a leap year + */ + day=1; + } + else + { + day=0; + } + + day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + + tm->tm_mday; + + tm->tm_wday=day%7; +} + + +void to_tm(unsigned long tim, struct rtc_time * tm) +{ + register int i; + register long hms, day; + + day = tim / SECDAY; + hms = tim % SECDAY; + + /* Hours, minutes, seconds are easy */ + tm->tm_hour = hms / 3600; + tm->tm_min = (hms % 3600) / 60; + tm->tm_sec = (hms % 3600) % 60; + + /* Number of years in days */ + for (i = STARTOFTIME; day >= days_in_year(i); i++) + day -= days_in_year(i); + tm->tm_year = i; + + /* Number of months in days left */ + if (leapyear(tm->tm_year)) + days_in_month(FEBRUARY) = 29; + for (i = 1; day >= days_in_month(i); i++) + day -= days_in_month(i); + days_in_month(FEBRUARY) = 28; + tm->tm_mon = i; + + /* Days are what is left over (+1) from all that. */ + tm->tm_mday = day + 1; + + /* + * Determine the day of week + */ + GregorianDay(tm); +} diff -Nru linux/arch/mips/sgi/kernel/indyIRQ.S.orig linux/arch/mips/sgi/kernel/indyIRQ.S --- linux/arch/mips/sgi/kernel/indyIRQ.S.orig Sun Jul 9 14:44:37 2000 +++ linux/arch/mips/sgi/kernel/indyIRQ.S Fri Jun 8 13:33:06 2001 @@ -66,8 +66,9 @@ andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero /* Wheee, a timer interrupt. */ - move a0, sp - jal indy_r4k_timer_interrupt + li a0, 7 + move a1, sp + jal ll_timer_interrupt nop # delay slot j ret_from_irq diff -Nru linux/arch/mips/config.in.orig linux/arch/mips/config.in --- linux/arch/mips/config.in.orig Fri Jun 1 19:08:56 2001 +++ linux/arch/mips/config.in Fri Jun 8 14:06:16 2001 @@ -141,7 +141,7 @@ define_bool CONFIG_BOARD_SCACHE y define_bool CONFIG_PC_KEYB y define_bool CONFIG_SGI y - define_bool CONFIG_OLD_TIME_C y + define_bool CONFIG_NEW_TIME_C y define_bool CONFIG_NEW_IRQ y fi if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then diff -Nru linux/include/asm-mips/time.h.orig linux/include/asm-mips/time.h --- linux/include/asm-mips/time.h.orig Thu Apr 19 14:05:18 2001 +++ linux/include/asm-mips/time.h Fri Jun 8 16:54:08 2001 @@ -15,6 +15,9 @@ #ifndef _ASM_TIME_H #define _ASM_TIME_H +#include /* for struct pt_regs */ +#include /* for asmlinkage */ + /* * RTC ops. By default, they point a no-RTC functions. * rtc_get_time - mktime(year, mon, day, hour, min, sec) in seconds.