blob: a322ee351e7c6960e83bfe2787c341dc34801f68 [file] [log] [blame]
Martin Roth433659a2014-05-12 21:55:00 -06001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Martin Roth433659a2014-05-12 21:55:00 -060014 */
15
16#include <arch/cpu.h>
Mohan D'Costaed0c8382014-09-18 15:57:06 +090017#include <arch/acpi.h>
Kyösti Mälkki9e94dbf2015-01-08 20:03:18 +020018#include <cbmem.h>
Martin Roth433659a2014-05-12 21:55:00 -060019#include <console/console.h>
20#include <cpu/intel/microcode.h>
21#include <cpu/x86/cr.h>
22#include <cpu/x86/msr.h>
23#include <device/device.h>
24#include <device/pci_def.h>
25#include <device/pci_ops.h>
26#include <stdlib.h>
Kyösti Mälkki9e94dbf2015-01-08 20:03:18 +020027#include <string.h>
Martin Roth433659a2014-05-12 21:55:00 -060028
Ben Gardnerfa6014a2015-12-08 21:20:25 -060029#include <soc/gpio.h>
30#include <soc/lpc.h>
31#include <soc/nvs.h>
32#include <soc/msr.h>
33#include <soc/pattrs.h>
34#include <soc/pci_devs.h>
35#include <soc/ramstage.h>
Martin Roth433659a2014-05-12 21:55:00 -060036
37/* Global PATTRS */
38DEFINE_PATTRS;
39
40#define SHOW_PATTRS 1
41
42static void detect_num_cpus(struct pattrs *attrs)
43{
44 int ecx = 0;
45
46 while (1) {
47 struct cpuid_result leaf_b;
48
49 leaf_b = cpuid_ext(0xb, ecx);
50
51 /* Bay Trail doesn't have hyperthreading so just determine the
52 * number of cores by from level type (ecx[15:8] == * 2). */
53 if ((leaf_b.ecx & 0xff00) == 0x0200) {
54 attrs->num_cpus = leaf_b.ebx & 0xffff;
55 break;
56 }
57 ecx++;
58 }
59}
60
61static inline void fill_in_msr(msr_t *msr, int idx)
62{
63 *msr = rdmsr(idx);
64 if (SHOW_PATTRS) {
65 printk(BIOS_DEBUG, "msr(%x) = %08x%08x\n",
66 idx, msr->hi, msr->lo);
67 }
68}
69
70static const char *stepping_str[] = {
Ben Gardner2d3d1b72015-11-19 16:12:21 -060071 "A0", "A1", "B0", "B1", "B2", "B3", "C0", "D0",
Martin Roth433659a2014-05-12 21:55:00 -060072};
73
74static void fill_in_pattrs(void)
75{
76 device_t dev;
77 msr_t msr;
78 struct pattrs *attrs = (struct pattrs *)pattrs_get();
79
80 attrs->cpuid = cpuid_eax(1);
81 dev = dev_find_slot(0, PCI_DEVFN(LPC_DEV, LPC_FUNC));
82 attrs->revid = pci_read_config8(dev, REVID);
83 /* The revision to stepping IDs have two values per metal stepping. */
Ben Gardner2d3d1b72015-11-19 16:12:21 -060084 if (attrs->revid >= RID_D_STEPPING_START) {
85 attrs->stepping = (attrs->revid - RID_D_STEPPING_START) / 2;
86 attrs->stepping += STEP_D0;
87 } else if (attrs->revid >= RID_C_STEPPING_START) {
88 attrs->stepping = (attrs->revid - RID_C_STEPPING_START) / 2;
89 attrs->stepping += STEP_C0;
90 } else if (attrs->revid >= RID_B_STEPPING_START) {
Martin Roth433659a2014-05-12 21:55:00 -060091 attrs->stepping = (attrs->revid - RID_B_STEPPING_START) / 2;
92 attrs->stepping += STEP_B0;
93 } else {
94 attrs->stepping = (attrs->revid - RID_A_STEPPING_START) / 2;
95 attrs->stepping += STEP_A0;
96 }
97
York Yang72e33a72015-10-19 13:35:21 -070098 attrs->microcode_patch = intel_microcode_find();
Martin Roth433659a2014-05-12 21:55:00 -060099 attrs->address_bits = cpuid_eax(0x80000008) & 0xff;
100 detect_num_cpus(attrs);
101
102 if (SHOW_PATTRS) {
103 printk(BIOS_DEBUG,
104 "CPUID: %08x\nCores: %d\nRevision ID: %02x\nStepping: %s\n",
105 attrs->cpuid, attrs->num_cpus, attrs->revid,
106 (attrs->stepping >= ARRAY_SIZE(stepping_str)) ? "??" :
107 stepping_str[attrs->stepping]);
108 }
109
110 fill_in_msr(&attrs->platform_id, MSR_IA32_PLATFORM_ID);
111 fill_in_msr(&attrs->platform_info, MSR_PLATFORM_INFO);
112
113 /* Set IA core speed ratio and voltages */
114 msr = rdmsr(MSR_IACORE_RATIOS);
115 attrs->iacore_ratios[IACORE_MIN] = msr.lo & 0x7f;
116 attrs->iacore_ratios[IACORE_LFM] = (msr.lo >> 8) & 0x7f;
117 attrs->iacore_ratios[IACORE_MAX] = (msr.lo >> 16) & 0x7f;
118 msr = rdmsr(MSR_IACORE_TURBO_RATIOS);
119 attrs->iacore_ratios[IACORE_TURBO] = (msr.lo & 0xff); /* 1 core max */
120
121 msr = rdmsr(MSR_IACORE_VIDS);
122 attrs->iacore_vids[IACORE_MIN] = msr.lo & 0x7f;
123 attrs->iacore_vids[IACORE_LFM] = (msr.lo >> 8) & 0x7f;
124 attrs->iacore_vids[IACORE_MAX] = (msr.lo >> 16) & 0x7f;
125 msr = rdmsr(MSR_IACORE_TURBO_VIDS);
126 attrs->iacore_vids[IACORE_TURBO] = (msr.lo & 0xff); /* 1 core max */
127
128 /* Set bus clock speed */
129 attrs->bclk_khz = bus_freq_khz();
130}
131
Mohan D'Costaed0c8382014-09-18 15:57:06 +0900132static void s3_resume_prepare(void)
133{
134 global_nvs_t *gnvs;
Mohan D'Costaed0c8382014-09-18 15:57:06 +0900135
136 gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(global_nvs_t));
Kyösti Mälkki9e94dbf2015-01-08 20:03:18 +0200137 if (gnvs == NULL)
Mohan D'Costaed0c8382014-09-18 15:57:06 +0900138 return;
Mohan D'Costaed0c8382014-09-18 15:57:06 +0900139
Kyösti Mälkki9e94dbf2015-01-08 20:03:18 +0200140 if (!acpi_is_wakeup_s3())
141 memset(gnvs, 0, sizeof(global_nvs_t));
Mohan D'Costaed0c8382014-09-18 15:57:06 +0900142}
143
Martin Roth433659a2014-05-12 21:55:00 -0600144void baytrail_init_pre_device(void)
145{
146 struct soc_gpio_config *config;
147
148 fill_in_pattrs();
149
150 /* Allow for SSE instructions to be executed. */
151 write_cr4(read_cr4() | CR4_OSFXSR | CR4_OSXMMEXCPT);
152
Mohan D'Costaed0c8382014-09-18 15:57:06 +0900153 /* Indicate S3 resume to rest of ramstage. */
154 s3_resume_prepare();
155
Martin Roth433659a2014-05-12 21:55:00 -0600156 /* Get GPIO initial states from mainboard */
157 config = mainboard_get_gpios();
158 setup_soc_gpios(config);
159}