//-----------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//-----------------------------------------------------------------------------
//
//  Copyright (C) 2004-2007, Freescale Semiconductor, Inc. All Rights Reserved.
//  THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
//  AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT
//
//-----------------------------------------------------------------------------
//
//  File:  intr.h
//
//  This file contains LogicPD i.MX31 ZOOM LITEKIT interrupt code.
//
//-----------------------------------------------------------------------------

#include <cmnintrin.h>

#include "bsp.h"

//extern UINT32 g_oalIrqTranslate[OAL_INTR_IRQ_MAXIMUM];
//extern ULARGE_INTEGER g_oalIrqMask[OAL_INTR_IRQ_MAXIMUM];
//extern UINT32 g_oalGpioTranslate[DDK_GPIO_PORT3+1][GPIO_INTR_SOURCES_MAX];
//extern UINT32 g_oalGpioMask[DDK_GPIO_PORT3+1][OAL_INTR_IRQ_MAXIMUM];

extern PCSP_GPIO_REGS g_pGPIO1;
extern PCSP_IOMUX_REGS g_pIOMUX;
//extern PCSP_PBC_REGS  g_pPBC;
extern PCSP_GPIO_REGS g_ppGPIO[GPIO_PORT_MAX];

#if 0
static  UINT16 *g_CPLDIntMaskAdr;
static  UINT16 *g_CPLDIntStateAdr;
static UINT16 *g_CPLDIntResetAdr;
#endif

//------------------------------------------------------------------------------
//
//  Function:  BSPIntrInit
//
BOOL BSPIntrInit()
{
   OALIntrStaticTranslate(SYSINTR_USBOTG, IRQ_USB_OTG);
   //OALMSG(1, (TEXT("KERNEL: Translate USB OTG =>irq(0x%x)->sysintr(0x%x)\r\n"), IRQ_USB_OTG, SYSINTR_USBOTG));
   
   // Config uP_nWAKEUP pin
   CONFIG_GPIOSPINNAME_INTERRUPT(g_ppGPIO, uP_nWAKEUP);
   
   // Config WRLAN_nINT pin
   CONFIG_GPIOSPINNAME_INTERRUPT(g_ppGPIO, WRLAN_nINT);
   
   // Config uP_nIRQx pin
   CONFIG_GPIOSPINNAME_INTERRUPT(g_ppGPIO, uP_nIRQA);
   CONFIG_GPIOSPINNAME_INTERRUPT(g_ppGPIO, uP_nIRQB);
   CONFIG_GPIOSPINNAME_INTERRUPT(g_ppGPIO, uP_nIRQC);
   CONFIG_GPIOSPINNAME_INTERRUPT(g_ppGPIO, uP_nIRQD);
   
#if 0
   // Add GPIO line interupt -> IRQ mapping.
   g_oalGpioTranslate[BSP_PBC_GPIO_PORT][BSP_PBC_GPIO_PIN] = BSP_PBC_IRQ;
   //g_oalGpioMask[BSP_PBC_GPIO_PORT][BSP_PBC_IRQ] |= (1U << BSP_PBC_GPIO_PIN);
   
   //OAL_IOMUX_SET_MUX(g_pIOMUX, DDK_IOMUX_PIN_GPIO1_1, DDK_IOMUX_OUT_GPIO, DDK_IOMUX_IN_GPIO);
   //OAL_IOMUX_SET_PAD(g_pIOMUX, DDK_IOMUX_PIN_GPIO1_1, DDK_IOMUX_PAD_SLEW_SLOW, DDK_IOMUX_PAD_DRIVE_MAX, DDK_IOMUX_PAD_MODE_CMOS, DDK_IOMUX_PAD_TRIG_CMOS, DDK_IOMUX_PAD_PULL_UP_100K) ;
   
   
   // Configure PBC interrupt line
   INSREG32(&g_pGPIO1->GDIR, GPIO_PIN_MASK(BSP_PBC_GPIO_PIN), 
       GPIO_PIN_VAL(GPIO_GDIR_INPUT, BSP_PBC_GPIO_PIN));
   
   INSREG32(&g_pGPIO1->ICR1, GPIO_ICR_MASK(BSP_PBC_GPIO_PIN), 
       GPIO_ICR_VAL(GPIO_ICR_LOW_LEVEL, BSP_PBC_GPIO_PIN));
   
   INSREG32(&g_pGPIO1->IMR, GPIO_PIN_MASK(BSP_PBC_GPIO_PIN), 
       GPIO_PIN_VAL(GPIO_IMR_UNMASKED, BSP_PBC_GPIO_PIN));
   
   g_CPLDIntMaskAdr= (UINT16 *) OALPAtoUA(CPLD_MX31_BASE_PA_ADDRESS + CPLD_MX31_RW_INTERRUPT_MASK_OFFSET);
   g_CPLDIntStateAdr = (UINT16 *) OALPAtoUA(CPLD_MX31_BASE_PA_ADDRESS + CPLD_MX31_RO_INTERRUPT_STATUS_OFFSET);
   g_CPLDIntResetAdr = (UINT16 *) OALPAtoUA(CPLD_MX31_BASE_PA_ADDRESS + CPLD_MX31_W_INTERRUPT_RESET_OFFSET);
   
   
   //clear Intrrupt status
   OUTREG16(g_CPLDIntResetAdr, 0x1f);
   OUTREG16(g_CPLDIntResetAdr, 0x0);
   //Mask All CPLD Interrupt
   OUTREG16(g_CPLDIntMaskAdr, 0x1f);
#endif
   
   return TRUE;
}

