armv7对应的CACHE操作相关文件解析

来源:互联网 发布:js combox获取选中值 编辑:程序博客网 时间:2024/06/07 04:37

最近在使用TI的DRA726芯片。A15端需要访问图像,而图像是在外设空间的,用DMA拷贝到CACHE空间。

这样就导致了DMA的CACHE一致性的问题,需要在DMA之后清除所使用图像空间的数据CACHE。

以这个A15核心为例,解析一下ARM的CACHE操作,涉及的文件有:cacheflush.h   cache-v7.S  proc-macros.S  proc-v7.S

内存是OS中非常厉害,非常复杂的一套系统,科学严谨,每一部分都需要研究几本书才能够彻底明白。

CACHE最基本的就是加速原理,依据就是程序的局部性原理。

CACHE实际实施起来,细节就非常复杂了,比如启动的过程中,如何建立CACHE,从直接访问内存到CACHE访问等等具体问题。

这次主要就项目中的CACHE一致性问题,借机会给组员们一起分享了。

/* *  arch/arm/include/asm/cacheflush.h * *  Copyright (C) 1999-2002 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#ifndef _ASMARM_CACHEFLUSH_H#define _ASMARM_CACHEFLUSH_H#include <linux/mm.h>#include <asm/glue-cache.h>#include <asm/shmparam.h>#include <asm/cachetype.h>#include <asm/outercache.h>#define CACHE_COLOUR(vaddr)((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)/* * This flag is used to indicate that the page pointed to by a pte is clean * and does not require cleaning before returning it to the user. */#define PG_dcache_clean PG_arch_1/* *MM Cache Management *=================== * *The arch/arm/mm/cache-*.S and arch/arm/mm/proc-*.S files *implement these methods. * *Start addresses are inclusive and end addresses are exclusive; *start addresses should be rounded down, end addresses up. * *See Documentation/cachetlb.txt for more information. *Please note that the implementation of these, and the required *effects are cache-type (VIVT/VIPT/PIPT) specific. * *flush_icache_all() * *Unconditionally clean and invalidate the entire icache. *Currently only needed for cache-v6.S and cache-v7.S, see *__flush_icache_all for the generic implementation. * *flush_kern_all() * *Unconditionally clean and invalidate the entire cache. * *     flush_kern_louis() * *             Flush data cache levels up to the level of unification *             inner shareable and invalidate the I-cache. *             Only needed from v7 onwards, falls back to flush_cache_all() *             for all other processor versions. * *flush_user_all() * *Clean and invalidate all user space cache entries *before a change of page tables. * *flush_user_range(start, end, flags) * *Clean and invalidate a range of cache entries in the *specified address space before a change of page tables. *- start - user start address (inclusive, page aligned) *- end   - user end address   (exclusive, page aligned) *- flags - vma->vm_flags field * *coherent_kern_range(start, end) * *Ensure coherency between the Icache and the Dcache in the *region described by start, end.  If you have non-snooping *Harvard caches, you need to implement this function. *- start  - virtual start address *- end    - virtual end address * *coherent_user_range(start, end) * *Ensure coherency between the Icache and the Dcache in the *region described by start, end.  If you have non-snooping *Harvard caches, you need to implement this function. *- start  - virtual start address *- end    - virtual end address * *flush_kern_dcache_area(kaddr, size) * *Ensure that the data held in page is written back. *- kaddr  - page address *- size   - region size * *DMA Cache Coherency *=================== * *dma_flush_range(start, end) * *Clean and invalidate the specified virtual address range. *- start  - virtual start address *- end    - virtual end address */struct cpu_cache_fns {void (*flush_icache_all)(void);void (*flush_kern_all)(void);void (*flush_kern_louis)(void);void (*flush_user_all)(void);void (*flush_user_range)(unsigned long, unsigned long, unsigned int);void (*coherent_kern_range)(unsigned long, unsigned long);int  (*coherent_user_range)(unsigned long, unsigned long);void (*flush_kern_dcache_area)(void *, size_t);void (*dma_map_area)(const void *, size_t, int);void (*dma_unmap_area)(const void *, size_t, int);void (*dma_flush_range)(const void *, const void *);};/* * Select the calling method */#ifdef MULTI_CACHEextern struct cpu_cache_fns cpu_cache;#define __cpuc_flush_icache_allcpu_cache.flush_icache_all#define __cpuc_flush_kern_allcpu_cache.flush_kern_all#define __cpuc_flush_kern_louiscpu_cache.flush_kern_louis#define __cpuc_flush_user_allcpu_cache.flush_user_all#define __cpuc_flush_user_rangecpu_cache.flush_user_range#define __cpuc_coherent_kern_rangecpu_cache.coherent_kern_range#define __cpuc_coherent_user_rangecpu_cache.coherent_user_range#define __cpuc_flush_dcache_areacpu_cache.flush_kern_dcache_area/* * These are private to the dma-mapping API.  Do not use directly. * Their sole purpose is to ensure that data held in the cache * is visible to DMA, or data written by DMA to system memory is * visible to the CPU. */#define dmac_map_areacpu_cache.dma_map_area#define dmac_unmap_areacpu_cache.dma_unmap_area#define dmac_flush_rangecpu_cache.dma_flush_range#elseextern void __cpuc_flush_icache_all(void);extern void __cpuc_flush_kern_all(void);extern void __cpuc_flush_kern_louis(void);extern void __cpuc_flush_user_all(void);extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int);extern void __cpuc_coherent_kern_range(unsigned long, unsigned long);extern int  __cpuc_coherent_user_range(unsigned long, unsigned long);extern void __cpuc_flush_dcache_area(void *, size_t);/* * These are private to the dma-mapping API.  Do not use directly. * Their sole purpose is to ensure that data held in the cache * is visible to DMA, or data written by DMA to system memory is * visible to the CPU. */extern void dmac_map_area(const void *, size_t, int);extern void dmac_unmap_area(const void *, size_t, int);extern void dmac_flush_range(const void *, const void *);#endif/* * Copy user data from/to a page which is mapped into a different * processes address space.  Really, we want to allow our "user * space" model to handle this. */extern void copy_to_user_page(struct vm_area_struct *, struct page *,unsigned long, void *, const void *, unsigned long);#define copy_from_user_page(vma, page, vaddr, dst, src, len) \do {\memcpy(dst, src, len);\} while (0)/* * Convert calls to our calling convention. *//* Invalidate I-cache */#define __flush_icache_all_generic()\asm("mcrp15, 0, %0, c7, c5, 0"\    : : "r" (0));/* Invalidate I-cache inner shareable */#define __flush_icache_all_v7_smp()\asm("mcrp15, 0, %0, c7, c1, 0"\    : : "r" (0));/* * Optimized __flush_icache_all for the common cases. Note that UP ARMv7 * will fall through to use __flush_icache_all_generic. */#if (defined(CONFIG_CPU_V7) && \     (defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K))) || \defined(CONFIG_SMP_ON_UP)#define __flush_icache_preferred__cpuc_flush_icache_all#elif __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)#define __flush_icache_preferred__flush_icache_all_v7_smp#elif __LINUX_ARM_ARCH__ == 6 && defined(CONFIG_ARM_ERRATA_411920)#define __flush_icache_preferred__cpuc_flush_icache_all#else#define __flush_icache_preferred__flush_icache_all_generic#endifstatic inline void __flush_icache_all(void){__flush_icache_preferred();dsb();}/* * Flush caches up to Level of Unification Inner Shareable */#define flush_cache_louis()__cpuc_flush_kern_louis()#define flush_cache_all()__cpuc_flush_kern_all()static inline void vivt_flush_cache_mm(struct mm_struct *mm){if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm)))__cpuc_flush_user_all();}static inline voidvivt_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end){struct mm_struct *mm = vma->vm_mm;if (!mm || cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm)))__cpuc_flush_user_range(start & PAGE_MASK, PAGE_ALIGN(end),vma->vm_flags);}static inline voidvivt_flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn){struct mm_struct *mm = vma->vm_mm;if (!mm || cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm))) {unsigned long addr = user_addr & PAGE_MASK;__cpuc_flush_user_range(addr, addr + PAGE_SIZE, vma->vm_flags);}}#ifndef CONFIG_CPU_CACHE_VIPT#define flush_cache_mm(mm) \vivt_flush_cache_mm(mm)#define flush_cache_range(vma,start,end) \vivt_flush_cache_range(vma,start,end)#define flush_cache_page(vma,addr,pfn) \vivt_flush_cache_page(vma,addr,pfn)#elseextern void flush_cache_mm(struct mm_struct *mm);extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn);#endif#define flush_cache_dup_mm(mm) flush_cache_mm(mm)/* * flush_cache_user_range is used when we want to ensure that the * Harvard caches are synchronised for the user space address range. * This is used for the ARM private sys_cacheflush system call. */#define flush_cache_user_range(s,e)__cpuc_coherent_user_range(s,e)/* * Perform necessary cache operations to ensure that data previously * stored within this range of addresses can be executed by the CPU. */#define flush_icache_range(s,e)__cpuc_coherent_kern_range(s,e)/* * Perform necessary cache operations to ensure that the TLB will * see data written in the specified area. */#define clean_dcache_area(start,size)cpu_dcache_clean_area(start, size)/* * flush_dcache_page is used when the kernel has written to the page * cache page at virtual address page->virtual. * * If this page isn't mapped (ie, page_mapping == NULL), or it might * have userspace mappings, then we _must_ always clean + invalidate * the dcache entries associated with the kernel mapping. * * Otherwise we can defer the operation, and clean the cache when we are * about to change to user space.  This is the same method as used on SPARC64. * See update_mmu_cache for the user space part. */#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1extern void flush_dcache_page(struct page *);static inline void flush_kernel_vmap_range(void *addr, int size){if ((cache_is_vivt() || cache_is_vipt_aliasing()))  __cpuc_flush_dcache_area(addr, (size_t)size);}static inline void invalidate_kernel_vmap_range(void *addr, int size){if ((cache_is_vivt() || cache_is_vipt_aliasing()))  __cpuc_flush_dcache_area(addr, (size_t)size);}#define ARCH_HAS_FLUSH_ANON_PAGEstatic inline void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr){extern void __flush_anon_page(struct vm_area_struct *vma,struct page *, unsigned long);if (PageAnon(page))__flush_anon_page(vma, page, vmaddr);}#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGEextern void flush_kernel_dcache_page(struct page *);#define flush_dcache_mmap_lock(mapping) \spin_lock_irq(&(mapping)->tree_lock)#define flush_dcache_mmap_unlock(mapping) \spin_unlock_irq(&(mapping)->tree_lock)#define flush_icache_user_range(vma,page,addr,len) \flush_dcache_page(page)/* * We don't appear to need to do anything here.  In fact, if we did, we'd * duplicate cache flushing elsewhere performed by flush_dcache_page(). */#define flush_icache_page(vma,page)do { } while (0)/* * flush_cache_vmap() is used when creating mappings (eg, via vmap, * vmalloc, ioremap etc) in kernel space for pages.  On non-VIPT * caches, since the direct-mappings of these pages may contain cached * data, we need to do a full cache flush to ensure that writebacks * don't corrupt data placed into these pages via the new mappings. */static inline void flush_cache_vmap(unsigned long start, unsigned long end){if (!cache_is_vipt_nonaliasing())flush_cache_all();else/* * set_pte_at() called from vmap_pte_range() does not * have a DSB after cleaning the cache line. */dsb(ishst);}static inline void flush_cache_vunmap(unsigned long start, unsigned long end){if (!cache_is_vipt_nonaliasing())flush_cache_all();}/* * Memory synchronization helpers for mixed cached vs non cached accesses. * * Some synchronization algorithms have to set states in memory with the * cache enabled or disabled depending on the code path.  It is crucial * to always ensure proper cache maintenance to update main memory right * away in that case. * * Any cached write must be followed by a cache clean operation. * Any cached read must be preceded by a cache invalidate operation. * Yet, in the read case, a cache flush i.e. atomic clean+invalidate * operation is needed to avoid discarding possible concurrent writes to the * accessed memory. * * Also, in order to prevent a cached writer from interfering with an * adjacent non-cached writer, each state variable must be located to * a separate cache line. *//* * This needs to be >= the max cache writeback size of all * supported platforms included in the current kernel configuration. * This is used to align state variables to their own cache lines. */#define __CACHE_WRITEBACK_ORDER 6  /* guessed from existing platforms */#define __CACHE_WRITEBACK_GRANULE (1 << __CACHE_WRITEBACK_ORDER)/* * There is no __cpuc_clean_dcache_area but we use it anyway for * code intent clarity, and alias it to __cpuc_flush_dcache_area. */#define __cpuc_clean_dcache_area __cpuc_flush_dcache_area/* * Ensure preceding writes to *p by this CPU are visible to * subsequent reads by other CPUs: */static inline void __sync_cache_range_w(volatile void *p, size_t size){char *_p = (char *)p;__cpuc_clean_dcache_area(_p, size);outer_clean_range(__pa(_p), __pa(_p + size));}/* * Ensure preceding writes to *p by other CPUs are visible to * subsequent reads by this CPU.  We must be careful not to * discard data simultaneously written by another CPU, hence the * usage of flush rather than invalidate operations. */static inline void __sync_cache_range_r(volatile void *p, size_t size){char *_p = (char *)p;#ifdef CONFIG_OUTER_CACHEif (outer_cache.flush_range) {/* * Ensure dirty data migrated from other CPUs into our cache * are cleaned out safely before the outer cache is cleaned: */__cpuc_clean_dcache_area(_p, size);/* Clean and invalidate stale data for *p from outer ... */outer_flush_range(__pa(_p), __pa(_p + size));}#endif/* ... and inner cache: */__cpuc_flush_dcache_area(_p, size);}#define sync_cache_w(ptr) __sync_cache_range_w(ptr, sizeof *(ptr))#define sync_cache_r(ptr) __sync_cache_range_r(ptr, sizeof *(ptr))/* * Disabling cache access for one CPU in an ARMv7 SMP system is tricky. * To do so we must: * * - Clear the SCTLR.C bit to prevent further cache allocations * - Flush the desired level of cache * - Clear the ACTLR "SMP" bit to disable local coherency * * ... and so without any intervening memory access in between those steps, * not even to the stack. * * WARNING -- After this has been called: * * - No ldrex/strex (and similar) instructions must be used. * - The CPU is obviously no longer coherent with the other CPUs. * - This is unlikely to work as expected if Linux is running non-secure. * * Note: * * - This is known to apply to several ARMv7 processor implementations, *   however some exceptions may exist.  Caveat emptor. * * - The clobber list is dictated by the call to v7_flush_dcache_*. *   fp is preserved to the stack explicitly prior disabling the cache *   since adding it to the clobber list is incompatible with having *   CONFIG_FRAME_POINTER=y.  ip is saved as well if ever r12-clobbering *   trampoline are inserted by the linker and to keep sp 64-bit aligned. */#define v7_exit_coherency_flush(level) \asm volatile( \"stmfdsp!, {fp, ip} \n\t" \"mrcp15, 0, r0, c1, c0, 0@ get SCTLR \n\t" \"bicr0, r0, #"__stringify(CR_C)" \n\t" \"mcrp15, 0, r0, c1, c0, 0@ set SCTLR \n\t" \"isb\n\t" \"blv7_flush_dcache_"__stringify(level)" \n\t" \"clrex\n\t" \"mrcp15, 0, r0, c1, c0, 1@ get ACTLR \n\t" \"bicr0, r0, #(1 << 6)@ disable local coherency \n\t" \"mcrp15, 0, r0, c1, c0, 1@ set ACTLR \n\t" \"isb\n\t" \"dsb\n\t" \"ldmfdsp!, {fp, ip}" \: : : "r0","r1","r2","r3","r4","r5","r6","r7", \      "r9","r10","lr","memory" )int set_memory_ro(unsigned long addr, int numpages);int set_memory_rw(unsigned long addr, int numpages);int set_memory_x(unsigned long addr, int numpages);int set_memory_nx(unsigned long addr, int numpages);#endif

