/******************************************************************************
 *
 *	ICU 32202 / ONCHIP / FX200  DIAGNOSTIC
 *
 * This module contains  Implementation for both types of ICU 
 * NS32202 and ONCHIP.
 * Note also that some general interrupt menaging routine included.
 *
 * History:
 *   +----------+------------+------------------------------------------------+
 *   |   Date   |     by     |     Description                                |
 *   +----------+------------+------------------------------------------------+
 *   |          | Amir       | Written                                        |
 *   +----------+------------+------------------------------------------------+
 * 
 *****************************************************************************/


#include "cc_def.h"
#include "diag.h"

#pragma interrupt (timer_handler__);

/* Forward private function */
/****************************/

private void clock_interrupt (/**/);
public void unmask_interrupt__(/*int_num*/);
public void mask_interrupt__(/*int_num*/);
public void icu_init__();
public void set_handler__(/* n,  handler */);

private volatile int interrupt_flag;

extern void *mod_table__[4];

/****************************************************************************
 *
 * if (ICU_TYPE == NS32202)
 *
 ***************************************************************************/
#if (ICU_TYPE == NS32202)

#ifndef	ICU_BUS_WIDTH
#   define ICU_BUS_WIDTH    1
#endif

#define icu ((volatile byte *) ICU_ADDR) 
#define TIMER_INT 0
#define COUNT 25000

#ifndef ONE_UART
#   define LEVEL_MASK (1 << UART0_INT) +  (1 << UART1_INT) 
#else
#   define LEVEL_MASK (1 << UART0_INT)
#endif

#define PENDING_INT (TIMER_INT < 8 ? BIT_ON(TIMER_INT, icu[IPND_L]) : \
		BIT_ON(TIMER_INT - 8, icu[IPND_H]) )

/* Memory maped registers */
/**************************/

#define	HVCT	    0 * ICU_BUS_WIDTH	/* HARDWARE VECTORE		    */
#define	SVCT	    1 * ICU_BUS_WIDTH	/* SOFTWARE VECTORE		    */
#define	ELTG_L	    2 * ICU_BUS_WIDTH	/* EDGE/LEVEL TRIGGERING LOW	    */
#define	ELTG_H	    3 * ICU_BUS_WIDTH	/* EDGE/LEVEL TRIGGERING HIGH	    */
#define	TPL_L	    4 * ICU_BUS_WIDTH	/* TRIGGERING POLARITY LOW	    */
#define	TPL_H	    5 * ICU_BUS_WIDTH	/* TRIGGERING POLARITY HIGH	    */
#define	IPND_L	    6 * ICU_BUS_WIDTH	/* INTERRUPT PENDING LOW	    */
#define	IPND_H	    7 * ICU_BUS_WIDTH	/* INTERRUPT PENDING HIGH	    */
#define	ISRV_L	    8 * ICU_BUS_WIDTH	/* INTERRUPT IN SERVICE LOW	    */
#define	ISRV_H	    9 * ICU_BUS_WIDTH	/* INTERRUPT IN SERVICE HIGH	    */
#define	IMSK_L	    10 * ICU_BUS_WIDTH	/* INTERRUPT MASK LOW		    */
#define	IMSK_H	    11 * ICU_BUS_WIDTH	/* INTERRUPT MASK HIGH		    */
#define	CSRC_L	    12 * ICU_BUS_WIDTH	/* CASCADED SOURCE LOW		    */
#define	CSRC_H	    13 * ICU_BUS_WIDTH	/* CASCADED SOURCE HIGH		    */
#define	FPRT_L	    14 * ICU_BUS_WIDTH	/* FIRST PRIORITY LOW		    */
#define	FPRT_H	    15 * ICU_BUS_WIDTH	/* FIRST PRIORITY HIGH		    */
#define	MCTL	    16 * ICU_BUS_WIDTH	/* MODE CONTROL			    */
#define	OCASN	    17 * ICU_BUS_WIDTH	/* OUTPUT CLOCK ASSIGNMENT	    */
#define	CIPTR	    18 * ICU_BUS_WIDTH	/* COUNTER INTERRUPT POINTER	    */
#define	PDAT	    19 * ICU_BUS_WIDTH	/* PORT DATA			    */
#define	IPS	    20 * ICU_BUS_WIDTH	/* INTERRUPT/PORT SELECT	    */
#define	PDIR	    21 * ICU_BUS_WIDTH	/* PORT DIRECTION		    */
#define	CCTL	    22 * ICU_BUS_WIDTH	/* COUNTER CONTROL		    */
#define	CICTL	    23 * ICU_BUS_WIDTH	/* COUNTER INTERRUPT CONTROL	    */
#define	LCSV_L	    24 * ICU_BUS_WIDTH	/* L-COUNTER STARTING VALUE LOW	    */
#define	LCSV_H	    25 * ICU_BUS_WIDTH	/* L-COUNTER STARTING VALUE HIGH    */
#define	HCSV_L	    26 * ICU_BUS_WIDTH	/* H-COUNTER STARTING VALUE LOW	    */
#define	HCSV_H	    27 * ICU_BUS_WIDTH	/* H-COUNTER STARTING VALUE HIGH    */
#define	LCCV_L	    28 * ICU_BUS_WIDTH	/* L-COUNTER CURRENT VALUE LOW	    */
#define	LCCV_H	    29 * ICU_BUS_WIDTH	/* L-COUNTER CURRENT VALUE HIGH	    */
#define	HCCV_L	    30 * ICU_BUS_WIDTH	/* H-COUNTER CURRENT VALUE LOW	    */
#define	HCCV_H	    31 * ICU_BUS_WIDTH	/* H-COUNTER CURRENT VALUE HIGH	    */


