blob: f69273e984c5808e90a5b0fefa9167272d20e271 [file] [log] [blame]
Nico Hubere34e1782016-09-29 12:33:01 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
5 * Copyright (C) 2016 secunet Security Networks AG
Krystian Hebel97445f22019-02-26 11:19:58 +01006 * Copyright (C) 2019 Protectli
Nico Hubere34e1782016-09-29 12:33:01 +02007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19#include <stdlib.h>
20#include <arch/io.h>
21#include <console/console.h>
22#include <delay.h>
23
24#include "env_ctrl.h"
25#include "env_ctrl_chip.h"
26
27static inline u8 ite_ec_read(const u16 base, const u8 addr)
28{
29 outb(addr, base + 5);
30 return inb(base + 6);
31}
32
33static inline void ite_ec_write(const u16 base, const u8 addr, const u8 value)
34{
35 outb(addr, base + 5);
36 outb(value, base + 6);
37}
38
39static void extemp_force_idle_status(const u16 base)
40{
41 u8 reg;
42 int retries = 10;
43
44 /* Wait up to 10ms for non-busy state. */
45 while (retries > 0) {
46 reg = ite_ec_read(base, ITE_EC_EXTEMP_STATUS);
47
48 if ((reg & ITE_EC_EXTEMP_STATUS_HOST_BUSY) == 0x0)
49 break;
50
51 retries--;
52
53 mdelay(1);
54 }
55
56 if (retries == 0 && (reg & ITE_EC_EXTEMP_STATUS_HOST_BUSY) == 0x1) {
57 /*
58 * SIO is busy due to unfinished peci transaction.
59 * Re-configure Register 0x8E to terminate processes.
60 */
61 ite_ec_write(base, ITE_EC_EXTEMP_CONTROL,
62 ITE_EC_EXTEMP_CTRL_AUTO_4HZ |
63 ITE_EC_EXTEMP_CTRL_AUTO_START);
64 }
65}
66
67/*
Vagiz Trakhanov177f7732017-10-17 18:04:55 +000068 * Setup PECI interface
Nico Hubere34e1782016-09-29 12:33:01 +020069 */
Vagiz Trakhanov177f7732017-10-17 18:04:55 +000070static void enable_peci(const u16 base)
Nico Hubere34e1782016-09-29 12:33:01 +020071{
Nico Hubere34e1782016-09-29 12:33:01 +020072 /* Enable PECI interface */
73 ite_ec_write(base, ITE_EC_INTERFACE_SELECT,
74 ITE_EC_INTERFACE_SEL_PECI |
75 ITE_EC_INTERFACE_SPEED_TOLERANCE);
76
77 /* Setup External Temperature using PECI GetTemp */
78 ite_ec_write(base, ITE_EC_EXTEMP_ADDRESS,
79 PECI_CLIENT_ADDRESS);
80 ite_ec_write(base, ITE_EC_EXTEMP_COMMAND,
81 PECI_GETTEMP_COMMAND);
82 ite_ec_write(base, ITE_EC_EXTEMP_WRITE_LENGTH,
83 PECI_GETTEMP_WRITE_LENGTH);
84 ite_ec_write(base, ITE_EC_EXTEMP_READ_LENGTH,
85 PECI_GETTEMP_READ_LENGTH);
86 ite_ec_write(base, ITE_EC_EXTEMP_CONTROL,
87 ITE_EC_EXTEMP_CTRL_AUTO_4HZ |
88 ITE_EC_EXTEMP_CTRL_AUTO_START);
Nico Hubere34e1782016-09-29 12:33:01 +020089}
90
91/*
Vagiz Trakhanov177f7732017-10-17 18:04:55 +000092 * Set up External Temperature to read via PECI or thermal diode/resistor
Nico Hubere34e1782016-09-29 12:33:01 +020093 * into TMPINx register
94 */
Samuel Holland901bdb32017-06-06 20:40:27 -050095static void enable_tmpin(const u16 base, const u8 tmpin,
Vagiz Trakhanov17c57712017-09-28 14:21:54 +000096 const struct ite_ec_thermal_config *const conf)
Nico Hubere34e1782016-09-29 12:33:01 +020097{
98 u8 reg;
99
100 reg = ite_ec_read(base, ITE_EC_ADC_TEMP_CHANNEL_ENABLE);
101
Vagiz Trakhanov17c57712017-09-28 14:21:54 +0000102 switch (conf->mode) {
Vagiz Trakhanov177f7732017-10-17 18:04:55 +0000103 case THERMAL_PECI:
104 if (reg & ITE_EC_ADC_TEMP_EXT_REPORTS_TO_MASK) {
105 printk(BIOS_WARNING, "PECI specified for multiple TMPIN\n");
106 return;
107 }
108 enable_peci(base);
109 reg |= ITE_EC_ADC_TEMP_EXT_REPORTS_TO(tmpin);
110 break;
Nico Hubere34e1782016-09-29 12:33:01 +0200111 case THERMAL_DIODE:
112 reg |= ITE_EC_ADC_TEMP_DIODE_MODE(tmpin);
113 break;
114 case THERMAL_RESISTOR:
115 reg |= ITE_EC_ADC_TEMP_RESISTOR_MODE(tmpin);
116 break;
117 default:
118 printk(BIOS_WARNING,
119 "Unsupported thermal mode 0x%x on TMPIN%d\n",
Vagiz Trakhanov17c57712017-09-28 14:21:54 +0000120 conf->mode, tmpin);
Nico Hubere34e1782016-09-29 12:33:01 +0200121 return;
122 }
123
124 ite_ec_write(base, ITE_EC_ADC_TEMP_CHANNEL_ENABLE, reg);
125
Vagiz Trakhanov17c57712017-09-28 14:21:54 +0000126 /* Set temperature offsets */
127 if (conf->mode != THERMAL_RESISTOR) {
128 reg = ite_ec_read(base, ITE_EC_BEEP_ENABLE);
129 reg |= ITE_EC_TEMP_ADJUST_WRITE_ENABLE;
130 ite_ec_write(base, ITE_EC_BEEP_ENABLE, reg);
131 ite_ec_write(base, ITE_EC_TEMP_ADJUST[tmpin-1], conf->offset);
132 }
133
Vagiz Trakhanovcc9c0cb2017-09-28 14:25:59 +0000134 /* Set temperature limits */
135 u8 max = conf->max;
136 ite_ec_write(base, ITE_EC_HIGH_TEMP_LIMIT(tmpin),
137 max ? max : 127);
138 ite_ec_write(base, ITE_EC_LOW_TEMP_LIMIT(tmpin), conf->min);
139
Nico Hubere34e1782016-09-29 12:33:01 +0200140 /* Enable the startup of monitoring operation */
141 reg = ite_ec_read(base, ITE_EC_CONFIGURATION);
142 reg |= ITE_EC_CONFIGURATION_START;
143 ite_ec_write(base, ITE_EC_CONFIGURATION, reg);
144}
145
146static void fan_smartconfig(const u16 base, const u8 fan,
147 const enum ite_ec_fan_mode mode,
148 const struct ite_ec_fan_smartconfig *const conf)
149{
150 u8 pwm_ctrl;
151 u8 pwm_start = 0;
152 u8 pwm_auto = 0;
153
154 if (mode == FAN_SMART_SOFTWARE) {
155 pwm_ctrl = ITE_EC_FAN_CTL_PWM_MODE_SOFTWARE;
156
157 /* 50% duty cycle by default */
158 const u8 duty = conf->pwm_start ? conf->pwm_start : 50;
159 if (IS_ENABLED(CONFIG_SUPERIO_ITE_ENV_CTRL_8BIT_PWM))
160 pwm_start = ITE_EC_FAN_CTL_PWM_DUTY(duty);
161 else
162 pwm_ctrl |= ITE_EC_FAN_CTL_PWM_DUTY(duty);
163 } else {
164 pwm_ctrl = ITE_EC_FAN_CTL_PWM_MODE_AUTOMATIC;
165 pwm_ctrl |= ITE_EC_FAN_CTL_TEMPIN(conf->tmpin);
166
167 pwm_start = ITE_EC_FAN_CTL_PWM_START_DUTY(conf->pwm_start);
168 pwm_start |= ITE_EC_FAN_CTL_PWM_SLOPE_BIT6(conf->slope);
169
170 pwm_auto = ITE_EC_FAN_CTL_PWM_SLOPE_LOWER(conf->slope);
Arthur Heymanse68947d2016-11-26 14:43:18 +0100171 if (conf->smoothing)
172 pwm_auto |= ITE_EC_FAN_CTL_AUTO_SMOOTHING_EN;
Nico Hubere34e1782016-09-29 12:33:01 +0200173
174 ite_ec_write(base, ITE_EC_FAN_CTL_TEMP_LIMIT_OFF(fan),
175 conf->tmp_off);
176 ite_ec_write(base, ITE_EC_FAN_CTL_TEMP_LIMIT_START(fan),
177 conf->tmp_start);
178 /* Full speed above 127°C by default */
179 ite_ec_write(base, ITE_EC_FAN_CTL_TEMP_LIMIT_FULL(fan),
180 conf->tmp_full ? conf->tmp_full : 127);
181 ite_ec_write(base, ITE_EC_FAN_CTL_DELTA_TEMP(fan),
182 ITE_EC_FAN_CTL_DELTA_TEMP_INTRVL(conf->tmp_delta));
183 }
184
185 ite_ec_write(base, ITE_EC_FAN_CTL_PWM_CONTROL(fan), pwm_ctrl);
186 ite_ec_write(base, ITE_EC_FAN_CTL_PWM_START(fan), pwm_start);
187 ite_ec_write(base, ITE_EC_FAN_CTL_PWM_AUTO(fan), pwm_auto);
188}
189
190static void enable_fan(const u16 base, const u8 fan,
191 const struct ite_ec_fan_config *const conf)
192{
193 u8 reg;
194
Krystian Hebel97445f22019-02-26 11:19:58 +0100195 if (conf->mode == FAN_IGNORE ||
196 (IS_ENABLED(CONFIG_SUPERIO_ITE_ENV_CTRL_NO_ONOFF) &&
197 conf->mode <= FAN_MODE_OFF))
Nico Hubere34e1782016-09-29 12:33:01 +0200198 return;
199
200 /* FAN_CTL2 might have its own frequency setting */
201 if (IS_ENABLED(CONFIG_SUPERIO_ITE_ENV_CTRL_PWM_FREQ2) && fan == 2) {
202 reg = ite_ec_read(base, ITE_EC_ADC_TEMP_EXTRA_CHANNEL_ENABLE);
203 reg &= ~ITE_EC_FAN_PWM_CLOCK_MASK;
204 reg |= ITE_EC_FAN_PWM_DEFAULT_CLOCK;
205 ite_ec_write(base, ITE_EC_ADC_TEMP_EXTRA_CHANNEL_ENABLE, reg);
206 }
207
208 if (conf->mode >= FAN_SMART_SOFTWARE) {
209 fan_smartconfig(base, fan, conf->mode, &conf->smart);
210 } else {
211 reg = ite_ec_read(base, ITE_EC_FAN_CTL_MODE);
212 if (conf->mode == FAN_MODE_ON)
213 reg |= ITE_EC_FAN_CTL_ON(fan);
214 else
215 reg &= ~ITE_EC_FAN_CTL_ON(fan);
216 ite_ec_write(base, ITE_EC_FAN_CTL_MODE, reg);
217 }
218
Krystian Hebel65b514c2019-03-01 11:27:22 +0100219 if (IS_ENABLED(CONFIG_SUPERIO_ITE_ENV_CTRL_FAN16_CONFIG)
Nico Hubere34e1782016-09-29 12:33:01 +0200220 && conf->mode >= FAN_MODE_ON) {
221 reg = ite_ec_read(base, ITE_EC_FAN_TAC_COUNTER_ENABLE);
222 reg |= ITE_EC_FAN_TAC_16BIT_ENABLE(fan);
223 ite_ec_write(base, ITE_EC_FAN_TAC_COUNTER_ENABLE, reg);
224 }
225
Krystian Hebel97445f22019-02-26 11:19:58 +0100226 if (IS_ENABLED(CONFIG_SUPERIO_ITE_ENV_CTRL_5FANS) && fan > 3) {
227 reg = ite_ec_read(base, ITE_EC_FAN_SEC_CTL);
228 if (conf->mode >= FAN_MODE_ON)
229 reg |= ITE_EC_FAN_SEC_CTL_TAC_EN(fan);
230 else
231 reg &= ~ITE_EC_FAN_SEC_CTL_TAC_EN(fan);
232 ite_ec_write(base, ITE_EC_FAN_SEC_CTL, reg);
233 } else {
234 reg = ite_ec_read(base, ITE_EC_FAN_MAIN_CTL);
235 if (conf->mode >= FAN_MODE_ON)
236 reg |= ITE_EC_FAN_MAIN_CTL_TAC_EN(fan);
237 else
238 reg &= ~ITE_EC_FAN_MAIN_CTL_TAC_EN(fan);
239
240 /* Some ITEs have SmartGuardian always enabled */
241 if (!IS_ENABLED(CONFIG_SUPERIO_ITE_ENV_CTRL_NO_ONOFF)) {
242 if (conf->mode >= FAN_SMART_SOFTWARE)
243 reg |= ITE_EC_FAN_MAIN_CTL_SMART(fan);
244 else
245 reg &= ~ITE_EC_FAN_MAIN_CTL_SMART(fan);
246 }
247 ite_ec_write(base, ITE_EC_FAN_MAIN_CTL, reg);
248 }
Nico Hubere34e1782016-09-29 12:33:01 +0200249}
250
Vagiz Trakhanov41aa5ec2017-10-23 13:17:44 +0000251static void enable_beeps(const u16 base, const struct ite_ec_config *const conf)
252{
253 u8 reg = 0;
254 u8 freq = ITE_EC_BEEP_TONE_DIVISOR(10) | ITE_EC_BEEP_FREQ_DIVISOR(10);
255
256 if (conf->tmpin_beep) {
257 reg |= ITE_EC_BEEP_ON_TMP_LIMIT;
258 ite_ec_write(base, ITE_EC_BEEP_FREQ_DIV_OF_TMPIN, freq);
259 }
260 if (conf->fan_beep) {
261 reg |= ITE_EC_BEEP_ON_FAN_LIMIT;
262 ite_ec_write(base, ITE_EC_BEEP_FREQ_DIV_OF_FAN, freq);
263 }
264 if (conf->vin_beep) {
265 reg |= ITE_EC_BEEP_ON_VIN_LIMIT;
266 ite_ec_write(base, ITE_EC_BEEP_FREQ_DIV_OF_VIN, freq);
267 }
268
269 if (reg) {
270 reg |= ite_ec_read(base, ITE_EC_BEEP_ENABLE);
271 ite_ec_write(base, ITE_EC_BEEP_ENABLE, reg);
272 }
273}
274
Nico Hubere34e1782016-09-29 12:33:01 +0200275void ite_ec_init(const u16 base, const struct ite_ec_config *const conf)
276{
277 size_t i;
278
279 /* Configure 23.43kHz PWM active high output */
280 u8 fan_ctl = ite_ec_read(base, ITE_EC_FAN_CTL_MODE);
281 fan_ctl &= ~ITE_EC_FAN_PWM_CLOCK_MASK;
282 fan_ctl |= ITE_EC_FAN_PWM_DEFAULT_CLOCK;
283 fan_ctl |= ITE_EC_FAN_CTL_POLARITY_HIGH;
284 ite_ec_write(base, ITE_EC_FAN_CTL_MODE, fan_ctl);
285
Nico Hubere34e1782016-09-29 12:33:01 +0200286 /* Enable HWM if configured */
287 for (i = 0; i < ITE_EC_TMPIN_CNT; ++i)
Vagiz Trakhanov17c57712017-09-28 14:21:54 +0000288 enable_tmpin(base, i + 1, &conf->tmpin[i]);
Nico Hubere34e1782016-09-29 12:33:01 +0200289
290 /* Enable reading of voltage pins */
291 ite_ec_write(base, ITE_EC_ADC_VOLTAGE_CHANNEL_ENABLE, conf->vin_mask);
292
293 /* Enable FANx if configured */
294 for (i = 0; i < ITE_EC_FAN_CNT; ++i)
295 enable_fan(base, i + 1, &conf->fan[i]);
296
Vagiz Trakhanov41aa5ec2017-10-23 13:17:44 +0000297 /* Enable beeps if configured */
298 enable_beeps(base, conf);
299
Nico Hubere34e1782016-09-29 12:33:01 +0200300 /*
301 * System may get wrong temperature data when SIO is in
302 * busy state. Therefore, check the status and terminate
303 * processes if needed.
304 */
Vagiz Trakhanov177f7732017-10-17 18:04:55 +0000305 for (i = 0; i < ITE_EC_TMPIN_CNT; ++i)
306 if (conf->tmpin[i].mode == THERMAL_PECI)
307 extemp_force_idle_status(base);
Nico Hubere34e1782016-09-29 12:33:01 +0200308}