This patch adds support for the Intel i82810 northbridge and various i82801xx
[coreboot.git] / src / southbridge / intel / i82801xx / i82801xx_lpc.c
1 /*
2  * This file is part of the LinuxBIOS project.
3  *
4  * Copyright (C) 2003 Linux Networx
5  * Copyright (C) 2003 SuSE Linux AG
6  * Copyright (C) 2005 Tyan Computer
7  * (Written by Yinghai Lu <yinghailu@gmail.com> for Tyan Computer)
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
22  */
23  
24 /* from i82801dbm, needs to be fixed to support everything the i82801er does */
25
26 #include <console/console.h>
27 #include <device/device.h>
28 #include <device/pci.h>
29 #include <device/pci_ids.h>
30 #include <pc80/mc146818rtc.h>
31 #include <pc80/isa-dma.h>
32 #include <arch/io.h>
33 #include "i82801xx.h"
34
35 #define NMI_OFF 0
36
37 void i82801xx_enable_ioapic( struct device *dev) 
38 {
39         uint32_t reg32;
40         volatile uint32_t *ioapic_index = (volatile uint32_t *)0xfec00000;
41         volatile uint32_t *ioapic_data = (volatile uint32_t *)0xfec00010;
42
43         reg32 = pci_read_config32(dev, GEN_CNTL);
44         reg32 |= (3 << 7); /* Enable IOAPIC */
45         reg32 |= (1 << 13); /* Coprocessor error enable */
46         reg32 |= (1 << 1); /* Delayed transaction enable */
47         reg32 |= (1 << 2); /* DMA collection buffer enable */
48         pci_write_config32(dev, GEN_CNTL, reg32);
49         printk_debug("IOAPIC Southbridge enabled %x\n", reg32);
50
51         *ioapic_index = 0;
52         *ioapic_data = (1 << 25);
53
54         *ioapic_index = 0;
55         reg32 = *ioapic_data;
56         printk_debug("Southbridge APIC ID = %x\n", reg32);
57         if(reg32 != (1 << 25))
58                 die("APIC Error\n");
59
60         /* TODO: From i82801ca, needed/useful on other ICH? */
61         *ioapic_index = 3;      // Select Boot Configuration register
62         *ioapic_data = 1;       // Use Processor System Bus to deliver interrupts
63 }
64
65 void i82801xx_enable_serial_irqs( struct device *dev)
66 {
67         /* set packet length and toggle silent mode bit */
68         pci_write_config8(dev, SERIRQ_CNTL, (1 << 7)|(1 << 6)|((21 - 17) << 2)|(0 << 0));
69         pci_write_config8(dev, SERIRQ_CNTL, (1 << 7)|(0 << 6)|((21 - 17) << 2)|(0 << 0));
70         /* TODO: Explain/#define the real meaning of these magic numbers ^^^ */
71 }
72
73 void i82801xx_lpc_route_dma( struct device *dev, uint8_t mask) 
74 {
75         uint16_t reg16;
76         int i;
77         reg16 = pci_read_config16(dev, PCI_DMA_CFG);
78         reg16 &= 0x300;
79         for(i = 0; i < 8; i++) {
80                 if (i == 4)
81                         continue;
82                 reg16 |= ((mask & (1 << i))? 3:1) << (i * 2);
83         }
84         pci_write_config16(dev, PCI_DMA_CFG, reg16);
85 }
86
87 void i82801xx_rtc_init(struct device *dev)
88 {//todo:needs serious cleanup/comments
89         uint8_t reg8;
90         uint32_t reg32;
91         int rtc_failed;
92         byte = pci_read_config8(dev, GEN_PMCON_3);
93         rtc_failed = byte & RTC_BATTERY_DEAD;
94         if (rtc_failed) {
95                 reg8 &= ~(1 << 1); /* preserve the power fail state */
96                 pci_write_config8(dev, GEN_PMCON_3, reg8);
97         }
98         reg32 = pci_read_config32(dev, GEN_STS);
99         rtc_failed |= reg32 & (1 << 2);
100         rtc_init(rtc_failed);
101 }
102
103
104 void i82801xx_1f0_misc(struct device *dev)
105 {
106         /* TODO: break this down into smaller functions */
107
108         //move to acpi_enable or something
109         /* Set ACPI base address to 0x1100 (I/O space) */
110         pci_write_config32(dev, PMBASE, PM_BASE_ADDR | 1);
111         /* Enable ACPI I/O and power management */
112         pci_write_config8(dev, ACPI_CNTL, 0x10);
113         /* Set GPIO base address to 0x1180 (I/O space) */
114         pci_write_config32(dev, GPIO_BASE, GPIO_BASE_ADDR | 1);
115         /* Enable GPIO */
116         pci_write_config8(dev, GPIO_CNTL, 0x10);
117         
118         //get rid of?
119         /* Route PIRQA to IRQ11, PIRQB to IRQ3, PIRQC to IRQ5, PIRQD to IRQ10 */
120         pci_write_config32(dev, PIRQA_ROUT, 0x0A05030B);
121         /* Route PIRQE to IRQ7. Leave PIRQF - PIRQH unrouted */
122         pci_write_config8(dev, PIRQE_ROUT, 0x07);
123         
124         //move to i82801xx_init
125         /* Prevent LPC disabling, enable parity errors, and SERR# (System Error) */
126         pci_write_config16(dev, PCI_COMMAND, 0x014f);
127         /* Enable access to the upper 128 byte bank of CMOS RAM */
128         pci_write_config8(dev, RTC_CONF, 0x04);
129         /* Decode 0x3F8-0x3FF (COM1) for COMA port, 0x2F8-0x2FF (COM2) for COMB */
130         pci_write_config8(dev, COM_DEC, 0x10);
131         /* LPT decode defaults to 0x378-0x37F and 0x778-0x77F
132          * Floppy decode defaults to 0x3F0-0x3F5, 0x3F7 */
133         /* Enable: COMA, COMB, LPT, Floppy
134          * Disable: Microcontroller, Sound, Gameport */
135         pci_write_config16(dev, LPC_EN, 0x000F);
136 }
137
138 static void enable_hpet(struct device *dev)
139 {
140 #ifdef HPET_PRESENT
141         uint32_t reg32;
142         uint32_t code = (0 & 0x3);
143
144         reg32 = pci_read_config32(dev, GEN_CNTL);
145         reg32 |= (1 << 17); /* Enable HPET */
146         /*Bits [16:15]Memory Address Range
147         00 FED0_0000h - FED0_03FFh
148         01 FED0_1000h - FED0_13FFh
149         10 FED0_2000h - FED0_23FFh
150         11 FED0_3000h - FED0_33FFh*/
151
152         reg32 &= ~(3 << 15); /* Clear it */
153         reg32 |= (code << 15);
154         /* reg32 is never written to anywhere?? */
155         printk_debug("Enabling HPET @0x%x\n", HPET_ADDR | (code << 12));
156 #endif
157 }
158
159
160 static void lpc_init(struct device *dev)
161 {
162         uint8_t byte;
163         int pwr_on = -1;
164         int nmi_option;
165
166         /* IO APIC initialization */
167         i82801xx_enable_ioapic(dev);
168
169         i82801xx_enable_serial_irqs(dev);
170
171         /* TODO: Find out if this is being used/works */
172 #ifdef SUSPICIOUS_LOOKING_CODE  
173         /* The ICH-4 datasheet does not mention this configuration register. */ 
174         /* This code may have been inherited (incorrectly) from code for 
175         the AMD 766 southbridge, which *does* support this functionality. */
176
177         /* Posted memory write enable */
178         byte = pci_read_config8(dev, 0x46);
179         pci_write_config8(dev, 0x46, byte | (1<<0)); 
180 #endif
181
182         /* power after power fail */
183         /* FIXME this doesn't work! */
184         /* Which state do we want to goto after g3 (power restored)?
185          * 0 == S0 Full On
186          * 1 == S5 Soft Off
187          */
188         pci_write_config8(dev, GEN_PMCON_3, pwr_on?0:1);
189         printk_info("Set power %s if power fails\n", pwr_on?"on":"off");
190
191         /* Set up NMI on errors */
192         byte = inb(0x61);
193         byte &= ~(1 << 3); /* IOCHK# NMI Enable */
194         byte &= ~(1 << 2); /* PCI SERR# Enable */
195         outb(byte, 0x61);
196         byte = inb(0x70);
197
198         nmi_option = NMI_OFF;
199         get_option(&nmi_option, "nmi");
200         if (nmi_option) {                       
201                 byte &= ~(1 << 7); /* set NMI */
202                 outb(byte, 0x70);
203         }
204         
205         /* Initialize the real time clock */
206         i82801xx_rtc_init(dev);
207
208         i82801xx_lpc_route_dma(dev, 0xff);
209
210         /* Initialize isa dma */
211         isa_dma_init();
212
213         i82801xx_1f0_misc(dev);
214         /* Initialize the High Precision Event Timers, if present */
215         enable_hpet(dev);
216 }
217
218 static void i82801xx_lpc_read_resources(device_t dev)
219 {
220         struct resource *res;
221
222         /* Get the normal pci resources of this device */
223         pci_dev_read_resources(dev);
224
225         /* Add an extra subtractive resource for both memory and I/O */
226         res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
227         res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
228
229         res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
230         res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
231 }
232
233 static void i82801xx_lpc_enable_resources(device_t dev)
234 {
235         pci_dev_enable_resources(dev);
236         enable_childrens_resources(dev);
237 }
238
239 static struct device_operations lpc_ops  = {
240         .read_resources   = i82801xx_lpc_read_resources,
241         .set_resources    = pci_dev_set_resources,
242         .enable_resources = i82801xx_lpc_enable_resources,
243         .init             = lpc_init,
244         .scan_bus         = scan_static_bus,
245         .enable           = i82801xx_enable,
246 };
247
248 static struct pci_driver i82801aa_lpc __pci_driver = {
249         .ops    = &lpc_ops,
250         .vendor = PCI_VENDOR_ID_INTEL,
251         .device = 0x2410,
252 };
253
254 static struct pci_driver i82801ab_lpc __pci_driver = {
255         .ops    = &lpc_ops,
256         .vendor = PCI_VENDOR_ID_INTEL,
257         .device = 0x2420,
258 };
259
260 static struct pci_driver i82801ba_lpc __pci_driver = {
261         .ops    = &lpc_ops,
262         .vendor = PCI_VENDOR_ID_INTEL,
263         .device = 0x2440,
264 };
265
266 static struct pci_driver i82801ca_lpc __pci_driver = {
267         .ops    = &lpc_ops,
268         .vendor = PCI_VENDOR_ID_INTEL,
269         .device = 0x2480,
270 };
271
272 static struct pci_driver i82801db_lpc __pci_driver = {
273         .ops    = &lpc_ops,
274         .vendor = PCI_VENDOR_ID_INTEL,
275         .device = 0x24c0,
276 };
277
278 static struct pci_driver i82801dbm_lpc __pci_driver = {
279         .ops    = &lpc_ops,
280         .vendor = PCI_VENDOR_ID_INTEL,
281         .device = 0x24cc,
282 };
283
284 /* i82801eb and er */
285 static struct pci_driver i82801ex_lpc __pci_driver = {
286         .ops    = &lpc_ops,
287         .vendor = PCI_VENDOR_ID_INTEL,
288         .device = 0x24d0,
289 };