Blame view

arch/mips/sni/time.c 4.85 KB
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
1
  #include <linux/types.h>
334955ef9   Ralf Baechle   i8253: Create lin...
2
  #include <linux/i8253.h>
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
3
  #include <linux/interrupt.h>
ca4d3e674   David Howells   MIPS: Add missing...
4
  #include <linux/irq.h>
631330f58   Ralf Baechle   MIPS: Build fix -...
5
  #include <linux/smp.h>
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
6
  #include <linux/time.h>
c9294022a   Thomas Bogendoerfer   [MIPS] SNI: regis...
7
  #include <linux/clockchips.h>
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
8
9
10
  
  #include <asm/sni.h>
  #include <asm/time.h>
4b550488f   Ralf Baechle   [MIPS] Deforest t...
11
  #include <asm-generic/rtc.h>
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
12
13
14
15
  
  #define SNI_CLOCK_TICK_RATE     3686400
  #define SNI_COUNTER2_DIV        64
  #define SNI_COUNTER0_DIV        ((SNI_CLOCK_TICK_RATE / SNI_COUNTER2_DIV) / HZ)
84953b39f   Ralf Baechle   [MIPS] SNI: Conve...
16
17
  static void a20r_set_mode(enum clock_event_mode mode,
                            struct clock_event_device *evt)
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
18
  {
84953b39f   Ralf Baechle   [MIPS] SNI: Conve...
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  	switch (mode) {
  	case CLOCK_EVT_MODE_PERIODIC:
  		*(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34;
  		wmb();
  		*(volatile u8 *)(A20R_PT_CLOCK_BASE +  0) = SNI_COUNTER0_DIV;
  		wmb();
  		*(volatile u8 *)(A20R_PT_CLOCK_BASE +  0) = SNI_COUNTER0_DIV >> 8;
  		wmb();
  
  		*(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0xb4;
  		wmb();
  		*(volatile u8 *)(A20R_PT_CLOCK_BASE +  8) = SNI_COUNTER2_DIV;
  		wmb();
  		*(volatile u8 *)(A20R_PT_CLOCK_BASE +  8) = SNI_COUNTER2_DIV >> 8;
  		wmb();
  
                  break;
          case CLOCK_EVT_MODE_ONESHOT:
          case CLOCK_EVT_MODE_UNUSED:
          case CLOCK_EVT_MODE_SHUTDOWN:
                  break;
          case CLOCK_EVT_MODE_RESUME:
                  break;
          }
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
43
  }
84953b39f   Ralf Baechle   [MIPS] SNI: Conve...
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  static struct clock_event_device a20r_clockevent_device = {
  	.name		= "a20r-timer",
  	.features	= CLOCK_EVT_FEAT_PERIODIC,
  
  	/* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
  
  	.rating		= 300,
  	.irq		= SNI_A20R_IRQ_TIMER,
  	.set_mode	= a20r_set_mode,
  };
  
  static irqreturn_t a20r_interrupt(int irq, void *dev_id)
  {
  	struct clock_event_device *cd = dev_id;
  
  	*(volatile u8 *)A20R_PT_TIM0_ACK = 0;
  	wmb();
  
  	cd->event_handler(cd);
  
  	return IRQ_HANDLED;
  }
  
  static struct irqaction a20r_irqaction = {
  	.handler	= a20r_interrupt,
8b5690f88   Yong Zhang   MIPS: irq: Remove...
69
  	.flags		= IRQF_PERCPU | IRQF_TIMER,
84953b39f   Ralf Baechle   [MIPS] SNI: Conve...
70
71
  	.name		= "a20r-timer",
  };
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
72
73
74
75
  /*
   * a20r platform uses 2 counters to divide the input frequency.
   * Counter 2 output is connected to Counter 0 & 1 input.
   */
84953b39f   Ralf Baechle   [MIPS] SNI: Conve...
76
  static void __init sni_a20r_timer_setup(void)
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
77
  {
84953b39f   Ralf Baechle   [MIPS] SNI: Conve...
78
79
80
  	struct clock_event_device *cd = &a20r_clockevent_device;
  	struct irqaction *action = &a20r_irqaction;
  	unsigned int cpu = smp_processor_id();
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
81

320ab2b0b   Rusty Russell   cpumask: convert ...
82
  	cd->cpumask             = cpumask_of(cpu);
c9294022a   Thomas Bogendoerfer   [MIPS] SNI: regis...
83
  	clockevents_register_device(cd);
84953b39f   Ralf Baechle   [MIPS] SNI: Conve...
84
85
  	action->dev_id = cd;
  	setup_irq(SNI_A20R_IRQ_TIMER, &a20r_irqaction);
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
86
87
88
89
90
91
92
93
94
  }
  
  #define SNI_8254_TICK_RATE        1193182UL
  
  #define SNI_8254_TCSAMP_COUNTER   ((SNI_8254_TICK_RATE / HZ) + 255)
  
  static __init unsigned long dosample(void)
  {
  	u32 ct0, ct1;
11b9d0eca   Ralf Baechle   MIPS: SNI: Fix GC...
95
  	volatile u8 msb;
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
96
97
  
  	/* Start the counter. */
49a89efbb   Ralf Baechle   [MIPS] Fix "no sp...
98
  	outb_p(0x34, 0x43);
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
99
  	outb_p(SNI_8254_TCSAMP_COUNTER & 0xff, 0x40);
49a89efbb   Ralf Baechle   [MIPS] Fix "no sp...
100
  	outb(SNI_8254_TCSAMP_COUNTER >> 8, 0x40);
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
101
102
103
104
105
106
  
  	/* Get initial counter invariant */
  	ct0 = read_c0_count();
  
  	/* Latch and spin until top byte of counter0 is zero */
  	do {
49a89efbb   Ralf Baechle   [MIPS] Fix "no sp...
107
  		outb(0x00, 0x43);
11b9d0eca   Ralf Baechle   MIPS: SNI: Fix GC...
108
  		(void) inb(0x40);
49a89efbb   Ralf Baechle   [MIPS] Fix "no sp...
109
  		msb = inb(0x40);
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
110
111
112
113
  		ct1 = read_c0_count();
  	} while (msb);
  
  	/* Stop the counter. */
49a89efbb   Ralf Baechle   [MIPS] Fix "no sp...
114
  	outb(0x38, 0x43);
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
115
116
117
118
119
120
121
122
123
124
125
126
  	/*
  	 * Return the difference, this is how far the r4k counter increments
  	 * for every 1/HZ seconds. We round off the nearest 1 MHz of master
  	 * clock (= 1000000 / HZ / 2).
  	 */
  	/*return (ct1 - ct0 + (500000/HZ/2)) / (500000/HZ) * (500000/HZ);*/
  	return (ct1 - ct0) / (500000/HZ) * (500000/HZ);
  }
  
  /*
   * Here we need to calibrate the cycle counter to at least be close.
   */
4b550488f   Ralf Baechle   [MIPS] Deforest t...
127
  void __init plat_time_init(void)
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  {
  	unsigned long r4k_ticks[3];
  	unsigned long r4k_tick;
  
  	/*
  	 * Figure out the r4k offset, the algorithm is very simple and works in
  	 * _all_ cases as long as the 8254 counter register itself works ok (as
  	 * an interrupt driving timer it does not because of bug, this is why
  	 * we are using the onchip r4k counter/compare register to serve this
  	 * purpose, but for r4k_offset calculation it will work ok for us).
  	 * There are other very complicated ways of performing this calculation
  	 * but this one works just fine so I am not going to futz around. ;-)
  	 */
  	printk(KERN_INFO "Calibrating system timer... ");
  	dosample();	/* Prime cache. */
  	dosample();	/* Prime cache. */
  	/* Zero is NOT an option. */
  	do {
  		r4k_ticks[0] = dosample();
  	} while (!r4k_ticks[0]);
  	do {
  		r4k_ticks[1] = dosample();
  	} while (!r4k_ticks[1]);
  
  	if (r4k_ticks[0] != r4k_ticks[1]) {
  		printk("warning: timer counts differ, retrying... ");
  		r4k_ticks[2] = dosample();
  		if (r4k_ticks[2] == r4k_ticks[0]
  		    || r4k_ticks[2] == r4k_ticks[1])
  			r4k_tick = r4k_ticks[2];
  		else {
  			printk("disagreement, using average... ");
  			r4k_tick = (r4k_ticks[0] + r4k_ticks[1]
  				   + r4k_ticks[2]) / 3;
  		}
  	} else
  		r4k_tick = r4k_ticks[0];
  
  	printk("%d [%d.%04d MHz CPU]
  ", (int) r4k_tick,
  		(int) (r4k_tick / (500000 / HZ)),
  		(int) (r4k_tick % (500000 / HZ)));
  
  	mips_hpt_frequency = r4k_tick * HZ;
d865bea4d   Ralf Baechle   [MIPS] i8253 PIT ...
172

c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
173
174
175
176
177
  	switch (sni_brd_type) {
  	case SNI_BRD_10:
  	case SNI_BRD_10NEW:
  	case SNI_BRD_TOWER_OASIC:
  	case SNI_BRD_MINITOWER:
84953b39f   Ralf Baechle   [MIPS] SNI: Conve...
178
179
  		sni_a20r_timer_setup();
  		break;
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
180
  	}
231a35d37   Thomas Bogendoerfer   [MIPS] RM: Collec...
181
  	setup_pit_timer();
c066a32a8   Thomas Bogendoerfer   [MIPS] Support fo...
182
  }
4b550488f   Ralf Baechle   [MIPS] Deforest t...
183

d4f587c67   Martin Schwidefsky   timekeeping: Incr...
184
  void read_persistent_clock(struct timespec *ts)
4b550488f   Ralf Baechle   [MIPS] Deforest t...
185
  {
d4f587c67   Martin Schwidefsky   timekeeping: Incr...
186
187
  	ts->tv_sec = -1;
  	ts->tv_nsec = 0;
4b550488f   Ralf Baechle   [MIPS] Deforest t...
188
  }