]>
Commit | Line | Data |
---|---|---|
8ef07571 SG |
1 | /* |
2 | * Copyright (c) 2011 The Chromium OS Authors. | |
3 | * (C) Copyright 2010,2011 | |
4 | * Graeme Russ, <graeme.russ@gmail.com> | |
5 | * | |
6 | * Portions from Coreboot mainboard/google/link/romstage.c | |
7 | * Copyright (C) 2007-2010 coresystems GmbH | |
8 | * Copyright (C) 2011 Google Inc. | |
9 | * | |
10 | * SPDX-License-Identifier: GPL-2.0 | |
11 | */ | |
12 | ||
13 | #include <common.h> | |
65dd74a6 SG |
14 | #include <errno.h> |
15 | #include <fdtdec.h> | |
16 | #include <malloc.h> | |
191c008a SG |
17 | #include <net.h> |
18 | #include <rtc.h> | |
19 | #include <spi.h> | |
20 | #include <spi_flash.h> | |
98655f3a SG |
21 | #include <syscon.h> |
22 | #include <asm/cpu.h> | |
65dd74a6 SG |
23 | #include <asm/processor.h> |
24 | #include <asm/gpio.h> | |
25 | #include <asm/global_data.h> | |
06d336cc | 26 | #include <asm/intel_regs.h> |
f6220f1a | 27 | #include <asm/mrccache.h> |
147ba41d | 28 | #include <asm/mrc_common.h> |
aaafcd6c | 29 | #include <asm/mtrr.h> |
65dd74a6 | 30 | #include <asm/pci.h> |
8b900a41 | 31 | #include <asm/report_platform.h> |
65dd74a6 SG |
32 | #include <asm/arch/me.h> |
33 | #include <asm/arch/pei_data.h> | |
34 | #include <asm/arch/pch.h> | |
35 | #include <asm/post.h> | |
36 | #include <asm/arch/sandybridge.h> | |
37 | ||
38 | DECLARE_GLOBAL_DATA_PTR; | |
39 | ||
191c008a SG |
40 | #define CMOS_OFFSET_MRC_SEED 152 |
41 | #define CMOS_OFFSET_MRC_SEED_S3 156 | |
42 | #define CMOS_OFFSET_MRC_SEED_CHK 160 | |
43 | ||
65dd74a6 SG |
44 | ulong board_get_usable_ram_top(ulong total_size) |
45 | { | |
147ba41d | 46 | return mrc_common_board_get_usable_ram_top(total_size); |
65dd74a6 SG |
47 | } |
48 | ||
49 | void dram_init_banksize(void) | |
50 | { | |
147ba41d | 51 | mrc_common_dram_init_banksize(); |
65dd74a6 SG |
52 | } |
53 | ||
191c008a SG |
54 | static int read_seed_from_cmos(struct pei_data *pei_data) |
55 | { | |
56 | u16 c1, c2, checksum, seed_checksum; | |
93f8a311 | 57 | struct udevice *dev; |
53327d3e | 58 | int ret = 0; |
93f8a311 | 59 | |
53327d3e SG |
60 | ret = uclass_get_device(UCLASS_RTC, 0, &dev); |
61 | if (ret) { | |
62 | debug("Cannot find RTC: err=%d\n", ret); | |
93f8a311 BM |
63 | return -ENODEV; |
64 | } | |
191c008a SG |
65 | |
66 | /* | |
67 | * Read scrambler seeds from CMOS RAM. We don't want to store them in | |
68 | * SPI flash since they change on every boot and that would wear down | |
69 | * the flash too much. So we store these in CMOS and the large MRC | |
70 | * data in SPI flash. | |
71 | */ | |
9fbc5ccd SG |
72 | ret = rtc_read32(dev, CMOS_OFFSET_MRC_SEED, &pei_data->scrambler_seed); |
73 | if (!ret) { | |
74 | ret = rtc_read32(dev, CMOS_OFFSET_MRC_SEED_S3, | |
75 | &pei_data->scrambler_seed_s3); | |
76 | } | |
77 | if (ret) { | |
78 | debug("Failed to read from RTC %s\n", dev->name); | |
79 | return ret; | |
80 | } | |
81 | ||
191c008a SG |
82 | debug("Read scrambler seed 0x%08x from CMOS 0x%02x\n", |
83 | pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED); | |
191c008a SG |
84 | debug("Read S3 scrambler seed 0x%08x from CMOS 0x%02x\n", |
85 | pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3); | |
86 | ||
87 | /* Compute seed checksum and compare */ | |
88 | c1 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed, | |
89 | sizeof(u32)); | |
90 | c2 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed_s3, | |
91 | sizeof(u32)); | |
92 | checksum = add_ip_checksums(sizeof(u32), c1, c2); | |
93 | ||
93f8a311 BM |
94 | seed_checksum = rtc_read8(dev, CMOS_OFFSET_MRC_SEED_CHK); |
95 | seed_checksum |= rtc_read8(dev, CMOS_OFFSET_MRC_SEED_CHK + 1) << 8; | |
191c008a SG |
96 | |
97 | if (checksum != seed_checksum) { | |
98 | debug("%s: invalid seed checksum\n", __func__); | |
99 | pei_data->scrambler_seed = 0; | |
100 | pei_data->scrambler_seed_s3 = 0; | |
101 | return -EINVAL; | |
102 | } | |
103 | ||
104 | return 0; | |
105 | } | |
106 | ||
107 | static int prepare_mrc_cache(struct pei_data *pei_data) | |
108 | { | |
109 | struct mrc_data_container *mrc_cache; | |
4b9f6a66 | 110 | struct mrc_region entry; |
191c008a SG |
111 | int ret; |
112 | ||
113 | ret = read_seed_from_cmos(pei_data); | |
114 | if (ret) | |
115 | return ret; | |
42913a1c | 116 | ret = mrccache_get_region(NULL, &entry); |
191c008a SG |
117 | if (ret) |
118 | return ret; | |
119 | mrc_cache = mrccache_find_current(&entry); | |
120 | if (!mrc_cache) | |
121 | return -ENOENT; | |
122 | ||
3e45de6e BM |
123 | pei_data->mrc_input = mrc_cache->data; |
124 | pei_data->mrc_input_len = mrc_cache->data_size; | |
191c008a SG |
125 | debug("%s: at %p, size %x checksum %04x\n", __func__, |
126 | pei_data->mrc_input, pei_data->mrc_input_len, | |
127 | mrc_cache->checksum); | |
128 | ||
129 | return 0; | |
130 | } | |
131 | ||
191c008a SG |
132 | static int write_seeds_to_cmos(struct pei_data *pei_data) |
133 | { | |
134 | u16 c1, c2, checksum; | |
93f8a311 | 135 | struct udevice *dev; |
53327d3e | 136 | int ret = 0; |
93f8a311 | 137 | |
53327d3e SG |
138 | ret = uclass_get_device(UCLASS_RTC, 0, &dev); |
139 | if (ret) { | |
140 | debug("Cannot find RTC: err=%d\n", ret); | |
93f8a311 BM |
141 | return -ENODEV; |
142 | } | |
191c008a SG |
143 | |
144 | /* Save the MRC seed values to CMOS */ | |
93f8a311 | 145 | rtc_write32(dev, CMOS_OFFSET_MRC_SEED, pei_data->scrambler_seed); |
191c008a SG |
146 | debug("Save scrambler seed 0x%08x to CMOS 0x%02x\n", |
147 | pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED); | |
148 | ||
93f8a311 | 149 | rtc_write32(dev, CMOS_OFFSET_MRC_SEED_S3, pei_data->scrambler_seed_s3); |
191c008a SG |
150 | debug("Save s3 scrambler seed 0x%08x to CMOS 0x%02x\n", |
151 | pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3); | |
152 | ||
153 | /* Save a simple checksum of the seed values */ | |
154 | c1 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed, | |
155 | sizeof(u32)); | |
156 | c2 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed_s3, | |
157 | sizeof(u32)); | |
158 | checksum = add_ip_checksums(sizeof(u32), c1, c2); | |
159 | ||
93f8a311 BM |
160 | rtc_write8(dev, CMOS_OFFSET_MRC_SEED_CHK, checksum & 0xff); |
161 | rtc_write8(dev, CMOS_OFFSET_MRC_SEED_CHK + 1, (checksum >> 8) & 0xff); | |
191c008a SG |
162 | |
163 | return 0; | |
164 | } | |
165 | ||
191c008a SG |
166 | /* Use this hook to save our SDRAM parameters */ |
167 | int misc_init_r(void) | |
168 | { | |
169 | int ret; | |
170 | ||
42913a1c | 171 | ret = mrccache_save(); |
191c008a SG |
172 | if (ret) |
173 | printf("Unable to save MRC data: %d\n", ret); | |
174 | ||
175 | return 0; | |
176 | } | |
177 | ||
147ba41d SG |
178 | static void post_system_agent_init(struct udevice *dev, struct udevice *me_dev, |
179 | struct pei_data *pei_data) | |
65dd74a6 | 180 | { |
65dd74a6 | 181 | uint16_t done; |
65dd74a6 SG |
182 | |
183 | /* | |
184 | * Send ME init done for SandyBridge here. This is done inside the | |
185 | * SystemAgent binary on IvyBridge | |
186 | */ | |
1641bb8c | 187 | dm_pci_read_config16(dev, PCI_DEVICE_ID, &done); |
65dd74a6 SG |
188 | done &= BASE_REV_MASK; |
189 | if (BASE_REV_SNB == done) | |
c02a4242 | 190 | intel_early_me_init_done(dev, me_dev, ME_INIT_STATUS_SUCCESS); |
65dd74a6 | 191 | else |
8b900a41 | 192 | intel_me_status(me_dev); |
65dd74a6 | 193 | |
147ba41d SG |
194 | /* If PCIe init is skipped, set the PEG clock gating */ |
195 | if (!pei_data->pcie_init) | |
196 | setbits_le32(MCHBAR_REG(0x7010), 1); | |
197 | } | |
191c008a | 198 | |
147ba41d SG |
199 | static int recovery_mode_enabled(void) |
200 | { | |
201 | return false; | |
191c008a SG |
202 | } |
203 | ||
147ba41d | 204 | static int copy_spd(struct udevice *dev, struct pei_data *peid) |
65dd74a6 | 205 | { |
147ba41d SG |
206 | const void *data; |
207 | int ret; | |
65dd74a6 | 208 | |
147ba41d SG |
209 | ret = mrc_locate_spd(dev, sizeof(peid->spd_data[0]), &data); |
210 | if (ret) | |
211 | return ret; | |
65dd74a6 | 212 | |
147ba41d | 213 | memcpy(peid->spd_data[0], data, sizeof(peid->spd_data[0])); |
65dd74a6 SG |
214 | |
215 | return 0; | |
216 | } | |
217 | ||
218 | /** | |
219 | * sdram_find() - Find available memory | |
220 | * | |
221 | * This is a bit complicated since on x86 there are system memory holes all | |
222 | * over the place. We create a list of available memory blocks | |
2588e711 SG |
223 | * |
224 | * @dev: Northbridge device | |
65dd74a6 | 225 | */ |
2588e711 | 226 | static int sdram_find(struct udevice *dev) |
65dd74a6 SG |
227 | { |
228 | struct memory_info *info = &gd->arch.meminfo; | |
229 | uint32_t tseg_base, uma_size, tolud; | |
230 | uint64_t tom, me_base, touud; | |
231 | uint64_t uma_memory_base = 0; | |
232 | uint64_t uma_memory_size; | |
233 | unsigned long long tomk; | |
234 | uint16_t ggc; | |
2588e711 | 235 | u32 val; |
65dd74a6 SG |
236 | |
237 | /* Total Memory 2GB example: | |
238 | * | |
239 | * 00000000 0000MB-1992MB 1992MB RAM (writeback) | |
240 | * 7c800000 1992MB-2000MB 8MB TSEG (SMRR) | |
241 | * 7d000000 2000MB-2002MB 2MB GFX GTT (uncached) | |
242 | * 7d200000 2002MB-2034MB 32MB GFX UMA (uncached) | |
243 | * 7f200000 2034MB TOLUD | |
244 | * 7f800000 2040MB MEBASE | |
245 | * 7f800000 2040MB-2048MB 8MB ME UMA (uncached) | |
246 | * 80000000 2048MB TOM | |
247 | * 100000000 4096MB-4102MB 6MB RAM (writeback) | |
248 | * | |
249 | * Total Memory 4GB example: | |
250 | * | |
251 | * 00000000 0000MB-2768MB 2768MB RAM (writeback) | |
252 | * ad000000 2768MB-2776MB 8MB TSEG (SMRR) | |
253 | * ad800000 2776MB-2778MB 2MB GFX GTT (uncached) | |
254 | * ada00000 2778MB-2810MB 32MB GFX UMA (uncached) | |
255 | * afa00000 2810MB TOLUD | |
256 | * ff800000 4088MB MEBASE | |
257 | * ff800000 4088MB-4096MB 8MB ME UMA (uncached) | |
258 | * 100000000 4096MB TOM | |
259 | * 100000000 4096MB-5374MB 1278MB RAM (writeback) | |
260 | * 14fe00000 5368MB TOUUD | |
261 | */ | |
262 | ||
263 | /* Top of Upper Usable DRAM, including remap */ | |
2588e711 SG |
264 | dm_pci_read_config32(dev, TOUUD + 4, &val); |
265 | touud = (uint64_t)val << 32; | |
266 | dm_pci_read_config32(dev, TOUUD, &val); | |
267 | touud |= val; | |
65dd74a6 SG |
268 | |
269 | /* Top of Lower Usable DRAM */ | |
2588e711 | 270 | dm_pci_read_config32(dev, TOLUD, &tolud); |
65dd74a6 SG |
271 | |
272 | /* Top of Memory - does not account for any UMA */ | |
2588e711 SG |
273 | dm_pci_read_config32(dev, 0xa4, &val); |
274 | tom = (uint64_t)val << 32; | |
275 | dm_pci_read_config32(dev, 0xa0, &val); | |
276 | tom |= val; | |
65dd74a6 SG |
277 | |
278 | debug("TOUUD %llx TOLUD %08x TOM %llx\n", touud, tolud, tom); | |
279 | ||
280 | /* ME UMA needs excluding if total memory <4GB */ | |
2588e711 SG |
281 | dm_pci_read_config32(dev, 0x74, &val); |
282 | me_base = (uint64_t)val << 32; | |
283 | dm_pci_read_config32(dev, 0x70, &val); | |
284 | me_base |= val; | |
65dd74a6 SG |
285 | |
286 | debug("MEBASE %llx\n", me_base); | |
287 | ||
288 | /* TODO: Get rid of all this shifting by 10 bits */ | |
289 | tomk = tolud >> 10; | |
290 | if (me_base == tolud) { | |
291 | /* ME is from MEBASE-TOM */ | |
292 | uma_size = (tom - me_base) >> 10; | |
293 | /* Increment TOLUD to account for ME as RAM */ | |
294 | tolud += uma_size << 10; | |
295 | /* UMA starts at old TOLUD */ | |
296 | uma_memory_base = tomk * 1024ULL; | |
297 | uma_memory_size = uma_size * 1024ULL; | |
298 | debug("ME UMA base %llx size %uM\n", me_base, uma_size >> 10); | |
299 | } | |
300 | ||
301 | /* Graphics memory comes next */ | |
2588e711 | 302 | dm_pci_read_config16(dev, GGC, &ggc); |
65dd74a6 SG |
303 | if (!(ggc & 2)) { |
304 | debug("IGD decoded, subtracting "); | |
305 | ||
306 | /* Graphics memory */ | |
307 | uma_size = ((ggc >> 3) & 0x1f) * 32 * 1024ULL; | |
308 | debug("%uM UMA", uma_size >> 10); | |
309 | tomk -= uma_size; | |
310 | uma_memory_base = tomk * 1024ULL; | |
311 | uma_memory_size += uma_size * 1024ULL; | |
312 | ||
313 | /* GTT Graphics Stolen Memory Size (GGMS) */ | |
314 | uma_size = ((ggc >> 8) & 0x3) * 1024ULL; | |
315 | tomk -= uma_size; | |
316 | uma_memory_base = tomk * 1024ULL; | |
317 | uma_memory_size += uma_size * 1024ULL; | |
318 | debug(" and %uM GTT\n", uma_size >> 10); | |
319 | } | |
320 | ||
321 | /* Calculate TSEG size from its base which must be below GTT */ | |
2588e711 | 322 | dm_pci_read_config32(dev, 0xb8, &tseg_base); |
65dd74a6 SG |
323 | uma_size = (uma_memory_base - tseg_base) >> 10; |
324 | tomk -= uma_size; | |
325 | uma_memory_base = tomk * 1024ULL; | |
326 | uma_memory_size += uma_size * 1024ULL; | |
327 | debug("TSEG base 0x%08x size %uM\n", tseg_base, uma_size >> 10); | |
328 | ||
329 | debug("Available memory below 4GB: %lluM\n", tomk >> 10); | |
330 | ||
331 | /* Report the memory regions */ | |
147ba41d SG |
332 | mrc_add_memory_area(info, 1 << 20, 2 << 28); |
333 | mrc_add_memory_area(info, (2 << 28) + (2 << 20), 4 << 28); | |
334 | mrc_add_memory_area(info, (4 << 28) + (2 << 20), tseg_base); | |
335 | mrc_add_memory_area(info, 1ULL << 32, touud); | |
aaafcd6c SG |
336 | |
337 | /* Add MTRRs for memory */ | |
338 | mtrr_add_request(MTRR_TYPE_WRBACK, 0, 2ULL << 30); | |
339 | mtrr_add_request(MTRR_TYPE_WRBACK, 2ULL << 30, 512 << 20); | |
340 | mtrr_add_request(MTRR_TYPE_WRBACK, 0xaULL << 28, 256 << 20); | |
341 | mtrr_add_request(MTRR_TYPE_UNCACHEABLE, tseg_base, 16 << 20); | |
342 | mtrr_add_request(MTRR_TYPE_UNCACHEABLE, tseg_base + (16 << 20), | |
343 | 32 << 20); | |
344 | ||
65dd74a6 SG |
345 | /* |
346 | * If >= 4GB installed then memory from TOLUD to 4GB | |
347 | * is remapped above TOM, TOUUD will account for both | |
348 | */ | |
349 | if (touud > (1ULL << 32ULL)) { | |
350 | debug("Available memory above 4GB: %lluM\n", | |
351 | (touud >> 20) - 4096); | |
352 | } | |
353 | ||
354 | return 0; | |
355 | } | |
356 | ||
357 | static void rcba_config(void) | |
358 | { | |
359 | /* | |
360 | * GFX INTA -> PIRQA (MSI) | |
361 | * D28IP_P3IP WLAN INTA -> PIRQB | |
362 | * D29IP_E1P EHCI1 INTA -> PIRQD | |
363 | * D26IP_E2P EHCI2 INTA -> PIRQF | |
364 | * D31IP_SIP SATA INTA -> PIRQF (MSI) | |
365 | * D31IP_SMIP SMBUS INTB -> PIRQH | |
366 | * D31IP_TTIP THRT INTC -> PIRQA | |
367 | * D27IP_ZIP HDA INTA -> PIRQA (MSI) | |
368 | * | |
369 | * TRACKPAD -> PIRQE (Edge Triggered) | |
370 | * TOUCHSCREEN -> PIRQG (Edge Triggered) | |
371 | */ | |
372 | ||
373 | /* Device interrupt pin register (board specific) */ | |
374 | writel((INTC << D31IP_TTIP) | (NOINT << D31IP_SIP2) | | |
375 | (INTB << D31IP_SMIP) | (INTA << D31IP_SIP), RCB_REG(D31IP)); | |
376 | writel(NOINT << D30IP_PIP, RCB_REG(D30IP)); | |
377 | writel(INTA << D29IP_E1P, RCB_REG(D29IP)); | |
378 | writel(INTA << D28IP_P3IP, RCB_REG(D28IP)); | |
379 | writel(INTA << D27IP_ZIP, RCB_REG(D27IP)); | |
380 | writel(INTA << D26IP_E2P, RCB_REG(D26IP)); | |
381 | writel(NOINT << D25IP_LIP, RCB_REG(D25IP)); | |
382 | writel(NOINT << D22IP_MEI1IP, RCB_REG(D22IP)); | |
383 | ||
384 | /* Device interrupt route registers */ | |
385 | writel(DIR_ROUTE(PIRQB, PIRQH, PIRQA, PIRQC), RCB_REG(D31IR)); | |
386 | writel(DIR_ROUTE(PIRQD, PIRQE, PIRQF, PIRQG), RCB_REG(D29IR)); | |
387 | writel(DIR_ROUTE(PIRQB, PIRQC, PIRQD, PIRQE), RCB_REG(D28IR)); | |
388 | writel(DIR_ROUTE(PIRQA, PIRQH, PIRQA, PIRQB), RCB_REG(D27IR)); | |
389 | writel(DIR_ROUTE(PIRQF, PIRQE, PIRQG, PIRQH), RCB_REG(D26IR)); | |
390 | writel(DIR_ROUTE(PIRQA, PIRQB, PIRQC, PIRQD), RCB_REG(D25IR)); | |
391 | writel(DIR_ROUTE(PIRQA, PIRQB, PIRQC, PIRQD), RCB_REG(D22IR)); | |
392 | ||
393 | /* Enable IOAPIC (generic) */ | |
394 | writew(0x0100, RCB_REG(OIC)); | |
395 | /* PCH BWG says to read back the IOAPIC enable register */ | |
396 | (void)readw(RCB_REG(OIC)); | |
397 | ||
398 | /* Disable unused devices (board specific) */ | |
399 | setbits_le32(RCB_REG(FD), PCH_DISABLE_ALWAYS); | |
400 | } | |
8ef07571 SG |
401 | |
402 | int dram_init(void) | |
403 | { | |
147ba41d | 404 | struct pei_data _pei_data __aligned(8) = { |
65dd74a6 | 405 | .pei_version = PEI_VERSION, |
06d336cc | 406 | .mchbar = MCH_BASE_ADDRESS, |
65dd74a6 SG |
407 | .dmibar = DEFAULT_DMIBAR, |
408 | .epbar = DEFAULT_EPBAR, | |
2d934e57 | 409 | .pciexbar = CONFIG_PCIE_ECAM_BASE, |
65dd74a6 SG |
410 | .smbusbar = SMBUS_IO_BASE, |
411 | .wdbbar = 0x4000000, | |
412 | .wdbsize = 0x1000, | |
413 | .hpet_address = CONFIG_HPET_ADDRESS, | |
414 | .rcba = DEFAULT_RCBABASE, | |
415 | .pmbase = DEFAULT_PMBASE, | |
416 | .gpiobase = DEFAULT_GPIOBASE, | |
417 | .thermalbase = 0xfed08000, | |
418 | .system_type = 0, /* 0 Mobile, 1 Desktop/Server */ | |
419 | .tseg_size = CONFIG_SMM_TSEG_SIZE, | |
420 | .ts_addresses = { 0x00, 0x00, 0x00, 0x00 }, | |
421 | .ec_present = 1, | |
422 | .ddr3lv_support = 1, | |
423 | /* | |
424 | * 0 = leave channel enabled | |
425 | * 1 = disable dimm 0 on channel | |
426 | * 2 = disable dimm 1 on channel | |
427 | * 3 = disable dimm 0+1 on channel | |
428 | */ | |
429 | .dimm_channel0_disabled = 2, | |
430 | .dimm_channel1_disabled = 2, | |
431 | .max_ddr3_freq = 1600, | |
432 | .usb_port_config = { | |
433 | /* | |
434 | * Empty and onboard Ports 0-7, set to un-used pin | |
435 | * OC3 | |
436 | */ | |
437 | { 0, 3, 0x0000 }, /* P0= Empty */ | |
438 | { 1, 0, 0x0040 }, /* P1= Left USB 1 (OC0) */ | |
439 | { 1, 1, 0x0040 }, /* P2= Left USB 2 (OC1) */ | |
440 | { 1, 3, 0x0040 }, /* P3= SDCARD (no OC) */ | |
441 | { 0, 3, 0x0000 }, /* P4= Empty */ | |
442 | { 1, 3, 0x0040 }, /* P5= WWAN (no OC) */ | |
443 | { 0, 3, 0x0000 }, /* P6= Empty */ | |
444 | { 0, 3, 0x0000 }, /* P7= Empty */ | |
445 | /* | |
446 | * Empty and onboard Ports 8-13, set to un-used pin | |
447 | * OC4 | |
448 | */ | |
449 | { 1, 4, 0x0040 }, /* P8= Camera (no OC) */ | |
450 | { 1, 4, 0x0040 }, /* P9= Bluetooth (no OC) */ | |
451 | { 0, 4, 0x0000 }, /* P10= Empty */ | |
452 | { 0, 4, 0x0000 }, /* P11= Empty */ | |
453 | { 0, 4, 0x0000 }, /* P12= Empty */ | |
454 | { 0, 4, 0x0000 }, /* P13= Empty */ | |
455 | }, | |
456 | }; | |
147ba41d | 457 | struct pei_data *pei_data = &_pei_data; |
c02a4242 | 458 | struct udevice *dev, *me_dev; |
65dd74a6 SG |
459 | int ret; |
460 | ||
9532fe3b SG |
461 | /* We need the pinctrl set up early */ |
462 | ret = syscon_get_by_driver_data(X86_SYSCON_PINCONF, &dev); | |
463 | if (ret) | |
464 | return ret; | |
465 | ||
3f603cbb | 466 | ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &dev); |
1641bb8c SG |
467 | if (ret) |
468 | return ret; | |
98655f3a | 469 | ret = syscon_get_by_driver_data(X86_SYSCON_ME, &me_dev); |
c02a4242 SG |
470 | if (ret) |
471 | return ret; | |
147ba41d | 472 | ret = copy_spd(dev, pei_data); |
65dd74a6 SG |
473 | if (ret) |
474 | return ret; | |
147ba41d SG |
475 | pei_data->boot_mode = gd->arch.pei_boot_mode; |
476 | debug("Boot mode %d\n", gd->arch.pei_boot_mode); | |
477 | debug("mrc_input %p\n", pei_data->mrc_input); | |
65dd74a6 | 478 | |
147ba41d SG |
479 | /* |
480 | * Do not pass MRC data in for recovery mode boot, | |
481 | * Always pass it in for S3 resume. | |
482 | */ | |
483 | if (!recovery_mode_enabled() || | |
484 | pei_data->boot_mode == PEI_BOOT_RESUME) { | |
485 | ret = prepare_mrc_cache(pei_data); | |
486 | if (ret) | |
487 | debug("prepare_mrc_cache failed: %d\n", ret); | |
488 | } | |
65dd74a6 | 489 | |
147ba41d SG |
490 | /* If MRC data is not found we cannot continue S3 resume. */ |
491 | if (pei_data->boot_mode == PEI_BOOT_RESUME && !pei_data->mrc_input) { | |
492 | debug("Giving up in sdram_initialize: No MRC data\n"); | |
493 | reset_cpu(0); | |
494 | } | |
65dd74a6 | 495 | |
147ba41d SG |
496 | /* Pass console handler in pei_data */ |
497 | pei_data->tx_byte = sdram_console_tx_byte; | |
65dd74a6 | 498 | |
147ba41d SG |
499 | /* Wait for ME to be ready */ |
500 | ret = intel_early_me_init(me_dev); | |
65dd74a6 SG |
501 | if (ret) |
502 | return ret; | |
147ba41d SG |
503 | ret = intel_early_me_uma_size(me_dev); |
504 | if (ret < 0) | |
505 | return ret; | |
65dd74a6 | 506 | |
147ba41d SG |
507 | ret = mrc_common_init(dev, pei_data, false); |
508 | if (ret) | |
509 | return ret; | |
510 | ||
511 | ret = sdram_find(dev); | |
512 | if (ret) | |
513 | return ret; | |
65dd74a6 | 514 | gd->ram_size = gd->arch.meminfo.total_32bit_memory; |
8ef07571 | 515 | |
147ba41d SG |
516 | debug("MRC output data length %#x at %p\n", pei_data->mrc_output_len, |
517 | pei_data->mrc_output); | |
518 | ||
519 | post_system_agent_init(dev, me_dev, pei_data); | |
520 | report_memory_config(); | |
521 | ||
522 | /* S3 resume: don't save scrambler seed or MRC data */ | |
523 | if (pei_data->boot_mode != PEI_BOOT_RESUME) { | |
524 | /* | |
525 | * This will be copied to SDRAM in reserve_arch(), then written | |
526 | * to SPI flash in mrccache_save() | |
527 | */ | |
528 | gd->arch.mrc_output = (char *)pei_data->mrc_output; | |
529 | gd->arch.mrc_output_len = pei_data->mrc_output_len; | |
530 | ret = write_seeds_to_cmos(pei_data); | |
531 | if (ret) | |
532 | debug("Failed to write seeds to CMOS: %d\n", ret); | |
533 | } | |
534 | ||
535 | writew(0xCAFE, MCHBAR_REG(SSKPD)); | |
536 | if (ret) | |
537 | return ret; | |
538 | ||
539 | rcba_config(); | |
540 | ||
8ef07571 SG |
541 | return 0; |
542 | } |