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

📄 marathon.c

📁 Lido PXA270平台开发板的最新BSP,包括源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*******************************************************************************
* Name         : marathon.c
* Title        : Marathon hardware kernel/driver shared code
* Author       : Tim Rowley
* Created      : 24th April 2003
*
* Copyright    : 2003 by Imagination Technologies Limited.
*                All rights reserved.  No p	art of this software, either
*                material or conceptual may be copied or distributed,
*                transmitted, transcribed, stored in a retrieval system 
*                or translated into any human or computer language in any
*                form by any means, electronic, mechanical, manual or
*                other-wise, or disclosed to third parties without the
*                express written permission of Imagination Technologies
*                Limited, Unit 8, HomePark Industrial Estate, 
*                King's Langley, Hertfordshire, WD4 8LZ, U.K.
*
* Description  : Marathon hardware kernel/driver shared code
*
* Platform     : Generic
* 
* Modifications:-
* $Log: marathon.c $
*
*  --- Revision Logs Removed --- 
*
*  --- Revision Logs Removed --- 
*
*  --- Revision Logs Removed --- 
*
*  --- Revision Logs Removed --- 
*
*  --- Revision Logs Removed --- 
*******************************************************************************/
 
// #pragma optimize( "", off )


#ifdef SUPPORT_MARATHON_DEVICE

/************************************************************* Include files */

#include "services_headers.h"
#include "syscommon.h"
#include "pdpdefs.h"

#undef UNREFERENCED_PARAMETER
#include <windows.h>
#ifndef MARATHON_INTEGRATION_BSP
#include <oemioctl.h>
#endif
 
/************************************************************ Type definitions */
typedef struct __Freq_Status_S
{
	unsigned long CPDIS;
	unsigned long PDDIS;
	unsigned long NMulti;
	unsigned long LMulti;
	unsigned long fastbus_mode;
	unsigned long turbo_mode;
}FREQ_STATUS;


/******************************************************* Function prototypes */

static void	CalcTimings();
static void ConfigureChipSelect(IMG_UINT32 ui32ChipSelect, IMG_UINT32 ui32MemoryConfig, PSYS_SPECIFIC_DATA pMSysData);

/*****************************************************************************
 FUNCTION	: SetPLL
    
 PURPOSE	: 

 PARAMETERS	: 
			  
 RETURNS	: 
*****************************************************************************/

