Update of /cvsroot/linux-vax/kernel-2.4/arch/mips/philips/nino
In directory usw-pr-cvs1:/tmp/cvs-serv20728/mips/philips/nino
Added Files:
Makefile int-handler.S irq.c kgdb.c power.c prom.c reset.c
rtc.c setup.c time.c
Log Message:
synch 2.4.15 commit 39
--- NEW FILE ---
#
# Makefile for the Philips Nino specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
.S.s:
$(CPP) $(AFLAGS) $< -o $@
.S.o:
$(CC) $(AFLAGS) -c $< -o $@
O_TARGET := nino.o
all: nino.o
obj-y := int-handler.o setup.o irq.o time.o reset.o rtc.o prom.o power.o
int-handler.o: int-handler.S
obj-$(CONFIG_REMOTE_DEBUG) += kgdb.o
obj-$(CONFIG_BLK_DEV_INITRD) += ramdisk.o
ramdisk.o:
$(MAKE) -C ramdisk
mv ramdisk/ramdisk.o ramdisk.o
clean:
rm -f *.o
include $(TOPDIR)/Rules.make
--- NEW FILE ---
/*
* linux/arch/mips/philips/nino/int-handler.S
*
* Copyright (C) 1999 Harald Koerfgen
* Copyright (C) 2000 Jim Pick (ji...@ji...)
* Copyright (C) 2001 Steven J. Hill (sj...@re...)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Interrupt handler for Philips Nino.
*/
#include <asm/asm.h>
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
#include <asm/tx3912.h>
.data
.globl HighPriVect
HighPriVect: .word spurious # Reserved
.word io_posnegint0 # IOPOSINT(0) or IONEGINT(0)
.word spurious # CHIDMACNTINT
.word spurious # TELDMACNTINT
.word spurious # SNDDMACNTINT
.word spurious # Reserved
.word io_negint56 # IONEGINT(6) or IONEGINT(5)
.word spurious # Reserved
.word io_posint56 # IOPOSINT(6) or IOPOSINT(5)
.word spurious # Reserved
.word spurious # UARTBRXINT
.word uarta_rx # UARTARXINT
.word spurious # Reserved
.word periodic_timer # PERINT
.word spurious # ALARMINT
.word spurious # POSPWROKINT or NEGPWROKINT
/*
* Here is the entry point to handle all interrupts.
*/
.text
.set noreorder
.align 5
NESTED(nino_handle_int, PT_SIZE, ra)
.set noat
SAVE_ALL
CLI
.set at
/*
* Get pending Interrupts
*/
mfc0 t0, CP0_CAUSE # Get pending interrupts
andi t2, t0, IE_IRQ4 # IRQ4 (high priority)
bne t2, IE_IRQ4, low_priority
nop
/*
* Ok, we've got a high priority interrupt (a.k.a. an external interrupt).
* Read Interrupt Status Register 6 to get vector.
*/
high_priority:
lui t0, %hi(IntStatus6)
lw t1, %lo(IntStatus6)(t0)
andi t1, INT6_INTVECT
la t2, HighPriVect
addu t1, t1, t2
lw t2, 0(t1)
jr t2
nop
/*
* Ok, we've got one of over a hundred other interupts.
*/
low_priority:
lui t0, %hi(IntStatus1)
lw t1, %lo(IntStatus1)(t0)
j handle_it
li a0, 20
/*
* We don't currently handle spurious interrupts.
*/
spurious:
j spurious_interrupt
nop
/*
* We have the IRQ number, dispatch to the real handler.
*/
handle_it: jal do_IRQ
move a1,sp
j ret_from_irq
nop
/************************************
* High priority interrupt mappings *
************************************/
/*
* Periodic timer - IRQ 0
*/
periodic_timer:
j handle_it
li a0, 0
/*
* UARTA RX - IRQ 3
*/
uarta_rx:
j handle_it
li a0, 3
/*
* GPIO Pin 0 transition - IRQ 10
*/
io_posnegint0:
j handle_it
li a0, 10
/*
* GPIO Pin 5 or 6 transition (0-to-1) - IRQ 11
*/
io_posint56:
j handle_it
li a0, 11
/*
* GPIO Pin 5 or 6 transition (1-to-0) - IRQ 12
*/
io_negint56:
j handle_it
li a0, 12
END(nino_handle_int)
--- NEW FILE ---
/*
* linux/arch/mips/philips/nino/irq.c
*
* Copyright (C) 1992 Linus Torvalds
* Copyright (C) 1999 Harald Koerfgen
* Copyright (C) 2000 Pavel Machek (pa...@su...)
* Copyright (C) 2001 Steven J. Hill (sj...@re...)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Generic interrupt handler for Philips Nino.
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <asm/bitops.h>
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
#include <asm/tx3912.h>
unsigned long spurious_count = 0;
irq_cpustat_t irq_stat [NR_CPUS];
static inline void mask_irq(unsigned int irq_nr)
{
switch (irq_nr) {
case 0: /* Periodic Timer Interrupt */
IntClear5 = INT5_PERIODICINT;
IntClear6 = INT6_PERIODICINT;
IntEnable6 &= ~INT6_PERIODICINT;
break;
case 3:
/* Serial port receive interrupt */
break;
case 2:
/* Serial port transmit interrupt */
break;
default:
printk( "Attempt to mask unknown IRQ %d?\n", irq_nr );
}
}
static inline void unmask_irq(unsigned int irq_nr)
{
switch (irq_nr) {
case 0:
IntEnable6 |= INT6_PERIODICINT;
break;
case 3:
/* Serial port receive interrupt */
break;
case 2:
/* Serial port transmit interrupt */
break;
default:
printk( "Attempt to unmask unknown IRQ %d?\n", irq_nr );
}
}
void disable_irq(unsigned int irq_nr)
{
unsigned long flags;
save_and_cli(flags);
mask_irq(irq_nr);
restore_flags(flags);
}
void enable_irq(unsigned int irq_nr)
{
unsigned long flags;
save_and_cli(flags);
unmask_irq(irq_nr);
restore_flags(flags);
}
/*
* Pointers to the low-level handlers: first the general ones, then the
* fast ones, then the bad ones.
*/
extern void interrupt(void);
static struct irqaction *irq_action[NR_IRQS] =
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
int get_irq_list(char *buf)
{
int i, len = 0;
struct irqaction *action;
for (i = 0; i < NR_IRQS; i++) {
action = irq_action[i];
if (!action)
continue;
len += sprintf(buf + len, "%2d: %8d %c %s",
i, kstat.irqs[0][i],
(action->flags & SA_INTERRUPT) ? '+' : ' ',
action->name);
for (action = action->next; action; action = action->next) {
len += sprintf(buf + len, ",%s %s",
(action->flags & SA_INTERRUPT) ? " +" : "",
action->name);
}
len += sprintf(buf + len, "\n");
}
return len;
}
atomic_t __mips_bh_counter;
/*
* do_IRQ handles IRQ's that have been installed without the
* SA_INTERRUPT flag: it uses the full signal-handling return
* and runs with other interrupts enabled. All relatively slow
* IRQ's should use this format: notably the keyboard/timer
* routines.
*/
asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
{
struct irqaction *action;
int do_random, cpu;
if (irq == 20) {
if (IntStatus2 & 0xfffff00) {
if (IntStatus2 & 0x0f000000)
return do_IRQ(2, regs);
}
}
cpu = smp_processor_id();
irq_enter(cpu, irq);
kstat.irqs[cpu][irq]++;
if (irq == 20) {
printk("20 %08lx %08lx\n %08lx %08lx\n %08lx\n",
IntStatus1, IntStatus2, IntStatus3,
IntStatus4, IntStatus5 );
printk("20 %08lx %08lx\n %08lx %08lx\n %08lx\n",
IntEnable1, IntEnable2, IntEnable3,
IntEnable4, IntEnable5 );
}
mask_irq(irq);
action = *(irq + irq_action);
if (action) {
if (!(action->flags & SA_INTERRUPT))
__sti();
do_random = 0;
do {
do_random |= action->flags;
action->handler(irq, action->dev_id, regs);
action = action->next;
} while (action);
if (do_random & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
unmask_irq(irq);
__cli();
} else {
IntClear1 = ~0;
IntClear3 = ~0;
IntClear4 = ~0;
IntClear5 = ~0;
unmask_irq(irq);
}
irq_exit(cpu, irq);
/* unmasking and bottom half handling is done magically for us. */
}
/*
* Idea is to put all interrupts
* in a single table and differenciate them just by number.
*/
int setup_nino_irq(int irq, struct irqaction *new)
{
int shared = 0;
struct irqaction *old, **p;
unsigned long flags;
p = irq_action + irq;
if ((old = *p) != NULL) {
/* Can't share interrupts unless both agree to */
if (!(old->flags & new->flags & SA_SHIRQ))
return -EBUSY;
/* Can't share interrupts unless both are same type */
if ((old->flags ^ new->flags) & SA_INTERRUPT)
return -EBUSY;
/* add new interrupt at end of irq queue */
do {
p = &old->next;
old = *p;
} while (old);
shared = 1;
}
if (new->flags & SA_SAMPLE_RANDOM)
rand_initialize_irq(irq);
save_and_cli(flags);
*p = new;
if (!shared) {
unmask_irq(irq);
}
restore_flags(flags);
return 0;
}
int request_irq(unsigned int irq,
void (*handler) (int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id)
{
int retval;
struct irqaction *action;
if (irq >= NR_IRQS)
return -EINVAL;
if (!handler)
return -EINVAL;
action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action)
return -ENOMEM;
action->handler = handler;
action->flags = irqflags;
action->mask = 0;
action->name = devname;
action->next = NULL;
action->dev_id = dev_id;
retval = setup_nino_irq(irq, action);
if (retval)
kfree(action);
return retval;
}
void free_irq(unsigned int irq, void *dev_id)
{
struct irqaction *action, **p;
unsigned long flags;
if (irq >= NR_IRQS) {
printk(KERN_CRIT __FUNCTION__ ": trying to free IRQ%d\n", irq);
return;
}
for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
if (action->dev_id != dev_id)
continue;
/* Found it - now free it */
save_and_cli(flags);
*p = action->next;
if (!irq[irq_action])
mask_irq(irq);
restore_flags(flags);
kfree(action);
return;
}
printk(KERN_CRIT __FUNCTION__ ": trying to free free IRQ%d\n", irq);
}
unsigned long probe_irq_on(void)
{
/* TODO */
return 0;
}
int probe_irq_off(unsigned long irqs)
{
/* TODO */
return 0;
}
void __init init_IRQ(void)
{
irq_setup();
}
--- NEW FILE ---
/*
* linux/arch/mips/philips/nino/kgdb.c
*
* Copyright (C) 2001 Steven J. Hill (sj...@re...)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Kernel debugging on the Philips Nino.
*/
#include <asm/system.h>
#include <asm/tx3912.h>
static int remoteDebugInitialized = 0;
void debugInit(void)
{
/*
* If low-level debugging (before GDB or console operational) is
* configured, then we do not need to re-initialize the UART.
*/
#ifndef CONFIG_DEBUG_LL
earlyInitUartPR31700();
#endif
}
char getDebugChar(void)
{
char buf;
unsigned long int2, flags;
if (!remoteDebugInitialized) {
debugInit();
remoteDebugInitialized = 1;
}
save_and_cli(flags);
int2 = IntEnable2;
IntEnable2 = 0;
while(!(UartA_Ctrl1 & UART_RX_HOLD_FULL));
buf = UartA_Data;
IntEnable2 = int2;
restore_flags(flags);
return buf;
}
int putDebugChar(char c)
{
int i;
unsigned long int2;
if (!remoteDebugInitialized) {
debugInit();
remoteDebugInitialized = 1;
}
int2 = IntEnable2;
IntEnable2 &=
~(INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY);
for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < 10000); i++);
IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY;
UartA_Data = c;
for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < 10000); i++);
IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY;
IntEnable2 = int2;
return 1;
}
--- NEW FILE ---
/*
* linux/arch/mips/philips/nino/power.c
*
* Copyright (C) 2000 Jim Pick <ji...@ji...>
* Copyright (C) 2001 Steven J. Hill (sj...@re...)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Power management routines on the Philips Nino.
*/
#include <asm/tx3912.h>
void nino_wait(void)
{
/* We stop the CPU to conserve power */
PowerControl |= PWR_STOPCPU;
/*
* We wait until an interrupt happens...
*/
/* We resume here */
PowerControl &= ~PWR_STOPCPU;
/* Give ourselves a little delay */
__asm__ __volatile__(
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t");
}
--- NEW FILE ---
/*
* linux/arch/mips/philips/nino/prom.c
*
* Copyright (C) 2001 Steven J. Hill (sj...@re...)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Early initialization code for the Philips Nino.
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <asm/bootinfo.h>
#include <asm/addrspace.h>
#include <asm/page.h>
char arcs_cmdline[COMMAND_LINE_SIZE];
#ifdef CONFIG_FB_TX3912
extern u_long tx3912fb_paddr;
extern u_long tx3912fb_vaddr;
extern u_long tx3912fb_size;
#endif
/* Do basic initialization */
void __init prom_init(int argc, char **argv,
unsigned long magic, int *prom_vec)
{
u_long free_end, mem_size;
u_int i;
/*
* collect args and prepare cmd_line
*/
for (i = 1; i < argc; i++) {
strcat(arcs_cmdline, argv[i]);
if (i < (argc - 1))
strcat(arcs_cmdline, " ");
}
mips_machgroup = MACH_GROUP_PHILIPS;
mips_machtype = MACH_PHILIPS_NINO;
#ifdef CONFIG_NINO_4MB
mem_size = 4 << 20;
#elif CONFIG_NINO_8MB
mem_size = 8 << 20;
#elif CONFIG_NINO_16MB
mem_size = 16 << 20;
#endif
#ifdef CONFIG_FB_TX3912
/*
* The LCD controller requires that the framebuffer
* start address fall within a 1MB segment and is
* aligned on a 16 byte boundary. The way to assure
* this is to place the framebuffer at the end of
* memory and mark it as reserved.
*/
free_end = (mem_size - tx3912fb_size) & PAGE_MASK;
add_memory_region(0, free_end, BOOT_MEM_RAM);
add_memory_region(free_end, (mem_size - free_end), BOOT_MEM_RESERVED);
/*
* Calculate physical and virtual addresses for
* the beginning of the framebuffer.
*/
tx3912fb_paddr = PHYSADDR(free_end);
tx3912fb_vaddr = KSEG1ADDR(free_end);
#else
add_memory_region(0, mem_size, BOOT_MEM_RAM);
#endif
}
void __init prom_free_prom_memory (void)
{
}
--- NEW FILE ---
/*
* linux/arch/mips/philips/nino/reset.c
*
* Copyright (C) 2001 Steven J. Hill (sj...@re...)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Generic restart, halt and power off functions for Philips Nino.
*/
#include <linux/init.h>
#include <asm/reboot.h>
void (*reset_vector)(void) = (void (*)(void)) 0xBFC00000;
void nino_machine_restart(char *command)
{
reset_vector();
}
void nino_machine_halt(void)
{
reset_vector();
}
void nino_machine_power_off(void)
{
reset_vector();
}
void __init setup_nino_reset_vectors(void)
{
_machine_restart = nino_machine_restart;
_machine_halt = nino_machine_halt;
_machine_power_off = nino_machine_power_off;
}
--- NEW FILE ---
/*
* linux/arch/mips/philips/nino/rtc.c
*
* Copyright (C) 2001 Steven J. Hill (sj...@re...)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Functions to access RTC on the Philips Nino.
*/
#include <linux/spinlock.h>
#include <linux/mc146818rtc.h>
static unsigned char nino_rtc_read_data(unsigned long addr)
{
return 0;
}
static void nino_rtc_write_data(unsigned char data, unsigned long addr)
{
}
static int nino_rtc_bcd_mode(void)
{
return 0;
}
struct rtc_ops nino_rtc_ops =
{
&nino_rtc_read_data,
&nino_rtc_write_data,
&nino_rtc_bcd_mode
};
--- NEW FILE ---
/*
* linux/arch/mips/philips/nino/setup.c
*
* Copyright (C) 2001 Steven J. Hill (sj...@re...)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Interrupt and exception initialization for Philips Nino.
*/
#include <linux/console.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/mc146818rtc.h>
#include <linux/sched.h>
#include <asm/addrspace.h>
#include <asm/gdb-stub.h>
#include <asm/irq.h>
#include <asm/wbflush.h>
#include <asm/tx3912.h>
extern struct rtc_ops nino_rtc_ops;
extern void nino_wait(void);
extern void setup_nino_reset_vectors(void);
extern asmlinkage void nino_handle_int(void);
extern int setup_nino_irq(int, struct irqaction *);
void (*board_time_init) (struct irqaction * irq);
#ifdef CONFIG_REMOTE_DEBUG
extern void set_debug_traps(void);
extern void breakpoint(void);
static int remote_debug = 0;
#endif
static void __init nino_irq_setup(void)
{
unsigned int tmp;
/* Turn all interrupts off */
IntEnable1 = 0;
IntEnable2 = 0;
IntEnable3 = 0;
IntEnable4 = 0;
IntEnable5 = 0;
IntEnable6 = 0;
/* Clear all interrupts */
IntClear1 = 0xffffffff;
IntClear2 = 0xffffffff;
IntClear3 = 0xffffffff;
IntClear4 = 0xffffffff;
IntClear5 = 0xffffffff;
IntClear6 = 0xffffffff;
/*
* Enable only the interrupts for the UART and negative
* edge (1-to-0) triggered multi-function I/O pins.
*/
change_cp0_status(ST0_BEV, 0);
tmp = read_32bit_cp0_register(CP0_STATUS);
change_cp0_status(ST0_IM, tmp | IE_IRQ2 | IE_IRQ4);
/* Register the global interrupt handler */
set_except_vector(0, nino_handle_int);
#ifdef CONFIG_REMOTE_DEBUG
if (remote_debug) {
set_debug_traps();
breakpoint();
}
#endif
}
static __init void nino_time_init(struct irqaction *irq)
{
unsigned int scratch = 0;
/*
* Enable periodic interrupts
*/
setup_nino_irq(0, irq);
RTCperiodTimer = PER_TIMER_COUNT;
RTCtimerControl = TIM_ENPERTIMER;
IntEnable5 |= INT5_PERIODICINT;
scratch = inl(TX3912_CLK_CTRL_BASE);
scratch |= TX3912_CLK_CTRL_ENTIMERCLK;
outl(scratch, TX3912_CLK_CTRL_BASE);
/* Enable all interrupts */
IntEnable6 |= INT6_GLOBALEN | INT6_PERIODICINT;
}
void __init nino_setup(void)
{
irq_setup = nino_irq_setup;
board_time_init = nino_time_init;
/* Base address to use for PC type I/O accesses */
mips_io_port_base = KSEG1ADDR(0xB0C00000);
setup_nino_reset_vectors();
/* Function called during process idle (cpu_idle) */
cpu_wait = nino_wait;
#ifdef CONFIG_FB
conswitchp = &dummy_con;
#endif
#ifdef CONFIG_REMOTE_DEBUG
remote_debug = 1;
#endif
rtc_ops = &nino_rtc_ops;
}
--- NEW FILE ---
/*
* linux/arch/mips/philips/nino/time.c
*
* Copyright (C) 1999 Harald Koerfgen
* Copyright (C) 2000 Pavel Machek (pa...@su...)
* Copyright (C) 2001 Steven J. Hill (sj...@re...)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Time handling functinos for Philips Nino.
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/delay.h>
#include <asm/tx3912.h>
extern volatile unsigned long wall_jiffies;
extern rwlock_t xtime_lock;
static struct timeval xbase;
#define USECS_PER_JIFFY (1000000/HZ)
/*
* Poll the Interrupt Status Registers
*/
#undef POLL_STATUS
static unsigned long do_gettimeoffset(void)
{
/*
* This is a kludge
*/
return 0;
}
static
void inline readRTC(unsigned long *high, unsigned long *low)
{
/* read twice, and keep reading till we find two
* the same pairs. This is needed in case the RTC
* was updating its registers and we read a old
* High but a new Low. */
do {
*high = RTChigh & RTC_HIGHMASK;
*low = RTClow;
} while (*high != (RTChigh & RTC_HIGHMASK) || RTClow!=*low);
}
/*
* This version of gettimeofday has near millisecond resolution.
*/
void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
unsigned long high, low;
read_lock_irqsave(&xtime_lock, flags);
// 40 bit RTC, driven by 32khz source:
// +-----------+-----------------------------------------+
// | HHHH.HHHH | LLLL.LLLL.LLLL.LLLL.LMMM.MMMM.MMMM.MMMM |
// +-----------+-----------------------------------------+
readRTC(&high,&low);
tv->tv_sec = (high << 17) | (low >> 15);
tv->tv_usec = (low % 32768) * 1953 / 64;
tv->tv_sec += xbase.tv_sec;
tv->tv_usec += xbase.tv_usec;
tv->tv_usec += do_gettimeoffset();
/*
* xtime is atomically updated in timer_bh. lost_ticks is
* nonzero if the timer bottom half hasnt executed yet.
*/
if (jiffies - wall_jiffies)
tv->tv_usec += USECS_PER_JIFFY;
read_unlock_irqrestore(&xtime_lock, flags);
if (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
tv->tv_sec++;
}
}
void do_settimeofday(struct timeval *tv)
{
write_lock_irq(&xtime_lock);
/* This is revolting. We need to set the xtime.tv_usec
* correctly. However, the value in this location is
* is value at the last tick.
* Discover what correction gettimeofday
* would have done, and then undo it!
*/
tv->tv_usec -= do_gettimeoffset();
if (tv->tv_usec < 0) {
tv->tv_usec += 1000000;
tv->tv_sec--;
}
/* reset RTC to 0 (real time is xbase + RTC) */
xbase = *tv;
RTCtimerControl |= TIM_RTCCLEAR;
RTCtimerControl &= ~TIM_RTCCLEAR;
RTCalarmHigh = RTCalarmLow = ~0UL;
xtime = *tv;
time_state = TIME_BAD;
time_maxerror = MAXPHASE;
time_esterror = MAXPHASE;
write_unlock_irq(&xtime_lock);
}
static int set_rtc_mmss(unsigned long nowtime)
{
int retval = 0;
return retval;
}
/* last time the cmos clock got updated */
static long last_rtc_update = 0;
/*
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
int do_write = 1;
static void
timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
#ifdef POLL_STATUS
static unsigned long old_IntStatus1 = 0;
static unsigned long old_IntStatus3 = 0;
static unsigned long old_IntStatus4 = 0;
static unsigned long old_IntStatus5 = 0;
static int counter = 0;
int i;
new_spircv = SPIData & 0xff;
if ((old_spircv != new_spircv) && (new_spircv != 0xff)) {
printk( "SPIData changed: %x\n", new_spircv );
}
old_spircv = new_spircv;
if (do_write)
SPIData = 0;
#endif
if (!user_mode(regs)) {
if (prof_buffer && current->pid) {
extern int _stext;
unsigned long pc = regs->cp0_epc;
pc -= (unsigned long) &_stext;
pc >>= prof_shift;
/*
* Dont ignore out-of-bounds pc values silently,
* put them into the last histogram slot, so if
* present, they will show up as a sharp peak.
*/
if (pc > prof_len - 1)
pc = prof_len - 1;
atomic_inc((atomic_t *) & prof_buffer[pc]);
}
}
/*
* aaaand... action!
*/
do_timer(regs);
/*
* If we have an externally syncronized Linux clock, then update
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
*/
if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
xtime.tv_usec > 500000 - (tick >> 1) &&
xtime.tv_usec < 500000 + (tick >> 1))
{
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
}
}
static struct irqaction irq0 = {timer_interrupt, SA_INTERRUPT, 0,
"timer", NULL, NULL};
void (*board_time_init) (struct irqaction * irq);
int __init time_init(void)
{
struct timeval starttime;
starttime.tv_sec = mktime(2000, 1, 1, 0, 0, 0);
starttime.tv_usec = 0;
do_settimeofday(&starttime);
board_time_init(&irq0);
return 0;
}
|