summaryrefslogtreecommitdiff
path: root/src/cpu/amd/quadcore/quadcore.c
blob: 8125fb474fef8b2b9b36d98cf5d9d77e808a382b (plain)
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
 * This file is part of the coreboot project.
 *
 * 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; version 2 of the License.
 *
 * 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.
 */

#include <arch/cpu.h>
#include <console/console.h>
#include <device/pci_ops.h>
#include <pc80/mc146818rtc.h>
#if CONFIG(HAVE_OPTION_TABLE)
#include "option_table.h"
#endif

#include "cpu/amd/quadcore/quadcore_id.c"

u32 get_core_num_in_bsp(u32 nodeid)
{
	u32 dword;
	if (is_fam15h()) {
		/* Family 15h moved CmpCap to F5x84 [7:0] */
		dword = pci_read_config32(NODE_PCI(nodeid, 5), 0x84);
		dword &= 0xff;
	} else {
		dword = pci_read_config32(NODE_PCI(nodeid, 3), 0xe8);
		dword >>= 12;
		/* Bit 15 is CmpCap[2] since Revision D. */
		if ((cpuid_ecx(0x80000008) & 0xff) > 3)
			dword = ((dword & 8) >> 1) | (dword & 3);
		else
			dword &= 3;
	}
	return dword;
}

u8 set_apicid_cpuid_lo(void)
{
	// set the NB_CFG[54]=1; why the OS will be happy with that ???
	msr_t msr;
	msr = rdmsr(NB_CFG_MSR);
	msr.hi |= (1<<(54-32)); // InitApicIdCpuIdLo
	wrmsr(NB_CFG_MSR, msr);

	return 1;
}

void real_start_other_core(uint32_t nodeid, uint32_t cores)
{
	ssize_t i;
	uint32_t dword;

	printk(BIOS_DEBUG,
		"Start other core - nodeid: %02x  cores: %02x\n", nodeid, cores);

	/* set PCI_DEV(0, 0x18+nodeid, 3), 0x44 bit 27 to redirect all MC4
	   accesses and error logging to core0 */
	dword = pci_read_config32(NODE_PCI(nodeid, 3), 0x44);
	dword |= 1 << 30;	/* SyncFloodOnDramAdrParErr=1 */
	dword |= 1 << 27;	/* NbMcaToMstCpuEn=1 */
	dword |= 1 << 21;	/* SyncFloodOnAnyUcErr=1 */
	dword |= 1 << 20;	/* SyncFloodOnWDT=1 */
	dword |= 1 << 2;	/* SyncFloodOnDramUcEcc=1 */
	pci_write_config32(NODE_PCI(nodeid, 3), 0x44, dword);
	if (is_fam15h()) {
		uint32_t core_activation_flags = 0;
		uint32_t active_cores = 0;

		/* Set PCI_DEV(0, 0x18+nodeid, 0),
		 * 0x1dc bits 7:1 to start cores
		 */
		dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x1dc);
		for (i = 1; i < cores + 1; i++)
			core_activation_flags |= 1 << i;
		/* Start the first core of each compute unit */
		active_cores |= core_activation_flags & 0x55;
		pci_write_config32(NODE_PCI(nodeid, 0), 0x1dc, dword
				  | active_cores);

		/* Each core shares a single set of MTRR registers with
		 * another core in the same compute unit, therefore, it
		 * is important that one core in each CU starts in advance
		 * of the other in order to avoid one core stomping all over
		 * the other core's settings.
		 */

		/* Wait for the first core of each compute unit to start... */
		for (i = 1; i < cores + 1; i++) {
			if (!(i & 0x1)) {
				uint32_t ap_apicid =
				get_boot_apic_id(nodeid, i);
				/* Timeout */
				wait_cpu_state(ap_apicid, F10_APSTATE_ASLEEP,
						F10_APSTATE_ASLEEP);
			}
		}

		/* Start the second core of each compute unit */
		active_cores |= core_activation_flags & 0xaa;
		pci_write_config32(NODE_PCI(nodeid, 0), 0x1dc, dword |
				   active_cores);
	} else {
		// set PCI_DEV(0, 0x18+nodeid, 0), 0x68 bit 5 to start core1
		dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x68);
		dword |= 1 << 5;
		pci_write_config32(NODE_PCI(nodeid, 0), 0x68, dword);

		if (cores > 1) {
			dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x168);
			for (i = 0; i < cores - 1; i++)
				dword |= 1 << i;
			pci_write_config32(NODE_PCI(nodeid, 0), 0x168, dword);
		}
	}
}

#if (!CONFIG(CPU_AMD_MODEL_10XXX))
//it is running on core0 of node0
static void start_other_cores(void)
{
	u32 nodes;
	u32 nodeid;

	// disable multi_core
	if (read_option(multi_core, 0) != 0)  {
		printk(BIOS_DEBUG, "Skip additional core init\n");
		return;
	}

	nodes = get_nodes();

	for (nodeid = 0; nodeid < nodes; nodeid++) {
		u32 cores = get_core_num_in_bsp(nodeid);
		printk(BIOS_DEBUG, "init node: %02x  cores: %02x pass 1\n",
			nodeid, cores);
		if (cores > 0)
			real_start_other_core(nodeid, cores);
	}
}
#endif