blob: 18d4471545f2506b5487cd85bcce86e07a03d346 [file] [log] [blame]
Zheng Baod0985752011-01-20 04:45:48 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2010 Advanced Micro Devices, Inc.
Timothy Pearson1eaaa0e2015-08-14 15:20:42 -05005 * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
Zheng Baod0985752011-01-20 04:45:48 +00006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
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.
Zheng Baod0985752011-01-20 04:45:48 +000015 */
16
17#include <console/console.h>
18#include <device/device.h>
19#include <device/pci.h>
20#include <device/pnp.h>
21#include <device/pci_ids.h>
22#include <device/pci_ops.h>
23#include <pc80/mc146818rtc.h>
24#include <pc80/isa-dma.h>
Zheng Baod0985752011-01-20 04:45:48 +000025#include <arch/io.h>
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +020026#include <arch/acpi.h>
Zheng Baod0985752011-01-20 04:45:48 +000027#include "sb800.h"
28
29static void lpc_init(device_t dev)
30{
31 u8 byte;
32 u32 dword;
33 device_t sm_dev;
34
35 /* Enable the LPC Controller */
36 sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
37 dword = pci_read_config32(sm_dev, 0x64);
38 dword |= 1 << 20;
39 pci_write_config32(sm_dev, 0x64, dword);
40
41 /* Initialize isa dma */
42 isa_dma_init();
43
44 /* Enable DMA transaction on the LPC bus */
45 byte = pci_read_config8(dev, 0x40);
46 byte |= (1 << 2);
47 pci_write_config8(dev, 0x40, byte);
48
49 /* Disable the timeout mechanism on LPC */
50 byte = pci_read_config8(dev, 0x48);
51 byte &= ~(1 << 7);
52 pci_write_config8(dev, 0x48, byte);
53
54 /* Disable LPC MSI Capability */
55 byte = pci_read_config8(dev, 0x78);
56 byte &= ~(1 << 1);
57 byte &= ~(1 << 0); /* Keep the old way. i.e., when bus master/DMA cycle is going
58 on on LPC, it holds PCI grant, so no LPC slave cycle can
59 interrupt and visit LPC. */
60 pci_write_config8(dev, 0x78, byte);
61
62 /* bit0: Enable prefetch a cacheline (64 bytes) when Host reads code from SPI rom */
63 /* bit3: Fix SPI_CS# timing issue when running at 66M. TODO:A12. */
64 byte = pci_read_config8(dev, 0xBB);
65 byte |= 1 << 0 | 1 << 3;
66 pci_write_config8(dev, 0xBB, byte);
zbao366f0fc2012-08-03 16:58:53 +080067
Gabe Black03abaee212014-04-30 21:31:44 -070068 cmos_check_update_date();
Zheng Baod0985752011-01-20 04:45:48 +000069}
70
71static void sb800_lpc_read_resources(device_t dev)
72{
73 struct resource *res;
74
75 /* Get the normal pci resources of this device */
76 pci_dev_read_resources(dev); /* We got one for APIC, or one more for TRAP */
77
78 pci_get_resource(dev, 0xA0); /* SPI ROM base address */
79
80 /* Add an extra subtractive resource for both memory and I/O. */
81 res = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
82 res->base = 0;
83 res->size = 0x1000;
84 res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
85 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
86
87 res = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
88 res->base = 0xff800000;
89 res->size = 0x00800000; /* 8 MB for flash */
90 res->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
91 IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
92
Patrick Georgi2c2e78d2012-02-16 18:54:37 +010093 //res = new_resource(dev, 3);
94 //res->base = IO_APIC_ADDR;
Zheng Baod0985752011-01-20 04:45:48 +000095 //res->size = 0x00001000;
96 //res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
97
98 compact_resources(dev);
99}
100
101static void sb800_lpc_set_resources(struct device *dev)
102{
103 struct resource *res;
104
105 pci_dev_set_resources(dev);
106
Martin Rothdcf253c2014-12-16 20:51:31 -0700107 /* Special case. SPI Base Address. The SpiRomEnable should be set. */
Zheng Baod0985752011-01-20 04:45:48 +0000108 res = find_resource(dev, 0xA0);
109 pci_write_config32(dev, 0xA0, res->base | 1 << 1);
110
111}
112
113/**
114 * @brief Enable resources for children devices
115 *
Martin Rothdcf253c2014-12-16 20:51:31 -0700116 * @param dev the device whose children's resources are to be enabled
Zheng Baod0985752011-01-20 04:45:48 +0000117 *
118 */
119static void sb800_lpc_enable_childrens_resources(device_t dev)
120{
121 struct bus *link;
122 u32 reg, reg_x;
123 int var_num = 0;
Rudolf Marek74ad66c2011-02-12 16:24:48 +0000124 u16 reg_var[3] = {0x0, 0x0, 0x0};
125 u8 wiosize = pci_read_config8(dev, 0x74);
Zheng Baod0985752011-01-20 04:45:48 +0000126
127 reg = pci_read_config32(dev, 0x44);
128 reg_x = pci_read_config32(dev, 0x48);
129
130 for (link = dev->link_list; link; link = link->next) {
131 device_t child;
132 for (child = link->children; child;
133 child = child->sibling) {
134 if (child->enabled
135 && (child->path.type == DEVICE_PATH_PNP)) {
136 struct resource *res;
137 for (res = child->resource_list; res; res = res->next) {
138 u32 base, end; /* don't need long long */
139 if (!(res->flags & IORESOURCE_IO))
140 continue;
141 base = res->base;
142 end = resource_end(res);
143 printk(BIOS_DEBUG, "sb800 lpc decode:%s, base=0x%08x, end=0x%08x\n",
144 dev_path(child), base, end);
145 switch (base) {
146 case 0x60: /* KB */
147 case 0x64: /* MS */
148 reg |= (1 << 29);
149 break;
150 case 0x3f8: /* COM1 */
151 reg |= (1 << 6);
152 break;
153 case 0x2f8: /* COM2 */
154 reg |= (1 << 7);
155 break;
Rudolf Marek74ad66c2011-02-12 16:24:48 +0000156 case 0x378: /* Parallel 1 */
Zheng Baod0985752011-01-20 04:45:48 +0000157 reg |= (1 << 0);
Rudolf Marek74ad66c2011-02-12 16:24:48 +0000158 reg |= (1 << 1); /* + 0x778 for ECP */
Zheng Baod0985752011-01-20 04:45:48 +0000159 break;
160 case 0x3f0: /* FD0 */
161 reg |= (1 << 26);
162 break;
Rudolf Marek74ad66c2011-02-12 16:24:48 +0000163 case 0x220: /* Audio 0 */
Zheng Baod0985752011-01-20 04:45:48 +0000164 reg |= (1 << 8);
165 break;
166 case 0x300: /* Midi 0 */
167 reg |= (1 << 18);
168 break;
169 case 0x400:
170 reg_x |= (1 << 16);
171 break;
172 case 0x480:
173 reg_x |= (1 << 17);
174 break;
175 case 0x500:
176 reg_x |= (1 << 18);
177 break;
178 case 0x580:
179 reg_x |= (1 << 19);
180 break;
181 case 0x4700:
182 reg_x |= (1 << 22);
183 break;
184 case 0xfd60:
185 reg_x |= (1 << 23);
186 break;
187 default:
188 if (var_num >= 3)
189 continue; /* only 3 var ; compact them ? */
190 switch (var_num) {
191 case 0:
192 reg_x |= (1 << 2);
Rudolf Marek74ad66c2011-02-12 16:24:48 +0000193 if ((end - base) < 16)
194 wiosize |= (1 << 0);
Zheng Baod0985752011-01-20 04:45:48 +0000195 break;
196 case 1:
197 reg_x |= (1 << 24);
Rudolf Marek74ad66c2011-02-12 16:24:48 +0000198 if ((end - base) < 16)
199 wiosize |= (1 << 2);
Zheng Baod0985752011-01-20 04:45:48 +0000200 break;
201 case 2:
202 reg_x |= (1 << 25);
Rudolf Marek74ad66c2011-02-12 16:24:48 +0000203 reg_x |= (1 << 24);
204 if ((end - base) < 16)
205 wiosize |= (1 << 3);
Zheng Baod0985752011-01-20 04:45:48 +0000206 break;
207 }
208 reg_var[var_num++] =
209 base & 0xffff;
210 }
211 }
212 }
213 }
214 }
215 pci_write_config32(dev, 0x44, reg);
216 pci_write_config32(dev, 0x48, reg_x);
217 /* Set WideIO for as many IOs found (fall through is on purpose) */
218 switch (var_num) {
219 case 2:
220 pci_write_config16(dev, 0x90, reg_var[2]);
221 case 1:
222 pci_write_config16(dev, 0x66, reg_var[1]);
223 case 0:
224 pci_write_config16(dev, 0x64, reg_var[0]);
225 break;
226 }
Rudolf Marek74ad66c2011-02-12 16:24:48 +0000227 pci_write_config8(dev, 0x74, wiosize);
Zheng Baod0985752011-01-20 04:45:48 +0000228}
229
230static void sb800_lpc_enable_resources(device_t dev)
231{
232 pci_dev_enable_resources(dev);
233 sb800_lpc_enable_childrens_resources(dev);
234}
235
236static struct pci_operations lops_pci = {
237 .set_subsystem = pci_dev_set_subsystem,
238};
239
240static struct device_operations lpc_ops = {
241 .read_resources = sb800_lpc_read_resources,
242 .set_resources = sb800_lpc_set_resources,
243 .enable_resources = sb800_lpc_enable_resources,
Vladimir Serbinenko83f81ca2014-11-09 13:30:50 +0100244#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
Vladimir Serbinenko2a19fb12014-10-02 20:09:19 +0200245 .write_acpi_tables = acpi_write_hpet,
246#endif
Zheng Baod0985752011-01-20 04:45:48 +0000247 .init = lpc_init,
Kyösti Mälkkid0e212c2015-02-26 20:47:47 +0200248 .scan_bus = scan_lpc_bus,
Zheng Baod0985752011-01-20 04:45:48 +0000249 .ops_pci = &lops_pci,
250};
251static const struct pci_driver lpc_driver __pci_driver = {
252 .ops = &lpc_ops,
253 .vendor = PCI_VENDOR_ID_ATI,
254 .device = PCI_DEVICE_ID_ATI_SB800_LPC,
255};