Add VIA CX700 support, plus VIA vt8454c reference board support.
[coreboot.git] / src / northbridge / via / cx700 / cx700_lpc.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2007-2009 coresystems GmbH
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; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  */
19
20 #include <arch/io.h>
21 #include <console/console.h>
22
23 #include <device/device.h>
24 #include <device/pci.h>
25 #include <device/pci_ops.h>
26 #include <device/pci_ids.h>
27
28 #include <pc80/mc146818rtc.h>
29 #include <pc80/i8259.h>
30 #include <pc80/keyboard.h>
31 #include <pc80/isa-dma.h>
32
33 #include <cpu/x86/lapic.h>
34 #include <stdlib.h>
35
36 #define ACPI_IO_BASE    0x400
37 #define HPET_ADDR       0xfe800000UL
38 #define IOAPIC_ADDR     0xfec00000ULL
39
40 #ifdef CONFIG_IOAPIC
41 struct ioapicreg {
42         unsigned int reg;
43         unsigned int value_low, value_high;
44 };
45
46 static struct ioapicreg ioapicregvalues[] = {
47 #define ALL             (0xff << 24)
48 #define NONE            (0)
49 #define DISABLED        (1 << 16)
50 #define ENABLED         (0 << 16)
51 #define TRIGGER_EDGE    (0 << 15)
52 #define TRIGGER_LEVEL   (1 << 15)
53 #define POLARITY_HIGH   (0 << 13)
54 #define POLARITY_LOW    (1 << 13)
55 #define PHYSICAL_DEST   (0 << 11)
56 #define LOGICAL_DEST    (1 << 11)
57 #define ExtINT          (7 << 8)
58 #define NMI             (4 << 8)
59 #define SMI             (2 << 8)
60 #define INT             (1 << 8)
61         /* IO-APIC virtual wire mode configuration */
62         /* mask, trigger, polarity, destination, delivery, vector */
63         { 0, ENABLED | TRIGGER_EDGE | POLARITY_HIGH | PHYSICAL_DEST | ExtINT, NONE},
64         { 1, DISABLED, NONE},
65         { 2, DISABLED, NONE},
66         { 3, DISABLED, NONE},
67         { 4, DISABLED, NONE},
68         { 5, DISABLED, NONE},
69         { 6, DISABLED, NONE},
70         { 7, DISABLED, NONE},
71         { 8, DISABLED, NONE},
72         { 9, DISABLED, NONE},
73         {10, DISABLED, NONE},
74         {11, DISABLED, NONE},
75         {12, DISABLED, NONE},
76         {13, DISABLED, NONE},
77         {14, DISABLED, NONE},
78         {15, DISABLED, NONE},
79         {16, DISABLED, NONE},
80         {17, DISABLED, NONE},
81         {18, DISABLED, NONE},
82         {19, DISABLED, NONE},
83         {20, DISABLED, NONE},
84         {21, DISABLED, NONE},
85         {22, DISABLED, NONE},
86         {23, DISABLED, NONE},
87 };
88
89 static void setup_ioapic(void)
90 {
91         int i;
92         unsigned long value_low, value_high, val;
93         unsigned long ioapic_base = IOAPIC_ADDR;
94         volatile unsigned long *l;
95         struct ioapicreg *a = ioapicregvalues;
96         unsigned long bsp_lapicid = lapicid();
97
98         l = (unsigned long *)ioapic_base;
99
100         /* Set APIC ADDR */
101         l[0] = 0;
102         val = l[4];
103         l[4] = (val & 0xF0FFFF) | (2 << 24);    // 2 == ID as programmed elsewhere. should be a define? XXX
104
105         /* Set APIC to FSB message bus. */
106         l[0] = 0x3;
107         val = l[4];
108         l[4] = (val & 0xFFFFFE) | 1;
109
110         ioapicregvalues[0].value_high = bsp_lapicid << (56 - 32);
111
112         printk_debug("IOAPIC:  Bootstrap Processor Local APIC ID = %02x\n", bsp_lapicid);
113
114         for (i = 0; i < ARRAY_SIZE(ioapicregvalues); i++, a++) {
115                 l[0] = (a->reg * 2) + 0x10;
116                 l[4] = a->value_low;
117                 value_low = l[4];
118                 l[0] = (a->reg * 2) + 0x11;
119                 l[4] = a->value_high;
120                 value_high = l[4];
121                 if ((i == 0) && (value_low == 0xffffffff)) {
122                         printk_warning("IOAPIC is not responding.\n");
123                         return;
124                 }
125                 printk_debug("IOAPIC: IRQ reg 0x%08x value 0x%08x 0x%08x\n",
126                              a->reg, a->value_low, a->value_high);
127         }
128 }
129 #endif
130
131 static const unsigned char pci_irqs[4] = { 11, 11, 10, 10 };
132
133 static const unsigned char usb_pins[4] = { 'A', 'B', 'C', 'D' };
134 static const unsigned char vga_pins[4] = { 'A', 'B', 'C', 'D' };
135 static const unsigned char slot_pins[4] = { 'B', 'C', 'D', 'A' };
136 static const unsigned char ac97_pins[4] = { 'B', 'C', 'D', 'A' };
137
138 static unsigned char *pin_to_irq(const unsigned char *pin)
139 {
140         static unsigned char irqs[4];
141         int i;
142         for (i = 0; i < 4; i++)
143                 irqs[i] = pci_irqs[pin[i] - 'A'];
144
145         return irqs;
146 }
147
148 static void pci_routing_fixup(struct device *dev)
149 {
150         printk_debug("%s: device is %p\n", __FUNCTION__, dev);
151
152         /* set up PCI IRQ routing */
153         pci_write_config8(dev, 0x55, pci_irqs[0] << 4);
154         pci_write_config8(dev, 0x56, pci_irqs[1] | (pci_irqs[2] << 4));
155         pci_write_config8(dev, 0x57, pci_irqs[3] << 4);
156
157         /* Assigning IRQs */
158         printk_debug("Setting up USB interrupts.\n");
159         pci_assign_irqs(0, 0x10, pin_to_irq(usb_pins));
160
161         printk_debug("Setting up VGA interrupts.\n");
162         pci_assign_irqs(1, 0x00, pin_to_irq(vga_pins));
163
164         printk_debug("Setting up PCI slot interrupts.\n");
165         pci_assign_irqs(2, 0x04, pin_to_irq(slot_pins));
166         // more?
167
168         printk_debug("Setting up AC97 interrupts.\n");
169         pci_assign_irqs(0x80, 0x1, pin_to_irq(ac97_pins));
170 }
171
172 /*
173  * Set up the power management capabilities directly into ACPI mode.  This
174  * avoids having to handle any System Management Interrupts (SMI's) which I
175  * can't figure out how to do !!!!
176  */
177
178 void setup_pm(device_t dev)
179 {
180         /* Debounce LID and PWRBTN# Inputs for 16ms. */
181         pci_write_config8(dev, 0x80, 0x20);
182
183         /* Set ACPI base address to IO ACPI_IO_BASE */
184         pci_write_config16(dev, 0x88, ACPI_IO_BASE | 1);
185
186         /* set ACPI irq to 9 */
187         pci_write_config8(dev, 0x82, 0x49);
188
189         /* Primary interupt channel, define wake events 0=IRQ0 15=IRQ15 1=en. */
190         pci_write_config16(dev, 0x84, 0x609a);
191
192         /* SMI output level to low, 7.5us throttle clock */
193         pci_write_config8(dev, 0x8d, 0x18);
194
195         /* GP Timer Control 1s */
196         pci_write_config8(dev, 0x93, 0x88);
197
198         /* Power Well */
199         pci_write_config8(dev, 0x94, 0x20);     // 0x20??
200
201         /* 7 = stp to sust delay 1msec
202          * 6 = SUSST# Deasserted Before PWRGD for STD
203          */
204         pci_write_config8(dev, 0x95, 0xc0);     // 0xc1??
205
206         /* Disable GP2 & GP3 Timer */
207         pci_write_config8(dev, 0x98, 0);
208
209         /* GP2 Timer Counter */
210         pci_write_config8(dev, 0x99, 0xfb);
211         /* GP3 Timer Counter */
212         //pci_write_config8(dev, 0x9a, 0x20);
213
214         /* Multi Function Select 1 */
215         pci_write_config8(dev, 0xe4, 0x00);
216
217         /* Multi Function Select 2 */
218         pci_write_config8(dev, 0xe5, 0x41);     //??
219
220         /* Enable ACPI access (and setup like award) */
221         pci_write_config8(dev, 0x81, 0x84);
222
223         /* Clear status events. */
224         outw(0xffff, ACPI_IO_BASE + 0x00);
225         outw(0xffff, ACPI_IO_BASE + 0x20);
226         outw(0xffff, ACPI_IO_BASE + 0x28);
227         outl(0xffffffff, ACPI_IO_BASE + 0x30);
228
229         /* Disable SCI on GPIO. */
230         outw(0x0, ACPI_IO_BASE + 0x22);
231
232         /* Disable SMI on GPIO. */
233         outw(0x0, ACPI_IO_BASE + 0x24);
234
235         /* Disable all global enable SMIs. */
236         outw(0x0, ACPI_IO_BASE + 0x2a);
237
238         /* All SMI off, both IDE buses ON, PSON rising edge. */
239         outw(0x0, ACPI_IO_BASE + 0x2c);
240
241         /* Primary activity SMI disable. */
242         outl(0x0, ACPI_IO_BASE + 0x34);
243
244         /* GP timer reload on none. */
245         outl(0x0, ACPI_IO_BASE + 0x38);
246
247         /* Disable extended IO traps. */
248         outb(0x0, ACPI_IO_BASE + 0x42);
249
250         /* SCI is generated for RTC/pwrBtn/slpBtn. */
251         outw(0x0001, ACPI_IO_BASE + 0x04);
252
253         /* Allow SLP# signal to assert LDTSTOP_L.
254          * Will work for C3 and for FID/VID change.
255          */
256         outb(0x1, ACPI_IO_BASE + 0x11);
257 }
258
259 static void cx700_set_lpc_registers(struct device *dev)
260 {
261         unsigned char enables;
262
263         printk_debug("VIA CX700 LPC bridge init\n");
264
265         // enable the internal I/O decode
266         enables = pci_read_config8(dev, 0x6C);
267         enables |= 0x80;
268         pci_write_config8(dev, 0x6C, enables);
269
270         // Map 4MB of FLASH into the address space
271 //      pci_write_config8(dev, 0x41, 0x7f);
272
273         // Set bit 6 of 0x40, because Award does it (IO recovery time)
274         // IMPORTANT FIX - EISA 0x4d0 decoding must be on so that PCI
275         // interrupts can be properly marked as level triggered.
276         enables = pci_read_config8(dev, 0x40);
277         enables |= 0x44;
278         pci_write_config8(dev, 0x40, enables);
279
280         /* DMA Line buffer control */
281         enables = pci_read_config8(dev, 0x42);
282         enables |= 0xf0;
283         pci_write_config8(dev, 0x42, enables);
284
285         /* I/O recovery time */
286         pci_write_config8(dev, 0x4c, 0x44);
287
288         /* ROM memory cycles go to LPC. */
289         pci_write_config8(dev, 0x59, 0x80);
290
291         /* Enable SM dynamic clock gating */
292         pci_write_config8(dev, 0x5b, 0x01);
293
294         /* Set Read Pass Write Control Enable */
295         pci_write_config8(dev, 0x48, 0x0c);
296
297         /* Set SM Misc Control: Enable Internal APIC . */
298         enables = pci_read_config8(dev, 0x58);
299         enables |= 1 << 6;
300         pci_write_config8(dev, 0x58, enables);
301         enables = pci_read_config8(dev, 0x4d);
302         enables |= 1 << 3;
303         pci_write_config8(dev, 0x4d, enables);
304
305         /* Set bit 3 of 0x4f to match award (use INIT# as cpu reset) */
306         enables = pci_read_config8(dev, 0x4f);
307         enables |= 0x08;
308         pci_write_config8(dev, 0x4f, enables);
309
310         /* enable KBC configuration */
311         pci_write_config8(dev, 0x51, 0x1f);
312
313         /* enable serial irq */
314         pci_write_config8(dev, 0x52, 0x9);
315
316         /* dma */
317         pci_write_config8(dev, 0x53, 0x00);
318
319         // Power management setup
320         setup_pm(dev);
321
322         /* set up isa bus -- i/o recovery time, rom write enable, extend-ale */
323         pci_write_config8(dev, 0x40, 0x54);
324
325         /* Enable HPET timer */
326         pci_write_config32(dev, 0x68, (1 << 31) | (HPET_ADDR >> 8));
327
328 }
329
330 void cx700_read_resources(device_t dev)
331 {
332         struct resource *resource;
333
334         /* Make sure we call our childrens set/enable functions - these
335          * are not called unless this device has a resource to set.
336          */
337
338         pci_dev_read_resources(dev);
339
340         resource = new_resource(dev, 1);
341         resource->flags |=
342             IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_IO | IORESOURCE_STORED;
343         resource->size = 2;
344         resource->base = 0x2e;
345 }
346
347 void cx700_set_resources(device_t dev)
348 {
349         struct resource *resource;
350         resource = find_resource(dev, 1);
351         resource->flags |= IORESOURCE_STORED;
352         pci_dev_set_resources(dev);
353 }
354
355 void cx700_enable_resources(device_t dev)
356 {
357         /* Enable SuperIO decoding */
358         pci_dev_enable_resources(dev);
359         enable_childrens_resources(dev);
360 }
361
362 static void cx700_lpc_init(struct device *dev)
363 {
364         cx700_set_lpc_registers(dev);
365
366 #ifdef CONFIG_IOAPIC
367         setup_ioapic();
368 #endif
369
370         /* Initialize interrupts */
371         pci_routing_fixup(dev);
372         /* make sure interupt controller is configured before keyboard init */
373         setup_i8259();
374
375         /* Start the Real Time Clock */
376         rtc_init(0);
377
378         /* Initialize isa dma */
379         isa_dma_init();
380
381         /* Initialize keyboard controller */
382         init_pc_keyboard(0x60, 0x64, 0);
383 }
384
385 static struct device_operations cx700_lpc_ops = {
386         .read_resources = cx700_read_resources,
387         .set_resources = cx700_set_resources,
388         .enable_resources = cx700_enable_resources,
389         .init = &cx700_lpc_init,
390         .scan_bus = scan_static_bus,
391 };
392
393 static const struct pci_driver lpc_driver __pci_driver = {
394         .ops = &cx700_lpc_ops,
395         .vendor = PCI_VENDOR_ID_VIA,
396         .device = 0x8324,
397 };