--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/open-src/driver/efb/sun-src/src/efb_driver.c Mon Apr 25 13:38:53 2011 -0700
@@ -0,0 +1,605 @@
+/*
+ * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Copyright 2000 through 2004 by Marc Aurele La France (TSI @ UQV), [email protected]
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of Marc Aurele La France not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Marc Aurele La France makes no representations
+ * about the suitability of this software for any purpose. It is provided
+ * "as-is" without express or implied warranty.
+ *
+ * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
+ * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include "radeon.h"
+#include "radeon_probe.h"
+#include "radeon_version.h"
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "efb.h"
+#include "fb.h"
+
+#ifdef XSERVER_LIBPCIACCESS
+#include "pciaccess.h"
+#endif
+
+
+/* Module loader interface for subsidiary driver module */
+
+static XF86ModuleVersionInfo EFBVersionRec =
+{
+ RADEON_DRIVER_NAME,
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ RADEON_VERSION_MAJOR, RADEON_VERSION_MINOR, RADEON_VERSION_PATCH,
+ ABI_CLASS_VIDEODRV,
+ ABI_VIDEODRV_VERSION,
+ MOD_CLASS_VIDEODRV,
+ {0, 0, 0, 0}
+};
+
+/*
+ * EFBSetup --
+ *
+ * This function is called every time the module is loaded.
+ */
+static pointer
+EFBSetup
+(
+ pointer Module,
+ pointer Options,
+ int *ErrorMajor,
+ int *ErrorMinor
+)
+{
+ static Bool Inited = FALSE;
+
+ if (!Inited) {
+ Inited = TRUE;
+ xf86AddDriver(&RADEON, Module, HaveDriverFuncs);
+ }
+
+ return (pointer)TRUE;
+}
+
+/* The following record must be called efbModuleData */
+_X_EXPORT XF86ModuleData efbModuleData =
+{
+ &EFBVersionRec,
+ EFBSetup,
+ NULL
+};
+
+
+#define EFB_REG_SIZE 256*1024
+#define EFB_REG_SIZE_LOG2 18
+
+#ifndef XSERVER_LIBPCIACCESS
+pciVideoPtr EFBGetPciInfo(RADEONInfoPtr info)
+{
+ int status;
+ pciVideoPtr pciInfo = NULL;
+ int i;
+ int cmd = GFX_IOCTL_GET_PCI_CONFIG;
+ struct gfx_pci_cfg pciCfg;
+ int bar;
+
+ if ((status = ioctl(info->fd, GFX_IOCTL_GET_PCI_CONFIG, &pciCfg))
+ != -1) {
+ pciInfo = malloc(sizeof(pciVideoRec));
+
+ pciInfo->vendor = pciCfg.VendorID;
+ pciInfo->chipType = pciCfg.DeviceID;
+ pciInfo->chipRev = pciCfg.RevisionID;
+ pciInfo->subsysVendor = pciCfg.SubVendorID;
+ pciInfo->subsysCard = pciCfg.SubSystemID;
+
+ // TODO: need to fill in the complete structure
+ //
+ for (i = 0; i < 6; i++) {
+ bar = pciCfg.bar[i];
+ if (bar != 0) {
+ if (bar & PCI_MAP_IO) {
+ pciInfo->ioBase[i] = (memType)PCIGETIO(bar);
+ pciInfo->type[i] = bar & PCI_MAP_IO_ATTR_MASK;
+
+ // TODO: size?
+ } else {
+ pciInfo->type[i] = bar & PCI_MAP_MEMORY_ATTR_MASK;
+ pciInfo->memBase[i] = (memType)PCIGETMEMORY(bar);
+ if (PCI_MAP_IS64BITMEM(bar)) {
+ if (i == 5) {
+ pciInfo->memBase[i] = 0;
+ } else {
+ int bar_hi = pciCfg.bar[i+1];
+ /* 64 bit architecture */
+ pciInfo->memBase[i] |=
+ (memType)bar_hi << 32;
+ ++i; /* Step over the next BAR */
+ }
+ }
+ pciInfo->size[i] = EFB_REG_SIZE_LOG2;
+ }
+ }
+ }
+ }
+
+ return pciInfo;
+}
+#else
+
+/*
+ * These defines are from the xorg 1.3 xf86pci.h
+ */
+#define PCI_MAP_MEMORY 0x00000000
+#define PCI_MAP_IO 0x00000001
+
+#define PCI_MAP_MEMORY_TYPE 0x00000007
+#define PCI_MAP_MEMORY_TYPE_64BIT 0x00000004
+#define PCI_MAP_IO_TYPE 0x00000003
+
+#define PCI_MAP_MEMORY_ADDRESS_MASK 0xfffffff0
+#define PCI_MAP_IO_ADDRESS_MASK 0xfffffffc
+
+#define PCI_MAP_IS_IO(b) ((b) & PCI_MAP_IO)
+
+#define PCI_MAP_IS64BITMEM(b) \
+ (((b) & PCI_MAP_MEMORY_TYPE) == PCI_MAP_MEMORY_TYPE_64BIT)
+
+#define PCIGETMEMORY(b) ((b) & PCI_MAP_MEMORY_ADDRESS_MASK)
+#define PCIGETMEMORY64HIGH(b) (*((CARD32*)&(b) + 1))
+#define PCIGETMEMORY64(b) \
+ (PCIGETMEMORY(b) | ((CARD64)PCIGETMEMORY64HIGH(b) << 32))
+
+#define PCIGETIO(b) ((b) & PCI_MAP_IO_ADDRESS_MASK)
+
+
+struct pci_device * EFBGetPciInfo(RADEONInfoPtr info)
+{
+ int status;
+ struct pci_device *pciInfo = NULL;
+ int i;
+ int cmd = GFX_IOCTL_GET_PCI_CONFIG;
+ struct gfx_pci_cfg pciCfg;
+ int bar;
+
+ if ((status = ioctl(info->fd, GFX_IOCTL_GET_PCI_CONFIG, &pciCfg))
+ != -1) {
+ pciInfo = malloc(sizeof(struct pci_device));
+
+ pciInfo->vendor_id = pciCfg.VendorID;
+ pciInfo->device_id = pciCfg.DeviceID;
+ pciInfo->revision = pciCfg.RevisionID;
+ pciInfo->subvendor_id = pciCfg.SubVendorID;
+ pciInfo->subvendor_id = pciCfg.SubSystemID;
+
+ // TODO: need to fill in the complete structure
+ //
+ for (i = 0; i < 6; i++) {
+ bar = pciCfg.bar[i];
+ if (bar != 0) {
+ if (PCI_MAP_IS_IO(bar)) {
+ pciInfo->regions[i].base_addr = (pciaddr_t)PCIGETIO(bar);
+ } else {
+ pciInfo->regions[i].size = EFB_REG_SIZE;
+ if (PCI_MAP_IS64BITMEM(bar)) {
+ pciInfo->regions[i].base_addr = (pciaddr_t)PCIGETMEMORY64(bar);
+ ++i; /* Step over the next BAR */
+ } else {
+ pciInfo->regions[i].base_addr = (pciaddr_t)PCIGETMEMORY(bar);
+ }
+ }
+ }
+ }
+ }
+
+ return pciInfo;
+}
+#endif
+
+
+pointer
+EFBMapVidMem(ScrnInfoPtr pScrn, unsigned int flags, PCITAG picTag,
+ unsigned long base, unsigned long size)
+{
+ int BUS_BASE = 0;
+ pointer memBase;
+ int fdd;
+ int mapflags = MAP_SHARED;
+ int prot;
+ memType realBase, alignOff;
+ unsigned long realSize;
+ int pageSize;
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+
+ fdd = info->fd;
+ realBase = base & ~(getpagesize() - 1);
+ alignOff = base - realBase;
+
+ pageSize = getpagesize();
+ realSize = size + (pageSize - 1) & (~(pageSize - 1));
+
+ printf("base: %lx, realBase: %lx, alignOff: %lx \n",
+ base, realBase, alignOff);
+
+ if (flags & VIDMEM_READONLY) {
+ prot = PROT_READ;
+ } else {
+ prot = PROT_READ | PROT_WRITE;
+ }
+
+ memBase = mmap((caddr_t)0, realSize + alignOff, prot, mapflags, fdd,
+ (off_t)(off_t)realBase + BUS_BASE);
+
+ if (memBase == MAP_FAILED) {
+ printf("RADEONMapVidMem: Could not map framebuffer\n");
+ return NULL;
+ }
+
+ return ((char *)memBase + alignOff);
+}
+
+void
+EFBUnmapVidMem(ScrnInfoPtr pScrn, pointer base, unsigned long size)
+{
+ memType alignOff = (memType)base - ((memType)base & ~(getpagesize() - 1));
+
+ printf("alignment offset: %lx\n",alignOff);
+ munmap((caddr_t)((memType)base - alignOff), (size + alignOff));
+
+ return;
+}
+
+
+void
+EFBNotifyModeChanged(ScrnInfoPtr pScrn)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ int status;
+
+ struct gfx_video_mode mode;
+
+ if (pScrn->currentMode->name) {
+ strlcpy(mode.mode_name, pScrn->currentMode->name, GFX_MAX_VMODE_LEN);
+ } else {
+ strlcpy(mode.mode_name, " ", GFX_MAX_VMODE_LEN);
+ }
+
+ mode.vRefresh = pScrn->currentMode->VRefresh;
+
+ status = ioctl(info->fd, GFX_IOCTL_SET_VIDEO_MODE, &mode);
+}
+
+void
+EFBScreenInit(ScrnInfoPtr pScrn)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+
+ if (xf86ReturnOptValBool(info->Options, OPTION_DISABLE_RANDR, FALSE)) {
+
+ xf86DrvMsg (pScrn->scrnIndex, X_INFO, "RANDR is disabled\n");
+
+ //
+ // disable RANDR
+ //
+ EnableDisableExtension("RANDR", FALSE);
+ }
+
+ EFBNotifyModeChanged(pScrn);
+}
+
+void
+EFBCloseScreen(ScrnInfoPtr pScrn)
+{
+ EFBNotifyModeChanged(pScrn);
+}
+
+DisplayModePtr
+EFBOutputGetEDIDModes(xf86OutputPtr output)
+{
+ xf86MonPtr edid_mon = output->MonInfo;
+
+ if (!strcmp(edid_mon->vendor.name, "SUN")) {
+ if (edid_mon->ver.version == 1 &&
+ edid_mon->ver.revision <= 2) {
+
+ //
+ // force detail timing to be the preferred one
+ //
+ edid_mon->features.msc |= 0x2;
+ }
+ }
+
+ return (xf86OutputGetEDIDModes(output));
+}
+
+DisplayModePtr
+efb_get_modes(xf86OutputPtr output)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ DisplayModePtr pModes;
+
+ pModes = RADEONProbeOutputModes(output);
+
+ //
+ // display modes have precedence
+ //
+ if (pScrn->display->modes[0] != NULL) {
+ int mm;
+ char *modes;
+ DisplayModePtr dModes, preferredMode = NULL;
+ int found = 0, done = 0;
+ for (mm = 0; pScrn->display->modes[mm] != NULL && !found; mm++) {
+ modes = pScrn->display->modes[mm];
+ if (!strcasecmp(modes, "Auto") || !strcasecmp(modes, "None")) {
+ done = found = 1;
+ } else {
+ done = 0;
+ dModes = pModes;
+ while (dModes && !done) {
+ if (!strcmp(modes, dModes->name)) {
+ done = found = 1;
+ dModes->type |= M_T_PREFERRED;
+ preferredMode = dModes;
+ } else {
+ dModes = dModes->next;
+ }
+ }
+ }
+ }
+
+ if (found && preferredMode) {
+ dModes = pModes;
+ while (dModes) {
+ if ((dModes->type & M_T_PREFERRED) &&
+ (dModes != preferredMode)) {
+ dModes->type &= ~M_T_PREFERRED;
+ }
+ dModes = dModes->next;
+ }
+ }
+ }
+
+ return(pModes);
+}
+
+char *efb_default_mode = "1024x768";
+
+float ratio[] = { 10/16, /* 16:10 AR */
+ 3/4, /* 4:3 AR */
+ 4/5, /* 5:4 AR */
+ 9/16 /* 16:9 AR */
+ };
+
+char *efb_get_edid_preferred_mode(ScrnInfoPtr pScrn, int head)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ int i, status;
+ unsigned int length;
+ gfx_edid_t edid_buf;
+ unsigned char *data;
+ unsigned char *mode = "1280x1024";
+ unsigned char pmode[10];
+ unsigned char *vblk, *pblk;
+ unsigned int width = 0, height = 0;
+
+ edid_buf.head = head;
+ edid_buf.version = GFX_EDID_VERSION;
+ status = ioctl(info->fd, GFX_IOCTL_GET_EDID_LENGTH, &edid_buf);
+ if (status == -1) {
+ return strdup(efb_default_mode);
+ }
+
+ data = edid_buf.data = (char *)malloc(edid_buf.length);
+ status = ioctl(info->fd, GFX_IOCTL_GET_EDID, &edid_buf);
+ if (status == -1) {
+ return strdup(efb_default_mode);
+ }
+
+ vblk = data + 8 + 10; /* skip header & product info */
+
+ pblk = vblk + 2 + 5 + 10 + 3 + 16; /* skip to preferred timing block */
+
+ for (i = 0; i < 4 && width == 0; i++, pblk+=18) {
+ if (!((pblk[0] == 0) && (pblk[0] == 0))) {
+ width = pblk[2] | ((pblk[4] & 0xf0) << 4);
+ height = pblk[5] | ((pblk[7] & 0xf0) << 4);
+ }
+ }
+
+ sprintf(pmode, "%dx%d", width, height);
+
+ return strdup(pmode);
+}
+
+void efb_set_position(xf86CrtcConfigPtr config, BOOL swap,
+ int pos1X, int pos1Y, int pos2X, int pos2Y)
+{
+ int o;
+ xf86OutputPtr output;
+ char *value[2];
+ char str[20];
+ OptionInfoRec *p;
+
+ int first = 0;
+ int second = 1;
+
+ if (swap) {
+ first = 1;
+ second = 0;
+ }
+
+ sprintf(str,"%d %d", pos1X, pos1Y);
+ value[first] = strdup(str);
+ sprintf(str,"%d %d", pos2X, pos2Y);
+ value[second] = strdup(str);
+
+ for (o = 0; o < 2; o++) {
+
+ output = config->output[o];
+
+ for (p = output->options; p->token >= 0; p++) {
+
+ if (strcmp(p->name, "Position") == 0) {
+ if (!p->found) {
+ p->value.str = value[o];
+ p->found = TRUE;
+ }
+ }
+ }
+ }
+}
+
+void EFBPreInitOutputConfiguration(ScrnInfoPtr pScrn, xf86CrtcConfigPtr config)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+
+ Bool doubleWide = FALSE;
+ Bool doubleHigh = FALSE;
+ Bool swap = FALSE;
+ int offset = 0, position = 0;
+ int head0 = GFX_EDID_HEAD_ONE;
+ int head1 = GFX_EDID_HEAD_TWO;
+ char *str;
+
+ str = xf86GetOptValString(info->Options, OPTION_DUAL_DISPLAY);
+ if ((str != NULL) && (strcasecmp(str, "Enable") == 0)) {
+ doubleWide = TRUE;
+ }
+ str = xf86GetOptValString(info->Options, OPTION_DUAL_DISPLAY_VERTICAL);
+ if ((str != NULL) && (strcasecmp(str, "Enable") == 0)) {
+ doubleHigh = TRUE;
+ }
+
+ // do the output configuration here only if dual display is enabled
+
+ if ((doubleWide == FALSE) && (doubleHigh == FALSE)) {
+ return;
+ }
+
+ if ((doubleWide == TRUE) || (doubleHigh == TRUE)) {
+ char *outputOrder;
+
+ outputOrder = xf86GetOptValString(info->Options, OPTION_OUTPUTS);
+ if ((outputOrder != NULL) && (strcasecmp(outputOrder, "Swapped") == 0)) {
+ swap = TRUE;
+ head0 = GFX_EDID_HEAD_TWO;
+ head1 = GFX_EDID_HEAD_ONE;
+ }
+ }
+
+ if (pScrn->display->modes[0] != NULL) {
+ int mm;
+ char *modes;
+ int found = 0, done = 0;
+ for (mm = 0; pScrn->display->modes[mm] != NULL && !found; mm++) {
+ modes = pScrn->display->modes[mm];
+ if (!strcasecmp(modes, "Auto") || !strcasecmp(modes, "None")) {
+ free(pScrn->display->modes[mm]);
+ pScrn->display->modes[mm] = efb_get_edid_preferred_mode(pScrn, head0);
+ found = 1;
+ }
+ }
+ } else {
+ pScrn->display->modes = malloc(2*sizeof(char *));
+ pScrn->display->modes[0] = efb_get_edid_preferred_mode(pScrn, head0);
+ pScrn->display->modes[1] = NULL;
+ }
+
+ if ((doubleWide == TRUE) || (doubleHigh == TRUE)) {
+
+ char *mode, *token;
+ int width, height, position;
+ char value[10];
+ xf86OutputPtr output;
+
+ mode = strdup(pScrn->display->modes[0]);
+ token = strtok(mode, "x");
+ width = atoi(token);
+ token = strtok(NULL, "x");
+ height = atoi(token);
+
+ free(mode);
+
+ //
+ // check for stream offset
+ //
+ if (doubleWide == TRUE) {
+ xf86GetOptValInteger(info->Options, OPTION_STREAM_XOFFSET, &offset);
+
+ position = width;
+
+ if (offset != 0) {
+ position += offset;
+ }
+
+ efb_set_position(config, swap, 0, 0, position, 0);
+
+ } else {
+ xf86GetOptValInteger(info->Options, OPTION_STREAM_YOFFSET, &offset);
+
+ position = height;
+
+ if (offset != 0) {
+ position += offset;
+ }
+
+ efb_set_position(config, swap, 0, 0, 0, position);
+ }
+
+ //
+ // if display virtual dimension is specified in xorg.conf, leave it alone
+ //
+ if (!pScrn->display->virtualX || !pScrn->display->virtualY) {
+ if (doubleWide) {
+ pScrn->display->virtualX = width * 2 + offset;
+ pScrn->display->virtualY = height;
+ } else if (doubleHigh) {
+ pScrn->display->virtualX = width;
+ pScrn->display->virtualY = height * 2 + offset;
+ }
+ }
+
+ }
+}