IMG_BOOL SetPLL(IMG_UINT32 ui32PLL, IMG_UINT32 ui32DesiredFreq, IMG_UINT32 *pui32ResultFreq)
{
	IMG_UINT32 ui32Val, ui32Mask, ui32Reg;
	IMG_UINT32 ui32M, ui32N, ui32P, ui32PostDiv, ui32MaxPostDiv=1;
	IMG_UINT32 ui32BestFreq=0, ui32BestM, ui32BestN, ui32BestP, ui32BestVCO, ui32BestPostDiv;
	
	PSYS_SPECIFIC_DATA pMSysData;

	GET_MARATHON_SYS_DATA(pMSysData);

#if 0
// include this if we find that we are not getting an accurate enough
// clock for the pixel clock otherwise leave it out for speed reasons
// (changes the number of pll combinations from 3472 to 1774192)
	if(ui32PLL==1)
	{
		ui32MaxPostDiv = MAR_PLL_MAX_POSTDIV;
	}
#endif

	/* Find PLL factors */
	for(ui32PostDiv=MAR_PLL_MIN_POSTDIV; ui32PostDiv<=ui32MaxPostDiv; ui32PostDiv++)
		for (ui32M=MAR_PLL_MIN_M; ui32M<=MAR_PLL_MAX_M; ui32M++)
			for (ui32N=MAR_PLL_MIN_N; ui32N<=MAR_PLL_MAX_N; ui32N++)
				for (ui32P=MAR_PLL_MIN_P; ui32P<=MAR_PLL_MAX_P; ui32P++)
				{
					DWORD ui32VCO = (MAR_REFCLK_FREQ*ui32M)/ui32N;
					DWORD ui32Output = ((MAR_REFCLK_FREQ*ui32M)/(ui32N*(1<<ui32P))) / ui32PostDiv;
					// check for the VCO limits
					if ((ui32VCO >= MAR_PLL_MIN_VCO) &&
						(ui32VCO <= MAR_PLL_MAX_VCO))
					{
						if ((ui32Output <= ui32DesiredFreq) &&
							(ui32Output > ui32BestFreq))
						{
							ui32BestFreq = ui32Output;
							ui32BestM = ui32M;
							ui32BestN = ui32N;
							ui32BestP = ui32P;
							ui32BestVCO = ui32VCO;
							ui32BestPostDiv = ui32PostDiv;
						}
						else if (ui32Output == ui32BestFreq)
						{
							// if we have got the same value then make the
							// decision based upon the lowest VCO
							if (ui32VCO < ui32BestVCO)
							{
								ui32BestFreq = ui32Output;
								ui32BestM = ui32M;
								ui32BestN = ui32N;
								ui32BestP = ui32P;
								ui32BestVCO = ui32VCO;
								ui32BestPostDiv = ui32PostDiv;
							}
						}
					}
				}


	PVR_DPF((PVR_DBG_MESSAGE,"SetPLL: desired=%d result=%d", ui32DesiredFreq, ui32BestFreq));
	PVR_DPF((PVR_DBG_MESSAGE,"SetPLL: m=%d n=%d p=%d od=%d vco=%d", ui32BestM, ui32BestN, ui32BestP, ui32BestPostDiv, ui32BestVCO));

	/* Prep for programming up PLL */
	ui32Val = (ui32BestM << 7) | (ui32BestN << 4) | (ui32BestP << 1) | 1;
	switch (ui32PLL)
	{
		case 0:
			ui32Mask	= MAR_PLL_STAT_SYS_LOCKED;
			ui32Reg		= MAR_PLL0_CTL;
			break;
		case 1:
			ui32Mask	= MAR_PLL_STAT_PIX_LOCKED;
			ui32Reg		= MAR_PLL1_CTL;
			break;
		default:
			PVR_DPF((PVR_DBG_ERROR,"SetPLL: Illegal PLL specified"));
			return FALSE;
	}

#ifdef MARATHON_FPGA
	PVR_DPF((PVR_DBG_WARNING, "SetPLL: MARATHON_FPGA #defined, so defaulting to REFCLK"));
	ui32BestFreq = MAR_REFCLK_FREQ;
#endif

	/* Bail if we can't achieve the desired frequency or if it's REFCLK */
	if ((ui32BestFreq == 0) || (ui32BestFreq == MAR_REFCLK_FREQ))
		goto refclk;

	PDUMPSCRIPT("---- SetPLL start");
	PDUMPREGTAG(PDUMPTAGS_REG_MSOC, 0);

	/* Program, wait for lock */
	WriteHWReg(pMSysData->pvLinRegBaseAddr, ui32Reg, ui32Val);

	PDUMPPOL(NULL, PDUMPTAGS_REG_MSOC, MAR_PLL_STAT, ui32Mask, ui32Mask, 0, 5000, 10);
	for (ui32Val = 0; ui32Val < 10; ui32Val++)
	{
		if (ReadHWReg(pMSysData->pvLinRegBaseAddr, MAR_PLL_STAT) & ui32Mask)
		{
			*pui32ResultFreq = ui32BestFreq;
			// if the PLL Locked we can program up the output divider
			if (ui32PLL==1)
			{
				WriteHWReg(pMSysData->pvLinRegBaseAddr, MAR_PIXCLK_DIV, ui32BestPostDiv);
				WriteHWReg(pMSysData->pvLinRegBaseAddr, MAR_PLL_STAT, 0); /* Clear PLL histories */
			}
			PDUMPSCRIPT("---- SetPLL fini");
			return TRUE;
		}

		HostWaitus(5000);
	}

 refclk:

	/* No lock - turn off */
	WriteHWReg(pMSysData->pvLinRegBaseAddr, ui32Reg, 0);
	*pui32ResultFreq = MAR_REFCLK_FREQ;

	PDUMPSCRIPT("---- SetPLL fini");

	return(FALSE);
}

