📄 pcmciasupport.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 + -