blob: d16e3cc5098ea1cdb45fcd66b7d71ee2035e0991 [file] [log] [blame]
Yinghai Luc65bd562007-02-01 00:10:05 +00001/*
Stefan Reinauer7e61e452008-01-18 10:35:56 +00002 * This file is part of the coreboot project.
Yinghai Luc65bd562007-02-01 00:10:05 +00003 *
4 * Copyright (C) 2003 Linux Networx
5 * Copyright (C) 2003 SuSE Linux AG
6 * Copyright (C) 2004 Tyan Computer
7 * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer.
8 * Copyright (C) 2006,2007 AMD
9 * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26#include <console/console.h>
27#include <device/device.h>
28#include <device/pci.h>
29#include <device/pnp.h>
30#include <device/pci_ids.h>
31#include <device/pci_ops.h>
32#include <pc80/mc146818rtc.h>
33#include <pc80/isa-dma.h>
34#include <bitops.h>
35#include <arch/io.h>
Stefan Reinauer0401bd82010-01-16 18:31:34 +000036#include <arch/ioapic.h>
Yinghai Luc65bd562007-02-01 00:10:05 +000037#include <cpu/x86/lapic.h>
Carl-Daniel Hailfinger2ee67792008-10-01 12:52:52 +000038#include <stdlib.h>
Yinghai Luc65bd562007-02-01 00:10:05 +000039#include "mcp55.h"
40
41#define NMI_OFF 0
42
Yinghai Luc65bd562007-02-01 00:10:05 +000043// 0x7a or e3
44#define PREVIOUS_POWER_STATE 0x7A
45
46#define MAINBOARD_POWER_OFF 0
47#define MAINBOARD_POWER_ON 1
Yinghai Luf327d9f2008-02-20 17:41:38 +000048#define SLOW_CPU_OFF 0
49#define SLOW_CPU__ON 1
Yinghai Luc65bd562007-02-01 00:10:05 +000050
Stefan Reinauer08670622009-06-30 15:17:49 +000051#ifndef CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL
52#define CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON
Yinghai Luc65bd562007-02-01 00:10:05 +000053#endif
54
Yinghai Luf327d9f2008-02-20 17:41:38 +000055static void lpc_common_init(device_t dev, int master)
Yinghai Luc65bd562007-02-01 00:10:05 +000056{
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000057 u8 byte;
58 u32 ioapic_base;
Yinghai Luc65bd562007-02-01 00:10:05 +000059
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000060 /* IOAPIC initialization. */
Yinghai Luc65bd562007-02-01 00:10:05 +000061 byte = pci_read_config8(dev, 0x74);
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000062 byte |= (1 << 0); /* Enable IOAPIC. */
Yinghai Luc65bd562007-02-01 00:10:05 +000063 pci_write_config8(dev, 0x74, byte);
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000064 ioapic_base = pci_read_config32(dev, PCI_BASE_ADDRESS_1); /* 0x14 */
Yinghai Luc65bd562007-02-01 00:10:05 +000065
Stefan Reinauer0401bd82010-01-16 18:31:34 +000066 if (master)
67 setup_ioapic(ioapic_base, 0);
Stefan Reinauer14e22772010-04-27 06:56:47 +000068 else
Stefan Reinauer0401bd82010-01-16 18:31:34 +000069 clear_ioapic(ioapic_base);
Yinghai Luc65bd562007-02-01 00:10:05 +000070}
71
72static void lpc_slave_init(device_t dev)
73{
Yinghai Luf327d9f2008-02-20 17:41:38 +000074 lpc_common_init(dev, 0);
Yinghai Luc65bd562007-02-01 00:10:05 +000075}
76
Yinghai Luc65bd562007-02-01 00:10:05 +000077static void enable_hpet(struct device *dev)
78{
79 unsigned long hpet_address;
80
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000081 pci_write_config32(dev, 0x44, 0xfed00001);
82 hpet_address=pci_read_config32(dev, 0x44) & 0xfffffffe;
Myles Watson08e0fb82010-03-22 16:33:25 +000083 printk(BIOS_DEBUG, "enabling HPET @0x%lx\n", hpet_address);
Yinghai Luc65bd562007-02-01 00:10:05 +000084}
Yinghai Luc65bd562007-02-01 00:10:05 +000085
86static void lpc_init(device_t dev)
87{
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000088 u8 byte, byte_old;
89 int on, nmi_option;
Yinghai Luc65bd562007-02-01 00:10:05 +000090
Yinghai Luf327d9f2008-02-20 17:41:38 +000091 lpc_common_init(dev, 1);
Yinghai Luc65bd562007-02-01 00:10:05 +000092
93#if 0
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000094 /* Posted memory write enable. */
Yinghai Luc65bd562007-02-01 00:10:05 +000095 byte = pci_read_config8(dev, 0x46);
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +000096 pci_write_config8(dev, 0x46, byte | (1 << 0));
Yinghai Luc65bd562007-02-01 00:10:05 +000097#endif
98 /* power after power fail */
99
100#if 1
Stefan Reinauer08670622009-06-30 15:17:49 +0000101 on = CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
Luc Verhaegena9c5ea02009-06-03 14:19:33 +0000102 get_option(&on, "power_on_after_fail");
Yinghai Luc65bd562007-02-01 00:10:05 +0000103 byte = pci_read_config8(dev, PREVIOUS_POWER_STATE);
104 byte &= ~0x40;
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000105 if (!on)
Yinghai Luc65bd562007-02-01 00:10:05 +0000106 byte |= 0x40;
Yinghai Luc65bd562007-02-01 00:10:05 +0000107 pci_write_config8(dev, PREVIOUS_POWER_STATE, byte);
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000108 printk(BIOS_INFO, "set power %s after power fail\n", on ? "on" : "off");
Yinghai Luc65bd562007-02-01 00:10:05 +0000109#endif
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000110 /* Throttle the CPU speed down for testing. */
Yinghai Luc65bd562007-02-01 00:10:05 +0000111 on = SLOW_CPU_OFF;
Luc Verhaegena9c5ea02009-06-03 14:19:33 +0000112 get_option(&on, "slow_cpu");
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000113 if (on) {
114 u16 pm10_bar;
115 u32 dword;
116 pm10_bar = (pci_read_config16(dev, 0x60) & 0xff00);
117 outl(((on << 1) + 0x10), (pm10_bar + 0x10));
Yinghai Luc65bd562007-02-01 00:10:05 +0000118 dword = inl(pm10_bar + 0x10);
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000119 on = 8 - on;
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000120 printk(BIOS_DEBUG, "Throttling CPU %2d.%1.1d percent.\n",
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000121 (on * 12) + (on >> 1), (on & 1) * 5);
Yinghai Luc65bd562007-02-01 00:10:05 +0000122 }
123
124#if 0
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000125 /* Enable Port 92 fast reset (default is enabled). */
Yinghai Luc65bd562007-02-01 00:10:05 +0000126 byte = pci_read_config8(dev, 0xe8);
127 byte |= ~(1 << 3);
128 pci_write_config8(dev, 0xe8, byte);
129#endif
130
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000131 /* Enable error reporting. */
132 /* Set up sync flood detected. */
Yinghai Luc65bd562007-02-01 00:10:05 +0000133 byte = pci_read_config8(dev, 0x47);
134 byte |= (1 << 1);
135 pci_write_config8(dev, 0x47, byte);
136
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000137 /* Set up NMI on errors. */
138 byte = inb(0x70); /* RTC70 */
Yinghai Luc65bd562007-02-01 00:10:05 +0000139 byte_old = byte;
140 nmi_option = NMI_OFF;
Luc Verhaegena9c5ea02009-06-03 14:19:33 +0000141 get_option(&nmi_option, "nmi");
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000142 if (nmi_option)
143 byte &= ~(1 << 7); /* Set NMI. */
144 else
145 byte |= ( 1 << 7); /* Can't mask NMI from PCI-E and NMI_NOW. */
146 if (byte != byte_old)
Ed Swierke42e1422009-07-10 15:05:35 +0000147 outb(byte, 0x70);
Yinghai Luc65bd562007-02-01 00:10:05 +0000148
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000149 /* Initialize the real time clock. */
Yinghai Luc65bd562007-02-01 00:10:05 +0000150 rtc_init(0);
151
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000152 /* Initialize ISA DMA. */
Yinghai Luc65bd562007-02-01 00:10:05 +0000153 isa_dma_init();
154
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000155 /* Initialize the High Precision Event Timers (HPET). */
Harald Gutmann62cfe162009-06-19 12:03:40 +0000156 enable_hpet(dev);
Yinghai Luc65bd562007-02-01 00:10:05 +0000157}
158
159static void mcp55_lpc_read_resources(device_t dev)
160{
161 struct resource *res;
Yinghai Luc65bd562007-02-01 00:10:05 +0000162
Myles Watson29cc9ed2009-07-02 18:56:24 +0000163 /* Get the normal PCI resources of this device. */
164 /* We got one for APIC, or one more for TRAP. */
165 pci_dev_read_resources(dev);
Yinghai Luc65bd562007-02-01 00:10:05 +0000166
Myles Watson29cc9ed2009-07-02 18:56:24 +0000167 /* Add an extra subtractive resource for both memory and I/O. */
Yinghai Luc65bd562007-02-01 00:10:05 +0000168 res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
Myles Watson29cc9ed2009-07-02 18:56:24 +0000169 res->base = 0;
170 res->size = 0x1000;
171 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
172 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Yinghai Luc65bd562007-02-01 00:10:05 +0000173
174 res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
Myles Watson29cc9ed2009-07-02 18:56:24 +0000175 res->base = 0xff800000;
176 res->size = 0x00800000; /* 8 MB for flash */
177 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
178 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Yinghai Luc65bd562007-02-01 00:10:05 +0000179
Myles Watson29cc9ed2009-07-02 18:56:24 +0000180 res = new_resource(dev, 3); /* IOAPIC */
Uwe Hermann74d1a6e2010-10-12 17:34:08 +0000181 res->base = IO_APIC_ADDR;
Myles Watson29cc9ed2009-07-02 18:56:24 +0000182 res->size = 0x00001000;
183 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
Yinghai Luc65bd562007-02-01 00:10:05 +0000184}
185
186/**
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000187 * Enable resources for children devices.
Yinghai Luc65bd562007-02-01 00:10:05 +0000188 *
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000189 * @param dev The device whose children's resources are to be enabled.
Yinghai Luc65bd562007-02-01 00:10:05 +0000190 */
191static void mcp55_lpc_enable_childrens_resources(device_t dev)
192{
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000193 u32 reg, reg_var[4];
194 int i, var_num = 0;
Myles Watson894a3472010-06-09 22:41:35 +0000195 struct bus *link;
Yinghai Luc65bd562007-02-01 00:10:05 +0000196
197 reg = pci_read_config32(dev, 0xa0);
198
Myles Watson894a3472010-06-09 22:41:35 +0000199 for (link = dev->link_list; link; link = link->next) {
Yinghai Luc65bd562007-02-01 00:10:05 +0000200 device_t child;
Myles Watson894a3472010-06-09 22:41:35 +0000201 for (child = link->children; child; child = child->sibling) {
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000202 if (child->enabled && (child->path.type == DEVICE_PATH_PNP)) {
Myles Watsonc25cc112010-05-21 14:33:48 +0000203 struct resource *res;
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000204 for (res = child->resource_list; res; res = res->next) {
205 unsigned long base, end; /* Don't need long long. */
206 if (!(res->flags & IORESOURCE_IO))
207 continue;
Yinghai Luc65bd562007-02-01 00:10:05 +0000208 base = res->base;
209 end = resource_end(res);
Myles Watson08e0fb82010-03-22 16:33:25 +0000210 printk(BIOS_DEBUG, "mcp55 lpc decode:%s, base=0x%08lx, end=0x%08lx\n",dev_path(child),base, end);
Yinghai Luc65bd562007-02-01 00:10:05 +0000211 switch(base) {
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000212 case 0x3f8: /* COM1 */
213 reg |= (1 << 0);
214 break;
215 case 0x2f8: /* COM2 */
216 reg |= (1 << 1);
217 break;
218 case 0x378: /* Parallel 1 */
219 reg |= (1 << 24);
220 break;
221 case 0x3f0: /* FD0 */
222 reg |= (1 << 20);
223 break;
224 case 0x220: /* Audio 0 */
225 reg |= (1 << 8);
226 break;
227 case 0x300: /* Midi 0 */
228 reg |= (1 << 12);
229 break;
Yinghai Luc65bd562007-02-01 00:10:05 +0000230 }
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000231 if ((base == 0x290)
232 || (base >= 0x400)) {
233 /* Only 4 var; compact them? */
234 if (var_num >= 4)
235 continue;
236 reg |= (1 << (28 + var_num));
237 reg_var[var_num++] = (base & 0xffff) | ((end & 0xffff) << 16);
Yinghai Luc65bd562007-02-01 00:10:05 +0000238 }
239 }
240 }
241 }
242 }
243 pci_write_config32(dev, 0xa0, reg);
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000244 for (i = 0; i < var_num; i++)
245 pci_write_config32(dev, 0xa8 + i * 4, reg_var[i]);
Yinghai Luc65bd562007-02-01 00:10:05 +0000246}
247
248static void mcp55_lpc_enable_resources(device_t dev)
249{
250 pci_dev_enable_resources(dev);
251 mcp55_lpc_enable_childrens_resources(dev);
252}
253
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000254static struct device_operations lpc_ops = {
255 .read_resources = mcp55_lpc_read_resources,
256 .set_resources = pci_dev_set_resources,
257 .enable_resources = mcp55_lpc_enable_resources,
258 .init = lpc_init,
259 .scan_bus = scan_static_bus,
260// .enable = mcp55_enable,
261 .ops_pci = &mcp55_pci_ops,
Yinghai Luc65bd562007-02-01 00:10:05 +0000262};
Patrick Georgiefff7332012-07-26 19:48:23 +0200263static const unsigned short lpc_ids[] = {
264 PCI_DEVICE_ID_NVIDIA_MCP55_LPC,
265 PCI_DEVICE_ID_NVIDIA_MCP55_PRO,
266 PCI_DEVICE_ID_NVIDIA_MCP55_LPC_2,
267 PCI_DEVICE_ID_NVIDIA_MCP55_LPC_3,
268 PCI_DEVICE_ID_NVIDIA_MCP55_LPC_4,
269 PCI_DEVICE_ID_NVIDIA_MCP55_LPC_5,
270 PCI_DEVICE_ID_NVIDIA_MCP55_LPC_6,
271 0
272};
Stefan Reinauerf1cf1f72007-10-24 09:08:58 +0000273static const struct pci_driver lpc_driver __pci_driver = {
Yinghai Luc65bd562007-02-01 00:10:05 +0000274 .ops = &lpc_ops,
275 .vendor = PCI_VENDOR_ID_NVIDIA,
Patrick Georgiefff7332012-07-26 19:48:23 +0200276 .devices = lpc_ids,
Yinghai Luc65bd562007-02-01 00:10:05 +0000277};
278
Uwe Hermannc7f0c8f2011-01-04 19:51:33 +0000279static struct device_operations lpc_slave_ops = {
280 .read_resources = mcp55_lpc_read_resources,
281 .set_resources = pci_dev_set_resources,
282 .enable_resources = pci_dev_enable_resources,
283 .init = lpc_slave_init,
284// .enable = mcp55_enable,
285 .ops_pci = &mcp55_pci_ops,
Yinghai Luc65bd562007-02-01 00:10:05 +0000286};
287
Stefan Reinauerf1cf1f72007-10-24 09:08:58 +0000288static const struct pci_driver lpc_driver_slave __pci_driver = {
Yinghai Luc65bd562007-02-01 00:10:05 +0000289 .ops = &lpc_slave_ops,
290 .vendor = PCI_VENDOR_ID_NVIDIA,
291 .device = PCI_DEVICE_ID_NVIDIA_MCP55_SLAVE,
292};