blob: 4f3d704a8ce64cc69c31040e95501483a5646311 [file] [log] [blame]
Alexandru Gagniuc23211b02013-06-09 16:06:07 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2012-2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
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.
Alexandru Gagniuc23211b02013-06-09 16:06:07 -050015 */
16
17#include <arch/io.h>
18#include <arch/pirq_routing.h>
19#include <console/console.h>
20#include <device/pci.h>
21#include <device/pci_ids.h>
22#include <pc80/i8259.h>
23#include <pc80/mc146818rtc.h>
24#include <drivers/generic/ioapic/chip.h>
25
26#include "vx900.h"
27#include "chip.h"
28
29/**
Martin Roth543888d2015-01-06 10:20:42 -070030 * @file vx900/lpc.c
Alexandru Gagniuc23211b02013-06-09 16:06:07 -050031 *
32 * STATUS:
33 * We do a fair bit of setup, and most of it seems to work fairly well. There
34 * are still a few FIXME items here and there, but overall, this code hasn't
35 * been touched much from its initial 2012 version to 2013, when it was revived.
36 *
37 * We do the IOAPIC setup with the assumption that it is declared in the
38 * mainboard's devicetree.cb. We cannot use the IOAPIC however. The interrupts
39 * do not make it to the CPU. This issue is still under investigation.
40 *
41 * We also route PIRQs with CONFIG_PIRQ_ROUTE. This is currently the only way to
42 * get interrupts working.
43 *
44 * On the VX900, the keyboard can be connected directly to the chipset
45 * (referenced as "internal keyboard" in the documents). As long as that is the
46 * case (not connected to the superIO), and we disable the superIO keyboard LDN,
47 * it will work, but perhaps this should be more configurable.
48 */
49
50static void vx900_lpc_misc_stuff(device_t dev)
51{
52 char extint;
53 u8 val;
54 struct northbridge_via_vx900_config *nb = (void *)dev->chip_info;
55
56 /* GPIO 11,10 to SATALED [1,0] */
57 pci_mod_config8(dev, 0xe4, 0, 1 << 0);
58
59 /* Route the external interrupt line */
60 extint = nb->ext_int_route_to_pirq;
61 if (extint < 'A' || extint > 'H') {
62 printk(BIOS_WARNING, "Invalid PIRQ%c for external interrupt\n",
63 extint);
64 } else {
65 printk(BIOS_INFO, "Routing external interrupt to PIRQ%c\n",
66 extint);
67 val = extint - 'A';
68 val |= (1 << 3); /* bit3 enables the external int */
69 pci_mod_config8(dev, 0x55, 0xf, val);
70
71 }
72}
73
74static void vx900_lpc_dma_setup(device_t dev)
75{
76 /* These are the steps recommended by VIA in order to get DMA running */
77
78 /* Enable Positive South Module PCI Cycle Decoding */
79 /* FIXME: Setting this seems to hang our system */
80 //pci_mod_config8(dev, 0x58, 0, 1<<4);
81 /* Positive decoding for ROM + APIC + On-board IO ports */
82 pci_mod_config8(dev, 0x6c, 0, (1 << 2) | (1 << 3) | (1 << 7));
83 /* Enable DMA channels. BIOS guide recommends DMA channel 2 off */
84 pci_write_config8(dev, 0x53, 0xfb);
85 /* Disable PCI/DMA Memory Cycles Output to PCI Bus */
86 pci_mod_config8(dev, 0x5b, (1 << 5), 0);
87 /* DMA bandwidth control - Improved bandwidth */
88 pci_write_config8(dev, 0x53, 0xff);
89 /* ISA Positive Decoding control */
90 pci_write_config8(dev, 0x6d, 0xdf);
91 pci_write_config8(dev, 0x6e, 0x98);
92 pci_write_config8(dev, 0x6f, 0x30);
93}
94
95/**
96 *\brief VX900: Set up the south module IOAPIC (for the ISA/LPC bus)
97 *
98 * Enable the IOAPIC in the south module, and properly set it up.
99 * \n
100 * This is the hardware specific initialization for the IOAPIC, and complements
101 * the setup done by the generic IOAPIC driver. In order for the IOAPIC to work
102 * properly, it _must_ be declared in devicetree.cb .
103 * \n
104 * We are assuming this is called before the drivers/generic/ioapic code,
105 * which should be the case if devicetree.cb is set up properly.
106 */
107static void vx900_lpc_ioapic_setup(device_t dev)
108{
109 /* Find the IOAPIC, and make sure it's set up correctly in devicetree.cb
110 * If it's not, then the generic ioapic driver will not set it up
111 * correctly, and the MP table will not be correctly generated */
112 device_t ioapic;
113 for (ioapic = dev->next; ioapic; ioapic = ioapic->next) {
114 if (ioapic->path.type == DEVICE_PATH_IOAPIC)
115 break;
116 }
117
118 /* You did put an IOAPIC in devicetree.cb, didn't you? */
119 if (ioapic == 0) {
120 /* We don't have enough info to set up the IOAPIC */
121 printk(BIOS_ERR, "ERROR: South module IOAPIC not found. "
122 "Check your devicetree.cb\n");
123 return;
124 }
125
126 /* Found an IOAPIC, now we need to make sure it's the right one */
127 ioapic_config_t *config = (ioapic_config_t *) ioapic->chip_info;
128 if (!config->have_isa_interrupts) {
129 /* Umh, is this the right IOAPIC ? */
130 printk(BIOS_ERR, "ERROR: South module IOAPIC not carrying ISA "
131 "interrupts. Check your devicetree.cb\n");
132 printk(BIOS_ERR, "Will not initialize this IOAPIC.\n");
133 return;
134 }
135
136 /* The base address of this IOAPIC _must_ be at 0xfec00000.
137 * Don't move this value to a #define, as people might think it's
138 * configurable. It is not. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800139 const void *base = config->base;
140 if (base != (void *)0xfec00000) {
Alexandru Gagniuc23211b02013-06-09 16:06:07 -0500141 printk(BIOS_ERR, "ERROR: South module IOAPIC base should be at "
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800142 "0xfec00000\n but we found it at %p\n", base);
Alexandru Gagniuc23211b02013-06-09 16:06:07 -0500143 return;
144 }
145
Stefan Reinauer65b72ab2015-01-05 12:59:54 -0800146 printk(BIOS_DEBUG, "VX900 LPC: Setting up the south module IOAPIC.\n");
Alexandru Gagniuc23211b02013-06-09 16:06:07 -0500147 /* Enable IOAPIC
148 * So much work for one line of code. Talk about bloat :)
149 * The 8259 PIC should still work even if the IOAPIC is enabled, so
150 * there's no crime in enabling the IOAPIC here. */
151 pci_mod_config8(dev, 0x58, 0, 1 << 6);
152}
153
154static void vx900_lpc_interrupt_stuff(device_t dev)
155{
156 /* Enable setting trigger mode through 0x4d0, and 0x4d1 ports
157 * And enable I/O recovery time */
158 pci_mod_config8(dev, 0x40, 0, (1 << 2) | (1 << 6));
159 /* Set serial IRQ frame width to 6 PCI cycles (recommended by VIA)
160 * And enable serial IRQ */
161 pci_mod_config8(dev, 0x52, 3 << 0, (1 << 3) | (1 << 0));
162
163 /* Disable IRQ12 storm FIXME: bad comment */
164 pci_mod_config8(dev, 0x51, (1 << 2), 0);
165
166 pci_write_config8(dev, 0x4c, (1 << 6));
167
168 /* FIXME: Do we really need this? SeaBIOS/linux runs fine without it.
169 * Is this something the payload/OS should do, or is it safe for us to
170 * do it? */
171 /* Get the IRQs up and running */
172 setup_i8259();
173
174 vx900_lpc_dma_setup(dev);
175
176 /* The IOAPIC is special, and we treat it separately */
177 vx900_lpc_ioapic_setup(dev);
178}
179
180static void vx900_lpc_init(device_t dev)
181{
182 vx900_lpc_interrupt_stuff(dev);
183 vx900_lpc_misc_stuff(dev);
184 dump_pci_device(dev);
185}
186
187static struct device_operations vx900_lpc_ops = {
188 .read_resources = pci_dev_read_resources,
189 .set_resources = pci_dev_set_resources,
190 .enable_resources = pci_dev_enable_resources,
191 .init = vx900_lpc_init,
Kyösti Mälkkid0e212c2015-02-26 20:47:47 +0200192 .scan_bus = scan_lpc_bus,
Alexandru Gagniuc23211b02013-06-09 16:06:07 -0500193};
194
195static const struct pci_driver lpc_driver __pci_driver = {
196 .ops = &vx900_lpc_ops,
197 .vendor = PCI_VENDOR_ID_VIA,
198 .device = PCI_DEVICE_ID_VIA_VX900_LPC,
199};
200
201#if CONFIG_PIRQ_ROUTE
202void pirq_assign_irqs(const u8 * pirq)
203{
204 device_t lpc;
205
206 lpc = dev_find_device(PCI_VENDOR_ID_VIA,
207 PCI_DEVICE_ID_VIA_VX900_LPC, 0);
208
209 /* Take care of INTA -> INTD */
210 pci_mod_config8(lpc, 0x55, (0xf << 4), pirq[0] << 4);
211 pci_write_config8(lpc, 0x56, pirq[1] | (pirq[2] << 4));
212 pci_write_config8(lpc, 0x57, pirq[3] << 4);
213
214 /* Enable INTE -> INTH to be on separate IRQs */
215 pci_mod_config8(lpc, 0x46, 0, 1 << 4);
216 /* Now do INTE -> INTH */
217 pci_write_config8(lpc, 0x44, pirq[4] | (pirq[5] << 4));
218 pci_write_config8(lpc, 0x45, pirq[6] | (pirq[7] << 4));
219}
220#endif