Index: head/sys/powerpc/booke/booke_machdep.c =================================================================== --- head/sys/powerpc/booke/booke_machdep.c (revision 292902) +++ head/sys/powerpc/booke/booke_machdep.c (revision 292903) @@ -1,397 +1,409 @@ /*- * Copyright (C) 2006-2012 Semihalf * All rights reserved. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. */ /*- * Copyright (C) 2001 Benno Rice * All rights reserved. * * 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. * * THIS SOFTWARE IS PROVIDED BY Benno Rice ``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 TOOLS GMBH 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. * $NetBSD: machdep.c,v 1.74.2.1 2000/11/01 16:13:48 tv Exp $ */ /*- * Copyright (C) 1995, 1996 Wolfgang Solfrank. * Copyright (C) 1995, 1996 TooLs GmbH. * All rights reserved. * * 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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 __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include "opt_ddb.h" #include "opt_hwpmc_hooks.h" #include "opt_kstack_pages.h" #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(MPC85XX) || defined(QORIQ_DPAA) #include #endif #ifdef DDB #include #endif #ifdef DEBUG #define debugf(fmt, args...) printf(fmt, ##args) #else #define debugf(fmt, args...) #endif extern unsigned char kernel_text[]; extern unsigned char _etext[]; extern unsigned char _edata[]; extern unsigned char __bss_start[]; extern unsigned char __sbss_start[]; extern unsigned char __sbss_end[]; extern unsigned char _end[]; extern vm_offset_t __endkernel; /* * Bootinfo is passed to us by legacy loaders. Save the address of the * structure to handle backward compatibility. */ uint32_t *bootinfo; void print_kernel_section_addr(void); void print_kenv(void); uintptr_t booke_init(uint32_t, uint32_t); void ivor_setup(void); extern void *interrupt_vector_base; extern void *int_critical_input; extern void *int_machine_check; extern void *int_data_storage; extern void *int_instr_storage; extern void *int_external_input; extern void *int_alignment; extern void *int_fpu; extern void *int_program; extern void *int_syscall; extern void *int_decrementer; extern void *int_fixed_interval_timer; extern void *int_watchdog; extern void *int_data_tlb_error; extern void *int_inst_tlb_error; extern void *int_debug; extern void *int_vec; extern void *int_vecast; #ifdef HWPMC_HOOKS extern void *int_performance_counter; #endif #define SET_TRAP(ivor, handler) \ KASSERT(((uintptr_t)(&handler) & ~0xffffUL) == \ ((uintptr_t)(&interrupt_vector_base) & ~0xffffUL), \ ("Handler " #handler " too far from interrupt vector base")); \ mtspr(ivor, (uintptr_t)(&handler) & 0xffffUL); uintptr_t powerpc_init(vm_offset_t fdt, vm_offset_t, vm_offset_t, void *mdp); void booke_cpu_init(void); void booke_cpu_init(void) { pmap_mmu_install(MMU_TYPE_BOOKE, BUS_PROBE_GENERIC); } void ivor_setup(void) { mtspr(SPR_IVPR, ((uintptr_t)&interrupt_vector_base) & 0xffff0000); SET_TRAP(SPR_IVOR0, int_critical_input); SET_TRAP(SPR_IVOR1, int_machine_check); SET_TRAP(SPR_IVOR2, int_data_storage); SET_TRAP(SPR_IVOR3, int_instr_storage); SET_TRAP(SPR_IVOR4, int_external_input); SET_TRAP(SPR_IVOR5, int_alignment); SET_TRAP(SPR_IVOR6, int_program); SET_TRAP(SPR_IVOR8, int_syscall); SET_TRAP(SPR_IVOR10, int_decrementer); SET_TRAP(SPR_IVOR11, int_fixed_interval_timer); SET_TRAP(SPR_IVOR12, int_watchdog); SET_TRAP(SPR_IVOR13, int_data_tlb_error); SET_TRAP(SPR_IVOR14, int_inst_tlb_error); SET_TRAP(SPR_IVOR15, int_debug); #ifdef HWPMC_HOOKS SET_TRAP(SPR_IVOR35, int_performance_counter); #endif switch ((mfpvr() >> 16) & 0xffff) { case FSL_E6500: SET_TRAP(SPR_IVOR32, int_vec); SET_TRAP(SPR_IVOR33, int_vecast); /* FALLTHROUGH */ case FSL_E500mc: case FSL_E5500: SET_TRAP(SPR_IVOR7, int_fpu); } } static int booke_check_for_fdt(uint32_t arg1, vm_offset_t *dtbp) { void *ptr; if (arg1 % 8 != 0) return (-1); ptr = (void *)pmap_early_io_map(arg1, PAGE_SIZE); if (fdt_check_header(ptr) != 0) return (-1); *dtbp = (vm_offset_t)ptr; return (0); } uintptr_t booke_init(uint32_t arg1, uint32_t arg2) { uintptr_t ret; void *mdp; vm_offset_t dtbp, end; end = (uintptr_t)_end; dtbp = (vm_offset_t)NULL; /* Set up TLB initially */ bootinfo = NULL; bzero(__sbss_start, __sbss_end - __sbss_start); bzero(__bss_start, _end - __bss_start); tlb1_init(); /* * Handle the various ways we can get loaded and started: * - FreeBSD's loader passes the pointer to the metadata * in arg1, with arg2 undefined. arg1 has a value that's * relative to the kernel's link address (i.e. larger * than 0xc0000000). * - Juniper's loader passes the metadata pointer in arg2 * and sets arg1 to zero. This is to signal that the * loader maps the kernel and starts it at its link * address (unlike the FreeBSD loader). * - U-Boot passes the standard argc and argv parameters * in arg1 and arg2 (resp). arg1 is between 1 and some * relatively small number, such as 64K. arg2 is the * physical address of the argv vector. * - ePAPR loaders pass an FDT blob in r3 (arg1) and the magic hex * string 0x45504150 ('EPAP') in r6 (which has been lost by now). * r4 (arg2) is supposed to be set to zero, but is not always. */ if (arg1 == 0) /* Juniper loader */ mdp = (void *)arg2; else if (booke_check_for_fdt(arg1, &dtbp) == 0) { /* ePAPR */ end = roundup(end, 8); memmove((void *)end, (void *)dtbp, fdt_totalsize((void *)dtbp)); dtbp = end; end += fdt_totalsize((void *)dtbp); __endkernel = end; mdp = NULL; } else if (arg1 > (uintptr_t)kernel_text) /* FreeBSD loader */ mdp = (void *)arg1; else /* U-Boot */ mdp = NULL; ret = powerpc_init(dtbp, 0, 0, mdp); - /* Enable L1 caches */ + /* Default to 32 byte cache line size. */ + switch ((mfpvr()) >> 16) { + case FSL_E500mc: + case FSL_E5500: + case FSL_E6500: + cacheline_size = 64; + break; + } + + /* Enable caches */ booke_enable_l1_cache(); + booke_enable_l2_cache(); + + booke_enable_bpred(); return (ret); } #define RES_GRANULE 32 extern uint32_t tlb0_miss_locks[]; /* Initialise a struct pcpu. */ void cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t sz) { pcpu->pc_tid_next = TID_MIN; #ifdef SMP uint32_t *ptr; int words_per_gran = RES_GRANULE / sizeof(uint32_t); ptr = &tlb0_miss_locks[cpuid * words_per_gran]; pcpu->pc_booke_tlb_lock = ptr; *ptr = TLB_UNLOCKED; *(ptr + 1) = 0; /* recurse counter */ #endif } /* Shutdown the CPU as much as possible. */ void cpu_halt(void) { mtmsr(mfmsr() & ~(PSL_CE | PSL_EE | PSL_ME | PSL_DE)); while (1) ; } int ptrace_single_step(struct thread *td) { struct trapframe *tf; tf = td->td_frame; tf->srr1 |= PSL_DE; tf->cpu.booke.dbcr0 |= (DBCR0_IDM | DBCR0_IC); return (0); } int ptrace_clear_single_step(struct thread *td) { struct trapframe *tf; tf = td->td_frame; tf->srr1 &= ~PSL_DE; tf->cpu.booke.dbcr0 &= ~(DBCR0_IDM | DBCR0_IC); return (0); } void kdb_cpu_clear_singlestep(void) { register_t r; r = mfspr(SPR_DBCR0); mtspr(SPR_DBCR0, r & ~DBCR0_IC); kdb_frame->srr1 &= ~PSL_DE; } void kdb_cpu_set_singlestep(void) { register_t r; r = mfspr(SPR_DBCR0); mtspr(SPR_DBCR0, r | DBCR0_IC | DBCR0_IDM); kdb_frame->srr1 |= PSL_DE; } Index: head/sys/powerpc/booke/locore.S =================================================================== --- head/sys/powerpc/booke/locore.S (revision 292902) +++ head/sys/powerpc/booke/locore.S (revision 292903) @@ -1,777 +1,884 @@ /*- * Copyright (C) 2007-2009 Semihalf, Rafal Jaworowski * Copyright (C) 2006 Semihalf, Marian Balakowicz * All rights reserved. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. * * $FreeBSD$ */ #include "assym.s" #include "opt_hwpmc_hooks.h" #include #include #include #include #include #include #include #include #define TMPSTACKSZ 16384 .text .globl btext btext: /* * This symbol is here for the benefit of kvm_mkdb, and is supposed to * mark the start of kernel text. */ .globl kernel_text kernel_text: /* * Startup entry. Note, this must be the first thing in the text segment! */ .text .globl __start __start: /* * Assumptions on the boot loader: * - System memory starts from physical address 0 * - It's mapped by a single TLB1 entry * - TLB1 mapping is 1:1 pa to va * - Kernel is loaded at 64MB boundary * - All PID registers are set to the same value * - CPU is running in AS=0 * * Registers contents provided by the loader(8): * r1 : stack pointer * r3 : metadata pointer * * We rearrange the TLB1 layout as follows: * - Find TLB1 entry we started in * - Make sure it's protected, invalidate other entries * - Create temp entry in the second AS (make sure it's not TLB[1]) * - Switch to temp mapping * - Map 64MB of RAM in TLB1[1] * - Use AS=1, set EPN to KERNBASE and RPN to kernel load address * - Switch to to TLB1[1] mapping * - Invalidate temp mapping * * locore registers use: * r1 : stack pointer * r2 : trace pointer (AP only, for early diagnostics) * r3-r27 : scratch registers * r28 : temp TLB1 entry * r29 : initial TLB1 entry we started in * r30-r31 : arguments (metadata pointer) */ /* * Keep arguments in r30 & r31 for later use. */ mr %r30, %r3 mr %r31, %r4 /* * Initial cleanup */ li %r3, PSL_DE /* Keep debug exceptions for CodeWarrior. */ mtmsr %r3 isync mfpvr %r3 rlwinm %r3, %r3, 16, 16, 31 lis %r4, HID0_E500_DEFAULT_SET@h ori %r4, %r4, HID0_E500_DEFAULT_SET@l /* Check for e500mc and e5500 */ cmpli 0, 0, %r3, FSL_E500mc bne 2f lis %r4, HID0_E500MC_DEFAULT_SET@h ori %r4, %r4, HID0_E500MC_DEFAULT_SET@l b 3f 2: cmpli 0, 0, %r3, FSL_E5500 bne 3f lis %r4, HID0_E5500_DEFAULT_SET@h ori %r4, %r4, HID0_E5500_DEFAULT_SET@l 3: mtspr SPR_HID0, %r4 isync /* * E500mc and E5500 do not have HID1 register, so skip HID1 setup on * this core. */ cmpli 0, 0, %r3, FSL_E500mc beq 1f cmpli 0, 0, %r3, FSL_E5500 beq 1f lis %r3, HID1_E500_DEFAULT_SET@h ori %r3, %r3, HID1_E500_DEFAULT_SET@l mtspr SPR_HID1, %r3 isync 1: /* Invalidate all entries in TLB0 */ li %r3, 0 bl tlb_inval_all cmpwi %r30, 0 beq done_mapping /* * Locate the TLB1 entry that maps this code */ bl 1f 1: mflr %r3 bl tlb1_find_current /* the entry found is returned in r29 */ bl tlb1_inval_all_but_current /* * Create temporary mapping in AS=1 and switch to it */ addi %r3, %r29, 1 bl tlb1_temp_mapping_as1 mfmsr %r3 ori %r3, %r3, (PSL_IS | PSL_DS) bl 2f 2: mflr %r4 addi %r4, %r4, 20 mtspr SPR_SRR0, %r4 mtspr SPR_SRR1, %r3 rfi /* Switch context */ /* * Invalidate initial entry */ mr %r3, %r29 bl tlb1_inval_entry /* * Setup final mapping in TLB1[1] and switch to it */ /* Final kernel mapping, map in 64 MB of RAM */ lis %r3, MAS0_TLBSEL1@h /* Select TLB1 */ li %r4, 0 /* Entry 0 */ rlwimi %r3, %r4, 16, 10, 15 mtspr SPR_MAS0, %r3 isync li %r3, (TLB_SIZE_64M << MAS1_TSIZE_SHIFT)@l oris %r3, %r3, (MAS1_VALID | MAS1_IPROT)@h mtspr SPR_MAS1, %r3 /* note TS was not filled, so it's TS=0 */ isync lis %r3, KERNBASE@h ori %r3, %r3, KERNBASE@l /* EPN = KERNBASE */ #ifdef SMP ori %r3, %r3, MAS2_M@l /* WIMGE = 0b00100 */ #endif mtspr SPR_MAS2, %r3 isync /* Discover phys load address */ bl 3f 3: mflr %r4 /* Use current address */ rlwinm %r4, %r4, 0, 0, 5 /* 64MB alignment mask */ ori %r4, %r4, (MAS3_SX | MAS3_SW | MAS3_SR)@l mtspr SPR_MAS3, %r4 /* Set RPN and protection */ isync bl zero_mas7 bl zero_mas8 tlbwe isync msync /* Switch to the above TLB1[1] mapping */ bl 4f 4: mflr %r4 rlwinm %r4, %r4, 0, 8, 31 /* Current offset from kernel load address */ rlwinm %r3, %r3, 0, 0, 19 add %r4, %r4, %r3 /* Convert to kernel virtual address */ addi %r4, %r4, 36 li %r3, PSL_DE /* Note AS=0 */ mtspr SPR_SRR0, %r4 mtspr SPR_SRR1, %r3 rfi /* * Invalidate temp mapping */ mr %r3, %r28 bl tlb1_inval_entry done_mapping: /* * Setup a temporary stack */ bl 1f .long tmpstack-. 1: mflr %r1 lwz %r2,0(%r1) add %r1,%r1,%r2 addi %r1, %r1, (TMPSTACKSZ - 16) /* * Relocate kernel */ bl 1f .long _DYNAMIC-. .long _GLOBAL_OFFSET_TABLE_-. 1: mflr %r5 lwz %r3,0(%r5) /* _DYNAMIC in %r3 */ add %r3,%r3,%r5 lwz %r4,4(%r5) /* GOT pointer */ add %r4,%r4,%r5 lwz %r4,4(%r4) /* got[0] is _DYNAMIC link addr */ subf %r4,%r4,%r3 /* subtract to calculate relocbase */ bl elf_reloc_self /* * Initialise exception vector offsets */ bl ivor_setup /* * Set up arguments and jump to system initialization code */ mr %r3, %r30 mr %r4, %r31 /* Prepare core */ bl booke_init /* Switch to thread0.td_kstack now */ mr %r1, %r3 li %r3, 0 stw %r3, 0(%r1) /* Machine independet part, does not return */ bl mi_startup /* NOT REACHED */ 5: b 5b #ifdef SMP /************************************************************************/ /* AP Boot page */ /************************************************************************/ .text .globl __boot_page .align 12 __boot_page: bl 1f .globl bp_ntlb1s bp_ntlb1s: .long 0 .globl bp_tlb1 bp_tlb1: - .space 4 * 3 * 16 + .space 4 * 3 * 64 .globl bp_tlb1_end bp_tlb1_end: /* * Initial configuration */ 1: mflr %r31 /* r31 hold the address of bp_ntlb1s */ /* Set HIDs */ mfpvr %r3 rlwinm %r3, %r3, 16, 16, 31 /* HID0 for E500 is default */ lis %r4, HID0_E500_DEFAULT_SET@h ori %r4, %r4, HID0_E500_DEFAULT_SET@l cmpli 0, 0, %r3, FSL_E500mc bne 2f lis %r4, HID0_E500MC_DEFAULT_SET@h ori %r4, %r4, HID0_E500MC_DEFAULT_SET@l b 3f 2: cmpli 0, 0, %r3, FSL_E5500 bne 3f lis %r4, HID0_E5500_DEFAULT_SET@h ori %r4, %r4, HID0_E5500_DEFAULT_SET@l 3: mtspr SPR_HID0, %r4 isync /* * E500mc and E5500 do not have HID1 register, so skip HID1 setup on * this core. */ cmpli 0, 0, %r3, FSL_E500mc beq 1f cmpli 0, 0, %r3, FSL_E5500 beq 1f lis %r3, HID1_E500_DEFAULT_SET@h ori %r3, %r3, HID1_E500_DEFAULT_SET@l mtspr SPR_HID1, %r3 isync 1: /* Enable branch prediction */ li %r3, BUCSR_BPEN mtspr SPR_BUCSR, %r3 isync /* Invalidate all entries in TLB0 */ li %r3, 0 bl tlb_inval_all /* * Find TLB1 entry which is translating us now */ bl 2f 2: mflr %r3 bl tlb1_find_current /* the entry number found is in r29 */ bl tlb1_inval_all_but_current /* * Create temporary translation in AS=1 and switch to it */ lwz %r3, 0(%r31) bl tlb1_temp_mapping_as1 mfmsr %r3 ori %r3, %r3, (PSL_IS | PSL_DS) bl 3f 3: mflr %r4 addi %r4, %r4, 20 mtspr SPR_SRR0, %r4 mtspr SPR_SRR1, %r3 rfi /* Switch context */ /* * Invalidate initial entry */ mr %r3, %r29 bl tlb1_inval_entry /* * Setup final mapping in TLB1[1] and switch to it */ lwz %r6, 0(%r31) addi %r5, %r31, 4 li %r4, 0 4: lis %r3, MAS0_TLBSEL1@h rlwimi %r3, %r4, 16, 12, 15 mtspr SPR_MAS0, %r3 isync lwz %r3, 0(%r5) mtspr SPR_MAS1, %r3 isync lwz %r3, 4(%r5) mtspr SPR_MAS2, %r3 isync lwz %r3, 8(%r5) mtspr SPR_MAS3, %r3 isync tlbwe isync msync addi %r5, %r5, 12 addi %r4, %r4, 1 cmpw %r4, %r6 blt 4b /* Switch to the final mapping */ bl 5f .long __boot_page-. 5: mflr %r5 lwz %r3,0(%r3) add %r5,%r5,%r3 /* __boot_page in r5 */ bl 6f 6: mflr %r3 rlwinm %r3, %r3, 0, 0xfff /* Offset from boot page start */ add %r3, %r3, %r5 /* Make this virtual address */ addi %r3, %r3, 32 li %r4, 0 /* Note AS=0 */ mtspr SPR_SRR0, %r3 mtspr SPR_SRR1, %r4 rfi /* * At this point we're running at virtual addresses KERNBASE and beyond so * it's allowed to directly access all locations the kernel was linked * against. */ /* * Invalidate temp mapping */ mr %r3, %r28 bl tlb1_inval_entry /* * Setup a temporary stack */ bl 1f .long tmpstack-. 1: mflr %r1 lwz %r2,0(%r1) add %r1,%r1,%r2 addi %r1, %r1, (TMPSTACKSZ - 16) /* * Initialise exception vector offsets */ bl ivor_setup /* * Assign our pcpu instance */ bl 1f .long ap_pcpu-. 1: mflr %r4 lwz %r3, 0(%r4) add %r3, %r3, %r4 lwz %r3, 0(%r3) mtsprg0 %r3 bl pmap_bootstrap_ap bl cpudep_ap_bootstrap /* Switch to the idle thread's kstack */ mr %r1, %r3 bl machdep_ap_bootstrap /* NOT REACHED */ 6: b 6b #endif /* SMP */ /* * Invalidate all entries in the given TLB. * * r3 TLBSEL */ tlb_inval_all: rlwinm %r3, %r3, 3, (1 << 3) /* TLBSEL */ ori %r3, %r3, (1 << 2) /* INVALL */ tlbivax 0, %r3 isync msync tlbsync msync blr /* * expects address to look up in r3, returns entry number in r29 * * FIXME: the hidden assumption is we are now running in AS=0, but we should * retrieve actual AS from MSR[IS|DS] and put it in MAS6[SAS] */ tlb1_find_current: mfspr %r17, SPR_PID0 slwi %r17, %r17, MAS6_SPID0_SHIFT mtspr SPR_MAS6, %r17 isync tlbsx 0, %r3 mfspr %r17, SPR_MAS0 rlwinm %r29, %r17, 16, 20, 31 /* MAS0[ESEL] -> r29 */ /* Make sure we have IPROT set on the entry */ mfspr %r17, SPR_MAS1 oris %r17, %r17, MAS1_IPROT@h mtspr SPR_MAS1, %r17 isync tlbwe isync msync blr /* * Invalidates a single entry in TLB1. * * r3 ESEL * r4-r5 scratched */ tlb1_inval_entry: lis %r4, MAS0_TLBSEL1@h /* Select TLB1 */ rlwimi %r4, %r3, 16, 10, 15 /* Select our entry */ mtspr SPR_MAS0, %r4 isync tlbre li %r5, 0 /* MAS1[V] = 0 */ mtspr SPR_MAS1, %r5 isync tlbwe isync msync blr /* * r3 entry of temp translation * r29 entry of current translation * r28 returns temp entry passed in r3 * r4-r5 scratched */ tlb1_temp_mapping_as1: mr %r28, %r3 /* Read our current translation */ lis %r3, MAS0_TLBSEL1@h /* Select TLB1 */ rlwimi %r3, %r29, 16, 10, 15 /* Select our current entry */ mtspr SPR_MAS0, %r3 isync tlbre /* Prepare and write temp entry */ lis %r3, MAS0_TLBSEL1@h /* Select TLB1 */ rlwimi %r3, %r28, 16, 10, 15 /* Select temp entry */ mtspr SPR_MAS0, %r3 isync mfspr %r5, SPR_MAS1 li %r4, 1 /* AS=1 */ rlwimi %r5, %r4, 12, 19, 19 li %r4, 0 /* Global mapping, TID=0 */ rlwimi %r5, %r4, 16, 8, 15 oris %r5, %r5, (MAS1_VALID | MAS1_IPROT)@h mtspr SPR_MAS1, %r5 isync mflr %r3 bl zero_mas7 bl zero_mas8 mtlr %r3 tlbwe isync msync blr /* * Loops over TLB1, invalidates all entries skipping the one which currently * maps this code. * * r29 current entry * r3-r5 scratched */ tlb1_inval_all_but_current: mr %r6, %r3 mfspr %r3, SPR_TLB1CFG /* Get number of entries */ andi. %r3, %r3, TLBCFG_NENTRY_MASK@l li %r4, 0 /* Start from Entry 0 */ 1: lis %r5, MAS0_TLBSEL1@h rlwimi %r5, %r4, 16, 10, 15 mtspr SPR_MAS0, %r5 isync tlbre mfspr %r5, SPR_MAS1 cmpw %r4, %r29 /* our current entry? */ beq 2f rlwinm %r5, %r5, 0, 2, 31 /* clear VALID and IPROT bits */ mtspr SPR_MAS1, %r5 isync tlbwe isync msync 2: addi %r4, %r4, 1 cmpw %r4, %r3 /* Check if this is the last entry */ bne 1b blr /* * MAS7 and MAS8 conditional zeroing. */ .globl zero_mas7 zero_mas7: mfpvr %r20 rlwinm %r20, %r20, 16, 16, 31 cmpli 0, 0, %r20, FSL_E500v1 beq 1f li %r20, 0 mtspr SPR_MAS7, %r20 isync 1: blr .globl zero_mas8 zero_mas8: mfpvr %r20 rlwinm %r20, %r20, 16, 16, 31 cmpli 0, 0, %r20, FSL_E500mc beq 1f cmpli 0, 0, %r20, FSL_E5500 beq 1f blr 1: li %r20, 0 mtspr SPR_MAS8, %r20 isync blr #ifdef SMP __boot_page_padding: /* * Boot page needs to be exactly 4K, with the last word of this page * acting as the reset vector, so we need to stuff the remainder. * Upon release from holdoff CPU fetches the last word of the boot * page. */ .space 4092 - (__boot_page_padding - __boot_page) b __boot_page #endif /* SMP */ /************************************************************************/ /* locore subroutines */ /************************************************************************/ /* * Cache disable/enable/inval sequences according * to section 2.16 of E500CORE RM. */ ENTRY(dcache_inval) /* Invalidate d-cache */ mfspr %r3, SPR_L1CSR0 ori %r3, %r3, (L1CSR0_DCFI | L1CSR0_DCLFR)@l msync isync mtspr SPR_L1CSR0, %r3 isync 1: mfspr %r3, SPR_L1CSR0 andi. %r3, %r3, L1CSR0_DCFI bne 1b blr ENTRY(dcache_disable) /* Disable d-cache */ mfspr %r3, SPR_L1CSR0 li %r4, L1CSR0_DCE@l not %r4, %r4 and %r3, %r3, %r4 msync isync mtspr SPR_L1CSR0, %r3 isync blr ENTRY(dcache_enable) /* Enable d-cache */ mfspr %r3, SPR_L1CSR0 oris %r3, %r3, (L1CSR0_DCPE | L1CSR0_DCE)@h ori %r3, %r3, (L1CSR0_DCPE | L1CSR0_DCE)@l msync isync mtspr SPR_L1CSR0, %r3 isync blr ENTRY(icache_inval) /* Invalidate i-cache */ mfspr %r3, SPR_L1CSR1 ori %r3, %r3, (L1CSR1_ICFI | L1CSR1_ICLFR)@l isync mtspr SPR_L1CSR1, %r3 isync 1: mfspr %r3, SPR_L1CSR1 andi. %r3, %r3, L1CSR1_ICFI bne 1b blr ENTRY(icache_disable) /* Disable i-cache */ mfspr %r3, SPR_L1CSR1 li %r4, L1CSR1_ICE@l not %r4, %r4 and %r3, %r3, %r4 isync mtspr SPR_L1CSR1, %r3 isync blr ENTRY(icache_enable) /* Enable i-cache */ mfspr %r3, SPR_L1CSR1 oris %r3, %r3, (L1CSR1_ICPE | L1CSR1_ICE)@h ori %r3, %r3, (L1CSR1_ICPE | L1CSR1_ICE)@l isync mtspr SPR_L1CSR1, %r3 isync + blr + +/* + * L2 cache disable/enable/inval sequences for E500mc. + */ + +ENTRY(l2cache_inval) + mfspr %r3, SPR_L2CSR0 + oris %r3, %r3, (L2CSR0_L2FI | L2CSR0_L2LFC)@h + ori %r3, %r3, (L2CSR0_L2FI | L2CSR0_L2LFC)@l + isync + mtspr SPR_L2CSR0, %r3 + isync +1: mfspr %r3, SPR_L2CSR0 + andis. %r3, %r3, L2CSR0_L2FI@h + bne 1b + blr + +ENTRY(l2cache_enable) + mfspr %r3, SPR_L2CSR0 + oris %r3, %r3, (L2CSR0_L2E | L2CSR0_L2PE)@h + isync + mtspr SPR_L2CSR0, %r3 + isync + blr + +/* + * Branch predictor setup. + */ +ENTRY(bpred_enable) + mfspr %r3, SPR_BUCSR + ori %r3, %r3, BUCSR_BBFI + isync + mtspr SPR_BUCSR, %r3 + isync + ori %r3, %r3, BUCSR_BPEN + isync + mtspr SPR_BUCSR, %r3 + isync + blr + +ENTRY(dataloss_erratum_access) + /* Lock two cache lines into I-Cache */ + sync + mfspr %r11, SPR_L1CSR1 + rlwinm %r11, %r11, 0, ~L1CSR1_ICUL + sync + isync + mtspr SPR_L1CSR1, %r11 + isync + + mflr %r9 + bl 1f + .long 2f-. +1: + mflr %r5 + lwz %r8, 0(%r5) + mtlr %r9 + add %r8, %r8, %r5 + icbtls 0, 0, %r8 + addi %r9, %r8, 64 + + sync + mfspr %r11, SPR_L1CSR1 +3: andi. %r11, %r11, L1CSR1_ICUL + bne 3b + + icbtls 0, 0, %r9 + + sync + mfspr %r11, SPR_L1CSR1 +3: andi. %r11, %r11, L1CSR1_ICUL + bne 3b + + b 2f + .align 6 + /* Inside a locked cacheline, wait a while, write, then wait a while */ +2: sync + + mfspr %r5, TBR_TBL +4: addis %r11, %r5, 0x100000@h /* wait around one million timebase ticks */ + mfspr %r5, TBR_TBL + subf. %r5, %r5, %r11 + bgt 4b + + stw %r4, 0(%r3) + + mfspr %r5, TBR_TBL +4: addis %r11, %r5, 0x100000@h /* wait around one million timebase ticks */ + mfspr %r5, TBR_TBL + subf. %r5, %r5, %r11 + bgt 4b + + sync + + /* + * Fill out the rest of this cache line and the next with nops, + * to ensure that nothing outside the locked area will be + * fetched due to a branch. + */ + .rept 19 + nop + .endr + + icblc 0, 0, %r8 + icblc 0, 0, %r9 + blr /* * int setfault() * * Similar to setjmp to setup for handling faults on accesses to user memory. * Any routine using this may only call bcopy, either the form below, * or the (currently used) C code optimized, so it doesn't use any non-volatile * registers. */ .globl setfault setfault: mflr %r0 mfsprg0 %r4 lwz %r4, TD_PCB(%r2) stw %r3, PCB_ONFAULT(%r4) mfcr %r4 stw %r0, 0(%r3) stw %r1, 4(%r3) stw %r2, 8(%r3) stw %r4, 12(%r3) stmw %r13, 16(%r3) /* store CR, CTR, XER, [r13 .. r31] */ li %r3, 0 /* return FALSE */ blr /************************************************************************/ /* Data section */ /************************************************************************/ .data .align 3 GLOBAL(__startkernel) .long begin GLOBAL(__endkernel) .long end .align 4 tmpstack: .space TMPSTACKSZ tmpstackbound: .space 10240 /* XXX: this really should not be necessary */ /* * Compiled KERNBASE locations */ .globl kernbase .set kernbase, KERNBASE #include Index: head/sys/powerpc/booke/machdep_e500.c =================================================================== --- head/sys/powerpc/booke/machdep_e500.c (revision 292902) +++ head/sys/powerpc/booke/machdep_e500.c (revision 292903) @@ -1,156 +1,125 @@ /*- * Copyright (c) 2011-2012 Semihalf. * All rights reserved. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE 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 THE 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 __FBSDID("$FreeBSD$"); +#include #include +#include +#include #include +#include +#include + #include #include #include extern void dcache_enable(void); extern void dcache_inval(void); extern void icache_enable(void); extern void icache_inval(void); extern void l2cache_enable(void); extern void l2cache_inval(void); +extern void bpred_enable(void); void booke_init_tlb(vm_paddr_t fdt_immr_pa) { } void booke_enable_l1_cache(void) { uint32_t csr; /* Enable D-cache if applicable */ csr = mfspr(SPR_L1CSR0); if ((csr & L1CSR0_DCE) == 0) { dcache_inval(); dcache_enable(); } csr = mfspr(SPR_L1CSR0); if ((boothowto & RB_VERBOSE) != 0 || (csr & L1CSR0_DCE) == 0) printf("L1 D-cache %sabled\n", (csr & L1CSR0_DCE) ? "en" : "dis"); /* Enable L1 I-cache if applicable. */ csr = mfspr(SPR_L1CSR1); if ((csr & L1CSR1_ICE) == 0) { icache_inval(); icache_enable(); } csr = mfspr(SPR_L1CSR1); if ((boothowto & RB_VERBOSE) != 0 || (csr & L1CSR1_ICE) == 0) printf("L1 I-cache %sabled\n", (csr & L1CSR1_ICE) ? "en" : "dis"); } -#if 0 void booke_enable_l2_cache(void) { uint32_t csr; /* Enable L2 cache on E500mc */ if ((((mfpvr() >> 16) & 0xFFFF) == FSL_E500mc) || (((mfpvr() >> 16) & 0xFFFF) == FSL_E5500)) { csr = mfspr(SPR_L2CSR0); if ((csr & L2CSR0_L2E) == 0) { l2cache_inval(); l2cache_enable(); } csr = mfspr(SPR_L2CSR0); if ((boothowto & RB_VERBOSE) != 0 || (csr & L2CSR0_L2E) == 0) printf("L2 cache %sabled\n", (csr & L2CSR0_L2E) ? "en" : "dis"); } } void -booke_enable_l3_cache(void) +booke_enable_bpred(void) { - uint32_t csr, size, ver; + uint32_t csr; - /* Enable L3 CoreNet Platform Cache (CPC) */ - ver = SVR_VER(mfspr(SPR_SVR)); - if (ver == SVR_P2041 || ver == SVR_P2041E || ver == SVR_P3041 || - ver == SVR_P3041E || ver == SVR_P5020 || ver == SVR_P5020E) { - csr = ccsr_read4(OCP85XX_CPC_CSR0); - if ((csr & OCP85XX_CPC_CSR0_CE) == 0) { - l3cache_inval(); - l3cache_enable(); - } - - csr = ccsr_read4(OCP85XX_CPC_CSR0); - if ((boothowto & RB_VERBOSE) != 0 || - (csr & OCP85XX_CPC_CSR0_CE) == 0) { - size = OCP85XX_CPC_CFG0_SZ_K(ccsr_read4(OCP85XX_CPC_CFG0)); - printf("L3 Corenet Platform Cache: %d KB %sabled\n", - size, (csr & OCP85XX_CPC_CSR0_CE) == 0 ? - "dis" : "en"); - } - } + bpred_enable(); + csr = mfspr(SPR_BUCSR); + if ((boothowto & RB_VERBOSE) != 0 || (csr & BUCSR_BPEN) == 0) + printf("Branch Predictor %sabled\n", + (csr & BUCSR_BPEN) ? "en" : "dis"); } void booke_disable_l2_cache(void) { } - -static void -l3cache_inval(void) -{ - - /* Flash invalidate the CPC and clear all the locks */ - ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_FI | - OCP85XX_CPC_CSR0_LFC); - while (ccsr_read4(OCP85XX_CPC_CSR0) & (OCP85XX_CPC_CSR0_FI | - OCP85XX_CPC_CSR0_LFC)) - ; -} - -static void -l3cache_enable(void) -{ - - ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_CE | - OCP85XX_CPC_CSR0_PE); - /* Read back to sync write */ - ccsr_read4(OCP85XX_CPC_CSR0); -} -#endif Index: head/sys/powerpc/mpc85xx/mpc85xx.c =================================================================== --- head/sys/powerpc/mpc85xx/mpc85xx.c (revision 292902) +++ head/sys/powerpc/mpc85xx/mpc85xx.c (revision 292903) @@ -1,251 +1,422 @@ /*- * Copyright (C) 2008 Semihalf, Rafal Jaworowski * All rights reserved. * * 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. * * 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 __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include +#include #include #include #include +#include #include #include +#include #include #include #include +#include +#include +#include +#include + #include /* * MPC85xx system specific routines */ uint32_t ccsr_read4(uintptr_t addr) { volatile uint32_t *ptr = (void *)addr; return (*ptr); } void ccsr_write4(uintptr_t addr, uint32_t val) { volatile uint32_t *ptr = (void *)addr; *ptr = val; powerpc_iomb(); } int law_getmax(void) { uint32_t ver; int law_max; ver = SVR_VER(mfspr(SPR_SVR)); switch (ver) { case SVR_MPC8555: case SVR_MPC8555E: law_max = 8; break; case SVR_MPC8533: case SVR_MPC8533E: case SVR_MPC8548: case SVR_MPC8548E: law_max = 10; break; case SVR_P5020: case SVR_P5020E: law_max = 32; break; default: law_max = 8; } return (law_max); } static inline void law_write(uint32_t n, uint64_t bar, uint32_t sr) { #if defined(QORIQ_DPAA) ccsr_write4(OCP85XX_LAWBARH(n), bar >> 32); ccsr_write4(OCP85XX_LAWBARL(n), bar); #else ccsr_write4(OCP85XX_LAWBAR(n), bar >> 12); #endif ccsr_write4(OCP85XX_LAWSR(n), sr); /* * The last write to LAWAR should be followed by a read * of LAWAR before any device try to use any of windows. * What more the read of LAWAR should be followed by isync * instruction. */ ccsr_read4(OCP85XX_LAWSR(n)); isync(); } static inline void law_read(uint32_t n, uint64_t *bar, uint32_t *sr) { #if defined(QORIQ_DPAA) *bar = (uint64_t)ccsr_read4(OCP85XX_LAWBARH(n)) << 32 | ccsr_read4(OCP85XX_LAWBARL(n)); #else *bar = (uint64_t)ccsr_read4(OCP85XX_LAWBAR(n)) << 12; #endif *sr = ccsr_read4(OCP85XX_LAWSR(n)); } static int law_find_free(void) { uint32_t i,sr; uint64_t bar; int law_max; law_max = law_getmax(); /* Find free LAW */ for (i = 0; i < law_max; i++) { law_read(i, &bar, &sr); if ((sr & 0x80000000) == 0) break; } return (i); } #define _LAW_SR(trgt,size) (0x80000000 | (trgt << 20) | (ffsl(size) - 2)) int law_enable(int trgt, uint64_t bar, uint32_t size) { uint64_t bar_tmp; uint32_t sr, sr_tmp; int i, law_max; if (size == 0) return (0); law_max = law_getmax(); sr = _LAW_SR(trgt, size); /* Bail if already programmed. */ for (i = 0; i < law_max; i++) { law_read(i, &bar_tmp, &sr_tmp); if (sr == sr_tmp && bar == bar_tmp) return (0); } /* Find an unused access window. */ i = law_find_free(); if (i == law_max) return (ENOSPC); law_write(i, bar, sr); return (0); } int law_disable(int trgt, uint64_t bar, uint32_t size) { uint64_t bar_tmp; uint32_t sr, sr_tmp; int i, law_max; law_max = law_getmax(); sr = _LAW_SR(trgt, size); /* Find and disable requested LAW. */ for (i = 0; i < law_max; i++) { law_read(i, &bar_tmp, &sr_tmp); if (sr == sr_tmp && bar == bar_tmp) { law_write(i, 0, 0); return (0); } } return (ENOENT); } int law_pci_target(struct resource *res, int *trgt_mem, int *trgt_io) { u_long start; uint32_t ver; int trgt, rv; ver = SVR_VER(mfspr(SPR_SVR)); start = rman_get_start(res) & 0xf000; rv = 0; trgt = -1; switch (start) { case 0x0000: case 0x8000: trgt = 0; break; case 0x1000: case 0x9000: trgt = 1; break; case 0x2000: case 0xa000: if (ver == SVR_MPC8548E || ver == SVR_MPC8548) trgt = 3; else trgt = 2; break; case 0x3000: case 0xb000: if (ver == SVR_MPC8548E || ver == SVR_MPC8548) rv = EINVAL; else trgt = 3; break; default: rv = ENXIO; } if (rv == 0) { *trgt_mem = trgt; *trgt_io = trgt; } return (rv); } +static void +l3cache_inval(void) +{ + + /* Flash invalidate the CPC and clear all the locks */ + ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_FI | + OCP85XX_CPC_CSR0_LFC); + while (ccsr_read4(OCP85XX_CPC_CSR0) & (OCP85XX_CPC_CSR0_FI | + OCP85XX_CPC_CSR0_LFC)) + ; +} + +static void +l3cache_enable(void) +{ + + ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_CE | + OCP85XX_CPC_CSR0_PE); + /* Read back to sync write */ + ccsr_read4(OCP85XX_CPC_CSR0); +} + +void +mpc85xx_enable_l3_cache(void) +{ + uint32_t csr, size, ver; + + /* Enable L3 CoreNet Platform Cache (CPC) */ + ver = SVR_VER(mfspr(SPR_SVR)); + if (ver == SVR_P2041 || ver == SVR_P2041E || ver == SVR_P3041 || + ver == SVR_P3041E || ver == SVR_P5020 || ver == SVR_P5020E) { + csr = ccsr_read4(OCP85XX_CPC_CSR0); + if ((csr & OCP85XX_CPC_CSR0_CE) == 0) { + l3cache_inval(); + l3cache_enable(); + } + + csr = ccsr_read4(OCP85XX_CPC_CSR0); + if ((boothowto & RB_VERBOSE) != 0 || + (csr & OCP85XX_CPC_CSR0_CE) == 0) { + size = OCP85XX_CPC_CFG0_SZ_K(ccsr_read4(OCP85XX_CPC_CFG0)); + printf("L3 Corenet Platform Cache: %d KB %sabled\n", + size, (csr & OCP85XX_CPC_CSR0_CE) == 0 ? + "dis" : "en"); + } + } +} + +static void +mpc85xx_dataloss_erratum_spr976(void) +{ + uint32_t svr = SVR_VER(mfspr(SPR_SVR)); + + /* Ignore whether it's the E variant */ + svr &= ~0x8; + + if (svr != SVR_P3041 && svr != SVR_P4040 && + svr != SVR_P4080 && svr != SVR_P5020) + return; + + mb(); + isync(); + mtspr(976, (mfspr(976) & ~0x1f8) | 0x48); + isync(); +} + +static vm_offset_t +mpc85xx_map_dcsr(void) +{ + phandle_t node; + u_long b, s; + int err; + + /* + * Try to access the dcsr node directly i.e. through /aliases/. + */ + if ((node = OF_finddevice("dcsr")) != -1) + if (fdt_is_compatible_strict(node, "fsl,dcsr")) + goto moveon; + /* + * Find the node the long way. + */ + if ((node = OF_finddevice("/")) == -1) + return (ENXIO); + + if ((node = ofw_bus_find_compatible(node, "fsl,dcsr")) == 0) + return (ENXIO); + +moveon: + err = fdt_get_range(node, 0, &b, &s); + + if (err != 0) + return (err); + +#ifdef QORIQ_DPAA + law_enable(OCP85XX_TGTIF_DCSR, b, 0x400000); +#endif + return pmap_early_io_map(b, 0x400000); +} + + + +void +mpc85xx_fix_errata(vm_offset_t va_ccsr) +{ + uint32_t svr = SVR_VER(mfspr(SPR_SVR)); + vm_offset_t va_dcsr; + + /* Ignore whether it's the E variant */ + svr &= ~0x8; + + if (svr != SVR_P3041 && svr != SVR_P4040 && + svr != SVR_P4080 && svr != SVR_P5020) + return; + + if (mfmsr() & PSL_EE) + return; + + /* + * dcsr region need to be mapped thus patch can refer to. + * Align dcsr right after ccsbar. + */ + va_dcsr = mpc85xx_map_dcsr(); + if (va_dcsr == 0) + goto err; + + /* + * As A004510 errata specify, special purpose register 976 + * SPR976[56:60] = 6'b001001 must be set. e500mc core reference manual + * does not document SPR976 register. + */ + mpc85xx_dataloss_erratum_spr976(); + + /* + * Specific settings in the CCF and core platform cache (CPC) + * are required to reconfigure the CoreNet coherency fabric. + * The register settings that should be updated are described + * in errata and relay on base address, offset and updated value. + * Special conditions must be used to update these registers correctly. + */ + dataloss_erratum_access(va_dcsr + 0xb0e08, 0xe0201800); + dataloss_erratum_access(va_dcsr + 0xb0e18, 0xe0201800); + dataloss_erratum_access(va_dcsr + 0xb0e38, 0xe0400000); + dataloss_erratum_access(va_dcsr + 0xb0008, 0x00900000); + dataloss_erratum_access(va_dcsr + 0xb0e40, 0xe00a0000); + + switch (svr) { + case SVR_P5020: + dataloss_erratum_access(va_ccsr + 0x18600, 0xc0000000); + break; + case SVR_P4040: + case SVR_P4080: + dataloss_erratum_access(va_ccsr + 0x18600, 0xff000000); + break; + case SVR_P3041: + dataloss_erratum_access(va_ccsr + 0x18600, 0xf0000000); + } + dataloss_erratum_access(va_ccsr + 0x10f00, 0x415e5000); + dataloss_erratum_access(va_ccsr + 0x11f00, 0x415e5000); + +err: + return; +} Index: head/sys/powerpc/mpc85xx/mpc85xx.h =================================================================== --- head/sys/powerpc/mpc85xx/mpc85xx.h (revision 292902) +++ head/sys/powerpc/mpc85xx/mpc85xx.h (revision 292903) @@ -1,113 +1,151 @@ /*- * Copyright (C) 2008 Semihalf, Rafal Jaworowski * Copyright 2006 by Juniper Networks. * All rights reserved. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE 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. * * $FreeBSD$ */ #ifndef _MPC85XX_H_ #define _MPC85XX_H_ #include /* * Configuration control and status registers */ extern vm_offset_t ccsrbar_va; #define CCSRBAR_VA ccsrbar_va #define OCP85XX_CCSRBAR (CCSRBAR_VA + 0x0) #define OCP85XX_BPTR (CCSRBAR_VA + 0x20) +#define OCP85XX_BSTRH (CCSRBAR_VA + 0x20) +#define OCP85XX_BSTRL (CCSRBAR_VA + 0x24) +#define OCP85XX_BSTAR (CCSRBAR_VA + 0x28) + +#define OCP85XX_COREDISR (CCSRBAR_VA + 0xE0094) +#define OCP85XX_BRR (CCSRBAR_VA + 0xE00E4) + /* + * Run Control and Power Management registers + */ +#define CCSR_CTBENR (CCSRBAR_VA + 0xE2084) +#define CCSR_CTBCKSELR (CCSRBAR_VA + 0xE208C) +#define CCSR_CTBCHLTCR (CCSRBAR_VA + 0xE2094) + +/* + * DDR Memory controller. + */ +#define OCP85XX_DDR1_CS0_CONFIG (CCSRBAR_VA + 0x8080) + +/* * E500 Coherency Module registers */ #define OCP85XX_EEBPCR (CCSRBAR_VA + 0x1010) /* * Local access registers */ #if defined(QORIQ_DPAA) /* Write order: OCP_LAWBARH -> OCP_LAWBARL -> OCP_LAWSR */ #define OCP85XX_LAWBARH(n) (CCSRBAR_VA + 0xc00 + 0x10 * (n)) #define OCP85XX_LAWBARL(n) (CCSRBAR_VA + 0xc04 + 0x10 * (n)) #define OCP85XX_LAWSR(n) (CCSRBAR_VA + 0xc08 + 0x10 * (n)) #else #define OCP85XX_LAWBAR(n) (CCSRBAR_VA + 0xc08 + 0x10 * (n)) #define OCP85XX_LAWSR(n) (CCSRBAR_VA + 0xc10 + 0x10 * (n)) #endif /* Attribute register */ #define OCP85XX_ENA_MASK 0x80000000 #define OCP85XX_DIS_MASK 0x7fffffff #if defined(QORIQ_DPAA) #define OCP85XX_TGTIF_LBC 0x1f #define OCP85XX_TGTIF_RAM_INTL 0x14 #define OCP85XX_TGTIF_RAM1 0x10 #define OCP85XX_TGTIF_RAM2 0x11 #define OCP85XX_TGTIF_BMAN 0x18 +#define OCP85XX_TGTIF_DCSR 0x1D #define OCP85XX_TGTIF_QMAN 0x3C #define OCP85XX_TRGT_SHIFT 20 #else #define OCP85XX_TGTIF_LBC 0x04 #define OCP85XX_TGTIF_RAM_INTL 0x0b #define OCP85XX_TGTIF_RIO 0x0c #define OCP85XX_TGTIF_RAM1 0x0f #define OCP85XX_TGTIF_RAM2 0x16 #endif /* * L2 cache registers */ #define OCP85XX_L2CTL (CCSRBAR_VA + 0x20000) /* + * L3 CoreNet platform cache (CPC) registers + */ +#define OCP85XX_CPC_CSR0 (CCSRBAR_VA + 0x10000) +#define OCP85XX_CPC_CSR0_CE 0x80000000 +#define OCP85XX_CPC_CSR0_PE 0x40000000 +#define OCP85XX_CPC_CSR0_FI 0x00200000 +#define OCP85XX_CPC_CSR0_WT 0x00080000 +#define OCP85XX_CPC_CSR0_FL 0x00000800 +#define OCP85XX_CPC_CSR0_LFC 0x00000400 +#define OCP85XX_CPC_CFG0 (CCSRBAR_VA + 0x10008) +#define OCP85XX_CPC_CFG_SZ_MASK 0x00003fff +#define OCP85XX_CPC_CFG0_SZ_K(x) (((x) & OCP85XX_CPC_CFG_SZ_MASK) << 6) + +/* * Power-On Reset configuration */ #define OCP85XX_PORDEVSR (CCSRBAR_VA + 0xe000c) #define OCP85XX_PORDEVSR_IO_SEL 0x00780000 #define OCP85XX_PORDEVSR_IO_SEL_SHIFT 19 #define OCP85XX_PORDEVSR2 (CCSRBAR_VA + 0xe0014) /* * Status Registers. */ #define OCP85XX_RSTCR (CCSRBAR_VA + 0xe00b0) /* * Prototypes. */ uint32_t ccsr_read4(uintptr_t addr); void ccsr_write4(uintptr_t addr, uint32_t val); int law_enable(int trgt, uint64_t bar, uint32_t size); int law_disable(int trgt, uint64_t bar, uint32_t size); int law_getmax(void); int law_pci_target(struct resource *, int *, int *); DECLARE_CLASS(mpc85xx_platform); int mpc85xx_attach(platform_t); + +void mpc85xx_enable_l3_cache(void); +void mpc85xx_fix_errata(vm_offset_t); +void dataloss_erratum_access(vm_offset_t, uint32_t); #endif /* _MPC85XX_H_ */ Index: head/sys/powerpc/mpc85xx/platform_mpc85xx.c =================================================================== --- head/sys/powerpc/mpc85xx/platform_mpc85xx.c (revision 292902) +++ head/sys/powerpc/mpc85xx/platform_mpc85xx.c (revision 292903) @@ -1,404 +1,480 @@ /*- * Copyright (c) 2008-2012 Semihalf. * All rights reserved. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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 "opt_platform.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include "platform_if.h" #ifdef SMP extern void *ap_pcpu; extern vm_paddr_t kernload; /* Kernel physical load address */ extern uint8_t __boot_page[]; /* Boot page body */ extern uint32_t bp_ntlb1s; extern uint32_t bp_tlb1[]; extern uint32_t bp_tlb1_end[]; #endif extern uint32_t *bootinfo; vm_offset_t ccsrbar_va; static int cpu, maxcpu; static int mpc85xx_probe(platform_t); static void mpc85xx_mem_regions(platform_t, struct mem_region *phys, int *physsz, struct mem_region *avail, int *availsz); static u_long mpc85xx_timebase_freq(platform_t, struct cpuref *cpuref); static int mpc85xx_smp_first_cpu(platform_t, struct cpuref *cpuref); static int mpc85xx_smp_next_cpu(platform_t, struct cpuref *cpuref); static int mpc85xx_smp_get_bsp(platform_t, struct cpuref *cpuref); static int mpc85xx_smp_start_cpu(platform_t, struct pcpu *cpu); static void mpc85xx_reset(platform_t); static platform_method_t mpc85xx_methods[] = { PLATFORMMETHOD(platform_probe, mpc85xx_probe), PLATFORMMETHOD(platform_attach, mpc85xx_attach), PLATFORMMETHOD(platform_mem_regions, mpc85xx_mem_regions), PLATFORMMETHOD(platform_timebase_freq, mpc85xx_timebase_freq), PLATFORMMETHOD(platform_smp_first_cpu, mpc85xx_smp_first_cpu), PLATFORMMETHOD(platform_smp_next_cpu, mpc85xx_smp_next_cpu), PLATFORMMETHOD(platform_smp_get_bsp, mpc85xx_smp_get_bsp), PLATFORMMETHOD(platform_smp_start_cpu, mpc85xx_smp_start_cpu), PLATFORMMETHOD(platform_reset, mpc85xx_reset), PLATFORMMETHOD_END }; DEFINE_CLASS_0(mpc85xx, mpc85xx_platform, mpc85xx_methods, 0); PLATFORM_DEF(mpc85xx_platform); static int mpc85xx_probe(platform_t plat) { u_int pvr = mfpvr() >> 16; if ((pvr & 0xfff0) == FSL_E500v1) return (BUS_PROBE_DEFAULT); return (ENXIO); } int mpc85xx_attach(platform_t plat) { phandle_t cpus, child, ccsr; const char *soc_name_guesses[] = {"/soc", "soc", NULL}; const char **name; pcell_t ranges[6], acells, pacells, scells; uint32_t sr; uint64_t ccsrbar, ccsrsize; int i, law_max, tgt; if ((cpus = OF_finddevice("/cpus")) != -1) { for (maxcpu = 0, child = OF_child(cpus); child != 0; child = OF_peer(child), maxcpu++) ; } else maxcpu = 1; /* * Locate CCSR region. Irritatingly, there is no way to find it * unless you already know where it is. Try to infer its location * from the device tree. */ ccsr = -1; for (name = soc_name_guesses; *name != NULL && ccsr == -1; name++) ccsr = OF_finddevice(*name); if (ccsr == -1) { char type[64]; /* That didn't work. Search for devices of type "soc" */ child = OF_child(OF_peer(0)); for (OF_child(child); child != 0; child = OF_peer(child)) { if (OF_getprop(child, "device_type", type, sizeof(type)) <= 0) continue; if (strcmp(type, "soc") == 0) { ccsr = child; break; } } } if (ccsr == -1) panic("Could not locate CCSR window!"); OF_getprop(ccsr, "#size-cells", &scells, sizeof(scells)); OF_getprop(ccsr, "#address-cells", &acells, sizeof(acells)); OF_searchprop(OF_parent(ccsr), "#address-cells", &pacells, sizeof(pacells)); OF_getprop(ccsr, "ranges", ranges, sizeof(ranges)); ccsrbar = ccsrsize = 0; for (i = acells; i < acells + pacells; i++) { ccsrbar <<= 32; ccsrbar |= ranges[i]; } for (i = acells + pacells; i < acells + pacells + scells; i++) { ccsrsize <<= 32; ccsrsize |= ranges[i]; } ccsrbar_va = pmap_early_io_map(ccsrbar, ccsrsize); + mpc85xx_fix_errata(ccsrbar_va); + mpc85xx_enable_l3_cache(); + /* * Clear local access windows. Skip DRAM entries, so we don't shoot * ourselves in the foot. */ law_max = law_getmax(); for (i = 0; i < law_max; i++) { sr = ccsr_read4(OCP85XX_LAWSR(i)); - if ((sr & 0x80000000) == 0) + if ((sr & OCP85XX_ENA_MASK) == 0) continue; tgt = (sr & 0x01f00000) >> 20; if (tgt == OCP85XX_TGTIF_RAM1 || tgt == OCP85XX_TGTIF_RAM2 || tgt == OCP85XX_TGTIF_RAM_INTL) continue; - ccsr_write4(OCP85XX_LAWSR(i), sr & 0x7fffffff); + ccsr_write4(OCP85XX_LAWSR(i), sr & OCP85XX_DIS_MASK); } return (0); } void mpc85xx_mem_regions(platform_t plat, struct mem_region *phys, int *physsz, struct mem_region *avail, int *availsz) { ofw_mem_regions(phys, physsz, avail, availsz); } static u_long mpc85xx_timebase_freq(platform_t plat, struct cpuref *cpuref) { u_long ticks; phandle_t cpus, child; pcell_t freq; if (bootinfo != NULL) { if (bootinfo[0] == 1) { /* Backward compatibility. See 8-STABLE. */ ticks = bootinfo[3] >> 3; } else { /* Compatibility with Juniper's loader. */ ticks = bootinfo[5] >> 3; } } else ticks = 0; if ((cpus = OF_finddevice("/cpus")) == -1) goto out; if ((child = OF_child(cpus)) == 0) goto out; switch (OF_getproplen(child, "timebase-frequency")) { case 4: { uint32_t tbase; OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase)); ticks = tbase; return (ticks); } case 8: { uint64_t tbase; OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase)); ticks = tbase; return (ticks); } default: break; } freq = 0; if (OF_getprop(child, "bus-frequency", (void *)&freq, sizeof(freq)) <= 0) goto out; /* * Time Base and Decrementer are updated every 8 CCB bus clocks. * HID0[SEL_TBCLK] = 0 */ if (freq != 0) +#ifdef QORIQ_DPAA + ticks = freq / 32; +#else ticks = freq / 8; +#endif out: if (ticks <= 0) panic("Unable to determine timebase frequency!"); return (ticks); } static int mpc85xx_smp_first_cpu(platform_t plat, struct cpuref *cpuref) { cpu = 0; cpuref->cr_cpuid = cpu; cpuref->cr_hwref = cpuref->cr_cpuid; if (bootverbose) printf("powerpc_smp_first_cpu: cpuid %d\n", cpuref->cr_cpuid); cpu++; return (0); } static int mpc85xx_smp_next_cpu(platform_t plat, struct cpuref *cpuref) { if (cpu >= maxcpu) return (ENOENT); cpuref->cr_cpuid = cpu++; cpuref->cr_hwref = cpuref->cr_cpuid; if (bootverbose) printf("powerpc_smp_next_cpu: cpuid %d\n", cpuref->cr_cpuid); return (0); } static int mpc85xx_smp_get_bsp(platform_t plat, struct cpuref *cpuref) { cpuref->cr_cpuid = mfspr(SPR_PIR); cpuref->cr_hwref = cpuref->cr_cpuid; return (0); } static int mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc) { #ifdef SMP uint32_t *tlb1; - uint32_t bptr, eebpcr; + vm_paddr_t bptr; + uint32_t reg; int i, timeout; + uintptr_t brr; + int cpuid; - eebpcr = ccsr_read4(OCP85XX_EEBPCR); - if ((eebpcr & (1 << (pc->pc_cpuid + 24))) != 0) { +#ifdef QORIQ_DPAA + uint32_t tgt; + + reg = ccsr_read4(OCP85XX_COREDISR); + cpuid = pc->pc_cpuid; + + if ((reg & cpuid) != 0) { + printf("%s: CPU %d is disabled!\n", __func__, pc->pc_cpuid); + return (-1); + } + + brr = OCP85XX_BRR; +#else /* QORIQ_DPAA */ + brr = OCP85XX_EEBPCR; + cpuid = pc->pc_cpuid + 24; +#endif + reg = ccsr_read4(brr); + if ((reg & (1 << cpuid)) != 0) { printf("SMP: CPU %d already out of hold-off state!\n", pc->pc_cpuid); return (ENXIO); } ap_pcpu = pc; + __asm __volatile("msync; isync"); i = 0; tlb1 = bp_tlb1; while (i < bp_ntlb1s && tlb1 < bp_tlb1_end) { mtspr(SPR_MAS0, MAS0_TLBSEL(1) | MAS0_ESEL(i)); __asm __volatile("isync; tlbre"); tlb1[0] = mfspr(SPR_MAS1); tlb1[1] = mfspr(SPR_MAS2); tlb1[2] = mfspr(SPR_MAS3); i++; tlb1 += 3; } if (i < bp_ntlb1s) bp_ntlb1s = i; + /* Flush caches to have our changes hit DRAM. */ + cpu_flush_dcache(__boot_page, 4096); + + bptr = ((vm_paddr_t)(uintptr_t)__boot_page - KERNBASE) + kernload; + KASSERT((bptr & 0xfff) == 0, + ("%s: boot page is not aligned (%#jx)", __func__, (uintmax_t)bptr)); +#ifdef QORIQ_DPAA + /* + * Read DDR controller configuration to select proper BPTR target ID. + * + * On P5020 bit 29 of DDR1_CS0_CONFIG enables DDR controllers + * interleaving. If this bit is set, we have to use + * OCP85XX_TGTIF_RAM_INTL as BPTR target ID. On other QorIQ DPAA SoCs, + * this bit is reserved and always 0. + */ + + reg = ccsr_read4(OCP85XX_DDR1_CS0_CONFIG); + if (reg & (1 << 29)) + tgt = OCP85XX_TGTIF_RAM_INTL; + else + tgt = OCP85XX_TGTIF_RAM1; + + /* + * Set BSTR to the physical address of the boot page + */ + ccsr_write4(OCP85XX_BSTRH, bptr >> 32); + ccsr_write4(OCP85XX_BSTRL, bptr); + ccsr_write4(OCP85XX_BSTAR, OCP85XX_ENA_MASK | + (tgt << OCP85XX_TRGT_SHIFT) | (ffsl(PAGE_SIZE) - 2)); + + /* Read back OCP85XX_BSTAR to synchronize write */ + ccsr_read4(OCP85XX_BSTAR); + + /* + * Enable and configure time base on new CPU. + */ + + /* Set TB clock source to platform clock / 32 */ + reg = ccsr_read4(CCSR_CTBCKSELR); + ccsr_write4(CCSR_CTBCKSELR, reg & ~(1 << pc->pc_cpuid)); + + /* Enable TB */ + reg = ccsr_read4(CCSR_CTBENR); + ccsr_write4(CCSR_CTBENR, reg | (1 << pc->pc_cpuid)); +#else + + /* * Set BPTR to the physical address of the boot page */ - bptr = ((uint32_t)__boot_page - KERNBASE) + kernload; - KASSERT((bptr & 0xfff) == 0, - ("%s: boot page is not aligned (%#x)", __func__, bptr)); bptr = (bptr >> 12) | 0x80000000u; ccsr_write4(OCP85XX_BPTR, bptr); __asm __volatile("isync; msync"); - /* Flush caches to have our changes hit DRAM. */ - cpu_flush_dcache(__boot_page, 4096); +#endif /* QORIQ_DPAA */ /* * Release AP from hold-off state */ - eebpcr |= (1 << (pc->pc_cpuid + 24)); - ccsr_write4(OCP85XX_EEBPCR, eebpcr); + reg = ccsr_read4(brr); + ccsr_write4(brr, reg | (1 << cpuid)); __asm __volatile("isync; msync"); timeout = 500; while (!pc->pc_awake && timeout--) DELAY(1000); /* wait 1ms */ /* * Disable boot page translation so that the 4K page at the default * address (= 0xfffff000) isn't permanently remapped and thus not * usable otherwise. */ +#ifdef QORIQ_DPAA + ccsr_write4(OCP85XX_BSTAR, 0); +#else ccsr_write4(OCP85XX_BPTR, 0); +#endif __asm __volatile("isync; msync"); if (!pc->pc_awake) printf("SMP: CPU %d didn't wake up.\n", pc->pc_cpuid); return ((pc->pc_awake) ? 0 : EBUSY); #else /* No SMP support */ return (ENXIO); #endif } static void mpc85xx_reset(platform_t plat) { /* * Try the dedicated reset register first. * If the SoC doesn't have one, we'll fall * back to using the debug control register. */ ccsr_write4(OCP85XX_RSTCR, 2); /* Clear DBCR0, disables debug interrupts and events. */ mtspr(SPR_DBCR0, 0); __asm __volatile("isync"); /* Enable Debug Interrupts in MSR. */ mtmsr(mfmsr() | PSL_DE); /* Enable debug interrupts and issue reset. */ mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | DBCR0_RST_SYSTEM); printf("Reset failed...\n"); while (1) ; }