/*
    Copyright 2001 (c) by Authors,
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.
 
    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.
 
    For further information, please visit http://www.tik.ee.ethz.ch/~topsy
 
    This software is provided under the terms of the GNU General Public 
    Licence. A full copy of the GNU GPL is provided in the file COPYING 
    found in the development root of Topsy.
*/
/*
	
    File:                  $Source: /home/ruf/cvs_Topsy/cvs/Topsy/IO/sa1100/Drivers/Attic/IXPInt.c,v $
    Affiliation:           ETH Zuerich, TIK
    Version:               $Revision: 2936 $
    Last Date of Change:   $Date: 2007-03-21 15:23:42 +0100 (Mit, 21 Mär 2007) $  by: $Author: baderma $
 
*/

#include "types.h"
#include "Topsy.h"
#include "Support.h"
#include "cpu.h"
#include "IXPMemAccess.h"
#include "IXP_Defines.h"

// this code is based upon parts of vera from Princeton


typedef enum {
  IREG_CINTFIQ = 1 << 29,     // CINTs produce FIQs
  IREG_UEIRQ   = 1 << 30,     // uEs produce IRQs
  IREG_UEFIQ   = 1 << 31      // uEs produce FIQs
} IREG_fields;

typedef enum {
  INT_VAL_PCI  = 1 << 2,          // PCI interrupt active
  INT_VAL_UENG = 1 << 4           // uE interrupt active
} INT_VALUE_fields;


#define SA_DMXMSG_ARR_ADDR			0
#define SA_MSG_FATAL_ERROR			8
#define SA_MSG_DEBUG						4
#define DRAM_RESERVED						(16*1024*1024)  /* Reserved at bottom of SDRAM */
#define VECTOR_IRQ							(DRAM_BASE + DRAM_RESERVED + 0x00000000)
#define CPSR_IRQ_DISABLE				0x00000080

typedef Boolean (*Interrupt_handler_func_t)(uint32, uint32);


// Registerable handlers
static void (*Int_ueInterruptHandler)(uint32 tidMask);


/*****************************************************************************/
/*                                                                           */
/* Function Name: irqHandler                                                 */
/* Parameters:                                                               */
/*      uint32  src     The source of the interrupt (IRQ register).          */
/*      uint32  status  The contents of the IRQ_STATUS register.             */
/* Returns: TRUE.                                                            */
/* Effects: Calls the Int_ueInterruptHandler function.                       */
/*                                                                           */
/*****************************************************************************/

static Boolean irqHandler(uint32 src, uint32 status)
{
  uint32 IREG_value;

  /* Clear the interrupt. */
  IREG_value = memRead32(IXP1200_IREG);
  memWrite32(IXP1200_IREG, IREG_value);

  IREG_value &= 0x00FFFFFF;

  Int_ueInterruptHandler(IREG_value);

  return TRUE;
}


/*****************************************************************************/
/*                                                                           */
/* Function Name: ueInterruptHandler                                         */
/* Parameters: uint32  tidMask  Which thread(s) sent a message.              */
/* Returns: <none>                                                           */
/* Effects: Reads and decodes the message from the microengines.             */
/*                                                                           */
/*****************************************************************************/

void ueInterruptHandler(uint32 tidMask)
{
  int tid = 0;

  // Check thread state
  for (tid = 0; tid < 24; tid++)
  {
    uint32 threadMsg;

    if (! (tidMask & (1 << tid)))
      continue;

    // Clear demux messages
    threadMsg = scratchRead32(SA_DMXMSG_ARR_ADDR + tid);
    if (threadMsg == 0)
      continue;
    scratchWrite32(SA_DMXMSG_ARR_ADDR + tid, 0);

    if (threadMsg & SA_MSG_FATAL_ERROR)
    {
      printf("FATAL uE ERROR, tid: %d\n", tid);
    }
    if (threadMsg & SA_MSG_DEBUG)
    {
      printf("DEBUG uE MESSAGE, tid: %d\n", tid);
    }
  }
}


/*****************************************************************************/
/*                                                                           */
/*  DESCRIPTION                                                              */
/*      Get the contents of the current process status register (CPSR).      */
/*                                                                           */
/*  RETURN VALUE                                                             */
/*      The contents of the CPSR                                             */
/*****************************************************************************/

inline uint32 get_cpsr(void)
{
  uint32 cpsr;

asm volatile("mrs  %0, cpsr" : "=r" (cpsr));

  return cpsr;
}

/*****************************************************************************/
/*                                                                           */
/*  DESCRIPTION                                                              */
/*      Set the value of the current process status register (CPSR).         */
/*                                                                           */
/*  PARAMETER                                                                */
/*      cpsr  -  The new value of the CPSR                                   */
/*****************************************************************************/

inline void set_cpsr(uint32 cpsr)
{
asm volatile("msr  cpsr, %0" : : "r" (cpsr));
}


/*****************************************************************************/
/*                                                                           */
/* Function Name: cpsr_enable_irq                                            */
/* Parameters: <none>                                                        */
/* Returns: <none>                                                           */
/* Effects: enables normal interrupts                                        */
/*****************************************************************************/

extern inline void cpsr_enable_irq(void)
{
  uint32		cpsr;

  cpsr = get_cpsr();
  cpsr &= ~CPSR_IRQ_DISABLE;        /* Clear the disable bit */
  set_cpsr(cpsr);
}


/*****************************************************************************/
/*                                                                           */
/* Function Name: Interrupt_Init                                             */
/* Parameters: <none>                                                        */
/* Returns: <none>                                                           */
/* Effects: Initializes the interrupt handler lists and enables the          */
/*          interrupts.                                                      */
/*****************************************************************************/

void
Interrupt_Init()
{
  /* Register ISRs with the SK Loader */
  memWrite32(VECTOR_IRQ, (uint32)irqHandler);

  /* Enable the interrupts. */
  cpsr_enable_irq();
}


/*****************************************************************************/
/*                                                                           */
/* Function Name: Int_Init                                                   */
/* Parameters:                                                               */
/*      void (*ue_ih)(uint32 tid))      Handle a microengine interrupt.      */
/* Returns: <none>                                                           */
/* Effects: sets an interrupt handler for interrupts from the microengines.  */
/*****************************************************************************/

void Int_Init(void (*ue_ih)(uint32 tid))
{
  // Clear the IREG register uE interrupts
  memWrite32(IXP1200_IREG, 0);
  memWrite32(IXP1200_IREG, memRead32(IXP1200_IREG));  // Clear IXP1200_IREG

  // Make uEs generate IRQ interrupts
  memWrite32(IXP1200_IREG, IREG_UEIRQ);

  Int_ueInterruptHandler = ue_ih;

  // Enable interrupts
  Interrupt_Init();
}
