/*++
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) 2002. Samsung Electronics, co. ltd  All rights reserved.

	[Updates]
	
	2003.03.14 PCMCIA Wakeup fixed. jylee
	
--*/

#include <windows.h>
#include <types.h>
#include <cardserv.h>
#include <sockserv.h>
#include <sockpd.h>
#include <ceddk.h>
//#include <pc.h>
#include <nkintr.h>
#include <oalintr.h>
#include <S2440.h> 
#include <pd6710.h>
#include <drv_glob.h>

extern VOID InitSocketNoCard(UINT uSocket);

//void PD_DataBackup();
void PD_DataRestore();

DWORD gIntrPcmciaState = SYSINTR_PCMCIA_STATE;
DWORD gIntrPcmciaLevel = SYSINTR_PCMCIA_LEVEL;
DWORD g_Irq = 3;        // fixed by S3C2440 development platform

volatile PUCHAR g_PCICIndex;
volatile PUCHAR g_PCICData;
CRITICAL_SECTION g_PCIC_Crit;

volatile IOPreg *v_pIOPRegs;
volatile MEMreg *v_pMEMRegs;
volatile PUCHAR *v_pPCMCIAPort;  

// be written by fwood for wake-up
//volatile IOPreg IOPRegs_bak;
//volatile MEMreg MEMRegs_bak;


// when power up, restore datas
// by shlim
void PD_DataRestore()
{
	UINT8 tmp;

	// Register Restore for wake-up

	// 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));
	// jylee
	v_pIOPRegs->rGPGUP = (v_pIOPRegs->rGPGUP & ~(0x1<<0)); // pullup enabled

	
	// 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));

	//v_pIOPRegs->rEINTMASK |= (1<<8);
	v_pIOPRegs->rEXTINT1=(v_pIOPRegs->rEXTINT1 & ~(0xf<<0)) | (0x2<<0); 	// EINT8 : falling edge trigger
	v_pIOPRegs->rEXTINT0=(v_pIOPRegs->rEXTINT0 & ~(0xf<<12)) | (0x2<<12); 	// EINT3 : falling edge trigger
	v_pIOPRegs->rEINTMASK &= ~(1<<8);

	g_PCICIndex = ((volatile PUCHAR)((ULONG)v_pPCMCIAPort+0x3e0));
	g_PCICData  = ((volatile PUCHAR)((ULONG)v_pPCMCIAPort+0x3e1));

	//
	// 0x3E0 is the standard Intel compatible socket controller I/O port.
	//
	PCICIndex(0, REG_CHIP_REVISION);
	tmp = PCICDataRead();
	if ((tmp != 0x83) && (tmp != 0x82)) {
		DEBUGMSG(1,
			(TEXT("PDCardInitServices CHIP_REVISION = 0x%x, expected = 0x83 !!!\r\n"), tmp));
		return ;
	}

	// otput2card_disable, AUTO_POWER, VCC_POWER_OFF,Vpp1=0V
	PCICIndex(0, REG_POWER_CONTROL);
	PCICDataWrite((0<<7) | (1<<5) | (0<<4) | (0<<0));

	// INPACK_ignored,speak_enable,edge_irq_intr,edge_management_intr,nVCC_3_enabled(temp)
	PCICIndex(0, REG_GENERAL_CONTROL);

	// Management int, System int -> edge triggering(PULSE)  
//  PCICDataWrite(MISC1_VCC_33|MISC1_PM_IRQ|MISC1_PS_IRQ|MISC1_SPK_ENABLE);
	// Management int -> edge triggering(PULSE), System int -> LEVEL triggering 
	PCICDataWrite(MISC1_VCC_33|MISC1_PM_IRQ|MISC1_SPK_ENABLE);

	// 25Mhz_bypass,low_power_dynamic,IRQ12=drive_LED
	PCICIndex(0, REG_GLOBAL_CONTROL);
//  PCICDataWrite(MISC2_BFS|MISC2_LOW_POWER_MODE|MISC2_LED_ENABLE);
	PCICDataWrite(MISC2_LOW_POWER_MODE|MISC2_LED_ENABLE);
	
	// before configuring timing register, FIFO should be cleared.
	PCICIndex(0, REG_FIFO_CTRL);
	PCICDataWrite(FIFO_EMPTY_WRITE);    //Flush FIFO

	//default access time is 300ns
	PCICIndex(0, REG_SETUP_TIMING0);
	PCICDataWrite(5);                   //80ns(no spec)
	PCICIndex(0, REG_CMD_TIMING0);
	PCICDataWrite(20);                  //320ns(by spec,25Mhz clock)
	PCICIndex(0, REG_RECOVERY_TIMING0);
	PCICDataWrite(5);                   //80ns(no spec)

	//default access time is 300ns
	PCICIndex(0, REG_SETUP_TIMING1);
	PCICDataWrite(2);                   //80ns(no spec)
	PCICIndex(0, REG_CMD_TIMING1);
	PCICDataWrite(8);                   //320ns(by spec,25Mhz clock)
	PCICIndex(0, REG_RECOVERY_TIMING1);
	PCICDataWrite(2);                   //80ns(no spec)

	PCICIndex(0, REG_CHIP_INFO);
	PCICDataWrite(0);

	PCICIndex(0, REG_CHIP_REVISION);
	tmp = PCICDataRead();
	RETAILMSG(0, (TEXT("PDCardInitServices REG_CHIP_REVISION = 0x%x\r\n"), tmp));

	DEBUGMSG(1, (TEXT("InitSocketNoCard(0) is called\r\n")));	
//	InitSocketNoCard(0);

}


