Merge tag 'u-boot-atmel-fixes-2020.07-a' of https://gitlab.denx.de/u-boot/custodians...
[oweals/u-boot.git] / arch / x86 / cpu / baytrail / cpu.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2015 Google, Inc
4  *
5  * Based on code from coreboot
6  */
7
8 #include <common.h>
9 #include <cpu.h>
10 #include <dm.h>
11 #include <init.h>
12 #include <log.h>
13 #include <pci.h>
14 #include <asm/cpu.h>
15 #include <asm/cpu_x86.h>
16 #include <asm/io.h>
17 #include <asm/lapic.h>
18 #include <asm/msr.h>
19 #include <asm/turbo.h>
20
21 #define BYT_PRV_CLK                     0x800
22 #define BYT_PRV_CLK_EN                  (1 << 0)
23 #define BYT_PRV_CLK_M_VAL_SHIFT         1
24 #define BYT_PRV_CLK_N_VAL_SHIFT         16
25 #define BYT_PRV_CLK_UPDATE              (1 << 31)
26
27 static void hsuart_clock_set(void *base)
28 {
29         u32 m, n, reg;
30
31         /*
32          * Configure the BayTrail UART clock for the internal HS UARTs
33          * (PCI devices) to 58982400 Hz
34          */
35         m = 0x2400;
36         n = 0x3d09;
37         reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT);
38         writel(reg, base + BYT_PRV_CLK);
39         reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE;
40         writel(reg, base + BYT_PRV_CLK);
41 }
42
43 /*
44  * Configure the internal clock of both SIO HS-UARTs, if they are enabled
45  * via FSP
46  */
47 int arch_cpu_init_dm(void)
48 {
49         struct udevice *dev;
50         void *base;
51         int ret;
52         int i;
53
54         /* Loop over the 2 HS-UARTs */
55         for (i = 0; i < 2; i++) {
56                 ret = dm_pci_bus_find_bdf(PCI_BDF(0, 0x1e, 3 + i), &dev);
57                 if (!ret) {
58                         base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
59                                               PCI_REGION_MEM);
60                         hsuart_clock_set(base);
61                 }
62         }
63
64         return 0;
65 }
66
67 static void set_max_freq(void)
68 {
69         msr_t perf_ctl;
70         msr_t msr;
71
72         /* Enable speed step */
73         msr = msr_read(MSR_IA32_MISC_ENABLE);
74         msr.lo |= MISC_ENABLE_ENHANCED_SPEEDSTEP;
75         msr_write(MSR_IA32_MISC_ENABLE, msr);
76
77         /*
78          * Set guaranteed ratio [21:16] from IACORE_RATIOS to bits [15:8] of
79          * the PERF_CTL
80          */
81         msr = msr_read(MSR_IACORE_RATIOS);
82         perf_ctl.lo = (msr.lo & 0x3f0000) >> 8;
83
84         /*
85          * Set guaranteed vid [22:16] from IACORE_VIDS to bits [7:0] of
86          * the PERF_CTL
87          */
88         msr = msr_read(MSR_IACORE_VIDS);
89         perf_ctl.lo |= (msr.lo & 0x7f0000) >> 16;
90         perf_ctl.hi = 0;
91
92         msr_write(MSR_IA32_PERF_CTL, perf_ctl);
93 }
94
95 static int cpu_x86_baytrail_probe(struct udevice *dev)
96 {
97         if (!ll_boot_init())
98                 return 0;
99         debug("Init BayTrail core\n");
100
101         /*
102          * On BayTrail the turbo disable bit is actually scoped at the
103          * building-block level, not package. For non-BSP cores that are
104          * within a building block, enable turbo. The cores within the BSP's
105          * building block will just see it already enabled and move on.
106          */
107         if (lapicid())
108                 turbo_enable();
109
110         /* Dynamic L2 shrink enable and threshold */
111         msr_clrsetbits_64(MSR_PMG_CST_CONFIG_CONTROL, 0x3f000f, 0xe0008),
112
113         /* Disable C1E */
114         msr_clrsetbits_64(MSR_POWER_CTL, 2, 0);
115         msr_setbits_64(MSR_POWER_MISC, 0x44);
116
117         /* Set this core to max frequency ratio */
118         set_max_freq();
119
120         return 0;
121 }
122
123 static unsigned bus_freq(void)
124 {
125         msr_t clk_info = msr_read(MSR_BSEL_CR_OVERCLOCK_CONTROL);
126         switch (clk_info.lo & 0x3) {
127         case 0:
128                 return 83333333;
129         case 1:
130                 return 100000000;
131         case 2:
132                 return 133333333;
133         case 3:
134                 return 116666666;
135         default:
136                 return 0;
137         }
138 }
139
140 static unsigned long tsc_freq(void)
141 {
142         msr_t platform_info;
143         ulong bclk = bus_freq();
144
145         if (!bclk)
146                 return 0;
147
148         platform_info = msr_read(MSR_PLATFORM_INFO);
149
150         return bclk * ((platform_info.lo >> 8) & 0xff);
151 }
152
153 static int baytrail_get_info(struct udevice *dev, struct cpu_info *info)
154 {
155         info->cpu_freq = tsc_freq();
156         info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU;
157
158         return 0;
159 }
160
161 static int baytrail_get_count(struct udevice *dev)
162 {
163         int ecx = 0;
164
165         /*
166          * Use the algorithm described in Intel 64 and IA-32 Architectures
167          * Software Developer's Manual Volume 3 (3A, 3B & 3C): System
168          * Programming Guide, Jan-2015. Section 8.9.2: Hierarchical Mapping
169          * of CPUID Extended Topology Leaf.
170          */
171         while (1) {
172                 struct cpuid_result leaf_b;
173
174                 leaf_b = cpuid_ext(0xb, ecx);
175
176                 /*
177                  * Bay Trail doesn't have hyperthreading so just determine the
178                  * number of cores by from level type (ecx[15:8] == * 2)
179                  */
180                 if ((leaf_b.ecx & 0xff00) == 0x0200)
181                         return leaf_b.ebx & 0xffff;
182
183                 ecx++;
184         }
185
186         return 0;
187 }
188
189 static const struct cpu_ops cpu_x86_baytrail_ops = {
190         .get_desc       = cpu_x86_get_desc,
191         .get_info       = baytrail_get_info,
192         .get_count      = baytrail_get_count,
193         .get_vendor     = cpu_x86_get_vendor,
194 };
195
196 static const struct udevice_id cpu_x86_baytrail_ids[] = {
197         { .compatible = "intel,baytrail-cpu" },
198         { }
199 };
200
201 U_BOOT_DRIVER(cpu_x86_baytrail_drv) = {
202         .name           = "cpu_x86_baytrail",
203         .id             = UCLASS_CPU,
204         .of_match       = cpu_x86_baytrail_ids,
205         .bind           = cpu_x86_bind,
206         .probe          = cpu_x86_baytrail_probe,
207         .ops            = &cpu_x86_baytrail_ops,
208         .flags          = DM_FLAG_PRE_RELOC,
209 };