1/*
2 * HP Quicksilver AGP GART routines
3 *
4 * Copyright (c) 2006, Kyle McMartin <kyle@parisc-linux.org>
5 *
6 * Based on drivers/char/agpgart/hp-agp.c which is
7 * (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P.
8 *	Bjorn Helgaas <bjorn.helgaas@hp.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/pci.h>
18#include <linux/init.h>
19#include <linux/klist.h>
20#include <linux/agp_backend.h>
21
22#include <asm-parisc/parisc-device.h>
23#include <asm-parisc/ropes.h>
24
25#include "agp.h"
26
27#define DRVNAME	"quicksilver"
28#define DRVPFX	DRVNAME ": "
29
30#ifndef log2
31#define log2(x)		ffz(~(x))
32#endif
33
34#define AGP8X_MODE_BIT		3
35#define AGP8X_MODE		(1 << AGP8X_MODE_BIT)
36
37static struct _parisc_agp_info {
38	void __iomem *ioc_regs;
39	void __iomem *lba_regs;
40
41	int lba_cap_offset;
42
43	u64 *gatt;
44	u64 gatt_entries;
45
46	u64 gart_base;
47	u64 gart_size;
48
49	int io_page_size;
50	int io_pages_per_kpage;
51} parisc_agp_info;
52
53static struct gatt_mask parisc_agp_masks[] =
54{
55        {
56		.mask = SBA_PDIR_VALID_BIT,
57		.type = 0
58	}
59};
60
61static struct aper_size_info_fixed parisc_agp_sizes[] =
62{
63        {0, 0, 0},              /* filled in by parisc_agp_fetch_size() */
64};
65
66static int
67parisc_agp_fetch_size(void)
68{
69	int size;
70
71	size = parisc_agp_info.gart_size / MB(1);
72	parisc_agp_sizes[0].size = size;
73	agp_bridge->current_size = (void *) &parisc_agp_sizes[0];
74
75	return size;
76}
77
78static int
79parisc_agp_configure(void)
80{
81	struct _parisc_agp_info *info = &parisc_agp_info;
82
83	agp_bridge->gart_bus_addr = info->gart_base;
84	agp_bridge->capndx = info->lba_cap_offset;
85	agp_bridge->mode = readl(info->lba_regs+info->lba_cap_offset+PCI_AGP_STATUS);
86
87	return 0;
88}
89
90static void
91parisc_agp_tlbflush(struct agp_memory *mem)
92{
93	struct _parisc_agp_info *info = &parisc_agp_info;
94
95	writeq(info->gart_base | log2(info->gart_size), info->ioc_regs+IOC_PCOM);
96	readq(info->ioc_regs+IOC_PCOM);	/* flush */
97}
98
99static int
100parisc_agp_create_gatt_table(struct agp_bridge_data *bridge)
101{
102	struct _parisc_agp_info *info = &parisc_agp_info;
103	int i;
104
105	for (i = 0; i < info->gatt_entries; i++) {
106		info->gatt[i] = (unsigned long)agp_bridge->scratch_page;
107	}
108
109	return 0;
110}
111
112static int
113parisc_agp_free_gatt_table(struct agp_bridge_data *bridge)
114{
115	struct _parisc_agp_info *info = &parisc_agp_info;
116
117	info->gatt[0] = SBA_AGPGART_COOKIE;
118
119	return 0;
120}
121
122static int
123parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
124{
125	struct _parisc_agp_info *info = &parisc_agp_info;
126	int i, k;
127	off_t j, io_pg_start;
128	int io_pg_count;
129
130	if (type != 0 || mem->type != 0) {
131		return -EINVAL;
132	}
133
134	io_pg_start = info->io_pages_per_kpage * pg_start;
135	io_pg_count = info->io_pages_per_kpage * mem->page_count;
136	if ((io_pg_start + io_pg_count) > info->gatt_entries) {
137		return -EINVAL;
138	}
139
140	j = io_pg_start;
141	while (j < (io_pg_start + io_pg_count)) {
142		if (info->gatt[j])
143			return -EBUSY;
144		j++;
145	}
146
147	if (mem->is_flushed == FALSE) {
148		global_cache_flush();
149		mem->is_flushed = TRUE;
150	}
151
152	for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
153		unsigned long paddr;
154
155		paddr = mem->memory[i];
156		for (k = 0;
157		     k < info->io_pages_per_kpage;
158		     k++, j++, paddr += info->io_page_size) {
159			info->gatt[j] =
160				agp_bridge->driver->mask_memory(agp_bridge,
161					paddr, type);
162		}
163	}
164
165	agp_bridge->driver->tlb_flush(mem);
166
167	return 0;
168}
169
170static int
171parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
172{
173	struct _parisc_agp_info *info = &parisc_agp_info;
174	int i, io_pg_start, io_pg_count;
175
176	if (type != 0 || mem->type != 0) {
177		return -EINVAL;
178	}
179
180	io_pg_start = info->io_pages_per_kpage * pg_start;
181	io_pg_count = info->io_pages_per_kpage * mem->page_count;
182	for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
183		info->gatt[i] = agp_bridge->scratch_page;
184	}
185
186	agp_bridge->driver->tlb_flush(mem);
187	return 0;
188}
189
190static unsigned long
191parisc_agp_mask_memory(struct agp_bridge_data *bridge,
192		    unsigned long addr, int type)
193{
194	return SBA_PDIR_VALID_BIT | addr;
195}
196
197static void
198parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode)
199{
200	struct _parisc_agp_info *info = &parisc_agp_info;
201	u32 command;
202
203	command = readl(info->lba_regs + info->lba_cap_offset + PCI_AGP_STATUS);
204
205	command = agp_collect_device_status(bridge, mode, command);
206	command |= 0x00000100;
207
208	writel(command, info->lba_regs + info->lba_cap_offset + PCI_AGP_COMMAND);
209
210	agp_device_command(command, (mode & AGP8X_MODE) != 0);
211}
212
213static const struct agp_bridge_driver parisc_agp_driver = {
214	.owner			= THIS_MODULE,
215	.size_type		= FIXED_APER_SIZE,
216	.configure		= parisc_agp_configure,
217	.fetch_size		= parisc_agp_fetch_size,
218	.tlb_flush		= parisc_agp_tlbflush,
219	.mask_memory		= parisc_agp_mask_memory,
220	.masks			= parisc_agp_masks,
221	.agp_enable		= parisc_agp_enable,
222	.cache_flush		= global_cache_flush,
223	.create_gatt_table	= parisc_agp_create_gatt_table,
224	.free_gatt_table	= parisc_agp_free_gatt_table,
225	.insert_memory		= parisc_agp_insert_memory,
226	.remove_memory		= parisc_agp_remove_memory,
227	.alloc_by_type		= agp_generic_alloc_by_type,
228	.free_by_type		= agp_generic_free_by_type,
229	.agp_alloc_page		= agp_generic_alloc_page,
230	.agp_destroy_page	= agp_generic_destroy_page,
231	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
232	.cant_use_aperture	= 1,
233};
234
235static int __init
236agp_ioc_init(void __iomem *ioc_regs)
237{
238	struct _parisc_agp_info *info = &parisc_agp_info;
239        u64 iova_base, *io_pdir, io_tlb_ps;
240        int io_tlb_shift;
241
242        printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n");
243
244        info->ioc_regs = ioc_regs;
245
246        io_tlb_ps = readq(info->ioc_regs+IOC_TCNFG);
247        switch (io_tlb_ps) {
248        case 0: io_tlb_shift = 12; break;
249        case 1: io_tlb_shift = 13; break;
250        case 2: io_tlb_shift = 14; break;
251        case 3: io_tlb_shift = 16; break;
252        default:
253                printk(KERN_ERR DRVPFX "Invalid IOTLB page size "
254                       "configuration 0x%llx\n", io_tlb_ps);
255                info->gatt = NULL;
256                info->gatt_entries = 0;
257                return -ENODEV;
258        }
259        info->io_page_size = 1 << io_tlb_shift;
260        info->io_pages_per_kpage = PAGE_SIZE / info->io_page_size;
261
262        iova_base = readq(info->ioc_regs+IOC_IBASE) & ~0x1;
263        info->gart_base = iova_base + PLUTO_IOVA_SIZE - PLUTO_GART_SIZE;
264
265        info->gart_size = PLUTO_GART_SIZE;
266        info->gatt_entries = info->gart_size / info->io_page_size;
267
268        io_pdir = phys_to_virt(readq(info->ioc_regs+IOC_PDIR_BASE));
269        info->gatt = &io_pdir[(PLUTO_IOVA_SIZE/2) >> PAGE_SHIFT];
270
271        if (info->gatt[0] != SBA_AGPGART_COOKIE) {
272                info->gatt = NULL;
273                info->gatt_entries = 0;
274                printk(KERN_ERR DRVPFX "No reserved IO PDIR entry found; "
275                       "GART disabled\n");
276                return -ENODEV;
277        }
278
279        return 0;
280}
281
282static int
283lba_find_capability(int cap)
284{
285	struct _parisc_agp_info *info = &parisc_agp_info;
286        u16 status;
287        u8 pos, id;
288        int ttl = 48;
289
290        status = readw(info->lba_regs + PCI_STATUS);
291        if (!(status & PCI_STATUS_CAP_LIST))
292                return 0;
293        pos = readb(info->lba_regs + PCI_CAPABILITY_LIST);
294        while (ttl-- && pos >= 0x40) {
295                pos &= ~3;
296                id = readb(info->lba_regs + pos + PCI_CAP_LIST_ID);
297                if (id == 0xff)
298                        break;
299                if (id == cap)
300                        return pos;
301                pos = readb(info->lba_regs + pos + PCI_CAP_LIST_NEXT);
302        }
303        return 0;
304}
305
306static int __init
307agp_lba_init(void __iomem *lba_hpa)
308{
309	struct _parisc_agp_info *info = &parisc_agp_info;
310        int cap;
311
312	info->lba_regs = lba_hpa;
313        info->lba_cap_offset = lba_find_capability(PCI_CAP_ID_AGP);
314
315        cap = readl(lba_hpa + info->lba_cap_offset) & 0xff;
316        if (cap != PCI_CAP_ID_AGP) {
317                printk(KERN_ERR DRVPFX "Invalid capability ID 0x%02x at 0x%x\n",
318                       cap, info->lba_cap_offset);
319                return -ENODEV;
320        }
321
322        return 0;
323}
324
325static int __init
326parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
327{
328	struct pci_dev *fake_bridge_dev = NULL;
329	struct agp_bridge_data *bridge;
330	int error = 0;
331
332	fake_bridge_dev = alloc_pci_dev();
333	if (!fake_bridge_dev) {
334		error = -ENOMEM;
335		goto fail;
336	}
337
338	error = agp_ioc_init(ioc_hpa);
339	if (error)
340		goto fail;
341
342	error = agp_lba_init(lba_hpa);
343	if (error)
344		goto fail;
345
346	bridge = agp_alloc_bridge();
347	if (!bridge) {
348		error = -ENOMEM;
349		goto fail;
350	}
351	bridge->driver = &parisc_agp_driver;
352
353	fake_bridge_dev->vendor = PCI_VENDOR_ID_HP;
354	fake_bridge_dev->device = PCI_DEVICE_ID_HP_PCIX_LBA;
355	bridge->dev = fake_bridge_dev;
356
357	error = agp_add_bridge(bridge);
358
359fail:
360	return error;
361}
362
363static struct device *next_device(struct klist_iter *i) {
364	struct klist_node * n = klist_next(i);
365	return n ? container_of(n, struct device, knode_parent) : NULL;
366}
367
368static int
369parisc_agp_init(void)
370{
371	extern struct sba_device *sba_list;
372
373	int err = -1;
374	struct parisc_device *sba = NULL, *lba = NULL;
375	struct lba_device *lbadev = NULL;
376	struct device *dev = NULL;
377	struct klist_iter i;
378
379	if (!sba_list)
380		goto out;
381
382	/* Find our parent Pluto */
383	sba = sba_list->dev;
384	if (!IS_PLUTO(sba)) {
385		printk(KERN_INFO DRVPFX "No Pluto found, so no AGPGART for you.\n");
386		goto out;
387	}
388
389	/* Now search our Pluto for our precious AGP device... */
390	klist_iter_init(&sba->dev.klist_children, &i);
391	while ((dev = next_device(&i))) {
392		struct parisc_device *padev = to_parisc_device(dev);
393		if (IS_QUICKSILVER(padev))
394			lba = padev;
395	}
396	klist_iter_exit(&i);
397
398	if (!lba) {
399		printk(KERN_INFO DRVPFX "No AGP devices found.\n");
400		goto out;
401	}
402
403	lbadev = parisc_get_drvdata(lba);
404
405	/* w00t, let's go find our cookies... */
406	parisc_agp_setup(sba_list->ioc[0].ioc_hpa, lbadev->hba.base_addr);
407
408	return 0;
409
410out:
411	return err;
412}
413
414module_init(parisc_agp_init);
415
416MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>");
417MODULE_LICENSE("GPL");
418