1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <cpu/x86/msr.h>
5 #include <device/device.h>
6 #include <drivers/intel/gma/int15.h>
8 #include <southbridge/intel/common/gpio.h>
9 #include "sch5555_ec.h"
11 static void mainboard_enable(struct device
*dev
)
13 install_intel_vga_int15_handler(GMA_INT15_ACTIVE_LFP_NONE
,
14 GMA_INT15_PANEL_FIT_DEFAULT
,
15 GMA_INT15_BOOT_DISPLAY_DEFAULT
, 0);
18 struct chip_operations mainboard_ops
= {
19 .enable_dev
= mainboard_enable
,
22 #define HWM_TAB_ADD_TEMP_TARGET 1
23 #define HWM_TAB_PKG_POWER_ANY 0xffff
24 #define CHASSIS_TYPE_UNKNOWN 0xff
26 struct hwm_tab_entry
{
33 struct hwm_tab_entry HWM_TAB3
[] = {
34 { 0x005, 0x33, 0, 0xffff },
35 { 0x018, 0x2f, 0, 0xffff },
36 { 0x019, 0x2f, 0, 0xffff },
37 { 0x01a, 0x2f, 0, 0xffff },
38 { 0x080, 0x00, 0, 0xffff },
39 { 0x081, 0x00, 0, 0xffff },
40 { 0x083, 0xbb, 0, 0xffff },
41 { 0x085, 0x8a, 0, 0x0010 },
42 { 0x086, 0x4c, 0, 0x0010 },
43 { 0x08a, 0x66, 0, 0x0010 },
44 { 0x08b, 0x5b, 0, 0x0010 },
45 { 0x090, 0x65, 0, 0xffff },
46 { 0x091, 0x70, 0, 0xffff },
47 { 0x092, 0x86, 0, 0xffff },
48 { 0x096, 0xa4, 0, 0xffff },
49 { 0x097, 0xa4, 0, 0xffff },
50 { 0x098, 0xa4, 0, 0xffff },
51 { 0x09b, 0xa4, 0, 0xffff },
52 { 0x0a0, 0x0e, 0, 0xffff },
53 { 0x0a1, 0x0e, 0, 0xffff },
54 { 0x0ae, 0x7c, 0, 0xffff },
55 { 0x0af, 0x86, 0, 0xffff },
56 { 0x0b0, 0x9a, 0, 0xffff },
57 { 0x0b3, 0x9a, 0, 0xffff },
58 { 0x0b6, 0x08, 0, 0xffff },
59 { 0x0b7, 0x08, 0, 0xffff },
60 { 0x0ea, 0x64, 0, 0x0020 },
61 { 0x0ea, 0x5c, 0, 0x0010 },
62 { 0x0ef, 0xff, 0, 0xffff },
63 { 0x0f8, 0x15, 0, 0xffff },
64 { 0x0f9, 0x00, 0, 0xffff },
65 { 0x0f0, 0x30, 0, 0xffff },
66 { 0x0fd, 0x01, 0, 0xffff },
67 { 0x1a1, 0x00, 0, 0xffff },
68 { 0x1a2, 0x00, 0, 0xffff },
69 { 0x1b1, 0x08, 0, 0xffff },
70 { 0x1be, 0x99, 0, 0xffff },
71 { 0x280, 0xa0, 0, 0x0010 },
72 { 0x281, 0x0f, 0, 0x0010 },
73 { 0x282, 0x03, 0, 0xffff },
74 { 0x283, 0x0a, 0, 0xffff },
75 { 0x284, 0x80, 0, 0xffff },
76 { 0x285, 0x03, 0, 0xffff },
77 { 0x288, 0x68, 0, 0x0010 },
78 { 0x289, 0x10, 0, 0x0010 },
79 { 0x28a, 0x03, 0, 0xffff },
80 { 0x28b, 0x0a, 0, 0xffff },
81 { 0x28c, 0x80, 0, 0xffff },
82 { 0x28d, 0x03, 0, 0xffff },
85 struct hwm_tab_entry HWM_TAB4
[] = {
86 { 0x005, 0x33, 0, 0xffff },
87 { 0x018, 0x2f, 0, 0xffff },
88 { 0x019, 0x2f, 0, 0xffff },
89 { 0x01a, 0x2f, 0, 0xffff },
90 { 0x080, 0x00, 0, 0xffff },
91 { 0x081, 0x00, 0, 0xffff },
92 { 0x083, 0xbb, 0, 0xffff },
93 { 0x085, 0x99, 0, 0x0020 },
94 { 0x085, 0xad, 0, 0x0010 },
95 { 0x086, 0x1c, 0, 0xffff },
96 { 0x08a, 0x39, 0, 0x0020 },
97 { 0x08a, 0x41, 0, 0x0010 },
98 { 0x08b, 0x76, 0, 0x0020 },
99 { 0x08b, 0x8b, 0, 0x0010 },
100 { 0x090, 0x5e, 0, 0xffff },
101 { 0x091, 0x5e, 0, 0xffff },
102 { 0x092, 0x86, 0, 0xffff },
103 { 0x096, 0xa4, 0, 0xffff },
104 { 0x097, 0xa4, 0, 0xffff },
105 { 0x098, 0xa4, 0, 0xffff },
106 { 0x09b, 0xa4, 0, 0xffff },
107 { 0x0a0, 0x0a, 0, 0xffff },
108 { 0x0a1, 0x0a, 0, 0xffff },
109 { 0x0ae, 0x7c, 0, 0xffff },
110 { 0x0af, 0x7c, 0, 0xffff },
111 { 0x0b0, 0x9a, 0, 0xffff },
112 { 0x0b3, 0x7c, 0, 0xffff },
113 { 0x0b6, 0x08, 0, 0xffff },
114 { 0x0b7, 0x08, 0, 0xffff },
115 { 0x0ea, 0x64, 0, 0x0020 },
116 { 0x0ea, 0x5c, 0, 0x0010 },
117 { 0x0ef, 0xff, 0, 0xffff },
118 { 0x0f8, 0x15, 0, 0xffff },
119 { 0x0f9, 0x00, 0, 0xffff },
120 { 0x0f0, 0x30, 0, 0xffff },
121 { 0x0fd, 0x01, 0, 0xffff },
122 { 0x1a1, 0x00, 0, 0xffff },
123 { 0x1a2, 0x00, 0, 0xffff },
124 { 0x1b1, 0x08, 0, 0xffff },
125 { 0x1be, 0x90, 0, 0xffff },
126 { 0x280, 0x94, 0, 0x0020 },
127 { 0x281, 0x11, 0, 0x0020 },
128 { 0x280, 0x94, 0, 0x0010 },
129 { 0x281, 0x11, 0, 0x0010 },
130 { 0x282, 0x03, 0, 0xffff },
131 { 0x283, 0x0a, 0, 0xffff },
132 { 0x284, 0x80, 0, 0xffff },
133 { 0x285, 0x03, 0, 0xffff },
134 { 0x288, 0x28, 0, 0x0020 },
135 { 0x289, 0x0a, 0, 0x0020 },
136 { 0x288, 0x28, 0, 0x0010 },
137 { 0x289, 0x0a, 0, 0x0010 },
138 { 0x28a, 0x03, 0, 0xffff },
139 { 0x28b, 0x0a, 0, 0xffff },
140 { 0x28c, 0x80, 0, 0xffff },
141 { 0x28d, 0x03, 0, 0xffff },
144 struct hwm_tab_entry HWM_TAB5
[] = {
145 { 0x005, 0x33, 0, 0xffff },
146 { 0x018, 0x2f, 0, 0xffff },
147 { 0x019, 0x2f, 0, 0xffff },
148 { 0x01a, 0x2f, 0, 0xffff },
149 { 0x080, 0x00, 0, 0xffff },
150 { 0x081, 0x00, 0, 0xffff },
151 { 0x083, 0xbb, 0, 0xffff },
152 { 0x085, 0x66, 0, 0x0020 },
153 { 0x085, 0x5d, 0, 0x0010 },
154 { 0x086, 0x1c, 0, 0xffff },
155 { 0x08a, 0x39, 0, 0x0020 },
156 { 0x08a, 0x41, 0, 0x0010 },
157 { 0x08b, 0x76, 0, 0x0020 },
158 { 0x08b, 0x80, 0, 0x0010 },
159 { 0x090, 0x5d, 0, 0x0020 },
160 { 0x090, 0x5e, 0, 0x0010 },
161 { 0x091, 0x5e, 0, 0xffff },
162 { 0x092, 0x86, 0, 0xffff },
163 { 0x096, 0xa4, 0, 0xffff },
164 { 0x097, 0xa4, 0, 0xffff },
165 { 0x098, 0xa3, 0, 0x0020 },
166 { 0x098, 0xa4, 0, 0x0010 },
167 { 0x09b, 0xa4, 0, 0xffff },
168 { 0x0a0, 0x08, 0, 0xffff },
169 { 0x0a1, 0x0a, 0, 0xffff },
170 { 0x0ae, 0x7c, 0, 0xffff },
171 { 0x0af, 0x7c, 0, 0xffff },
172 { 0x0b0, 0x9a, 0, 0xffff },
173 { 0x0b3, 0x7c, 0, 0xffff },
174 { 0x0b6, 0x08, 0, 0xffff },
175 { 0x0b7, 0x08, 0, 0xffff },
176 { 0x0ea, 0x64, 0, 0x0020 },
177 { 0x0ea, 0x5c, 0, 0x0010 },
178 { 0x0ef, 0xff, 0, 0xffff },
179 { 0x0f8, 0x15, 0, 0xffff },
180 { 0x0f9, 0x00, 0, 0xffff },
181 { 0x0f0, 0x30, 0, 0xffff },
182 { 0x0fd, 0x01, 0, 0xffff },
183 { 0x1a1, 0x00, 0, 0xffff },
184 { 0x1a2, 0x00, 0, 0xffff },
185 { 0x1b1, 0x08, 0, 0xffff },
186 { 0x1be, 0x98, 0, 0x0020 },
187 { 0x1be, 0x90, 0, 0x0010 },
188 { 0x280, 0x94, 0, 0x0020 },
189 { 0x281, 0x11, 0, 0x0020 },
190 { 0x280, 0x94, 0, 0x0010 },
191 { 0x281, 0x11, 0, 0x0010 },
192 { 0x282, 0x03, 0, 0xffff },
193 { 0x283, 0x0a, 0, 0xffff },
194 { 0x284, 0x80, 0, 0xffff },
195 { 0x285, 0x03, 0, 0xffff },
196 { 0x288, 0x28, 0, 0x0020 },
197 { 0x289, 0x0a, 0, 0x0020 },
198 { 0x288, 0x28, 0, 0x0010 },
199 { 0x289, 0x0a, 0, 0x0010 },
200 { 0x28a, 0x03, 0, 0xffff },
201 { 0x28b, 0x0a, 0, 0xffff },
202 { 0x28c, 0x80, 0, 0xffff },
203 { 0x28d, 0x03, 0, 0xffff },
206 struct hwm_tab_entry HWM_TAB6
[] = {
207 { 0x005, 0x33, 0, 0xffff },
208 { 0x018, 0x2f, 0, 0xffff },
209 { 0x019, 0x2f, 0, 0xffff },
210 { 0x01a, 0x2f, 0, 0xffff },
211 { 0x080, 0x00, 0, 0xffff },
212 { 0x081, 0x00, 0, 0xffff },
213 { 0x083, 0xbb, 0, 0xffff },
214 { 0x085, 0x98, 0, 0xffff },
215 { 0x086, 0x3c, 0, 0xffff },
216 { 0x08a, 0x39, 0, 0x0020 },
217 { 0x08a, 0x3d, 0, 0x0010 },
218 { 0x08b, 0x44, 0, 0x0020 },
219 { 0x08b, 0x51, 0, 0x0010 },
220 { 0x090, 0x61, 0, 0xffff },
221 { 0x091, 0x6d, 0, 0xffff },
222 { 0x092, 0x86, 0, 0xffff },
223 { 0x096, 0xa4, 0, 0xffff },
224 { 0x097, 0xa4, 0, 0xffff },
225 { 0x098, 0x9f, 0, 0x0020 },
226 { 0x098, 0xa4, 0, 0x0010 },
227 { 0x09b, 0xa4, 0, 0xffff },
228 { 0x0a0, 0x0e, 0, 0xffff },
229 { 0x0a1, 0x0e, 0, 0xffff },
230 { 0x0ae, 0x7c, 0, 0xffff },
231 { 0x0af, 0x7c, 0, 0xffff },
232 { 0x0b0, 0x9b, 0, 0x0020 },
233 { 0x0b0, 0x98, 0, 0x0010 },
234 { 0x0b3, 0x9a, 0, 0xffff },
235 { 0x0b6, 0x08, 0, 0xffff },
236 { 0x0b7, 0x08, 0, 0xffff },
237 { 0x0ea, 0x64, 0, 0x0020 },
238 { 0x0ea, 0x5c, 0, 0x0010 },
239 { 0x0ef, 0xff, 0, 0xffff },
240 { 0x0f8, 0x15, 0, 0xffff },
241 { 0x0f9, 0x00, 0, 0xffff },
242 { 0x0f0, 0x30, 0, 0xffff },
243 { 0x0fd, 0x01, 0, 0xffff },
244 { 0x1a1, 0x00, 0, 0xffff },
245 { 0x1a2, 0x00, 0, 0xffff },
246 { 0x1b1, 0x08, 0, 0xffff },
247 { 0x1be, 0x9a, 0, 0x0020 },
248 { 0x1be, 0x96, 0, 0x0010 },
249 { 0x280, 0x94, 0, 0x0020 },
250 { 0x281, 0x11, 0, 0x0020 },
251 { 0x280, 0x94, 0, 0x0010 },
252 { 0x281, 0x11, 0, 0x0010 },
253 { 0x282, 0x03, 0, 0xffff },
254 { 0x283, 0x0a, 0, 0xffff },
255 { 0x284, 0x80, 0, 0xffff },
256 { 0x285, 0x03, 0, 0xffff },
257 { 0x288, 0x94, 0, 0x0020 },
258 { 0x289, 0x11, 0, 0x0020 },
259 { 0x288, 0x94, 0, 0x0010 },
260 { 0x289, 0x11, 0, 0x0010 },
261 { 0x28a, 0x03, 0, 0xffff },
262 { 0x28b, 0x0a, 0, 0xffff },
263 { 0x28c, 0x80, 0, 0xffff },
264 { 0x28d, 0x03, 0, 0xffff },
267 static uint8_t get_chassis_type(void)
269 uint8_t gpio_chassis_type
;
271 // Read chassis type from GPIO
272 gpio_chassis_type
= get_gpio(70) << 3 | get_gpio(38) << 2 |
273 get_gpio(17) << 1 | get_gpio(1);
275 printk(BIOS_DEBUG
, "GPIO chassis type = %#x\n", gpio_chassis_type
);
277 // Turn it into internal chassis index
278 switch (gpio_chassis_type
) {
291 return CHASSIS_TYPE_UNKNOWN
;
296 static uint8_t get_temp_target(void)
298 uint8_t val
= rdmsr(0x1a2).lo
>> 8 & 0xff;
304 static uint16_t get_pkg_power(void)
306 const unsigned int pkg_power
= rdmsr(0x614).lo
& 0x7fff;
307 const unsigned int power_unit
= 1 << (rdmsr(0x606).lo
& 0xf);
308 if (pkg_power
/ power_unit
> 65)
314 static void apply_hwm_tab(struct hwm_tab_entry
*arr
, size_t size
)
316 uint8_t temp_target
= get_temp_target();
317 uint16_t pkg_power
= get_pkg_power();
319 printk(BIOS_DEBUG
, "Temp target = %#x\n", temp_target
);
320 printk(BIOS_DEBUG
, "Package power = %#x\n", pkg_power
);
322 for (size_t i
= 0; i
< size
; ++i
) {
323 // Skip entry if it doesn't apply for this package power
324 if (arr
[i
].pkg_power
!= pkg_power
&&
325 arr
[i
].pkg_power
!= HWM_TAB_PKG_POWER_ANY
)
328 uint8_t val
= arr
[i
].val
;
330 // Add temp target to value if requested (current tables never do)
331 if (arr
[i
].flags
& HWM_TAB_ADD_TEMP_TARGET
)
335 sch5555_mbox_write(1, arr
[i
].addr
, val
);
340 static void sch5555_ec_hwm_init(void *arg
)
342 uint8_t chassis_type
, saved_2fc
;
344 printk(BIOS_DEBUG
, "OptiPlex 9020 late HWM init\n");
346 saved_2fc
= sch5555_mbox_read(1, 0x2fc);
347 sch5555_mbox_write(1, 0x2fc, 0xa0);
348 sch5555_mbox_write(1, 0x2fd, 0x32);
350 chassis_type
= get_chassis_type();
352 if (chassis_type
!= CHASSIS_TYPE_UNKNOWN
) {
353 printk(BIOS_DEBUG
, "Chassis type = %#x\n", chassis_type
);
355 printk(BIOS_DEBUG
, "WARNING: Unknown chassis type\n");
358 // Apply HWM table based on chassis type
359 switch (chassis_type
) {
361 apply_hwm_tab(HWM_TAB3
, ARRAY_SIZE(HWM_TAB3
));
364 apply_hwm_tab(HWM_TAB4
, ARRAY_SIZE(HWM_TAB4
));
367 apply_hwm_tab(HWM_TAB5
, ARRAY_SIZE(HWM_TAB5
));
370 apply_hwm_tab(HWM_TAB6
, ARRAY_SIZE(HWM_TAB6
));
374 // NOTE: vendor firmware applies these when "max core address" > 2
375 // i think this is always the case
376 sch5555_mbox_write(1, 0x9e, 0x30);
377 sch5555_mbox_write(1, 0xeb, sch5555_mbox_read(1, 0xea));
379 sch5555_mbox_write(1, 0x2fc, saved_2fc
);
381 // Apply full speed fan config if requested or if the chassis type is unknown
382 if (chassis_type
== CHASSIS_TYPE_UNKNOWN
|| get_uint_option("fan_full_speed", 0)) {
383 printk(BIOS_DEBUG
, "Setting full fan speed\n");
384 sch5555_mbox_write(1, 0x80, 0x60 | sch5555_mbox_read(1, 0x80));
385 sch5555_mbox_write(1, 0x81, 0x60 | sch5555_mbox_read(1, 0x81));
388 sch5555_mbox_read(1, 0xb8);
390 if ((chassis_type
== 4 || chassis_type
== 5) && sch5555_mbox_read(1, 0x26) == 0) {
391 sch5555_mbox_write(1, 0xa0, sch5555_mbox_read(1, 0xa0) & 0xfb);
392 sch5555_mbox_write(1, 0xa1, sch5555_mbox_read(1, 0xa1) & 0xfb);
393 sch5555_mbox_write(1, 0xa2, sch5555_mbox_read(1, 0xa2) & 0xfb);
394 sch5555_mbox_write(1, 0x8a, 0x99);
395 sch5555_mbox_write(1, 0x8b, 0x47);
396 sch5555_mbox_write(1, 0x8c, 0x91);
400 BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE
, BS_ON_EXIT
, sch5555_ec_hwm_init
, NULL
);