]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0 |
24774278 SG |
2 | /* |
3 | * From Coreboot northbridge/intel/sandybridge/northbridge.c | |
4 | * | |
5 | * Copyright (C) 2007-2009 coresystems GmbH | |
6 | * Copyright (C) 2011 The Chromium Authors | |
24774278 SG |
7 | */ |
8 | ||
d678a59d | 9 | #include <common.h> |
279006db | 10 | #include <dm.h> |
f7ae49fc | 11 | #include <log.h> |
401d1c4f | 12 | #include <asm/global_data.h> |
24774278 | 13 | #include <asm/msr.h> |
24774278 | 14 | #include <asm/cpu.h> |
06d336cc | 15 | #include <asm/intel_regs.h> |
24774278 SG |
16 | #include <asm/io.h> |
17 | #include <asm/pci.h> | |
18 | #include <asm/processor.h> | |
19 | #include <asm/arch/pch.h> | |
20 | #include <asm/arch/model_206ax.h> | |
21 | #include <asm/arch/sandybridge.h> | |
c05ed00a | 22 | #include <linux/delay.h> |
24774278 | 23 | |
05af050e SG |
24 | DECLARE_GLOBAL_DATA_PTR; |
25 | ||
1605b100 | 26 | int bridge_silicon_revision(struct udevice *dev) |
24774278 | 27 | { |
1605b100 SG |
28 | struct cpuid_result result; |
29 | u16 bridge_id; | |
30 | u8 stepping; | |
31 | ||
32 | result = cpuid(1); | |
33 | stepping = result.eax & 0xf; | |
34 | dm_pci_read_config16(dev, PCI_DEVICE_ID, &bridge_id); | |
35 | bridge_id &= 0xf0; | |
36 | return bridge_id | stepping; | |
24774278 SG |
37 | } |
38 | ||
1a9dd221 | 39 | static int get_pcie_bar(struct udevice *dev, u32 *base, u32 *len) |
24774278 | 40 | { |
24774278 SG |
41 | u32 pciexbar_reg; |
42 | ||
43 | *base = 0; | |
44 | *len = 0; | |
45 | ||
1a9dd221 | 46 | dm_pci_read_config32(dev, PCIEXBAR, &pciexbar_reg); |
24774278 SG |
47 | |
48 | if (!(pciexbar_reg & (1 << 0))) | |
49 | return 0; | |
50 | ||
51 | switch ((pciexbar_reg >> 1) & 3) { | |
52 | case 0: /* 256MB */ | |
53 | *base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) | | |
54 | (1 << 28)); | |
55 | *len = 256 * 1024 * 1024; | |
56 | return 1; | |
57 | case 1: /* 128M */ | |
58 | *base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) | | |
59 | (1 << 28) | (1 << 27)); | |
60 | *len = 128 * 1024 * 1024; | |
61 | return 1; | |
62 | case 2: /* 64M */ | |
63 | *base = pciexbar_reg & ((1 << 31) | (1 << 30) | (1 << 29) | | |
64 | (1 << 28) | (1 << 27) | (1 << 26)); | |
65 | *len = 64 * 1024 * 1024; | |
66 | return 1; | |
67 | } | |
68 | ||
69 | return 0; | |
70 | } | |
71 | ||
1a9dd221 | 72 | static void add_fixed_resources(struct udevice *dev, int index) |
24774278 SG |
73 | { |
74 | u32 pcie_config_base, pcie_config_size; | |
75 | ||
1a9dd221 | 76 | if (get_pcie_bar(dev, &pcie_config_base, &pcie_config_size)) { |
24774278 SG |
77 | debug("Adding PCIe config bar base=0x%08x size=0x%x\n", |
78 | pcie_config_base, pcie_config_size); | |
79 | } | |
80 | } | |
81 | ||
1605b100 | 82 | static void northbridge_dmi_init(struct udevice *dev, int rev) |
24774278 SG |
83 | { |
84 | /* Clear error status bits */ | |
85 | writel(0xffffffff, DMIBAR_REG(0x1c4)); | |
86 | writel(0xffffffff, DMIBAR_REG(0x1d0)); | |
87 | ||
88 | /* Steps prior to DMI ASPM */ | |
1605b100 | 89 | if ((rev & BASE_REV_MASK) == BASE_REV_SNB) { |
24774278 SG |
90 | clrsetbits_le32(DMIBAR_REG(0x250), (1 << 22) | (1 << 20), |
91 | 1 << 21); | |
92 | } | |
93 | ||
94 | setbits_le32(DMIBAR_REG(0x238), 1 << 29); | |
95 | ||
1605b100 | 96 | if (rev >= SNB_STEP_D0) { |
24774278 | 97 | setbits_le32(DMIBAR_REG(0x1f8), 1 << 16); |
1605b100 | 98 | } else if (rev >= SNB_STEP_D1) { |
24774278 SG |
99 | clrsetbits_le32(DMIBAR_REG(0x1f8), 1 << 26, 1 << 16); |
100 | setbits_le32(DMIBAR_REG(0x1fc), (1 << 12) | (1 << 23)); | |
101 | } | |
102 | ||
103 | /* Enable ASPM on SNB link, should happen before PCH link */ | |
1605b100 | 104 | if ((rev & BASE_REV_MASK) == BASE_REV_SNB) |
24774278 SG |
105 | setbits_le32(DMIBAR_REG(0xd04), 1 << 4); |
106 | ||
107 | setbits_le32(DMIBAR_REG(0x88), (1 << 1) | (1 << 0)); | |
108 | } | |
109 | ||
1605b100 | 110 | static void northbridge_init(struct udevice *dev, int rev) |
24774278 SG |
111 | { |
112 | u32 bridge_type; | |
113 | ||
114 | add_fixed_resources(dev, 6); | |
1605b100 | 115 | northbridge_dmi_init(dev, rev); |
24774278 SG |
116 | |
117 | bridge_type = readl(MCHBAR_REG(0x5f10)); | |
118 | bridge_type &= ~0xff; | |
119 | ||
1605b100 | 120 | if ((rev & BASE_REV_MASK) == BASE_REV_IVB) { |
24774278 SG |
121 | /* Enable Power Aware Interrupt Routing - fixed priority */ |
122 | clrsetbits_8(MCHBAR_REG(0x5418), 0xf, 0x4); | |
123 | ||
124 | /* 30h for IvyBridge */ | |
125 | bridge_type |= 0x30; | |
126 | } else { | |
127 | /* 20h for Sandybridge */ | |
128 | bridge_type |= 0x20; | |
129 | } | |
130 | writel(bridge_type, MCHBAR_REG(0x5f10)); | |
131 | ||
132 | /* | |
133 | * Set bit 0 of BIOS_RESET_CPL to indicate to the CPU | |
134 | * that BIOS has initialized memory and power management | |
135 | */ | |
136 | setbits_8(MCHBAR_REG(BIOS_RESET_CPL), 1); | |
137 | debug("Set BIOS_RESET_CPL\n"); | |
138 | ||
139 | /* Configure turbo power limits 1ms after reset complete bit */ | |
140 | mdelay(1); | |
141 | set_power_limits(28); | |
142 | ||
143 | /* | |
144 | * CPUs with configurable TDP also need power limits set | |
145 | * in MCHBAR. Use same values from MSR_PKG_POWER_LIMIT. | |
146 | */ | |
2f0c2f03 | 147 | if (cpu_ivybridge_config_tdp_levels()) { |
24774278 SG |
148 | msr_t msr = msr_read(MSR_PKG_POWER_LIMIT); |
149 | ||
150 | writel(msr.lo, MCHBAR_REG(0x59A0)); | |
151 | writel(msr.hi, MCHBAR_REG(0x59A4)); | |
152 | } | |
153 | ||
154 | /* Set here before graphics PM init */ | |
155 | writel(0x00100001, MCHBAR_REG(0x5500)); | |
156 | } | |
157 | ||
279006db SG |
158 | static void sandybridge_setup_northbridge_bars(struct udevice *dev) |
159 | { | |
160 | /* Set up all hardcoded northbridge BARs */ | |
161 | debug("Setting up static registers\n"); | |
162 | dm_pci_write_config32(dev, EPBAR, DEFAULT_EPBAR | 1); | |
163 | dm_pci_write_config32(dev, EPBAR + 4, (0LL + DEFAULT_EPBAR) >> 32); | |
06d336cc SG |
164 | dm_pci_write_config32(dev, MCHBAR, MCH_BASE_ADDRESS | 1); |
165 | dm_pci_write_config32(dev, MCHBAR + 4, (0LL + MCH_BASE_ADDRESS) >> 32); | |
279006db SG |
166 | /* 64MB - busses 0-63 */ |
167 | dm_pci_write_config32(dev, PCIEXBAR, DEFAULT_PCIEXBAR | 5); | |
168 | dm_pci_write_config32(dev, PCIEXBAR + 4, | |
169 | (0LL + DEFAULT_PCIEXBAR) >> 32); | |
170 | dm_pci_write_config32(dev, DMIBAR, DEFAULT_DMIBAR | 1); | |
171 | dm_pci_write_config32(dev, DMIBAR + 4, (0LL + DEFAULT_DMIBAR) >> 32); | |
172 | ||
173 | /* Set C0000-FFFFF to access RAM on both reads and writes */ | |
174 | dm_pci_write_config8(dev, PAM0, 0x30); | |
175 | dm_pci_write_config8(dev, PAM1, 0x33); | |
176 | dm_pci_write_config8(dev, PAM2, 0x33); | |
177 | dm_pci_write_config8(dev, PAM3, 0x33); | |
178 | dm_pci_write_config8(dev, PAM4, 0x33); | |
179 | dm_pci_write_config8(dev, PAM5, 0x33); | |
180 | dm_pci_write_config8(dev, PAM6, 0x33); | |
181 | } | |
182 | ||
6744c0d6 SG |
183 | /** |
184 | * sandybridge_init_iommu() - Set up IOMMU so that azalia can be used | |
185 | * | |
186 | * It is not obvious where these values come from. They may be undocumented. | |
187 | */ | |
188 | static void sandybridge_init_iommu(struct udevice *dev) | |
189 | { | |
190 | u32 capid0_a; | |
191 | ||
192 | dm_pci_read_config32(dev, 0xe4, &capid0_a); | |
193 | if (capid0_a & (1 << 23)) { | |
194 | log_debug("capid0_a not needed\n"); | |
195 | return; | |
196 | } | |
197 | ||
198 | /* setup BARs */ | |
199 | writel(IOMMU_BASE1 >> 32, MCHBAR_REG(0x5404)); | |
200 | writel(IOMMU_BASE1 | 1, MCHBAR_REG(0x5400)); | |
201 | writel(IOMMU_BASE2 >> 32, MCHBAR_REG(0x5414)); | |
202 | writel(IOMMU_BASE2 | 1, MCHBAR_REG(0x5410)); | |
203 | ||
204 | /* lock policies */ | |
205 | writel(0x80000000, IOMMU_BASE1 + 0xff0); | |
206 | ||
207 | /* Enable azalia sound */ | |
208 | writel(0x20000000, IOMMU_BASE2 + 0xff0); | |
209 | writel(0xa0000000, IOMMU_BASE2 + 0xff0); | |
210 | } | |
211 | ||
9ed781a6 | 212 | static int bd82x6x_northbridge_early_init(struct udevice *dev) |
279006db SG |
213 | { |
214 | const int chipset_type = SANDYBRIDGE_MOBILE; | |
215 | u32 capid0_a; | |
216 | u8 reg8; | |
217 | ||
279006db SG |
218 | /* Device ID Override Enable should be done very early */ |
219 | dm_pci_read_config32(dev, 0xe4, &capid0_a); | |
220 | if (capid0_a & (1 << 10)) { | |
221 | dm_pci_read_config8(dev, 0xf3, ®8); | |
222 | reg8 &= ~7; /* Clear 2:0 */ | |
223 | ||
224 | if (chipset_type == SANDYBRIDGE_MOBILE) | |
225 | reg8 |= 1; /* Set bit 0 */ | |
226 | ||
227 | dm_pci_write_config8(dev, 0xf3, reg8); | |
228 | } | |
229 | ||
230 | sandybridge_setup_northbridge_bars(dev); | |
231 | ||
6744c0d6 SG |
232 | /* Setup IOMMU BARs */ |
233 | sandybridge_init_iommu(dev); | |
234 | ||
279006db SG |
235 | /* Device Enable */ |
236 | dm_pci_write_config32(dev, DEVEN, DEVEN_HOST | DEVEN_IGD); | |
237 | ||
238 | return 0; | |
239 | } | |
240 | ||
9ed781a6 SG |
241 | static int bd82x6x_northbridge_probe(struct udevice *dev) |
242 | { | |
1605b100 SG |
243 | int rev; |
244 | ||
9ed781a6 SG |
245 | if (!(gd->flags & GD_FLG_RELOC)) |
246 | return bd82x6x_northbridge_early_init(dev); | |
247 | ||
1605b100 SG |
248 | rev = bridge_silicon_revision(dev); |
249 | northbridge_init(dev, rev); | |
9ed781a6 SG |
250 | |
251 | return 0; | |
252 | } | |
253 | ||
279006db SG |
254 | static const struct udevice_id bd82x6x_northbridge_ids[] = { |
255 | { .compatible = "intel,bd82x6x-northbridge" }, | |
256 | { } | |
257 | }; | |
258 | ||
259 | U_BOOT_DRIVER(bd82x6x_northbridge_drv) = { | |
260 | .name = "bd82x6x_northbridge", | |
261 | .id = UCLASS_NORTHBRIDGE, | |
262 | .of_match = bd82x6x_northbridge_ids, | |
263 | .probe = bd82x6x_northbridge_probe, | |
264 | }; |