/* *  linux/arch/arm/mm/cache-v7.S * *  Copyright (C) 2001 Deep Blue Solutions Ltd. *  Copyright (C) 2005 ARM Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * *  This is the "shell" of the ARMv7 processor support. */#include <linux/linkage.h>#include <linux/init.h>#include <asm/assembler.h>#include <asm/errno.h>#include <asm/unwind.h>#include "proc-macros.S"/* * The secondary kernel init calls v7_flush_dcache_all before it enables * the L1; however, the L1 comes out of reset in an undefined state, so * the clean + invalidate performed by v7_flush_dcache_all causes a bunch * of cache lines with uninitialized data and uninitialized tags to get * written out to memory, which does really unpleasant things to the main * processor.  We fix this by performing an invalidate, rather than a * clean + invalidate, before jumping into the kernel. * * This function is cloned from arch/arm/mach-tegra/headsmp.S, and needs * to be called for both secondary cores startup and primary core resume * procedures. */ENTRY(v7_invalidate_l1)       mov     r0, #0       mcr     p15, 2, r0, c0, c0, 0       mrc     p15, 1, r0, c0, c0, 0       ldr     r1, =0x7fff       and     r2, r1, r0, lsr #13       ldr     r1, =0x3ff       and     r3, r1, r0, lsr #3      @ NumWays - 1       add     r2, r2, #1              @ NumSets       and     r0, r0, #0x7       add     r0, r0, #4      @ SetShift       clz     r1, r3          @ WayShift       add     r4, r3, #1      @ NumWays1:     sub     r2, r2, #1      @ NumSets--       mov     r3, r4          @ Temp = NumWays2:     subs    r3, r3, #1      @ Temp--       mov     r5, r3, lsl r1       mov     r6, r2, lsl r0       orr     r5, r5, r6      @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)       mcr     p15, 0, r5, c7, c6, 2       bgt     2b       cmp     r2, #0       bgt     1b       dsb       isb       mov     pc, lrENDPROC(v7_invalidate_l1)/* *v7_flush_icache_all() * *Flush the whole I-cache. * *Registers: *r0 - set to 0 */ENTRY(v7_flush_icache_all)movr0, #0ALT_SMP(mcrp15, 0, r0, c7, c1, 0)@ invalidate I-cache inner shareableALT_UP(mcrp15, 0, r0, c7, c5, 0)@ I+BTB cache invalidatemovpc, lrENDPROC(v7_flush_icache_all) /* *     v7_flush_dcache_louis() * *     Flush the D-cache up to the Level of Unification Inner Shareable * *     Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode) */ENTRY(v7_flush_dcache_louis)dmb@ ensure ordering with previous memory accessesmrcp15, 1, r0, c0, c0, 1@ read clidr, r0 = clidrALT_SMP(andsr3, r0, #(7 << 21))@ extract LoUIS from clidrALT_UP(andsr3, r0, #(7 << 27))@ extract LoUU from clidr#ifdef CONFIG_ARM_ERRATA_643719ALT_SMP(mrceqp15, 0, r2, c0, c0, 0)@ read main ID registerALT_UP(moveqpc, lr)@ LoUU is zero, so nothing to doldreqr1, =0x410fc090                 @ ID of ARM Cortex A9 r0p?biceqr2, r2, #0x0000000f             @ clear minor revision numberteqeqr2, r1                          @ test for errata affected core and if so...orreqsr3, #(1 << 21)@   fix LoUIS value (and set flags state to 'ne')#endifALT_SMP(movr3, r3, lsr #20)@ r3 = LoUIS * 2ALT_UP(movr3, r3, lsr #26)@ r3 = LoUU * 2moveqpc, lr@ return if level == 0movr10, #0@ r10 (starting level) = 0bflush_levels@ start flushing cache levelsENDPROC(v7_flush_dcache_louis)/* *v7_flush_dcache_all() * *Flush the whole D-cache. * *Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode) * *- mm    - mm_struct describing address space */ENTRY(v7_flush_dcache_all)dmb@ ensure ordering with previous memory accessesmrcp15, 1, r0, c0, c0, 1@ read clidrandsr3, r0, #0x7000000@ extract loc from clidrmovr3, r3, lsr #23@ left align loc bit fieldbeqfinished@ if loc is 0, then no need to cleanmovr10, #0@ start clean at cache level 0flush_levels:addr2, r10, r10, lsr #1@ work out 3x current cache levelmovr1, r0, lsr r2@ extract cache type bits from clidrandr1, r1, #7@ mask of the bits for current cache onlycmpr1, #2@ see what cache we have at this levelbltskip@ skip if no cache, or just i-cache#ifdef CONFIG_PREEMPTsave_and_disable_irqs_notrace r9@ make cssr&csidr read atomic#endifmcrp15, 2, r10, c0, c0, 0@ select current cache level in cssrisb@ isb to sych the new cssr&csidrmrcp15, 1, r1, c0, c0, 0@ read the new csidr#ifdef CONFIG_PREEMPTrestore_irqs_notrace r9#endifandr2, r1, #7@ extract the length of the cache linesaddr2, r2, #4@ add 4 (line length offset)ldrr4, =0x3ffandsr4, r4, r1, lsr #3@ find maximum number on the way sizeclzr5, r4@ find bit position of way size incrementldrr7, =0x7fffandsr7, r7, r1, lsr #13@ extract max number of the index sizeloop1:movr9, r7@ create working copy of max indexloop2: ARM(orrr11, r10, r4, lsl r5)@ factor way and cache number into r11 THUMB(lslr6, r4, r5) THUMB(orrr11, r10, r6)@ factor way and cache number into r11 ARM(orrr11, r11, r9, lsl r2)@ factor index number into r11 THUMB(lslr6, r9, r2) THUMB(orrr11, r11, r6)@ factor index number into r11mcrp15, 0, r11, c7, c14, 2@ clean & invalidate by set/waysubsr9, r9, #1@ decrement the indexbgeloop2subsr4, r4, #1@ decrement the waybgeloop1skip:addr10, r10, #2@ increment cache numbercmpr3, r10bgtflush_levelsfinished:movr10, #0@ swith back to cache level 0mcrp15, 2, r10, c0, c0, 0@ select current cache level in cssrdsbisbmovpc, lrENDPROC(v7_flush_dcache_all)/* *v7_flush_cache_all() * *Flush the entire cache system. *  The data cache flush is now achieved using atomic clean / invalidates *  working outwards from L1 cache. This is done using Set/Way based cache *  maintenance instructions. *  The instruction cache can still be invalidated back to the point of *  unification in a single instruction. * */ENTRY(v7_flush_kern_cache_all) ARM(stmfdsp!, {r4-r5, r7, r9-r11, lr}) THUMB(stmfdsp!, {r4-r7, r9-r11, lr})blv7_flush_dcache_allmovr0, #0ALT_SMP(mcrp15, 0, r0, c7, c1, 0)@ invalidate I-cache inner shareableALT_UP(mcrp15, 0, r0, c7, c5, 0)@ I+BTB cache invalidate ARM(ldmfdsp!, {r4-r5, r7, r9-r11, lr}) THUMB(ldmfdsp!, {r4-r7, r9-r11, lr})movpc, lrENDPROC(v7_flush_kern_cache_all) /* *     v7_flush_kern_cache_louis(void) * *     Flush the data cache up to Level of Unification Inner Shareable. *     Invalidate the I-cache to the point of unification. */ENTRY(v7_flush_kern_cache_louis) ARM(stmfdsp!, {r4-r5, r7, r9-r11, lr}) THUMB(stmfdsp!, {r4-r7, r9-r11, lr})blv7_flush_dcache_louismovr0, #0ALT_SMP(mcrp15, 0, r0, c7, c1, 0)@ invalidate I-cache inner shareableALT_UP(mcrp15, 0, r0, c7, c5, 0)@ I+BTB cache invalidate ARM(ldmfdsp!, {r4-r5, r7, r9-r11, lr}) THUMB(ldmfdsp!, {r4-r7, r9-r11, lr})movpc, lrENDPROC(v7_flush_kern_cache_louis)/* *v7_flush_cache_all() * *Flush all TLB entries in a particular address space * *- mm    - mm_struct describing address space */ENTRY(v7_flush_user_cache_all)/*FALLTHROUGH*//* *v7_flush_cache_range(start, end, flags) * *Flush a range of TLB entries in the specified address space. * *- start - start address (may not be aligned) *- end   - end address (exclusive, may not be aligned) *- flags- vm_area_struct flags describing address space * *It is assumed that: *- we have a VIPT cache. */ENTRY(v7_flush_user_cache_range)movpc, lrENDPROC(v7_flush_user_cache_all)ENDPROC(v7_flush_user_cache_range)/* *v7_coherent_kern_range(start,end) * *Ensure that the I and D caches are coherent within specified *region.  This is typically used when code has been written to *a memory region, and will be executed. * *- start   - virtual start address of region *- end     - virtual end address of region * *It is assumed that: *- the Icache does not read data from the write buffer */ENTRY(v7_coherent_kern_range)/* FALLTHROUGH *//* *v7_coherent_user_range(start,end) * *Ensure that the I and D caches are coherent within specified *region.  This is typically used when code has been written to *a memory region, and will be executed. * *- start   - virtual start address of region *- end     - virtual end address of region * *It is assumed that: *- the Icache does not read data from the write buffer */ENTRY(v7_coherent_user_range) UNWIND(.fnstart)dcache_line_size r2, r3subr3, r2, #1bicr12, r0, r3#ifdef CONFIG_ARM_ERRATA_764369ALT_SMP(W(dsb))ALT_UP(W(nop))#endif1: USER(mcrp15, 0, r12, c7, c11, 1)@ clean D line to the point of unificationaddr12, r12, r2cmpr12, r1blo1bdsbishsticache_line_size r2, r3subr3, r2, #1bicr12, r0, r32: USER(mcrp15, 0, r12, c7, c5, 1)@ invalidate I lineaddr12, r12, r2cmpr12, r1blo2bmovr0, #0ALT_SMP(mcrp15, 0, r0, c7, c1, 6)@ invalidate BTB Inner ShareableALT_UP(mcrp15, 0, r0, c7, c5, 6)@ invalidate BTBdsbishstisbmovpc, lr/* * Fault handling for the cache operation above. If the virtual address in r0 * isn't mapped, fail with -EFAULT. */9001:#ifdef CONFIG_ARM_ERRATA_775420dsb#endifmovr0, #-EFAULTmovpc, lr UNWIND(.fnend)ENDPROC(v7_coherent_kern_range)ENDPROC(v7_coherent_user_range)/* *v7_flush_kern_dcache_area(void *addr, size_t size) * *Ensure that the data held in the page kaddr is written back *to the page in question. * *- addr- kernel address *- size- region size */ENTRY(v7_flush_kern_dcache_area)dcache_line_size r2, r3addr1, r0, r1subr3, r2, #1bicr0, r0, r3#ifdef CONFIG_ARM_ERRATA_764369ALT_SMP(W(dsb))ALT_UP(W(nop))#endif1:mcrp15, 0, r0, c7, c14, 1@ clean & invalidate D line / unified lineaddr0, r0, r2cmpr0, r1blo1bdsbmovpc, lrENDPROC(v7_flush_kern_dcache_area)/* *v7_dma_inv_range(start,end) * *Invalidate the data cache within the specified region; we will *be performing a DMA operation in this region and we want to *purge old data in the cache. * *- start   - virtual start address of region *- end     - virtual end address of region */v7_dma_inv_range:dcache_line_size r2, r3subr3, r2, #1tstr0, r3bicr0, r0, r3#ifdef CONFIG_ARM_ERRATA_764369ALT_SMP(W(dsb))ALT_UP(W(nop))#endifmcrnep15, 0, r0, c7, c14, 1@ clean & invalidate D / U linetstr1, r3bicr1, r1, r3mcrnep15, 0, r1, c7, c14, 1@ clean & invalidate D / U line1:mcrp15, 0, r0, c7, c6, 1@ invalidate D / U lineaddr0, r0, r2cmpr0, r1blo1bdsbmovpc, lrENDPROC(v7_dma_inv_range)/* *v7_dma_clean_range(start,end) *- start   - virtual start address of region *- end     - virtual end address of region */v7_dma_clean_range:dcache_line_size r2, r3subr3, r2, #1bicr0, r0, r3#ifdef CONFIG_ARM_ERRATA_764369ALT_SMP(W(dsb))ALT_UP(W(nop))#endif1:mcrp15, 0, r0, c7, c10, 1@ clean D / U lineaddr0, r0, r2cmpr0, r1blo1bdsbmovpc, lrENDPROC(v7_dma_clean_range)/* *v7_dma_flush_range(start,end) *- start   - virtual start address of region *- end     - virtual end address of region */ENTRY(v7_dma_flush_range)dcache_line_size r2, r3subr3, r2, #1bicr0, r0, r3#ifdef CONFIG_ARM_ERRATA_764369ALT_SMP(W(dsb))ALT_UP(W(nop))#endif1:mcrp15, 0, r0, c7, c14, 1@ clean & invalidate D / U lineaddr0, r0, r2cmpr0, r1blo1bdsbmovpc, lrENDPROC(v7_dma_flush_range)/* *dma_map_area(start, size, dir) *- start- kernel virtual start address *- size- size of region *- dir- DMA direction */ENTRY(v7_dma_map_area)addr1, r1, r0teqr2, #DMA_FROM_DEVICEbeqv7_dma_inv_rangebv7_dma_clean_rangeENDPROC(v7_dma_map_area)/* *dma_unmap_area(start, size, dir) *- start- kernel virtual start address *- size- size of region *- dir- DMA direction */ENTRY(v7_dma_unmap_area)addr1, r1, r0teqr2, #DMA_TO_DEVICEbnev7_dma_inv_rangemovpc, lrENDPROC(v7_dma_unmap_area)__INITDATA@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)define_cache_functions v7

/* * We need constants.h for: *  VMA_VM_MM *  VMA_VM_FLAGS *  VM_EXEC */#include <asm/asm-offsets.h>#include <asm/thread_info.h>/* * vma_vm_mm - get mm pointer from vma pointer (vma->vm_mm) */.macrovma_vm_mm, rd, rnldr\rd, [\rn, #VMA_VM_MM].endm/* * vma_vm_flags - get vma->vm_flags */.macrovma_vm_flags, rd, rnldr\rd, [\rn, #VMA_VM_FLAGS].endm.macrotsk_mm, rd, rnldr\rd, [\rn, #TI_TASK]ldr\rd, [\rd, #TSK_ACTIVE_MM].endm/* * act_mm - get current->active_mm */.macroact_mm, rdbic\rd, sp, #8128bic\rd, \rd, #63ldr\rd, [\rd, #TI_TASK]ldr\rd, [\rd, #TSK_ACTIVE_MM].endm/* * mmid - get context id from mm pointer (mm->context.id) * note, this field is 64bit, so in big-endian the two words are swapped too. */.macrommid, rd, rn#ifdef __ARMEB__ldr\rd, [\rn, #MM_CONTEXT_ID + 4 ]#elseldr\rd, [\rn, #MM_CONTEXT_ID]#endif.endm/* * mask_asid - mask the ASID from the context ID */.macroasid, rd, rnand\rd, \rn, #255.endm.macrocrval, clear, mmuset, ucset#ifdef CONFIG_MMU.word\clear.word\mmuset#else.word\clear.word\ucset#endif.endm/* * dcache_line_size - get the minimum D-cache line size from the CTR register * on ARMv7. */.macrodcache_line_size, reg, tmpmrcp15, 0, \tmp, c0, c0, 1@ read ctrlsr\tmp, \tmp, #16and\tmp, \tmp, #0xf@ cache line size encodingmov\reg, #4@ bytes per wordmov\reg, \reg, lsl \tmp@ actual cache line size.endm/* * icache_line_size - get the minimum I-cache line size from the CTR register * on ARMv7. */.macroicache_line_size, reg, tmpmrcp15, 0, \tmp, c0, c0, 1@ read ctrand\tmp, \tmp, #0xf@ cache line size encodingmov\reg, #4@ bytes per wordmov\reg, \reg, lsl \tmp@ actual cache line size.endm/* * Sanity check the PTE configuration for the code below - which makes * certain assumptions about how these bits are laid out. */#ifdef CONFIG_MMU#if L_PTE_SHARED != PTE_EXT_SHARED#error PTE shared bit mismatch#endif#if !defined (CONFIG_ARM_LPAE) && \(L_PTE_XN+L_PTE_USER+L_PTE_RDONLY+L_PTE_DIRTY+L_PTE_YOUNG+\ L_PTE_FILE+L_PTE_PRESENT) > L_PTE_SHARED#error Invalid Linux PTE bit settings#endif#endif/* CONFIG_MMU *//* * The ARMv6 and ARMv7 set_pte_ext translation function. * * Permission translation: *  YUWD  APX AP1 AP0SVCUser *  0xxx   0   0   0no accno acc *  100x   1   0   1r/ono acc *  10x0   1   0   1r/ono acc *  1011   0   0   1r/wno acc *  110x   1   1   1r/or/o *  11x0   1   1   1r/or/o *  1111   0   1   1r/wr/w */.macroarmv6_mt_table pfx\pfx\()_mt_table:.long0x00@ L_PTE_MT_UNCACHED.longPTE_EXT_TEX(1)@ L_PTE_MT_BUFFERABLE.longPTE_CACHEABLE@ L_PTE_MT_WRITETHROUGH.longPTE_CACHEABLE | PTE_BUFFERABLE@ L_PTE_MT_WRITEBACK.longPTE_BUFFERABLE@ L_PTE_MT_DEV_SHARED.long0x00@ unused.long0x00@ L_PTE_MT_MINICACHE (not present).longPTE_EXT_TEX(1) | PTE_CACHEABLE | PTE_BUFFERABLE@ L_PTE_MT_WRITEALLOC.long0x00@ unused.longPTE_EXT_TEX(1)@ L_PTE_MT_DEV_WC.long0x00@ unused.longPTE_CACHEABLE | PTE_BUFFERABLE@ L_PTE_MT_DEV_CACHED.longPTE_EXT_TEX(2)@ L_PTE_MT_DEV_NONSHARED.long0x00@ unused.long0x00@ unused.longPTE_CACHEABLE | PTE_BUFFERABLE | PTE_EXT_APX@ L_PTE_MT_VECTORS.endm.macroarmv6_set_pte_ext pfxstrr1, [r0], #2048@ linux versionbicr3, r1, #0x000003fcbicr3, r3, #PTE_TYPE_MASKorrr3, r3, r2orrr3, r3, #PTE_EXT_AP0 | 2adrip, \pfx\()_mt_tableandr2, r1, #L_PTE_MT_MASKldrr2, [ip, r2]eorr1, r1, #L_PTE_DIRTYtstr1, #L_PTE_DIRTY|L_PTE_RDONLYorrner3, r3, #PTE_EXT_APXtstr1, #L_PTE_USERorrner3, r3, #PTE_EXT_AP1tstner3, #PTE_EXT_APX@ user read-only -> kernel read-onlybicner3, r3, #PTE_EXT_AP0tstr1, #L_PTE_XNorrner3, r3, #PTE_EXT_XNeorr3, r3, r2tstr1, #L_PTE_YOUNGtstner1, #L_PTE_PRESENTmoveqr3, #0tstner1, #L_PTE_NONEmovner3, #0strr3, [r0]mcrp15, 0, r0, c7, c10, 1@ flush_pte.endm/* * The ARMv3, ARMv4 and ARMv5 set_pte_ext translation function, * covering most CPUs except Xscale and Xscale 3. * * Permission translation: *  YUWD   APSVCUser *  0xxx  0x00no accno acc *  100x  0x00r/ono acc *  10x0  0x00r/ono acc *  1011  0x55r/wno acc *  110x  0xaar/wr/o *  11x0  0xaar/wr/o *  1111  0xffr/wr/w */.macroarmv3_set_pte_ext wc_disable=1strr1, [r0], #2048@ linux versioneorr3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTYbicr2, r1, #PTE_SMALL_AP_MASK@ keep C, B bitsbicr2, r2, #PTE_TYPE_MASKorrr2, r2, #PTE_TYPE_SMALLtstr3, #L_PTE_USER@ user?orrner2, r2, #PTE_SMALL_AP_URO_SRWtstr3, #L_PTE_RDONLY | L_PTE_DIRTY@ write and dirty?orreqr2, r2, #PTE_SMALL_AP_UNO_SRWtstr3, #L_PTE_PRESENT | L_PTE_YOUNG@ present and young?movner2, #0.if\wc_disable#ifdef CONFIG_CPU_DCACHE_WRITETHROUGHtstr2, #PTE_CACHEABLEbicner2, r2, #PTE_BUFFERABLE#endif.endifstrr2, [r0]@ hardware version.endm/* * Xscale set_pte_ext translation, split into two halves to cope * with work-arounds.  r3 must be preserved by code between these * two macros. * * Permission translation: *  YUWD  APSVCUser *  0xxx  00no accno acc *  100x  00r/ono acc *  10x0  00r/ono acc *  1011  01r/wno acc *  110x  10r/wr/o *  11x0  10r/wr/o *  1111  11r/wr/w */.macroxscale_set_pte_ext_prologuestrr1, [r0]@ linux versioneorr3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTYbicr2, r1, #PTE_SMALL_AP_MASK@ keep C, B bitsorrr2, r2, #PTE_TYPE_EXT@ extended pagetstr3, #L_PTE_USER@ user?orrner2, r2, #PTE_EXT_AP_URO_SRW@ yes -> user r/o, system r/wtstr3, #L_PTE_RDONLY | L_PTE_DIRTY@ write and dirty?orreqr2, r2, #PTE_EXT_AP_UNO_SRW@ yes -> user n/a, system r/w@ combined with user -> user r/w.endm.macroxscale_set_pte_ext_epiloguetstr3, #L_PTE_PRESENT | L_PTE_YOUNG@ present and young?movner2, #0@ no -> faultstrr2, [r0, #2048]!@ hardware versionmovip, #0mcrp15, 0, r0, c7, c10, 1@ clean L1 D linemcrp15, 0, ip, c7, c10, 4@ data write barrier.endm.macro define_processor_functions name:req, dabort:req, pabort:req, nommu=0, suspend=0.type\name\()_processor_functions, #object.align 2ENTRY(\name\()_processor_functions).word\dabort.word\pabort.wordcpu_\name\()_proc_init.wordcpu_\name\()_proc_fin.wordcpu_\name\()_reset.wordcpu_\name\()_do_idle.wordcpu_\name\()_dcache_clean_area.wordcpu_\name\()_switch_mm.if \nommu.word0.else.wordcpu_\name\()_set_pte_ext.endif.if \suspend.wordcpu_\name\()_suspend_size#ifdef CONFIG_PM_SLEEP.wordcpu_\name\()_do_suspend.wordcpu_\name\()_do_resume#else.word0.word0#endif.else.word0.word0.word0.endif.size\name\()_processor_functions, . - \name\()_processor_functions.endm.macro define_cache_functions name:req.align 2.type\name\()_cache_fns, #objectENTRY(\name\()_cache_fns).long\name\()_flush_icache_all.long\name\()_flush_kern_cache_all.long   \name\()_flush_kern_cache_louis.long\name\()_flush_user_cache_all.long\name\()_flush_user_cache_range.long\name\()_coherent_kern_range.long\name\()_coherent_user_range.long\name\()_flush_kern_dcache_area.long\name\()_dma_map_area.long\name\()_dma_unmap_area.long\name\()_dma_flush_range.size\name\()_cache_fns, . - \name\()_cache_fns.endm.macro define_tlb_functions name:req, flags_up:req, flags_smp.type\name\()_tlb_fns, #objectENTRY(\name\()_tlb_fns).long\name\()_flush_user_tlb_range.long\name\()_flush_kern_tlb_range.ifnb \flags_smpALT_SMP(.long\flags_smp )ALT_UP(.long\flags_up ).else.long\flags_up.endif.size\name\()_tlb_fns, . - \name\()_tlb_fns.endm.macro globl_equ x, y.globl\x.equ\x, \y.endm