/*****************************************************************************
 FUNCTION	: MarathonBoot
    
 PURPOSE	: Initialise Marathon SOC

 PARAMETERS	: PPVRSRV_DEV psDevInfo
			  
 RETURNS	: 
*****************************************************************************/

IMG_VOID MarathonBoot()
{
	IMG_UINT32	ui32Val;

	PSYS_SPECIFIC_DATA	pMSysData;

	GET_MARATHON_SYS_DATA(pMSysData);

	/*************************************************************************/

	PDUMPSCRIPT("---- MarathonBoot start");

	/* init marathon memory controller */
	WriteHWReg(pMSysData->pvLinRegBaseAddr, MAR_SDCLK_CONFIG, MAR_SDCLK_CONFIG_ON);
	WriteHWReg(pMSysData->pvLinRegBaseAddr, MAR_MEMCLK_CONFIG, MAR_MEMCLK_CONFIG_ON);
	HostWaitus(pMSysData->pMemConfig->ui32CKEWait+999);

	CalcTimings();

	WriteHWReg(pMSysData->pvLinRegBaseAddr, MC_CONFIG, MC_CONFIG_LMC_TS | MC_CONFIG_LMD_TS | MC_CONFIG_LMA_TS | MC_CONFIG_LMC_DS);

	/* Default state for memory is Active, complete transition */
	SysSDRAMSetState(SYS_SDRAM_POWER_ACTIVE);

	/* Shutdown memory will be woken when needed */
	//SysSDRAMSetState(SYS_SDRAM_POWER_SHUTDOWN);

	PDUMPSCRIPT("RDW :FB:%08X", 1024*1024);
	PDUMPSCRIPT("WRW :FB:%08X %08X", 1024*1024, dwVal & 0x0f0f0f0f);

#ifdef MAR_NO_CLOCKCONTROL
	/* Turn everything on... */
	WriteHWReg(pMSysData->pvLinRegBaseAddr, MAR_MBXCLK_CONFIG, ((pMSysData->ui32MBXDivider-1) << 2) | MAR_MBXCLK_CONFIG_ALL); /* 2D/3D  */
	WriteHWReg(pMSysData->pvLinRegBaseAddr, MAR_PIXCLK_CONFIG, MAR_PIXCLK_CONFIG_ON);		 /* PixClk */
	WriteHWReg(pMSysData->pvLinRegBaseAddr, MAR_VIDCLK_CONFIG, MAR_VIDCLK_CONFIG_ON);		 /* VidClk */
	WriteHWReg(pMSysData->pvLinRegBaseAddr, MAR_M24CLK_CONFIG,((pMSysData->ui32M24VADivider-1) << 1) | MAR_M24CLK_CONFIG_ON);/* M24Clk */
#endif

	ui32Val = 0;

	if(pMSysData->bConfigTimeout)	ui32Val |= 0xffffff << 8;
	if(pMSysData->bConfigPrefetch)	ui32Val |= 1;

	WriteHWReg(pMSysData->pvLinRegBaseAddr, MAR_SYS_CONFIG, ui32Val);

	PVR_DPF((PVR_DBG_MESSAGE, "MARATHON: Booting at %dHz core clock.\n", pMSysData->ui32CoreClock));
	ChangeSYSCLK(pMSysData->ui32CoreClock);

#ifdef MAR_NO_CLOCKCONTROL
	/* These may need scaling down following the clock change */
	WriteHWReg(pMSysData->pvLinRegBaseAddr, MAR_MBXCLK_CONFIG,
		          ((pMSysData->ui32MBXDivider-1) << 2) | MAR_MBXCLK_CONFIG_ALL); /* 2D/3D  */

	WriteHWReg(pMSysData->pvLinRegBaseAddr, MAR_M24CLK_CONFIG,
				  ((pMSysData->ui32M24VADivider-1) << 1) | MAR_M24CLK_CONFIG_ON);/* M24Clk */
#endif

#ifndef MAR_NO_CLOCKCONTROL
		/* Turn the MBX cores back off */
		WriteHWReg(pMSysData->pvLinRegBaseAddr, MAR_MBXCLK_CONFIG, MAR_MBXCLK_CONFIG_OFF);

		/* Only Enable 2D - CreateParameterBuffer() or dynamic clock gating code will manage 3D */
		WriteHWReg(pMSysData->pvLinRegBaseAddr, MAR_MBXCLK_CONFIG, ((pMSysData->ui32MBXDivider-1) << 2) | MAR_MBXCLK_CONFIG_2D);
#endif

	/* set power state */
	pMSysData->eMode = PowerRun;

	PDUMPSCRIPT("---- MarathonBoot fini");
}

