📄 pcmcia.c
字号:
/*++
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.
Copyright (c) 2001. Samsung Electronics, co. ltd All rights reserved.
--*/
#include <windows.h>
#include <ethdbg.h>
#include <halether.h>
#include "..\..\drivers\pcmcia\sockpd.h"
#include "..\..\drivers\pcmcia\pd6710.h"
#include <S2440.h>
#define PCMCIA_ATTR_READ(x) ((*(volatile unsigned char *)(x+attr_addr)))
#define CIS_R0 0x3F8
#define CARD_IS_UNKNOWN 0
#define CARD_IS_MEMORY 1
#define CARD_IS_ENET 2
#define PD6710_MEM_BASE_ADDRESS (0xA4000000) //(0x10000000) // nGCS2 (A24 == 0)
#define PD6710_IO_BASE_ADDRESS (0xA5000000) //(0x11000000) // (A24 == 1)
#define rPD6710_INDEX (*(volatile unsigned char *)(PD6710_IO_BASE_ADDRESS+0x3e0))
#define rPD6710_DATA (*(volatile unsigned char *)(PD6710_IO_BASE_ADDRESS+0x3e1))
void PCICDataWrite_(unsigned char index, unsigned char data)
{
rPD6710_INDEX=index;
rPD6710_DATA=data;
}
unsigned char PCICDataRead_(unsigned char index)
{
rPD6710_INDEX=index;
return rPD6710_DATA;
}
void PCICDataModify_(unsigned char index,unsigned char mask,unsigned char data)
{
rPD6710_INDEX=index;
rPD6710_DATA=(rPD6710_DATA)&~mask|data;
}
static void Delay(DWORD dwMSecs)
{
#define MSEC_DELAY_SCALER 0x200
volatile DWORD dwScaledSecs = (dwMSecs * MSEC_DELAY_SCALER);
while (dwScaledSecs)
{
dwScaledSecs--;
}
}
int PrintTuples(unsigned long attr_addr)
{
UCHAR data, tuple_id, *pData;
UCHAR buf[256];
int offset;
int size;
int i, numBytes;
ULONG configBase;
EdbgOutputDebugString("\n[Tuple Listing]\n");
offset = 0;
while (1) {
tuple_id = PCMCIA_ATTR_READ(offset);
if (tuple_id == 0xFF) {
break; /* End of Chain */
}
EdbgOutputDebugString ("[%x] ID=0x%x\n", offset, tuple_id);
offset+=2;
size = PCMCIA_ATTR_READ(offset);
EdbgOutputDebugString ("[%x] SIZE=0x%x", offset, size);
offset+=2;
pData = buf;
for (i=0; i<size; i++, offset+=2) {
data = PCMCIA_ATTR_READ(offset);
if ((i%8) == 0) {
EdbgOutputDebugString ("\n[%x] DATA=", offset);
}
*pData ++ = data;
EdbgOutputDebugString ("0x%x ", data);
}
EdbgOutputDebugString ("\n\n");
pData = buf;
switch (tuple_id) {
case 0x15:
EdbgOutputDebugString ("* Major version= %s\n",
(*pData==4) ? "for 2.01/2.1" : "for PCCard 95");
pData ++;
EdbgOutputDebugString ("* Minor version= %s\n",
(*pData==1) ? "for 2.0/2.01/2.1" : "for PCCard 95");
pData ++;
EdbgOutputDebugString ("* Menufacturer= %s\n", pData);
pData += (strlen (pData) + 1);
EdbgOutputDebugString ("* Product= %s\n", pData);
pData += (strlen (pData) + 1);
EdbgOutputDebugString ("* Product info 1= %s\n", pData);
pData += (strlen (pData) + 1);
EdbgOutputDebugString ("* Product info 2= %s\n", pData);
EdbgOutputDebugString ("\n");
break;
case 0x1a:
numBytes = ((*pData) & 0x3)+1;
pData += 2;
configBase = 0;
for (i=numBytes; i>0; i--) {
configBase <<= 8;
configBase |= *(pData + i - 1);
}
EdbgOutputDebugString ("* Config Base= 0x%x\n", configBase);
EdbgOutputDebugString ("\n");
break;
default:
break;
} /* switch-tuple_id */
}
return 0;
} /* PrintTuples */
PVOID PCMCIA_Init(void)
{
unsigned char tmp, uByte;
int Offset;
volatile unsigned char *pAttr;
volatile IOPreg *v_pIOPRegs = (volatile IOPreg *)IOP_BASE;
volatile MEMreg *v_pMEMRegs = (volatile MEMreg *)MEMCTRL_BASE;
UINT EbootDeviceAddress = 0;
// Initialize S3C2440 for PD6710
// EINT3(GPF3) is enabled.
v_pIOPRegs->rGPFCON = (v_pIOPRegs->rGPFCON & ~(0x3<<6)) | (0x2<<6);
// EINT3 is PULLUP enabled.
v_pIOPRegs->rGPFUP = (v_pIOPRegs->rGPFUP & ~(0x1<<3));
// EINT8(GPG0) is enabled.
v_pIOPRegs->rGPGCON = (v_pIOPRegs->rGPGCON & ~(0x3<<0)) | (0x2<<0);
// EINT8 is *not* PULLUP enabled.
v_pIOPRegs->rGPGUP = (v_pIOPRegs->rGPGUP | (0x1<<0));
// nGCS2=nUB/nLB(nSBHE),nWAIT,16-bit
v_pMEMRegs->rBWSCON = (v_pMEMRegs->rBWSCON & ~(0xf<<8)) | (0xd<<8);
// BANK2 access timing
v_pMEMRegs->rBANKCON2 = ((B6710_Tacs<<13)+(B6710_Tcos<<11)+(B6710_Tacc<<8)+(B6710_Tcoh<<6)\
+(B6710_Tah<<4)+(B6710_Tacp<<2)+(B6710_PMC));
// EINT8=Level-high triggered, IRQ3.
// EINT3=Falling Edge triggering -> connected INTR(controller)
v_pIOPRegs->rEXTINT1=(v_pIOPRegs->rEXTINT1 & ~(0xf<<0)) | (0x1<<0);
v_pIOPRegs->rEXTINT0=(v_pIOPRegs->rEXTINT0 & ~(0xf<<12)) | (0x2<<12);
//
// 0x3E0 is the standard Intel compatible socket controller I/O port.
//
tmp = PCICDataRead_(REG_CHIP_REVISION);
if ((tmp != 0x83) && (tmp != 0x82)) {
EdbgOutputDebugString("PDCardInitServices CHIP_REVISION = 0x%x, expected = 0x83 !!!\r\n", tmp);
return(NULL);
}
//output2card_disable,AUTO_POWER,VCC_POWER_OFF,Vpp1=0V
PCICDataWrite_(REG_POWER_CONTROL, (0<<7)|(1<<5)|(0<<4)|(0<<0));
// Management int -> edge triggering(PULSE), System int -> LEVEL triggering
PCICDataWrite_(REG_GENERAL_CONTROL, (MISC1_VCC_33|MISC1_PM_IRQ|MISC1_SPK_ENABLE));
// 25Mhz_bypass,low_power_dynamic,IRQ12=drive_LED
// PCICDataWrite_(REG_GLOBAL_CONTROL, (MISC2_BFS|MISC2_LOW_POWER_MODE|MISC2_LED_ENABLE));
PCICDataWrite_(REG_GLOBAL_CONTROL, (MISC2_LOW_POWER_MODE|MISC2_LED_ENABLE));
//status_change_int_enable, card_detect_int_enable, IRQ disabled(IRQ_3)
PCICDataWrite_(REG_STATUS_CHANGE_INT_CONFIG, (1<<0)|(1<<3)|(3<<4));
//IO0=16bit,timing_set_0
PCICDataWrite_(REG_IO_WINDOW_CONTROL, 1|(1<<1)|(0<<3));
// I/O windows must never include 3e0h and 3e1h
// IO AREA=0x300~0x340(NE2K) -> 0x300~0x340
PCICDataWrite_(REG_IO_MAP0_START_ADDR_LO, 0x00);
PCICDataWrite_(REG_IO_MAP0_START_ADDR_HI, 0x3);
PCICDataWrite_(REG_IO_MAP0_END_ADDR_LO, 0x40);
PCICDataWrite_(REG_IO_MAP0_END_ADDR_HI, 0x3);
PCICDataWrite_(REG_CARD_IO_MAP0_OFFSET_L, 0x0);
PCICDataWrite_(REG_CARD_IO_MAP0_OFFSET_H, 0x0);
//If this is memory window, the lowest 64KB should be reserved.
//MEM AREA=0x0~0xFFFF ->0x0~0xFFFFFF
PCICDataWrite_(REG_MEM_MAP0_START_ADDR_LO, 0x00); //MEM0=8bit data width
PCICDataWrite_(REG_MEM_MAP0_START_ADDR_HI, 0x00);
PCICDataWrite_(REG_MEM_MAP0_END_ADDR_LO, 0x01); //0x0 ~ 0xffff
PCICDataWrite_(REG_MEM_MAP0_END_ADDR_HI, 0x00|(0<<6)); //timing_set_0
PCICDataWrite_(REG_MEM_MAP0_ADDR_OFFSET_LO, 0x0);
PCICDataWrite_(REG_MEM_MAP0_ADDR_OFFSET_HI, 0x0|(1<<6)); //nREG=active
//memory map 0 enabled, I/O map 0 enabled
PCICDataWrite_(REG_WINDOW_ENABLE, 1|(1<<6));
// before configuring timing register, FIFO should be cleared.
PCICDataWrite_(REG_FIFO_CTRL, FIFO_EMPTY_WRITE); //Flush FIFO
//default access time is 300ns
PCICDataWrite_(REG_SETUP_TIMING0, 2); //80ns(no spec)
PCICDataWrite_(REG_CMD_TIMING0, 8); //320ns(by spec,25Mhz clock)
PCICDataWrite_(REG_RECOVERY_TIMING0, 2); //80ns(no spec)
//default access time is 300ns
PCICDataWrite_(REG_SETUP_TIMING1, 2); //80ns(no spec)
PCICDataWrite_(REG_CMD_TIMING1, 8); //320ns(by spec,25Mhz clock)
PCICDataWrite_(REG_RECOVERY_TIMING1, 2); //80ns(no spec)
PCICDataWrite_(REG_CHIP_INFO,0x0);
if((PCICDataRead_(REG_CHIP_INFO)&0xc0) != 0xc0 || (PCICDataRead_(REG_CHIP_INFO)&0xc0) != 0x00 )
{
EdbgOutputDebugString("PD6710 hardware identification error!!!\n");
return(NULL);
}
EbootDeviceAddress = PD6710_MEM_BASE_ADDRESS;
if((PCICDataRead_(REG_INTERFACE_STATUS)&0xc)==0xc)
{
EdbgOutputDebugString("Card is inserted.\n");
//For card contact stablization. This delay is needed for stable operation.
//If this delay isn't here, CF card will not be identified.
if(PCICDataRead_(REG_GENERAL_CONTROL)&0x1) //MISC_CTRL1[0] 0=3.3V 1=5.0V
{
PCICDataModify_(REG_GENERAL_CONTROL,0x2,0x0); //nVCC_5_enabled
EdbgOutputDebugString("5.0V card is detected.\n");
}
else
{
PCICDataModify_(REG_GENERAL_CONTROL,0x2,0x2); //nVCC_3_enabled
EdbgOutputDebugString("3.3V card is detected.\n");
}
PCICDataModify_(REG_POWER_CONTROL,(1<<4)|3,(1<<4)|1);
//VCC_POWER_on,VPP=Vcc(3.3V or 5.0V)
Delay(20);
//Delay 10ms should be here for power stabilization.
//If this time is not here, the program may halt
// in case that the pc card has been inserted before power_on
//But, Why?
Delay(2); //RESET should be Hi-Z for minimum 1ms
PCICDataModify_(REG_INTERRUPT_AND_GENERAL_CONTROL,(1<<6),0); //RESET=active(H)
PCICDataModify_(REG_POWER_CONTROL,(1<<7),(1<<7)); //output2card_enable(RESET=Hi-Z -> output)
PCICDataModify_(REG_INTERRUPT_AND_GENERAL_CONTROL,(1<<6),0); //RESET=active(H)
Delay(1); //wait for minimum 10us
PCICDataModify_(REG_INTERRUPT_AND_GENERAL_CONTROL, (1<<6),(1<<6)); //RESET=inactive(L)
Delay(40); //wait for 20ms
// Watch for RDY signal to be asserted by the card. The NE2000 card will initially come up in memory mode so it's
// safe to watch for RDY. Later, we put the NE2000 in IO mode.
//
while(!(PCICDataRead_(REG_INTERFACE_STATUS)&0x20));
PCICDataModify_(REG_INTERRUPT_AND_GENERAL_CONTROL,(1<<5),(1<<5)); //mem_card -> mem_io_card
PCICDataModify_(REG_INTERRUPT_AND_GENERAL_CONTROL, 0xf, 0x3); // IREQ == IRQ3.
Delay(200);
//If this delay isn't here, some CF card will not be identified.
//In oder to remove this delay, I think, we have to check READY signal.
}
else {
EdbgOutputDebugString("NO card is detected.\n");
return(NULL);
}
// Switch the NE2000 card to 16-bit IO mode.
//
if(PCICDataRead_(REG_GENERAL_CONTROL)&0x1)
{
// 5V.
//
uByte = 0x21;
Offset = CIS_R0;
pAttr = (PUCHAR) EbootDeviceAddress;
pAttr += Offset;
*pAttr = uByte;
uByte = 0x1;
Offset = CIS_R0 + 2;
pAttr = (PUCHAR) EbootDeviceAddress;
pAttr += Offset;
*pAttr = uByte;
}
else
{
// 3.3V.
//
uByte = 0x20;
Offset = CIS_R0;
pAttr = (PUCHAR) EbootDeviceAddress;
pAttr += Offset;
*pAttr = uByte;
}
Delay(200);
#if 0
// Print tuple information from the PCMCIA/CF card.
//
PrintTuples(EbootDeviceAddress);
#endif
return ((PVOID)(PD6710_IO_BASE_ADDRESS + 0x300));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -