summaryrefslogtreecommitdiff
path: root/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h
blob: 0b2b5eb22e9b7a2d0781f9c67b3e3b00aa7c6cbe (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 2005-2008 Cavium Networks, Inc
 */
#ifndef __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H
#define __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H


#define CP0_CYCLE_COUNTER $9, 6
#define CP0_CVMCTL_REG $9, 7
#define CP0_CVMMEMCTL_REG $11,7
#define CP0_PRID_REG $15, 0
#define CP0_PRID_OCTEON_PASS1 0x000d0000
#define CP0_PRID_OCTEON_CN30XX 0x000d0200

.macro  kernel_entry_setup
	# Registers set by bootloader:
	# (only 32 bits set by bootloader, all addresses are physical
	# addresses, and need to have the appropriate memory region set
	# by the kernel
	# a0 = argc
	# a1 = argv (kseg0 compat addr)
	# a2 = 1 if init core, zero otherwise
	# a3 = address of boot descriptor block
	.set push
	.set arch=octeon
	# Read the cavium mem control register
	dmfc0   v0, CP0_CVMMEMCTL_REG
	# Clear the lower 6 bits, the CVMSEG size
	dins    v0, $0, 0, 6
	ori     v0, CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE
	dmtc0   v0, CP0_CVMMEMCTL_REG	# Write the cavium mem control register
	dmfc0   v0, CP0_CVMCTL_REG	# Read the cavium control register
#ifdef CONFIG_CAVIUM_OCTEON_HW_FIX_UNALIGNED
	# Disable unaligned load/store support but leave HW fixup enabled
	or  v0, v0, 0x5001
	xor v0, v0, 0x1001
#else
	# Disable unaligned load/store and HW fixup support
	or  v0, v0, 0x5001
	xor v0, v0, 0x5001
#endif
	# Read the processor ID register
	mfc0 v1, CP0_PRID_REG
	# Disable instruction prefetching (Octeon Pass1 errata)
	or  v0, v0, 0x2000
	# Skip reenable of prefetching for Octeon Pass1
	beq v1, CP0_PRID_OCTEON_PASS1, skip
	nop
	# Reenable instruction prefetching, not on Pass1
	xor v0, v0, 0x2000
	# Strip off pass number off of processor id
	srl v1, 8
	sll v1, 8
	# CN30XX needs some extra stuff turned off for better performance
	bne v1, CP0_PRID_OCTEON_CN30XX, skip
	nop
	# CN30XX Use random Icache replacement
	or  v0, v0, 0x400
	# CN30XX Disable instruction prefetching
	or  v0, v0, 0x2000
skip:
	# Write the cavium control register
	dmtc0   v0, CP0_CVMCTL_REG
	sync
	# Flush dcache after config change
	cache   9, 0($0)
	# Get my core id
	rdhwr   v0, $0
	# Jump the master to kernel_entry
	bne     a2, zero, octeon_main_processor
	nop

#ifdef CONFIG_SMP

	#
	# All cores other than the master need to wait here for SMP bootstrap
	# to begin
	#

	# This is the variable where the next core to boot os stored
	PTR_LA  t0, octeon_processor_boot
octeon_spin_wait_boot:
	# Get the core id of the next to be booted
	LONG_L  t1, (t0)
	# Keep looping if it isn't me
	bne t1, v0, octeon_spin_wait_boot
	nop
	# Get my GP from the global variable
	PTR_LA  t0, octeon_processor_gp
	LONG_L  gp, (t0)
	# Get my SP from the global variable
	PTR_LA  t0, octeon_processor_sp
	LONG_L  sp, (t0)
	# Set the SP global variable to zero so the master knows we've started
	LONG_S  zero, (t0)
#ifdef __OCTEON__
	syncw
	syncw
#else
	sync
#endif
	# Jump to the normal Linux SMP entry point
	j   smp_bootstrap
	nop
#else /* CONFIG_SMP */

	#
	# Someone tried to boot SMP with a non SMP kernel. All extra cores
	# will halt here.
	#
octeon_wait_forever:
	wait
	b   octeon_wait_forever
	nop

#endif /* CONFIG_SMP */
octeon_main_processor:
	.set pop
.endm

/*
 * Do SMP slave processor setup necessary before we can savely execute C code.
 */
	.macro  smp_slave_setup
	.endm

#endif /* __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H */