/** @file

  Copyright (c) 2004  - 2014, Intel Corporation. All rights reserved.<BR>
                                                                                   

  This program and the accompanying materials are licensed and made available under

  the terms and conditions of the BSD License that accompanies this distribution.  

  The full text of the license may be found at                                     

  http://opensource.org/licenses/bsd-license.php.                                  

                                                                                   

  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,            

  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.    

                                                                                   


Module Name:

    LpcIsaAcpi.c

Abstract: IsaAcpi implementation



--*/

#include "LpcDriver.h"

//
// PS/2 Keyboard Controller
//
static EFI_ISA_ACPI_RESOURCE  mLpcWpce791Ps2KeyboardDeviceResources[] = {
  {EfiIsaAcpiResourceIo,        0, 0x60, 0x64},
  {EfiIsaAcpiResourceInterrupt, 0, 1,     0},
  {EfiIsaAcpiResourceEndOfList, 0, 0,     0}
};

//
// PS/2 Mouse Controller
//
static EFI_ISA_ACPI_RESOURCE  mLpcWpce791Ps2MouseDeviceResources[] = {
  {EfiIsaAcpiResourceIo,        0, 0x60, 0x64},
  {EfiIsaAcpiResourceInterrupt, 0, 12,     0},
  {EfiIsaAcpiResourceEndOfList, 0, 0,     0}
};

//
// COM
//
static EFI_ISA_ACPI_RESOURCE  mLpcWpce791ComDeviceResources[] = {
  {EfiIsaAcpiResourceIo,        0, 0x3f8, 0x3ff},
  {EfiIsaAcpiResourceInterrupt, 0, 4,     0},
  {EfiIsaAcpiResourceEndOfList, 0, 0,     0}
};

//
// Table of ISA Controllers
//
EFI_ISA_ACPI_RESOURCE_LIST mLpcWpce791DeviceList[] = {
  {{EISA_PNP_ID(0x303), 0}, mLpcWpce791Ps2KeyboardDeviceResources }, // PS/2 Keyboard Controller
  {{EISA_PNP_ID(0xF03), 0}, mLpcWpce791Ps2MouseDeviceResources	  }, // PS/2 Mouse Controller
  {{EISA_PNP_ID(0x501), 0}, mLpcWpce791ComDeviceResources	      }, // COM
  {{0,                  0}, NULL                                  }  // End
};

static ICH_DMA_INIT  mIchDmaInitTable [] = {
//
//Register OFFSET,           Value
//

            0x0D8,           0x000,   // Reset DMA Controller 2
            0x0D0,           0x000,   // Enable DMA controller 2
            0x00C,           0x000,   // Reset DMA Controller 1
            0x008,           0x000,   // Enable DMA controller 1

            //
            // Channel 4
            //
            0x0D6,           0x0c0,   // DMA contr. 2 Cascade mode, addr. increment, disable auto init.
            0x0D2,           0x000,   // Clear write request register
            0x0d4,           0x000,   // Enable DREQs for channel

            //
            // Channel 0
            //
            0x00B,           0x040,   // DMA contr. 1 single mode, addr. increment, disable auto init.
            0x009,           0x000,   // Clear write request register
            0x00A,           0x000,   // Enable DREQs for channel

            //
            // Channel 1
            //
            0x00B,           0x041,   // DMA contr. 1 single mode, addr. increment, disable auto init.
            0x009,           0x001,   // Clear write request register
            0x00A,           0x001,   // Enable DREQs for channel

            //
            // Channel 2
            //
            0x00B,           0x042,   // DMA contr. 1 single mode, addr. increment, disable auto init.
            0x009,           0x002,   // Clear write request register
            0x00A,           0x002,   // Enable DREQs for channel

            //
            // Channel 3
            //
            0x00B,           0x043,   // DMA contr. 1 single mode, addr. increment, disable auto init.
            0x009,           0x003,   // Clear write request register
            0x00A,           0x003,   // Enable DREQs for channel

            //
            // Channel 5
            //
            0x0D6,           0x041,   // DMA contr. 2 single mode, addr. increment, disable auto init.
            0x0D2,           0x001,   // Clear write request register
            0x0D4,           0x001,   // Enable DREQs for channel

            //
            // Channel 6
            //
            0x0D6,           0x042,   // DMA contr. 2 single mode, addr. increment, disable auto init.
            0x0D2,           0x002,   // Clear write request register
            0x0D4,           0x002,   // Enable DREQs for channel

            //
            // Channel 7
            //
            0x0D6,           0x043,   // DMA contr. 2 single mode, addr. increment, disable auto init.
            0x0D2,           0x003,   // Clear write request register
            0x0D4,           0x003    // Enable DREQs for channel

};