//
// The PCMCIA MDD calls PDCardInitServices to initialize the PDD layer.
//
STATUS
PDCardInitServices(DWORD dwInfo)
{
	UINT8 tmp;
 
	DEBUGMSG (1,(TEXT("++PDCardInitServices\n\r")));

	// Since the single PCMCIA slot can be used for download/KITL, we need to check to see if it's in use supporting a KITL
	// NIC.  If so, we shouldn't proceed with PCMCIA initialization.
	//

	// Allocate PCMCIA buffers.
	v_pIOPRegs = VirtualAlloc(0, sizeof(IOPreg), MEM_RESERVE, PAGE_NOACCESS);
	if (v_pIOPRegs == NULL) 
	{
		DEBUGMSG (1,(TEXT("v_pIOPRegs is not allocated\n\r")));
		goto pcis_fail;
	}
	if (!VirtualCopy((PVOID)v_pIOPRegs, (PVOID)IOP_BASE, sizeof(IOPreg), PAGE_READWRITE|PAGE_NOCACHE)) {
		DEBUGMSG (1,(TEXT("v_pIOPRegs is not mapped\n\r")));
		goto pcis_fail;
	}
	DEBUGMSG (1,(TEXT("v_pIOPRegs is mapped to %x\n\r"), v_pIOPRegs));
	
	v_pMEMRegs = VirtualAlloc(0,sizeof(MEMreg), MEM_RESERVE,PAGE_NOACCESS);
	if(v_pMEMRegs == NULL) 
	{
		DEBUGMSG (1,(TEXT("v_pMEMRegs is not allocated\n\r")));
		goto pcis_fail;
	}
	if(!VirtualCopy((PVOID)v_pMEMRegs,(PVOID)MEMCTRL_BASE,sizeof(MEMreg), PAGE_READWRITE|PAGE_NOCACHE)) {
		DEBUGMSG (1,(TEXT("v_pMEMRegs is not mapped\n\r")));
		goto pcis_fail;
	}    
	DEBUGMSG (1,(TEXT("v_pMEMRegs is mapped to %x\n\r"), v_pMEMRegs));

	v_pPCMCIAPort = VirtualAlloc(0, 0x0400, MEM_RESERVE,PAGE_NOACCESS);
	if(v_pPCMCIAPort == NULL) 
	{
		DEBUGMSG (1,(TEXT("v_pPCMCIAPort is not allocated\n\r")));
		goto pcis_fail;
	}
	if(!VirtualCopy((PVOID)v_pPCMCIAPort,(PVOID)PD6710_IO_BASE_ADDRESS, 0x0400, PAGE_READWRITE|PAGE_NOCACHE)) {
		DEBUGMSG (1,(TEXT("v_pPCMCIAPort is not mapped\n\r")));
		goto pcis_fail;
	}    
	DEBUGMSG (1,(TEXT("v_pPCMCIAPort is mapped to %x\n\r"), v_pPCMCIAPort));
	
	// 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));
	// jylee
	v_pIOPRegs->rGPGUP = (v_pIOPRegs->rGPGUP & ~(0x1<<0)); // pullup enabled

	
	// 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));

	
	// jylee 2003.03.19
	//v_pIOPRegs->rEXTINT1=(v_pIOPRegs->rEXTINT1 & ~(0xf<<0)) | (0x7<<0); // both edge trigger
	v_pIOPRegs->rEXTINT1=(v_pIOPRegs->rEXTINT1 & ~(0xf<<0)) | (0x2<<0); 	// EINT8 : falling edge trigger
	v_pIOPRegs->rEXTINT0=(v_pIOPRegs->rEXTINT0 & ~(0xf<<12)) | (0x2<<12); 	// EINT3 : falling edge trigger
		
	g_PCICIndex = ((volatile PUCHAR)((ULONG)v_pPCMCIAPort+0x3e0));
	g_PCICData = ((volatile PUCHAR)((ULONG)v_pPCMCIAPort+0x3e1));

	DEBUGMSG(1,
		(TEXT("PDCardInitServices g_PCICIndex = 0x%x, g_PCICData = 0x%x\r\n"),
		g_PCICIndex, g_PCICData));

	InitializeCriticalSection(&g_PCIC_Crit);
	
	//
	// 0x3E0 is the standard Intel compatible socket controller I/O port.
	//
	PCICIndex(0, REG_CHIP_REVISION);
	tmp = PCICDataRead();
	if ((tmp != 0x83) && (tmp != 0x82)) {
		DEBUGMSG(1,
			(TEXT("PDCardInitServices CHIP_REVISION = 0x%x, expected = 0x83 !!!\r\n"), tmp));
		return CERR_BAD_ADAPTER;
	}

	// otput2card_disable, AUTO_POWER, VCC_POWER_OFF,Vpp1=0V
	PCICIndex(0, REG_POWER_CONTROL);
	PCICDataWrite((0<<7) | (1<<5) | (0<<4) | (0<<0));

	// INPACK_ignored,speak_enable,edge_irq_intr,edge_management_intr,nVCC_3_enabled(temp)
	PCICIndex(0, REG_GENERAL_CONTROL);

	// Management int, System int -> edge triggering(PULSE)  
//  PCICDataWrite(MISC1_VCC_33|MISC1_PM_IRQ|MISC1_PS_IRQ|MISC1_SPK_ENABLE);
	// Management int -> edge triggering(PULSE), System int -> LEVEL triggering 
	PCICDataWrite(MISC1_VCC_33|MISC1_PM_IRQ|MISC1_SPK_ENABLE);

	// 25Mhz_bypass,low_power_dynamic,IRQ12=drive_LED
	PCICIndex(0, REG_GLOBAL_CONTROL);
//  PCICDataWrite(MISC2_BFS|MISC2_LOW_POWER_MODE|MISC2_LED_ENABLE);
	PCICDataWrite(MISC2_LOW_POWER_MODE|MISC2_LED_ENABLE);
	
	// before configuring timing register, FIFO should be cleared.
	PCICIndex(0, REG_FIFO_CTRL);
	PCICDataWrite(FIFO_EMPTY_WRITE);    //Flush FIFO

	//default access time is 300ns
	PCICIndex(0, REG_SETUP_TIMING0);
	PCICDataWrite(5);                   //80ns(no spec)
	PCICIndex(0, REG_CMD_TIMING0);
	PCICDataWrite(20);                  //320ns(by spec,25Mhz clock)
	PCICIndex(0, REG_RECOVERY_TIMING0);
	PCICDataWrite(5);                   //80ns(no spec)

	//default access time is 300ns
	PCICIndex(0, REG_SETUP_TIMING1);
	PCICDataWrite(2);                   //80ns(no spec)
	PCICIndex(0, REG_CMD_TIMING1);
	PCICDataWrite(8);                   //320ns(by spec,25Mhz clock)
	PCICIndex(0, REG_RECOVERY_TIMING1);
	PCICDataWrite(2);                   //80ns(no spec)

	DEBUGMSG(1, (TEXT("InitSocketNoCard(0) is called\r\n")));
	InitSocketNoCard(0);
//  InitSocketNoCard(1);

	PCICIndex(0, REG_CHIP_REVISION);
	tmp = PCICDataRead();
	DEBUGMSG(1, (TEXT("PDCardInitServices REG_CHIP_REVISION = 0x%x\r\n"), tmp));

#ifdef DEBUG
	DumpSocketRegisters(0);
#endif


	DEBUGMSG (1,(TEXT("--PDCardInitServices\n\r")));

	return CERR_SUCCESS;

pcis_fail:
	if (v_pIOPRegs) {
		VirtualFree((LPVOID)v_pIOPRegs, 0, MEM_RELEASE);
	}
	if (v_pMEMRegs) {
		VirtualFree((LPVOID)v_pMEMRegs, 0, MEM_RELEASE);
	}
	if (v_pPCMCIAPort) {
		VirtualFree((LPVOID)v_pPCMCIAPort, 0, MEM_RELEASE);
	}

	return CERR_OUT_OF_RESOURCE;    
}


