/*
* Copyright (c) 2006-2008 Advanced Micro Devices,Inc. ("AMD").
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.

* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA 
*/

//******************************************************************************
//*    Routines related to the Flash device.  
//******************************************************************************





#include "VSA2.H"
#include "CHIPSET.H"
#include "SYSMGR.H"
#include "MDD.H"
#include "PCI.H"
#include "GX2.H"
#include "LEGACY.H"
#include "PROTOS.H"

// Function prototypes:
extern void Hide_IDE_Hdr(void);
extern void Hide_Flash_Hdr(void);


// External variables:
extern ULONG MDD_Base;
extern USHORT Flash_Function, IDE_Function;
extern UCHAR Flash_Allocated;



//***********************************************************************
// Returns non-zero if Flash device is enabled
//***********************************************************************
UCHAR FlashIsEnabled(void)
{ UCHAR Pin;

  Pin = (UCHAR)Read_MSR_LO(MDD_Base + MSR_PIN_OPTS) & PIN_OPT_IDE;
  Pin ^= PIN_OPT_IDE;
  return Pin;
}


//***********************************************************************
// Allocates Flash BARs
//***********************************************************************
void Allocate_Flash_BARs(void)
{ ULONG MsrAddr, MsrData[2], Size;
  USHORT Bar;
  UCHAR Resource;
  static UCHAR Flash_LBARs[4] = {
    MSR_LBAR_FLSH0,
    MSR_LBAR_FLSH1,
    MSR_LBAR_FLSH2,
    MSR_LBAR_FLSH3,
  };


  // BARs are only to be allocated once
  if (Flash_Allocated == 0) {

    Flash_Allocated = 1;
    // Determine type/size of PCI BAR for each Flash device
    MsrAddr = MDD_Base;
    for (Bar = BAR0; Bar <= BAR3; Bar += 4) {
      // Read the Flash LBAR
      (UCHAR)MsrAddr = Flash_LBARs[(Bar-BAR0)/4];
      Read_MSR(MsrAddr, MsrData);

      // If LBAR size has not been programmed, then don't configure the PCI BAR
      Size = MsrData[1] & ~(MEM_IO | NOR_NAND | LBAR_EN);
      if (Size == 0x00000000) {
        continue;
      }

      // MMIO or IO resource
      if (MsrData[1] & MEM_IO ) {
        // MMIO mode
        Size &= LBAR_MEM_MASK;
        Resource = RESOURCE_MMIO;
      } else {
        // IO mode
        // Required for proper byte count calculation
        Size |= 0xFFFF0000;
        Resource = RESOURCE_IO;
      }
      // Convert mask to byte count
      Size = ~Size + 1;
      // Allocate BAR
      SYS_ALLOCATE_RESOURCE(Resource, Bar, Size, DEVICE_ID_AMD_FLASH, ID_MDD);
    }
  }
}



//***********************************************************************
// Switches between Flash and IDE headers
//***********************************************************************
void pascal Flash_IDE_Switch(USHORT Function, ULONG Data)
{ ULONG PinOptions, PinMsr, FlashMsr, LBar[2], SavedLBar[2];

  // Switch pins to Flash mode
  PinMsr = MDD_Base + MSR_PIN_OPTS;
  PinOptions = Read_MSR_LO(PinMsr);

  if (Function == Flash_Function) {
    // Currently in Flash mode

    // Switching to IDE mode ?
    if (Data == 0xBEEFDEAD) {

      // Hide the Flash header
      Hide_Flash_Hdr();

      // Switch pins to IDE mode
      PinOptions |= PIN_OPT_IDE;
      Write_MSR_LO(PinMsr, PinOptions);

      // Disconnect the ROM from the DMA pins
      in_8(0x3F6);
    }

  }	else {

    // Currently in IDE mode

    // Switching to Flash mode ?
    if (Data == 0xDEADBEEF) {

      // Hide the IDE header
      Hide_IDE_Hdr();

      // Allocate Flash BARs
      Allocate_Flash_BARs();

      // Enable Flash mode
      PinOptions &= ~PIN_OPT_IDE;
      Write_MSR_LO(PinMsr, PinOptions);

      // Handle Canary circuit

      // Set CS1# to respond to I/O address 22h
      FlashMsr = MDD_Base + MSR_LBAR_FLSH1;
      Read_MSR(FlashMsr, SavedLBar);
      LBar[0] = 0x00000022;
      LBar[1] = 0x0000FFF0 | LBAR_EN;
      Write_MSR(FlashMsr, LBar);

      // Turn Canary circuit on
      in_8(0x22);

      // Restore CS1 LBAR
      Write_MSR(FlashMsr, SavedLBar);
    }
  }
}
