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