; > Copro15ops

; from kernel source for 3.7

ARM_config_cp        CP 15  ;coprocessor number for configuration control

ARM_ID_reg           CN  0  ;processor ID
ARM_control_reg      CN  1  ;control
ARM_tbase_reg        CN  2  ;translation base (MMU)
ARM_domain_reg       CN  3  ;domain access control (MMU)

ARM67_TLBflush_reg   CN  5  ;TLB flush, ARMs 6 or 7
ARM67_TLBpurge_reg   CN  6  ;TLB purge entry, ARMs 6 or 7
ARM67_cacheflush_reg CN  7  ;cache flush, ARMs 6 or 7

ARM8A_cache_reg      CN  7  ;cache operations, ARMs 8 or StrongARM
ARM8A_TLB_reg        CN  8  ;TLB operations, ARMs 8 or StrongARM

ARM8_cacheLD_reg     CN  9  ;cache lock-down, ARM 8
ARM8_TLBLD_reg       CN 10  ;TLB lock-down, ARM 8

ARMA_TCI_reg         CN 15  ;Test,Clock and Idle control

;so that bleedin' AASM will accept the general value for MCR CRm field
C0  CN  0
C1  CN  1
C2  CN  2
C3  CN  3
C4  CN  4
C5  CN  5
C6  CN  6
C7  CN  7
C8  CN  8
C9  CN  9
C10 CN 10
C11 CN 11
C12 CN 12
C13 CN 13
C14 CN 14
C15 CN 15


;
; ----------------- all ARMs ---------------------------------------------
;

;set MMU translation base
        MACRO
        ARM_MMU_transbase $reg,$cond
        MCR$cond ARM_config_cp,0,$reg,ARM_tbase_reg,C0,0
        MEND

;set MMU domain access register
        MACRO
        ARM_MMU_domain $reg,$cond
        MCR$cond ARM_config_cp,0,$reg,ARM_domain_reg,C0,0
        MEND

;read control register
        MACRO
        ARM_read_control $reg,$cond
        MRC$cond ARM_config_cp,0,$reg,ARM_control_reg,C0,0
        MEND

;set control register
        MACRO
        ARM_write_control $reg,$cond
        MCR$cond ARM_config_cp,0,$reg,ARM_control_reg,C0,0
        MEND

;read ID register to register $id
;bits 15:12 of returned ID will be 0,7,8,10 for ARM 6,7,8,A
        MACRO
        ARM_read_ID $id,$cond
        MRC$cond ARM_config_cp,0,$id,ARM_ID_reg,C0,0  
        MEND

;read ARM 'number' (6,7,8,&A currently) into $num
        MACRO
        ARM_number $num
        ARM_read_ID $num
        ANDS     $num,$num,#&F000
        MOVEQ    $num,#&6000       ;catch and correct daft ARM 6 ID layout
        MOV      $num,$num,LSR #12
        MEND

;flush whole TLB (both data and instruction for StrongARM)
;trashes $temp
        MACRO
        ARM_flush_TLB $temp
        ARM_read_ID $temp
        AND      $temp,$temp,#&F000
        CMP      $temp,#&8000   ;ARM 8?
        CMPNE    $temp,#&A000   ;or StrongARM?
        MCRNE    ARM_config_cp,0,R0,ARM67_TLBflush_reg,C0,0
        MCREQ    ARM_config_cp,0,R0,ARM8A_TLB_reg,C7,0
        MEND

;flush whole cache (both data and instruction for StrongARM),
;without worrying about any cache cleaning
;trashes $temp
        MACRO
        ARM_flush_cache $temp
        ARM_read_ID $temp
        AND      $temp,$temp,#&F000
        CMP      $temp,#&8000   ;ARM 8?
        CMPNE    $temp,#&A000   ;or StrongARM?
        MCRNE    ARM_config_cp,0,R0,ARM67_cacheflush_reg,C0,0
        MCREQ    ARM_config_cp,0,R0,ARM8A_cache_reg,C7,0
        MEND

;flush whole TLB and cache (both data and instruction for StrongARM),
;without worrying about any cache cleaning
;trashes $temp
        MACRO
        ARM_flush_cacheandTLB $temp
        ARM_read_ID $temp
        AND      $temp,$temp,#&F000
        CMP      $temp,#&8000   ;ARM 8?
        CMPNE    $temp,#&A000   ;or StrongARM?
        MCRNE    ARM_config_cp,0,R0,ARM67_cacheflush_reg,C0,0
        MCRNE    ARM_config_cp,0,R0,ARM67_TLBflush_reg,C0,0
        MCREQ    ARM_config_cp,0,R0,ARM8A_cache_reg,C7,0
        MCREQ    ARM_config_cp,0,R0,ARM8A_TLB_reg,C7,0
        MEND

;
; -------------- ARM 6,7 only --------------------------------------------
;

;flush cache
        MACRO
        ARM67_flush_cache $cond
        MCR$cond ARM_config_cp,0,R0,ARM67_cacheflush_reg,C0,0
        MEND

;flush TLB
        MACRO
        ARM67_flush_TLB $cond
        MCR$cond ARM_config_cp,0,R0,ARM67_TLBflush_reg,C0,0
        MEND

;flush TLB entry, virtual address in $reg
        MACRO
        ARM67_flush_TLBentry $reg,$cond
        MCR$cond ARM_config_cp,0,$reg,ARM67_TLBpurge_reg,C0,0
        MEND

;
; -------------- ARM 8 only ----------------------------------------------
;


