📄 marathon.c
字号:
/*******************************************************************************
* 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 + -