/*
 *  linux/atari/config.c
 *
 *  Copyright (C) 1994 Bj”rn Brauel
 *
 *  5/2/94 Roman Hodek:
 *    Added setting of time_adj to get a better clock.
 *
 *  5/14/94 Roman Hodek:
 *    gettod() for TT 
 *
 *  5/15/94 Roman Hodek:
 *    hard_reset_now() for Atari (and others?)
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file README.legal in the main directory of this archive
 * for more details.
 */

/*
 * Miscellaneous atari stuff
 */

#include <linux/config.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/mktime.h>
#include <linux/mm.h>
#include <linux/bootinfo.h>
#include <linux/mc146818rtc.h>

#include <linux/atarihw.h>
#include <linux/atariints.h>

#include <asm/system.h>


extern long	time_adj;		/* from kernel/sched.c */


void atari_sched_init (isrfunc timer_routine)
{
	/* set Timer A data Register */
	mfp.tim_dt_a=INT_TICKS;

    /* install interrupt service routine for MFP Timer A */
    add_isr (IRQ_MFP_TIMA, timer_routine, 0, NULL); 
    /* start timer A, div = 1:100 */
	mfp.tim_ct_a = 0x06; 
	/* enable timer A Interrupt */   
	mfp.int_en_a |= 0x20;

	/* The excact frequency of our timer is 2.4576 MHz / 100 / 246 =
	 * 99.90243902 Hz. This gives a difference of 9.76954 us to real time
	 * per clock tick. time_adj is in us scaled by 2^24, thus it should
	 * be 9.76954 * 2^24 = 163905683
	 */
	time_adj = 163905683;
}


unsigned long atari_gettimeoffset (void)
{
    unsigned long ticks, flags;

    save_flags(flags);
    cli();

    ticks = (unsigned long)mfp.tim_dt_a;
    restore_flags(flags);
    
    ticks = (INT_TICKS-1) - ticks;
    ticks = ticks * 10000L / INT_TICKS;
    
    return ticks;

}


#define	RTC_READ(reg)							\
    ({	unsigned char	__val;					\
		tt_rtc.regsel = (reg);					\
		__val = tt_rtc.data;					\
		__val;									\
	})

#define	RTC_WRITE(reg,val)						\
    do {										\
	    tt_rtc.regsel = (reg);					\
		tt_rtc.data = (val);					\
	} while(0)
    

void atari_gettod( struct mktime *time )

{
		int				i;
		unsigned char	ctrl;
		
		for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
			if (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)
				break;
		for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms*/
			if (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP))
				break;

		time->sec  = RTC_READ(RTC_SECONDS);
		time->min  = RTC_READ(RTC_MINUTES);
		time->hour = RTC_READ(RTC_HOURS);
		time->day  = RTC_READ(RTC_DAY_OF_MONTH);
		time->mon  = RTC_READ(RTC_MONTH);
		time->year = RTC_READ(RTC_YEAR);

		/* Adjust values (let the setup valid for TOS) */
		time->mon--;
		time->year += 70;

		ctrl = RTC_READ(RTC_CONTROL); 

		if (!(ctrl & RTC_DM_BINARY)) {
			BCD_TO_BIN(time->sec);
			BCD_TO_BIN(time->min);
			BCD_TO_BIN(time->hour);
			BCD_TO_BIN(time->day);
			BCD_TO_BIN(time->mon);
			BCD_TO_BIN(time->year);
		}
		if (!(ctrl & RTC_24H)) {
			if (time->hour & 0x80) {
				time->hour &= ~0x80;
				time->hour += 12;
			}
		}
}


void waitbut (void)
{
}

void ata_serial_print (const char *str)
{
}


/* ++roman:
 *
 * This function does a reset on machines that lack the ability to
 * 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
 * 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
 * really ROM (mapped by hardware). For other 680x0 machines: don't
 * know if it works...
 *
 * 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
 * (the PC before the pmove statement points to the virtual address of
 * 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
 * statement after the pmove is in the cache already (otherwise 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
 * an address register . The jump statement is surely in the cache
 * now. After that, that physical address of the reset code is loaded
 * into the same address register, pmove is done and the same jump
 * statements goes to the reset code. Since there are not many
 * 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
 * address of a C label. No hope to compile this with another compiler
 * than GCC!
 */
  
void __volatile__ atari_reset( void )

{	long	tc_val = 0, *tc_val_p = &tc_val;
	void	*jmp_addr;
	void	*after_jmp_addr = (void *)VTOP( &&after_jmp );
	
	cli();
	jmp_addr = &&disable_mmu;
	goto before_jmp;

  disable_mmu:
	jmp_addr = after_jmp_addr;
	__asm__ __volatile__
		( "pmove	%0@,tc"
		  : /* no outputs */
		  : "a" (tc_val_p)
		);
  before_jmp:
	__asm__ __volatile__
		( "jmp		%1@"
		  : /* no outputs */
		  : "a" (tc_val_p), "a" (jmp_addr)
		);
  after_jmp:
	__asm__ __volatile__
		( "movel	0x0,sp\n\t"
		  "movel	0x4,a0\n\t"
		  "jmp		a0@"
		  : /* no outputs */
		  : /* no inputs */
		  : "a0"
		);
}

