blob: 82f30fa6cd36b9bbaf4aa9469d24ad571af9d7be [file] [log] [blame]
Felix Held3f3eca92020-01-23 17:12:32 +01001/* SPDX-License-Identifier: GPL-2.0-or-later */
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -07002
3#include <device/device.h>
4#include <device/pnp.h>
Ted Kuo4e8f23b2015-03-18 10:42:22 +08005#include <console/console.h>
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -07006#include <pc80/keyboard.h>
7#include <arch/io.h>
Ryan Linbd978852014-09-22 23:29:16 -07008#include <delay.h>
Edward O'Callaghan0f7ec312014-11-01 12:11:58 +11009#include <superio/conf_mode.h>
Felix Heldfa120eb2019-10-07 18:45:10 +020010#include <superio/hwm5_conf.h>
Edward O'Callaghan0f7ec312014-11-01 12:11:58 +110011
Edward O'Callaghandef00be2014-04-30 05:01:52 +100012#include "chip.h" /* FIXME */
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -070013#include "it8772f.h"
14
Felix Heldfa120eb2019-10-07 18:45:10 +020015/* FIXME: see if the common ITE environment controller code can be used here */
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -070016
Ryan Linbd978852014-09-22 23:29:16 -070017static void it8772f_extemp_force_idle_status(struct resource *res)
18{
19 u8 reg;
20 int retries = 10;
21
22 /* Wait up to 10ms for non-busy state. */
23 while (retries > 0) {
Felix Heldfa120eb2019-10-07 18:45:10 +020024 reg = pnp_read_hwm5_index(res->base, IT8772F_EXTEMP_STATUS);
Ryan Linbd978852014-09-22 23:29:16 -070025
26 if ((reg & IT8772F_EXTEMP_STATUS_HOST_BUSY) == 0x0)
27 break;
28
29 retries--;
30
31 mdelay(1);
32 }
33
34 if (retries == 0 && (reg & IT8772F_EXTEMP_STATUS_HOST_BUSY) == 0x1) {
35 /*
36 * SIO is busy due to unfinished peci transaction.
37 * Re-configure Register 0x8E to terminate processes.
38 */
Felix Heldfa120eb2019-10-07 18:45:10 +020039 pnp_write_hwm5_index(res->base, IT8772F_EXTEMP_CONTROL,
Ryan Linbd978852014-09-22 23:29:16 -070040 IT8772F_EXTEMP_CONTROL_AUTO_4HZ |
41 IT8772F_EXTEMP_CONTROL_AUTO_START);
42 }
43}
44
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -070045/*
46 * Setup External Temperature to read via PECI into TMPINx register
47 */
48static void it8772f_enable_peci(struct resource *res, int tmpin)
49{
50 if (tmpin < 1 || tmpin > 3)
51 return;
52
53 /* Enable PECI interface */
Felix Heldfa120eb2019-10-07 18:45:10 +020054 pnp_write_hwm5_index(res->base, IT8772F_INTERFACE_SELECT,
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -070055 IT8772F_INTERFACE_SEL_PECI |
56 IT8772F_INTERFACE_SPEED_TOLERANCE);
57
58 /* Setup External Temperature using PECI GetTemp */
Felix Heldfa120eb2019-10-07 18:45:10 +020059 pnp_write_hwm5_index(res->base, IT8772F_EXTEMP_ADDRESS,
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -070060 PECI_CLIENT_ADDRESS);
Felix Heldfa120eb2019-10-07 18:45:10 +020061 pnp_write_hwm5_index(res->base, IT8772F_EXTEMP_COMMAND,
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -070062 PECI_GETTEMP_COMMAND);
Felix Heldfa120eb2019-10-07 18:45:10 +020063 pnp_write_hwm5_index(res->base, IT8772F_EXTEMP_WRITE_LENGTH,
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -070064 PECI_GETTEMP_WRITE_LENGTH);
Felix Heldfa120eb2019-10-07 18:45:10 +020065 pnp_write_hwm5_index(res->base, IT8772F_EXTEMP_READ_LENGTH,
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -070066 PECI_GETTEMP_READ_LENGTH);
Felix Heldfa120eb2019-10-07 18:45:10 +020067 pnp_write_hwm5_index(res->base, IT8772F_EXTEMP_CONTROL,
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -070068 IT8772F_EXTEMP_CONTROL_AUTO_4HZ |
69 IT8772F_EXTEMP_CONTROL_AUTO_START);
70
71 /* External Temperature reported in TMPINx register */
Felix Heldfa120eb2019-10-07 18:45:10 +020072 pnp_write_hwm5_index(res->base, IT8772F_ADC_TEMP_CHANNEL_ENABLE,
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -070073 (tmpin & 3) << 6);
74}
75
76/*
Ted Kuo4e8f23b2015-03-18 10:42:22 +080077 * Set up External Temperature to read via thermal diode/resistor
78 * into TMPINx register
79 */
80static void it8772f_enable_tmpin(struct resource *res, int tmpin,
81 enum thermal_mode mode)
82{
83 u8 reg;
84
85 if (tmpin != 1 && tmpin != 2)
86 return;
87
Felix Heldfa120eb2019-10-07 18:45:10 +020088 reg = pnp_read_hwm5_index(res->base, IT8772F_ADC_TEMP_CHANNEL_ENABLE);
Ted Kuo4e8f23b2015-03-18 10:42:22 +080089
90 switch (mode) {
91 case THERMAL_DIODE:
92 /* Thermal Diode Mode */
Felix Heldfa120eb2019-10-07 18:45:10 +020093 pnp_write_hwm5_index(res->base, IT8772F_ADC_TEMP_CHANNEL_ENABLE,
Ted Kuo4e8f23b2015-03-18 10:42:22 +080094 reg | tmpin);
95 break;
96 case THERMAL_RESISTOR:
97 /* Thermal Resistor Mode */
Felix Heldfa120eb2019-10-07 18:45:10 +020098 pnp_write_hwm5_index(res->base, IT8772F_ADC_TEMP_CHANNEL_ENABLE,
Ted Kuo4e8f23b2015-03-18 10:42:22 +080099 reg | (tmpin << 3));
100 break;
101 default:
102 printk(BIOS_ERR, "Unsupported thermal mode 0x%x on TMPIN%d\n",
103 mode, tmpin);
104 return;
105 }
106
Felix Heldfa120eb2019-10-07 18:45:10 +0200107 reg = pnp_read_hwm5_index(res->base, IT8772F_CONFIGURATION);
Ted Kuo4e8f23b2015-03-18 10:42:22 +0800108
109 /* Enable the startup of monitoring operation */
Felix Heldfa120eb2019-10-07 18:45:10 +0200110 pnp_write_hwm5_index(res->base, IT8772F_CONFIGURATION, reg | 0x01);
Ted Kuo4e8f23b2015-03-18 10:42:22 +0800111}
112
113/*
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700114 * Setup a FAN PWM interface for software control
115 */
Ted Kuo08debac2015-03-27 18:59:07 +0800116static void it8772f_enable_fan(struct resource *res, int fan, u8 fan_speed)
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700117{
118 u8 reg;
119
120 if (fan < 1 || fan > 3)
121 return;
122
123 /* Enable 6MHz (23.43kHz PWM) active high output */
Felix Heldfa120eb2019-10-07 18:45:10 +0200124 reg = pnp_read_hwm5_index(res->base, IT8772F_FAN_CTL_MODE);
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700125 reg |= IT8772F_FAN_CTL_ON(fan) |
126 IT8772F_FAN_PWM_CLOCK_6MHZ |
127 IT8772F_FAN_CTL_POLARITY_HIGH;
Felix Heldfa120eb2019-10-07 18:45:10 +0200128 pnp_write_hwm5_index(res->base, IT8772F_FAN_CTL_MODE, reg);
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700129
130 /* Enable output in smart mode */
Felix Heldfa120eb2019-10-07 18:45:10 +0200131 reg = pnp_read_hwm5_index(res->base, IT8772F_FAN_MAIN_CTL);
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700132 reg |= IT8772F_FAN_MAIN_CTL_TAC_SMART(fan);
133 reg |= IT8772F_FAN_MAIN_CTL_TAC_EN(fan);
Felix Heldfa120eb2019-10-07 18:45:10 +0200134 pnp_write_hwm5_index(res->base, IT8772F_FAN_MAIN_CTL, reg);
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700135
136 switch (fan) {
137 case 2:
138 /* Enable software operation */
Felix Heldfa120eb2019-10-07 18:45:10 +0200139 pnp_write_hwm5_index(res->base, IT8772F_FAN_CTL2_PWM_MODE,
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700140 IT8772F_FAN_CTL_PWM_MODE_SOFTWARE);
141 /* Disable Smoothing */
Felix Heldfa120eb2019-10-07 18:45:10 +0200142 pnp_write_hwm5_index(res->base, IT8772F_FAN_CTL2_AUTO_MODE,
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700143 IT8772F_FAN_CTL_AUTO_SMOOTHING_DIS);
Ted Kuo08debac2015-03-27 18:59:07 +0800144 /* Set a default fan speed */
145 if (fan_speed)
Felix Heldfa120eb2019-10-07 18:45:10 +0200146 pnp_write_hwm5_index(res->base, IT8772F_FAN_CTL2_PWM_START,
Ted Kuo08debac2015-03-27 18:59:07 +0800147 fan_speed);
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700148 break;
149 case 3:
150 /* Enable software operation */
Felix Heldfa120eb2019-10-07 18:45:10 +0200151 pnp_write_hwm5_index(res->base, IT8772F_FAN_CTL3_PWM_MODE,
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700152 IT8772F_FAN_CTL_PWM_MODE_SOFTWARE);
153 /* Disable Smoothing */
Felix Heldfa120eb2019-10-07 18:45:10 +0200154 pnp_write_hwm5_index(res->base, IT8772F_FAN_CTL3_AUTO_MODE,
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700155 IT8772F_FAN_CTL_AUTO_SMOOTHING_DIS);
Ted Kuo08debac2015-03-27 18:59:07 +0800156 /* Set a default fan speed */
157 if (fan_speed)
Felix Heldfa120eb2019-10-07 18:45:10 +0200158 pnp_write_hwm5_index(res->base, IT8772F_FAN_CTL3_PWM_START,
Ted Kuo08debac2015-03-27 18:59:07 +0800159 fan_speed);
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700160 break;
161 }
162}
163
Edward O'Callaghanf21bdc32014-10-21 07:43:41 +1100164static void it8772f_init(struct device *dev)
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700165{
166 struct superio_ite_it8772f_config *conf = dev->chip_info;
167 struct resource *res;
168
169 if (!dev->enabled)
170 return;
171
172 switch (dev->path.pnp.device) {
173 case IT8772F_EC:
Angel Ponsc167b742021-11-03 13:25:02 +0100174 res = probe_resource(dev, PNP_IDX_IO0);
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700175 if (!res)
176 break;
177
178 /* Enable PECI if configured */
179 it8772f_enable_peci(res, conf->peci_tmpin);
180
Ted Kuo4e8f23b2015-03-18 10:42:22 +0800181 /* Enable HWM if configured */
182 if (conf->tmpin1_mode != THERMAL_MODE_DISABLED)
183 it8772f_enable_tmpin(res, 1, conf->tmpin1_mode);
184 if (conf->tmpin2_mode != THERMAL_MODE_DISABLED)
185 it8772f_enable_tmpin(res, 2, conf->tmpin2_mode);
186
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700187 /* Enable FANx if configured */
188 if (conf->fan1_enable)
Ted Kuo08debac2015-03-27 18:59:07 +0800189 it8772f_enable_fan(res, 1, 0);
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700190 if (conf->fan2_enable)
Ted Kuo08debac2015-03-27 18:59:07 +0800191 it8772f_enable_fan(res, 2,
192 conf->fan2_speed ? conf->fan2_speed : 0x80);
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700193 if (conf->fan3_enable)
Ted Kuo08debac2015-03-27 18:59:07 +0800194 it8772f_enable_fan(res, 3,
195 conf->fan3_speed ? conf->fan3_speed : 0x80);
Ryan Linbd978852014-09-22 23:29:16 -0700196
197 /*
198 * System may get wrong temperature data when SIO is in
199 * busy state. Therefore, check the status and terminate
200 * processes if needed.
201 */
202 it8772f_extemp_force_idle_status(res);
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700203 break;
204 case IT8772F_GPIO:
205 /* Set GPIO output levels */
Angel Ponsc167b742021-11-03 13:25:02 +0100206 res = probe_resource(dev, PNP_IDX_IO1);
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700207 if (res) {
208 if (conf->gpio_set1)
209 outb(conf->gpio_set1, res->base + 0);
210 if (conf->gpio_set2)
211 outb(conf->gpio_set2, res->base + 1);
212 if (conf->gpio_set3)
213 outb(conf->gpio_set3, res->base + 2);
214 if (conf->gpio_set4)
215 outb(conf->gpio_set4, res->base + 3);
216 if (conf->gpio_set5)
217 outb(conf->gpio_set5, res->base + 4);
218 if (conf->gpio_set6)
219 outb(conf->gpio_set6, res->base + 5);
220 }
221 break;
222 case IT8772F_KBCK:
223 if (!conf->skip_keyboard) {
224 set_kbc_ps2_mode();
Timothy Pearson448e3862015-11-24 14:12:01 -0600225 pc_keyboard_init(NO_AUX_DEVICE);
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700226 }
227 break;
228 case IT8772F_KBCM:
229 break;
230 case IT8772F_IR:
231 break;
232 }
233}
234
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700235static struct device_operations ops = {
Nico Huber9cb09412013-06-15 15:30:19 +0200236 .read_resources = pnp_read_resources,
Nico Huber0b2ee932013-06-15 19:58:35 +0200237 .set_resources = pnp_set_resources,
238 .enable_resources = pnp_enable_resources,
239 .enable = pnp_alt_enable,
Nico Huber9cb09412013-06-15 15:30:19 +0200240 .init = it8772f_init,
Edward O'Callaghan0f7ec312014-11-01 12:11:58 +1100241 .ops_pnp_mode = &pnp_conf_mode_870155_aa,
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700242};
243
244static struct pnp_info pnp_dev_info[] = {
245 /* Floppy Disk Controller */
Felix Heldc40275b2017-12-27 22:11:30 +0100246 { NULL, IT8772F_FDC, PNP_IO0 | PNP_IRQ0, 0x0ff8, },
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700247 /* Serial Port 1 */
Felix Heldc40275b2017-12-27 22:11:30 +0100248 { NULL, IT8772F_SP1, PNP_IO0 | PNP_IRQ0, 0x0ff8, },
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700249 /* Environmental Controller */
Felix Heldc40275b2017-12-27 22:11:30 +0100250 { NULL, IT8772F_EC, PNP_IO0 | PNP_IO1 | PNP_IRQ0 |
Damien Zammit62c02762015-12-28 23:04:47 +1100251 PNP_MSC4 | PNP_MSCA,
Samuel Holland7daac912017-06-06 22:55:01 -0500252 0x0ff8, 0x0ffc, },
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700253 /* KBC Keyboard */
Felix Heldc40275b2017-12-27 22:11:30 +0100254 { NULL, IT8772F_KBCK, PNP_IO0 | PNP_IO1 | PNP_IRQ0,
Samuel Holland7daac912017-06-06 22:55:01 -0500255 0x0fff, 0x0fff, },
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700256 /* KBC Mouse */
Felix Heldc40275b2017-12-27 22:11:30 +0100257 { NULL, IT8772F_KBCM, PNP_IRQ0, },
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700258 /* 27 GPIOs */
Felix Heldc40275b2017-12-27 22:11:30 +0100259 { NULL, IT8772F_GPIO, PNP_IO0 | PNP_IO1,
Samuel Holland7daac912017-06-06 22:55:01 -0500260 0x0fff, 0x0ff8, },
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700261 /* Infrared */
Felix Heldc40275b2017-12-27 22:11:30 +0100262 { NULL, IT8772F_IR, PNP_IO0 | PNP_IRQ0, 0x0ff8, },
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700263};
264
265static void enable_dev(struct device *dev)
266{
Felix Heldc40275b2017-12-27 22:11:30 +0100267 pnp_enable_devices(dev, &ops, ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
Stefan Reinauerb0dd1d92012-03-30 15:04:07 -0700268}
269
270struct chip_operations superio_ite_it8772f_ops = {
271 CHIP_NAME("ITE IT8772F Super I/O")
272 .enable_dev = enable_dev,
273};