initial commit with v2.6.9
[linux-2.6.9-moxart.git] / drivers / char / agp / uninorth-agp.c
blob14dfb59ffa66bba49880cf252f4d674a8683a9c1
1 /*
2 * UniNorth AGPGART routines.
3 */
4 #include <linux/module.h>
5 #include <linux/pci.h>
6 #include <linux/init.h>
7 #include <linux/pagemap.h>
8 #include <linux/agp_backend.h>
9 #include <asm/uninorth.h>
10 #include <asm/pci-bridge.h>
11 #include "agp.h"
13 static int uninorth_fetch_size(void)
15 int i;
16 u32 temp;
17 struct aper_size_info_32 *values;
19 pci_read_config_dword(agp_bridge->dev, UNI_N_CFG_GART_BASE, &temp);
20 temp &= ~(0xfffff000);
21 values = A_SIZE_32(agp_bridge->driver->aperture_sizes);
23 for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
24 if (temp == values[i].size_value) {
25 agp_bridge->previous_size =
26 agp_bridge->current_size = (void *) (values + i);
27 agp_bridge->aperture_size_idx = i;
28 return values[i].size;
32 agp_bridge->previous_size =
33 agp_bridge->current_size = (void *) (values + 1);
34 agp_bridge->aperture_size_idx = 1;
35 return values[1].size;
37 return 0;
40 static void uninorth_tlbflush(struct agp_memory *mem)
42 pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
43 UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL);
44 pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
45 UNI_N_CFG_GART_ENABLE);
46 pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
47 UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_2xRESET);
48 pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
49 UNI_N_CFG_GART_ENABLE);
52 static void uninorth_cleanup(void)
54 pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
55 UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL);
56 pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
57 0);
58 pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
59 UNI_N_CFG_GART_2xRESET);
60 pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
61 0);
64 static int uninorth_configure(void)
66 struct aper_size_info_32 *current_size;
68 current_size = A_SIZE_32(agp_bridge->current_size);
70 printk(KERN_INFO PFX "configuring for size idx: %d\n",
71 current_size->size_value);
73 /* aperture size and gatt addr */
74 pci_write_config_dword(agp_bridge->dev,
75 UNI_N_CFG_GART_BASE,
76 (agp_bridge->gatt_bus_addr & 0xfffff000)
77 | current_size->size_value);
79 /* HACK ALERT
80 * UniNorth seem to be buggy enough not to handle properly when
81 * the AGP aperture isn't mapped at bus physical address 0
83 agp_bridge->gart_bus_addr = 0;
84 pci_write_config_dword(agp_bridge->dev,
85 UNI_N_CFG_AGP_BASE, agp_bridge->gart_bus_addr);
87 return 0;
90 static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start,
91 int type)
93 int i, j, num_entries;
94 void *temp;
96 temp = agp_bridge->current_size;
97 num_entries = A_SIZE_32(temp)->num_entries;
99 if (type != 0 || mem->type != 0)
100 /* We know nothing of memory types */
101 return -EINVAL;
102 if ((pg_start + mem->page_count) > num_entries)
103 return -EINVAL;
105 j = pg_start;
107 while (j < (pg_start + mem->page_count)) {
108 if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j]))
109 return -EBUSY;
110 j++;
113 for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
114 agp_bridge->gatt_table[j] = cpu_to_le32((mem->memory[i] & 0xfffff000) | 0x00000001UL);
115 flush_dcache_range((unsigned long)__va(mem->memory[i]),
116 (unsigned long)__va(mem->memory[i])+0x1000);
118 (void)in_le32((volatile u32*)&agp_bridge->gatt_table[pg_start]);
119 mb();
120 flush_dcache_range((unsigned long)&agp_bridge->gatt_table[pg_start],
121 (unsigned long)&agp_bridge->gatt_table[pg_start + mem->page_count]);
123 uninorth_tlbflush(mem);
124 return 0;
127 static void uninorth_agp_enable(u32 mode)
129 u32 command, scratch;
130 int timeout;
132 pci_read_config_dword(agp_bridge->dev,
133 agp_bridge->capndx + PCI_AGP_STATUS,
134 &command);
136 command = agp_collect_device_status(mode, command);
137 command |= 0x100;
139 uninorth_tlbflush(NULL);
141 timeout = 0;
142 do {
143 pci_write_config_dword(agp_bridge->dev,
144 agp_bridge->capndx + PCI_AGP_COMMAND,
145 command);
146 pci_read_config_dword(agp_bridge->dev,
147 agp_bridge->capndx + PCI_AGP_COMMAND,
148 &scratch);
149 } while ((scratch & 0x100) == 0 && ++timeout < 1000);
150 if ((scratch & 0x100) == 0)
151 printk(KERN_ERR PFX "failed to write UniNorth AGP command reg\n");
153 agp_device_command(command, 0);
155 uninorth_tlbflush(NULL);
158 static int uninorth_create_gatt_table(void)
160 char *table;
161 char *table_end;
162 int size;
163 int page_order;
164 int num_entries;
165 int i;
166 void *temp;
167 struct page *page;
169 /* We can't handle 2 level gatt's */
170 if (agp_bridge->driver->size_type == LVL2_APER_SIZE)
171 return -EINVAL;
173 table = NULL;
174 i = agp_bridge->aperture_size_idx;
175 temp = agp_bridge->current_size;
176 size = page_order = num_entries = 0;
178 do {
179 size = A_SIZE_32(temp)->size;
180 page_order = A_SIZE_32(temp)->page_order;
181 num_entries = A_SIZE_32(temp)->num_entries;
183 table = (char *) __get_free_pages(GFP_KERNEL, page_order);
185 if (table == NULL) {
186 i++;
187 agp_bridge->current_size = A_IDX32(agp_bridge);
188 } else {
189 agp_bridge->aperture_size_idx = i;
191 } while (!table && (i < agp_bridge->driver->num_aperture_sizes));
193 if (table == NULL)
194 return -ENOMEM;
196 table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
198 for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
199 SetPageReserved(page);
201 agp_bridge->gatt_table_real = (u32 *) table;
202 agp_bridge->gatt_table = (u32 *)table;
203 agp_bridge->gatt_bus_addr = virt_to_phys(table);
205 for (i = 0; i < num_entries; i++) {
206 agp_bridge->gatt_table[i] =
207 (unsigned long) agp_bridge->scratch_page;
210 flush_dcache_range((unsigned long)table, (unsigned long)table_end);
212 return 0;
215 static int uninorth_free_gatt_table(void)
217 int page_order;
218 char *table, *table_end;
219 void *temp;
220 struct page *page;
222 temp = agp_bridge->current_size;
223 page_order = A_SIZE_32(temp)->page_order;
225 /* Do not worry about freeing memory, because if this is
226 * called, then all agp memory is deallocated and removed
227 * from the table.
230 table = (char *) agp_bridge->gatt_table_real;
231 table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
233 for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
234 ClearPageReserved(page);
236 free_pages((unsigned long) agp_bridge->gatt_table_real, page_order);
238 return 0;
241 void null_cache_flush(void)
243 mb();
246 /* Setup function */
248 static struct aper_size_info_32 uninorth_sizes[7] =
250 #if 0 /* Not sure uninorth supports that high aperture sizes */
251 {256, 65536, 6, 64},
252 {128, 32768, 5, 32},
253 {64, 16384, 4, 16},
254 #endif
255 {32, 8192, 3, 8},
256 {16, 4096, 2, 4},
257 {8, 2048, 1, 2},
258 {4, 1024, 0, 1}
261 struct agp_bridge_driver uninorth_agp_driver = {
262 .owner = THIS_MODULE,
263 .aperture_sizes = (void *)uninorth_sizes,
264 .size_type = U32_APER_SIZE,
265 .num_aperture_sizes = 4,
266 .configure = uninorth_configure,
267 .fetch_size = uninorth_fetch_size,
268 .cleanup = uninorth_cleanup,
269 .tlb_flush = uninorth_tlbflush,
270 .mask_memory = agp_generic_mask_memory,
271 .masks = NULL,
272 .cache_flush = null_cache_flush,
273 .agp_enable = uninorth_agp_enable,
274 .create_gatt_table = uninorth_create_gatt_table,
275 .free_gatt_table = uninorth_free_gatt_table,
276 .insert_memory = uninorth_insert_memory,
277 .remove_memory = agp_generic_remove_memory,
278 .alloc_by_type = agp_generic_alloc_by_type,
279 .free_by_type = agp_generic_free_by_type,
280 .agp_alloc_page = agp_generic_alloc_page,
281 .agp_destroy_page = agp_generic_destroy_page,
282 .cant_use_aperture = 1,
285 static struct agp_device_ids uninorth_agp_device_ids[] __devinitdata = {
287 .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP,
288 .chipset_name = "UniNorth",
291 .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP_P,
292 .chipset_name = "UniNorth/Pangea",
295 .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP15,
296 .chipset_name = "UniNorth 1.5",
299 .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP2,
300 .chipset_name = "UniNorth 2",
304 static int __devinit agp_uninorth_probe(struct pci_dev *pdev,
305 const struct pci_device_id *ent)
307 struct agp_device_ids *devs = uninorth_agp_device_ids;
308 struct agp_bridge_data *bridge;
309 u8 cap_ptr;
310 int j;
312 cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
313 if (cap_ptr == 0)
314 return -ENODEV;
316 /* probe for known chipsets */
317 for (j = 0; devs[j].chipset_name != NULL; ++j) {
318 if (pdev->device == devs[j].device_id) {
319 printk(KERN_INFO PFX "Detected Apple %s chipset\n",
320 devs[j].chipset_name);
321 goto found;
325 printk(KERN_ERR PFX "Unsupported Apple chipset (device id: %04x).\n",
326 pdev->device);
327 return -ENODEV;
329 found:
330 bridge = agp_alloc_bridge();
331 if (!bridge)
332 return -ENOMEM;
334 bridge->driver = &uninorth_agp_driver;
335 bridge->dev = pdev;
336 bridge->capndx = cap_ptr;
338 /* Fill in the mode register */
339 pci_read_config_dword(pdev, cap_ptr+PCI_AGP_STATUS, &bridge->mode);
341 pci_set_drvdata(pdev, bridge);
342 return agp_add_bridge(bridge);
345 static void __devexit agp_uninorth_remove(struct pci_dev *pdev)
347 struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
349 agp_remove_bridge(bridge);
350 agp_put_bridge(bridge);
353 static struct pci_device_id agp_uninorth_pci_table[] = {
355 .class = (PCI_CLASS_BRIDGE_HOST << 8),
356 .class_mask = ~0,
357 .vendor = PCI_VENDOR_ID_APPLE,
358 .device = PCI_ANY_ID,
359 .subvendor = PCI_ANY_ID,
360 .subdevice = PCI_ANY_ID,
365 MODULE_DEVICE_TABLE(pci, agp_uninorth_pci_table);
367 static struct pci_driver agp_uninorth_pci_driver = {
368 .name = "agpgart-uninorth",
369 .id_table = agp_uninorth_pci_table,
370 .probe = agp_uninorth_probe,
371 .remove = agp_uninorth_remove,
374 static int __init agp_uninorth_init(void)
376 return pci_module_init(&agp_uninorth_pci_driver);
379 static void __exit agp_uninorth_cleanup(void)
381 pci_unregister_driver(&agp_uninorth_pci_driver);
384 module_init(agp_uninorth_init);
385 module_exit(agp_uninorth_cleanup);
387 MODULE_AUTHOR("Ben Herrenschmidt & Paul Mackerras");
388 MODULE_LICENSE("GPL");