blob: 3870de866fb536f693e392f17e343c63520907aa [file] [log] [blame]
Richard Smithcb8eab42006-07-24 04:25:47 +00001#include <console/console.h>
2#include <arch/io.h>
3#include <stdint.h>
4#include <device/device.h>
5#include <device/pci.h>
6#include <device/pci_ids.h>
7#include <stdlib.h>
8#include <string.h>
9#include <bitops.h>
10#include "chip.h"
11#include "northbridge.h"
Uwe Hermann1a9c8922007-04-01 17:24:03 +000012#include "i440bx.h"
Richard Smithcb8eab42006-07-24 04:25:47 +000013
Richard Smithcb8eab42006-07-24 04:25:47 +000014static void northbridge_init(device_t dev)
15{
16 printk_spew("Northbridge Init\n");
17}
18
Richard Smithcb8eab42006-07-24 04:25:47 +000019static struct device_operations northbridge_operations = {
20 .read_resources = pci_dev_read_resources,
21 .set_resources = pci_dev_set_resources,
22 .enable_resources = pci_dev_enable_resources,
23 .init = northbridge_init,
24 .enable = 0,
25 .ops_pci = 0,
26};
27
28static struct pci_driver northbridge_driver __pci_driver = {
29 .ops = &northbridge_operations,
30 .vendor = PCI_VENDOR_ID_INTEL,
31 .device = 0x7190,
32};
33
34
Richard Smithcb8eab42006-07-24 04:25:47 +000035#define BRIDGE_IO_MASK (IORESOURCE_IO | IORESOURCE_MEM)
36
37static void pci_domain_read_resources(device_t dev)
38{
39 struct resource *resource;
Uwe Hermann1a9c8922007-04-01 17:24:03 +000040 unsigned reg;
Richard Smithcb8eab42006-07-24 04:25:47 +000041
42 /* Initialize the system wide io space constraints */
Uwe Hermann1a9c8922007-04-01 17:24:03 +000043 resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
Richard Smithcb8eab42006-07-24 04:25:47 +000044 resource->limit = 0xffffUL;
45 resource->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
46
47 /* Initialize the system wide memory resources constraints */
Uwe Hermann1a9c8922007-04-01 17:24:03 +000048 resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
Richard Smithcb8eab42006-07-24 04:25:47 +000049 resource->limit = 0xffffffffULL;
50 resource->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
51}
52
53static void ram_resource(device_t dev, unsigned long index,
54 unsigned long basek, unsigned long sizek)
55{
56 struct resource *resource;
57
58 if (!sizek) {
59 return;
60 }
61 resource = new_resource(dev, index);
62 resource->base = ((resource_t)basek) << 10;
63 resource->size = ((resource_t)sizek) << 10;
64 resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE | \
65 IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
66}
67
68static void tolm_test(void *gp, struct device *dev, struct resource *new)
69{
70 struct resource **best_p = gp;
71 struct resource *best;
72 best = *best_p;
73 if (!best || (best->base > new->base)) {
74 best = new;
75 }
76 *best_p = best;
77}
78
79static uint32_t find_pci_tolm(struct bus *bus)
80{
81 struct resource *min;
82 uint32_t tolm;
83 min = 0;
84 search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min);
85 tolm = 0xffffffffUL;
86 if (min && tolm > min->base) {
87 tolm = min->base;
88 }
89 return tolm;
90}
91
92static void pci_domain_set_resources(device_t dev)
93{
Richard Smithcb8eab42006-07-24 04:25:47 +000094 device_t mc_dev;
95 uint32_t pci_tolm;
96
97 pci_tolm = find_pci_tolm(&dev->link[0]);
98 mc_dev = dev->link[0].children;
99 if (mc_dev) {
Uwe Hermann1a9c8922007-04-01 17:24:03 +0000100 /* Figure out which areas are/should be occupied by RAM.
101 * This is all computed in kilobytes and converted to/from
102 * the memory controller right at the edges.
103 * Having different variables in different units is
104 * too confusing to get right. Kilobytes are good up to
105 * 4 Terabytes of RAM...
106 */
107 uint16_t tolm_r;
Richard Smithcb8eab42006-07-24 04:25:47 +0000108 unsigned long tomk, tolmk;
Uwe Hermann1a9c8922007-04-01 17:24:03 +0000109 int idx;
Richard Smithcb8eab42006-07-24 04:25:47 +0000110
Uwe Hermann1a9c8922007-04-01 17:24:03 +0000111 /* Get the value of the highest DRB. This tells the end of
112 * the physical memory. The units are ticks of 8MB
113 * i.e. 1 means 8MB.
114 */
Ceri Coburne1dd5e92007-05-10 22:46:17 +0000115 tomk = ((unsigned long)pci_read_config8(mc_dev, DRB7)) << 13;
116 printk_debug("Setting RAM size to %d MB\n", tomk >> 10);
Richard Smithcb8eab42006-07-24 04:25:47 +0000117 /* Compute the top of Low memory */
118 tolmk = pci_tolm >> 10;
119 if (tolmk >= tomk) {
120 /* The PCI hole does does not overlap the memory.
121 */
122 tolmk = tomk;
123 }
Uwe Hermann1a9c8922007-04-01 17:24:03 +0000124 /* Write the ram configuration registers,
125 * preserving the reserved bits.
126 */
127 tolm_r = pci_read_config16(mc_dev, 0xc4);
128 tolm_r = ((tolmk >> 10) << 3) | (tolm_r & 0xf);
129 pci_write_config16(mc_dev, 0xc4, tolm_r);
130
Richard Smithcb8eab42006-07-24 04:25:47 +0000131 /* Report the memory regions */
132 idx = 10;
Uwe Hermann1a9c8922007-04-01 17:24:03 +0000133 ram_resource(dev, idx++, 0, 640);
134 ram_resource(dev, idx++, 768, tolmk - 768);
Richard Smithcb8eab42006-07-24 04:25:47 +0000135 }
136 assign_resources(&dev->link[0]);
137}
138
139static unsigned int pci_domain_scan_bus(device_t dev, unsigned int max)
140{
141 max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0, 0), 0xff, max);
142 return max;
143}
144
145static struct device_operations pci_domain_ops = {
146 .read_resources = pci_domain_read_resources,
147 .set_resources = pci_domain_set_resources,
148 .enable_resources = enable_childrens_resources,
149 .init = 0,
150 .scan_bus = pci_domain_scan_bus,
151};
152
153static void cpu_bus_init(device_t dev)
154{
155 initialize_cpus(&dev->link[0]);
156}
157
158static void cpu_bus_noop(device_t dev)
159{
160}
161
162static struct device_operations cpu_bus_ops = {
163 .read_resources = cpu_bus_noop,
164 .set_resources = cpu_bus_noop,
165 .enable_resources = cpu_bus_noop,
166 .init = cpu_bus_init,
167 .scan_bus = 0,
168};
169
170static void enable_dev(struct device *dev)
171{
Uwe Hermann1a9c8922007-04-01 17:24:03 +0000172 struct device_path path;
173
Richard Smithcb8eab42006-07-24 04:25:47 +0000174 /* Set the operations if it is a special bus type */
175 if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) {
176 dev->ops = &pci_domain_ops;
177 pci_set_method(dev);
178 }
179 else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) {
180 dev->ops = &cpu_bus_ops;
181 }
182}
183
184struct chip_operations northbridge_intel_i440bx_ops = {
Uwe Hermanna7aa29b2006-11-05 18:50:49 +0000185 CHIP_NAME("Intel 440BX Northbridge")
Uwe Hermann1a9c8922007-04-01 17:24:03 +0000186 .enable_dev = enable_dev,
Richard Smithcb8eab42006-07-24 04:25:47 +0000187};