2 * SBUS and OpenPROM access functions.
4 * Copyright (C) 2000 Jakub Jelinek (jakub@redhat.com)
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * JAKUB JELINEK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #ifdef HAVE_XORG_CONFIG_H
25 #include <xorg-config.h>
32 #include <sys/ioctl.h>
35 #include <sys/utsname.h>
39 #include "xf86_OSlib.h"
41 #include "xf86sbusBus.h"
46 static int promFd
= -1;
47 static int promCurrentNode
;
48 static int promOpenCount
= 0;
49 static int promP1275
= -1;
52 #define MAX_VAL (4096-128-4)
53 static struct openpromio
*promOpio
;
55 sbusDevicePtr
*xf86SbusInfo
= NULL
;
57 struct sbus_devtable sbusDeviceTable
[] = {
58 {SBUS_DEVICE_BW2
, FBTYPE_SUN2BW
, "bwtwo", "sunbw2",
59 "Sun Monochrome (bwtwo)"},
60 {SBUS_DEVICE_CG2
, FBTYPE_SUN2COLOR
, "cgtwo", NULL
, "Sun Color2 (cgtwo)"},
61 {SBUS_DEVICE_CG3
, FBTYPE_SUN3COLOR
, "cgthree", "suncg3",
62 "Sun Color3 (cgthree)"},
63 {SBUS_DEVICE_CG4
, FBTYPE_SUN4COLOR
, "cgfour", NULL
, "Sun Color4 (cgfour)"},
64 {SBUS_DEVICE_CG6
, FBTYPE_SUNFAST_COLOR
, "cgsix", "suncg6", "Sun GX"},
65 {SBUS_DEVICE_CG8
, FBTYPE_MEMCOLOR
, "cgeight", NULL
, "Sun CG8/RasterOps"},
66 {SBUS_DEVICE_CG12
, FBTYPE_SUNGP3
, "cgtwelve", NULL
, "Sun GS (cgtwelve)"},
67 {SBUS_DEVICE_CG14
, FBTYPE_MDICOLOR
, "cgfourteen", "suncg14", "Sun SX"},
68 {SBUS_DEVICE_GT
, FBTYPE_SUNGT
, "gt", NULL
, "Sun Graphics Tower"},
69 {SBUS_DEVICE_MGX
, -1, "mgx", NULL
, "Quantum 3D MGXplus"},
70 {SBUS_DEVICE_LEO
, FBTYPE_SUNLEO
, "leo", "sunleo", "Sun ZX or Turbo ZX"},
71 {SBUS_DEVICE_TCX
, FBTYPE_TCXCOLOR
, "tcx", "suntcx", "Sun TCX"},
72 {SBUS_DEVICE_FFB
, FBTYPE_CREATOR
, "ffb", "sunffb", "Sun FFB"},
73 {SBUS_DEVICE_FFB
, FBTYPE_CREATOR
, "afb", "sunffb", "Sun Elite3D"},
78 promGetSibling(int node
)
80 promOpio
->oprom_size
= sizeof(int);
84 *(int *) promOpio
->oprom_array
= node
;
85 if (ioctl(promFd
, OPROMNEXT
, promOpio
) < 0)
87 promCurrentNode
= *(int *) promOpio
->oprom_array
;
88 return *(int *) promOpio
->oprom_array
;
92 promGetChild(int node
)
94 promOpio
->oprom_size
= sizeof(int);
96 if (!node
|| node
== -1)
98 *(int *) promOpio
->oprom_array
= node
;
99 if (ioctl(promFd
, OPROMCHILD
, promOpio
) < 0)
101 promCurrentNode
= *(int *) promOpio
->oprom_array
;
102 return *(int *) promOpio
->oprom_array
;
106 promGetProperty(const char *prop
, int *lenp
)
108 promOpio
->oprom_size
= MAX_VAL
;
110 strcpy(promOpio
->oprom_array
, prop
);
111 if (ioctl(promFd
, OPROMGETPROP
, promOpio
) < 0)
114 *lenp
= promOpio
->oprom_size
;
115 return promOpio
->oprom_array
;
119 promGetBool(const char *prop
)
121 promOpio
->oprom_size
= 0;
123 *(int *) promOpio
->oprom_array
= 0;
125 promOpio
->oprom_size
= MAX_PROP
;
126 if (ioctl(promFd
, OPROMNXTPROP
, promOpio
) < 0)
128 if (!promOpio
->oprom_size
)
130 if (!strcmp(promOpio
->oprom_array
, prop
))
135 #define PROM_NODE_SIBLING 0x01
136 #define PROM_NODE_PREF 0x02
137 #define PROM_NODE_SBUS 0x04
138 #define PROM_NODE_EBUS 0x08
139 #define PROM_NODE_PCI 0x10
142 promSetNode(sbusPromNodePtr pnode
)
146 if (!pnode
->node
|| pnode
->node
== -1)
148 if (pnode
->cookie
[0] & PROM_NODE_SIBLING
)
149 node
= promGetSibling(pnode
->cookie
[1]);
151 node
= promGetChild(pnode
->cookie
[1]);
152 if (pnode
->node
!= node
)
167 f
= fopen("/proc/cpuinfo", "r");
170 while (fgets(buffer
, 1024, f
) != NULL
)
171 if (!strncmp(buffer
, "type", 4) && strstr(buffer
, "sun4u")) {
177 struct utsname buffer
;
179 if ((uname(&buffer
) >= 0) && !strcmp(buffer
.machine
, "sun4u"))
183 #elif defined(__FreeBSD__)
186 #error Missing promIsP1275() function for this OS
193 if (promOpenCount
> 1) {
213 promFd
= open("/dev/openprom", O_RDONLY
, 0);
216 promOpio
= (struct openpromio
*) malloc(4096);
221 promRootNode
= promGetSibling(0);
233 sparcPromGetProperty(sbusPromNodePtr pnode
, const char *prop
, int *lenp
)
235 if (promSetNode(pnode
))
237 return promGetProperty(prop
, lenp
);
241 sparcPromGetBool(sbusPromNodePtr pnode
, const char *prop
)
243 if (promSetNode(pnode
))
245 return promGetBool(prop
);
249 promWalkGetDriverName(int node
, int oldnode
)
256 prop
= promGetProperty("device_type", &len
);
257 if (prop
&& (len
> 0))
259 if (!strcmp(prop
, "display")) {
260 prop
= promGetProperty("name", &len
);
261 if (!prop
|| len
<= 0)
263 while ((*prop
>= 'A' && *prop
<= 'Z') || *prop
== ',')
265 for (i
= 0; sbusDeviceTable
[i
].devId
; i
++)
266 if (!strcmp(prop
, sbusDeviceTable
[i
].promName
))
268 devId
= sbusDeviceTable
[i
].devId
;
271 if (sbusDeviceTable
[i
].driverName
)
272 return sbusDeviceTable
[i
].driverName
;
276 nextnode
= promGetChild(node
);
280 name
= promWalkGetDriverName(nextnode
, node
);
285 nextnode
= promGetSibling(node
);
287 return promWalkGetDriverName(nextnode
, node
);
292 sparcDriverName(void)
296 if (sparcPromInit() < 0)
299 name
= promWalkGetDriverName(promRootNode
, 0);
305 promWalkAssignNodes(int node
, int oldnode
, int flags
,
306 sbusDevicePtr
* devicePtrs
)
309 int len
, sbus
= flags
& PROM_NODE_SBUS
;
312 sbusPromNode pNode
, pNode2
;
314 prop
= promGetProperty("device_type", &len
);
315 if (prop
&& (len
> 0))
317 if (!strcmp(prop
, "display")) {
318 prop
= promGetProperty("name", &len
);
319 if (!prop
|| len
<= 0)
321 while ((*prop
>= 'A' && *prop
<= 'Z') || *prop
== ',')
323 for (i
= 0; sbusDeviceTable
[i
].devId
; i
++)
324 if (!strcmp(prop
, sbusDeviceTable
[i
].promName
))
326 devId
= sbusDeviceTable
[i
].devId
;
330 if (devId
== SBUS_DEVICE_FFB
) {
332 * All /SUNW,ffb outside of SBUS tree come before all
333 * /SUNW,afb outside of SBUS tree in Linux.
335 if (!strcmp(prop
, "afb"))
336 flags
|= PROM_NODE_PREF
;
338 else if (devId
!= SBUS_DEVICE_CG14
)
341 for (i
= 0; i
< 32; i
++) {
342 if (!devicePtrs
[i
] || devicePtrs
[i
]->devId
!= devId
)
344 if (devicePtrs
[i
]->node
.node
) {
345 if ((devicePtrs
[i
]->node
.
346 cookie
[0] & ~PROM_NODE_SIBLING
) <=
347 (flags
& ~PROM_NODE_SIBLING
))
349 for (j
= i
+ 1, pNode
= devicePtrs
[i
]->node
; j
< 32;
351 if (!devicePtrs
[j
] || devicePtrs
[j
]->devId
!= devId
)
353 pNode2
= devicePtrs
[j
]->node
;
354 devicePtrs
[j
]->node
= pNode
;
358 devicePtrs
[i
]->node
.node
= node
;
359 devicePtrs
[i
]->node
.cookie
[0] = flags
;
360 devicePtrs
[i
]->node
.cookie
[1] = oldnode
;
367 prop
= promGetProperty("name", &len
);
368 if (prop
&& len
> 0) {
369 if (!strcmp(prop
, "sbus") || !strcmp(prop
, "sbi"))
370 sbus
= PROM_NODE_SBUS
;
373 nextnode
= promGetChild(node
);
375 promWalkAssignNodes(nextnode
, node
, sbus
, devicePtrs
);
377 nextnode
= promGetSibling(node
);
379 promWalkAssignNodes(nextnode
, node
, PROM_NODE_SIBLING
| sbus
,
384 sparcPromAssignNodes(void)
386 sbusDevicePtr psdp
, *psdpp
;
387 int n
, holes
= 0, i
, j
;
389 sbusDevicePtr devicePtrs
[32];
391 memset(devicePtrs
, 0, sizeof(devicePtrs
));
392 for (psdpp
= xf86SbusInfo
, n
= 0; (psdp
= *psdpp
); psdpp
++, n
++) {
393 if (psdp
->fbNum
!= n
)
395 devicePtrs
[psdp
->fbNum
] = psdp
;
397 if (holes
&& (f
= fopen("/proc/fb", "r")) != NULL
) {
398 /* We could not open one of fb devices, check /proc/fb to see what
399 * were the types of the cards missed. */
405 } procFbPrefixes
[] = {
406 {SBUS_DEVICE_BW2
, "BWtwo"},
407 {SBUS_DEVICE_CG14
, "CGfourteen"},
408 {SBUS_DEVICE_CG6
, "CGsix"},
409 {SBUS_DEVICE_CG3
, "CGthree"},
410 {SBUS_DEVICE_FFB
, "Creator"},
411 {SBUS_DEVICE_FFB
, "Elite 3D"},
412 {SBUS_DEVICE_LEO
, "Leo"},
413 {SBUS_DEVICE_TCX
, "TCX"},
417 while (fscanf(f
, "%d %63s\n", &fbNum
, buffer
) == 2) {
418 for (i
= 0; procFbPrefixes
[i
].devId
; i
++)
419 if (!strncmp(procFbPrefixes
[i
].prefix
, buffer
,
420 strlen(procFbPrefixes
[i
].prefix
)))
422 devId
= procFbPrefixes
[i
].devId
;
425 if (devicePtrs
[fbNum
]) {
426 if (devicePtrs
[fbNum
]->devId
!= devId
)
427 xf86ErrorF("Inconsistent /proc/fb with FBIOGATTR\n");
429 else if (!devicePtrs
[fbNum
]) {
430 devicePtrs
[fbNum
] = psdp
= xnfcalloc(sizeof(sbusDevice
), 1);
439 promWalkAssignNodes(promRootNode
, 0, PROM_NODE_PREF
, devicePtrs
);
440 for (i
= 0, j
= 0; i
< 32; i
++)
441 if (devicePtrs
[i
] && devicePtrs
[i
]->fbNum
== -1)
443 xf86SbusInfo
= xnfrealloc(xf86SbusInfo
, sizeof(psdp
) * (n
+ j
+ 1));
444 for (i
= 0, psdpp
= xf86SbusInfo
; i
< 32; i
++)
446 if (devicePtrs
[i
]->fbNum
== -1) {
447 memmove(psdpp
+ 1, psdpp
, sizeof(psdpp
) * (n
+ 1));
448 *psdpp
= devicePtrs
[i
];
460 static char regstr
[40];
463 prop
= promGetProperty("reg", &len
);
464 if (prop
&& len
>= 4) {
465 unsigned int *reg
= (unsigned int *) prop
;
467 if (!promP1275
|| (type
== PROM_NODE_SBUS
) || (type
== PROM_NODE_EBUS
))
468 snprintf(regstr
, sizeof(regstr
), "@%x,%x", reg
[0], reg
[1]);
469 else if (type
== PROM_NODE_PCI
) {
470 if ((reg
[0] >> 8) & 7)
471 snprintf(regstr
, sizeof(regstr
), "@%x,%x",
472 (reg
[0] >> 11) & 0x1f, (reg
[0] >> 8) & 7);
474 snprintf(regstr
, sizeof(regstr
), "@%x", (reg
[0] >> 11) & 0x1f);
477 snprintf(regstr
, sizeof(regstr
), "@%x", reg
[0]);
479 unsigned int regs
[2];
481 /* Things get more complicated on UPA. If upa-portid exists,
482 then address is @upa-portid,second-int-in-reg, otherwise
483 it is @first-int-in-reg/16,second-int-in-reg (well, probably
484 upa-portid always exists, but just to be safe). */
485 memcpy(regs
, reg
, sizeof(regs
));
486 prop
= promGetProperty("upa-portid", &len
);
487 if (prop
&& len
== 4) {
488 reg
= (unsigned int *) prop
;
489 snprintf(regstr
, sizeof(regstr
), "@%x,%x", reg
[0], regs
[1]);
492 snprintf(regstr
, sizeof(regstr
), "@%x,%x", regs
[0] >> 4,
500 promWalkNode2Pathname(char *path
, int parent
, int node
, int searchNode
,
504 int len
, ntype
= type
;
507 prop
= promGetProperty("name", &len
);
509 if (!prop
|| len
<= 0)
511 if ((!strcmp(prop
, "sbus") || !strcmp(prop
, "sbi")) && !type
)
512 ntype
= PROM_NODE_SBUS
;
513 else if (!strcmp(prop
, "ebus") && type
== PROM_NODE_PCI
)
514 ntype
= PROM_NODE_EBUS
;
515 else if (!strcmp(prop
, "pci") && !type
)
516 ntype
= PROM_NODE_PCI
;
517 strcpy(path
+ 1, prop
);
518 p
= promGetReg(type
);
521 if (node
== searchNode
)
523 nextnode
= promGetChild(node
);
525 promWalkNode2Pathname(strchr(path
, 0), node
, nextnode
, searchNode
,
528 nextnode
= promGetSibling(node
);
530 promWalkNode2Pathname(path
, parent
, nextnode
, searchNode
, type
))
536 sparcPromNode2Pathname(sbusPromNodePtr pnode
)
545 if (promWalkNode2Pathname
546 (ret
, promRootNode
, promGetChild(promRootNode
), pnode
->node
, 0))
553 promWalkPathname2Node(char *name
, char *regstr
, int parent
, int type
)
559 prop
= promGetProperty("name", &len
);
560 if (!prop
|| len
<= 0)
562 if ((!strcmp(prop
, "sbus") || !strcmp(prop
, "sbi")) && !type
)
563 type
= PROM_NODE_SBUS
;
564 else if (!strcmp(prop
, "ebus") && type
== PROM_NODE_PCI
)
565 type
= PROM_NODE_EBUS
;
566 else if (!strcmp(prop
, "pci") && !type
)
567 type
= PROM_NODE_PCI
;
568 for (node
= promGetChild(parent
); node
; node
= promGetSibling(node
)) {
569 prop
= promGetProperty("name", &len
);
570 if (!prop
|| len
<= 0)
572 if (*name
&& strcmp(name
, prop
))
575 p
= promGetReg(type
);
576 if (!*p
|| strcmp(p
+ 1, regstr
))
582 for (node
= promGetChild(parent
); node
; node
= promGetSibling(node
)) {
583 ret
= promWalkPathname2Node(name
, regstr
, node
, type
);
589 name
= strchr(regstr
, 0) + 1;
592 p
= strchr(name
, '/');
597 regstr
= strchr(name
, '@');
609 sparcPromPathname2Node(const char *pathName
)
612 char *name
, *regstr
, *p
;
614 i
= strlen(pathName
);
615 name
= malloc(i
+ 2);
618 strcpy(name
, pathName
);
620 if (name
[0] != '/') {
624 p
= strchr(name
+ 1, '/');
629 regstr
= strchr(name
, '@');
634 if (name
+ 1 == regstr
) {
639 i
= promWalkPathname2Node(name
+ 1, regstr
, promRootNode
, 0);
645 xf86MapSbusMem(sbusDevicePtr psdp
, unsigned long offset
, unsigned long size
)
648 unsigned long pagemask
= getpagesize() - 1;
649 unsigned long off
= offset
& ~pagemask
;
650 unsigned long len
= ((offset
+ size
+ pagemask
) & ~pagemask
) - off
;
652 if (psdp
->fd
== -1) {
653 psdp
->fd
= open(psdp
->device
, O_RDWR
);
657 else if (psdp
->fd
< 0)
660 ret
= (pointer
) mmap(NULL
, len
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
,
662 if (ret
== (pointer
) -1) {
663 ret
= (pointer
) mmap(NULL
, len
, PROT_READ
| PROT_WRITE
, MAP_SHARED
,
666 if (ret
== (pointer
) -1)
669 return (char *) ret
+ (offset
- off
);
673 xf86UnmapSbusMem(sbusDevicePtr psdp
, pointer addr
, unsigned long size
)
675 unsigned long mask
= getpagesize() - 1;
676 unsigned long base
= (unsigned long) addr
& ~mask
;
677 unsigned long len
= (((unsigned long) addr
+ size
+ mask
) & ~mask
) - base
;
679 munmap((pointer
) base
, len
);
682 /* Tell OS that we are driving the HW cursor ourselves. */
684 xf86SbusHideOsHwCursor(sbusDevicePtr psdp
)
686 struct fbcursor fbcursor
;
687 unsigned char zeros
[8];
689 memset(&fbcursor
, 0, sizeof(fbcursor
));
690 memset(&zeros
, 0, sizeof(zeros
));
691 fbcursor
.cmap
.count
= 2;
692 fbcursor
.cmap
.red
= zeros
;
693 fbcursor
.cmap
.green
= zeros
;
694 fbcursor
.cmap
.blue
= zeros
;
695 fbcursor
.image
= (char *) zeros
;
696 fbcursor
.mask
= (char *) zeros
;
697 fbcursor
.size
.x
= 32;
699 fbcursor
.set
= FB_CUR_SETALL
;
700 ioctl(psdp
->fd
, FBIOSCURSOR
, &fbcursor
);
703 /* Set HW cursor colormap. */
705 xf86SbusSetOsHwCursorCmap(sbusDevicePtr psdp
, int bg
, int fg
)
707 struct fbcursor fbcursor
;
708 unsigned char red
[2], green
[2], blue
[2];
710 memset(&fbcursor
, 0, sizeof(fbcursor
));
717 fbcursor
.cmap
.count
= 2;
718 fbcursor
.cmap
.red
= red
;
719 fbcursor
.cmap
.green
= green
;
720 fbcursor
.cmap
.blue
= blue
;
721 fbcursor
.set
= FB_CUR_SETCMAP
;
722 ioctl(psdp
->fd
, FBIOSCURSOR
, &fbcursor
);