1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2016 Google, Inc
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <dm.h>
9*4882a593Smuzhiyun #include <syscon.h>
10*4882a593Smuzhiyun #include <asm/cpu.h>
11*4882a593Smuzhiyun #include <asm/gpio.h>
12*4882a593Smuzhiyun #include <asm/intel_regs.h>
13*4882a593Smuzhiyun #include <asm/mrc_common.h>
14*4882a593Smuzhiyun #include <asm/pch_common.h>
15*4882a593Smuzhiyun #include <asm/post.h>
16*4882a593Smuzhiyun #include <asm/arch/me.h>
17*4882a593Smuzhiyun #include <asm/report_platform.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun static const char *const ecc_decoder[] = {
20*4882a593Smuzhiyun "inactive",
21*4882a593Smuzhiyun "active on IO",
22*4882a593Smuzhiyun "disabled on IO",
23*4882a593Smuzhiyun "active"
24*4882a593Smuzhiyun };
25*4882a593Smuzhiyun
mrc_common_board_get_usable_ram_top(ulong total_size)26*4882a593Smuzhiyun ulong mrc_common_board_get_usable_ram_top(ulong total_size)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun struct memory_info *info = &gd->arch.meminfo;
29*4882a593Smuzhiyun uintptr_t dest_addr = 0;
30*4882a593Smuzhiyun struct memory_area *largest = NULL;
31*4882a593Smuzhiyun int i;
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun /* Find largest area of memory below 4GB */
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun for (i = 0; i < info->num_areas; i++) {
36*4882a593Smuzhiyun struct memory_area *area = &info->area[i];
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun if (area->start >= 1ULL << 32)
39*4882a593Smuzhiyun continue;
40*4882a593Smuzhiyun if (!largest || area->size > largest->size)
41*4882a593Smuzhiyun largest = area;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /* If no suitable area was found, return an error. */
45*4882a593Smuzhiyun assert(largest);
46*4882a593Smuzhiyun if (!largest || largest->size < (2 << 20))
47*4882a593Smuzhiyun panic("No available memory found for relocation");
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun dest_addr = largest->start + largest->size;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun return (ulong)dest_addr;
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
mrc_common_dram_init_banksize(void)54*4882a593Smuzhiyun void mrc_common_dram_init_banksize(void)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun struct memory_info *info = &gd->arch.meminfo;
57*4882a593Smuzhiyun int num_banks;
58*4882a593Smuzhiyun int i;
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun for (i = 0, num_banks = 0; i < info->num_areas; i++) {
61*4882a593Smuzhiyun struct memory_area *area = &info->area[i];
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun if (area->start >= 1ULL << 32)
64*4882a593Smuzhiyun continue;
65*4882a593Smuzhiyun gd->bd->bi_dram[num_banks].start = area->start;
66*4882a593Smuzhiyun gd->bd->bi_dram[num_banks].size = area->size;
67*4882a593Smuzhiyun num_banks++;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
mrc_add_memory_area(struct memory_info * info,uint64_t start,uint64_t end)71*4882a593Smuzhiyun int mrc_add_memory_area(struct memory_info *info, uint64_t start,
72*4882a593Smuzhiyun uint64_t end)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun struct memory_area *ptr;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun if (info->num_areas == CONFIG_NR_DRAM_BANKS)
77*4882a593Smuzhiyun return -ENOSPC;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun ptr = &info->area[info->num_areas];
80*4882a593Smuzhiyun ptr->start = start;
81*4882a593Smuzhiyun ptr->size = end - start;
82*4882a593Smuzhiyun info->total_memory += ptr->size;
83*4882a593Smuzhiyun if (ptr->start < (1ULL << 32))
84*4882a593Smuzhiyun info->total_32bit_memory += ptr->size;
85*4882a593Smuzhiyun debug("%d: memory %llx size %llx, total now %llx / %llx\n",
86*4882a593Smuzhiyun info->num_areas, ptr->start, ptr->size,
87*4882a593Smuzhiyun info->total_32bit_memory, info->total_memory);
88*4882a593Smuzhiyun info->num_areas++;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun return 0;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun /*
94*4882a593Smuzhiyun * Dump in the log memory controller configuration as read from the memory
95*4882a593Smuzhiyun * controller registers.
96*4882a593Smuzhiyun */
report_memory_config(void)97*4882a593Smuzhiyun void report_memory_config(void)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun u32 addr_decoder_common, addr_decode_ch[2];
100*4882a593Smuzhiyun int i;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun addr_decoder_common = readl(MCHBAR_REG(0x5000));
103*4882a593Smuzhiyun addr_decode_ch[0] = readl(MCHBAR_REG(0x5004));
104*4882a593Smuzhiyun addr_decode_ch[1] = readl(MCHBAR_REG(0x5008));
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun debug("memcfg DDR3 clock %d MHz\n",
107*4882a593Smuzhiyun (readl(MCHBAR_REG(0x5e04)) * 13333 * 2 + 50) / 100);
108*4882a593Smuzhiyun debug("memcfg channel assignment: A: %d, B % d, C % d\n",
109*4882a593Smuzhiyun addr_decoder_common & 3,
110*4882a593Smuzhiyun (addr_decoder_common >> 2) & 3,
111*4882a593Smuzhiyun (addr_decoder_common >> 4) & 3);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(addr_decode_ch); i++) {
114*4882a593Smuzhiyun u32 ch_conf = addr_decode_ch[i];
115*4882a593Smuzhiyun debug("memcfg channel[%d] config (%8.8x):\n", i, ch_conf);
116*4882a593Smuzhiyun debug(" ECC %s\n", ecc_decoder[(ch_conf >> 24) & 3]);
117*4882a593Smuzhiyun debug(" enhanced interleave mode %s\n",
118*4882a593Smuzhiyun ((ch_conf >> 22) & 1) ? "on" : "off");
119*4882a593Smuzhiyun debug(" rank interleave %s\n",
120*4882a593Smuzhiyun ((ch_conf >> 21) & 1) ? "on" : "off");
121*4882a593Smuzhiyun debug(" DIMMA %d MB width x%d %s rank%s\n",
122*4882a593Smuzhiyun ((ch_conf >> 0) & 0xff) * 256,
123*4882a593Smuzhiyun ((ch_conf >> 19) & 1) ? 16 : 8,
124*4882a593Smuzhiyun ((ch_conf >> 17) & 1) ? "dual" : "single",
125*4882a593Smuzhiyun ((ch_conf >> 16) & 1) ? "" : ", selected");
126*4882a593Smuzhiyun debug(" DIMMB %d MB width x%d %s rank%s\n",
127*4882a593Smuzhiyun ((ch_conf >> 8) & 0xff) * 256,
128*4882a593Smuzhiyun ((ch_conf >> 20) & 1) ? 16 : 8,
129*4882a593Smuzhiyun ((ch_conf >> 18) & 1) ? "dual" : "single",
130*4882a593Smuzhiyun ((ch_conf >> 16) & 1) ? ", selected" : "");
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
mrc_locate_spd(struct udevice * dev,int size,const void ** spd_datap)134*4882a593Smuzhiyun int mrc_locate_spd(struct udevice *dev, int size, const void **spd_datap)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun const void *blob = gd->fdt_blob;
137*4882a593Smuzhiyun int spd_index;
138*4882a593Smuzhiyun struct gpio_desc desc[4];
139*4882a593Smuzhiyun int spd_node;
140*4882a593Smuzhiyun int node;
141*4882a593Smuzhiyun int ret;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun ret = gpio_request_list_by_name(dev, "board-id-gpios", desc,
144*4882a593Smuzhiyun ARRAY_SIZE(desc), GPIOD_IS_IN);
145*4882a593Smuzhiyun if (ret < 0) {
146*4882a593Smuzhiyun debug("%s: gpio ret=%d\n", __func__, ret);
147*4882a593Smuzhiyun return ret;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun spd_index = dm_gpio_get_values_as_int(desc, ret);
150*4882a593Smuzhiyun debug("spd index %d\n", spd_index);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun node = fdt_first_subnode(blob, dev_of_offset(dev));
153*4882a593Smuzhiyun if (node < 0)
154*4882a593Smuzhiyun return -EINVAL;
155*4882a593Smuzhiyun for (spd_node = fdt_first_subnode(blob, node);
156*4882a593Smuzhiyun spd_node > 0;
157*4882a593Smuzhiyun spd_node = fdt_next_subnode(blob, spd_node)) {
158*4882a593Smuzhiyun int len;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun if (fdtdec_get_int(blob, spd_node, "reg", -1) != spd_index)
161*4882a593Smuzhiyun continue;
162*4882a593Smuzhiyun *spd_datap = fdt_getprop(blob, spd_node, "data", &len);
163*4882a593Smuzhiyun if (len < size) {
164*4882a593Smuzhiyun printf("Missing SPD data\n");
165*4882a593Smuzhiyun return -EINVAL;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun debug("Using SDRAM SPD data for '%s'\n",
169*4882a593Smuzhiyun fdt_get_name(blob, spd_node, NULL));
170*4882a593Smuzhiyun return 0;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun printf("No SPD data found for index %d\n", spd_index);
174*4882a593Smuzhiyun return -ENOENT;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
sdram_console_tx_byte(unsigned char byte)177*4882a593Smuzhiyun asmlinkage void sdram_console_tx_byte(unsigned char byte)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun #ifdef DEBUG
180*4882a593Smuzhiyun putc(byte);
181*4882a593Smuzhiyun #endif
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun /**
185*4882a593Smuzhiyun * Find the PEI executable in the ROM and execute it.
186*4882a593Smuzhiyun *
187*4882a593Smuzhiyun * @me_dev: Management Engine device
188*4882a593Smuzhiyun * @pei_data: configuration data for UEFI PEI reference code
189*4882a593Smuzhiyun */
sdram_initialise(struct udevice * dev,struct udevice * me_dev,void * pei_data,bool use_asm_linkage)190*4882a593Smuzhiyun static int sdram_initialise(struct udevice *dev, struct udevice *me_dev,
191*4882a593Smuzhiyun void *pei_data, bool use_asm_linkage)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun unsigned version;
194*4882a593Smuzhiyun const char *data;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun report_platform_info(dev);
197*4882a593Smuzhiyun debug("Starting UEFI PEI System Agent\n");
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun debug("PEI data at %p:\n", pei_data);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun data = (char *)CONFIG_X86_MRC_ADDR;
202*4882a593Smuzhiyun if (data) {
203*4882a593Smuzhiyun int rv;
204*4882a593Smuzhiyun ulong start;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun debug("Calling MRC at %p\n", data);
207*4882a593Smuzhiyun post_code(POST_PRE_MRC);
208*4882a593Smuzhiyun start = get_timer(0);
209*4882a593Smuzhiyun if (use_asm_linkage) {
210*4882a593Smuzhiyun asmlinkage int (*func)(void *);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun func = (asmlinkage int (*)(void *))data;
213*4882a593Smuzhiyun rv = func(pei_data);
214*4882a593Smuzhiyun } else {
215*4882a593Smuzhiyun int (*func)(void *);
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun func = (int (*)(void *))data;
218*4882a593Smuzhiyun rv = func(pei_data);
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun post_code(POST_MRC);
221*4882a593Smuzhiyun if (rv) {
222*4882a593Smuzhiyun switch (rv) {
223*4882a593Smuzhiyun case -1:
224*4882a593Smuzhiyun printf("PEI version mismatch.\n");
225*4882a593Smuzhiyun break;
226*4882a593Smuzhiyun case -2:
227*4882a593Smuzhiyun printf("Invalid memory frequency.\n");
228*4882a593Smuzhiyun break;
229*4882a593Smuzhiyun default:
230*4882a593Smuzhiyun printf("MRC returned %x.\n", rv);
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun printf("Nonzero MRC return value.\n");
233*4882a593Smuzhiyun return -EFAULT;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun debug("MRC execution time %lu ms\n", get_timer(start));
236*4882a593Smuzhiyun } else {
237*4882a593Smuzhiyun printf("UEFI PEI System Agent not found.\n");
238*4882a593Smuzhiyun return -ENOSYS;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun version = readl(MCHBAR_REG(MCHBAR_PEI_VERSION));
242*4882a593Smuzhiyun debug("System Agent Version %d.%d.%d Build %d\n",
243*4882a593Smuzhiyun version >> 24 , (version >> 16) & 0xff,
244*4882a593Smuzhiyun (version >> 8) & 0xff, version & 0xff);
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun #if CONFIG_USBDEBUG
247*4882a593Smuzhiyun /* mrc.bin reconfigures USB, so reinit it to have debug */
248*4882a593Smuzhiyun early_usbdebug_init();
249*4882a593Smuzhiyun #endif
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun return 0;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
mrc_common_init(struct udevice * dev,void * pei_data,bool use_asm_linkage)254*4882a593Smuzhiyun int mrc_common_init(struct udevice *dev, void *pei_data, bool use_asm_linkage)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun struct udevice *me_dev;
257*4882a593Smuzhiyun int ret;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun ret = syscon_get_by_driver_data(X86_SYSCON_ME, &me_dev);
260*4882a593Smuzhiyun if (ret)
261*4882a593Smuzhiyun return ret;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun ret = sdram_initialise(dev, me_dev, pei_data, use_asm_linkage);
264*4882a593Smuzhiyun if (ret)
265*4882a593Smuzhiyun return ret;
266*4882a593Smuzhiyun quick_ram_check();
267*4882a593Smuzhiyun post_code(POST_DRAM);
268*4882a593Smuzhiyun report_memory_config();
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun return 0;
271*4882a593Smuzhiyun }
272