1 /* $Id: ffb_drv.c,v 1.16 2001/10/18 16:00:24 davem Exp $
2  * ffb_drv.c: Creator/Creator3D direct rendering driver.
3  *
4  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
5  */
6 
7 #include <linux/config.h>
8 #include "ffb.h"
9 #include "drmP.h"
10 
11 #include "ffb_drv.h"
12 
13 #include <linux/sched.h>
14 #include <linux/smp_lock.h>
15 #include <asm/shmparam.h>
16 #include <asm/oplib.h>
17 #include <asm/upa.h>
18 
19 #define DRIVER_AUTHOR		"David S. Miller"
20 
21 #define DRIVER_NAME		"ffb"
22 #define DRIVER_DESC		"Creator/Creator3D"
23 #define DRIVER_DATE		"20000517"
24 
25 #define DRIVER_MAJOR		0
26 #define DRIVER_MINOR		0
27 #define DRIVER_PATCHLEVEL	1
28 
29 #define DRIVER_FOPS						\
30 static struct file_operations	DRM(fops) = {			\
31 	owner:   		THIS_MODULE,			\
32 	open:	 		DRM(open),			\
33 	flush:	 		DRM(flush),			\
34 	release: 		DRM(release),			\
35 	ioctl:	 		DRM(ioctl),			\
36 	mmap:	 		DRM(mmap),			\
37 	read:	 		DRM(read),			\
38 	fasync:	 		DRM(fasync),			\
39 	poll:	 		DRM(poll),			\
40 	get_unmapped_area:	ffb_get_unmapped_area,		\
41 }
42 
43 #define DRIVER_COUNT_CARDS()	ffb_count_card_instances()
44 /* Allocate private structure and fill it */
45 #define DRIVER_PRESETUP()	do {		\
46 	int _ret;				\
47 	_ret = ffb_presetup(dev);		\
48 	if (_ret != 0) return _ret;		\
49 } while(0)
50 
51 /* Free private structure */
52 #define DRIVER_PRETAKEDOWN()	do {				\
53 	if (dev->dev_private) kfree(dev->dev_private);		\
54 } while(0)
55 
56 #define DRIVER_POSTCLEANUP()	do {				\
57 	if (ffb_position != NULL) kfree(ffb_position);		\
58 } while(0)
59 
60 /* We have to free up the rogue hw context state holding error or
61  * else we will leak it.
62  */
63 #define DRIVER_RELEASE()	do {					\
64 	ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) dev->dev_private;	\
65 	int context = _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock);	\
66 	int idx;							\
67 									\
68 	idx = context - 1;						\
69 	if (fpriv &&							\
70 	    context != DRM_KERNEL_CONTEXT &&				\
71 	    fpriv->hw_state[idx] != NULL) {				\
72 		kfree(fpriv->hw_state[idx]);				\
73 		fpriv->hw_state[idx] = NULL;				\
74 	}								\
75 } while(0)
76 
77 /* For mmap customization */
78 #define DRIVER_GET_MAP_OFS()	(map->offset & 0xffffffff)
79 #define DRIVER_GET_REG_OFS()	ffb_get_reg_offset(dev)
80 
81 typedef struct _ffb_position_t {
82 	int node;
83 	int root;
84 } ffb_position_t;
85 
86 static ffb_position_t *ffb_position;
87 
get_ffb_type(ffb_dev_priv_t * ffb_priv,int instance)88 static void get_ffb_type(ffb_dev_priv_t *ffb_priv, int instance)
89 {
90 	volatile unsigned char *strap_bits;
91 	unsigned char val;
92 
93 	strap_bits = (volatile unsigned char *)
94 		(ffb_priv->card_phys_base + 0x00200000UL);
95 
96 	/* Don't ask, you have to read the value twice for whatever
97 	 * reason to get correct contents.
98 	 */
99 	val = upa_readb(strap_bits);
100 	val = upa_readb(strap_bits);
101 	switch (val & 0x78) {
102 	case (0x0 << 5) | (0x0 << 3):
103 		ffb_priv->ffb_type = ffb1_prototype;
104 		printk("ffb%d: Detected FFB1 pre-FCS prototype\n", instance);
105 		break;
106 	case (0x0 << 5) | (0x1 << 3):
107 		ffb_priv->ffb_type = ffb1_standard;
108 		printk("ffb%d: Detected FFB1\n", instance);
109 		break;
110 	case (0x0 << 5) | (0x3 << 3):
111 		ffb_priv->ffb_type = ffb1_speedsort;
112 		printk("ffb%d: Detected FFB1-SpeedSort\n", instance);
113 		break;
114 	case (0x1 << 5) | (0x0 << 3):
115 		ffb_priv->ffb_type = ffb2_prototype;
116 		printk("ffb%d: Detected FFB2/vertical pre-FCS prototype\n", instance);
117 		break;
118 	case (0x1 << 5) | (0x1 << 3):
119 		ffb_priv->ffb_type = ffb2_vertical;
120 		printk("ffb%d: Detected FFB2/vertical\n", instance);
121 		break;
122 	case (0x1 << 5) | (0x2 << 3):
123 		ffb_priv->ffb_type = ffb2_vertical_plus;
124 		printk("ffb%d: Detected FFB2+/vertical\n", instance);
125 		break;
126 	case (0x2 << 5) | (0x0 << 3):
127 		ffb_priv->ffb_type = ffb2_horizontal;
128 		printk("ffb%d: Detected FFB2/horizontal\n", instance);
129 		break;
130 	case (0x2 << 5) | (0x2 << 3):
131 		ffb_priv->ffb_type = ffb2_horizontal;
132 		printk("ffb%d: Detected FFB2+/horizontal\n", instance);
133 		break;
134 	default:
135 		ffb_priv->ffb_type = ffb2_vertical;
136 		printk("ffb%d: Unknown boardID[%08x], assuming FFB2\n", instance, val);
137 		break;
138 	};
139 }
140 
ffb_apply_upa_parent_ranges(int parent,struct linux_prom64_registers * regs)141 static void ffb_apply_upa_parent_ranges(int parent,
142 					struct linux_prom64_registers *regs)
143 {
144 	struct linux_prom64_ranges ranges[PROMREG_MAX];
145 	char name[128];
146 	int len, i;
147 
148 	prom_getproperty(parent, "name", name, sizeof(name));
149 	if (strcmp(name, "upa") != 0)
150 		return;
151 
152 	len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges));
153 	if (len <= 0)
154 		return;
155 
156 	len /= sizeof(struct linux_prom64_ranges);
157 	for (i = 0; i < len; i++) {
158 		struct linux_prom64_ranges *rng = &ranges[i];
159 		u64 phys_addr = regs->phys_addr;
160 
161 		if (phys_addr >= rng->ot_child_base &&
162 		    phys_addr < (rng->ot_child_base + rng->or_size)) {
163 			regs->phys_addr -= rng->ot_child_base;
164 			regs->phys_addr += rng->ot_parent_base;
165 			return;
166 		}
167 	}
168 
169 	return;
170 }
171 
ffb_init_one(drm_device_t * dev,int prom_node,int parent_node,int instance)172 static int ffb_init_one(drm_device_t *dev, int prom_node, int parent_node,
173 			int instance)
174 {
175 	struct linux_prom64_registers regs[2*PROMREG_MAX];
176 	ffb_dev_priv_t *ffb_priv = (ffb_dev_priv_t *)dev->dev_private;
177 	int i;
178 
179 	ffb_priv->prom_node = prom_node;
180 	if (prom_getproperty(ffb_priv->prom_node, "reg",
181 			     (void *)regs, sizeof(regs)) <= 0) {
182 		return -EINVAL;
183 	}
184 	ffb_apply_upa_parent_ranges(parent_node, &regs[0]);
185 	ffb_priv->card_phys_base = regs[0].phys_addr;
186 	ffb_priv->regs = (ffb_fbcPtr)
187 		(regs[0].phys_addr + 0x00600000UL);
188 	get_ffb_type(ffb_priv, instance);
189 	for (i = 0; i < FFB_MAX_CTXS; i++)
190 		ffb_priv->hw_state[i] = NULL;
191 
192 	return 0;
193 }
194 
ffb_count_siblings(int root)195 static int __init ffb_count_siblings(int root)
196 {
197 	int node, child, count = 0;
198 
199 	child = prom_getchild(root);
200 	for (node = prom_searchsiblings(child, "SUNW,ffb"); node;
201 	     node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb"))
202 		count++;
203 
204 	return count;
205 }
206 
ffb_scan_siblings(int root,int instance)207 static int __init ffb_scan_siblings(int root, int instance)
208 {
209 	int node, child;
210 
211 	child = prom_getchild(root);
212 	for (node = prom_searchsiblings(child, "SUNW,ffb"); node;
213 	     node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) {
214 		ffb_position[instance].node = node;
215 		ffb_position[instance].root = root;
216 		instance++;
217 	}
218 
219 	return instance;
220 }
221 
222 static int ffb_presetup(drm_device_t *);
223 
ffb_count_card_instances(void)224 static int __init ffb_count_card_instances(void)
225 {
226 	int root, total, instance;
227 
228 	total = ffb_count_siblings(prom_root_node);
229 	root = prom_getchild(prom_root_node);
230 	for (root = prom_searchsiblings(root, "upa"); root;
231 	     root = prom_searchsiblings(prom_getsibling(root), "upa"))
232 		total += ffb_count_siblings(root);
233 
234 	ffb_position = kmalloc(sizeof(ffb_position_t) * total, GFP_KERNEL);
235 
236 	/* Actual failure will be caught during ffb_presetup b/c we can't catch
237 	 * it easily here.
238 	 */
239 	if (!ffb_position)
240 		return -ENOMEM;
241 
242 	instance = ffb_scan_siblings(prom_root_node, 0);
243 
244 	root = prom_getchild(prom_root_node);
245 	for (root = prom_searchsiblings(root, "upa"); root;
246 	     root = prom_searchsiblings(prom_getsibling(root), "upa"))
247 		instance = ffb_scan_siblings(root, instance);
248 
249 	return total;
250 }
251 
ffb_find_map(struct file * filp,unsigned long off)252 static drm_map_t *ffb_find_map(struct file *filp, unsigned long off)
253 {
254 	drm_file_t	*priv	= filp->private_data;
255 	drm_device_t	*dev;
256 	drm_map_list_t  *r_list;
257 	struct list_head *list;
258 	drm_map_t	*map;
259 
260 	if (!priv || (dev = priv->dev) == NULL)
261 		return NULL;
262 
263 	list_for_each(list, &dev->maplist->head) {
264 		unsigned long uoff;
265 
266 		r_list = (drm_map_list_t *)list;
267 		map = r_list->map;
268 		if (!map)
269 			continue;
270 		uoff = (map->offset & 0xffffffff);
271 		if (uoff == off)
272 			return map;
273 	}
274 
275 	return NULL;
276 }
277 
ffb_get_unmapped_area(struct file * filp,unsigned long hint,unsigned long len,unsigned long pgoff,unsigned long flags)278 static unsigned long ffb_get_unmapped_area(struct file *filp,
279 					   unsigned long hint,
280 					   unsigned long len,
281 					   unsigned long pgoff,
282 					   unsigned long flags)
283 {
284 	drm_map_t *map = ffb_find_map(filp, pgoff << PAGE_SHIFT);
285 	unsigned long addr = -ENOMEM;
286 
287 	if (!map)
288 		return get_unmapped_area(NULL, hint, len, pgoff, flags);
289 
290 	if (map->type == _DRM_FRAME_BUFFER ||
291 	    map->type == _DRM_REGISTERS) {
292 #ifdef HAVE_ARCH_FB_UNMAPPED_AREA
293 		addr = get_fb_unmapped_area(filp, hint, len, pgoff, flags);
294 #else
295 		addr = get_unmapped_area(NULL, hint, len, pgoff, flags);
296 #endif
297 	} else if (map->type == _DRM_SHM && SHMLBA > PAGE_SIZE) {
298 		unsigned long slack = SHMLBA - PAGE_SIZE;
299 
300 		addr = get_unmapped_area(NULL, hint, len + slack, pgoff, flags);
301 		if (!(addr & ~PAGE_MASK)) {
302 			unsigned long kvirt = (unsigned long) map->handle;
303 
304 			if ((kvirt & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) {
305 				unsigned long koff, aoff;
306 
307 				koff = kvirt & (SHMLBA - 1);
308 				aoff = addr & (SHMLBA - 1);
309 				if (koff < aoff)
310 					koff += SHMLBA;
311 
312 				addr += (koff - aoff);
313 			}
314 		}
315 	} else {
316 		addr = get_unmapped_area(NULL, hint, len, pgoff, flags);
317 	}
318 
319 	return addr;
320 }
321 
ffb_get_reg_offset(drm_device_t * dev)322 static unsigned long ffb_get_reg_offset(drm_device_t *dev)
323 {
324 	ffb_dev_priv_t *ffb_priv = (ffb_dev_priv_t *)dev->dev_private;
325 
326 	if (ffb_priv)
327 		return ffb_priv->card_phys_base;
328 
329 	return 0;
330 }
331 
332 #include "drm_auth.h"
333 #include "drm_bufs.h"
334 #include "drm_dma.h"
335 #include "drm_drawable.h"
336 #include "drm_drv.h"
337 
338 /* This functions must be here since it references DRM(numdevs)
339  * which drm_drv.h declares.
340  */
ffb_presetup(drm_device_t * dev)341 static int ffb_presetup(drm_device_t *dev)
342 {
343 	ffb_dev_priv_t	*ffb_priv;
344 	drm_device_t *temp_dev;
345 	int ret = 0;
346 	int i;
347 
348 	/* Check for the case where no device was found. */
349 	if (ffb_position == NULL)
350 		return -ENODEV;
351 
352 	/* Find our instance number by finding our device in dev structure */
353 	for (i = 0; i < DRM(numdevs); i++) {
354 		temp_dev = &(DRM(device)[i]);
355 		if(temp_dev == dev)
356 			break;
357 	}
358 
359 	if (i == DRM(numdevs))
360 		return -ENODEV;
361 
362 	ffb_priv = kmalloc(sizeof(ffb_dev_priv_t), GFP_KERNEL);
363 	if (!ffb_priv)
364 		return -ENOMEM;
365 	memset(ffb_priv, 0, sizeof(*ffb_priv));
366 	dev->dev_private = ffb_priv;
367 
368 	ret = ffb_init_one(dev,
369 			   ffb_position[i].node,
370 			   ffb_position[i].root,
371 			   i);
372 	return ret;
373 }
374 
375 #include "drm_fops.h"
376 #include "drm_init.h"
377 #include "drm_ioctl.h"
378 #include "drm_lock.h"
379 #include "drm_memory.h"
380 #include "drm_proc.h"
381 #include "drm_vm.h"
382 #include "drm_stub.h"
383