/*
|
/*
|
* linux/atari/config.c
|
* linux/atari/config.c
|
*
|
*
|
* Copyright (C) 1994 Bj”rn Brauel
|
* Copyright (C) 1994 Bj”rn Brauel
|
*
|
*
|
* 5/2/94 Roman Hodek:
|
* 5/2/94 Roman Hodek:
|
* Added setting of time_adj to get a better clock.
|
* Added setting of time_adj to get a better clock.
|
*
|
*
|
* 5/14/94 Roman Hodek:
|
* 5/14/94 Roman Hodek:
|
* gettod() for TT
|
* gettod() for TT
|
*
|
*
|
* 5/15/94 Roman Hodek:
|
* 5/15/94 Roman Hodek:
|
* hard_reset_now() for Atari (and others?)
|
* hard_reset_now() for Atari (and others?)
|
*
|
*
|
* 94/12/30 Andreas Schwab:
|
* 94/12/30 Andreas Schwab:
|
* atari_sched_init fixed to get precise clock.
|
* atari_sched_init fixed to get precise clock.
|
*
|
*
|
* This file is subject to the terms and conditions of the GNU General Public
|
* This file is subject to the terms and conditions of the GNU General Public
|
* License. See the file COPYING in the main directory of this archive
|
* License. See the file COPYING in the main directory of this archive
|
* for more details.
|
* for more details.
|
*/
|
*/
|
|
|
/*
|
/*
|
* Miscellaneous atari stuff
|
* Miscellaneous atari stuff
|
*/
|
*/
|
|
|
#include <linux/config.h>
|
#include <linux/config.h>
|
#include <linux/types.h>
|
#include <linux/types.h>
|
#include <linux/mm.h>
|
#include <linux/mm.h>
|
#include <asm/bootinfo.h>
|
#include <asm/bootinfo.h>
|
#include <linux/mc146818rtc.h>
|
#include <linux/mc146818rtc.h>
|
#include <linux/kd.h>
|
#include <linux/kd.h>
|
#include <linux/tty.h>
|
#include <linux/tty.h>
|
#include <linux/console.h>
|
#include <linux/console.h>
|
|
|
#include <asm/atarihw.h>
|
#include <asm/atarihw.h>
|
#include <asm/atarihdreg.h>
|
#include <asm/atarihdreg.h>
|
#include <asm/atariints.h>
|
#include <asm/atariints.h>
|
|
|
#include <asm/system.h>
|
#include <asm/system.h>
|
#include <asm/io.h>
|
#include <asm/io.h>
|
#include <asm/irq.h>
|
#include <asm/irq.h>
|
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
#include <asm/machdep.h>
|
#include <asm/machdep.h>
|
|
|
extern void atari_sched_init(isrfunc);
|
extern void atari_sched_init(isrfunc);
|
extern int atari_keyb_init(void);
|
extern int atari_keyb_init(void);
|
extern int atari_kbdrate (struct kbd_repeat *);
|
extern int atari_kbdrate (struct kbd_repeat *);
|
extern void atari_kbd_leds (unsigned int);
|
extern void atari_kbd_leds (unsigned int);
|
extern void atari_init_INTS (void);
|
extern void atari_init_INTS (void);
|
extern int atari_add_isr (unsigned long, isrfunc, int, void *, char *);
|
extern int atari_add_isr (unsigned long, isrfunc, int, void *, char *);
|
extern int atari_remove_isr (unsigned long, isrfunc, void *);
|
extern int atari_remove_isr (unsigned long, isrfunc, void *);
|
extern void atari_enable_irq (unsigned);
|
extern void atari_enable_irq (unsigned);
|
extern void atari_disable_irq (unsigned);
|
extern void atari_disable_irq (unsigned);
|
extern int atari_get_irq_list (char *buf, int len);
|
extern int atari_get_irq_list (char *buf, int len);
|
extern unsigned long atari_gettimeoffset (void);
|
extern unsigned long atari_gettimeoffset (void);
|
extern void atari_mste_gettod (int *, int *, int *, int *, int *, int *);
|
extern void atari_mste_gettod (int *, int *, int *, int *, int *, int *);
|
extern void atari_gettod (int *, int *, int *, int *, int *, int *);
|
extern void atari_gettod (int *, int *, int *, int *, int *, int *);
|
extern int atari_mste_hwclk (int, struct hwclk_time *);
|
extern int atari_mste_hwclk (int, struct hwclk_time *);
|
extern int atari_hwclk (int, struct hwclk_time *);
|
extern int atari_hwclk (int, struct hwclk_time *);
|
extern int atari_mste_set_clock_mmss (unsigned long);
|
extern int atari_mste_set_clock_mmss (unsigned long);
|
extern int atari_set_clock_mmss (unsigned long);
|
extern int atari_set_clock_mmss (unsigned long);
|
extern void atari_mksound( unsigned int count, unsigned int ticks );
|
extern void atari_mksound( unsigned int count, unsigned int ticks );
|
extern void atari_reset( void );
|
extern void atari_reset( void );
|
#ifdef CONFIG_BLK_DEV_FD
|
#ifdef CONFIG_BLK_DEV_FD
|
extern int atari_floppy_init (void);
|
extern int atari_floppy_init (void);
|
extern void atari_floppy_setup(char *, int *);
|
extern void atari_floppy_setup(char *, int *);
|
#endif
|
#endif
|
extern void atari_waitbut (void);
|
extern void atari_waitbut (void);
|
extern struct consw fb_con;
|
extern struct consw fb_con;
|
extern struct fb_info *atari_fb_init(long *);
|
extern struct fb_info *atari_fb_init(long *);
|
extern void atari_debug_init (void);
|
extern void atari_debug_init (void);
|
extern void atari_video_setup(char *, int *);
|
extern void atari_video_setup(char *, int *);
|
|
|
extern void (*kd_mksound)(unsigned int, unsigned int);
|
extern void (*kd_mksound)(unsigned int, unsigned int);
|
|
|
/* This function tests for the presence of an address, specially a
|
/* This function tests for the presence of an address, specially a
|
* hardware register address. It is called very early in the kernel
|
* hardware register address. It is called very early in the kernel
|
* initialization process, when the VBR register isn't set up yet. On
|
* initialization process, when the VBR register isn't set up yet. On
|
* an Atari, it still points to address 0, which is unmapped. So a bus
|
* an Atari, it still points to address 0, which is unmapped. So a bus
|
* error would cause another bus error while fetching the exception
|
* error would cause another bus error while fetching the exception
|
* vector, and the CPU would do nothing at all. So we needed to set up
|
* vector, and the CPU would do nothing at all. So we needed to set up
|
* a temporary VBR and a vector table for the duration of the test.
|
* a temporary VBR and a vector table for the duration of the test.
|
*/
|
*/
|
|
|
static int hwreg_present( volatile void *regp )
|
static int hwreg_present( volatile void *regp )
|
{
|
{
|
int ret = 0;
|
int ret = 0;
|
long save_sp, save_vbr;
|
long save_sp, save_vbr;
|
long tmp_vectors[3];
|
long tmp_vectors[3];
|
|
|
__asm__ __volatile__
|
__asm__ __volatile__
|
( "movec %/vbr,%2\n\t"
|
( "movec %/vbr,%2\n\t"
|
"movel #Lberr1,%4@(8)\n\t"
|
"movel #Lberr1,%4@(8)\n\t"
|
"movec %4,%/vbr\n\t"
|
"movec %4,%/vbr\n\t"
|
"movel %/sp,%1\n\t"
|
"movel %/sp,%1\n\t"
|
"moveq #0,%0\n\t"
|
"moveq #0,%0\n\t"
|
"tstb %3@\n\t"
|
"tstb %3@\n\t"
|
"nop\n\t"
|
"nop\n\t"
|
"moveq #1,%0\n"
|
"moveq #1,%0\n"
|
"Lberr1:\n\t"
|
"Lberr1:\n\t"
|
"movel %1,%/sp\n\t"
|
"movel %1,%/sp\n\t"
|
"movec %2,%/vbr"
|
"movec %2,%/vbr"
|
: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
|
: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
|
: "a" (regp), "a" (tmp_vectors)
|
: "a" (regp), "a" (tmp_vectors)
|
);
|
);
|
|
|
return( ret );
|
return( ret );
|
}
|
}
|
|
|
#if 0
|
#if 0
|
static int hwreg_present_bywrite( volatile void *regp,
|
static int hwreg_present_bywrite( volatile void *regp,
|
unsigned char val )
|
unsigned char val )
|
|
|
{
|
{
|
int ret;
|
int ret;
|
long save_sp, save_vbr;
|
long save_sp, save_vbr;
|
static long tmp_vectors[3] = { 0, 0, (long)&&after_test };
|
static long tmp_vectors[3] = { 0, 0, (long)&&after_test };
|
|
|
__asm__ __volatile__
|
__asm__ __volatile__
|
( "movec %/vbr,%2\n\t" /* save vbr value */
|
( "movec %/vbr,%2\n\t" /* save vbr value */
|
"movec %4,%/vbr\n\t" /* set up temporary vectors */
|
"movec %4,%/vbr\n\t" /* set up temporary vectors */
|
"movel %/sp,%1\n\t" /* save sp */
|
"movel %/sp,%1\n\t" /* save sp */
|
"moveq #0,%0\n\t" /* assume not present */
|
"moveq #0,%0\n\t" /* assume not present */
|
"moveb %5,%3@\n\t" /* write the hardware reg */
|
"moveb %5,%3@\n\t" /* write the hardware reg */
|
"cmpb %3@,%5\n\t" /* compare it */
|
"cmpb %3@,%5\n\t" /* compare it */
|
"seq %0" /* comes here only if reg */
|
"seq %0" /* comes here only if reg */
|
/* is present */
|
/* is present */
|
: "=d&" (ret), "=r&" (save_sp), "=r&" (save_vbr)
|
: "=d&" (ret), "=r&" (save_sp), "=r&" (save_vbr)
|
: "a" (regp), "r" (tmp_vectors), "d" (val)
|
: "a" (regp), "r" (tmp_vectors), "d" (val)
|
);
|
);
|
after_test:
|
after_test:
|
__asm__ __volatile__
|
__asm__ __volatile__
|
( "movel %0,%/sp\n\t" /* restore sp */
|
( "movel %0,%/sp\n\t" /* restore sp */
|
"movec %1,%/vbr" /* restore vbr */
|
"movec %1,%/vbr" /* restore vbr */
|
: : "r" (save_sp), "r" (save_vbr) : "sp"
|
: : "r" (save_sp), "r" (save_vbr) : "sp"
|
);
|
);
|
|
|
return( ret );
|
return( ret );
|
}
|
}
|
#endif
|
#endif
|
|
|
/* Basically the same, but writes a value into a word register, protected
|
/* Basically the same, but writes a value into a word register, protected
|
* by a bus error handler */
|
* by a bus error handler */
|
|
|
static int hwreg_write( volatile void *regp, unsigned short val )
|
static int hwreg_write( volatile void *regp, unsigned short val )
|
{
|
{
|
int ret;
|
int ret;
|
long save_sp, save_vbr;
|
long save_sp, save_vbr;
|
long tmp_vectors[3];
|
long tmp_vectors[3];
|
|
|
__asm__ __volatile__
|
__asm__ __volatile__
|
( "movec %/vbr,%2\n\t"
|
( "movec %/vbr,%2\n\t"
|
"movel #Lberr2,%4@(8)\n\t"
|
"movel #Lberr2,%4@(8)\n\t"
|
"movec %4,%/vbr\n\t"
|
"movec %4,%/vbr\n\t"
|
"movel %/sp,%1\n\t"
|
"movel %/sp,%1\n\t"
|
"moveq #0,%0\n\t"
|
"moveq #0,%0\n\t"
|
"movew %5,%3@\n\t"
|
"movew %5,%3@\n\t"
|
"nop \n\t" /* If this nop isn't present, 'ret' may already be
|
"nop \n\t" /* If this nop isn't present, 'ret' may already be
|
* loaded with 1 at the time the bus error
|
* loaded with 1 at the time the bus error
|
* happens! */
|
* happens! */
|
"moveq #1,%0\n"
|
"moveq #1,%0\n"
|
"Lberr2:\n\t"
|
"Lberr2:\n\t"
|
"movel %1,%/sp\n\t"
|
"movel %1,%/sp\n\t"
|
"movec %2,%/vbr"
|
"movec %2,%/vbr"
|
: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
|
: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
|
: "a" (regp), "a" (tmp_vectors), "g" (val)
|
: "a" (regp), "a" (tmp_vectors), "g" (val)
|
);
|
);
|
|
|
return( ret );
|
return( ret );
|
}
|
}
|
|
|
/* ++roman: This is a more elaborate test for an SCC chip, since the plain
|
/* ++roman: This is a more elaborate test for an SCC chip, since the plain
|
* Medusa board generates DTACK at the SCC's standard addresses, but a SCC
|
* Medusa board generates DTACK at the SCC's standard addresses, but a SCC
|
* board in the Medusa is possible. Also, the addresses where the ST_ESCC
|
* board in the Medusa is possible. Also, the addresses where the ST_ESCC
|
* resides generate DTACK without the chip, too.
|
* resides generate DTACK without the chip, too.
|
* The method is to write values into the interrupt vector register, that
|
* The method is to write values into the interrupt vector register, that
|
* should be readable without trouble (from channel A!).
|
* should be readable without trouble (from channel A!).
|
*/
|
*/
|
|
|
static int scc_test( volatile char *ctla )
|
static int scc_test( volatile char *ctla )
|
{
|
{
|
if (!hwreg_present( ctla ))
|
if (!hwreg_present( ctla ))
|
return( 0 );
|
return( 0 );
|
MFPDELAY();
|
MFPDELAY();
|
|
|
*ctla = 2; MFPDELAY();
|
*ctla = 2; MFPDELAY();
|
*ctla = 0x40; MFPDELAY();
|
*ctla = 0x40; MFPDELAY();
|
|
|
*ctla = 2; MFPDELAY();
|
*ctla = 2; MFPDELAY();
|
if (*ctla != 0x40) return( 0 );
|
if (*ctla != 0x40) return( 0 );
|
MFPDELAY();
|
MFPDELAY();
|
|
|
*ctla = 2; MFPDELAY();
|
*ctla = 2; MFPDELAY();
|
*ctla = 0x60; MFPDELAY();
|
*ctla = 0x60; MFPDELAY();
|
|
|
*ctla = 2; MFPDELAY();
|
*ctla = 2; MFPDELAY();
|
if (*ctla != 0x60) return( 0 );
|
if (*ctla != 0x60) return( 0 );
|
|
|
return( 1 );
|
return( 1 );
|
}
|
}
|
|
|
void config_atari(void)
|
void config_atari(void)
|
{
|
{
|
mach_sched_init = atari_sched_init;
|
mach_sched_init = atari_sched_init;
|
mach_keyb_init = atari_keyb_init;
|
mach_keyb_init = atari_keyb_init;
|
mach_kbdrate = atari_kbdrate;
|
mach_kbdrate = atari_kbdrate;
|
mach_kbd_leds = atari_kbd_leds;
|
mach_kbd_leds = atari_kbd_leds;
|
mach_init_INTS = atari_init_INTS;
|
mach_init_INTS = atari_init_INTS;
|
mach_add_isr = atari_add_isr;
|
mach_add_isr = atari_add_isr;
|
mach_remove_isr = atari_remove_isr;
|
mach_remove_isr = atari_remove_isr;
|
mach_enable_irq = atari_enable_irq;
|
mach_enable_irq = atari_enable_irq;
|
mach_disable_irq = atari_disable_irq;
|
mach_disable_irq = atari_disable_irq;
|
mach_get_irq_list = atari_get_irq_list;
|
mach_get_irq_list = atari_get_irq_list;
|
mach_gettimeoffset = atari_gettimeoffset;
|
mach_gettimeoffset = atari_gettimeoffset;
|
mach_mksound = atari_mksound;
|
mach_mksound = atari_mksound;
|
mach_reset = atari_reset;
|
mach_reset = atari_reset;
|
#ifdef CONFIG_BLK_DEV_FD
|
#ifdef CONFIG_BLK_DEV_FD
|
mach_floppy_init = atari_floppy_init;
|
mach_floppy_init = atari_floppy_init;
|
mach_floppy_setup = atari_floppy_setup;
|
mach_floppy_setup = atari_floppy_setup;
|
#endif
|
#endif
|
conswitchp = &fb_con;
|
conswitchp = &fb_con;
|
waitbut = atari_waitbut;
|
waitbut = atari_waitbut;
|
mach_fb_init = atari_fb_init;
|
mach_fb_init = atari_fb_init;
|
mach_max_dma_address = 0xffffff;
|
mach_max_dma_address = 0xffffff;
|
mach_debug_init = atari_debug_init;
|
mach_debug_init = atari_debug_init;
|
mach_video_setup = atari_video_setup;
|
mach_video_setup = atari_video_setup;
|
kd_mksound = atari_mksound;
|
kd_mksound = atari_mksound;
|
|
|
/* ++bjoern:
|
/* ++bjoern:
|
* Determine hardware present
|
* Determine hardware present
|
*/
|
*/
|
|
|
printk( "Atari hardware found: " );
|
printk( "Atari hardware found: " );
|
if (is_medusa) {
|
if (is_medusa) {
|
/* There's no Atari video hardware on the Medusa, but all the
|
/* There's no Atari video hardware on the Medusa, but all the
|
* addresses below generate a DTACK so no bus error occurs! */
|
* addresses below generate a DTACK so no bus error occurs! */
|
}
|
}
|
else if (hwreg_present( f030_xreg )) {
|
else if (hwreg_present( f030_xreg )) {
|
ATARIHW_SET(VIDEL_SHIFTER);
|
ATARIHW_SET(VIDEL_SHIFTER);
|
printk( "VIDEL " );
|
printk( "VIDEL " );
|
/* This is a temporary hack: If there is Falcon video
|
/* This is a temporary hack: If there is Falcon video
|
* hardware, we assume that the ST-DMA serves SCSI instead of
|
* hardware, we assume that the ST-DMA serves SCSI instead of
|
* ACSI. In the future, there should be a better method for
|
* ACSI. In the future, there should be a better method for
|
* this...
|
* this...
|
*/
|
*/
|
ATARIHW_SET(ST_SCSI);
|
ATARIHW_SET(ST_SCSI);
|
printk( "STDMA-SCSI " );
|
printk( "STDMA-SCSI " );
|
}
|
}
|
else if (hwreg_present( tt_palette )) {
|
else if (hwreg_present( tt_palette )) {
|
ATARIHW_SET(TT_SHIFTER);
|
ATARIHW_SET(TT_SHIFTER);
|
printk( "TT_SHIFTER " );
|
printk( "TT_SHIFTER " );
|
}
|
}
|
else if (hwreg_present( &shifter.bas_hi )) {
|
else if (hwreg_present( &shifter.bas_hi )) {
|
if (hwreg_present( &shifter.bas_lo ) &&
|
if (hwreg_present( &shifter.bas_lo ) &&
|
(shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) {
|
(shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) {
|
ATARIHW_SET(EXTD_SHIFTER);
|
ATARIHW_SET(EXTD_SHIFTER);
|
printk( "EXTD_SHIFTER " );
|
printk( "EXTD_SHIFTER " );
|
}
|
}
|
else {
|
else {
|
ATARIHW_SET(STND_SHIFTER);
|
ATARIHW_SET(STND_SHIFTER);
|
printk( "STND_SHIFTER " );
|
printk( "STND_SHIFTER " );
|
}
|
}
|
}
|
}
|
if (hwreg_present( &mfp.par_dt_reg )) {
|
if (hwreg_present( &mfp.par_dt_reg )) {
|
ATARIHW_SET(ST_MFP);
|
ATARIHW_SET(ST_MFP);
|
printk( "ST_MFP " );
|
printk( "ST_MFP " );
|
}
|
}
|
if (hwreg_present( &tt_mfp.par_dt_reg )) {
|
if (hwreg_present( &tt_mfp.par_dt_reg )) {
|
ATARIHW_SET(TT_MFP);
|
ATARIHW_SET(TT_MFP);
|
printk( "TT_MFP " );
|
printk( "TT_MFP " );
|
}
|
}
|
if (hwreg_present( &tt_scsi_dma.dma_addr_hi )) {
|
if (hwreg_present( &tt_scsi_dma.dma_addr_hi )) {
|
ATARIHW_SET(SCSI_DMA);
|
ATARIHW_SET(SCSI_DMA);
|
printk( "TT_SCSI_DMA " );
|
printk( "TT_SCSI_DMA " );
|
}
|
}
|
if (hwreg_present( &st_dma.dma_hi )) {
|
if (hwreg_present( &st_dma.dma_hi )) {
|
ATARIHW_SET(STND_DMA);
|
ATARIHW_SET(STND_DMA);
|
printk( "STND_DMA " );
|
printk( "STND_DMA " );
|
}
|
}
|
if (is_medusa || /* The ST-DMA address registers aren't readable
|
if (is_medusa || /* The ST-DMA address registers aren't readable
|
* on all Medusas, so the test below may fail */
|
* on all Medusas, so the test below may fail */
|
(hwreg_present( &st_dma.dma_vhi ) &&
|
(hwreg_present( &st_dma.dma_vhi ) &&
|
(st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) &&
|
(st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) &&
|
st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa &&
|
st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa &&
|
(st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) &&
|
(st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) &&
|
st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) {
|
st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) {
|
ATARIHW_SET(EXTD_DMA);
|
ATARIHW_SET(EXTD_DMA);
|
printk( "EXTD_DMA " );
|
printk( "EXTD_DMA " );
|
}
|
}
|
if (hwreg_present( &tt_scsi.scsi_data )) {
|
if (hwreg_present( &tt_scsi.scsi_data )) {
|
ATARIHW_SET(TT_SCSI);
|
ATARIHW_SET(TT_SCSI);
|
printk( "TT_SCSI " );
|
printk( "TT_SCSI " );
|
}
|
}
|
if (hwreg_present( &sound_ym.rd_data_reg_sel )) {
|
if (hwreg_present( &sound_ym.rd_data_reg_sel )) {
|
ATARIHW_SET(YM_2149);
|
ATARIHW_SET(YM_2149);
|
printk( "YM2149 " );
|
printk( "YM2149 " );
|
}
|
}
|
if (!is_medusa && hwreg_present( &tt_dmasnd.ctrl )) {
|
if (!is_medusa && hwreg_present( &tt_dmasnd.ctrl )) {
|
ATARIHW_SET(PCM_8BIT);
|
ATARIHW_SET(PCM_8BIT);
|
printk( "PCM " );
|
printk( "PCM " );
|
}
|
}
|
if (hwreg_present( (void *)(0xffff8940) )) {
|
if (hwreg_present( (void *)(0xffff8940) )) {
|
ATARIHW_SET(CODEC);
|
ATARIHW_SET(CODEC);
|
printk( "CODEC " );
|
printk( "CODEC " );
|
}
|
}
|
if (hwreg_present( &tt_scc_dma.dma_ctrl ) &&
|
if (hwreg_present( &tt_scc_dma.dma_ctrl ) &&
|
#if 0
|
#if 0
|
/* This test sucks! Who knows some better? */
|
/* This test sucks! Who knows some better? */
|
(tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
|
(tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
|
(tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
|
(tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
|
#else
|
#else
|
!is_medusa
|
!is_medusa
|
#endif
|
#endif
|
) {
|
) {
|
ATARIHW_SET(SCC_DMA);
|
ATARIHW_SET(SCC_DMA);
|
printk( "SCC_DMA " );
|
printk( "SCC_DMA " );
|
}
|
}
|
if (scc_test( &scc.cha_a_ctrl )) {
|
if (scc_test( &scc.cha_a_ctrl )) {
|
ATARIHW_SET(SCC);
|
ATARIHW_SET(SCC);
|
printk( "SCC " );
|
printk( "SCC " );
|
}
|
}
|
if (scc_test( &st_escc.cha_b_ctrl )) {
|
if (scc_test( &st_escc.cha_b_ctrl )) {
|
ATARIHW_SET( ST_ESCC );
|
ATARIHW_SET( ST_ESCC );
|
printk( "ST_ESCC " );
|
printk( "ST_ESCC " );
|
}
|
}
|
if (hwreg_present( &tt_scu.sys_mask )) {
|
if (hwreg_present( &tt_scu.sys_mask )) {
|
ATARIHW_SET(SCU);
|
ATARIHW_SET(SCU);
|
/* Assume a VME bus if there's a SCU */
|
/* Assume a VME bus if there's a SCU */
|
ATARIHW_SET( VME );
|
ATARIHW_SET( VME );
|
printk( "VME SCU " );
|
printk( "VME SCU " );
|
}
|
}
|
if (hwreg_present( (void *)(0xffff9210) )) {
|
if (hwreg_present( (void *)(0xffff9210) )) {
|
ATARIHW_SET(ANALOG_JOY);
|
ATARIHW_SET(ANALOG_JOY);
|
printk( "ANALOG_JOY " );
|
printk( "ANALOG_JOY " );
|
}
|
}
|
if (hwreg_present( blitter.halftone )) {
|
if (hwreg_present( blitter.halftone )) {
|
ATARIHW_SET(BLITTER);
|
ATARIHW_SET(BLITTER);
|
printk( "BLITTER " );
|
printk( "BLITTER " );
|
}
|
}
|
if (hwreg_present( (void *)(ATA_HD_BASE+ATA_HD_CMD) )) {
|
if (hwreg_present( (void *)(ATA_HD_BASE+ATA_HD_CMD) )) {
|
ATARIHW_SET(IDE);
|
ATARIHW_SET(IDE);
|
printk( "IDE " );
|
printk( "IDE " );
|
}
|
}
|
#if 1 /* This maybe wrong */
|
#if 1 /* This maybe wrong */
|
if (!is_medusa &&
|
if (!is_medusa &&
|
hwreg_present( &tt_microwire.data ) &&
|
hwreg_present( &tt_microwire.data ) &&
|
hwreg_present( &tt_microwire.mask ) &&
|
hwreg_present( &tt_microwire.mask ) &&
|
(tt_microwire.mask = 0x7ff,
|
(tt_microwire.mask = 0x7ff,
|
tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR,
|
tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR,
|
tt_microwire.data != 0)) {
|
tt_microwire.data != 0)) {
|
ATARIHW_SET(MICROWIRE);
|
ATARIHW_SET(MICROWIRE);
|
while (tt_microwire.mask != 0x7ff) ;
|
while (tt_microwire.mask != 0x7ff) ;
|
printk( "MICROWIRE " );
|
printk( "MICROWIRE " );
|
}
|
}
|
#endif
|
#endif
|
if (hwreg_present( &tt_rtc.regsel )) {
|
if (hwreg_present( &tt_rtc.regsel )) {
|
ATARIHW_SET(TT_CLK);
|
ATARIHW_SET(TT_CLK);
|
printk( "TT_CLK " );
|
printk( "TT_CLK " );
|
mach_gettod = atari_gettod;
|
mach_gettod = atari_gettod;
|
mach_hwclk = atari_hwclk;
|
mach_hwclk = atari_hwclk;
|
mach_set_clock_mmss = atari_set_clock_mmss;
|
mach_set_clock_mmss = atari_set_clock_mmss;
|
}
|
}
|
if (hwreg_present( &mste_rtc.sec_ones)) {
|
if (hwreg_present( &mste_rtc.sec_ones)) {
|
ATARIHW_SET(MSTE_CLK);
|
ATARIHW_SET(MSTE_CLK);
|
printk( "MSTE_CLK ");
|
printk( "MSTE_CLK ");
|
mach_gettod = atari_mste_gettod;
|
mach_gettod = atari_mste_gettod;
|
mach_hwclk = atari_mste_hwclk;
|
mach_hwclk = atari_mste_hwclk;
|
mach_set_clock_mmss = atari_mste_set_clock_mmss;
|
mach_set_clock_mmss = atari_mste_set_clock_mmss;
|
}
|
}
|
if (!is_medusa &&
|
if (!is_medusa &&
|
hwreg_present( &dma_wd.fdc_speed ) &&
|
hwreg_present( &dma_wd.fdc_speed ) &&
|
hwreg_write( &dma_wd.fdc_speed, 0 )) {
|
hwreg_write( &dma_wd.fdc_speed, 0 )) {
|
ATARIHW_SET(FDCSPEED);
|
ATARIHW_SET(FDCSPEED);
|
printk( "FDC_SPEED ");
|
printk( "FDC_SPEED ");
|
}
|
}
|
if (!ATARIHW_PRESENT(ST_SCSI)) {
|
if (!ATARIHW_PRESENT(ST_SCSI)) {
|
ATARIHW_SET(ACSI);
|
ATARIHW_SET(ACSI);
|
printk( "ACSI " );
|
printk( "ACSI " );
|
}
|
}
|
printk("\n");
|
printk("\n");
|
|
|
if (m68k_is040or060)
|
if (m68k_is040or060)
|
/* Now it seems to be safe to turn of the tt0 transparent
|
/* Now it seems to be safe to turn of the tt0 transparent
|
* translation (the one that must not be turned off in
|
* translation (the one that must not be turned off in
|
* head.S...)
|
* head.S...)
|
*/
|
*/
|
__asm__ volatile ("moveq #0,%/d0;"
|
__asm__ volatile ("moveq #0,%/d0;"
|
".long 0x4e7b0004;" /* movec d0,itt0 */
|
".long 0x4e7b0004;" /* movec d0,itt0 */
|
".long 0x4e7b0006;" /* movec d0,dtt0 */
|
".long 0x4e7b0006;" /* movec d0,dtt0 */
|
: /* no outputs */
|
: /* no outputs */
|
: /* no inputs */
|
: /* no inputs */
|
: "d0");
|
: "d0");
|
|
|
/* allocator for memory that must reside in st-ram */
|
/* allocator for memory that must reside in st-ram */
|
atari_stram_init ();
|
atari_stram_init ();
|
|
|
/* Set up a mapping for the VMEbus address region:
|
/* Set up a mapping for the VMEbus address region:
|
*
|
*
|
* VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff
|
* VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff
|
* (MegaSTE) In both cases, the whole 16 MB chunk is mapped at
|
* (MegaSTE) In both cases, the whole 16 MB chunk is mapped at
|
* 0xfe000000 virt., because this can be done with a single
|
* 0xfe000000 virt., because this can be done with a single
|
* transparent translation. On the 68040, lots of often unused
|
* transparent translation. On the 68040, lots of often unused
|
* page tables would be needed otherwise. On a MegaSTE or similar,
|
* page tables would be needed otherwise. On a MegaSTE or similar,
|
* the highest byte is stripped off by hardware due to the 24 bit
|
* the highest byte is stripped off by hardware due to the 24 bit
|
* design of the bus.
|
* design of the bus.
|
*/
|
*/
|
|
|
if (!m68k_is040or060) {
|
if (!m68k_is040or060) {
|
unsigned long tt1_val;
|
unsigned long tt1_val;
|
tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache
|
tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache
|
* inhibit, read and write, FDC mask = 3,
|
* inhibit, read and write, FDC mask = 3,
|
* FDC val = 4 -> Supervisor only */
|
* FDC val = 4 -> Supervisor only */
|
__asm__ __volatile__ ( "pmove %0@,%/tt1" : : "a" (&tt1_val) );
|
__asm__ __volatile__ ( "pmove %0@,%/tt1" : : "a" (&tt1_val) );
|
}
|
}
|
else {
|
else {
|
__asm__ __volatile__
|
__asm__ __volatile__
|
( "movel %0,%/d0\n\t"
|
( "movel %0,%/d0\n\t"
|
".long 0x4e7b0005\n\t" /* movec d0,itt1 */
|
".long 0x4e7b0005\n\t" /* movec d0,itt1 */
|
".long 0x4e7b0007" /* movec d0,dtt1 */
|
".long 0x4e7b0007" /* movec d0,dtt1 */
|
:
|
:
|
: "g" (0xfe00a040) /* Translate 0xfexxxxxx, enable,
|
: "g" (0xfe00a040) /* Translate 0xfexxxxxx, enable,
|
* supervisor only, non-cacheable/
|
* supervisor only, non-cacheable/
|
* serialized, writable */
|
* serialized, writable */
|
: "d0" );
|
: "d0" );
|
|
|
}
|
}
|
}
|
}
|
|
|
void atari_sched_init (isrfunc timer_routine)
|
void atari_sched_init (isrfunc timer_routine)
|
{
|
{
|
/* set Timer C data Register */
|
/* set Timer C data Register */
|
mfp.tim_dt_c = INT_TICKS;
|
mfp.tim_dt_c = INT_TICKS;
|
/* start timer C, div = 1:100 */
|
/* start timer C, div = 1:100 */
|
mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60;
|
mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60;
|
/* install interrupt service routine for MFP Timer C */
|
/* install interrupt service routine for MFP Timer C */
|
add_isr (IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, NULL, "timer");
|
add_isr (IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, NULL, "timer");
|
}
|
}
|
|
|
/* ++andreas: gettimeoffset fixed to check for pending interrupt */
|
/* ++andreas: gettimeoffset fixed to check for pending interrupt */
|
|
|
#define TICK_SIZE 10000
|
#define TICK_SIZE 10000
|
|
|
/* This is always executed with interrupts disabled. */
|
/* This is always executed with interrupts disabled. */
|
unsigned long atari_gettimeoffset (void)
|
unsigned long atari_gettimeoffset (void)
|
{
|
{
|
unsigned long ticks, offset = 0;
|
unsigned long ticks, offset = 0;
|
|
|
/* read MFP timer C current value */
|
/* read MFP timer C current value */
|
ticks = mfp.tim_dt_c;
|
ticks = mfp.tim_dt_c;
|
/* The probability of underflow is less than 2% */
|
/* The probability of underflow is less than 2% */
|
if (ticks > INT_TICKS - INT_TICKS / 50)
|
if (ticks > INT_TICKS - INT_TICKS / 50)
|
/* Check for pending timer interrupt */
|
/* Check for pending timer interrupt */
|
if (mfp.int_pn_b & (1 << 5))
|
if (mfp.int_pn_b & (1 << 5))
|
offset = TICK_SIZE;
|
offset = TICK_SIZE;
|
|
|
ticks = INT_TICKS - ticks;
|
ticks = INT_TICKS - ticks;
|
ticks = ticks * 10000L / INT_TICKS;
|
ticks = ticks * 10000L / INT_TICKS;
|
|
|
return ticks + offset;
|
return ticks + offset;
|
}
|
}
|
|
|
|
|
static void
|
static void
|
mste_read(struct MSTE_RTC *val)
|
mste_read(struct MSTE_RTC *val)
|
{
|
{
|
#define COPY(v) val->v=(mste_rtc.v & 0xf)
|
#define COPY(v) val->v=(mste_rtc.v & 0xf)
|
do {
|
do {
|
COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
|
COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
|
COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
|
COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
|
COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
|
COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
|
COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
|
COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
|
COPY(year_tens) ;
|
COPY(year_tens) ;
|
/* prevent from reading the clock while it changed */
|
/* prevent from reading the clock while it changed */
|
} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
|
} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
|
#undef COPY
|
#undef COPY
|
}
|
}
|
|
|
static void
|
static void
|
mste_write(struct MSTE_RTC *val)
|
mste_write(struct MSTE_RTC *val)
|
{
|
{
|
#define COPY(v) mste_rtc.v=val->v
|
#define COPY(v) mste_rtc.v=val->v
|
do {
|
do {
|
COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
|
COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ;
|
COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
|
COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ;
|
COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
|
COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ;
|
COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
|
COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ;
|
COPY(year_tens) ;
|
COPY(year_tens) ;
|
/* prevent from writing the clock while it changed */
|
/* prevent from writing the clock while it changed */
|
} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
|
} while (val->sec_ones != (mste_rtc.sec_ones & 0xf));
|
#undef COPY
|
#undef COPY
|
}
|
}
|
|
|
#define RTC_READ(reg) \
|
#define RTC_READ(reg) \
|
({ unsigned char __val; \
|
({ unsigned char __val; \
|
outb(reg,&tt_rtc.regsel); \
|
outb(reg,&tt_rtc.regsel); \
|
__val = tt_rtc.data; \
|
__val = tt_rtc.data; \
|
__val; \
|
__val; \
|
})
|
})
|
|
|
#define RTC_WRITE(reg,val) \
|
#define RTC_WRITE(reg,val) \
|
do { \
|
do { \
|
outb(reg,&tt_rtc.regsel); \
|
outb(reg,&tt_rtc.regsel); \
|
tt_rtc.data = (val); \
|
tt_rtc.data = (val); \
|
} while(0)
|
} while(0)
|
|
|
|
|
void atari_mste_gettod (int *yearp, int *monp, int *dayp,
|
void atari_mste_gettod (int *yearp, int *monp, int *dayp,
|
int *hourp, int *minp, int *secp)
|
int *hourp, int *minp, int *secp)
|
{
|
{
|
int hr24=0;
|
int hr24=0;
|
struct MSTE_RTC val;
|
struct MSTE_RTC val;
|
|
|
mste_rtc.mode=(mste_rtc.mode | 1);
|
mste_rtc.mode=(mste_rtc.mode | 1);
|
hr24=mste_rtc.mon_tens & 1;
|
hr24=mste_rtc.mon_tens & 1;
|
mste_rtc.mode=(mste_rtc.mode & ~1);
|
mste_rtc.mode=(mste_rtc.mode & ~1);
|
|
|
mste_read(&val);
|
mste_read(&val);
|
*secp = val.sec_ones + val.sec_tens * 10;
|
*secp = val.sec_ones + val.sec_tens * 10;
|
*minp = val.min_ones + val.min_tens * 10;
|
*minp = val.min_ones + val.min_tens * 10;
|
if (hr24)
|
if (hr24)
|
*hourp = val.hr_ones + val.hr_tens * 10;
|
*hourp = val.hr_ones + val.hr_tens * 10;
|
else {
|
else {
|
*hourp = val.hr_ones + (val.hr_tens & 1) * 10;
|
*hourp = val.hr_ones + (val.hr_tens & 1) * 10;
|
if (val.hr_tens & 2)
|
if (val.hr_tens & 2)
|
*hourp += 12;
|
*hourp += 12;
|
}
|
}
|
*dayp = val.day_ones + val.day_tens * 10;
|
*dayp = val.day_ones + val.day_tens * 10;
|
*monp = val.mon_ones + val.mon_tens * 10;
|
*monp = val.mon_ones + val.mon_tens * 10;
|
*yearp = val.year_ones + val.year_tens * 10 + 80;
|
*yearp = val.year_ones + val.year_tens * 10 + 80;
|
}
|
}
|
|
|
|
|
void atari_gettod (int *yearp, int *monp, int *dayp,
|
void atari_gettod (int *yearp, int *monp, int *dayp,
|
int *hourp, int *minp, int *secp)
|
int *hourp, int *minp, int *secp)
|
{
|
{
|
unsigned char ctrl;
|
unsigned char ctrl;
|
unsigned short tos_version;
|
unsigned short tos_version;
|
|
|
while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ;
|
while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ;
|
while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ;
|
while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ;
|
|
|
*secp = RTC_READ(RTC_SECONDS);
|
*secp = RTC_READ(RTC_SECONDS);
|
*minp = RTC_READ(RTC_MINUTES);
|
*minp = RTC_READ(RTC_MINUTES);
|
*hourp = RTC_READ(RTC_HOURS);
|
*hourp = RTC_READ(RTC_HOURS);
|
*dayp = RTC_READ(RTC_DAY_OF_MONTH);
|
*dayp = RTC_READ(RTC_DAY_OF_MONTH);
|
*monp = RTC_READ(RTC_MONTH);
|
*monp = RTC_READ(RTC_MONTH);
|
*yearp = RTC_READ(RTC_YEAR);
|
*yearp = RTC_READ(RTC_YEAR);
|
|
|
ctrl = RTC_READ(RTC_CONTROL);
|
ctrl = RTC_READ(RTC_CONTROL);
|
|
|
if (!(ctrl & RTC_DM_BINARY)) {
|
if (!(ctrl & RTC_DM_BINARY)) {
|
BCD_TO_BIN(*secp);
|
BCD_TO_BIN(*secp);
|
BCD_TO_BIN(*minp);
|
BCD_TO_BIN(*minp);
|
BCD_TO_BIN(*hourp);
|
BCD_TO_BIN(*hourp);
|
BCD_TO_BIN(*dayp);
|
BCD_TO_BIN(*dayp);
|
BCD_TO_BIN(*monp);
|
BCD_TO_BIN(*monp);
|
BCD_TO_BIN(*yearp);
|
BCD_TO_BIN(*yearp);
|
}
|
}
|
if (!(ctrl & RTC_24H)) {
|
if (!(ctrl & RTC_24H)) {
|
if (*hourp & 0x80) {
|
if (*hourp & 0x80) {
|
*hourp &= ~0x80;
|
*hourp &= ~0x80;
|
*hourp += 12;
|
*hourp += 12;
|
}
|
}
|
}
|
}
|
/* Adjust values (let the setup valid) */
|
/* Adjust values (let the setup valid) */
|
|
|
/* Fetch tos version at Physical 2 */
|
/* Fetch tos version at Physical 2 */
|
/* We my not be able to access this address if the kernel is
|
/* We my not be able to access this address if the kernel is
|
loaded to st ram, since the first page is unmapped. On the
|
loaded to st ram, since the first page is unmapped. On the
|
Medusa this is always the case and there is nothing we can do
|
Medusa this is always the case and there is nothing we can do
|
about this, so we just assume the smaller offset. For the TT
|
about this, so we just assume the smaller offset. For the TT
|
we use the fact that in head.S we have set up a mapping
|
we use the fact that in head.S we have set up a mapping
|
0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
|
0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
|
in the last 16MB of the address space. */
|
in the last 16MB of the address space. */
|
tos_version = is_medusa ? 0xfff : *(unsigned short *)0xFF000002;
|
tos_version = is_medusa ? 0xfff : *(unsigned short *)0xFF000002;
|
*yearp += (tos_version < 0x306) ? 70 : 68;
|
*yearp += (tos_version < 0x306) ? 70 : 68;
|
}
|
}
|
|
|
#define HWCLK_POLL_INTERVAL 5
|
#define HWCLK_POLL_INTERVAL 5
|
|
|
int atari_mste_hwclk( int op, struct hwclk_time *t )
|
int atari_mste_hwclk( int op, struct hwclk_time *t )
|
{
|
{
|
int hour, year;
|
int hour, year;
|
int hr24=0;
|
int hr24=0;
|
struct MSTE_RTC val;
|
struct MSTE_RTC val;
|
|
|
mste_rtc.mode=(mste_rtc.mode | 1);
|
mste_rtc.mode=(mste_rtc.mode | 1);
|
hr24=mste_rtc.mon_tens & 1;
|
hr24=mste_rtc.mon_tens & 1;
|
mste_rtc.mode=(mste_rtc.mode & ~1);
|
mste_rtc.mode=(mste_rtc.mode & ~1);
|
|
|
if (op) {
|
if (op) {
|
/* write: prepare values */
|
/* write: prepare values */
|
|
|
val.sec_ones = t->sec % 10;
|
val.sec_ones = t->sec % 10;
|
val.sec_tens = t->sec / 10;
|
val.sec_tens = t->sec / 10;
|
val.min_ones = t->min % 10;
|
val.min_ones = t->min % 10;
|
val.min_tens = t->min / 10;
|
val.min_tens = t->min / 10;
|
hour = t->hour;
|
hour = t->hour;
|
val.hr_ones = hour % 10;
|
val.hr_ones = hour % 10;
|
val.hr_tens = hour / 10;
|
val.hr_tens = hour / 10;
|
if (!hr24 && hour > 11) {
|
if (!hr24 && hour > 11) {
|
hour -= 12;
|
hour -= 12;
|
val.hr_ones = hour % 10;
|
val.hr_ones = hour % 10;
|
val.hr_tens = (hour / 10) | 2;
|
val.hr_tens = (hour / 10) | 2;
|
}
|
}
|
val.day_ones = t->day % 10;
|
val.day_ones = t->day % 10;
|
val.day_tens = t->day / 10;
|
val.day_tens = t->day / 10;
|
val.mon_ones = (t->mon+1) % 10;
|
val.mon_ones = (t->mon+1) % 10;
|
val.mon_tens = (t->mon+1) / 10;
|
val.mon_tens = (t->mon+1) / 10;
|
year = t->year - 80;
|
year = t->year - 80;
|
val.year_ones = year % 10;
|
val.year_ones = year % 10;
|
val.year_tens = year / 10;
|
val.year_tens = year / 10;
|
val.weekday = t->wday;
|
val.weekday = t->wday;
|
mste_write(&val);
|
mste_write(&val);
|
mste_rtc.mode=(mste_rtc.mode | 1);
|
mste_rtc.mode=(mste_rtc.mode | 1);
|
val.year_ones = (year % 4); /* leap year register */
|
val.year_ones = (year % 4); /* leap year register */
|
mste_rtc.mode=(mste_rtc.mode & ~1);
|
mste_rtc.mode=(mste_rtc.mode & ~1);
|
}
|
}
|
else {
|
else {
|
mste_read(&val);
|
mste_read(&val);
|
t->sec = val.sec_ones + val.sec_tens * 10;
|
t->sec = val.sec_ones + val.sec_tens * 10;
|
t->min = val.min_ones + val.min_tens * 10;
|
t->min = val.min_ones + val.min_tens * 10;
|
if (hr24)
|
if (hr24)
|
t->hour = val.hr_ones + val.hr_tens * 10;
|
t->hour = val.hr_ones + val.hr_tens * 10;
|
else {
|
else {
|
t->hour = val.hr_ones + (val.hr_tens & 1) * 10;
|
t->hour = val.hr_ones + (val.hr_tens & 1) * 10;
|
if (val.hr_tens & 2)
|
if (val.hr_tens & 2)
|
t->hour += 12;
|
t->hour += 12;
|
}
|
}
|
t->day = val.day_ones + val.day_tens * 10;
|
t->day = val.day_ones + val.day_tens * 10;
|
t->mon = val.mon_ones + val.mon_tens * 10 - 1;
|
t->mon = val.mon_ones + val.mon_tens * 10 - 1;
|
t->year = val.year_ones + val.year_tens * 10 + 80;
|
t->year = val.year_ones + val.year_tens * 10 + 80;
|
t->wday = val.weekday;
|
t->wday = val.weekday;
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
int atari_hwclk( int op, struct hwclk_time *t )
|
int atari_hwclk( int op, struct hwclk_time *t )
|
{
|
{
|
int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
|
int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
|
unsigned long flags;
|
unsigned long flags;
|
unsigned short tos_version;
|
unsigned short tos_version;
|
unsigned char ctrl;
|
unsigned char ctrl;
|
|
|
/* Tos version at Physical 2. See above for explanation why we
|
/* Tos version at Physical 2. See above for explanation why we
|
cannot use PTOV(2). */
|
cannot use PTOV(2). */
|
tos_version = is_medusa ? 0xfff : *(unsigned short *)0xff000002;
|
tos_version = is_medusa ? 0xfff : *(unsigned short *)0xff000002;
|
|
|
ctrl = RTC_READ(RTC_CONTROL); /* control registers are
|
ctrl = RTC_READ(RTC_CONTROL); /* control registers are
|
* independent from the UIP */
|
* independent from the UIP */
|
|
|
if (op) {
|
if (op) {
|
/* write: prepare values */
|
/* write: prepare values */
|
|
|
sec = t->sec;
|
sec = t->sec;
|
min = t->min;
|
min = t->min;
|
hour = t->hour;
|
hour = t->hour;
|
day = t->day;
|
day = t->day;
|
mon = t->mon + 1;
|
mon = t->mon + 1;
|
year = t->year - ((tos_version < 0x306) ? 70 : 68);
|
year = t->year - ((tos_version < 0x306) ? 70 : 68);
|
wday = t->wday + (t->wday >= 0);
|
wday = t->wday + (t->wday >= 0);
|
|
|
if (!(ctrl & RTC_24H) && hour > 11) {
|
if (!(ctrl & RTC_24H) && hour > 11) {
|
hour -= 12;
|
hour -= 12;
|
hour |= 0x80;
|
hour |= 0x80;
|
}
|
}
|
|
|
if (!(ctrl & RTC_DM_BINARY)) {
|
if (!(ctrl & RTC_DM_BINARY)) {
|
BIN_TO_BCD(sec);
|
BIN_TO_BCD(sec);
|
BIN_TO_BCD(min);
|
BIN_TO_BCD(min);
|
BIN_TO_BCD(hour);
|
BIN_TO_BCD(hour);
|
BIN_TO_BCD(day);
|
BIN_TO_BCD(day);
|
BIN_TO_BCD(mon);
|
BIN_TO_BCD(mon);
|
BIN_TO_BCD(year);
|
BIN_TO_BCD(year);
|
if (wday >= 0) BIN_TO_BCD(wday);
|
if (wday >= 0) BIN_TO_BCD(wday);
|
}
|
}
|
}
|
}
|
|
|
/* Reading/writing the clock registers is a bit critical due to
|
/* Reading/writing the clock registers is a bit critical due to
|
* the regular update cycle of the RTC. While an update is in
|
* the regular update cycle of the RTC. While an update is in
|
* progress, registers 0..9 shouldn't be touched.
|
* progress, registers 0..9 shouldn't be touched.
|
* The problem is solved like that: If an update is currently in
|
* The problem is solved like that: If an update is currently in
|
* progress (the UIP bit is set), the process sleeps for a while
|
* progress (the UIP bit is set), the process sleeps for a while
|
* (50ms). This really should be enough, since the update cycle
|
* (50ms). This really should be enough, since the update cycle
|
* normally needs 2 ms.
|
* normally needs 2 ms.
|
* If the UIP bit reads as 0, we have at least 244 usecs until the
|
* If the UIP bit reads as 0, we have at least 244 usecs until the
|
* update starts. This should be enough... But to be sure,
|
* update starts. This should be enough... But to be sure,
|
* additionally the RTC_SET bit is set to prevent an update cycle.
|
* additionally the RTC_SET bit is set to prevent an update cycle.
|
*/
|
*/
|
|
|
while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
|
while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
|
current->state = TASK_INTERRUPTIBLE;
|
current->state = TASK_INTERRUPTIBLE;
|
current->timeout = jiffies + HWCLK_POLL_INTERVAL;
|
current->timeout = jiffies + HWCLK_POLL_INTERVAL;
|
schedule();
|
schedule();
|
}
|
}
|
|
|
save_flags(flags);
|
save_flags(flags);
|
cli();
|
cli();
|
RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
|
RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
|
if (!op) {
|
if (!op) {
|
sec = RTC_READ( RTC_SECONDS );
|
sec = RTC_READ( RTC_SECONDS );
|
min = RTC_READ( RTC_MINUTES );
|
min = RTC_READ( RTC_MINUTES );
|
hour = RTC_READ( RTC_HOURS );
|
hour = RTC_READ( RTC_HOURS );
|
day = RTC_READ( RTC_DAY_OF_MONTH );
|
day = RTC_READ( RTC_DAY_OF_MONTH );
|
mon = RTC_READ( RTC_MONTH );
|
mon = RTC_READ( RTC_MONTH );
|
year = RTC_READ( RTC_YEAR );
|
year = RTC_READ( RTC_YEAR );
|
wday = RTC_READ( RTC_DAY_OF_WEEK );
|
wday = RTC_READ( RTC_DAY_OF_WEEK );
|
}
|
}
|
else {
|
else {
|
RTC_WRITE( RTC_SECONDS, sec );
|
RTC_WRITE( RTC_SECONDS, sec );
|
RTC_WRITE( RTC_MINUTES, min );
|
RTC_WRITE( RTC_MINUTES, min );
|
RTC_WRITE( RTC_HOURS, hour );
|
RTC_WRITE( RTC_HOURS, hour );
|
RTC_WRITE( RTC_DAY_OF_MONTH, day );
|
RTC_WRITE( RTC_DAY_OF_MONTH, day );
|
RTC_WRITE( RTC_MONTH, mon );
|
RTC_WRITE( RTC_MONTH, mon );
|
RTC_WRITE( RTC_YEAR, year );
|
RTC_WRITE( RTC_YEAR, year );
|
if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
|
if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
|
}
|
}
|
RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
|
RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
|
restore_flags(flags);
|
restore_flags(flags);
|
|
|
if (!op) {
|
if (!op) {
|
/* read: adjust values */
|
/* read: adjust values */
|
|
|
if (!(ctrl & RTC_DM_BINARY)) {
|
if (!(ctrl & RTC_DM_BINARY)) {
|
BCD_TO_BIN(sec);
|
BCD_TO_BIN(sec);
|
BCD_TO_BIN(min);
|
BCD_TO_BIN(min);
|
BCD_TO_BIN(hour);
|
BCD_TO_BIN(hour);
|
BCD_TO_BIN(day);
|
BCD_TO_BIN(day);
|
BCD_TO_BIN(mon);
|
BCD_TO_BIN(mon);
|
BCD_TO_BIN(year);
|
BCD_TO_BIN(year);
|
BCD_TO_BIN(wday);
|
BCD_TO_BIN(wday);
|
}
|
}
|
|
|
if (!(ctrl & RTC_24H)) {
|
if (!(ctrl & RTC_24H)) {
|
if (hour & 0x80) {
|
if (hour & 0x80) {
|
hour &= ~0x80;
|
hour &= ~0x80;
|
hour += 12;
|
hour += 12;
|
}
|
}
|
}
|
}
|
|
|
t->sec = sec;
|
t->sec = sec;
|
t->min = min;
|
t->min = min;
|
t->hour = hour;
|
t->hour = hour;
|
t->day = day;
|
t->day = day;
|
t->mon = mon - 1;
|
t->mon = mon - 1;
|
t->year = year + ((tos_version < 0x306) ? 70 : 68);
|
t->year = year + ((tos_version < 0x306) ? 70 : 68);
|
t->wday = wday - 1;
|
t->wday = wday - 1;
|
}
|
}
|
|
|
return( 0 );
|
return( 0 );
|
}
|
}
|
|
|
|
|
int atari_mste_set_clock_mmss (unsigned long nowtime)
|
int atari_mste_set_clock_mmss (unsigned long nowtime)
|
{
|
{
|
short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
|
short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
|
struct MSTE_RTC val;
|
struct MSTE_RTC val;
|
unsigned char rtc_minutes;
|
unsigned char rtc_minutes;
|
|
|
mste_read(&val);
|
mste_read(&val);
|
rtc_minutes= val.min_ones + val.min_tens * 10;
|
rtc_minutes= val.min_ones + val.min_tens * 10;
|
if ((rtc_minutes < real_minutes
|
if ((rtc_minutes < real_minutes
|
? real_minutes - rtc_minutes
|
? real_minutes - rtc_minutes
|
: rtc_minutes - real_minutes) < 30)
|
: rtc_minutes - real_minutes) < 30)
|
{
|
{
|
val.sec_ones = real_seconds % 10;
|
val.sec_ones = real_seconds % 10;
|
val.sec_tens = real_seconds / 10;
|
val.sec_tens = real_seconds / 10;
|
val.min_ones = real_minutes % 10;
|
val.min_ones = real_minutes % 10;
|
val.min_tens = real_minutes / 10;
|
val.min_tens = real_minutes / 10;
|
mste_write(&val);
|
mste_write(&val);
|
}
|
}
|
else
|
else
|
return -1;
|
return -1;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
int atari_set_clock_mmss (unsigned long nowtime)
|
int atari_set_clock_mmss (unsigned long nowtime)
|
{
|
{
|
int retval = 0;
|
int retval = 0;
|
short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
|
short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
|
unsigned char save_control, save_freq_select, rtc_minutes;
|
unsigned char save_control, save_freq_select, rtc_minutes;
|
|
|
save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
|
save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
|
RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);
|
RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);
|
|
|
save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */
|
save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */
|
RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2);
|
RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2);
|
|
|
rtc_minutes = RTC_READ (RTC_MINUTES);
|
rtc_minutes = RTC_READ (RTC_MINUTES);
|
if (!(save_control & RTC_DM_BINARY))
|
if (!(save_control & RTC_DM_BINARY))
|
BCD_TO_BIN (rtc_minutes);
|
BCD_TO_BIN (rtc_minutes);
|
|
|
/* Since we're only adjusting minutes and seconds, don't interfere
|
/* Since we're only adjusting minutes and seconds, don't interfere
|
with hour overflow. This avoids messing with unknown time zones
|
with hour overflow. This avoids messing with unknown time zones
|
but requires your RTC not to be off by more than 30 minutes. */
|
but requires your RTC not to be off by more than 30 minutes. */
|
if ((rtc_minutes < real_minutes
|
if ((rtc_minutes < real_minutes
|
? real_minutes - rtc_minutes
|
? real_minutes - rtc_minutes
|
: rtc_minutes - real_minutes) < 30)
|
: rtc_minutes - real_minutes) < 30)
|
{
|
{
|
if (!(save_control & RTC_DM_BINARY))
|
if (!(save_control & RTC_DM_BINARY))
|
{
|
{
|
BIN_TO_BCD (real_seconds);
|
BIN_TO_BCD (real_seconds);
|
BIN_TO_BCD (real_minutes);
|
BIN_TO_BCD (real_minutes);
|
}
|
}
|
RTC_WRITE (RTC_SECONDS, real_seconds);
|
RTC_WRITE (RTC_SECONDS, real_seconds);
|
RTC_WRITE (RTC_MINUTES, real_minutes);
|
RTC_WRITE (RTC_MINUTES, real_minutes);
|
}
|
}
|
else
|
else
|
retval = -1;
|
retval = -1;
|
|
|
RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
|
RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
|
RTC_WRITE (RTC_CONTROL, save_control);
|
RTC_WRITE (RTC_CONTROL, save_control);
|
return retval;
|
return retval;
|
}
|
}
|
|
|
|
|
void atari_waitbut (void)
|
void atari_waitbut (void)
|
{
|
{
|
/* sorry, no-op */
|
/* sorry, no-op */
|
}
|
}
|
|
|
|
|
static inline void ata_mfp_out (char c)
|
static inline void ata_mfp_out (char c)
|
{
|
{
|
while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */
|
while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */
|
barrier ();
|
barrier ();
|
mfp.usart_dta = c;
|
mfp.usart_dta = c;
|
}
|
}
|
|
|
void ata_mfp_print (const char *str)
|
void ata_mfp_print (const char *str)
|
{
|
{
|
for( ; *str; ++str ) {
|
for( ; *str; ++str ) {
|
if (*str == '\n')
|
if (*str == '\n')
|
ata_mfp_out( '\r' );
|
ata_mfp_out( '\r' );
|
ata_mfp_out( *str );
|
ata_mfp_out( *str );
|
}
|
}
|
}
|
}
|
|
|
static inline void ata_scc_out (char c)
|
static inline void ata_scc_out (char c)
|
{
|
{
|
do {
|
do {
|
MFPDELAY();
|
MFPDELAY();
|
} while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
|
} while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
|
MFPDELAY();
|
MFPDELAY();
|
scc.cha_b_data = c;
|
scc.cha_b_data = c;
|
}
|
}
|
|
|
void ata_scc_print (const char *str)
|
void ata_scc_print (const char *str)
|
{
|
{
|
for( ; *str; ++str ) {
|
for( ; *str; ++str ) {
|
if (*str == '\n')
|
if (*str == '\n')
|
ata_scc_out( '\r' );
|
ata_scc_out( '\r' );
|
ata_scc_out( *str );
|
ata_scc_out( *str );
|
}
|
}
|
}
|
}
|
|
|
static int ata_par_out (char c)
|
static int ata_par_out (char c)
|
{
|
{
|
extern unsigned long loops_per_sec;
|
extern unsigned long loops_per_sec;
|
unsigned char tmp;
|
unsigned char tmp;
|
/* This a some-seconds timeout in case no printer is connected */
|
/* This a some-seconds timeout in case no printer is connected */
|
unsigned long i = loops_per_sec > 1 ? loops_per_sec : 10000000;
|
unsigned long i = loops_per_sec > 1 ? loops_per_sec : 10000000;
|
|
|
while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */
|
while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */
|
;
|
;
|
if (!i) return( 0 );
|
if (!i) return( 0 );
|
|
|
sound_ym.rd_data_reg_sel = 15; /* select port B */
|
sound_ym.rd_data_reg_sel = 15; /* select port B */
|
sound_ym.wd_data = c; /* put char onto port */
|
sound_ym.wd_data = c; /* put char onto port */
|
sound_ym.rd_data_reg_sel = 14; /* select port A */
|
sound_ym.rd_data_reg_sel = 14; /* select port A */
|
tmp = sound_ym.rd_data_reg_sel;
|
tmp = sound_ym.rd_data_reg_sel;
|
sound_ym.wd_data = tmp & ~0x20; /* set strobe L */
|
sound_ym.wd_data = tmp & ~0x20; /* set strobe L */
|
MFPDELAY(); /* wait a bit */
|
MFPDELAY(); /* wait a bit */
|
sound_ym.wd_data = tmp | 0x20; /* set strobe H */
|
sound_ym.wd_data = tmp | 0x20; /* set strobe H */
|
return( 1 );
|
return( 1 );
|
}
|
}
|
|
|
void ata_par_print (const char *str)
|
void ata_par_print (const char *str)
|
{
|
{
|
static int printer_present = 1;
|
static int printer_present = 1;
|
|
|
if (!printer_present)
|
if (!printer_present)
|
return;
|
return;
|
|
|
for( ; *str; ++str ) {
|
for( ; *str; ++str ) {
|
if (*str == '\n')
|
if (*str == '\n')
|
if (!ata_par_out( '\r' )) {
|
if (!ata_par_out( '\r' )) {
|
printer_present = 0;
|
printer_present = 0;
|
return;
|
return;
|
}
|
}
|
if (!ata_par_out( *str )) {
|
if (!ata_par_out( *str )) {
|
printer_present = 0;
|
printer_present = 0;
|
return;
|
return;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
void atari_debug_init( void )
|
void atari_debug_init( void )
|
{
|
{
|
extern void (*debug_print_proc)(const char *);
|
extern void (*debug_print_proc)(const char *);
|
extern char m68k_debug_device[];
|
extern char m68k_debug_device[];
|
|
|
if (!strcmp( m68k_debug_device, "ser" )) {
|
if (!strcmp( m68k_debug_device, "ser" )) {
|
/* defaults to ser2 for a Falcon and ser1 otherwise */
|
/* defaults to ser2 for a Falcon and ser1 otherwise */
|
strcpy( m68k_debug_device,
|
strcpy( m68k_debug_device,
|
((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_FALCON) ?
|
((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_FALCON) ?
|
"ser2" : "ser1" );
|
"ser2" : "ser1" );
|
|
|
}
|
}
|
|
|
if (!strcmp( m68k_debug_device, "ser1" )) {
|
if (!strcmp( m68k_debug_device, "ser1" )) {
|
/* ST-MFP Modem1 serial port */
|
/* ST-MFP Modem1 serial port */
|
mfp.trn_stat &= ~0x01; /* disable TX */
|
mfp.trn_stat &= ~0x01; /* disable TX */
|
mfp.usart_ctr = 0x88; /* clk 1:16, 8N1 */
|
mfp.usart_ctr = 0x88; /* clk 1:16, 8N1 */
|
mfp.tim_ct_cd &= 0x70; /* stop timer D */
|
mfp.tim_ct_cd &= 0x70; /* stop timer D */
|
mfp.tim_dt_d = 2; /* 9600 bps */
|
mfp.tim_dt_d = 2; /* 9600 bps */
|
mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */
|
mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */
|
mfp.trn_stat |= 0x01; /* enable TX */
|
mfp.trn_stat |= 0x01; /* enable TX */
|
debug_print_proc = ata_mfp_print;
|
debug_print_proc = ata_mfp_print;
|
}
|
}
|
else if (!strcmp( m68k_debug_device, "ser2" )) {
|
else if (!strcmp( m68k_debug_device, "ser2" )) {
|
/* SCC Modem2 serial port */
|
/* SCC Modem2 serial port */
|
static unsigned char *p, scc_table[] = {
|
static unsigned char *p, scc_table[] = {
|
9, 12, /* Reset */
|
9, 12, /* Reset */
|
4, 0x44, /* x16, 1 stopbit, no parity */
|
4, 0x44, /* x16, 1 stopbit, no parity */
|
3, 0xc0, /* receiver: 8 bpc */
|
3, 0xc0, /* receiver: 8 bpc */
|
5, 0xe2, /* transmitter: 8 bpc, assert dtr/rts */
|
5, 0xe2, /* transmitter: 8 bpc, assert dtr/rts */
|
9, 0, /* no interrupts */
|
9, 0, /* no interrupts */
|
10, 0, /* NRZ */
|
10, 0, /* NRZ */
|
11, 0x50, /* use baud rate generator */
|
11, 0x50, /* use baud rate generator */
|
12, 24, 13, 0, /* 9600 baud */
|
12, 24, 13, 0, /* 9600 baud */
|
14, 2, 14, 3, /* use master clock for BRG, enable */
|
14, 2, 14, 3, /* use master clock for BRG, enable */
|
3, 0xc1, /* enable receiver */
|
3, 0xc1, /* enable receiver */
|
5, 0xea, /* enable transmitter */
|
5, 0xea, /* enable transmitter */
|
0
|
0
|
};
|
};
|
|
|
(void)scc.cha_b_ctrl; /* reset reg pointer */
|
(void)scc.cha_b_ctrl; /* reset reg pointer */
|
for( p = scc_table; *p != 0; ) {
|
for( p = scc_table; *p != 0; ) {
|
scc.cha_b_ctrl = *p++;
|
scc.cha_b_ctrl = *p++;
|
MFPDELAY();
|
MFPDELAY();
|
scc.cha_b_ctrl = *p++;
|
scc.cha_b_ctrl = *p++;
|
MFPDELAY();
|
MFPDELAY();
|
}
|
}
|
debug_print_proc = ata_scc_print;
|
debug_print_proc = ata_scc_print;
|
}
|
}
|
else if (!strcmp( m68k_debug_device, "par" )) {
|
else if (!strcmp( m68k_debug_device, "par" )) {
|
/* parallel printer */
|
/* parallel printer */
|
atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */
|
atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */
|
sound_ym.rd_data_reg_sel = 7; /* select mixer control */
|
sound_ym.rd_data_reg_sel = 7; /* select mixer control */
|
sound_ym.wd_data = 0xff; /* sound off, ports are output */
|
sound_ym.wd_data = 0xff; /* sound off, ports are output */
|
sound_ym.rd_data_reg_sel = 15; /* select port B */
|
sound_ym.rd_data_reg_sel = 15; /* select port B */
|
sound_ym.wd_data = 0; /* no char */
|
sound_ym.wd_data = 0; /* no char */
|
sound_ym.rd_data_reg_sel = 14; /* select port A */
|
sound_ym.rd_data_reg_sel = 14; /* select port A */
|
sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */
|
sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */
|
debug_print_proc = ata_par_print;
|
debug_print_proc = ata_par_print;
|
}
|
}
|
else
|
else
|
debug_print_proc = NULL;
|
debug_print_proc = NULL;
|
}
|
}
|
|
|
|
|
void ata_serial_print (const char *str)
|
void ata_serial_print (const char *str)
|
{
|
{
|
int c;
|
int c;
|
|
|
while (c = *str++, c != 0)
|
while (c = *str++, c != 0)
|
{
|
{
|
if (c == '\n')
|
if (c == '\n')
|
{
|
{
|
while (!(mfp.trn_stat & (1 << 7)))
|
while (!(mfp.trn_stat & (1 << 7)))
|
barrier ();
|
barrier ();
|
mfp.usart_dta = '\r';
|
mfp.usart_dta = '\r';
|
}
|
}
|
while (!(mfp.trn_stat & (1 << 7)))
|
while (!(mfp.trn_stat & (1 << 7)))
|
barrier ();
|
barrier ();
|
mfp.usart_dta = c;
|
mfp.usart_dta = c;
|
}
|
}
|
}
|
}
|
|
|
/* ++roman:
|
/* ++roman:
|
*
|
*
|
* This function does a reset on machines that lack the ability to
|
* This function does a reset on machines that lack the ability to
|
* assert the processor's _RESET signal somehow via hardware. It is
|
* assert the processor's _RESET signal somehow via hardware. It is
|
* based on the fact that you can find the initial SP and PC values
|
* based on the fact that you can find the initial SP and PC values
|
* after a reset at physical addresses 0 and 4. This works pretty well
|
* after a reset at physical addresses 0 and 4. This works pretty well
|
* for Atari machines, since the lowest 8 bytes of physical memory are
|
* for Atari machines, since the lowest 8 bytes of physical memory are
|
* really ROM (mapped by hardware). For other 680x0 machines: don't
|
* really ROM (mapped by hardware). For other 680x0 machines: don't
|
* know if it works...
|
* know if it works...
|
*
|
*
|
* To get the values at addresses 0 and 4, the MMU better is turned
|
* To get the values at addresses 0 and 4, the MMU better is turned
|
* off first. After that, we have to jump into physical address space
|
* off first. After that, we have to jump into physical address space
|
* (the PC before the pmove statement points to the virtual address of
|
* (the PC before the pmove statement points to the virtual address of
|
* the code). Getting that physical address is not hard, but the code
|
* the code). Getting that physical address is not hard, but the code
|
* becomes a bit complex since I've tried to ensure that the jump
|
* becomes a bit complex since I've tried to ensure that the jump
|
* statement after the pmove is in the cache already (otherwise the
|
* statement after the pmove is in the cache already (otherwise the
|
* processor can't fetch it!). For that, the code first jumps to the
|
* processor can't fetch it!). For that, the code first jumps to the
|
* jump statement with the (virtual) address of the pmove section in
|
* jump statement with the (virtual) address of the pmove section in
|
* an address register . The jump statement is surely in the cache
|
* an address register . The jump statement is surely in the cache
|
* now. After that, that physical address of the reset code is loaded
|
* now. After that, that physical address of the reset code is loaded
|
* into the same address register, pmove is done and the same jump
|
* into the same address register, pmove is done and the same jump
|
* statements goes to the reset code. Since there are not many
|
* statements goes to the reset code. Since there are not many
|
* statements between the two jumps, I hope it stays in the cache.
|
* statements between the two jumps, I hope it stays in the cache.
|
*
|
*
|
* The C code makes heavy use of the GCC features that you can get the
|
* The C code makes heavy use of the GCC features that you can get the
|
* address of a C label. No hope to compile this with another compiler
|
* address of a C label. No hope to compile this with another compiler
|
* than GCC!
|
* than GCC!
|
*/
|
*/
|
|
|
/* ++andreas: no need for complicated code, just depend on prefetch */
|
/* ++andreas: no need for complicated code, just depend on prefetch */
|
|
|
void atari_reset (void)
|
void atari_reset (void)
|
{
|
{
|
long tc_val = 0;
|
long tc_val = 0;
|
long reset_addr;
|
long reset_addr;
|
|
|
/* On the Medusa, phys. 0x4 may contain garbage because it's no
|
/* On the Medusa, phys. 0x4 may contain garbage because it's no
|
ROM. See above for explanation why we cannot use PTOV(4). */
|
ROM. See above for explanation why we cannot use PTOV(4). */
|
reset_addr = is_medusa ? 0xe00030 : *(unsigned long *) 0xff000004;
|
reset_addr = is_medusa ? 0xe00030 : *(unsigned long *) 0xff000004;
|
|
|
acia.key_ctrl = ACIA_RESET; /* reset ACIA for switch off OverScan, if it's active */
|
acia.key_ctrl = ACIA_RESET; /* reset ACIA for switch off OverScan, if it's active */
|
|
|
/* processor independent: turn off interrupts and reset the VBR;
|
/* processor independent: turn off interrupts and reset the VBR;
|
* the caches must be left enabled, else prefetching the final jump
|
* the caches must be left enabled, else prefetching the final jump
|
* instruction doesn't work. */
|
* instruction doesn't work. */
|
cli();
|
cli();
|
__asm__ __volatile__
|
__asm__ __volatile__
|
("moveq #0,%/d0\n\t"
|
("moveq #0,%/d0\n\t"
|
"movec %/d0,%/vbr"
|
"movec %/d0,%/vbr"
|
: : : "d0" );
|
: : : "d0" );
|
|
|
if (m68k_is040or060) {
|
if (m68k_is040or060) {
|
unsigned long jmp_addr040 = VTOP(&&jmp_addr_label040);
|
unsigned long jmp_addr040 = VTOP(&&jmp_addr_label040);
|
if (m68k_is040or060 == 6) {
|
if (m68k_is040or060 == 6) {
|
/* 68060: clear PCR to turn off superscalar operation */
|
/* 68060: clear PCR to turn off superscalar operation */
|
__asm__ __volatile__
|
__asm__ __volatile__
|
("moveq #0,%/d0\n\t"
|
("moveq #0,%/d0\n\t"
|
".long 0x4e7b0808" /* movec d0,pcr */
|
".long 0x4e7b0808" /* movec d0,pcr */
|
: : : "d0" );
|
: : : "d0" );
|
}
|
}
|
|
|
__asm__ __volatile__
|
__asm__ __volatile__
|
("movel %0,%/d0\n\t"
|
("movel %0,%/d0\n\t"
|
"andl #0xff000000,%/d0\n\t"
|
"andl #0xff000000,%/d0\n\t"
|
"orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */
|
"orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */
|
".long 0x4e7b0004\n\t" /* movec d0,itt0 */
|
".long 0x4e7b0004\n\t" /* movec d0,itt0 */
|
".long 0x4e7b0006\n\t" /* movec d0,dtt0 */
|
".long 0x4e7b0006\n\t" /* movec d0,dtt0 */
|
"jmp %0@\n\t"
|
"jmp %0@\n\t"
|
: /* no outputs */
|
: /* no outputs */
|
: "a" (jmp_addr040)
|
: "a" (jmp_addr040)
|
: "d0" );
|
: "d0" );
|
jmp_addr_label040:
|
jmp_addr_label040:
|
__asm__ __volatile__
|
__asm__ __volatile__
|
("moveq #0,%/d0\n\t"
|
("moveq #0,%/d0\n\t"
|
"nop\n\t"
|
"nop\n\t"
|
".word 0xf4d8\n\t" /* cinva i/d */
|
".word 0xf4d8\n\t" /* cinva i/d */
|
".word 0xf518\n\t" /* pflusha */
|
".word 0xf518\n\t" /* pflusha */
|
".long 0x4e7b0003\n\t" /* movec d0,tc */
|
".long 0x4e7b0003\n\t" /* movec d0,tc */
|
"jmp %0@"
|
"jmp %0@"
|
: /* no outputs */
|
: /* no outputs */
|
: "a" (reset_addr)
|
: "a" (reset_addr)
|
: "d0");
|
: "d0");
|
}
|
}
|
else
|
else
|
__asm__ __volatile__
|
__asm__ __volatile__
|
("pmove %0@,%/tc\n\t"
|
("pmove %0@,%/tc\n\t"
|
"jmp %1@"
|
"jmp %1@"
|
: /* no outputs */
|
: /* no outputs */
|
: "a" (&tc_val), "a" (reset_addr));
|
: "a" (&tc_val), "a" (reset_addr));
|
}
|
}
|
|
|
|
|
void atari_get_model(char *model)
|
void atari_get_model(char *model)
|
{
|
{
|
strcpy(model, "Atari ");
|
strcpy(model, "Atari ");
|
switch (boot_info.bi_atari.mch_cookie >> 16) {
|
switch (boot_info.bi_atari.mch_cookie >> 16) {
|
case ATARI_MCH_ST:
|
case ATARI_MCH_ST:
|
if (ATARIHW_PRESENT(MSTE_CLK))
|
if (ATARIHW_PRESENT(MSTE_CLK))
|
strcat (model, "Mega ST");
|
strcat (model, "Mega ST");
|
else
|
else
|
strcat (model, "ST");
|
strcat (model, "ST");
|
break;
|
break;
|
case ATARI_MCH_STE:
|
case ATARI_MCH_STE:
|
if ((boot_info.bi_atari.mch_cookie & 0xffff) == 0x10)
|
if ((boot_info.bi_atari.mch_cookie & 0xffff) == 0x10)
|
strcat (model, "Mega STE");
|
strcat (model, "Mega STE");
|
else
|
else
|
strcat (model, "STE");
|
strcat (model, "STE");
|
break;
|
break;
|
case ATARI_MCH_TT:
|
case ATARI_MCH_TT:
|
if (is_medusa)
|
if (is_medusa)
|
/* Medusa has TT _MCH cookie */
|
/* Medusa has TT _MCH cookie */
|
strcat (model, "Medusa");
|
strcat (model, "Medusa");
|
else
|
else
|
strcat (model, "TT");
|
strcat (model, "TT");
|
break;
|
break;
|
case ATARI_MCH_FALCON:
|
case ATARI_MCH_FALCON:
|
strcat (model, "Falcon");
|
strcat (model, "Falcon");
|
break;
|
break;
|
default:
|
default:
|
sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)",
|
sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)",
|
boot_info.bi_atari.mch_cookie);
|
boot_info.bi_atari.mch_cookie);
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
|
|
int atari_get_hardware_list(char *buffer)
|
int atari_get_hardware_list(char *buffer)
|
{
|
{
|
int len = 0, i;
|
int len = 0, i;
|
|
|
for (i = 0; i < boot_info.num_memory; i++)
|
for (i = 0; i < boot_info.num_memory; i++)
|
len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n",
|
len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n",
|
boot_info.memory[i].size >> 20,
|
boot_info.memory[i].size >> 20,
|
boot_info.memory[i].addr,
|
boot_info.memory[i].addr,
|
(boot_info.memory[i].addr & 0xff000000 ?
|
(boot_info.memory[i].addr & 0xff000000 ?
|
"alternate RAM" : "ST-RAM"));
|
"alternate RAM" : "ST-RAM"));
|
|
|
#define ATARIHW_ANNOUNCE(name,str) \
|
#define ATARIHW_ANNOUNCE(name,str) \
|
if (ATARIHW_PRESENT(name)) \
|
if (ATARIHW_PRESENT(name)) \
|
len += sprintf (buffer + len, "\t%s\n", str)
|
len += sprintf (buffer + len, "\t%s\n", str)
|
|
|
len += sprintf (buffer + len, "Detected hardware:\n");
|
len += sprintf (buffer + len, "Detected hardware:\n");
|
ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter");
|
ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter");
|
ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter");
|
ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter");
|
ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter");
|
ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter");
|
ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter");
|
ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter");
|
ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator");
|
ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator");
|
ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound");
|
ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound");
|
ATARIHW_ANNOUNCE(CODEC, "CODEC Sound");
|
ATARIHW_ANNOUNCE(CODEC, "CODEC Sound");
|
ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)");
|
ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)");
|
ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)");
|
ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)");
|
ATARIHW_ANNOUNCE(ACSI, "ACSI Interface");
|
ATARIHW_ANNOUNCE(ACSI, "ACSI Interface");
|
ATARIHW_ANNOUNCE(IDE, "IDE Interface");
|
ATARIHW_ANNOUNCE(IDE, "IDE Interface");
|
ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC");
|
ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC");
|
ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901");
|
ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901");
|
ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901");
|
ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901");
|
ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530");
|
ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530");
|
ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230");
|
ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230");
|
ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface");
|
ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface");
|
ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface");
|
ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface");
|
ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)");
|
ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)");
|
ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)");
|
ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)");
|
ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380");
|
ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380");
|
ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC");
|
ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC");
|
ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A");
|
ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A");
|
ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15");
|
ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15");
|
ATARIHW_ANNOUNCE(SCU, "System Control Unit");
|
ATARIHW_ANNOUNCE(SCU, "System Control Unit");
|
ATARIHW_ANNOUNCE(BLITTER, "Blitter");
|
ATARIHW_ANNOUNCE(BLITTER, "Blitter");
|
ATARIHW_ANNOUNCE(VME, "VME Bus");
|
ATARIHW_ANNOUNCE(VME, "VME Bus");
|
|
|
return(len);
|
return(len);
|
}
|
}
|
|
|