//------------------------------------------------------------------------------

BOOL BSPIntrRequestIrqs(DEVICE_LOCATION *pDevLoc, UINT32 *pCount, UINT32 *pIrqs)
{
   BOOL rc = FALSE;
   
   OALMSG(OAL_INTR&&OAL_FUNC, (
       __WFUNCTION__ L"(0x%08x->%d/%d/0x%08x/%d, 0x%08x, 0x%08x)+\r\n",
       pDevLoc, pDevLoc->IfcType, pDevLoc->BusNumber, pDevLoc->LogicalLoc,
       pDevLoc->Pin, pCount, pIrqs
   ));
   
   if (pIrqs == NULL || pCount == NULL || *pCount < 1) {
      goto cleanUp;
   }
   
   switch (pDevLoc->IfcType) {
      case Internal:
         switch ((ULONG)pDevLoc->LogicalLoc) {
            case BSP_BASE_REG_PA_LAN911x_IOBASE:
               pIrqs[0] = GET_GPIOPINNAME_IRQ(WRLAN_nINT);
               *pCount = 1;
               rc = TRUE;
               break;
      }
      break;
   }
   
cleanUp:
   OALMSG(OAL_INTR&&OAL_FUNC, (__WFUNCTION__ L"(rc = %d)-\r\n", rc));
   return rc;
}

//------------------------------------------------------------------------------
//
//  Function:  BSPIntrEnableIrq
//
//  This function is called from OALIntrEnableIrq to enable interrupt on
//  secondary interrupt controller.
//
UINT32 BSPIntrEnableIrq(UINT32 irq)
{
   
//   OALMSG(OAL_INTR&&OAL_VERBOSE, (__WFUNCTION__ L"(%d)+\r\n", irq));
   OALMSG(OAL_INTR, (__WFUNCTION__ L"(%d)+\r\n", irq));
   
   if ((IRQ_GPIO_Pxy_MIN <= irq) && (irq <= IRQ_GPIO_Pxy_MAX)) {
      // GPIO irq
      DWORD dwPortIndex, dwPinMask;
      
      dwPortIndex = GET_GPIOIRQ_PORTINDEX(irq);
      dwPinMask   = GET_GPIOIRQ_PINMASK(irq);
      
      // Clear Interrupt Status
      g_ppGPIO[dwPortIndex]->ISR  = dwPinMask;
      // Enable Interrupt
      g_ppGPIO[dwPortIndex]->IMR |= dwPinMask;
      
      irq = (UINT32)OAL_INTR_IRQ_UNDEFINED;
   }
   
//   OALMSG(OAL_INTR&&OAL_VERBOSE, (__WFUNCTION__ L"(%d)-\r\n", irq));
   OALMSG(OAL_INTR, (__WFUNCTION__ L"(%d)-\r\n", irq));
   return irq;
}

//------------------------------------------------------------------------------
//
//  Function:  BSPIntrDisableIrq
//
//  This function is called from OALIntrDisableIrq to disable interrupt on
//  secondary interrupt controller.
//
UINT32 BSPIntrDisableIrq(UINT32 irq)
{
//   UINT16 mask = 0;
   
//   OALMSG(OAL_INTR&&OAL_VERBOSE, (__WFUNCTION__ L"(%d)+\r\n", irq));
   OALMSG(OAL_INTR, (__WFUNCTION__ L"(%d)+\r\n", irq));
   
   if ((IRQ_GPIO_Pxy_MIN <= irq) && (irq <= IRQ_GPIO_Pxy_MAX)) {
      // GPIO irq
      DWORD dwPortIndex, dwPinMask;
      
      dwPortIndex = GET_GPIOIRQ_PORTINDEX(irq);
      dwPinMask   = GET_GPIOIRQ_PINMASK(irq);
      
      // Disable Interrupt
      g_ppGPIO[dwPortIndex]->IMR &= ~dwPinMask;
      // Clear Interrupt Status
      g_ppGPIO[dwPortIndex]->ISR  = dwPinMask;
      
      irq = (UINT32)OAL_INTR_IRQ_UNDEFINED;
   }
#if 0
   // Create PBC interrupt mask based on IRQ
   switch (irq) {
      case BSP_LAN911x_IRQ:
         mask = CPLD_MX31_RW_INT_MASK_ALL; // Mask all CPLD interrupt
         // Disable interrupts within PBC
         OUTREG16(g_CPLDIntMaskAdr, mask);
         OUTREG16(g_CPLDIntResetAdr, 0xffff);
         OUTREG16(g_CPLDIntResetAdr, 0x0);
         
         // Tell upper layers we dealt with BSP interrupt
         irq = (UINT32) OAL_INTR_IRQ_UNDEFINED;
         break;
      default:
         break;
   }
#endif
   
//   OALMSG(OAL_INTR&&OAL_VERBOSE, (__WFUNCTION__ L"(%d)-\r\n", irq));
   OALMSG(OAL_INTR, (__WFUNCTION__ L"(%d)-\r\n", irq));
   return irq;
}


//------------------------------------------------------------------------------
//
//  Function:  BSPIntrDoneIrq
//
//  This function is called from OALIntrDoneIrq to finish interrupt on
//  secondary interrupt controller.
//
UINT32 BSPIntrDoneIrq(UINT32 irq)
{
   OALMSG(OAL_INTR&&OAL_VERBOSE, (__WFUNCTION__ L"(%d)+\r\n", irq));
   
#if 0
   //clear Intrrupt status
   OUTREG16(g_CPLDIntResetAdr, 0xffff);
   OUTREG16(g_CPLDIntResetAdr, 0x0);
   return BSPIntrEnableIrq(irq);
#endif
   if ((IRQ_GPIO_Pxy_MIN <= irq) && (irq <= IRQ_GPIO_Pxy_MAX)) {
      // GPIO irq
      DWORD dwPortIndex, dwPinMask;
      
      dwPortIndex = GET_GPIOIRQ_PORTINDEX(irq);
      dwPinMask   = GET_GPIOIRQ_PINMASK(irq);
      
      // Clear Interrupt Status
      g_ppGPIO[dwPortIndex]->ISR  = dwPinMask;
      // Enable Interrupt
      g_ppGPIO[dwPortIndex]->IMR |= dwPinMask;
      
      irq = (UINT32)OAL_INTR_IRQ_UNDEFINED;
   }
   
   OALMSG(OAL_INTR&&OAL_VERBOSE, (__WFUNCTION__ L"(%d)-\r\n", irq));
   return irq;
}


//------------------------------------------------------------------------------
//
//  Function:  BSPIntrActiveIrq
//
//  This function is called from interrupt handler to give BSP chance to
//  translate IRQ in case of secondary interrupt controller.
//
UINT32 BSPIntrActiveIrq(UINT32 irq)
{
//   UINT16 IntTemp;
   OALMSG(OAL_INTR&&OAL_VERBOSE, (__WFUNCTION__ L"(%d)+\r\n", irq));
   
#if 0
   if (irq == BSP_PBC_IRQ) {
      // clear interrupt status, e.g. Clear external Ethernet interrupt(GPIO 1_1)
      OUTREG32(&g_pGPIO1->ISR, 1 << BSP_PBC_GPIO_PIN);
      
      IntTemp = INREG16(g_CPLDIntStateAdr) ;
      irq = (UINT32) OAL_INTR_IRQ_UNDEFINED;
      
      //OALMSGS(1, ((L"State %X, Mask %X\r\n"), INREG16(g_CPLDIntStateAdr), INREG16(g_CPLDIntMaskAdr)));
      // Determine pending shared PBC interrupt source
      // Only Ethernet Interrupt IRQ NO. be assigned, others not be defined.
      
      if ( IntTemp & CPLD_MX31_RW_INT_MASK_BUTTON2) {
         irq = (UINT32) OAL_INTR_IRQ_UNDEFINED;
      }
      else if ( IntTemp & CPLD_MX31_RW_INT_MASK_BUTTON1) {
         irq = (UINT32) OAL_INTR_IRQ_UNDEFINED;
      }
      else if ( IntTemp & CPLD_MX31_RW_INT_MASK_XUARTB) {
         irq = (UINT32) OAL_INTR_IRQ_UNDEFINED;
      }
      else if ( IntTemp & CPLD_MX31_RW_INT_MASK_XUARTA) {
         irq = (UINT32) OAL_INTR_IRQ_UNDEFINED;
      }
      else {
          irq = BSP_LAN911x_IRQ;
      }
      
      if (irq != OAL_INTR_IRQ_UNDEFINED) {
         BSPIntrDisableIrq(irq);
      }
   }
#endif
   
   if (IS_GPIOIRQ(irq)) {
      // Disable interrupt
      g_ppGPIO[GET_GPIOIRQ_PORTINDEX(irq)]->IMR &= ~GET_GPIOIRQ_PINMASK(irq);
   }
   
   OALMSG(OAL_INTR&&OAL_VERBOSE, (__WFUNCTION__ L"(%d)-\r\n", irq));
   return irq;
}

//------------------------------------------------------------------------------
