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