//
// ISA ACPI Protocol Functions
//
/**

  Enumerate the ISA devices on the ISA bus

**/
VOID
IsaDeviceLookup (
  IN  EFI_ISA_ACPI_DEVICE_ID      *Device,
  OUT EFI_ISA_ACPI_RESOURCE_LIST  **IsaAcpiDevice,
  OUT EFI_ISA_ACPI_RESOURCE_LIST  **NextIsaAcpiDevice
  )
{
  UINTN  Index;

  *IsaAcpiDevice = NULL;
  if (NextIsaAcpiDevice != NULL) {
    *NextIsaAcpiDevice = NULL;
  }
  if (Device == NULL) {
    Index = 0;
  } else {
    for(Index = 0; mLpcWpce791DeviceList[Index].Device.HID != 0; Index++) {
      if (Device->HID == mLpcWpce791DeviceList[Index].Device.HID &&
          Device->UID == mLpcWpce791DeviceList[Index].Device.UID    ) {
        break;
      }
    }
    if (mLpcWpce791DeviceList[Index].Device.HID == 0) {
      return;
    }
    *IsaAcpiDevice = &(mLpcWpce791DeviceList[Index]);
    Index++;
  }
  if (NextIsaAcpiDevice != NULL && mLpcWpce791DeviceList[Index].Device.HID != 0){
    *NextIsaAcpiDevice = &(mLpcWpce791DeviceList[Index]);
  }
}


/**
  Enumerate the ISA devices on the ISA bus
  It is hard code now and future it will get from ACPI table

**/
EFI_STATUS
EFIAPI
IsaDeviceEnumerate (
  IN     EFI_ISA_ACPI_PROTOCOL       *This,
  OUT    EFI_ISA_ACPI_DEVICE_ID      **Device
  )
{
  EFI_ISA_ACPI_RESOURCE_LIST  *IsaAcpiDevice;
  EFI_ISA_ACPI_RESOURCE_LIST  *NextIsaAcpiDevice;

  IsaDeviceLookup (*Device, &IsaAcpiDevice, &NextIsaAcpiDevice);
  if (NextIsaAcpiDevice == NULL) {
    return EFI_NOT_FOUND;
  }
  *Device = &(NextIsaAcpiDevice->Device);
  return EFI_SUCCESS;
}

/**
  Set ISA device power use sio

**/
EFI_STATUS
EFIAPI
IsaDeviceSetPower (
  IN     EFI_ISA_ACPI_PROTOCOL       *This,
  IN     EFI_ISA_ACPI_DEVICE_ID      *Device,
  IN     BOOLEAN                     OnOff
  )
{
  return EFI_UNSUPPORTED;
}