/* *  linux/arch/arm/mm/proc-v7.S * *  Copyright (C) 2001 Deep Blue Solutions Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * *  This is the "shell" of the ARMv7 processor support. */#include <linux/init.h>#include <linux/linkage.h>#include <asm/assembler.h>#include <asm/asm-offsets.h>#include <asm/hwcap.h>#include <asm/pgtable-hwdef.h>#include <asm/pgtable.h>#include "proc-macros.S"#ifdef CONFIG_ARM_LPAE#include "proc-v7-3level.S"#else#include "proc-v7-2level.S"#endifENTRY(cpu_v7_proc_init)movpc, lrENDPROC(cpu_v7_proc_init)ENTRY(cpu_v7_proc_fin)mrcp15, 0, r0, c1, c0, 0@ ctrl registerbicr0, r0, #0x1000@ ...i............bicr0, r0, #0x0006@ .............ca.mcrp15, 0, r0, c1, c0, 0@ disable cachesmovpc, lrENDPROC(cpu_v7_proc_fin)/* *cpu_v7_reset(loc) * *Perform a soft reset of the system.  Put the CPU into the *same state as it would be if it had been reset, and branch *to what would be the reset vector. * *- loc   - location to jump to for soft reset * *This code must be executed using a flat identity mapping with *      caches disabled. */.align5.pushsection.idmap.text, "ax"ENTRY(cpu_v7_reset)mrcp15, 0, r1, c1, c0, 0@ ctrl registerbicr1, r1, #0x1@ ...............m THUMB(bicr1, r1, #1 << 30 )@ SCTLR.TE (Thumb exceptions)mcrp15, 0, r1, c1, c0, 0@ disable MMUisbbxr0ENDPROC(cpu_v7_reset).popsection/* *cpu_v7_do_idle() * *Idle the processor (eg, wait for interrupt). * *IRQs are already disabled. */ENTRY(cpu_v7_do_idle)dsb@ WFI may enter a low-power modewfimovpc, lrENDPROC(cpu_v7_do_idle)ENTRY(cpu_v7_dcache_clean_area)ALT_SMP(W(nop))@ MP extensions imply L1 PTWALT_UP_B(1f)movpc, lr1:dcache_line_size r2, r32:mcrp15, 0, r0, c7, c10, 1@ clean D entryaddr0, r0, r2subsr1, r1, r2bhi2bdsbishstmovpc, lrENDPROC(cpu_v7_dcache_clean_area)stringcpu_v7_name, "ARMv7 Processor".align/* Suspend/resume support: derived from arch/arm/mach-s5pv210/sleep.S */.globlcpu_v7_suspend_size.equcpu_v7_suspend_size, 4 * 9#ifdef CONFIG_ARM_CPU_SUSPENDENTRY(cpu_v7_do_suspend)stmfdsp!, {r4 - r10, lr}mrcp15, 0, r4, c13, c0, 0@ FCSE/PIDmrcp15, 0, r5, c13, c0, 3@ User r/o thread IDstmiar0!, {r4 - r5}#ifdef CONFIG_MMUmrcp15, 0, r6, c3, c0, 0@ Domain ID#ifdef CONFIG_ARM_LPAEmrrcp15, 1, r5, r7, c2@ TTB 1#elsemrcp15, 0, r7, c2, c0, 1@ TTB 1#endifmrcp15, 0, r11, c2, c0, 2@ TTB control register#endifmrcp15, 0, r8, c1, c0, 0@ Control registermrcp15, 0, r9, c1, c0, 1@ Auxiliary control registermrcp15, 0, r10, c1, c0, 2@ Co-processor access controlstmiar0, {r5 - r11}ldmfdsp!, {r4 - r10, pc}ENDPROC(cpu_v7_do_suspend)ENTRY(cpu_v7_do_resume)movip, #0mcrp15, 0, ip, c7, c5, 0@ invalidate I cachemcrp15, 0, ip, c13, c0, 1@ set reserved context IDldmiar0!, {r4 - r5}mcrp15, 0, r4, c13, c0, 0@ FCSE/PIDmcrp15, 0, r5, c13, c0, 3@ User r/o thread IDldmiar0, {r5 - r11}#ifdef CONFIG_MMUmcrp15, 0, ip, c8, c7, 0@ invalidate TLBsmcrp15, 0, r6, c3, c0, 0@ Domain ID#ifdef CONFIG_ARM_LPAEmcrrp15, 0, r1, ip, c2@ TTB 0mcrrp15, 1, r5, r7, c2@ TTB 1#elseALT_SMP(orrr1, r1, #TTB_FLAGS_SMP)ALT_UP(orrr1, r1, #TTB_FLAGS_UP)mcrp15, 0, r1, c2, c0, 0@ TTB 0mcrp15, 0, r7, c2, c0, 1@ TTB 1#endifmcrp15, 0, r11, c2, c0, 2@ TTB control registerldrr4, =PRRR@ PRRRldrr5, =NMRR@ NMRRmcrp15, 0, r4, c10, c2, 0@ write PRRRmcrp15, 0, r5, c10, c2, 1@ write NMRR#endif/* CONFIG_MMU */mrcp15, 0, r4, c1, c0, 1@ Read Auxiliary control registerteqr4, r9@ Is it already set?mcrnep15, 0, r9, c1, c0, 1@ No, so write itmcrp15, 0, r10, c1, c0, 2@ Co-processor access controlisbdsbmovr0, r8@ control registerbcpu_resume_mmuENDPROC(cpu_v7_do_resume)#endif#ifdef CONFIG_CPU_PJ4Bglobl_equcpu_pj4b_switch_mm,     cpu_v7_switch_mmglobl_equcpu_pj4b_set_pte_ext,cpu_v7_set_pte_extglobl_equcpu_pj4b_proc_init,cpu_v7_proc_initglobl_equcpu_pj4b_proc_fin, cpu_v7_proc_finglobl_equcpu_pj4b_reset,   cpu_v7_reset#ifdef CONFIG_PJ4B_ERRATA_4742ENTRY(cpu_pj4b_do_idle)dsb@ WFI may enter a low-power modewfidsb@barriermovpc, lrENDPROC(cpu_pj4b_do_idle)#elseglobl_equcpu_pj4b_do_idle,  cpu_v7_do_idle#endifglobl_equcpu_pj4b_dcache_clean_area,cpu_v7_dcache_clean_areaglobl_equcpu_pj4b_do_suspend,cpu_v7_do_suspendglobl_equcpu_pj4b_do_resume,cpu_v7_do_resumeglobl_equcpu_pj4b_suspend_size,cpu_v7_suspend_size#endif/* *__v7_setup * *Initialise TLB, Caches, and MMU state ready to switch the MMU *on.  Return in r0 the new CP15 C1 control register setting. * *This should be able to cover all ARMv7 cores. * *It is assumed that: *- cache type register is implemented */__v7_ca5mp_setup:__v7_ca9mp_setup:__v7_cr7mp_setup:movr10, #(1 << 0)@ Cache/TLB ops broadcastingb1f__v7_ca7mp_setup:__v7_ca15mp_setup:movr10, #01:#ifdef CONFIG_SMPALT_SMP(mrcp15, 0, r0, c1, c0, 1)ALT_UP(movr0, #(1 << 6))@ fake it for UPtstr0, #(1 << 6)@ SMP/nAMP mode enabled?orreqr0, r0, #(1 << 6)@ Enable SMP/nAMP modeorreqr0, r0, r10@ Enable CPU-specific SMP bitsmcreqp15, 0, r0, c1, c0, 1#endifb__v7_setup__v7_pj4b_setup:#ifdef CONFIG_CPU_PJ4B/* Auxiliary Debug Modes Control 1 Register */#define PJ4B_STATIC_BP (1 << 2) /* Enable Static BP */#define PJ4B_INTER_PARITY (1 << 8) /* Disable Internal Parity Handling */#define PJ4B_CLEAN_LINE (1 << 16) /* Disable data transfer for clean line *//* Auxiliary Debug Modes Control 2 Register */#define PJ4B_FAST_LDR (1 << 23) /* Disable fast LDR */#define PJ4B_SNOOP_DATA (1 << 25) /* Do not interleave write and snoop data */#define PJ4B_CWF (1 << 27) /* Disable Critical Word First feature */#define PJ4B_OUTSDNG_NC (1 << 29) /* Disable outstanding non cacheable rqst */#define PJ4B_L1_REP_RR (1 << 30) /* L1 replacement - Strict round robin */#define PJ4B_AUX_DBG_CTRL2 (PJ4B_SNOOP_DATA | PJ4B_CWF |\    PJ4B_OUTSDNG_NC | PJ4B_L1_REP_RR)/* Auxiliary Functional Modes Control Register 0 */#define PJ4B_SMP_CFB (1 << 1) /* Set SMP mode. Join the coherency fabric */#define PJ4B_L1_PAR_CHK (1 << 2) /* Support L1 parity checking */#define PJ4B_BROADCAST_CACHE (1 << 8) /* Broadcast Cache and TLB maintenance *//* Auxiliary Debug Modes Control 0 Register */#define PJ4B_WFI_WFE (1 << 22) /* WFI/WFE - serve the DVM and back to idle *//* Auxiliary Debug Modes Control 1 Register */mrcp15, 1,r0, c15, c1, 1orr     r0, r0, #PJ4B_CLEAN_LINEorr     r0, r0, #PJ4B_INTER_PARITYbicr0, r0, #PJ4B_STATIC_BPmcrp15, 1,r0, c15, c1, 1/* Auxiliary Debug Modes Control 2 Register */mrcp15, 1,r0, c15, c1, 2bicr0, r0, #PJ4B_FAST_LDRorrr0, r0, #PJ4B_AUX_DBG_CTRL2mcrp15, 1,r0, c15, c1, 2/* Auxiliary Functional Modes Control Register 0 */mrcp15, 1,r0, c15, c2, 0#ifdef CONFIG_SMPorrr0, r0, #PJ4B_SMP_CFB#endiforrr0, r0, #PJ4B_L1_PAR_CHKorrr0, r0, #PJ4B_BROADCAST_CACHEmcrp15, 1,r0, c15, c2, 0/* Auxiliary Debug Modes Control 0 Register */mrcp15, 1,r0, c15, c1, 0orrr0, r0, #PJ4B_WFI_WFEmcrp15, 1,r0, c15, c1, 0#endif /* CONFIG_CPU_PJ4B */__v7_setup:adrr12, __v7_setup_stack@ the local stackstmiar12, {r0-r5, r7, r9, r11, lr}bl      v7_flush_dcache_louisldmiar12, {r0-r5, r7, r9, r11, lr}mrcp15, 0, r0, c0, c0, 0@ read main ID registerandr10, r0, #0xff000000@ ARM?teqr10, #0x41000000bne3fandr5, r0, #0x00f00000@ variantandr6, r0, #0x0000000f@ revisionorrr6, r6, r5, lsr #20-4@ combine variant and revisionubfxr0, r0, #4, #12@ primary part number/* Cortex-A8 Errata */ldrr10, =0x00000c08@ Cortex-A8 primary part numberteqr0, r10bne2f#if defined(CONFIG_ARM_ERRATA_430973) && !defined(CONFIG_ARCH_MULTIPLATFORM)teqr5, #0x00100000@ only present in r1p*mrceqp15, 0, r10, c1, c0, 1@ read aux control registerorreqr10, r10, #(1 << 6)@ set IBE to 1mcreqp15, 0, r10, c1, c0, 1@ write aux control register#endif#ifdef CONFIG_ARM_ERRATA_458693teqr6, #0x20@ only present in r2p0mrceqp15, 0, r10, c1, c0, 1@ read aux control registerorreqr10, r10, #(1 << 5)@ set L1NEON to 1orreqr10, r10, #(1 << 9)@ set PLDNOP to 1mcreqp15, 0, r10, c1, c0, 1@ write aux control register#endif#ifdef CONFIG_ARM_ERRATA_460075teqr6, #0x20@ only present in r2p0mrceqp15, 1, r10, c9, c0, 2@ read L2 cache aux ctrl registertsteqr10, #1 << 22orreqr10, r10, #(1 << 22)@ set the Write Allocate disable bitmcreqp15, 1, r10, c9, c0, 2@ write the L2 cache aux ctrl register#endifb3f/* Cortex-A9 Errata */2:ldrr10, =0x00000c09@ Cortex-A9 primary part numberteqr0, r10bne3f#ifdef CONFIG_ARM_ERRATA_742230cmpr6, #0x22@ only present up to r2p2mrclep15, 0, r10, c15, c0, 1@ read diagnostic registerorrler10, r10, #1 << 4@ set bit #4mcrlep15, 0, r10, c15, c0, 1@ write diagnostic register#endif#ifdef CONFIG_ARM_ERRATA_742231teqr6, #0x20@ present in r2p0teqner6, #0x21@ present in r2p1teqner6, #0x22@ present in r2p2mrceqp15, 0, r10, c15, c0, 1@ read diagnostic registerorreqr10, r10, #1 << 12@ set bit #12orreqr10, r10, #1 << 22@ set bit #22mcreqp15, 0, r10, c15, c0, 1@ write diagnostic register#endif#ifdef CONFIG_ARM_ERRATA_743622teqr5, #0x00200000@ only present in r2p*mrceqp15, 0, r10, c15, c0, 1@ read diagnostic registerorreqr10, r10, #1 << 6@ set bit #6mcreqp15, 0, r10, c15, c0, 1@ write diagnostic register#endif#if defined(CONFIG_ARM_ERRATA_751472) && defined(CONFIG_SMP)ALT_SMP(cmp r6, #0x30)@ present prior to r3p0ALT_UP_B(1f)mrcltp15, 0, r10, c15, c0, 1@ read diagnostic registerorrltr10, r10, #1 << 11@ set bit #11mcrltp15, 0, r10, c15, c0, 1@ write diagnostic register1:#endif/* Cortex-A15 Errata */3:ldrr10, =0x00000c0f@ Cortex-A15 primary part numberteqr0, r10bne4f#ifdef CONFIG_ARM_ERRATA_773022cmpr6, #0x4@ only present up to r0p4mrclep15, 0, r10, c1, c0, 1@ read aux control registerorrler10, r10, #1 << 1@ disable loop buffermcrlep15, 0, r10, c1, c0, 1@ write aux control register#endif4:movr10, #0mcrp15, 0, r10, c7, c5, 0@ I+BTB cache invalidate#ifdef CONFIG_MMUmcrp15, 0, r10, c8, c7, 0@ invalidate I + D TLBsv7_ttb_setup r10, r4, r8, r5@ TTBCR, TTBRx setupldrr5, =PRRR@ PRRRldrr6, =NMRR@ NMRRmcrp15, 0, r5, c10, c2, 0@ write PRRRmcrp15, 0, r6, c10, c2, 1@ write NMRR#endifdsb@ Complete invalidations#ifndef CONFIG_ARM_THUMBEEmrcp15, 0, r0, c0, c1, 0@ read ID_PFR0 for ThumbEEandr0, r0, #(0xf << 12)@ ThumbEE enabled fieldteqr0, #(1 << 12)@ check if ThumbEE is presentbne1fmovr5, #0mcrp14, 6, r5, c1, c0, 0@ Initialize TEEHBR to 0mrcp14, 6, r0, c0, c0, 0@ load TEECRorrr0, r0, #1@ set the 1st bit in order tomcrp14, 6, r0, c0, c0, 0@ stop userspace TEEHBR access1:#endifadrr5, v7_crvalldmiar5, {r5, r6} ARM_BE8(orrr6, r6, #1 << 25)@ big-endian page tables#ifdef CONFIG_SWP_EMULATEorr     r5, r5, #(1 << 10)              @ set SW bit in "clear"bic     r6, r6, #(1 << 10)              @ clear it in "mmuset"#endif   mrcp15, 0, r0, c1, c0, 0@ read control registerbicr0, r0, r5@ clear bits themorrr0, r0, r6@ set them THUMB(orrr0, r0, #1 << 30)@ Thumb exceptionsmovpc, lr@ return to head.S:__retENDPROC(__v7_setup).align2__v7_setup_stack:.space4 * 11@ 11 registers__INITDATA@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1#ifdef CONFIG_CPU_PJ4Bdefine_processor_functions pj4b, dabort=v7_early_abort, pabort=v7_pabort, suspend=1#endif.section ".rodata"stringcpu_arch_name, "armv7"stringcpu_elf_name, "v7".align.section ".proc.info.init", #alloc, #execinstr/* * Standard v7 proc info content */.macro __v7_proc initfunc, mm_mmuflags = 0, io_mmuflags = 0, hwcaps = 0, proc_fns = v7_processor_functionsALT_SMP(.longPMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \PMD_SECT_AF | PMD_FLAGS_SMP | \mm_mmuflags)ALT_UP(.longPMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \PMD_SECT_AF | PMD_FLAGS_UP | \mm_mmuflags).longPMD_TYPE_SECT | PMD_SECT_AP_WRITE | \PMD_SECT_AP_READ | PMD_SECT_AF | \io_mmuflagsW(b)\initfunc.longcpu_arch_name.longcpu_elf_name.longHWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_FAST_MULT | \HWCAP_EDSP | HWCAP_TLS | \hwcaps.longcpu_v7_name.long\proc_fns.longv7wbi_tlb_fns.longv6_user_fns.longv7_cache_fns.endm#ifndef CONFIG_ARM_LPAE/* * ARM Ltd. Cortex A5 processor. */.type   __v7_ca5mp_proc_info, #object__v7_ca5mp_proc_info:.long0x410fc050.long0xff0ffff0__v7_proc __v7_ca5mp_setup.size__v7_ca5mp_proc_info, . - __v7_ca5mp_proc_info/* * ARM Ltd. Cortex A9 processor. */.type   __v7_ca9mp_proc_info, #object__v7_ca9mp_proc_info:.long0x410fc090.long0xff0ffff0__v7_proc __v7_ca9mp_setup.size__v7_ca9mp_proc_info, . - __v7_ca9mp_proc_info#endif/* CONFIG_ARM_LPAE *//* * Marvell PJ4B processor. */#ifdef CONFIG_CPU_PJ4B.type   __v7_pj4b_proc_info, #object__v7_pj4b_proc_info:.long0x560f5800.long0xff0fff00__v7_proc __v7_pj4b_setup, proc_fns = pj4b_processor_functions.size__v7_pj4b_proc_info, . - __v7_pj4b_proc_info#endif/* * ARM Ltd. Cortex R7 processor. */.type__v7_cr7mp_proc_info, #object__v7_cr7mp_proc_info:.long0x410fc170.long0xff0ffff0__v7_proc __v7_cr7mp_setup.size__v7_cr7mp_proc_info, . - __v7_cr7mp_proc_info/* * ARM Ltd. Cortex A7 processor. */.type__v7_ca7mp_proc_info, #object__v7_ca7mp_proc_info:.long0x410fc070.long0xff0ffff0__v7_proc __v7_ca7mp_setup.size__v7_ca7mp_proc_info, . - __v7_ca7mp_proc_info/* * ARM Ltd. Cortex A15 processor. */.type__v7_ca15mp_proc_info, #object__v7_ca15mp_proc_info:.long0x410fc0f0.long0xff0ffff0__v7_proc __v7_ca15mp_setup.size__v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info/* * Qualcomm Inc. Krait processors. */.type__krait_proc_info, #object__krait_proc_info:.long0x510f0400@ Required ID value.long0xff0ffc00@ Mask for ID/* * Some Krait processors don't indicate support for SDIV and UDIV * instructions in the ARM instruction set, even though they actually * do support them. */__v7_proc __v7_setup, hwcaps = HWCAP_IDIV.size__krait_proc_info, . - __krait_proc_info/* * Match any ARMv7 processor core. */.type__v7_proc_info, #object__v7_proc_info:.long0x000f0000@ Required ID value.long0x000f0000@ Mask for ID__v7_proc __v7_setup.size__v7_proc_info, . - __v7_proc_info






0 0