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

📄 abl_arm922t_cp15_driver.c

📁 SHARP_ARM720T_LH79524/5软件开发包_支持TFT_LCD_NAND_FLASH_ETH_USB
💻 C
📖 第 1 页 / 共 3 页
字号:
/***********************************************************************
 * $Workfile:   abl_arm922t_cp15_driver.c  $
 * $Revision:   1.10  $
 * $Author:   WellsK  $
 * $Date:   May 27 2005 14:21:36  $
 *
 * Project: ARM922T Coprocessor 15 driver
 *
 * Description:
 *     This file contains driver support for the MMU and cache
 *     coprocessor (15) of the ARM922T.
 *
 * Revision History:
 * $Log:   //smaicnt2/pvcs/VM/sharpmcu/archives/sharpmcu/software/abl/source/abl_arm922t_cp15_driver.c-arc  $
 * 
 *    Rev 1.10   May 27 2005 14:21:36   WellsK
 * Fix a compilation issue with inline assembly instructions for
 * GNU when performing a load immediate (MOV r0, 0).
 * 
 *    Rev 1.9   May 12 2005 12:48:28   PattamattaD
 * Added some more utility functions
 * 
 *    Rev 1.8   Oct 04 2004 15:01:38   WellsK
 * Added ARM ADS versions of the cache adn write buffer
 * flush functions. GNU, GHS, and IAR are pending.
 * 
 *    Rev 1.7   Apr 15 2004 15:20:14   WellsK
 * Added IAR intrinsic functions for NOPs.
 * 
 *    Rev 1.6   Mar 29 2004 12:09:26   WellsK
 * Fixed/improved support for IAR toolchain.
 * 
 *    Rev 1.5   Dec 02 2003 10:12:28   WellsK
 * Corrected mask value in void cp15_force_cache_coherence
 * function.
 * 
 *    Rev 1.4   Oct 01 2003 12:06:28   WellsK
 * Added cp15_get_ttb function.
 * 
 *    Rev 1.3   Sep 30 2003 17:01:42   WellsK
 * Corrected __ARM_CC define. Used __arm instead.
 * 
 *    Rev 1.2   Sep 25 2003 15:13:52   WellsK
 * Added support for IAR environment.
 * 
 *    Rev 1.1   Sep 10 2003 11:27:10   WellsK
 * Added a function for setting the virtual address of where the
 * MMU table is located.
 * 
 *    Rev 1.0   Jun 09 2003 12:06:26   WellsK
 * Initial revision.
 * 
 *
 ***********************************************************************
 * SHARP MICROELECTRONICS OF THE AMERICAS MAKES NO REPRESENTATION
 * OR WARRANTIES WITH RESPECT TO THE PERFORMANCE OF THIS SOFTWARE,
 * AND SPECIFICALLY DISCLAIMS ANY RESPONSIBILITY FOR ANY DAMAGES, 
 * SPECIAL OR CONSEQUENTIAL, CONNECTED WITH THE USE OF THIS SOFTWARE.
 *
 * SHARP MICROELECTRONICS OF THE AMERICAS PROVIDES THIS SOFTWARE SOLELY 
 * FOR THE PURPOSE OF SOFTWARE DEVELOPMENT INCORPORATING THE USE OF A 
 * SHARP MICROCONTROLLER OR SYSTEM-ON-CHIP PRODUCT. USE OF THIS SOURCE
 * FILE IMPLIES ACCEPTANCE OF THESE CONDITIONS.
 *
 * COPYRIGHT (C) 2001 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
 *     CAMAS, WA
 **********************************************************************/

#include "abl_arm922t_cp15_driver.h"

#ifdef __ICCARM__ 
#include "inarm.h"
#endif

/***********************************************************************
 * CP15 driver private data
 **********************************************************************/

/* The address translation functions of this driver require a saved
   pointer to the virtual base address of the MMU table. */
UNS_32 *virtual_tlb_addr;

/***********************************************************************
 * CP15 driver private functions and macros
 **********************************************************************/

#ifdef __ghs__
/* Simple GHS function returning the TTB register */
asm UNS_32 getttb (void)
{
%reg ttb
    MRC     p15, 0, r0, c2, c0, 0
}

/* Simple GHS function returning the MMU control register */
asm UNS_32 getstatus (void)
{
%reg status
    MRC     p15, 0, r0, c1, c0, 0
}

/* Simple GHS function used to support cache invalidation */
asm void invalcache (UNS_32 *adr)
{
%reg adr
    MCR     p15, 0, adr, c7, c14, 1
    MCR     p15, 0, adr, c7, c5, 1
%con adr
    MOV     r0, adr
    MCR     p15, 0, r0, c7, c14, 1
    MCR     p15, 0, r0, c7, c5, 1
}