/****************************************************************************
 *
 *	icu_init__()
 *
 * Working mode:     Fixed mode
 *		     8-Bit bus mode
 ****************************************************************************/

public	void icu_init__()
{				/* freez counters , set coutd, fixed mode    */
    icu[MCTL] = 0xc2;		/* halt counters by clearing bit CRUNL,CRUNH */
    icu[CCTL] = 0x3;   		/* also unconcatenate h/l counters           */

    icu[LCSV_L] = 0;			/* initialize counters if needed     */
    icu[LCSV_H] = 0;			/* initialize counters start values  */
    icu[HCSV_L] = COUNT & 0xff;		/* Low counter isn't used            */
    icu[HCSV_H] = (COUNT >> 8) & 0xff;

    icu[CIPTR]	= TIMER_INT << 4; 	/* H_counter interrupt position      */
    icu[LCCV_L] = 0;			/* initialize counters current value */
    icu[LCCV_H] = 0;			/* Low counter isn't used            */
    icu[HCCV_L] = COUNT & 0xff;
    icu[HCCV_H] = (COUNT >> 8) & 0xff;
    icu[CICTL] = 0x10;	      /* enable writes to the H_counter control reg` */
    icu[CICTL] = 0x30;			/* hcounter interrupt enable 	     */

					/* initialize 8 bit bus 	     */
    icu[IPS]   = 0xff;			/* all ports are interrupt sources   */
    icu[PDIR]  = 0xff;			/* ports direction: as in reset      */
    icu[OCASN] = 0x0;			/* reset. PDAT = irrelevant 	     */

    icu[ISRV_L] = 0x0; 			/* clear interrupt-in-service 	     */
    icu[ISRV_H] = 0x0;
    icu[CSRC_L] = 0x0; 			/* No cascade source interrupt 	     */
    icu[CSRC_H] = 0x0;
    icu[SVCT] = 0x10;   /* master ICU, non cascaded,Interrupt starts from 16 */
    icu[TPL_L]	= LEVEL_MASK & 0xff;    	/* Triggering polarity	     */
    icu[TPL_H]	= (LEVEL_MASK >> 8) & 0xff;	/* Rising Edge/ Hign-Level   */

#if (BOARD == GX32ED)
    icu[ELTG_L] = 0x0;			/* Edge triggered 		     */
    icu[ELTG_H] = 0x0;			/* Edge triggered 		     */
#endif
#if (BOARD == CG16ED)
    icu[ELTG_L] = 0xff;			/* level triggered 		     */
    icu[ELTG_H] = 0xff;			/* level triggered 		     */
#endif

    icu[MCTL] &=  ~(1 << 6);		/* clear bit coutd 		     */
    icu[CCTL] |= 0x30;			/* interrupt when H/L counter is zero */
    icu[IMSK_L] = 0xff;			/* Mask all interrupt 		     */
    icu[IMSK_H] = 0xff;
}

/****************************************************************************
 *
 *	clock_interrupt()
 *
 ****************************************************************************/

private void clock_interrupt ()
{
    icu[CCTL]   = 0x0c;         	/* Start counters                    */
}

/****************************************************************************
 *
 *	timer_handler__()
 *
 ****************************************************************************/

public void timer_handler__()
{
    interrupt_flag = 1;
}

/****************************************************************************
 *
 *      mask_interrupt__()
 *      unmask_interrupt__()
 * 
 *  These functions mask/unmask an interrupt level.
 *
 ****************************************************************************/
public void unmask_interrupt__(int_num)
	int     int_num;
{
    if (int_num < 8)
	CLEAR_BIT(int_num, icu[IMSK_L]);
    else if (int_num < 16)
	CLEAR_BIT(int_num - 8, icu[IMSK_H]);
}

public void mask_interrupt__(int_num)
    int     int_num;
{ 
    if (int_num < 8)
	SET_BIT(int_num, icu[IMSK_L]);
    else if (int_num < 16)
	SET_BIT(int_num - 8, icu[IMSK_H]);
}

#endif /* ICU_TYPE == NS32202 */


#if (ICU_TYPE == ON_CHIP_ICU)

/* On Chip & On board registers of ICU */
/***************************************/

#define	ISRV			(* ((volatile word *) 0xFFFFFE04))
#define TIMER0_ADD		0xfffff810
#define TIMER1_ADD		0xfffff820
#define TIMER2_ADD		0xfffff830


#define TIMER0			*((volatile word *) TIMER0_ADD)
#define T0RA			*((volatile word *) (TIMER0_ADD + 0x4))
#define T0RB			*((volatile word *) (TIMER0_ADD + 0x8))
#define T0CNTL			*((volatile word *) (TIMER0_ADD + 0xc))

#define TIMER1			*(( volatile word *) TIMER1_ADD)
#define T1RA			*(( volatile word *) (TIMER1_ADD + 0x4))
#define T1RB			*(( volatile word *) (TIMER1_ADD + 0x8))
#define T1CNTL			*(( volatile word *) (TIMER1_ADD + 0xc))

#define TIMER2			*((volatile word *) TIMER2_ADD)
#define T2RA			*((volatile word *) (TIMER2_ADD + 0x4))
#define T2RB			*((volatile word *) (TIMER2_ADD + 0x8))
#define T2CNTL			*((volatile word *) (TIMER2_ADD + 0xc))


#define TIME_COUNT  3125    /* Interrupt every 1/1000 sec in 25 MHz */

#define	IPFA	    3	    /* Clock Interrupt pending flag A	    */
#define	IENA	    2	    /* Interrupt Enable bit     A	    */

#define	TIMER_INT   13

#define PENDING_INT (BIT_ON(IPFA,T0CNTL))

/****************************************************************************
 *
 *	icu_init__()
 *
 ****************************************************************************/

public	void icu_init__()
{
    ISRV = 0;	    			/* Clear interrupt in service */
    T0CNTL = 0;	   			/* Reset Timer-1 Cntrl register */
}

/****************************************************************************
 *
 *	clock_interrupt()
 *
 ****************************************************************************/

private void clock_interrupt()
{
    TIMER0 = TIME_COUNT;
    T0RA = TIME_COUNT;	    			/* initialization of timer1 */
    T0RB = 1;
    T0CNTL = 0x34;	    	/* start the timer at Mode 1 int-A enable   */
}

