Make the reserved video memory on Geode GX1 based systems configurable.
[coreboot.git] / src / northbridge / amd / gx1 / 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 <stdlib.h>
8 #include <string.h>
9 #include <bitops.h>
10 #include "chip.h"
11 #include "northbridge.h"
12 #include <cpu/amd/gx1def.h>
13 #include <cpu/x86/cache.h>
14
15 #define NORTHBRIDGE_FILE "northbridge.c"
16 /*
17 */
18
19 static void optimize_xbus(device_t dev)
20 {
21         /* Optimise X-Bus performance */
22         pci_write_config8(dev, 0x40, 0x1e);
23         pci_write_config8(dev, 0x41, 0x52);
24         pci_write_config8(dev, 0x43, 0xc1);
25         pci_write_config8(dev, 0x44, 0x00);
26 }
27
28 /**
29  * Enables memory from 0xC0000 up to 0xFFFFF.
30  * So this region is read/write and cache able
31  *
32  * FIXME: What about PCI master access into
33  *        this region?
34  **/
35
36 static void enable_shadow(device_t dev)
37 {
38        writel(0x77777777,GX_BASE+BC_XMAP_2);
39        writel(0x77777777,GX_BASE+BC_XMAP_3);
40 }
41
42 static void northbridge_init(device_t dev) 
43 {
44         printk_debug("northbridge: %s()\n", __FUNCTION__);
45         
46         optimize_xbus(dev);
47         enable_shadow(dev);
48         printk_spew("Calling enable_cache()\n");
49         enable_cache();
50 }
51
52
53 static struct device_operations northbridge_operations = {
54         .read_resources   = pci_dev_read_resources,
55         .set_resources    = pci_dev_set_resources,
56         .enable_resources = pci_dev_enable_resources,
57         .init             = northbridge_init,
58         .enable           = 0,
59         .ops_pci          = 0,
60 };
61
62 static struct pci_driver northbridge_driver __pci_driver = {
63         .ops = &northbridge_operations,
64         .vendor = PCI_VENDOR_ID_CYRIX,
65         .device = PCI_DEVICE_ID_CYRIX_PCI_MASTER, 
66 };
67
68
69
70 #define BRIDGE_IO_MASK (IORESOURCE_IO | IORESOURCE_MEM)
71
72 static void pci_domain_read_resources(device_t dev)
73 {
74         struct resource *resource;
75
76         printk_spew("%s:%s()\n", NORTHBRIDGE_FILE, __FUNCTION__);
77
78         /* Initialize the system wide io space constraints */
79         resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0,0));
80         resource->limit = 0xffffUL;
81         resource->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
82
83         /* Initialize the system wide memory resources constraints */
84         resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1,0));
85         resource->limit = 0xffffffffULL;
86         resource->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
87 }
88
89 static void ram_resource(device_t dev, unsigned long index,
90         unsigned long basek, unsigned long sizek)
91 {
92         struct resource *resource;
93
94         if (!sizek) {
95                 return;
96         }
97         resource = new_resource(dev, index);
98         resource->base  = ((resource_t)basek) << 10;
99         resource->size  = ((resource_t)sizek) << 10;
100         resource->flags =  IORESOURCE_MEM | IORESOURCE_CACHEABLE | \
101                 IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
102 }
103
104 static void tolm_test(void *gp, struct device *dev, struct resource *new)
105 {
106         struct resource **best_p = gp;
107         struct resource *best;
108         best = *best_p;
109         if (!best || (best->base > new->base)) {
110                 best = new;
111         }
112         *best_p = best;
113 }
114
115 static uint32_t find_pci_tolm(struct bus *bus)
116 {
117         struct resource *min;
118         uint32_t tolm;
119         min = 0;
120         search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min);
121         tolm = 0xffffffffUL;
122         if (min && tolm > min->base) {
123                 tolm = min->base;
124         }
125         return tolm;
126 }
127
128 static void pci_domain_set_resources(device_t dev)
129 {
130         device_t mc_dev;
131         uint32_t pci_tolm;
132
133         pci_tolm = find_pci_tolm(&dev->link[0]);
134         mc_dev = dev->link[0].children;
135         if (mc_dev) {
136                 unsigned int tomk, tolmk;
137                 unsigned int ramreg = 0;
138                 int i, idx;
139                 unsigned int *bcdramtop = (unsigned int *)(GX_BASE + BC_DRAM_TOP);
140                 unsigned int *mcgbaseadd = (unsigned int *)(GX_BASE + MC_GBASE_ADD);
141
142                 for(i=0; i<0x20; i+= 0x10) {
143                         unsigned int *mcreg = (unsigned int *)(GX_BASE + MC_BANK_CFG);
144                         unsigned int mem_config = *mcreg;
145
146                         if (((mem_config & (DIMM_PG_SZ << i)) >> (4 + i)) == 7)
147                                 continue;
148                         ramreg += 1 << (((mem_config & (DIMM_SZ << i)) >> (i + 8)) + 2);
149                 }
150                         
151                 tomk = ramreg << 10;
152
153                 /* Sort out the framebuffer size */
154                 tomk -= CONFIG_VIDEO_MB * 1024;
155                 *bcdramtop = ((tomk << 10) - 1);
156                 *mcgbaseadd = (tomk >> 9);
157
158                 printk_debug("BC_DRAM_TOP = 0x%08x\n", *bcdramtop);
159                 printk_debug("MC_GBASE_ADD = 0x%08x\n", *mcgbaseadd);
160
161                 printk_debug("I would set ram size to %d Mbytes\n", (tomk >> 10));
162
163                 /* Compute the top of Low memory */
164                 tolmk = pci_tolm >> 10;
165                 if (tolmk >= tomk) {
166                         /* The PCI hole does does not overlap the memory.
167                          */
168                         tolmk = tomk;
169                 }
170                 /* Report the memory regions */
171                 idx = 10;
172                 ram_resource(dev, idx++, 0, tolmk);
173         }
174         assign_resources(&dev->link[0]);
175 }
176
177 static unsigned int pci_domain_scan_bus(device_t dev, unsigned int max)
178 {
179         max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0, 0), 0xff, max);
180         return max;
181 }
182
183 static struct device_operations pci_domain_ops = {
184         .read_resources   = pci_domain_read_resources,
185         .set_resources    = pci_domain_set_resources,
186         .enable_resources = enable_childrens_resources,
187         .init             = 0,
188         .scan_bus         = pci_domain_scan_bus,
189 };  
190
191 static void cpu_bus_init(device_t dev)
192 {
193         printk_spew("%s:%s()\n", NORTHBRIDGE_FILE, __FUNCTION__);
194         initialize_cpus(&dev->link[0]);
195 }
196
197 static void cpu_bus_noop(device_t dev)
198 {
199 }
200
201 static struct device_operations cpu_bus_ops = {
202         .read_resources   = cpu_bus_noop,
203         .set_resources    = cpu_bus_noop,
204         .enable_resources = cpu_bus_noop,
205         .init             = cpu_bus_init,
206         .scan_bus         = 0,
207 };
208
209 static void enable_dev(struct device *dev)
210 {
211         printk_spew("%s:%s()\n", NORTHBRIDGE_FILE, __FUNCTION__);
212         /* Set the operations if it is a special bus type */
213         if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) {
214                 printk_spew("DEVICE_PATH_PCI_DOMAIN\n");
215                 dev->ops = &pci_domain_ops;
216                 pci_set_method(dev);
217         }
218         else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) {
219                 printk_spew("DEVICE_PATH_APIC_CLUSTER\n");
220                 dev->ops = &cpu_bus_ops;
221         } else {
222                 printk_spew("device path type %d\n",dev->path.type);
223         }
224 }
225
226 struct chip_operations northbridge_amd_gx1_ops = {
227         CHIP_NAME("AMD GX1 Northbridge")
228         .enable_dev = enable_dev, 
229 };