/*****************************************************************************
   
	Copyright (c) 2004-2006 SMSC. All rights reserved.

	Use of this source code is subject to the terms of the SMSC Software
	License Agreement (SLA) under which you licensed this software product.	 
	If you did not accept the terms of the SLA, you are not authorized to use
	this source code. 

	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.
	 
	File name   : chip.c
	Description : Freescale i.Mx related Routines

	

*****************************************************************************/

//-----------------------------------------------------------------------------
//
// Copyright (C) 2005-2007, Freescale Semiconductor, Inc. All Rights Reserved.
// THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
// AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT
//
//-----------------------------------------------------------------------------

/*lint -save*/
/*lint -e14 -e43 -e46 -e123 -e427 -e537 -e620 -e652 -e659 -e683*/
/*lint -e726 -e760 -e761 -e762 -e763 -e767 -e773 -e793 -e806 -e828 -e912*/
/*lint -e935 -e937 -e950 -e955 -e956 -e957 -e958 -e959 -e960 -e961 -e962*/
/*lint -e973 -e1916*/
#pragma warning(disable: 4115)
#pragma warning(disable: 4214)
#pragma warning(disable: 4201)
#pragma warning(disable: 4127)

#include <windows.h>
#include <Pkfuncs.h>
#include <ceddk.h>
#include <nkintr.h>
#include <Oal_intr.h>

#include "smsc9118.h"


extern DWORD	ReadCLKCFG(void);

void PlatformSetBusWidth(const DWORD dwBusWidth)
{
	PHYSICAL_ADDRESS	PhysAddr;
	volatile PDWORD		pdwMemCtrl;

	PhysAddr.LowPart = (DWORD)BSP_BASE_REG_PA_LAN911x_IOBASE;
	PhysAddr.HighPart = -1L;
	pdwMemCtrl = MmMapIoSpace(PhysAddr, (ULONG)PAGE_SIZE, (BOOLEAN)FALSE);
	if (pdwMemCtrl == NULL)
	{
		SMSC_WARNING0("Failed to get Virtual address of MemController\r\n");
	}
	else
	{
		// pdwMemCtrl[4]  : MSC2
		if (dwBusWidth == 16UL)
		{
			pdwMemCtrl[4] = pdwMemCtrl[4] | 0x00080000UL;
		}
		else if (dwBusWidth == 32UL)
		{
			pdwMemCtrl[4] = pdwMemCtrl[4] & 0xFFF7FFFFUL;
		}
		else
		{
			SMSC_WARNING0("Wrong Bus Width. Should be 16 ro 32. Set to 32bit as default.\r\n");
			pdwMemCtrl[4] = pdwMemCtrl[4] & 0xFFF7FFFFUL;
		}
	}

	MmUnmapIoSpace(pdwMemCtrl, (ULONG)PAGE_SIZE);
}

/* PlatformInitialize: 
 *   perform any platform initialization necessary to make the Lan9118 visible.
 *   This function must be called before PlatformGetLanBase
 */
void PlatformInitialize()
{
	PHYSICAL_ADDRESS	PhysAddr;
	volatile PDWORD		pdwMemCtrl;	
	
	

	SMSC_TRACE0(DBG_INIT, "+PlatformInitialize()\r\n");

	PhysAddr.LowPart = (DWORD)BSP_BASE_REG_PA_LAN911x_IOBASE;
	PhysAddr.HighPart = -1L;
	pdwMemCtrl = MmMapIoSpace(PhysAddr, (ULONG)PAGE_SIZE, (BOOLEAN)FALSE);
	if (pdwMemCtrl == NULL)
	{
		SMSC_WARNING0("Failed to get Virtual address of MemController\r\n");
	}
	else
	{
		SMSC_TRACE0(DBG_INIT, "Set Default Bus Timing for SMSC912x\r\n");
		// pdwMemCtrl[4]  : MSC2
		//pdwMemCtrl[4] = pdwMemCtrl[4] & 0x0000FFFFUL;
		//pdwMemCtrl[4] = pdwMemCtrl[4] | 0x8CD10000UL;	// 32bit as default
	}
	MmUnmapIoSpace(pdwMemCtrl, (ULONG)PAGE_SIZE);	

	SMSC_TRACE0(DBG_INIT, "+PlatformInitialize()\r\n");
}

