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

📄 mmu_flush.c

📁 Lido PXA270平台开发板的最新BSP,包括源代码
💻 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 + -