📄 mmu_flush.c
字号:
/* -*- c-file-style: "img" -*-
<module>
* Name : mmu_flush.c
* Title : MMU Flush Mechanism
* Author : Marcus Shawcroft
* Created : 14 May 2003
*
* Copyright : 2003 by Imagination Technologies Limited.
* All rights reserved. No part 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 :
*
* Forces a flush of the MMU TLBs.
*
* Platform : ALL
*
</module>
*/
#include "services_headers.h"
#include "mmu_flush.h"
#include "hash.h"
#include "ra.h"
#include "mmu.h"
#include "mbx1defs.h"
#include "env.h"
#include "mbx12ddef.h"
#if defined (FIX_HW_PRN_63)
/* 2D Slaveport Commands */
#define CMD_2D_CLIP (0x0)
#define CMD_2D_PAT (0x1)
#define CMD_2D_CTRL (0x2)
#define CMD_2D_SRC_OFF (0x3)
#define CMD_2D_MSK_OFF (0x4)
#define CMD_2D_MSK_SIZE (0x5)
#define CMD_2D_STRETCH (0x6)
#define CMD_2D_FENCE (0x7)
#define CMD_2D_BLIT (0x8)
#define CMD_2D_SRC_SURFACE (0x9)
#define CMD_2D_DST_SURFACE (0xa)
#define CMD_2D_PAT_SURFACE (0xb)
#define CMD_2D_SRC_PALETTE (0xc)
#define CMD_2D_PAT_PALETTE (0xd)
#define CMD_2D_MSK_SURFACE (0xe)
#define CMD_2D_FLUSH (0xf)
/* surface memory type encodings */
#define SMT_SYSTEM_MEMORY 0
#define SMT_SYSTEM_FRAME_BUFFER 1
#define SMT_SYSTEM_FOLLOW 2
#define FLD_MASK_SIZE_WIDTH 26:14
#define FLD_MASK_SIZE_HEIGHT 12:0
#define FLD_CMD 31:28
#define FLD_USE_DEST_FOR_MASK 27:27
#define FLD_COPY_ORDER 24:23
#define FLD_DST_CK 22:21
#define FLD_SRC_CK 20:19
#define FLD_CLIP_ENABLE 18:18
#define FLD_ALPHA_ENABLE 17:17
#define FLD_PATTERN_ENABLE 16:16
#define FLD_ROP_B 15:8
#define FLD_ROP_A 7:0
#define FLD_MEMORY 27:26
#define FLD_PF 19:15
#define FLD_STRIDE 14:0
#define FLD_X_START 28:16
#define FLD_Y_START 12:0
#define FLD_X_END 28:16
#define FLD_Y_END 12:0
#define FLD_BASE_ADDR 25:0
#define _PACK_S(F) (1?F)
#define _PACK_E(F) (0?F)
#define _PACK_W(F) (_PACK_S(F)-_PACK_E(F)+1)
#define _PACK_MASK(F) ((1<<_PACK_W(F))-1)
#define PACK(v,F) ((v&_PACK_MASK(F))<<_PACK_E(F))
#endif
/*---------------------------------------------------------------------------
<function>
FUNCTION: MMUFLUSH_Create
PURPOSE: Create an mmu flush manager.
PARAMETERS: In: pMMU - The mmu to manage flushes on.
In: pFlush - Filled in by flush manager.
In: pPager - Dual page pager for working space allocations.
RETURNS: IMG_TRUE - Success.
IMG_FALSE - Failure.
</function>
-----------------------------------------------------------------------------*/
IMG_BOOL
MMUFLUSH_Create (MMU *pMMU, MMU_FLUSH *pFlush, DP_PAGER *pPager)
{
IMG_BOOL bRes;
PVR_ASSERT (pMMU != IMG_NULL);
bRes = MMU_Alloc( pMMU,
DEV_PAGE_SIZE,
IMG_NULL,
0,
0,
&(pFlush->DstSurfaceDevVAddr));
if (!bRes)
{
PVR_DPF((PVR_DBG_FATAL, "MMUFLUSH_Create: ERROR calling MMU_Alloc"));
return IMG_FALSE;
}
bRes = DP_AllocContiguous ( pPager,
0,
DEV_PAGE_SIZE,
IMG_NULL,
DEV_PAGE_SIZE,
&pFlush->CpuVAddr,
&pFlush->CpuPAddr);
if (!bRes)
{
PVR_DPF((PVR_DBG_FATAL, "MMUFLUSH_Create: ERROR calling DP_AllocContiguous"));
MMU_Free (pMMU, pFlush->DstSurfaceDevVAddr);
return IMG_FALSE;
}
MMU_MapPage (pMMU,
pFlush->DstSurfaceDevVAddr,
ENV_CpuPAddrToDevPAddr (pFlush->CpuPAddr));
return IMG_TRUE;
}
/*---------------------------------------------------------------------------
<function>
FUNCTION: MMUFLUSH_Delete
PURPOSE: Delete an mmu flush manager.
PARAMETERS: In: pMMU - The mmu to manage flushes on.
In: pFlush - Filled in by flush manager.
In: pPager - Dual page pager for working space deallocations.
RETURNS: None.
</function>
-----------------------------------------------------------------------------*/
void
MMUFLUSH_Delete (MMU *pMMU, MMU_FLUSH *pFlush, DP_PAGER *pPager)
{
PVR_ASSERT (pMMU != IMG_NULL);
MMU_Free (pMMU, pFlush->DstSurfaceDevVAddr);
DP_FreeContiguous (pPager, 0, pFlush->CpuPAddr);
}
#if defined (FIX_HW_PRN_63)
/*!****************************************************************************
@Function _2DSync
@Input *pDev :
@Input cpuVAddr :
@Return :
@Description : Synchronisation by means of a 2D blit: It issues the command
and polls for the blit to take effect.
IMPORTANT NOTE: It reuses the already set source/destination!!!
******************************************************************************/
static void
_2DSync( struct device_tag *pDev,
IMG_CPU_VIRTADDR cpuVAddr)
{
const IMG_UINT32 SyncFillColour = 0x5555;
IMG_INT32 tries;
/* Reset the sync surface */
*((char *)cpuVAddr) = 0;
/* Blit */
HW_Write2DSlavePort ( pDev,
MBX2D_BLIT_BH |
MBX2D_USE_DST_FOR_MASK |
MBX2D_ROP3_PATCOPY);
HW_Write2DSlavePort (pDev, SyncFillColour); /* fill colour */
HW_Write2DSlavePort (pDev,
PACK (0, FLD_X_START) |
PACK (0 /*uIndexStart*/, FLD_Y_START));
HW_Write2DSlavePort (pDev,
PACK (1, FLD_X_END) |
PACK (1 /*uIndexEnd+1*/, FLD_Y_END));
/* - 2d Flush */
HW_Write2DSlavePort (pDev, MBX2D_FLUSH_BH);
/* Poll for fill colour to appear */
/* FIXME: how many tries are enough ? */
tries = 50;
while (tries)
{
if (*((char *)cpuVAddr) == (SyncFillColour & 0x0ff))
break;
HostWaitus(250); /* FIXME, what is a good value here */
tries--;
}
PVR_DPF((PVR_DBG_VERBOSE, "_2DSync tries %d", 50-tries));
PVR_ASSERT(tries > 0);
}
/*----------------------------------------------------------------------------
<function>
FUNCTION: MMUFLUSH_Range
PURPOSE: Flush a device virtual address range from the MMU cache.
PARAMETERS: In: pMMU - the mmu.
In: vaddr - base of the device virtual address range to flush.
In: uSize - size of the device virtual address range to flush
in bytes.
RETURNS: None.
</function>
-----------------------------------------------------------------------------*/
void
MMUFLUSH_Range (struct device_tag *pDev,
IMG_DEV_VIRTADDR BaseDevVAddr,
IMG_SIZE_T uSize,
MMU_FLUSH *pFlush)
{
IMG_UINT32 uIndexStart;
IMG_UINT32 uIndexEnd;
IMG_UINT32 uStatus;
IMG_UINT32 uOffset;
IMG_UINT32 uIndex;
IMG_UINT32 uIteration;
#define MMUCACHELINES 256
#define DST_STRIDE 4
#define MSK_WIDTH 8
#define SRC_STRIDE 4096
#define MSK_STRIDE 4096
PVR_DPF ((PVR_DBG_MESSAGE,
"MMU_FlushRange (dv=0x%lx, size=0x%lx)",
BaseDevVAddr.uiAddr, uSize));
uSize = DEV_PAGE_ALIGN (uSize);
uIndexStart = (BaseDevVAddr.uiAddr >> DEV_PAGE_SHIFT) & (MMUCACHELINES-1);
uIndexEnd = ((BaseDevVAddr.uiAddr + uSize) >> DEV_PAGE_SHIFT) & (MMUCACHELINES-1);
if (uIndexEnd < uIndexStart)
{
uIndexStart = 0;
uIndexEnd = MMUCACHELINES-1;
}
PVR_DPF ((PVR_DBG_MESSAGE,
" index start=0x%x, index end=0x%x", uIndexStart, uIndexEnd));
HW_FlushFifo (pDev);
/* Setup Destination Surface */
HW_Write2DSlavePort (pDev,
PACK (CMD_2D_DST_SURFACE, FLD_CMD) |
PACK (7, FLD_PF) |
PACK (DST_STRIDE, FLD_STRIDE));
HW_Write2DSlavePort (pDev, PACK (pFlush->DstSurfaceDevVAddr.uiAddr, FLD_BASE_ADDR));
/* Setup offset for src: (0,0) for each src */
HW_Write2DSlavePort (pDev,
PACK (CMD_2D_SRC_OFF, FLD_CMD) |
PACK (0, 26:14) |
PACK (0, 12:0)); /* block header */
/* Setup Mask offset: (0,0) for each mask */
HW_Write2DSlavePort (pDev,
PACK (CMD_2D_MSK_OFF, FLD_CMD) |
PACK (0, 26:14) |
PACK (0, 12:0)); /* block header */
/* Setup Mask Size */
HW_Write2DSlavePort (pDev,
PACK (CMD_2D_MSK_SIZE, FLD_CMD) |
PACK (MSK_WIDTH, FLD_MASK_SIZE_WIDTH) |
PACK (MMUCACHELINES, FLD_MASK_SIZE_HEIGHT));
/* Flush the range by writing to it */
for (uIndex=uIndexStart; uIndex <= uIndexEnd; uIndex++)
{
HW_FlushFifo (pDev);
for (uIteration=0; uIteration<8; uIteration++)
{
uOffset = ((uIteration<<8) | uIndex) << DEV_PAGE_SHIFT;
HW_Write2DSlavePort (pDev,
PACK (CMD_2D_SRC_SURFACE, FLD_CMD) |
PACK (SMT_SYSTEM_FRAME_BUFFER, FLD_MEMORY) |
PACK (7, FLD_PF) |
PACK (SRC_STRIDE, FLD_STRIDE));
HW_Write2DSlavePort (pDev, PACK (uOffset, FLD_BASE_ADDR)); /* base address */
HW_Write2DSlavePort (pDev,
PACK (CMD_2D_MSK_SURFACE, FLD_CMD) |
PACK (SMT_SYSTEM_FRAME_BUFFER, FLD_MEMORY) |
PACK (7, FLD_PF) |
PACK (MSK_STRIDE, FLD_STRIDE));
HW_Write2DSlavePort (pDev, PACK (uOffset, FLD_BASE_ADDR)); /* base address */
HW_Write2DSlavePort (pDev,
PACK (CMD_2D_BLIT, FLD_CMD) |
PACK (0, FLD_USE_DEST_FOR_MASK) |
PACK (0, FLD_COPY_ORDER) |
PACK (0, FLD_DST_CK) |
PACK (0, FLD_SRC_CK) |
PACK (0, FLD_CLIP_ENABLE) |
PACK (0, FLD_ALPHA_ENABLE) |
PACK (0, FLD_PATTERN_ENABLE) |
PACK (0xcc, FLD_ROP_B) |
PACK (0xcc, FLD_ROP_A));
HW_Write2DSlavePort (pDev, 0xff); /* fill colour */
HW_Write2DSlavePort (pDev,
PACK (0, FLD_X_START) |
PACK (0 /*uIndexStart*/, FLD_Y_START));
HW_Write2DSlavePort (pDev,
PACK (1, FLD_X_END) |
PACK (1 /*uIndexEnd+1*/, FLD_Y_END));
}
}
/* Do a fill colour blit to the destination and poll for the change to
* take place, we cannot use the 2D interrupt as it may be caught and
* reset by the ISR handler
*/
_2DSync(pDev, pFlush->CpuVAddr);
/* write MMU_Invalidate */
HW_ModifyReg (pDev,
MBX1_GLOBREG_MMU_ENABLE,
MMU_INVALIDATE_MASK,
MMU_INVALIDATE_MASK);
/* spin for invalidate complete */
do
{
uStatus = HW_ReadReg (pDev, MBX1_GLOBREG_MMU_ENABLE);
}
while ((uStatus & MMU_INVAL_STATUS_MASK) != 0);
}
#else
/*----------------------------------------------------------------------------
<function>
FUNCTION: MMUFLUSH_Range
PURPOSE: Flush a device virtual address range from the MMU cache.
PARAMETERS: In: pMMU - the mmu.
In: vaddr - base of the device virtual address range to flush.
In: uSize - size of the device virtual address range to flush
in bytes.
RETURNS: None.
</function>
-----------------------------------------------------------------------------*/
void
MMUFLUSH_Range (struct device_tag *pDev,
IMG_DEV_VIRTADDR BaseDevVAddr,
IMG_SIZE_T uSize,
MMU_FLUSH *pFlush)
{
}
#endif
/* todo: boilerplate */
void
MMUFLUSH_TLBReload (struct device_tag *pDev,
IMG_DEV_VIRTADDR DevVAddr,
IMG_DEV_PHYADDR DevPAddr)
{
IMG_UINT32 u;
IMG_UINT32 uTag;
IMG_UINT32 uIndex;
IMG_UINT32 uStatus;
PVR_DPF ((PVR_DBG_MESSAGE,
"MMUFLUSH_TLBReload (0x%x, 0x%x, 0x%x)",
(IMG_UINT32)pDev, DevVAddr.uiAddr, DevPAddr.uiAddr));
uTag = (DevVAddr.uiAddr >> (MBX1_MMU_PAGE_BITS + MBX1_MMU_INDEX_BITS)) &
MBX1_MMU_TAG_MASK;
uIndex = (DevVAddr.uiAddr >> MBX1_MMU_PAGE_BITS) & MBX1_MMU_INDEX_MASK;
u = (uTag << MBX1_MMU_IDX_INVAL_TAG_SHIFT) | (uIndex << MBX1_MMU_IDX_INVAL_INDEX_SHIFT);
/* write tag and index */
HW_WriteReg (pDev, MBX1_GLOBREG_MMU_IDX_INVAL, u);
/* write new physical address */
HW_WriteReg (pDev, MBX1_GLOBREG_MMU_PHYSADD_INVAL, (DevPAddr.uiAddr >> MBX1_MMU_PHYSADD_INVAL_ADDR_SHIFT));
/* write MMU_Invalidate */
HW_ModifyReg (pDev,
MBX1_GLOBREG_MMU_ENABLE,
MMU_INVALIDATE_MASK,
MMU_INVALIDATE_MASK);
/* spin for invalidate complete */
do
{
uStatus = HW_ReadReg (pDev, MBX1_GLOBREG_MMU_ENABLE);
}
while ((uStatus & MMU_INVAL_STATUS_MASK) != 0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -