linux/arch/blackfin/mach-bf561/secondary.S
Yi Li eb7bd9c461 Blackfin: cleanup sync handling when enabling/disabling cplbs
The handling of updating the [DI]MEM_CONTROL MMRs does not follow proper
sync procedures as laid out in the Blackfin programming manual.  So rather
than audit/fix every call location, create helper functions that do the
right things in order to safely update these MMRs.  Then convert all call
sites to use these new helper functions.

While we're fixing the code, drop the workaround for anomaly 05000125 as
that anomaly applies to old versions of silicon that we do not support.

Signed-off-by: Yi Li <yi.li@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
2009-09-16 22:10:19 -04:00

204 lines
4.0 KiB
ArmAsm

/*
* File: arch/blackfin/mach-bf561/secondary.S
* Based on: arch/blackfin/mach-bf561/head.S
* Author: Philippe Gerum <rpm@xenomai.org>
*
* Copyright 2007 Analog Devices Inc.
*
* Description: BF561 coreB bootstrap file
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/blackfin.h>
#include <asm/asm-offsets.h>
__INIT
/* Lay the initial stack into the L1 scratch area of Core B */
#define INITIAL_STACK (COREB_L1_SCRATCH_START + L1_SCRATCH_LENGTH - 12)
ENTRY(_coreb_trampoline_start)
/* Set the SYSCFG register */
R0 = 0x36;
SYSCFG = R0; /*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/
R0 = 0;
/*Clear Out All the data and pointer Registers*/
R1 = R0;
R2 = R0;
R3 = R0;
R4 = R0;
R5 = R0;
R6 = R0;
R7 = R0;
P0 = R0;
P1 = R0;
P2 = R0;
P3 = R0;
P4 = R0;
P5 = R0;
LC0 = r0;
LC1 = r0;
L0 = r0;
L1 = r0;
L2 = r0;
L3 = r0;
/* Clear Out All the DAG Registers*/
B0 = r0;
B1 = r0;
B2 = r0;
B3 = r0;
I0 = r0;
I1 = r0;
I2 = r0;
I3 = r0;
M0 = r0;
M1 = r0;
M2 = r0;
M3 = r0;
/* Turn off the icache */
p0.l = LO(IMEM_CONTROL);
p0.h = HI(IMEM_CONTROL);
R1 = [p0];
R0 = ~ENICPLB;
R0 = R0 & R1;
/* Disabling of CPLBs should be proceeded by a CSYNC */
CSYNC;
[p0] = R0;
SSYNC;
/* Turn off the dcache */
p0.l = LO(DMEM_CONTROL);
p0.h = HI(DMEM_CONTROL);
R1 = [p0];
R0 = ~ENDCPLB;
R0 = R0 & R1;
/* Disabling of CPLBs should be proceeded by a CSYNC */
CSYNC;
[p0] = R0;
SSYNC;
/* in case of double faults, save a few things */
p0.l = _init_retx_coreb;
p0.h = _init_retx_coreb;
R0 = RETX;
[P0] = R0;
#ifdef CONFIG_DEBUG_DOUBLEFAULT
/* Only save these if we are storing them,
* This happens here, since L1 gets clobbered
* below
*/
GET_PDA(p0, r0);
r7 = [p0 + PDA_DF_RETX];
p1.l = _init_saved_retx_coreb;
p1.h = _init_saved_retx_coreb;
[p1] = r7;
r7 = [p0 + PDA_DF_DCPLB];
p1.l = _init_saved_dcplb_fault_addr_coreb;
p1.h = _init_saved_dcplb_fault_addr_coreb;
[p1] = r7;
r7 = [p0 + PDA_DF_ICPLB];
p1.l = _init_saved_icplb_fault_addr_coreb;
p1.h = _init_saved_icplb_fault_addr_coreb;
[p1] = r7;
r7 = [p0 + PDA_DF_SEQSTAT];
p1.l = _init_saved_seqstat_coreb;
p1.h = _init_saved_seqstat_coreb;
[p1] = r7;
#endif
/* Initialize stack pointer */
sp.l = lo(INITIAL_STACK);
sp.h = hi(INITIAL_STACK);
fp = sp;
usp = sp;
/* This section keeps the processor in supervisor mode
* during core B startup. Branches to the idle task.
*/
/* EVT15 = _real_start */
p0.l = lo(EVT15);
p0.h = hi(EVT15);
p1.l = _coreb_start;
p1.h = _coreb_start;
[p0] = p1;
csync;
p0.l = lo(IMASK);
p0.h = hi(IMASK);
p1.l = IMASK_IVG15;
p1.h = 0x0;
[p0] = p1;
csync;
raise 15;
p0.l = .LWAIT_HERE;
p0.h = .LWAIT_HERE;
reti = p0;
#if defined(ANOMALY_05000281)
nop; nop; nop;
#endif
rti;
.LWAIT_HERE:
jump .LWAIT_HERE;
ENDPROC(_coreb_trampoline_start)
ENTRY(_coreb_trampoline_end)
ENTRY(_coreb_start)
[--sp] = reti;
p0.l = lo(WDOGB_CTL);
p0.h = hi(WDOGB_CTL);
r0 = 0xAD6(z);
w[p0] = r0; /* Clear the watchdog. */
ssync;
/*
* switch to IDLE stack.
*/
p0.l = _secondary_stack;
p0.h = _secondary_stack;
sp = [p0];
usp = sp;
fp = sp;
sp += -12;
call _init_pda
sp += 12;
call _secondary_start_kernel;
.L_exit:
jump.s .L_exit;
ENDPROC(_coreb_start)
__FINIT