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

📄 lh7a400_cp15_driver.c

📁 sharp触摸屏测试代码
💻 C
字号:
/**********************************************************************
 *	$Workfile:   LH7A400_cp15_driver.c  $
 *	$Revision:   1.3  $
 *	$Author:   BarnettH  $
 *	$Date:   Jun 19 2002 09:39:44  $
 *
 *	Project: LH7A400
 *
 *	Description:
 *  This module contains utilities for controlling coprocessor 15
 *  MMU and cache functions for the LH7A400
 *
 *	References:
 *  ARM Architecture Reference Manual (ARM DDI 0100E)
 *  ARM 922 (Rev 0) Technical Reference Manual (ARM DDI 0184A)
 *
 *	Revision History:
 *	$Log:   //smaicnt2/pvcs/VM/CHIPS/archives/LH7A400/MMU/Drivers/LH7A400_cp15_driver.c-arc  $
 * 
 *    Rev 1.3   Jun 19 2002 09:39:44   BarnettH
 * Changed identifier 'virtual' to 'virtual_addr' to eliminate conflict with C++ keyword.
 * 
 *    Rev 1.2   Jan 30 2002 08:31:58   KovitzP
 * corrected bug in TLB base address mask
 * 
 *    Rev 1.1   Jan 09 2002 09:32:24   KovitzP
 * Added LH7A400_ prefix to function names
 * 
 *    Rev 1.0   Jan 07 2002 11:13:12   KovitzP
 * Initial revision.
 * 
 * 
 *	COPYRIGHT (C) 2001 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
 *		CAMAS, WA
 *********************************************************************/
#include "SMA_types.h"
#include "LH7A400_cp15_driver.h"
#ifndef NULL
#define NULL 0
#endif
static UNS_32 decode_level2(UNS_32 level2, UNS_32 addr);


/**********************************************************************
*
* Function: LH7A400_cp15_map_virtual_to_physical
*
* Purpose:
*  given a virtual address, return a 
*  UNS_32 containing the physical address 
*
* Processing:
*  return (UNS_32)addr if MMU is turned off. Otherwise, read the 
*  address of the translation table from the translation table base
*  address register. Use the upper 12 bits of the addr to index the
*  translation table and read out the descriptor. If the descriptor is
*  invalid, return 0. If the descriptor is for a 1 Meg section, read back
*  the upper 12 bits of the physical address. The lower 20 bits of the
*  physical address is the lower 20 bits of the virtual address. If
*  the descriptor is for a coarse page table, read the coarse page
*  table descriptor and use the most significant 22 bits as the base
*  address of the page table. If the descriptor is for a fine page
*  table, read the fine page table descriptor and use the most 
*  significant 20 bits as the base address of the page table.
*
*  If not a section base, read the level 2 page descriptor from the page
*  table.  If bits 1..0 of the level2 descriptor are 01, then it is a
*  large page table descriptor. The most significant 16 bits of the
*  descriptor are the most significant 16 bits of the physical address;
*  the least significant 16-bits of the virtual address are the least
*  significant 16-bits of the address. If bits 1..0 of the level2
*  descriptor are 10, then it is a small page table descriptor. The most
*  significant 20 bits of the level2 descriptor are the most significant
*  20 bits of the physical address; the least significant 12 bits are
*  the least significant 12 bits of the physical address. If bits 1..0 of
*  the level2 descriptor are 11, then it is a tiny page table descriptor.
*  The most significant 22 bits of the level2 descriptor are the most
*  significant 22 bits of the physical address; the least significant
*  10 bits are the least significant 10 bits of the physical address. If
*  bits 1..0 of the level2 descriptor are 0, return 0 (invalid).
*
* Parameters: 
*  addr:  the virtual address to be converted
*
* Outputs: None
*
* Returns:
*  the physical address or 0 if the address does not translate.
*
* Notes:
*  CAUTION: This routine counts on the physical address and the 
*  virtual address of the translation table being the same. If
*  they are not the same, then the step that reads the translation
*  table base register won't initialize the tlb variable properly.
*  If page tables are used, then the virtual addresses of the page
*  tables must be the same as the physical addresses or else the page
*  table read will return an invalid value.
*
**********************************************************************/
UNS_32 LH7A400_cp15_map_virtual_to_physical(void * addr)
{
   register UNS_32 tlb_val;
   register UNS_32 status;
   UNS_32  * tlb, tlb_entry, index, virtual_addr;
   UNS_32 * page_table, level2;
    
   virtual_addr = (UNS_32)addr;
   /* read the control register and verify that MMU is on */
   __asm
   {
      MRC p15,0,status,c1,c0,0;
   }
   if ((status & _BIT(0)) == 0) /* bit 0 is MMU enable bit */
   {
      /* then MMU is off; virtual is physical */
      return virtual_addr;
   }
   /* read the translation table base register */
   __asm
   {
      MRC p15,0,tlb_val,c2,c0,0;
   }
   /* mask off unpredictable bits */
   tlb = (UNS_32 *)(tlb_val & _SBF(14,_BITMASK(18)) );
   /* 
   get the level 1 translation table entry 
   indexed by bits 31:20 of the address
   */
   index = virtual_addr;
   index >>= 20;
   tlb_entry = tlb[index];
   /* figure out how to use the tlb entry based on the lower two bits */
   switch (tlb_entry & _BITMASK(2))
   {
      case 0:
         /* invalid */
         return 0;
         break;
      case 1:
         /* course page tables */
         index = (virtual_addr >> 12) & _BITMASK(8);
         page_table = (UNS_32 *)(tlb_entry & _SBF(10, _BITMASK(22)) );
         level2 = page_table[index];
         break;
      case 2:
         /* 
         section base -- upper 12 bits of entry is physical memory base
         lower 20 bits of virtual address is offset from that base
         */
         return (tlb_entry & _SBF(20,_BITMASK(12)) ) | 
                (virtual_addr & _BITMASK(20) );
         break;
      case 3:
         /* fine page tables */
         index = (virtual_addr >> 10) & _BITMASK(10);
         page_table = (UNS_32 *)(tlb_entry & _SBF(12, _BITMASK(20)) );
         level2 = page_table[index];
         break;
         
   }
   
   switch (level2 & _BITMASK(2) )
   {
      case 1:
         /* large page table */
         return (level2 & _SBF(16, _BITMASK(16)) ) | 
                (virtual_addr & _BITMASK(16) );
      case 2:
         /* small page table */
         return (level2 & _SBF(12, _BITMASK(20)) ) | 
                (virtual_addr & _BITMASK(12) );
      case 3:
         return (level2 & _SBF(10, _BITMASK(22)) ) |
                (virtual_addr & _BITMASK(10) );
   }
   /* this line should not execute */
   return 0;
}