/****************************************************************************
 *
 *	timer_handler__()
 *
 * Clear IPFA . U can't use CLEAR BIT since U can't be sure about The read
 * value of  TOCNL register.  Therefore, U must use MOVW instruction
 *
 ****************************************************************************/

public void timer_handler__()
{
    interrupt_flag = 1;
    T0CNTL = 0x34;
}

private const int mask_map[] = {-1,7,6,5,4,-1,-1,-1,3,2,-1,-1,1,-1,-1,0};

public void unmask_interrupt__(int_num)
    int     int_num;
{
#ifdef IMASK
    if (mask_map[int_num] !=  (-1))
	CLEAR_BIT(mask_map[int_num], IMASK);
#endif
}

public void mask_interrupt__(int_num)
    int     int_num;
{
#ifdef IMASK
    if (mask_map[int_num] !=  (-1))
	SET_BIT(mask_map[int_num], IMASK);
#endif
}
#endif /* ICU_TYPE == ON_CHIP_ICU   */



#if (ICU_TYPE == FX200ICU)

#ifndef	ICU_BUS_WIDTH
#   define ICU_BUS_WIDTH    2
#endif

#define icu ((volatile word *) ICU_ADDR) 
#define ivct ((volatile byte *) ICU_ADDR) 
#define TIMER_INT 3

/* Memory maped registers */

#define	IVCT	    0 * ICU_BUS_WIDTH	/* Interrupt vector register 	*/
#define	IELTG	    2 * ICU_BUS_WIDTH	/* Edge / level triger		*/
#define	ITRPL	    3 * ICU_BUS_WIDTH	/* Trigger polarity		*/
#define	IPEND	    4 * ICU_BUS_WIDTH	/* Interrupt pending register	*/
#define	IENAM	    5 * ICU_BUS_WIDTH	/* Interrupt enable & mask reg`	*/
#define	IECLR	    6 * ICU_BUS_WIDTH	/* Edge interrupt clear reg`	*/

#define PENDING_INT (BIT_ON(TIMER_INT,icu[IPEND]))

/****************************************************************************
 *
 *	icu_init__()
 *
 ****************************************************************************/

public	void icu_init__()
{
    icu[IELTG] = 0xfe0e;	/* Normal internal int` source		*/
    icu[ITRPL] = 0xffff;   	/* Normal internal int polarity		*/
    icu[IECLR] = 0xffff;   	/* Clear pending edge triggerd int`	*/
    icu[IENAM] = 0x0;   	/* mask all interrupts			*/
}

/****************************************************************************
 *
 *	clock_interrupt()
 *
 ****************************************************************************/

private void clock_interrupt ()
{
    *((volatile byte *) MCLON_ADD) = 7; 
    *((volatile byte *) MCLOFF_ADD) = 7; 
    *((volatile word *) MCFG_ADD) |= 0x1; 
    *((volatile word *) TIMER_ADD) = 1228; /* Start counter in TCU	*/
}

/****************************************************************************
 *
 *	timer_handler__()
 *
 ****************************************************************************/

public void timer_handler__()
{
    icu[IECLR] = 0xffff;        /* Clear pending edge triggerd int`     */
    interrupt_flag = 1;
}

public void mask_interrupt__(int_num)
	int     int_num;
{
	CLEAR_BIT(int_num, icu[IENAM]);
}

public void unmask_interrupt__(int_num)
    int     int_num;
{ 
	SET_BIT(int_num, icu[IENAM]);
}

#endif /* ICU_TYPE == FX200ICU  */


#if (ICU_TYPE == A1DICU)

#ifndef	ICU_BUS_WIDTH
#   define ICU_BUS_WIDTH    2
#endif

#define ICU ((volatile byte *) ICU_ADDR) 

#define TIMER_INT 2
#define TIMER	*((volatile byte *) TIMER_ADDR)

/* Memory maped registers */

#define	IVCT	    0 * ICU_BUS_WIDTH	/* Interrupt vector register 	*/
#define	IPEND	    1 * ICU_BUS_WIDTH	/* Interrupt pending register	*/
#define	IGEN	    1 * ICU_BUS_WIDTH	/* Software Interrupt control	*/
#define	IENAM	    2 * ICU_BUS_WIDTH	/* Interrupt enable & mask reg`	*/


#define PENDING_INT (BIT_ON(TIMER_INT,ICU[IPEND]))

/****************************************************************************
 *
 *	icu_init__()
 *
 ****************************************************************************/

public	void icu_init__()
{
    ICU[IENAM] = 0x0;   	/* mask all interrupts			*/
}

/****************************************************************************
 *
 *	clock_interrupt()
 *
 ****************************************************************************/

private void clock_interrupt ()
{
    TIMER = 0x0;    /* Reset 10mseq timer int` */
}

/****************************************************************************
 *
 *	timer_handler__()
 *
 ****************************************************************************/

public void timer_handler__()
{
    CLEAR_BIT(TIMER_INT, ICU[IENAM]);    /* Clear pending int`     */
    interrupt_flag = 1;
}

public void mask_interrupt__(int_num)
	int     int_num;
{
	CLEAR_BIT(int_num, ICU[IENAM]);
}

public void unmask_interrupt__(int_num)
    int     int_num;
{ 
	SET_BIT(int_num, ICU[IENAM]);
}

#endif /* ICU_TYPE == A1D  */



#if (ICU_TYPE == DRAGON_ICU)
public void unmask_interrupt__(int_num)
    int int_num;
	{}

public void mask_interrupt__(int_num)
    int int_num;
	{}
#endif	/* ICU_TYPE == DRAGON) */


/****************************************************************************
 *
 *	set_handler__()
 *
 *  This function sets an interrupt handler entry in the dispatch table.
 *
 ****************************************************************************/

public void set_handler__(n, handler)
int    n;
void   (*handler)();
{
#if (NON_DE_AVAILABLE)
    diag_dispatch__[n + 16].mod	 = (short) mod_table__;
    diag_dispatch__[n + 16].offset = (short) 
                                     ((int)handler - (int)mod_table__[P_BASE]);
#else
    diag_dispatch__[n + 16].funcp = handler;
#endif
    unmask_interrupt__(n);

}

/****************************************************************************
 *
 *	test_icu__()
 *
 * As a first test disable interrupts and check the IPND register;
 *
 ****************************************************************************/
#if (ICU_TYPE != DRAGON_ICU)

public char * test_icu__()
{
    int	i;

    _interrupt_disable();
    icu_init__();
    clock_interrupt();
    for (i = 0; i < 0x100000; i++) {
	if (PENDING_INT) {
	    break;
	}
    }
    if ( i == 0x100000) {
	strcpy (error, "FAILURE: NO PENDING INTERRUPT FROM TIMER.");
	return error;
    }
    if (debug_flag) {
	strcpy(msg__,  "PENDING INTERRUPT TEST FROM TIMER PASSED");
	print_str (msg__);
    }
    icu_init__();
    interrupt_flag = 0;
    clock_interrupt();
#if (ICU_TYPE == FX200ICU)
    set_handler__(TIMER_INT + 0x10, timer_handler__);
#else
    set_handler__(TIMER_INT, timer_handler__);
#endif
    unmask_interrupt__ (TIMER_INT);
    _interrupt_enable();
    for (i = 0; i < 0x100000; i++) {
	if (interrupt_flag)
	    break;
    }
    _interrupt_disable();
    icu_init__();
    if ( i == 0x100000) {
	strcpy (error, "FAILURE: NO INTERRUPT FROM TIMER.");
	return error;
    }
    if (debug_flag) {
	strcpy(msg__,  "TEST INTERRUPT FROM TIMER PASSED");
	print_str (msg__);
    }
    icu_init__();
    return NULL;   
}
#endif