;
; -------------- StrongARM only ------------------------------------------
;

;clean whole data cache, using 16k private cleaner area at address in
;$cleanaddr
;trashes $cleanaddr,$temp1,$temp2
;
;method:
;clean whole (16k) data cache by reading 16k private cleaner area in 8-word
;(one cache line) steps
;
;note: this routine should NOT be used as is without care - remember
;      1) interrupts should be off (to guarantee this clean is effective)
;      2) DC should be flushed afterwards (to guarantee next clean using
;         private area is effective, ie. all private area flushed out now)
;      see ARMA_fullycleanflush_DC for 'packaged routine'
;
        MACRO
        ARMA_clean_DC $cleanaddr,$temp1,$temp2
        ADD     $temp1,$cleanaddr,#16*1024
10
        LDR     $temp2,[$cleanaddr],#32
        TEQ     $temp1,$cleanaddr
        BNE     %BT10
        MEND

;flush whole data cache
        MACRO
        ARMA_flush_DC $cond
        MCR$cond ARM_config_cp,0,R0,ARM8A_cache_reg,C6,0
        MEND

;clean data cache entry, virtual addr in $reg
        MACRO
        ARMA_clean_DCentry $reg,$cond
        MCR$cond ARM_config_cp,0,$reg,ARM8A_cache_reg,C10,1
        MEND

;flush data cache entry, virtual addr in $reg
        MACRO
        ARMA_flush_DCentry $reg,$cond
        MCR$cond ARM_config_cp,0,$reg,ARM8A_cache_reg,C6,1
        MEND

;clean and flush data cache entry, virtual addr in $reg
        MACRO
        ARMA_cleanflush_DCentry $reg,$cond
        MCR$cond ARM_config_cp,0,$reg,ARM8A_cache_reg,C14,1
        MEND

;clean data cache for virtual address range from $lo (inclusive) to $hi (exclusive)
;corrupts $lo,$hi
        MACRO
        ARMA_clean_DCrange $lo,$hi
        BIC     $lo,$lo,#31    ;align down to 8-word (1 cache line) boundary
        ADD     $hi,$hi,#31
        BIC     $hi,$hi,#31    ;align up to 8-word boundary
01
        ARMA_clean_DCentry $lo ;clean entry for virtual address $lo
        ADD     $lo,$lo,#32    ;next line
        ARMA_clean_DCentry $lo
        ADD     $lo,$lo,#32
        ARMA_clean_DCentry $lo
        ADD     $lo,$lo,#32
        ARMA_clean_DCentry $lo
        ADD     $lo,$lo,#32
        CMP     $lo,$hi
        BLO     %BT01
        MEND

;drain write buffer
        MACRO
        ARMA_drain_WB $cond
        MCR$cond ARM_config_cp,0,R0,ARM8A_cache_reg,C10,4
        MEND

;flush whole instruction cache
        MACRO
        ARMA_flush_IC $WithoutNOPs,$cond
        MCR$cond ARM_config_cp,0,R0,ARM8A_cache_reg,C5,0
      [ "$WithoutNOPs" = ""
        MOV     R0,R0 ; 4 NOPS - up to 4 further instructions may come from IC before flush
        MOV     R0,R0
        MOV     R0,R0
        MOV     R0,R0
      ]
        MEND

;flush whole instruction cache and whole data cache
        MACRO
        ARMA_flush_ICandDC $WithoutNOPs,$cond
        MCR$cond ARM_config_cp,0,R0,ARM8A_cache_reg,C7,0
      [ "$WithoutNOPs" = ""
        MOV     R0,R0 ; 4 NOPS - up to 4 further instructions may come from IC before flush
        MOV     R0,R0
        MOV     R0,R0
        MOV     R0,R0
      ]
        MEND

;flush whole instruction TLB
        MACRO
        ARMA_flush_ITLB $cond
        MCR$cond ARM_config_cp,0,R0,ARM8A_TLB_reg,C5,0
        MEND

;flush whole data TLB
        MACRO
        ARMA_flush_DTLB $cond
        MCR$cond ARM_config_cp,0,R0,ARM8A_TLB_reg,C6,0
        MEND

;flush whole instruction and data TLBs
        MACRO
        ARMA_flush_TLBs $cond
        MCR$cond ARM_config_cp,0,R0,ARM8A_TLB_reg,C7,0
        MEND

;flush data TLB entry, virtual address in $reg
        MACRO
        ARMA_flush_DTLBentry $reg,$cond
        MCR$cond ARM_config_cp,0,$reg,ARM8A_TLB_reg,C6,1
        MEND

;fully clean and flush DC - see ARMA_clean_DC for more info
;assumed to be 26 bit mode
        MACRO
        ARMA_fullycleanflush_DC $cleanaddr,$temp1,$temp2,$temp3
        MOV     $temp3,pc
        ORR     $temp1,$temp3,#I_bit
        TEQP    $temp1,#0             ;disable IRQs
        ARMA_clean_DC $cleanaddr,$temp1,$temp2
        ARMA_flush_DC
        TEQP    $temp3,#0             ;restore IRQ state
        MEND

;enable core clock switching (fast core clock allowed)
        MACRO
        ARMA_fastcoreclock $cond
        MCR$cond ARM_config_cp,0,R0,ARMA_TCI_reg,C1,2
        MEND

;disable core clock switching (core clock is memory clock)
        MACRO
        ARMA_slowcoreclock $cond
        MCR$cond ARM_config_cp,0,R0,ARMA_TCI_reg,C2,2
        MEND


    END