/**********************************************************************
*
* Function: LH7A400_cp15_map_physical_to_virtual
*
* Purpose:
*  given a physical address, return a 
*  void pointer containing the virtual address 
*
* Processing:
*
* Parameters: 
*  addr:  the physical address to be converted
*
* Outputs: None
*
* Returns:
*  the virtual address or NULL if the address does not translate.
*
* Notes:
*  CAUTION: This routine counts on the physical address and the 
*  virtual address of the translation table being the same. If
*  they are not the same, then the step that reads the translation
*  table base register won't initialize the tlb variable properly.
*  If page tables are used, then the virtual addresses of the page
*  tables must be the same as the physical addresses or else the page
*  table read will return an invalid value.
*
**********************************************************************/
void * LH7A400_cp15_map_physical_to_virtual(UNS_32 addr)
{
   register UNS_32 tlb_val;
   register UNS_32 status;
   UNS_32 * tlb, tlb_entry, index;
   UNS_32 * page_table, level2, index2;
   void * virtual_addr;
   /* 
   do a linear search of the translation table until the
   level 1 descriptor corresponding to the physical address is found 
   */
   /* read the control register and verify that MMU is on */
   __asm
   {
      MRC p15,0,status,c1,c0,0;
   }
   if ((status & _BIT(0)) == 0) /* bit 0 is MMU enable bit */
   {
      /* then MMU is off; virtual is physical */
      return (void *)addr;
   }
   /* read the translation table base register */
   __asm
   {
      MRC p15,0,tlb_val,c2,c0,0;
   }
   /* mask off unpredictable bits */
   tlb = (UNS_32 *)(tlb_val & _SBF(14,_BITMASK(18)) );
   
   /* 
   search until found or all 4096 translation 
   table entries are examined.
   */
   for (index = 0; index < 4096; index ++)
   {
      tlb_entry = tlb[index];
      switch (tlb_entry & _BITMASK(3))
      {
         case 0:
         /* invalid */
            break;
         case 1:
            /* course page tables */
            for (index2 = 0; index2 < 256; index2++)
            {
               page_table = (UNS_32 *)(tlb_entry & _SBF(10, _BITMASK(22)) );
               level2 = page_table[index2];
               if (level2)
               {
                  virtual_addr = (void *)decode_level2(level2, addr);

                  if (virtual_addr)
                     return virtual_addr;
               }
               break;
            }
         case 2:
            /* 
            section base -- upper 12 bits of entry is physical memory base
            lower 20 bits of virtual address is offset from that base
            */
            if ( (tlb_entry & _SBF(20,_BITMASK(12))) 
                  == (addr & _SBF(20,_BITMASK(12))) )
            {
               return (void *)( _SBF(20,index) | (addr & _BITMASK(20)) );
            }
            break;
         case 3:
            /* fine page tables */
            for (index2 = 0; index2 < 256; index2++)
            {
               page_table = (UNS_32 *)(tlb_entry & _SBF(12, _BITMASK(20)) );
               level2 = page_table[index2];
               if (level2)
               {
                  virtual_addr = (void *)decode_level2(level2, addr);

                  if (virtual_addr)
                     return virtual_addr;
               }
            }
            break;
      }
   }
   /* virtual address not found */
   return NULL;
}

