⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcmciasupport.c

📁 CIRRUS 公司EP93XX系列CPU的WINCE下的BSP
💻 C
字号:
//**********************************************************************
//                                                                      
// Filename: pcmciasupport.c
//                                                                      
// Description: Contains routines for the pcmcia card initialization.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Use of this source code is subject to the terms of the Cirrus 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 
// EULA.RTF on your install media.
//
// Copyright(c) Cirrus Logic Corporation 2002, All Rights Reserved                       
//                                                                      
//**********************************************************************

#include "eboot.h"
#include <windows.h>
#include <memorymap.h>
#include <hwdefs.h>
#include <debugtimer.h>
#include <halether.h>
#include <clocks.h>
//#include "powerpccard.h"
#include <pcmciasupport.h>

static unsigned char Vcc = 0;
static unsigned char Vpp1 = 0;
static unsigned char Vpp2 = 0;

#define ERROR_POWERPCCARD_INVALID_PARMS 1
#define ERROR_POWERPCCARD_TIMEOUT       2

//
// Definitions to program the TPS2202A PCMCIA controller.
//
#define     AVPP_0V         0x000
#define     BVPP_0V         0x000
#define     AVCC_0V         0x000
#define     AVCC_33V        0x004
#define     AVCC_5V         0x008
#define     BVCC_0V         0x000
#define     BVCC_33V        0x080
#define     BVCC_5V         0x040
#define     ENABLE          0x100
#define     EE_ADDRESS      (0x55<<9)

//
// The propagation delay of the EP931x board.  
// Don't know what this number is.  This number is probably high right now.
//
#define PCMCIA_BOARD_DELAY          40


/* START_FUNC ****************************************************************
*
*  Description:
*        This function controls the power to the PC Card socket.
*
*  Exception Handling (if any):
*     None
*
*  Garbage Collection (if any):
*     None
*
*  Global Data:
*     None
*
** END_FUNC ******************************************************************/
// Synopsis: control the power to the pc card.



static unsigned char PowerPCCardWrite
(
  unsigned char vccOut,
  unsigned char vpp1Out,
  unsigned char vpp2Out
)
{    
    unsigned char retVal = 0;    // 0 = G_SUCCESS
    ULONG         ulSwitchSettings;
    int       i;
    
    
    if(vccOut == 50)
    {
        //
        // Configure PCMCIA for 5 Volts.
        //
        ulSwitchSettings = EE_ADDRESS |ENABLE | AVPP_0V | BVPP_0V |AVCC_5V | BVCC_0V;
    }
    else if(vccOut ==33)
    {
        //
        // Configure PCMCIA for 3.3 Volts.
        //
        ulSwitchSettings = EE_ADDRESS | ENABLE | AVPP_0V | BVPP_0V |AVCC_33V | BVCC_0V;
    }
    else if(vccOut == 0)
    {
        //
        // Configure PCMCIA for 0 Volts.
        //
        ulSwitchSettings = EE_ADDRESS | ENABLE | AVPP_0V | BVPP_0V |AVCC_0V | BVCC_0V;
        
    }
    else
    {
        return (ERROR_POWERPCCARD_INVALID_PARMS);
    }
        
    //
    // Update these variables while processing
    //
    Vcc = vccOut;      
    Vpp1 = vpp1Out;
    Vpp2 = vpp2Out;             

    //
    // Turn on the power to the socket !!!
    //
    //  EECLK  -> Clock
    //  EEDATA -> Data
    //  SLA0   -> Latch
    //*EEPROM_CONFIG   =  CONFIG_S0DIR;
    //Sleep(20);
    //*EEPROM_CONFIG   =  CONFIG_S0DIR | CONFIG_DDIR | CONFIG_CDIR ;
    *GPIO_PGDDR         =  GPIOG_EECLK | GPIOG_EEDAT | GPIOG_SLA0;
 
    
    //
    // Clear all except EECLK
    // 
    //*EEPROM_DATA     = DATA_EECLK;
    *GPIO_PGDR          = GPIOG_EECLK;

    //
    // Raise the clock.
    //    
    DelayInuSec(50);
    //*EEPROM_DATA     = 0;
    *GPIO_PGDR          = 0;
    DelayInuSec(50);

    for (i=18; i>=0; --i)
    //for (i=9; i>=0; --i)
    {
        if((ulSwitchSettings >> i) & 1)
        {
            //
            // Put the data on the bus and lower the clock.
            //
            *GPIO_PGDR = GPIOG_EEDAT ;
            DelayInuSec(50);
        
            //
            // Raise the clock to latch the data in.
            //
            //*EEPROM_DATA    = DATA_EECLK | DATA_EEDAT;
            *GPIO_PGDR       = GPIOG_EECLK | GPIOG_EEDAT;
            DelayInuSec(50);

            //
            // Lower the clock again.
            //        
            //*EEPROM_DATA     = DATA_EEDAT;
            *GPIO_PGDR        = GPIOG_EEDAT;
            DelayInuSec(50);
        }
        else            
        {
            //
            // Put the data on the bus and lower the clock.
            //
            //*EEPROM_DATA    = 0 ;
            *GPIO_PGDR       = 0;
            DelayInuSec(50);
        
            //
            // Raise the clock to latch the data in.
            //
            //*EEPROM_DATA     = DATA_EECLK ;
            *GPIO_PGDR       = GPIOG_EECLK ;
            DelayInuSec(50);

            //
            // Lower the clock again.
            //        
            //*EEPROM_DATA     = 0;
            *GPIO_PGDR       = 0 ;
            DelayInuSec(50);
        }                    
    }
        
    //
    // Raise and lower the Latch.
    //
    *GPIO_PGDR       = GPIOG_SLA0;
    DelayInuSec(50);

    *GPIO_PGDR       = 0;
    *GPIO_PGDR       = GPIOG_EECLK;
    DelayInuSec(50);
    *GPIO_PGDR       = GPIOG_EECLK| GPIOG_EEDAT;
    DelayInuSec(50);
    
    //
    // Change the configuration back to zero.
    // This will cause the PCMCIA interface to reset.
    //
    //*EEPROM_CONFIG  = CONFIG_S0DIR;

    return(retVal);
}


//****************************************************************************
// detectVolts
//****************************************************************************
// Detects the voltage neede by a pcmcia card.
// 
//
static ULONG   detectVolts(void)
{
    ULONG   ulVS;
    
    // *PCMCIA_PCCONFIG    = PCMCIA_PCCONFIG_VSEN | PCMCIA_PCCONFIG_VS2 | PCMCIA_PCCONFIG_VS1;
    *GPIO_PFDR = GPIOF_PCMCIA_VS1 | GPIOF_PCMCIA_VS2;
    
     ulVS    = *GPIO_PFDR &( GPIOF_PCMCIA_CD1 | GPIOF_PCMCIA_CD2 | 
                             GPIOF_PCMCIA_VS1 | GPIOF_PCMCIA_VS2);

    
    //if(*PCMCIA_PCCONFIG & (PCMCIA_PCCONFIG_MCD2 | PCMCIA_PCCONFIG_MCD1))
    if(ulVS &( GPIOF_PCMCIA_CD1 | GPIOF_PCMCIA_CD2))
    {
        EdbgOutputDebugString("Card Voltage: Card bus, Unsupported card.\n");
        return 0;
    }

    //ulVS                = *PCMCIA_PCCONFIG & (PCMCIA_PCCONFIG_VS2FBK | PCMCIA_PCCONFIG_VS1FBK);
    
    else if(ulVS == 0)
    {
        EdbgOutputDebugString("Card Voltage: x.x 3.3v and 5v Card.\n");
        return 33;
    }
    else if (ulVS == GPIOF_PCMCIA_VS1)
    {
        EdbgOutputDebugString("Card Voltage: x.xv (Not supported).\n");
        return 0;
    }
    else if (ulVS == GPIOF_PCMCIA_VS2)
    {
        EdbgOutputDebugString("Card Voltage: 3.3v.\n");
        return 33;
    }
    else if (ulVS == (GPIOF_PCMCIA_VS1 | GPIOF_PCMCIA_VS2))
    {
        EdbgOutputDebugString("Card Voltage: 5v.\n");
        return 50;
    }
    
    return 0;
    
}
//****************************************************************************
// CalculatePcmciaTimings
//****************************************************************************
// Calculate the pcmcia timings based on the register settings. 
// For example here is for Attribute/Memory Read.
//
//
// Address:   _______XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX___________
//
// Data:      __________________________XXXXXXXXXXXXXX________________________
//
// CE#:       -------______________________________________________-----------
//
// REG#:      -------______________________________________________-----------
//
// OE#:       --------------------___________________-------------------------
//
//
//                   |<---------------Cycle time ----------------->|
//
//                   |< Address >|<-- Access Time -->|< Hold Time >|
//                      Time           ta(CE)             th(CE)
//                      tsu(A)
//
//  See PCMCIA Electrical Specification Section 4.7 for the timing numbers.
//
//
//