void PlatformSetBusTiming(const DWORD dwChipIdReg)
{
	PHYSICAL_ADDRESS	PhysAddr;
	volatile PDWORD		pdwMemCtrl;
	DWORD				dwChipId;

	SMSC_TRACE0(DBG_INIT, "+PlatformSetBusTiming()\r\n");
	dwChipId = dwChipIdReg & 0xFFFF0000UL;
	if ((dwChipId == 0x01180000UL) ||
		(dwChipId == 0x01170000UL) ||
		(dwChipId == 0x01120000UL) ||
		(dwChipId == 0x118A0000UL) ||
		(dwChipId == 0x117A0000UL))
	{
		PhysAddr.LowPart = (DWORD)BSP_BASE_REG_PA_LAN911x_IOBASE;
		PhysAddr.HighPart = -1L;
		pdwMemCtrl = MmMapIoSpace(PhysAddr, (ULONG)PAGE_SIZE, (BOOLEAN)FALSE);
		if (pdwMemCtrl == NULL)
		{
			SMSC_WARNING0("Failed to get Virtual address of MemController\r\n");
		}
		else
		{
			// pdwMemCtrl[4]  : MSC2
			pdwMemCtrl[4] = pdwMemCtrl[4] & 0x0008FFFFUL;	// keep 16/32bit flag
			pdwMemCtrl[4] = pdwMemCtrl[4] | 0x83710000UL;
		}

		MmUnmapIoSpace(pdwMemCtrl, (ULONG)PAGE_SIZE);
	}
	SMSC_TRACE0(DBG_INIT, "-PlatformSetBusTiming()\r\n");
}

/* PlatformDisplayInfo:
 *   Will display info specific to the platform, such as
 *   processor registers, or DMA configurations
 */