//
// Function to set the PCIC index register
//
VOID
PCICIndex(
	UINT socket_num,
	UINT8  register_num
	)
{
	WRITE_PORT_UCHAR(g_PCICIndex,
		(UINT8)((socket_num == 0 ? 0 : 0x40)|register_num));
}

//
// Function to write to the PCIC data register
//
VOID
PCICDataWrite(
	UINT8 value
	)
{
	WRITE_PORT_UCHAR(g_PCICData, value);
}

//
// Function to read the PCIC data register
//
UINT8
PCICDataRead(VOID)
{
	return READ_PORT_UCHAR(g_PCICData);
}

#ifdef DEBUG
UCHAR SocketRegisters[2][REG_LAST_INDEX+1];

LPWSTR RegisterNames[] = {
TEXT("REG_CHIP_REVISION"), //                    0x00
TEXT("REG_INTERFACE_STATUS"), //                 0x01
TEXT("REG_POWER_CONTROL"), //                    0x02
TEXT("REG_INTERRUPT_AND_GENERAL_CONTROL"), //    0x03
TEXT("REG_CARD_STATUS_CHANGE"), //               0x04
TEXT("REG_STATUS_CHANGE_INT_CONFIG"), //         0x05
TEXT("REG_WINDOW_ENABLE"), //                    0x06
TEXT("REG_IO_WINDOW_CONTROL"), //                0x07
TEXT("REG_IO_MAP0_START_ADDR_LO"), //            0x08
TEXT("REG_IO_MAP0_START_ADDR_HI"), //            0x09
TEXT("REG_IO_MAP0_END_ADDR_LO"), //              0x0A
TEXT("REG_IO_MAP0_END_ADDR_HI"), //              0x0B
TEXT("REG_IO_MAP1_START_ADDR_LO"), //            0x0C
TEXT("REG_IO_MAP1_START_ADDR_HI"), //            0x0D
TEXT("REG_IO_MAP1_END_ADDR_LO"), //              0x0E
TEXT("REG_IO_MAP1_END_ADDR_HI"), //              0x0F
TEXT("REG_MEM_MAP0_START_ADDR_LO"), //           0x10
TEXT("REG_MEM_MAP0_START_ADDR_HI"), //           0x11
TEXT("REG_MEM_MAP0_END_ADDR_LO"), //             0x12
TEXT("REG_MEM_MAP0_END_ADDR_HI"), //             0x13
TEXT("REG_MEM_MAP0_ADDR_OFFSET_LO"), //          0x14
TEXT("REG_MEM_MAP0_ADDR_OFFSET_HI"), //          0x15
TEXT("REG_GENERAL_CONTROL"), //                  0x16
TEXT("REG_FIFO_CTRL"), //                        0x17
TEXT("REG_MEM_MAP1_START_ADDR_LO"), //           0x18
TEXT("REG_MEM_MAP1_START_ADDR_HI"), //           0x19
TEXT("REG_MEM_MAP1_END_ADDR_LO"), //             0x1A
TEXT("REG_MEM_MAP1_END_ADDR_HI"), //             0x1B
TEXT("REG_MEM_MAP1_ADDR_OFFSET_LO"), //          0x1C
TEXT("REG_MEM_MAP1_ADDR_OFFSET_HI"), //          0x1D
TEXT("REG_GLOBAL_CONTROL"), //                   0x1E
TEXT("REG_CHIP_INFO"), //                        0x1F
TEXT("REG_MEM_MAP2_START_ADDR_LO"), //           0x20
TEXT("REG_MEM_MAP2_START_ADDR_HI"), //           0x21
TEXT("REG_MEM_MAP2_END_ADDR_LO"), //             0x22
TEXT("REG_MEM_MAP2_END_ADDR_HI"), //             0x23
TEXT("REG_MEM_MAP2_ADDR_OFFSET_LO"), //          0x24
TEXT("REG_MEM_MAP2_ADDR_OFFSET_HI"), //          0x25
TEXT("REG_ATA_CTRL"), //                         0x26
TEXT("REG_SCRATCHPAD"), //                       0x27
TEXT("REG_MEM_MAP3_START_ADDR_LO"), //           0x28
TEXT("REG_MEM_MAP3_START_ADDR_HI"), //           0x29
TEXT("REG_MEM_MAP3_END_ADDR_LO"), //             0x2A
TEXT("REG_MEM_MAP3_END_ADDR_HI"), //             0x2B
TEXT("REG_MEM_MAP3_ADDR_OFFSET_LO"), //          0x2C
TEXT("REG_MEM_MAP3_ADDR_OFFSET_HI"), //          0x2D
TEXT("REG_EXTENDED_INDEX"), //                   0x2E
TEXT("REG_EXTENDED_DATA"), //                    0x2F
TEXT("REG_MEM_MAP4_START_ADDR_LO"), //           0x30
TEXT("REG_MEM_MAP4_START_ADDR_HI"), //           0x31
TEXT("REG_MEM_MAP4_END_ADDR_LO"), //             0x32
TEXT("REG_MEM_MAP4_END_ADDR_HI"), //             0x33
TEXT("REG_MEM_MAP4_ADDR_OFFSET_LO"), //          0x34
TEXT("REG_MEM_MAP4_ADDR_OFFSET_HI"), //          0x35
TEXT("REG_CARD_IO_MAP0_OFFSET_L"), //            0x36
TEXT("REG_CARD_IO_MAP0_OFFSET_H"), //            0x37
TEXT("REG_CARD_IO_MAP1_OFFSET_L"), //            0x38
TEXT("REG_CARD_IO_MAP1_OFFSET_H"), //            0x39
TEXT("REG_SETUP_TIMING0"), //                    0x3A
TEXT("REG_CMD_TIMING0"), //                      0x3B
TEXT("REG_RECOVERY_TIMING0"), //                 0x3C
TEXT("REG_CMD_TIMING1"), //                      0x3D
TEXT("REG_CMD_TIMING1"), //                      0x3E
TEXT("REG_RECOVERY_TIMING1"), //                 0x3F
};