static UINT32 CalculatePcmciaTimings
(
    UINT32 NsSpeed
)
{
    ULONG   ulAddressTime;
    ULONG   ulHoldTime;
    ULONG   ulAccessTime;
    ULONG   ulSMC;
    //ULONG   ulHCLK = REAL_HCLOCK;
    ULONG   ulHCLK = 92000000;
    ULONG   ulHPeriod;
    ULONG   ulHAccessTime;
    ULONG   ulHAddressTime;
    ULONG   ulHHoldTime;
    
    switch(NsSpeed)
    {
        case 600:
        default:
            ulAccessTime    = 600;
            ulAddressTime   = 100;
            ulHoldTime      = 35;
            break;
            
        case 300:
            ulAccessTime    = 300;
            ulAddressTime   = 30;
            ulHoldTime      = 20;
            break;
            
        case 250:
            ulAccessTime    = 250;
            ulAddressTime   = 30;
            ulHoldTime      = 20;
            break;
            
        case 200:
            ulAccessTime    = 200;
            ulAddressTime   = 20;
            ulHoldTime      = 20;
            break;
            
        case 150:
            ulAccessTime    = 150;
            ulAddressTime   = 20;
            ulHoldTime      = 20;
            break;
            
        case 100:
            ulAccessTime    = 100;
            ulAddressTime   = 10;
            ulHoldTime      = 15;
            break;
            
        //
        // Special case for I/O all access.
        //            
        case 0:
            ulAccessTime    = 165;
            ulAddressTime   = 70;
            ulHoldTime      = 20;
            break;
    }

    //
    // Add in a board delay.
    //
    ulAccessTime    += PCMCIA_BOARD_DELAY;
    ulAddressTime   += PCMCIA_BOARD_DELAY;
    ulHoldTime      += PCMCIA_BOARD_DELAY;
    
    //
    // This gives us the period in nanosecods.
    //
    // = 1000000000 (ns/s) / HCLK (cycle/s)
    //
    // = (ns/cycle)
    //
    ulHPeriod       = (1000000000/ ulHCLK);
    
    //
    // Find the number of hclk cycles for cycle time, address time and
    // hold time.
    //
    // = ulAccessTime   (ns) / ulHPeriod (ns/Cycles)
    // = ulAddressTime (ns) / ulHPeriod (ns/Cycles)
    // = ulHoldTime    (ns) / ulHPeriod (ns/Cycles)
    //
    ulHAccessTime    = ulAccessTime / ulHPeriod;
    if(ulHAccessTime > 0xFF)
        ulHAccessTime  = 0xFF;
    
    ulHAddressTime  = ulAddressTime / ulHPeriod;
    if(ulHAddressTime > 0xFF)
        ulHAddressTime = 0xFF;
            
    ulHHoldTime     = (ulHoldTime /ulHPeriod) + 1;
    if(ulHHoldTime >0xF)
        ulHHoldTime     = 0xF;

    ulSMC = (PCCONFIG_ADDRESSTIME_MASK & (ulHAddressTime << PCCONFIG_ADDRESSTIME_SHIFT)) |
            (PCCONFIG_HOLDTIME_MASK & (ulHHoldTime << PCCONFIG_HOLDTIME_SHIFT)) |
            (PCCONFIG_ACCESSTIME_MASK & (ulHAccessTime << PCCONFIG_ACCESSTIME_SHIFT)) ;

    return ulSMC;    
}