void PlatformDisplayInfo()
{
	PDWORD		pPtr;
	BOOL		bRet;
	DWORD		msc2, mdrefr;
	DWORD		cccr, ccsr, clkcfg;
	DWORD		L, M, N2, r_clk, t_clk, s_clk, m_clk, k0db, k1db;

	SMSC_TRACE0(DBG_INIT, "+PlatformDisplayInfo()\r\n");
	pPtr = (PDWORD)VirtualAlloc((LPVOID)0, (DWORD)PAGE_SIZE, (DWORD)MEM_RESERVE, (DWORD)PAGE_NOACCESS);	
	bRet = VirtualCopy((PVOID)pPtr, (PVOID)(0x48000000UL>>8), 1024UL, (DWORD)(PAGE_READONLY | PAGE_PHYSICAL | PAGE_NOCACHE));
	if (bRet == TRUE) {
		msc2 = pPtr[4];
		mdrefr = pPtr[1];
		SMSC_TRACE1(DBG_INIT, "MDREFR = 0x%08x\r\n", mdrefr);
		SMSC_TRACE1(DBG_INIT, "MSC2 = 0x%08x\r\n", msc2);

	}
	else {
		SMSC_WARNING1("Error! at VirtualCopy(). ErrNo = %d\r\n", GetLastError());
		bRet = VirtualFree((PVOID)pPtr, 0UL, (DWORD)MEM_RELEASE);
		return;
	}
	bRet = VirtualFree((PVOID)pPtr, 0UL, (DWORD)MEM_RELEASE);

	pPtr = (PDWORD)VirtualAlloc((LPVOID)0UL, (DWORD)PAGE_SIZE, (DWORD)MEM_RESERVE, (DWORD)PAGE_NOACCESS);	

	bRet = VirtualCopy((PVOID)pPtr, (PVOID)((DWORD)0x41300000UL>>8), 1024UL, (DWORD)(PAGE_READONLY | PAGE_PHYSICAL | PAGE_NOCACHE));
	if (bRet == TRUE) {
		cccr = pPtr[0];
		ccsr = pPtr[3];
		clkcfg = ReadCLKCFG();
		SMSC_TRACE1(DBG_INIT, "CCCR = 0x%08x\r\n", cccr);
		SMSC_TRACE1(DBG_INIT, "CCSR = 0x%08x\r\n", ccsr);
		SMSC_TRACE1(DBG_INIT, "CLKCFG = 0x%08x\r\n", clkcfg);

		L = ccsr & 0x1FUL;
		N2 = (ccsr >> 7) & 0x07UL;

		if (L <= 10UL) 
		{
			M = 1UL;
		}
		else if (L <= 20UL) 
		{
			M = 2UL;
		}
		else 
		{
			M = 4UL;
		}

		r_clk = (L * 13000000UL);
		t_clk = (L * 13000000UL * N2) / 2UL;

		if (clkcfg & 0x08UL)
		{
			s_clk = r_clk;		// Fast Clk Mode
		}
		else
		{
			s_clk = r_clk / 2UL;
		}

		if (cccr & 0x2000000UL)
		{
			m_clk = s_clk;		// Alt setting
		}
		else
		{
			m_clk = r_clk / M;
		}
		if (mdrefr & (1UL<<29))
		{
			k0db = 4UL;
		}
		else if (mdrefr & (1UL<<14))
		{
			k0db = 2UL;
		}
		else
		{
			k0db = 1UL;
		}

		if (mdrefr & (1UL<<17))
		{
			k1db = 2UL;
		}
		else
		{
			k1db = 1UL;
		}

		if (clkcfg & 0x1UL) 
		{
			SMSC_TRACE4(DBG_INIT, "Turbo Mode Clk: %d.%02dMHz (*%d.%d)\r\n",
				(ULONG)(t_clk/1000000UL), (ULONG)((t_clk%1000000UL)/10000UL), 
				(ULONG)(N2/2UL), (ULONG)((N2%2UL)*5UL));
		}
		else 
		{
			SMSC_TRACE3(DBG_INIT, "Run Mode Clk: %d.%02dMHz (*%d)\r\n", 
				(ULONG)(r_clk/1000000UL), (ULONG)((r_clk%1000000UL)/1000000UL), 
				L);
		}
		SMSC_TRACE5(DBG_INIT, "MemClk: %d.%02dMHz (Alt=%d, SDCLK[0]=/%d, SDCLK[1]=/%d\r\n", 
				(ULONG)(m_clk/1000000UL), 
				(ULONG)((m_clk % 1000000UL)/10000UL), 
				(ULONG)((cccr>>25UL)&1UL), k0db, k1db);
		SMSC_TRACE2(DBG_INIT, "SysClk: %d.%02dMHz\r\n", 
				(ULONG)(s_clk/1000000UL), 
				(ULONG)((s_clk%1000000UL)/10000UL));

		if (mdrefr & (1UL<<20UL))
		{
			SMSC_TRACE0(DBG_INIT, "APD is ON\r\n");
		}
		else
		{
			SMSC_TRACE0(DBG_INIT, "APD is OFF\r\n");
		}
	}
	else 
	{
		SMSC_WARNING1("Error! at VirtualCopy(). ErrNo = %d\r\n", GetLastError());
	}
	bRet = VirtualFree((PVOID)pPtr, 0UL, (DWORD)MEM_RELEASE);
	SMSC_TRACE0(DBG_INIT, "-PlatformDisplayInfo()\r\n");
}

BOOL DmaStartXfer(const DMA_XFER * const dmaXfer)
{
        // Remove-W4: Warning C4100 workaround
        UNREFERENCED_PARAMETER(dmaXfer);
	return TRUE;
}