/* Simple GHS function used to support cache invalidation */
asm void inval_all_cache(void)
{
    MOV     r0, 0
    MCR     p15, 0, r0, c7, c7, 0
}

/* Simple GHS function used to support translation table base
   register invalidation */
asm void invaltlb (UNS_32 *adr)
{
%reg adr
    MCR     p15, 0, adr, c8, c5, 1
    NOP
    NOP
%con adr
    MOV     r0, adr
    MCR     p15, 0, r0, c8, c5, 1
    NOP
    NOP
}

/* Simple GHS function used to invalidate all TLB entries */
asm void inval_all_tlb(void)
{
    MOV     r0, 0
    MCR     p15, 0, r0, c8, c7, 0
}

/* Simple GHS function used to enable/disable MMU */
asm void set_mmu (UNS_32 val)
{
%reg val
    MRC     p15, 0, val, c1, c0, 0
}

/* Simple GHS function used to set TTB address */
asm void set_ttb (UNS_32 addr)
{
%reg addr
    MCR     p15, 0, addr, c2, c5, 0
}

/* Simple GHS function used to set domain access control */
asm void set_dac (UNS_32 reg_val)
{
%reg reg_val
    MCR     p15, 0, reg_val, c3, c0, 0
}
#endif

/***********************************************************************
 * CP15 driver public functions
 **********************************************************************/

/***********************************************************************
 *
 * Function: cp15_decode_level2
 *
 * Purpose:
 *     Given a level2 descriptor and a physical address, return 
 *     the virtual address if the level2 descriptor can map the 
 *     physical address.
 *
 * Processing:
 *     Translate and return the level 2 virtual address for 
 *     the given physical address.
 *
 * Parameters:
 *     level2: MMU level 2 table value
 *     addr:   Physical address to be converted
 *
 * Outputs: None
 *
 * Returns:
 *      The virtual address or 0 if the address does not translate.
 *
 * Notes: None
 *
 **********************************************************************/
static UNS_32 cp15_decode_level2(UNS_32 level2,
                                 UNS_32 addr)
{
    UNS_32 dcd = 0;
    
    switch (level2 & ARM922T_L2D_TYPE_PAGE_MASK)
    {
        case ARM922T_L2D_TYPE_LARGE_PAGE:
            /* Large page table */
            if ((level2 & ARM922T_L2D_LPAGE_MASK) ==
                (addr & ARM922T_L2D_LPAGE_MASK))
            {
                dcd = (level2 & ARM922T_L2D_LPAGE_MASK) | 
                    (addr & (~ARM922T_L2D_LPAGE_MASK));
            }
            break;

        case ARM922T_L2D_TYPE_SMALL_PAGE:
            /* Small page table */
            if ((level2 & ARM922T_L2D_SPAGE_MASK) ==
                (addr & ARM922T_L2D_SPAGE_MASK))
            {
                dcd = (level2 & ARM922T_L2D_SPAGE_MASK) | 
                   (addr & (~ARM922T_L2D_SPAGE_MASK));
            }
            break;

        case ARM922T_L2D_TYPE_TINY_PAGE:
            /* Tiny page table */
            if ((level2 & ARM922T_L2D_TPAGE_MASK) ==
                (addr & ARM922T_L2D_TPAGE_MASK))
            {
                dcd = (level2 & ARM922T_L2D_TPAGE_MASK) |
                    (addr & (~ARM922T_L2D_TPAGE_MASK));
            }

        default:
            break;
    }

    return dcd;
}

/***********************************************************************
 * CP15 driver public functions
 **********************************************************************/

/***********************************************************************
 *
 * Function: cp15_map_virtual_to_physical
 *
 * Purpose: Return a physical address for a passed virtual 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: None
 *
 **********************************************************************/