/**********************************************************************
*
* Function: decode_level2
*
* Purpose:
*  given a level2 descriptor and a physical address, return 
*  the virtual address if the level2 descriptor can map the 
*  physical address. Otherwise, 
*
* Processing:
*
* Parameters: 
*  addr:  the physical address to be converted
*
* Outputs: None
*
* Returns:
*  the virtual address or NULL if the address does not translate.
*
* Notes:
*  CAUTION: This routine counts on the physical address and the 
*  virtual address of the translation table being the same. If
*  they are not the same, then the step that reads the translation
*  table base register won't initialize the tlb variable properly.
*  If page tables are used, then the virtual addresses of the page
*  tables must be the same as the physical addresses or else the page
*  table read will return an invalid value.
*
**********************************************************************/
static UNS_32 decode_level2(UNS_32 level2, UNS_32 addr)
{
   switch (level2 & _BITMASK(2) )
   {
      case 1:
         /* large page table */
         if ( (level2 & _SBF(16, _BITMASK(16))) ==
              (addr & _SBF(16, _BITMASK(16))) )
            return (level2 & _SBF(16, _BITMASK(16)) ) | 
                   (addr & _BITMASK(16) );
      case 2:
         /* small page table */
         if ( (level2 & _SBF(12, _BITMASK(20))) ==
              (addr & _SBF(12, _BITMASK(20))) )
            return (level2 & _SBF(12, _BITMASK(20)) ) | 
                (addr & _BITMASK(12) );
      case 3:
         if ( (level2 & _SBF(10, _BITMASK(22))) ==
              (addr & _SBF(10, _BITMASK(22))) )
            return (level2 & _SBF(10, _BITMASK(22)) ) |
                (addr & _BITMASK(10) );
   }
   return 0;
}


/**********************************************************************
*
* Function: LH7A400_force_cache_coherence
*
* Purpose:
*  Force the CPU to recognize the block of  code that was just written
*  to memory between start_adr and end_adr even if caching and write
*  buffering is on.
*
* Processing:
*  cache lines are 32-bytes (8 words); clean and invalidate each
*  line of D-cache and invalidate each line of I-cache within the
*  address range.
*
*  Invalidate the I-TLB within the the address range. The I-TLB has
*  256 word granularity.
*
* Parameters: 
*  start_adr:  The first address in the code block
*  end_adr:    The last address in the code block
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
**********************************************************************/
void LH7A400_force_cache_coherence(UNS_32 * const start_adr, 
                                   UNS_32 * const end_adr)
{
   register UNS_32 * adr;
   
   /* 
   cache lines are 32-bytes (8 words); clean and invalidate each
   line of D-cache and invalidate each line of I-cache within the
   address range.
   */
   for (adr = (UNS_32 *)((UNS_32)start_adr & _SBF(2,_BITMASK(30)) );
        adr < end_adr;
        adr += 8)
   {
      /* p15 is MMU coprocessor, Cache OPS is c7, TLB OPS is c8 */ 
      __asm
      {
		   MOV      r0,adr
      /* Clean and Invalidate D-Cache single entry using MVA format */ 
	   	MCR      p15, 0, r0, c7, c14, 1
      /* Invalidate I-Cache single entry using MVA format */ 
	   	MCR      p15, 0, r0, c7, c5, 1
      }
   }
   
   /*
   Invalidate the I-TLB within the the address range. The I-TLB has
   256 word granularity.
   */
   for (adr = (UNS_32 *)((UNS_32)start_adr & _SBF(10,_BITMASK(22)) );
        adr < end_adr;
        adr += 256)
   {
      __asm
      {
         MOV      r0,adr
   	/* Invalidate I-TLB using MVA format */ 
         MCR      p15, 0, r0, c8, c5, 1
         NOP
         NOP
      }
   }
}

⌨️ 快捷键说明

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