/**
  Get current Resource of the specific ISA device
  It is hardcode now and future will get from ACPI table

**/
EFI_STATUS
EFIAPI
IsaGetCurrentResource (
  IN     EFI_ISA_ACPI_PROTOCOL        *This,
  IN     EFI_ISA_ACPI_DEVICE_ID       *Device,
  OUT    EFI_ISA_ACPI_RESOURCE_LIST   **ResourceList
  )
{
  IsaDeviceLookup (Device, ResourceList, NULL);
  if (*ResourceList == NULL || (*ResourceList)->ResourceItem == NULL) {
    return EFI_NOT_FOUND;
  }
  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
IsaGetPossibleResource (
  IN     EFI_ISA_ACPI_PROTOCOL       *This,
  IN     EFI_ISA_ACPI_DEVICE_ID      *Device,
  OUT    EFI_ISA_ACPI_RESOURCE_LIST  **ResourceList
  )
{
  //
  // Not supported yet
  //
  return EFI_UNSUPPORTED;
}


EFI_STATUS
EFIAPI
IsaSetResource (
  IN     EFI_ISA_ACPI_PROTOCOL       *This,
  IN     EFI_ISA_ACPI_DEVICE_ID      *Device,
  IN     EFI_ISA_ACPI_RESOURCE_LIST  *ResourceList
  )
{
  return EFI_UNSUPPORTED;
}

EFI_STATUS
EFIAPI
IsaEnableDevice (
  IN    EFI_ISA_ACPI_PROTOCOL        *This,
  IN    EFI_ISA_ACPI_DEVICE_ID       *Device,
  IN    BOOLEAN                      Enable
  )
{

  return EFI_UNSUPPORTED;
}

/**

  Clear out Resource List if device is set to disable by platform policy

**/
VOID
EmptyResourceList (
  IN  UINT32      DeviceHid
  )
{
  UINT8     Index;
  for (Index = 0; mLpcWpce791DeviceList[Index].Device.HID != 0; Index++) {
    if (DeviceHid == mLpcWpce791DeviceList[Index].Device.HID) {
      mLpcWpce791DeviceList[Index].ResourceItem = NULL;
    }
  }
  return;
}

/**

  Clear out Resource List if device is set to disable by platform policy

**/
VOID
EmptyResourceListHidUid (
  IN  UINT32      DeviceHid,
  IN  UINT32      DeviceUid
  )
{
  UINT8     Index;
  for (Index = 0; mLpcWpce791DeviceList[Index].Device.HID != 0; Index++) {
    if ((DeviceHid == mLpcWpce791DeviceList[Index].Device.HID) &&
        (DeviceUid == mLpcWpce791DeviceList[Index].Device.UID)) {
      mLpcWpce791DeviceList[Index].ResourceItem = NULL;
    }
  }
  return;
}

EFI_STATUS
EFIAPI
IsaInitDevice (
  IN    EFI_ISA_ACPI_PROTOCOL        *This,
  IN    EFI_ISA_ACPI_DEVICE_ID       *Device
  )
{
  EFI_WPCE791_POLICY_PROTOCOL      *LpcWpce791Policy;
  EFI_STATUS                      Status;

  //
  // Disable configuration according to platform protocol
  //
  Status = gBS->LocateProtocol (
                  &gEfiLpcWpce791PolicyProtocolGuid,
                  NULL,
                  (VOID **) &LpcWpce791Policy
                  );
  if (!EFI_ERROR(Status)) {
    if (LpcWpce791Policy->DeviceEnables.Ps2Keyboard == EFI_WPCE791_PS2_KEYBOARD_DISABLE) {
      EmptyResourceList(EISA_PNP_ID(0x303));
      DisableLogicalDevice (SIO_KEYBOARD);
      EmptyResourceList(EISA_PNP_ID(0xF03));
      DisableLogicalDevice (SIO_KEYBOARD);
    }
    if (LpcWpce791Policy->DeviceEnables.Ps2Mouse == EFI_WPCE791_PS2_MOUSE_DISABLE) {
      EmptyResourceList(EISA_PNP_ID(0xF03));
      DisableLogicalDevice (SIO_MOUSE);
    }
  }

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
LpcInterfaceInit (
  IN    EFI_ISA_ACPI_PROTOCOL        *This
  )
{
  EFI_PCI_IO_PROTOCOL             *PciIo;
  UINTN                           Index;

  PciIo = (LPC_ISA_ACPI_FROM_THIS (This))->PciIo;

  //
  // DMA controller initialize
  //
  for (Index=0; Index < (sizeof(mIchDmaInitTable)/sizeof(ICH_DMA_INIT)); Index++) {
    PciIo->Io.Write (
                PciIo,
                EfiPciIoWidthUint8,
                EFI_PCI_IO_PASS_THROUGH_BAR,
                mIchDmaInitTable[Index].Register,
                1,
                &mIchDmaInitTable[Index].Value
                );
  }

  return EFI_SUCCESS;
}