//****************************************************************************
// OEMPCMCIAInitialize
//****************************************************************************
// This routine initialize the PCMCIA and the GPIO lines used for PCMCIA
// 
//  GPIOG_0 = EECLK
//  GPIOG_1 = EEDAT
//  GPIOG_2 = SLA0
//
//  GPIOF_0 = WP        Output
//  GPIOF_1 = CD1       Input/Output
//  GPIOF_2 = CD2       Input/Output
//  GPIOF_3 = BVD1      Input
//  GPIOF_4 = BVD2      Input
//  GPIOF_5 = VS1       Input
//  GPIOF_6 = IRQ       Input
//  GPIOF_7 = VS2       Input
//
//
int OEMPCMCIAInitialize(void)
{
    int iVolts;
    int iReturnValue = 1;
    //
    // All other GPIO pins except WP..
    //
    *GPIO_PFDDR = GPIOF_PCMCIA_WP;
    *GPIO_PFDR  = 0;        


    //
    // Temporarily disable all PCMCIA interrupts.
    //
    *GPIO_INTENF    = 0;

    //
    // Acknowlege any pending edge triggered PCMCIA interrupts.
    //
    *GPIO_FEOI      = 0xFF;
    
    //
    // We want to make the  GPIOF_PCMCIA_IRQ pin level triggered.
    // We don't care about any of the other bits in the register.
    //
    *GPIO_FINTTYPE1 = 0;
    
    //
    // We want the GPIOF_PCMCIA to be triggered high.
    //
    //*GPIO_FINTTYPE2  = GPIOF_PCMCIA_IRQ;

    //
    // We want the GPIOF_PCMCIA to be triggered low.
    //
    *GPIO_FINTTYPE2 = 0;
    
    //
    // Enable the interrupt.
    //
    *GPIO_INTENF    = GPIOF_PCMCIA_IRQ;

    //
    // Detect the correct voltages.
    //
    iVolts = detectVolts();

    //
    // Program the voltage to the PCMCIA card.
    // 
    if(iVolts )
    {
        PowerPCCardWrite
        (
            iVolts,
            0,
            0
        );

        //
        // Set the enable and reset lines.
        //   
        *SMC_PCCONT |= PCCONT_PC1EN | PCCONT_PC1RST;
        DelayInMsec(600);
    
        //
        // Enable waiting on the wait line...
        //   
        *SMC_PCCONT |= PCCONT_WEN1;
        DelayInMsec(600);

        //
        // Clear the reset line.
        //    
        *SMC_PCCONT &= ~PCCONT_PC1RST;
        DelayInMsec(400);


        //
        // Initialize the SMC interface.  Rather than parse the pcmcia configuration space,
        // just set the Attribute and memory timings to 600 ns and PCMCIA timing to I/O all 
        // access.
        //
        *SMC_PCCONFIG_ATT1  = CalculatePcmciaTimings(300);
        *SMC_PCCONFIG_MEM1  = CalculatePcmciaTimings(300);
        *SMC_PCCONFIG_IO1   = CalculatePcmciaTimings(0 ) | PCCONFIG_MW_16BIT;
        //*SMC_PCCONFIG_IO1   = CalculatePcmciaTimings(0 );
    }
    else
    {    
        iReturnValue = 0;
    }


    return iReturnValue;
}
    

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -