162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
362306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
462306a36Sopenharmony_ci * for more details.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2005-2008 Cavium Networks, Inc
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci#ifndef __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H
962306a36Sopenharmony_ci#define __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define CP0_CVMCTL_REG $9, 7
1262306a36Sopenharmony_ci#define CP0_CVMMEMCTL_REG $11,7
1362306a36Sopenharmony_ci#define CP0_PRID_REG $15, 0
1462306a36Sopenharmony_ci#define CP0_DCACHE_ERR_REG $27, 1
1562306a36Sopenharmony_ci#define CP0_PRID_OCTEON_PASS1 0x000d0000
1662306a36Sopenharmony_ci#define CP0_PRID_OCTEON_CN30XX 0x000d0200
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci.macro	kernel_entry_setup
1962306a36Sopenharmony_ci	# Registers set by bootloader:
2062306a36Sopenharmony_ci	# (only 32 bits set by bootloader, all addresses are physical
2162306a36Sopenharmony_ci	# addresses, and need to have the appropriate memory region set
2262306a36Sopenharmony_ci	# by the kernel
2362306a36Sopenharmony_ci	# a0 = argc
2462306a36Sopenharmony_ci	# a1 = argv (kseg0 compat addr)
2562306a36Sopenharmony_ci	# a2 = 1 if init core, zero otherwise
2662306a36Sopenharmony_ci	# a3 = address of boot descriptor block
2762306a36Sopenharmony_ci	.set push
2862306a36Sopenharmony_ci	.set arch=octeon
2962306a36Sopenharmony_ci	# Read the cavium mem control register
3062306a36Sopenharmony_ci	dmfc0	v0, CP0_CVMMEMCTL_REG
3162306a36Sopenharmony_ci	# Clear the lower 6 bits, the CVMSEG size
3262306a36Sopenharmony_ci	dins	v0, $0, 0, 6
3362306a36Sopenharmony_ci	ori	v0, CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE
3462306a36Sopenharmony_ci	dmtc0	v0, CP0_CVMMEMCTL_REG	# Write the cavium mem control register
3562306a36Sopenharmony_ci	dmfc0	v0, CP0_CVMCTL_REG	# Read the cavium control register
3662306a36Sopenharmony_ci	# Disable unaligned load/store support but leave HW fixup enabled
3762306a36Sopenharmony_ci	# Needed for octeon specific memcpy
3862306a36Sopenharmony_ci	or  v0, v0, 0x5001
3962306a36Sopenharmony_ci	xor v0, v0, 0x1001
4062306a36Sopenharmony_ci	# First clear off CvmCtl[IPPCI] bit and move the performance
4162306a36Sopenharmony_ci	# counters interrupt to IRQ 6
4262306a36Sopenharmony_ci	dli	v1, ~(7 << 7)
4362306a36Sopenharmony_ci	and	v0, v0, v1
4462306a36Sopenharmony_ci	ori	v0, v0, (6 << 7)
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	mfc0	v1, CP0_PRID_REG
4762306a36Sopenharmony_ci	and	t1, v1, 0xfff8
4862306a36Sopenharmony_ci	xor	t1, t1, 0x9000		# 63-P1
4962306a36Sopenharmony_ci	beqz	t1, 4f
5062306a36Sopenharmony_ci	and	t1, v1, 0xfff8
5162306a36Sopenharmony_ci	xor	t1, t1, 0x9008		# 63-P2
5262306a36Sopenharmony_ci	beqz	t1, 4f
5362306a36Sopenharmony_ci	and	t1, v1, 0xfff8
5462306a36Sopenharmony_ci	xor	t1, t1, 0x9100		# 68-P1
5562306a36Sopenharmony_ci	beqz	t1, 4f
5662306a36Sopenharmony_ci	and	t1, v1, 0xff00
5762306a36Sopenharmony_ci	xor	t1, t1, 0x9200		# 66-PX
5862306a36Sopenharmony_ci	bnez	t1, 5f			# Skip WAR for others.
5962306a36Sopenharmony_ci	and	t1, v1, 0x00ff
6062306a36Sopenharmony_ci	slti	t1, t1, 2		# 66-P1.2 and later good.
6162306a36Sopenharmony_ci	beqz	t1, 5f
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci4:	# core-16057 work around
6462306a36Sopenharmony_ci	or	v0, v0, 0x2000		# Set IPREF bit.
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci5:	# No core-16057 work around
6762306a36Sopenharmony_ci	# Write the cavium control register
6862306a36Sopenharmony_ci	dmtc0	v0, CP0_CVMCTL_REG
6962306a36Sopenharmony_ci	sync
7062306a36Sopenharmony_ci	# Flush dcache after config change
7162306a36Sopenharmony_ci	cache	9, 0($0)
7262306a36Sopenharmony_ci	# Zero all of CVMSEG to make sure parity is correct
7362306a36Sopenharmony_ci	dli	v0, CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE
7462306a36Sopenharmony_ci	dsll	v0, 7
7562306a36Sopenharmony_ci	beqz	v0, 2f
7662306a36Sopenharmony_ci1:	dsubu	v0, 8
7762306a36Sopenharmony_ci	sd	$0, -32768(v0)
7862306a36Sopenharmony_ci	bnez	v0, 1b
7962306a36Sopenharmony_ci2:
8062306a36Sopenharmony_ci	mfc0	v0, CP0_PRID_REG
8162306a36Sopenharmony_ci	bbit0	v0, 15, 1f
8262306a36Sopenharmony_ci	# OCTEON II or better have bit 15 set.  Clear the error bits.
8362306a36Sopenharmony_ci	and	t1, v0, 0xff00
8462306a36Sopenharmony_ci	dli	v0, 0x9500
8562306a36Sopenharmony_ci	bge	t1, v0, 1f  # OCTEON III has no DCACHE_ERR_REG COP0
8662306a36Sopenharmony_ci	dli	v0, 0x27
8762306a36Sopenharmony_ci	dmtc0	v0, CP0_DCACHE_ERR_REG
8862306a36Sopenharmony_ci1:
8962306a36Sopenharmony_ci	# Get my core id
9062306a36Sopenharmony_ci	rdhwr	v0, $0
9162306a36Sopenharmony_ci	# Jump the master to kernel_entry
9262306a36Sopenharmony_ci	bne	a2, zero, octeon_main_processor
9362306a36Sopenharmony_ci	nop
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#ifdef CONFIG_SMP
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	#
9862306a36Sopenharmony_ci	# All cores other than the master need to wait here for SMP bootstrap
9962306a36Sopenharmony_ci	# to begin
10062306a36Sopenharmony_ci	#
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ciocteon_spin_wait_boot:
10362306a36Sopenharmony_ci#ifdef CONFIG_RELOCATABLE
10462306a36Sopenharmony_ci	PTR_LA	t0, octeon_processor_relocated_kernel_entry
10562306a36Sopenharmony_ci	LONG_L	t0, (t0)
10662306a36Sopenharmony_ci	beq	zero, t0, 1f
10762306a36Sopenharmony_ci	nop
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	jr	t0
11062306a36Sopenharmony_ci	nop
11162306a36Sopenharmony_ci1:
11262306a36Sopenharmony_ci#endif /* CONFIG_RELOCATABLE */
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	# This is the variable where the next core to boot is stored
11562306a36Sopenharmony_ci	PTR_LA	t0, octeon_processor_boot
11662306a36Sopenharmony_ci	# Get the core id of the next to be booted
11762306a36Sopenharmony_ci	LONG_L	t1, (t0)
11862306a36Sopenharmony_ci	# Keep looping if it isn't me
11962306a36Sopenharmony_ci	bne t1, v0, octeon_spin_wait_boot
12062306a36Sopenharmony_ci	nop
12162306a36Sopenharmony_ci	# Get my GP from the global variable
12262306a36Sopenharmony_ci	PTR_LA	t0, octeon_processor_gp
12362306a36Sopenharmony_ci	LONG_L	gp, (t0)
12462306a36Sopenharmony_ci	# Get my SP from the global variable
12562306a36Sopenharmony_ci	PTR_LA	t0, octeon_processor_sp
12662306a36Sopenharmony_ci	LONG_L	sp, (t0)
12762306a36Sopenharmony_ci	# Set the SP global variable to zero so the master knows we've started
12862306a36Sopenharmony_ci	LONG_S	zero, (t0)
12962306a36Sopenharmony_ci#ifdef __OCTEON__
13062306a36Sopenharmony_ci	syncw
13162306a36Sopenharmony_ci	syncw
13262306a36Sopenharmony_ci#else
13362306a36Sopenharmony_ci	sync
13462306a36Sopenharmony_ci#endif
13562306a36Sopenharmony_ci	# Jump to the normal Linux SMP entry point
13662306a36Sopenharmony_ci	j   smp_bootstrap
13762306a36Sopenharmony_ci	nop
13862306a36Sopenharmony_ci#else /* CONFIG_SMP */
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	#
14162306a36Sopenharmony_ci	# Someone tried to boot SMP with a non SMP kernel. All extra cores
14262306a36Sopenharmony_ci	# will halt here.
14362306a36Sopenharmony_ci	#
14462306a36Sopenharmony_ciocteon_wait_forever:
14562306a36Sopenharmony_ci	wait
14662306a36Sopenharmony_ci	b   octeon_wait_forever
14762306a36Sopenharmony_ci	nop
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#endif /* CONFIG_SMP */
15062306a36Sopenharmony_ciocteon_main_processor:
15162306a36Sopenharmony_ci	.set pop
15262306a36Sopenharmony_ci.endm
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/*
15562306a36Sopenharmony_ci * Do SMP slave processor setup necessary before we can safely execute C code.
15662306a36Sopenharmony_ci */
15762306a36Sopenharmony_ci	.macro	smp_slave_setup
15862306a36Sopenharmony_ci	.endm
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci#define USE_KEXEC_SMP_WAIT_FINAL
16162306a36Sopenharmony_ci	.macro  kexec_smp_wait_final
16262306a36Sopenharmony_ci	.set push
16362306a36Sopenharmony_ci	.set noreorder
16462306a36Sopenharmony_ci	synci		0($0)
16562306a36Sopenharmony_ci	.set pop
16662306a36Sopenharmony_ci	.endm
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci#endif /* __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H */
169