Add support for ITE IT8772F SuperI/O chip
[coreboot.git] / src / superio / ite / it8772f / superio.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2011 The ChromiumOS Authors.  All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 #include <device/device.h>
22 #include <device/pnp.h>
23 #include <uart8250.h>
24 #include <pc80/keyboard.h>
25 #include <arch/io.h>
26 #include <stdlib.h>
27 #include "chip.h"
28 #include "it8772f.h"
29
30 static void pnp_enter_ext_func_mode(device_t dev)
31 {
32         u16 port = dev->path.pnp.port;
33
34         outb(0x87, port);
35         outb(0x01, port);
36         outb(0x55, port);
37         outb((port == 0x4e) ? 0xaa : 0x55, port);
38 }
39
40 static void pnp_exit_ext_func_mode(device_t dev)
41 {
42         pnp_write_config(dev, 0x02, 0x02);
43 }
44
45 static inline u8 it8772f_envc_read(struct resource *res, u8 addr)
46 {
47         outb(addr, res->base + 5);
48         return inb(res->base + 6);
49 }
50
51 static inline void it8772f_envc_write(struct resource *res, u8 addr, u8 value)
52 {
53         outb(addr, res->base + 5);
54         outb(value, res->base + 6);
55 }
56
57 /*
58  * Setup External Temperature to read via PECI into TMPINx register
59  */
60 static void it8772f_enable_peci(struct resource *res, int tmpin)
61 {
62         if (tmpin < 1 || tmpin > 3)
63                 return;
64
65         /* Enable PECI interface */
66         it8772f_envc_write(res, IT8772F_INTERFACE_SELECT,
67                            IT8772F_INTERFACE_SEL_PECI |
68                            IT8772F_INTERFACE_SPEED_TOLERANCE);
69
70         /* Setup External Temperature using PECI GetTemp */
71         it8772f_envc_write(res, IT8772F_EXTEMP_ADDRESS,
72                            PECI_CLIENT_ADDRESS);
73         it8772f_envc_write(res, IT8772F_EXTEMP_COMMAND,
74                            PECI_GETTEMP_COMMAND);
75         it8772f_envc_write(res, IT8772F_EXTEMP_WRITE_LENGTH,
76                            PECI_GETTEMP_WRITE_LENGTH);
77         it8772f_envc_write(res, IT8772F_EXTEMP_READ_LENGTH,
78                            PECI_GETTEMP_READ_LENGTH);
79         it8772f_envc_write(res, IT8772F_EXTEMP_CONTROL,
80                            IT8772F_EXTEMP_CONTROL_AUTO_4HZ |
81                            IT8772F_EXTEMP_CONTROL_AUTO_START);
82
83         /* External Temperature reported in TMPINx register */
84         it8772f_envc_write(res, IT8772F_ADC_TEMP_CHANNEL_ENABLE,
85                            (tmpin & 3) << 6);
86 }
87
88 /*
89  * Setup a FAN PWM interface for software control
90  */
91 static void it8772f_enable_fan(struct resource *res, int fan)
92 {
93         u8 reg;
94
95         if (fan < 1 || fan > 3)
96                 return;
97
98         /* Enable 6MHz (23.43kHz PWM) active high output */
99         reg = it8772f_envc_read(res, IT8772F_FAN_CTL_MODE);
100         reg |= IT8772F_FAN_CTL_ON(fan) |
101                 IT8772F_FAN_PWM_CLOCK_6MHZ |
102                 IT8772F_FAN_CTL_POLARITY_HIGH;
103         it8772f_envc_write(res, IT8772F_FAN_CTL_MODE, reg);
104
105         /* Enable output in smart mode */
106         reg = it8772f_envc_read(res, IT8772F_FAN_MAIN_CTL);
107         reg |= IT8772F_FAN_MAIN_CTL_TAC_SMART(fan);
108         reg |= IT8772F_FAN_MAIN_CTL_TAC_EN(fan);
109         it8772f_envc_write(res, IT8772F_FAN_MAIN_CTL, reg);
110
111         switch (fan) {
112         case 2:
113                 /* Enable software operation */
114                 it8772f_envc_write(res, IT8772F_FAN_CTL2_PWM_MODE,
115                                    IT8772F_FAN_CTL_PWM_MODE_SOFTWARE);
116                 /* Disable Smoothing */
117                 it8772f_envc_write(res, IT8772F_FAN_CTL2_AUTO_MODE,
118                                    IT8772F_FAN_CTL_AUTO_SMOOTHING_DIS);
119                 /* Set a default medium fan speed */
120                 it8772f_envc_write(res, IT8772F_FAN_CTL2_PWM_START, 0x80);
121                 break;
122         case 3:
123                 /* Enable software operation */
124                 it8772f_envc_write(res, IT8772F_FAN_CTL3_PWM_MODE,
125                                    IT8772F_FAN_CTL_PWM_MODE_SOFTWARE);
126                 /* Disable Smoothing */
127                 it8772f_envc_write(res, IT8772F_FAN_CTL3_AUTO_MODE,
128                                    IT8772F_FAN_CTL_AUTO_SMOOTHING_DIS);
129                 /* Set a default medium fan speed */
130                 it8772f_envc_write(res, IT8772F_FAN_CTL3_PWM_START, 0x80);
131                 break;
132         }
133 }
134
135 static void it8772f_init(device_t dev)
136 {
137         struct superio_ite_it8772f_config *conf = dev->chip_info;
138         struct resource *res;
139
140         if (!dev->enabled)
141                 return;
142
143         switch (dev->path.pnp.device) {
144         case IT8772F_EC:
145                 res = find_resource(dev, PNP_IDX_IO0);
146                 if (!res)
147                         break;
148
149                 /* Enable PECI if configured */
150                 it8772f_enable_peci(res, conf->peci_tmpin);
151
152                 /* Enable FANx if configured */
153                 if (conf->fan1_enable)
154                         it8772f_enable_fan(res, 1);
155                 if (conf->fan2_enable)
156                         it8772f_enable_fan(res, 2);
157                 if (conf->fan3_enable)
158                         it8772f_enable_fan(res, 3);
159                 break;
160         case IT8772F_GPIO:
161                 /* Set GPIO output levels */
162                 res = find_resource(dev, PNP_IDX_IO1);
163                 if (res) {
164                         if (conf->gpio_set1)
165                                 outb(conf->gpio_set1, res->base + 0);
166                         if (conf->gpio_set2)
167                                 outb(conf->gpio_set2, res->base + 1);
168                         if (conf->gpio_set3)
169                                 outb(conf->gpio_set3, res->base + 2);
170                         if (conf->gpio_set4)
171                                 outb(conf->gpio_set4, res->base + 3);
172                         if (conf->gpio_set5)
173                                 outb(conf->gpio_set5, res->base + 4);
174                         if (conf->gpio_set6)
175                                 outb(conf->gpio_set6, res->base + 5);
176                 }
177                 break;
178         case IT8772F_KBCK:
179                 if (!conf->skip_keyboard) {
180                         set_kbc_ps2_mode();
181                         pc_keyboard_init(&conf->keyboard);
182                 }
183                 break;
184         case IT8772F_KBCM:
185                 break;
186         case IT8772F_IR:
187                 break;
188         }
189 }
190
191 static void it8772f_pnp_set_resources(device_t dev)
192 {
193         pnp_enter_ext_func_mode(dev);
194         pnp_set_resources(dev);
195         pnp_exit_ext_func_mode(dev);
196 }
197
198 static void it8772f_pnp_enable_resources(device_t dev)
199 {
200         pnp_enter_ext_func_mode(dev);
201         pnp_enable_resources(dev);
202         pnp_exit_ext_func_mode(dev);
203 }
204
205 static void it8772f_pnp_enable(device_t dev)
206 {
207         pnp_enter_ext_func_mode(dev);
208         pnp_set_logical_device(dev);
209         pnp_set_enable(dev, !!dev->enabled);
210         pnp_exit_ext_func_mode(dev);
211 }
212
213 static struct device_operations ops = {
214         .read_resources         = pnp_read_resources,
215         .set_resources          = it8772f_pnp_set_resources,
216         .enable_resources       = it8772f_pnp_enable_resources,
217         .enable                 = it8772f_pnp_enable,
218         .init                   = it8772f_init,
219 };
220
221 static struct pnp_info pnp_dev_info[] = {
222         /* Floppy Disk Controller */
223         { &ops, IT8772F_FDC, PNP_IO0 | PNP_IRQ0, {0x0ff8, 0}, },
224         /* Serial Port 1 */
225         { &ops, IT8772F_SP1, PNP_IO0 | PNP_IRQ0, {0x0ff8, 0}, },
226         /* Environmental Controller */
227         { &ops, IT8772F_EC, PNP_IO0 | PNP_IO1 | PNP_IRQ0,
228           {0x0ff8, 0}, {0x0ffc, 4}, },
229         /* KBC Keyboard */
230         { &ops, IT8772F_KBCK, PNP_IO0 | PNP_IO1 | PNP_IRQ0,
231           {0x0fff, 0}, {0x0fff, 4}, },
232         /* KBC Mouse */
233         { &ops, IT8772F_KBCM, PNP_IRQ0, },
234         /* 27 GPIOs */
235         { &ops, IT8772F_GPIO, PNP_IO0 | PNP_IO1,
236           {0x0fff, 0}, {0x0ff8, 0}, },
237         /* Infrared */
238         { &ops, IT8772F_IR, PNP_IO0 | PNP_IRQ0, {0x0ff8, 0}, },
239 };
240
241 static void enable_dev(struct device *dev)
242 {
243         pnp_enable_devices(dev, &pnp_ops,
244                 ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
245 }
246
247 struct chip_operations superio_ite_it8772f_ops = {
248         CHIP_NAME("ITE IT8772F Super I/O")
249         .enable_dev = enable_dev,
250 };