DWORD DmaGetDwCnt(const DMA_XFER * const dmaXfer, const DWORD dwDmaCh)
{
       // Remove-W4: Warning C4100 workaround
       UNREFERENCED_PARAMETER(dmaXfer); 
       UNREFERENCED_PARAMETER(dwDmaCh);  
       return 0;
}

void DmaDisable(const DMA_XFER * const dmaXfer, const DWORD dwDmaCh)
{
       // Remove-W4: Warning C4100 workaround
       UNREFERENCED_PARAMETER(dmaXfer); 
       UNREFERENCED_PARAMETER(dwDmaCh);
}

void DmaComplete(const DMA_XFER * const dmaXfer, const DWORD dwDmaCh) 
{
	DWORD 	dwTimeOut = 1000000UL;

	while ((DmaGetDwCnt(dmaXfer, dwDmaCh)) && (dwTimeOut))
	{
		SMSC_MICRO_DELAY(1U);
		dwTimeOut--;
	}

	if (dwTimeOut == 0UL) {
		SMSC_WARNING0("DmaComplete: Timed out\n");
	}
	
	DmaDisable(dmaXfer, dwDmaCh);
}

void CleanCacheLine(DWORD dwAddr);
void DrainWriteBuffers(void);
ULONG GetPID(void);

VOID BufferCacheFlush(const void * const pucBufAddress, const DWORD uiBufLen)
{
	DWORD	dwCurrAddr, dwEndAddr, dwLinesToGo;

	dwCurrAddr = (DWORD)pucBufAddress & ~(CACHE_LINE_BYTES-1UL);
	dwEndAddr = (((DWORD)pucBufAddress) + uiBufLen + CACHE_LINE_BYTES) & ~(CACHE_LINE_BYTES-1UL);

	dwLinesToGo = (dwEndAddr - dwCurrAddr) / CACHE_LINE_BYTES;
	while (dwLinesToGo)
	{
		CleanCacheLine(dwCurrAddr+GetPID());
		dwCurrAddr += CACHE_LINE_BYTES;
		dwLinesToGo--;
	}
	DrainWriteBuffers();
}

void PlatformEnableGpioInterrupt(void)
{
}

/*
	EXPORT	CleanCacheLine
	EXPORT	DrainWriteBuffers
	EXPORT	GetCPSR
	EXPORT	GetTTB
	EXPORT	GetPID
	EXPORT	ReadCLKCFG
	EXPORT	DisableCPUInt
	EXPORT	EnableCPUInt
*/

void EnableCPUInt(void) {}
void DisableCPUInt(void) {}
BOOL DmaInitialize(NDIS_HANDLE hMiniportAdapterContext) 
{
        // Remove-W4: Warning C4100 workaround
        UNREFERENCED_PARAMETER(hMiniportAdapterContext);
	return TRUE;
}

DWORD	ReadCLKCFG(void) 
{
	return 0;
}
void DrainWriteBuffers(void) {}

void CleanCacheLine(DWORD dwAddr)
{
        // Remove-W4: Warning C4100 workaround
        UNREFERENCED_PARAMETER(dwAddr);
}

ULONG GetPID(void)
{
	return 0;
}

VOID smscEnableIntr(    IN  NDIS_HANDLE             MiniportAdapterContext    )
{
	SMSC9118_ADAPTER * const pAdapter = ((PSMSC9118_ADAPTER)MiniportAdapterContext);
	Lan_EnableIRQ( &pAdapter->lan9118_data);
}
VOID smscDisableIntr(    IN  NDIS_HANDLE             MiniportAdapterContext    )
{
	SMSC9118_ADAPTER * const pAdapter = ((PSMSC9118_ADAPTER)MiniportAdapterContext);
	Lan_DisableIRQ( &pAdapter->lan9118_data);
}




