0c6d8642141b9f313010ca6bfecba0a5746687bb
[coreboot.git] / src / superio / winbond / w83627hf / superio.c
1 /* Copyright 2000  AG Electronics Ltd. */
2 /* Copyright 2003-2004 Linux Networx */
3 /* Copyright 2004 Tyan
4    By LYH change from PC87360 */
5 /* This code is distributed without warranty under the GPL v2 (see COPYING) */
6
7 #include <arch/io.h>
8 #include <device/device.h>
9 #include <device/pnp.h>
10 #include <console/console.h>
11 #include <string.h>
12 #include <bitops.h>
13 #include <uart8250.h>
14 #include <pc80/keyboard.h>
15 #include <pc80/mc146818rtc.h>
16 #include <stdlib.h>
17 #include "chip.h"
18 #include "w83627hf.h"
19
20
21 static void pnp_enter_ext_func_mode(device_t dev)
22 {
23         outb(0x87, dev->path.pnp.port);
24         outb(0x87, dev->path.pnp.port);
25 }
26 static void pnp_exit_ext_func_mode(device_t dev)
27 {
28         outb(0xaa, dev->path.pnp.port);
29 }
30
31 static void pnp_write_index(unsigned long port_base, uint8_t reg, uint8_t value)
32 {
33         outb(reg, port_base);
34         outb(value, port_base + 1);
35 }
36
37 static uint8_t pnp_read_index(unsigned long port_base, uint8_t reg)
38 {
39         outb(reg, port_base);
40         return inb(port_base + 1);
41 }
42
43 static void enable_hwm_smbus(device_t dev) {
44         /* set the pin 91,92 as I2C bus */
45         uint8_t reg, value;
46         reg = 0x2b;
47         value = pnp_read_config(dev, reg);
48         value &= 0x3f;
49         pnp_write_config(dev, reg, value);
50 }
51
52 static void init_acpi(device_t dev)
53 {
54         uint8_t  value = 0x20;
55         uint32_t power_on = 1;
56
57         get_option("power_on_after_fail", &power_on);
58         pnp_enter_ext_func_mode(dev);
59         pnp_write_index(dev->path.pnp.port,7,0x0a);
60         value = pnp_read_config(dev, 0xE4);
61         value &= ~(3<<5);
62         if(power_on) {
63                 value |= (1<<5);
64         }
65         pnp_write_config(dev, 0xE4, value);
66         pnp_exit_ext_func_mode(dev);
67 }
68
69 static void init_hwm(unsigned long base)
70 {
71         uint8_t  reg, value;
72         int i;
73
74         unsigned  hwm_reg_values[] = {
75 /*              reg  mask  data */
76                 0x40, 0xff, 0x81,  /* start HWM */
77                 0x48, 0xaa, 0x2a,  /* set SMBus base to 0x54>>1 */
78                 0x4a, 0x21, 0x21,  /* set T2 SMBus base to 0x92>>1 and T3 SMBus base to 0x94>>1 */
79                 0x4e, 0x80, 0x00,
80                 0x43, 0x00, 0xff,
81                 0x44, 0x00, 0x3f,
82                 0x4c, 0xbf, 0x18,
83                 0x4d, 0xff, 0x80   /* turn off beep */
84
85         };
86
87         for(i = 0; i<  ARRAY_SIZE(hwm_reg_values); i+=3 ) { 
88                 reg = hwm_reg_values[i];        
89                 value = pnp_read_index(base, reg);              
90                 value &= 0xff & hwm_reg_values[i+1];
91                 value |= 0xff & hwm_reg_values[i+2];
92 #if 0
93                 printk_debug("base = 0x%04x, reg = 0x%02x, value = 0x%02x\r\n", base, reg,value);
94 #endif
95                 pnp_write_index(base, reg, value);
96         }
97 }
98
99 static void w83627hf_init(device_t dev)
100 {
101         struct superio_winbond_w83627hf_config *conf;
102         struct resource *res0, *res1;
103         if (!dev->enabled) {
104                 return;
105         }
106         conf = dev->chip_info;
107         switch(dev->path.pnp.device) {
108         case W83627HF_SP1:
109                 res0 = find_resource(dev, PNP_IDX_IO0);
110                 init_uart8250(res0->base, &conf->com1);
111                 break;
112         case W83627HF_SP2:
113                 res0 = find_resource(dev, PNP_IDX_IO0);
114                 init_uart8250(res0->base, &conf->com2);
115                 break;
116         case W83627HF_KBC:
117                 res0 = find_resource(dev, PNP_IDX_IO0);
118                 res1 = find_resource(dev, PNP_IDX_IO1);
119                 init_pc_keyboard(res0->base, res1->base, &conf->keyboard);
120                 break;
121         case W83627HF_HWM:
122                 res0 = find_resource(dev, PNP_IDX_IO0);
123 #define HWM_INDEX_PORT 5
124                 init_hwm(res0->base + HWM_INDEX_PORT);
125                 break;
126         case W83627HF_ACPI:
127                 init_acpi(dev);
128                 break;
129         }
130 }
131
132 void w83627hf_pnp_set_resources(device_t dev)
133 {
134         pnp_enter_ext_func_mode(dev);
135         pnp_set_resources(dev);
136         pnp_exit_ext_func_mode(dev);
137
138 }
139
140 void w83627hf_pnp_enable_resources(device_t dev)
141 {
142         pnp_enter_ext_func_mode(dev);
143         pnp_enable_resources(dev);
144         switch(dev->path.pnp.device) {
145         case W83627HF_HWM:
146                 printk_debug("w83627hf hwm smbus enabled\n");
147                 enable_hwm_smbus(dev);
148                 break;
149         }
150         pnp_exit_ext_func_mode(dev);
151
152 }
153
154 void w83627hf_pnp_enable(device_t dev)
155 {
156
157         if (!dev->enabled) {
158                 pnp_enter_ext_func_mode(dev);
159
160                 pnp_set_logical_device(dev);
161                 pnp_set_enable(dev, 0);
162
163                 pnp_exit_ext_func_mode(dev);
164         }
165 }
166
167 static struct device_operations ops = {
168         .read_resources   = pnp_read_resources,
169         .set_resources    = w83627hf_pnp_set_resources,
170         .enable_resources = w83627hf_pnp_enable_resources,
171         .enable           = w83627hf_pnp_enable,
172         .init             = w83627hf_init,
173 };
174
175 static struct pnp_info pnp_dev_info[] = {
176         { &ops, W83627HF_FDC,  PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x07f8, 0}, },
177         { &ops, W83627HF_PP,   PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, { 0x07f8, 0}, },
178         { &ops, W83627HF_SP1,  PNP_IO0 | PNP_IRQ0, { 0x7f8, 0 }, },
179         { &ops, W83627HF_SP2,  PNP_IO0 | PNP_IRQ0, { 0x7f8, 0 }, },
180         // No 4 { 0,},
181         { &ops, W83627HF_KBC,  PNP_IO0 | PNP_IO1 | PNP_IRQ0 | PNP_IRQ1, { 0x7ff, 0 }, { 0x7ff, 0x4}, },
182         { &ops, W83627HF_CIR, PNP_IO0 | PNP_IRQ0, { 0x7f8, 0 }, },
183         { &ops, W83627HF_GAME_MIDI_GPIO1, PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x7ff, 0 }, {0x7fe, 0x4}, },
184         { &ops, W83627HF_GPIO2, },
185         { &ops, W83627HF_GPIO3, },
186         { &ops, W83627HF_ACPI, },
187         { &ops, W83627HF_HWM,  PNP_IO0 | PNP_IRQ0, { 0xff8, 0 }, },
188 };
189
190 static void enable_dev(struct device *dev)
191 {
192         pnp_enable_devices(dev, &ops,
193                 ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
194 }
195
196 struct chip_operations superio_winbond_w83627hf_ops = {
197         CHIP_NAME("Winbond W83627HF Super I/O")
198         .enable_dev = enable_dev,
199 };