blob: b3312e60bfc5246904564b4649a6899aad6c01ed [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
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <stdlib.h>
19#include <arch/io.h>
20#include <console/console.h>
21#include <delay.h>
22
23#include "env_ctrl.h"
24#include "env_ctrl_chip.h"
25
26static inline u8 ite_ec_read(const u16 base, const u8 addr)
27{
28 outb(addr, base + 5);
29 return inb(base + 6);
30}
31
32static inline void ite_ec_write(const u16 base, const u8 addr, const u8 value)
33{
34 outb(addr, base + 5);
35 outb(value, base + 6);
36}
37
38static void extemp_force_idle_status(const u16 base)
39{
40 u8 reg;
41 int retries = 10;
42
43 /* Wait up to 10ms for non-busy state. */
44 while (retries > 0) {
45 reg = ite_ec_read(base, ITE_EC_EXTEMP_STATUS);
46
47 if ((reg & ITE_EC_EXTEMP_STATUS_HOST_BUSY) == 0x0)
48 break;
49
50 retries--;
51
52 mdelay(1);
53 }
54
55 if (retries == 0 && (reg & ITE_EC_EXTEMP_STATUS_HOST_BUSY) == 0x1) {
56 /*
57 * SIO is busy due to unfinished peci transaction.
58 * Re-configure Register 0x8E to terminate processes.
59 */
60 ite_ec_write(base, ITE_EC_EXTEMP_CONTROL,
61 ITE_EC_EXTEMP_CTRL_AUTO_4HZ |
62 ITE_EC_EXTEMP_CTRL_AUTO_START);
63 }
64}
65
66/*
67 * Setup External Temperature to read via PECI into TMPINx register
68 */
69static void enable_peci(const u16 base, const u8 tmpin)
70{
71 if (tmpin == 0 || tmpin > ITE_EC_TMPIN_CNT)
72 return;
73
74 /* Enable PECI interface */
75 ite_ec_write(base, ITE_EC_INTERFACE_SELECT,
76 ITE_EC_INTERFACE_SEL_PECI |
77 ITE_EC_INTERFACE_SPEED_TOLERANCE);
78
79 /* Setup External Temperature using PECI GetTemp */
80 ite_ec_write(base, ITE_EC_EXTEMP_ADDRESS,
81 PECI_CLIENT_ADDRESS);
82 ite_ec_write(base, ITE_EC_EXTEMP_COMMAND,
83 PECI_GETTEMP_COMMAND);
84 ite_ec_write(base, ITE_EC_EXTEMP_WRITE_LENGTH,
85 PECI_GETTEMP_WRITE_LENGTH);
86 ite_ec_write(base, ITE_EC_EXTEMP_READ_LENGTH,
87 PECI_GETTEMP_READ_LENGTH);
88 ite_ec_write(base, ITE_EC_EXTEMP_CONTROL,
89 ITE_EC_EXTEMP_CTRL_AUTO_4HZ |
90 ITE_EC_EXTEMP_CTRL_AUTO_START);
91
92 /* External Temperature reported in TMPINx register */
93 ite_ec_write(base, ITE_EC_ADC_TEMP_CHANNEL_ENABLE,
94 (tmpin & 3) << 6);
95}
96
97/*
98 * Set up External Temperature to read via thermal diode/resistor
99 * into TMPINx register
100 */
101static void enable_tmpin(const u16 base, const int tmpin,
102 const enum ite_ec_thermal_mode mode)
103{
104 u8 reg;
105
106 reg = ite_ec_read(base, ITE_EC_ADC_TEMP_CHANNEL_ENABLE);
107
108 switch (mode) {
109 case THERMAL_DIODE:
110 reg |= ITE_EC_ADC_TEMP_DIODE_MODE(tmpin);
111 break;
112 case THERMAL_RESISTOR:
113 reg |= ITE_EC_ADC_TEMP_RESISTOR_MODE(tmpin);
114 break;
115 default:
116 printk(BIOS_WARNING,
117 "Unsupported thermal mode 0x%x on TMPIN%d\n",
118 mode, tmpin);
119 return;
120 }
121
122 ite_ec_write(base, ITE_EC_ADC_TEMP_CHANNEL_ENABLE, reg);
123
124 /* Enable the startup of monitoring operation */
125 reg = ite_ec_read(base, ITE_EC_CONFIGURATION);
126 reg |= ITE_EC_CONFIGURATION_START;
127 ite_ec_write(base, ITE_EC_CONFIGURATION, reg);
128}
129
130static void fan_smartconfig(const u16 base, const u8 fan,
131 const enum ite_ec_fan_mode mode,
132 const struct ite_ec_fan_smartconfig *const conf)
133{
134 u8 pwm_ctrl;
135 u8 pwm_start = 0;
136 u8 pwm_auto = 0;
137
138 if (mode == FAN_SMART_SOFTWARE) {
139 pwm_ctrl = ITE_EC_FAN_CTL_PWM_MODE_SOFTWARE;
140
141 /* 50% duty cycle by default */
142 const u8 duty = conf->pwm_start ? conf->pwm_start : 50;
143 if (IS_ENABLED(CONFIG_SUPERIO_ITE_ENV_CTRL_8BIT_PWM))
144 pwm_start = ITE_EC_FAN_CTL_PWM_DUTY(duty);
145 else
146 pwm_ctrl |= ITE_EC_FAN_CTL_PWM_DUTY(duty);
147 } else {
148 pwm_ctrl = ITE_EC_FAN_CTL_PWM_MODE_AUTOMATIC;
149 pwm_ctrl |= ITE_EC_FAN_CTL_TEMPIN(conf->tmpin);
150
151 pwm_start = ITE_EC_FAN_CTL_PWM_START_DUTY(conf->pwm_start);
152 pwm_start |= ITE_EC_FAN_CTL_PWM_SLOPE_BIT6(conf->slope);
153
154 pwm_auto = ITE_EC_FAN_CTL_PWM_SLOPE_LOWER(conf->slope);
Arthur Heymanse68947d2016-11-26 14:43:18 +0100155 if (conf->smoothing)
156 pwm_auto |= ITE_EC_FAN_CTL_AUTO_SMOOTHING_EN;
Nico Hubere34e1782016-09-29 12:33:01 +0200157
158 ite_ec_write(base, ITE_EC_FAN_CTL_TEMP_LIMIT_OFF(fan),
159 conf->tmp_off);
160 ite_ec_write(base, ITE_EC_FAN_CTL_TEMP_LIMIT_START(fan),
161 conf->tmp_start);
162 /* Full speed above 127°C by default */
163 ite_ec_write(base, ITE_EC_FAN_CTL_TEMP_LIMIT_FULL(fan),
164 conf->tmp_full ? conf->tmp_full : 127);
165 ite_ec_write(base, ITE_EC_FAN_CTL_DELTA_TEMP(fan),
166 ITE_EC_FAN_CTL_DELTA_TEMP_INTRVL(conf->tmp_delta));
167 }
168
169 ite_ec_write(base, ITE_EC_FAN_CTL_PWM_CONTROL(fan), pwm_ctrl);
170 ite_ec_write(base, ITE_EC_FAN_CTL_PWM_START(fan), pwm_start);
171 ite_ec_write(base, ITE_EC_FAN_CTL_PWM_AUTO(fan), pwm_auto);
172}
173
174static void enable_fan(const u16 base, const u8 fan,
175 const struct ite_ec_fan_config *const conf)
176{
177 u8 reg;
178
179 if (conf->mode == FAN_IGNORE)
180 return;
181
182 /* FAN_CTL2 might have its own frequency setting */
183 if (IS_ENABLED(CONFIG_SUPERIO_ITE_ENV_CTRL_PWM_FREQ2) && fan == 2) {
184 reg = ite_ec_read(base, ITE_EC_ADC_TEMP_EXTRA_CHANNEL_ENABLE);
185 reg &= ~ITE_EC_FAN_PWM_CLOCK_MASK;
186 reg |= ITE_EC_FAN_PWM_DEFAULT_CLOCK;
187 ite_ec_write(base, ITE_EC_ADC_TEMP_EXTRA_CHANNEL_ENABLE, reg);
188 }
189
190 if (conf->mode >= FAN_SMART_SOFTWARE) {
191 fan_smartconfig(base, fan, conf->mode, &conf->smart);
192 } else {
193 reg = ite_ec_read(base, ITE_EC_FAN_CTL_MODE);
194 if (conf->mode == FAN_MODE_ON)
195 reg |= ITE_EC_FAN_CTL_ON(fan);
196 else
197 reg &= ~ITE_EC_FAN_CTL_ON(fan);
198 ite_ec_write(base, ITE_EC_FAN_CTL_MODE, reg);
199 }
200
201 if (IS_ENABLED(SUPERIO_ITE_ENV_CTRL_FAN16_CONFIG)
202 && conf->mode >= FAN_MODE_ON) {
203 reg = ite_ec_read(base, ITE_EC_FAN_TAC_COUNTER_ENABLE);
204 reg |= ITE_EC_FAN_TAC_16BIT_ENABLE(fan);
205 ite_ec_write(base, ITE_EC_FAN_TAC_COUNTER_ENABLE, reg);
206 }
207
208 reg = ite_ec_read(base, ITE_EC_FAN_MAIN_CTL);
209 if (conf->mode >= FAN_MODE_ON)
210 reg |= ITE_EC_FAN_MAIN_CTL_TAC_EN(fan);
211 else
212 reg &= ~ITE_EC_FAN_MAIN_CTL_TAC_EN(fan);
213 if (conf->mode >= FAN_SMART_SOFTWARE)
214 reg |= ITE_EC_FAN_MAIN_CTL_SMART(fan);
215 else
216 reg &= ~ITE_EC_FAN_MAIN_CTL_SMART(fan);
217 ite_ec_write(base, ITE_EC_FAN_MAIN_CTL, reg);
218}
219
220void ite_ec_init(const u16 base, const struct ite_ec_config *const conf)
221{
222 size_t i;
223
224 /* Configure 23.43kHz PWM active high output */
225 u8 fan_ctl = ite_ec_read(base, ITE_EC_FAN_CTL_MODE);
226 fan_ctl &= ~ITE_EC_FAN_PWM_CLOCK_MASK;
227 fan_ctl |= ITE_EC_FAN_PWM_DEFAULT_CLOCK;
228 fan_ctl |= ITE_EC_FAN_CTL_POLARITY_HIGH;
229 ite_ec_write(base, ITE_EC_FAN_CTL_MODE, fan_ctl);
230
231 /* Enable PECI if configured */
232 enable_peci(base, conf->peci_tmpin);
233
234 /* Enable HWM if configured */
235 for (i = 0; i < ITE_EC_TMPIN_CNT; ++i)
236 enable_tmpin(base, i + 1, conf->tmpin_mode[i]);
237
238 /* Enable reading of voltage pins */
239 ite_ec_write(base, ITE_EC_ADC_VOLTAGE_CHANNEL_ENABLE, conf->vin_mask);
240
241 /* Enable FANx if configured */
242 for (i = 0; i < ITE_EC_FAN_CNT; ++i)
243 enable_fan(base, i + 1, &conf->fan[i]);
244
245 /*
246 * System may get wrong temperature data when SIO is in
247 * busy state. Therefore, check the status and terminate
248 * processes if needed.
249 */
250 if (conf->peci_tmpin != 0)
251 extemp_force_idle_status(base);
252}