summaryrefslogtreecommitdiff
path: root/src/glamo-kms-driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glamo-kms-driver.c')
-rw-r--r--src/glamo-kms-driver.c478
1 files changed, 478 insertions, 0 deletions
diff --git a/src/glamo-kms-driver.c b/src/glamo-kms-driver.c
new file mode 100644
index 0000000..34c7baf
--- /dev/null
+++ b/src/glamo-kms-driver.c
@@ -0,0 +1,478 @@
+/*
+ * KMS Support for the SMedia Glamo3362 X.org Driver
+ *
+ * Copyright 2009 Thomas White <taw@bitwiz.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * The KMS parts of this driver are based on xf86-video-modesetting, to
+ * which the following notice applies:
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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, sub license, 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
+ *
+ *
+ * Author: Alan Hourihane <alanh@tungstengraphics.com>
+ *
+ */
+
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdint.h>
+
+#include <xorg-server.h>
+#include <drm.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "xf86.h"
+#include "xf86Crtc.h"
+#include "xf86str.h"
+#include "xf86drm.h"
+#include "micmap.h"
+
+#include "glamo.h"
+#include "glamo-kms-driver.h"
+#include "glamo-kms-exa.h"
+#include "glamo-dri2.h"
+#include "glamo-kms-crtc.h"
+#include "glamo-kms-output.h"
+
+
+/* Return TRUE if KMS can be used */
+Bool GlamoKernelModesettingAvailable()
+{
+ DIR *dir;
+ struct dirent *ent;
+
+ dir = opendir("/sys/bus/platform/devices/glamo-fb.0/");
+ if ( !dir ) return FALSE;
+
+ do {
+
+ ent = readdir(dir);
+ if ( !ent ) return FALSE;
+
+ if ( strncmp(ent->d_name, "drm:controlD", 12) == 0 ) {
+ closedir(dir);
+ return TRUE;
+ }
+
+ } while ( ent );
+
+ closedir(dir);
+ return FALSE;
+}
+
+
+void GlamoKMSAdjustFrame(int scrnIndex, int x, int y, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+ xf86OutputPtr output = config->output[config->compat_output];
+ xf86CrtcPtr crtc = output->crtc;
+
+ if (crtc && crtc->enabled) {
+ crtc->funcs->mode_set(crtc,
+ pScrn->currentMode,
+ pScrn->currentMode,
+ x, y);
+ crtc->x = output->initial_x + x;
+ crtc->y = output->initial_y + y;
+ }
+}
+
+
+static Bool CreateFrontBuffer(ScrnInfoPtr pScrn)
+{
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+ ScreenPtr pScreen = pScrn->pScreen;
+ PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+ unsigned int flags;
+
+ GlamoKMSExaMakeFullyFledged(rootPixmap,
+ pScrn->virtualX, pScrn->virtualY,
+ pScrn->depth, pScrn->bitsPerPixel,
+ pScrn->displayWidth*pScrn->bitsPerPixel/8);
+
+ drmModeAddFB(pGlamo->drm_fd,
+ pScrn->virtualX,
+ pScrn->virtualY,
+ pScrn->depth,
+ pScrn->bitsPerPixel,
+ pScrn->displayWidth * pScrn->bitsPerPixel / 8,
+ driGetPixmapHandle(rootPixmap, &flags), &pGlamo->fb_id);
+
+ pScrn->frameX0 = 0;
+ pScrn->frameY0 = 0;
+ GlamoKMSAdjustFrame(pScrn->scrnIndex,
+ pScrn->frameX0, pScrn->frameY0,
+ 0);
+
+ return TRUE;
+}
+
+
+static Bool crtc_resize(ScrnInfoPtr pScrn, int width, int height)
+{
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+
+ if ( (width == pScrn->virtualX) && (height == pScrn->virtualY) )
+ return TRUE; /* Nothing to do */
+
+ ErrorF("RESIZING TO %dx%d\n", width, height);
+
+ pScrn->virtualX = width;
+ pScrn->virtualY = height;
+
+ /* HW dependent - FIXME */
+ pScrn->displayWidth = pScrn->virtualX;
+
+ drmModeRmFB(pGlamo->drm_fd, pGlamo->fb_id);
+
+ /* now create new frontbuffer */
+ return CreateFrontBuffer(pScrn);
+}
+
+
+static const xf86CrtcConfigFuncsRec crtc_config_funcs = {
+ crtc_resize
+};
+
+
+Bool GlamoKMSPreInit(ScrnInfoPtr pScrn, int flags)
+{
+ xf86CrtcConfigPtr xf86_config;
+ GlamoPtr pGlamo;
+ rgb defaultWeight = { 0, 0, 0 };
+ int max_width, max_height;
+ Gamma zeros = { 0.0, 0.0, 0.0 };
+
+ /* Can't do this yet */
+ if ( flags & PROBE_DETECT ) {
+ ConfiguredMonitor = NULL;
+ return TRUE;
+ }
+
+ /* Allocate driverPrivate */
+ if ( !GlamoGetRec(pScrn) ) return FALSE;
+ pGlamo = GlamoPTR(pScrn);
+ pGlamo->SaveGeneration = -1;
+
+ pScrn->displayWidth = 24; /* Nonsense default value */
+
+ /* Open DRM */
+ pGlamo->drm_fd = drmOpen(NULL, "platform:glamo-fb");
+ if ( pGlamo->drm_fd < 0 ) return FALSE;
+
+ pScrn->monitor = pScrn->confScreen->monitor;
+ pScrn->progClock = TRUE;
+ pScrn->rgbBits = 8;
+
+ /* Prefer 16bpp for everything */
+ if ( !xf86SetDepthBpp(pScrn, 16, 16, 16, NoDepth24Support) ) {
+ return FALSE;
+ }
+
+ /* We can only handle 16bpp */
+ if ( pScrn->depth != 16 ) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Given depth (%d) is not supported by the driver\n",
+ pScrn->depth);
+ return FALSE;
+ }
+ xf86PrintDepthBpp(pScrn);
+
+ if ( !xf86SetWeight(pScrn, defaultWeight, defaultWeight) ) return FALSE;
+ if ( !xf86SetDefaultVisual(pScrn, -1) ) return FALSE;
+
+ /* Allocate an xf86CrtcConfig */
+ xf86CrtcConfigInit(pScrn, &crtc_config_funcs);
+ xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+
+ max_width = 480;
+ max_height = 640;
+ xf86CrtcSetSizeRange(pScrn, 320, 200, max_width, max_height);
+
+ crtc_init(pScrn);
+ output_init(pScrn);
+
+ if ( !xf86InitialConfiguration(pScrn, TRUE) ) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n");
+ return FALSE;
+ }
+
+ if ( !xf86SetGamma(pScrn, zeros) ) {
+ return FALSE;
+ }
+
+ if ( pScrn->modes == NULL ) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
+ return FALSE;
+ }
+
+ pScrn->currentMode = pScrn->modes;
+
+ /* Set display resolution */
+ xf86SetDpi(pScrn, 0, 0);
+
+ /* Load the required sub modules */
+ if (!xf86LoadSubModule(pScrn, "fb")) return FALSE;
+ xf86LoadSubModule(pScrn, "exa");
+ xf86LoadSubModule(pScrn, "dri2");
+
+ return TRUE;
+}
+
+
+static Bool GlamoKMSCloseScreen(int scrnIndex, ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+
+ if ( pScrn->vtSema ) {
+ GlamoKMSLeaveVT(scrnIndex, 0);
+ }
+ driCloseScreen(pScreen);
+
+ pScreen->CreateScreenResources = pGlamo->CreateScreenResources;
+
+ if ( pGlamo->exa ) {
+ GlamoKMSExaClose(pScrn);
+ }
+
+ drmClose(pGlamo->drm_fd);
+ pGlamo->drm_fd = -1;
+
+ pScrn->vtSema = FALSE;
+ pScreen->CloseScreen = pGlamo->CloseScreen;
+ return (*pScreen->CloseScreen)(scrnIndex, pScreen);
+}
+
+
+static Bool GlamoKMSCreateScreenResources(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+ PixmapPtr rootPixmap;
+ Bool ret;
+ unsigned int flags;
+
+ pScreen->CreateScreenResources = pGlamo->CreateScreenResources;
+ ret = pScreen->CreateScreenResources(pScreen);
+ pScreen->CreateScreenResources = GlamoKMSCreateScreenResources;
+
+ rootPixmap = pScreen->GetScreenPixmap(pScreen);
+
+ if (!GlamoKMSExaMakeFullyFledged(rootPixmap, -1, -1, -1, -1, -1))
+ FatalError("Couldn't adjust screen pixmap\n");
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Adding FB: %i %i %i %i %i %i\n",
+ pGlamo->drm_fd, pScrn->virtualX, pScrn->virtualY,
+ pScrn->depth, pScrn->bitsPerPixel,
+ pScrn->displayWidth * pScrn->bitsPerPixel / 8);
+
+ drmModeAddFB(pGlamo->drm_fd,
+ pScrn->virtualX,
+ pScrn->virtualY,
+ pScrn->depth,
+ pScrn->bitsPerPixel,
+ pScrn->displayWidth * pScrn->bitsPerPixel / 8,
+ driGetPixmapHandle(rootPixmap, &flags), &pGlamo->fb_id);
+
+ GlamoKMSAdjustFrame(pScrn->scrnIndex,
+ pScrn->frameX0, pScrn->frameY0,
+ 0);
+
+ return ret;
+}
+
+
+Bool GlamoKMSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc,
+ char **argv)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+ VisualPtr visual;
+
+ /* Deal with server regeneration */
+ if ( pGlamo->drm_fd < 0 ) {
+ pGlamo->drm_fd = drmOpen(NULL, "platform:glamo-fb");
+ if ( pGlamo->drm_fd < 0 ) return FALSE;
+ }
+
+ pScrn->pScreen = pScreen;
+ pGlamo->pScreen = pScreen;
+
+ /* HW dependent - FIXME */
+ pScrn->displayWidth = pScrn->virtualX;
+
+ miClearVisualTypes();
+
+ if ( !miSetVisualTypes(pScrn->depth,
+ miGetDefaultVisualMask(pScrn->depth),
+ pScrn->rgbBits, pScrn->defaultVisual) ) {
+ return FALSE;
+ }
+
+ if ( !miSetPixmapDepths() ) return FALSE;
+
+ pScrn->memPhysBase = 0;
+ pScrn->fbOffset = 0;
+
+ if ( !fbScreenInit(pScreen, NULL,
+ pScrn->virtualX, pScrn->virtualY,
+ pScrn->xDpi, pScrn->yDpi,
+ pScrn->displayWidth, pScrn->bitsPerPixel) ) {
+ return FALSE;
+ }
+
+ if (pScrn->bitsPerPixel > 8) {
+ /* Fixup RGB ordering */
+ visual = pScreen->visuals + pScreen->numVisuals;
+ while (--visual >= pScreen->visuals) {
+ if ((visual->class | DynamicClass) == DirectColor) {
+ visual->offsetRed = pScrn->offset.red;
+ visual->offsetGreen = pScrn->offset.green;
+ visual->offsetBlue = pScrn->offset.blue;
+ visual->redMask = pScrn->mask.red;
+ visual->greenMask = pScrn->mask.green;
+ visual->blueMask = pScrn->mask.blue;
+ }
+ }
+ }
+
+ fbPictureInit(pScreen, NULL, 0);
+
+ pGlamo->CreateScreenResources = pScreen->CreateScreenResources;
+ pScreen->CreateScreenResources = GlamoKMSCreateScreenResources;
+
+ xf86SetBlackWhitePixels(pScreen);
+
+ GlamoKMSExaInit(pScrn);
+
+ miInitializeBackingStore(pScreen);
+ xf86SetBackingStore(pScreen);
+ xf86SetSilkenMouse(pScreen);
+ miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
+
+ /* Must force it before EnterVT, so we are in control of VT and
+ * later memory should be bound when allocating, e.g rotate_mem */
+ pScrn->vtSema = TRUE;
+
+ pScreen->SaveScreen = xf86SaveScreen;
+ pGlamo->CloseScreen = pScreen->CloseScreen;
+ pScreen->CloseScreen = GlamoKMSCloseScreen;
+
+ if ( !xf86CrtcScreenInit(pScreen) ) return FALSE;
+
+ if ( !miCreateDefColormap(pScreen) ) return FALSE;
+
+ xf86DPMSInit(pScreen, xf86DPMSSet, 0);
+
+ if ( serverGeneration == 1 ) {
+ xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
+ }
+
+ driScreenInit(pScreen);
+
+ return GlamoKMSEnterVT(scrnIndex, 1);
+}
+
+
+Bool GlamoKMSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ return xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
+}
+
+
+Bool GlamoKMSEnterVT(int scrnIndex, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+
+ /* Only save state once per server generation since that's what most
+ * drivers do. Could change this to save state at each VT enter. */
+ if ( pGlamo->SaveGeneration != serverGeneration ) {
+ pGlamo->SaveGeneration = serverGeneration;
+ /* ...except there is no hardware state to save */
+ }
+
+ if ( !flags ) {
+ /* signals startup as we'll do this in CreateScreenResources */
+ CreateFrontBuffer(pScrn);
+ }
+
+ if ( !xf86SetDesiredModes(pScrn) ) return FALSE;
+
+ return TRUE;
+}
+
+
+void GlamoKMSLeaveVT(int scrnIndex, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+ int o;
+
+ for (o = 0; o < config->num_crtc; o++) {
+
+ xf86CrtcPtr crtc = config->crtc[o];
+
+ if ( crtc->rotatedPixmap || crtc->rotatedData ) {
+ crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap,
+ crtc->rotatedData);
+ crtc->rotatedPixmap = NULL;
+ crtc->rotatedData = NULL;
+ }
+
+ }
+
+ drmModeRmFB(pGlamo->drm_fd, pGlamo->fb_id);
+
+ pScrn->vtSema = FALSE;
+}
+
+
+ModeStatus GlamoKMSValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose,
+ int flags)
+{
+ return MODE_OK;
+}