aboutsummaryrefslogtreecommitdiff
path: root/src/soc/intel/common/block/systemagent/systemagent_early.c
blob: 855d953b689827ac55a33024a8e3afe6245cd5d9 (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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/*
 * This file is part of the coreboot project.
 *
 * Copyright (C) 2017 Intel Corporation.
 *
 * 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/io.h>
#include <delay.h>
#include <device/device.h>
#include <device/pci.h>
#include <intelblocks/systemagent.h>
#include <soc/iomap.h>
#include <soc/pci_devs.h>
#include <soc/systemagent.h>
#include "systemagent_def.h"
#include <timer.h>

#if !ENV_RAMSTAGE
void bootblock_systemagent_early_init(void)
{
	uint32_t reg;
	uint8_t pciexbar_length;

	/*
	 * The PCIEXBAR is assumed to live in the memory mapped IO space under
	 * 4GiB.
	 */
	reg = 0;
	pci_io_write_config32(SA_DEV_ROOT, PCIEXBAR + 4, reg);

	/* Get PCI Express Region Length */
	switch (CONFIG_SA_PCIEX_LENGTH) {
	case 256 * MiB:
		pciexbar_length = PCIEXBAR_LENGTH_256MB;
		break;
	case 128 * MiB:
		pciexbar_length = PCIEXBAR_LENGTH_128MB;
		break;
	case 64 * MiB:
		pciexbar_length = PCIEXBAR_LENGTH_64MB;
		break;
	default:
		pciexbar_length = PCIEXBAR_LENGTH_256MB;
	}
	reg = CONFIG_MMCONF_BASE_ADDRESS | (pciexbar_length << 1)
				| PCIEXBAR_PCIEXBAREN;
	pci_io_write_config32(SA_DEV_ROOT, PCIEXBAR, reg);

	/*
	 * TSEG defines the base of SMM range. BIOS determines the base
	 * of TSEG memory which must be at or below Graphics base of GTT
	 * Stolen memory, hence its better to clear TSEG register early
	 * to avoid power on default non-zero value (if any).
	 */
	pci_write_config32(SA_DEV_ROOT, TSEG, 0);
}
#endif

void sa_set_pci_bar(const struct sa_mmio_descriptor *fixed_set_resources,
		size_t count)
{
	int i;

	for (i = 0; i < count; i++) {
		uintptr_t base;
		unsigned int index;

		index = fixed_set_resources[i].index;
		/* Check if PCI BAR already enabled */
		base = pci_read_config32(SA_DEV_ROOT, index);

		/* If enabled don't program it. */
		if (base & 0x1)
			return;

		base = fixed_set_resources[i].base;

		pci_write_config32(SA_DEV_ROOT, index, base | 1);
	}
}

/*
 * There are special BARs that actually are programmed in the MCHBAR. These
 * Intel special features, but they do consume resources that need to be
 * accounted for.
 */
void sa_set_mch_bar(const struct sa_mmio_descriptor *fixed_set_resources,
		size_t count)
{
	int i;

	for (i = 0; i < count; i++) {
		uintptr_t base;
		unsigned int index;

		base = fixed_set_resources[i].base;
		index = fixed_set_resources[i].index;
		write32((void *)(MCH_BASE_ADDRESS + index), base | 1);
	}
}

void enable_pam_region(void)
{
	/* All read and writes in this region are serviced by DRAM */
	pci_write_config8(SA_DEV_ROOT, PAM0, 0x30);
	pci_write_config8(SA_DEV_ROOT, PAM1, 0x33);
	pci_write_config8(SA_DEV_ROOT, PAM2, 0x33);
	pci_write_config8(SA_DEV_ROOT, PAM3, 0x33);
	pci_write_config8(SA_DEV_ROOT, PAM4, 0x33);
	pci_write_config8(SA_DEV_ROOT, PAM5, 0x33);
	pci_write_config8(SA_DEV_ROOT, PAM6, 0x33);
}

void enable_bios_reset_cpl(void)
{
	u8 bios_reset_cpl;

	/*
	 * Set bits 0+1 of BIOS_RESET_CPL to indicate to the CPU
	 * that BIOS has initialized memory and power management
	 */
	bios_reset_cpl = MCHBAR8(BIOS_RESET_CPL);
	bios_reset_cpl |= 3;
	MCHBAR8(BIOS_RESET_CPL) = bios_reset_cpl;
}

uint32_t sa_get_tolud_base(void)
{
	/* All regions concerned for have 1 MiB alignment. */
	return ALIGN_DOWN(pci_read_config32(SA_DEV_ROOT, TOLUD), 1*MiB);
}

static uint16_t sa_get_ggc_reg(void)
{
	return pci_read_config16(SA_DEV_ROOT, GGC);
}

size_t sa_get_dsm_size(void)
{
	return (((sa_get_ggc_reg() & G_GMS_MASK) >> G_GMS_OFFSET) * 32*MiB);
}

size_t sa_get_gsm_size(void)
{
	uint8_t ggms;

	ggms = (sa_get_ggc_reg() & G_GGMS_MASK) >> G_GGMS_OFFSET;

	/*
	 * Size of GSM: 0x0: No Preallocated Memory 0x1: 2MB Memory
	 * 0x2: 4MB Memory 0x3: 8MB Memory
	 */
	if (ggms)
		return 1*MiB << ggms;
	else
		return 0;
}

/*
 * Get DPR size in case CONFIG_SA_ENABLE_DPR is selected by SoC.
 */
size_t sa_get_dpr_size(void)
{
	uintptr_t dpr_reg;
	size_t size = 0;
	/*
	 * DMA Protected Range can be reserved below TSEG for PCODE patch
	 * or TXT/BootGuard related data.  Rather than report a base address
	 * the DPR register reports the TOP of the region, which is the same
	 * as TSEG base.  The region size is reported in MiB in bits 11:4.
	 */
	dpr_reg = pci_read_config32(SA_DEV_ROOT, DPR);
	if (dpr_reg & DPR_EPM)
		size = (dpr_reg & DPR_SIZE_MASK) << 16;

	return size;
}