/*************************************************************************/ /*!
|
@File
|
@Title DDK implementation of the Services abstraction layer
|
@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
|
@Description DDK implementation of the Services abstraction layer
|
@License Dual MIT/GPLv2
|
|
The contents of this file are subject to the MIT license as set out below.
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
of this software and associated documentation files (the "Software"), to deal
|
in the Software without restriction, including without limitation the rights
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
copies of the Software, and to permit persons to whom the Software is
|
furnished to do so, subject to the following conditions:
|
|
The above copyright notice and this permission notice shall be included in
|
all copies or substantial portions of the Software.
|
|
Alternatively, the contents of this file may be used under the terms of
|
the GNU General Public License Version 2 ("GPL") in which case the provisions
|
of GPL are applicable instead of those above.
|
|
If you wish to allow use of your version of this file only under the terms of
|
GPL, and not to allow others to use your version of this file under the terms
|
of the MIT license, indicate your decision by deleting the provisions above
|
and replace them with the notice and other provisions required by GPL as set
|
out in the file called "GPL-COPYING" included in this distribution. If you do
|
not delete the provisions above, a recipient may use your version of this file
|
under the terms of either the MIT license or GPL.
|
|
This License is also included in this distribution in the file called
|
"MIT-COPYING".
|
|
EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
|
PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
*/ /**************************************************************************/
|
|
#if defined (PDUMP)
|
#include <stdarg.h>
|
#endif
|
|
#include "rgxlayer_km_impl.h"
|
#include "pdump_km.h"
|
#include "devicemem_utils.h"
|
#include "pvrsrv.h"
|
#include "rgxdevice.h"
|
#include "rgxfwutils.h"
|
|
void RGXWriteReg32(const void *hPrivate, IMG_UINT32 ui32RegAddr, IMG_UINT32 ui32RegValue)
|
{
|
RGX_POWER_LAYER_PARAMS *psPowerParams;
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
void *pvRegsBase;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psPowerParams = (RGX_POWER_LAYER_PARAMS*)hPrivate;
|
psDevInfo = psPowerParams->psDevInfo;
|
pvRegsBase = psDevInfo->pvRegsBaseKM;
|
|
#if defined(PDUMP)
|
if( !(psPowerParams->ui32PdumpFlags & PDUMP_FLAGS_NOHW) )
|
#endif
|
{
|
OSWriteHWReg32(pvRegsBase, ui32RegAddr, ui32RegValue);
|
}
|
|
PDUMPREG32(RGX_PDUMPREG_NAME, ui32RegAddr, ui32RegValue, psPowerParams->ui32PdumpFlags);
|
}
|
|
void RGXWriteReg64(const void *hPrivate, IMG_UINT32 ui32RegAddr, IMG_UINT64 ui64RegValue)
|
{
|
RGX_POWER_LAYER_PARAMS *psPowerParams;
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
void *pvRegsBase;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psPowerParams = (RGX_POWER_LAYER_PARAMS*)hPrivate;
|
psDevInfo = psPowerParams->psDevInfo;
|
pvRegsBase = psDevInfo->pvRegsBaseKM;
|
|
#if defined(PDUMP)
|
if( !(psPowerParams->ui32PdumpFlags & PDUMP_FLAGS_NOHW) )
|
#endif
|
{
|
OSWriteHWReg64(pvRegsBase, ui32RegAddr, ui64RegValue);
|
}
|
|
PDUMPREG64(RGX_PDUMPREG_NAME, ui32RegAddr, ui64RegValue, psPowerParams->ui32PdumpFlags);
|
}
|
|
IMG_UINT32 RGXReadReg32(const void *hPrivate, IMG_UINT32 ui32RegAddr)
|
{
|
RGX_POWER_LAYER_PARAMS *psPowerParams;
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
void *pvRegsBase;
|
IMG_UINT32 ui32RegValue;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psPowerParams = (RGX_POWER_LAYER_PARAMS*)hPrivate;
|
psDevInfo = psPowerParams->psDevInfo;
|
pvRegsBase = psDevInfo->pvRegsBaseKM;
|
|
#if defined(PDUMP)
|
if(psPowerParams->ui32PdumpFlags & PDUMP_FLAGS_NOHW)
|
{
|
ui32RegValue = IMG_UINT32_MAX;
|
}
|
else
|
#endif
|
{
|
ui32RegValue = OSReadHWReg32(pvRegsBase, ui32RegAddr);
|
}
|
|
PDUMPREGREAD32(RGX_PDUMPREG_NAME, ui32RegAddr, psPowerParams->ui32PdumpFlags);
|
|
return ui32RegValue;
|
}
|
|
IMG_UINT64 RGXReadReg64(const void *hPrivate, IMG_UINT32 ui32RegAddr)
|
{
|
RGX_POWER_LAYER_PARAMS *psPowerParams;
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
void *pvRegsBase;
|
IMG_UINT64 ui64RegValue;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psPowerParams = (RGX_POWER_LAYER_PARAMS*)hPrivate;
|
psDevInfo = psPowerParams->psDevInfo;
|
pvRegsBase = psDevInfo->pvRegsBaseKM;
|
|
#if defined(PDUMP)
|
if(psPowerParams->ui32PdumpFlags & PDUMP_FLAGS_NOHW)
|
{
|
ui64RegValue = IMG_UINT64_MAX;
|
}
|
else
|
#endif
|
{
|
ui64RegValue = OSReadHWReg64(pvRegsBase, ui32RegAddr);
|
}
|
|
PDUMPREGREAD64(RGX_PDUMPREG_NAME, ui32RegAddr, PDUMP_FLAGS_CONTINUOUS);
|
|
return ui64RegValue;
|
}
|
|
PVRSRV_ERROR RGXPollReg32(const void *hPrivate,
|
IMG_UINT32 ui32RegAddr,
|
IMG_UINT32 ui32RegValue,
|
IMG_UINT32 ui32RegMask)
|
{
|
RGX_POWER_LAYER_PARAMS *psPowerParams;
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
void *pvRegsBase;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psPowerParams = (RGX_POWER_LAYER_PARAMS*)hPrivate;
|
psDevInfo = psPowerParams->psDevInfo;
|
pvRegsBase = psDevInfo->pvRegsBaseKM;
|
|
#if defined(PDUMP)
|
if( !(psPowerParams->ui32PdumpFlags & PDUMP_FLAGS_NOHW) )
|
#endif
|
{
|
if (PVRSRVPollForValueKM((IMG_UINT32 *)((IMG_UINT8*)pvRegsBase + ui32RegAddr),
|
ui32RegValue,
|
ui32RegMask) != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "RGXPollReg32: Poll for Reg (0x%x) failed", ui32RegAddr));
|
return PVRSRV_ERROR_TIMEOUT;
|
}
|
}
|
|
PDUMPREGPOL(RGX_PDUMPREG_NAME,
|
ui32RegAddr,
|
ui32RegValue,
|
ui32RegMask,
|
psPowerParams->ui32PdumpFlags,
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
return PVRSRV_OK;
|
}
|
|
PVRSRV_ERROR RGXPollReg64(const void *hPrivate,
|
IMG_UINT32 ui32RegAddr,
|
IMG_UINT64 ui64RegValue,
|
IMG_UINT64 ui64RegMask)
|
{
|
RGX_POWER_LAYER_PARAMS *psPowerParams;
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
void *pvRegsBase;
|
|
/* Split lower and upper words */
|
IMG_UINT32 ui32UpperValue = (IMG_UINT32) (ui64RegValue >> 32);
|
IMG_UINT32 ui32LowerValue = (IMG_UINT32) (ui64RegValue);
|
IMG_UINT32 ui32UpperMask = (IMG_UINT32) (ui64RegMask >> 32);
|
IMG_UINT32 ui32LowerMask = (IMG_UINT32) (ui64RegMask);
|
|
PVR_ASSERT(hPrivate != NULL);
|
psPowerParams = (RGX_POWER_LAYER_PARAMS*)hPrivate;
|
psDevInfo = psPowerParams->psDevInfo;
|
pvRegsBase = psDevInfo->pvRegsBaseKM;
|
|
#if defined(PDUMP)
|
if( !(psPowerParams->ui32PdumpFlags & PDUMP_FLAGS_NOHW) )
|
#endif
|
{
|
if (PVRSRVPollForValueKM((IMG_UINT32 *)((IMG_UINT8*)pvRegsBase + ui32RegAddr + 4),
|
ui32UpperValue,
|
ui32UpperMask) != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "RGXPollReg64: Poll for upper part of Reg (0x%x) failed", ui32RegAddr));
|
return PVRSRV_ERROR_TIMEOUT;
|
}
|
|
if (PVRSRVPollForValueKM((IMG_UINT32 *)((IMG_UINT8*)pvRegsBase + ui32RegAddr),
|
ui32LowerValue,
|
ui32LowerMask) != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "RGXPollReg64: Poll for upper part of Reg (0x%x) failed", ui32RegAddr));
|
return PVRSRV_ERROR_TIMEOUT;
|
}
|
}
|
|
PDUMPREGPOL(RGX_PDUMPREG_NAME,
|
ui32RegAddr + 4,
|
ui32UpperValue,
|
ui32UpperMask,
|
psPowerParams->ui32PdumpFlags,
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
|
PDUMPREGPOL(RGX_PDUMPREG_NAME,
|
ui32RegAddr,
|
ui32LowerValue,
|
ui32LowerMask,
|
psPowerParams->ui32PdumpFlags,
|
PDUMP_POLL_OPERATOR_EQUAL);
|
|
return PVRSRV_OK;
|
}
|
|
void RGXWaitCycles(const void *hPrivate, IMG_UINT32 ui32Cycles, IMG_UINT32 ui32TimeUs)
|
{
|
PVR_UNREFERENCED_PARAMETER(hPrivate);
|
OSWaitus(ui32TimeUs);
|
PDUMPIDLWITHFLAGS(ui32Cycles, PDUMP_FLAGS_CONTINUOUS);
|
}
|
|
void RGXCommentLogPower(const void *hPrivate, const IMG_CHAR *pszString, ...)
|
{
|
#if defined(PDUMP)
|
va_list argList;
|
va_start(argList, pszString);
|
PDumpCommentWithFlagsVA(PDUMP_FLAGS_CONTINUOUS, pszString, argList);
|
va_end(argList);
|
PVR_UNREFERENCED_PARAMETER(hPrivate);
|
#else
|
PVR_UNREFERENCED_PARAMETER(hPrivate);
|
PVR_UNREFERENCED_PARAMETER(pszString);
|
#endif
|
}
|
|
|
void RGXAcquireKernelMMUPC(const void *hPrivate, IMG_DEV_PHYADDR *psPCAddr)
|
{
|
PVR_ASSERT(hPrivate != NULL);
|
*psPCAddr = ((RGX_POWER_LAYER_PARAMS*)hPrivate)->sPCAddr;
|
}
|
|
#if defined(PDUMP)
|
|
void RGXWriteKernelMMUPC64(const void *hPrivate,
|
IMG_UINT32 ui32PCReg,
|
IMG_UINT32 ui32PCRegAlignShift,
|
IMG_UINT32 ui32PCRegShift,
|
IMG_UINT64 ui64PCVal)
|
{
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psDevInfo = ((RGX_POWER_LAYER_PARAMS*)hPrivate)->psDevInfo;
|
|
/* Write the cat-base address */
|
OSWriteHWReg64(psDevInfo->pvRegsBaseKM, ui32PCReg, ui64PCVal);
|
|
/* Pdump catbase address */
|
MMU_PDumpWritePageCatBase(psDevInfo->psKernelMMUCtx,
|
RGX_PDUMPREG_NAME,
|
ui32PCReg,
|
8,
|
ui32PCRegAlignShift,
|
ui32PCRegShift,
|
PDUMP_FLAGS_CONTINUOUS);
|
}
|
|
void RGXWriteKernelMMUPC32(const void *hPrivate,
|
IMG_UINT32 ui32PCReg,
|
IMG_UINT32 ui32PCRegAlignShift,
|
IMG_UINT32 ui32PCRegShift,
|
IMG_UINT32 ui32PCVal)
|
{
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psDevInfo = ((RGX_POWER_LAYER_PARAMS*)hPrivate)->psDevInfo;
|
|
/* Write the cat-base address */
|
OSWriteHWReg32(psDevInfo->pvRegsBaseKM, ui32PCReg, ui32PCVal);
|
|
/* Pdump catbase address */
|
MMU_PDumpWritePageCatBase(psDevInfo->psKernelMMUCtx,
|
RGX_PDUMPREG_NAME,
|
ui32PCReg,
|
4,
|
ui32PCRegAlignShift,
|
ui32PCRegShift,
|
PDUMP_FLAGS_CONTINUOUS);
|
}
|
|
#endif /* defined(PDUMP) */
|
|
|
void RGXAcquireGPURegsAddr(const void *hPrivate, IMG_DEV_PHYADDR *psGPURegsAddr)
|
{
|
PVR_ASSERT(hPrivate != NULL);
|
*psGPURegsAddr = ((RGX_POWER_LAYER_PARAMS*)hPrivate)->sGPURegAddr;
|
}
|
|
#if defined(PDUMP)
|
void RGXMIPSWrapperConfig(const void *hPrivate,
|
IMG_UINT32 ui32RegAddr,
|
IMG_UINT64 ui64GPURegsAddr,
|
IMG_UINT32 ui32GPURegsAlign,
|
IMG_UINT32 ui32BootMode)
|
{
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psDevInfo = ((RGX_POWER_LAYER_PARAMS*)hPrivate)->psDevInfo;
|
|
OSWriteHWReg64(psDevInfo->pvRegsBaseKM,
|
ui32RegAddr,
|
(ui64GPURegsAddr >> ui32GPURegsAlign) | ui32BootMode);
|
|
/* Store register offset to temp PDump variable */
|
PDumpRegLabelToInternalVar(RGX_PDUMPREG_NAME, ui32RegAddr, ":SYSMEM:$1", PDUMP_FLAGS_CONTINUOUS);
|
|
/* Align register transactions identifier */
|
PDumpWriteVarSHRValueOp(":SYSMEM:$1", ui32GPURegsAlign, PDUMP_FLAGS_CONTINUOUS);
|
|
/* Enable micromips instruction encoding */
|
PDumpWriteVarORValueOp(":SYSMEM:$1", ui32BootMode, PDUMP_FLAGS_CONTINUOUS);
|
|
/* Do the actual register write */
|
PDumpInternalVarToReg64(RGX_PDUMPREG_NAME, ui32RegAddr, ":SYSMEM:$1", 0);
|
}
|
#endif
|
|
void RGXAcquireBootRemapAddr(const void *hPrivate, IMG_DEV_PHYADDR *psBootRemapAddr)
|
{
|
PVR_ASSERT(hPrivate != NULL);
|
*psBootRemapAddr = ((RGX_POWER_LAYER_PARAMS*)hPrivate)->sBootRemapAddr;
|
}
|
|
void RGXAcquireCodeRemapAddr(const void *hPrivate, IMG_DEV_PHYADDR *psCodeRemapAddr)
|
{
|
PVR_ASSERT(hPrivate != NULL);
|
*psCodeRemapAddr = ((RGX_POWER_LAYER_PARAMS*)hPrivate)->sCodeRemapAddr;
|
}
|
|
void RGXAcquireDataRemapAddr(const void *hPrivate, IMG_DEV_PHYADDR *psDataRemapAddr)
|
{
|
PVR_ASSERT(hPrivate != NULL);
|
*psDataRemapAddr = ((RGX_POWER_LAYER_PARAMS*)hPrivate)->sDataRemapAddr;
|
}
|
|
void RGXAcquireTrampolineRemapAddr(const void *hPrivate, IMG_DEV_PHYADDR *psTrampolineRemapAddr)
|
{
|
PVR_ASSERT(hPrivate != NULL);
|
*psTrampolineRemapAddr = ((RGX_POWER_LAYER_PARAMS*)hPrivate)->sTrampolineRemapAddr;
|
}
|
|
#if defined(PDUMP)
|
static inline
|
void RGXWriteRemapConfig2Reg(void *pvRegs,
|
PMR *psPMR,
|
IMG_DEVMEM_OFFSET_T uiLogicalOffset,
|
IMG_UINT32 ui32RegAddr,
|
IMG_UINT64 ui64PhyAddr,
|
IMG_UINT64 ui64PhyMask,
|
IMG_UINT64 ui64Settings)
|
{
|
OSWriteHWReg64(pvRegs, ui32RegAddr, (ui64PhyAddr & ui64PhyMask) | ui64Settings);
|
|
/* Store memory offset to temp PDump variable */
|
PDumpMemLabelToInternalVar(":SYSMEM:$1", psPMR, uiLogicalOffset, PDUMP_FLAGS_CONTINUOUS);
|
|
/* Keep only the relevant bits of the output physical address */
|
PDumpWriteVarANDValueOp(":SYSMEM:$1", ui64PhyMask, PDUMP_FLAGS_CONTINUOUS);
|
|
/* Extra settings for this remapped region */
|
PDumpWriteVarORValueOp(":SYSMEM:$1", ui64Settings, PDUMP_FLAGS_CONTINUOUS);
|
|
/* Do the actual register write */
|
PDumpInternalVarToReg32(RGX_PDUMPREG_NAME, ui32RegAddr, ":SYSMEM:$1", PDUMP_FLAGS_CONTINUOUS);
|
}
|
|
void RGXBootRemapConfig(const void *hPrivate,
|
IMG_UINT32 ui32Config1RegAddr,
|
IMG_UINT64 ui64Config1RegValue,
|
IMG_UINT32 ui32Config2RegAddr,
|
IMG_UINT64 ui64Config2PhyAddr,
|
IMG_UINT64 ui64Config2PhyMask,
|
IMG_UINT64 ui64Config2Settings)
|
{
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
IMG_UINT32 ui32BootRemapMemOffset = RGXMIPSFW_BOOT_NMI_CODE_BASE_PAGE * (IMG_UINT32)RGXMIPSFW_PAGE_SIZE;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psDevInfo = ((RGX_POWER_LAYER_PARAMS*)hPrivate)->psDevInfo;
|
|
/* Write remap config1 register */
|
RGXWriteReg64(hPrivate,
|
ui32Config1RegAddr,
|
ui64Config1RegValue);
|
|
/* Write remap config2 register */
|
RGXWriteRemapConfig2Reg(psDevInfo->pvRegsBaseKM,
|
psDevInfo->psRGXFWCodeMemDesc->psImport->hPMR,
|
psDevInfo->psRGXFWCodeMemDesc->uiOffset + ui32BootRemapMemOffset,
|
ui32Config2RegAddr,
|
ui64Config2PhyAddr,
|
ui64Config2PhyMask,
|
ui64Config2Settings);
|
}
|
|
void RGXCodeRemapConfig(const void *hPrivate,
|
IMG_UINT32 ui32Config1RegAddr,
|
IMG_UINT64 ui64Config1RegValue,
|
IMG_UINT32 ui32Config2RegAddr,
|
IMG_UINT64 ui64Config2PhyAddr,
|
IMG_UINT64 ui64Config2PhyMask,
|
IMG_UINT64 ui64Config2Settings)
|
{
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
IMG_UINT32 ui32CodeRemapMemOffset = RGXMIPSFW_EXCEPTIONSVECTORS_BASE_PAGE * (IMG_UINT32)RGXMIPSFW_PAGE_SIZE;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psDevInfo = ((RGX_POWER_LAYER_PARAMS*)hPrivate)->psDevInfo;
|
|
/* Write remap config1 register */
|
RGXWriteReg64(hPrivate,
|
ui32Config1RegAddr,
|
ui64Config1RegValue);
|
|
/* Write remap config2 register */
|
RGXWriteRemapConfig2Reg(psDevInfo->pvRegsBaseKM,
|
psDevInfo->psRGXFWCodeMemDesc->psImport->hPMR,
|
psDevInfo->psRGXFWCodeMemDesc->uiOffset + ui32CodeRemapMemOffset,
|
ui32Config2RegAddr,
|
ui64Config2PhyAddr,
|
ui64Config2PhyMask,
|
ui64Config2Settings);
|
}
|
|
void RGXDataRemapConfig(const void *hPrivate,
|
IMG_UINT32 ui32Config1RegAddr,
|
IMG_UINT64 ui64Config1RegValue,
|
IMG_UINT32 ui32Config2RegAddr,
|
IMG_UINT64 ui64Config2PhyAddr,
|
IMG_UINT64 ui64Config2PhyMask,
|
IMG_UINT64 ui64Config2Settings)
|
{
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
IMG_UINT32 ui32DataRemapMemOffset = RGXMIPSFW_BOOT_NMI_DATA_BASE_PAGE * (IMG_UINT32)RGXMIPSFW_PAGE_SIZE;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psDevInfo = ((RGX_POWER_LAYER_PARAMS*)hPrivate)->psDevInfo;
|
|
/* Write remap config1 register */
|
RGXWriteReg64(hPrivate,
|
ui32Config1RegAddr,
|
ui64Config1RegValue);
|
|
/* Write remap config2 register */
|
RGXWriteRemapConfig2Reg(psDevInfo->pvRegsBaseKM,
|
psDevInfo->psRGXFWDataMemDesc->psImport->hPMR,
|
psDevInfo->psRGXFWDataMemDesc->uiOffset + ui32DataRemapMemOffset,
|
ui32Config2RegAddr,
|
ui64Config2PhyAddr,
|
ui64Config2PhyMask,
|
ui64Config2Settings);
|
}
|
#endif
|
|
|
|
#define MAX_NUM_COHERENCY_TESTS (10)
|
IMG_BOOL RGXDoFWSlaveBoot(const void *hPrivate)
|
{
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
PVRSRV_DEVICE_CONFIG *psDevConfig;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psDevInfo = ((RGX_POWER_LAYER_PARAMS*)hPrivate)->psDevInfo;
|
|
if (psDevInfo->ui32CoherencyTestsDone >= MAX_NUM_COHERENCY_TESTS)
|
{
|
return IMG_FALSE;
|
}
|
|
psDevConfig = ((RGX_POWER_LAYER_PARAMS*)hPrivate)->psDevConfig;
|
|
return PVRSRVSystemSnoopingOfCPUCache(psDevConfig);
|
}
|
|
PVRSRV_ERROR RGXIOCoherencyTest(const void *hPrivate)
|
{
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
DEVMEM_MEMDESC *psIOCoherencyTestMemDesc;
|
IMG_UINT32 *pui32CpuVirtAddr;
|
RGXFWIF_DEV_VIRTADDR sCoherencyTestBuffer;
|
IMG_DEVMEM_SIZE_T uiCoherencyBlockSize = sizeof(IMG_UINT64);
|
IMG_DEVMEM_ALIGN_T uiCoherencyBlockAlign = sizeof(IMG_UINT64);
|
IMG_UINT32 ui32SLCCTRL;
|
IMG_UINT32 ui32TestNum;
|
PVRSRV_ERROR eError = PVRSRV_OK;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psDevInfo = ((RGX_POWER_LAYER_PARAMS*)hPrivate)->psDevInfo;
|
|
/* Size and align are 'expanded' because we request an export align allocation */
|
DevmemExportalignAdjustSizeAndAlign(DevmemGetHeapLog2PageSize(psDevInfo->psFirmwareHeap),
|
&uiCoherencyBlockSize,
|
&uiCoherencyBlockAlign);
|
|
/* Allocate, acquire cpu address and set firmware address */
|
eError = DevmemFwAllocateExportable(psDevInfo->psDeviceNode,
|
uiCoherencyBlockSize,
|
uiCoherencyBlockAlign,
|
PVRSRV_MEMALLOCFLAG_DEVICE_FLAG(PMMETA_PROTECT) |
|
PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE |
|
PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC |
|
PVRSRV_MEMALLOCFLAG_GPU_CACHE_COHERENT |
|
PVRSRV_MEMALLOCFLAG_CPU_CACHE_INCOHERENT |
|
PVRSRV_MEMALLOCFLAG_GPU_READABLE |
|
PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE |
|
PVRSRV_MEMALLOCFLAG_CPU_READABLE |
|
PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE,
|
"FwExIoCoherencyTestBuffer",
|
&psIOCoherencyTestMemDesc);
|
PVR_ASSERT(eError == PVRSRV_OK);
|
|
eError = DevmemAcquireCpuVirtAddr(psIOCoherencyTestMemDesc,
|
(void **) &pui32CpuVirtAddr);
|
PVR_ASSERT(eError == PVRSRV_OK);
|
|
/* Create a FW address which is uncached in the Meta DCache and in the SLC
|
* using the Meta bootloader segment.
|
* This segment is the only one configured correctly out of reset
|
* (when this test is meant to be executed).
|
*/
|
{
|
RGXSetFirmwareAddress(&sCoherencyTestBuffer,
|
psIOCoherencyTestMemDesc,
|
0,
|
RFW_FWADDR_FLAG_NONE);
|
|
/* Undo most of the FW mappings done by RGXSetFirmwareAddress */
|
sCoherencyTestBuffer.ui32Addr &= ~RGXFW_SEGMMU_DATA_META_CACHE_MASK;
|
sCoherencyTestBuffer.ui32Addr &= ~RGXFW_SEGMMU_DATA_VIVT_SLC_CACHE_MASK;
|
sCoherencyTestBuffer.ui32Addr -= RGXFW_SEGMMU_DATA_BASE_ADDRESS;
|
|
/* Map the buffer in the bootloader segment as uncached */
|
sCoherencyTestBuffer.ui32Addr |= RGXFW_BOOTLDR_META_ADDR;
|
sCoherencyTestBuffer.ui32Addr |= RGXFW_SEGMMU_DATA_META_UNCACHED;
|
}
|
|
/* Bypass the SLC when IO coherency is enabled */
|
ui32SLCCTRL = RGXReadReg32(hPrivate, RGX_CR_SLC_CTRL_BYPASS);
|
RGXWriteReg32(hPrivate,
|
RGX_CR_SLC_CTRL_BYPASS,
|
ui32SLCCTRL | RGX_CR_SLC_CTRL_BYPASS_BYP_CC_EN);
|
|
for (ui32TestNum = 1; ui32TestNum < 3; ui32TestNum++)
|
{
|
IMG_UINT32 i;
|
IMG_BOOL bPassed = IMG_TRUE;
|
|
PVR_LOG(("Startup I/O Coherency Test [pass #%u]", ui32TestNum));
|
|
for (i = 0; i < uiCoherencyBlockSize/sizeof(IMG_UINT32); i++)
|
{
|
IMG_UINT32 ui32FWAddr, ui32FWValue;
|
PVRSRV_ERROR eError2;
|
|
/* Ensures line is in dcache */
|
ui32FWValue = pui32CpuVirtAddr[i];
|
|
/* Dirty allocation in dcache */
|
pui32CpuVirtAddr[i] = i + ui32TestNum;
|
|
/* Flush possible cpu store-buffer(ing) */
|
OSWriteMemoryBarrier();
|
|
/* Read back value using RGX slave-port interface */
|
ui32FWAddr = sCoherencyTestBuffer.ui32Addr + (i * sizeof(IMG_UINT32));
|
|
eError2 = RGXReadMETAAddr(psDevInfo, ui32FWAddr, &ui32FWValue);
|
|
if (eError2 != PVRSRV_OK)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "RGXReadWithSP error: %s",
|
PVRSRVGetErrorStringKM(eError2)));
|
}
|
|
/* Compare to see if I/O coherency worked */
|
if (pui32CpuVirtAddr[i] != ui32FWValue)
|
{
|
PVR_DPF((PVR_DBG_ERROR, "Expected: %x, Got: %x",
|
pui32CpuVirtAddr[i], ui32FWValue));
|
|
bPassed = IMG_FALSE;
|
eError = PVRSRV_ERROR_INIT_FAILURE;
|
}
|
}
|
|
PVR_LOG(("I/O Coherency Test [pass #%u] completed, Passed? %d",
|
ui32TestNum, bPassed));
|
}
|
|
/* Restore SLC bypass settings */
|
RGXWriteReg32(hPrivate, RGX_CR_SLC_CTRL_BYPASS, ui32SLCCTRL);
|
|
RGXUnsetFirmwareAddress(psIOCoherencyTestMemDesc);
|
DevmemReleaseCpuVirtAddr(psIOCoherencyTestMemDesc);
|
DevmemFwFree(psDevInfo, psIOCoherencyTestMemDesc);
|
|
if (eError == PVRSRV_OK)
|
{
|
PVR_LOG(("I/O Coherency Test succeeded"));
|
psDevInfo->ui32CoherencyTestsDone = MAX_NUM_COHERENCY_TESTS + 1;
|
}
|
else
|
{
|
PVR_LOG(("I/O Coherency Test FAILED"));
|
psDevInfo->ui32CoherencyTestsDone++;
|
}
|
|
return eError;
|
}
|
|
IMG_BOOL RGXDeviceHasFeaturePower(const void *hPrivate, IMG_UINT64 ui64Feature)
|
{
|
RGX_POWER_LAYER_PARAMS *psPowerParams;
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psPowerParams = (RGX_POWER_LAYER_PARAMS*)hPrivate;
|
psDevInfo = psPowerParams->psDevInfo;
|
|
return (psDevInfo->sDevFeatureCfg.ui64Features & ui64Feature) != 0;
|
}
|
|
IMG_BOOL RGXDeviceHasErnBrnPower(const void *hPrivate, IMG_UINT64 ui64ErnsBrns)
|
{
|
RGX_POWER_LAYER_PARAMS *psPowerParams;
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psPowerParams = (RGX_POWER_LAYER_PARAMS*)hPrivate;
|
psDevInfo = psPowerParams->psDevInfo;
|
|
return (psDevInfo->sDevFeatureCfg.ui64ErnsBrns & ui64ErnsBrns) != 0;
|
}
|
|
IMG_UINT32 RGXGetDeviceSLCBanks(const void *hPrivate)
|
{
|
RGX_POWER_LAYER_PARAMS *psPowerParams;
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psPowerParams = (RGX_POWER_LAYER_PARAMS*)hPrivate;
|
psDevInfo = psPowerParams->psDevInfo;
|
|
return psDevInfo->sDevFeatureCfg.ui32SLCBanks;
|
}
|
|
IMG_UINT32 RGXGetDeviceSLCSize(const void *hPrivate)
|
{
|
RGX_POWER_LAYER_PARAMS *psPowerParams;
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psPowerParams = (RGX_POWER_LAYER_PARAMS*)hPrivate;
|
psDevInfo = psPowerParams->psDevInfo;
|
|
return psDevInfo->sDevFeatureCfg.ui32SLCSize;
|
}
|
|
IMG_UINT32 RGXGetDeviceCacheLineSize(const void *hPrivate)
|
{
|
RGX_POWER_LAYER_PARAMS *psPowerParams;
|
PVRSRV_RGXDEV_INFO *psDevInfo;
|
|
PVR_ASSERT(hPrivate != NULL);
|
psPowerParams = (RGX_POWER_LAYER_PARAMS*)hPrivate;
|
psDevInfo = psPowerParams->psDevInfo;
|
|
return psDevInfo->sDevFeatureCfg.ui32CacheLineSize;
|
}
|