1.6.16.4117/4.05.00.01
authorImagination Technologies/TI <imgtec>
Mon, 11 Feb 2013 00:26:08 +0000 (02:26 +0200)
committerGrazvydas Ignotas <notasas@gmail.com>
Mon, 11 Feb 2013 00:26:08 +0000 (02:26 +0200)
61 files changed:
Kbuild
Makefile
services4/3rdparty/bufferclass_ti/bc_cat.c
services4/3rdparty/dc_omapfb3_linux/omaplfb_displayclass.c
services4/3rdparty/dc_omapfb3_linux/omaplfb_linux.c
services4/3rdparty/dc_ti335x_linux/3rdparty_dc_drm_shared.h [new file with mode: 0644]
services4/3rdparty/dc_ti335x_linux/Kbuild [new file with mode: 0644]
services4/3rdparty/dc_ti335x_linux/kbuild/Makefile [new file with mode: 0644]
services4/3rdparty/dc_ti335x_linux/makefile.linux.common [new file with mode: 0644]
services4/3rdparty/dc_ti335x_linux/omaplfb.h [new file with mode: 0644]
services4/3rdparty/dc_ti335x_linux/omaplfb_displayclass.c [new file with mode: 0644]
services4/3rdparty/dc_ti335x_linux/omaplfb_linux.c [new file with mode: 0644]
services4/3rdparty/linux_drm/Kbuild_org [deleted file]
services4/3rdparty/linux_drm/drm_agpsupport.c
services4/3rdparty/linux_drm/drm_bufs.c
services4/3rdparty/linux_drm/drm_crtc.c
services4/3rdparty/linux_drm/drm_crtc_helper.c
services4/3rdparty/linux_drm/drm_debugfs.c
services4/3rdparty/linux_drm/drm_drv.c
services4/3rdparty/linux_drm/drm_edid.c
services4/3rdparty/linux_drm/drm_fb_helper.c
services4/3rdparty/linux_drm/drm_fops.c
services4/3rdparty/linux_drm/drm_gem.c
services4/3rdparty/linux_drm/drm_hashtab.c
services4/3rdparty/linux_drm/drm_info.c
services4/3rdparty/linux_drm/drm_ioc32.c
services4/3rdparty/linux_drm/drm_ioctl.c
services4/3rdparty/linux_drm/drm_irq.c
services4/3rdparty/linux_drm/drm_mm.c
services4/3rdparty/linux_drm/drm_modes.c
services4/3rdparty/linux_drm/drm_pci.c
services4/3rdparty/linux_drm/drm_platform.c
services4/3rdparty/linux_drm/drm_scatter.c
services4/3rdparty/linux_drm/drm_sman.c
services4/3rdparty/linux_drm/drm_stub.c
services4/3rdparty/linux_drm/drm_sysfs.c
services4/3rdparty/linux_drm/drm_usb.c [new file with mode: 0644]
services4/3rdparty/linux_drm/drm_vm.c
services4/srvkm/common/resman.c
services4/srvkm/devices/sgx/sgxinit.c
services4/srvkm/env/linux/event.c
services4/srvkm/env/linux/mm.c
services4/srvkm/env/linux/mm.h
services4/srvkm/env/linux/mmap.c
services4/srvkm/env/linux/module.c
services4/srvkm/env/linux/mutils.c
services4/srvkm/env/linux/mutils.h
services4/srvkm/env/linux/osfunc.c
services4/srvkm/env/linux/proc.c
services4/srvkm/env/linux/pvr_debug.c
services4/srvkm/env/linux/pvr_drm.c
services4/srvkm/env/linux/pvr_uaccess.h
services4/srvkm/hwdefs/sgxerrata.h
services4/system/ti335x/oemfuncs.h [new file with mode: 0644]
services4/system/ti335x/sysconfig.c [new file with mode: 0644]
services4/system/ti335x/sysconfig.h [new file with mode: 0644]
services4/system/ti335x/sysinfo.h [new file with mode: 0644]
services4/system/ti335x/syslocal.h [new file with mode: 0644]
services4/system/ti335x/sysutils.c [new file with mode: 0644]
services4/system/ti335x/sysutils_linux.c [new file with mode: 0644]
services4/system/ti335x/sysutils_linux_wqueue_compat.c [new file with mode: 0644]

diff --git a/Kbuild b/Kbuild
index b79c74d..47b38a2 100644 (file)
--- a/Kbuild
+++ b/Kbuild
@@ -46,11 +46,15 @@ EXTRA_CFLAGS += -DFBDEV_PRESENT
 endif
 
 
+ifeq ($(TI_PLATFORM),ti335x)
+DRIFILES = services4/srvkm/env/linux/pvr_drm.c services4/3rdparty/dc_ti335x_linux/omaplfb_linux.c services4/3rdparty/dc_ti335x_linux/omaplfb_displayclass.c 
+else
 ifeq ($(TI_PLATFORM),ti81xx)
 DRIFILES = services4/srvkm/env/linux/pvr_drm.c services4/3rdparty/dc_ti81xx_linux/omaplfb_linux.c services4/3rdparty/dc_ti81xx_linux/omaplfb_displayclass.c 
 else
 DRIFILES = services4/srvkm/env/linux/pvr_drm.c services4/3rdparty/dc_omapfb3_linux/omaplfb_linux.c services4/3rdparty/dc_omapfb3_linux/omaplfb_displayclass.c
 endif
+endif
 
 EXTRA_CFLAGS += -I$(src)/include4
 EXTRA_CFLAGS += -I$(src)/services4/include
@@ -84,13 +88,18 @@ pvrsrvkm-y +=  $(DRIFILES:.c=.o)
 endif
 
 ifneq ($(SUPPORT_XORG),1)
+ifeq ($(TI_PLATFORM),ti335x)
+obj-y := services4/3rdparty/dc_ti335x_linux/
+else
 ifeq ($(TI_PLATFORM),ti81xx)
 obj-y := services4/3rdparty/dc_ti81xx_linux/
 else
 obj-y := services4/3rdparty/dc_omapfb3_linux/
 endif
 endif
+endif
 obj-y += services4/3rdparty/bufferclass_ti/
+#obj-y += services4/3rdparty/bufferclass_example/
 
 ifeq ($(SUPPORT_XORG),1)
 obj-y += services4/3rdparty/linux_drm/
index 2e13203..cb63703 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -32,6 +32,9 @@ else
 SGXCORE = 530
 endif
 
+ifeq ($(TI_PLATFORM),ti335x)
+CORE = -DSGX530 -DSUPPORT_SGX530 -DSGX_CORE_REV=125
+else
 ifeq ($(TI_PLATFORM),omap4)
 CORE = -DSGX540 -DSUPPORT_SGX540 -DSGX_CORE_REV=120
 else
@@ -51,6 +54,7 @@ endif
 endif
 endif
 endif
+endif
 
 SUPPORT_SGX = 1
 SUPPORT_HW_RECOVERY = 1
@@ -94,11 +98,15 @@ endif
 # passive power management isn't enabled, the driver won't see the
 # system suspend/resume events, and so won't take appropriate action.
 ifeq ($(LDM_PLATFORM),1)
+ifeq ($(TI_PLATFORM),ti335x)
+SUPPORT_ACTIVE_POWER_MANAGEMENT ?= 1
+else
 ifeq ($(TI_PLATFORM),ti81xx)
 SUPPORT_ACTIVE_POWER_MANAGEMENT ?= 0
 else
 SUPPORT_ACTIVE_POWER_MANAGEMENT = 1
 endif
+endif
 else
 SUPPORT_ACTIVE_POWER_MANAGEMENT = 0
 endif
index 6cb1e7a..5861e8e 100644 (file)
@@ -126,7 +126,7 @@ static PVRSRV_ERROR BCClosePVRServices(IMG_HANDLE hPVRServices);
 static IMG_VOID *BCAllocKernelMem(unsigned long ulSize);
 static IMG_VOID BCFreeKernelMem(IMG_VOID *pvMem);
 
-static PVRSRV_ERROR BCAllocContigMemory(unsigned long ulSize,
+static BCE_ERROR BCAllocContigMemory(unsigned long ulSize,
                                IMG_HANDLE * phMemHandle,
                                IMG_CPU_VIRTADDR *pLinAddr,
                                IMG_CPU_PHYADDR *pPhysAddr);
@@ -745,7 +745,7 @@ void BCFreeDiscontigMemory(unsigned long ulSize,
 }
 #else
 
-PVRSRV_ERROR BCAllocContigMemory(unsigned long ulSize,
+BCE_ERROR BCAllocContigMemory(unsigned long ulSize,
                                  IMG_HANDLE unref__ *phMemHandle, 
                                  IMG_CPU_VIRTADDR *pLinAddr, 
                                  IMG_CPU_PHYADDR *pPhysAddr)
index 0e035ad..fb80596 100644 (file)
@@ -360,7 +360,6 @@ static PVRSRV_ERROR CreateDCSwapChain(IMG_HANDLE hDevice,
 
        UNREFERENCED_PARAMETER(ui32OEMFlags);
        
-       
        if(!hDevice
        || !psDstSurfAttrib
        || !psSrcSurfAttrib
@@ -722,7 +721,6 @@ void OMAPLFBSwapHandler(OMAPLFB_BUFFER *psBuffer)
        OMAPLFB_DEVINFO *psDevInfo = psBuffer->psDevInfo;
        OMAPLFB_SWAPCHAIN *psSwapChain = psDevInfo->psSwapChain;
        OMAPLFB_BOOL bPreviouslyNotVSynced;
-
 #if defined(SUPPORT_DRI_DRM)
        if (!OMAPLFBAtomicBoolRead(&psDevInfo->sLeaveVT))
 #endif
@@ -765,7 +763,6 @@ void OMAPLFBSwapHandler(OMAPLFB_BUFFER *psBuffer)
                                break;
                }
        }
-
        psDevInfo->sPVRJTable.pfnPVRSRVCmdComplete((IMG_HANDLE)psBuffer->hCmdComplete, IMG_TRUE);
 }
 
@@ -829,8 +826,11 @@ static OMAPLFB_ERROR OMAPLFBInitFBDev(OMAPLFB_DEVINFO *psDevInfo)
        unsigned long FBSize;
        unsigned long ulLCM;
        unsigned uiFBDevID = psDevInfo->uiFBDevID;
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+        console_lock();
+#else
        acquire_console_sem();
+#endif
 
        psLINFBInfo = registered_fb[uiFBDevID];
        if (psLINFBInfo == NULL)
@@ -972,7 +972,11 @@ static OMAPLFB_ERROR OMAPLFBInitFBDev(OMAPLFB_DEVINFO *psDevInfo)
 ErrorModPut:
        module_put(psLINFBOwner);
 ErrorRelSem:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+        console_unlock();
+#else
        release_console_sem();
+#endif
 
        return eError;
 }
@@ -981,8 +985,11 @@ static void OMAPLFBDeInitFBDev(OMAPLFB_DEVINFO *psDevInfo)
 {
        struct fb_info *psLINFBInfo = psDevInfo->psLINFBInfo;
        struct module *psLINFBOwner;
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+        console_lock();
+#else
        acquire_console_sem();
+#endif
 
        psLINFBOwner = psLINFBInfo->fbops->owner;
 
@@ -992,8 +999,11 @@ static void OMAPLFBDeInitFBDev(OMAPLFB_DEVINFO *psDevInfo)
        }
 
        module_put(psLINFBOwner);
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+        console_unlock();
+#else
        release_console_sem();
+#endif
 }
 
 static OMAPLFB_DEVINFO *OMAPLFBInitDev(unsigned uiFBDevID)
index 171e735..8aac78a 100644 (file)
@@ -236,8 +236,11 @@ void OMAPLFBFlip(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_BUFFER *psBuffer)
        struct fb_var_screeninfo sFBVar;
        int res;
        unsigned long ulYResVirtual;
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+        console_lock();
+#else
        acquire_console_sem();
+#endif
 
        sFBVar = psDevInfo->psLINFBInfo->var;
 
@@ -268,21 +271,28 @@ void OMAPLFBFlip(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_BUFFER *psBuffer)
                        printk(KERN_INFO DRIVER_PREFIX ": %s: Device %u: fb_pan_display failed (Y Offset: %lu, Error: %d)\n", __FUNCTION__, psDevInfo->uiFBDevID, psBuffer->ulYOffset, res);
                }
        }
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+        console_unlock();
+#else
        release_console_sem();
+#endif
 }
 
 OMAPLFB_UPDATE_MODE OMAPLFBGetUpdateMode(OMAPLFB_DEVINFO *psDevInfo)
 {
        struct omap_dss_device *psDSSDev = fb2display(psDevInfo->psLINFBInfo);
        OMAP_DSS_DRIVER(psDSSDrv, psDSSDev);
-
+        if (psDSSDrv == NULL || psDSSDev == NULL)
+        {
+               DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: No DSS device\n", __FUNCTION__, psDevInfo->uiFBDevID));
+        }
        enum omap_dss_update_mode eMode;
 
-       if (psDSSDrv == NULL || psDSSDrv->get_update_mode == NULL)
+       if (psDSSDrv->get_update_mode == NULL)
        {
                DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: Can't get update mode\n", __FUNCTION__, psDevInfo->uiFBDevID));
-               return OMAPLFB_UPDATE_MODE_UNDEFINED;
+               return OMAPLFB_UPDATE_MODE_AUTO;
+//             return OMAPLFB_UPDATE_MODE_UNDEFINED;
        }
 
        eMode = psDSSDrv->get_update_mode(psDSSDev);
@@ -441,10 +451,17 @@ static int OMAPLFBFrameBufferEvents(struct notifier_block *psNotif,
 OMAPLFB_ERROR OMAPLFBUnblankDisplay(OMAPLFB_DEVINFO *psDevInfo)
 {
        int res;
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+        console_lock();
+#else
        acquire_console_sem();
+#endif
        res = fb_blank(psDevInfo->psLINFBInfo, 0);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+        console_unlock();
+#else
        release_console_sem();
+#endif
        if (res != 0 && res != -EINVAL)
        {
                printk(KERN_WARNING DRIVER_PREFIX
@@ -459,9 +476,17 @@ OMAPLFB_ERROR OMAPLFBUnblankDisplay(OMAPLFB_DEVINFO *psDevInfo)
 
 static void OMAPLFBBlankDisplay(OMAPLFB_DEVINFO *psDevInfo)
 {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+        console_lock();
+#else
        acquire_console_sem();
+#endif
        fb_blank(psDevInfo->psLINFBInfo, 1);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+        console_unlock();
+#else
        release_console_sem();
+#endif
 }
 
 static void OMAPLFBEarlySuspendHandler(struct early_suspend *h)
@@ -692,9 +717,17 @@ int PVR_DRM_MAKENAME(omaplfb, _Ioctl)(struct drm_device unref__ *dev, void *arg,
                                flush_workqueue(psDevInfo->psSwapChain->psWorkQueue);
                        }
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+        console_lock();
+#else
                        acquire_console_sem();
+#endif
                        ret = fb_blank(psDevInfo->psLINFBInfo, iFBMode);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+        console_unlock();
+#else
                        release_console_sem();
+#endif
 
                        OMAPLFBCreateSwapChainUnLock(psDevInfo);
 
@@ -717,7 +750,6 @@ int PVR_DRM_MAKENAME(omaplfb, _Init)(struct drm_device unref__ *dev)
 static int __init OMAPLFB_Init(void)
 #endif
 {
-
        if(OMAPLFBInit() != OMAPLFB_OK)
        {
                printk(KERN_WARNING DRIVER_PREFIX ": %s: OMAPLFBInit failed\n", __FUNCTION__);
diff --git a/services4/3rdparty/dc_ti335x_linux/3rdparty_dc_drm_shared.h b/services4/3rdparty/dc_ti335x_linux/3rdparty_dc_drm_shared.h
new file mode 100644 (file)
index 0000000..9b6d240
--- /dev/null
@@ -0,0 +1,45 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope it will be useful but, except 
+ * as otherwise stated in writing, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
+ *
+ ******************************************************************************/
+
+#ifndef __3RDPARTY_DC_DRM_SHARED_H__
+#define __3RDPARTY_DC_DRM_SHARED_H__
+#if defined(SUPPORT_DRI_DRM)
+
+#define        PVR_DRM_DISP_CMD_ENTER_VT       1
+#define        PVR_DRM_DISP_CMD_LEAVE_VT       2
+
+#define        PVR_DRM_DISP_CMD_ON             3
+#define        PVR_DRM_DISP_CMD_STANDBY        4
+#define        PVR_DRM_DISP_CMD_SUSPEND        5
+#define        PVR_DRM_DISP_CMD_OFF            6
+
+#define        PVR_DRM_DISP_ARG_CMD            0
+#define        PVR_DRM_DISP_ARG_DEV            1
+#define        PVR_DRM_DISP_NUM_ARGS           2
+
+#endif 
+#endif 
+
diff --git a/services4/3rdparty/dc_ti335x_linux/Kbuild b/services4/3rdparty/dc_ti335x_linux/Kbuild
new file mode 100644 (file)
index 0000000..1ae2359
--- /dev/null
@@ -0,0 +1,32 @@
+SYS_USING_INTERRUPTS = 1
+SUPPORT_OMAP3430_OMAPFB3 =1
+SUPPORT_TI_DSS_FW = 0
+PVR_LINUX_USING_WORKQUEUES = 1
+
+SYS_CFLAGS.$(SYS_USING_INTERRUPTS)                      += -DSYS_USING_INTERRUPTS
+SYS_CFLAGS.$(SUPPORT_OMAP3430_OMAPFB3)                         += -DSUPPORT_OMAP3430_OMAPFB3
+SYS_CFLAGS.$(SUPPORT_TI_DSS_FW)                         += -DSUPPORT_TI_DSS_FW
+SYS_CFLAGS.$(PVR_LINUX_USING_WORKQUEUES)             += -DPVR_LINUX_USING_WORKQUEUES
+SYS_CFLAGS += -DDISPLAY_CONTROLLER=omaplfb
+
+EXTRA_CFLAGS = -DLINUX \
+               -DCONFIG_OMAP2_DSS \
+               -I$(PVR_BUILD_DIR)/include4 \
+               -I$(PVR_BUILD_DIR)/services4/include \
+               -I$(PVR_BUILD_DIR)/services4/system/$(PVR_SYSTEM) \
+               -I$(KERNELDIR)/drivers/video/omap2 \
+               -I$(PVR_BUILD_DIR)/services4/system/include \
+               $(SYS_CFLAGS.1) \
+
+ifneq ($(FBDEV),no)
+EXTRA_CFLAGS += -DFBDEV_PRESENT
+endif
+
+ifeq ($(SUPPORT_XORG),1)
+EXTRA_CFLAGS += -DSUPPORT_DRI_DRM
+EXTRA_CFLAGS += -DPVR_DISPLAY_CONTROLLER_DRM_IOCTL
+endif
+
+
+obj-m := omaplfb.o
+omaplfb-y := omaplfb_displayclass.o omaplfb_linux.o
diff --git a/services4/3rdparty/dc_ti335x_linux/kbuild/Makefile b/services4/3rdparty/dc_ti335x_linux/kbuild/Makefile
new file mode 100644 (file)
index 0000000..f52617a
--- /dev/null
@@ -0,0 +1,36 @@
+#
+# Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+# 
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+# 
+# This program is distributed in the hope it will be useful but, except 
+# as otherwise stated in writing, 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.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+# 
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# Imagination Technologies Ltd. <gpl-support@imgtec.com>
+# Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
+# 
+#
+
+MODULE         = $(DISPLAY_CONTROLLER)
+
+INCLUDES =
+
+SOURCES        =
+
+SYM_VERS_DEPS = $(EURASIAROOT)/services4/srvkm/env/linux
+
+include $(EURASIAROOT)/services4/$(DISPLAY_CONTROLLER_DIR)/makefile.linux.common
+
+include $(EURASIAROOT)/eurasiacon/build/linux/kbuild/Makefile.kbuild_subdir_common
diff --git a/services4/3rdparty/dc_ti335x_linux/makefile.linux.common b/services4/3rdparty/dc_ti335x_linux/makefile.linux.common
new file mode 100644 (file)
index 0000000..d5b4a30
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+# 
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+# 
+# This program is distributed in the hope it will be useful but, except 
+# as otherwise stated in writing, 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.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+# 
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# Imagination Technologies Ltd. <gpl-support@imgtec.com>
+# Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
+# 
+#
+#
+
+ifeq ($(SUPPORT_DRI_DRM),1)
+DISPLAY_CONTROLLER_SOURCES_ROOT = $(KBUILDROOT)/$(DISPLAY_CONTROLLER_DIR)
+MODULE_CFLAGS += -DPVR_DISPLAY_CONTROLLER_DRM_IOCTL
+else
+DISPLAY_CONTROLLER_SOURCES_ROOT = ..
+endif
+
+INCLUDES +=    -I$(EURASIAROOT)/include4 \
+               -I$(EURASIAROOT)/services4/include \
+               -I$(EURASIAROOT)/services4/system/$(PVR_SYSTEM) \
+               -I$(EURASIAROOT)/services4/system/include \
+               -I$(KERNELDIR)/drivers/video/omap2 \
+               -I$(KERNELDIR)/arch/arm/plat-omap/include
+
+SOURCES        +=      $(DISPLAY_CONTROLLER_SOURCES_ROOT)/omaplfb_displayclass.c \
+                       $(DISPLAY_CONTROLLER_SOURCES_ROOT)/omaplfb_linux.c
diff --git a/services4/3rdparty/dc_ti335x_linux/omaplfb.h b/services4/3rdparty/dc_ti335x_linux/omaplfb.h
new file mode 100644 (file)
index 0000000..f202e1e
--- /dev/null
@@ -0,0 +1,271 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope it will be useful but, except 
+ * as otherwise stated in writing, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
+ *
+ ******************************************************************************/
+
+#ifndef __OMAPLFB_H__
+#define __OMAPLFB_H__
+
+#include <linux/version.h>
+
+#include <asm/atomic.h>
+
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/notifier.h>
+#include <linux/mutex.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#define unref__ __attribute__ ((unused))
+
+typedef void *       OMAPLFB_HANDLE;
+
+typedef bool OMAPLFB_BOOL, *OMAPLFB_PBOOL;
+#define        OMAPLFB_FALSE false
+#define OMAPLFB_TRUE true
+
+typedef        atomic_t        OMAPLFB_ATOMIC_BOOL;
+
+typedef atomic_t       OMAPLFB_ATOMIC_INT;
+
+typedef struct OMAPLFB_BUFFER_TAG
+{
+       struct OMAPLFB_BUFFER_TAG       *psNext;
+       struct OMAPLFB_DEVINFO_TAG      *psDevInfo;
+
+       struct work_struct sWork;
+
+       
+       unsigned long                   ulYOffset;
+
+       
+       
+       IMG_SYS_PHYADDR                 sSysAddr;
+       IMG_CPU_VIRTADDR                sCPUVAddr;
+       PVRSRV_SYNC_DATA                *psSyncData;
+
+       OMAPLFB_HANDLE                  hCmdComplete;
+       unsigned long                   ulSwapInterval;
+} OMAPLFB_BUFFER;
+
+typedef struct OMAPLFB_SWAPCHAIN_TAG
+{
+       
+       unsigned int                    uiSwapChainID;
+
+       
+       unsigned long                   ulBufferCount;
+
+       
+       OMAPLFB_BUFFER                  *psBuffer;
+
+       
+       struct workqueue_struct         *psWorkQueue;
+
+       
+       OMAPLFB_BOOL                    bNotVSynced;
+
+       
+       int                             iBlankEvents;
+
+       
+       unsigned int                    uiFBDevID;
+} OMAPLFB_SWAPCHAIN;
+
+typedef struct OMAPLFB_FBINFO_TAG
+{
+       unsigned long       ulFBSize;
+       unsigned long       ulBufferSize;
+       unsigned long       ulRoundedBufferSize;
+       unsigned long       ulWidth;
+       unsigned long       ulHeight;
+       unsigned long       ulByteStride;
+       unsigned long       ulPhysicalWidthmm;
+       unsigned long       ulPhysicalHeightmm;
+
+       
+       
+       IMG_SYS_PHYADDR     sSysAddr;
+       IMG_CPU_VIRTADDR    sCPUVAddr;
+
+       
+       PVRSRV_PIXEL_FORMAT ePixelFormat;
+}OMAPLFB_FBINFO;
+
+typedef struct OMAPLFB_DEVINFO_TAG
+{
+       
+       unsigned int            uiFBDevID;
+
+       
+       unsigned int            uiPVRDevID;
+
+       
+       struct mutex            sCreateSwapChainMutex;
+
+       
+       OMAPLFB_BUFFER          sSystemBuffer;
+
+       
+       PVRSRV_DC_DISP2SRV_KMJTABLE     sPVRJTable;
+       
+       
+       PVRSRV_DC_SRV2DISP_KMJTABLE     sDCJTable;
+
+       
+       OMAPLFB_FBINFO          sFBInfo;
+
+       
+       OMAPLFB_SWAPCHAIN      *psSwapChain;
+
+       
+       unsigned int            uiSwapChainID;
+
+       
+       OMAPLFB_ATOMIC_BOOL     sFlushCommands;
+
+       
+       struct fb_info         *psLINFBInfo;
+
+       
+       struct notifier_block   sLINNotifBlock;
+
+       
+       
+
+       
+       IMG_DEV_VIRTADDR        sDisplayDevVAddr;
+
+       DISPLAY_INFO            sDisplayInfo;
+
+       
+       DISPLAY_FORMAT          sDisplayFormat;
+       
+       
+       DISPLAY_DIMS            sDisplayDim;
+
+       
+       OMAPLFB_ATOMIC_BOOL     sBlanked;
+
+       
+       OMAPLFB_ATOMIC_INT      sBlankEvents;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+       
+       OMAPLFB_ATOMIC_BOOL     sEarlySuspendFlag;
+
+       struct early_suspend    sEarlySuspend;
+#endif
+
+#if defined(SUPPORT_DRI_DRM)
+       OMAPLFB_ATOMIC_BOOL     sLeaveVT;
+#endif
+
+}  OMAPLFB_DEVINFO;
+
+#define        OMAPLFB_PAGE_SIZE 4096
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define        DEBUG_PRINTK(x) printk x
+#else
+#define        DEBUG_PRINTK(x)
+#endif
+
+#define DISPLAY_DEVICE_NAME "PowerVR OMAP Linux Display Driver"
+#define        DRVNAME "omaplfb"
+#define        DEVNAME DRVNAME
+#define        DRIVER_PREFIX DRVNAME
+
+typedef enum _OMAPLFB_ERROR_
+{
+       OMAPLFB_OK                             =  0,
+       OMAPLFB_ERROR_GENERIC                  =  1,
+       OMAPLFB_ERROR_OUT_OF_MEMORY            =  2,
+       OMAPLFB_ERROR_TOO_FEW_BUFFERS          =  3,
+       OMAPLFB_ERROR_INVALID_PARAMS           =  4,
+       OMAPLFB_ERROR_INIT_FAILURE             =  5,
+       OMAPLFB_ERROR_CANT_REGISTER_CALLBACK   =  6,
+       OMAPLFB_ERROR_INVALID_DEVICE           =  7,
+       OMAPLFB_ERROR_DEVICE_REGISTER_FAILED   =  8,
+       OMAPLFB_ERROR_SET_UPDATE_MODE_FAILED   =  9
+} OMAPLFB_ERROR;
+
+typedef enum _OMAPLFB_UPDATE_MODE_
+{
+       OMAPLFB_UPDATE_MODE_UNDEFINED                   = 0,
+       OMAPLFB_UPDATE_MODE_MANUAL                      = 1,
+       OMAPLFB_UPDATE_MODE_AUTO                        = 2,
+       OMAPLFB_UPDATE_MODE_DISABLED                    = 3
+} OMAPLFB_UPDATE_MODE;
+
+#ifndef UNREFERENCED_PARAMETER
+#define        UNREFERENCED_PARAMETER(param) (param) = (param)
+#endif
+
+OMAPLFB_ERROR OMAPLFBInit(void);
+OMAPLFB_ERROR OMAPLFBDeInit(void);
+
+OMAPLFB_DEVINFO *OMAPLFBGetDevInfoPtr(unsigned uiFBDevID);
+unsigned OMAPLFBMaxFBDevIDPlusOne(void);
+void *OMAPLFBAllocKernelMem(unsigned long ulSize);
+void OMAPLFBFreeKernelMem(void *pvMem);
+OMAPLFB_ERROR OMAPLFBGetLibFuncAddr(char *szFunctionName, PFN_DC_GET_PVRJTABLE *ppfnFuncTable);
+OMAPLFB_ERROR OMAPLFBCreateSwapQueue (OMAPLFB_SWAPCHAIN *psSwapChain);
+void OMAPLFBDestroySwapQueue(OMAPLFB_SWAPCHAIN *psSwapChain);
+void OMAPLFBInitBufferForSwap(OMAPLFB_BUFFER *psBuffer);
+void OMAPLFBSwapHandler(OMAPLFB_BUFFER *psBuffer);
+void OMAPLFBQueueBufferForSwap(OMAPLFB_SWAPCHAIN *psSwapChain, OMAPLFB_BUFFER *psBuffer);
+void OMAPLFBFlip(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_BUFFER *psBuffer);
+OMAPLFB_UPDATE_MODE OMAPLFBGetUpdateMode(OMAPLFB_DEVINFO *psDevInfo);
+OMAPLFB_BOOL OMAPLFBSetUpdateMode(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_UPDATE_MODE eMode);
+OMAPLFB_BOOL OMAPLFBWaitForVSync(OMAPLFB_DEVINFO *psDevInfo);
+OMAPLFB_BOOL OMAPLFBManualSync(OMAPLFB_DEVINFO *psDevInfo);
+OMAPLFB_BOOL OMAPLFBCheckModeAndSync(OMAPLFB_DEVINFO *psDevInfo);
+OMAPLFB_ERROR OMAPLFBUnblankDisplay(OMAPLFB_DEVINFO *psDevInfo);
+OMAPLFB_ERROR OMAPLFBEnableLFBEventNotification(OMAPLFB_DEVINFO *psDevInfo);
+OMAPLFB_ERROR OMAPLFBDisableLFBEventNotification(OMAPLFB_DEVINFO *psDevInfo);
+void OMAPLFBCreateSwapChainLockInit(OMAPLFB_DEVINFO *psDevInfo);
+void OMAPLFBCreateSwapChainLockDeInit(OMAPLFB_DEVINFO *psDevInfo);
+void OMAPLFBCreateSwapChainLock(OMAPLFB_DEVINFO *psDevInfo);
+void OMAPLFBCreateSwapChainUnLock(OMAPLFB_DEVINFO *psDevInfo);
+void OMAPLFBAtomicBoolInit(OMAPLFB_ATOMIC_BOOL *psAtomic, OMAPLFB_BOOL bVal);
+void OMAPLFBAtomicBoolDeInit(OMAPLFB_ATOMIC_BOOL *psAtomic);
+void OMAPLFBAtomicBoolSet(OMAPLFB_ATOMIC_BOOL *psAtomic, OMAPLFB_BOOL bVal);
+OMAPLFB_BOOL OMAPLFBAtomicBoolRead(OMAPLFB_ATOMIC_BOOL *psAtomic);
+void OMAPLFBAtomicIntInit(OMAPLFB_ATOMIC_INT *psAtomic, int iVal);
+void OMAPLFBAtomicIntDeInit(OMAPLFB_ATOMIC_INT *psAtomic);
+void OMAPLFBAtomicIntSet(OMAPLFB_ATOMIC_INT *psAtomic, int iVal);
+int OMAPLFBAtomicIntRead(OMAPLFB_ATOMIC_INT *psAtomic);
+void OMAPLFBAtomicIntInc(OMAPLFB_ATOMIC_INT *psAtomic);
+
+#endif 
+
diff --git a/services4/3rdparty/dc_ti335x_linux/omaplfb_displayclass.c b/services4/3rdparty/dc_ti335x_linux/omaplfb_displayclass.c
new file mode 100644 (file)
index 0000000..67564f7
--- /dev/null
@@ -0,0 +1,1259 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope it will be useful but, except 
+ * as otherwise stated in writing, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/notifier.h>
+
+#include "img_defs.h"
+#include "servicesext.h"
+#include "kerneldisplay.h"
+#include "omaplfb.h"
+
+#define OMAPLFB_COMMAND_COUNT          1
+
+#define        OMAPLFB_VSYNC_SETTLE_COUNT      5
+
+#define        OMAPLFB_MAX_NUM_DEVICES         1 // FB_MAX
+#if (OMAPLFB_MAX_NUM_DEVICES > FB_MAX)
+#error "OMAPLFB_MAX_NUM_DEVICES must not be greater than FB_MAX"
+#endif
+
+static OMAPLFB_DEVINFO *gapsDevInfo[OMAPLFB_MAX_NUM_DEVICES];
+
+static PFN_DC_GET_PVRJTABLE gpfnGetPVRJTable = NULL;
+
+static inline unsigned long RoundUpToMultiple(unsigned long x, unsigned long y)
+{
+       unsigned long div = x / y;
+       unsigned long rem = x % y;
+
+       return (div + ((rem == 0) ? 0 : 1)) * y;
+}
+
+static unsigned long GCD(unsigned long x, unsigned long y)
+{
+       while (y != 0)
+       {
+               unsigned long r = x % y;
+               x = y;
+               y = r;
+       }
+
+       return x;
+}
+
+static unsigned long LCM(unsigned long x, unsigned long y)
+{
+       unsigned long gcd = GCD(x, y);
+
+       return (gcd == 0) ? 0 : ((x / gcd) * y);
+}
+
+unsigned OMAPLFBMaxFBDevIDPlusOne(void)
+{
+       return OMAPLFB_MAX_NUM_DEVICES;
+}
+
+OMAPLFB_DEVINFO *OMAPLFBGetDevInfoPtr(unsigned uiFBDevID)
+{
+       WARN_ON(uiFBDevID >= OMAPLFBMaxFBDevIDPlusOne());
+
+       if (uiFBDevID >= OMAPLFB_MAX_NUM_DEVICES)
+       {
+               return NULL;
+       }
+
+       return gapsDevInfo[uiFBDevID];
+}
+
+static inline void OMAPLFBSetDevInfoPtr(unsigned uiFBDevID, OMAPLFB_DEVINFO *psDevInfo)
+{
+       WARN_ON(uiFBDevID >= OMAPLFB_MAX_NUM_DEVICES);
+
+       if (uiFBDevID < OMAPLFB_MAX_NUM_DEVICES)
+       {
+               gapsDevInfo[uiFBDevID] = psDevInfo;
+       }
+}
+
+static inline OMAPLFB_BOOL SwapChainHasChanged(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_SWAPCHAIN *psSwapChain)
+{
+       return (psDevInfo->psSwapChain != psSwapChain) ||
+               (psDevInfo->uiSwapChainID != psSwapChain->uiSwapChainID);
+}
+
+static inline OMAPLFB_BOOL DontWaitForVSync(OMAPLFB_DEVINFO *psDevInfo)
+{
+       OMAPLFB_BOOL bDontWait;
+
+       bDontWait = OMAPLFBAtomicBoolRead(&psDevInfo->sBlanked) ||
+                       OMAPLFBAtomicBoolRead(&psDevInfo->sFlushCommands);
+
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+       bDontWait = bDontWait || OMAPLFBAtomicBoolRead(&psDevInfo->sEarlySuspendFlag);
+#endif
+#if defined(SUPPORT_DRI_DRM)
+       bDontWait = bDontWait || OMAPLFBAtomicBoolRead(&psDevInfo->sLeaveVT);
+#endif
+       return bDontWait;
+}
+
+static IMG_VOID SetDCState(IMG_HANDLE hDevice, IMG_UINT32 ui32State)
+{
+       OMAPLFB_DEVINFO *psDevInfo = (OMAPLFB_DEVINFO *)hDevice;
+
+       switch (ui32State)
+       {
+               case DC_STATE_FLUSH_COMMANDS:
+                       OMAPLFBAtomicBoolSet(&psDevInfo->sFlushCommands, OMAPLFB_TRUE);
+                       break;
+               case DC_STATE_NO_FLUSH_COMMANDS:
+                       OMAPLFBAtomicBoolSet(&psDevInfo->sFlushCommands, OMAPLFB_FALSE);
+                       break;
+               default:
+                       break;
+       }
+}
+
+static PVRSRV_ERROR OpenDCDevice(IMG_UINT32 uiPVRDevID,
+                                 IMG_HANDLE *phDevice,
+                                 PVRSRV_SYNC_DATA* psSystemBufferSyncData)
+{
+       OMAPLFB_DEVINFO *psDevInfo;
+       OMAPLFB_ERROR eError;
+       unsigned uiMaxFBDevIDPlusOne = OMAPLFBMaxFBDevIDPlusOne();
+       unsigned i;
+
+       for (i = 0; i < uiMaxFBDevIDPlusOne; i++)
+       {
+               psDevInfo = OMAPLFBGetDevInfoPtr(i);
+               if (psDevInfo != NULL && psDevInfo->uiPVRDevID == uiPVRDevID)
+               {
+                       break;
+               }
+       }
+       if (i == uiMaxFBDevIDPlusOne)
+       {
+               DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX
+                       ": %s: PVR Device %u not found\n", __FUNCTION__, uiPVRDevID));
+               return PVRSRV_ERROR_INVALID_DEVICE;
+       }
+
+       
+       psDevInfo->sSystemBuffer.psSyncData = psSystemBufferSyncData;
+       
+       eError = OMAPLFBUnblankDisplay(psDevInfo);
+       if (eError != OMAPLFB_OK)
+       {
+               DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX
+                       ": %s: Device %u: OMAPLFBUnblankDisplay failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, eError));
+               return PVRSRV_ERROR_UNBLANK_DISPLAY_FAILED;
+       }
+
+       
+       *phDevice = (IMG_HANDLE)psDevInfo;
+       
+       return PVRSRV_OK;
+}
+
+static PVRSRV_ERROR CloseDCDevice(IMG_HANDLE hDevice)
+{
+#if defined(SUPPORT_DRI_DRM)
+       OMAPLFB_DEVINFO *psDevInfo = (OMAPLFB_DEVINFO *)hDevice;
+
+       OMAPLFBAtomicBoolSet(&psDevInfo->sLeaveVT, OMAPLFB_FALSE);
+       (void) OMAPLFBUnblankDisplay(psDevInfo);
+#else
+       UNREFERENCED_PARAMETER(hDevice);
+#endif
+       return PVRSRV_OK;
+}
+
+static PVRSRV_ERROR EnumDCFormats(IMG_HANDLE hDevice,
+                                  IMG_UINT32 *pui32NumFormats,
+                                  DISPLAY_FORMAT *psFormat)
+{
+       OMAPLFB_DEVINFO *psDevInfo;
+       
+       if(!hDevice || !pui32NumFormats)
+       {
+               return PVRSRV_ERROR_INVALID_PARAMS;
+       }
+
+       psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+       
+       *pui32NumFormats = 1;
+       
+       if(psFormat)
+       {
+               psFormat[0] = psDevInfo->sDisplayFormat;
+       }
+
+       return PVRSRV_OK;
+}
+
+static PVRSRV_ERROR EnumDCDims(IMG_HANDLE hDevice, 
+                               DISPLAY_FORMAT *psFormat,
+                               IMG_UINT32 *pui32NumDims,
+                               DISPLAY_DIMS *psDim)
+{
+       OMAPLFB_DEVINFO *psDevInfo;
+
+       if(!hDevice || !psFormat || !pui32NumDims)
+       {
+               return PVRSRV_ERROR_INVALID_PARAMS;
+       }
+
+       psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+
+       *pui32NumDims = 1;
+
+       
+       if(psDim)
+       {
+               psDim[0] = psDevInfo->sDisplayDim;
+       }
+       
+       return PVRSRV_OK;
+}
+
+
+static PVRSRV_ERROR GetDCSystemBuffer(IMG_HANDLE hDevice, IMG_HANDLE *phBuffer)
+{
+       OMAPLFB_DEVINFO *psDevInfo;
+       
+       if(!hDevice || !phBuffer)
+       {
+               return PVRSRV_ERROR_INVALID_PARAMS;
+       }
+
+       psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+
+       *phBuffer = (IMG_HANDLE)&psDevInfo->sSystemBuffer;
+
+       return PVRSRV_OK;
+}
+
+
+static PVRSRV_ERROR GetDCInfo(IMG_HANDLE hDevice, DISPLAY_INFO *psDCInfo)
+{
+       OMAPLFB_DEVINFO *psDevInfo;
+       
+       if(!hDevice || !psDCInfo)
+       {
+               return PVRSRV_ERROR_INVALID_PARAMS;
+       }
+
+       psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+
+       *psDCInfo = psDevInfo->sDisplayInfo;
+
+       return PVRSRV_OK;
+}
+
+static PVRSRV_ERROR GetDCBufferAddr(IMG_HANDLE        hDevice,
+                                    IMG_HANDLE        hBuffer, 
+                                    IMG_SYS_PHYADDR   **ppsSysAddr,
+                                    IMG_UINT32        *pui32ByteSize,
+                                    IMG_VOID          **ppvCpuVAddr,
+                                    IMG_HANDLE        *phOSMapInfo,
+                                    IMG_BOOL          *pbIsContiguous,
+                                       IMG_UINT32                *pui32TilingStride)
+{
+       OMAPLFB_DEVINFO *psDevInfo;
+       OMAPLFB_BUFFER *psSystemBuffer;
+
+       UNREFERENCED_PARAMETER(pui32TilingStride);
+
+       if(!hDevice)
+       {
+               return PVRSRV_ERROR_INVALID_PARAMS;
+       }
+
+       if(!hBuffer)
+       {
+               return PVRSRV_ERROR_INVALID_PARAMS;
+       }
+
+       if (!ppsSysAddr)
+       {
+               return PVRSRV_ERROR_INVALID_PARAMS;
+       }
+
+       if (!pui32ByteSize)
+       {
+               return PVRSRV_ERROR_INVALID_PARAMS;
+       }
+
+       psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+
+       psSystemBuffer = (OMAPLFB_BUFFER *)hBuffer;
+
+       *ppsSysAddr = &psSystemBuffer->sSysAddr;
+
+       *pui32ByteSize = (IMG_UINT32)psDevInfo->sFBInfo.ulBufferSize;
+
+       if (ppvCpuVAddr)
+       {
+               *ppvCpuVAddr = psSystemBuffer->sCPUVAddr;
+       }
+
+       if (phOSMapInfo)
+       {
+               *phOSMapInfo = (IMG_HANDLE)0;
+       }
+
+       if (pbIsContiguous)
+       {
+               *pbIsContiguous = IMG_TRUE;
+       }
+
+       return PVRSRV_OK;
+}
+
+static PVRSRV_ERROR CreateDCSwapChain(IMG_HANDLE hDevice,
+                                      IMG_UINT32 ui32Flags,
+                                      DISPLAY_SURF_ATTRIBUTES *psDstSurfAttrib,
+                                      DISPLAY_SURF_ATTRIBUTES *psSrcSurfAttrib,
+                                      IMG_UINT32 ui32BufferCount,
+                                      PVRSRV_SYNC_DATA **ppsSyncData,
+                                      IMG_UINT32 ui32OEMFlags,
+                                      IMG_HANDLE *phSwapChain,
+                                      IMG_UINT32 *pui32SwapChainID)
+{
+       OMAPLFB_DEVINFO *psDevInfo;
+       OMAPLFB_SWAPCHAIN *psSwapChain;
+       OMAPLFB_BUFFER *psBuffer;
+       IMG_UINT32 i;
+       PVRSRV_ERROR eError;
+       IMG_UINT32 ui32BuffersToSkip;
+
+       UNREFERENCED_PARAMETER(ui32OEMFlags);
+       
+       
+       if(!hDevice
+       || !psDstSurfAttrib
+       || !psSrcSurfAttrib
+       || !ppsSyncData
+       || !phSwapChain)
+       {
+               return PVRSRV_ERROR_INVALID_PARAMS;
+       }
+
+       psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+       
+       
+       if (psDevInfo->sDisplayInfo.ui32MaxSwapChains == 0)
+       {
+               return PVRSRV_ERROR_NOT_SUPPORTED;
+       }
+
+       OMAPLFBCreateSwapChainLock(psDevInfo);
+
+       
+       if(psDevInfo->psSwapChain != NULL)
+       {
+               eError = PVRSRV_ERROR_FLIP_CHAIN_EXISTS;
+               goto ExitUnLock;
+       }
+       
+       
+       if(ui32BufferCount > psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers)
+       {
+               eError = PVRSRV_ERROR_TOOMANYBUFFERS;
+               goto ExitUnLock;
+       }
+       
+       if ((psDevInfo->sFBInfo.ulRoundedBufferSize * (unsigned long)ui32BufferCount) > psDevInfo->sFBInfo.ulFBSize)
+       {
+               eError = PVRSRV_ERROR_TOOMANYBUFFERS;
+               goto ExitUnLock;
+       }
+
+       
+       ui32BuffersToSkip = psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers - ui32BufferCount;
+
+       
+       if(psDstSurfAttrib->pixelformat != psDevInfo->sDisplayFormat.pixelformat
+       || psDstSurfAttrib->sDims.ui32ByteStride != psDevInfo->sDisplayDim.ui32ByteStride
+       || psDstSurfAttrib->sDims.ui32Width != psDevInfo->sDisplayDim.ui32Width
+       || psDstSurfAttrib->sDims.ui32Height != psDevInfo->sDisplayDim.ui32Height)
+       {
+               
+               eError = PVRSRV_ERROR_INVALID_PARAMS;
+               goto ExitUnLock;
+       }               
+
+       if(psDstSurfAttrib->pixelformat != psSrcSurfAttrib->pixelformat
+       || psDstSurfAttrib->sDims.ui32ByteStride != psSrcSurfAttrib->sDims.ui32ByteStride
+       || psDstSurfAttrib->sDims.ui32Width != psSrcSurfAttrib->sDims.ui32Width
+       || psDstSurfAttrib->sDims.ui32Height != psSrcSurfAttrib->sDims.ui32Height)
+       {
+               
+               eError = PVRSRV_ERROR_INVALID_PARAMS;
+               goto ExitUnLock;
+       }               
+
+       
+       UNREFERENCED_PARAMETER(ui32Flags);
+       
+#if defined(PVR_OMAPFB3_UPDATE_MODE)
+       if (!OMAPLFBSetUpdateMode(psDevInfo, PVR_OMAPFB3_UPDATE_MODE))
+       {
+               printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Couldn't set frame buffer update mode %d\n", __FUNCTION__, psDevInfo->uiFBDevID, PVR_OMAPFB3_UPDATE_MODE);
+       }
+#endif
+       
+       psSwapChain = (OMAPLFB_SWAPCHAIN*)OMAPLFBAllocKernelMem(sizeof(OMAPLFB_SWAPCHAIN));
+       if(!psSwapChain)
+       {
+               eError = PVRSRV_ERROR_OUT_OF_MEMORY;
+               goto ExitUnLock;
+       }
+
+       psBuffer = (OMAPLFB_BUFFER*)OMAPLFBAllocKernelMem(sizeof(OMAPLFB_BUFFER) * ui32BufferCount);
+       if(!psBuffer)
+       {
+               eError = PVRSRV_ERROR_OUT_OF_MEMORY;
+               goto ErrorFreeSwapChain;
+       }
+
+       psSwapChain->ulBufferCount = (unsigned long)ui32BufferCount;
+       psSwapChain->psBuffer = psBuffer;
+       psSwapChain->bNotVSynced = OMAPLFB_TRUE;
+       psSwapChain->uiFBDevID = psDevInfo->uiFBDevID;
+
+       
+       for(i=0; i<ui32BufferCount-1; i++)
+       {
+               psBuffer[i].psNext = &psBuffer[i+1];
+       }
+       
+       psBuffer[i].psNext = &psBuffer[0];
+
+       
+       for(i=0; i<ui32BufferCount; i++)
+       {
+               IMG_UINT32 ui32SwapBuffer = i + ui32BuffersToSkip;
+               IMG_UINT32 ui32BufferOffset = ui32SwapBuffer * (IMG_UINT32)psDevInfo->sFBInfo.ulRoundedBufferSize;
+
+               psBuffer[i].psSyncData = ppsSyncData[i];
+
+               psBuffer[i].sSysAddr.uiAddr = psDevInfo->sFBInfo.sSysAddr.uiAddr + ui32BufferOffset;
+               psBuffer[i].sCPUVAddr = psDevInfo->sFBInfo.sCPUVAddr + ui32BufferOffset;
+               psBuffer[i].ulYOffset = ui32BufferOffset / psDevInfo->sFBInfo.ulByteStride;
+               psBuffer[i].psDevInfo = psDevInfo;
+
+               OMAPLFBInitBufferForSwap(&psBuffer[i]);
+       }
+
+       if (OMAPLFBCreateSwapQueue(psSwapChain) != OMAPLFB_OK)
+       { 
+               printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Failed to create workqueue\n", __FUNCTION__, psDevInfo->uiFBDevID);
+               eError = PVRSRV_ERROR_UNABLE_TO_INSTALL_ISR;
+               goto ErrorFreeBuffers;
+       }
+
+       if (OMAPLFBEnableLFBEventNotification(psDevInfo)!= OMAPLFB_OK)
+       {
+               eError = PVRSRV_ERROR_UNABLE_TO_ENABLE_EVENT;
+               printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Couldn't enable framebuffer event notification\n", __FUNCTION__, psDevInfo->uiFBDevID);
+               goto ErrorDestroySwapQueue;
+       }
+
+       psDevInfo->uiSwapChainID++;
+       if (psDevInfo->uiSwapChainID == 0)
+       {
+               psDevInfo->uiSwapChainID++;
+       }
+
+       psSwapChain->uiSwapChainID = psDevInfo->uiSwapChainID;
+
+       psDevInfo->psSwapChain = psSwapChain;
+
+       *pui32SwapChainID = psDevInfo->uiSwapChainID;
+
+       *phSwapChain = (IMG_HANDLE)psSwapChain;
+
+       eError = PVRSRV_OK;
+       goto ExitUnLock;
+
+ErrorDestroySwapQueue:
+       OMAPLFBDestroySwapQueue(psSwapChain);
+ErrorFreeBuffers:
+       OMAPLFBFreeKernelMem(psBuffer);
+ErrorFreeSwapChain:
+       OMAPLFBFreeKernelMem(psSwapChain);
+ExitUnLock:
+       OMAPLFBCreateSwapChainUnLock(psDevInfo);
+       return eError;
+}
+
+static PVRSRV_ERROR DestroyDCSwapChain(IMG_HANDLE hDevice,
+       IMG_HANDLE hSwapChain)
+{
+       OMAPLFB_DEVINFO *psDevInfo;
+       OMAPLFB_SWAPCHAIN *psSwapChain;
+       OMAPLFB_ERROR eError;
+
+       
+       if(!hDevice || !hSwapChain)
+       {
+               return PVRSRV_ERROR_INVALID_PARAMS;
+       }
+       
+       psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+       psSwapChain = (OMAPLFB_SWAPCHAIN*)hSwapChain;
+
+       OMAPLFBCreateSwapChainLock(psDevInfo);
+
+       if (SwapChainHasChanged(psDevInfo, psSwapChain))
+       {
+               printk(KERN_WARNING DRIVER_PREFIX
+                       ": %s: Device %u: Swap chain mismatch\n", __FUNCTION__, psDevInfo->uiFBDevID);
+
+               eError = PVRSRV_ERROR_INVALID_PARAMS;
+               goto ExitUnLock;
+       }
+
+       
+       OMAPLFBDestroySwapQueue(psSwapChain);
+
+       eError = OMAPLFBDisableLFBEventNotification(psDevInfo);
+       if (eError != OMAPLFB_OK)
+       {
+               printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Couldn't disable framebuffer event notification\n", __FUNCTION__, psDevInfo->uiFBDevID);
+       }
+
+       
+       OMAPLFBFreeKernelMem(psSwapChain->psBuffer);
+       OMAPLFBFreeKernelMem(psSwapChain);
+
+       psDevInfo->psSwapChain = NULL;
+
+       OMAPLFBFlip(psDevInfo, &psDevInfo->sSystemBuffer);
+       (void) OMAPLFBCheckModeAndSync(psDevInfo);
+
+       eError = PVRSRV_OK;
+
+ExitUnLock:
+       OMAPLFBCreateSwapChainUnLock(psDevInfo);
+
+       return eError;
+}
+
+static PVRSRV_ERROR SetDCDstRect(IMG_HANDLE hDevice,
+       IMG_HANDLE hSwapChain,
+       IMG_RECT *psRect)
+{
+       UNREFERENCED_PARAMETER(hDevice);
+       UNREFERENCED_PARAMETER(hSwapChain);
+       UNREFERENCED_PARAMETER(psRect);
+
+       
+       
+       return PVRSRV_ERROR_NOT_SUPPORTED;
+}
+
+static PVRSRV_ERROR SetDCSrcRect(IMG_HANDLE hDevice,
+                                 IMG_HANDLE hSwapChain,
+                                 IMG_RECT *psRect)
+{
+       UNREFERENCED_PARAMETER(hDevice);
+       UNREFERENCED_PARAMETER(hSwapChain);
+       UNREFERENCED_PARAMETER(psRect);
+
+       
+
+       return PVRSRV_ERROR_NOT_SUPPORTED;
+}
+
+static PVRSRV_ERROR SetDCDstColourKey(IMG_HANDLE hDevice,
+                                      IMG_HANDLE hSwapChain,
+                                      IMG_UINT32 ui32CKColour)
+{
+       UNREFERENCED_PARAMETER(hDevice);
+       UNREFERENCED_PARAMETER(hSwapChain);
+       UNREFERENCED_PARAMETER(ui32CKColour);
+
+       
+
+       return PVRSRV_ERROR_NOT_SUPPORTED;
+}
+
+static PVRSRV_ERROR SetDCSrcColourKey(IMG_HANDLE hDevice,
+                                      IMG_HANDLE hSwapChain,
+                                      IMG_UINT32 ui32CKColour)
+{
+       UNREFERENCED_PARAMETER(hDevice);
+       UNREFERENCED_PARAMETER(hSwapChain);
+       UNREFERENCED_PARAMETER(ui32CKColour);
+
+       
+
+       return PVRSRV_ERROR_NOT_SUPPORTED;
+}
+
+static PVRSRV_ERROR GetDCBuffers(IMG_HANDLE hDevice,
+                                 IMG_HANDLE hSwapChain,
+                                 IMG_UINT32 *pui32BufferCount,
+                                 IMG_HANDLE *phBuffer)
+{
+       OMAPLFB_DEVINFO   *psDevInfo;
+       OMAPLFB_SWAPCHAIN *psSwapChain;
+       PVRSRV_ERROR eError;
+       unsigned i;
+       
+       
+       if(!hDevice 
+       || !hSwapChain
+       || !pui32BufferCount
+       || !phBuffer)
+       {
+               return PVRSRV_ERROR_INVALID_PARAMS;
+       }
+       
+       psDevInfo = (OMAPLFB_DEVINFO*)hDevice;
+       psSwapChain = (OMAPLFB_SWAPCHAIN*)hSwapChain;
+
+       OMAPLFBCreateSwapChainLock(psDevInfo);
+
+       if (SwapChainHasChanged(psDevInfo, psSwapChain))
+       {
+               printk(KERN_WARNING DRIVER_PREFIX
+                       ": %s: Device %u: Swap chain mismatch\n", __FUNCTION__, psDevInfo->uiFBDevID);
+
+               eError = PVRSRV_ERROR_INVALID_PARAMS;
+               goto Exit;
+       }
+       
+       
+       *pui32BufferCount = (IMG_UINT32)psSwapChain->ulBufferCount;
+       
+       
+       for(i=0; i<psSwapChain->ulBufferCount; i++)
+       {
+               phBuffer[i] = (IMG_HANDLE)&psSwapChain->psBuffer[i];
+       }
+       
+       eError = PVRSRV_OK;
+
+Exit:
+       OMAPLFBCreateSwapChainUnLock(psDevInfo);
+
+       return eError;
+}
+
+static PVRSRV_ERROR SwapToDCBuffer(IMG_HANDLE hDevice,
+                                   IMG_HANDLE hBuffer,
+                                   IMG_UINT32 ui32SwapInterval,
+                                   IMG_HANDLE hPrivateTag,
+                                   IMG_UINT32 ui32ClipRectCount,
+                                   IMG_RECT *psClipRect)
+{
+       UNREFERENCED_PARAMETER(hDevice);
+       UNREFERENCED_PARAMETER(hBuffer);
+       UNREFERENCED_PARAMETER(ui32SwapInterval);
+       UNREFERENCED_PARAMETER(hPrivateTag);
+       UNREFERENCED_PARAMETER(ui32ClipRectCount);
+       UNREFERENCED_PARAMETER(psClipRect);
+       
+       
+
+       return PVRSRV_OK;
+}
+
+static PVRSRV_ERROR SwapToDCSystem(IMG_HANDLE hDevice,
+                                   IMG_HANDLE hSwapChain)
+{
+       UNREFERENCED_PARAMETER(hDevice);
+       UNREFERENCED_PARAMETER(hSwapChain);
+       
+       
+       return PVRSRV_OK;
+}
+
+static OMAPLFB_BOOL WaitForVSyncSettle(OMAPLFB_DEVINFO *psDevInfo)
+{
+               unsigned i;
+               for(i = 0; i < OMAPLFB_VSYNC_SETTLE_COUNT; i++)
+               {
+                       if (DontWaitForVSync(psDevInfo) || !OMAPLFBWaitForVSync(psDevInfo))
+                       {
+                               return OMAPLFB_FALSE;
+                       }
+               }
+
+               return OMAPLFB_TRUE;
+}
+
+void OMAPLFBSwapHandler(OMAPLFB_BUFFER *psBuffer)
+{
+       OMAPLFB_DEVINFO *psDevInfo = psBuffer->psDevInfo;
+       OMAPLFB_SWAPCHAIN *psSwapChain = psDevInfo->psSwapChain;
+       OMAPLFB_BOOL bPreviouslyNotVSynced;
+#if 1
+#if defined(SUPPORT_DRI_DRM)
+       if (!OMAPLFBAtomicBoolRead(&psDevInfo->sLeaveVT))
+#endif
+       {
+               OMAPLFBFlip(psDevInfo, psBuffer);
+       }
+#endif
+       bPreviouslyNotVSynced = psSwapChain->bNotVSynced;
+       psSwapChain->bNotVSynced = OMAPLFB_TRUE;
+
+
+       if (!DontWaitForVSync(psDevInfo))
+       {
+               OMAPLFB_UPDATE_MODE eMode = OMAPLFBGetUpdateMode(psDevInfo);
+               int iBlankEvents = OMAPLFBAtomicIntRead(&psDevInfo->sBlankEvents);
+
+               switch(eMode)
+               {
+                       case OMAPLFB_UPDATE_MODE_AUTO:
+                               psSwapChain->bNotVSynced = OMAPLFB_FALSE;
+
+                               if (bPreviouslyNotVSynced || psSwapChain->iBlankEvents != iBlankEvents)
+                               {
+                                       psSwapChain->iBlankEvents = iBlankEvents;
+                                       psSwapChain->bNotVSynced = !WaitForVSyncSettle(psDevInfo);
+                               } else if (psBuffer->ulSwapInterval != 0)
+                               {
+                                       psSwapChain->bNotVSynced = !OMAPLFBWaitForVSync(psDevInfo);
+                               }
+                               break;
+#if defined(PVR_OMAPFB3_MANUAL_UPDATE_SYNC_IN_SWAP)
+                       case OMAPLFB_UPDATE_MODE_MANUAL:
+                               if (psBuffer->ulSwapInterval != 0)
+                               {
+                                       (void) OMAPLFBManualSync(psDevInfo);
+                               }
+                               break;
+#endif
+                       default:
+                               break;
+               }
+       }
+
+#if 0
+#if defined(SUPPORT_DRI_DRM)
+        if (!OMAPLFBAtomicBoolRead(&psDevInfo->sLeaveVT))
+#endif
+        {
+                OMAPLFBFlip(psDevInfo, psBuffer);
+        }
+#endif
+
+       psDevInfo->sPVRJTable.pfnPVRSRVCmdComplete((IMG_HANDLE)psBuffer->hCmdComplete, IMG_TRUE);
+}
+
+static IMG_BOOL ProcessFlip(IMG_HANDLE  hCmdCookie,
+                            IMG_UINT32  ui32DataSize,
+                            IMG_VOID   *pvData)
+{
+       DISPLAYCLASS_FLIP_COMMAND *psFlipCmd;
+       OMAPLFB_DEVINFO *psDevInfo;
+       OMAPLFB_BUFFER *psBuffer;
+       OMAPLFB_SWAPCHAIN *psSwapChain;
+
+       
+       if(!hCmdCookie || !pvData)
+       {
+               return IMG_FALSE;
+       }
+
+       
+       psFlipCmd = (DISPLAYCLASS_FLIP_COMMAND*)pvData;
+
+       if (psFlipCmd == IMG_NULL || sizeof(DISPLAYCLASS_FLIP_COMMAND) != ui32DataSize)
+       {
+               return IMG_FALSE;
+       }
+
+       
+       psDevInfo = (OMAPLFB_DEVINFO*)psFlipCmd->hExtDevice;
+       psBuffer = (OMAPLFB_BUFFER*)psFlipCmd->hExtBuffer;
+       psSwapChain = (OMAPLFB_SWAPCHAIN*) psFlipCmd->hExtSwapChain;
+
+       OMAPLFBCreateSwapChainLock(psDevInfo);
+
+       if (SwapChainHasChanged(psDevInfo, psSwapChain))
+       {
+               
+               DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX
+                       ": %s: Device %u (PVR Device ID %u): The swap chain has been destroyed\n",
+                       __FUNCTION__, psDevInfo->uiFBDevID, psDevInfo->uiPVRDevID));
+       }
+       else
+       {
+               psBuffer->hCmdComplete = (OMAPLFB_HANDLE)hCmdCookie;
+               psBuffer->ulSwapInterval = (unsigned long)psFlipCmd->ui32SwapInterval;
+
+               OMAPLFBQueueBufferForSwap(psSwapChain, psBuffer);
+       }
+
+       OMAPLFBCreateSwapChainUnLock(psDevInfo);
+
+       return IMG_TRUE;
+}
+
+
+static OMAPLFB_ERROR OMAPLFBInitFBDev(OMAPLFB_DEVINFO *psDevInfo)
+{
+       struct fb_info *psLINFBInfo;
+       struct module *psLINFBOwner;
+       OMAPLFB_FBINFO *psPVRFBInfo = &psDevInfo->sFBInfo;
+       OMAPLFB_ERROR eError = OMAPLFB_ERROR_GENERIC;
+       unsigned long FBSize;
+       unsigned long ulLCM;
+       unsigned uiFBDevID = psDevInfo->uiFBDevID;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+       console_lock();
+#else
+       acquire_console_sem();
+#endif
+
+       psLINFBInfo = registered_fb[uiFBDevID];
+       if (psLINFBInfo == NULL)
+       {
+               eError = OMAPLFB_ERROR_INVALID_DEVICE;
+               goto ErrorRelSem;
+       }
+
+       FBSize = (psLINFBInfo->screen_size) != 0 ?
+                                       psLINFBInfo->screen_size :
+                                       psLINFBInfo->fix.smem_len;
+
+       
+       if (FBSize == 0 || psLINFBInfo->fix.line_length == 0)
+       {
+               eError = OMAPLFB_ERROR_INVALID_DEVICE;
+               goto ErrorRelSem;
+       }
+
+       psLINFBOwner = psLINFBInfo->fbops->owner;
+       if (!try_module_get(psLINFBOwner))
+       {
+               printk(KERN_INFO DRIVER_PREFIX
+                       ": %s: Device %u: Couldn't get framebuffer module\n", __FUNCTION__, uiFBDevID);
+
+               goto ErrorRelSem;
+       }
+
+       if (psLINFBInfo->fbops->fb_open != NULL)
+       {
+               int res;
+
+               res = psLINFBInfo->fbops->fb_open(psLINFBInfo, 0);
+               if (res != 0)
+               {
+                       printk(KERN_INFO DRIVER_PREFIX
+                               " %s: Device %u: Couldn't open framebuffer(%d)\n", __FUNCTION__, uiFBDevID, res);
+
+                       goto ErrorModPut;
+               }
+       }
+
+       psDevInfo->psLINFBInfo = psLINFBInfo;
+
+       ulLCM = LCM(psLINFBInfo->fix.line_length, OMAPLFB_PAGE_SIZE);
+
+       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+                       ": Device %u: Framebuffer physical address: 0x%lx\n",
+                       psDevInfo->uiFBDevID, psLINFBInfo->fix.smem_start));
+       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+                       ": Device %u: Framebuffer virtual address: 0x%lx\n",
+                       psDevInfo->uiFBDevID, (unsigned long)psLINFBInfo->screen_base));
+       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+                       ": Device %u: Framebuffer size: %lu\n",
+                       psDevInfo->uiFBDevID, FBSize));
+       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+                       ": Device %u: Framebuffer virtual width: %u\n",
+                       psDevInfo->uiFBDevID, psLINFBInfo->var.xres_virtual));
+       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+                       ": Device %u: Framebuffer virtual height: %u\n",
+                       psDevInfo->uiFBDevID, psLINFBInfo->var.yres_virtual));
+       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+                       ": Device %u: Framebuffer width: %u\n",
+                       psDevInfo->uiFBDevID, psLINFBInfo->var.xres));
+       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+                       ": Device %u: Framebuffer height: %u\n",
+                       psDevInfo->uiFBDevID, psLINFBInfo->var.yres));
+       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+                       ": Device %u: Framebuffer stride: %u\n",
+                       psDevInfo->uiFBDevID, psLINFBInfo->fix.line_length));
+       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+                       ": Device %u: LCM of stride and page size: %lu\n",
+                       psDevInfo->uiFBDevID, ulLCM));
+
+       
+       psPVRFBInfo->sSysAddr.uiAddr = psLINFBInfo->fix.smem_start;
+       psPVRFBInfo->sCPUVAddr = psLINFBInfo->screen_base;
+
+       psPVRFBInfo->ulWidth = psLINFBInfo->var.xres;
+       psPVRFBInfo->ulHeight = psLINFBInfo->var.yres;
+       psPVRFBInfo->ulByteStride =  psLINFBInfo->fix.line_length;
+       psPVRFBInfo->ulFBSize = FBSize;
+       psPVRFBInfo->ulBufferSize = psPVRFBInfo->ulHeight * psPVRFBInfo->ulByteStride;
+       
+       psPVRFBInfo->ulRoundedBufferSize = RoundUpToMultiple(psPVRFBInfo->ulBufferSize, ulLCM);
+
+       if(psLINFBInfo->var.bits_per_pixel == 16)
+       {
+               if((psLINFBInfo->var.red.length == 5) &&
+                       (psLINFBInfo->var.green.length == 6) && 
+                       (psLINFBInfo->var.blue.length == 5) && 
+                       (psLINFBInfo->var.red.offset == 11) &&
+                       (psLINFBInfo->var.green.offset == 5) && 
+                       (psLINFBInfo->var.blue.offset == 0) && 
+                       (psLINFBInfo->var.red.msb_right == 0)) 
+               {
+                       psPVRFBInfo->ePixelFormat = PVRSRV_PIXEL_FORMAT_RGB565;
+               }
+               else
+               {
+                       printk(KERN_INFO DRIVER_PREFIX ": %s: Device %u: Unknown FB format\n", __FUNCTION__, uiFBDevID);
+               }
+       }
+       else if(psLINFBInfo->var.bits_per_pixel == 32)
+       {
+               if((psLINFBInfo->var.red.length == 8) &&
+                       (psLINFBInfo->var.green.length == 8) && 
+                       (psLINFBInfo->var.blue.length == 8) && 
+                       (psLINFBInfo->var.red.offset == 16) &&
+                       (psLINFBInfo->var.green.offset == 8) && 
+                       (psLINFBInfo->var.blue.offset == 0) && 
+                       (psLINFBInfo->var.red.msb_right == 0)) 
+               {
+                       psPVRFBInfo->ePixelFormat = PVRSRV_PIXEL_FORMAT_ARGB8888;
+               }
+               else
+               {
+                       printk(KERN_INFO DRIVER_PREFIX ": %s: Device %u: Unknown FB format\n", __FUNCTION__, uiFBDevID);
+               }
+       }       
+       else
+       {
+               printk(KERN_INFO DRIVER_PREFIX ": %s: Device %u: Unknown FB format\n", __FUNCTION__, uiFBDevID);
+       }
+
+       psDevInfo->sFBInfo.ulPhysicalWidthmm =
+               ((int)psLINFBInfo->var.width  > 0) ? psLINFBInfo->var.width  : 90;
+
+       psDevInfo->sFBInfo.ulPhysicalHeightmm =
+               ((int)psLINFBInfo->var.height > 0) ? psLINFBInfo->var.height : 54;
+
+       
+       psDevInfo->sFBInfo.sSysAddr.uiAddr = psPVRFBInfo->sSysAddr.uiAddr;
+       psDevInfo->sFBInfo.sCPUVAddr = psPVRFBInfo->sCPUVAddr;
+
+       eError = OMAPLFB_OK;
+       goto ErrorRelSem;
+
+ErrorModPut:
+       module_put(psLINFBOwner);
+ErrorRelSem:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+       console_unlock();
+#else
+       release_console_sem();
+#endif
+
+       return eError;
+}
+
+static void OMAPLFBDeInitFBDev(OMAPLFB_DEVINFO *psDevInfo)
+{
+       struct fb_info *psLINFBInfo = psDevInfo->psLINFBInfo;
+       struct module *psLINFBOwner;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+       console_lock();
+#else
+       acquire_console_sem();
+#endif
+       psLINFBOwner = psLINFBInfo->fbops->owner;
+
+       if (psLINFBInfo->fbops->fb_release != NULL) 
+       {
+               (void) psLINFBInfo->fbops->fb_release(psLINFBInfo, 0);
+       }
+
+       module_put(psLINFBOwner);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+        console_unlock();
+#else
+       release_console_sem();
+#endif
+}
+
+static OMAPLFB_DEVINFO *OMAPLFBInitDev(unsigned uiFBDevID)
+{
+       PFN_CMD_PROC            pfnCmdProcList[OMAPLFB_COMMAND_COUNT];
+       IMG_UINT32              aui32SyncCountList[OMAPLFB_COMMAND_COUNT][2];
+       OMAPLFB_DEVINFO         *psDevInfo = NULL;
+
+       
+       psDevInfo = (OMAPLFB_DEVINFO *)OMAPLFBAllocKernelMem(sizeof(OMAPLFB_DEVINFO));
+
+       if(psDevInfo == NULL)
+       {
+               printk(KERN_ERR DRIVER_PREFIX
+                       ": %s: Device %u: Couldn't allocate device information structure\n", __FUNCTION__, uiFBDevID);
+
+               goto ErrorExit;
+       }
+
+       
+       memset(psDevInfo, 0, sizeof(OMAPLFB_DEVINFO));
+
+       psDevInfo->uiFBDevID = uiFBDevID;
+
+       
+       if(!(*gpfnGetPVRJTable)(&psDevInfo->sPVRJTable))
+       {
+               goto ErrorFreeDevInfo;
+       }
+#ifdef FBDEV_PRESENT
+       
+       if(OMAPLFBInitFBDev(psDevInfo) != OMAPLFB_OK)
+       {
+               
+               goto ErrorFreeDevInfo;
+       }
+
+       psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = (IMG_UINT32)(psDevInfo->sFBInfo.ulFBSize / psDevInfo->sFBInfo.ulRoundedBufferSize);
+       if (psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers != 0)
+       {
+               psDevInfo->sDisplayInfo.ui32MaxSwapChains = 1;
+               psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 1;
+       }
+
+       psDevInfo->sDisplayInfo.ui32PhysicalWidthmm = psDevInfo->sFBInfo.ulPhysicalWidthmm;
+       psDevInfo->sDisplayInfo.ui32PhysicalHeightmm = psDevInfo->sFBInfo.ulPhysicalHeightmm;
+
+       strncpy(psDevInfo->sDisplayInfo.szDisplayName, DISPLAY_DEVICE_NAME, MAX_DISPLAY_NAME_SIZE);
+
+       psDevInfo->sDisplayFormat.pixelformat = psDevInfo->sFBInfo.ePixelFormat;
+       psDevInfo->sDisplayDim.ui32Width      = (IMG_UINT32)psDevInfo->sFBInfo.ulWidth;
+       psDevInfo->sDisplayDim.ui32Height     = (IMG_UINT32)psDevInfo->sFBInfo.ulHeight;
+       psDevInfo->sDisplayDim.ui32ByteStride = (IMG_UINT32)psDevInfo->sFBInfo.ulByteStride;
+
+       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+               ": Device %u: Maximum number of swap chain buffers: %u\n",
+               psDevInfo->uiFBDevID, psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers));
+
+               
+       
+       psDevInfo->sSystemBuffer.sSysAddr = psDevInfo->sFBInfo.sSysAddr;
+       psDevInfo->sSystemBuffer.sCPUVAddr = psDevInfo->sFBInfo.sCPUVAddr;
+       psDevInfo->sSystemBuffer.psDevInfo = psDevInfo;
+
+       OMAPLFBInitBufferForSwap(&psDevInfo->sSystemBuffer);
+#else
+                psDevInfo->sSystemBuffer.sCPUVAddr = 0x100;
+//                psDevInfo->sSystemBuffer.ulBufferSize = 600*3200;
+
+                psDevInfo->sDisplayFormat.pixelformat = 20;
+                psDevInfo->sFBInfo.ulWidth      =  800;
+                psDevInfo->sFBInfo.ulHeight     =  600;
+                psDevInfo->sFBInfo.ulByteStride =  3200;
+                psDevInfo->sFBInfo.ulFBSize     =  8388608;
+                psDevInfo->sFBInfo.ulBufferSize = 600*3200;
+#endif
+
+
+       psDevInfo->sDCJTable.ui32TableSize = sizeof(PVRSRV_DC_SRV2DISP_KMJTABLE);
+       psDevInfo->sDCJTable.pfnOpenDCDevice = OpenDCDevice;
+       psDevInfo->sDCJTable.pfnCloseDCDevice = CloseDCDevice;
+       psDevInfo->sDCJTable.pfnEnumDCFormats = EnumDCFormats;
+       psDevInfo->sDCJTable.pfnEnumDCDims = EnumDCDims;
+       psDevInfo->sDCJTable.pfnGetDCSystemBuffer = GetDCSystemBuffer;
+       psDevInfo->sDCJTable.pfnGetDCInfo = GetDCInfo;
+       psDevInfo->sDCJTable.pfnGetBufferAddr = GetDCBufferAddr;
+       psDevInfo->sDCJTable.pfnCreateDCSwapChain = CreateDCSwapChain;
+       psDevInfo->sDCJTable.pfnDestroyDCSwapChain = DestroyDCSwapChain;
+       psDevInfo->sDCJTable.pfnSetDCDstRect = SetDCDstRect;
+       psDevInfo->sDCJTable.pfnSetDCSrcRect = SetDCSrcRect;
+       psDevInfo->sDCJTable.pfnSetDCDstColourKey = SetDCDstColourKey;
+       psDevInfo->sDCJTable.pfnSetDCSrcColourKey = SetDCSrcColourKey;
+       psDevInfo->sDCJTable.pfnGetDCBuffers = GetDCBuffers;
+       psDevInfo->sDCJTable.pfnSwapToDCBuffer = SwapToDCBuffer;
+       psDevInfo->sDCJTable.pfnSwapToDCSystem = SwapToDCSystem;
+       psDevInfo->sDCJTable.pfnSetDCState = SetDCState;
+
+       
+       if(psDevInfo->sPVRJTable.pfnPVRSRVRegisterDCDevice(
+               &psDevInfo->sDCJTable,
+               &psDevInfo->uiPVRDevID) != PVRSRV_OK)
+       {
+               printk(KERN_ERR DRIVER_PREFIX
+                       ": %s: Device %u: PVR Services device registration failed\n", __FUNCTION__, uiFBDevID);
+
+               goto ErrorDeInitFBDev;
+       }
+       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX
+               ": Device %u: PVR Device ID: %u\n",
+               psDevInfo->uiFBDevID, psDevInfo->uiPVRDevID));
+       
+       
+       pfnCmdProcList[DC_FLIP_COMMAND] = ProcessFlip;
+
+       
+       aui32SyncCountList[DC_FLIP_COMMAND][0] = 0; 
+       aui32SyncCountList[DC_FLIP_COMMAND][1] = 2; 
+
+       
+
+
+
+       if (psDevInfo->sPVRJTable.pfnPVRSRVRegisterCmdProcList(psDevInfo->uiPVRDevID,
+                                                                                                                       &pfnCmdProcList[0],
+                                                                                                                       aui32SyncCountList,
+                                                                                                                       OMAPLFB_COMMAND_COUNT) != PVRSRV_OK)
+       {
+               printk(KERN_ERR DRIVER_PREFIX
+                       ": %s: Device %u: Couldn't register command processing functions with PVR Services\n", __FUNCTION__, uiFBDevID);
+               goto ErrorUnregisterDevice;
+       }
+
+       OMAPLFBCreateSwapChainLockInit(psDevInfo);
+
+       OMAPLFBAtomicBoolInit(&psDevInfo->sBlanked, OMAPLFB_FALSE);
+       OMAPLFBAtomicIntInit(&psDevInfo->sBlankEvents, 0);
+       OMAPLFBAtomicBoolInit(&psDevInfo->sFlushCommands, OMAPLFB_FALSE);
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+       OMAPLFBAtomicBoolInit(&psDevInfo->sEarlySuspendFlag, OMAPLFB_FALSE);
+#endif
+#if defined(SUPPORT_DRI_DRM)
+       OMAPLFBAtomicBoolInit(&psDevInfo->sLeaveVT, OMAPLFB_FALSE);
+#endif
+       return psDevInfo;
+
+ErrorUnregisterDevice:
+       (void)psDevInfo->sPVRJTable.pfnPVRSRVRemoveDCDevice(psDevInfo->uiPVRDevID);
+ErrorDeInitFBDev:
+       OMAPLFBDeInitFBDev(psDevInfo);
+ErrorFreeDevInfo:
+       OMAPLFBFreeKernelMem(psDevInfo);
+ErrorExit:
+       return NULL;
+}
+
+OMAPLFB_ERROR OMAPLFBInit(void)
+{
+       unsigned uiMaxFBDevIDPlusOne = OMAPLFBMaxFBDevIDPlusOne();
+       unsigned i;
+       unsigned uiDevicesFound = 0;
+
+       if(OMAPLFBGetLibFuncAddr ("PVRGetDisplayClassJTable", &gpfnGetPVRJTable) != OMAPLFB_OK)
+       {
+               return OMAPLFB_ERROR_INIT_FAILURE;
+       }
+
+       
+       for(i = uiMaxFBDevIDPlusOne; i-- != 0;)
+       {
+               OMAPLFB_DEVINFO *psDevInfo = OMAPLFBInitDev(i);
+
+               if (psDevInfo != NULL)
+               {
+                       
+                       OMAPLFBSetDevInfoPtr(psDevInfo->uiFBDevID, psDevInfo);
+                       uiDevicesFound++;
+               }
+       }
+
+       return (uiDevicesFound != 0) ? OMAPLFB_OK : OMAPLFB_ERROR_INIT_FAILURE;
+}
+
+static OMAPLFB_BOOL OMAPLFBDeInitDev(OMAPLFB_DEVINFO *psDevInfo)
+{
+       PVRSRV_DC_DISP2SRV_KMJTABLE *psPVRJTable = &psDevInfo->sPVRJTable;
+
+       OMAPLFBCreateSwapChainLockDeInit(psDevInfo);
+
+       OMAPLFBAtomicBoolDeInit(&psDevInfo->sBlanked);
+       OMAPLFBAtomicIntDeInit(&psDevInfo->sBlankEvents);
+       OMAPLFBAtomicBoolDeInit(&psDevInfo->sFlushCommands);
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+       OMAPLFBAtomicBoolDeInit(&psDevInfo->sEarlySuspendFlag);
+#endif
+#if defined(SUPPORT_DRI_DRM)
+       OMAPLFBAtomicBoolDeInit(&psDevInfo->sLeaveVT);
+#endif
+       psPVRJTable = &psDevInfo->sPVRJTable;
+
+       if (psPVRJTable->pfnPVRSRVRemoveCmdProcList (psDevInfo->uiPVRDevID, OMAPLFB_COMMAND_COUNT) != PVRSRV_OK)
+       {
+               printk(KERN_ERR DRIVER_PREFIX
+                       ": %s: Device %u: PVR Device %u: Couldn't unregister command processing functions\n", __FUNCTION__, psDevInfo->uiFBDevID, psDevInfo->uiPVRDevID);
+               return OMAPLFB_FALSE;
+       }
+
+       
+       if (psPVRJTable->pfnPVRSRVRemoveDCDevice(psDevInfo->uiPVRDevID) != PVRSRV_OK)
+       {
+               printk(KERN_ERR DRIVER_PREFIX
+                       ": %s: Device %u: PVR Device %u: Couldn't remove device from PVR Services\n", __FUNCTION__, psDevInfo->uiFBDevID, psDevInfo->uiPVRDevID);
+               return OMAPLFB_FALSE;
+       }
+#ifdef FBDEV_PRESENT   
+       OMAPLFBDeInitFBDev(psDevInfo);
+#endif
+       OMAPLFBSetDevInfoPtr(psDevInfo->uiFBDevID, NULL);
+
+       
+       OMAPLFBFreeKernelMem(psDevInfo);
+
+       return OMAPLFB_TRUE;
+}
+
+OMAPLFB_ERROR OMAPLFBDeInit(void)
+{
+       unsigned uiMaxFBDevIDPlusOne = OMAPLFBMaxFBDevIDPlusOne();
+       unsigned i;
+       OMAPLFB_BOOL bError = OMAPLFB_FALSE;
+
+       for(i = 0; i < uiMaxFBDevIDPlusOne; i++)
+       {
+               OMAPLFB_DEVINFO *psDevInfo = OMAPLFBGetDevInfoPtr(i);
+
+               if (psDevInfo != NULL)
+               {
+                       bError |= !OMAPLFBDeInitDev(psDevInfo);
+               }
+       }
+
+       return (bError) ? OMAPLFB_ERROR_INIT_FAILURE : OMAPLFB_OK;
+}
+
diff --git a/services4/3rdparty/dc_ti335x_linux/omaplfb_linux.c b/services4/3rdparty/dc_ti335x_linux/omaplfb_linux.c
new file mode 100644 (file)
index 0000000..c07ddf2
--- /dev/null
@@ -0,0 +1,836 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope it will be useful but, except 
+ * as otherwise stated in writing, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
+#ifndef AUTOCONF_INCLUDED
+#include <linux/config.h>
+#endif
+#endif
+
+
+#include <asm/atomic.h>
+
+#if defined(SUPPORT_DRI_DRM)
+#include <drm/drmP.h>
+#else
+#include <linux/module.h>
+#endif
+
+//#include <linux/time.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/hardirq.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/omapfb.h>
+#include <linux/mutex.h>
+
+#include <video/da8xx-fb.h>
+#include <plat/vrfb.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
+#define PVR_OMAPFB3_NEEDS_PLAT_VRFB_H
+#endif
+
+#if defined(PVR_OMAPFB3_NEEDS_PLAT_VRFB_H)
+# include <plat/vrfb.h>
+#else
+# if defined(PVR_OMAPFB3_NEEDS_MACH_VRFB_H)
+#  include <mach/vrfb.h>
+# endif
+#endif
+
+#if defined(DEBUG)
+#define        PVR_DEBUG DEBUG
+#undef DEBUG
+#endif
+#include <omapfb/omapfb.h>
+#if defined(DEBUG)
+#undef DEBUG
+#endif
+#if defined(PVR_DEBUG)
+#define        DEBUG PVR_DEBUG
+#undef PVR_DEBUG
+#endif
+
+#include "img_defs.h"
+#include "servicesext.h"
+#include "kerneldisplay.h"
+#include "omaplfb.h"
+#include "pvrmodule.h"
+#if defined(SUPPORT_DRI_DRM)
+#include "pvr_drm.h"
+#include "3rdparty_dc_drm_shared.h"
+#endif
+
+#if 0
+#if !defined(PVR_LINUX_USING_WORKQUEUES)
+#error "PVR_LINUX_USING_WORKQUEUES must be defined"
+#endif
+#endif
+
+MODULE_SUPPORTED_DEVICE(DEVNAME);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
+#define OMAP_DSS_DRIVER(drv, dev) struct omap_dss_driver *drv = (dev) != NULL ? (dev)->driver : NULL
+#define OMAP_DSS_MANAGER(man, dev) struct omap_overlay_manager *man = (dev) != NULL ? (dev)->manager : NULL
+#define        WAIT_FOR_VSYNC(man)     ((man)->wait_for_vsync)
+#else
+#define OMAP_DSS_DRIVER(drv, dev) struct omap_dss_device *drv = (dev)
+#define OMAP_DSS_MANAGER(man, dev) struct omap_dss_device *man = (dev)
+#define        WAIT_FOR_VSYNC(man)     ((man)->wait_vsync)
+#endif
+
+void *OMAPLFBAllocKernelMem(unsigned long ulSize)
+{
+       return kmalloc(ulSize, GFP_KERNEL);
+}
+
+void OMAPLFBFreeKernelMem(void *pvMem)
+{
+       kfree(pvMem);
+}
+
+void OMAPLFBCreateSwapChainLockInit(OMAPLFB_DEVINFO *psDevInfo)
+{
+       mutex_init(&psDevInfo->sCreateSwapChainMutex);
+}
+
+void OMAPLFBCreateSwapChainLockDeInit(OMAPLFB_DEVINFO *psDevInfo)
+{
+       mutex_destroy(&psDevInfo->sCreateSwapChainMutex);
+}
+
+void OMAPLFBCreateSwapChainLock(OMAPLFB_DEVINFO *psDevInfo)
+{
+       mutex_lock(&psDevInfo->sCreateSwapChainMutex);
+}
+
+void OMAPLFBCreateSwapChainUnLock(OMAPLFB_DEVINFO *psDevInfo)
+{
+       mutex_unlock(&psDevInfo->sCreateSwapChainMutex);
+}
+
+void OMAPLFBAtomicBoolInit(OMAPLFB_ATOMIC_BOOL *psAtomic, OMAPLFB_BOOL bVal)
+{
+       atomic_set(psAtomic, (int)bVal);
+}
+
+void OMAPLFBAtomicBoolDeInit(OMAPLFB_ATOMIC_BOOL *psAtomic)
+{
+}
+
+void OMAPLFBAtomicBoolSet(OMAPLFB_ATOMIC_BOOL *psAtomic, OMAPLFB_BOOL bVal)
+{
+       atomic_set(psAtomic, (int)bVal);
+}
+
+OMAPLFB_BOOL OMAPLFBAtomicBoolRead(OMAPLFB_ATOMIC_BOOL *psAtomic)
+{
+       return (OMAPLFB_BOOL)atomic_read(psAtomic);
+}
+
+void OMAPLFBAtomicIntInit(OMAPLFB_ATOMIC_INT *psAtomic, int iVal)
+{
+       atomic_set(psAtomic, iVal);
+}
+
+void OMAPLFBAtomicIntDeInit(OMAPLFB_ATOMIC_INT *psAtomic)
+{
+}
+
+void OMAPLFBAtomicIntSet(OMAPLFB_ATOMIC_INT *psAtomic, int iVal)
+{
+       atomic_set(psAtomic, iVal);
+}
+
+int OMAPLFBAtomicIntRead(OMAPLFB_ATOMIC_INT *psAtomic)
+{
+       return atomic_read(psAtomic);
+}
+
+void OMAPLFBAtomicIntInc(OMAPLFB_ATOMIC_INT *psAtomic)
+{
+       atomic_inc(psAtomic);
+}
+
+OMAPLFB_ERROR OMAPLFBGetLibFuncAddr (char *szFunctionName, PFN_DC_GET_PVRJTABLE *ppfnFuncTable)
+{
+       if(strcmp("PVRGetDisplayClassJTable", szFunctionName) != 0)
+       {
+               return (OMAPLFB_ERROR_INVALID_PARAMS);
+       }
+
+       
+       *ppfnFuncTable = PVRGetDisplayClassJTable;
+
+       return (OMAPLFB_OK);
+}
+
+void OMAPLFBQueueBufferForSwap(OMAPLFB_SWAPCHAIN *psSwapChain, OMAPLFB_BUFFER *psBuffer)
+{
+       int res = queue_work(psSwapChain->psWorkQueue, &psBuffer->sWork);
+
+       if (res == 0)
+       {
+               printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: Buffer already on work queue\n", __FUNCTION__, psSwapChain->uiFBDevID);
+       }
+}
+
+static void WorkQueueHandler(struct work_struct *psWork)
+{
+       OMAPLFB_BUFFER *psBuffer = container_of(psWork, OMAPLFB_BUFFER, sWork);
+
+       OMAPLFBSwapHandler(psBuffer);
+}
+
+OMAPLFB_ERROR OMAPLFBCreateSwapQueue(OMAPLFB_SWAPCHAIN *psSwapChain)
+{
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34))
+        psSwapChain->psWorkQueue = __create_workqueue(DEVNAME, 1, 1, 1);
+#else  
+       psSwapChain->psWorkQueue = create_workqueue(DEVNAME);
+#endif
+       if (psSwapChain->psWorkQueue == NULL)
+       {
+               printk(KERN_WARNING DRIVER_PREFIX ": %s: Device %u: create_singlethreaded_workqueue failed\n", __FUNCTION__, psSwapChain->uiFBDevID);
+
+               return (OMAPLFB_ERROR_INIT_FAILURE);
+       }
+
+       return (OMAPLFB_OK);
+}
+
+void OMAPLFBInitBufferForSwap(OMAPLFB_BUFFER *psBuffer)
+{
+       INIT_WORK(&psBuffer->sWork, WorkQueueHandler);
+}
+
+void OMAPLFBDestroySwapQueue(OMAPLFB_SWAPCHAIN *psSwapChain)
+{
+       destroy_workqueue(psSwapChain->psWorkQueue);
+}
+
+void OMAPLFBFlip(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_BUFFER *psBuffer)
+{
+       struct fb_var_screeninfo sFBVar;
+       int res;
+       unsigned long ulYResVirtual;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+       console_lock();
+#else
+       acquire_console_sem();
+#endif
+
+       sFBVar = psDevInfo->psLINFBInfo->var;
+
+       sFBVar.xoffset = 0;
+       sFBVar.yoffset = psBuffer->ulYOffset;
+
+       ulYResVirtual = psBuffer->ulYOffset + sFBVar.yres;
+       
+       if (sFBVar.xres_virtual != sFBVar.xres || sFBVar.yres_virtual < ulYResVirtual)
+       {
+               sFBVar.xres_virtual = sFBVar.xres;
+               sFBVar.yres_virtual = ulYResVirtual;
+
+               sFBVar.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
+
+               res = fb_set_var(psDevInfo->psLINFBInfo, &sFBVar);
+               if (res != 0)
+               {
+                       printk(KERN_INFO DRIVER_PREFIX ": %s: Device %u: fb_set_var failed (Y Offset: %lu, Error: %d)\n", __FUNCTION__, psDevInfo->uiFBDevID, psBuffer->ulYOffset, res);
+               }
+       }
+       else
+       {
+               res = fb_pan_display(psDevInfo->psLINFBInfo, &sFBVar);
+               if (res != 0)
+               {
+                        printk (" fb_pan api failed \n");
+                       printk(KERN_INFO DRIVER_PREFIX ": %s: Device %u: fb_pan_display failed (Y Offset: %lu, Error: %d)\n", __FUNCTION__, psDevInfo->uiFBDevID, psBuffer->ulYOffset, res);
+               }
+       }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+       console_unlock();
+#else
+       release_console_sem();
+#endif
+}
+
+OMAPLFB_UPDATE_MODE OMAPLFBGetUpdateMode(OMAPLFB_DEVINFO *psDevInfo)
+{
+#if 0
+       struct omap_dss_device *psDSSDev = fb2display(psDevInfo->psLINFBInfo);
+       OMAP_DSS_DRIVER(psDSSDrv, psDSSDev);
+
+       enum omap_dss_update_mode eMode;
+
+       if (psDSSDrv == NULL || psDSSDrv->get_update_mode == NULL)
+       {
+               DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: Can't get update mode\n", __FUNCTION__, psDevInfo->uiFBDevID));
+               return OMAPLFB_UPDATE_MODE_UNDEFINED;
+       }
+
+       eMode = psDSSDrv->get_update_mode(psDSSDev);
+       switch(eMode)
+       {
+               case OMAP_DSS_UPDATE_AUTO:
+                       return OMAPLFB_UPDATE_MODE_AUTO;
+               case OMAP_DSS_UPDATE_MANUAL:
+                       return OMAPLFB_UPDATE_MODE_MANUAL;
+               case OMAP_DSS_UPDATE_DISABLED:
+                       return OMAPLFB_UPDATE_MODE_DISABLED;
+               default:
+                       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: Unknown update mode (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, eMode));
+                       break;
+       }
+
+       return OMAPLFB_UPDATE_MODE_UNDEFINED;
+#endif
+        return OMAPLFB_UPDATE_MODE_AUTO;
+}
+
+OMAPLFB_BOOL OMAPLFBSetUpdateMode(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_UPDATE_MODE eMode)
+{
+#if 0
+       struct omap_dss_device *psDSSDev = fb2display(psDevInfo->psLINFBInfo);
+       OMAP_DSS_DRIVER(psDSSDrv, psDSSDev);
+       enum omap_dss_update_mode eDSSMode;
+       int res;
+
+       if (psDSSDrv == NULL || psDSSDrv->set_update_mode == NULL)
+       {
+               DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: Can't set update mode\n", __FUNCTION__, psDevInfo->uiFBDevID));
+               return OMAPLFB_FALSE;
+       }
+
+       switch(eMode)
+       {
+               case OMAPLFB_UPDATE_MODE_AUTO:
+                       eDSSMode = OMAP_DSS_UPDATE_AUTO;
+                       break;
+               case OMAPLFB_UPDATE_MODE_MANUAL:
+                       eDSSMode = OMAP_DSS_UPDATE_MANUAL;
+                       break;
+               case OMAPLFB_UPDATE_MODE_DISABLED:
+                       eDSSMode = OMAP_DSS_UPDATE_DISABLED;
+                       break;
+               default:
+                       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: Unknown update mode (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, eMode));
+                       return OMAPLFB_FALSE;
+       }
+
+       res = psDSSDrv->set_update_mode(psDSSDev, eDSSMode);
+       if (res != 0)
+       {
+               DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: set_update_mode failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, res));
+       }
+
+       return (res == 0);
+#endif
+        return 1;
+}
+
+OMAPLFB_BOOL OMAPLFBWaitForVSync(OMAPLFB_DEVINFO *psDevInfo)
+{
+//struct timeval tv;
+//static time_t curtime,curtime1;
+//     struct omap_dss_device *psDSSDev = fb2display(psDevInfo->psLINFBInfo);
+//     OMAP_DSS_MANAGER(psDSSMan, psDSSDev);
+//        printk("Testing vsync\n");
+/*     if (psDSSMan != NULL && WAIT_FOR_VSYNC(psDSSMan) != NULL)
+       {
+               printk("Vsync call\n");
+               do_gettimeofday(&tv);
+               curtime=tv.tv_usec;
+               printk("The time is %ld\n",curtime);
+               int res = WAIT_FOR_VSYNC(psDSSMan)(psDSSMan);
+               do_gettimeofday(&tv);
+                curtime1=tv.tv_usec;
+               printk("The time is %ld\n",curtime1);
+               if (res != 0)
+               {
+                       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: Wait for vsync failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, res));
+                       return OMAPLFB_FALSE;
+               }
+       }*/
+#if 0
+        struct vps_grpx_ctrl *gctrl;
+        int r;
+        gctrl = vps_grpx_get_ctrl(psDevInfo->uiFBDevID); 
+        printk (" BVSYNC \n");
+        r = gctrl->wait_for_vsync(gctrl);
+        printk (" AVSYNC: %d\n", vsync_num++);
+        return OMAPLFB_TRUE;
+#endif
+//    unsigned long timeout = msecs_to_jiffies(500);
+
+#if FBDEV_PRESENT
+      int r;
+
+      void grpx_irq_wait_handler(void *data)
+      {
+          complete((struct completion *)data);
+//     do_gettimeofday(&tv);
+  //      curtime=tv.tv_usec;
+//printk("The time in handler is %ld\n",curtime);
+      }
+      DECLARE_COMPLETION_ONSTACK(completion);
+
+      if (register_vsync_cb((vsync_callback_t)grpx_irq_wait_handler, &completion, psDevInfo->uiFBDevID) != 0)
+      {
+          printk (KERN_WARNING DRIVER_PREFIX ": Failed to register for vsync call back\n");
+          return OMAPLFB_FALSE;
+      }
+//do_gettimeofday(&tv);
+//curtime=tv.tv_usec;
+//printk("The time is %ld\n",curtime);
+//    timeout = wait_for_completion_interruptible_timeout(&completion, timeout);
+      r = wait_for_completion_interruptible(&completion);
+      if (unregister_vsync_cb((vsync_callback_t)grpx_irq_wait_handler , &completion, psDevInfo->uiFBDevID) != 0)
+      {
+          printk (KERN_WARNING DRIVER_PREFIX ": Failed to un-register for vsync call back\n");
+          return OMAPLFB_FALSE;
+      }
+#endif
+      return OMAPLFB_TRUE;
+}
+
+OMAPLFB_BOOL OMAPLFBManualSync(OMAPLFB_DEVINFO *psDevInfo)
+{
+#if 0
+       struct omap_dss_device *psDSSDev = fb2display(psDevInfo->psLINFBInfo);
+       OMAP_DSS_DRIVER(psDSSDrv, psDSSDev);
+
+       if (psDSSDrv != NULL && psDSSDrv->sync != NULL)
+       {
+               int res = psDSSDrv->sync(psDSSDev);
+               if (res != 0)
+               {
+                       printk(KERN_INFO DRIVER_PREFIX ": %s: Device %u: Sync failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, res);
+                       return OMAPLFB_FALSE;
+               }
+       }
+#endif
+
+       return OMAPLFB_TRUE;
+}
+
+OMAPLFB_BOOL OMAPLFBCheckModeAndSync(OMAPLFB_DEVINFO *psDevInfo)
+{
+       OMAPLFB_UPDATE_MODE eMode = OMAPLFBGetUpdateMode(psDevInfo);
+
+       switch(eMode)
+       {
+               case OMAPLFB_UPDATE_MODE_AUTO:
+               case OMAPLFB_UPDATE_MODE_MANUAL:
+                       return OMAPLFBManualSync(psDevInfo);
+               default:
+                       break;
+       }
+
+       return OMAPLFB_TRUE;
+}
+
+static int OMAPLFBFrameBufferEvents(struct notifier_block *psNotif,
+                             unsigned long event, void *data)
+{
+       OMAPLFB_DEVINFO *psDevInfo;
+       struct fb_event *psFBEvent = (struct fb_event *)data;
+       struct fb_info *psFBInfo = psFBEvent->info;
+       OMAPLFB_BOOL bBlanked;
+
+       
+       if (event != FB_EVENT_BLANK)
+       {
+               return 0;
+       }
+
+       bBlanked = (*(IMG_INT *)psFBEvent->data != 0) ? OMAPLFB_TRUE: OMAPLFB_FALSE;
+
+       psDevInfo = OMAPLFBGetDevInfoPtr(psFBInfo->node);
+
+#if 0
+       if (psDevInfo != NULL)
+       {
+               if (bBlanked)
+               {
+                       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: Blank event received\n", __FUNCTION__, psDevInfo->uiFBDevID));
+               }
+               else
+               {
+                       DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: Unblank event received\n", __FUNCTION__, psDevInfo->uiFBDevID));
+               }
+       }
+       else
+       {
+               DEBUG_PRINTK((KERN_INFO DRIVER_PREFIX ": %s: Device %u: Blank/Unblank event for unknown framebuffer\n", __FUNCTION__, psFBInfo->node));
+       }
+#endif
+
+       if (psDevInfo != NULL)
+       {
+               OMAPLFBAtomicBoolSet(&psDevInfo->sBlanked, bBlanked);
+               OMAPLFBAtomicIntInc(&psDevInfo->sBlankEvents);
+       }
+
+       return 0;
+}
+
+OMAPLFB_ERROR OMAPLFBUnblankDisplay(OMAPLFB_DEVINFO *psDevInfo)
+{
+       int res;
+#ifdef FBDEV_PRESENT
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+       console_lock();
+#else
+       acquire_console_sem();
+#endif
+       res = fb_blank(psDevInfo->psLINFBInfo, 0);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+       console_unlock();
+#else
+       release_console_sem();
+#endif
+       if (res != 0 && res != -EINVAL)
+       {
+               printk(KERN_WARNING DRIVER_PREFIX
+                       ": %s: Device %u: fb_blank failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, res);
+               return (OMAPLFB_ERROR_GENERIC);
+       }
+#endif
+
+       return (OMAPLFB_OK);
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+
+static void OMAPLFBBlankDisplay(OMAPLFB_DEVINFO *psDevInfo)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+       console_lock();
+#else
+       acquire_console_sem();
+#endif
+       fb_blank(psDevInfo->psLINFBInfo, 1);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+       console_unlock();
+#else
+       release_console_sem();
+#endif
+}
+
+static void OMAPLFBEarlySuspendHandler(struct early_suspend *h)
+{
+       unsigned uiMaxFBDevIDPlusOne = OMAPLFBMaxFBDevIDPlusOne();
+       unsigned i;
+
+       for (i=0; i < uiMaxFBDevIDPlusOne; i++)
+       {
+               OMAPLFB_DEVINFO *psDevInfo = OMAPLFBGetDevInfoPtr(i);
+
+               if (psDevInfo != NULL)
+               {
+                       OMAPLFBAtomicBoolSet(&psDevInfo->sEarlySuspendFlag, OMAPLFB_TRUE);
+                       OMAPLFBBlankDisplay(psDevInfo);
+               }
+       }
+}
+
+static void OMAPLFBEarlyResumeHandler(struct early_suspend *h)
+{
+       unsigned uiMaxFBDevIDPlusOne = OMAPLFBMaxFBDevIDPlusOne();
+       unsigned i;
+
+       for (i=0; i < uiMaxFBDevIDPlusOne; i++)
+       {
+               OMAPLFB_DEVINFO *psDevInfo = OMAPLFBGetDevInfoPtr(i);
+
+               if (psDevInfo != NULL)
+               {
+                       OMAPLFBUnblankDisplay(psDevInfo);
+                       OMAPLFBAtomicBoolSet(&psDevInfo->sEarlySuspendFlag, OMAPLFB_FALSE);
+               }
+       }
+}
+
+#endif 
+
+OMAPLFB_ERROR OMAPLFBEnableLFBEventNotification(OMAPLFB_DEVINFO *psDevInfo)
+{
+       int                res;
+       OMAPLFB_ERROR         eError;
+
+       
+       memset(&psDevInfo->sLINNotifBlock, 0, sizeof(psDevInfo->sLINNotifBlock));
+
+       psDevInfo->sLINNotifBlock.notifier_call = OMAPLFBFrameBufferEvents;
+
+       OMAPLFBAtomicBoolSet(&psDevInfo->sBlanked, OMAPLFB_FALSE);
+       OMAPLFBAtomicIntSet(&psDevInfo->sBlankEvents, 0);
+
+       res = fb_register_client(&psDevInfo->sLINNotifBlock);
+       if (res != 0)
+       {
+               printk(KERN_WARNING DRIVER_PREFIX
+                       ": %s: Device %u: fb_register_client failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, res);
+
+               return (OMAPLFB_ERROR_GENERIC);
+       }
+
+       eError = OMAPLFBUnblankDisplay(psDevInfo);
+       if (eError != OMAPLFB_OK)
+       {
+               printk(KERN_WARNING DRIVER_PREFIX
+                       ": %s: Device %u: UnblankDisplay failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, eError);
+               return eError;
+       }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+       psDevInfo->sEarlySuspend.suspend = OMAPLFBEarlySuspendHandler;
+       psDevInfo->sEarlySuspend.resume = OMAPLFBEarlyResumeHandler;
+       psDevInfo->sEarlySuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
+       register_early_suspend(&psDevInfo->sEarlySuspend);
+#endif
+
+       return (OMAPLFB_OK);
+}
+
+OMAPLFB_ERROR OMAPLFBDisableLFBEventNotification(OMAPLFB_DEVINFO *psDevInfo)
+{
+       int res;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+       unregister_early_suspend(&psDevInfo->sEarlySuspend);
+#endif
+
+       
+       res = fb_unregister_client(&psDevInfo->sLINNotifBlock);
+       if (res != 0)
+       {
+               printk(KERN_WARNING DRIVER_PREFIX
+                       ": %s: Device %u: fb_unregister_client failed (%d)\n", __FUNCTION__, psDevInfo->uiFBDevID, res);
+               return (OMAPLFB_ERROR_GENERIC);
+       }
+
+       OMAPLFBAtomicBoolSet(&psDevInfo->sBlanked, OMAPLFB_FALSE);
+
+       return (OMAPLFB_OK);
+}
+
+#if defined(SUPPORT_DRI_DRM) && defined(PVR_DISPLAY_CONTROLLER_DRM_IOCTL)
+static OMAPLFB_DEVINFO *OMAPLFBPVRDevIDToDevInfo(unsigned uiPVRDevID)
+{
+       unsigned uiMaxFBDevIDPlusOne = OMAPLFBMaxFBDevIDPlusOne();
+       unsigned i;
+
+       for (i=0; i < uiMaxFBDevIDPlusOne; i++)
+       {
+               OMAPLFB_DEVINFO *psDevInfo = OMAPLFBGetDevInfoPtr(i);
+
+               if (psDevInfo->uiPVRDevID == uiPVRDevID)
+               {
+                       return psDevInfo;
+               }
+       }
+
+       printk(KERN_WARNING DRIVER_PREFIX
+               ": %s: PVR Device %u: Couldn't find device\n", __FUNCTION__, uiPVRDevID);
+
+       return NULL;
+}
+
+int PVR_DRM_MAKENAME(omaplfb, _Ioctl)(struct drm_device unref__ *dev, void *arg, struct drm_file unref__ *pFile)
+{
+       uint32_t *puiArgs;
+       uint32_t uiCmd;
+       unsigned uiPVRDevID;
+       int ret = 0;
+       OMAPLFB_DEVINFO *psDevInfo;
+
+       if (arg == NULL)
+       {
+               return -EFAULT;
+       }
+
+       puiArgs = (uint32_t *)arg;
+       uiCmd = puiArgs[PVR_DRM_DISP_ARG_CMD];
+       uiPVRDevID = puiArgs[PVR_DRM_DISP_ARG_DEV];
+
+       psDevInfo = OMAPLFBPVRDevIDToDevInfo(uiPVRDevID);
+       if (psDevInfo == NULL)
+       {
+               return -EINVAL;
+       }
+
+
+       switch (uiCmd)
+       {
+               case PVR_DRM_DISP_CMD_LEAVE_VT:
+               case PVR_DRM_DISP_CMD_ENTER_VT:
+               {
+                       OMAPLFB_BOOL bLeaveVT = (uiCmd == PVR_DRM_DISP_CMD_LEAVE_VT);
+                       DEBUG_PRINTK((KERN_WARNING DRIVER_PREFIX ": %s: PVR Device %u: %s\n",
+                               __FUNCTION__, uiPVRDevID,
+                               bLeaveVT ? "Leave VT" : "Enter VT"));
+
+                       OMAPLFBCreateSwapChainLock(psDevInfo);
+                       
+                       OMAPLFBAtomicBoolSet(&psDevInfo->sLeaveVT, bLeaveVT);
+                       if (psDevInfo->psSwapChain != NULL)
+                       {
+                               flush_workqueue(psDevInfo->psSwapChain->psWorkQueue);
+
+                               if (bLeaveVT)
+                               {
+                                       OMAPLFBFlip(psDevInfo, &psDevInfo->sSystemBuffer);
+                                       (void) OMAPLFBCheckModeAndSync(psDevInfo);
+                               }
+                       }
+
+                       OMAPLFBCreateSwapChainUnLock(psDevInfo);
+                       (void) OMAPLFBUnblankDisplay(psDevInfo);
+                       break;
+               }
+               case PVR_DRM_DISP_CMD_ON:
+               case PVR_DRM_DISP_CMD_STANDBY:
+               case PVR_DRM_DISP_CMD_SUSPEND:
+               case PVR_DRM_DISP_CMD_OFF:
+               {
+                       int iFBMode;
+#if defined(DEBUG)
+                       {
+                               const char *pszMode;
+                               switch(uiCmd)
+                               {
+                                       case PVR_DRM_DISP_CMD_ON:
+                                               pszMode = "On";
+                                               break;
+                                       case PVR_DRM_DISP_CMD_STANDBY:
+                                               pszMode = "Standby";
+                                               break;
+                                       case PVR_DRM_DISP_CMD_SUSPEND:
+                                               pszMode = "Suspend";
+                                               break;
+                                       case PVR_DRM_DISP_CMD_OFF:
+                                               pszMode = "Off";
+                                               break;
+                                       default:
+                                               pszMode = "(Unknown Mode)";
+                                               break;
+                               }
+                               printk (KERN_WARNING DRIVER_PREFIX ": %s: PVR Device %u: Display %s\n",
+                               __FUNCTION__, uiPVRDevID, pszMode);
+                       }
+#endif
+                       switch(uiCmd)
+                       {
+                               case PVR_DRM_DISP_CMD_ON:
+                                       iFBMode = FB_BLANK_UNBLANK;
+                                       break;
+                               case PVR_DRM_DISP_CMD_STANDBY:
+                                       iFBMode = FB_BLANK_HSYNC_SUSPEND;
+                                       break;
+                               case PVR_DRM_DISP_CMD_SUSPEND:
+                                       iFBMode = FB_BLANK_VSYNC_SUSPEND;
+                                       break;
+                               case PVR_DRM_DISP_CMD_OFF:
+                                       iFBMode = FB_BLANK_POWERDOWN;
+                                       break;
+                               default:
+                                       return -EINVAL;
+                       }
+
+                       OMAPLFBCreateSwapChainLock(psDevInfo);
+
+                       if (psDevInfo->psSwapChain != NULL)
+                       {
+                               flush_workqueue(psDevInfo->psSwapChain->psWorkQueue);
+                       }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+                       console_lock();
+#else
+                       acquire_console_sem();
+#endif
+                       ret = fb_blank(psDevInfo->psLINFBInfo, iFBMode);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
+                       console_unlock();
+#else
+                       release_console_sem();
+#endif
+
+                       OMAPLFBCreateSwapChainUnLock(psDevInfo);
+
+                       break;
+               }
+               default:
+               {
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+
+       return ret;
+}
+#endif
+
+#if defined(SUPPORT_DRI_DRM)
+int PVR_DRM_MAKENAME(omaplfb, _Init)(struct drm_device unref__ *dev)
+#else
+static int __init OMAPLFB_Init(void)
+#endif
+{
+
+       if(OMAPLFBInit() != OMAPLFB_OK)
+       {
+               printk(KERN_WARNING DRIVER_PREFIX ": %s: OMAPLFBInit failed\n", __FUNCTION__);
+               return -ENODEV;
+       }
+
+       return 0;
+
+}
+
+#if defined(SUPPORT_DRI_DRM)
+void PVR_DRM_MAKENAME(omaplfb, _Cleanup)(struct drm_device unref__ *dev)
+#else
+static void __exit OMAPLFB_Cleanup(void)
+#endif
+{    
+       if(OMAPLFBDeInit() != OMAPLFB_OK)
+       {
+               printk(KERN_WARNING DRIVER_PREFIX ": %s: OMAPLFBDeInit failed\n", __FUNCTION__);
+       }
+}
+
+#if !defined(SUPPORT_DRI_DRM)
+late_initcall(OMAPLFB_Init);
+module_exit(OMAPLFB_Cleanup);
+#endif
diff --git a/services4/3rdparty/linux_drm/Kbuild_org b/services4/3rdparty/linux_drm/Kbuild_org
deleted file mode 100644 (file)
index c66ab7a..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-obj-m  := drm.o
-
-EXT_SOURCE_DIR := $(KERNELDIR)/drivers/gpu/drm
-EXT_BUILD_DIR :=tmp_$(TI_PLATFORM)_$(BUILD)_drm
-
-FILES := \
-pvr_drm_stubs.c \
-$(EXT_BUILD_DIR)/drm_auth.c \
-
-
-EXT_SOURCE_LIST := \
-        drm_auth.c drm_bufs.c drm_cache.c \
-        drm_context.c drm_dma.c drm_drawable.c \
-        drm_drv.c drm_fops.c drm_gem.c drm_ioctl.c drm_irq.c \
-        drm_lock.c drm_memory.c drm_proc.c drm_stub.c drm_vm.c \
-        drm_agpsupport.c drm_scatter.c ati_pcigart.c drm_pci.c \
-        drm_sysfs.c drm_hashtab.c drm_sman.c drm_mm.c \
-        drm_crtc.c drm_modes.c drm_edid.c \
-        drm_info.c drm_debugfs.c drm_encoder_slave.c
-
-EXT_SOURCES := $(addprefix $(EXT_BUILD_DIR)/,$(EXT_SOURCE_LIST))
-FILES += $(EXT_SOURCES)
-
-EXTRA_CFLAGS += -I$(KERNELDIR)/include/drm
-EXTRA_CFLAGS += -I$(EXT_SOURCE_DIR)
-
-EXTRA_CFLAGS +=  -DCONFIG_PCI -Wno-error
-EXTRA_CFLAS += $(ALL_CFLAGS)
-
-
-drm-y  := $(FILES:.c=.o)
index 252fdb9..0cb2ba5 100644 (file)
@@ -466,10 +466,4 @@ drm_agp_bind_pages(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_agp_bind_pages);
 
-void drm_agp_chipset_flush(struct drm_device *dev)
-{
-       agp_flush_chipset(dev->agp->bridge);
-}
-EXPORT_SYMBOL(drm_agp_chipset_flush);
-
 #endif /* __OS_HAS_AGP */
index 3e257a5..61e1ef9 100644 (file)
@@ -46,10 +46,11 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
        list_for_each_entry(entry, &dev->maplist, head) {
                /*
                 * Because the kernel-userspace ABI is fixed at a 32-bit offset
-                * while PCI resources may live above that, we ignore the map
-                * offset for maps of type _DRM_FRAMEBUFFER or _DRM_REGISTERS.
-                * It is assumed that each driver will have only one resource of
-                * each type.
+                * while PCI resources may live above that, we only compare the
+                * lower 32 bits of the map offset for maps of type
+                * _DRM_FRAMEBUFFER or _DRM_REGISTERS.
+                * It is assumed that if a driver have more than one resource
+                * of each type, the lower 32 bits are different.
                 */
                if (!entry->map ||
                    map->type != entry->map->type ||
@@ -59,9 +60,12 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
                case _DRM_SHM:
                        if (map->flags != _DRM_CONTAINS_LOCK)
                                break;
+                       return entry;
                case _DRM_REGISTERS:
                case _DRM_FRAME_BUFFER:
-                       return entry;
+                       if ((entry->map->offset & 0xffffffff) ==
+                           (map->offset & 0xffffffff))
+                               return entry;
                default: /* Make gcc happy */
                        ;
                }
@@ -182,9 +186,6 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
                        kfree(map);
                        return -EINVAL;
                }
-#endif
-#ifdef __alpha__
-               map->offset += dev->hose->mem_space->start;
 #endif
                /* Some drivers preinitialize some maps, without the X Server
                 * needing to be aware of it.  Therefore, we just return success
index 2baa670..fe738f0 100644 (file)
@@ -499,6 +499,7 @@ void drm_connector_cleanup(struct drm_connector *connector)
        mutex_lock(&dev->mode_config.mutex);
        drm_mode_object_put(dev, &connector->base);
        list_del(&connector->head);
+       dev->mode_config.num_connector--;
        mutex_unlock(&dev->mode_config.mutex);
 }
 EXPORT_SYMBOL(drm_connector_cleanup);
@@ -529,6 +530,7 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)
        mutex_lock(&dev->mode_config.mutex);
        drm_mode_object_put(dev, &encoder->base);
        list_del(&encoder->head);
+       dev->mode_config.num_encoder--;
        mutex_unlock(&dev->mode_config.mutex);
 }
 EXPORT_SYMBOL(drm_encoder_cleanup);
@@ -886,9 +888,6 @@ int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
        total_objects += dev->mode_config.num_connector;
        total_objects += dev->mode_config.num_encoder;
 
-       if (total_objects == 0)
-               return -EINVAL;
-
        group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
        if (!group->id_list)
                return -ENOMEM;
@@ -1073,6 +1072,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
        uint32_t __user *encoder_id;
        struct drm_mode_group *mode_group;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
 
        /*
@@ -1110,7 +1112,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
        if (card_res->count_fbs >= fb_count) {
                copied = 0;
                fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
-               list_for_each_entry(fb, &file_priv->fbs, head) {
+               list_for_each_entry(fb, &file_priv->fbs, filp_head) {
                        if (put_user(fb->base.id, fb_id + copied)) {
                                ret = -EFAULT;
                                goto out;
@@ -1244,6 +1246,9 @@ int drm_mode_getcrtc(struct drm_device *dev,
        struct drm_mode_object *obj;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
 
        obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
@@ -1312,6 +1317,9 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
        uint64_t __user *prop_values;
        uint32_t __user *encoder_ptr;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
@@ -1431,6 +1439,9 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
        struct drm_encoder *encoder;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, enc_resp->encoder_id,
                                   DRM_MODE_OBJECT_ENCODER);
@@ -1486,6 +1497,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
        int ret = 0;
        int i;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, crtc_req->crtc_id,
                                   DRM_MODE_OBJECT_CRTC);
@@ -1603,6 +1617,9 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
        struct drm_crtc *crtc;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        if (!req->flags) {
                DRM_ERROR("no operation set\n");
                return -EINVAL;
@@ -1667,6 +1684,9 @@ int drm_mode_addfb(struct drm_device *dev,
        struct drm_framebuffer *fb;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        if ((config->min_width > r->width) || (r->width > config->max_width)) {
                DRM_ERROR("mode new framebuffer width not within limits\n");
                return -EINVAL;
@@ -1678,7 +1698,7 @@ int drm_mode_addfb(struct drm_device *dev,
 
        mutex_lock(&dev->mode_config.mutex);
 
-       /* TODO check buffer is sufficently large */
+       /* TODO check buffer is sufficiently large */
        /* TODO setup destructor callback */
 
        fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
@@ -1724,9 +1744,12 @@ int drm_mode_rmfb(struct drm_device *dev,
        int ret = 0;
        int found = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB);
-       /* TODO check that we realy get a framebuffer back. */
+       /* TODO check that we really get a framebuffer back. */
        if (!obj) {
                DRM_ERROR("mode invalid framebuffer id\n");
                ret = -EINVAL;
@@ -1780,6 +1803,9 @@ int drm_mode_getfb(struct drm_device *dev,
        struct drm_framebuffer *fb;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
        if (!obj) {
@@ -1813,6 +1839,9 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
        int num_clips;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
        if (!obj) {
@@ -1996,6 +2025,9 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev,
        struct drm_mode_modeinfo *umode = &mode_cmd->mode;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
 
        obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
@@ -2042,6 +2074,9 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev,
        struct drm_mode_modeinfo *umode = &mode_cmd->mode;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
 
        obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
@@ -2211,6 +2246,9 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
        uint64_t __user *values_ptr;
        uint32_t __user *blob_length_ptr;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
        if (!obj) {
@@ -2333,6 +2371,9 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
        int ret = 0;
        void *blob_ptr;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
        if (!obj) {
@@ -2393,6 +2434,9 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
        int ret = -EINVAL;
        int i;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
 
        obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR);
@@ -2509,6 +2553,9 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
        int size;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
        if (!obj) {
@@ -2560,6 +2607,9 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev,
        int size;
        int ret = 0;
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -EINVAL;
+
        mutex_lock(&dev->mode_config.mutex);
        obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
        if (!obj) {
@@ -2674,3 +2724,56 @@ out:
        mutex_unlock(&dev->mode_config.mutex);
        return ret;
 }
+
+void drm_mode_config_reset(struct drm_device *dev)
+{
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+               if (crtc->funcs->reset)
+                       crtc->funcs->reset(crtc);
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+               if (encoder->funcs->reset)
+                       encoder->funcs->reset(encoder);
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+               if (connector->funcs->reset)
+                       connector->funcs->reset(connector);
+}
+EXPORT_SYMBOL(drm_mode_config_reset);
+
+int drm_mode_create_dumb_ioctl(struct drm_device *dev,
+                              void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_create_dumb *args = data;
+
+       if (!dev->driver->dumb_create)
+               return -ENOSYS;
+       return dev->driver->dumb_create(file_priv, dev, args);
+}
+
+int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
+                            void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_map_dumb *args = data;
+
+       /* call driver ioctl to get mmap offset */
+       if (!dev->driver->dumb_map_offset)
+               return -ENOSYS;
+
+       return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset);
+}
+
+int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
+                               void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_destroy_dumb *args = data;
+
+       if (!dev->driver->dumb_destroy)
+               return -ENOSYS;
+
+       return dev->driver->dumb_destroy(file_priv, dev, args->handle);
+}
index 2d4e17a..f88a9b2 100644 (file)
@@ -336,20 +336,20 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
                              struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_display_mode *adjusted_mode, saved_mode;
+       struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
        struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
        struct drm_encoder_helper_funcs *encoder_funcs;
        int saved_x, saved_y;
        struct drm_encoder *encoder;
        bool ret = true;
 
-       adjusted_mode = drm_mode_duplicate(dev, mode);
-
        crtc->enabled = drm_helper_crtc_in_use(crtc);
-
        if (!crtc->enabled)
                return true;
 
+       adjusted_mode = drm_mode_duplicate(dev, mode);
+
+       saved_hwmode = crtc->hwmode;
        saved_mode = crtc->mode;
        saved_x = crtc->x;
        saved_y = crtc->y;
@@ -427,11 +427,20 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 
        }
 
-       /* XXX free adjustedmode */
-       drm_mode_destroy(dev, adjusted_mode);
+       /* Store real post-adjustment hardware mode. */
+       crtc->hwmode = *adjusted_mode;
+
+       /* Calculate and store various constants which
+        * are later needed by vblank and swap-completion
+        * timestamping. They are derived from true hwmode.
+        */
+       drm_calc_timestamping_constants(crtc);
+
        /* FIXME: add subpixel order */
 done:
+       drm_mode_destroy(dev, adjusted_mode);
        if (!ret) {
+               crtc->hwmode = saved_hwmode;
                crtc->mode = saved_mode;
                crtc->x = saved_x;
                crtc->y = saved_y;
@@ -486,14 +495,17 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
 
        crtc_funcs = set->crtc->helper_private;
 
+       if (!set->mode)
+               set->fb = NULL;
+
        if (set->fb) {
                DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
                                set->crtc->base.id, set->fb->base.id,
                                (int)set->num_connectors, set->x, set->y);
        } else {
-               DRM_DEBUG_KMS("[CRTC:%d] [NOFB] #connectors=%d (x y) (%i %i)\n",
-                               set->crtc->base.id, (int)set->num_connectors,
-                               set->x, set->y);
+               DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
+               set->mode = NULL;
+               set->num_connectors = 0;
        }
 
        dev = set->crtc->dev;
@@ -548,6 +560,11 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                        mode_changed = true;
                } else if (set->fb == NULL) {
                        mode_changed = true;
+               } else if (set->fb->depth != set->crtc->fb->depth) {
+                       mode_changed = true;
+               } else if (set->fb->bits_per_pixel !=
+                          set->crtc->fb->bits_per_pixel) {
+                       mode_changed = true;
                } else
                        fb_changed = true;
        }
@@ -638,8 +655,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                mode_changed = true;
 
        if (mode_changed) {
-               set->crtc->enabled = (set->mode != NULL);
-               if (set->mode != NULL) {
+               set->crtc->enabled = drm_helper_crtc_in_use(set->crtc);
+               if (set->crtc->enabled) {
                        DRM_DEBUG_KMS("attempting to set mode from"
                                        " userspace\n");
                        drm_mode_debug_printmodeline(set->mode);
@@ -650,9 +667,16 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                                                      old_fb)) {
                                DRM_ERROR("failed to set mode on [CRTC:%d]\n",
                                          set->crtc->base.id);
+                               set->crtc->fb = old_fb;
                                ret = -EINVAL;
                                goto fail;
                        }
+                       DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
+                       for (i = 0; i < set->num_connectors; i++) {
+                               DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
+                                             drm_get_connector_name(set->connectors[i]));
+                               set->connectors[i]->dpms = DRM_MODE_DPMS_ON;
+                       }
                }
                drm_helper_disable_unused_functions(dev);
        } else if (fb_changed) {
@@ -664,14 +688,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                        set->crtc->fb = set->fb;
                ret = crtc_funcs->mode_set_base(set->crtc,
                                                set->x, set->y, old_fb);
-               if (ret != 0)
+               if (ret != 0) {
+                       set->crtc->fb = old_fb;
                        goto fail;
-       }
-       DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
-       for (i = 0; i < set->num_connectors; i++) {
-               DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
-                             drm_get_connector_name(set->connectors[i]));
-               set->connectors[i]->dpms = DRM_MODE_DPMS_ON;
+               }
        }
 
        kfree(save_connectors);
index 9d8c892..9d2668a 100644 (file)
@@ -90,7 +90,6 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count,
        struct drm_device *dev = minor->dev;
        struct dentry *ent;
        struct drm_info_node *tmp;
-       char name[64];
        int i, ret;
 
        for (i = 0; i < count; i++) {
@@ -108,6 +107,9 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count,
                ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
                                          root, tmp, &drm_debugfs_fops);
                if (!ent) {
+                       char name[64];
+                       strncpy(name, root->d_name.name,
+                                               min(root->d_name.len, 64U));
                        DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/%s\n",
                                  name, files[i].name);
                        kfree(tmp);
index 271835a..93a112d 100644 (file)
@@ -67,6 +67,7 @@ static struct drm_ioctl_desc drm_ioctls[] = {
        DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, 0),
        DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0),
        DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, 0),
        DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER),
 
        DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
@@ -150,7 +151,10 @@ static struct drm_ioctl_desc drm_ioctls[] = {
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
        DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED)
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED)
 };
 
 #define DRM_CORE_IOCTL_COUNT   ARRAY_SIZE( drm_ioctls )
@@ -234,49 +238,6 @@ int drm_lastclose(struct drm_device * dev)
        return 0;
 }
 
-/**
- * Module initialization. Called via init_module at module load time, or via
- * linux/init/main.c (this is not currently supported).
- *
- * \return zero on success or a negative number on failure.
- *
- * Initializes an array of drm_device structures, and attempts to
- * initialize all available devices, using consecutive minors, registering the
- * stubs and initializing the device.
- *
- * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
- * after the initialization for driver customization.
- */
-int drm_init(struct drm_driver *driver)
-{
-       DRM_DEBUG("\n");
-       INIT_LIST_HEAD(&driver->device_list);
-
-       if (driver->driver_features & DRIVER_USE_PLATFORM_DEVICE)
-               return drm_platform_init(driver);
-       else
-               return drm_pci_init(driver);
-}
-
-EXPORT_SYMBOL(drm_init);
-
-void drm_exit(struct drm_driver *driver)
-{
-       struct drm_device *dev, *tmp;
-       DRM_DEBUG("\n");
-
-       if (driver->driver_features & DRIVER_MODESET) {
-               pci_unregister_driver(&driver->pci_driver);
-       } else {
-               list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
-                       drm_put_dev(dev);
-       }
-
-       DRM_INFO("Module unloaded\n");
-}
-
-EXPORT_SYMBOL(drm_exit);
-
 /** File operations structure */
 static const struct file_operations drm_stub_fops = {
        .owner = THIS_MODULE,
index a245d17..7425e5c 100644 (file)
@@ -127,6 +127,23 @@ static const u8 edid_header[] = {
        0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
 };
 
+ /*
+ * Sanity check the header of the base EDID block.  Return 8 if the header
+ * is perfect, down to 0 if it's totally wrong.
+ */
+int drm_edid_header_is_valid(const u8 *raw_edid)
+{
+       int i, score = 0;
+
+       for (i = 0; i < sizeof(edid_header); i++)
+               if (raw_edid[i] == edid_header[i])
+                       score++;
+
+       return score;
+}
+EXPORT_SYMBOL(drm_edid_header_is_valid);
+
+
 /*
  * Sanity check the EDID block (base or extension).  Return 0 if the block
  * doesn't check out, or 1 if it's valid.
@@ -139,12 +156,7 @@ drm_edid_block_valid(u8 *raw_edid)
        struct edid *edid = (struct edid *)raw_edid;
 
        if (raw_edid[0] == 0x00) {
-               int score = 0;
-
-               for (i = 0; i < sizeof(edid_header); i++)
-                       if (raw_edid[i] == edid_header[i])
-                               score++;
-
+               int score = drm_edid_header_is_valid(raw_edid);
                if (score == 8) ;
                else if (score >= 6) {
                        DRM_DEBUG("Fixing EDID header, your hardware may be failing\n");
@@ -184,9 +196,9 @@ drm_edid_block_valid(u8 *raw_edid)
 
 bad:
        if (raw_edid) {
-               DRM_ERROR("Raw EDID:\n");
-               print_hex_dump_bytes(KERN_ERR, DUMP_PREFIX_NONE, raw_edid, EDID_LENGTH);
-               printk("\n");
+               printk(KERN_ERR "Raw EDID:\n");
+               print_hex_dump(KERN_ERR, " \t", DUMP_PREFIX_NONE, 16, 1,
+                              raw_edid, EDID_LENGTH, false);
        }
        return 0;
 }
@@ -230,24 +242,43 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
                      int block, int len)
 {
        unsigned char start = block * EDID_LENGTH;
-       struct i2c_msg msgs[] = {
-               {
-                       .addr   = DDC_ADDR,
-                       .flags  = 0,
-                       .len    = 1,
-                       .buf    = &start,
-               }, {
-                       .addr   = DDC_ADDR,
-                       .flags  = I2C_M_RD,
-                       .len    = len,
-                       .buf    = buf,
-               }
-       };
+       int ret, retries = 5;
 
-       if (i2c_transfer(adapter, msgs, 2) == 2)
-               return 0;
+       /* The core i2c driver will automatically retry the transfer if the
+        * adapter reports EAGAIN. However, we find that bit-banging transfers
+        * are susceptible to errors under a heavily loaded machine and
+        * generate spurious NAKs and timeouts. Retrying the transfer
+        * of the individual block a few times seems to overcome this.
+        */
+       do {
+               struct i2c_msg msgs[] = {
+                       {
+                               .addr   = DDC_ADDR,
+                               .flags  = 0,
+                               .len    = 1,
+                               .buf    = &start,
+                       }, {
+                               .addr   = DDC_ADDR,
+                               .flags  = I2C_M_RD,
+                               .len    = len,
+                               .buf    = buf,
+                       }
+               };
+               ret = i2c_transfer(adapter, msgs, 2);
+       } while (ret != 2 && --retries);
 
-       return -1;
+       return ret == 2 ? 0 : -1;
+}
+
+static bool drm_edid_is_zero(u8 *in_edid, int length)
+{
+       int i;
+       u32 *raw_edid = (u32 *)in_edid;
+
+       for (i = 0; i < length / 4; i++)
+               if (*(raw_edid + i) != 0)
+                       return false;
+       return true;
 }
 
 static u8 *
@@ -265,6 +296,10 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
                        goto out;
                if (drm_edid_block_valid(block))
                        break;
+               if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) {
+                       connector->null_edid_counter++;
+                       goto carp;
+               }
        }
        if (i == 4)
                goto carp;
@@ -449,12 +484,11 @@ static void edid_fixup_preferred(struct drm_connector *connector,
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
                                           int hsize, int vsize, int fresh)
 {
+       struct drm_display_mode *mode = NULL;
        int i;
-       struct drm_display_mode *ptr, *mode;
 
-       mode = NULL;
        for (i = 0; i < drm_num_dmt_modes; i++) {
-               ptr = &drm_dmt_modes[i];
+               const struct drm_display_mode *ptr = &drm_dmt_modes[i];
                if (hsize == ptr->hdisplay &&
                        vsize == ptr->vdisplay &&
                        fresh == drm_mode_vrefresh(ptr)) {
@@ -885,7 +919,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
 }
 
 static bool
-mode_is_rb(struct drm_display_mode *mode)
+mode_is_rb(const struct drm_display_mode *mode)
 {
        return (mode->htotal - mode->hdisplay == 160) &&
               (mode->hsync_end - mode->hdisplay == 80) &&
@@ -894,7 +928,8 @@ mode_is_rb(struct drm_display_mode *mode)
 }
 
 static bool
-mode_in_hsync_range(struct drm_display_mode *mode, struct edid *edid, u8 *t)
+mode_in_hsync_range(const struct drm_display_mode *mode,
+                   struct edid *edid, u8 *t)
 {
        int hsync, hmin, hmax;
 
@@ -910,7 +945,8 @@ mode_in_hsync_range(struct drm_display_mode *mode, struct edid *edid, u8 *t)
 }
 
 static bool
-mode_in_vsync_range(struct drm_display_mode *mode, struct edid *edid, u8 *t)
+mode_in_vsync_range(const struct drm_display_mode *mode,
+                   struct edid *edid, u8 *t)
 {
        int vsync, vmin, vmax;
 
@@ -941,7 +977,7 @@ range_pixel_clock(struct edid *edid, u8 *t)
 }
 
 static bool
-mode_in_range(struct drm_display_mode *mode, struct edid *edid,
+mode_in_range(const struct drm_display_mode *mode, struct edid *edid,
              struct detailed_timing *timing)
 {
        u32 max_clock;
@@ -1288,7 +1324,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
 /**
  * Search EDID for CEA extension block.
  */
-static u8 *drm_find_cea_extension(struct edid *edid)
+u8 *drm_find_cea_extension(struct edid *edid)
 {
        u8 *edid_ext = NULL;
        int i;
@@ -1309,6 +1345,7 @@ static u8 *drm_find_cea_extension(struct edid *edid)
 
        return edid_ext;
 }
+EXPORT_SYMBOL(drm_find_cea_extension);
 
 /**
  * drm_detect_hdmi_monitor - detect whether monitor is hdmi.
@@ -1402,6 +1439,73 @@ end:
 }
 EXPORT_SYMBOL(drm_detect_monitor_audio);
 
+/**
+ * drm_add_display_info - pull display info out if present
+ * @edid: EDID data
+ * @info: display info (attached to connector)
+ *
+ * Grab any available display info and stuff it into the drm_display_info
+ * structure that's part of the connector.  Useful for tracking bpp and
+ * color spaces.
+ */
+static void drm_add_display_info(struct edid *edid,
+                                struct drm_display_info *info)
+{
+       u8 *edid_ext;
+
+       info->width_mm = edid->width_cm * 10;
+       info->height_mm = edid->height_cm * 10;
+
+       /* driver figures it out in this case */
+       info->bpc = 0;
+       info->color_formats = 0;
+
+       /* Only defined for 1.4 with digital displays */
+       if (edid->revision < 4)
+               return;
+
+       if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
+               return;
+
+       switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
+       case DRM_EDID_DIGITAL_DEPTH_6:
+               info->bpc = 6;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_8:
+               info->bpc = 8;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_10:
+               info->bpc = 10;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_12:
+               info->bpc = 12;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_14:
+               info->bpc = 14;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_16:
+               info->bpc = 16;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_UNDEF:
+       default:
+               info->bpc = 0;
+               break;
+       }
+
+       info->color_formats = DRM_COLOR_FORMAT_RGB444;
+       if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB444)
+               info->color_formats = DRM_COLOR_FORMAT_YCRCB444;
+       if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB422)
+               info->color_formats = DRM_COLOR_FORMAT_YCRCB422;
+
+       /* Get data from CEA blocks if present */
+       edid_ext = drm_find_cea_extension(edid);
+       if (!edid_ext)
+               return;
+
+       info->cea_rev = edid_ext[1];
+}
+
 /**
  * drm_add_edid_modes - add modes from EDID data, if available
  * @connector: connector we're probing
@@ -1450,8 +1554,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
        if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
                edid_fixup_preferred(connector, quirks);
 
-       connector->display_info.width_mm = edid->width_cm * 10;
-       connector->display_info.height_mm = edid->height_cm * 10;
+       drm_add_display_info(edid, &connector->display_info);
 
        return num_modes;
 }
@@ -1472,7 +1575,7 @@ int drm_add_modes_noedid(struct drm_connector *connector,
                        int hdisplay, int vdisplay)
 {
        int i, count, num_modes = 0;
-       struct drm_display_mode *mode, *ptr;
+       struct drm_display_mode *mode;
        struct drm_device *dev = connector->dev;
 
        count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
@@ -1482,7 +1585,7 @@ int drm_add_modes_noedid(struct drm_connector *connector,
                vdisplay = 0;
 
        for (i = 0; i < count; i++) {
-               ptr = &drm_dmt_modes[i];
+               const struct drm_display_mode *ptr = &drm_dmt_modes[i];
                if (hdisplay && vdisplay) {
                        /*
                         * Only when two are valid, they will be used to check
index d2849e4..f7c6854 100644 (file)
@@ -70,174 +70,50 @@ fail:
 }
 EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
 
-/**
- * drm_fb_helper_connector_parse_command_line - parse command line for connector
- * @connector - connector to parse line for
- * @mode_option - per connector mode option
- *
- * This parses the connector specific then generic command lines for
- * modes and options to configure the connector.
- *
- * This uses the same parameters as the fb modedb.c, except for extra
- *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
- *
- * enable/enable Digital/disable bit at the end
- */
-static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_connector *fb_helper_conn,
-                                                      const char *mode_option)
-{
-       const char *name;
-       unsigned int namelen;
-       int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
-       unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
-       int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
-       int i;
-       enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
-       struct drm_fb_helper_cmdline_mode *cmdline_mode;
-       struct drm_connector *connector;
-
-       if (!fb_helper_conn)
-               return false;
-       connector = fb_helper_conn->connector;
-
-       cmdline_mode = &fb_helper_conn->cmdline_mode;
-       if (!mode_option)
-               mode_option = fb_mode_option;
-
-       if (!mode_option) {
-               cmdline_mode->specified = false;
-               return false;
-       }
-
-       name = mode_option;
-       namelen = strlen(name);
-       for (i = namelen-1; i >= 0; i--) {
-               switch (name[i]) {
-               case '@':
-                       namelen = i;
-                       if (!refresh_specified && !bpp_specified &&
-                           !yres_specified) {
-                               refresh = simple_strtol(&name[i+1], NULL, 10);
-                               refresh_specified = 1;
-                               if (cvt || rb)
-                                       cvt = 0;
-                       } else
-                               goto done;
-                       break;
-               case '-':
-                       namelen = i;
-                       if (!bpp_specified && !yres_specified) {
-                               bpp = simple_strtol(&name[i+1], NULL, 10);
-                               bpp_specified = 1;
-                               if (cvt || rb)
-                                       cvt = 0;
-                       } else
-                               goto done;
-                       break;
-               case 'x':
-                       if (!yres_specified) {
-                               yres = simple_strtol(&name[i+1], NULL, 10);
-                               yres_specified = 1;
-                       } else
-                               goto done;
-               case '0' ... '9':
-                       break;
-               case 'M':
-                       if (!yres_specified)
-                               cvt = 1;
-                       break;
-               case 'R':
-                       if (cvt)
-                               rb = 1;
-                       break;
-               case 'm':
-                       if (!cvt)
-                               margins = 1;
-                       break;
-               case 'i':
-                       if (!cvt)
-                               interlace = 1;
-                       break;
-               case 'e':
-                       force = DRM_FORCE_ON;
-                       break;
-               case 'D':
-                       if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
-                           (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
-                               force = DRM_FORCE_ON;
-                       else
-                               force = DRM_FORCE_ON_DIGITAL;
-                       break;
-               case 'd':
-                       force = DRM_FORCE_OFF;
-                       break;
-               default:
-                       goto done;
-               }
-       }
-       if (i < 0 && yres_specified) {
-               xres = simple_strtol(name, NULL, 10);
-               res_specified = 1;
-       }
-done:
-
-       DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
-               drm_get_connector_name(connector), xres, yres,
-               (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
-               "", (margins) ? " with margins" : "", (interlace) ?
-               " interlaced" : "");
-
-       if (force) {
-               const char *s;
-               switch (force) {
-               case DRM_FORCE_OFF: s = "OFF"; break;
-               case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
-               default:
-               case DRM_FORCE_ON: s = "ON"; break;
-               }
-
-               DRM_INFO("forcing %s connector %s\n",
-                        drm_get_connector_name(connector), s);
-               connector->force = force;
-       }
-
-       if (res_specified) {
-               cmdline_mode->specified = true;
-               cmdline_mode->xres = xres;
-               cmdline_mode->yres = yres;
-       }
-
-       if (refresh_specified) {
-               cmdline_mode->refresh_specified = true;
-               cmdline_mode->refresh = refresh;
-       }
-
-       if (bpp_specified) {
-               cmdline_mode->bpp_specified = true;
-               cmdline_mode->bpp = bpp;
-       }
-       cmdline_mode->rb = rb ? true : false;
-       cmdline_mode->cvt = cvt  ? true : false;
-       cmdline_mode->interlace = interlace ? true : false;
-
-       return true;
-}
-
 static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
 {
        struct drm_fb_helper_connector *fb_helper_conn;
        int i;
 
        for (i = 0; i < fb_helper->connector_count; i++) {
+               struct drm_cmdline_mode *mode;
+               struct drm_connector *connector;
                char *option = NULL;
 
                fb_helper_conn = fb_helper->connector_info[i];
+               connector = fb_helper_conn->connector;
+               mode = &fb_helper_conn->cmdline_mode;
 
                /* do something on return - turn off connector maybe */
-               if (fb_get_options(drm_get_connector_name(fb_helper_conn->connector), &option))
+               if (fb_get_options(drm_get_connector_name(connector), &option))
                        continue;
 
-               drm_fb_helper_connector_parse_command_line(fb_helper_conn, option);
+               if (drm_mode_parse_command_line_for_connector(option,
+                                                             connector,
+                                                             mode)) {
+                       if (mode->force) {
+                               const char *s;
+                               switch (mode->force) {
+                               case DRM_FORCE_OFF: s = "OFF"; break;
+                               case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
+                               default:
+                               case DRM_FORCE_ON: s = "ON"; break;
+                               }
+
+                               DRM_INFO("forcing %s connector %s\n",
+                                        drm_get_connector_name(connector), s);
+                               connector->force = mode->force;
+                       }
+
+                       DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
+                                     drm_get_connector_name(connector),
+                                     mode->xres, mode->yres,
+                                     mode->refresh_specified ? mode->refresh : 60,
+                                     mode->rb ? " reduced blanking" : "",
+                                     mode->margins ? " with margins" : "",
+                                     mode->interlace ?  " interlaced" : "");
+               }
+
        }
        return 0;
 }
@@ -342,9 +218,22 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
 
+bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
+{
+       bool error = false;
+       int i, ret;
+       for (i = 0; i < fb_helper->crtc_count; i++) {
+               struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
+               ret = drm_crtc_helper_set_config(mode_set);
+               if (ret)
+                       error = true;
+       }
+       return error;
+}
+EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode);
+
 bool drm_fb_helper_force_kernel_mode(void)
 {
-       int i = 0;
        bool ret, error = false;
        struct drm_fb_helper *helper;
 
@@ -352,12 +241,12 @@ bool drm_fb_helper_force_kernel_mode(void)
                return false;
 
        list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
-               for (i = 0; i < helper->crtc_count; i++) {
-                       struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
-                       ret = drm_crtc_helper_set_config(mode_set);
-                       if (ret)
-                               error = true;
-               }
+               if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+                       continue;
+
+               ret = drm_fb_helper_restore_fbdev_mode(helper);
+               if (ret)
+                       error = true;
        }
        return error;
 }
@@ -367,7 +256,6 @@ int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
 {
        printk(KERN_ERR "panic occurred, switching back to text console\n");
        return drm_fb_helper_force_kernel_mode();
-       return 0;
 }
 EXPORT_SYMBOL(drm_fb_helper_panic);
 
@@ -627,6 +515,11 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
                value = (red << info->var.red.offset) |
                        (green << info->var.green.offset) |
                        (blue << info->var.blue.offset);
+               if (info->var.transp.length > 0) {
+                       u32 mask = (1 << info->var.transp.length) - 1;
+                       mask <<= info->var.transp.offset;
+                       value |= mask;
+               }
                palette[regno] = value;
                return 0;
        }
@@ -672,7 +565,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
        struct drm_crtc_helper_funcs *crtc_funcs;
        u16 *red, *green, *blue, *transp;
        struct drm_crtc *crtc;
-       int i, rc = 0;
+       int i, j, rc = 0;
        int start;
 
        for (i = 0; i < fb_helper->crtc_count; i++) {
@@ -685,7 +578,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
                transp = cmap->transp;
                start = cmap->start;
 
-               for (i = 0; i < cmap->len; i++) {
+               for (j = 0; j < cmap->len; j++) {
                        u16 hred, hgreen, hblue, htransp = 0xffff;
 
                        hred = *red++;
@@ -883,7 +776,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
        /* first up get a count of crtcs now in use and new min/maxes width/heights */
        for (i = 0; i < fb_helper->connector_count; i++) {
                struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
-               struct drm_fb_helper_cmdline_mode *cmdline_mode;
+               struct drm_cmdline_mode *cmdline_mode;
 
                cmdline_mode = &fb_helper_conn->cmdline_mode;
 
@@ -985,6 +878,8 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
        info->fix.type = FB_TYPE_PACKED_PIXELS;
        info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
                FB_VISUAL_TRUECOLOR;
+       info->fix.mmio_start = 0;
+       info->fix.mmio_len = 0;
        info->fix.type_aux = 0;
        info->fix.xpanstep = 1; /* doing it in hw */
        info->fix.ypanstep = 1; /* doing it in hw */
@@ -1005,6 +900,7 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe
        info->var.xres_virtual = fb->width;
        info->var.yres_virtual = fb->height;
        info->var.bits_per_pixel = fb->bits_per_pixel;
+       info->var.accel_flags = FB_ACCELF_TEXT;
        info->var.xoffset = 0;
        info->var.yoffset = 0;
        info->var.activate = FB_ACTIVATE_NOW;
@@ -1102,7 +998,7 @@ static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_conn
 
 static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
 {
-       struct drm_fb_helper_cmdline_mode *cmdline_mode;
+       struct drm_cmdline_mode *cmdline_mode;
        cmdline_mode = &fb_connector->cmdline_mode;
        return cmdline_mode->specified;
 }
@@ -1110,7 +1006,7 @@ static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
 static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
                                                      int width, int height)
 {
-       struct drm_fb_helper_cmdline_mode *cmdline_mode;
+       struct drm_cmdline_mode *cmdline_mode;
        struct drm_display_mode *mode = NULL;
 
        cmdline_mode = &fb_helper_conn->cmdline_mode;
@@ -1142,19 +1038,8 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne
        }
 
 create_mode:
-       if (cmdline_mode->cvt)
-               mode = drm_cvt_mode(fb_helper_conn->connector->dev,
-                                   cmdline_mode->xres, cmdline_mode->yres,
-                                   cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
-                                   cmdline_mode->rb, cmdline_mode->interlace,
-                                   cmdline_mode->margins);
-       else
-               mode = drm_gtf_mode(fb_helper_conn->connector->dev,
-                                   cmdline_mode->xres, cmdline_mode->yres,
-                                   cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
-                                   cmdline_mode->interlace,
-                                   cmdline_mode->margins);
-       drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+       mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
+                                                cmdline_mode);
        list_add(&mode->head, &fb_helper_conn->connector->modes);
        return mode;
 }
@@ -1495,17 +1380,33 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
 }
 EXPORT_SYMBOL(drm_fb_helper_initial_config);
 
-bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
+/**
+ * drm_fb_helper_hotplug_event - respond to a hotplug notification by
+ *                               probing all the outputs attached to the fb.
+ * @fb_helper: the drm_fb_helper
+ *
+ * LOCKING:
+ * Called at runtime, must take mode config lock.
+ *
+ * Scan the connectors attached to the fb_helper and try to put together a
+ * setup after *notification of a change in output configuration.
+ *
+ * RETURNS:
+ * 0 on success and a non-zero error code otherwise.
+ */
+int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 {
+       struct drm_device *dev = fb_helper->dev;
        int count = 0;
        u32 max_width, max_height, bpp_sel;
        bool bound = false, crtcs_bound = false;
        struct drm_crtc *crtc;
 
        if (!fb_helper->fb)
-               return false;
+               return 0;
 
-       list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) {
+       mutex_lock(&dev->mode_config.mutex);
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                if (crtc->fb)
                        crtcs_bound = true;
                if (crtc->fb == fb_helper->fb)
@@ -1514,7 +1415,8 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 
        if (!bound && crtcs_bound) {
                fb_helper->delayed_hotplug = true;
-               return false;
+               mutex_unlock(&dev->mode_config.mutex);
+               return 0;
        }
        DRM_DEBUG_KMS("\n");
 
@@ -1525,8 +1427,30 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
        count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
                                                    max_height);
        drm_setup_crtcs(fb_helper);
+       mutex_unlock(&dev->mode_config.mutex);
 
        return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
 }
 EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
 
+/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
+ * but the module doesn't depend on any fb console symbols.  At least
+ * attempt to load fbcon to avoid leaving the system without a usable console.
+ */
+#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
+static int __init drm_fb_helper_modinit(void)
+{
+       const char *name = "fbcon";
+       struct module *fbcon;
+
+       mutex_lock(&module_mutex);
+       fbcon = find_module(name);
+       mutex_unlock(&module_mutex);
+
+       if (!fbcon)
+               request_module_nowait(name);
+       return 0;
+}
+
+module_init(drm_fb_helper_modinit);
+#endif
index a39794b..2ec7d48 100644 (file)
@@ -236,6 +236,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
                return -EBUSY;  /* No exclusive opens */
        if (!drm_cpu_valid())
                return -EINVAL;
+       if (dev->switch_power_state != DRM_SWITCH_POWER_ON)
+               return -EINVAL;
 
        DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id);
 
index ea1c4b0..186d62e 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/module.h>
 #include <linux/mman.h>
 #include <linux/pagemap.h>
+#include <linux/shmem_fs.h>
 #include "drmP.h"
 
 /** @file drm_gem.c
@@ -101,7 +102,7 @@ drm_gem_init(struct drm_device *dev)
 
        dev->mm_private = mm;
 
-       if (drm_ht_create(&mm->offset_hash, 19)) {
+       if (drm_ht_create(&mm->offset_hash, 12)) {
                kfree(mm);
                return -ENOMEM;
        }
@@ -128,7 +129,7 @@ drm_gem_destroy(struct drm_device *dev)
 }
 
 /**
- * Initialize an already allocate GEM object of the specified size with
+ * Initialize an already allocated GEM object of the specified size with
  * shmfs backing store.
  */
 int drm_gem_object_init(struct drm_device *dev,
@@ -149,6 +150,27 @@ int drm_gem_object_init(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_gem_object_init);
 
+/**
+ * Initialize an already allocated GEM object of the specified size with
+ * no GEM provided backing store. Instead the caller is responsible for
+ * backing the object and handling it.
+ */
+int drm_gem_private_object_init(struct drm_device *dev,
+                       struct drm_gem_object *obj, size_t size)
+{
+       BUG_ON((size & (PAGE_SIZE - 1)) != 0);
+
+       obj->dev = dev;
+       obj->filp = NULL;
+
+       kref_init(&obj->refcount);
+       atomic_set(&obj->handle_count, 0);
+       obj->size = size;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_gem_private_object_init);
+
 /**
  * Allocate a GEM object of the specified size with shmfs backing store
  */
@@ -181,7 +203,7 @@ EXPORT_SYMBOL(drm_gem_object_alloc);
 /**
  * Removes the mapping from handle to filp for this object.
  */
-static int
+int
 drm_gem_handle_delete(struct drm_file *filp, u32 handle)
 {
        struct drm_device *dev;
@@ -210,10 +232,13 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle)
        idr_remove(&filp->object_idr, handle);
        spin_unlock(&filp->table_lock);
 
+       if (dev->driver->gem_close_object)
+               dev->driver->gem_close_object(obj, filp);
        drm_gem_object_handle_unreference_unlocked(obj);
 
        return 0;
 }
+EXPORT_SYMBOL(drm_gem_handle_delete);
 
 /**
  * Create a handle for this object. This adds a handle reference
@@ -225,7 +250,8 @@ drm_gem_handle_create(struct drm_file *file_priv,
                       struct drm_gem_object *obj,
                       u32 *handlep)
 {
-       int     ret;
+       struct drm_device *dev = obj->dev;
+       int ret;
 
        /*
         * Get the user-visible handle using idr.
@@ -246,6 +272,15 @@ again:
                return ret;
 
        drm_gem_object_handle_reference(obj);
+
+       if (dev->driver->gem_open_object) {
+               ret = dev->driver->gem_open_object(obj, file_priv);
+               if (ret) {
+                       drm_gem_handle_delete(file_priv, *handlep);
+                       return ret;
+               }
+       }
+
        return 0;
 }
 EXPORT_SYMBOL(drm_gem_handle_create);
@@ -400,7 +435,12 @@ drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
 static int
 drm_gem_object_release_handle(int id, void *ptr, void *data)
 {
+       struct drm_file *file_priv = data;
        struct drm_gem_object *obj = ptr;
+       struct drm_device *dev = obj->dev;
+
+       if (dev->driver->gem_close_object)
+               dev->driver->gem_close_object(obj, file_priv);
 
        drm_gem_object_handle_unreference_unlocked(obj);
 
@@ -416,7 +456,7 @@ void
 drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
 {
        idr_for_each(&file_private->object_idr,
-                    &drm_gem_object_release_handle, NULL);
+                    &drm_gem_object_release_handle, file_private);
 
        idr_remove_all(&file_private->object_idr);
        idr_destroy(&file_private->object_idr);
@@ -425,7 +465,8 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
 void
 drm_gem_object_release(struct drm_gem_object *obj)
 {
-       fput(obj->filp);
+       if (obj->filp)
+           fput(obj->filp);
 }
 EXPORT_SYMBOL(drm_gem_object_release);
 
@@ -498,11 +539,12 @@ EXPORT_SYMBOL(drm_gem_vm_open);
 void drm_gem_vm_close(struct vm_area_struct *vma)
 {
        struct drm_gem_object *obj = vma->vm_private_data;
+       struct drm_device *dev = obj->dev;
 
-       mutex_lock(&obj->dev->struct_mutex);
+       mutex_lock(&dev->struct_mutex);
        drm_vm_close_locked(vma);
        drm_gem_object_unreference(obj);
-       mutex_unlock(&obj->dev->struct_mutex);
+       mutex_unlock(&dev->struct_mutex);
 }
 EXPORT_SYMBOL(drm_gem_vm_close);
 
index a93d7b4..e3a7568 100644 (file)
 
 int drm_ht_create(struct drm_open_hash *ht, unsigned int order)
 {
-       unsigned int i;
+       unsigned int size = 1 << order;
 
-       ht->size = 1 << order;
        ht->order = order;
-       ht->fill = 0;
        ht->table = NULL;
-       ht->use_vmalloc = ((ht->size * sizeof(*ht->table)) > PAGE_SIZE);
-       if (!ht->use_vmalloc) {
-               ht->table = kcalloc(ht->size, sizeof(*ht->table), GFP_KERNEL);
-       }
-       if (!ht->table) {
-               ht->use_vmalloc = 1;
-               ht->table = vmalloc(ht->size*sizeof(*ht->table));
-       }
+       if (size <= PAGE_SIZE / sizeof(*ht->table))
+               ht->table = kcalloc(size, sizeof(*ht->table), GFP_KERNEL);
+       else
+               ht->table = vzalloc(size*sizeof(*ht->table));
        if (!ht->table) {
                DRM_ERROR("Out of memory for hash table\n");
                return -ENOMEM;
        }
-       for (i=0; i< ht->size; ++i) {
-               INIT_HLIST_HEAD(&ht->table[i]);
-       }
        return 0;
 }
 EXPORT_SYMBOL(drm_ht_create);
@@ -180,7 +171,6 @@ int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key)
        list = drm_ht_find_key(ht, key);
        if (list) {
                hlist_del_init(list);
-               ht->fill--;
                return 0;
        }
        return -EINVAL;
@@ -189,7 +179,6 @@ int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key)
 int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item)
 {
        hlist_del_init(&item->head);
-       ht->fill--;
        return 0;
 }
 EXPORT_SYMBOL(drm_ht_remove_item);
@@ -197,10 +186,10 @@ EXPORT_SYMBOL(drm_ht_remove_item);
 void drm_ht_remove(struct drm_open_hash *ht)
 {
        if (ht->table) {
-               if (ht->use_vmalloc)
-                       vfree(ht->table);
-               else
+               if ((PAGE_SIZE / sizeof(*ht->table)) >> ht->order)
                        kfree(ht->table);
+               else
+                       vfree(ht->table);
                ht->table = NULL;
        }
 }
index 3cdbaf3..ab1162d 100644 (file)
@@ -47,30 +47,19 @@ int drm_name_info(struct seq_file *m, void *data)
        struct drm_minor *minor = node->minor;
        struct drm_device *dev = minor->dev;
        struct drm_master *master = minor->master;
-
+       const char *bus_name;
        if (!master)
                return 0;
 
-       if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) {
-               if (master->unique) {
-                       seq_printf(m, "%s %s %s\n",
-                                       dev->driver->platform_device->name,
-                                       dev_name(dev->dev), master->unique);
-               } else {
-                       seq_printf(m, "%s\n",
-                               dev->driver->platform_device->name);
-               }
+       bus_name = dev->driver->bus->get_name(dev);
+       if (master->unique) {
+               seq_printf(m, "%s %s %s\n",
+                          bus_name,
+                          dev_name(dev->dev), master->unique);
        } else {
-               if (master->unique) {
-                       seq_printf(m, "%s %s %s\n",
-                               dev->driver->pci_driver.name,
-                               dev_name(dev->dev), master->unique);
-               } else {
-                       seq_printf(m, "%s %s\n", dev->driver->pci_driver.name,
-                               dev_name(dev->dev));
-               }
+               seq_printf(m, "%s %s\n",
+                          bus_name, dev_name(dev->dev));
        }
-
        return 0;
 }
 
@@ -283,17 +272,18 @@ int drm_vma_info(struct seq_file *m, void *data)
 #endif
 
        mutex_lock(&dev->struct_mutex);
-       seq_printf(m, "vma use count: %d, high_memory = %p, 0x%08llx\n",
+       seq_printf(m, "vma use count: %d, high_memory = %pK, 0x%pK\n",
                   atomic_read(&dev->vma_count),
-                  high_memory, (u64)virt_to_phys(high_memory));
+                  high_memory, (void *)virt_to_phys(high_memory));
 
        list_for_each_entry(pt, &dev->vmalist, head) {
                vma = pt->vma;
                if (!vma)
                        continue;
                seq_printf(m,
-                          "\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
-                          pt->pid, vma->vm_start, vma->vm_end,
+                          "\n%5d 0x%pK-0x%pK %c%c%c%c%c%c 0x%08lx000",
+                          pt->pid,
+                          (void *)vma->vm_start, (void *)vma->vm_end,
                           vma->vm_flags & VM_READ ? 'r' : '-',
                           vma->vm_flags & VM_WRITE ? 'w' : '-',
                           vma->vm_flags & VM_EXEC ? 'x' : '-',
index d61d185..4a058c7 100644 (file)
@@ -28,6 +28,7 @@
  * IN THE SOFTWARE.
  */
 #include <linux/compat.h>
+#include <linux/ratelimit.h>
 
 #include "drmP.h"
 #include "drm_core.h"
@@ -253,10 +254,10 @@ static int compat_drm_addmap(struct file *file, unsigned int cmd,
                return -EFAULT;
 
        m32.handle = (unsigned long)handle;
-       if (m32.handle != (unsigned long)handle && printk_ratelimit())
-               printk(KERN_ERR "compat_drm_addmap truncated handle"
-                      " %p for type %d offset %x\n",
-                      handle, m32.type, m32.offset);
+       if (m32.handle != (unsigned long)handle)
+               printk_ratelimited(KERN_ERR "compat_drm_addmap truncated handle"
+                                  " %p for type %d offset %x\n",
+                                  handle, m32.type, m32.offset);
 
        if (copy_to_user(argp, &m32, sizeof(m32)))
                return -EFAULT;
index 47db4df..904d7e9 100644 (file)
@@ -96,7 +96,7 @@ int drm_setunique(struct drm_device *dev, void *data,
 {
        struct drm_unique *u = data;
        struct drm_master *master = file_priv->master;
-       int domain, bus, slot, func, ret;
+       int ret;
 
        if (master->unique_len || master->unique)
                return -EBUSY;
@@ -104,50 +104,12 @@ int drm_setunique(struct drm_device *dev, void *data,
        if (!u->unique_len || u->unique_len > 1024)
                return -EINVAL;
 
-       master->unique_len = u->unique_len;
-       master->unique_size = u->unique_len + 1;
-       master->unique = kmalloc(master->unique_size, GFP_KERNEL);
-       if (!master->unique) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       if (copy_from_user(master->unique, u->unique, master->unique_len)) {
-               ret = -EFAULT;
-               goto err;
-       }
-
-       master->unique[master->unique_len] = '\0';
-
-       dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) +
-                              strlen(master->unique) + 2, GFP_KERNEL);
-       if (!dev->devname) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
-               master->unique);
+       if (!dev->driver->bus->set_unique)
+               return -EINVAL;
 
-       /* Return error if the busid submitted doesn't match the device's actual
-        * busid.
-        */
-       ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
-       if (ret != 3) {
-               ret = -EINVAL;
+       ret = dev->driver->bus->set_unique(dev, master, u);
+       if (ret)
                goto err;
-       }
-
-       domain = bus >> 8;
-       bus &= 0xff;
-
-       if ((domain != drm_get_pci_domain(dev)) ||
-           (bus != dev->pdev->bus->number) ||
-           (slot != PCI_SLOT(dev->pdev->devfn)) ||
-           (func != PCI_FUNC(dev->pdev->devfn))) {
-               ret = -EINVAL;
-               goto err;
-       }
 
        return 0;
 
@@ -159,74 +121,15 @@ err:
 static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
 {
        struct drm_master *master = file_priv->master;
-       int len, ret;
+       int ret;
 
        if (master->unique != NULL)
                drm_unset_busid(dev, master);
 
-       if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) {
-               master->unique_len = 10 + strlen(dev->platformdev->name);
-               master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL);
-
-               if (master->unique == NULL)
-                       return -ENOMEM;
-
-               len = snprintf(master->unique, master->unique_len,
-                       "platform:%s", dev->platformdev->name);
-
-               if (len > master->unique_len) {
-                       DRM_ERROR("Unique buffer overflowed\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               dev->devname =
-                       kmalloc(strlen(dev->platformdev->name) +
-                               master->unique_len + 2, GFP_KERNEL);
-
-               if (dev->devname == NULL) {
-                       ret = -ENOMEM;
-                       goto err;
-               }
-
-               sprintf(dev->devname, "%s@%s", dev->platformdev->name,
-                       master->unique);
-
-       } else {
-               master->unique_len = 40;
-               master->unique_size = master->unique_len;
-               master->unique = kmalloc(master->unique_size, GFP_KERNEL);
-               if (master->unique == NULL)
-                       return -ENOMEM;
-
-               len = snprintf(master->unique, master->unique_len,
-                       "pci:%04x:%02x:%02x.%d",
-                       drm_get_pci_domain(dev),
-                       dev->pdev->bus->number,
-                       PCI_SLOT(dev->pdev->devfn),
-                       PCI_FUNC(dev->pdev->devfn));
-               if (len >= master->unique_len) {
-                       DRM_ERROR("buffer overflow");
-                       ret = -EINVAL;
-                       goto err;
-               } else
-                       master->unique_len = len;
-
-               dev->devname =
-                       kmalloc(strlen(dev->driver->pci_driver.name) +
-                               master->unique_len + 2, GFP_KERNEL);
-
-               if (dev->devname == NULL) {
-                       ret = -ENOMEM;
-                       goto err;
-               }
-
-               sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
-                       master->unique);
-       }
-
+       ret = dev->driver->bus->set_busid(dev, master);
+       if (ret)
+               goto err;
        return 0;
-
 err:
        drm_unset_busid(dev, master);
        return ret;
@@ -364,6 +267,28 @@ int drm_getstats(struct drm_device *dev, void *data,
        return 0;
 }
 
+/**
+ * Get device/driver capabilities
+ */
+int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+       struct drm_get_cap *req = data;
+
+       req->value = 0;
+       switch (req->capability) {
+       case DRM_CAP_DUMB_BUFFER:
+               if (dev->driver->dumb_create)
+                       req->value = 1;
+               break;
+       case DRM_CAP_VBLANK_HIGH_CRTC:
+               req->value = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
 /**
  * Setversion ioctl.
  *
index 16d5155..3830e9e 100644 (file)
 #include <linux/slab.h>
 
 #include <linux/vgaarb.h>
+
+/* Access macro for slots in vblank timestamp ringbuffer. */
+#define vblanktimestamp(dev, crtc, count) ( \
+       (dev)->_vblank_time[(crtc) * DRM_VBLANKTIME_RBSIZE + \
+       ((count) % DRM_VBLANKTIME_RBSIZE)])
+
+/* Retry timestamp calculation up to 3 times to satisfy
+ * drm_timestamp_precision before giving up.
+ */
+#define DRM_TIMESTAMP_MAXRETRIES 3
+
+/* Threshold in nanoseconds for detection of redundant
+ * vblank irq in drm_handle_vblank(). 1 msec should be ok.
+ */
+#define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000
+
 /**
  * Get interrupt from bus id.
  *
@@ -58,23 +74,96 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
 {
        struct drm_irq_busid *p = data;
 
-       if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE))
+       if (!dev->driver->bus->irq_by_busid)
                return -EINVAL;
 
        if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                return -EINVAL;
 
-       if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
-           (p->busnum & 0xff) != dev->pdev->bus->number ||
-           p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
-               return -EINVAL;
+       return dev->driver->bus->irq_by_busid(dev, p);
+}
 
-       p->irq = dev->pdev->irq;
+/*
+ * Clear vblank timestamp buffer for a crtc.
+ */
+static void clear_vblank_timestamps(struct drm_device *dev, int crtc)
+{
+       memset(&dev->_vblank_time[crtc * DRM_VBLANKTIME_RBSIZE], 0,
+               DRM_VBLANKTIME_RBSIZE * sizeof(struct timeval));
+}
 
-       DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
-                 p->irq);
+/*
+ * Disable vblank irq's on crtc, make sure that last vblank count
+ * of hardware and corresponding consistent software vblank counter
+ * are preserved, even if there are any spurious vblank irq's after
+ * disable.
+ */
+static void vblank_disable_and_save(struct drm_device *dev, int crtc)
+{
+       unsigned long irqflags;
+       u32 vblcount;
+       s64 diff_ns;
+       int vblrc;
+       struct timeval tvblank;
+
+       /* Prevent vblank irq processing while disabling vblank irqs,
+        * so no updates of timestamps or count can happen after we've
+        * disabled. Needed to prevent races in case of delayed irq's.
+        * Disable preemption, so vblank_time_lock is held as short as
+        * possible, even under a kernel with PREEMPT_RT patches.
+        */
+       preempt_disable();
+       spin_lock_irqsave(&dev->vblank_time_lock, irqflags);
 
-       return 0;
+       dev->driver->disable_vblank(dev, crtc);
+       dev->vblank_enabled[crtc] = 0;
+
+       /* No further vblank irq's will be processed after
+        * this point. Get current hardware vblank count and
+        * vblank timestamp, repeat until they are consistent.
+        *
+        * FIXME: There is still a race condition here and in
+        * drm_update_vblank_count() which can cause off-by-one
+        * reinitialization of software vblank counter. If gpu
+        * vblank counter doesn't increment exactly at the leading
+        * edge of a vblank interval, then we can lose 1 count if
+        * we happen to execute between start of vblank and the
+        * delayed gpu counter increment.
+        */
+       do {
+               dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc);
+               vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0);
+       } while (dev->last_vblank[crtc] != dev->driver->get_vblank_counter(dev, crtc));
+
+       /* Compute time difference to stored timestamp of last vblank
+        * as updated by last invocation of drm_handle_vblank() in vblank irq.
+        */
+       vblcount = atomic_read(&dev->_vblank_count[crtc]);
+       diff_ns = timeval_to_ns(&tvblank) -
+                 timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));
+
+       /* If there is at least 1 msec difference between the last stored
+        * timestamp and tvblank, then we are currently executing our
+        * disable inside a new vblank interval, the tvblank timestamp
+        * corresponds to this new vblank interval and the irq handler
+        * for this vblank didn't run yet and won't run due to our disable.
+        * Therefore we need to do the job of drm_handle_vblank() and
+        * increment the vblank counter by one to account for this vblank.
+        *
+        * Skip this step if there isn't any high precision timestamp
+        * available. In that case we can't account for this and just
+        * hope for the best.
+        */
+       if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) {
+               atomic_inc(&dev->_vblank_count[crtc]);
+               smp_mb__after_atomic_inc();
+       }
+
+       /* Invalidate all timestamps while vblank irq's are off. */
+       clear_vblank_timestamps(dev, crtc);
+
+       spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
+       preempt_enable();
 }
 
 static void vblank_disable_fn(unsigned long arg)
@@ -91,10 +180,7 @@ static void vblank_disable_fn(unsigned long arg)
                if (atomic_read(&dev->vblank_refcount[i]) == 0 &&
                    dev->vblank_enabled[i]) {
                        DRM_DEBUG("disabling vblank on crtc %d\n", i);
-                       dev->last_vblank[i] =
-                               dev->driver->get_vblank_counter(dev, i);
-                       dev->driver->disable_vblank(dev, i);
-                       dev->vblank_enabled[i] = 0;
+                       vblank_disable_and_save(dev, i);
                }
                spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
        }
@@ -117,6 +203,7 @@ void drm_vblank_cleanup(struct drm_device *dev)
        kfree(dev->last_vblank);
        kfree(dev->last_vblank_wait);
        kfree(dev->vblank_inmodeset);
+       kfree(dev->_vblank_time);
 
        dev->num_crtcs = 0;
 }
@@ -129,6 +216,8 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
        setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
                    (unsigned long)dev);
        spin_lock_init(&dev->vbl_lock);
+       spin_lock_init(&dev->vblank_time_lock);
+
        dev->num_crtcs = num_crtcs;
 
        dev->vbl_queue = kmalloc(sizeof(wait_queue_head_t) * num_crtcs,
@@ -161,6 +250,19 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
        if (!dev->vblank_inmodeset)
                goto err;
 
+       dev->_vblank_time = kcalloc(num_crtcs * DRM_VBLANKTIME_RBSIZE,
+                                   sizeof(struct timeval), GFP_KERNEL);
+       if (!dev->_vblank_time)
+               goto err;
+
+       DRM_INFO("Supports vblank timestamp caching Rev 1 (10.10.2010).\n");
+
+       /* Driver specific high-precision vblank timestamping supported? */
+       if (dev->driver->get_vblank_timestamp)
+               DRM_INFO("Driver supports precise vblank timestamp query.\n");
+       else
+               DRM_INFO("No driver support for vblank timestamp query.\n");
+
        /* Zero per-crtc vblank stuff */
        for (i = 0; i < num_crtcs; i++) {
                init_waitqueue_head(&dev->vbl_queue[i]);
@@ -189,11 +291,14 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state)
        if (!dev->irq_enabled)
                return;
 
-       if (state)
-               dev->driver->irq_uninstall(dev);
-       else {
-               dev->driver->irq_preinstall(dev);
-               dev->driver->irq_postinstall(dev);
+       if (state) {
+               if (dev->driver->irq_uninstall)
+                       dev->driver->irq_uninstall(dev);
+       } else {
+               if (dev->driver->irq_preinstall)
+                       dev->driver->irq_preinstall(dev);
+               if (dev->driver->irq_postinstall)
+                       dev->driver->irq_postinstall(dev);
        }
 }
 
@@ -236,7 +341,8 @@ int drm_irq_install(struct drm_device *dev)
        DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
 
        /* Before installing handler */
-       dev->driver->irq_preinstall(dev);
+       if (dev->driver->irq_preinstall)
+               dev->driver->irq_preinstall(dev);
 
        /* Install handler */
        if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
@@ -261,11 +367,16 @@ int drm_irq_install(struct drm_device *dev)
                vga_client_register(dev->pdev, (void *)dev, drm_irq_vgaarb_nokms, NULL);
 
        /* After installing handler */
-       ret = dev->driver->irq_postinstall(dev);
+       if (dev->driver->irq_postinstall)
+               ret = dev->driver->irq_postinstall(dev);
+
        if (ret < 0) {
                mutex_lock(&dev->struct_mutex);
                dev->irq_enabled = 0;
                mutex_unlock(&dev->struct_mutex);
+               if (!drm_core_check_feature(dev, DRIVER_MODESET))
+                       vga_client_register(dev->pdev, NULL, NULL, NULL);
+               free_irq(drm_dev_to_irq(dev), dev);
        }
 
        return ret;
@@ -279,7 +390,7 @@ EXPORT_SYMBOL(drm_irq_install);
  *
  * Calls the driver's \c drm_driver_irq_uninstall() function, and stops the irq.
  */
-int drm_irq_uninstall(struct drm_device * dev)
+int drm_irq_uninstall(struct drm_device *dev)
 {
        unsigned long irqflags;
        int irq_enabled, i;
@@ -311,7 +422,8 @@ int drm_irq_uninstall(struct drm_device * dev)
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                vga_client_register(dev->pdev, NULL, NULL, NULL);
 
-       dev->driver->irq_uninstall(dev);
+       if (dev->driver->irq_uninstall)
+               dev->driver->irq_uninstall(dev);
 
        free_irq(drm_dev_to_irq(dev), dev);
 
@@ -335,7 +447,9 @@ int drm_control(struct drm_device *dev, void *data,
 {
        struct drm_control *ctl = data;
 
-       /* if we haven't irq we fallback for compatibility reasons - this used to be a separate function in drm_dma.h */
+       /* if we haven't irq we fallback for compatibility reasons -
+        * this used to be a separate function in drm_dma.h
+        */
 
 
        switch (ctl->func) {
@@ -359,6 +473,286 @@ int drm_control(struct drm_device *dev, void *data,
        }
 }
 
+/**
+ * drm_calc_timestamping_constants - Calculate and
+ * store various constants which are later needed by
+ * vblank and swap-completion timestamping, e.g, by
+ * drm_calc_vbltimestamp_from_scanoutpos().
+ * They are derived from crtc's true scanout timing,
+ * so they take things like panel scaling or other
+ * adjustments into account.
+ *
+ * @crtc drm_crtc whose timestamp constants should be updated.
+ *
+ */
+void drm_calc_timestamping_constants(struct drm_crtc *crtc)
+{
+       s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0;
+       u64 dotclock;
+
+       /* Dot clock in Hz: */
+       dotclock = (u64) crtc->hwmode.clock * 1000;
+
+       /* Fields of interlaced scanout modes are only halve a frame duration.
+        * Double the dotclock to get halve the frame-/line-/pixelduration.
+        */
+       if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE)
+               dotclock *= 2;
+
+       /* Valid dotclock? */
+       if (dotclock > 0) {
+               /* Convert scanline length in pixels and video dot clock to
+                * line duration, frame duration and pixel duration in
+                * nanoseconds:
+                */
+               pixeldur_ns = (s64) div64_u64(1000000000, dotclock);
+               linedur_ns  = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal *
+                                             1000000000), dotclock);
+               framedur_ns = (s64) crtc->hwmode.crtc_vtotal * linedur_ns;
+       } else
+               DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n",
+                         crtc->base.id);
+
+       crtc->pixeldur_ns = pixeldur_ns;
+       crtc->linedur_ns  = linedur_ns;
+       crtc->framedur_ns = framedur_ns;
+
+       DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n",
+                 crtc->base.id, crtc->hwmode.crtc_htotal,
+                 crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay);
+       DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n",
+                 crtc->base.id, (int) dotclock/1000, (int) framedur_ns,
+                 (int) linedur_ns, (int) pixeldur_ns);
+}
+EXPORT_SYMBOL(drm_calc_timestamping_constants);
+
+/**
+ * drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms
+ * drivers. Implements calculation of exact vblank timestamps from
+ * given drm_display_mode timings and current video scanout position
+ * of a crtc. This can be called from within get_vblank_timestamp()
+ * implementation of a kms driver to implement the actual timestamping.
+ *
+ * Should return timestamps conforming to the OML_sync_control OpenML
+ * extension specification. The timestamp corresponds to the end of
+ * the vblank interval, aka start of scanout of topmost-leftmost display
+ * pixel in the following video frame.
+ *
+ * Requires support for optional dev->driver->get_scanout_position()
+ * in kms driver, plus a bit of setup code to provide a drm_display_mode
+ * that corresponds to the true scanout timing.
+ *
+ * The current implementation only handles standard video modes. It
+ * returns as no operation if a doublescan or interlaced video mode is
+ * active. Higher level code is expected to handle this.
+ *
+ * @dev: DRM device.
+ * @crtc: Which crtc's vblank timestamp to retrieve.
+ * @max_error: Desired maximum allowable error in timestamps (nanosecs).
+ *             On return contains true maximum error of timestamp.
+ * @vblank_time: Pointer to struct timeval which should receive the timestamp.
+ * @flags: Flags to pass to driver:
+ *         0 = Default.
+ *         DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
+ * @refcrtc: drm_crtc* of crtc which defines scanout timing.
+ *
+ * Returns negative value on error, failure or if not supported in current
+ * video mode:
+ *
+ * -EINVAL   - Invalid crtc.
+ * -EAGAIN   - Temporary unavailable, e.g., called before initial modeset.
+ * -ENOTSUPP - Function not supported in current display mode.
+ * -EIO      - Failed, e.g., due to failed scanout position query.
+ *
+ * Returns or'ed positive status flags on success:
+ *
+ * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping.
+ * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval.
+ *
+ */
+int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
+                                         int *max_error,
+                                         struct timeval *vblank_time,
+                                         unsigned flags,
+                                         struct drm_crtc *refcrtc)
+{
+       struct timeval stime, raw_time;
+       struct drm_display_mode *mode;
+       int vbl_status, vtotal, vdisplay;
+       int vpos, hpos, i;
+       s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
+       bool invbl;
+
+       if (crtc < 0 || crtc >= dev->num_crtcs) {
+               DRM_ERROR("Invalid crtc %d\n", crtc);
+               return -EINVAL;
+       }
+
+       /* Scanout position query not supported? Should not happen. */
+       if (!dev->driver->get_scanout_position) {
+               DRM_ERROR("Called from driver w/o get_scanout_position()!?\n");
+               return -EIO;
+       }
+
+       mode = &refcrtc->hwmode;
+       vtotal = mode->crtc_vtotal;
+       vdisplay = mode->crtc_vdisplay;
+
+       /* Durations of frames, lines, pixels in nanoseconds. */
+       framedur_ns = refcrtc->framedur_ns;
+       linedur_ns  = refcrtc->linedur_ns;
+       pixeldur_ns = refcrtc->pixeldur_ns;
+
+       /* If mode timing undefined, just return as no-op:
+        * Happens during initial modesetting of a crtc.
+        */
+       if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) {
+               DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc);
+               return -EAGAIN;
+       }
+
+       /* Get current scanout position with system timestamp.
+        * Repeat query up to DRM_TIMESTAMP_MAXRETRIES times
+        * if single query takes longer than max_error nanoseconds.
+        *
+        * This guarantees a tight bound on maximum error if
+        * code gets preempted or delayed for some reason.
+        */
+       for (i = 0; i < DRM_TIMESTAMP_MAXRETRIES; i++) {
+               /* Disable preemption to make it very likely to
+                * succeed in the first iteration even on PREEMPT_RT kernel.
+                */
+               preempt_disable();
+
+               /* Get system timestamp before query. */
+               do_gettimeofday(&stime);
+
+               /* Get vertical and horizontal scanout pos. vpos, hpos. */
+               vbl_status = dev->driver->get_scanout_position(dev, crtc, &vpos, &hpos);
+
+               /* Get system timestamp after query. */
+               do_gettimeofday(&raw_time);
+
+               preempt_enable();
+
+               /* Return as no-op if scanout query unsupported or failed. */
+               if (!(vbl_status & DRM_SCANOUTPOS_VALID)) {
+                       DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n",
+                                 crtc, vbl_status);
+                       return -EIO;
+               }
+
+               duration_ns = timeval_to_ns(&raw_time) - timeval_to_ns(&stime);
+
+               /* Accept result with <  max_error nsecs timing uncertainty. */
+               if (duration_ns <= (s64) *max_error)
+                       break;
+       }
+
+       /* Noisy system timing? */
+       if (i == DRM_TIMESTAMP_MAXRETRIES) {
+               DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n",
+                         crtc, (int) duration_ns/1000, *max_error/1000, i);
+       }
+
+       /* Return upper bound of timestamp precision error. */
+       *max_error = (int) duration_ns;
+
+       /* Check if in vblank area:
+        * vpos is >=0 in video scanout area, but negative
+        * within vblank area, counting down the number of lines until
+        * start of scanout.
+        */
+       invbl = vbl_status & DRM_SCANOUTPOS_INVBL;
+
+       /* Convert scanout position into elapsed time at raw_time query
+        * since start of scanout at first display scanline. delta_ns
+        * can be negative if start of scanout hasn't happened yet.
+        */
+       delta_ns = (s64) vpos * linedur_ns + (s64) hpos * pixeldur_ns;
+
+       /* Is vpos outside nominal vblank area, but less than
+        * 1/100 of a frame height away from start of vblank?
+        * If so, assume this isn't a massively delayed vblank
+        * interrupt, but a vblank interrupt that fired a few
+        * microseconds before true start of vblank. Compensate
+        * by adding a full frame duration to the final timestamp.
+        * Happens, e.g., on ATI R500, R600.
+        *
+        * We only do this if DRM_CALLED_FROM_VBLIRQ.
+        */
+       if ((flags & DRM_CALLED_FROM_VBLIRQ) && !invbl &&
+           ((vdisplay - vpos) < vtotal / 100)) {
+               delta_ns = delta_ns - framedur_ns;
+
+               /* Signal this correction as "applied". */
+               vbl_status |= 0x8;
+       }
+
+       /* Subtract time delta from raw timestamp to get final
+        * vblank_time timestamp for end of vblank.
+        */
+       *vblank_time = ns_to_timeval(timeval_to_ns(&raw_time) - delta_ns);
+
+       DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
+                 crtc, (int)vbl_status, hpos, vpos,
+                 (long)raw_time.tv_sec, (long)raw_time.tv_usec,
+                 (long)vblank_time->tv_sec, (long)vblank_time->tv_usec,
+                 (int)duration_ns/1000, i);
+
+       vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD;
+       if (invbl)
+               vbl_status |= DRM_VBLANKTIME_INVBL;
+
+       return vbl_status;
+}
+EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
+
+/**
+ * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent
+ * vblank interval.
+ *
+ * @dev: DRM device
+ * @crtc: which crtc's vblank timestamp to retrieve
+ * @tvblank: Pointer to target struct timeval which should receive the timestamp
+ * @flags: Flags to pass to driver:
+ *         0 = Default.
+ *         DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
+ *
+ * Fetches the system timestamp corresponding to the time of the most recent
+ * vblank interval on specified crtc. May call into kms-driver to
+ * compute the timestamp with a high-precision GPU specific method.
+ *
+ * Returns zero if timestamp originates from uncorrected do_gettimeofday()
+ * call, i.e., it isn't very precisely locked to the true vblank.
+ *
+ * Returns non-zero if timestamp is considered to be very precise.
+ */
+u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
+                             struct timeval *tvblank, unsigned flags)
+{
+       int ret = 0;
+
+       /* Define requested maximum error on timestamps (nanoseconds). */
+       int max_error = (int) drm_timestamp_precision * 1000;
+
+       /* Query driver if possible and precision timestamping enabled. */
+       if (dev->driver->get_vblank_timestamp && (max_error > 0)) {
+               ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error,
+                                                       tvblank, flags);
+               if (ret > 0)
+                       return (u32) ret;
+       }
+
+       /* GPU high precision timestamp query unsupported or failed.
+        * Return gettimeofday timestamp as best estimate.
+        */
+       do_gettimeofday(tvblank);
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_get_last_vbltimestamp);
+
 /**
  * drm_vblank_count - retrieve "cooked" vblank counter value
  * @dev: DRM device
@@ -374,6 +768,40 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc)
 }
 EXPORT_SYMBOL(drm_vblank_count);
 
+/**
+ * drm_vblank_count_and_time - retrieve "cooked" vblank counter value
+ * and the system timestamp corresponding to that vblank counter value.
+ *
+ * @dev: DRM device
+ * @crtc: which counter to retrieve
+ * @vblanktime: Pointer to struct timeval to receive the vblank timestamp.
+ *
+ * Fetches the "cooked" vblank count value that represents the number of
+ * vblank events since the system was booted, including lost events due to
+ * modesetting activity. Returns corresponding system timestamp of the time
+ * of the vblank interval that corresponds to the current value vblank counter
+ * value.
+ */
+u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
+                             struct timeval *vblanktime)
+{
+       u32 cur_vblank;
+
+       /* Read timestamp from slot of _vblank_time ringbuffer
+        * that corresponds to current vblank count. Retry if
+        * count has incremented during readout. This works like
+        * a seqlock.
+        */
+       do {
+               cur_vblank = atomic_read(&dev->_vblank_count[crtc]);
+               *vblanktime = vblanktimestamp(dev, crtc, cur_vblank);
+               smp_rmb();
+       } while (cur_vblank != atomic_read(&dev->_vblank_count[crtc]));
+
+       return cur_vblank;
+}
+EXPORT_SYMBOL(drm_vblank_count_and_time);
+
 /**
  * drm_update_vblank_count - update the master vblank counter
  * @dev: DRM device
@@ -392,7 +820,8 @@ EXPORT_SYMBOL(drm_vblank_count);
  */
 static void drm_update_vblank_count(struct drm_device *dev, int crtc)
 {
-       u32 cur_vblank, diff;
+       u32 cur_vblank, diff, tslot, rc;
+       struct timeval t_vblank;
 
        /*
         * Interrupts were disabled prior to this call, so deal with counter
@@ -400,8 +829,18 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
         * NOTE!  It's possible we lost a full dev->max_vblank_count events
         * here if the register is small or we had vblank interrupts off for
         * a long time.
+        *
+        * We repeat the hardware vblank counter & timestamp query until
+        * we get consistent results. This to prevent races between gpu
+        * updating its hardware counter while we are retrieving the
+        * corresponding vblank timestamp.
         */
-       cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
+       do {
+               cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
+               rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0);
+       } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc));
+
+       /* Deal with counter wrap */
        diff = cur_vblank - dev->last_vblank[crtc];
        if (cur_vblank < dev->last_vblank[crtc]) {
                diff += dev->max_vblank_count;
@@ -413,7 +852,18 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
        DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",
                  crtc, diff);
 
+       /* Reinitialize corresponding vblank timestamp if high-precision query
+        * available. Skip this step if query unsupported or failed. Will
+        * reinitialize delayed at next vblank interrupt in that case.
+        */
+       if (rc) {
+               tslot = atomic_read(&dev->_vblank_count[crtc]) + diff;
+               vblanktimestamp(dev, crtc, tslot) = t_vblank;
+       }
+
+       smp_mb__before_atomic_inc();
        atomic_add(diff, &dev->_vblank_count[crtc]);
+       smp_mb__after_atomic_inc();
 }
 
 /**
@@ -429,15 +879,27 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
  */
 int drm_vblank_get(struct drm_device *dev, int crtc)
 {
-       unsigned long irqflags;
+       unsigned long irqflags, irqflags2;
        int ret = 0;
 
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
        /* Going from 0->1 means we have to enable interrupts again */
        if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) {
+               /* Disable preemption while holding vblank_time_lock. Do
+                * it explicitely to guard against PREEMPT_RT kernel.
+                */
+               preempt_disable();
+               spin_lock_irqsave(&dev->vblank_time_lock, irqflags2);
                if (!dev->vblank_enabled[crtc]) {
+                       /* Enable vblank irqs under vblank_time_lock protection.
+                        * All vblank count & timestamp updates are held off
+                        * until we are done reinitializing master counter and
+                        * timestamps. Filtercode in drm_handle_vblank() will
+                        * prevent double-accounting of same vblank interval.
+                        */
                        ret = dev->driver->enable_vblank(dev, crtc);
-                       DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
+                       DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n",
+                                 crtc, ret);
                        if (ret)
                                atomic_dec(&dev->vblank_refcount[crtc]);
                        else {
@@ -445,6 +907,8 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
                                drm_update_vblank_count(dev, crtc);
                        }
                }
+               spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags2);
+               preempt_enable();
        } else {
                if (!dev->vblank_enabled[crtc]) {
                        atomic_dec(&dev->vblank_refcount[crtc]);
@@ -463,27 +927,50 @@ EXPORT_SYMBOL(drm_vblank_get);
  * @crtc: which counter to give up
  *
  * Release ownership of a given vblank counter, turning off interrupts
- * if possible.
+ * if possible. Disable interrupts after drm_vblank_offdelay milliseconds.
  */
 void drm_vblank_put(struct drm_device *dev, int crtc)
 {
-       BUG_ON (atomic_read (&dev->vblank_refcount[crtc]) == 0);
+       BUG_ON(atomic_read(&dev->vblank_refcount[crtc]) == 0);
 
        /* Last user schedules interrupt disable */
-       if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
-               mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ);
+       if (atomic_dec_and_test(&dev->vblank_refcount[crtc]) &&
+           (drm_vblank_offdelay > 0))
+               mod_timer(&dev->vblank_disable_timer,
+                         jiffies + ((drm_vblank_offdelay * DRM_HZ)/1000));
 }
 EXPORT_SYMBOL(drm_vblank_put);
 
 void drm_vblank_off(struct drm_device *dev, int crtc)
 {
+       struct drm_pending_vblank_event *e, *t;
+       struct timeval now;
        unsigned long irqflags;
+       unsigned int seq;
 
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
-       dev->driver->disable_vblank(dev, crtc);
+       vblank_disable_and_save(dev, crtc);
        DRM_WAKEUP(&dev->vbl_queue[crtc]);
-       dev->vblank_enabled[crtc] = 0;
-       dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc);
+
+       /* Send any queued vblank events, lest the natives grow disquiet */
+       seq = drm_vblank_count_and_time(dev, crtc, &now);
+       list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
+               if (e->pipe != crtc)
+                       continue;
+               DRM_DEBUG("Sending premature vblank event on disable: \
+                         wanted %d, current %d\n",
+                         e->event.sequence, seq);
+
+               e->event.sequence = seq;
+               e->event.tv_sec = now.tv_sec;
+               e->event.tv_usec = now.tv_usec;
+               drm_vblank_put(dev, e->pipe);
+               list_move_tail(&e->base.link, &e->base.file_priv->event_list);
+               wake_up_interruptible(&e->base.file_priv->event_wait);
+               trace_drm_vblank_event_delivered(e->base.pid, e->pipe,
+                                                e->event.sequence);
+       }
+
        spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 }
 EXPORT_SYMBOL(drm_vblank_off);
@@ -549,7 +1036,8 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
                    struct drm_file *file_priv)
 {
        struct drm_modeset_ctl *modeset = data;
-       int crtc, ret = 0;
+       int ret = 0;
+       unsigned int crtc;
 
        /* If drm_vblank_init() hasn't been called yet, just no-op */
        if (!dev->num_crtcs)
@@ -602,7 +1090,6 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
        e->base.file_priv = file_priv;
        e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
 
-       do_gettimeofday(&now);
        spin_lock_irqsave(&dev->event_lock, flags);
 
        if (file_priv->event_space < sizeof e->event) {
@@ -611,7 +1098,8 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
        }
 
        file_priv->event_space -= sizeof e->event;
-       seq = drm_vblank_count(dev, pipe);
+       seq = drm_vblank_count_and_time(dev, pipe, &now);
+
        if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) &&
            (seq - vblwait->request.sequence) <= (1 << 23)) {
                vblwait->request.sequence = seq + 1;
@@ -626,15 +1114,18 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
 
        e->event.sequence = vblwait->request.sequence;
        if ((seq - vblwait->request.sequence) <= (1 << 23)) {
+               e->event.sequence = seq;
                e->event.tv_sec = now.tv_sec;
                e->event.tv_usec = now.tv_usec;
                drm_vblank_put(dev, pipe);
                list_add_tail(&e->base.link, &e->base.file_priv->event_list);
                wake_up_interruptible(&e->base.file_priv->event_wait);
+               vblwait->reply.sequence = seq;
                trace_drm_vblank_event_delivered(current->pid, pipe,
                                                 vblwait->request.sequence);
        } else {
                list_add_tail(&e->base.link, &dev->vblank_event_list);
+               vblwait->reply.sequence = vblwait->request.sequence;
        }
 
        spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -668,7 +1159,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
 {
        union drm_wait_vblank *vblwait = data;
        int ret = 0;
-       unsigned int flags, seq, crtc;
+       unsigned int flags, seq, crtc, high_crtc;
 
        if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled))
                return -EINVAL;
@@ -677,16 +1168,21 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
                return -EINVAL;
 
        if (vblwait->request.type &
-           ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
+           ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK |
+             _DRM_VBLANK_HIGH_CRTC_MASK)) {
                DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
                          vblwait->request.type,
-                         (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
+                         (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK |
+                          _DRM_VBLANK_HIGH_CRTC_MASK));
                return -EINVAL;
        }
 
        flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
-       crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
-
+       high_crtc = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK);
+       if (high_crtc)
+               crtc = high_crtc >> _DRM_VBLANK_HIGH_CRTC_SHIFT;
+       else
+               crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
        if (crtc >= dev->num_crtcs)
                return -EINVAL;
 
@@ -727,11 +1223,10 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
        if (ret != -EINTR) {
                struct timeval now;
 
-               do_gettimeofday(&now);
-
+               vblwait->reply.sequence = drm_vblank_count_and_time(dev, crtc, &now);
                vblwait->reply.tval_sec = now.tv_sec;
                vblwait->reply.tval_usec = now.tv_usec;
-               vblwait->reply.sequence = drm_vblank_count(dev, crtc);
+
                DRM_DEBUG("returning %d to client\n",
                          vblwait->reply.sequence);
        } else {
@@ -750,8 +1245,7 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc)
        unsigned long flags;
        unsigned int seq;
 
-       do_gettimeofday(&now);
-       seq = drm_vblank_count(dev, crtc);
+       seq = drm_vblank_count_and_time(dev, crtc, &now);
 
        spin_lock_irqsave(&dev->event_lock, flags);
 
@@ -787,13 +1281,68 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc)
  * Drivers should call this routine in their vblank interrupt handlers to
  * update the vblank counter and send any signals that may be pending.
  */
-void drm_handle_vblank(struct drm_device *dev, int crtc)
+bool drm_handle_vblank(struct drm_device *dev, int crtc)
 {
+       u32 vblcount;
+       s64 diff_ns;
+       struct timeval tvblank;
+       unsigned long irqflags;
+
        if (!dev->num_crtcs)
-               return;
+               return false;
+
+       /* Need timestamp lock to prevent concurrent execution with
+        * vblank enable/disable, as this would cause inconsistent
+        * or corrupted timestamps and vblank counts.
+        */
+       spin_lock_irqsave(&dev->vblank_time_lock, irqflags);
+
+       /* Vblank irq handling disabled. Nothing to do. */
+       if (!dev->vblank_enabled[crtc]) {
+               spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
+               return false;
+       }
+
+       /* Fetch corresponding timestamp for this vblank interval from
+        * driver and store it in proper slot of timestamp ringbuffer.
+        */
+
+       /* Get current timestamp and count. */
+       vblcount = atomic_read(&dev->_vblank_count[crtc]);
+       drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ);
+
+       /* Compute time difference to timestamp of last vblank */
+       diff_ns = timeval_to_ns(&tvblank) -
+                 timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));
+
+       /* Update vblank timestamp and count if at least
+        * DRM_REDUNDANT_VBLIRQ_THRESH_NS nanoseconds
+        * difference between last stored timestamp and current
+        * timestamp. A smaller difference means basically
+        * identical timestamps. Happens if this vblank has
+        * been already processed and this is a redundant call,
+        * e.g., due to spurious vblank interrupts. We need to
+        * ignore those for accounting.
+        */
+       if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) {
+               /* Store new timestamp in ringbuffer. */
+               vblanktimestamp(dev, crtc, vblcount + 1) = tvblank;
+
+               /* Increment cooked vblank count. This also atomically commits
+                * the timestamp computed above.
+                */
+               smp_mb__before_atomic_inc();
+               atomic_inc(&dev->_vblank_count[crtc]);
+               smp_mb__after_atomic_inc();
+       } else {
+               DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n",
+                         crtc, (int) diff_ns);
+       }
 
-       atomic_inc(&dev->_vblank_count[crtc]);
        DRM_WAKEUP(&dev->vbl_queue[crtc]);
        drm_handle_vblank_events(dev, crtc);
+
+       spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
+       return true;
 }
 EXPORT_SYMBOL(drm_handle_vblank);
index a6bfc30..959186c 100644 (file)
@@ -64,8 +64,8 @@ static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic)
                else {
                        child =
                            list_entry(mm->unused_nodes.next,
-                                      struct drm_mm_node, free_stack);
-                       list_del(&child->free_stack);
+                                      struct drm_mm_node, node_list);
+                       list_del(&child->node_list);
                        --mm->num_unused;
                }
                spin_unlock(&mm->unused_lock);
@@ -94,195 +94,242 @@ int drm_mm_pre_get(struct drm_mm *mm)
                        return ret;
                }
                ++mm->num_unused;
-               list_add_tail(&node->free_stack, &mm->unused_nodes);
+               list_add_tail(&node->node_list, &mm->unused_nodes);
        }
        spin_unlock(&mm->unused_lock);
        return 0;
 }
 EXPORT_SYMBOL(drm_mm_pre_get);
 
-static int drm_mm_create_tail_node(struct drm_mm *mm,
-                                  unsigned long start,
-                                  unsigned long size, int atomic)
+static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node)
 {
-       struct drm_mm_node *child;
-
-       child = drm_mm_kmalloc(mm, atomic);
-       if (unlikely(child == NULL))
-               return -ENOMEM;
-
-       child->free = 1;
-       child->size = size;
-       child->start = start;
-       child->mm = mm;
+       return hole_node->start + hole_node->size;
+}
 
-       list_add_tail(&child->node_list, &mm->node_list);
-       list_add_tail(&child->free_stack, &mm->free_stack);
+static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
+{
+       struct drm_mm_node *next_node =
+               list_entry(hole_node->node_list.next, struct drm_mm_node,
+                          node_list);
 
-       return 0;
+       return next_node->start;
 }
 
-static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent,
-                                                unsigned long size,
-                                                int atomic)
+static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
+                                struct drm_mm_node *node,
+                                unsigned long size, unsigned alignment)
 {
-       struct drm_mm_node *child;
+       struct drm_mm *mm = hole_node->mm;
+       unsigned long tmp = 0, wasted = 0;
+       unsigned long hole_start = drm_mm_hole_node_start(hole_node);
+       unsigned long hole_end = drm_mm_hole_node_end(hole_node);
 
-       child = drm_mm_kmalloc(parent->mm, atomic);
-       if (unlikely(child == NULL))
-               return NULL;
+       BUG_ON(!hole_node->hole_follows || node->allocated);
 
-       INIT_LIST_HEAD(&child->free_stack);
+       if (alignment)
+               tmp = hole_start % alignment;
 
-       child->size = size;
-       child->start = parent->start;
-       child->mm = parent->mm;
+       if (!tmp) {
+               hole_node->hole_follows = 0;
+               list_del_init(&hole_node->hole_stack);
+       } else
+               wasted = alignment - tmp;
 
-       list_add_tail(&child->node_list, &parent->node_list);
-       INIT_LIST_HEAD(&child->free_stack);
+       node->start = hole_start + wasted;
+       node->size = size;
+       node->mm = mm;
+       node->allocated = 1;
 
-       parent->size -= size;
-       parent->start += size;
-       return child;
-}
+       INIT_LIST_HEAD(&node->hole_stack);
+       list_add(&node->node_list, &hole_node->node_list);
 
+       BUG_ON(node->start + node->size > hole_end);
+
+       if (node->start + node->size < hole_end) {
+               list_add(&node->hole_stack, &mm->hole_stack);
+               node->hole_follows = 1;
+       } else {
+               node->hole_follows = 0;
+       }
+}
 
-struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node,
+struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *hole_node,
                                             unsigned long size,
                                             unsigned alignment,
                                             int atomic)
 {
+       struct drm_mm_node *node;
+
+       node = drm_mm_kmalloc(hole_node->mm, atomic);
+       if (unlikely(node == NULL))
+               return NULL;
 
-       struct drm_mm_node *align_splitoff = NULL;
-       unsigned tmp = 0;
+       drm_mm_insert_helper(hole_node, node, size, alignment);
 
-       if (alignment)
-               tmp = node->start % alignment;
+       return node;
+}
+EXPORT_SYMBOL(drm_mm_get_block_generic);
 
-       if (tmp) {
-               align_splitoff =
-                   drm_mm_split_at_start(node, alignment - tmp, atomic);
-               if (unlikely(align_splitoff == NULL))
-                       return NULL;
-       }
+/**
+ * Search for free space and insert a preallocated memory node. Returns
+ * -ENOSPC if no suitable free area is available. The preallocated memory node
+ * must be cleared.
+ */
+int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node,
+                      unsigned long size, unsigned alignment)
+{
+       struct drm_mm_node *hole_node;
 
-       if (node->size == size) {
-               list_del_init(&node->free_stack);
-               node->free = 0;
-       } else {
-               node = drm_mm_split_at_start(node, size, atomic);
-       }
+       hole_node = drm_mm_search_free(mm, size, alignment, 0);
+       if (!hole_node)
+               return -ENOSPC;
 
-       if (align_splitoff)
-               drm_mm_put_block(align_splitoff);
+       drm_mm_insert_helper(hole_node, node, size, alignment);
 
-       return node;
+       return 0;
 }
-EXPORT_SYMBOL(drm_mm_get_block_generic);
+EXPORT_SYMBOL(drm_mm_insert_node);
 
-struct drm_mm_node *drm_mm_get_block_range_generic(struct drm_mm_node *node,
-                                               unsigned long size,
-                                               unsigned alignment,
-                                               unsigned long start,
-                                               unsigned long end,
-                                               int atomic)
+static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
+                                      struct drm_mm_node *node,
+                                      unsigned long size, unsigned alignment,
+                                      unsigned long start, unsigned long end)
 {
-       struct drm_mm_node *align_splitoff = NULL;
-       unsigned tmp = 0;
-       unsigned wasted = 0;
+       struct drm_mm *mm = hole_node->mm;
+       unsigned long tmp = 0, wasted = 0;
+       unsigned long hole_start = drm_mm_hole_node_start(hole_node);
+       unsigned long hole_end = drm_mm_hole_node_end(hole_node);
 
-       if (node->start < start)
-               wasted += start - node->start;
+       BUG_ON(!hole_node->hole_follows || node->allocated);
+
+       if (hole_start < start)
+               wasted += start - hole_start;
        if (alignment)
-               tmp = ((node->start + wasted) % alignment);
+               tmp = (hole_start + wasted) % alignment;
 
        if (tmp)
                wasted += alignment - tmp;
-       if (wasted) {
-               align_splitoff = drm_mm_split_at_start(node, wasted, atomic);
-               if (unlikely(align_splitoff == NULL))
-                       return NULL;
+
+       if (!wasted) {
+               hole_node->hole_follows = 0;
+               list_del_init(&hole_node->hole_stack);
        }
 
-       if (node->size == size) {
-               list_del_init(&node->free_stack);
-               node->free = 0;
+       node->start = hole_start + wasted;
+       node->size = size;
+       node->mm = mm;
+       node->allocated = 1;
+
+       INIT_LIST_HEAD(&node->hole_stack);
+       list_add(&node->node_list, &hole_node->node_list);
+
+       BUG_ON(node->start + node->size > hole_end);
+       BUG_ON(node->start + node->size > end);
+
+       if (node->start + node->size < hole_end) {
+               list_add(&node->hole_stack, &mm->hole_stack);
+               node->hole_follows = 1;
        } else {
-               node = drm_mm_split_at_start(node, size, atomic);
+               node->hole_follows = 0;
        }
+}
+
+struct drm_mm_node *drm_mm_get_block_range_generic(struct drm_mm_node *hole_node,
+                                               unsigned long size,
+                                               unsigned alignment,
+                                               unsigned long start,
+                                               unsigned long end,
+                                               int atomic)
+{
+       struct drm_mm_node *node;
 
-       if (align_splitoff)
-               drm_mm_put_block(align_splitoff);
+       node = drm_mm_kmalloc(hole_node->mm, atomic);
+       if (unlikely(node == NULL))
+               return NULL;
+
+       drm_mm_insert_helper_range(hole_node, node, size, alignment,
+                                  start, end);
 
        return node;
 }
 EXPORT_SYMBOL(drm_mm_get_block_range_generic);
 
-/*
- * Put a block. Merge with the previous and / or next block if they are free.
- * Otherwise add to the free stack.
+/**
+ * Search for free space and insert a preallocated memory node. Returns
+ * -ENOSPC if no suitable free area is available. This is for range
+ * restricted allocations. The preallocated memory node must be cleared.
  */
-
-void drm_mm_put_block(struct drm_mm_node *cur)
+int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node,
+                               unsigned long size, unsigned alignment,
+                               unsigned long start, unsigned long end)
 {
+       struct drm_mm_node *hole_node;
 
-       struct drm_mm *mm = cur->mm;
-       struct list_head *cur_head = &cur->node_list;
-       struct list_head *root_head = &mm->node_list;
-       struct drm_mm_node *prev_node = NULL;
-       struct drm_mm_node *next_node;
+       hole_node = drm_mm_search_free_in_range(mm, size, alignment,
+                                               start, end, 0);
+       if (!hole_node)
+               return -ENOSPC;
 
-       int merged = 0;
+       drm_mm_insert_helper_range(hole_node, node, size, alignment,
+                                  start, end);
 
-       BUG_ON(cur->scanned_block || cur->scanned_prev_free
-                                 || cur->scanned_next_free);
+       return 0;
+}
+EXPORT_SYMBOL(drm_mm_insert_node_in_range);
 
-       if (cur_head->prev != root_head) {
-               prev_node =
-                   list_entry(cur_head->prev, struct drm_mm_node, node_list);
-               if (prev_node->free) {
-                       prev_node->size += cur->size;
-                       merged = 1;
-               }
-       }
-       if (cur_head->next != root_head) {
-               next_node =
-                   list_entry(cur_head->next, struct drm_mm_node, node_list);
-               if (next_node->free) {
-                       if (merged) {
-                               prev_node->size += next_node->size;
-                               list_del(&next_node->node_list);
-                               list_del(&next_node->free_stack);
-                               spin_lock(&mm->unused_lock);
-                               if (mm->num_unused < MM_UNUSED_TARGET) {
-                                       list_add(&next_node->free_stack,
-                                                &mm->unused_nodes);
-                                       ++mm->num_unused;
-                               } else
-                                       kfree(next_node);
-                               spin_unlock(&mm->unused_lock);
-                       } else {
-                               next_node->size += cur->size;
-                               next_node->start = cur->start;
-                               merged = 1;
-                       }
-               }
-       }
-       if (!merged) {
-               cur->free = 1;
-               list_add(&cur->free_stack, &mm->free_stack);
-       } else {
-               list_del(&cur->node_list);
-               spin_lock(&mm->unused_lock);
-               if (mm->num_unused < MM_UNUSED_TARGET) {
-                       list_add(&cur->free_stack, &mm->unused_nodes);
-                       ++mm->num_unused;
-               } else
-                       kfree(cur);
-               spin_unlock(&mm->unused_lock);
-       }
+/**
+ * Remove a memory node from the allocator.
+ */
+void drm_mm_remove_node(struct drm_mm_node *node)
+{
+       struct drm_mm *mm = node->mm;
+       struct drm_mm_node *prev_node;
+
+       BUG_ON(node->scanned_block || node->scanned_prev_free
+                                  || node->scanned_next_free);
+
+       prev_node =
+           list_entry(node->node_list.prev, struct drm_mm_node, node_list);
+
+       if (node->hole_follows) {
+               BUG_ON(drm_mm_hole_node_start(node)
+                               == drm_mm_hole_node_end(node));
+               list_del(&node->hole_stack);
+       } else
+               BUG_ON(drm_mm_hole_node_start(node)
+                               != drm_mm_hole_node_end(node));
+
+       if (!prev_node->hole_follows) {
+               prev_node->hole_follows = 1;
+               list_add(&prev_node->hole_stack, &mm->hole_stack);
+       } else
+               list_move(&prev_node->hole_stack, &mm->hole_stack);
+
+       list_del(&node->node_list);
+       node->allocated = 0;
 }
+EXPORT_SYMBOL(drm_mm_remove_node);
+
+/*
+ * Remove a memory node from the allocator and free the allocated struct
+ * drm_mm_node. Only to be used on a struct drm_mm_node obtained by one of the
+ * drm_mm_get_block functions.
+ */
+void drm_mm_put_block(struct drm_mm_node *node)
+{
+
+       struct drm_mm *mm = node->mm;
+
+       drm_mm_remove_node(node);
 
+       spin_lock(&mm->unused_lock);
+       if (mm->num_unused < MM_UNUSED_TARGET) {
+               list_add(&node->node_list, &mm->unused_nodes);
+               ++mm->num_unused;
+       } else
+               kfree(node);
+       spin_unlock(&mm->unused_lock);
+}
 EXPORT_SYMBOL(drm_mm_put_block);
 
 static int check_free_hole(unsigned long start, unsigned long end,
@@ -319,8 +366,10 @@ struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
        best = NULL;
        best_size = ~0UL;
 
-       list_for_each_entry(entry, &mm->free_stack, free_stack) {
-               if (!check_free_hole(entry->start, entry->start + entry->size,
+       list_for_each_entry(entry, &mm->hole_stack, hole_stack) {
+               BUG_ON(!entry->hole_follows);
+               if (!check_free_hole(drm_mm_hole_node_start(entry),
+                                    drm_mm_hole_node_end(entry),
                                     size, alignment))
                        continue;
 
@@ -353,12 +402,13 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm,
        best = NULL;
        best_size = ~0UL;
 
-       list_for_each_entry(entry, &mm->free_stack, free_stack) {
-               unsigned long adj_start = entry->start < start ?
-                       start : entry->start;
-               unsigned long adj_end = entry->start + entry->size > end ?
-                       end : entry->start + entry->size;
+       list_for_each_entry(entry, &mm->hole_stack, hole_stack) {
+               unsigned long adj_start = drm_mm_hole_node_start(entry) < start ?
+                       start : drm_mm_hole_node_start(entry);
+               unsigned long adj_end = drm_mm_hole_node_end(entry) > end ?
+                       end : drm_mm_hole_node_end(entry);
 
+               BUG_ON(!entry->hole_follows);
                if (!check_free_hole(adj_start, adj_end, size, alignment))
                        continue;
 
@@ -375,6 +425,23 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm,
 }
 EXPORT_SYMBOL(drm_mm_search_free_in_range);
 
+/**
+ * Moves an allocation. To be used with embedded struct drm_mm_node.
+ */
+void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new)
+{
+       list_replace(&old->node_list, &new->node_list);
+       list_replace(&old->hole_stack, &new->hole_stack);
+       new->hole_follows = old->hole_follows;
+       new->mm = old->mm;
+       new->start = old->start;
+       new->size = old->size;
+
+       old->allocated = 0;
+       new->allocated = 1;
+}
+EXPORT_SYMBOL(drm_mm_replace_node);
+
 /**
  * Initializa lru scanning.
  *
@@ -392,9 +459,37 @@ void drm_mm_init_scan(struct drm_mm *mm, unsigned long size,
        mm->scanned_blocks = 0;
        mm->scan_hit_start = 0;
        mm->scan_hit_size = 0;
+       mm->scan_check_range = 0;
+       mm->prev_scanned_node = NULL;
 }
 EXPORT_SYMBOL(drm_mm_init_scan);
 
+/**
+ * Initializa lru scanning.
+ *
+ * This simply sets up the scanning routines with the parameters for the desired
+ * hole. This version is for range-restricted scans.
+ *
+ * Warning: As long as the scan list is non-empty, no other operations than
+ * adding/removing nodes to/from the scan list are allowed.
+ */
+void drm_mm_init_scan_with_range(struct drm_mm *mm, unsigned long size,
+                                unsigned alignment,
+                                unsigned long start,
+                                unsigned long end)
+{
+       mm->scan_alignment = alignment;
+       mm->scan_size = size;
+       mm->scanned_blocks = 0;
+       mm->scan_hit_start = 0;
+       mm->scan_hit_size = 0;
+       mm->scan_start = start;
+       mm->scan_end = end;
+       mm->scan_check_range = 1;
+       mm->prev_scanned_node = NULL;
+}
+EXPORT_SYMBOL(drm_mm_init_scan_with_range);
+
 /**
  * Add a node to the scan list that might be freed to make space for the desired
  * hole.
@@ -404,58 +499,42 @@ EXPORT_SYMBOL(drm_mm_init_scan);
 int drm_mm_scan_add_block(struct drm_mm_node *node)
 {
        struct drm_mm *mm = node->mm;
-       struct list_head *prev_free, *next_free;
-       struct drm_mm_node *prev_node, *next_node;
+       struct drm_mm_node *prev_node;
+       unsigned long hole_start, hole_end;
+       unsigned long adj_start;
+       unsigned long adj_end;
 
        mm->scanned_blocks++;
 
-       prev_free = next_free = NULL;
-
-       BUG_ON(node->free);
+       BUG_ON(node->scanned_block);
        node->scanned_block = 1;
-       node->free = 1;
-
-       if (node->node_list.prev != &mm->node_list) {
-               prev_node = list_entry(node->node_list.prev, struct drm_mm_node,
-                                      node_list);
-
-               if (prev_node->free) {
-                       list_del(&prev_node->node_list);
-
-                       node->start = prev_node->start;
-                       node->size += prev_node->size;
-
-                       prev_node->scanned_prev_free = 1;
-
-                       prev_free = &prev_node->free_stack;
-               }
-       }
-
-       if (node->node_list.next != &mm->node_list) {
-               next_node = list_entry(node->node_list.next, struct drm_mm_node,
-                                      node_list);
 
-               if (next_node->free) {
-                       list_del(&next_node->node_list);
-
-                       node->size += next_node->size;
-
-                       next_node->scanned_next_free = 1;
-
-                       next_free = &next_node->free_stack;
-               }
+       prev_node = list_entry(node->node_list.prev, struct drm_mm_node,
+                              node_list);
+
+       node->scanned_preceeds_hole = prev_node->hole_follows;
+       prev_node->hole_follows = 1;
+       list_del(&node->node_list);
+       node->node_list.prev = &prev_node->node_list;
+       node->node_list.next = &mm->prev_scanned_node->node_list;
+       mm->prev_scanned_node = node;
+
+       hole_start = drm_mm_hole_node_start(prev_node);
+       hole_end = drm_mm_hole_node_end(prev_node);
+       if (mm->scan_check_range) {
+               adj_start = hole_start < mm->scan_start ?
+                       mm->scan_start : hole_start;
+               adj_end = hole_end > mm->scan_end ?
+                       mm->scan_end : hole_end;
+       } else {
+               adj_start = hole_start;
+               adj_end = hole_end;
        }
 
-       /* The free_stack list is not used for allocated objects, so these two
-        * pointers can be abused (as long as no allocations in this memory
-        * manager happens). */
-       node->free_stack.prev = prev_free;
-       node->free_stack.next = next_free;
-
-       if (check_free_hole(node->start, node->start + node->size,
+       if (check_free_hole(adj_start , adj_end,
                            mm->scan_size, mm->scan_alignment)) {
-               mm->scan_hit_start = node->start;
-               mm->scan_hit_size = node->size;
+               mm->scan_hit_start = hole_start;
+               mm->scan_hit_size = hole_end;
 
                return 1;
        }
@@ -472,7 +551,7 @@ EXPORT_SYMBOL(drm_mm_scan_add_block);
  * corrupted.
  *
  * When the scan list is empty, the selected memory nodes can be freed. An
- * immediatly following drm_mm_search_free with best_match = 0 will then return
+ * immediately following drm_mm_search_free with best_match = 0 will then return
  * the just freed block (because its at the top of the free_stack list).
  *
  * Returns one if this block should be evicted, zero otherwise. Will always
@@ -481,39 +560,19 @@ EXPORT_SYMBOL(drm_mm_scan_add_block);
 int drm_mm_scan_remove_block(struct drm_mm_node *node)
 {
        struct drm_mm *mm = node->mm;
-       struct drm_mm_node *prev_node, *next_node;
+       struct drm_mm_node *prev_node;
 
        mm->scanned_blocks--;
 
        BUG_ON(!node->scanned_block);
        node->scanned_block = 0;
-       node->free = 0;
 
-       prev_node = list_entry(node->free_stack.prev, struct drm_mm_node,
-                              free_stack);
-       next_node = list_entry(node->free_stack.next, struct drm_mm_node,
-                              free_stack);
+       prev_node = list_entry(node->node_list.prev, struct drm_mm_node,
+                              node_list);
 
-       if (prev_node) {
-               BUG_ON(!prev_node->scanned_prev_free);
-               prev_node->scanned_prev_free = 0;
-
-               list_add_tail(&prev_node->node_list, &node->node_list);
-
-               node->start = prev_node->start + prev_node->size;
-               node->size -= prev_node->size;
-       }
-
-       if (next_node) {
-               BUG_ON(!next_node->scanned_next_free);
-               next_node->scanned_next_free = 0;
-
-               list_add(&next_node->node_list, &node->node_list);
-
-               node->size -= next_node->size;
-       }
-
-       INIT_LIST_HEAD(&node->free_stack);
+       prev_node->hole_follows = node->scanned_preceeds_hole;
+       INIT_LIST_HEAD(&node->node_list);
+       list_add(&node->node_list, &prev_node->node_list);
 
        /* Only need to check for containement because start&size for the
         * complete resulting free block (not just the desired part) is
@@ -530,7 +589,7 @@ EXPORT_SYMBOL(drm_mm_scan_remove_block);
 
 int drm_mm_clean(struct drm_mm * mm)
 {
-       struct list_head *head = &mm->node_list;
+       struct list_head *head = &mm->head_node.node_list;
 
        return (head->next->next == head);
 }
@@ -538,38 +597,40 @@ EXPORT_SYMBOL(drm_mm_clean);
 
 int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
 {
-       INIT_LIST_HEAD(&mm->node_list);
-       INIT_LIST_HEAD(&mm->free_stack);
+       INIT_LIST_HEAD(&mm->hole_stack);
        INIT_LIST_HEAD(&mm->unused_nodes);
        mm->num_unused = 0;
        mm->scanned_blocks = 0;
        spin_lock_init(&mm->unused_lock);
 
-       return drm_mm_create_tail_node(mm, start, size, 0);
+       /* Clever trick to avoid a special case in the free hole tracking. */
+       INIT_LIST_HEAD(&mm->head_node.node_list);
+       INIT_LIST_HEAD(&mm->head_node.hole_stack);
+       mm->head_node.hole_follows = 1;
+       mm->head_node.scanned_block = 0;
+       mm->head_node.scanned_prev_free = 0;
+       mm->head_node.scanned_next_free = 0;
+       mm->head_node.mm = mm;
+       mm->head_node.start = start + size;
+       mm->head_node.size = start - mm->head_node.start;
+       list_add_tail(&mm->head_node.hole_stack, &mm->hole_stack);
+
+       return 0;
 }
 EXPORT_SYMBOL(drm_mm_init);
 
 void drm_mm_takedown(struct drm_mm * mm)
 {
-       struct list_head *bnode = mm->free_stack.next;
-       struct drm_mm_node *entry;
-       struct drm_mm_node *next;
-
-       entry = list_entry(bnode, struct drm_mm_node, free_stack);
+       struct drm_mm_node *entry, *next;
 
-       if (entry->node_list.next != &mm->node_list ||
-           entry->free_stack.next != &mm->free_stack) {
+       if (!list_empty(&mm->head_node.node_list)) {
                DRM_ERROR("Memory manager not clean. Delaying takedown\n");
                return;
        }
 
-       list_del(&entry->free_stack);
-       list_del(&entry->node_list);
-       kfree(entry);
-
        spin_lock(&mm->unused_lock);
-       list_for_each_entry_safe(entry, next, &mm->unused_nodes, free_stack) {
-               list_del(&entry->free_stack);
+       list_for_each_entry_safe(entry, next, &mm->unused_nodes, node_list) {
+               list_del(&entry->node_list);
                kfree(entry);
                --mm->num_unused;
        }
@@ -582,19 +643,37 @@ EXPORT_SYMBOL(drm_mm_takedown);
 void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
 {
        struct drm_mm_node *entry;
-       int total_used = 0, total_free = 0, total = 0;
-
-       list_for_each_entry(entry, &mm->node_list, node_list) {
-               printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8ld: %s\n",
+       unsigned long total_used = 0, total_free = 0, total = 0;
+       unsigned long hole_start, hole_end, hole_size;
+
+       hole_start = drm_mm_hole_node_start(&mm->head_node);
+       hole_end = drm_mm_hole_node_end(&mm->head_node);
+       hole_size = hole_end - hole_start;
+       if (hole_size)
+               printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
+                       prefix, hole_start, hole_end,
+                       hole_size);
+       total_free += hole_size;
+
+       drm_mm_for_each_node(entry, mm) {
+               printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: used\n",
                        prefix, entry->start, entry->start + entry->size,
-                       entry->size, entry->free ? "free" : "used");
-               total += entry->size;
-               if (entry->free)
-                       total_free += entry->size;
-               else
-                       total_used += entry->size;
+                       entry->size);
+               total_used += entry->size;
+
+               if (entry->hole_follows) {
+                       hole_start = drm_mm_hole_node_start(entry);
+                       hole_end = drm_mm_hole_node_end(entry);
+                       hole_size = hole_end - hole_start;
+                       printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
+                               prefix, hole_start, hole_end,
+                               hole_size);
+                       total_free += hole_size;
+               }
        }
-       printk(KERN_DEBUG "%s total: %d, used %d free %d\n", prefix, total,
+       total = total_free + total_used;
+
+       printk(KERN_DEBUG "%s total: %lu, used %lu free %lu\n", prefix, total,
                total_used, total_free);
 }
 EXPORT_SYMBOL(drm_mm_debug_table);
@@ -603,17 +682,34 @@ EXPORT_SYMBOL(drm_mm_debug_table);
 int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
 {
        struct drm_mm_node *entry;
-       int total_used = 0, total_free = 0, total = 0;
-
-       list_for_each_entry(entry, &mm->node_list, node_list) {
-               seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: %s\n", entry->start, entry->start + entry->size, entry->size, entry->free ? "free" : "used");
-               total += entry->size;
-               if (entry->free)
-                       total_free += entry->size;
-               else
-                       total_used += entry->size;
+       unsigned long total_used = 0, total_free = 0, total = 0;
+       unsigned long hole_start, hole_end, hole_size;
+
+       hole_start = drm_mm_hole_node_start(&mm->head_node);
+       hole_end = drm_mm_hole_node_end(&mm->head_node);
+       hole_size = hole_end - hole_start;
+       if (hole_size)
+               seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n",
+                               hole_start, hole_end, hole_size);
+       total_free += hole_size;
+
+       drm_mm_for_each_node(entry, mm) {
+               seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: used\n",
+                               entry->start, entry->start + entry->size,
+                               entry->size);
+               total_used += entry->size;
+               if (entry->hole_follows) {
+                       hole_start = drm_mm_hole_node_start(entry);
+                       hole_end = drm_mm_hole_node_end(entry);
+                       hole_size = hole_end - hole_start;
+                       seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n",
+                                       hole_start, hole_end, hole_size);
+                       total_free += hole_size;
+               }
        }
-       seq_printf(m, "total: %d, used %d free %d\n", total, total_used, total_free);
+       total = total_free + total_used;
+
+       seq_printf(m, "total: %lu, used %lu free %lu\n", total, total_used, total_free);
        return 0;
 }
 EXPORT_SYMBOL(drm_mm_dump_table);
index 58e65f9..ad74fb4 100644 (file)
@@ -593,7 +593,7 @@ EXPORT_SYMBOL(drm_mode_height);
  *
  * Return @modes's hsync rate in kHz, rounded to the nearest int.
  */
-int drm_mode_hsync(struct drm_display_mode *mode)
+int drm_mode_hsync(const struct drm_display_mode *mode)
 {
        unsigned int calc_val;
 
@@ -627,7 +627,7 @@ EXPORT_SYMBOL(drm_mode_hsync);
  * If it is 70.288, it will return 70Hz.
  * If it is 59.6, it will return 60Hz.
  */
-int drm_mode_vrefresh(struct drm_display_mode *mode)
+int drm_mode_vrefresh(const struct drm_display_mode *mode)
 {
        int refresh = 0;
        unsigned int calc_val;
@@ -725,7 +725,7 @@ EXPORT_SYMBOL(drm_mode_set_crtcinfo);
  * a pointer to it.  Used to create new instances of established modes.
  */
 struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
-                                           struct drm_display_mode *mode)
+                                           const struct drm_display_mode *mode)
 {
        struct drm_display_mode *nmode;
        int new_id;
@@ -974,3 +974,192 @@ void drm_mode_connector_list_update(struct drm_connector *connector)
        }
 }
 EXPORT_SYMBOL(drm_mode_connector_list_update);
+
+/**
+ * drm_mode_parse_command_line_for_connector - parse command line for connector
+ * @mode_option - per connector mode option
+ * @connector - connector to parse line for
+ *
+ * This parses the connector specific then generic command lines for
+ * modes and options to configure the connector.
+ *
+ * This uses the same parameters as the fb modedb.c, except for extra
+ *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
+ *
+ * enable/enable Digital/disable bit at the end
+ */
+bool drm_mode_parse_command_line_for_connector(const char *mode_option,
+                                              struct drm_connector *connector,
+                                              struct drm_cmdline_mode *mode)
+{
+       const char *name;
+       unsigned int namelen;
+       bool res_specified = false, bpp_specified = false, refresh_specified = false;
+       unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
+       bool yres_specified = false, cvt = false, rb = false;
+       bool interlace = false, margins = false, was_digit = false;
+       int i;
+       enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
+
+#ifdef CONFIG_FB
+       if (!mode_option)
+               mode_option = fb_mode_option;
+#endif
+
+       if (!mode_option) {
+               mode->specified = false;
+               return false;
+       }
+
+       name = mode_option;
+       namelen = strlen(name);
+       for (i = namelen-1; i >= 0; i--) {
+               switch (name[i]) {
+               case '@':
+                       if (!refresh_specified && !bpp_specified &&
+                           !yres_specified && !cvt && !rb && was_digit) {
+                               refresh = simple_strtol(&name[i+1], NULL, 10);
+                               refresh_specified = true;
+                               was_digit = false;
+                       } else
+                               goto done;
+                       break;
+               case '-':
+                       if (!bpp_specified && !yres_specified && !cvt &&
+                           !rb && was_digit) {
+                               bpp = simple_strtol(&name[i+1], NULL, 10);
+                               bpp_specified = true;
+                               was_digit = false;
+                       } else
+                               goto done;
+                       break;
+               case 'x':
+                       if (!yres_specified && was_digit) {
+                               yres = simple_strtol(&name[i+1], NULL, 10);
+                               yres_specified = true;
+                               was_digit = false;
+                       } else
+                               goto done;
+               case '0' ... '9':
+                       was_digit = true;
+                       break;
+               case 'M':
+                       if (yres_specified || cvt || was_digit)
+                               goto done;
+                       cvt = true;
+                       break;
+               case 'R':
+                       if (yres_specified || cvt || rb || was_digit)
+                               goto done;
+                       rb = true;
+                       break;
+               case 'm':
+                       if (cvt || yres_specified || was_digit)
+                               goto done;
+                       margins = true;
+                       break;
+               case 'i':
+                       if (cvt || yres_specified || was_digit)
+                               goto done;
+                       interlace = true;
+                       break;
+               case 'e':
+                       if (yres_specified || bpp_specified || refresh_specified ||
+                           was_digit || (force != DRM_FORCE_UNSPECIFIED))
+                               goto done;
+
+                       force = DRM_FORCE_ON;
+                       break;
+               case 'D':
+                       if (yres_specified || bpp_specified || refresh_specified ||
+                           was_digit || (force != DRM_FORCE_UNSPECIFIED))
+                               goto done;
+
+                       if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
+                           (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
+                               force = DRM_FORCE_ON;
+                       else
+                               force = DRM_FORCE_ON_DIGITAL;
+                       break;
+               case 'd':
+                       if (yres_specified || bpp_specified || refresh_specified ||
+                           was_digit || (force != DRM_FORCE_UNSPECIFIED))
+                               goto done;
+
+                       force = DRM_FORCE_OFF;
+                       break;
+               default:
+                       goto done;
+               }
+       }
+
+       if (i < 0 && yres_specified) {
+               char *ch;
+               xres = simple_strtol(name, &ch, 10);
+               if ((ch != NULL) && (*ch == 'x'))
+                       res_specified = true;
+               else
+                       i = ch - name;
+       } else if (!yres_specified && was_digit) {
+               /* catch mode that begins with digits but has no 'x' */
+               i = 0;
+       }
+done:
+       if (i >= 0) {
+               printk(KERN_WARNING
+                       "parse error at position %i in video mode '%s'\n",
+                       i, name);
+               mode->specified = false;
+               return false;
+       }
+
+       if (res_specified) {
+               mode->specified = true;
+               mode->xres = xres;
+               mode->yres = yres;
+       }
+
+       if (refresh_specified) {
+               mode->refresh_specified = true;
+               mode->refresh = refresh;
+       }
+
+       if (bpp_specified) {
+               mode->bpp_specified = true;
+               mode->bpp = bpp;
+       }
+       mode->rb = rb;
+       mode->cvt = cvt;
+       mode->interlace = interlace;
+       mode->margins = margins;
+       mode->force = force;
+
+       return true;
+}
+EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
+
+struct drm_display_mode *
+drm_mode_create_from_cmdline_mode(struct drm_device *dev,
+                                 struct drm_cmdline_mode *cmd)
+{
+       struct drm_display_mode *mode;
+
+       if (cmd->cvt)
+               mode = drm_cvt_mode(dev,
+                                   cmd->xres, cmd->yres,
+                                   cmd->refresh_specified ? cmd->refresh : 60,
+                                   cmd->rb, cmd->interlace,
+                                   cmd->margins);
+       else
+               mode = drm_gtf_mode(dev,
+                                   cmd->xres, cmd->yres,
+                                   cmd->refresh_specified ? cmd->refresh : 60,
+                                   cmd->interlace,
+                                   cmd->margins);
+       if (!mode)
+               return NULL;
+
+       drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+       return mode;
+}
+EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
index f5bd9e5..b6a19cb 100644 (file)
@@ -125,6 +125,177 @@ void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
 EXPORT_SYMBOL(drm_pci_free);
 
 #ifdef CONFIG_PCI
+
+static int drm_get_pci_domain(struct drm_device *dev)
+{
+#ifndef __alpha__
+       /* For historical reasons, drm_get_pci_domain() is busticated
+        * on most archs and has to remain so for userspace interface
+        * < 1.4, except on alpha which was right from the beginning
+        */
+       if (dev->if_version < 0x10004)
+               return 0;
+#endif /* __alpha__ */
+
+       return pci_domain_nr(dev->pdev->bus);
+}
+
+static int drm_pci_get_irq(struct drm_device *dev)
+{
+       return dev->pdev->irq;
+}
+
+static const char *drm_pci_get_name(struct drm_device *dev)
+{
+       struct pci_driver *pdriver = dev->driver->kdriver.pci;
+       return pdriver->name;
+}
+
+int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
+{
+       int len, ret;
+       struct pci_driver *pdriver = dev->driver->kdriver.pci;
+       master->unique_len = 40;
+       master->unique_size = master->unique_len;
+       master->unique = kmalloc(master->unique_size, GFP_KERNEL);
+       if (master->unique == NULL)
+               return -ENOMEM;
+
+
+       len = snprintf(master->unique, master->unique_len,
+                      "pci:%04x:%02x:%02x.%d",
+                      drm_get_pci_domain(dev),
+                      dev->pdev->bus->number,
+                      PCI_SLOT(dev->pdev->devfn),
+                      PCI_FUNC(dev->pdev->devfn));
+
+       if (len >= master->unique_len) {
+               DRM_ERROR("buffer overflow");
+               ret = -EINVAL;
+               goto err;
+       } else
+               master->unique_len = len;
+
+       dev->devname =
+               kmalloc(strlen(pdriver->name) +
+                       master->unique_len + 2, GFP_KERNEL);
+
+       if (dev->devname == NULL) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       sprintf(dev->devname, "%s@%s", pdriver->name,
+               master->unique);
+
+       return 0;
+err:
+       return ret;
+}
+
+int drm_pci_set_unique(struct drm_device *dev,
+                      struct drm_master *master,
+                      struct drm_unique *u)
+{
+       int domain, bus, slot, func, ret;
+       const char *bus_name;
+
+       master->unique_len = u->unique_len;
+       master->unique_size = u->unique_len + 1;
+       master->unique = kmalloc(master->unique_size, GFP_KERNEL);
+       if (!master->unique) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       if (copy_from_user(master->unique, u->unique, master->unique_len)) {
+               ret = -EFAULT;
+               goto err;
+       }
+
+       master->unique[master->unique_len] = '\0';
+
+       bus_name = dev->driver->bus->get_name(dev);
+       dev->devname = kmalloc(strlen(bus_name) +
+                              strlen(master->unique) + 2, GFP_KERNEL);
+       if (!dev->devname) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       sprintf(dev->devname, "%s@%s", bus_name,
+               master->unique);
+
+       /* Return error if the busid submitted doesn't match the device's actual
+        * busid.
+        */
+       ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
+       if (ret != 3) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       domain = bus >> 8;
+       bus &= 0xff;
+
+       if ((domain != drm_get_pci_domain(dev)) ||
+           (bus != dev->pdev->bus->number) ||
+           (slot != PCI_SLOT(dev->pdev->devfn)) ||
+           (func != PCI_FUNC(dev->pdev->devfn))) {
+               ret = -EINVAL;
+               goto err;
+       }
+       return 0;
+err:
+       return ret;
+}
+
+
+static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
+{
+       if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
+           (p->busnum & 0xff) != dev->pdev->bus->number ||
+           p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
+               return -EINVAL;
+
+       p->irq = dev->pdev->irq;
+
+       DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
+                 p->irq);
+       return 0;
+}
+
+int drm_pci_agp_init(struct drm_device *dev)
+{
+       if (drm_core_has_AGP(dev)) {
+               if (drm_pci_device_is_agp(dev))
+                       dev->agp = drm_agp_init(dev);
+               if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP)
+                   && (dev->agp == NULL)) {
+                       DRM_ERROR("Cannot initialize the agpgart module.\n");
+                       return -EINVAL;
+               }
+               if (drm_core_has_MTRR(dev)) {
+                       if (dev->agp)
+                               dev->agp->agp_mtrr =
+                                       mtrr_add(dev->agp->agp_info.aper_base,
+                                                dev->agp->agp_info.aper_size *
+                                                1024 * 1024, MTRR_TYPE_WRCOMB, 1);
+               }
+       }
+       return 0;
+}
+
+static struct drm_bus drm_pci_bus = {
+       .bus_type = DRIVER_BUS_PCI,
+       .get_irq = drm_pci_get_irq,
+       .get_name = drm_pci_get_name,
+       .set_busid = drm_pci_set_busid,
+       .set_unique = drm_pci_set_unique,
+       .irq_by_busid = drm_pci_irq_by_busid,
+       .agp_init = drm_pci_agp_init,
+};
+
 /**
  * Register.
  *
@@ -219,7 +390,7 @@ err_g1:
 EXPORT_SYMBOL(drm_get_pci_dev);
 
 /**
- * PCI device initialization. Called via drm_init at module load time,
+ * PCI device initialization. Called direct from modules at load time.
  *
  * \return zero on success or a negative number on failure.
  *
@@ -229,18 +400,24 @@ EXPORT_SYMBOL(drm_get_pci_dev);
  * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
  * after the initialization for driver customization.
  */
-int drm_pci_init(struct drm_driver *driver)
+int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
 {
        struct pci_dev *pdev = NULL;
        const struct pci_device_id *pid;
        int i;
 
+       DRM_DEBUG("\n");
+
+       INIT_LIST_HEAD(&driver->device_list);
+       driver->kdriver.pci = pdriver;
+       driver->bus = &drm_pci_bus;
+
        if (driver->driver_features & DRIVER_MODESET)
-               return pci_register_driver(&driver->pci_driver);
+               return pci_register_driver(pdriver);
 
        /* If not using KMS, fall back to stealth mode manual scanning. */
-       for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) {
-               pid = &driver->pci_driver.id_table[i];
+       for (i = 0; pdriver->id_table[i].vendor != 0; i++) {
+               pid = &pdriver->id_table[i];
 
                /* Loop around setting up a DRM device for each PCI device
                 * matching our ID and device class.  If we had the internal
@@ -265,10 +442,27 @@ int drm_pci_init(struct drm_driver *driver)
 
 #else
 
-int drm_pci_init(struct drm_driver *driver)
+int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
 {
        return -1;
 }
 
 #endif
+
+EXPORT_SYMBOL(drm_pci_init);
+
 /*@}*/
+void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
+{
+       struct drm_device *dev, *tmp;
+       DRM_DEBUG("\n");
+
+       if (driver->driver_features & DRIVER_MODESET) {
+               pci_unregister_driver(pdriver);
+       } else {
+               list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
+                       drm_put_dev(dev);
+       }
+       DRM_INFO("Module unloaded\n");
+}
+EXPORT_SYMBOL(drm_pci_exit);
index 92d1d0f..2a8b626 100644 (file)
@@ -109,8 +109,61 @@ err_g1:
 }
 EXPORT_SYMBOL(drm_get_platform_dev);
 
+static int drm_platform_get_irq(struct drm_device *dev)
+{
+       return platform_get_irq(dev->platformdev, 0);
+}
+
+static const char *drm_platform_get_name(struct drm_device *dev)
+{
+       return dev->platformdev->name;
+}
+
+static int drm_platform_set_busid(struct drm_device *dev, struct drm_master *master)
+{
+       int len, ret;
+
+       master->unique_len = 13 + strlen(dev->platformdev->name);
+       master->unique_size = master->unique_len;
+       master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL);
+
+       if (master->unique == NULL)
+               return -ENOMEM;
+
+       len = snprintf(master->unique, master->unique_len,
+                       "platform:%s:%02d", dev->platformdev->name, dev->platformdev->id);
+
+       if (len > master->unique_len) {
+               DRM_ERROR("Unique buffer overflowed\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       dev->devname =
+               kmalloc(strlen(dev->platformdev->name) +
+                       master->unique_len + 2, GFP_KERNEL);
+
+       if (dev->devname == NULL) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       sprintf(dev->devname, "%s@%s", dev->platformdev->name,
+               master->unique);
+       return 0;
+err:
+       return ret;
+}
+
+static struct drm_bus drm_platform_bus = {
+       .bus_type = DRIVER_BUS_PLATFORM,
+       .get_irq = drm_platform_get_irq,
+       .get_name = drm_platform_get_name,
+       .set_busid = drm_platform_set_busid,
+};
+
 /**
- * Platform device initialization. Called via drm_init at module load time,
+ * Platform device initialization. Called direct from modules.
  *
  * \return zero on success or a negative number on failure.
  *
@@ -121,7 +174,24 @@ EXPORT_SYMBOL(drm_get_platform_dev);
  * after the initialization for driver customization.
  */
 
-int drm_platform_init(struct drm_driver *driver)
+int drm_platform_init(struct drm_driver *driver, struct platform_device *platform_device)
 {
-       return drm_get_platform_dev(driver->platform_device, driver);
+       DRM_DEBUG("\n");
+
+       driver->kdriver.platform_device = platform_device;
+       driver->bus = &drm_platform_bus;
+       INIT_LIST_HEAD(&driver->device_list);
+       return drm_get_platform_dev(platform_device, driver);
+}
+EXPORT_SYMBOL(drm_platform_init);
+
+void drm_platform_exit(struct drm_driver *driver, struct platform_device *platform_device)
+{
+       struct drm_device *dev, *tmp;
+       DRM_DEBUG("\n");
+
+       list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
+               drm_put_dev(dev);
+       DRM_INFO("Module unloaded\n");
 }
+EXPORT_SYMBOL(drm_platform_exit);
index d15e09b..7525e03 100644 (file)
@@ -83,30 +83,26 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request)
        if (dev->sg)
                return -EINVAL;
 
-       entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
                return -ENOMEM;
 
-       memset(entry, 0, sizeof(*entry));
        pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
        DRM_DEBUG("size=%ld pages=%ld\n", request->size, pages);
 
        entry->pages = pages;
-       entry->pagelist = kmalloc(pages * sizeof(*entry->pagelist), GFP_KERNEL);
+       entry->pagelist = kcalloc(pages, sizeof(*entry->pagelist), GFP_KERNEL);
        if (!entry->pagelist) {
                kfree(entry);
                return -ENOMEM;
        }
 
-       memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist));
-
-       entry->busaddr = kmalloc(pages * sizeof(*entry->busaddr), GFP_KERNEL);
+       entry->busaddr = kcalloc(pages, sizeof(*entry->busaddr), GFP_KERNEL);
        if (!entry->busaddr) {
                kfree(entry->pagelist);
                kfree(entry);
                return -ENOMEM;
        }
-       memset((void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr));
 
        entry->virtual = drm_vmalloc_dma(pages << PAGE_SHIFT);
        if (!entry->virtual) {
index 463aed9..3466458 100644 (file)
@@ -59,9 +59,7 @@ drm_sman_init(struct drm_sman * sman, unsigned int num_managers,
 {
        int ret = 0;
 
-       sman->mm = (struct drm_sman_mm *) kcalloc(num_managers,
-                                                 sizeof(*sman->mm),
-                                                 GFP_KERNEL);
+       sman->mm = kcalloc(num_managers, sizeof(*sman->mm), GFP_KERNEL);
        if (!sman->mm) {
                ret = -ENOMEM;
                goto out;
index cdc89ee..6d7b083 100644 (file)
 unsigned int drm_debug = 0;    /* 1 to enable debug output */
 EXPORT_SYMBOL(drm_debug);
 
+unsigned int drm_vblank_offdelay = 5000;    /* Default to 5000 msecs. */
+EXPORT_SYMBOL(drm_vblank_offdelay);
+
+unsigned int drm_timestamp_precision = 20;  /* Default to 20 usecs. */
+EXPORT_SYMBOL(drm_timestamp_precision);
+
 MODULE_AUTHOR(CORE_AUTHOR);
 MODULE_DESCRIPTION(CORE_DESC);
 MODULE_LICENSE("GPL and additional rights");
 MODULE_PARM_DESC(debug, "Enable debug output");
+MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]");
+MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
 
 module_param_named(debug, drm_debug, int, 0600);
+module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
+module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
 
 struct idr drm_minors_idr;
 
 struct class *drm_class;
 struct proc_dir_entry *drm_proc_root;
 struct dentry *drm_debugfs_root;
+
+int drm_err(const char *func, const char *format, ...)
+{
+       struct va_format vaf;
+       va_list args;
+       int r;
+
+       va_start(args, format);
+
+       vaf.fmt = format;
+       vaf.va = &args;
+
+       r = printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* %pV", func, &vaf);
+
+       va_end(args);
+
+       return r;
+}
+EXPORT_SYMBOL(drm_err);
+
 void drm_ut_debug_printk(unsigned int request_level,
                         const char *prefix,
                         const char *function_name,
@@ -68,6 +98,7 @@ void drm_ut_debug_printk(unsigned int request_level,
        }
 }
 EXPORT_SYMBOL(drm_ut_debug_printk);
+
 static int drm_minor_get_id(struct drm_device *dev, int type)
 {
        int new_id;
@@ -259,25 +290,14 @@ int drm_fill_in_dev(struct drm_device *dev,
 
        dev->driver = driver;
 
-       if (drm_core_has_AGP(dev)) {
-               if (drm_device_is_agp(dev))
-                       dev->agp = drm_agp_init(dev);
-               if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP)
-                   && (dev->agp == NULL)) {
-                       DRM_ERROR("Cannot initialize the agpgart module.\n");
-                       retcode = -EINVAL;
+       if (dev->driver->bus->agp_init) {
+               retcode = dev->driver->bus->agp_init(dev);
+               if (retcode)
                        goto error_out_unreg;
-               }
-               if (drm_core_has_MTRR(dev)) {
-                       if (dev->agp)
-                               dev->agp->agp_mtrr =
-                                   mtrr_add(dev->agp->agp_info.aper_base,
-                                            dev->agp->agp_info.aper_size *
-                                            1024 * 1024, MTRR_TYPE_WRCOMB, 1);
-               }
        }
 
 
+
        retcode = drm_ctxbitmap_init(dev);
        if (retcode) {
                DRM_ERROR("Cannot allocate memory for context bitmap.\n");
@@ -415,7 +435,6 @@ int drm_put_minor(struct drm_minor **minor_p)
  *
  * Cleans up all DRM device, calling drm_lastclose().
  *
- * \sa drm_init
  */
 void drm_put_dev(struct drm_device *dev)
 {
@@ -465,6 +484,7 @@ void drm_put_dev(struct drm_device *dev)
 
        drm_put_minor(&dev->primary);
 
+       list_del(&dev->driver_item);
        if (dev->devname) {
                kfree(dev->devname);
                dev->devname = NULL;
index 85da4c4..2eee8e0 100644 (file)
@@ -158,8 +158,15 @@ static ssize_t status_show(struct device *device,
 {
        struct drm_connector *connector = to_drm_connector(device);
        enum drm_connector_status status;
+       int ret;
+
+       ret = mutex_lock_interruptible(&connector->dev->mode_config.mutex);
+       if (ret)
+               return ret;
 
        status = connector->funcs->detect(connector, true);
+       mutex_unlock(&connector->dev->mode_config.mutex);
+
        return snprintf(buf, PAGE_SIZE, "%s\n",
                        drm_get_connector_status_name(status));
 }
diff --git a/services4/3rdparty/linux_drm/drm_usb.c b/services4/3rdparty/linux_drm/drm_usb.c
new file mode 100644 (file)
index 0000000..206d230
--- /dev/null
@@ -0,0 +1,117 @@
+#include "drmP.h"
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB
+int drm_get_usb_dev(struct usb_interface *interface,
+                   const struct usb_device_id *id,
+                   struct drm_driver *driver)
+{
+       struct drm_device *dev;
+       struct usb_device *usbdev;
+       int ret;
+
+       DRM_DEBUG("\n");
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       usbdev = interface_to_usbdev(interface);
+       dev->usbdev = usbdev;
+       dev->dev = &usbdev->dev;
+
+       mutex_lock(&drm_global_mutex);
+
+       ret = drm_fill_in_dev(dev, NULL, driver);
+       if (ret) {
+               printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
+               goto err_g1;
+       }
+
+       usb_set_intfdata(interface, dev);
+       ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
+       if (ret)
+               goto err_g1;
+
+       ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY);
+       if (ret)
+               goto err_g2;
+
+       if (dev->driver->load) {
+               ret = dev->driver->load(dev, 0);
+               if (ret)
+                       goto err_g3;
+       }
+
+       /* setup the grouping for the legacy output */
+       ret = drm_mode_group_init_legacy_group(dev,
+                                              &dev->primary->mode_group);
+       if (ret)
+               goto err_g3;
+
+       list_add_tail(&dev->driver_item, &driver->device_list);
+
+       mutex_unlock(&drm_global_mutex);
+
+       DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+                driver->name, driver->major, driver->minor, driver->patchlevel,
+                driver->date, dev->primary->index);
+
+       return 0;
+
+err_g3:
+       drm_put_minor(&dev->primary);
+err_g2:
+       drm_put_minor(&dev->control);
+err_g1:
+       kfree(dev);
+       mutex_unlock(&drm_global_mutex);
+       return ret;
+
+}
+EXPORT_SYMBOL(drm_get_usb_dev);
+
+static int drm_usb_get_irq(struct drm_device *dev)
+{
+       return 0;
+}
+
+static const char *drm_usb_get_name(struct drm_device *dev)
+{
+       return "USB";
+}
+
+static int drm_usb_set_busid(struct drm_device *dev,
+                              struct drm_master *master)
+{
+       return 0;
+}
+
+static struct drm_bus drm_usb_bus = {
+       .bus_type = DRIVER_BUS_USB,
+       .get_irq = drm_usb_get_irq,
+       .get_name = drm_usb_get_name,
+       .set_busid = drm_usb_set_busid,
+};
+    
+int drm_usb_init(struct drm_driver *driver, struct usb_driver *udriver)
+{
+       int res;
+       DRM_DEBUG("\n");
+
+       INIT_LIST_HEAD(&driver->device_list);
+       driver->kdriver.usb = udriver;
+       driver->bus = &drm_usb_bus;
+
+       res = usb_register(udriver);
+       return res;
+}
+EXPORT_SYMBOL(drm_usb_init);
+
+void drm_usb_exit(struct drm_driver *driver,
+                 struct usb_driver *udriver)
+{
+       usb_deregister(udriver);
+}
+EXPORT_SYMBOL(drm_usb_exit);
+#endif
index 2c3fcbd..5db96d4 100644 (file)
@@ -526,7 +526,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
 static resource_size_t drm_core_get_reg_ofs(struct drm_device *dev)
 {
 #ifdef __alpha__
-       return dev->hose->dense_mem_base - dev->hose->mem_space->start;
+       return dev->hose->dense_mem_base;
 #else
        return 0;
 #endif
index 6ae4ce2..bc127ac 100644 (file)
 #include "services_headers.h"
 #include "resman.h"
 
+#include <linux/version.h>
 #ifdef __linux__
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
 #ifndef AUTOCONF_INCLUDED
  #include <linux/config.h>
 #endif
+#endif
 
-#include <linux/version.h>
 #include <linux/sched.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9)
 #include <linux/hardirq.h>
index c898ab2..54462a5 100644 (file)
@@ -391,6 +391,7 @@ PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO       *psDevInfo,
        }
        PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "End of SGX initialisation script part 2\n");
 
+              //  OSWriteHWReg(psDevInfo->pvRegsBaseKM, 0xFF08, 0x80000000);//OCP Bypass mode
 #ifdef PLAT_TI81xx
        OSWriteHWReg(psDevInfo->pvRegsBaseKM, 0xFF08, 0x80000000);//OCP Bypass mode
         if(cpu_is_ti816x()) {
@@ -408,8 +409,10 @@ PVRSRV_ERROR SGXInitialise(PVRSRV_SGXDEV_INFO      *psDevInfo,
         }
 
 #else
-        if(cpu_is_omap3630() || cpu_is_omap44xx())
-                OSWriteHWReg(psDevInfo->pvRegsBaseKM, 0xFF08, 0x80000000);//OCP Bypass mode
+        if(!cpu_is_omap3530())
+       {
+               OSWriteHWReg(psDevInfo->pvRegsBaseKM, 0xFF08, 0x80000000);//OCP Bypass mode
+       }
 #endif
 
 
index 2a930a6..f8e8acb 100644 (file)
  *
  ******************************************************************************/
 
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
 #ifndef AUTOCONF_INCLUDED
  #include <linux/config.h>
 #endif
+#endif
 
-#include <linux/version.h>
 #include <asm/io.h>
 #include <asm/page.h>
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22))
index ecaba8e..8211d4a 100644 (file)
  *
  ******************************************************************************/
 
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
 #ifndef AUTOCONF_INCLUDED
  #include <linux/config.h>
 #endif
+#endif
 
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <asm/io.h>
index 047b3ad..21f295f 100644 (file)
 #ifndef __IMG_LINUX_MM_H__
 #define __IMG_LINUX_MM_H__
 
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
 #ifndef AUTOCONF_INCLUDED
  #include <linux/config.h>
 #endif
+#endif
 
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/list.h>
index 66cef26..2359c71 100644 (file)
  *
  ******************************************************************************/
 
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
 #ifndef AUTOCONF_INCLUDED
  #include <linux/config.h>
 #endif
+#endif
 
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
index df1b49f..305db3a 100644 (file)
  *
  ******************************************************************************/
 
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
 #ifndef AUTOCONF_INCLUDED
  #include <linux/config.h>
 #endif
+#endif
+
 
 #if !defined(SUPPORT_DRI_DRM)
        
@@ -44,7 +49,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/fs.h>
 #include <linux/proc_fs.h>
 
index 83eab51..0a7cad1 100644 (file)
  *
  ******************************************************************************/
 
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
 #ifndef AUTOCONF_INCLUDED
 #include <linux/config.h>
 #endif
-#include <linux/version.h>
+#endif
 
 #include <linux/spinlock.h>
 #include <linux/mm.h>
index c42eadc..cdde900 100644 (file)
 #ifndef __IMG_LINUX_MUTILS_H__
 #define __IMG_LINUX_MUTILS_H__
 
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
 #ifndef AUTOCONF_INCLUDED
 #include <linux/config.h>
 #endif
-
-#include <linux/version.h>
+#endif
 
 #if !(defined(__i386__) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)))
 #if defined(SUPPORT_LINUX_X86_PAT)
index e50bae7..f7fa57b 100644 (file)
  *
  ******************************************************************************/
 
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
 #ifndef AUTOCONF_INCLUDED
  #include <linux/config.h>
 #endif
+#endif
 
-#include <linux/version.h>
 #include <asm/io.h>
 #include <asm/page.h>
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22))
index 965346d..27078ef 100644 (file)
  *
  ******************************************************************************/
 
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
 #ifndef AUTOCONF_INCLUDED
  #include <linux/config.h>
 #endif
+#endif
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/fs.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
index 091f659..476319c 100644 (file)
  *
  ******************************************************************************/
 
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
 #ifndef AUTOCONF_INCLUDED
  #include <linux/config.h>
 #endif
+#endif
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -72,7 +75,8 @@ static IMG_CHAR gszBufferIRQ[PVR_MAX_MSG_LEN + 1];
 static PVRSRV_LINUX_MUTEX gsDebugMutexNonIRQ;
 
  
-static spinlock_t gsDebugLockIRQ = SPIN_LOCK_UNLOCKED;
+//static spinlock_t gsDebugLockIRQ = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(gsDebugLockIRQ);
 
 #if !defined (USE_SPIN_LOCK)  
 #define        USE_SPIN_LOCK (in_interrupt() || !preemptible())
index 1127915..c7eecb3 100644 (file)
 
 #if defined(SUPPORT_DRI_DRM)
 
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
 #ifndef AUTOCONF_INCLUDED
  #include <linux/config.h>
 #endif
+#endif
 
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/fs.h>
 #include <linux/proc_fs.h>
 #include <linux/sched.h>
@@ -371,11 +373,23 @@ static struct drm_driver sPVRDrmDriver =
                .poll = drm_poll,
                .fasync = drm_fasync,
        },
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,38))
        .pci_driver = 
        {
                .name = PVR_DRM_NAME,
                .id_table = asPciIdList,
        },
+#else
+       .kdriver = 
+       {
+       PVR_DRM_NAME,
+       asPciIdList,
+       },
+//     {
+//             .pci->name = PVR_DRM_NAME,
+//             .pci->id_table = asPciIdList,
+//     },
+#endif
                
        .name = PVR_DRM_NAME,
        .desc = PVR_DRM_DESC,
@@ -385,6 +399,13 @@ static struct drm_driver sPVRDrmDriver =
        .patchlevel = PVRVERSION_BUILD,
 };
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39))
+static struct pci_driver pci_pvr_driver = {
+        .name = PVR_DRM_NAME,
+        .id_table = asPciIdList,
+};
+#endif
+
 static int __init PVRSRVDrmInit(void)
 {
        int iRes;
@@ -401,7 +422,11 @@ static int __init PVRSRVDrmInit(void)
        }
 #endif
 
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,38))
        iRes = drm_init(&sPVRDrmDriver);
+#else
+       iRes = drm_pci_init(&sPVRDrmDriver,&pci_pvr_driver);
+#endif
 #if defined(PVR_DRI_DRM_NOT_PCI)
        if (iRes != 0)
        {
@@ -413,7 +438,11 @@ static int __init PVRSRVDrmInit(void)
        
 static void __exit PVRSRVDrmExit(void)
 {
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,38))
        drm_exit(&sPVRDrmDriver);
+#else
+       drm_pci_exit(&sPVRDrmDriver,&pci_pvr_driver);
+#endif
 
 #if defined(PVR_DRI_DRM_NOT_PCI)
        drm_pvr_dev_remove();
index 04fdcc2..7bc47ac 100644 (file)
 #ifndef __PVR_UACCESS_H__
 #define __PVR_UACCESS_H__
 
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
 #ifndef AUTOCONF_INCLUDED
  #include <linux/config.h>
 #endif
+#endif
 
-#include <linux/version.h>
 #include <asm/uaccess.h>
 
 static inline unsigned long pvr_copy_to_user(void __user *pvTo, const void *pvFrom, unsigned long ulBytes)
index 9b34224..5c57200 100644 (file)
@@ -61,6 +61,7 @@
        #endif
         #if SGX_CORE_REV == 103
                #define FIX_HW_BRN_22934
+              #define FIX_HW_BRN_28889
         #else
 
        #if SGX_CORE_REV == 110
diff --git a/services4/system/ti335x/oemfuncs.h b/services4/system/ti335x/oemfuncs.h
new file mode 100644 (file)
index 0000000..206f7fa
--- /dev/null
@@ -0,0 +1,56 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope it will be useful but, except 
+ * as otherwise stated in writing, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
+ *
+ ******************************************************************************/
+
+#if !defined(__OEMFUNCS_H__)
+#define __OEMFUNCS_H__
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+typedef IMG_UINT32   (*PFN_SRV_BRIDGEDISPATCH)( IMG_UINT32  Ioctl,
+                                                                                               IMG_BYTE   *pInBuf,
+                                                                                               IMG_UINT32  InBufLen, 
+                                                                                           IMG_BYTE   *pOutBuf,
+                                                                                               IMG_UINT32  OutBufLen,
+                                                                                               IMG_UINT32 *pdwBytesTransferred);
+typedef struct PVRSRV_DC_OEM_JTABLE_TAG
+{
+       PFN_SRV_BRIDGEDISPATCH                  pfnOEMBridgeDispatch;
+       IMG_PVOID                                               pvDummy1;
+       IMG_PVOID                                               pvDummy2;
+       IMG_PVOID                                               pvDummy3;
+
+} PVRSRV_DC_OEM_JTABLE;
+
+#define OEM_GET_EXT_FUNCS                      (1<<1)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif 
+
diff --git a/services4/system/ti335x/sysconfig.c b/services4/system/ti335x/sysconfig.c
new file mode 100644 (file)
index 0000000..be47008
--- /dev/null
@@ -0,0 +1,974 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope it will be useful but, except 
+ * as otherwise stated in writing, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
+ *
+ ******************************************************************************/
+
+#include "services_headers.h"
+#include "kerneldisplay.h"
+#include "oemfuncs.h"
+#include "sgxinfo.h"
+#include "sgxinfokm.h"
+#include "syslocal.h"
+#include "sysconfig.h"
+
+#include "ocpdefs.h"
+
+#if !defined(NO_HARDWARE) && \
+     defined(SYS_USING_INTERRUPTS) && \
+     defined(SGX530) && (SGX_CORE_REV == 125)
+#define SGX_OCP_REGS_ENABLED
+#endif
+
+SYS_DATA* gpsSysData = (SYS_DATA*)IMG_NULL;
+SYS_DATA  gsSysData;
+
+static SYS_SPECIFIC_DATA gsSysSpecificData;
+SYS_SPECIFIC_DATA *gpsSysSpecificData;
+
+static IMG_UINT32      gui32SGXDeviceID;
+static SGX_DEVICE_MAP  gsSGXDeviceMap;
+static PVRSRV_DEVICE_NODE *gpsSGXDevNode;
+
+#define DEVICE_SGX_INTERRUPT (1 << 0)
+
+#if defined(NO_HARDWARE)
+static IMG_CPU_VIRTADDR gsSGXRegsCPUVAddr;
+#endif
+
+IMG_UINT32 PVRSRV_BridgeDispatchKM(IMG_UINT32  Ioctl,
+                                                                  IMG_BYTE             *pInBuf,
+                                                                  IMG_UINT32   InBufLen,
+                                                                  IMG_BYTE             *pOutBuf,
+                                                                  IMG_UINT32   OutBufLen,
+                                                                  IMG_UINT32   *pdwBytesTransferred);
+
+#if defined(DEBUG) && defined(DUMP_OMAP34xx_CLOCKS) && defined(__linux__)
+
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#include <mach/clock.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29))
+#include <../mach-omap2/clock_34xx.h>
+#define ONCHIP_CLKS onchip_clks
+#else
+#include <../mach-omap2/clock34xx.h>
+#define ONCHIP_CLKS onchip_34xx_clks
+#endif
+
+static void omap3_clk_recalc(struct clk *clk) {}
+static void omap3_followparent_recalc(struct clk *clk) {}
+static void omap3_propagate_rate(struct clk *clk) {}
+static void omap3_table_recalc(struct clk *clk) {}
+static long omap3_round_to_table_rate(struct clk *clk, unsigned long rate) { return 0; }
+static int omap3_select_table_rate(struct clk *clk, unsigned long rate) { return 0; }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
+static void omap3_dpll_recalc(struct clk *clk, unsigned long parent_rate,
+                                                         u8 rate_storage) {}
+static void omap3_clkoutx2_recalc(struct clk *clk, unsigned long parent_rate,
+                                                                 u8 rate_storage) {}
+static void omap3_dpll_allow_idle(struct clk *clk) {}
+static void omap3_dpll_deny_idle(struct clk *clk) {}
+static u32 omap3_dpll_autoidle_read(struct clk *clk) { return 0; }
+static int omap3_noncore_dpll_enable(struct clk *clk) { return 0; }
+static void omap3_noncore_dpll_disable(struct clk *clk) {}
+static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) { return 0; }
+static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) { return 0; }
+void followparent_recalc(struct clk *clk, unsigned long new_parent_rate,
+                                                               u8 rate_storage) {}
+long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) { return 0; }
+void omap2_clksel_recalc(struct clk *clk, unsigned long new_parent_rate,
+                                                               u8 rate_storage) {}
+long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate) { return 0; }
+int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) { return 0; }
+void omap2_fixed_divisor_recalc(struct clk *clk, unsigned long new_parent_rate,
+                                                                          u8 rate_storage) {}
+void omap2_init_clksel_parent(struct clk *clk) {}
+#endif
+
+static void dump_omap34xx_clocks(void)
+{
+       struct clk **c;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29))
+       struct vdd_prcm_config *t1 = vdd1_rate_table;
+       struct vdd_prcm_config *t2 = vdd2_rate_table;
+
+       t1 = t1;
+       t2 = t2;
+#else
+       
+       omap3_dpll_allow_idle(0);
+       omap3_dpll_deny_idle(0);
+       omap3_dpll_autoidle_read(0);
+       omap3_clk_recalc(0);
+       omap3_followparent_recalc(0);
+       omap3_propagate_rate(0);
+       omap3_table_recalc(0);
+       omap3_round_to_table_rate(0, 0);
+       omap3_select_table_rate(0, 0);
+#endif
+
+       for(c = ONCHIP_CLKS; c < ONCHIP_CLKS + ARRAY_SIZE(ONCHIP_CLKS); c++)
+       {
+               struct clk *cp = *c, *copy;
+               unsigned long rate;
+               copy = clk_get(NULL, cp->name);
+               if(!copy)
+                       continue;
+               rate = clk_get_rate(copy);
+               if (rate < 1000000)
+               {
+                       PVR_DPF((PVR_DBG_ERROR, "%s: clock %s is %lu KHz (%lu Hz)", __func__, cp->name, rate/1000, rate));
+               }
+               else
+               {
+                       PVR_DPF((PVR_DBG_ERROR, "%s: clock %s is %lu MHz (%lu Hz)", __func__, cp->name, rate/1000000, rate));
+               }
+       }
+}
+
+#else  
+
+static INLINE void dump_omap34xx_clocks(void) {}
+
+#endif 
+
+#if defined(SGX_OCP_REGS_ENABLED)
+
+#define SYS_TI335x_OCP_REGS_SYS_PHYS_BASE              (SYS_TI335x_SGX_REGS_SYS_PHYS_BASE + EUR_CR_OCP_REVISION)
+#define SYS_TI335x_OCP_REGS_SIZE                               0x110
+
+static IMG_CPU_VIRTADDR gpvOCPRegsLinAddr;
+
+static PVRSRV_ERROR EnableSGXClocksWrap(SYS_DATA *psSysData)
+{
+       PVRSRV_ERROR eError = EnableSGXClocks(psSysData);
+
+       if(eError == PVRSRV_OK)
+       {
+               OSWriteHWReg(gpvOCPRegsLinAddr,
+                                        EUR_CR_OCP_DEBUG_CONFIG - EUR_CR_OCP_REVISION,
+                                        EUR_CR_OCP_DEBUG_CONFIG_THALIA_INT_BYPASS_MASK);
+       }
+
+       return eError;
+}
+
+#else 
+
+static INLINE PVRSRV_ERROR EnableSGXClocksWrap(SYS_DATA *psSysData)
+{
+       return EnableSGXClocks(psSysData);
+}
+
+#endif 
+
+static INLINE PVRSRV_ERROR EnableSystemClocksWrap(SYS_DATA *psSysData)
+{
+       PVRSRV_ERROR eError = EnableSystemClocks(psSysData);
+
+#if !defined(SUPPORT_ACTIVE_POWER_MANAGEMENT)
+       if(eError == PVRSRV_OK)
+       {
+               
+               EnableSGXClocksWrap(psSysData);
+       }
+#endif
+
+       return eError;
+}
+
+static PVRSRV_ERROR SysLocateDevices(SYS_DATA *psSysData)
+{
+#if defined(NO_HARDWARE)
+       PVRSRV_ERROR eError;
+       IMG_CPU_PHYADDR sCpuPAddr;
+#endif
+
+       PVR_UNREFERENCED_PARAMETER(psSysData);
+
+       
+       gsSGXDeviceMap.ui32Flags = 0x0;
+       
+#if defined(NO_HARDWARE)
+       
+       
+       eError = OSBaseAllocContigMemory(SYS_TI335x_SGX_REGS_SIZE, 
+                                                                        &gsSGXRegsCPUVAddr,
+                                                                        &sCpuPAddr);
+       if(eError != PVRSRV_OK)
+       {
+               return eError;
+       }
+       gsSGXDeviceMap.sRegsCpuPBase = sCpuPAddr;
+       gsSGXDeviceMap.sRegsSysPBase = SysCpuPAddrToSysPAddr(gsSGXDeviceMap.sRegsCpuPBase);
+       gsSGXDeviceMap.ui32RegsSize = SYS_TI335x_SGX_REGS_SIZE;
+#if defined(__linux__)
+       
+       gsSGXDeviceMap.pvRegsCpuVBase = gsSGXRegsCPUVAddr;
+#else
+       
+       gsSGXDeviceMap.pvRegsCpuVBase = IMG_NULL;
+#endif
+
+       OSMemSet(gsSGXRegsCPUVAddr, 0, SYS_TI335x_SGX_REGS_SIZE);
+
+       
+
+
+       gsSGXDeviceMap.ui32IRQ = 0;
+
+#else 
+
+       gsSGXDeviceMap.sRegsSysPBase.uiAddr = SYS_TI335x_SGX_REGS_SYS_PHYS_BASE;
+       gsSGXDeviceMap.sRegsCpuPBase = SysSysPAddrToCpuPAddr(gsSGXDeviceMap.sRegsSysPBase);
+       gsSGXDeviceMap.ui32RegsSize = SYS_TI335x_SGX_REGS_SIZE;
+
+       gsSGXDeviceMap.ui32IRQ = SYS_TI335x_SGX_IRQ;
+
+#endif 
+
+#if defined(PDUMP)
+       {
+               
+               static IMG_CHAR pszPDumpDevName[] = "SGXMEM";
+               gsSGXDeviceMap.pszPDumpDevName = pszPDumpDevName;
+       }
+#endif
+
+       
+
+
+       return PVRSRV_OK;
+}
+
+
+IMG_CHAR *SysCreateVersionString(IMG_CPU_PHYADDR sRegRegion)
+{
+       static IMG_CHAR aszVersionString[100];
+       SYS_DATA        *psSysData;
+       IMG_UINT32      ui32SGXRevision;
+       IMG_INT32       i32Count;
+#if !defined(NO_HARDWARE)
+       IMG_VOID        *pvRegsLinAddr;
+
+       pvRegsLinAddr = OSMapPhysToLin(sRegRegion,
+                                                                  SYS_TI335x_SGX_REGS_SIZE,
+                                                                  PVRSRV_HAP_UNCACHED|PVRSRV_HAP_KERNEL_ONLY,
+                                                                  IMG_NULL);
+       if(!pvRegsLinAddr)
+       {
+               return IMG_NULL;
+       }
+
+       ui32SGXRevision = OSReadHWReg((IMG_PVOID)((IMG_PBYTE)pvRegsLinAddr),
+                                                                 EUR_CR_CORE_REVISION);
+#else
+       ui32SGXRevision = 0;
+#endif
+
+       SysAcquireData(&psSysData);
+
+       i32Count = OSSNPrintf(aszVersionString, 100,
+                                                 "SGX revision = %u.%u.%u",
+                                                 (IMG_UINT)((ui32SGXRevision & EUR_CR_CORE_REVISION_MAJOR_MASK)
+                                                       >> EUR_CR_CORE_REVISION_MAJOR_SHIFT),
+                                                 (IMG_UINT)((ui32SGXRevision & EUR_CR_CORE_REVISION_MINOR_MASK)
+                                                       >> EUR_CR_CORE_REVISION_MINOR_SHIFT),
+                                                 (IMG_UINT)((ui32SGXRevision & EUR_CR_CORE_REVISION_MAINTENANCE_MASK)
+                                                       >> EUR_CR_CORE_REVISION_MAINTENANCE_SHIFT)
+                                                );
+
+#if !defined(NO_HARDWARE)
+       OSUnMapPhysToLin(pvRegsLinAddr,
+                                        SYS_TI335x_SGX_REGS_SIZE,
+                                        PVRSRV_HAP_UNCACHED|PVRSRV_HAP_KERNEL_ONLY,
+                                        IMG_NULL);
+#endif
+
+       if(i32Count == -1)
+       {
+               return IMG_NULL;
+       }
+
+       return aszVersionString;
+}
+
+
+PVRSRV_ERROR SysInitialise(IMG_VOID)
+{
+       IMG_UINT32                      i;
+       PVRSRV_ERROR            eError;
+       PVRSRV_DEVICE_NODE      *psDeviceNode;
+       IMG_CPU_PHYADDR         TimerRegPhysBase;
+#if !defined(SGX_DYNAMIC_TIMING_INFO)
+       SGX_TIMING_INFORMATION* psTimingInfo;
+#endif
+       gpsSysData = &gsSysData;
+       OSMemSet(gpsSysData, 0, sizeof(SYS_DATA));
+
+       gpsSysSpecificData =  &gsSysSpecificData;
+       OSMemSet(gpsSysSpecificData, 0, sizeof(SYS_SPECIFIC_DATA));
+
+       gpsSysData->pvSysSpecificData = gpsSysSpecificData;
+
+       eError = OSInitEnvData(&gpsSysData->pvEnvSpecificData);
+       if (eError != PVRSRV_OK)
+       {
+               PVR_DPF((PVR_DBG_ERROR,"SysInitialise: Failed to setup env structure"));
+               (IMG_VOID)SysDeinitialise(gpsSysData);
+               gpsSysData = IMG_NULL;
+               return eError;
+       }
+       SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_ENVDATA);
+
+       gpsSysData->ui32NumDevices = SYS_DEVICE_COUNT;
+
+       
+       for(i=0; i<SYS_DEVICE_COUNT; i++)
+       {
+               gpsSysData->sDeviceID[i].uiID = i;
+               gpsSysData->sDeviceID[i].bInUse = IMG_FALSE;
+       }
+
+       gpsSysData->psDeviceNodeList = IMG_NULL;
+       gpsSysData->psQueueList = IMG_NULL;
+
+       eError = SysInitialiseCommon(gpsSysData);
+       if (eError != PVRSRV_OK)
+       {
+               PVR_DPF((PVR_DBG_ERROR,"SysInitialise: Failed in SysInitialiseCommon"));
+               (IMG_VOID)SysDeinitialise(gpsSysData);
+               gpsSysData = IMG_NULL;
+               return eError;
+       }
+
+       TimerRegPhysBase.uiAddr = SYS_TI335x_GP7TIMER_REGS_SYS_PHYS_BASE;
+       gpsSysData->pvSOCTimerRegisterKM = IMG_NULL;
+       gpsSysData->hSOCTimerRegisterOSMemHandle = 0;
+       OSReservePhys(TimerRegPhysBase,
+                                 4,
+                                 PVRSRV_HAP_MULTI_PROCESS|PVRSRV_HAP_UNCACHED,
+                                 (IMG_VOID **)&gpsSysData->pvSOCTimerRegisterKM,
+                                 &gpsSysData->hSOCTimerRegisterOSMemHandle);
+
+#if !defined(SGX_DYNAMIC_TIMING_INFO)
+       
+       psTimingInfo = &gsSGXDeviceMap.sTimingInfo;
+       psTimingInfo->ui32CoreClockSpeed = SYS_SGX_CLOCK_SPEED;
+
+       psTimingInfo->ui32HWRecoveryFreq = SYS_SGX_HWRECOVERY_TIMEOUT_FREQ; 
+#if defined(SUPPORT_ACTIVE_POWER_MANAGEMENT)
+       psTimingInfo->bEnableActivePM = IMG_TRUE;
+#else  
+       psTimingInfo->bEnableActivePM = IMG_FALSE;
+#endif 
+       psTimingInfo->ui32ActivePowManLatencyms = SYS_SGX_ACTIVE_POWER_LATENCY_MS; 
+       psTimingInfo->ui32uKernelFreq = SYS_SGX_PDS_TIMER_FREQ; 
+#endif
+
+       
+
+       gpsSysSpecificData->ui32SrcClockDiv = 3;
+
+       
+
+
+
+       eError = SysLocateDevices(gpsSysData);
+       if (eError != PVRSRV_OK)
+       {
+               PVR_DPF((PVR_DBG_ERROR,"SysInitialise: Failed to locate devices"));
+               (IMG_VOID)SysDeinitialise(gpsSysData);
+               gpsSysData = IMG_NULL;
+               return eError;
+       }
+       SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_LOCATEDEV);
+
+#if defined(SGX_OCP_REGS_ENABLED)
+       {
+               IMG_SYS_PHYADDR sOCPRegsSysPBase;
+               IMG_CPU_PHYADDR sOCPRegsCpuPBase;
+
+               sOCPRegsSysPBase.uiAddr = SYS_TI335x_OCP_REGS_SYS_PHYS_BASE;
+               sOCPRegsCpuPBase                = SysSysPAddrToCpuPAddr(sOCPRegsSysPBase);
+
+               gpvOCPRegsLinAddr               = OSMapPhysToLin(sOCPRegsCpuPBase,
+                                                                                                SYS_TI335x_OCP_REGS_SIZE,
+                                                                                                PVRSRV_HAP_UNCACHED|PVRSRV_HAP_KERNEL_ONLY,
+                                                                                                IMG_NULL);
+
+               if (gpvOCPRegsLinAddr == IMG_NULL)
+               {
+                       PVR_DPF((PVR_DBG_ERROR,"SysInitialise: Failed to map OCP registers"));
+                       return PVRSRV_ERROR_BAD_MAPPING;
+               }
+       }
+#endif
+
+       
+
+
+       eError = PVRSRVRegisterDevice(gpsSysData, SGXRegisterDevice,
+                                                                 DEVICE_SGX_INTERRUPT, &gui32SGXDeviceID);
+       if (eError != PVRSRV_OK)
+       {
+               PVR_DPF((PVR_DBG_ERROR,"SysInitialise: Failed to register device!"));
+               (IMG_VOID)SysDeinitialise(gpsSysData);
+               gpsSysData = IMG_NULL;
+               return eError;
+       }
+       SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_REGDEV);
+
+       
+
+
+       
+       psDeviceNode = gpsSysData->psDeviceNodeList;
+       while(psDeviceNode)
+       {
+               
+               switch(psDeviceNode->sDevId.eDeviceType)
+               {
+                       case PVRSRV_DEVICE_TYPE_SGX:
+                       {
+                               DEVICE_MEMORY_INFO *psDevMemoryInfo;
+                               DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
+
+                               
+
+
+                               psDeviceNode->psLocalDevMemArena = IMG_NULL;
+
+                               
+                               psDevMemoryInfo = &psDeviceNode->sDevMemoryInfo;
+                               psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap;
+
+                               
+                               for(i=0; i<psDevMemoryInfo->ui32HeapCount; i++)
+                               {
+                                       psDeviceMemoryHeap[i].ui32Attribs |= PVRSRV_BACKINGSTORE_SYSMEM_NONCONTIG;
+                               }
+
+                               gpsSGXDevNode = psDeviceNode;
+                               gsSysSpecificData.psSGXDevNode = psDeviceNode;
+
+                               break;
+                       }
+                       default:
+                               PVR_DPF((PVR_DBG_ERROR,"SysInitialise: Failed to find SGX device node!"));
+                               return PVRSRV_ERROR_INIT_FAILURE;
+               }
+
+               
+               psDeviceNode = psDeviceNode->psNext;
+       }
+
+       eError = EnableSystemClocksWrap(gpsSysData);
+       if (eError != PVRSRV_OK)
+       {
+               PVR_DPF((PVR_DBG_ERROR,"SysInitialise: Failed to Enable system clocks (%d)", eError));
+               (IMG_VOID)SysDeinitialise(gpsSysData);
+               gpsSysData = IMG_NULL;
+               return eError;
+       }
+       SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_SYSCLOCKS);
+#if defined(SUPPORT_ACTIVE_POWER_MANAGEMENT)
+       eError = EnableSGXClocksWrap(gpsSysData);
+       if (eError != PVRSRV_OK)
+       {
+               PVR_DPF((PVR_DBG_ERROR,"SysInitialise: Failed to Enable SGX clocks (%d)", eError));
+               (IMG_VOID)SysDeinitialise(gpsSysData);
+               gpsSysData = IMG_NULL;
+               return eError;
+       }
+#endif 
+
+       dump_omap34xx_clocks();
+
+       eError = PVRSRVInitialiseDevice(gui32SGXDeviceID);
+       if (eError != PVRSRV_OK)
+       {
+               PVR_DPF((PVR_DBG_ERROR,"SysInitialise: Failed to initialise device!"));
+               (IMG_VOID)SysDeinitialise(gpsSysData);
+               gpsSysData = IMG_NULL;
+               return eError;
+       }
+       SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_INITDEV);
+
+#if defined(SUPPORT_ACTIVE_POWER_MANAGEMENT)
+       
+       DisableSGXClocks(gpsSysData);
+#endif 
+
+       return PVRSRV_OK;
+}
+
+
+PVRSRV_ERROR SysFinalise(IMG_VOID)
+{
+       PVRSRV_ERROR eError = PVRSRV_OK;
+
+#if defined(SUPPORT_ACTIVE_POWER_MANAGEMENT)
+       eError = EnableSGXClocksWrap(gpsSysData);
+       if (eError != PVRSRV_OK)
+       {
+               PVR_DPF((PVR_DBG_ERROR,"SysInitialise: Failed to Enable SGX clocks (%d)", eError));
+               (IMG_VOID)SysDeinitialise(gpsSysData);
+               gpsSysData = IMG_NULL;
+               return eError;
+       }
+#endif 
+
+#if defined(SYS_USING_INTERRUPTS)
+
+       eError = OSInstallMISR(gpsSysData);
+       if (eError != PVRSRV_OK)
+       {
+               PVR_DPF((PVR_DBG_ERROR,"SysFinalise: Failed to install MISR"));
+               (IMG_VOID)SysDeinitialise(gpsSysData);
+               gpsSysData = IMG_NULL;
+               return eError;
+       }
+       SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_MISR);
+
+       
+       eError = OSInstallDeviceLISR(gpsSysData, gsSGXDeviceMap.ui32IRQ, "SGX ISR", gpsSGXDevNode);
+       if (eError != PVRSRV_OK)
+       {
+               PVR_DPF((PVR_DBG_ERROR,"SysFinalise: Failed to install ISR"));
+               (IMG_VOID)SysDeinitialise(gpsSysData);
+               gpsSysData = IMG_NULL;
+               return eError;
+       }
+       SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_LISR);
+#endif 
+
+       
+       gpsSysData->pszVersionString = SysCreateVersionString(gsSGXDeviceMap.sRegsCpuPBase);
+       if (!gpsSysData->pszVersionString)
+       {
+               PVR_DPF((PVR_DBG_ERROR,"SysFinalise: Failed to create a system version string"));
+       }
+       else
+       {
+               PVR_DPF((PVR_DBG_WARNING, "SysFinalise: Version string: %s", gpsSysData->pszVersionString));
+       }
+
+#if defined(SUPPORT_ACTIVE_POWER_MANAGEMENT)
+       
+       DisableSGXClocks(gpsSysData);
+#endif 
+
+       gpsSysSpecificData->bSGXInitComplete = IMG_TRUE;
+
+       return eError;
+}
+
+
+PVRSRV_ERROR SysDeinitialise (SYS_DATA *psSysData)
+{
+       PVRSRV_ERROR eError;
+
+#if defined(SYS_USING_INTERRUPTS)
+       if (SYS_SPECIFIC_DATA_TEST(gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_LISR))
+       {
+               eError = OSUninstallDeviceLISR(psSysData);
+               if (eError != PVRSRV_OK)
+               {
+                       PVR_DPF((PVR_DBG_ERROR,"SysDeinitialise: OSUninstallDeviceLISR failed"));
+                       return eError;
+               }
+       }
+
+       if (SYS_SPECIFIC_DATA_TEST(gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_MISR))
+       {
+               eError = OSUninstallMISR(psSysData);
+               if (eError != PVRSRV_OK)
+               {
+                       PVR_DPF((PVR_DBG_ERROR,"SysDeinitialise: OSUninstallMISR failed"));
+                       return eError;
+               }
+       }
+#else
+       PVR_UNREFERENCED_PARAMETER(psSysData);
+#endif 
+
+       if (SYS_SPECIFIC_DATA_TEST(gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_INITDEV))
+       {
+#if defined(SUPPORT_ACTIVE_POWER_MANAGEMENT)
+               PVR_ASSERT(SYS_SPECIFIC_DATA_TEST(gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_SYSCLOCKS));
+               
+               eError = EnableSGXClocksWrap(gpsSysData);
+               if (eError != PVRSRV_OK)
+               {
+                       PVR_DPF((PVR_DBG_ERROR,"SysDeinitialise: EnableSGXClocks failed"));
+                       return eError;
+               }
+#endif 
+
+               
+               eError = PVRSRVDeinitialiseDevice (gui32SGXDeviceID);
+               if (eError != PVRSRV_OK)
+               {
+                       PVR_DPF((PVR_DBG_ERROR,"SysDeinitialise: failed to de-init the device"));
+                       return eError;
+               }
+       }
+       
+#if defined(SGX_OCP_REGS_ENABLED)
+       OSUnMapPhysToLin(gpvOCPRegsLinAddr,
+                                        SYS_TI335x_OCP_REGS_SIZE,
+                                        PVRSRV_HAP_UNCACHED|PVRSRV_HAP_KERNEL_ONLY,
+                                        IMG_NULL);
+#endif
+
+       
+
+       if (SYS_SPECIFIC_DATA_TEST(gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_SYSCLOCKS))
+       {
+               DisableSystemClocks(gpsSysData);
+       }
+
+       if (SYS_SPECIFIC_DATA_TEST(gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_ENVDATA))
+       {       
+               eError = OSDeInitEnvData(gpsSysData->pvEnvSpecificData);
+               if (eError != PVRSRV_OK)
+               {
+                       PVR_DPF((PVR_DBG_ERROR,"SysDeinitialise: failed to de-init env structure"));
+                       return eError;
+               }
+       }
+
+       if(gpsSysData->pvSOCTimerRegisterKM)
+       {
+               OSUnReservePhys(gpsSysData->pvSOCTimerRegisterKM,
+                                               4,
+                                               PVRSRV_HAP_MULTI_PROCESS|PVRSRV_HAP_UNCACHED,
+                                               gpsSysData->hSOCTimerRegisterOSMemHandle);
+       }
+
+       SysDeinitialiseCommon(gpsSysData);
+
+#if defined(NO_HARDWARE)
+       if(SYS_SPECIFIC_DATA_TEST(gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_LOCATEDEV))
+       {
+               
+               OSBaseFreeContigMemory(SYS_TI335x_SGX_REGS_SIZE, gsSGXRegsCPUVAddr, gsSGXDeviceMap.sRegsCpuPBase);
+       }
+#endif
+
+       
+       gpsSysSpecificData->ui32SysSpecificData = 0;
+       gpsSysSpecificData->bSGXInitComplete = IMG_FALSE;
+
+       gpsSysData = IMG_NULL;
+
+       return PVRSRV_OK;
+}
+
+
+PVRSRV_ERROR SysGetDeviceMemoryMap(PVRSRV_DEVICE_TYPE  eDeviceType,
+                                                                  IMG_VOID                             **ppvDeviceMap)
+{
+
+       switch(eDeviceType)
+       {
+               case PVRSRV_DEVICE_TYPE_SGX:
+               {
+                       
+                       *ppvDeviceMap = (IMG_VOID*)&gsSGXDeviceMap;
+
+                       break;
+               }
+               default:
+               {
+                       PVR_DPF((PVR_DBG_ERROR,"SysGetDeviceMemoryMap: unsupported device type"));
+               }
+       }
+       return PVRSRV_OK;
+}
+
+
+IMG_DEV_PHYADDR SysCpuPAddrToDevPAddr(PVRSRV_DEVICE_TYPE       eDeviceType,
+                                                                         IMG_CPU_PHYADDR               CpuPAddr)
+{
+       IMG_DEV_PHYADDR DevPAddr;
+
+       PVR_UNREFERENCED_PARAMETER(eDeviceType);
+
+       
+       DevPAddr.uiAddr = CpuPAddr.uiAddr;
+       
+       return DevPAddr;
+}
+
+IMG_CPU_PHYADDR SysSysPAddrToCpuPAddr (IMG_SYS_PHYADDR sys_paddr)
+{
+       IMG_CPU_PHYADDR cpu_paddr;
+
+       
+       cpu_paddr.uiAddr = sys_paddr.uiAddr;
+       return cpu_paddr;
+}
+
+IMG_SYS_PHYADDR SysCpuPAddrToSysPAddr (IMG_CPU_PHYADDR cpu_paddr)
+{
+       IMG_SYS_PHYADDR sys_paddr;
+
+       
+       sys_paddr.uiAddr = cpu_paddr.uiAddr;
+       return sys_paddr;
+}
+
+
+IMG_DEV_PHYADDR SysSysPAddrToDevPAddr(PVRSRV_DEVICE_TYPE eDeviceType, IMG_SYS_PHYADDR SysPAddr)
+{
+       IMG_DEV_PHYADDR DevPAddr;
+
+       PVR_UNREFERENCED_PARAMETER(eDeviceType);
+
+       
+       DevPAddr.uiAddr = SysPAddr.uiAddr;
+
+       return DevPAddr;
+}
+
+
+IMG_SYS_PHYADDR SysDevPAddrToSysPAddr(PVRSRV_DEVICE_TYPE eDeviceType, IMG_DEV_PHYADDR DevPAddr)
+{
+       IMG_SYS_PHYADDR SysPAddr;
+
+       PVR_UNREFERENCED_PARAMETER(eDeviceType);
+
+       
+       SysPAddr.uiAddr = DevPAddr.uiAddr;
+
+       return SysPAddr;
+}
+
+
+IMG_VOID SysRegisterExternalDevice(PVRSRV_DEVICE_NODE *psDeviceNode)
+{
+       PVR_UNREFERENCED_PARAMETER(psDeviceNode);
+}
+
+
+IMG_VOID SysRemoveExternalDevice(PVRSRV_DEVICE_NODE *psDeviceNode)
+{
+       PVR_UNREFERENCED_PARAMETER(psDeviceNode);
+}
+
+
+IMG_UINT32 SysGetInterruptSource(SYS_DATA                      *psSysData,
+                                                                PVRSRV_DEVICE_NODE     *psDeviceNode)
+{
+       PVR_UNREFERENCED_PARAMETER(psSysData);
+#if defined(NO_HARDWARE)
+       
+       return 0xFFFFFFFF;
+#else
+       
+       return psDeviceNode->ui32SOCInterruptBit;
+#endif
+}
+
+
+IMG_VOID SysClearInterrupts(SYS_DATA* psSysData, IMG_UINT32 ui32ClearBits)
+{
+       PVR_UNREFERENCED_PARAMETER(psSysData);
+       PVR_UNREFERENCED_PARAMETER(ui32ClearBits);
+
+       
+       OSReadHWReg(((PVRSRV_SGXDEV_INFO *)gpsSGXDevNode->pvDevice)->pvRegsBaseKM,
+                                                                               EUR_CR_EVENT_HOST_CLEAR);
+}
+
+
+PVRSRV_ERROR SysSystemPrePowerState(PVRSRV_SYS_POWER_STATE eNewPowerState)
+{
+       PVRSRV_ERROR eError = PVRSRV_OK;
+
+       if (eNewPowerState == PVRSRV_SYS_POWER_STATE_D3)
+       {
+               PVR_TRACE(("SysSystemPrePowerState: Entering state D3"));
+
+#if defined(SYS_USING_INTERRUPTS)
+               if (SYS_SPECIFIC_DATA_TEST(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_LISR))
+               {
+#if defined(SYS_CUSTOM_POWERLOCK_WRAP)
+                       IMG_BOOL bWrapped = WrapSystemPowerChange(&gsSysSpecificData);
+#endif
+                       eError = OSUninstallDeviceLISR(gpsSysData);
+#if defined(SYS_CUSTOM_POWERLOCK_WRAP)
+                       if (bWrapped)
+                       {
+                               UnwrapSystemPowerChange(&gsSysSpecificData);
+                       }
+#endif
+                       if (eError != PVRSRV_OK)
+                       {
+                               PVR_DPF((PVR_DBG_ERROR,"SysSystemPrePowerState: OSUninstallDeviceLISR failed (%d)", eError));
+                               return eError;
+                       }
+                       SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, SYS_SPECIFIC_DATA_PM_UNINSTALL_LISR);
+                       SYS_SPECIFIC_DATA_CLEAR(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_LISR);
+               }
+#endif
+
+               if (SYS_SPECIFIC_DATA_TEST(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_SYSCLOCKS))
+               {
+                       DisableSystemClocks(gpsSysData);
+
+                       SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, SYS_SPECIFIC_DATA_PM_DISABLE_SYSCLOCKS);
+                       SYS_SPECIFIC_DATA_CLEAR(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_SYSCLOCKS);
+               }
+       }
+
+       return eError;
+}
+
+
+PVRSRV_ERROR SysSystemPostPowerState(PVRSRV_SYS_POWER_STATE eNewPowerState)
+{
+       PVRSRV_ERROR eError = PVRSRV_OK;
+
+       if (eNewPowerState == PVRSRV_SYS_POWER_STATE_D0)
+       {
+               PVR_TRACE(("SysSystemPostPowerState: Entering state D0"));
+
+               if (SYS_SPECIFIC_DATA_TEST(&gsSysSpecificData, SYS_SPECIFIC_DATA_PM_DISABLE_SYSCLOCKS))
+               {
+                       eError = EnableSystemClocksWrap(gpsSysData);
+                       if (eError != PVRSRV_OK)
+                       {
+                               PVR_DPF((PVR_DBG_ERROR,"SysSystemPostPowerState: EnableSystemClocksWrap failed (%d)", eError));
+                               return eError;
+                       }
+                       SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_SYSCLOCKS);
+                       SYS_SPECIFIC_DATA_CLEAR(&gsSysSpecificData, SYS_SPECIFIC_DATA_PM_DISABLE_SYSCLOCKS);
+               }
+
+#if defined(SYS_USING_INTERRUPTS)
+               if (SYS_SPECIFIC_DATA_TEST(&gsSysSpecificData, SYS_SPECIFIC_DATA_PM_UNINSTALL_LISR))
+               {
+#if defined(SYS_CUSTOM_POWERLOCK_WRAP)
+                       IMG_BOOL bWrapped = WrapSystemPowerChange(&gsSysSpecificData);
+#endif
+
+                       eError = OSInstallDeviceLISR(gpsSysData, gsSGXDeviceMap.ui32IRQ, "SGX ISR", gpsSGXDevNode);
+#if defined(SYS_CUSTOM_POWERLOCK_WRAP)
+                       if (bWrapped)
+                       {
+                               UnwrapSystemPowerChange(&gsSysSpecificData);
+                       }
+#endif
+                       if (eError != PVRSRV_OK)
+                       {
+                               PVR_DPF((PVR_DBG_ERROR,"SysSystemPostPowerState: OSInstallDeviceLISR failed to install ISR (%d)", eError));
+                               return eError;
+                       }
+                       SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_LISR);
+                       SYS_SPECIFIC_DATA_CLEAR(&gsSysSpecificData, SYS_SPECIFIC_DATA_PM_UNINSTALL_LISR);
+               }
+#endif
+       }
+       return eError;
+}
+
+
+PVRSRV_ERROR SysDevicePrePowerState(IMG_UINT32                         ui32DeviceIndex,
+                                                                       PVRSRV_DEV_POWER_STATE  eNewPowerState,
+                                                                       PVRSRV_DEV_POWER_STATE  eCurrentPowerState)
+{
+       PVR_UNREFERENCED_PARAMETER(eCurrentPowerState);
+
+       if (ui32DeviceIndex != gui32SGXDeviceID)
+       {
+               return PVRSRV_OK;
+       }
+
+#if defined(SUPPORT_ACTIVE_POWER_MANAGEMENT)
+       if (eNewPowerState == PVRSRV_DEV_POWER_STATE_OFF)
+       {
+               PVR_DPF((PVR_DBG_MESSAGE, "SysDevicePrePowerState: SGX Entering state D3"));
+               DisableSGXClocks(gpsSysData);
+       }
+#else  
+       PVR_UNREFERENCED_PARAMETER(eNewPowerState );
+#endif 
+       return PVRSRV_OK;
+}
+
+
+PVRSRV_ERROR SysDevicePostPowerState(IMG_UINT32                                ui32DeviceIndex,
+                                                                        PVRSRV_DEV_POWER_STATE eNewPowerState,
+                                                                        PVRSRV_DEV_POWER_STATE eCurrentPowerState)
+{
+       PVRSRV_ERROR eError = PVRSRV_OK;
+
+       PVR_UNREFERENCED_PARAMETER(eNewPowerState);
+
+       if (ui32DeviceIndex != gui32SGXDeviceID)
+       {
+               return eError;
+       }
+
+#if defined(SUPPORT_ACTIVE_POWER_MANAGEMENT)
+       if (eCurrentPowerState == PVRSRV_DEV_POWER_STATE_OFF)
+       {
+               PVR_DPF((PVR_DBG_MESSAGE, "SysDevicePostPowerState: SGX Leaving state D3"));
+               eError = EnableSGXClocksWrap(gpsSysData);
+       }
+#else  
+       PVR_UNREFERENCED_PARAMETER(eCurrentPowerState);
+#endif 
+
+       return eError;
+}
+
+
+PVRSRV_ERROR SysOEMFunction (  IMG_UINT32      ui32ID,
+                                                               IMG_VOID        *pvIn,
+                                                               IMG_UINT32      ulInSize,
+                                                               IMG_VOID        *pvOut,
+                                                               IMG_UINT32      ulOutSize)
+{
+       PVR_UNREFERENCED_PARAMETER(ui32ID);
+       PVR_UNREFERENCED_PARAMETER(pvIn);
+       PVR_UNREFERENCED_PARAMETER(ulInSize);
+       PVR_UNREFERENCED_PARAMETER(pvOut);
+       PVR_UNREFERENCED_PARAMETER(ulOutSize);
+
+       if ((ui32ID == OEM_GET_EXT_FUNCS) &&
+               (ulOutSize == sizeof(PVRSRV_DC_OEM_JTABLE)))
+       {
+               
+               PVRSRV_DC_OEM_JTABLE *psOEMJTable = (PVRSRV_DC_OEM_JTABLE*) pvOut;
+               psOEMJTable->pfnOEMBridgeDispatch = &PVRSRV_BridgeDispatchKM;
+               return PVRSRV_OK;
+       }
+
+       return PVRSRV_ERROR_INVALID_PARAMS;
+}
diff --git a/services4/system/ti335x/sysconfig.h b/services4/system/ti335x/sysconfig.h
new file mode 100644 (file)
index 0000000..db9a774
--- /dev/null
@@ -0,0 +1,54 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope it will be useful but, except 
+ * as otherwise stated in writing, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
+ *
+ ******************************************************************************/
+
+#if !defined(__SOCCONFIG_H__)
+#define __SOCCONFIG_H__
+
+#include "syscommon.h"
+
+#define VS_PRODUCT_NAME        "TI335x"
+
+#define SYS_SGX_CLOCK_SPEED            200000000
+
+#define SYS_SGX_HWRECOVERY_TIMEOUT_FREQ                (100)   
+#define SYS_SGX_PDS_TIMER_FREQ                         (1000)  
+
+#if !defined(SYS_SGX_ACTIVE_POWER_LATENCY_MS)
+#define SYS_SGX_ACTIVE_POWER_LATENCY_MS                (1)
+#endif
+
+
+#define SYS_TI335x_SGX_REGS_SYS_PHYS_BASE  0x56000000
+
+#define SYS_TI335x_SGX_REGS_SIZE           0x1000000
+
+#define SYS_TI335x_SGX_IRQ                              37
+
+#define SYS_TI335x_GP7TIMER_ENABLE_SYS_PHYS_BASE      0x4804A038
+#define SYS_TI335x_GP7TIMER_REGS_SYS_PHYS_BASE       0x4804A03C
+#define SYS_TI335x_GP7TIMER_TSICR_SYS_PHYS_BASE              0x4804A054
+#endif 
diff --git a/services4/system/ti335x/sysinfo.h b/services4/system/ti335x/sysinfo.h
new file mode 100644 (file)
index 0000000..79766ed
--- /dev/null
@@ -0,0 +1,40 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope it will be useful but, except 
+ * as otherwise stated in writing, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
+ *
+ ******************************************************************************/
+
+#if !defined(__SYSINFO_H__)
+#define __SYSINFO_H__
+
+#if defined(PVR_LINUX_USING_WORKQUEUES)
+#define MAX_HW_TIME_US                         (1000000)
+#else
+#define MAX_HW_TIME_US                         (500000)
+#endif
+
+#define WAIT_TRY_COUNT                         (10000)
+
+#define SYS_DEVICE_COUNT 3 
+
+#endif 
diff --git a/services4/system/ti335x/syslocal.h b/services4/system/ti335x/syslocal.h
new file mode 100644 (file)
index 0000000..b05fc1c
--- /dev/null
@@ -0,0 +1,135 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope it will be useful but, except 
+ * as otherwise stated in writing, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
+ *
+ ******************************************************************************/
+
+#if !defined(__SYSLOCAL_H__)
+#define __SYSLOCAL_H__
+
+#if defined(__linux__)
+
+#include <linux/version.h>
+#include <linux/clk.h>
+#if defined(PVR_LINUX_USING_WORKQUEUES)
+#include <linux/mutex.h>
+#else
+#include <linux/spinlock.h>
+#endif
+#include <asm/atomic.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26))
+#include <linux/semaphore.h>
+#include <linux/resource.h>
+#else 
+#include <asm/semaphore.h>
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22))
+#include <asm/arch/resource.h>
+#endif 
+#endif 
+
+#endif 
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+IMG_CHAR *SysCreateVersionString(IMG_CPU_PHYADDR sRegRegion);
+
+IMG_VOID DisableSystemClocks(SYS_DATA *psSysData);
+PVRSRV_ERROR EnableSystemClocks(SYS_DATA *psSysData);
+
+IMG_VOID DisableSGXClocks(SYS_DATA *psSysData);
+PVRSRV_ERROR EnableSGXClocks(SYS_DATA *psSysData);
+
+#define SYS_SPECIFIC_DATA_ENABLE_SYSCLOCKS     0x00000001
+#define SYS_SPECIFIC_DATA_ENABLE_LISR          0x00000002
+#define SYS_SPECIFIC_DATA_ENABLE_MISR          0x00000004
+#define SYS_SPECIFIC_DATA_ENABLE_ENVDATA       0x00000008
+#define SYS_SPECIFIC_DATA_ENABLE_LOCDEV                0x00000010
+#define SYS_SPECIFIC_DATA_ENABLE_REGDEV                0x00000020
+#define SYS_SPECIFIC_DATA_ENABLE_PDUMPINIT     0x00000040
+#define SYS_SPECIFIC_DATA_ENABLE_INITDEV       0x00000080
+#define SYS_SPECIFIC_DATA_ENABLE_LOCATEDEV     0x00000100
+
+#define        SYS_SPECIFIC_DATA_PM_UNINSTALL_LISR     0x00000200
+#define        SYS_SPECIFIC_DATA_PM_DISABLE_SYSCLOCKS  0x00000400
+
+#define        SYS_SPECIFIC_DATA_SET(psSysSpecData, flag) ((IMG_VOID)((psSysSpecData)->ui32SysSpecificData |= (flag)))
+
+#define        SYS_SPECIFIC_DATA_CLEAR(psSysSpecData, flag) ((IMG_VOID)((psSysSpecData)->ui32SysSpecificData &= ~(flag)))
+
+#define        SYS_SPECIFIC_DATA_TEST(psSysSpecData, flag) (((psSysSpecData)->ui32SysSpecificData & (flag)) != 0)
+typedef struct _SYS_SPECIFIC_DATA_TAG_
+{
+       IMG_UINT32      ui32SysSpecificData;
+       PVRSRV_DEVICE_NODE *psSGXDevNode;
+       IMG_BOOL        bSGXInitComplete;
+#if !defined(__linux__)
+       IMG_BOOL        bSGXClocksEnabled;
+#endif
+       IMG_UINT32      ui32SrcClockDiv;
+#if defined(__linux__)
+       IMG_BOOL        bSysClocksOneTimeInit;
+       atomic_t        sSGXClocksEnabled;
+#if defined(PVR_LINUX_USING_WORKQUEUES)
+       struct mutex    sPowerLock;
+#else
+       IMG_BOOL        bConstraintNotificationsEnabled;
+       spinlock_t      sPowerLock;
+       atomic_t        sPowerLockCPU;
+       spinlock_t      sNotifyLock;
+       atomic_t        sNotifyLockCPU;
+       IMG_BOOL        bCallVDD2PostFunc;
+#endif
+       struct clk      *psCORE_CK;
+       struct clk      *psSGX_FCK;
+       struct clk      *psSGX_ICK;
+       struct clk      *psMPU_CK;
+#if defined(DEBUG) || defined(TIMING)
+       struct clk      *psGPT11_FCK;
+       struct clk      *psGPT11_ICK;
+#endif
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22))              
+       struct constraint_handle *pVdd2Handle;
+#endif 
+#endif 
+} SYS_SPECIFIC_DATA;
+
+extern SYS_SPECIFIC_DATA *gpsSysSpecificData;
+
+#if defined(SYS_CUSTOM_POWERLOCK_WRAP)
+IMG_BOOL WrapSystemPowerChange(SYS_SPECIFIC_DATA *psSysSpecData);
+IMG_VOID UnwrapSystemPowerChange(SYS_SPECIFIC_DATA *psSysSpecData);
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif 
+
+
diff --git a/services4/system/ti335x/sysutils.c b/services4/system/ti335x/sysutils.c
new file mode 100644 (file)
index 0000000..7d81114
--- /dev/null
@@ -0,0 +1,34 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope it will be useful but, except 
+ * as otherwise stated in writing, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
+ *
+ ******************************************************************************/
+
+#if defined(__linux__)
+#if defined(PVR_LINUX_USING_WORKQUEUES)
+#include "sysutils_linux_wqueue_compat.c"
+#else
+#include "sysutils_linux.c"
+#endif
+#endif
+
diff --git a/services4/system/ti335x/sysutils_linux.c b/services4/system/ti335x/sysutils_linux.c
new file mode 100644 (file)
index 0000000..4cac03a
--- /dev/null
@@ -0,0 +1,774 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope it will be useful but, except 
+ * as otherwise stated in writing, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/hardirq.h>
+#include <linux/spinlock.h>
+#include <asm/bug.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26))
+#include <linux/semaphore.h>
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,31))
+//#include <plat/resource.h>
+#include <plat/omap-pm.h>
+#else 
+#include <mach/resource.h>
+#endif 
+#else 
+#include <asm/semaphore.h>
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22))
+#include <asm/arch/resource.h>
+#endif 
+#endif 
+
+#if    (LINUX_VERSION_CODE >  KERNEL_VERSION(2,6,22)) && \
+       (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27))
+#define CONSTRAINT_NOTIFICATIONS
+#endif 
+#include "sgxdefs.h"
+#include "services_headers.h"
+#include "sysinfo.h"
+#include "sgxapi_km.h"
+#include "sysconfig.h"
+#include "sgxinfokm.h"
+#include "syslocal.h"
+
+#define        ONE_MHZ 1000000
+#define        HZ_TO_MHZ(m) ((m) / ONE_MHZ)
+
+#if defined(SUPPORT_OMAP3430_SGXFCLK_96M)
+#define SGX_PARENT_CLOCK "cm_96m_fck"
+#else
+#define SGX_PARENT_CLOCK "core_ck"
+#endif
+
+//#define DEBUG
+#if !defined(PDUMP) && !defined(NO_HARDWARE)
+static IMG_BOOL PowerLockWrappedOnCPU(SYS_SPECIFIC_DATA *psSysSpecData)
+{
+       IMG_INT iCPU;
+       IMG_BOOL bLocked = IMG_FALSE;
+
+       if (!in_interrupt())
+       {
+               iCPU = get_cpu();
+               bLocked = (iCPU == atomic_read(&psSysSpecData->sPowerLockCPU));
+
+               put_cpu();
+       }
+
+       return bLocked;
+}
+
+static IMG_VOID PowerLockWrap(SYS_SPECIFIC_DATA *psSysSpecData)
+{
+       IMG_INT iCPU;
+
+       if (!in_interrupt())
+       {
+               
+               iCPU = get_cpu();
+
+               
+               PVR_ASSERT(iCPU != -1);
+
+               PVR_ASSERT(!PowerLockWrappedOnCPU(psSysSpecData));
+
+               spin_lock(&psSysSpecData->sPowerLock);
+
+               atomic_set(&psSysSpecData->sPowerLockCPU, iCPU);
+       }
+}
+
+static IMG_VOID PowerLockUnwrap(SYS_SPECIFIC_DATA *psSysSpecData)
+{
+       if (!in_interrupt())
+       {
+               PVR_ASSERT(PowerLockWrappedOnCPU(psSysSpecData));
+
+               atomic_set(&psSysSpecData->sPowerLockCPU, -1);
+
+               spin_unlock(&psSysSpecData->sPowerLock);
+
+               put_cpu();
+       }
+}
+
+PVRSRV_ERROR SysPowerLockWrap(SYS_DATA *psSysData)
+{
+       SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
+
+       PowerLockWrap(psSysSpecData);
+
+       return PVRSRV_OK;
+}
+
+IMG_VOID SysPowerLockUnwrap(SYS_DATA *psSysData)
+{
+       SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
+
+       PowerLockUnwrap(psSysSpecData);
+}
+#else  
+static IMG_BOOL PowerLockWrappedOnCPU(SYS_SPECIFIC_DATA unref__ *psSysSpecData)
+{
+       return IMG_FALSE;
+}
+
+static IMG_VOID PowerLockWrap(SYS_SPECIFIC_DATA unref__ *psSysSpecData)
+{
+}
+
+static IMG_VOID PowerLockUnwrap(SYS_SPECIFIC_DATA unref__ *psSysSpecData)
+{
+}
+
+PVRSRV_ERROR SysPowerLockWrap(SYS_DATA unref__ *psSysData)
+{
+       return PVRSRV_OK;
+}
+
+IMG_VOID SysPowerLockUnwrap(SYS_DATA unref__ *psSysData)
+{
+}
+#endif 
+
+IMG_BOOL WrapSystemPowerChange(SYS_SPECIFIC_DATA *psSysSpecData)
+{
+       IMG_BOOL bPowerLock = PowerLockWrappedOnCPU(psSysSpecData);
+
+       if (bPowerLock)
+       {
+               PowerLockUnwrap(psSysSpecData);
+       }
+
+       return bPowerLock;
+}
+
+IMG_VOID UnwrapSystemPowerChange(SYS_SPECIFIC_DATA *psSysSpecData)
+{
+       PowerLockWrap(psSysSpecData);
+}
+
+static inline IMG_UINT32 scale_by_rate(IMG_UINT32 val, IMG_UINT32 rate1, IMG_UINT32 rate2)
+{
+       if (rate1 >= rate2)
+       {
+               return val * (rate1 / rate2);
+       }
+
+       return val / (rate2 / rate1);
+}
+
+static inline IMG_UINT32 scale_prop_to_SGX_clock(IMG_UINT32 val, IMG_UINT32 rate)
+{
+
+       return scale_by_rate(val, rate, SYS_SGX_CLOCK_SPEED);
+}
+
+static inline IMG_UINT32 scale_inv_prop_to_SGX_clock(IMG_UINT32 val, IMG_UINT32 rate)
+{
+       return scale_by_rate(val, SYS_SGX_CLOCK_SPEED, rate);
+}
+
+IMG_VOID SysGetSGXTimingInformation(SGX_TIMING_INFORMATION *psTimingInfo)
+{
+       IMG_UINT32 rate;
+
+#if defined(NO_HARDWARE)
+       rate = SYS_SGX_CLOCK_SPEED;
+
+#else
+       PVR_ASSERT(atomic_read(&gpsSysSpecificData->sSGXClocksEnabled) != 0);
+
+       rate = clk_get_rate(gpsSysSpecificData->psSGX_FCK);
+       PVR_ASSERT(rate != 0);
+#endif
+       psTimingInfo->ui32CoreClockSpeed = rate;
+       psTimingInfo->ui32HWRecoveryFreq = scale_prop_to_SGX_clock(SYS_SGX_HWRECOVERY_TIMEOUT_FREQ, rate);
+       psTimingInfo->ui32uKernelFreq = scale_prop_to_SGX_clock(SYS_SGX_PDS_TIMER_FREQ, rate);
+#if defined(SUPPORT_ACTIVE_POWER_MANAGEMENT)
+       psTimingInfo->bEnableActivePM = IMG_TRUE;
+#else
+       psTimingInfo->bEnableActivePM = IMG_FALSE;
+#endif 
+       psTimingInfo->ui32ActivePowManLatencyms = SYS_SGX_ACTIVE_POWER_LATENCY_MS;
+}
+
+#if defined(CONSTRAINT_NOTIFICATIONS)
+#if !defined(SGX_DYNAMIC_TIMING_INFO)
+#error "SGX_DYNAMIC_TIMING_INFO must be defined for this platform"
+#endif
+
+static struct constraint_id cnstr_id_vdd2 = {
+       .type = RES_OPP_CO,
+       .data = (IMG_VOID *)"vdd2_opp"
+};
+
+#if !defined(PDUMP) && !defined(NO_HARDWARE)
+static inline IMG_BOOL ConstraintNotificationsEnabled(SYS_SPECIFIC_DATA *psSysSpecData)
+{
+       return (atomic_read(&psSysSpecData->sSGXClocksEnabled) != 0) && psSysSpecData->bSGXInitComplete && psSysSpecData->bConstraintNotificationsEnabled;
+
+}
+
+static IMG_BOOL NotifyLockedOnCPU(SYS_SPECIFIC_DATA *psSysSpecData)
+{
+       IMG_INT iCPU = get_cpu();
+       IMG_BOOL bLocked = (iCPU == atomic_read(&psSysSpecData->sNotifyLockCPU));
+
+       put_cpu();
+
+       return bLocked;
+}
+
+static IMG_VOID NotifyLock(SYS_SPECIFIC_DATA *psSysSpecData)
+{
+       IMG_INT iCPU;
+
+       BUG_ON(in_interrupt());
+
+       
+       iCPU = get_cpu();
+
+       
+       PVR_ASSERT(iCPU != -1);
+
+       PVR_ASSERT(!NotifyLockedOnCPU(psSysSpecData));
+
+       spin_lock(&psSysSpecData->sNotifyLock);
+
+       atomic_set(&psSysSpecData->sNotifyLockCPU, iCPU);
+}
+
+static IMG_VOID NotifyUnlock(SYS_SPECIFIC_DATA *psSysSpecData)
+{
+       PVR_ASSERT(NotifyLockedOnCPU(psSysSpecData));
+
+       atomic_set(&psSysSpecData->sNotifyLockCPU, -1);
+
+       spin_unlock(&psSysSpecData->sNotifyLock);
+
+       put_cpu();
+}
+
+static int VDD2PostFunc(struct notifier_block *n, unsigned long event, IMG_VOID *ptr)
+{
+       PVR_UNREFERENCED_PARAMETER(n);
+       PVR_UNREFERENCED_PARAMETER(event);
+       PVR_UNREFERENCED_PARAMETER(ptr);
+
+       if (in_interrupt())
+       {
+               PVR_DPF((PVR_DBG_ERROR, "%s Called in interrupt context.  Ignoring.", __FUNCTION__));
+               return 0;
+       }
+
+       
+       if (!NotifyLockedOnCPU(gpsSysSpecificData))
+       {
+               return 0;
+       }
+
+#if defined(DEBUG)
+       if (ConstraintNotificationsEnabled(gpsSysSpecificData))
+       {
+               IMG_UINT32 rate;
+
+               rate = clk_get_rate(gpsSysSpecificData->psSGX_FCK);
+
+               PVR_ASSERT(rate != 0);
+
+               PVR_DPF((PVR_DBG_MESSAGE, "%s: SGX clock rate: %dMHz", __FUNCTION__, HZ_TO_MHZ(rate)));
+       }
+#endif
+       if (gpsSysSpecificData->bCallVDD2PostFunc)
+       {
+               PVRSRVDevicePostClockSpeedChange(gpsSysSpecificData->psSGXDevNode->sDevId.ui32DeviceIndex, IMG_TRUE, IMG_NULL);
+
+               gpsSysSpecificData->bCallVDD2PostFunc = IMG_FALSE;
+       }
+       else
+       {
+               if (ConstraintNotificationsEnabled(gpsSysSpecificData))
+               {
+                       PVR_TRACE(("%s: Not calling PVR clock speed notification functions", __FUNCTION__));
+               }
+       }
+
+       NotifyUnlock(gpsSysSpecificData);
+
+       return 0;
+}
+
+static int VDD2PreFunc(struct notifier_block *n, unsigned long event, IMG_VOID *ptr)
+{
+       PVR_UNREFERENCED_PARAMETER(n);
+       PVR_UNREFERENCED_PARAMETER(event);
+       PVR_UNREFERENCED_PARAMETER(ptr);
+
+       if (in_interrupt())
+       {
+               PVR_DPF((PVR_DBG_WARNING, "%s Called in interrupt context.  Ignoring.", __FUNCTION__));
+               return 0;
+       }
+
+       if (PowerLockWrappedOnCPU(gpsSysSpecificData))
+       {
+               PVR_DPF((PVR_DBG_WARNING, "%s Called from within a power transition.  Ignoring.", __FUNCTION__));
+               return 0;
+       }
+
+       NotifyLock(gpsSysSpecificData);
+
+       PVR_ASSERT(!gpsSysSpecificData->bCallVDD2PostFunc);
+
+       if (ConstraintNotificationsEnabled(gpsSysSpecificData))
+       {
+               PVRSRV_ERROR eError;
+
+               eError = PVRSRVDevicePreClockSpeedChange(gpsSysSpecificData->psSGXDevNode->sDevId.ui32DeviceIndex, IMG_TRUE, IMG_NULL);
+
+               gpsSysSpecificData->bCallVDD2PostFunc = (eError == PVRSRV_OK);
+
+       }
+
+       return 0;
+}
+
+static struct notifier_block sVDD2Pre = {
+       VDD2PreFunc,
+        NULL
+};
+
+static struct notifier_block sVDD2Post = {
+       VDD2PostFunc,
+        NULL
+};
+
+static IMG_VOID RegisterConstraintNotifications(IMG_VOID)
+{
+       PVR_TRACE(("Registering constraint notifications"));
+
+       PVR_ASSERT(!gpsSysSpecificData->bConstraintNotificationsEnabled);
+
+       constraint_register_pre_notification(gpsSysSpecificData->pVdd2Handle, &sVDD2Pre,
+                                               max_vdd2_opp+1);
+
+       constraint_register_post_notification(gpsSysSpecificData->pVdd2Handle, &sVDD2Post,
+                                               max_vdd2_opp+1);
+
+       
+       NotifyLock(gpsSysSpecificData);
+       gpsSysSpecificData->bConstraintNotificationsEnabled = IMG_TRUE;
+       NotifyUnlock(gpsSysSpecificData);
+
+       PVR_TRACE(("VDD2 constraint notifications registered"));
+}
+
+static IMG_VOID UnRegisterConstraintNotifications(IMG_VOID)
+{
+       PVR_TRACE(("Unregistering constraint notifications"));
+
+       
+       NotifyLock(gpsSysSpecificData);
+       gpsSysSpecificData->bConstraintNotificationsEnabled = IMG_FALSE;
+       NotifyUnlock(gpsSysSpecificData);
+
+       
+       constraint_unregister_pre_notification(gpsSysSpecificData->pVdd2Handle, &sVDD2Pre,
+                                               max_vdd2_opp+1);
+
+       constraint_unregister_post_notification(gpsSysSpecificData->pVdd2Handle, &sVDD2Post,
+                                               max_vdd2_opp+1);
+}
+#else
+static IMG_VOID RegisterConstraintNotifications(IMG_VOID)
+{
+}
+
+static IMG_VOID UnRegisterConstraintNotifications(IMG_VOID)
+{
+}
+#endif 
+#endif 
+
+PVRSRV_ERROR EnableSGXClocks(SYS_DATA *psSysData)
+{
+#if !defined(NO_HARDWARE)
+       SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
+       long lNewRate;
+       long lRate;
+       IMG_INT res;
+
+       
+       if (atomic_read(&psSysSpecData->sSGXClocksEnabled) != 0)
+       {
+               return PVRSRV_OK;
+       }
+
+       PVR_DPF((PVR_DBG_MESSAGE, "EnableSGXClocks: Enabling SGX Clocks"));
+
+       res = clk_enable(psSysSpecData->psSGX_FCK);
+       if (res < 0)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSGXClocks: Couldn't enable SGX functional clock (%d)", res));
+               return PVRSRV_ERROR_UNABLE_TO_ENABLE_CLOCK;
+       }
+
+#if 0
+       lNewRate = clk_round_rate(psSysSpecData->psSGX_FCK, SYS_SGX_CLOCK_SPEED + ONE_MHZ);
+       if (lNewRate <= 0)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSGXClocks: Couldn't round SGX functional clock rate"));
+               return PVRSRV_ERROR_UNABLE_TO_ROUND_CLOCK_RATE;
+       }
+
+       
+       lRate = clk_get_rate(psSysSpecData->psSGX_FCK);
+       if (lRate != lNewRate)
+       {
+               res = clk_set_rate(psSysSpecData->psSGX_FCK, lNewRate);
+               if (res < 0)
+               {
+                       PVR_DPF((PVR_DBG_WARNING, "EnableSGXClocks: Couldn't set SGX functional clock rate (%d)", res));
+               }
+       }
+#endif
+
+//             IMG_UINT32 rate = clk_get_rate(psSysSpecData->psSGX_FCK);
+//             PVR_TRACE((PVR_DBG_MESSAGE, "EnableSGXClocks: SGX Functional Clock is %dMhz", HZ_TO_MHZ(rate)));
+#if defined(DEBUG)
+       {
+               IMG_UINT32 rate = clk_get_rate(psSysSpecData->psSGX_FCK);
+               PVR_DPF((PVR_DBG_MESSAGE, "EnableSGXClocks: SGX Functional Clock is %dMhz", HZ_TO_MHZ(rate)));
+       }
+#endif
+
+       
+       atomic_set(&psSysSpecData->sSGXClocksEnabled, 1);
+
+#else  
+       PVR_UNREFERENCED_PARAMETER(psSysData);
+#endif 
+       return PVRSRV_OK;
+}
+
+
+IMG_VOID DisableSGXClocks(SYS_DATA *psSysData)
+{
+#if !defined(NO_HARDWARE)
+       SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
+
+       
+       if (atomic_read(&psSysSpecData->sSGXClocksEnabled) == 0)
+       {
+               return;
+       }
+
+       PVR_DPF((PVR_DBG_MESSAGE, "DisableSGXClocks: Disabling SGX Clocks"));
+
+       if (psSysSpecData->psSGX_FCK)
+       {
+               clk_disable(psSysSpecData->psSGX_FCK);
+       }
+
+       
+       atomic_set(&psSysSpecData->sSGXClocksEnabled, 0);
+
+#else  
+       PVR_UNREFERENCED_PARAMETER(psSysData);
+#endif 
+}
+
+PVRSRV_ERROR EnableSystemClocks(SYS_DATA *psSysData)
+{
+       SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
+       struct clk *psCLK;
+       IMG_INT res;
+       PVRSRV_ERROR eError;
+       IMG_BOOL bPowerLock;
+
+#if defined(DEBUG) || defined(TIMING)
+       IMG_INT rate;
+       struct clk *sys_ck;
+       IMG_CPU_PHYADDR     TimerRegPhysBase;
+       IMG_HANDLE hTimerEnable;
+       IMG_UINT32 *pui32TimerEnable;
+
+#endif 
+
+       PVR_TRACE(("EnableSystemClocks: Enabling System Clocks"));
+
+       if (!psSysSpecData->bSysClocksOneTimeInit)
+       {
+               bPowerLock = IMG_FALSE;
+
+               spin_lock_init(&psSysSpecData->sPowerLock);
+               atomic_set(&psSysSpecData->sPowerLockCPU, -1);
+               spin_lock_init(&psSysSpecData->sNotifyLock);
+               atomic_set(&psSysSpecData->sNotifyLockCPU, -1);
+
+               atomic_set(&psSysSpecData->sSGXClocksEnabled, 0);
+                
+               psCLK = clk_get(NULL, "sgx_ck");
+               
+                if (IS_ERR(psCLK))
+               {
+                       PVR_DPF((PVR_DBG_ERROR, "EnableSsystemClocks: Couldn't get SGX Functional Clock"));
+                       goto ExitError;
+               }
+               if(clk_enable(psCLK) != 0)
+               {
+                       printk("Could not enable SGX clock\n");
+                       goto ExitError;
+               }
+               psSysSpecData->psSGX_FCK = psCLK;
+
+               psSysSpecData->bSysClocksOneTimeInit = IMG_TRUE;
+       }
+       else
+       {
+               
+               bPowerLock = PowerLockWrappedOnCPU(psSysSpecData);
+               if (bPowerLock)
+               {
+                       PowerLockUnwrap(psSysSpecData);
+               }
+       }
+
+#if defined(CONSTRAINT_NOTIFICATIONS)
+       psSysSpecData->pVdd2Handle = constraint_get(PVRSRV_MODNAME, &cnstr_id_vdd2);
+       if (IS_ERR(psSysSpecData->pVdd2Handle))
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get VDD2 constraint handle"));
+               goto ExitError;
+       }
+
+       RegisterConstraintNotifications();
+#endif
+
+#if defined(DEBUG) || defined(TIMING)
+        psCLK = clk_get(NULL, "gpt7_fck");
+       if (IS_ERR(psCLK))
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get GPTIMER11 functional clock"));
+               goto ExitUnRegisterConstraintNotifications;
+       }
+       psSysSpecData->psGPT11_FCK = psCLK;
+
+        psCLK = clk_get(NULL, "gpt7_ick");
+       if (IS_ERR(psCLK))
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get GPTIMER11 interface clock"));
+               goto ExitUnRegisterConstraintNotifications;
+       }
+       psSysSpecData->psGPT11_ICK = psCLK;
+
+       rate = clk_get_rate(psSysSpecData->psGPT11_FCK);
+       PVR_TRACE(("GPTIMER11 clock is %dMHz", HZ_TO_MHZ(rate)));
+
+       res = clk_enable(psSysSpecData->psGPT11_FCK);
+       if (res < 0)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't enable GPTIMER11 functional clock (%d)", res));
+               goto ExitUnRegisterConstraintNotifications;
+       }
+
+       res = clk_enable(psSysSpecData->psGPT11_ICK);
+       if (res < 0)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't enable GPTIMER11 interface clock (%d)", res));
+               goto ExitDisableGPT11FCK;
+       }
+
+       
+       TimerRegPhysBase.uiAddr = SYS_TI335x_GP7TIMER_TSICR_SYS_PHYS_BASE;
+       pui32TimerEnable = OSMapPhysToLin(TimerRegPhysBase,
+                  4,
+                  PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
+                  &hTimerEnable);
+
+       if (pui32TimerEnable == IMG_NULL)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: OSMapPhysToLin failed"));
+               goto ExitDisableGPT11ICK;
+       }
+
+       rate = *pui32TimerEnable;
+       if(!(rate & 4))
+       {
+               PVR_TRACE(("Setting GPTIMER11 mode to posted (currently is non-posted)"));
+
+               
+               *pui32TimerEnable = rate | 4;
+       }
+
+       OSUnMapPhysToLin(pui32TimerEnable,
+                   4,
+                   PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
+                   hTimerEnable);
+
+       
+       TimerRegPhysBase.uiAddr = SYS_TI335x_GP7TIMER_ENABLE_SYS_PHYS_BASE;
+       pui32TimerEnable = OSMapPhysToLin(TimerRegPhysBase,
+                  4,
+                  PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
+                  &hTimerEnable);
+
+       if (pui32TimerEnable == IMG_NULL)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: OSMapPhysToLin failed"));
+               goto ExitDisableGPT11ICK;
+       }
+
+       
+       *pui32TimerEnable = 3;
+
+       OSUnMapPhysToLin(pui32TimerEnable,
+                   4,
+                   PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
+                   hTimerEnable);
+
+#endif 
+
+#if defined(PDUMP) && !defined(NO_HARDWARE) && defined(CONSTRAINT_NOTIFICATIONS)
+       PVR_TRACE(("EnableSystemClocks: Setting SGX OPP constraint"));
+
+       
+       res = constraint_set(psSysSpecData->pVdd2Handle, max_vdd2_opp);
+       if (res != 0)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: constraint_set failed (%d)", res));
+               goto ExitConstraintSetFailed;
+       }
+#endif
+       eError = PVRSRV_OK;
+       goto Exit;
+
+#if defined(PDUMP) && !defined(NO_HARDWARE) && defined(CONSTRAINT_NOTIFICATIONS)
+ExitConstraintSetFailed:
+#endif
+#if defined(DEBUG) || defined(TIMING)
+ExitDisableGPT11ICK:
+       clk_disable(psSysSpecData->psGPT11_ICK);
+ExitDisableGPT11FCK:
+       clk_disable(psSysSpecData->psGPT11_FCK);
+ExitUnRegisterConstraintNotifications:
+#endif 
+#if defined(CONSTRAINT_NOTIFICATIONS)
+       UnRegisterConstraintNotifications();
+       constraint_put(psSysSpecData->pVdd2Handle);
+#endif
+Exit:
+       if (bPowerLock)
+       {
+               PowerLockWrap(psSysSpecData);
+       }
+
+ExitError:
+       eError = PVRSRV_ERROR_DISABLE_CLOCK_FAILURE;
+       return eError;
+}
+
+IMG_VOID DisableSystemClocks(SYS_DATA *psSysData)
+{
+       SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
+       IMG_BOOL bPowerLock;
+#if defined(DEBUG) || defined(TIMING)
+       IMG_CPU_PHYADDR TimerRegPhysBase;
+       IMG_HANDLE hTimerDisable;
+       IMG_UINT32 *pui32TimerDisable;
+#endif 
+
+       PVR_TRACE(("DisableSystemClocks: Disabling System Clocks"));
+
+       
+       DisableSGXClocks(psSysData);
+
+       bPowerLock = PowerLockWrappedOnCPU(psSysSpecData);
+       if (bPowerLock)
+       {
+               
+               PowerLockUnwrap(psSysSpecData);
+       }
+
+#if defined(PDUMP) && !defined(NO_HARDWARE) && defined(CONSTRAINT_NOTIFICATIONS)
+       {
+               int res;
+
+               PVR_TRACE(("DisableSystemClocks: Removing SGX OPP constraint"));
+
+               
+               res = constraint_remove(psSysSpecData->pVdd2Handle);
+               if (res != 0)
+               {
+                       PVR_DPF((PVR_DBG_WARNING, "DisableSystemClocks: constraint_remove failed (%d)", res));
+               }
+       }
+#endif
+
+#if defined(CONSTRAINT_NOTIFICATIONS)
+       UnRegisterConstraintNotifications();
+#endif
+
+#if defined(DEBUG) || defined(TIMING)
+       
+       TimerRegPhysBase.uiAddr = SYS_TI335x_GP7TIMER_ENABLE_SYS_PHYS_BASE;
+       pui32TimerDisable = OSMapPhysToLin(TimerRegPhysBase,
+                               4,
+                               PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
+                               &hTimerDisable);
+
+       if (pui32TimerDisable == IMG_NULL)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "DisableSystemClocks: OSMapPhysToLin failed"));
+       }
+       else
+       {
+               *pui32TimerDisable = 0;
+
+               OSUnMapPhysToLin(pui32TimerDisable,
+                               4,
+                               PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
+                               hTimerDisable);
+       }
+
+       clk_disable(psSysSpecData->psGPT11_ICK);
+
+       clk_disable(psSysSpecData->psGPT11_FCK);
+
+#endif 
+#if defined(CONSTRAINT_NOTIFICATIONS)
+       constraint_put(psSysSpecData->pVdd2Handle);
+#endif
+       if (bPowerLock)
+       {
+               PowerLockWrap(psSysSpecData);
+       }
+}
diff --git a/services4/system/ti335x/sysutils_linux_wqueue_compat.c b/services4/system/ti335x/sysutils_linux_wqueue_compat.c
new file mode 100644 (file)
index 0000000..4185daf
--- /dev/null
@@ -0,0 +1,505 @@
+/**********************************************************************
+ *
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope it will be useful but, except 
+ * as otherwise stated in writing, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Imagination Technologies Ltd. <gpl-support@imgtec.com>
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK 
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/hardirq.h>
+#include <linux/mutex.h>
+
+#include "sgxdefs.h"
+#include "services_headers.h"
+#include "sysinfo.h"
+#include "sgxapi_km.h"
+#include "sysconfig.h"
+#include "sgxinfokm.h"
+#include "syslocal.h"
+
+#if !defined(PVR_LINUX_USING_WORKQUEUES)
+#error "PVR_LINUX_USING_WORKQUEUES must be defined"
+#endif
+
+#define        ONE_MHZ 1000000
+#define        HZ_TO_MHZ(m) ((m) / ONE_MHZ)
+
+#if defined(SUPPORT_OMAP3430_SGXFCLK_96M)
+#define SGX_PARENT_CLOCK "cm_96m_fck"
+#else
+#define SGX_PARENT_CLOCK "core_ck"
+#endif
+
+static IMG_VOID PowerLockWrap(SYS_SPECIFIC_DATA *psSysSpecData)
+{
+       if (!in_interrupt())
+       {
+               mutex_lock(&psSysSpecData->sPowerLock);
+
+       }
+}
+
+static IMG_VOID PowerLockUnwrap(SYS_SPECIFIC_DATA *psSysSpecData)
+{
+       if (!in_interrupt())
+       {
+               mutex_unlock(&psSysSpecData->sPowerLock);
+       }
+}
+
+PVRSRV_ERROR SysPowerLockWrap(SYS_DATA *psSysData)
+{
+       SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
+
+       PowerLockWrap(psSysSpecData);
+
+       return PVRSRV_OK;
+}
+
+IMG_VOID SysPowerLockUnwrap(SYS_DATA *psSysData)
+{
+       SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
+
+       PowerLockUnwrap(psSysSpecData);
+}
+
+IMG_BOOL WrapSystemPowerChange(SYS_SPECIFIC_DATA *psSysSpecData)
+{
+       return IMG_TRUE;
+}
+
+IMG_VOID UnwrapSystemPowerChange(SYS_SPECIFIC_DATA *psSysSpecData)
+{
+}
+
+static inline IMG_UINT32 scale_by_rate(IMG_UINT32 val, IMG_UINT32 rate1, IMG_UINT32 rate2)
+{
+       if (rate1 >= rate2)
+       {
+               return val * (rate1 / rate2);
+       }
+
+       return val / (rate2 / rate1);
+}
+
+static inline IMG_UINT32 scale_prop_to_SGX_clock(IMG_UINT32 val, IMG_UINT32 rate)
+{
+       return scale_by_rate(val, rate, SYS_SGX_CLOCK_SPEED);
+}
+
+static inline IMG_UINT32 scale_inv_prop_to_SGX_clock(IMG_UINT32 val, IMG_UINT32 rate)
+{
+       return scale_by_rate(val, SYS_SGX_CLOCK_SPEED, rate);
+}
+
+IMG_VOID SysGetSGXTimingInformation(SGX_TIMING_INFORMATION *psTimingInfo)
+{
+       IMG_UINT32 rate;
+
+#if defined(NO_HARDWARE)
+       rate = SYS_SGX_CLOCK_SPEED;
+
+#else
+       PVR_ASSERT(atomic_read(&gpsSysSpecificData->sSGXClocksEnabled) != 0);
+
+       rate = clk_get_rate(gpsSysSpecificData->psSGX_FCK);
+       PVR_ASSERT(rate != 0);
+#endif
+       psTimingInfo->ui32CoreClockSpeed = rate;
+       psTimingInfo->ui32HWRecoveryFreq = scale_prop_to_SGX_clock(SYS_SGX_HWRECOVERY_TIMEOUT_FREQ, rate);
+       psTimingInfo->ui32uKernelFreq = scale_prop_to_SGX_clock(SYS_SGX_PDS_TIMER_FREQ, rate);
+#if defined(SUPPORT_ACTIVE_POWER_MANAGEMENT)
+       psTimingInfo->bEnableActivePM = IMG_TRUE;
+#else
+       psTimingInfo->bEnableActivePM = IMG_FALSE;
+#endif 
+       psTimingInfo->ui32ActivePowManLatencyms = SYS_SGX_ACTIVE_POWER_LATENCY_MS;
+}
+
+PVRSRV_ERROR EnableSGXClocks(SYS_DATA *psSysData)
+{
+#if !defined(NO_HARDWARE)
+       SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
+/*
+       long lNewRate;
+       long lRate;
+*/
+       IMG_INT res;
+
+       
+       if (atomic_read(&psSysSpecData->sSGXClocksEnabled) != 0)
+       {
+               return PVRSRV_OK;
+       }
+
+       PVR_DPF((PVR_DBG_MESSAGE, "EnableSGXClocks: Enabling SGX Clocks"));
+
+#if defined(DEBUG)
+       {
+
+               IMG_UINT32 rate = clk_get_rate(psSysSpecData->psMPU_CK);
+               PVR_DPF((PVR_DBG_MESSAGE, "EnableSGXClocks: CPU Clock is %dMhz", HZ_TO_MHZ(rate)));
+       }
+#endif
+
+       res = clk_enable(psSysSpecData->psSGX_FCK);
+       if (res < 0)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSGXClocks: Couldn't enable SGX functional clock (%d)", res));
+               return PVRSRV_ERROR_UNABLE_TO_ENABLE_CLOCK;
+       }
+/*
+       res = clk_enable(psSysSpecData->psSGX_ICK);
+       if (res < 0)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSGXClocks: Couldn't enable SGX interface clock (%d)", res));
+
+               clk_disable(psSysSpecData->psSGX_FCK);
+               return PVRSRV_ERROR_UNABLE_TO_ENABLE_CLOCK;
+       }
+
+       lNewRate = clk_round_rate(psSysSpecData->psSGX_FCK, SYS_SGX_CLOCK_SPEED + ONE_MHZ);
+       if (lNewRate <= 0)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSGXClocks: Couldn't round SGX functional clock rate"));
+               return PVRSRV_ERROR_UNABLE_TO_ROUND_CLOCK_RATE;
+       }
+
+       
+       lRate = clk_get_rate(psSysSpecData->psSGX_FCK);
+       if (lRate != lNewRate)
+       {
+               res = clk_set_rate(psSysSpecData->psSGX_FCK, lNewRate);
+               if (res < 0)
+               {
+                       PVR_DPF((PVR_DBG_WARNING, "EnableSGXClocks: Couldn't set SGX functional clock rate (%d)", res));
+               }
+       }
+*/
+#if defined(DEBUG)
+       {
+               IMG_UINT32 rate = clk_get_rate(psSysSpecData->psSGX_FCK);
+               PVR_DPF((PVR_DBG_MESSAGE, "EnableSGXClocks: SGX Functional Clock is %dMhz", HZ_TO_MHZ(rate)));
+       }
+#endif
+
+       
+       atomic_set(&psSysSpecData->sSGXClocksEnabled, 1);
+
+#else  
+       PVR_UNREFERENCED_PARAMETER(psSysData);
+#endif 
+       return PVRSRV_OK;
+}
+
+
+IMG_VOID DisableSGXClocks(SYS_DATA *psSysData)
+{
+#if !defined(NO_HARDWARE)
+       SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
+
+       
+       if (atomic_read(&psSysSpecData->sSGXClocksEnabled) == 0)
+       {
+               return;
+       }
+
+       PVR_DPF((PVR_DBG_MESSAGE, "DisableSGXClocks: Disabling SGX Clocks"));
+
+/*     if (psSysSpecData->psSGX_ICK)
+       {
+               clk_disable(psSysSpecData->psSGX_ICK);
+       }
+*/
+       if (psSysSpecData->psSGX_FCK)
+       {
+               clk_disable(psSysSpecData->psSGX_FCK);
+       }
+
+       
+       atomic_set(&psSysSpecData->sSGXClocksEnabled, 0);
+
+#else  
+       PVR_UNREFERENCED_PARAMETER(psSysData);
+#endif 
+}
+
+PVRSRV_ERROR EnableSystemClocks(SYS_DATA *psSysData)
+{
+       SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
+       struct clk *psCLK;
+//     IMG_INT res;
+//      IMG_BOOL bPowerLock;
+       PVRSRV_ERROR eError;
+
+#if defined(DEBUG) || defined(TIMING)
+        IMG_INT res;
+       IMG_INT rate;
+       struct clk *sys_ck;
+       IMG_CPU_PHYADDR     TimerRegPhysBase;
+       IMG_HANDLE hTimerEnable;
+       IMG_UINT32 *pui32TimerEnable;
+
+#endif 
+
+       PVR_TRACE(("EnableSystemClocks: Enabling System Clocks"));
+
+       if (!psSysSpecData->bSysClocksOneTimeInit)
+       {
+               mutex_init(&psSysSpecData->sPowerLock);
+
+               atomic_set(&psSysSpecData->sSGXClocksEnabled, 0);
+
+               psCLK = clk_get(NULL, "sgx_ck");
+                if (IS_ERR(psCLK))
+                {
+                        PVR_DPF((PVR_DBG_ERROR, "EnableSsystemClocks: Couldn't get SGX Functional Clock"));
+                        goto ExitError;
+                }
+               if(clk_enable(psCLK) != 0)
+                {
+                        printk("Could not enable SGX clock\n");
+                        goto ExitError;
+                }
+
+                psSysSpecData->psSGX_FCK = psCLK; 
+
+                psSysSpecData->bSysClocksOneTimeInit = IMG_TRUE;
+        }
+/*        else
+        {
+
+                bPowerLock = PowerLockWrappedOnCPU(psSysSpecData);
+                if (bPowerLock)
+                {
+                        PowerLockUnwrap(psSysSpecData);
+                }
+        }
+
+*/
+
+/*             
+                psCLK = clk_get(NULL, SGX_PARENT_CLOCK);
+               if (IS_ERR(psCLK))
+               {
+                       PVR_DPF((PVR_DBG_ERROR, "EnableSsystemClocks: Couldn't get Core Clock"));
+                       goto ExitError;
+               }
+               psSysSpecData->psCORE_CK = psCLK;
+
+               psCLK = clk_get(NULL, "sgx_fck");
+               if (IS_ERR(psCLK))
+               {
+                       PVR_DPF((PVR_DBG_ERROR, "EnableSsystemClocks: Couldn't get SGX Functional Clock"));
+                       goto ExitError;
+               }
+               psSysSpecData->psSGX_FCK = psCLK;
+
+               psCLK = clk_get(NULL, "sgx_ick");
+               if (IS_ERR(psCLK))
+               {
+                       PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get SGX Interface Clock"));
+                       goto ExitError;
+               }
+               psSysSpecData->psSGX_ICK = psCLK;
+
+#if defined(DEBUG)
+               psCLK = clk_get(NULL, "mpu_ck");
+               if (IS_ERR(psCLK))
+               {
+                       PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get MPU Clock"));
+                       goto ExitError;
+               }
+               psSysSpecData->psMPU_CK = psCLK;
+#endif
+               res = clk_set_parent(psSysSpecData->psSGX_FCK, psSysSpecData->psCORE_CK);
+               if (res < 0)
+               {
+                       PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't set SGX parent clock (%d)", res));
+                       goto ExitError;
+               }
+
+               psSysSpecData->bSysClocksOneTimeInit = IMG_TRUE;
+       }
+*/
+#if defined(DEBUG) || defined(TIMING)
+        psCLK = clk_get(NULL, "gpt7_fck");
+       if (IS_ERR(psCLK))
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get GPTIMER11 functional clock"));
+               goto ExitUnRegisterConstraintNotifications;
+       }
+       psSysSpecData->psGPT11_FCK = psCLK;
+
+        psCLK = clk_get(NULL, "gpt7_ick");
+       if (IS_ERR(psCLK))
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get GPTIMER11 interface clock"));
+               goto ExitUnRegisterConstraintNotifications;
+       }
+       psSysSpecData->psGPT11_ICK = psCLK;
+/*
+       sys_ck = clk_get(NULL, "sys_ck");
+       if (IS_ERR(sys_ck))
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get System clock"));
+               goto ExitUnRegisterConstraintNotifications;
+       }
+
+       if(clk_get_parent(psSysSpecData->psGPT11_FCK) != sys_ck)
+       {
+               PVR_TRACE(("Setting GPTIMER11 parent to System Clock"));
+               res = clk_set_parent(psSysSpecData->psGPT11_FCK, sys_ck);
+               if (res < 0)
+               {
+                       PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't set GPTIMER11 parent clock (%d)", res));
+               goto ExitUnRegisterConstraintNotifications;
+               }
+       }
+*/
+       rate = clk_get_rate(psSysSpecData->psGPT11_FCK);
+       PVR_TRACE(("GPTIMER11 clock is %dMHz", HZ_TO_MHZ(rate)));
+
+       res = clk_enable(psSysSpecData->psGPT11_FCK);
+       if (res < 0)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't enable GPTIMER11 functional clock (%d)", res));
+               goto ExitUnRegisterConstraintNotifications;
+       }
+
+       res = clk_enable(psSysSpecData->psGPT11_ICK);
+       if (res < 0)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't enable GPTIMER11 interface clock (%d)", res));
+               goto ExitDisableGPT11FCK;
+       }
+
+       
+       TimerRegPhysBase.uiAddr = SYS_TI335x_GP7TIMER_TSICR_SYS_PHYS_BASE;
+       pui32TimerEnable = OSMapPhysToLin(TimerRegPhysBase,
+                  4,
+                  PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
+                  &hTimerEnable);
+
+       if (pui32TimerEnable == IMG_NULL)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: OSMapPhysToLin failed"));
+               goto ExitDisableGPT11ICK;
+       }
+
+       rate = *pui32TimerEnable;
+       if(!(rate & 4))
+       {
+               PVR_TRACE(("Setting GPTIMER11 mode to posted (currently is non-posted)"));
+
+               
+               *pui32TimerEnable = rate | 4;
+       }
+
+       OSUnMapPhysToLin(pui32TimerEnable,
+                   4,
+                   PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
+                   hTimerEnable);
+
+       
+       TimerRegPhysBase.uiAddr = SYS_TI335x_GP7TIMER_ENABLE_SYS_PHYS_BASE;
+       pui32TimerEnable = OSMapPhysToLin(TimerRegPhysBase,
+                  4,
+                  PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
+                  &hTimerEnable);
+
+       if (pui32TimerEnable == IMG_NULL)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: OSMapPhysToLin failed"));
+               goto ExitDisableGPT11ICK;
+       }
+
+       
+       *pui32TimerEnable = 3;
+
+       OSUnMapPhysToLin(pui32TimerEnable,
+                   4,
+                   PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
+                   hTimerEnable);
+
+#endif 
+
+       eError = PVRSRV_OK;
+       goto Exit;
+
+#if defined(DEBUG) || defined(TIMING)
+ExitDisableGPT11ICK:
+       clk_disable(psSysSpecData->psGPT11_ICK);
+ExitDisableGPT11FCK:
+       clk_disable(psSysSpecData->psGPT11_FCK);
+ExitUnRegisterConstraintNotifications:
+#endif 
+ExitError:
+       eError = PVRSRV_ERROR_DISABLE_CLOCK_FAILURE;
+Exit:
+       return eError;
+}
+
+IMG_VOID DisableSystemClocks(SYS_DATA *psSysData)
+{
+#if defined(DEBUG) || defined(TIMING)
+       SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
+       IMG_CPU_PHYADDR TimerRegPhysBase;
+       IMG_HANDLE hTimerDisable;
+       IMG_UINT32 *pui32TimerDisable;
+#endif 
+
+       PVR_TRACE(("DisableSystemClocks: Disabling System Clocks"));
+
+       
+       DisableSGXClocks(psSysData);
+
+#if defined(DEBUG) || defined(TIMING)
+       
+       TimerRegPhysBase.uiAddr = SYS_TI335x_GP7TIMER_ENABLE_SYS_PHYS_BASE;
+       pui32TimerDisable = OSMapPhysToLin(TimerRegPhysBase,
+                               4,
+                               PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
+                               &hTimerDisable);
+
+       if (pui32TimerDisable == IMG_NULL)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "DisableSystemClocks: OSMapPhysToLin failed"));
+       }
+       else
+       {
+               *pui32TimerDisable = 0;
+
+               OSUnMapPhysToLin(pui32TimerDisable,
+                               4,
+                               PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
+                               hTimerDisable);
+       }
+
+       clk_disable(psSysSpecData->psGPT11_ICK);
+
+       clk_disable(psSysSpecData->psGPT11_FCK);
+
+#endif 
+}