]>
Commit | Line | Data |
---|---|---|
99eac90e AM |
1 | diff -urN linux-2.4.22.org/drivers/char/agp/agpgart_be.c linux-2.4.22/drivers/char/agp/agpgart_be.c |
2 | --- linux-2.4.22.org/drivers/char/agp/agpgart_be.c 2003-11-21 18:32:42.000000000 +0100 | |
3 | +++ linux-2.4.22/drivers/char/agp/agpgart_be.c 2003-11-21 18:34:41.000000000 +0100 | |
4 | @@ -53,6 +53,10 @@ | |
5 | #include <asm/msr.h> | |
6 | #endif | |
3d98ac96 | 7 | |
8 | +#ifdef CONFIG_AGP_UNINORTH | |
9 | +#include <asm/uninorth.h> | |
10 | +#endif | |
11 | + | |
12 | #include <linux/agp_backend.h> | |
13 | #include "agp.h" | |
14 | ||
99eac90e | 15 | @@ -81,7 +85,7 @@ |
3d98ac96 | 16 | { |
17 | #if defined(__i386__) || defined(__x86_64__) | |
18 | asm volatile ("wbinvd":::"memory"); | |
19 | -#elif defined(__alpha__) || defined(__ia64__) || defined(__sparc__) | |
20 | +#elif defined(__alpha__) || defined(__ia64__) || defined(__sparc__) || defined(__powerpc__) | |
21 | /* ??? I wonder if we'll really need to flush caches, or if the | |
22 | core logic can manage to keep the system coherent. The ARM | |
23 | speaks only of using `cflush' to get things in memory in | |
99eac90e AM |
24 | @@ -5918,6 +5922,405 @@ |
25 | } | |
26 | #endif /* CONFIG_AGP_ATI */ | |
3d98ac96 | 27 | |
28 | +#ifdef CONFIG_AGP_UNINORTH | |
29 | + | |
30 | +static int uninorth_fetch_size(void) | |
31 | +{ | |
32 | + int i; | |
33 | + u32 temp; | |
34 | + aper_size_info_32 *values; | |
35 | + | |
36 | + pci_read_config_dword(agp_bridge.dev, UNI_N_CFG_GART_BASE, &temp); | |
37 | + temp &= ~(0xfffff000); | |
38 | + values = A_SIZE_32(agp_bridge.aperture_sizes); | |
39 | + | |
40 | + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { | |
41 | + if (temp == values[i].size_value) { | |
42 | + agp_bridge.previous_size = | |
43 | + agp_bridge.current_size = (void *) (values + i); | |
44 | + agp_bridge.aperture_size_idx = i; | |
45 | + return values[i].size; | |
46 | + } | |
47 | + } | |
48 | + | |
49 | + agp_bridge.previous_size = | |
50 | + agp_bridge.current_size = (void *) (values + 1); | |
51 | + agp_bridge.aperture_size_idx = 1; | |
52 | + return values[1].size; | |
53 | + | |
54 | + return 0; | |
55 | +} | |
56 | + | |
57 | +static void uninorth_tlbflush(agp_memory * mem) | |
58 | +{ | |
59 | + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, | |
60 | + UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL); | |
61 | + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, | |
62 | + UNI_N_CFG_GART_ENABLE); | |
63 | + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, | |
64 | + UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_2xRESET); | |
65 | + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, | |
66 | + UNI_N_CFG_GART_ENABLE); | |
67 | +} | |
68 | + | |
69 | +static void uninorth_cleanup(void) | |
70 | +{ | |
71 | + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, | |
72 | + UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL); | |
73 | + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, | |
74 | + 0); | |
75 | + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, | |
76 | + UNI_N_CFG_GART_2xRESET); | |
77 | + pci_write_config_dword(agp_bridge.dev, UNI_N_CFG_GART_CTRL, | |
78 | + 0); | |
79 | +} | |
80 | + | |
81 | +static int uninorth_configure(void) | |
82 | +{ | |
83 | + aper_size_info_32 *current_size; | |
84 | + | |
85 | + current_size = A_SIZE_32(agp_bridge.current_size); | |
86 | + | |
87 | + printk("agp: configuring for size idx: %d\n", current_size->size_value); | |
88 | + | |
89 | + /* aperture size and gatt addr */ | |
90 | + pci_write_config_dword(agp_bridge.dev, | |
91 | + UNI_N_CFG_GART_BASE, | |
92 | + (agp_bridge.gatt_bus_addr & 0xfffff000) | |
93 | + | current_size->size_value); | |
94 | + | |
95 | + /* HACK ALERT | |
96 | + * UniNorth seem to be buggy enough not to handle properly when | |
97 | + * the AGP aperture isn't mapped at bus physical address 0 | |
98 | + */ | |
99 | + agp_bridge.gart_bus_addr = 0; | |
100 | + pci_write_config_dword(agp_bridge.dev, | |
101 | + UNI_N_CFG_AGP_BASE, agp_bridge.gart_bus_addr); | |
102 | + | |
103 | + return 0; | |
104 | +} | |
105 | + | |
106 | +static unsigned long uninorth_mask_memory(unsigned long addr, int type) | |
107 | +{ | |
108 | + return addr;/* | agp_bridge.masks[0].mask;*/ | |
109 | +} | |
110 | + | |
111 | +static int uninorth_insert_memory(agp_memory * mem, | |
112 | + off_t pg_start, int type) | |
113 | +{ | |
114 | + int i, j, num_entries; | |
115 | + void *temp; | |
116 | + | |
117 | + temp = agp_bridge.current_size; | |
118 | + num_entries = A_SIZE_32(temp)->num_entries; | |
119 | + | |
120 | + if (type != 0 || mem->type != 0) { | |
121 | + /* The generic routines know nothing of memory types */ | |
122 | + return -EINVAL; | |
123 | + } | |
124 | + if ((pg_start + mem->page_count) > num_entries) { | |
125 | + return -EINVAL; | |
126 | + } | |
127 | + j = pg_start; | |
128 | + | |
129 | + while (j < (pg_start + mem->page_count)) { | |
130 | + if (!PGE_EMPTY(agp_bridge.gatt_table[j])) { | |
131 | + return -EBUSY; | |
132 | + } | |
133 | + j++; | |
134 | + } | |
135 | + | |
136 | + if (mem->is_flushed == FALSE) { | |
137 | + CACHE_FLUSH(); | |
138 | + mem->is_flushed = TRUE; | |
139 | + } | |
140 | + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { | |
141 | + agp_bridge.gatt_table[j] = cpu_to_le32((mem->memory[i] & 0xfffff000) | 0x00000001UL); | |
142 | + flush_dcache_range(__va(mem->memory[i]), __va(mem->memory[i])+0x1000); | |
143 | + } | |
144 | + (void)in_le32((volatile u32*)&agp_bridge.gatt_table[pg_start]); | |
145 | + mb(); | |
146 | + flush_dcache_range((unsigned long)&agp_bridge.gatt_table[pg_start], | |
147 | + (unsigned long)&agp_bridge.gatt_table[pg_start + mem->page_count]); | |
148 | + | |
149 | + agp_bridge.tlb_flush(mem); | |
150 | + return 0; | |
151 | +} | |
152 | + | |
153 | +static void uninorth_agp_enable(u32 mode) | |
154 | +{ | |
155 | + struct pci_dev *device = NULL; | |
156 | + u32 command, scratch, cap_id; | |
157 | + u8 cap_ptr; | |
158 | + | |
159 | + pci_read_config_dword(agp_bridge.dev, | |
160 | + agp_bridge.capndx + 4, | |
161 | + &command); | |
162 | + | |
163 | + /* | |
164 | + * PASS1: go throu all devices that claim to be | |
165 | + * AGP devices and collect their data. | |
166 | + */ | |
167 | + | |
168 | + while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, | |
169 | + device)) != NULL) { | |
170 | + pci_read_config_dword(device, 0x04, &scratch); | |
171 | + | |
172 | + if (!(scratch & 0x00100000)) | |
173 | + continue; | |
174 | + | |
175 | + pci_read_config_byte(device, 0x34, &cap_ptr); | |
176 | + | |
177 | + if (cap_ptr != 0x00) { | |
178 | + do { | |
179 | + pci_read_config_dword(device, | |
180 | + cap_ptr, &cap_id); | |
181 | + | |
182 | + if ((cap_id & 0xff) != 0x02) | |
183 | + cap_ptr = (cap_id >> 8) & 0xff; | |
184 | + } | |
185 | + while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); | |
186 | + } | |
187 | + if (cap_ptr != 0x00) { | |
188 | + /* | |
189 | + * Ok, here we have a AGP device. Disable impossible | |
190 | + * settings, and adjust the readqueue to the minimum. | |
191 | + */ | |
192 | + | |
193 | + pci_read_config_dword(device, cap_ptr + 4, &scratch); | |
194 | + | |
195 | + /* adjust RQ depth */ | |
196 | + command = | |
197 | + ((command & ~0xff000000) | | |
198 | + min_t(u32, (mode & 0xff000000), | |
199 | + min_t(u32, (command & 0xff000000), | |
200 | + (scratch & 0xff000000)))); | |
201 | + | |
202 | + /* disable SBA if it's not supported */ | |
203 | + if (!((command & 0x00000200) && | |
204 | + (scratch & 0x00000200) && | |
205 | + (mode & 0x00000200))) | |
206 | + command &= ~0x00000200; | |
207 | + | |
208 | + /* disable FW if it's not supported */ | |
209 | + if (!((command & 0x00000010) && | |
210 | + (scratch & 0x00000010) && | |
211 | + (mode & 0x00000010))) | |
212 | + command &= ~0x00000010; | |
213 | + | |
214 | + if (!((command & 4) && | |
215 | + (scratch & 4) && | |
216 | + (mode & 4))) | |
217 | + command &= ~0x00000004; | |
218 | + | |
219 | + if (!((command & 2) && | |
220 | + (scratch & 2) && | |
221 | + (mode & 2))) | |
222 | + command &= ~0x00000002; | |
223 | + | |
224 | + if (!((command & 1) && | |
225 | + (scratch & 1) && | |
226 | + (mode & 1))) | |
227 | + command &= ~0x00000001; | |
228 | + } | |
229 | + } | |
230 | + /* | |
231 | + * PASS2: Figure out the 4X/2X/1X setting and enable the | |
232 | + * target (our motherboard chipset). | |
233 | + */ | |
234 | + | |
235 | + if (command & 4) { | |
236 | + command &= ~3; /* 4X */ | |
237 | + } | |
238 | + if (command & 2) { | |
239 | + command &= ~5; /* 2X */ | |
240 | + } | |
241 | + if (command & 1) { | |
242 | + command &= ~6; /* 1X */ | |
243 | + } | |
244 | + command |= 0x00000100; | |
245 | + | |
246 | + uninorth_tlbflush(NULL); | |
247 | + | |
248 | + do { | |
249 | + pci_write_config_dword(agp_bridge.dev, | |
250 | + agp_bridge.capndx + 8, | |
251 | + command); | |
252 | + pci_read_config_dword(agp_bridge.dev, | |
253 | + agp_bridge.capndx + 8, | |
254 | + &scratch); | |
255 | + } while((scratch & 0x100) == 0); | |
256 | + | |
257 | + /* | |
258 | + * PASS3: Go throu all AGP devices and update the | |
259 | + * command registers. | |
260 | + */ | |
261 | + | |
262 | + while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, | |
263 | + device)) != NULL) { | |
264 | + pci_read_config_dword(device, 0x04, &scratch); | |
265 | + | |
266 | + if (!(scratch & 0x00100000)) | |
267 | + continue; | |
268 | + | |
269 | + pci_read_config_byte(device, 0x34, &cap_ptr); | |
270 | + | |
271 | + if (cap_ptr != 0x00) { | |
272 | + do { | |
273 | + pci_read_config_dword(device, | |
274 | + cap_ptr, &cap_id); | |
275 | + | |
276 | + if ((cap_id & 0xff) != 0x02) | |
277 | + cap_ptr = (cap_id >> 8) & 0xff; | |
278 | + } | |
279 | + while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); | |
280 | + } | |
281 | + if (cap_ptr != 0x00) | |
282 | + pci_write_config_dword(device, cap_ptr + 8, command); | |
283 | + } | |
284 | + | |
285 | + uninorth_tlbflush(NULL); | |
286 | +} | |
287 | + | |
288 | +static int uninorth_create_gatt_table(void) | |
289 | +{ | |
290 | + char *table; | |
291 | + char *table_end; | |
292 | + int size; | |
293 | + int page_order; | |
294 | + int num_entries; | |
295 | + int i; | |
296 | + void *temp; | |
297 | + struct page *page; | |
298 | + | |
299 | + /* The generic routines can't handle 2 level gatt's */ | |
300 | + if (agp_bridge.size_type == LVL2_APER_SIZE) { | |
301 | + return -EINVAL; | |
302 | + } | |
303 | + | |
304 | + table = NULL; | |
305 | + i = agp_bridge.aperture_size_idx; | |
306 | + temp = agp_bridge.current_size; | |
307 | + size = page_order = num_entries = 0; | |
308 | + | |
309 | + do { | |
310 | + size = A_SIZE_32(temp)->size; | |
311 | + page_order = A_SIZE_32(temp)->page_order; | |
312 | + num_entries = A_SIZE_32(temp)->num_entries; | |
313 | + | |
314 | + table = (char *) __get_free_pages(GFP_KERNEL, page_order); | |
315 | + | |
316 | + if (table == NULL) { | |
317 | + i++; | |
318 | + agp_bridge.current_size = A_IDX32(); | |
319 | + } else { | |
320 | + agp_bridge.aperture_size_idx = i; | |
321 | + } | |
322 | + } while ((table == NULL) && | |
323 | + (i < agp_bridge.num_aperture_sizes)); | |
324 | + | |
325 | + if (table == NULL) { | |
326 | + return -ENOMEM; | |
327 | + } | |
328 | + table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); | |
329 | + | |
330 | + for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) | |
331 | + SetPageReserved(page); | |
332 | + | |
333 | + agp_bridge.gatt_table_real = (unsigned long *) table; | |
334 | + agp_bridge.gatt_table = (unsigned long *)table; | |
335 | + agp_bridge.gatt_bus_addr = virt_to_phys(table); | |
336 | + | |
337 | + for (i = 0; i < num_entries; i++) { | |
338 | + agp_bridge.gatt_table[i] = | |
339 | + (unsigned long) agp_bridge.scratch_page; | |
340 | + } | |
341 | + | |
342 | + flush_dcache_range((unsigned long)table, (unsigned long)table_end); | |
343 | + | |
344 | + return 0; | |
345 | +} | |
346 | + | |
347 | +static int uninorth_free_gatt_table(void) | |
348 | +{ | |
349 | + int page_order; | |
350 | + char *table, *table_end; | |
351 | + void *temp; | |
352 | + struct page *page; | |
353 | + | |
354 | + temp = agp_bridge.current_size; | |
355 | + page_order = A_SIZE_32(temp)->page_order; | |
356 | + | |
357 | + /* Do not worry about freeing memory, because if this is | |
358 | + * called, then all agp memory is deallocated and removed | |
359 | + * from the table. | |
360 | + */ | |
361 | + | |
362 | + table = (char *) agp_bridge.gatt_table_real; | |
363 | + table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); | |
364 | + | |
365 | + for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) | |
366 | + ClearPageReserved(page); | |
367 | + | |
368 | + free_pages((unsigned long) agp_bridge.gatt_table_real, page_order); | |
369 | + | |
370 | + return 0; | |
371 | +} | |
372 | + | |
373 | +/* Setup function */ | |
374 | +static gatt_mask uninorth_masks[] = | |
375 | +{ | |
376 | + {0x00000000, 0} | |
377 | +}; | |
378 | + | |
379 | +static aper_size_info_32 uninorth_sizes[7] = | |
380 | +{ | |
381 | +#if 0 /* Not sure uninorth supports that high aperture sizes */ | |
382 | + {256, 65536, 6, 64}, | |
383 | + {128, 32768, 5, 32}, | |
384 | + {64, 16384, 4, 16}, | |
385 | +#endif | |
386 | + {32, 8192, 3, 8}, | |
387 | + {16, 4096, 2, 4}, | |
388 | + {8, 2048, 1, 2}, | |
389 | + {4, 1024, 0, 1} | |
390 | +}; | |
391 | + | |
392 | +static int __init uninorth_setup (struct pci_dev *pdev) | |
393 | +{ | |
394 | + agp_bridge.masks = uninorth_masks; | |
395 | + agp_bridge.num_of_masks = 1; | |
396 | + agp_bridge.aperture_sizes = (void *)uninorth_sizes; | |
397 | + agp_bridge.size_type = U32_APER_SIZE; | |
398 | + agp_bridge.num_aperture_sizes = 4; //7; | |
399 | + agp_bridge.dev_private_data = NULL; | |
400 | + agp_bridge.needs_scratch_page = FALSE; | |
401 | + agp_bridge.configure = uninorth_configure; | |
402 | + agp_bridge.fetch_size = uninorth_fetch_size; | |
403 | + agp_bridge.cleanup = uninorth_cleanup; | |
404 | + agp_bridge.tlb_flush = uninorth_tlbflush; | |
405 | + agp_bridge.mask_memory = uninorth_mask_memory; | |
406 | + agp_bridge.agp_enable = uninorth_agp_enable; | |
407 | + agp_bridge.cache_flush = global_cache_flush; | |
408 | + agp_bridge.create_gatt_table = uninorth_create_gatt_table; | |
409 | + agp_bridge.free_gatt_table = uninorth_free_gatt_table; | |
410 | + agp_bridge.insert_memory = uninorth_insert_memory; | |
411 | + agp_bridge.remove_memory = agp_generic_remove_memory; | |
412 | + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; | |
413 | + agp_bridge.free_by_type = agp_generic_free_by_type; | |
414 | + agp_bridge.agp_alloc_page = agp_generic_alloc_page; | |
415 | + agp_bridge.agp_destroy_page = agp_generic_destroy_page; | |
416 | + agp_bridge.suspend = agp_generic_suspend; | |
417 | + agp_bridge.resume = agp_generic_resume; | |
418 | + agp_bridge.cant_use_aperture = 1; | |
419 | + | |
420 | + return 0; | |
421 | + | |
422 | + (void) pdev; /* unused */ | |
423 | +} | |
424 | + | |
425 | +#endif /* CONFIG_AGP_UNINORTH */ | |
426 | + | |
427 | /* per-chipset initialization data. | |
428 | * note -- all chipsets for a single vendor MUST be grouped together | |
429 | */ | |
99eac90e AM |
430 | @@ -6462,6 +6865,27 @@ |
431 | ati_generic_setup }, | |
432 | #endif /* CONFIG_AGP_ATI */ | |
3d98ac96 | 433 | |
434 | +#ifdef CONFIG_AGP_UNINORTH | |
435 | + { PCI_DEVICE_ID_APPLE_UNI_N_AGP, | |
436 | + PCI_VENDOR_ID_APPLE, | |
437 | + APPLE_UNINORTH, | |
438 | + "Apple", | |
439 | + "UniNorth", | |
440 | + uninorth_setup }, | |
441 | + { PCI_DEVICE_ID_APPLE_UNI_N_AGP_P, | |
442 | + PCI_VENDOR_ID_APPLE, | |
443 | + APPLE_UNINORTH, | |
444 | + "Apple", | |
445 | + "UniNorth/Pangea", | |
446 | + uninorth_setup }, | |
447 | + { PCI_DEVICE_ID_APPLE_UNI_N_AGP15, | |
448 | + PCI_VENDOR_ID_APPLE, | |
449 | + APPLE_UNINORTH, | |
450 | + "Apple", | |
451 | + "UniNorth 1.5", | |
452 | + uninorth_setup }, | |
453 | +#endif /* CONFIG_AGP_UNINORTH */ | |
454 | + | |
455 | { 0, }, /* dummy final entry, always present */ | |
456 | }; | |
457 | ||
99eac90e AM |
458 | diff -urN linux-2.4.22.org/drivers/char/Config.in linux-2.4.22/drivers/char/Config.in |
459 | --- linux-2.4.22.org/drivers/char/Config.in 2003-11-21 18:32:29.000000000 +0100 | |
460 | +++ linux-2.4.22/drivers/char/Config.in 2003-11-21 18:34:42.000000000 +0100 | |
461 | @@ -210,6 +210,9 @@ | |
462 | comment ' from the tpqic02-support package. It is available at' | |
463 | comment ' metalab.unc.edu or ftp://titus.cfw.com/pub/Linux/util/' | |
3d98ac96 | 464 | fi |
465 | + if [ "$CONFIG_ALL_PPC" = "y" ]; then | |
466 | + bool ' Apple UniNorth support' CONFIG_AGP_UNINORTH | |
467 | + fi | |
468 | fi | |
469 | ||
99eac90e AM |
470 | tristate 'IPMI top-level message handler' CONFIG_IPMI_HANDLER |
471 | diff -urN linux-2.4.22.org/include/linux/agp_backend.h linux-2.4.22/include/linux/agp_backend.h | |
472 | --- linux-2.4.22.org/include/linux/agp_backend.h 2003-11-21 18:31:25.000000000 +0100 | |
473 | +++ linux-2.4.22/include/linux/agp_backend.h 2003-11-21 18:35:20.000000000 +0100 | |
474 | @@ -95,6 +95,7 @@ | |
475 | NVIDIA_NFORCE3, | |
476 | NVIDIA_GENERIC, | |
3d98ac96 | 477 | HP_ZX1, |
478 | + APPLE_UNINORTH, | |
99eac90e AM |
479 | ATI_RS100, |
480 | ATI_RS200, | |
481 | ATI_RS250, |