/*****************************************************************************
 FUNCTION	: CalcTimings
    
 PURPOSE	: Setup Marathon memory controller

 PARAMETERS	: PPVRSRV_DEV psDevInfo
			  
 RETURNS	: 
*****************************************************************************/

static void	CalcTimings()
{
	IMG_UINT32 ui32Clock100;  /* clock interval * 100 (in nanoseconds) */
	IMG_UINT32 ui32TRAS, ui32TRP, ui32TRCD, ui32TRC, ui32TDPL;
	IMG_UINT32 ui32Val;

	PSYS_SPECIFIC_DATA	pMSysData;

	GET_MARATHON_SYS_DATA(pMSysData);


	PDUMPSCRIPT("---- CalcTimings start");

	ui32Clock100	= (100*1000*1000)/(pMSysData->ui32SysClk/1000);

	ui32TRAS	= (pMSysData->pMemConfig->ui32TRAS * 100 + ui32Clock100 - 1)/ui32Clock100;
	ui32TRP		= (pMSysData->pMemConfig->ui32TRP  * 100 + ui32Clock100 - 1)/ui32Clock100;
	ui32TRCD	= (pMSysData->pMemConfig->ui32TRCD * 100 + ui32Clock100 - 1)/ui32Clock100;
	ui32TRC		= (pMSysData->pMemConfig->ui32TRC  * 100 + ui32Clock100 - 1)/ui32Clock100;
	ui32TDPL	= pMSysData->pMemConfig->ui32TDPLClks;

	/* Satisfy TRP+TRAS > TRC */
	if (ui32TRP + ui32TRAS <= ui32TRC)
	{
		ui32TRAS = ui32TRC - ui32TRP + 1;
	}

	ui32Val =	(ui32TRAS << MC_TIMING_TRAS_SHIFT) |
				(ui32TRP  << MC_TIMING_TRP_SHIFT ) |
				(ui32TRCD << MC_TIMING_TRCD_SHIFT) |
				(ui32TRC  << MC_TIMING_TRC_SHIFT ) |
				(ui32TDPL << MC_TIMING_TDPL_SHIFT);

	WriteHWReg(pMSysData->pvLinRegBaseAddr, MC_TIMING, ui32Val);

	ui32Val = pMSysData->pMemConfig->ui32Refresh/(ui32Clock100*(1<<pMSysData->pMemConfig->ui32RowBits)/100);

	WriteHWReg(pMSysData->pvLinRegBaseAddr, MC_REFRESH, ui32Val);

	ui32Val = 1 << MC_TYPE_CAS_LATENCY_SHIFT;

	if(pMSysData->ui32SysClk >= pMSysData->pMemConfig->ui32CAS2Threshold)
	{
		ui32Val = 2 << MC_TYPE_CAS_LATENCY_SHIFT;
	}

	if(pMSysData->ui32SysClk >= pMSysData->pMemConfig->ui32CAS3Threshold)
	{
		ui32Val = 3 << MC_TYPE_CAS_LATENCY_SHIFT;
	}

	ui32Val |=	(pMSysData->pMemConfig->ui32BankBits << MC_TYPE_BANK_SIZE_SHIFT) |
				(pMSysData->pMemConfig->ui32RowBits  << MC_TYPE_ROW_SIZE_SHIFT ) |
				(pMSysData->pMemConfig->ui32ColBits  << MC_TYPE_COL_SIZE_SHIFT );

	WriteHWReg(pMSysData->pvLinRegBaseAddr, MC_TYPE, ui32Val);

/* XScale minimum pulse width for GPIO edge detection. Value from the
   PXA250 specification update.  Bulverde has a slightly smaller value
   (231ns). */

#define XSCALE_GPIO_PULSE 290

	ui32Val = (XSCALE_GPIO_PULSE*100)/ui32Clock100;
	WriteHWReg(pMSysData->pvLinRegBaseAddr, MAR_INT_MINPW, ui32Val);
	PVR_DPF((PVR_DBG_MESSAGE, "MARATHON: MINPW programmed to %d Marathon ticks.\n", ui32Val));

	PDUMPSCRIPT("---- CalcTimings fini");
}


