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 [richard@sleepie.demon.co.uk]
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