1/*
2 * Copyright 1992 by Rich Murphey <Rich@Rice.edu>
3 * Copyright 1993 by David Wexelblat <dwex@goblin.org>
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the names of Rich Murphey and David Wexelblat
10 * not be used in advertising or publicity pertaining to distribution of
11 * the software without specific, written prior permission.  Rich Murphey and
12 * David Wexelblat make no representations about the suitability of this
13 * software for any purpose.  It is provided "as is" without express or
14 * implied warranty.
15 *
16 * RICH MURPHEY AND DAVID WEXELBLAT DISCLAIM ALL WARRANTIES WITH REGARD TO
17 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL RICH MURPHEY OR DAVID WEXELBLAT BE LIABLE FOR
19 * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
20 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
21 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 *
24 */
25
26/*
27 * The ARM32 code here carries the following copyright:
28 *
29 * Copyright 1997
30 * Digital Equipment Corporation. All rights reserved.
31 * This software is furnished under license and may be used and copied only in
32 * accordance with the following terms and conditions.  Subject to these
33 * conditions, you may download, copy, install, use, modify and distribute
34 * this software in source and/or binary form. No title or ownership is
35 * transferred hereby.
36 *
37 * 1) Any source code used, modified or distributed must reproduce and retain
38 *    this copyright notice and list of conditions as they appear in the
39 *    source file.
40 *
41 * 2) No right is granted to use any trade name, trademark, or logo of Digital
42 *    Equipment Corporation. Neither the "Digital Equipment Corporation"
43 *    name nor any trademark or logo of Digital Equipment Corporation may be
44 *    used to endorse or promote products derived from this software without
45 *    the prior written permission of Digital Equipment Corporation.
46 *
47 * 3) This software is provided "AS-IS" and any express or implied warranties,
48 *    including but not limited to, any implied warranties of merchantability,
49 *    fitness for a particular purpose, or non-infringement are disclaimed.
50 *    In no event shall DIGITAL be liable for any damages whatsoever, and in
51 *    particular, DIGITAL shall not be liable for special, indirect,
52 *    consequential, or incidental damages or damages for lost profits, loss
53 *    of revenue or loss of use, whether such damages arise in contract,
54 *    negligence, tort, under statute, in equity, at law or otherwise, even
55 *    if advised of the possibility of such damage.
56 *
57 */
58
59#ifdef HAVE_XORG_CONFIG_H
60#include <xorg-config.h>
61#endif
62
63#include <X11/X.h>
64#include "xf86.h"
65#include "xf86Priv.h"
66#include "xf86_OSlib.h"
67#include "xf86OSpriv.h"
68
69#ifdef __arm32__
70#include "machine/devmap.h"
71struct memAccess
72{
73    int ioctl;
74    struct map_info memInfo;
75    pointer regionVirtBase;
76    Bool Checked;
77    Bool OK;
78};
79
80static pointer xf86MapInfoMap();
81static void xf86MapInfoUnmap();
82static struct memAccess *checkMapInfo();
83extern int vgaPhysLinearBase;
84
85/* A memAccess structure is needed for each possible region */
86struct memAccess vgaMemInfo = { CONSOLE_GET_MEM_INFO, NULL, NULL,
87				    FALSE, FALSE };
88struct memAccess linearMemInfo = { CONSOLE_GET_LINEAR_INFO, NULL, NULL,
89				       FALSE, FALSE };
90struct memAccess ioMemInfo = { CONSOLE_GET_IO_INFO, NULL, NULL,
91				   FALSE, FALSE };
92#endif /* __arm32__ */
93
94#if defined(__NetBSD__) && !defined(MAP_FILE)
95#define MAP_FLAGS MAP_SHARED
96#else
97#define MAP_FLAGS (MAP_FILE | MAP_SHARED)
98#endif
99
100#ifndef MAP_FAILED
101#define MAP_FAILED ((caddr_t)-1)
102#endif
103
104
105#define BUS_BASE	0L
106#define BUS_BASE_BWX	0L
107
108
109/***************************************************************************/
110/* Video Memory Mapping section                                            */
111/***************************************************************************/
112
113static Bool useDevMem = FALSE;
114static int  devMemFd = -1;
115
116#define DEV_MEM "/dev/mem"
117
118static pointer mapVidMem(int, unsigned long, unsigned long, int);
119static void unmapVidMem(int, pointer, unsigned long);
120
121/*
122 * Check if /dev/mem can be mmap'd.  If it can't print a warning when
123 * "warn" is TRUE.
124 */
125static void
126checkDevMem(Bool warn)
127{
128	static Bool devMemChecked = FALSE;
129	int fd;
130	pointer base;
131
132	if (devMemChecked)
133	    return;
134	devMemChecked = TRUE;
135
136	if ((fd = open(DEV_MEM, O_RDWR)) >= 0)
137	{
138	    /* Try to map a page at the VGA address */
139	    base = mmap((caddr_t)0, 4096, PROT_READ | PROT_WRITE,
140				 MAP_FLAGS, fd, (off_t)0xA0000 + BUS_BASE);
141
142	    if (base != MAP_FAILED)
143	    {
144		munmap((caddr_t)base, 4096);
145		devMemFd = fd;
146		useDevMem = TRUE;
147		return;
148	    } else {
149		/* This should not happen */
150		if (warn)
151		{
152		    xf86Msg(X_WARNING, "checkDevMem: failed to mmap %s (%s)\n",
153			    DEV_MEM, strerror(errno));
154		}
155		useDevMem = FALSE;
156		return;
157	    }
158	}
159	if (warn)
160	{
161	    xf86Msg(X_WARNING, "checkDevMem: failed to open %s (%s)\n",
162		    DEV_MEM, strerror(errno));
163	}
164	useDevMem = FALSE;
165	return;
166}
167
168void
169xf86OSInitVidMem(VidMemInfoPtr pVidMem)
170{
171
172	checkDevMem(TRUE);
173	pVidMem->linearSupported = useDevMem;
174	pVidMem->mapMem = armMapVidMem;
175	pVidMem->unmapVidMem = armUnmapVidMem;
176
177	pVidMem->initialised = TRUE;
178}
179
180static pointer
181mapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags)
182{
183	pointer base;
184
185	checkDevMem(FALSE);
186
187	if (useDevMem)
188	{
189	    if (devMemFd < 0)
190	    {
191		FatalError("xf86MapVidMem: failed to open %s (%s)\n",
192			   DEV_MEM, strerror(errno));
193	    }
194	    base = mmap((caddr_t)0, Size,
195			(flags & VIDMEM_READONLY) ?
196			 PROT_READ : (PROT_READ | PROT_WRITE),
197			MAP_FLAGS, devMemFd, (off_t)Base + BUS_BASE_BWX);
198	    if (base == MAP_FAILED)
199	    {
200		FatalError("%s: could not mmap %s [s=%x,a=%x] (%s)\n",
201			   "xf86MapVidMem", DEV_MEM, Size, Base,
202			   strerror(errno));
203	    }
204	    return base;
205	}
206
207	/* else, mmap /dev/vga */
208	if ((unsigned long)Base < 0xA0000 || (unsigned long)Base >= 0xC0000)
209	{
210		FatalError("%s: Address 0x%x outside allowable range\n",
211			   "xf86MapVidMem", Base);
212	}
213	base = mmap(0, Size,
214		    (flags & VIDMEM_READONLY) ?
215		     PROT_READ : (PROT_READ | PROT_WRITE),
216		    MAP_FLAGS, xf86Info.screenFd,
217		    (unsigned long)Base - 0xA0000);
218	if (base == MAP_FAILED)
219	{
220	    FatalError("xf86MapVidMem: Could not mmap /dev/vga (%s)\n",
221		       strerror(errno));
222	}
223	return base;
224}
225
226static void
227unmapVidMem(int ScreenNum, pointer Base, unsigned long Size)
228{
229	munmap((caddr_t)Base, Size);
230}
231
232/*
233 * Read BIOS via mmap()ing DEV_MEM
234 */
235
236int
237xf86ReadBIOS(unsigned long Base, unsigned long Offset, unsigned char *Buf,
238	     int Len)
239{
240	unsigned char *ptr;
241	int psize;
242	int mlen;
243
244	checkDevMem(TRUE);
245	if (devMemFd == -1) {
246	    return -1;
247	}
248
249	psize = getpagesize();
250	Offset += Base & (psize - 1);
251	Base &= ~(psize - 1);
252	mlen = (Offset + Len + psize - 1) & ~(psize - 1);
253	ptr = (unsigned char *)mmap((caddr_t)0, mlen, PROT_READ,
254					MAP_SHARED, devMemFd, (off_t)Base+BUS_BASE);
255	if ((long)ptr == -1)
256	{
257		xf86Msg(X_WARNING,
258			"xf86ReadBIOS: %s mmap[s=%x,a=%x,o=%x] failed (%s)\n",
259			DEV_MEM, Len, Base, Offset, strerror(errno));
260		return -1;
261	}
262#ifdef DEBUG
263	ErrorF("xf86ReadBIOS: BIOS at 0x%08x has signature 0x%04x\n",
264		Base, ptr[0] | (ptr[1] << 8));
265#endif
266	(void)memcpy(Buf, (void *)(ptr + Offset), Len);
267	(void)munmap((caddr_t)ptr, mlen);
268#ifdef DEBUG
269	xf86MsgVerb(X_INFO, 3, "xf86ReadBIOS(%x, %x, Buf, %x)"
270		"-> %02x %02x %02x %02x...\n",
271		Base, Offset, Len, Buf[0], Buf[1], Buf[2], Buf[3]);
272#endif
273	return Len;
274}
275
276
277/* XXX This needs to be updated for the ND */
278
279/*
280** Find out whether the console driver provides memory mapping information
281** for the specified region and return the map_info pointer. Print a warning if required.
282*/
283static struct memAccess *
284checkMapInfo(Bool warn, int Region)
285{
286    struct memAccess *memAccP;
287
288    switch (Region)
289    {
290	case VGA_REGION:
291	    memAccP = &vgaMemInfo;
292	    break;
293
294	case LINEAR_REGION:
295	    memAccP = &linearMemInfo;
296	    break;
297
298	case MMIO_REGION:
299	    memAccP = &ioMemInfo;
300	    break;
301
302	default:
303	    return NULL;
304	    break;
305    }
306
307    if(!memAccP->Checked)
308    {
309	if(ioctl(xf86Info.screenFd, memAccP->ioctl, &(memAccP->memInfo)) == -1)
310	{
311	    if(warn)
312	    {
313		xf86Msg(X_WARNING,
314		 "checkMapInfo: failed to get map info for region %d\n\t(%s)\n",
315		       Region, strerror(errno));
316	    }
317	}
318	else
319	{
320	    if(memAccP->memInfo.u.map_info_mmap.map_offset
321	       != MAP_INFO_UNKNOWN)
322		memAccP->OK = TRUE;
323	}
324	memAccP->Checked = TRUE;
325    }
326    if (memAccP->OK)
327    {
328	return memAccP;
329    }
330    else
331    {
332	return NULL;
333    }
334}
335
336static pointer
337xf86MapInfoMap(struct memAccess *memInfoP, pointer Base, unsigned long Size)
338{
339    struct map_info *mapInfoP = &(memInfoP->memInfo);
340
341    if (mapInfoP->u.map_info_mmap.map_size == MAP_INFO_UNKNOWN)
342    {
343	Size = (unsigned long)Base + Size;
344    }
345    else
346    {
347	Size = mapInfoP->u.map_info_mmap.map_size;
348    }
349
350    switch(mapInfoP->method)
351    {
352	case MAP_MMAP:
353	    /* Need to remap if size is unknown because we may not have
354	       mapped the whole region initially */
355	    if(memInfoP->regionVirtBase == NULL ||
356	       mapInfoP->u.map_info_mmap.map_size == MAP_INFO_UNKNOWN)
357	    {
358		if((memInfoP->regionVirtBase =
359		    mmap((caddr_t)0,
360			 Size,
361			 PROT_READ | PROT_WRITE,
362			 MAP_SHARED,
363			 xf86Info.screenFd,
364			 (unsigned long)mapInfoP->u.map_info_mmap.map_offset))
365		   == (pointer)-1)
366		{
367		    FatalError("xf86MapInfoMap: Failed to map memory at 0x%x\n\t%s\n",
368			       mapInfoP->u.map_info_mmap.map_offset, strerror(errno));
369		}
370		if(mapInfoP->u.map_info_mmap.internal_offset > 0)
371		    memInfoP->regionVirtBase +=
372			mapInfoP->u.map_info_mmap.internal_offset;
373	    }
374	    break;
375
376	default:
377	    FatalError("xf86MapInfoMap: Unsuported mapping method\n");
378	    break;
379    }
380
381    return (pointer)((int)memInfoP->regionVirtBase + (int)Base);
382}
383
384static void
385xf86MapInfoUnmap(struct memAccess *memInfoP, unsigned long Size)
386{
387    struct map_info *mapInfoP = &(memInfoP->memInfo);
388
389    switch(mapInfoP->method)
390    {
391	case MAP_MMAP:
392	    if(memInfoP->regionVirtBase != NULL)
393	    {
394		if(mapInfoP->u.map_info_mmap.map_size != MAP_INFO_UNKNOWN)
395		    Size = mapInfoP->u.map_info_mmap.map_size;
396		munmap((caddr_t)memInfoP->regionVirtBase, Size);
397		memInfoP->regionVirtBase = NULL;
398	    }
399	    break;
400	 default:
401	    FatalError("xf86MapInfoMap: Unsuported mapping method\n");
402	    break;
403    }
404}
405
406static pointer
407armMapVidMem(int ScreenNum, unsigned long Base, unsigned long Size, int flags)
408{
409	struct memAccess *memInfoP;
410
411	if((memInfoP = checkMapInfo(FALSE, Region)) != NULL)
412	{
413	    /*
414	     ** xf86 passes in a physical address offset from the start
415	     ** of physical memory, but xf86MapInfoMap expects an
416	     ** offset from the start of the specified region - it gets
417	     ** the physical address of the region from the display driver.
418	     */
419	    switch(Region)
420	    {
421	        case LINEAR_REGION:
422		    if (vgaPhysLinearBase)
423		    {
424			Base -= vgaPhysLinearBase;
425		    }
426		    break;
427		case VGA_REGION:
428		    Base -= 0xA0000;
429		    break;
430	    }
431
432	    base = xf86MapInfoMap(memInfoP, Base, Size);
433	    return base;
434	}
435	return mapVidMem(ScreenNum, Base, Size, flags);
436}
437
438static void
439armUnmapVidMem(int ScreenNum, pointer Base, unsigned long Size)
440{
441        struct memAccess *memInfoP;
442
443	if((memInfoP = checkMapInfo(FALSE, Region)) != NULL)
444	{
445	    xf86MapInfoUnmap(memInfoP, Base, Size);
446	}
447	unmapVidMem(ScreenNum, Base, Size);
448}
449
450#ifdef USE_DEV_IO
451static int IoFd = -1;
452
453Bool
454xf86EnableIO()
455{
456	if (IoFd >= 0)
457		return TRUE;
458
459	if ((IoFd = open("/dev/io", O_RDWR)) == -1)
460	{
461		xf86Msg(X_WARNING,"xf86EnableIO: "
462				"Failed to open /dev/io for extended I/O\n");
463		return FALSE;
464	}
465	return TRUE;
466}
467
468void
469xf86DisableIO()
470{
471	if (IoFd < 0)
472		return;
473
474	close(IoFd);
475	IoFd = -1;
476	return;
477}
478
479#endif
480
481#if defined(USE_ARC_MMAP) || defined(__arm32__)
482
483Bool
484xf86EnableIO()
485{
486	int fd;
487	pointer base;
488
489	if (ExtendedEnabled)
490		return TRUE;
491
492	if ((fd = open("/dev/ttyC0", O_RDWR)) >= 0) {
493		/* Try to map a page at the pccons I/O space */
494		base = (pointer)mmap((caddr_t)0, 65536, PROT_READ | PROT_WRITE,
495				MAP_FLAGS, fd, (off_t)0x0000);
496
497		if (base != (pointer)-1) {
498			IOPortBase = base;
499		}
500		else {
501			xf86Msg(X_WARNING,"EnableIO: failed to mmap %s (%s)\n",
502				"/dev/ttyC0", strerror(errno));
503			return FALSE;
504		}
505	}
506	else {
507		xf86Msg("EnableIO: failed to open %s (%s)\n",
508			"/dev/ttyC0", strerror(errno));
509		return FALSE;
510	}
511
512	ExtendedEnabled = TRUE;
513
514	return TRUE;
515}
516
517void
518xf86DisableIO()
519{
520	return;
521}
522
523#endif /* USE_ARC_MMAP */
524
525#if 0
526/*
527 * XXX This is here for reference.  It needs to be handled differently for the
528 * ND.
529 */
530#if defined(USE_ARC_MMAP) || defined(__arm32__)
531
532#ifdef USE_ARM32_MMAP
533#define	DEV_MEM_IOBASE	0x43000000
534#endif
535
536static Bool ScreenEnabled[MAXSCREENS];
537static Bool ExtendedEnabled = FALSE;
538static Bool InitDone = FALSE;
539
540Bool
541xf86EnableIOPorts(ScreenNum)
542int ScreenNum;
543{
544	int i;
545	int fd;
546	pointer base;
547
548#ifdef __arm32__
549	struct memAccess *memInfoP;
550	int *Size;
551#endif
552
553	ScreenEnabled[ScreenNum] = TRUE;
554
555	if (ExtendedEnabled)
556		return TRUE;
557
558#ifdef USE_ARC_MMAP
559	if ((fd = open("/dev/ttyC0", O_RDWR)) >= 0) {
560		/* Try to map a page at the pccons I/O space */
561		base = (pointer)mmap((caddr_t)0, 65536, PROT_READ | PROT_WRITE,
562				MAP_FLAGS, fd, (off_t)0x0000);
563
564		if (base != (pointer)-1) {
565			IOPortBase = base;
566		}
567		else {
568			xf86Msg(X_ERROR,
569				"EnableIOPorts: failed to mmap %s (%s)\n",
570				"/dev/ttyC0", strerror(errno));
571		}
572	}
573	else {
574		xf86Msg(X_ERROR, "EnableIOPorts: failed to open %s (%s)\n",
575			"/dev/ttyC0", strerror(errno));
576	}
577#endif
578
579#ifdef __arm32__
580	IOPortBase = (unsigned int)-1;
581
582	if((memInfoP = checkMapInfo(TRUE, MMIO_REGION)) != NULL)
583	{
584	    /*
585	     * xf86MapInfoMap maps an offset from the start of video IO
586	     * space (e.g. 0x3B0), but IOPortBase is expected to map to
587	     * physical address 0x000, so subtract the start of video I/O
588	     * space from the result.  This is safe for now becase we
589	     * actually mmap the start of the page, then the start of video
590	     * I/O space is added as an internal offset.
591	     */
592	    IOPortBase = (unsigned int)xf86MapInfoMap(memInfoP,
593						      (caddr_t)0x0, 0L)
594		- memInfoP->memInfo.u.map_info_mmap.internal_offset;
595	    ExtendedEnabled = TRUE;
596	    return TRUE;
597	}
598#ifdef USE_ARM32_MMAP
599	checkDevMem(TRUE);
600
601	if (devMemFd >= 0 && useDevMem)
602	{
603	    base = (pointer)mmap((caddr_t)0, 0x400, PROT_READ | PROT_WRITE,
604				 MAP_FLAGS, devMemFd, (off_t)DEV_MEM_IOBASE);
605
606	    if (base != (pointer)-1)
607		IOPortBase = (unsigned int)base;
608	}
609
610        if (IOPortBase == (unsigned int)-1)
611	{
612	    xf86Msg(X_WARNING,"xf86EnableIOPorts: failed to open mem device or map IO base. \n\
613Make sure you have the Aperture Driver installed, or a kernel built with the INSECURE option\n");
614	    return FALSE;
615	}
616#else
617	/* We don't have the IOBASE, so we can't map the address */
618	xf86Msg(X_WARNING,"xf86EnableIOPorts: failed to open mem device or map IO base. \n\
619Try building the server with USE_ARM32_MMAP defined\n");
620	return FALSE;
621#endif
622#endif
623
624	ExtendedEnabled = TRUE;
625
626	return TRUE;
627}
628
629void
630xf86DisableIOPorts(ScreenNum)
631int ScreenNum;
632{
633	int i;
634#ifdef __arm32__
635        struct memAccess *memInfoP;
636#endif
637
638	ScreenEnabled[ScreenNum] = FALSE;
639
640#ifdef __arm32__
641	if((memInfoP = checkMapInfo(FALSE, MMIO_REGION)) != NULL)
642	{
643	    xf86MapInfoUnmap(memInfoP, 0);
644	}
645#endif
646
647#ifdef USE_ARM32_MMAP
648	if (!ExtendedEnabled)
649	return;
650
651	for (i = 0; i < MAXSCREENS; i++)
652		if (ScreenEnabled[i])
653			return;
654
655	munmap((caddr_t)IOPortBase, 0x400);
656	IOPortBase = (unsigned int)-1;
657	ExtendedEnabled = FALSE;
658#endif
659
660	return;
661}
662
663#endif /* USE_ARC_MMAP || USE_ARM32_MMAP */
664#endif
665
666
667