/*****************************************************************************
 FUNCTION	: ChangeSYSCLK
    
 PURPOSE	: Alter system clock speed internal to Marathon.

 PARAMETERS	: PPVRSRV_DEV psDevInfo, DWORD dwDesiredFreq, PDWORD pdwResultFreq
			  
 RETURNS	: Nothing
*****************************************************************************/
void ChangeSYSCLK(IMG_UINT32 ui32DesiredFreq)
{
	IMG_UINT32 ui32Val, i;
	IMG_UINT32 ui32MinSysClk;
	IMG_UINT32 ui32PLLToUse;
	IMG_UINT32 ui32CurSysPll;
	PSYS_SPECIFIC_DATA	pMSysData;

	GET_MARATHON_SYS_DATA(pMSysData);

	/*************************** Must not drop the Freq below the pixel clock */

	ui32MinSysClk = pMSysData->ui32PixClk;

	if(ui32DesiredFreq < ui32MinSysClk)
	{
		ui32DesiredFreq = ui32MinSysClk;
	}

	/*************************************************************************/

	PDUMPSCRIPT("---- ChangeSYSCLK start");

	/*************************************************************************
	Work out which PLL we intend to use, if it is the SysClock AND the sysclock 
	Is not running then we can do the SetPLL before we change the memory timings
	etc
	**************************************************************************/

	ui32PLLToUse			= MAR_SYSCLK_SELECT_REFCLK;
	pMSysData->ui32SysClk	= MAR_REFCLK_FREQ;		

	// If our requested frequency is between RefClock and Pixclock, then use pixclock
	// this is the mode to be used in low power mode
	if((ui32DesiredFreq > MAR_REFCLK_FREQ) && (ui32DesiredFreq <= pMSysData->ui32PixClk))
	{
		ui32PLLToUse			= MAR_SYSCLK_SELECT_PLL1;
		pMSysData->ui32SysClk	= pMSysData->ui32PixClk;
	}
	else 
	{
		// If our requested frequency is > pixclock and is not RefClock then use PLL 0 
		// Normal mode of operation
		if((ui32DesiredFreq > pMSysData->ui32PixClk) && (ui32DesiredFreq != MAR_REFCLK_FREQ))
		{
			ui32PLLToUse = MAR_SYSCLK_SELECT_PLL0;
		}
	}

	ui32CurSysPll = ReadHWReg(pMSysData->pvLinRegBaseAddr,MAR_SYSCLK_SELECT);
	// now if we are going to use PLL0 and it is NOT CURRENTLY selected, then try and setup the pll

⌨️ 快捷键说明

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