Factor out a few commonly duplicated functions from northbridge.c.
[coreboot.git] / src / northbridge / via / vt8601 / northbridge.c
1 #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 <device/hypertransport.h>
8 #include <cpu/cpu.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <bitops.h>
12 #include "chip.h"
13 #include "northbridge.h"
14
15 /*
16  * This fixup is based on capturing values from an Award bios.  Without
17  * this fixup the DMA write performance is awful (i.e. hdparm -t /dev/hda is 20x
18  * slower than normal, ethernet drops packets).
19  * Apparently these registers govern some sort of bus master behavior.
20  */
21 static void northbridge_init(device_t dev)
22 {
23         printk(BIOS_SPEW, "VT8601 random fixup ...\n");
24         pci_write_config8(dev, 0x70, 0xc0);
25         pci_write_config8(dev, 0x71, 0x88);
26         pci_write_config8(dev, 0x72, 0xec);
27         pci_write_config8(dev, 0x73, 0x0c);
28         pci_write_config8(dev, 0x74, 0x0e);
29         pci_write_config8(dev, 0x75, 0x81);
30         pci_write_config8(dev, 0x76, 0x52);
31 }
32
33 static struct device_operations northbridge_operations = {
34         .read_resources   = pci_dev_read_resources,
35         .set_resources    = pci_dev_set_resources,
36         .enable_resources = pci_dev_enable_resources,
37         .init             = northbridge_init,
38         .enable           = 0,
39         .ops_pci          = 0,
40 };
41
42 static const struct pci_driver northbridge_driver __pci_driver = {
43         .ops = &northbridge_operations,
44         .vendor = PCI_VENDOR_ID_VIA,
45         .device = 0x0601, /* 0x8601 is the AGP bridge? */
46 };
47
48 #if CONFIG_WRITE_HIGH_TABLES==1
49 /* maximum size of high tables in KB */
50 #define HIGH_TABLES_SIZE 64
51 extern uint64_t high_tables_base, high_tables_size;
52 #endif
53
54 static void pci_domain_set_resources(device_t dev)
55 {
56         static const uint8_t ramregs[] = {
57                 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x56, 0x57
58         };
59         device_t mc_dev;
60         uint32_t pci_tolm;
61
62         pci_tolm = find_pci_tolm(dev->link_list);
63         mc_dev = dev->link_list->children;
64         if (mc_dev) {
65                 unsigned long tomk, tolmk;
66                 unsigned char rambits;
67                 int i, idx;
68
69                 for(rambits = 0, i = 0; i < ARRAY_SIZE(ramregs); i++) {
70                         unsigned char reg;
71                         reg = pci_read_config8(mc_dev, ramregs[i]);
72                         /* these are ENDING addresses, not sizes.
73                          * if there is memory in this slot, then reg will be > rambits.
74                          * So we just take the max, that gives us total.
75                          * We take the highest one to cover for once and future coreboot
76                          * bugs. We warn about bugs.
77                          */
78                         if (reg > rambits)
79                                 rambits = reg;
80                         if (reg < rambits)
81                                 printk(BIOS_ERR, "ERROR! register 0x%x is not set!\n",
82                                         ramregs[i]);
83                 }
84                 printk(BIOS_DEBUG, "I would set ram size to 0x%x Kbytes\n", (rambits)*8*1024);
85                 tomk = rambits*8*1024;
86                 /* Compute the top of Low memory */
87                 tolmk = pci_tolm >> 10;
88                 if (tolmk >= tomk) {
89                         /* The PCI hole does does not overlap the memory.
90                          */
91                         tolmk = tomk;
92                 }
93
94 #if CONFIG_WRITE_HIGH_TABLES == 1
95                 high_tables_base = (tolmk - HIGH_TABLES_SIZE) * 1024;
96                 high_tables_size = HIGH_TABLES_SIZE* 1024;
97                 printk(BIOS_DEBUG, "tom: %lx, high_tables_base: %llx, high_tables_size: %llx\n", tomk*1024, high_tables_base, high_tables_size);
98 #endif
99
100                 /* Report the memory regions */
101                 idx = 10;
102                 ram_resource(dev, idx++, 0, tolmk);
103         }
104         assign_resources(dev->link_list);
105 }
106
107 static struct device_operations pci_domain_ops = {
108         .read_resources   = pci_domain_read_resources,
109         .set_resources    = pci_domain_set_resources,
110         .enable_resources = NULL,
111         .init             = NULL,
112         .scan_bus         = pci_domain_scan_bus,
113 };
114
115 static void cpu_bus_init(device_t dev)
116 {
117         initialize_cpus(dev->link_list);
118 }
119
120 static void cpu_bus_noop(device_t dev)
121 {
122 }
123
124 static struct device_operations cpu_bus_ops = {
125         .read_resources   = cpu_bus_noop,
126         .set_resources    = cpu_bus_noop,
127         .enable_resources = cpu_bus_noop,
128         .init             = cpu_bus_init,
129         .scan_bus         = 0,
130 };
131
132 static void enable_dev(struct device *dev)
133 {
134         /* Set the operations if it is a special bus type */
135         if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) {
136                 dev->ops = &pci_domain_ops;
137                 pci_set_method(dev);
138         }
139         else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) {
140                 dev->ops = &cpu_bus_ops;
141         }
142 }
143
144 struct chip_operations northbridge_via_vt8601_ops = {
145         CHIP_NAME("VIA VT8601 Northbridge")
146         .enable_dev = enable_dev,
147 };