VOID
DisplaySocketRegister(
	UINT socket,
	UCHAR reg,
	UCHAR value
	)
{
	if (reg > (REG_LAST_INDEX+1)) return;

	if (RegisterNames[reg] != NULL) {
		DEBUGMSG(1,
			(TEXT("PCMCIA:PCIC Register[%d:%2x:%s] = 0x%x\r\n"),
			socket, reg, RegisterNames[reg & 0x3f], value));
	}
}


VOID
DumpSocketRegisters(
	UINT socket
	)
{
	UCHAR i;

    if (!DEBUGZONE(ZONE_PDD)) return;

	for (i = 0; i < REG_LAST_INDEX+1; i++) {
		PCICIndex(socket, i);
		SocketRegisters[socket][i] = PCICDataRead();
		DisplaySocketRegister(socket, i, SocketRegisters[socket][i]);
	}
}

VOID
DeltaSocketRegisters(
	UINT socket
	)
{
	static UCHAR idx;
	UCHAR CurrentRegisters[REG_LAST_INDEX];

    if (!DEBUGZONE(ZONE_PDD)) return;

	DEBUGMSG (1,(TEXT("++DeltaSocketRegisters #%x\n\r"), socket));

	for (idx = 0; idx < REG_LAST_INDEX+1; idx++) {
		PCICIndex(socket, idx);
		CurrentRegisters[idx] = PCICDataRead();
	}

	for (idx = 0; idx < REG_LAST_INDEX+1; idx++) {
		if (CurrentRegisters[idx] != SocketRegisters[socket][idx]) {
			DisplaySocketRegister(socket, idx, CurrentRegisters[idx]);
			SocketRegisters[socket][idx] = CurrentRegisters[idx];
		}
	}
	DEBUGMSG (1,(TEXT("--DeltaSocketRegisters\n\r")));
}
#endif  // DEBUG
