diff options
author | raj <raj@FreeBSD.org> | 2008-10-13 18:16:54 +0000 |
---|---|---|
committer | raj <raj@FreeBSD.org> | 2008-10-13 18:16:54 +0000 |
commit | b9c565987ac8d8b7f1fedf4ed5b320ae753180b2 (patch) | |
tree | 8760a63d9c68590231c64efd968790b4094cb95d | |
parent | 69ae2b2b5a37e65ff6b2e7d5e33a5fffd61a2eaf (diff) | |
download | FreeBSD-src-b9c565987ac8d8b7f1fedf4ed5b320ae753180b2.zip FreeBSD-src-b9c565987ac8d8b7f1fedf4ed5b320ae753180b2.tar.gz |
Introduce low-level support for new Marvell core CPUs: 88FR131, 88FR571.
They are compliant with ARMv5TE and integrated on 88F6281 (Kirkwood) and
MV78100 (Discovery) system-on-chip families.
Obtained from: Marvell, Semihalf
-rw-r--r-- | sys/arm/arm/cpufunc.c | 93 | ||||
-rw-r--r-- | sys/arm/arm/cpufunc_asm_feroceon.S | 386 | ||||
-rw-r--r-- | sys/arm/arm/identcpu.c | 12 | ||||
-rw-r--r-- | sys/arm/include/armreg.h | 15 | ||||
-rw-r--r-- | sys/arm/include/cpufunc.h | 12 |
5 files changed, 514 insertions, 4 deletions
diff --git a/sys/arm/arm/cpufunc.c b/sys/arm/arm/cpufunc.c index 8ad4aa9..6317769 100644 --- a/sys/arm/arm/cpufunc.c +++ b/sys/arm/arm/cpufunc.c @@ -357,6 +357,66 @@ struct cpu_functions armv5_ec_cpufuncs = { arm10_setup /* cpu setup */ }; + +struct cpu_functions feroceon_cpufuncs = { + /* CPU functions */ + + cpufunc_id, /* id */ + cpufunc_nullop, /* cpwait */ + + /* MMU functions */ + + cpufunc_control, /* control */ + cpufunc_domains, /* Domain */ + feroceon_setttb, /* Setttb */ + cpufunc_faultstatus, /* Faultstatus */ + cpufunc_faultaddress, /* Faultaddress */ + + /* TLB functions */ + + armv4_tlb_flushID, /* tlb_flushID */ + arm10_tlb_flushID_SE, /* tlb_flushID_SE */ + armv4_tlb_flushI, /* tlb_flushI */ + arm10_tlb_flushI_SE, /* tlb_flushI_SE */ + armv4_tlb_flushD, /* tlb_flushD */ + armv4_tlb_flushD_SE, /* tlb_flushD_SE */ + + /* Cache operations */ + + armv5_ec_icache_sync_all, /* icache_sync_all */ + armv5_ec_icache_sync_range, /* icache_sync_range */ + + armv5_ec_dcache_wbinv_all, /* dcache_wbinv_all */ + feroceon_dcache_wbinv_range, /* dcache_wbinv_range */ + feroceon_dcache_inv_range, /* dcache_inv_range */ + feroceon_dcache_wb_range, /* dcache_wb_range */ + + armv5_ec_idcache_wbinv_all, /* idcache_wbinv_all */ + feroceon_idcache_wbinv_range, /* idcache_wbinv_all */ + + feroceon_l2cache_wbinv_all, /* l2cache_wbinv_all */ + feroceon_l2cache_wbinv_range, /* l2cache_wbinv_range */ + feroceon_l2cache_inv_range, /* l2cache_inv_range */ + feroceon_l2cache_wb_range, /* l2cache_wb_range */ + + /* Other functions */ + + cpufunc_nullop, /* flush_prefetchbuf */ + armv4_drain_writebuf, /* drain_writebuf */ + cpufunc_nullop, /* flush_brnchtgt_C */ + (void *)cpufunc_nullop, /* flush_brnchtgt_E */ + + (void *)cpufunc_nullop, /* sleep */ + + /* Soft functions */ + + cpufunc_null_fixup, /* dataabt_fixup */ + cpufunc_null_fixup, /* prefetchabt_fixup */ + + arm10_context_switch, /* context_switch */ + + arm10_setup /* cpu setup */ +}; #endif /* CPU_ARM9E || CPU_ARM10 */ #ifdef CPU_ARM10 @@ -933,9 +993,36 @@ set_cpufuncs() } #endif /* CPU_ARM9 */ #if defined(CPU_ARM9E) || defined(CPU_ARM10) - if (cputype == CPU_ID_ARM926EJS || - cputype == CPU_ID_ARM1026EJS) { - cpufuncs = armv5_ec_cpufuncs; + if (cputype == CPU_ID_ARM926EJS || cputype == CPU_ID_ARM1026EJS || + cputype == CPU_ID_MV88FR131 || cputype == CPU_ID_MV88FR571_VD || + cputype == CPU_ID_MV88FR571_41) { + if (cputype == CPU_ID_MV88FR131 || + cputype == CPU_ID_MV88FR571_VD || + cputype == CPU_ID_MV88FR571_41) { + + cpufuncs = feroceon_cpufuncs; + /* + * Workaround for Marvell MV78100 CPU: Cache prefetch + * mechanism may affect the cache coherency validity, + * so it needs to be disabled. + * + * Refer to errata document MV-S501058-00C.pdf (p. 3.1 + * L2 Prefetching Mechanism) for details. + */ + if (cputype == CPU_ID_MV88FR571_VD || + cputype == CPU_ID_MV88FR571_41) { + feroceon_control_ext(0xffffffff, + FC_DCACHE_STREAM_EN | FC_WR_ALLOC_EN | + FC_BRANCH_TARG_BUF_DIS | FC_L2CACHE_EN | + FC_L2_PREF_DIS); + } else { + feroceon_control_ext(0xffffffff, + FC_DCACHE_STREAM_EN | FC_WR_ALLOC_EN | + FC_BRANCH_TARG_BUF_DIS | FC_L2CACHE_EN); + } + } else + cpufuncs = armv5_ec_cpufuncs; + cpu_reset_needs_v4_MMU_disable = 1; /* V4 or higher */ get_cachetype_cp15(); pmap_pte_init_generic(); diff --git a/sys/arm/arm/cpufunc_asm_feroceon.S b/sys/arm/arm/cpufunc_asm_feroceon.S new file mode 100644 index 0000000..0e89c63 --- /dev/null +++ b/sys/arm/arm/cpufunc_asm_feroceon.S @@ -0,0 +1,386 @@ +/*- + * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. + * All rights reserved. + * + * Developed by Semihalf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of MARVELL nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <machine/asm.h> +__FBSDID("$FreeBSD$"); + +#include <machine/param.h> + +.Lferoceon_cache_line_size: + .word _C_LABEL(arm_pdcache_line_size) +.Lferoceon_asm_page_mask: + .word _C_LABEL(PAGE_MASK) + +ENTRY(feroceon_setttb) + /* Disable irqs */ + mrs r2, cpsr + orr r3, r2, #I32_bit | F32_bit + msr cpsr_c, r3 + + mov r1, #0 + mcr p15, 0, r1, c7, c5, 0 /* Invalidate ICache */ +1: mrc p15, 0, r15, c7, c14, 3 /* Test, clean and invalidate DCache */ + bne 1b /* More to do? */ + + mcr p15, 1, r1, c15, c9, 0 /* Clean L2 */ + mcr p15, 1, r1, c15, c11, 0 /* Invalidate L2 */ + + /* Reenable irqs */ + msr cpsr_c, r2 + + mcr p15, 0, r1, c7, c10, 4 /* drain the write buffer */ + + mcr p15, 0, r0, c2, c0, 0 /* load new TTB */ + + mcr p15, 0, r0, c8, c7, 0 /* invalidate I+D TLBs */ + RET + +ENTRY(feroceon_dcache_wbinv_range) + str lr, [sp, #-4]! + mrs lr, cpsr + /* Start with cache line aligned address */ + ldr ip, .Lferoceon_cache_line_size + ldr ip, [ip] + sub ip, ip, #1 + and r2, r0, ip + add r1, r1, r2 + add r1, r1, ip + bics r1, r1, ip + bics r0, r0, ip + + ldr ip, .Lferoceon_asm_page_mask + and r2, r0, ip + rsb r2, r2, #PAGE_SIZE + cmp r1, r2 + movcc ip, r1 + movcs ip, r2 +1: + add r3, r0, ip + sub r2, r3, #1 + /* Disable irqs */ + orr r3, lr, #I32_bit | F32_bit + msr cpsr_c, r3 + mcr p15, 5, r0, c15, c15, 0 /* Clean and inv zone start address */ + mcr p15, 5, r2, c15, c15, 1 /* Clean and inv zone end address */ + /* Enable irqs */ + msr cpsr_c, lr + + add r0, r0, ip + sub r1, r1, ip + cmp r1, #PAGE_SIZE + movcc ip, r1 + movcs ip, #PAGE_SIZE + cmp r1, #0 + bne 1b + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ + ldr lr, [sp], #4 + RET + +ENTRY(feroceon_idcache_wbinv_range) + str lr, [sp, #-4]! + mrs lr, cpsr + /* Start with cache line aligned address */ + ldr ip, .Lferoceon_cache_line_size + ldr ip, [ip] + sub ip, ip, #1 + and r2, r0, ip + add r1, r1, r2 + add r1, r1, ip + bics r1, r1, ip + bics r0, r0, ip + + ldr ip, .Lferoceon_asm_page_mask + and r2, r0, ip + rsb r2, r2, #PAGE_SIZE + cmp r1, r2 + movcc ip, r1 + movcs ip, r2 +1: + add r3, r0, ip + sub r2, r3, #1 + /* Disable irqs */ + orr r3, lr, #I32_bit | F32_bit + msr cpsr_c, r3 + mcr p15, 5, r0, c15, c15, 0 /* Clean and inv zone start address */ + mcr p15, 5, r2, c15, c15, 1 /* Clean and inv zone end address */ + /* Enable irqs */ + msr cpsr_c, lr + + /* Invalidate and clean icache line by line */ + ldr r3, .Lferoceon_cache_line_size + ldr r3, [r3] +2: + mcr p15, 0, r0, c7, c5, 1 + add r0, r0, r3 + cmp r2, r0 + bhi 2b + + add r0, r2, #1 + sub r1, r1, ip + cmp r1, #PAGE_SIZE + movcc ip, r1 + movcs ip, #PAGE_SIZE + cmp r1, #0 + bne 1b + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ + ldr lr, [sp], #4 + RET + +ENTRY(feroceon_dcache_inv_range) + str lr, [sp, #-4]! + mrs lr, cpsr + /* Start with cache line aligned address */ + ldr ip, .Lferoceon_cache_line_size + ldr ip, [ip] + sub ip, ip, #1 + and r2, r0, ip + add r1, r1, r2 + add r1, r1, ip + bics r1, r1, ip + bics r0, r0, ip + + ldr ip, .Lferoceon_asm_page_mask + and r2, r0, ip + rsb r2, r2, #PAGE_SIZE + cmp r1, r2 + movcc ip, r1 + movcs ip, r2 +1: + add r3, r0, ip + sub r2, r3, #1 + /* Disable irqs */ + orr r3, lr, #I32_bit | F32_bit + msr cpsr_c, r3 + mcr p15, 5, r0, c15, c14, 0 /* Inv zone start address */ + mcr p15, 5, r2, c15, c14, 1 /* Inv zone end address */ + /* Enable irqs */ + msr cpsr_c, lr + + add r0, r0, ip + sub r1, r1, ip + cmp r1, #PAGE_SIZE + movcc ip, r1 + movcs ip, #PAGE_SIZE + cmp r1, #0 + bne 1b + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ + ldr lr, [sp], #4 + RET + +ENTRY(feroceon_dcache_wb_range) + str lr, [sp, #-4]! + mrs lr, cpsr + /* Start with cache line aligned address */ + ldr ip, .Lferoceon_cache_line_size + ldr ip, [ip] + sub ip, ip, #1 + and r2, r0, ip + add r1, r1, r2 + add r1, r1, ip + bics r1, r1, ip + bics r0, r0, ip + + ldr ip, .Lferoceon_asm_page_mask + and r2, r0, ip + rsb r2, r2, #PAGE_SIZE + cmp r1, r2 + movcc ip, r1 + movcs ip, r2 +1: + add r3, r0, ip + sub r2, r3, #1 + /* Disable irqs */ + orr r3, lr, #I32_bit | F32_bit + msr cpsr_c, r3 + mcr p15, 5, r0, c15, c13, 0 /* Clean zone start address */ + mcr p15, 5, r2, c15, c13, 1 /* Clean zone end address */ + /* Enable irqs */ + msr cpsr_c, lr + + add r0, r0, ip + sub r1, r1, ip + cmp r1, #PAGE_SIZE + movcc ip, r1 + movcs ip, #PAGE_SIZE + cmp r1, #0 + bne 1b + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ + ldr lr, [sp], #4 + RET + +ENTRY(feroceon_l2cache_wbinv_range) + str lr, [sp, #-4]! + mrs lr, cpsr + /* Start with cache line aligned address */ + ldr ip, .Lferoceon_cache_line_size + ldr ip, [ip] + sub ip, ip, #1 + and r2, r0, ip + add r1, r1, r2 + add r1, r1, ip + bics r1, r1, ip + bics r0, r0, ip + + ldr ip, .Lferoceon_asm_page_mask + and r2, r0, ip + rsb r2, r2, #PAGE_SIZE + cmp r1, r2 + movcc ip, r1 + movcs ip, r2 +1: + add r3, r0, ip + sub r2, r3, #1 + /* Disable irqs */ + orr r3, lr, #I32_bit | F32_bit + msr cpsr_c, r3 + mcr p15, 1, r0, c15, c9, 4 /* Clean L2 zone start address */ + mcr p15, 1, r2, c15, c9, 5 /* Clean L2 zone end address */ + mcr p15, 1, r0, c15, c11, 4 /* Inv L2 zone start address */ + mcr p15, 1, r2, c15, c11, 5 /* Inv L2 zone end address */ + /* Enable irqs */ + msr cpsr_c, lr + + add r0, r0, ip + sub r1, r1, ip + cmp r1, #PAGE_SIZE + movcc ip, r1 + movcs ip, #PAGE_SIZE + cmp r1, #0 + bne 1b + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ + ldr lr, [sp], #4 + RET + +ENTRY(feroceon_l2cache_inv_range) + str lr, [sp, #-4]! + mrs lr, cpsr + /* Start with cache line aligned address */ + ldr ip, .Lferoceon_cache_line_size + ldr ip, [ip] + sub ip, ip, #1 + and r2, r0, ip + add r1, r1, r2 + add r1, r1, ip + bics r1, r1, ip + bics r0, r0, ip + + ldr ip, .Lferoceon_asm_page_mask + and r2, r0, ip + rsb r2, r2, #PAGE_SIZE + cmp r1, r2 + movcc ip, r1 + movcs ip, r2 +1: + add r3, r0, ip + sub r2, r3, #1 + /* Disable irqs */ + orr r3, lr, #I32_bit | F32_bit + msr cpsr_c, r3 + mcr p15, 1, r0, c15, c11, 4 /* Inv L2 zone start address */ + mcr p15, 1, r2, c15, c11, 5 /* Inv L2 zone end address */ + /* Enable irqs */ + msr cpsr_c, lr + + add r0, r0, ip + sub r1, r1, ip + cmp r1, #PAGE_SIZE + movcc ip, r1 + movcs ip, #PAGE_SIZE + cmp r1, #0 + bne 1b + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ + ldr lr, [sp], #4 + RET + +ENTRY(feroceon_l2cache_wb_range) + str lr, [sp, #-4]! + mrs lr, cpsr + /* Start with cache line aligned address */ + ldr ip, .Lferoceon_cache_line_size + ldr ip, [ip] + sub ip, ip, #1 + and r2, r0, ip + add r1, r1, r2 + add r1, r1, ip + bics r1, r1, ip + bics r0, r0, ip + + ldr ip, .Lferoceon_asm_page_mask + and r2, r0, ip + rsb r2, r2, #PAGE_SIZE + cmp r1, r2 + movcc ip, r1 + movcs ip, r2 +1: + add r3, r0, ip + sub r2, r3, #1 + /* Disable irqs */ + orr r3, lr, #I32_bit | F32_bit + msr cpsr_c, r3 + mcr p15, 1, r0, c15, c9, 4 /* Clean L2 zone start address */ + mcr p15, 1, r2, c15, c9, 5 /* Clean L2 zone end address */ + /* Enable irqs */ + msr cpsr_c, lr + + add r0, r0, ip + sub r1, r1, ip + cmp r1, #PAGE_SIZE + movcc ip, r1 + movcs ip, #PAGE_SIZE + cmp r1, #0 + bne 1b + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ + ldr lr, [sp], #4 + RET + +ENTRY(feroceon_l2cache_wbinv_all) + mov r0, #0 + mcr p15, 1, r0, c15, c9, 0 /* Clean L2 */ + mcr p15, 1, r0, c15, c11, 0 /* Invalidate L2 */ + mcr p15, 0, r0, c7, c10, 4 /* drain the write buffer */ + RET + +ENTRY(feroceon_control_ext) + mrc p15, 1, r3, c15, c1, 0 /* Read the control register */ + bic r2, r3, r0 /* Clear bits */ + eor r2, r2, r1 /* XOR bits */ + + teq r2, r3 /* Only write if there is a change */ + mcrne p15, 1, r2, c15, c1, 0 /* Write new control register */ + mov r0, r3 /* Return old value */ + RET diff --git a/sys/arm/arm/identcpu.c b/sys/arm/arm/identcpu.c index 82e5c71..c8013b7 100644 --- a/sys/arm/arm/identcpu.c +++ b/sys/arm/arm/identcpu.c @@ -75,7 +75,8 @@ enum cpu_class { CPU_CLASS_ARM10EJ, CPU_CLASS_SA1, CPU_CLASS_XSCALE, - CPU_CLASS_ARM11J + CPU_CLASS_ARM11J, + CPU_CLASS_MARVELL }; static const char * const generic_steppings[16] = { @@ -304,6 +305,15 @@ const struct cpuidtab cpuids[] = { { CPU_ID_ARM1136JSR1, CPU_CLASS_ARM11J, "ARM1136J-S R1", generic_steppings }, + { CPU_ID_MV88FR131, CPU_CLASS_MARVELL, "Feroceon 88FR131", + generic_steppings }, + + { CPU_ID_MV88FR571_VD, CPU_CLASS_MARVELL, "Feroceon 88FR571-VD", + generic_steppings }, + + { CPU_ID_MV88FR571_41, CPU_CLASS_MARVELL, "Early Feroceon 88FR571", + generic_steppings }, + { 0, CPU_CLASS_NONE, NULL, NULL } }; diff --git a/sys/arm/include/armreg.h b/sys/arm/include/armreg.h index eabcea8..6ba8cf4 100644 --- a/sys/arm/include/armreg.h +++ b/sys/arm/include/armreg.h @@ -148,6 +148,9 @@ #define CPU_ID_SA110 0x4401a100 #define CPU_ID_SA1100 0x4401a110 #define CPU_ID_TI925T 0x54029250 +#define CPU_ID_MV88FR131 0x56251310 /* Marvell Feroceon 88FR131 Core */ +#define CPU_ID_MV88FR571_VD 0x56155710 /* Marvell Feroceon 88FR571-VD Core (ID from datasheet) */ +#define CPU_ID_MV88FR571_41 0x41159260 /* Marvell Feroceon 88FR571-VD Core (actual ID from CPU reg) */ #define CPU_ID_FA526 0x66015260 #define CPU_ID_SA1110 0x6901b110 #define CPU_ID_IXP1200 0x6901c120 @@ -253,6 +256,18 @@ /* Xscale Core 3 only */ #define XSCALE_AUXCTL_LLR 0x00000400 /* Enable L2 for LLR Cache */ +/* Marvell Feroceon Extra Features Register (CP15 register 1, opcode2 0) */ +#define FC_DCACHE_REPL_LOCK 0x80000000 /* Replace DCache Lock */ +#define FC_DCACHE_STREAM_EN 0x20000000 /* DCache Streaming Switch */ +#define FC_WR_ALLOC_EN 0x10000000 /* Enable Write Allocate */ +#define FC_L2_PREF_DIS 0x01000000 /* L2 Cache Prefetch Disable */ +#define FC_L2_INV_EVICT_LINE 0x00800000 /* L2 Invalidates Uncorrectable Error Line Eviction */ +#define FC_L2CACHE_EN 0x00400000 /* L2 enable */ +#define FC_ICACHE_REPL_LOCK 0x00080000 /* Replace ICache Lock */ +#define FC_GLOB_HIST_REG_EN 0x00040000 /* Branch Global History Register Enable */ +#define FC_BRANCH_TARG_BUF_DIS 0x00020000 /* Branch Target Buffer Disable */ +#define FC_L1_PAR_ERR_EN 0x00010000 /* L1 Parity Error Enable */ + /* Cache type register definitions */ #define CPU_CT_ISIZE(x) ((x) & 0xfff) /* I$ info */ #define CPU_CT_DSIZE(x) (((x) >> 12) & 0xfff) /* D$ info */ diff --git a/sys/arm/include/cpufunc.h b/sys/arm/include/cpufunc.h index 156b079..0e3b33b 100644 --- a/sys/arm/include/cpufunc.h +++ b/sys/arm/include/cpufunc.h @@ -376,6 +376,18 @@ extern unsigned arm10_dcache_sets_max; extern unsigned arm10_dcache_sets_inc; extern unsigned arm10_dcache_index_max; extern unsigned arm10_dcache_index_inc; + +u_int feroceon_control_ext (u_int, u_int); +void feroceon_setttb (u_int); +void feroceon_dcache_wbinv_range (vm_offset_t, vm_size_t); +void feroceon_dcache_inv_range (vm_offset_t, vm_size_t); +void feroceon_dcache_wb_range (vm_offset_t, vm_size_t); +void feroceon_idcache_wbinv_range (vm_offset_t, vm_size_t); + +void feroceon_l2cache_wbinv_range (vm_offset_t, vm_size_t); +void feroceon_l2cache_inv_range (vm_offset_t, vm_size_t); +void feroceon_l2cache_wb_range (vm_offset_t, vm_size_t); +void feroceon_l2cache_wbinv_all (void); #endif #ifdef CPU_ARM11 |