Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
m68k
bvme6000
config.c
Go to the documentation of this file.
1
/*
2
* arch/m68k/bvme6000/config.c
3
*
4
* Copyright (C) 1997 Richard Hirst [
[email protected]
]
5
*
6
* Based on:
7
*
8
* linux/amiga/config.c
9
*
10
* Copyright (C) 1993 Hamish Macdonald
11
*
12
* This file is subject to the terms and conditions of the GNU General Public
13
* License. See the file README.legal in the main directory of this archive
14
* for more details.
15
*/
16
17
#include <linux/types.h>
18
#include <linux/kernel.h>
19
#include <
linux/mm.h
>
20
#include <linux/tty.h>
21
#include <
linux/console.h
>
22
#include <linux/linkage.h>
23
#include <
linux/init.h
>
24
#include <
linux/major.h
>
25
#include <
linux/genhd.h
>
26
#include <linux/rtc.h>
27
#include <
linux/interrupt.h
>
28
#include <
linux/bcd.h
>
29
30
#include <asm/bootinfo.h>
31
#include <asm/pgtable.h>
32
#include <asm/setup.h>
33
#include <asm/irq.h>
34
#include <asm/traps.h>
35
#include <asm/rtc.h>
36
#include <asm/machdep.h>
37
#include <
asm/bvme6000hw.h
>
38
39
static
void
bvme6000_get_model(
char
*model);
40
extern
void
bvme6000_sched_init
(
irq_handler_t
handler);
41
extern
unsigned
long
bvme6000_gettimeoffset
(
void
);
42
extern
int
bvme6000_hwclk
(
int
,
struct
rtc_time
*);
43
extern
int
bvme6000_set_clock_mmss
(
unsigned
long
);
44
extern
void
bvme6000_reset
(
void
);
45
void
bvme6000_set_vectors
(
void
);
46
47
/* Save tick handler routine pointer, will point to xtime_update() in
48
* kernel/timer/timekeeping.c, called via bvme6000_process_int() */
49
50
static
irq_handler_t
tick_handler
;
51
52
53
int
bvme6000_parse_bootinfo
(
const
struct
bi_record
*
bi
)
54
{
55
if
(bi->
tag
==
BI_VME_TYPE
)
56
return
0;
57
else
58
return
1;
59
}
60
61
void
bvme6000_reset
(
void
)
62
{
63
volatile
PitRegsPtr
pit = (
PitRegsPtr
)
BVME_PIT_BASE
;
64
65
printk
(
"\r\n\nCalled bvme6000_reset\r\n"
66
"\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r"
);
67
/* The string of returns is to delay the reset until the whole
68
* message is output. */
69
/* Enable the watchdog, via PIT port C bit 4 */
70
71
pit->
pcddr
|= 0x10;
/* WDOG enable */
72
73
while
(1)
74
;
75
}
76
77
static
void
bvme6000_get_model(
char
*model)
78
{
79
sprintf
(model,
"BVME%d000"
,
m68k_cputype
==
CPU_68060
? 6 : 4);
80
}
81
82
/*
83
* This function is called during kernel startup to initialize
84
* the bvme6000 IRQ handling routines.
85
*/
86
static
void
__init
bvme6000_init_IRQ(
void
)
87
{
88
m68k_setup_user_interrupt
(
VEC_USER
, 192);
89
}
90
91
void
__init
config_bvme6000
(
void
)
92
{
93
volatile
PitRegsPtr
pit = (
PitRegsPtr
)
BVME_PIT_BASE
;
94
95
/* Board type is only set by newer versions of vmelilo/tftplilo */
96
if
(!vme_brdtype) {
97
if
(
m68k_cputype
==
CPU_68060
)
98
vme_brdtype =
VME_TYPE_BVME6000
;
99
else
100
vme_brdtype =
VME_TYPE_BVME4000
;
101
}
102
#if 0
103
/* Call bvme6000_set_vectors() so ABORT will work, along with BVMBug
104
* debugger. Note trap_init() will splat the abort vector, but
105
* bvme6000_init_IRQ() will put it back again. Hopefully. */
106
107
bvme6000_set_vectors
();
108
#endif
109
110
mach_max_dma_address
= 0xffffffff;
111
mach_sched_init
=
bvme6000_sched_init
;
112
mach_init_IRQ
= bvme6000_init_IRQ;
113
mach_gettimeoffset
=
bvme6000_gettimeoffset
;
114
mach_hwclk
=
bvme6000_hwclk
;
115
mach_set_clock_mmss
=
bvme6000_set_clock_mmss
;
116
mach_reset
=
bvme6000_reset
;
117
mach_get_model
= bvme6000_get_model;
118
119
printk
(
"Board is %sconfigured as a System Controller\n"
,
120
*
config_reg_ptr
&
BVME_CONFIG_SW1
?
""
:
"not "
);
121
122
/* Now do the PIT configuration */
123
124
pit->
pgcr
= 0x00;
/* Unidirectional 8 bit, no handshake for now */
125
pit->
psrr
= 0x18;
/* PIACK and PIRQ functions enabled */
126
pit->
pacr
= 0x00;
/* Sub Mode 00, H2 i/p, no DMA */
127
pit->
padr
= 0x00;
/* Just to be tidy! */
128
pit->
paddr
= 0x00;
/* All inputs for now (safest) */
129
pit->
pbcr
= 0x80;
/* Sub Mode 1x, H4 i/p, no DMA */
130
pit->
pbdr
= 0xbc | (*
config_reg_ptr
& BVME_CONFIG_SW1 ? 0 : 0x40);
131
/* PRI, SYSCON?, Level3, SCC clks from xtal */
132
pit->
pbddr
= 0xf3;
/* Mostly outputs */
133
pit->
pcdr
= 0x01;
/* PA transceiver disabled */
134
pit->
pcddr
= 0x03;
/* WDOG disable */
135
136
/* Disable snooping for Ethernet and VME accesses */
137
138
bvme_acr_addrctl
= 0;
139
}
140
141
142
irqreturn_t
bvme6000_abort_int
(
int
irq,
void
*
dev_id
)
143
{
144
unsigned
long
*
new
= (
unsigned
long
*)
vectors
;
145
unsigned
long
*old = (
unsigned
long
*)0xf8000000;
146
147
/* Wait for button release */
148
while
(*(
volatile
unsigned
char
*)
BVME_LOCAL_IRQ_STAT
&
BVME_ABORT_STATUS
)
149
;
150
151
*(
new
+4) = *(old+4);
/* Illegal instruction */
152
*(
new
+9) = *(old+9);
/* Trace */
153
*(
new
+47) = *(old+47);
/* Trap #15 */
154
*(
new
+0x1f) = *(old+0x1f);
/* ABORT switch */
155
return
IRQ_HANDLED
;
156
}
157
158
159
static
irqreturn_t
bvme6000_timer_int (
int
irq,
void
*
dev_id
)
160
{
161
volatile
RtcPtr_t
rtc
= (
RtcPtr_t
)
BVME_RTC_BASE
;
162
unsigned
char
msr = rtc->
msr
& 0xc0;
163
164
rtc->
msr
= msr | 0x20;
/* Ack the interrupt */
165
166
return
tick_handler
(irq, dev_id);
167
}
168
169
/*
170
* Set up the RTC timer 1 to mode 2, so T1 output toggles every 5ms
171
* (40000 x 125ns). It will interrupt every 10ms, when T1 goes low.
172
* So, when reading the elapsed time, you should read timer1,
173
* subtract it from 39999, and then add 40000 if T1 is high.
174
* That gives you the number of 125ns ticks in to the 10ms period,
175
* so divide by 8 to get the microsecond result.
176
*/
177
178
void
bvme6000_sched_init
(
irq_handler_t
timer_routine)
179
{
180
volatile
RtcPtr_t
rtc
= (
RtcPtr_t
)
BVME_RTC_BASE
;
181
unsigned
char
msr = rtc->
msr
& 0xc0;
182
183
rtc->
msr
= 0;
/* Ensure timer registers accessible */
184
185
tick_handler
= timer_routine;
186
if
(
request_irq
(
BVME_IRQ_RTC
, bvme6000_timer_int, 0,
187
"timer"
, bvme6000_timer_int))
188
panic
(
"Couldn't register timer int"
);
189
190
rtc->
t1cr_omr
= 0x04;
/* Mode 2, ext clk */
191
rtc->
t1msb
= 39999 >> 8;
192
rtc->
t1lsb
= 39999 & 0xff;
193
rtc->
irr_icr1
&= 0xef;
/* Route timer 1 to INTR pin */
194
rtc->
msr
= 0x40;
/* Access int.cntrl, etc */
195
rtc->
pfr_icr0
= 0x80;
/* Just timer 1 ints enabled */
196
rtc->
irr_icr1
= 0;
197
rtc->
t1cr_omr
= 0x0a;
/* INTR+T1 active lo, push-pull */
198
rtc->
t0cr_rtmr
&= 0xdf;
/* Stop timers in standby */
199
rtc->
msr
= 0;
/* Access timer 1 control */
200
rtc->
t1cr_omr
= 0x05;
/* Mode 2, ext clk, GO */
201
202
rtc->
msr
= msr;
203
204
if
(
request_irq
(
BVME_IRQ_ABORT
,
bvme6000_abort_int
, 0,
205
"abort"
,
bvme6000_abort_int
))
206
panic
(
"Couldn't register abort int"
);
207
}
208
209
210
/* This is always executed with interrupts disabled. */
211
212
/*
213
* NOTE: Don't accept any readings within 5us of rollover, as
214
* the T1INT bit may be a little slow getting set. There is also
215
* a fault in the chip, meaning that reads may produce invalid
216
* results...
217
*/
218
219
unsigned
long
bvme6000_gettimeoffset
(
void
)
220
{
221
volatile
RtcPtr_t
rtc
= (
RtcPtr_t
)
BVME_RTC_BASE
;
222
volatile
PitRegsPtr
pit = (
PitRegsPtr
)
BVME_PIT_BASE
;
223
unsigned
char
msr = rtc->
msr
& 0xc0;
224
unsigned
char
t1int, t1op;
225
unsigned
long
v
= 800000, ov;
226
227
rtc->
msr
= 0;
/* Ensure timer registers accessible */
228
229
do
{
230
ov =
v
;
231
t1int = rtc->
msr
& 0x20;
232
t1op = pit->
pcdr
& 0x04;
233
rtc->
t1cr_omr
|= 0x40;
/* Latch timer1 */
234
v = rtc->
t1msb
<< 8;
/* Read timer1 */
235
v |= rtc->
t1lsb
;
/* Read timer1 */
236
}
while
(t1int != (rtc->
msr
& 0x20) ||
237
t1op != (pit->
pcdr
& 0x04) ||
238
abs
(ov-v) > 80 ||
239
v > 39960);
240
241
v = 39999 -
v
;
242
if
(!t1op)
/* If in second half cycle.. */
243
v += 40000;
244
v /= 8;
/* Convert ticks to microseconds */
245
if
(t1int)
246
v += 10000;
/* Int pending, + 10ms */
247
rtc->
msr
= msr;
248
249
return
v
;
250
}
251
252
/*
253
* Looks like op is non-zero for setting the clock, and zero for
254
* reading the clock.
255
*
256
* struct hwclk_time {
257
* unsigned sec; 0..59
258
* unsigned min; 0..59
259
* unsigned hour; 0..23
260
* unsigned day; 1..31
261
* unsigned mon; 0..11
262
* unsigned year; 00...
263
* int wday; 0..6, 0 is Sunday, -1 means unknown/don't set
264
* };
265
*/
266
267
int
bvme6000_hwclk
(
int
op
,
struct
rtc_time
*
t
)
268
{
269
volatile
RtcPtr_t
rtc
= (
RtcPtr_t
)
BVME_RTC_BASE
;
270
unsigned
char
msr = rtc->
msr
& 0xc0;
271
272
rtc->
msr
= 0x40;
/* Ensure clock and real-time-mode-register
273
* are accessible */
274
if
(op)
275
{
/* Write.... */
276
rtc->
t0cr_rtmr
= t->
tm_year
%4;
277
rtc->
bcd_tenms
= 0;
278
rtc->
bcd_sec
=
bin2bcd
(t->
tm_sec
);
279
rtc->
bcd_min
=
bin2bcd
(t->
tm_min
);
280
rtc->
bcd_hr
=
bin2bcd
(t->
tm_hour
);
281
rtc->
bcd_dom
=
bin2bcd
(t->
tm_mday
);
282
rtc->
bcd_mth
=
bin2bcd
(t->
tm_mon
+ 1);
283
rtc->
bcd_year
=
bin2bcd
(t->
tm_year
%100);
284
if
(t->
tm_wday
>= 0)
285
rtc->
bcd_dow
=
bin2bcd
(t->
tm_wday
+1);
286
rtc->
t0cr_rtmr
= t->
tm_year
%4 | 0x08;
287
}
288
else
289
{
/* Read.... */
290
do
{
291
t->
tm_sec
=
bcd2bin
(rtc->
bcd_sec
);
292
t->
tm_min
=
bcd2bin
(rtc->
bcd_min
);
293
t->
tm_hour
=
bcd2bin
(rtc->
bcd_hr
);
294
t->
tm_mday
=
bcd2bin
(rtc->
bcd_dom
);
295
t->
tm_mon
=
bcd2bin
(rtc->
bcd_mth
)-1;
296
t->
tm_year
=
bcd2bin
(rtc->
bcd_year
);
297
if
(t->
tm_year
< 70)
298
t->
tm_year
+= 100;
299
t->
tm_wday
=
bcd2bin
(rtc->
bcd_dow
)-1;
300
}
while
(t->
tm_sec
!=
bcd2bin
(rtc->
bcd_sec
));
301
}
302
303
rtc->
msr
= msr;
304
305
return
0;
306
}
307
308
/*
309
* Set the minutes and seconds from seconds value 'nowtime'. Fail if
310
* clock is out by > 30 minutes. Logic lifted from atari code.
311
* Algorithm is to wait for the 10ms register to change, and then to
312
* wait a short while, and then set it.
313
*/
314
315
int
bvme6000_set_clock_mmss
(
unsigned
long
nowtime)
316
{
317
int
retval
= 0;
318
short
real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
319
unsigned
char
rtc_minutes, rtc_tenms;
320
volatile
RtcPtr_t
rtc
= (
RtcPtr_t
)
BVME_RTC_BASE
;
321
unsigned
char
msr = rtc->
msr
& 0xc0;
322
unsigned
long
flags
;
323
volatile
int
i
;
324
325
rtc->
msr
= 0;
/* Ensure clock accessible */
326
rtc_minutes =
bcd2bin
(rtc->
bcd_min
);
327
328
if
((rtc_minutes < real_minutes
329
? real_minutes - rtc_minutes
330
: rtc_minutes - real_minutes) < 30)
331
{
332
local_irq_save
(flags);
333
rtc_tenms = rtc->
bcd_tenms
;
334
while
(rtc_tenms == rtc->
bcd_tenms
)
335
;
336
for
(i = 0; i < 1000; i++)
337
;
338
rtc->
bcd_min
=
bin2bcd
(real_minutes);
339
rtc->
bcd_sec
=
bin2bcd
(real_seconds);
340
local_irq_restore
(flags);
341
}
342
else
343
retval = -1;
344
345
rtc->
msr
= msr;
346
347
return
retval
;
348
}
349
Generated on Thu Jan 10 2013 13:07:32 for Linux Kernel by
1.8.2