UNS_32 cp15_map_virtual_to_physical(void *addr)
{
    register UNS_32 status;
    UNS_32 *tlb, tlb_entry, index, virtual_addr;
    UNS_32 *page_table, level2;
    
    virtual_addr = (UNS_32) addr;
    
    /* Read the MMU control register */
#ifdef __GNUC__
    asm ("MRC p15, 0, %0, c1, c0, 0" : "=r" (status));
#endif
#ifdef __ghs__
    status = getstatus();
#endif
#ifdef __arm
    __asm
    {
        MRC p15, 0, status, c1, c0, 0;
    }
#endif
#ifdef __ICCARM__ 
   /* IAR CC includes some "intrinsic" functions to access ARM CP regs */
   status = __MRC(15, 0, 1, 0, 0);
#endif 

    /* Is MMU enabled? */
    if ((status & ARM922T_MMU_CONTROL_M) == 0)
    {
        /* MMU is off; virtual address is physical address */
        return virtual_addr;
    }

    /* Get TLB base address */
    tlb = virtual_tlb_addr;

    /*******************************************************************
     * Get the level 1 translation table entry 
     * indexed by bits 31:20 of the address
     ******************************************************************/
    index = virtual_addr;
    index >>= 20;
    tlb_entry = tlb[index];
    /* Perform function based on level 1 page type or section */
    switch (tlb_entry & ARM922T_L1D_TYPE_PG_SN_MASK)
    {
        case ARM922T_L1D_TYPE_FAULT:
            /* Invalid section or page, fault */
            return 0;

        case ARM922T_L1D_TYPE_CPAGE:
            /* Coarse page tables */
            index = (virtual_addr >> 12) & ARM922T_CPT_INDEX_MASK;
            page_table = (UNS_32 *)(tlb_entry &
                ARM922T_L2D_CP_BASE_MASK);
            level2 = page_table[index];
            break;

        case ARM922T_L1D_TYPE_SECTION:
            /* Section type */
            /***********************************************************
             * Section base -- upper 12 bits of entry is physical 
             * memory base lower 20 bits of virtual address is offset 
             * rom that base
             **********************************************************/
            return ((tlb_entry & ARM922T_L2D_SN_BASE_MASK) | 
                    (virtual_addr & ~(ARM922T_L2D_SN_BASE_MASK)));

        case ARM922T_L1D_TYPE_FPAGE:
            /* Fine page tables */
            index = (virtual_addr >> 10) & ARM922T_FPT_INDEX_MASK;
            page_table = (UNS_32 *)(tlb_entry &
                ARM922T_L2D_FP_BASE_MASK);
            level2 = page_table[index];
            break;

        default:
            /* This should never happen */
            return 0;
    }

    switch (level2 & ARM922T_L2D_TYPE_PAGE_MASK)
    {
        case ARM922T_L2D_TYPE_LARGE_PAGE:
            /* Large page table */
            return ((level2 & ARM922T_L2D_LPAGE_MASK) |
                    (virtual_addr & ~(ARM922T_L2D_LPAGE_MASK)));

        case ARM922T_L2D_TYPE_SMALL_PAGE:
            /* Small page table */
            return ((level2 & ARM922T_L2D_SPAGE_MASK) |
                    (virtual_addr & ~(ARM922T_L2D_SPAGE_MASK)));

        case ARM922T_L2D_TYPE_TINY_PAGE:
            /* Tiny page table */
            return ((level2 & ARM922T_L2D_TPAGE_MASK) |
                    (virtual_addr & ~(ARM922T_L2D_TPAGE_MASK)));

        default:
            break;
    }

    return 0;
}

/***********************************************************************
 *
 * Function: cp15_map_physical_to_virtual
 *
 * Purpose: Return a virtual address for a passed physical address
 *
 * Processing:
 *     Test if MMU is on, return if not.  Search for the virtual
 *     address of the provided physical address. If found, return a
 *     void pointer to virtual address.
 *
 * Parameters:
 *     addr: The physical address to be converted
 *
 * Outputs: None
 *
 * Returns:
 *      The virtual address or 0 if the address does not translate.
 *
 * Notes: None
 *
 **********************************************************************/
void * cp15_map_physical_to_virtual(UNS_32 addr)
{
    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 */
#ifdef __GNUC__
    asm ("MRC p15, 0, %0, c1, c0, 0" : "=r" (status));
#endif
#ifdef __ghs__
    status = getstatus ();
#endif
#ifdef __arm
    __asm
    {
        MRC p15, 0, status, c1, c0, 0;
    }
#endif
#ifdef __ICCARM__
   /* IAR CC includes some "intrinsic" functions to access ARM CP regs */
   status = __MRC(15, 0, 1, 0, 0);
#endif
    
    /* Is MMU enabled? */
    if ((status & ARM922T_MMU_CONTROL_M) == 0)
    {
        /* MMU is off; physical address is virtual address */
        return (void *)addr;
    }

    /* Get TLB base address */
    tlb = virtual_tlb_addr;
   
    /*******************************************************************
     * Search until found or all 4096 translation
     * table entries are examined.
     ******************************************************************/
    for (index = 0; index < ARM922T_TT_ENTRIES; index ++)
    {
        tlb_entry = tlb[index];
        switch (tlb_entry & ARM922T_L1D_TYPE_PG_SN_MASK)
        {
            case ARM922T_L1D_TYPE_FAULT:
                /* Invalid section or page, fault */
                break;

            case ARM922T_L1D_TYPE_CPAGE:
                /* Course page tables, loop through all entries */
                page_table = (UNS_32 *)(tlb_entry &
                    ARM922T_L2D_CP_BASE_MASK);
                for (index2 = 0; index2 < ARM922T_CPT_ENTRIES; index2++)
                {
                    level2 = page_table[index2];
                    if (level2)
                    {
                        virtual_addr = (void *)
                            cp15_decode_level2(level2, addr);

                        if (virtual_addr)
                        {

⌨️ 快捷键说明

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