📄 abl_arm922t_cp15_driver.c
字号:
return virtual_addr;
}
}
break;
}
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 from that base
******************************************************/
if ((tlb_entry & ARM922T_L2D_SN_BASE_MASK)
== (addr & ARM922T_L2D_SN_BASE_MASK))
{
return (void *)((index << 20) |
(addr & ~(ARM922T_L2D_SN_BASE_MASK)));
}
break;
case ARM922T_L1D_TYPE_FPAGE:
/* Fine page tables, loop through entries */
page_table = (UNS_32 *)(tlb_entry &
ARM922T_L2D_FP_BASE_MASK);
for (index2 = 0; index2 < ARM922T_FPT_ENTRIES; index2++)
{
level2 = page_table[index2];
if (level2)
{
virtual_addr = (void *)
cp15_decode_level2(level2, addr);
if (virtual_addr)
{
return virtual_addr;
}
}
}
break;
default:
break;
}
}
return 0;
}
/***********************************************************************
*
* Function: cp15_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 cp15_force_cache_coherence(UNS_32 *start_adr,
UNS_32 *end_adr)
{
register UNS_32 * addr;
/*******************************************************************
* 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. Make sure addresses are 32-bit aligned.
******************************************************************/
for (addr = (UNS_32 *)((UNS_32)start_adr & 0xFFFFFFE0);
addr < end_adr;
addr += 8)
{
/* p15 is MMU coprocessor, Cache OPS is c7, TLB OPS is c8 */
#ifdef __GNUC__
asm ("MOV r0, %0" : : "r" (addr));
/* Clean and Invalidate D-Cache single entry using MVA format */
asm ("MCR p15, 0, r0, c7, c14, 1");
/* Invalidate I-Cache single entry using MVA format */
asm ("MCR p15, 0, r0, c7, c5, 1");
#endif
#ifdef __ghs__
invalcache(addr);
#endif
#ifdef __arm
__asm
{
MOV r0, addr
/* 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
}
#endif
#ifdef __ICCARM__
/* Use IAR intrinsic functions */
__MCR(15, 0, (UNS_32)addr, 7, 14, 1);
__MCR(15, 0, (UNS_32)addr, 7, 5, 1);
#endif
}
/*******************************************************************
* Invalidate the I-TLB within the the address range. The I-TLB has
* 256 word granularity. Make sure addresses are '256 word' aligned.
******************************************************************/
for (addr = (UNS_32 *)((UNS_32)start_adr & 0xFFFFFC00);
addr < end_adr;
addr += 256)
{
#ifdef __GNUC__
asm ("MOV r0, %0" : : "r" (addr));
/* Invalidate I-TLB using MVA format */
asm ("MCR p15, 0, r0, c8, c5, 1");
asm ("NOP");
asm ("NOP");
#endif
#ifdef __ghs__
invaltlb(addr);
#endif
#ifdef __arm
__asm
{
MOV r0, addr
/* Invalidate I-TLB using MVA format */
MCR p15, 0, r0, c8, c5, 1
NOP
NOP
}
#endif
#ifdef __ICCARM__
/* Invalidate I-TLB using MVA format */
/* Use IAR intrinsic functions */
__MCR(15, 0, (UNS_32)addr, 8, 5, 1);
__no_operation();
__no_operation();
#endif
}
}
/***********************************************************************
*
* Function: cp15_init_mmu_trans_table
*
* Purpose: Initializes the MMU page table
*
* Processing:
* Return error if MMU is enabled. Return error if target
* Translation Table address is not 16K aligned. Clear the
* Translation Table area. Build the Translation Table from the
* initialization data in the Section Block array. Return no error.
*
* Parameters:
* tt: address of Translation Table in RAM.
* ttsbp: address of the beginning of the initialization array
*
* Outputs: None.
*
* Returns:
* This function returns _ERROR when the MMU is enabled, or the
* target address is not 16K aligned. Otherwise, it returns
* _NO_ERROR.
*
* Notes:
* This function is not intended to be used when the MMU is
* enabled.
*
**********************************************************************/
BOOL_32 cp15_init_mmu_trans_table(TRANSTABLE_T *tt,
TT_SECTION_BLOCK_T *ttsbp)
{
register UNS_32 control;
UNS_32 idx;
UNS_32 va_idx;
UNS_32 pa_addr;
UNS_32 *uiptr;
UNS_32 ret = _NO_ERROR;
/*******************************************************************
* The following check returns an error if the MMU is enabled.
* This condition is not necessarily an error, but an existing
* Translation Table for an enabled MMU should not be overwritten
* while the MMU is enabled.
******************************************************************/
/* Read the control register */
#ifdef __GNUC__
asm ("MRC p15, 0, %0, c1, c0, 0" : "=r" (control));
#endif
#ifdef __ghs__
control = getstatus ();
#endif
#ifdef __arm
__asm
{
MRC p15, 0, control, c1, c0, 0;
}
#endif
#ifdef __ICCARM__
/* Use IAR intrinsic functions */
control = __MRC(15, 0, 1, 0, 0);
#endif
/* Exit if MMU is already enabeld */
if ((control & ARM922T_MMU_CONTROL_M) != 0)
{
return (_ERROR);
}
/* Make sure table address is on a 16K boundary */
if (((INT_32) tt & ~(ARM922T_TT_ADDR_MASK)) != 0)
{
return (_ERROR);
}
/*******************************************************************
* Clear the entire Translation Table.
* This results in L1D_TYPE_FAULT being the default for any
* uninitialized entries.
******************************************************************/
uiptr = (UNS_32 *) tt;
for (idx = 0; idx < ARM922T_TT_ENTRIES; idx++)
*uiptr++ = ARM922T_L1D_TYPE_FAULT;
/* Build the translation table from user provided
TT_SECTION_BLOCK_TYPE array */
while (ttsbp->num_sections != 0)
{
switch ((ttsbp->entry) & ARM922T_L1D_TYPE_PG_SN_MASK)
{
case ARM922T_L1D_TYPE_SECTION:
va_idx = ttsbp->virt_addr >> 20;
pa_addr = ttsbp->phys_addr & ARM922T_L2D_SN_BASE_MASK;
for (idx = 0; idx < ttsbp->num_sections; idx++)
{
tt->vidx[va_idx] = (pa_addr | ttsbp->entry);
va_idx++;
pa_addr += 0x100000;
}
break;
case (ARM922T_L1D_TYPE_CPAGE):
va_idx = ttsbp->virt_addr >> 20;
pa_addr = ttsbp->phys_addr & ARM922T_L2D_CP_BASE_MASK;
for (idx = 0; idx < ttsbp->num_sections; idx++)
{
tt->vidx[va_idx] = pa_addr | ttsbp->entry;
va_idx++;
pa_addr += 0x100000;
}
break;
case ARM922T_L1D_TYPE_FAULT:
default:
break;
}
ttsbp++;
}
return ret;
}
/***********************************************************************
*
* Function: cp15_set_vmmu_addr
*
* Purpose: Set the virtual address of the MMU table
*
* Processing:
* Set the saved virtual MMU table address to the passed value.
*
* Parameters:
* addr: Virtual address of start of MMU table
*
* Outputs: None.
*
* Returns: Nothing
*
* Notes:
* This function must be called if the driver MMU functions are
* being used. This should be set after the call to the
* cp15_init_mmu_trans_table() function.
*
**********************************************************************/
void cp15_set_vmmu_addr(UNS_32 *addr)
{
virtual_tlb_addr = addr;
}
/***********************************************************************
*
* Function: cp15_get_ttb
*
* Purpose: Return the physical address of the MMU translation table
*
* Processing:
* Read the TTB register from coprocessor 15 and return it to the
* caller.
*
* Parameters: None
*
* Outputs: None.
*
* Returns: The base address of the MMU translation table
*
* Notes: None
*
**********************************************************************/
UNS_32 *cp15_get_ttb(void)
{
register UNS_32 ttb;
#ifdef __GNUC__
asm ("MRC p15, 0, %0, c2, c0, 0" : "=r" (ttb));
#endif
#ifdef __ghs__
ttb = getttb();
#endif
#ifdef __arm
__asm
{
MRC p15, 0, ttb, c2, c0, 0;
}
#endif
#ifdef __ICCARM__
/* use IAR CC intrinsic function to read CP15 reg */
ttb = __MRC(15, 0, 2, 0, 0);
#endif
return (UNS_32 *) ttb;
}
/***********************************************************************
*
* Function: cp15_dcache_flush
*
* Purpose: Force an data cache flush
*
* Processing:
* Flush each data cache entry using the segment/index method.
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
**********************************************************************/
void cp15_dcache_flush(void)
{
#ifdef __GNUC__
#endif
#ifdef __ghs__
#endif
#ifdef __arm
INT_32 segment, index, comp, cache_sz, total_seg;
__asm
{
MRC p15, 0, cache_sz, c0, c0, 1
}
/* For 8KB cache the size field is 4 and for 16 it is 5.
*/
total_seg = (1 << (ARM922T_MMU_DC_SIZE(cache_sz) - 2));
for (segment = 0; segment < total_seg; segment++)
{
for (index = 0; index < 64; index++)
{
/* For each segment and index, flush the data cache */
comp = (segment << 5) | (index << 26);
__asm
{
MCR p15, 0, comp, c8, c5, 1
}
}
}
#endif
#ifdef __ICCARM__
#endif
}
/***********************************************************************
*
* Function: cp15_write_buffer_flush
*
* Purpose: Force an write buffer flush
*
* Processing:
* Flush the write buffer and wait for completion of the flush.
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
**********************************************************************/
void cp15_write_buffer_flush(void)
{
#ifdef __GNUC__
#endif
#ifdef __ghs__
#endif
#ifdef __arm
__asm
{
MOV r0, #0
MCR p15, 0, r0, c7, c10, 4
}
#endif
#ifdef __ICCARM__
#endif
}
/***********************************************************************
*
* Function: cp15_mmu_enabled
*
* Purpose:
* Checks to see if the MMU is enabled
*
* Processing:
* Read the MMU control register and check if the MMU enable bit
* (bit 0) is set.
*
* Parameters: None
*
* Outputs: None
*
* Returns:
* TRUE if the MMU is enabled
* FALSE if the MMU is disabled
*
* Notes: None
*
**********************************************************************/
BOOL_32 cp15_mmu_enabled(void)
{
UNS_32 mmu_reg;
#ifdef __GNUC__
asm ("MRC p15, 0, %0, c1, c0, 0" : "=r" (mmu_reg));
#endif
#ifdef __ghs__
mmu_reg = getstatus ();
#endif
#ifdef __arm
__asm
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -