summaryrefslogtreecommitdiffstats
path: root/arch/arm26/mm/proc-funcs.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm26/mm/proc-funcs.S')
-rw-r--r--arch/arm26/mm/proc-funcs.S359
1 files changed, 359 insertions, 0 deletions
diff --git a/arch/arm26/mm/proc-funcs.S b/arch/arm26/mm/proc-funcs.S
new file mode 100644
index 00000000000..c3d4cd3f457
--- /dev/null
+++ b/arch/arm26/mm/proc-funcs.S
@@ -0,0 +1,359 @@
+/*
+ * linux/arch/arm26/mm/proc-arm2,3.S
+ *
+ * Copyright (C) 1997-1999 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.
+ *
+ * MMU functions for ARM2,3
+ *
+ * These are the low level assembler for performing cache
+ * and memory functions on ARM2, ARM250 and ARM3 processors.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/asm_offsets.h>
+#include <asm/procinfo.h>
+#include <asm/ptrace.h>
+
+/*
+ * MEMC workhorse code. It's both a horse which things it's a pig.
+ */
+/*
+ * Function: cpu_memc_update_entry(pgd_t *pgd, unsigned long phys_pte, unsigned long addr)
+ * Params : pgd Page tables/MEMC mapping
+ * : phys_pte physical address, or PTE
+ * : addr virtual address
+ */
+ENTRY(cpu_memc_update_entry)
+ tst r1, #PAGE_PRESENT @ is the page present
+ orreq r1, r1, #PAGE_OLD | PAGE_CLEAN
+ moveq r2, #0x01f00000
+ mov r3, r1, lsr #13 @ convert to physical page nr
+ and r3, r3, #0x3fc
+ adr ip, memc_phys_table_32
+ ldr r3, [ip, r3]
+ tst r1, #PAGE_OLD | PAGE_NOT_USER
+ biceq r3, r3, #0x200
+ tsteq r1, #PAGE_READONLY | PAGE_CLEAN
+ biceq r3, r3, #0x300
+ mov r2, r2, lsr #15 @ virtual -> nr
+ orr r3, r3, r2, lsl #15
+ and r2, r2, #0x300
+ orr r3, r3, r2, lsl #2
+ and r2, r3, #255
+ sub r0, r0, #256 * 4
+ str r3, [r0, r2, lsl #2]
+ strb r3, [r3]
+ movs pc, lr
+/*
+ * Params : r0 = preserved
+ * : r1 = memc table base (preserved)
+ * : r2 = page table entry
+ * : r3 = preserved
+ * : r4 = unused
+ * : r5 = memc physical address translation table
+ * : ip = virtual address (preserved)
+ */
+update_pte:
+ mov r4, r2, lsr #13
+ and r4, r4, #0x3fc
+ ldr r4, [r5, r4] @ covert to MEMC page
+
+ tst r2, #PAGE_OLD | PAGE_NOT_USER @ check for MEMC read
+ biceq r4, r4, #0x200
+ tsteq r2, #PAGE_READONLY | PAGE_CLEAN @ check for MEMC write
+ biceq r4, r4, #0x300
+
+ orr r4, r4, ip
+ and r2, ip, #0x01800000
+ orr r4, r4, r2, lsr #13
+
+ and r2, r4, #255
+ str r4, [r1, r2, lsl #2]
+ movs pc, lr
+
+/*
+ * Params : r0 = preserved
+ * : r1 = memc table base (preserved)
+ * : r2 = page table base
+ * : r3 = preserved
+ * : r4 = unused
+ * : r5 = memc physical address translation table
+ * : ip = virtual address (updated)
+ */
+update_pte_table:
+ stmfd sp!, {r0, lr}
+ bic r0, r2, #3
+1: ldr r2, [r0], #4 @ get entry
+ tst r2, #PAGE_PRESENT @ page present
+ blne update_pte @ process pte
+ add ip, ip, #32768 @ increment virt addr
+ ldr r2, [r0], #4 @ get entry
+ tst r2, #PAGE_PRESENT @ page present
+ blne update_pte @ process pte
+ add ip, ip, #32768 @ increment virt addr
+ ldr r2, [r0], #4 @ get entry
+ tst r2, #PAGE_PRESENT @ page present
+ blne update_pte @ process pte
+ add ip, ip, #32768 @ increment virt addr
+ ldr r2, [r0], #4 @ get entry
+ tst r2, #PAGE_PRESENT @ page present
+ blne update_pte @ process pte
+ add ip, ip, #32768 @ increment virt addr
+ tst ip, #32768 * 31 @ finished?
+ bne 1b
+ ldmfd sp!, {r0, pc}^
+
+/*
+ * Function: cpu_memc_update_all(pgd_t *pgd)
+ * Params : pgd Page tables/MEMC mapping
+ * Notes : this is optimised for 32k pages
+ */
+ENTRY(cpu_memc_update_all)
+ stmfd sp!, {r4, r5, lr}
+ bl clear_tables
+ sub r1, r0, #256 * 4 @ start of MEMC tables
+ adr r5, memc_phys_table_32 @ Convert to logical page number
+ mov ip, #0 @ virtual address
+1: ldmia r0!, {r2, r3} @ load two pgd entries
+ tst r2, #PAGE_PRESENT @ is pgd entry present?
+ addeq ip, ip, #1048576 @FIXME - PAGE_PRESENT is for PTEs technically...
+ blne update_pte_table
+ mov r2, r3
+ tst r2, #PAGE_PRESENT @ is pgd entry present?
+ addeq ip, ip, #1048576
+ blne update_pte_table
+ teq ip, #32 * 1048576
+ bne 1b
+ ldmfd sp!, {r4, r5, pc}^
+
+/*
+ * Build the table to map from physical page number to memc page number
+ */
+ .type memc_phys_table_32, #object
+memc_phys_table_32:
+ .irp b7, 0x00, 0x80
+ .irp b6, 0x00, 0x02
+ .irp b5, 0x00, 0x04
+ .irp b4, 0x00, 0x01
+
+ .irp b3, 0x00, 0x40
+ .irp b2, 0x00, 0x20
+ .irp b1, 0x00, 0x10
+ .irp b0, 0x00, 0x08
+ .long 0x03800300 + \b7 + \b6 + \b5 + \b4 + \b3 + \b2 + \b1 + \b0
+ .endr
+ .endr
+ .endr
+ .endr
+
+ .endr
+ .endr
+ .endr
+ .endr
+ .size memc_phys_table_32, . - memc_phys_table_32
+
+/*
+ * helper for cpu_memc_update_all, this clears out all
+ * mappings, setting them close to the top of memory,
+ * and inaccessible (0x01f00000).
+ * Params : r0 = page table pointer
+ */
+clear_tables: ldr r1, _arm3_set_pgd - 4
+ ldr r2, [r1]
+ sub r1, r0, #256 * 4 @ start of MEMC tables
+ add r2, r1, r2, lsl #2 @ end of tables
+ mov r3, #0x03f00000 @ Default mapping (null mapping)
+ orr r3, r3, #0x00000f00
+ orr r4, r3, #1
+ orr r5, r3, #2
+ orr ip, r3, #3
+1: stmia r1!, {r3, r4, r5, ip}
+ add r3, r3, #4
+ add r4, r4, #4
+ add r5, r5, #4
+ add ip, ip, #4
+ stmia r1!, {r3, r4, r5, ip}
+ add r3, r3, #4
+ add r4, r4, #4
+ add r5, r5, #4
+ add ip, ip, #4
+ teq r1, r2
+ bne 1b
+ mov pc, lr
+
+/*
+ * Function: *_set_pgd(pgd_t *pgd)
+ * Params : pgd New page tables/MEMC mapping
+ * Purpose : update MEMC hardware with new mapping
+ */
+ .word page_nr @ extern - declared in mm-memc.c
+_arm3_set_pgd: mcr p15, 0, r1, c1, c0, 0 @ flush cache
+_arm2_set_pgd: stmfd sp!, {lr}
+ ldr r1, _arm3_set_pgd - 4
+ ldr r2, [r1]
+ sub r0, r0, #256 * 4 @ start of MEMC tables
+ add r1, r0, r2, lsl #2 @ end of tables
+1: ldmia r0!, {r2, r3, ip, lr}
+ strb r2, [r2]
+ strb r3, [r3]
+ strb ip, [ip]
+ strb lr, [lr]
+ ldmia r0!, {r2, r3, ip, lr}
+ strb r2, [r2]
+ strb r3, [r3]
+ strb ip, [ip]
+ strb lr, [lr]
+ teq r0, r1
+ bne 1b
+ ldmfd sp!, {pc}^
+
+/*
+ * Function: *_proc_init (void)
+ * Purpose : Initialise the cache control registers
+ */
+_arm3_proc_init:
+ mov r0, #0x001f0000
+ orr r0, r0, #0x0000ff00
+ orr r0, r0, #0x000000ff
+ mcr p15, 0, r0, c3, c0 @ ARM3 Cacheable
+ mcr p15, 0, r0, c4, c0 @ ARM3 Updateable
+ mov r0, #0
+ mcr p15, 0, r0, c5, c0 @ ARM3 Disruptive
+ mcr p15, 0, r0, c1, c0 @ ARM3 Flush
+ mov r0, #3
+ mcr p15, 0, r0, c2, c0 @ ARM3 Control
+_arm2_proc_init:
+ movs pc, lr
+
+/*
+ * Function: *_proc_fin (void)
+ * Purpose : Finalise processor (disable caches)
+ */
+_arm3_proc_fin: mov r0, #2
+ mcr p15, 0, r0, c2, c0
+_arm2_proc_fin: orrs pc, lr, #PSR_I_BIT|PSR_F_BIT
+
+/*
+ * Function: *_xchg_1 (int new, volatile void *ptr)
+ * Params : new New value to store at...
+ * : ptr pointer to byte-wide location
+ * Purpose : Performs an exchange operation
+ * Returns : Original byte data at 'ptr'
+ */
+_arm2_xchg_1: mov r2, pc
+ orr r2, r2, #PSR_I_BIT
+ teqp r2, #0
+ ldrb r2, [r1]
+ strb r0, [r1]
+ mov r0, r2
+ movs pc, lr
+
+_arm3_xchg_1: swpb r0, r0, [r1]
+ movs pc, lr
+
+/*
+ * Function: *_xchg_4 (int new, volatile void *ptr)
+ * Params : new New value to store at...
+ * : ptr pointer to word-wide location
+ * Purpose : Performs an exchange operation
+ * Returns : Original word data at 'ptr'
+ */
+_arm2_xchg_4: mov r2, pc
+ orr r2, r2, #PSR_I_BIT
+ teqp r2, #0
+ ldr r2, [r1]
+ str r0, [r1]
+ mov r0, r2
+ movs pc, lr
+
+_arm3_xchg_4: swp r0, r0, [r1]
+ movs pc, lr
+
+_arm2_3_check_bugs:
+ bics pc, lr, #PSR_F_BIT @ Clear FIQ disable bit
+
+armvlsi_name: .asciz "ARM/VLSI"
+_arm2_name: .asciz "ARM 2"
+_arm250_name: .asciz "ARM 250"
+_arm3_name: .asciz "ARM 3"
+
+ .section ".init.text", #alloc, #execinstr
+/*
+ * Purpose : Function pointers used to access above functions - all calls
+ * come through these
+ */
+ .globl arm2_processor_functions
+arm2_processor_functions:
+ .word _arm2_3_check_bugs
+ .word _arm2_proc_init
+ .word _arm2_proc_fin
+ .word _arm2_set_pgd
+ .word _arm2_xchg_1
+ .word _arm2_xchg_4
+
+cpu_arm2_info:
+ .long armvlsi_name
+ .long _arm2_name
+
+ .globl arm250_processor_functions
+arm250_processor_functions:
+ .word _arm2_3_check_bugs
+ .word _arm2_proc_init
+ .word _arm2_proc_fin
+ .word _arm2_set_pgd
+ .word _arm3_xchg_1
+ .word _arm3_xchg_4
+
+cpu_arm250_info:
+ .long armvlsi_name
+ .long _arm250_name
+
+ .globl arm3_processor_functions
+arm3_processor_functions:
+ .word _arm2_3_check_bugs
+ .word _arm3_proc_init
+ .word _arm3_proc_fin
+ .word _arm3_set_pgd
+ .word _arm3_xchg_1
+ .word _arm3_xchg_4
+
+cpu_arm3_info:
+ .long armvlsi_name
+ .long _arm3_name
+
+arm2_arch_name: .asciz "armv1"
+arm3_arch_name: .asciz "armv2"
+arm2_elf_name: .asciz "v1"
+arm3_elf_name: .asciz "v2"
+ .align
+
+ .section ".proc.info", #alloc, #execinstr
+
+ .long 0x41560200
+ .long 0xfffffff0
+ .long arm2_arch_name
+ .long arm2_elf_name
+ .long 0
+ .long cpu_arm2_info
+ .long arm2_processor_functions
+
+ .long 0x41560250
+ .long 0xfffffff0
+ .long arm3_arch_name
+ .long arm3_elf_name
+ .long 0
+ .long cpu_arm250_info
+ .long arm250_processor_functions
+
+ .long 0x41560300
+ .long 0xfffffff0
+ .long arm3_arch_name
+ .long arm3_elf_name
+ .long 0
+ .long cpu_arm3_info
+ .long arm3_processor_functions
+