OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [mips/] [vr4181/] [common/] [time.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * Copyright 2001 MontaVista Software Inc.
3
 * Author: jsun@mvista.com or jsun@junsun.net
4
 *
5
 * rtc and time ops for vr4181.  Part of code is drived from
6
 * linux-vr, originally written  by Bradley D. LaRonde & Michael Klar.
7
 *
8
 * This program is free software; you can redistribute  it and/or modify it
9
 * under  the terms of  the GNU General  Public License as published by the
10
 * Free Software Foundation;  either version 2 of the  License, or (at your
11
 * option) any later version.
12
 *
13
 */
14
 
15
#include <linux/kernel.h>
16
#include <linux/spinlock.h>
17
#include <linux/param.h>                        /* for HZ */
18
#include <linux/time.h>
19
#include <linux/interrupt.h>
20
 
21
#include <asm/system.h>
22
#include <asm/time.h>
23
 
24
#include <asm/vr4181/vr4181.h>
25
 
26
#define COUNTS_PER_JIFFY ((32768 + HZ/2) / HZ)
27
 
28
/*
29
 * RTC ops
30
 */
31
 
32
extern spinlock_t rtc_lock;
33
 
34
/* per VR41xx docs, bad data can be read if between 2 counts */
35
static inline unsigned short
36
read_time_reg(volatile unsigned short *reg)
37
{
38
        unsigned short value;
39
        do {
40
                value = *reg;
41
                barrier();
42
        } while (value != *reg);
43
        return value;
44
}
45
 
46
static unsigned long
47
vr4181_rtc_get_time(void)
48
{
49
        unsigned short regh, regm, regl;
50
 
51
        // why this crazy order, you ask?  to guarantee that neither m
52
        // nor l wrap before all 3 read
53
        do {
54
                regm = read_time_reg(VR4181_ETIMEMREG);
55
                barrier();
56
                regh = read_time_reg(VR4181_ETIMEHREG);
57
                barrier();
58
                regl = read_time_reg(VR4181_ETIMELREG);
59
        } while (regm != read_time_reg(VR4181_ETIMEMREG));
60
        return ((regh << 17) | (regm << 1) | (regl >> 15));
61
}
62
 
63
static int
64
vr4181_rtc_set_time(unsigned long timeval)
65
{
66
        unsigned short intreg;
67
        unsigned long flags;
68
 
69
        spin_lock_irqsave(&rtc_lock, flags);
70
        intreg = *VR4181_RTCINTREG & 0x05;
71
        barrier();
72
        *VR4181_ETIMELREG = timeval << 15;
73
        *VR4181_ETIMEMREG = timeval >> 1;
74
        *VR4181_ETIMEHREG = timeval >> 17;
75
        barrier();
76
        // assume that any ints that just triggered are invalid, since the
77
        // time value is written non-atomically in 3 separate regs
78
        *VR4181_RTCINTREG = 0x05 ^ intreg;
79
        spin_unlock_irqrestore(&rtc_lock, flags);
80
 
81
        return 0;
82
}
83
 
84
 
85
/*
86
 * timer interrupt routine (wrapper)
87
 *
88
 * we need our own interrupt routine because we need to clear
89
 * RTC1 interrupt.
90
 */
91
static void
92
vr4181_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
93
{
94
        /* Clear the interrupt. */
95
        *VR4181_RTCINTREG = 0x2;
96
 
97
        /* call the generic one */
98
        timer_interrupt(irq, dev_id, regs);
99
}
100
 
101
 
102
/*
103
 * vr4181_time_init:
104
 *
105
 * We pick the following choices:
106
 *   . we use elapsed timer as the RTC.  We set some reasonable init data since
107
 *     it does not persist across reset
108
 *   . we use RTC1 as the system timer interrupt source.
109
 *   . we use CPU counter for fast_gettimeoffset and we calivrate the cpu
110
 *     frequency.  In other words, we use calibrate_div64_gettimeoffset().
111
 *   . we use our own timer interrupt routine which clears the interrupt
112
 *     and then calls the generic high-level timer interrupt routine.
113
 *
114
 */
115
 
116
extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
117
 
118
static void
119
vr4181_timer_setup(struct irqaction *irq)
120
{
121
        /* over-write the handler to be our own one */
122
        irq->handler = vr4181_timer_interrupt;
123
 
124
        /* sets up the frequency */
125
        *VR4181_RTCL1LREG = COUNTS_PER_JIFFY;
126
        *VR4181_RTCL1HREG = 0;
127
 
128
        /* and ack any pending ints */
129
        *VR4181_RTCINTREG = 0x2;
130
 
131
        /* setup irqaction */
132
        setup_irq(VR4181_IRQ_INT1, irq);
133
 
134
}
135
 
136
void
137
vr4181_init_time(void)
138
{
139
        /* setup hookup functions */
140
        rtc_get_time = vr4181_rtc_get_time;
141
        rtc_set_time = vr4181_rtc_set_time;
142
 
143
        board_timer_setup = vr4181_timer_setup;
144
}
145
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.