1 |
1623 |
jcastillo |
/*
|
2 |
|
|
* linux/atari/config.c
|
3 |
|
|
*
|
4 |
|
|
* Copyright (C) 1994 Bj”rn Brauel
|
5 |
|
|
*
|
6 |
|
|
* 5/2/94 Roman Hodek:
|
7 |
|
|
* Added setting of time_adj to get a better clock.
|
8 |
|
|
*
|
9 |
|
|
* 5/14/94 Roman Hodek:
|
10 |
|
|
* gettod() for TT
|
11 |
|
|
*
|
12 |
|
|
* 5/15/94 Roman Hodek:
|
13 |
|
|
* hard_reset_now() for Atari (and others?)
|
14 |
|
|
*
|
15 |
|
|
* 94/12/30 Andreas Schwab:
|
16 |
|
|
* atari_sched_init fixed to get precise clock.
|
17 |
|
|
*
|
18 |
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
19 |
|
|
* License. See the file COPYING in the main directory of this archive
|
20 |
|
|
* for more details.
|
21 |
|
|
*/
|
22 |
|
|
|
23 |
|
|
/*
|
24 |
|
|
* Miscellaneous atari stuff
|
25 |
|
|
*/
|
26 |
|
|
|
27 |
|
|
#include <linux/config.h>
|
28 |
|
|
#include <linux/types.h>
|
29 |
|
|
#include <linux/mm.h>
|
30 |
|
|
#include <asm/bootinfo.h>
|
31 |
|
|
#include <linux/mc146818rtc.h>
|
32 |
|
|
#include <linux/kd.h>
|
33 |
|
|
#include <linux/tty.h>
|
34 |
|
|
#include <linux/console.h>
|
35 |
|
|
|
36 |
|
|
#include <asm/atarihw.h>
|
37 |
|
|
#include <asm/atarihdreg.h>
|
38 |
|
|
#include <asm/atariints.h>
|
39 |
|
|
|
40 |
|
|
#include <asm/system.h>
|
41 |
|
|
#include <asm/io.h>
|
42 |
|
|
#include <asm/irq.h>
|
43 |
|
|
#include <asm/pgtable.h>
|
44 |
|
|
#include <asm/machdep.h>
|
45 |
|
|
|
46 |
|
|
extern void atari_sched_init(isrfunc);
|
47 |
|
|
extern int atari_keyb_init(void);
|
48 |
|
|
extern int atari_kbdrate (struct kbd_repeat *);
|
49 |
|
|
extern void atari_kbd_leds (unsigned int);
|
50 |
|
|
extern void atari_init_INTS (void);
|
51 |
|
|
extern int atari_add_isr (unsigned long, isrfunc, int, void *, char *);
|
52 |
|
|
extern int atari_remove_isr (unsigned long, isrfunc, void *);
|
53 |
|
|
extern void atari_enable_irq (unsigned);
|
54 |
|
|
extern void atari_disable_irq (unsigned);
|
55 |
|
|
extern int atari_get_irq_list (char *buf, int len);
|
56 |
|
|
extern unsigned long atari_gettimeoffset (void);
|
57 |
|
|
extern void atari_mste_gettod (int *, int *, int *, int *, int *, int *);
|
58 |
|
|
extern void atari_gettod (int *, int *, int *, int *, int *, int *);
|
59 |
|
|
extern int atari_mste_hwclk (int, struct hwclk_time *);
|
60 |
|
|
extern int atari_hwclk (int, struct hwclk_time *);
|
61 |
|
|
extern int atari_mste_set_clock_mmss (unsigned long);
|
62 |
|
|
extern int atari_set_clock_mmss (unsigned long);
|
63 |
|
|
extern void atari_mksound( unsigned int count, unsigned int ticks );
|
64 |
|
|
extern void atari_reset( void );
|
65 |
|
|
#ifdef CONFIG_BLK_DEV_FD
|
66 |
|
|
extern int atari_floppy_init (void);
|
67 |
|
|
extern void atari_floppy_setup(char *, int *);
|
68 |
|
|
#endif
|
69 |
|
|
extern void atari_waitbut (void);
|
70 |
|
|
extern struct consw fb_con;
|
71 |
|
|
extern struct fb_info *atari_fb_init(long *);
|
72 |
|
|
extern void atari_debug_init (void);
|
73 |
|
|
extern void atari_video_setup(char *, int *);
|
74 |
|
|
|
75 |
|
|
extern void (*kd_mksound)(unsigned int, unsigned int);
|
76 |
|
|
|
77 |
|
|
/* This function tests for the presence of an address, specially a
|
78 |
|
|
* hardware register address. It is called very early in the kernel
|
79 |
|
|
* initialization process, when the VBR register isn't set up yet. On
|
80 |
|
|
* an Atari, it still points to address 0, which is unmapped. So a bus
|
81 |
|
|
* error would cause another bus error while fetching the exception
|
82 |
|
|
* vector, and the CPU would do nothing at all. So we needed to set up
|
83 |
|
|
* a temporary VBR and a vector table for the duration of the test.
|
84 |
|
|
*/
|
85 |
|
|
|
86 |
|
|
static int hwreg_present( volatile void *regp )
|
87 |
|
|
{
|
88 |
|
|
int ret = 0;
|
89 |
|
|
long save_sp, save_vbr;
|
90 |
|
|
long tmp_vectors[3];
|
91 |
|
|
|
92 |
|
|
__asm__ __volatile__
|
93 |
|
|
( "movec %/vbr,%2\n\t"
|
94 |
|
|
"movel #Lberr1,%4@(8)\n\t"
|
95 |
|
|
"movec %4,%/vbr\n\t"
|
96 |
|
|
"movel %/sp,%1\n\t"
|
97 |
|
|
"moveq #0,%0\n\t"
|
98 |
|
|
"tstb %3@\n\t"
|
99 |
|
|
"nop\n\t"
|
100 |
|
|
"moveq #1,%0\n"
|
101 |
|
|
"Lberr1:\n\t"
|
102 |
|
|
"movel %1,%/sp\n\t"
|
103 |
|
|
"movec %2,%/vbr"
|
104 |
|
|
: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
|
105 |
|
|
: "a" (regp), "a" (tmp_vectors)
|
106 |
|
|
);
|
107 |
|
|
|
108 |
|
|
return( ret );
|
109 |
|
|
}
|
110 |
|
|
|
111 |
|
|
#if 0
|
112 |
|
|
static int hwreg_present_bywrite( volatile void *regp,
|
113 |
|
|
unsigned char val )
|
114 |
|
|
|
115 |
|
|
{
|
116 |
|
|
int ret;
|
117 |
|
|
long save_sp, save_vbr;
|
118 |
|
|
static long tmp_vectors[3] = { 0, 0, (long)&&after_test };
|
119 |
|
|
|
120 |
|
|
__asm__ __volatile__
|
121 |
|
|
( "movec %/vbr,%2\n\t" /* save vbr value */
|
122 |
|
|
"movec %4,%/vbr\n\t" /* set up temporary vectors */
|
123 |
|
|
"movel %/sp,%1\n\t" /* save sp */
|
124 |
|
|
"moveq #0,%0\n\t" /* assume not present */
|
125 |
|
|
"moveb %5,%3@\n\t" /* write the hardware reg */
|
126 |
|
|
"cmpb %3@,%5\n\t" /* compare it */
|
127 |
|
|
"seq %0" /* comes here only if reg */
|
128 |
|
|
/* is present */
|
129 |
|
|
: "=d&" (ret), "=r&" (save_sp), "=r&" (save_vbr)
|
130 |
|
|
: "a" (regp), "r" (tmp_vectors), "d" (val)
|
131 |
|
|
);
|
132 |
|
|
after_test:
|
133 |
|
|
__asm__ __volatile__
|
134 |
|
|
( "movel %0,%/sp\n\t" /* restore sp */
|
135 |
|
|
"movec %1,%/vbr" /* restore vbr */
|
136 |
|
|
: : "r" (save_sp), "r" (save_vbr) : "sp"
|
137 |
|
|
);
|
138 |
|
|
|
139 |
|
|
return( ret );
|
140 |
|
|
}
|
141 |
|
|
#endif
|
142 |
|
|
|
143 |
|
|
/* Basically the same, but writes a value into a word register, protected
|
144 |
|
|
* by a bus error handler */
|
145 |
|
|
|
146 |
|
|
static int hwreg_write( volatile void *regp, unsigned short val )
|
147 |
|
|
{
|
148 |
|
|
int ret;
|
149 |
|
|
long save_sp, save_vbr;
|
150 |
|
|
long tmp_vectors[3];
|
151 |
|
|
|
152 |
|
|
__asm__ __volatile__
|
153 |
|
|
( "movec %/vbr,%2\n\t"
|
154 |
|
|
"movel #Lberr2,%4@(8)\n\t"
|
155 |
|
|
"movec %4,%/vbr\n\t"
|
156 |
|
|
"movel %/sp,%1\n\t"
|
157 |
|
|
"moveq #0,%0\n\t"
|
158 |
|
|
"movew %5,%3@\n\t"
|
159 |
|
|
"nop \n\t" /* If this nop isn't present, 'ret' may already be
|
160 |
|
|
* loaded with 1 at the time the bus error
|
161 |
|
|
* happens! */
|
162 |
|
|
"moveq #1,%0\n"
|
163 |
|
|
"Lberr2:\n\t"
|
164 |
|
|
"movel %1,%/sp\n\t"
|
165 |
|
|
"movec %2,%/vbr"
|
166 |
|
|
: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
|
167 |
|
|
: "a" (regp), "a" (tmp_vectors), "g" (val)
|
168 |
|
|
);
|
169 |
|
|
|
170 |
|
|
return( ret );
|
171 |
|
|
}
|
172 |
|
|
|
173 |
|
|
/* ++roman: This is a more elaborate test for an SCC chip, since the plain
|
174 |
|
|
* Medusa board generates DTACK at the SCC's standard addresses, but a SCC
|
175 |
|
|
* board in the Medusa is possible. Also, the addresses where the ST_ESCC
|
176 |
|
|
* resides generate DTACK without the chip, too.
|
177 |
|
|
* The method is to write values into the interrupt vector register, that
|
178 |
|
|
* should be readable without trouble (from channel A!).
|
179 |
|
|
*/
|
180 |
|
|
|
181 |
|
|
static int scc_test( volatile char *ctla )
|
182 |
|
|
{
|
183 |
|
|
if (!hwreg_present( ctla ))
|
184 |
|
|
return( 0 );
|
185 |
|
|
MFPDELAY();
|
186 |
|
|
|
187 |
|
|
*ctla = 2; MFPDELAY();
|
188 |
|
|
*ctla = 0x40; MFPDELAY();
|
189 |
|
|
|
190 |
|
|
*ctla = 2; MFPDELAY();
|
191 |
|
|
if (*ctla != 0x40) return( 0 );
|
192 |
|
|
MFPDELAY();
|
193 |
|
|
|
194 |
|
|
*ctla = 2; MFPDELAY();
|
195 |
|
|
*ctla = 0x60; MFPDELAY();
|
196 |
|
|
|
197 |
|
|
*ctla = 2; MFPDELAY();
|
198 |
|
|
if (*ctla != 0x60) return( 0 );
|
199 |
|
|
|
200 |
|
|
return( 1 );
|
201 |
|
|
}
|
202 |
|
|
|
203 |
|
|
void config_atari(void)
|
204 |
|
|
{
|
205 |
|
|
mach_sched_init = atari_sched_init;
|
206 |
|
|
mach_keyb_init = atari_keyb_init;
|
207 |
|
|
mach_kbdrate = atari_kbdrate;
|
208 |
|
|
mach_kbd_leds = atari_kbd_leds;
|
209 |
|
|
mach_init_INTS = atari_init_INTS;
|
210 |
|
|
mach_add_isr = atari_add_isr;
|
211 |
|
|
mach_remove_isr = atari_remove_isr;
|
212 |
|
|
mach_enable_irq = atari_enable_irq;
|
213 |
|
|
mach_disable_irq = atari_disable_irq;
|
214 |
|
|
mach_get_irq_list = atari_get_irq_list;
|
215 |
|
|
mach_gettimeoffset = atari_gettimeoffset;
|
216 |
|
|
mach_mksound = atari_mksound;
|
217 |
|
|
mach_reset = atari_reset;
|
218 |
|
|
#ifdef CONFIG_BLK_DEV_FD
|
219 |
|
|
mach_floppy_init = atari_floppy_init;
|
220 |
|
|
mach_floppy_setup = atari_floppy_setup;
|
221 |
|
|
#endif
|
222 |
|
|
conswitchp = &fb_con;
|
223 |
|
|
waitbut = atari_waitbut;
|
224 |
|
|
mach_fb_init = atari_fb_init;
|
225 |
|
|
mach_max_dma_address = 0xffffff;
|
226 |
|
|
mach_debug_init = atari_debug_init;
|
227 |
|
|
mach_video_setup = atari_video_setup;
|
228 |
|
|
kd_mksound = atari_mksound;
|
229 |
|
|
|
230 |
|
|
/* ++bjoern:
|
231 |
|
|
* Determine hardware present
|
232 |
|
|
*/
|
233 |
|
|
|
234 |
|
|
printk( "Atari hardware found: " );
|
235 |
|
|
if (is_medusa) {
|
236 |
|
|
/* There's no Atari video hardware on the Medusa, but all the
|
237 |
|
|
* addresses below generate a DTACK so no bus error occurs! */
|
238 |
|
|
}
|
239 |
|
|
else if (hwreg_present( f030_xreg )) {
|
240 |
|
|
ATARIHW_SET(VIDEL_SHIFTER);
|
241 |
|
|
printk( "VIDEL " );
|
242 |
|
|
/* This is a temporary hack: If there is Falcon video
|
243 |
|
|
* hardware, we assume that the ST-DMA serves SCSI instead of
|
244 |
|
|
* ACSI. In the future, there should be a better method for
|
245 |
|
|
* this...
|
246 |
|
|
*/
|
247 |
|
|
ATARIHW_SET(ST_SCSI);
|
248 |
|
|
printk( "STDMA-SCSI " );
|
249 |
|
|
}
|
250 |
|
|
else if (hwreg_present( tt_palette )) {
|
251 |
|
|
ATARIHW_SET(TT_SHIFTER);
|
252 |
|
|
printk( "TT_SHIFTER " );
|
253 |
|
|
}
|
254 |
|
|
else if (hwreg_present( &shifter.bas_hi )) {
|
255 |
|
|
if (hwreg_present( &shifter.bas_lo ) &&
|
256 |
|
|
(shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) {
|
257 |
|
|
ATARIHW_SET(EXTD_SHIFTER);
|
258 |
|
|
printk( "EXTD_SHIFTER " );
|
259 |
|
|
}
|
260 |
|
|
else {
|
261 |
|
|
ATARIHW_SET(STND_SHIFTER);
|
262 |
|
|
printk( "STND_SHIFTER " );
|
263 |
|
|
}
|
264 |
|
|
}
|
265 |
|
|
if (hwreg_present( &mfp.par_dt_reg )) {
|
266 |
|
|
ATARIHW_SET(ST_MFP);
|
267 |
|
|
printk( "ST_MFP " );
|
268 |
|
|
}
|
269 |
|
|
if (hwreg_present( &tt_mfp.par_dt_reg )) {
|
270 |
|
|
ATARIHW_SET(TT_MFP);
|
271 |
|
|
printk( "TT_MFP " );
|
272 |
|
|
}
|
273 |
|
|
if (hwreg_present( &tt_scsi_dma.dma_addr_hi )) {
|
274 |
|
|
ATARIHW_SET(SCSI_DMA);
|
275 |
|
|
printk( "TT_SCSI_DMA " );
|
276 |
|
|
}
|
277 |
|
|
if (hwreg_present( &st_dma.dma_hi )) {
|
278 |
|
|
ATARIHW_SET(STND_DMA);
|
279 |
|
|
printk( "STND_DMA " );
|
280 |
|
|
}
|
281 |
|
|
if (is_medusa || /* The ST-DMA address registers aren't readable
|
282 |
|
|
* on all Medusas, so the test below may fail */
|
283 |
|
|
(hwreg_present( &st_dma.dma_vhi ) &&
|
284 |
|
|
(st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) &&
|
285 |
|
|
st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa &&
|
286 |
|
|
(st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) &&
|
287 |
|
|
st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) {
|
288 |
|
|
ATARIHW_SET(EXTD_DMA);
|
289 |
|
|
printk( "EXTD_DMA " );
|
290 |
|
|
}
|
291 |
|
|
if (hwreg_present( &tt_scsi.scsi_data )) {
|
292 |
|
|
ATARIHW_SET(TT_SCSI);
|
293 |
|
|
printk( "TT_SCSI " );
|
294 |
|
|
}
|
295 |
|
|
if (hwreg_present( &sound_ym.rd_data_reg_sel )) {
|
296 |
|
|
ATARIHW_SET(YM_2149);
|
297 |
|
|
printk( "YM2149 " );
|
298 |
|
|
}
|
299 |
|
|
if (!is_medusa && hwreg_present( &tt_dmasnd.ctrl )) {
|
300 |
|
|
ATARIHW_SET(PCM_8BIT);
|
301 |
|
|
printk( "PCM " );
|
302 |
|
|
}
|
303 |
|
|
if (hwreg_present( (void *)(0xffff8940) )) {
|
304 |
|
|
ATARIHW_SET(CODEC);
|
305 |
|
|
printk( "CODEC " );
|
306 |
|
|
}
|
307 |
|
|
if (hwreg_present( &tt_scc_dma.dma_ctrl ) &&
|
308 |
|
|
#if 0
|
309 |
|
|
/* This test sucks! Who knows some better? */
|
310 |
|
|
(tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
|
311 |
|
|
(tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
|
312 |
|
|
#else
|
313 |
|
|
!is_medusa
|
314 |
|
|
#endif
|
315 |
|
|
) {
|
316 |
|
|
ATARIHW_SET(SCC_DMA);
|
317 |
|
|
printk( "SCC_DMA " );
|
318 |
|
|
}
|
319 |
|
|
if (scc_test( &scc.cha_a_ctrl )) {
|
320 |
|
|
ATARIHW_SET(SCC);
|
321 |
|
|
printk( "SCC " );
|
322 |
|
|
}
|
323 |
|
|
if (scc_test( &st_escc.cha_b_ctrl )) {
|
324 |
|
|
ATARIHW_SET( ST_ESCC );
|
325 |
|
|
printk( "ST_ESCC " );
|
326 |
|
|
}
|
327 |
|
|
if (hwreg_present( &tt_scu.sys_mask )) {
|
328 |
|
|
ATARIHW_SET(SCU);
|
329 |
|
|
/* Assume a VME bus if there's a SCU */
|
330 |
|
|
ATARIHW_SET( VME );
|
331 |
|
|
printk( "VME SCU " );
|
332 |
|
|
}
|
333 |
|
|
if (hwreg_present( (void *)(0xffff9210) )) {
|
334 |
|
|
ATARIHW_SET(ANALOG_JOY);
|
335 |
|
|
printk( "ANALOG_JOY " );
|
336 |
|
|
}
|
337 |
|
|
if (hwreg_present( blitter.halftone )) {
|
338 |
|
|
ATARIHW_SET(BLITTER);
|
339 |
|
|
printk( "BLITTER " );
|
340 |
|
|
}
|
341 |
|
|
if (hwreg_present( (void *)(ATA_HD_BASE+ATA_HD_CMD) )) {
|
342 |
|
|
ATARIHW_SET(IDE);
|
343 |
|
|
printk( "IDE " );
|
344 |
|
|
}
|
345 |
|
|
#if 1 /* This maybe wrong */
|
346 |
|
|
if (!is_medusa &&
|
347 |
|
|
hwreg_present( &tt_microwire.data ) &&
|
348 |
|
|
hwreg_present( &tt_microwire.mask ) &&
|
349 |
|
|
(tt_microwire.mask = 0x7ff,
|
350 |
|
|
tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR,
|
351 |
|
|
tt_microwire.data != 0)) {
|
352 |
|
|
ATARIHW_SET(MICROWIRE);
|
353 |
|
|
while (tt_microwire.mask != 0x7ff) ;
|
354 |
|
|
printk( "MICROWIRE " );
|
355 |
|
|
}
|
356 |
|
|
#endif
|
357 |
|
|
if (hwreg_present( &tt_rtc.regsel )) {
|
358 |
|
|
ATARIHW_SET(TT_CLK);
|
359 |
|
|
printk( "TT_CLK " );
|
360 |
|
|
mach_gettod = atari_gettod;
|
361 |
|
|
mach_hwclk = atari_hwclk;
|
362 |
|
|
mach_set_clock_mmss = atari_set_clock_mmss;
|
363 |
|
|
}
|
364 |
|
|
if (hwreg_present( &mste_rtc.sec_ones)) {
|
365 |
|
|
ATARIHW_SET(MSTE_CLK);
|
366 |
|
|
printk( "MSTE_CLK ");
|
367 |
|
|
mach_gettod = atari_mste_gettod;
|
368 |
|
|
mach_hwclk = atari_mste_hwclk;
|
369 |
|
|
mach_set_clock_mmss = atari_mste_set_clock_mmss;
|
370 |
|
|
}
|
371 |
|
|
if (!is_medusa &&
|
372 |
|
|
hwreg_present( &dma_wd.fdc_speed ) &&
|
373 |
|
|
hwreg_write( &dma_wd.fdc_speed, 0 )) {
|
374 |
|
|
ATARIHW_SET(FDCSPEED);
|
375 |
|
|
printk( "FDC_SPEED ");
|
376 |
|
|
}
|
377 |
|
|
if (!ATARIHW_PRESENT(ST_SCSI)) {
|
378 |
|
|
ATARIHW_SET(ACSI);
|
379 |
|
|
printk( "ACSI " );
|
380 |
|
|
}
|
381 |
|
|
printk("\n");
|
382 |
|
|
|
383 |
|
|
if (m68k_is040or060)
|
384 |
|
|
/* Now it seems to be safe to turn of the tt0 transparent
|
385 |
|
|
* translation (the one that must not be turned off in
|
386 |
|
|
* head.S...)
|
387 |
|
|
*/
|
388 |
|
|
__asm__ volatile ("moveq #0,%/d0;"
|
389 |
|
|
".long 0x4e7b0004;" /* movec d0,itt0 */
|
390 |
|
|
".long 0x4e7b0006;" /* movec d0,dtt0 */
|
391 |
|
|
: /* no outputs */
|
392 |
|
|
: /* no inputs */
|
393 |
|
|
: "d0");
|
394 |
|
|
|
395 |
|
|
/* allocator for memory that must reside in st-ram */
|
396 |
|
|
atari_stram_init ();
|
397 |
|
|
|
398 |
|
|
/* Set up a mapping for the VMEbus address region:
|
399 |
|
|
*
|
400 |
|
|
* VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff
|
401 |
|
|
* (MegaSTE) In both cases, the whole 16 MB chunk is mapped at
|
402 |
|
|
* 0xfe000000 virt., because this can be done with a single
|
403 |
|
|
* transparent translation. On the 68040, lots of often unused
|
404 |
|
|
* page tables would be needed otherwise. On a MegaSTE or similar,
|
405 |
|
|
* the highest byte is stripped off by hardware due to the 24 bit
|
406 |
|
|
* design of the bus.
|
407 |
|
|
*/
|
408 |
|
|
|
409 |
|
|
if (!m68k_is040or060) {
|
410 |
|
|
unsigned long tt1_val;
|
411 |
|
|
tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache
|
412 |
|
|
* inhibit, read and write, FDC mask = 3,
|
413 |
|
|
* FDC val = 4 -> Supervisor only */
|
414 |
|
|
__asm__ __volatile__ ( "pmove %0@,%/tt1" : : "a" (&tt1_val) );
|
415 |
|
|
}
|
416 |
|
|
else {
|
417 |
|
|
__asm__ __volatile__
|
418 |
|
|
( "movel %0,%/d0\n\t"
|
419 |
|
|
".long 0x4e7b0005\n\t" /* movec d0,itt1 */
|
420 |
|
|
".long 0x4e7b0007" /* movec d0,dtt1 */
|
421 |
|
|
:
|
422 |
|
|
: "g" (0xfe00a040) /* Translate 0xfexxxxxx, enable,
|
423 |
|
|
* supervisor only, non-cacheable/
|
424 |
|
|
* serialized, writable */
|
425 |
|
|
: "d0" );
|
426 |
|
|
|
427 |
|
|
}
|
428 |
|
|
}
|
429 |
|
|
|
430 |
|
|
void atari_sched_init (isrfunc timer_routine)
|
431 |
|
|
{
|
432 |
|
|
/* set Timer C data Register */
|
433 |
|
|
mfp.tim_dt_c = INT_TICKS;
|
434 |
|
|
/* start timer C, div = 1:100 */
|
435 |
|
|
mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60;
|
436 |
|
|
/* install interrupt service routine for MFP Timer C */
|
437 |
|
|
add_isr (IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, NULL, "timer");
|
438 |
|
|
}
|
439 |
|
|
|
440 |
|
|
/* ++andreas: gettimeoffset fixed to check for pending interrupt */
|
441 |
|
|
|
442 |
|
|
#define TICK_SIZE 10000
|
443 |
|
|
|
444 |
|
|
/* This is always executed with interrupts disabled. */
|
445 |
|
|
unsigned long atari_gettimeoffset (void)
|
446 |
|
|
{
|
447 |
|
|
unsigned long ticks, offset = 0;
|
448 |
|
|
|
449 |
|
|
/* read MFP timer C current value */
|
450 |
|
|
ticks = mfp.tim_dt_c;
|
451 |
|
|
/* The probability of underflow is less than 2% */
|
452 |
|
|
if (ticks > INT_TICKS - INT_TICKS / 50)
|
453 |
|
|
/* Check for pending timer interrupt */
|
454 |
|
|
if (mfp.int_pn_b & (1 << 5))
|
455 |
|
|
offset = TICK_SIZE;
|
456 |
|
|
|
457 |
|
|
ticks = INT_TICKS - ticks;
|
458 |
|
|
ticks = ticks * 10000L / INT_TICKS;
|
459 |
|
|
|
460 |
|
|
return ticks + offset;
|
461 |
|
|
}
|
462 |
|
|
|
463 |
|
|
|
464 |
|
|
static void
|
465 |
|
|
mste_read(struct MSTE_RTC *val)
|
466 |
|
|
{
|
467 |
|
|
#define COPY(v) val->v=(mste_rtc.v & 0xf)
|
468 |
|
|
do {
|
469 |
|
|
COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
|
470 |
|
|
COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
|
471 |
|
|
COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
|
472 |
|
|
COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
|
473 |
|
|
COPY(year_tens) ;
|
474 |
|
|
/* prevent from reading the clock while it changed */
|
475 |
|
|
} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
|
476 |
|
|
#undef COPY
|
477 |
|
|
}
|
478 |
|
|
|
479 |
|
|
static void
|
480 |
|
|
mste_write(struct MSTE_RTC *val)
|
481 |
|
|
{
|
482 |
|
|
#define COPY(v) mste_rtc.v=val->v
|
483 |
|
|
do {
|
484 |
|
|
COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
|
485 |
|
|
COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
|
486 |
|
|
COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
|
487 |
|
|
COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
|
488 |
|
|
COPY(year_tens) ;
|
489 |
|
|
/* prevent from writing the clock while it changed */
|
490 |
|
|
} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
|
491 |
|
|
#undef COPY
|
492 |
|
|
}
|
493 |
|
|
|
494 |
|
|
#define RTC_READ(reg) \
|
495 |
|
|
({ unsigned char __val; \
|
496 |
|
|
outb(reg,&tt_rtc.regsel); \
|
497 |
|
|
__val = tt_rtc.data; \
|
498 |
|
|
__val; \
|
499 |
|
|
})
|
500 |
|
|
|
501 |
|
|
#define RTC_WRITE(reg,val) \
|
502 |
|
|
do { \
|
503 |
|
|
outb(reg,&tt_rtc.regsel); \
|
504 |
|
|
tt_rtc.data = (val); \
|
505 |
|
|
} while(0)
|
506 |
|
|
|
507 |
|
|
|
508 |
|
|
void atari_mste_gettod (int *yearp, int *monp, int *dayp,
|
509 |
|
|
int *hourp, int *minp, int *secp)
|
510 |
|
|
{
|
511 |
|
|
int hr24=0;
|
512 |
|
|
struct MSTE_RTC val;
|
513 |
|
|
|
514 |
|
|
mste_rtc.mode=(mste_rtc.mode | 1);
|
515 |
|
|
hr24=mste_rtc.mon_tens & 1;
|
516 |
|
|
mste_rtc.mode=(mste_rtc.mode & ~1);
|
517 |
|
|
|
518 |
|
|
mste_read(&val);
|
519 |
|
|
*secp = val.sec_ones + val.sec_tens * 10;
|
520 |
|
|
*minp = val.min_ones + val.min_tens * 10;
|
521 |
|
|
if (hr24)
|
522 |
|
|
*hourp = val.hr_ones + val.hr_tens * 10;
|
523 |
|
|
else {
|
524 |
|
|
*hourp = val.hr_ones + (val.hr_tens & 1) * 10;
|
525 |
|
|
if (val.hr_tens & 2)
|
526 |
|
|
*hourp += 12;
|
527 |
|
|
}
|
528 |
|
|
*dayp = val.day_ones + val.day_tens * 10;
|
529 |
|
|
*monp = val.mon_ones + val.mon_tens * 10;
|
530 |
|
|
*yearp = val.year_ones + val.year_tens * 10 + 80;
|
531 |
|
|
}
|
532 |
|
|
|
533 |
|
|
|
534 |
|
|
void atari_gettod (int *yearp, int *monp, int *dayp,
|
535 |
|
|
int *hourp, int *minp, int *secp)
|
536 |
|
|
{
|
537 |
|
|
unsigned char ctrl;
|
538 |
|
|
unsigned short tos_version;
|
539 |
|
|
|
540 |
|
|
while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ;
|
541 |
|
|
while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ;
|
542 |
|
|
|
543 |
|
|
*secp = RTC_READ(RTC_SECONDS);
|
544 |
|
|
*minp = RTC_READ(RTC_MINUTES);
|
545 |
|
|
*hourp = RTC_READ(RTC_HOURS);
|
546 |
|
|
*dayp = RTC_READ(RTC_DAY_OF_MONTH);
|
547 |
|
|
*monp = RTC_READ(RTC_MONTH);
|
548 |
|
|
*yearp = RTC_READ(RTC_YEAR);
|
549 |
|
|
|
550 |
|
|
ctrl = RTC_READ(RTC_CONTROL);
|
551 |
|
|
|
552 |
|
|
if (!(ctrl & RTC_DM_BINARY)) {
|
553 |
|
|
BCD_TO_BIN(*secp);
|
554 |
|
|
BCD_TO_BIN(*minp);
|
555 |
|
|
BCD_TO_BIN(*hourp);
|
556 |
|
|
BCD_TO_BIN(*dayp);
|
557 |
|
|
BCD_TO_BIN(*monp);
|
558 |
|
|
BCD_TO_BIN(*yearp);
|
559 |
|
|
}
|
560 |
|
|
if (!(ctrl & RTC_24H)) {
|
561 |
|
|
if (*hourp & 0x80) {
|
562 |
|
|
*hourp &= ~0x80;
|
563 |
|
|
*hourp += 12;
|
564 |
|
|
}
|
565 |
|
|
}
|
566 |
|
|
/* Adjust values (let the setup valid) */
|
567 |
|
|
|
568 |
|
|
/* Fetch tos version at Physical 2 */
|
569 |
|
|
/* We my not be able to access this address if the kernel is
|
570 |
|
|
loaded to st ram, since the first page is unmapped. On the
|
571 |
|
|
Medusa this is always the case and there is nothing we can do
|
572 |
|
|
about this, so we just assume the smaller offset. For the TT
|
573 |
|
|
we use the fact that in head.S we have set up a mapping
|
574 |
|
|
0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
|
575 |
|
|
in the last 16MB of the address space. */
|
576 |
|
|
tos_version = is_medusa ? 0xfff : *(unsigned short *)0xFF000002;
|
577 |
|
|
*yearp += (tos_version < 0x306) ? 70 : 68;
|
578 |
|
|
}
|
579 |
|
|
|
580 |
|
|
#define HWCLK_POLL_INTERVAL 5
|
581 |
|
|
|
582 |
|
|
int atari_mste_hwclk( int op, struct hwclk_time *t )
|
583 |
|
|
{
|
584 |
|
|
int hour, year;
|
585 |
|
|
int hr24=0;
|
586 |
|
|
struct MSTE_RTC val;
|
587 |
|
|
|
588 |
|
|
mste_rtc.mode=(mste_rtc.mode | 1);
|
589 |
|
|
hr24=mste_rtc.mon_tens & 1;
|
590 |
|
|
mste_rtc.mode=(mste_rtc.mode & ~1);
|
591 |
|
|
|
592 |
|
|
if (op) {
|
593 |
|
|
/* write: prepare values */
|
594 |
|
|
|
595 |
|
|
val.sec_ones = t->sec % 10;
|
596 |
|
|
val.sec_tens = t->sec / 10;
|
597 |
|
|
val.min_ones = t->min % 10;
|
598 |
|
|
val.min_tens = t->min / 10;
|
599 |
|
|
hour = t->hour;
|
600 |
|
|
val.hr_ones = hour % 10;
|
601 |
|
|
val.hr_tens = hour / 10;
|
602 |
|
|
if (!hr24 && hour > 11) {
|
603 |
|
|
hour -= 12;
|
604 |
|
|
val.hr_ones = hour % 10;
|
605 |
|
|
val.hr_tens = (hour / 10) | 2;
|
606 |
|
|
}
|
607 |
|
|
val.day_ones = t->day % 10;
|
608 |
|
|
val.day_tens = t->day / 10;
|
609 |
|
|
val.mon_ones = (t->mon+1) % 10;
|
610 |
|
|
val.mon_tens = (t->mon+1) / 10;
|
611 |
|
|
year = t->year - 80;
|
612 |
|
|
val.year_ones = year % 10;
|
613 |
|
|
val.year_tens = year / 10;
|
614 |
|
|
val.weekday = t->wday;
|
615 |
|
|
mste_write(&val);
|
616 |
|
|
mste_rtc.mode=(mste_rtc.mode | 1);
|
617 |
|
|
val.year_ones = (year % 4); /* leap year register */
|
618 |
|
|
mste_rtc.mode=(mste_rtc.mode & ~1);
|
619 |
|
|
}
|
620 |
|
|
else {
|
621 |
|
|
mste_read(&val);
|
622 |
|
|
t->sec = val.sec_ones + val.sec_tens * 10;
|
623 |
|
|
t->min = val.min_ones + val.min_tens * 10;
|
624 |
|
|
if (hr24)
|
625 |
|
|
t->hour = val.hr_ones + val.hr_tens * 10;
|
626 |
|
|
else {
|
627 |
|
|
t->hour = val.hr_ones + (val.hr_tens & 1) * 10;
|
628 |
|
|
if (val.hr_tens & 2)
|
629 |
|
|
t->hour += 12;
|
630 |
|
|
}
|
631 |
|
|
t->day = val.day_ones + val.day_tens * 10;
|
632 |
|
|
t->mon = val.mon_ones + val.mon_tens * 10 - 1;
|
633 |
|
|
t->year = val.year_ones + val.year_tens * 10 + 80;
|
634 |
|
|
t->wday = val.weekday;
|
635 |
|
|
}
|
636 |
|
|
return 0;
|
637 |
|
|
}
|
638 |
|
|
|
639 |
|
|
int atari_hwclk( int op, struct hwclk_time *t )
|
640 |
|
|
{
|
641 |
|
|
int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
|
642 |
|
|
unsigned long flags;
|
643 |
|
|
unsigned short tos_version;
|
644 |
|
|
unsigned char ctrl;
|
645 |
|
|
|
646 |
|
|
/* Tos version at Physical 2. See above for explanation why we
|
647 |
|
|
cannot use PTOV(2). */
|
648 |
|
|
tos_version = is_medusa ? 0xfff : *(unsigned short *)0xff000002;
|
649 |
|
|
|
650 |
|
|
ctrl = RTC_READ(RTC_CONTROL); /* control registers are
|
651 |
|
|
* independent from the UIP */
|
652 |
|
|
|
653 |
|
|
if (op) {
|
654 |
|
|
/* write: prepare values */
|
655 |
|
|
|
656 |
|
|
sec = t->sec;
|
657 |
|
|
min = t->min;
|
658 |
|
|
hour = t->hour;
|
659 |
|
|
day = t->day;
|
660 |
|
|
mon = t->mon + 1;
|
661 |
|
|
year = t->year - ((tos_version < 0x306) ? 70 : 68);
|
662 |
|
|
wday = t->wday + (t->wday >= 0);
|
663 |
|
|
|
664 |
|
|
if (!(ctrl & RTC_24H) && hour > 11) {
|
665 |
|
|
hour -= 12;
|
666 |
|
|
hour |= 0x80;
|
667 |
|
|
}
|
668 |
|
|
|
669 |
|
|
if (!(ctrl & RTC_DM_BINARY)) {
|
670 |
|
|
BIN_TO_BCD(sec);
|
671 |
|
|
BIN_TO_BCD(min);
|
672 |
|
|
BIN_TO_BCD(hour);
|
673 |
|
|
BIN_TO_BCD(day);
|
674 |
|
|
BIN_TO_BCD(mon);
|
675 |
|
|
BIN_TO_BCD(year);
|
676 |
|
|
if (wday >= 0) BIN_TO_BCD(wday);
|
677 |
|
|
}
|
678 |
|
|
}
|
679 |
|
|
|
680 |
|
|
/* Reading/writing the clock registers is a bit critical due to
|
681 |
|
|
* the regular update cycle of the RTC. While an update is in
|
682 |
|
|
* progress, registers 0..9 shouldn't be touched.
|
683 |
|
|
* The problem is solved like that: If an update is currently in
|
684 |
|
|
* progress (the UIP bit is set), the process sleeps for a while
|
685 |
|
|
* (50ms). This really should be enough, since the update cycle
|
686 |
|
|
* normally needs 2 ms.
|
687 |
|
|
* If the UIP bit reads as 0, we have at least 244 usecs until the
|
688 |
|
|
* update starts. This should be enough... But to be sure,
|
689 |
|
|
* additionally the RTC_SET bit is set to prevent an update cycle.
|
690 |
|
|
*/
|
691 |
|
|
|
692 |
|
|
while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
|
693 |
|
|
current->state = TASK_INTERRUPTIBLE;
|
694 |
|
|
current->timeout = jiffies + HWCLK_POLL_INTERVAL;
|
695 |
|
|
schedule();
|
696 |
|
|
}
|
697 |
|
|
|
698 |
|
|
save_flags(flags);
|
699 |
|
|
cli();
|
700 |
|
|
RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
|
701 |
|
|
if (!op) {
|
702 |
|
|
sec = RTC_READ( RTC_SECONDS );
|
703 |
|
|
min = RTC_READ( RTC_MINUTES );
|
704 |
|
|
hour = RTC_READ( RTC_HOURS );
|
705 |
|
|
day = RTC_READ( RTC_DAY_OF_MONTH );
|
706 |
|
|
mon = RTC_READ( RTC_MONTH );
|
707 |
|
|
year = RTC_READ( RTC_YEAR );
|
708 |
|
|
wday = RTC_READ( RTC_DAY_OF_WEEK );
|
709 |
|
|
}
|
710 |
|
|
else {
|
711 |
|
|
RTC_WRITE( RTC_SECONDS, sec );
|
712 |
|
|
RTC_WRITE( RTC_MINUTES, min );
|
713 |
|
|
RTC_WRITE( RTC_HOURS, hour );
|
714 |
|
|
RTC_WRITE( RTC_DAY_OF_MONTH, day );
|
715 |
|
|
RTC_WRITE( RTC_MONTH, mon );
|
716 |
|
|
RTC_WRITE( RTC_YEAR, year );
|
717 |
|
|
if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
|
718 |
|
|
}
|
719 |
|
|
RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
|
720 |
|
|
restore_flags(flags);
|
721 |
|
|
|
722 |
|
|
if (!op) {
|
723 |
|
|
/* read: adjust values */
|
724 |
|
|
|
725 |
|
|
if (!(ctrl & RTC_DM_BINARY)) {
|
726 |
|
|
BCD_TO_BIN(sec);
|
727 |
|
|
BCD_TO_BIN(min);
|
728 |
|
|
BCD_TO_BIN(hour);
|
729 |
|
|
BCD_TO_BIN(day);
|
730 |
|
|
BCD_TO_BIN(mon);
|
731 |
|
|
BCD_TO_BIN(year);
|
732 |
|
|
BCD_TO_BIN(wday);
|
733 |
|
|
}
|
734 |
|
|
|
735 |
|
|
if (!(ctrl & RTC_24H)) {
|
736 |
|
|
if (hour & 0x80) {
|
737 |
|
|
hour &= ~0x80;
|
738 |
|
|
hour += 12;
|
739 |
|
|
}
|
740 |
|
|
}
|
741 |
|
|
|
742 |
|
|
t->sec = sec;
|
743 |
|
|
t->min = min;
|
744 |
|
|
t->hour = hour;
|
745 |
|
|
t->day = day;
|
746 |
|
|
t->mon = mon - 1;
|
747 |
|
|
t->year = year + ((tos_version < 0x306) ? 70 : 68);
|
748 |
|
|
t->wday = wday - 1;
|
749 |
|
|
}
|
750 |
|
|
|
751 |
|
|
return( 0 );
|
752 |
|
|
}
|
753 |
|
|
|
754 |
|
|
|
755 |
|
|
int atari_mste_set_clock_mmss (unsigned long nowtime)
|
756 |
|
|
{
|
757 |
|
|
short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
|
758 |
|
|
struct MSTE_RTC val;
|
759 |
|
|
unsigned char rtc_minutes;
|
760 |
|
|
|
761 |
|
|
mste_read(&val);
|
762 |
|
|
rtc_minutes= val.min_ones + val.min_tens * 10;
|
763 |
|
|
if ((rtc_minutes < real_minutes
|
764 |
|
|
? real_minutes - rtc_minutes
|
765 |
|
|
: rtc_minutes - real_minutes) < 30)
|
766 |
|
|
{
|
767 |
|
|
val.sec_ones = real_seconds % 10;
|
768 |
|
|
val.sec_tens = real_seconds / 10;
|
769 |
|
|
val.min_ones = real_minutes % 10;
|
770 |
|
|
val.min_tens = real_minutes / 10;
|
771 |
|
|
mste_write(&val);
|
772 |
|
|
}
|
773 |
|
|
else
|
774 |
|
|
return -1;
|
775 |
|
|
return 0;
|
776 |
|
|
}
|
777 |
|
|
|
778 |
|
|
int atari_set_clock_mmss (unsigned long nowtime)
|
779 |
|
|
{
|
780 |
|
|
int retval = 0;
|
781 |
|
|
short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
|
782 |
|
|
unsigned char save_control, save_freq_select, rtc_minutes;
|
783 |
|
|
|
784 |
|
|
save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
|
785 |
|
|
RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);
|
786 |
|
|
|
787 |
|
|
save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */
|
788 |
|
|
RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2);
|
789 |
|
|
|
790 |
|
|
rtc_minutes = RTC_READ (RTC_MINUTES);
|
791 |
|
|
if (!(save_control & RTC_DM_BINARY))
|
792 |
|
|
BCD_TO_BIN (rtc_minutes);
|
793 |
|
|
|
794 |
|
|
/* Since we're only adjusting minutes and seconds, don't interfere
|
795 |
|
|
with hour overflow. This avoids messing with unknown time zones
|
796 |
|
|
but requires your RTC not to be off by more than 30 minutes. */
|
797 |
|
|
if ((rtc_minutes < real_minutes
|
798 |
|
|
? real_minutes - rtc_minutes
|
799 |
|
|
: rtc_minutes - real_minutes) < 30)
|
800 |
|
|
{
|
801 |
|
|
if (!(save_control & RTC_DM_BINARY))
|
802 |
|
|
{
|
803 |
|
|
BIN_TO_BCD (real_seconds);
|
804 |
|
|
BIN_TO_BCD (real_minutes);
|
805 |
|
|
}
|
806 |
|
|
RTC_WRITE (RTC_SECONDS, real_seconds);
|
807 |
|
|
RTC_WRITE (RTC_MINUTES, real_minutes);
|
808 |
|
|
}
|
809 |
|
|
else
|
810 |
|
|
retval = -1;
|
811 |
|
|
|
812 |
|
|
RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
|
813 |
|
|
RTC_WRITE (RTC_CONTROL, save_control);
|
814 |
|
|
return retval;
|
815 |
|
|
}
|
816 |
|
|
|
817 |
|
|
|
818 |
|
|
void atari_waitbut (void)
|
819 |
|
|
{
|
820 |
|
|
/* sorry, no-op */
|
821 |
|
|
}
|
822 |
|
|
|
823 |
|
|
|
824 |
|
|
static inline void ata_mfp_out (char c)
|
825 |
|
|
{
|
826 |
|
|
while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */
|
827 |
|
|
barrier ();
|
828 |
|
|
mfp.usart_dta = c;
|
829 |
|
|
}
|
830 |
|
|
|
831 |
|
|
void ata_mfp_print (const char *str)
|
832 |
|
|
{
|
833 |
|
|
for( ; *str; ++str ) {
|
834 |
|
|
if (*str == '\n')
|
835 |
|
|
ata_mfp_out( '\r' );
|
836 |
|
|
ata_mfp_out( *str );
|
837 |
|
|
}
|
838 |
|
|
}
|
839 |
|
|
|
840 |
|
|
static inline void ata_scc_out (char c)
|
841 |
|
|
{
|
842 |
|
|
do {
|
843 |
|
|
MFPDELAY();
|
844 |
|
|
} while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
|
845 |
|
|
MFPDELAY();
|
846 |
|
|
scc.cha_b_data = c;
|
847 |
|
|
}
|
848 |
|
|
|
849 |
|
|
void ata_scc_print (const char *str)
|
850 |
|
|
{
|
851 |
|
|
for( ; *str; ++str ) {
|
852 |
|
|
if (*str == '\n')
|
853 |
|
|
ata_scc_out( '\r' );
|
854 |
|
|
ata_scc_out( *str );
|
855 |
|
|
}
|
856 |
|
|
}
|
857 |
|
|
|
858 |
|
|
static int ata_par_out (char c)
|
859 |
|
|
{
|
860 |
|
|
extern unsigned long loops_per_sec;
|
861 |
|
|
unsigned char tmp;
|
862 |
|
|
/* This a some-seconds timeout in case no printer is connected */
|
863 |
|
|
unsigned long i = loops_per_sec > 1 ? loops_per_sec : 10000000;
|
864 |
|
|
|
865 |
|
|
while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */
|
866 |
|
|
;
|
867 |
|
|
if (!i) return( 0 );
|
868 |
|
|
|
869 |
|
|
sound_ym.rd_data_reg_sel = 15; /* select port B */
|
870 |
|
|
sound_ym.wd_data = c; /* put char onto port */
|
871 |
|
|
sound_ym.rd_data_reg_sel = 14; /* select port A */
|
872 |
|
|
tmp = sound_ym.rd_data_reg_sel;
|
873 |
|
|
sound_ym.wd_data = tmp & ~0x20; /* set strobe L */
|
874 |
|
|
MFPDELAY(); /* wait a bit */
|
875 |
|
|
sound_ym.wd_data = tmp | 0x20; /* set strobe H */
|
876 |
|
|
return( 1 );
|
877 |
|
|
}
|
878 |
|
|
|
879 |
|
|
void ata_par_print (const char *str)
|
880 |
|
|
{
|
881 |
|
|
static int printer_present = 1;
|
882 |
|
|
|
883 |
|
|
if (!printer_present)
|
884 |
|
|
return;
|
885 |
|
|
|
886 |
|
|
for( ; *str; ++str ) {
|
887 |
|
|
if (*str == '\n')
|
888 |
|
|
if (!ata_par_out( '\r' )) {
|
889 |
|
|
printer_present = 0;
|
890 |
|
|
return;
|
891 |
|
|
}
|
892 |
|
|
if (!ata_par_out( *str )) {
|
893 |
|
|
printer_present = 0;
|
894 |
|
|
return;
|
895 |
|
|
}
|
896 |
|
|
}
|
897 |
|
|
}
|
898 |
|
|
|
899 |
|
|
|
900 |
|
|
void atari_debug_init( void )
|
901 |
|
|
{
|
902 |
|
|
extern void (*debug_print_proc)(const char *);
|
903 |
|
|
extern char m68k_debug_device[];
|
904 |
|
|
|
905 |
|
|
if (!strcmp( m68k_debug_device, "ser" )) {
|
906 |
|
|
/* defaults to ser2 for a Falcon and ser1 otherwise */
|
907 |
|
|
strcpy( m68k_debug_device,
|
908 |
|
|
((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_FALCON) ?
|
909 |
|
|
"ser2" : "ser1" );
|
910 |
|
|
|
911 |
|
|
}
|
912 |
|
|
|
913 |
|
|
if (!strcmp( m68k_debug_device, "ser1" )) {
|
914 |
|
|
/* ST-MFP Modem1 serial port */
|
915 |
|
|
mfp.trn_stat &= ~0x01; /* disable TX */
|
916 |
|
|
mfp.usart_ctr = 0x88; /* clk 1:16, 8N1 */
|
917 |
|
|
mfp.tim_ct_cd &= 0x70; /* stop timer D */
|
918 |
|
|
mfp.tim_dt_d = 2; /* 9600 bps */
|
919 |
|
|
mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */
|
920 |
|
|
mfp.trn_stat |= 0x01; /* enable TX */
|
921 |
|
|
debug_print_proc = ata_mfp_print;
|
922 |
|
|
}
|
923 |
|
|
else if (!strcmp( m68k_debug_device, "ser2" )) {
|
924 |
|
|
/* SCC Modem2 serial port */
|
925 |
|
|
static unsigned char *p, scc_table[] = {
|
926 |
|
|
9, 12, /* Reset */
|
927 |
|
|
4, 0x44, /* x16, 1 stopbit, no parity */
|
928 |
|
|
3, 0xc0, /* receiver: 8 bpc */
|
929 |
|
|
5, 0xe2, /* transmitter: 8 bpc, assert dtr/rts */
|
930 |
|
|
9, 0, /* no interrupts */
|
931 |
|
|
10, 0, /* NRZ */
|
932 |
|
|
11, 0x50, /* use baud rate generator */
|
933 |
|
|
12, 24, 13, 0, /* 9600 baud */
|
934 |
|
|
14, 2, 14, 3, /* use master clock for BRG, enable */
|
935 |
|
|
3, 0xc1, /* enable receiver */
|
936 |
|
|
5, 0xea, /* enable transmitter */
|
937 |
|
|
|
938 |
|
|
};
|
939 |
|
|
|
940 |
|
|
(void)scc.cha_b_ctrl; /* reset reg pointer */
|
941 |
|
|
for( p = scc_table; *p != 0; ) {
|
942 |
|
|
scc.cha_b_ctrl = *p++;
|
943 |
|
|
MFPDELAY();
|
944 |
|
|
scc.cha_b_ctrl = *p++;
|
945 |
|
|
MFPDELAY();
|
946 |
|
|
}
|
947 |
|
|
debug_print_proc = ata_scc_print;
|
948 |
|
|
}
|
949 |
|
|
else if (!strcmp( m68k_debug_device, "par" )) {
|
950 |
|
|
/* parallel printer */
|
951 |
|
|
atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */
|
952 |
|
|
sound_ym.rd_data_reg_sel = 7; /* select mixer control */
|
953 |
|
|
sound_ym.wd_data = 0xff; /* sound off, ports are output */
|
954 |
|
|
sound_ym.rd_data_reg_sel = 15; /* select port B */
|
955 |
|
|
sound_ym.wd_data = 0; /* no char */
|
956 |
|
|
sound_ym.rd_data_reg_sel = 14; /* select port A */
|
957 |
|
|
sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */
|
958 |
|
|
debug_print_proc = ata_par_print;
|
959 |
|
|
}
|
960 |
|
|
else
|
961 |
|
|
debug_print_proc = NULL;
|
962 |
|
|
}
|
963 |
|
|
|
964 |
|
|
|
965 |
|
|
void ata_serial_print (const char *str)
|
966 |
|
|
{
|
967 |
|
|
int c;
|
968 |
|
|
|
969 |
|
|
while (c = *str++, c != 0)
|
970 |
|
|
{
|
971 |
|
|
if (c == '\n')
|
972 |
|
|
{
|
973 |
|
|
while (!(mfp.trn_stat & (1 << 7)))
|
974 |
|
|
barrier ();
|
975 |
|
|
mfp.usart_dta = '\r';
|
976 |
|
|
}
|
977 |
|
|
while (!(mfp.trn_stat & (1 << 7)))
|
978 |
|
|
barrier ();
|
979 |
|
|
mfp.usart_dta = c;
|
980 |
|
|
}
|
981 |
|
|
}
|
982 |
|
|
|
983 |
|
|
/* ++roman:
|
984 |
|
|
*
|
985 |
|
|
* This function does a reset on machines that lack the ability to
|
986 |
|
|
* assert the processor's _RESET signal somehow via hardware. It is
|
987 |
|
|
* based on the fact that you can find the initial SP and PC values
|
988 |
|
|
* after a reset at physical addresses 0 and 4. This works pretty well
|
989 |
|
|
* for Atari machines, since the lowest 8 bytes of physical memory are
|
990 |
|
|
* really ROM (mapped by hardware). For other 680x0 machines: don't
|
991 |
|
|
* know if it works...
|
992 |
|
|
*
|
993 |
|
|
* To get the values at addresses 0 and 4, the MMU better is turned
|
994 |
|
|
* off first. After that, we have to jump into physical address space
|
995 |
|
|
* (the PC before the pmove statement points to the virtual address of
|
996 |
|
|
* the code). Getting that physical address is not hard, but the code
|
997 |
|
|
* becomes a bit complex since I've tried to ensure that the jump
|
998 |
|
|
* statement after the pmove is in the cache already (otherwise the
|
999 |
|
|
* processor can't fetch it!). For that, the code first jumps to the
|
1000 |
|
|
* jump statement with the (virtual) address of the pmove section in
|
1001 |
|
|
* an address register . The jump statement is surely in the cache
|
1002 |
|
|
* now. After that, that physical address of the reset code is loaded
|
1003 |
|
|
* into the same address register, pmove is done and the same jump
|
1004 |
|
|
* statements goes to the reset code. Since there are not many
|
1005 |
|
|
* statements between the two jumps, I hope it stays in the cache.
|
1006 |
|
|
*
|
1007 |
|
|
* The C code makes heavy use of the GCC features that you can get the
|
1008 |
|
|
* address of a C label. No hope to compile this with another compiler
|
1009 |
|
|
* than GCC!
|
1010 |
|
|
*/
|
1011 |
|
|
|
1012 |
|
|
/* ++andreas: no need for complicated code, just depend on prefetch */
|
1013 |
|
|
|
1014 |
|
|
void atari_reset (void)
|
1015 |
|
|
{
|
1016 |
|
|
long tc_val = 0;
|
1017 |
|
|
long reset_addr;
|
1018 |
|
|
|
1019 |
|
|
/* On the Medusa, phys. 0x4 may contain garbage because it's no
|
1020 |
|
|
ROM. See above for explanation why we cannot use PTOV(4). */
|
1021 |
|
|
reset_addr = is_medusa ? 0xe00030 : *(unsigned long *) 0xff000004;
|
1022 |
|
|
|
1023 |
|
|
acia.key_ctrl = ACIA_RESET; /* reset ACIA for switch off OverScan, if it's active */
|
1024 |
|
|
|
1025 |
|
|
/* processor independent: turn off interrupts and reset the VBR;
|
1026 |
|
|
* the caches must be left enabled, else prefetching the final jump
|
1027 |
|
|
* instruction doesn't work. */
|
1028 |
|
|
cli();
|
1029 |
|
|
__asm__ __volatile__
|
1030 |
|
|
("moveq #0,%/d0\n\t"
|
1031 |
|
|
"movec %/d0,%/vbr"
|
1032 |
|
|
: : : "d0" );
|
1033 |
|
|
|
1034 |
|
|
if (m68k_is040or060) {
|
1035 |
|
|
unsigned long jmp_addr040 = VTOP(&&jmp_addr_label040);
|
1036 |
|
|
if (m68k_is040or060 == 6) {
|
1037 |
|
|
/* 68060: clear PCR to turn off superscalar operation */
|
1038 |
|
|
__asm__ __volatile__
|
1039 |
|
|
("moveq #0,%/d0\n\t"
|
1040 |
|
|
".long 0x4e7b0808" /* movec d0,pcr */
|
1041 |
|
|
: : : "d0" );
|
1042 |
|
|
}
|
1043 |
|
|
|
1044 |
|
|
__asm__ __volatile__
|
1045 |
|
|
("movel %0,%/d0\n\t"
|
1046 |
|
|
"andl #0xff000000,%/d0\n\t"
|
1047 |
|
|
"orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */
|
1048 |
|
|
".long 0x4e7b0004\n\t" /* movec d0,itt0 */
|
1049 |
|
|
".long 0x4e7b0006\n\t" /* movec d0,dtt0 */
|
1050 |
|
|
"jmp %0@\n\t"
|
1051 |
|
|
: /* no outputs */
|
1052 |
|
|
: "a" (jmp_addr040)
|
1053 |
|
|
: "d0" );
|
1054 |
|
|
jmp_addr_label040:
|
1055 |
|
|
__asm__ __volatile__
|
1056 |
|
|
("moveq #0,%/d0\n\t"
|
1057 |
|
|
"nop\n\t"
|
1058 |
|
|
".word 0xf4d8\n\t" /* cinva i/d */
|
1059 |
|
|
".word 0xf518\n\t" /* pflusha */
|
1060 |
|
|
".long 0x4e7b0003\n\t" /* movec d0,tc */
|
1061 |
|
|
"jmp %0@"
|
1062 |
|
|
: /* no outputs */
|
1063 |
|
|
: "a" (reset_addr)
|
1064 |
|
|
: "d0");
|
1065 |
|
|
}
|
1066 |
|
|
else
|
1067 |
|
|
__asm__ __volatile__
|
1068 |
|
|
("pmove %0@,%/tc\n\t"
|
1069 |
|
|
"jmp %1@"
|
1070 |
|
|
: /* no outputs */
|
1071 |
|
|
: "a" (&tc_val), "a" (reset_addr));
|
1072 |
|
|
}
|
1073 |
|
|
|
1074 |
|
|
|
1075 |
|
|
void atari_get_model(char *model)
|
1076 |
|
|
{
|
1077 |
|
|
strcpy(model, "Atari ");
|
1078 |
|
|
switch (boot_info.bi_atari.mch_cookie >> 16) {
|
1079 |
|
|
case ATARI_MCH_ST:
|
1080 |
|
|
if (ATARIHW_PRESENT(MSTE_CLK))
|
1081 |
|
|
strcat (model, "Mega ST");
|
1082 |
|
|
else
|
1083 |
|
|
strcat (model, "ST");
|
1084 |
|
|
break;
|
1085 |
|
|
case ATARI_MCH_STE:
|
1086 |
|
|
if ((boot_info.bi_atari.mch_cookie & 0xffff) == 0x10)
|
1087 |
|
|
strcat (model, "Mega STE");
|
1088 |
|
|
else
|
1089 |
|
|
strcat (model, "STE");
|
1090 |
|
|
break;
|
1091 |
|
|
case ATARI_MCH_TT:
|
1092 |
|
|
if (is_medusa)
|
1093 |
|
|
/* Medusa has TT _MCH cookie */
|
1094 |
|
|
strcat (model, "Medusa");
|
1095 |
|
|
else
|
1096 |
|
|
strcat (model, "TT");
|
1097 |
|
|
break;
|
1098 |
|
|
case ATARI_MCH_FALCON:
|
1099 |
|
|
strcat (model, "Falcon");
|
1100 |
|
|
break;
|
1101 |
|
|
default:
|
1102 |
|
|
sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)",
|
1103 |
|
|
boot_info.bi_atari.mch_cookie);
|
1104 |
|
|
break;
|
1105 |
|
|
}
|
1106 |
|
|
}
|
1107 |
|
|
|
1108 |
|
|
|
1109 |
|
|
int atari_get_hardware_list(char *buffer)
|
1110 |
|
|
{
|
1111 |
|
|
int len = 0, i;
|
1112 |
|
|
|
1113 |
|
|
for (i = 0; i < boot_info.num_memory; i++)
|
1114 |
|
|
len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n",
|
1115 |
|
|
boot_info.memory[i].size >> 20,
|
1116 |
|
|
boot_info.memory[i].addr,
|
1117 |
|
|
(boot_info.memory[i].addr & 0xff000000 ?
|
1118 |
|
|
"alternate RAM" : "ST-RAM"));
|
1119 |
|
|
|
1120 |
|
|
#define ATARIHW_ANNOUNCE(name,str) \
|
1121 |
|
|
if (ATARIHW_PRESENT(name)) \
|
1122 |
|
|
len += sprintf (buffer + len, "\t%s\n", str)
|
1123 |
|
|
|
1124 |
|
|
len += sprintf (buffer + len, "Detected hardware:\n");
|
1125 |
|
|
ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter");
|
1126 |
|
|
ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter");
|
1127 |
|
|
ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter");
|
1128 |
|
|
ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter");
|
1129 |
|
|
ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator");
|
1130 |
|
|
ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound");
|
1131 |
|
|
ATARIHW_ANNOUNCE(CODEC, "CODEC Sound");
|
1132 |
|
|
ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)");
|
1133 |
|
|
ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)");
|
1134 |
|
|
ATARIHW_ANNOUNCE(ACSI, "ACSI Interface");
|
1135 |
|
|
ATARIHW_ANNOUNCE(IDE, "IDE Interface");
|
1136 |
|
|
ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC");
|
1137 |
|
|
ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901");
|
1138 |
|
|
ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901");
|
1139 |
|
|
ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530");
|
1140 |
|
|
ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230");
|
1141 |
|
|
ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface");
|
1142 |
|
|
ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface");
|
1143 |
|
|
ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)");
|
1144 |
|
|
ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)");
|
1145 |
|
|
ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380");
|
1146 |
|
|
ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC");
|
1147 |
|
|
ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A");
|
1148 |
|
|
ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15");
|
1149 |
|
|
ATARIHW_ANNOUNCE(SCU, "System Control Unit");
|
1150 |
|
|
ATARIHW_ANNOUNCE(BLITTER, "Blitter");
|
1151 |
|
|
ATARIHW_ANNOUNCE(VME, "VME Bus");
|
1152 |
|
|
|
1153 |
|
|
return(len);
|
1154 |
|
|
}
|