diff options
Diffstat (limited to 'drivers')
26 files changed, 4674 insertions, 4 deletions
| diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile index d8a22c2a579..93f444de174 100644 --- a/drivers/gpu/Makefile +++ b/drivers/gpu/Makefile @@ -1,2 +1,2 @@ -obj-y			+= drm/ vga/ +obj-y			+= drm/ vga/ pvr/  obj-$(CONFIG_TEGRA_HOST1X)	+= host1x/ diff --git a/drivers/gpu/pvr/Kconfig b/drivers/gpu/pvr/Kconfig new file mode 100644 index 00000000000..34a122f2f7f --- /dev/null +++ b/drivers/gpu/pvr/Kconfig @@ -0,0 +1,32 @@ +config SGX_OMAP3630 +	tristate "PowerVR SGX for OMAP3630" +	depends on ARCH_OMAP3 +	help +	  Support for the PowerVR SGX 3D core with OMAP 3630. + +choice +	prompt "PowerVR build type" +	default SGX_BUILD_RELEASE + +config SGX_BUILD_RELEASE +	depends on SGX_OMAP3630 +	bool "SGX RELEASE" +        help +          SGX Release Build. + +config SGX_BUILD_DEBUG +	depends on SGX_OMAP3630 +	bool "SGX DEBUG" +        help +          SGX Debug Build. + +endchoice + +config SGX_PDUMP +	depends on SGX_OMAP3630 +	bool "PowerVR SGX Parameter Dump" +	default n +	help +	  This option enables the PDump (Parameter Dump) build to debug +	  the SGX driver. The user side of the driver must be built with +	  this option enabled as well. diff --git a/drivers/gpu/pvr/Makefile b/drivers/gpu/pvr/Makefile new file mode 100644 index 00000000000..a848a8c79ec --- /dev/null +++ b/drivers/gpu/pvr/Makefile @@ -0,0 +1,152 @@ +# +ccflags-y = -Idrivers/video/omap2 \ +	-Idrivers/gpu/pvr/include4\ +	-Idrivers/gpu/pvr/services4/include \ +	-Idrivers/gpu/pvr/services4/srvkm/hwdefs \ +	-Idrivers/gpu/pvr/services4/srvkm/include \ +	-Idrivers/gpu/pvr/services4/srvkm/bridged \ +	-Idrivers/gpu/pvr/services4/srvkm/bridged/sgx \ +	-Idrivers/gpu/pvr/services4/srvkm/devices/sgx \ +	-Idrivers/gpu/pvr/services4/srvkm/env/linux \ +	-Idrivers/gpu/pvr/services4/system/include \ +	-DLINUX -D__linux__ \ +	-DANDROID \ +	-DPVR_BUILD_DIR="\"omap3630_android\"" \ +	-DSUPPORT_SGX \ +	-DTRANSFER_QUEUE \ +	-DPVR_SECURE_HANDLES \ +	-DDISPLAY_CONTROLLER=omaplfb \ +	-DPVR_LINUX_MEM_AREA_POOL_MAX_PAGES=10800 \ +	-DPVR_LINUX_MEM_AREA_USE_VMAP \ +	-DPVR_LINUX_MEM_AREA_POOL_ALLOW_SHRINK \ +	-DSUPPORT_PERCONTEXT_PB \ +	-DSUPPORT_HW_RECOVERY \ +	-DSUPPORT_ACTIVE_POWER_MANAGEMENT \ +	-DSUPPORT_SGX_HWPERF \ +	-DSUPPORT_SGX_LOW_LATENCY_SCHEDULING \ +	-DSUPPORT_MEMINFO_IDS \ +	-DSUPPORT_SGX_NEW_STATUS_VALS \ +	-DSUPPORT_DBGDRV_EVENT_OBJECTS \ +	-DPVRSRV_USSE_EDM_STATUS_DEBUG \ +	-DSGX_DISABLE_VISTEST_SUPPORT \ +	-DSYS_USING_INTERRUPTS \ +	-DPVRSRV_NEW_PVR_DPF \ +	-DSUPPORT_NV12_FROM_2_HWADDRS \ +	-DSUPPORT_LINUX_X86_WRITECOMBINE \ +	-DSUPPORT_LINUX_X86_PAT \ +	-DSGX_DYNAMIC_TIMING_INFO \ +	-DSYS_CUSTOM_POWERLOCK_WRAP \ +	-DPVR_LINUX_USING_WORKQUEUES \ +	-DPVR_LINUX_MISR_USING_PRIVATE_WORKQUEUE \ +	-DPVR_LINUX_TIMERS_USING_WORKQUEUES \ +	-DLDM_PLATFORM \ +	-DPVRSRV_DUMP_MK_TRACE \ +	-DSUPPORT_LARGE_GENERAL_HEAP \ +	-DPVR_NO_OMAP_TIMER \ +	-DSUPPORT_DC_CMDCOMPLETE_WHEN_NO_LONGER_DISPLAYED \ +	-DPVR_LDM_DRIVER_REGISTRATION_NAME="\"pvrsrvkm\"" \ +	-DPVRSRV_MODNAME="\"pvrsrvkm\"" + +#ccflags-y += -Wno-unused-function -Wno-unused-variable + +ccflags-$(CONFIG_SGX_OMAP3630) += \ +	-Idrivers/gpu/pvr/services4/system/omap3630 \ +	-DSGX530 -DSUPPORT_SGX530 -DSGXCORE=530 \ +	-DSGX_CORE_REV=125 + +ccflags-$(CONFIG_SGX_BUILD_RELEASE) += \ +	-DPVR_BUILD_TYPE="\"release\"" \ +	-DRELEASE + +ccflags-$(CONFIG_SGX_BUILD_DEBUG) += \ +	-DPVR_BUILD_TYPE="\"debug\"" \ +	-DDEBUG \ +	-DDEBUG_LINUX_MEMORY_ALLOCATIONS \ +	-DDEBUG_LINUX_MEM_AREAS \ +	-DDEBUG_LINUX_MMAP_AREAS \ +	-DDEBUG_BRIDGE_KM \ +	-DDEBUG_BRIDGE_KM_DISPATCH_TABLE \ +	-DDEBUG_TRACE_BRIDGE_KM \ +	-DIGNORE_SGX_INIT_COMPATIBILITY_CHECK + +ccflags-$(CONFIG_SGX_PDUMP) += \ +	-Idrivers/gpu/pvr/tools/intern/debug/client \ +	-DPDUMP + +pvr_bridged-y := \ +	services4/srvkm/bridged/bridged_pvr_bridge.o \ +	services4/srvkm/bridged/bridged_support.o \ +	services4/srvkm/bridged/sgx/bridged_sgx_bridge.o + +pvr_common-y := \ +	services4/srvkm/common/buffer_manager.o \ +	services4/srvkm/common/deviceclass.o \ +	services4/srvkm/common/devicemem.o \ +	services4/srvkm/common/handle.o \ +	services4/srvkm/common/hash.o \ +	services4/srvkm/common/lists.o \ +	services4/srvkm/common/mem.o \ +	services4/srvkm/common/mem_debug.o \ +	services4/srvkm/common/metrics.o \ +	services4/srvkm/common/osfunc_common.o \ +	services4/srvkm/common/pdump_common.o \ +	services4/srvkm/common/perproc.o \ +	services4/srvkm/common/power.o \ +	services4/srvkm/common/pvrsrv.o \ +	services4/srvkm/common/queue.o \ +	services4/srvkm/common/ra.o \ +	services4/srvkm/common/refcount.o \ +	services4/srvkm/common/resman.o \ +	services4/srvkm/common/ttrace.o + +pvr_devices-y := \ +	services4/srvkm/devices/sgx/mmu.o \ +	services4/srvkm/devices/sgx/pb.o \ +	services4/srvkm/devices/sgx/sgxinit.o \ +	services4/srvkm/devices/sgx/sgxkick.o \ +	services4/srvkm/devices/sgx/sgxpower.o \ +	services4/srvkm/devices/sgx/sgxreset.o \ +	services4/srvkm/devices/sgx/sgxtransfer.o \ +	services4/srvkm/devices/sgx/sgxutils.o + +pvr_env-y := \ +	services4/srvkm/env/linux/event.o \ +	services4/srvkm/env/linux/mmap.o \ +	services4/srvkm/env/linux/mm.o \ +	services4/srvkm/env/linux/module.o \ +	services4/srvkm/env/linux/mutex.o \ +	services4/srvkm/env/linux/mutils.o \ +	services4/srvkm/env/linux/osfunc.o \ +	services4/srvkm/env/linux/osperproc.o \ +	services4/srvkm/env/linux/pdump.o \ +	services4/srvkm/env/linux/proc.o \ +	services4/srvkm/env/linux/pvr_bridge_k.o \ +	services4/srvkm/env/linux/pvr_debug.o \ +	services4/srvkm/env/linux/sysfs.o + +pvr_omaplfb-y := \ +	services4/3rdparty/dc_omapfb3_linux/omaplfb_displayclass.o \ +	services4/3rdparty/dc_omapfb3_linux/omaplfb_linux.o + +pvr_omap3630-$(CONFIG_SGX_OMAP3630) := \ +	services4/system/omap3630/sysconfig.o \ +	services4/system/omap3630/sysutils.o + +dbgdriv-$(CONFIG_SGX_PDUMP) := \ +	tools/intern/debug/dbgdriv/common/dbgdriv.o \ +	tools/intern/debug/dbgdriv/common/handle.o \ +	tools/intern/debug/dbgdriv/common/hotkey.o \ +	tools/intern/debug/dbgdriv/common/ioctl.o \ +	tools/intern/debug/dbgdriv/linux/hostfunc.o \ +	tools/intern/debug/dbgdriv/linux/main.o + +obj-$(CONFIG_SGX_OMAP3630) := \ +	pvr_bridged.o \ +	pvr_common.o \ +	pvr_devices.o \ +	pvr_env.o \ +	pvr_omaplfb.o \ +	pvr_omap3630.o + +obj-$(CONFIG_SGX_PDUMP) += dbgdriv.o +# diff --git a/drivers/gpu/pvr/services4/3rdparty/dc_omapfb3_linux/omaplfb_linux.c b/drivers/gpu/pvr/services4/3rdparty/dc_omapfb3_linux/omaplfb_linux.c index 82c7fcec920..9525688ab40 100644 --- a/drivers/gpu/pvr/services4/3rdparty/dc_omapfb3_linux/omaplfb_linux.c +++ b/drivers/gpu/pvr/services4/3rdparty/dc_omapfb3_linux/omaplfb_linux.c @@ -107,8 +107,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  #endif  #if defined(PVR_OMAPFB3_NEEDS_PLAT_VRFB_H) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))  #include <plat/vrfb.h>  #else +#include <video/omapvrfb.h> +#endif +#else  #if defined(PVR_OMAPFB3_NEEDS_MACH_VRFB_H)  #include <mach/vrfb.h>  #endif @@ -153,7 +157,11 @@ MODULE_SUPPORTED_DEVICE(DEVNAME);  #if !defined(PVR_OMAPLFB_DRM_FB)  #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 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0))  #define OMAP_DSS_MANAGER(man, dev) struct omap_overlay_manager *man = (dev) != NULL ? (dev)->manager : NULL +#else +#define OMAP_DSS_MANAGER(man, dev) struct omap_overlay_manager *man = (dev) != NULL ? (dev)->output->manager : NULL +#endif  #define	WAIT_FOR_VSYNC(man)	((man)->wait_for_vsync)  #else  #define OMAP_DSS_DRIVER(drv, dev) struct omap_dss_device *drv = (dev) @@ -419,6 +427,10 @@ void OMAPLFBFlip(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_BUFFER *psBuffer)  	OMAPLFB_CONSOLE_UNLOCK();  } +/* Newer kernels don't have any update mode capability */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) +  #if !defined(PVR_OMAPLFB_DRM_FB) || defined(DEBUG)  static OMAPLFB_BOOL OMAPLFBValidateDSSUpdateMode(enum omap_dss_update_mode eMode)  { @@ -515,6 +527,23 @@ static const char *OMAPLFBDSSUpdateModeToString(enum omap_dss_update_mode eMode)  	return OMAPLFBUpdateModeToString(OMAPLFBFromDSSUpdateMode(eMode));  } + +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) */ + +static const char *OMAPLFBUpdateModeToString(OMAPLFB_UPDATE_MODE eMode) +{ +	return "Not supported"; +} + +#if defined(PVR_OMAPLFB_DRM_FB) +static const char *OMAPLFBDSSUpdateModeToString(int eMode) +{ +	return "Not supported"; +} +#endif /* defined(PVR_OMAPLFB_DRM_FB) */ + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) */ +  void OMAPLFBPrintInfo(OMAPLFB_DEVINFO *psDevInfo)  {  #if defined(PVR_OMAPLFB_DRM_FB) @@ -555,6 +584,10 @@ void OMAPLFBPrintInfo(OMAPLFB_DEVINFO *psDevInfo)  }  #endif	/* defined(DEBUG) */ +/* Newer kernels don't have any update mode capability */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) +  /*    * Get display update mode.   * If the mode is AUTO, we can wait for VSync, if desired. @@ -710,6 +743,15 @@ OMAPLFB_BOOL OMAPLFBSetUpdateMode(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_UPDATE_MOD  #endif	/* defined(PVR_OMAPLFB_DRM_FB) */  } +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) */ + +OMAPLFB_UPDATE_MODE OMAPLFBGetUpdateMode(OMAPLFB_DEVINFO *psDevInfo) +{ +	return OMAPLFB_UPDATE_MODE_MANUAL; +} + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) */ +  /* Wait for VSync */  OMAPLFB_BOOL OMAPLFBWaitForVSync(OMAPLFB_DEVINFO *psDevInfo)  { diff --git a/drivers/gpu/pvr/services4/srvkm/common/ra.c b/drivers/gpu/pvr/services4/srvkm/common/ra.c index da489397e61..f22c5baccd2 100644 --- a/drivers/gpu/pvr/services4/srvkm/common/ra.c +++ b/drivers/gpu/pvr/services4/srvkm/common/ra.c @@ -1992,6 +1992,7 @@ static PVRSRV_ERROR RA_DumpHeapInfo(RA_ARENA *pArena, IMG_UINT32 ui32DebugLevel)  {  	BT 			*pBT; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))  	{  		IMG_UINT32 ui32PID = OSGetCurrentProcessIDKM();  		IMG_CHAR dirname_buffer[256]; @@ -2006,6 +2007,7 @@ static PVRSRV_ERROR RA_DumpHeapInfo(RA_ARENA *pArena, IMG_UINT32 ui32DebugLevel)  		PVR_LOG(("Base Name of the current process with ID %u is %s", ui32PID, proc_basename));  	} +#endif  	PVR_LOG(("Arena '%s':", pArena->name)); diff --git a/drivers/gpu/pvr/services4/srvkm/devices/sgx/sgxinit.c b/drivers/gpu/pvr/services4/srvkm/devices/sgx/sgxinit.c index 199aa9df2d3..c8292818b4b 100644 --- a/drivers/gpu/pvr/services4/srvkm/devices/sgx/sgxinit.c +++ b/drivers/gpu/pvr/services4/srvkm/devices/sgx/sgxinit.c @@ -1255,7 +1255,9 @@ static INLINE IMG_UINT32 GetDirListBaseReg(IMG_UINT32 ui32Index)  }  #endif +#if defined(CONFIG_DSSCOMP)  void dsscomp_kdump(void); +#endif  /*!  ******************************************************************************* @@ -1277,7 +1279,9 @@ IMG_VOID SGXDumpDebugInfo (PVRSRV_SGXDEV_INFO	*psDevInfo,  {  	IMG_UINT32	ui32CoreNum; +#if defined(CONFIG_DSSCOMP)  	dsscomp_kdump(); +#endif  	PVR_LOG(("SGX debug (%s)", PVRVERSION_STRING)); diff --git a/drivers/gpu/pvr/services4/srvkm/env/linux/mm.h b/drivers/gpu/pvr/services4/srvkm/env/linux/mm.h index 5c01322eaff..6801df466e7 100644 --- a/drivers/gpu/pvr/services4/srvkm/env/linux/mm.h +++ b/drivers/gpu/pvr/services4/srvkm/env/linux/mm.h @@ -600,7 +600,7 @@ static inline IMG_VOID FreeIONLinuxMemArea(LinuxMemArea *psLinuxMemArea)  static inline IMG_INT32  GetIONLinuxMemAreaInfo(LinuxMemArea *psLinuxMemArea, IMG_UINT32* ui32AddressOffsets, -                IMG_UINT32* ui32NumAddr); +                IMG_UINT32* ui32NumAddr)  {      PVR_UNREFERENCED_PARAMETER(psLinuxMemArea);      PVR_UNREFERENCED_PARAMETER(ui32AddressOffsets); diff --git a/drivers/gpu/pvr/services4/srvkm/env/linux/mmap.c b/drivers/gpu/pvr/services4/srvkm/env/linux/mmap.c index 1a485c48df4..3eb2cbad2bf 100644 --- a/drivers/gpu/pvr/services4/srvkm/env/linux/mmap.c +++ b/drivers/gpu/pvr/services4/srvkm/env/linux/mmap.c @@ -1077,7 +1077,11 @@ PVRMMap(struct file* pFile, struct vm_area_struct* ps_vma)      PVR_DPF((PVR_DBG_MESSAGE, "%s: Mapped psLinuxMemArea 0x%p\n",           __FUNCTION__, psOffsetStruct->psLinuxMemArea)); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0))      ps_vma->vm_flags |= VM_RESERVED; +#else +    ps_vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; /* Don't swap */ +#endif      ps_vma->vm_flags |= VM_IO;      /* diff --git a/drivers/gpu/pvr/services4/srvkm/env/linux/osfunc.c b/drivers/gpu/pvr/services4/srvkm/env/linux/osfunc.c index ac03185c48e..ca405828173 100644 --- a/drivers/gpu/pvr/services4/srvkm/env/linux/osfunc.c +++ b/drivers/gpu/pvr/services4/srvkm/env/linux/osfunc.c @@ -839,7 +839,7 @@ IMG_UINT32 OSGetCurrentProcessIDKM(IMG_VOID)  #endif  } - +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))  int OSGetProcCmdline(IMG_UINT32 ui32PID, char * buffer, int buff_size)  {  	int res = 0; @@ -893,7 +893,7 @@ const char* OSGetPathBaseName(char * buffer, int buff_size)  	}  	return base_name;  } - +#endif  /*!  ****************************************************************************** @@ -3781,7 +3781,11 @@ PVRSRV_ERROR OSAcquirePhysPageAddr(IMG_VOID *pvCPUVAddr,      }      /* Does the region represent memory mapped I/O? */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0))      if ((psVMArea->vm_flags & (VM_IO | VM_RESERVED)) != (VM_IO | VM_RESERVED)) +#else +    if ((psVMArea->vm_flags & (VM_IO | VM_DONTEXPAND | VM_DONTDUMP)) != (VM_IO | VM_DONTEXPAND | VM_DONTDUMP)) +#endif      {          PVR_DPF((PVR_DBG_ERROR,              "OSAcquirePhysPageAddr: Memory region does not represent memory mapped I/O (VMA flags: 0x%lx)", psVMArea->vm_flags)); diff --git a/drivers/gpu/pvr/services4/srvkm/env/linux/proc.c b/drivers/gpu/pvr/services4/srvkm/env/linux/proc.c index 7307257e09c..4a6e2fedc42 100644 --- a/drivers/gpu/pvr/services4/srvkm/env/linux/proc.c +++ b/drivers/gpu/pvr/services4/srvkm/env/linux/proc.c @@ -93,6 +93,18 @@ static struct file_operations pvr_proc_operations =  	.release	= seq_release,  }; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) +static ssize_t pvr_proc_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos); +static struct file_operations pvr_read_proc_operations = +{ +	.open		= pvr_proc_open, +	.read		= pvr_proc_read, +	.write		= pvr_proc_write, +	.llseek		= seq_lseek, +	.release	= seq_release, +}; +#endif +  static struct seq_operations pvr_proc_seq_operations =  {  	.start =	pvr_proc_seq_start, @@ -251,10 +263,15 @@ static IMG_INT pvr_proc_open(struct inode *inode,struct file *file)  	IMG_INT ret = seq_open(file, &pvr_proc_seq_operations);  	struct seq_file *seq = (struct seq_file*)file->private_data; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))  	struct proc_dir_entry* pvr_proc_entry = PDE(inode);  	/* Add pointer to handlers to seq_file structure */  	seq->private = pvr_proc_entry->data; +#else +	PVR_PROC_SEQ_HANDLERS *data = (PVR_PROC_SEQ_HANDLERS *)PDE_DATA(inode); +	seq->private = data; +#endif  	return ret;  } @@ -273,6 +290,7 @@ static ssize_t pvr_proc_write(struct file *file, const char __user *buffer,  		size_t count, loff_t *ppos)  {  	struct inode *inode = file->f_path.dentry->d_inode; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))  	struct proc_dir_entry * dp;  	PVR_UNREFERENCED_PARAMETER(ppos); @@ -282,6 +300,13 @@ static ssize_t pvr_proc_write(struct file *file, const char __user *buffer,  		return -EIO;  	return dp->write_proc(file, buffer, count, dp->data); +#else +	PVR_PROC_SEQ_HANDLERS *data = (PVR_PROC_SEQ_HANDLERS *)PDE_DATA(inode); +	PVR_UNREFERENCED_PARAMETER(ppos); +	if (!data->write_proc) +		return -EIO; +	return data->write_proc(file, buffer, count, data); +#endif  } @@ -452,6 +477,7 @@ static struct proc_dir_entry* CreateProcEntryInDirSeq(  		mode |= S_IWUSR;      } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))  	file=create_proc_entry(name, mode, pdir);      if (file) @@ -479,6 +505,26 @@ static struct proc_dir_entry* CreateProcEntryInDirSeq(          	return file;  		}      } +#else +	/* Pass the handlers */ +	{ +		PVR_PROC_SEQ_HANDLERS *seq_handlers; +		seq_handlers = (PVR_PROC_SEQ_HANDLERS *)kmalloc(sizeof(PVR_PROC_SEQ_HANDLERS), GFP_KERNEL); +		if (seq_handlers) +		{ +			seq_handlers->next = next_handler; +			seq_handlers->show = show_handler; +			seq_handlers->off2element = off2element_handler; +			seq_handlers->startstop = startstop_handler; +			seq_handlers->data = data; +			seq_handlers->write_proc = whandler; +			file = proc_create_data(name, mode, pdir, &pvr_proc_operations,seq_handlers); +			if (file) +				return file; +			kfree(seq_handlers); +		} +	} +#endif      PVR_DPF((PVR_DBG_ERROR, "CreateProcEntryInDirSeq: cannot make proc entry /proc/%s/%s: no memory", PVRProcDirRoot, name));      return NULL; @@ -652,6 +698,7 @@ struct proc_dir_entry* CreatePerProcessProcEntrySeq (      if (!psPerProc->psProcDir)      { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))          IMG_CHAR dirname_buffer[256];          IMG_CHAR dirname[256];          IMG_INT ret; @@ -666,6 +713,12 @@ struct proc_dir_entry* CreatePerProcessProcEntrySeq (          ret = snprintf(dirname, sizeof(dirname), "%u-%s", ui32PID, proc_basename);          PVR_DPF((PVR_DBG_MESSAGE, "Creating a new process entry for %s with ID %u\n", proc_basename, ui32PID)); +#else +        IMG_CHAR dirname[16]; +        IMG_INT ret; + +        ret = snprintf(dirname, sizeof(dirname), "%u", ui32PID); +#endif  		if (ret <=0 || ret >= (IMG_INT)sizeof(dirname))  		{ @@ -705,6 +758,7 @@ struct proc_dir_entry* CreatePerProcessProcEntrySeq (  *****************************************************************************/  IMG_VOID RemoveProcEntrySeq( struct proc_dir_entry* proc_entry )  { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))      if (dir)      {  		void* data = proc_entry->data ; @@ -715,6 +769,7 @@ IMG_VOID RemoveProcEntrySeq( struct proc_dir_entry* proc_entry )  			kfree( data );      } +#endif  }  /*! @@ -738,6 +793,7 @@ IMG_VOID RemovePerProcessProcEntrySeq(struct proc_dir_entry* proc_entry)      PVRSRV_ENV_PER_PROCESS_DATA *psPerProc;      psPerProc = LinuxTerminatingProcessPrivateData(); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))      if (!psPerProc)      {          psPerProc = PVRSRVFindPerProcessPrivateData(); @@ -758,6 +814,7 @@ IMG_VOID RemovePerProcessProcEntrySeq(struct proc_dir_entry* proc_entry)  		if(data)  			kfree( data );      } +#endif  }  /*! @@ -796,6 +853,7 @@ IMG_VOID RemovePerProcessProcEntrySeq(struct proc_dir_entry* proc_entry)   @Return      : length of string written to page  *****************************************************************************/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))  static IMG_INT pvr_read_proc(IMG_CHAR *page, IMG_CHAR **start, off_t off,                           IMG_INT count, IMG_INT *eof, IMG_VOID *data)  { @@ -820,6 +878,18 @@ static IMG_INT pvr_read_proc(IMG_CHAR *page, IMG_CHAR **start, off_t off,      return len;  } +#else +static ssize_t pvr_proc_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) +{ +	struct inode *inode = file->f_path.dentry->d_inode; +	PVR_PROC_SEQ_HANDLERS *data = (PVR_PROC_SEQ_HANDLERS *)PDE_DATA(inode); +	PVR_UNREFERENCED_PARAMETER(ppos); +	if (!data->read_proc) +		return -EIO; +	return -EIO; + +} +#endif  /*! @@ -847,6 +917,9 @@ static IMG_INT CreateProcEntryInDir(struct proc_dir_entry *pdir, const IMG_CHAR  {      struct proc_dir_entry * file;      mode_t mode; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) +	PVR_PROC_SEQ_HANDLERS *handlers; +#endif      if (!pdir)      { @@ -867,6 +940,7 @@ static IMG_INT CreateProcEntryInDir(struct proc_dir_entry *pdir, const IMG_CHAR  	mode |= S_IWUSR;      } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))      file = create_proc_entry(name, mode, pdir);      if (file) @@ -884,6 +958,23 @@ static IMG_INT CreateProcEntryInDir(struct proc_dir_entry *pdir, const IMG_CHAR      }      PVR_DPF((PVR_DBG_ERROR, "CreateProcEntry: cannot create proc entry %s in %s", name, pdir->name)); +#else +	handlers = (PVR_PROC_SEQ_HANDLERS *)kmalloc(sizeof(PVR_PROC_SEQ_HANDLERS), GFP_KERNEL); +	if (handlers) +	{ +		handlers->data = data; +		handlers->read_proc = rhandler; +		handlers->write_proc = whandler; +		file = proc_create_data(name, mode, pdir, &pvr_read_proc_operations, handlers); +		if (file) +		{ +			PVR_DPF((PVR_DBG_MESSAGE, "Created proc entry %s in %s", name, "?" /*pdir->name*/)); +			return 0; +		} +		kfree (handlers); +	} +	PVR_DPF((PVR_DBG_ERROR, "CreateProcEntry: cannot create proc entry %s in %s", name, "?" /*pdir->name*/)); +#endif      return -ENOMEM;  } @@ -1018,6 +1109,7 @@ IMG_INT CreateProcReadEntry(const IMG_CHAR * name, pvr_read_proc_t handler)          return -ENOMEM;      } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))  	/* PRQA S 0307 1 */ /* ignore warning about casting to different pointer type */      file = create_proc_read_entry (name, S_IFREG | S_IRUGO, dir, pvr_read_proc, (IMG_VOID *)handler); @@ -1028,6 +1120,12 @@ IMG_INT CreateProcReadEntry(const IMG_CHAR * name, pvr_read_proc_t handler)  #endif          return 0;      } +#else +	/* use file_ops pointing to pvr_read_proc */ +	file = proc_create_data(name, S_IFREG | S_IRUGO, dir, &pvr_read_proc_operations, handler); +	if (file) +		return 0; +#endif      PVR_DPF((PVR_DBG_ERROR, "CreateProcReadEntry: cannot make proc entry /proc/%s/%s: no memory", PVRProcDirRoot, name)); @@ -1124,7 +1222,9 @@ IMG_VOID RemoveProcEntry(const IMG_CHAR * name)  {      if (dir)      { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))          remove_proc_entry(name, dir); +#endif          PVR_DPF((PVR_DBG_MESSAGE, "Removing /proc/%s/%s", PVRProcDirRoot, name));      }  } @@ -1162,9 +1262,11 @@ IMG_VOID RemovePerProcessProcEntry(const IMG_CHAR *name)      if (psPerProc->psProcDir)      { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))          remove_proc_entry(name, psPerProc->psProcDir);          PVR_DPF((PVR_DBG_MESSAGE, "Removing proc entry %s from %s", name, psPerProc->psProcDir->name)); +#endif      }  } @@ -1187,6 +1289,7 @@ IMG_VOID RemovePerProcessProcDir(PVRSRV_ENV_PER_PROCESS_DATA *psPerProc)  {      if (psPerProc->psProcDir)      { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))          while (psPerProc->psProcDir->subdir)          {              PVR_DPF((PVR_DBG_WARNING, "Belatedly removing /proc/%s/%s/%s", PVRProcDirRoot, psPerProc->psProcDir->name, psPerProc->psProcDir->subdir->name)); @@ -1194,6 +1297,7 @@ IMG_VOID RemovePerProcessProcDir(PVRSRV_ENV_PER_PROCESS_DATA *psPerProc)              RemoveProcEntry(psPerProc->psProcDir->subdir->name);          }          RemoveProcEntry(psPerProc->psProcDir->name); +#endif      }  } @@ -1214,6 +1318,7 @@ IMG_VOID RemovePerProcessProcDir(PVRSRV_ENV_PER_PROCESS_DATA *psPerProc)  *****************************************************************************/  IMG_VOID RemoveProcEntries(IMG_VOID)  { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))  #ifdef DEBUG  	RemoveProcEntrySeq( g_pProcDebugLevel );  #ifdef PVR_MANUAL_POWER_CONTROL @@ -1233,6 +1338,9 @@ IMG_VOID RemoveProcEntries(IMG_VOID)  	}  	remove_proc_entry(PVRProcDirRoot, NULL); +#else +	proc_remove(dir); +#endif  }  /***************************************************************************** diff --git a/drivers/gpu/pvr/services4/srvkm/env/linux/proc.h b/drivers/gpu/pvr/services4/srvkm/env/linux/proc.h index bc2a554cb4e..62c6dafc0ad 100644 --- a/drivers/gpu/pvr/services4/srvkm/env/linux/proc.h +++ b/drivers/gpu/pvr/services4/srvkm/env/linux/proc.h @@ -46,6 +46,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  #include <asm/system.h>		// va_list etc  #include <linux/proc_fs.h>	// read_proc_t etc +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) +typedef int (read_proc_t)(char *page, char **start, off_t off, int count, int *eof, void *data); +typedef int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data); +#endif  #include <linux/seq_file.h> // seq_file  #define END_OF_FILE (off_t) -1 @@ -65,6 +69,10 @@ typedef struct _PVR_PROC_SEQ_HANDLERS_ {  	pvr_off2element_proc_seq_t *off2element;  	pvr_startstop_proc_seq_t *startstop;  	IMG_VOID *data; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) +	read_proc_t *read_proc; +	write_proc_t *write_proc; +#endif  } PVR_PROC_SEQ_HANDLERS; diff --git a/drivers/gpu/pvr/services4/system/omap3630/oemfuncs.h b/drivers/gpu/pvr/services4/system/omap3630/oemfuncs.h new file mode 100644 index 00000000000..090204238b0 --- /dev/null +++ b/drivers/gpu/pvr/services4/system/omap3630/oemfuncs.h @@ -0,0 +1,80 @@ +/*************************************************************************/ /*! +@Title          SGX kernel/client driver interface structures and prototypes +@Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@License        Dual MIT/GPLv2 + +The contents of this file are subject to the MIT license as set out below. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Alternatively, the contents of this file may be used under the terms of +the GNU General Public License Version 2 ("GPL") in which case the provisions +of GPL are applicable instead of those above. + +If you wish to allow use of your version of this file only under the terms of +GPL, and not to allow others to use your version of this file under the terms +of the MIT license, indicate your decision by deleting the provisions above +and replace them with the notice and other provisions required by GPL as set +out in the file called "GPL-COPYING" included in this distribution. If you do +not delete the provisions above, a recipient may use your version of this file +under the terms of either the MIT license or GPL. + +This License is also included in this distribution in the file called +"MIT-COPYING". + +EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS +PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ /**************************************************************************/ + +#if !defined(__OEMFUNCS_H__) +#define __OEMFUNCS_H__ + +#if defined (__cplusplus) +extern "C" { +#endif + +/* function in/out data structures: */ +typedef IMG_UINT32   (*PFN_SRV_BRIDGEDISPATCH)( IMG_UINT32  Ioctl, +												IMG_BYTE   *pInBuf, +												IMG_UINT32  InBufLen,  +											    IMG_BYTE   *pOutBuf, +												IMG_UINT32  OutBufLen, +												IMG_UINT32 *pdwBytesTransferred); +/* +	Function table for kernel 3rd party driver to kernel services +*/ +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	/* __OEMFUNCS_H__ */ + +/***************************************************************************** + End of file (oemfuncs.h) +*****************************************************************************/ + + diff --git a/drivers/gpu/pvr/services4/system/omap3630/sgxfreq.c b/drivers/gpu/pvr/services4/system/omap3630/sgxfreq.c new file mode 100644 index 00000000000..7e8e8fd6a07 --- /dev/null +++ b/drivers/gpu/pvr/services4/system/omap3630/sgxfreq.c @@ -0,0 +1,590 @@ +/* + * Copyright (C) 2012 Texas Instruments, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/opp.h> +#include <plat/gpu.h> +#include "sgxfreq.h" + +static struct sgxfreq_data { +	int freq_cnt; +	unsigned long *freq_list; +	unsigned long freq; +	unsigned long freq_request; +	unsigned long freq_limit; +	unsigned long total_idle_time; +	unsigned long total_active_time; +	struct mutex freq_mutex; +	struct list_head gov_list; +	struct sgxfreq_governor *gov; +	struct mutex gov_mutex; +	struct sgxfreq_sgx_data sgx_data; +	struct device *dev; +	struct gpu_platform_data *pdata; +} sfd; + +/* Governor init/deinit functions */ +int onoff_init(void); +int onoff_deinit(void); +int activeidle_init(void); +int activeidle_deinit(void); +int on3demand_init(void); +int on3demand_deinit(void); +int userspace_init(void); +int userspace_deinit(void); + + +typedef int sgxfreq_gov_init_t(void); +sgxfreq_gov_init_t *sgxfreq_gov_init[] = { +	onoff_init, +	activeidle_init, +	on3demand_init, +	userspace_init, +	NULL, +}; + +typedef int sgxfreq_gov_deinit_t(void); +sgxfreq_gov_deinit_t *sgxfreq_gov_deinit[] = { +	onoff_deinit, +	activeidle_deinit, +	on3demand_deinit, +	userspace_deinit, +	NULL, +}; + +#define SGXFREQ_DEFAULT_GOV_NAME "on3demand" +static unsigned long _idle_curr_time; +static unsigned long _idle_prev_time; +static unsigned long _active_curr_time; +static unsigned long _active_prev_time; + +#if defined(CONFIG_THERMAL_FRAMEWORK) +int cool_init(void); +void cool_deinit(void); +#endif + +/*********************** begin sysfs interface ***********************/ + +struct kobject *sgxfreq_kobj; + +static ssize_t show_frequency_list(struct device *dev, +				   struct device_attribute *attr, +				   char *buf) +{ +	int i; +	ssize_t count = 0; + +	for (i = 0; i < sfd.freq_cnt; i++) +		count += sprintf(&buf[count], "%lu ", sfd.freq_list[i]); +	count += sprintf(&buf[count], "\n"); + +	return count; +} + +static ssize_t show_frequency_request(struct device *dev, +				      struct device_attribute *attr, +				      char *buf) +{ +	return sprintf(buf, "%lu\n", sfd.freq_request); +} + +static ssize_t show_frequency_limit(struct device *dev, +				    struct device_attribute *attr, +				    char *buf) +{ +	return sprintf(buf, "%lu\n", sfd.freq_limit); +} + +static ssize_t show_frequency(struct device *dev, +			      struct device_attribute *attr, +			      char *buf) +{ +	return sprintf(buf, "%lu\n", sfd.freq); +} + +static ssize_t show_stat(struct device *dev, +			      struct device_attribute *attr, +			      char *buf) +{ +	return sprintf(buf, "gpu %lu %lu\n", +		sfd.total_active_time, sfd.total_idle_time); +} + +static ssize_t show_governor_list(struct device *dev, +				  struct device_attribute *attr, +				  char *buf) +{ +	ssize_t i = 0; +	struct sgxfreq_governor *t; + +	list_for_each_entry(t, &sfd.gov_list, governor_list) { +		if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) +		    - (SGXFREQ_NAME_LEN + 2))) +			goto out; +		i += scnprintf(&buf[i], SGXFREQ_NAME_LEN, "%s ", t->name); +	} +out: +	i += sprintf(&buf[i], "\n"); +	return i; +} + +static ssize_t show_governor(struct device *dev, +			     struct device_attribute *attr, char *buf) +{ +	if (sfd.gov) +		return scnprintf(buf, SGXFREQ_NAME_LEN, "%s\n", sfd.gov->name); + +	return sprintf(buf, "\n"); +} + +static ssize_t store_governor(struct device *dev, +			      struct device_attribute *attr, const char *buf, +			      size_t count) +{ +	int ret; +	char name[16]; + +	ret = sscanf(buf, "%15s", name); +	if (ret != 1) +		return -EINVAL; + +	ret = sgxfreq_set_governor(name); +	if (ret) +		return ret; +	else +		return count; +} + +static DEVICE_ATTR(frequency_list, 0444, show_frequency_list, NULL); +static DEVICE_ATTR(frequency_request, 0444, show_frequency_request, NULL); +static DEVICE_ATTR(frequency_limit, 0444, show_frequency_limit, NULL); +static DEVICE_ATTR(frequency, 0444, show_frequency, NULL); +static DEVICE_ATTR(governor_list, 0444, show_governor_list, NULL); +static DEVICE_ATTR(governor, 0644, show_governor, store_governor); +static DEVICE_ATTR(stat, 0444, show_stat, NULL); + +static const struct attribute *sgxfreq_attributes[] = { +	&dev_attr_frequency_list.attr, +	&dev_attr_frequency_request.attr, +	&dev_attr_frequency_limit.attr, +	&dev_attr_frequency.attr, +	&dev_attr_governor_list.attr, +	&dev_attr_governor.attr, +	&dev_attr_stat.attr, +	NULL +}; + +/************************ end sysfs interface ************************/ + +static void __set_freq(void) +{ +	unsigned long freq; + +	freq = min(sfd.freq_request, sfd.freq_limit); +	if (freq != sfd.freq) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)) +		sfd.pdata->device_scale(sfd.dev, sfd.dev, freq); +#else +		sfd.pdata->device_scale(sfd.dev, freq); +#endif +		sfd.freq = freq; +	} +} + +static struct sgxfreq_governor *__find_governor(const char *name) +{ +        struct sgxfreq_governor *t; + +        list_for_each_entry(t, &sfd.gov_list, governor_list) +                if (!strnicmp(name, t->name, SGXFREQ_NAME_LEN)) +                        return t; + +        return NULL; +} + +static void __update_timing_info(bool active) +{ +	struct timeval tv; +	do_gettimeofday(&tv); +	if(active) +	{ +		if(sfd.sgx_data.active == true) { +			_active_curr_time = __tv2msec(tv); +			sfd.total_active_time += __delta32( +					_active_curr_time, _active_prev_time); +			SGXFREQ_TRACE("A->A TA:= %lums \tdA: %lums \tTI: %lums \tdI: %lums\n", +					sfd.total_active_time, +					__delta32(_active_curr_time, _active_prev_time), +					sfd.total_active_time, +					(unsigned long)0); +			_active_prev_time = _active_curr_time; +		} else { +			_idle_curr_time = __tv2msec(tv); +			_active_prev_time = _idle_curr_time; +			sfd.total_idle_time += +					__delta32(_idle_curr_time, _idle_prev_time); +			SGXFREQ_TRACE("I->A TA:= %lums \tdA: %lums \tTI: %lums \tdI: %lums\n", +					sfd.total_active_time, +					(unsigned long)0, +					sfd.total_idle_time, +					__delta32(_idle_curr_time, _idle_prev_time)); +		} +	} else { +		if(sfd.sgx_data.active == true) +		{ +			_idle_prev_time = _active_curr_time = __tv2msec(tv); +			sfd.total_active_time += +					__delta32(_active_curr_time, _active_prev_time); +			SGXFREQ_TRACE("A->I TA:= %lums \tdA: %lums \tTI: %lums \tdI: %lums\n", +					sfd.total_active_time, +					__delta32(_active_curr_time, _active_prev_time), +					sfd.total_active_time, +					(unsigned long)0); +		} +		else +		{ +			_idle_curr_time = __tv2msec(tv); +			sfd.total_idle_time += __delta32( +					_idle_curr_time, _idle_prev_time); +			SGXFREQ_TRACE("I->I TA:= %lums \tdA: %lums \tTI: %lums \tdI: %lums\n", +					sfd.total_active_time, +					(unsigned long)0, +					sfd.total_idle_time, +					__delta32(_idle_curr_time, _idle_prev_time)); +			_idle_prev_time = _idle_curr_time; +		} +	} +} + +int sgxfreq_init(struct device *dev) +{ +	int i, ret; +	unsigned long freq; +	struct opp *opp; +	struct timeval tv; + +	sfd.dev = dev; +	if (!sfd.dev) +		return -EINVAL; + +	sfd.pdata = (struct gpu_platform_data *)dev->platform_data; +	if (!sfd.pdata || +	    !sfd.pdata->opp_get_opp_count || +	    !sfd.pdata->opp_find_freq_ceil || +	    !sfd.pdata->device_scale) +		return -EINVAL; + +	rcu_read_lock(); + +	sfd.freq_cnt = sfd.pdata->opp_get_opp_count(dev); +	if (sfd.freq_cnt < 1) { +		rcu_read_unlock(); +		return -ENODEV; +	} + +	sfd.freq_list = kmalloc(sfd.freq_cnt * sizeof(unsigned long), GFP_ATOMIC); +        if (!sfd.freq_list) { +		rcu_read_unlock(); +		return -ENOMEM; +	} + +	freq = 0; +	for (i = 0; i < sfd.freq_cnt; i++) { +		opp = sfd.pdata->opp_find_freq_ceil(dev, &freq); +		if (IS_ERR_OR_NULL(opp)) { +			rcu_read_unlock(); +			kfree(sfd.freq_list); +			return -ENODEV; +		} +		sfd.freq_list[i] = freq; +		freq++; +	} +	rcu_read_unlock(); + +	mutex_init(&sfd.freq_mutex); +	sfd.freq_limit = sfd.freq_list[sfd.freq_cnt - 1]; +	sgxfreq_set_freq_request(sfd.freq_list[sfd.freq_cnt - 1]); +	sfd.sgx_data.clk_on = false; +	sfd.sgx_data.active = false; + +	mutex_init(&sfd.gov_mutex); +	INIT_LIST_HEAD(&sfd.gov_list); + +	sgxfreq_kobj = kobject_create_and_add("sgxfreq", &sfd.dev->kobj); +	ret = sysfs_create_files(sgxfreq_kobj, sgxfreq_attributes); +	if (ret) { +		kfree(sfd.freq_list); +		return ret; +	} + +#if defined(CONFIG_THERMAL_FRAMEWORK) +	cool_init(); +#endif + +	for (i = 0; sgxfreq_gov_init[i] != NULL; i++) +		sgxfreq_gov_init[i](); + +	if (sgxfreq_set_governor(SGXFREQ_DEFAULT_GOV_NAME)) { +		kfree(sfd.freq_list); +		return -ENODEV; +	} +	do_gettimeofday(&tv); +	_idle_prev_time = _active_curr_time = _idle_curr_time = +		_active_prev_time = __tv2msec(tv); + +	return 0; +} + +int sgxfreq_deinit(void) +{ +	int i; + +	sgxfreq_set_governor(NULL); + +	sgxfreq_set_freq_request(sfd.freq_list[0]); + +#if defined(CONFIG_THERMAL_FRAMEWORK) +	cool_deinit(); +#endif + +	for (i = 0; sgxfreq_gov_deinit[i] != NULL; i++) +		sgxfreq_gov_deinit[i](); + +	sysfs_remove_files(sgxfreq_kobj, sgxfreq_attributes); +	kobject_put(sgxfreq_kobj); + +	kfree(sfd.freq_list); + +	return 0; +} + +int sgxfreq_register_governor(struct sgxfreq_governor *governor) +{ +	if (!governor) +		return -EINVAL; + +	list_add(&governor->governor_list, &sfd.gov_list); + +	return 0; +} + +void sgxfreq_unregister_governor(struct sgxfreq_governor *governor) +{ +	if (!governor) +		return; + +	list_del(&governor->governor_list); +} + +int sgxfreq_set_governor(const char *name) +{ +	int ret = 0; +	struct sgxfreq_governor *new_gov = 0; + +	if (name) { +		new_gov = __find_governor(name); +		if (!new_gov) +			return -EINVAL; +	} + +	mutex_lock(&sfd.gov_mutex); + +	if (sfd.gov && sfd.gov->gov_stop) +		sfd.gov->gov_stop(); + +	if (new_gov && new_gov->gov_start) +		ret = new_gov->gov_start(&sfd.sgx_data); + +	if (ret) { +		if (sfd.gov && sfd.gov->gov_start) +			sfd.gov->gov_start(&sfd.sgx_data); +		return -ENODEV; +	} +	sfd.gov = new_gov; + +	mutex_unlock(&sfd.gov_mutex); + +	return 0; +} + +int sgxfreq_get_freq_list(unsigned long **pfreq_list) +{ +	*pfreq_list = sfd.freq_list; + +	return sfd.freq_cnt; +} + +unsigned long sgxfreq_get_freq_min(void) +{ +	return sfd.freq_list[0]; +} + +unsigned long sgxfreq_get_freq_max(void) +{ +	return sfd.freq_list[sfd.freq_cnt - 1]; +} + +unsigned long sgxfreq_get_freq_floor(unsigned long freq) +{ +	int i; +	unsigned long f = 0; + +	for (i = sfd.freq_cnt - 1; i >= 0; i--) { +		f = sfd.freq_list[i]; +		if (f <= freq) +			return f; +	} + +	return f; +} + +unsigned long sgxfreq_get_freq_ceil(unsigned long freq) +{ +	int i; +	unsigned long f = 0; + +	for (i = 0; i < sfd.freq_cnt; i++) { +		f = sfd.freq_list[i]; +		if (f >= freq) +			return f; +	} + +	return f; +} + +unsigned long sgxfreq_get_freq(void) +{ +	return sfd.freq; +} + +unsigned long sgxfreq_get_freq_request(void) +{ +	return sfd.freq_request; +} + +unsigned long sgxfreq_get_freq_limit(void) +{ +	return sfd.freq_limit; +} + +unsigned long sgxfreq_set_freq_request(unsigned long freq_request) +{ +	freq_request = sgxfreq_get_freq_ceil(freq_request); + +	mutex_lock(&sfd.freq_mutex); + +	sfd.freq_request = freq_request; +	__set_freq(); + +	mutex_unlock(&sfd.freq_mutex); + +	return freq_request; +} + +unsigned long sgxfreq_set_freq_limit(unsigned long freq_limit) +{ +	freq_limit = sgxfreq_get_freq_ceil(freq_limit); + +	mutex_lock(&sfd.freq_mutex); + +	sfd.freq_limit = freq_limit; +	__set_freq(); + +	mutex_unlock(&sfd.freq_mutex); + +	return freq_limit; +} + +unsigned long sgxfreq_get_total_active_time(void) +{ +	__update_timing_info(sfd.sgx_data.active); +	return sfd.total_active_time; +} + +unsigned long sgxfreq_get_total_idle_time(void) +{ +	__update_timing_info(sfd.sgx_data.active); +	return sfd.total_idle_time; +} + +/* + * sgx_clk_on, sgx_clk_off, sgx_active, and sgx_idle notifications are + * serialized by power lock. governor notif calls need sync with governor + * setting. + */ +void sgxfreq_notif_sgx_clk_on(void) +{ +	sfd.sgx_data.clk_on = true; + +	mutex_lock(&sfd.gov_mutex); + +	if (sfd.gov && sfd.gov->sgx_clk_on) +		sfd.gov->sgx_clk_on(); + +	mutex_unlock(&sfd.gov_mutex); +} + +void sgxfreq_notif_sgx_clk_off(void) +{ +	sfd.sgx_data.clk_on = false; + +	mutex_lock(&sfd.gov_mutex); + +	if (sfd.gov && sfd.gov->sgx_clk_off) +		sfd.gov->sgx_clk_off(); + +	mutex_unlock(&sfd.gov_mutex); +} + + +void sgxfreq_notif_sgx_active(void) +{ +	__update_timing_info(true); + +	sfd.sgx_data.active = true; + +	mutex_lock(&sfd.gov_mutex); + +	if (sfd.gov && sfd.gov->sgx_active) +		sfd.gov->sgx_active(); + +	mutex_unlock(&sfd.gov_mutex); + +} + +void sgxfreq_notif_sgx_idle(void) +{ + +	__update_timing_info(false); + +	sfd.sgx_data.active = false; + +	mutex_lock(&sfd.gov_mutex); + +	if (sfd.gov && sfd.gov->sgx_idle) +		sfd.gov->sgx_idle(); + +	mutex_unlock(&sfd.gov_mutex); +} + +void sgxfreq_notif_sgx_frame_done(void) +{ +	mutex_lock(&sfd.gov_mutex); + +	if (sfd.gov && sfd.gov->sgx_frame_done) +		sfd.gov->sgx_frame_done(); + +	mutex_unlock(&sfd.gov_mutex); +} diff --git a/drivers/gpu/pvr/services4/system/omap3630/sgxfreq.h b/drivers/gpu/pvr/services4/system/omap3630/sgxfreq.h new file mode 100644 index 00000000000..ff6fc88d4a6 --- /dev/null +++ b/drivers/gpu/pvr/services4/system/omap3630/sgxfreq.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2012 Texas Instruments, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef SGXFREQ_H +#define SGXFREQ_H + +#include <linux/device.h> +#include <linux/time.h> + +#define SGXFREQ_NAME_LEN 16 + +//#define SGXFREQ_DEBUG_FTRACE +#if defined(SGXFREQ_DEBUG_FTRACE) +#define SGXFREQ_TRACE(...) trace_printk(__VA_ARGS__) +#else +#define SGXFREQ_TRACE(...) +#endif + +struct sgxfreq_sgx_data { +	bool clk_on; +	bool active; +}; + +struct sgxfreq_governor { +	char name[SGXFREQ_NAME_LEN]; +	int (*gov_start) (struct sgxfreq_sgx_data *data); +	void (*gov_stop) (void); +	void (*sgx_clk_on) (void); +	void (*sgx_clk_off) (void); +	void (*sgx_active) (void); +	void (*sgx_idle) (void); +	void (*sgx_frame_done) (void); +	struct list_head governor_list; +}; + +/* sgxfreq_init must be called before any other api */ +int sgxfreq_init(struct device *dev); +int sgxfreq_deinit(void); + +int sgxfreq_register_governor(struct sgxfreq_governor *governor); +void sgxfreq_unregister_governor(struct sgxfreq_governor *governor); + +int sgxfreq_set_governor(const char *name); + +int sgxfreq_get_freq_list(unsigned long **pfreq_list); + +unsigned long sgxfreq_get_freq_min(void); +unsigned long sgxfreq_get_freq_max(void); + +unsigned long sgxfreq_get_freq_floor(unsigned long freq); +unsigned long sgxfreq_get_freq_ceil(unsigned long freq); + +unsigned long sgxfreq_get_freq(void); +unsigned long sgxfreq_get_freq_request(void); +unsigned long sgxfreq_get_freq_limit(void); + +unsigned long sgxfreq_set_freq_request(unsigned long freq_request); +unsigned long sgxfreq_set_freq_limit(unsigned long freq_limit); + +unsigned long sgxfreq_get_total_active_time(void); +unsigned long sgxfreq_get_total_idle_time(void); + +/* Helper functions */ +static inline unsigned long __tv2msec(struct timeval tv) +{ +	return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); +} + +static inline unsigned long __delta32(unsigned long a, unsigned long b) +{ +	if (a >= b) +		return a - b; +	else +		return 1 + (0xFFFFFFFF - b) + a; +} + +/* External notifications to sgxfreq */ +void sgxfreq_notif_sgx_clk_on(void); +void sgxfreq_notif_sgx_clk_off(void); +void sgxfreq_notif_sgx_active(void); +void sgxfreq_notif_sgx_idle(void); +void sgxfreq_notif_sgx_frame_done(void); + +#endif diff --git a/drivers/gpu/pvr/services4/system/omap3630/sgxfreq_activeidle.c b/drivers/gpu/pvr/services4/system/omap3630/sgxfreq_activeidle.c new file mode 100644 index 00000000000..45159d7269b --- /dev/null +++ b/drivers/gpu/pvr/services4/system/omap3630/sgxfreq_activeidle.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2012 Texas Instruments, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/sysfs.h> +#include "sgxfreq.h" + +static int activeidle_start(struct sgxfreq_sgx_data *data); +static void activeidle_stop(void); +static void activeidle_sgx_active(void); +static void activeidle_sgx_idle(void); + +static struct activeidle_data { +	unsigned long freq_active; +	unsigned long freq_idle; +	struct mutex mutex; +	bool sgx_active; +} aid; + +static struct sgxfreq_governor activeidle_gov = { +	.name =	"activeidle", +	.gov_start = activeidle_start, +	.gov_stop = activeidle_stop, +	.sgx_active = activeidle_sgx_active, +	.sgx_idle = activeidle_sgx_idle, +}; + +/*********************** begin sysfs interface ***********************/ + +extern struct kobject *sgxfreq_kobj; + +static ssize_t show_freq_active(struct device *dev, +				struct device_attribute *attr, +				char *buf) +{ +	return sprintf(buf, "%lu\n", aid.freq_active); +} + +static ssize_t store_freq_active(struct device *dev, +				 struct device_attribute *attr, +				 const char *buf, size_t count) +{ +	int ret; +	unsigned long freq; + +	ret = sscanf(buf, "%lu", &freq); +	if (ret != 1) +		return -EINVAL; + +	freq = sgxfreq_get_freq_ceil(freq); + +	mutex_lock(&aid.mutex); + +	aid.freq_active = freq; +	if (aid.sgx_active) +		sgxfreq_set_freq_request(aid.freq_active); + +	mutex_unlock(&aid.mutex); + +	return count; +} + +static ssize_t show_freq_idle(struct device *dev, struct device_attribute *attr, +			      char *buf) +{ +	return sprintf(buf, "%lu\n", aid.freq_idle); +} + +static ssize_t store_freq_idle(struct device *dev, struct device_attribute *attr, +			       const char *buf, size_t count) +{ +	int ret; +	unsigned long freq; + +	ret = sscanf(buf, "%lu", &freq); +	if (ret != 1) +		return -EINVAL; + +	freq = sgxfreq_get_freq_floor(freq); + +	mutex_lock(&aid.mutex); + +	aid.freq_idle = freq; +	if (!aid.sgx_active) +		sgxfreq_set_freq_request(aid.freq_idle); + +	mutex_unlock(&aid.mutex); + +	return count; +} +static DEVICE_ATTR(freq_active, 0644, show_freq_active, store_freq_active); +static DEVICE_ATTR(freq_idle, 0644, show_freq_idle, store_freq_idle); + +static struct attribute *activeidle_attributes[] = { +	&dev_attr_freq_active.attr, +	&dev_attr_freq_idle.attr, +	NULL +}; + +static struct attribute_group activeidle_attr_group = { +	.attrs = activeidle_attributes, +	.name = "activeidle", +}; + +/************************ end sysfs interface ************************/ + +int activeidle_init(void) +{ +	int ret; + +	mutex_init(&aid.mutex); + +	ret = sgxfreq_register_governor(&activeidle_gov); +	if (ret) +		return ret; + +	aid.freq_idle = sgxfreq_get_freq_min(); +	aid.freq_active = sgxfreq_get_freq_max(); + +	return 0; +} + +int activeidle_deinit(void) +{ +	return 0; +} + +static int activeidle_start(struct sgxfreq_sgx_data *data) +{ +	int ret; + +	aid.sgx_active = data->active; + +	ret = sysfs_create_group(sgxfreq_kobj, &activeidle_attr_group); +	if (ret) +		return ret; + +	if (aid.sgx_active) +		sgxfreq_set_freq_request(aid.freq_active); +	else +		sgxfreq_set_freq_request(aid.freq_idle); + +	return 0; +} + +static void activeidle_stop(void) +{ +	sysfs_remove_group(sgxfreq_kobj, &activeidle_attr_group); +} + +static void activeidle_sgx_active(void) +{ +	mutex_lock(&aid.mutex); + +	aid.sgx_active = true; +	sgxfreq_set_freq_request(aid.freq_active); + +	mutex_unlock(&aid.mutex); +} + +static void activeidle_sgx_idle(void) +{ +	mutex_lock(&aid.mutex); + +	aid.sgx_active = false; +	sgxfreq_set_freq_request(aid.freq_idle); + +	mutex_unlock(&aid.mutex); +} diff --git a/drivers/gpu/pvr/services4/system/omap3630/sgxfreq_cool.c b/drivers/gpu/pvr/services4/system/omap3630/sgxfreq_cool.c new file mode 100644 index 00000000000..9233defd352 --- /dev/null +++ b/drivers/gpu/pvr/services4/system/omap3630/sgxfreq_cool.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2012 Texas Instruments, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/thermal_framework.h> + +static int cool_device(struct thermal_dev *dev, int cooling_level); + +static struct cool_data { +	int freq_cnt; +	unsigned long *freq_list; +} cd; + +static struct thermal_dev_ops cool_dev_ops = { +	.cool_device = cool_device, +}; + +static struct thermal_dev cool_dev = { +	.name = "gpu_cooling.0", +	.domain_name = "gpu", +	.dev_ops = &cool_dev_ops, +}; + +static struct thermal_dev case_cool_dev = { +	.name = "gpu_cooling.1", +	.domain_name = "case", +	.dev_ops = &cool_dev_ops, +}; + +static unsigned int gpu_cooling_level; +#if defined(CONFIG_CASE_TEMP_GOVERNOR) +static unsigned int case_cooling_level; +#endif + +int cool_init(void) +{ +	int ret; +	cd.freq_cnt = sgxfreq_get_freq_list(&cd.freq_list); +	if (!cd.freq_cnt || !cd.freq_list) +		return -EINVAL; + +	ret = thermal_cooling_dev_register(&cool_dev); +	if (ret) +		return ret; + +	return thermal_cooling_dev_register(&case_cool_dev); +} + +void cool_deinit(void) +{ +	thermal_cooling_dev_unregister(&cool_dev); +	thermal_cooling_dev_unregister(&case_cool_dev); +} + +static int cool_device(struct thermal_dev *dev, int cooling_level) +{ +	int freq_max_index, freq_limit_index; + +#if defined(CONFIG_CASE_TEMP_GOVERNOR) +	if (!strcmp(dev->domain_name, "case")) +	{ +		int tmp = 0; +		tmp = cooling_level - case_subzone_number; +		if (tmp < 0) +			tmp = 0; +		case_cooling_level = tmp; +	} +	else +#endif +	{ +               gpu_cooling_level = cooling_level; +	} + +	freq_max_index = cd.freq_cnt - 1; +#if defined(CONFIG_CASE_TEMP_GOVERNOR) +	if (case_cooling_level > gpu_cooling_level) +	{ +		freq_limit_index = freq_max_index - case_cooling_level; +	} +	else +#endif +	{ +		freq_limit_index = freq_max_index - gpu_cooling_level; +	} + +	if (freq_limit_index < 0) +		freq_limit_index = 0; + +	sgxfreq_set_freq_limit(cd.freq_list[freq_limit_index]); + +	return 0; +} diff --git a/drivers/gpu/pvr/services4/system/omap3630/sgxfreq_on3demand.c b/drivers/gpu/pvr/services4/system/omap3630/sgxfreq_on3demand.c new file mode 100644 index 00000000000..c4e4bd911f8 --- /dev/null +++ b/drivers/gpu/pvr/services4/system/omap3630/sgxfreq_on3demand.c @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2012 Texas Instruments, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/sysfs.h> +#include <linux/vmalloc.h> +#include <asm/io.h> +#include "sgxfreq.h" + +static int on3demand_start(struct sgxfreq_sgx_data *data); +static void on3demand_stop(void); +static void on3demand_predict(void); +static void on3demand_frame_done(void); +static void on3demand_active(void); +static void on3demand_timeout(struct work_struct *work); + + +static struct sgxfreq_governor on3demand_gov = { +	.name =	"on3demand", +	.gov_start = on3demand_start, +	.gov_stop = on3demand_stop, +	.sgx_frame_done = on3demand_frame_done, +	.sgx_active = on3demand_active, +}; + +static struct on3demand_data { +	unsigned int load; +	unsigned int up_threshold; +	unsigned int down_threshold; +	unsigned int history_size; +	unsigned long prev_total_idle; +	unsigned long prev_total_active; +	unsigned int low_load_cnt; +	unsigned int poll_interval; +	unsigned long delta_active; +	unsigned long delta_idle; +	bool polling_enabled; +	struct delayed_work work; +	struct mutex mutex; +} odd; + +#define ON3DEMAND_DEFAULT_UP_THRESHOLD			80 +#define ON3DEMAND_DEFAULT_DOWN_THRESHOLD		30 +#define ON3DEMAND_DEFAULT_HISTORY_SIZE_THRESHOLD	5 +/* For Live wallpaper frame done at interval of ~64ms */ +#define ON3DEMAND_DEFAULT_POLL_INTERVAL			75 + +/*FIXME: This should be dynamic and queried from platform */ +#define ON3DEMAND_FRAME_DONE_DEADLINE_MS 16 + + +/*********************** begin sysfs interface ***********************/ + +extern struct kobject *sgxfreq_kobj; + +static ssize_t show_down_threshold(struct device *dev, +	struct device_attribute *attr, char *buf) +{ +	return sprintf(buf, "%u\n", odd.down_threshold); +} + +static ssize_t store_down_threshold(struct device *dev, +	struct device_attribute *attr, const char *buf, size_t count) +{ +	int ret; +	unsigned int thres; + +	ret = sscanf(buf, "%u", &thres); +	if (ret != 1) +		return -EINVAL; + +	mutex_lock(&odd.mutex); + +	if (thres <= 100) { +		odd.down_threshold = thres; +		odd.low_load_cnt = 0; +	} else { +		return -EINVAL; +	} + +	mutex_unlock(&odd.mutex); + +	return count; +} + +static ssize_t show_up_threshold(struct device *dev, +	struct device_attribute *attr, char *buf) +{ +	return sprintf(buf, "%u\n", odd.up_threshold); +} + +static ssize_t store_up_threshold(struct device *dev, +	struct device_attribute *attr, const char *buf, size_t count) +{ +	int ret; +	unsigned int thres; + +	ret = sscanf(buf, "%u", &thres); +	if (ret != 1) +		return -EINVAL; + +	mutex_lock(&odd.mutex); + +	if (thres <= 100) { +		odd.up_threshold = thres; +		odd.low_load_cnt = 0; +	} else { +		return -EINVAL; +	} + +	mutex_unlock(&odd.mutex); + +	return count; +} + +static ssize_t show_history_size(struct device *dev, +	struct device_attribute *attr, char *buf) +{ +	return sprintf(buf, "%u\n", odd.history_size); +} + +static ssize_t store_history_size(struct device *dev, +	struct device_attribute *attr, const char *buf, size_t count) +{ +	int ret; +	unsigned int size; + +	ret = sscanf(buf, "%u", &size); +	if (ret != 1) +		return -EINVAL; + +	mutex_lock(&odd.mutex); + +	if (size >= 1) { +		odd.history_size = size; +		odd.low_load_cnt = 0; +	} else { +		return -EINVAL; +	} + +	mutex_unlock(&odd.mutex); + +	return count; +} + +static ssize_t show_load(struct device *dev, +	struct device_attribute *attr, char *buf) +{ +	return sprintf(buf, "%u\n", odd.load); +} + +static DEVICE_ATTR(down_threshold, 0644, +	show_down_threshold, store_down_threshold); +static DEVICE_ATTR(up_threshold, 0644, +	show_up_threshold, store_up_threshold); +static DEVICE_ATTR(history_size, 0644, +	show_history_size, store_history_size); +static DEVICE_ATTR(load, 0444, +	show_load, NULL); + +static struct attribute *on3demand_attributes[] = { +	&dev_attr_down_threshold.attr, +	&dev_attr_up_threshold.attr, +	&dev_attr_history_size.attr, +	&dev_attr_load.attr, +	NULL +}; + +static struct attribute_group on3demand_attr_group = { +	.attrs = on3demand_attributes, +	.name = "on3demand", +}; +/************************ end sysfs interface ************************/ + +int on3demand_init(void) +{ +	int ret; + +	mutex_init(&odd.mutex); + +	ret = sgxfreq_register_governor(&on3demand_gov); +	if (ret) +		return ret; + +	return 0; +} + +int on3demand_deinit(void) +{ +	return 0; +} + +static int on3demand_start(struct sgxfreq_sgx_data *data) +{ +	int ret; + +	odd.load = 0; +	odd.up_threshold = ON3DEMAND_DEFAULT_UP_THRESHOLD; +	odd.down_threshold = ON3DEMAND_DEFAULT_DOWN_THRESHOLD; +	odd.history_size = ON3DEMAND_DEFAULT_HISTORY_SIZE_THRESHOLD; +	odd.prev_total_active = 0; +	odd.prev_total_idle = 0; +	odd.low_load_cnt = 0; +	odd.poll_interval = ON3DEMAND_DEFAULT_POLL_INTERVAL; +	odd.polling_enabled = false; + +	INIT_DELAYED_WORK(&odd.work, on3demand_timeout); + +	ret = sysfs_create_group(sgxfreq_kobj, &on3demand_attr_group); +	if (ret) +		return ret; + +	return 0; +} + +static void on3demand_stop(void) +{ +	cancel_delayed_work_sync(&odd.work); +	sysfs_remove_group(sgxfreq_kobj, &on3demand_attr_group); +} + +static void on3demand_predict(void) +{ +	static unsigned short first_sample = 1; +	unsigned long total_active, total_idle; +	unsigned long freq; + +	if (first_sample == 1) { +		first_sample = 0; +		odd.prev_total_active = sgxfreq_get_total_active_time(); +		odd.prev_total_idle = sgxfreq_get_total_idle_time(); +		return; +	} + +	/* Sample new active and idle times */ +	total_active = sgxfreq_get_total_active_time(); +	total_idle = sgxfreq_get_total_idle_time(); + +	/* Compute load */ +	odd.delta_active = __delta32(total_active, odd.prev_total_active); +	odd.delta_idle = __delta32(total_idle, odd.prev_total_idle); + +	/* +	 * If SGX was active for longer than frame display time (1/fps), +	 * scale to highest possible frequency. +	 */ +	if (odd.delta_active > ON3DEMAND_FRAME_DONE_DEADLINE_MS) { +		odd.low_load_cnt = 0; +		sgxfreq_set_freq_request(sgxfreq_get_freq_max()); +	} + +	if ((odd.delta_active + odd.delta_idle)) +		odd.load = (100 * odd.delta_active / (odd.delta_active + odd.delta_idle)); + +	odd.prev_total_active = total_active; +	odd.prev_total_idle = total_idle; + +	/* Scale GPU frequency on purpose */ +	if (odd.load >= odd.up_threshold) { +		odd.low_load_cnt = 0; +		sgxfreq_set_freq_request(sgxfreq_get_freq_max()); +	} else if (odd.load <= odd.down_threshold) { +		if (odd.low_load_cnt == odd.history_size) { +			/* Convert load to frequency */ +			freq = (sgxfreq_get_freq() * odd.load) / 100; +			sgxfreq_set_freq_request(freq); +			odd.low_load_cnt = 0; +		} else { +			odd.low_load_cnt++; +		} +	} else { +		odd.low_load_cnt = 0; +	} +} + + +static void on3demand_active(void) +{ +	if (!odd.polling_enabled) { +		sgxfreq_set_freq_request(sgxfreq_get_freq_max()); +		odd.low_load_cnt = 0; +		odd.polling_enabled = true; +		schedule_delayed_work(&odd.work, odd.poll_interval * HZ/1000); +	} + +} + +static void on3demand_frame_done(void) +{ +	if (odd.polling_enabled) { +		cancel_delayed_work_sync(&odd.work); +		schedule_delayed_work(&odd.work, odd.poll_interval * HZ/1000); +	} +	on3demand_predict(); +} + +static void on3demand_timeout(struct work_struct *work) +{ +	/* +	 * If sgx was idle all throughout timer disable polling and +	 * enable it on next sgx active event +	 */ +	if (!odd.delta_active) { +		sgxfreq_set_freq_request(sgxfreq_get_freq_min()); +		odd.low_load_cnt = 0; +		odd.polling_enabled = false; +	} else { +		on3demand_predict(); +		odd.polling_enabled = true; +		schedule_delayed_work(&odd.work, odd.poll_interval * HZ/1000); +	} +} diff --git a/drivers/gpu/pvr/services4/system/omap3630/sgxfreq_onoff.c b/drivers/gpu/pvr/services4/system/omap3630/sgxfreq_onoff.c new file mode 100644 index 00000000000..39dd3fc5c42 --- /dev/null +++ b/drivers/gpu/pvr/services4/system/omap3630/sgxfreq_onoff.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2012 Texas Instruments, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/sysfs.h> +#include "sgxfreq.h" + +static int onoff_start(struct sgxfreq_sgx_data *data); +static void onoff_stop(void); +static void onoff_sgx_clk_on(void); +static void onoff_sgx_clk_off(void); + +static struct onoff_data { +	unsigned long freq_off; +	unsigned long freq_on; +	struct mutex mutex; +	bool sgx_clk_on; +} ood; + +static struct sgxfreq_governor onoff_gov = { +	.name =	"onoff", +	.gov_start = onoff_start, +	.gov_stop = onoff_stop, +	.sgx_clk_on = onoff_sgx_clk_on, +	.sgx_clk_off = onoff_sgx_clk_off, +}; + +/*********************** begin sysfs interface ***********************/ + +extern struct kobject *sgxfreq_kobj; + +static ssize_t show_freq_on(struct device *dev, struct device_attribute *attr, +			    char *buf) +{ +	return sprintf(buf, "%lu\n", ood.freq_on); +} + +static ssize_t store_freq_on(struct device *dev, struct device_attribute *attr, +			     const char *buf, size_t count) +{ +	int ret; +	unsigned long freq; + +	ret = sscanf(buf, "%lu", &freq); +	if (ret != 1) +		return -EINVAL; + +	freq = sgxfreq_get_freq_ceil(freq); + +	mutex_lock(&ood.mutex); + +	ood.freq_on = freq; +	if (ood.sgx_clk_on) +		sgxfreq_set_freq_request(ood.freq_on); + +	mutex_unlock(&ood.mutex); + +	return count; +} + +static ssize_t show_freq_off(struct device *dev, struct device_attribute *attr, +			     char *buf) +{ +	return sprintf(buf, "%lu\n", ood.freq_off); +} + +static ssize_t store_freq_off(struct device *dev, struct device_attribute *attr, +			      const char *buf, size_t count) +{ +	int ret; +	unsigned long freq; + +	ret = sscanf(buf, "%lu", &freq); +	if (ret != 1) +		return -EINVAL; + +	freq = sgxfreq_get_freq_floor(freq); + +	mutex_lock(&ood.mutex); + +	ood.freq_off = freq; +	if (!ood.sgx_clk_on) +		sgxfreq_set_freq_request(ood.freq_off); + +	mutex_unlock(&ood.mutex); + +	return count; +} +static DEVICE_ATTR(freq_on, 0644, show_freq_on, store_freq_on); +static DEVICE_ATTR(freq_off, 0644, show_freq_off, store_freq_off); + +static struct attribute *onoff_attributes[] = { +	&dev_attr_freq_on.attr, +	&dev_attr_freq_off.attr, +	NULL +}; + +static struct attribute_group onoff_attr_group = { +	.attrs = onoff_attributes, +	.name = "onoff", +}; + +/************************ end sysfs interface ************************/ + +int onoff_init(void) +{ +	int ret; + +	mutex_init(&ood.mutex); + +	ret = sgxfreq_register_governor(&onoff_gov); +	if (ret) +		return ret; + +	ood.freq_off = sgxfreq_get_freq_min(); +	ood.freq_on = sgxfreq_get_freq_max(); + +	return 0; +} + +int onoff_deinit(void) +{ +	return 0; +} + +static int onoff_start(struct sgxfreq_sgx_data *data) +{ +	int ret; + +	ood.sgx_clk_on = data->clk_on; + +	ret = sysfs_create_group(sgxfreq_kobj, &onoff_attr_group); +	if (ret) +		return ret; + +	if (ood.sgx_clk_on) +		sgxfreq_set_freq_request(ood.freq_on); +	else +		sgxfreq_set_freq_request(ood.freq_off); + +	return 0; +} + +static void onoff_stop(void) +{ +	sysfs_remove_group(sgxfreq_kobj, &onoff_attr_group); +} + +static void onoff_sgx_clk_on(void) +{ +	mutex_lock(&ood.mutex); + +	ood.sgx_clk_on = true; +	sgxfreq_set_freq_request(ood.freq_on); + +	mutex_unlock(&ood.mutex); +} + +static void onoff_sgx_clk_off(void) +{ +	mutex_lock(&ood.mutex); + +	ood.sgx_clk_on = false; +	sgxfreq_set_freq_request(ood.freq_off); + +	mutex_unlock(&ood.mutex); +} + diff --git a/drivers/gpu/pvr/services4/system/omap3630/sgxfreq_userspace.c b/drivers/gpu/pvr/services4/system/omap3630/sgxfreq_userspace.c new file mode 100644 index 00000000000..5ff0dd07d8a --- /dev/null +++ b/drivers/gpu/pvr/services4/system/omap3630/sgxfreq_userspace.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2012 Texas Instruments, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/sysfs.h> +#include "sgxfreq.h" + + +static int userspace_start(struct sgxfreq_sgx_data *data); +static void userspace_stop(void); +static void userspace_sgx_clk_on(void); +static void userspace_sgx_clk_off(void); +static void userspace_sgx_active(void); +static void userspace_sgx_idle(void); + + +static struct sgxfreq_governor userspace_gov = { +	.name =	"userspace", +	.gov_start = userspace_start, +	.gov_stop = userspace_stop, +	.sgx_clk_on = userspace_sgx_clk_on, +	.sgx_clk_off = userspace_sgx_clk_off, +	.sgx_active = userspace_sgx_active, +	.sgx_idle = userspace_sgx_idle, +}; + + +static struct userspace_data { +	unsigned long freq_user; /* in KHz */ +	struct mutex mutex; +} usd; + + +/*********************** begin sysfs interface ***********************/ + +extern struct kobject *sgxfreq_kobj; + + +static ssize_t show_frequency_set(struct device *dev, struct device_attribute *attr, +			    char *buf) +{ +	return sprintf(buf, "%lu\n", usd.freq_user); +} + + +static ssize_t store_frequency_set(struct device *dev, +	struct device_attribute *attr, const char *buf, size_t count) +{ +	int ret; +	unsigned long freq; + +	ret = sscanf(buf, "%lu", &freq); +	if (ret != 1) +		return -EINVAL; + +	mutex_lock(&odd.mutex); + +	if (freq > sgxfreq_get_freq_max()) +		freq = sgxfreq_get_freq_max(); +	usd.freq_user = sgxfreq_set_freq_request(freq); +	trace_printk("USERSPACE: new freq=%luHz.\n", usd.freq_user); + +	mutex_unlock(&odd.mutex); + +	return count; +} + + +static DEVICE_ATTR(frequency_set, 0644, +	show_frequency_set, store_frequency_set); + + +static struct attribute *userspace_attributes[] = { +	&dev_attr_frequency_set.attr, +	NULL +}; + + +static struct attribute_group userspace_attr_group = { +	.attrs = userspace_attributes, +	.name = "userspace", +}; + +/************************ end sysfs interface ************************/ + + +int userspace_init(void) +{ +	int ret; + +	mutex_init(&odd.mutex); + +	ret = sgxfreq_register_governor(&userspace_gov); +	if (ret) +		return ret; +	return 0; +} + + +int userspace_deinit(void) +{ +	return 0; +} + + +static int userspace_start(struct sgxfreq_sgx_data *data) +{ +	int ret; + +	usd.freq_user = sgxfreq_get_freq(); + +	ret = sysfs_create_group(sgxfreq_kobj, &userspace_attr_group); +	if (ret) +		return ret; + +	trace_printk("USERSPACE: started.\n"); + +	return 0; +} + + +static void userspace_stop(void) +{ +	usd.freq_user = sgxfreq_set_freq_request(sgxfreq_get_freq_min()); +	sysfs_remove_group(sgxfreq_kobj, &userspace_attr_group); + +	trace_printk("USERSPACE: stopped.\n"); +} + + +static void userspace_sgx_clk_on(void) +{ +	mutex_lock(&ood.mutex); + +	sgxfreq_set_freq_request(usd.freq_user); + +	mutex_unlock(&ood.mutex); +} + + +static void userspace_sgx_clk_off(void) +{ +	mutex_lock(&ood.mutex); + +	sgxfreq_set_freq_request(sgxfreq_get_freq_min()); + +	mutex_unlock(&ood.mutex); +} + + +static void userspace_sgx_active(void) +{ +	mutex_lock(&aid.mutex); + +	sgxfreq_set_freq_request(usd.freq_user); + +	mutex_unlock(&aid.mutex); +} + + +static void userspace_sgx_idle(void) +{ +	mutex_lock(&aid.mutex); + +	sgxfreq_set_freq_request(sgxfreq_get_freq_min()); + +	mutex_unlock(&aid.mutex); +} diff --git a/drivers/gpu/pvr/services4/system/omap3630/sysconfig.c b/drivers/gpu/pvr/services4/system/omap3630/sysconfig.c new file mode 100644 index 00000000000..625da765d7c --- /dev/null +++ b/drivers/gpu/pvr/services4/system/omap3630/sysconfig.c @@ -0,0 +1,1329 @@ +/*************************************************************************/ /*! +@Title          System Configuration +@Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description    System Configuration functions +@License        Dual MIT/GPLv2 + +The contents of this file are subject to the MIT license as set out below. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Alternatively, the contents of this file may be used under the terms of +the GNU General Public License Version 2 ("GPL") in which case the provisions +of GPL are applicable instead of those above. + +If you wish to allow use of your version of this file only under the terms of +GPL, and not to allow others to use your version of this file under the terms +of the MIT license, indicate your decision by deleting the provisions above +and replace them with the notice and other provisions required by GPL as set +out in the file called "GPL-COPYING" included in this distribution. If you do +not delete the provisions above, a recipient may use your version of this file +under the terms of either the MIT license or GPL. + +This License is also included in this distribution in the file called +"MIT-COPYING". + +EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS +PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ /**************************************************************************/ + +#include "sysconfig.h" +#include "services_headers.h" +#include "kerneldisplay.h" +#include "oemfuncs.h" +#include "sgxinfo.h" +#include "sgxinfokm.h" +#include "syslocal.h" + +#include "ocpdefs.h" + +#define OMAP5430_CORE_REV	0x10005 + +/* top level system data anchor point*/ +SYS_DATA* gpsSysData = (SYS_DATA*)IMG_NULL; +SYS_DATA  gsSysData; + +static SYS_SPECIFIC_DATA gsSysSpecificData; +SYS_SPECIFIC_DATA *gpsSysSpecificData; + +/* SGX structures */ +static IMG_UINT32			gui32SGXDeviceID; +static SGX_DEVICE_MAP		gsSGXDeviceMap; +static PVRSRV_DEVICE_NODE	*gpsSGXDevNode; + + +#if defined(NO_HARDWARE) || defined(SGX_OCP_REGS_ENABLED) +static IMG_CPU_VIRTADDR gsSGXRegsCPUVAddr; +#endif + +#if defined(PVR_LINUX_DYNAMIC_SGX_RESOURCE_INFO) +extern struct platform_device *gpsPVRLDMDev; +#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(SGX_OCP_REGS_ENABLED) + +static IMG_CPU_VIRTADDR gpvOCPRegsLinAddr; + +static PVRSRV_ERROR EnableSGXClocksWrap(SYS_DATA *psSysData) +{ +	PVRSRV_ERROR eError = EnableSGXClocks(psSysData); + +#if !defined(SGX_OCP_NO_INT_BYPASS) +	if(eError == PVRSRV_OK) +	{ +		OSWriteHWReg(gpvOCPRegsLinAddr, EUR_CR_OCP_SYSCONFIG, 0x14); +		OSWriteHWReg(gpvOCPRegsLinAddr, EUR_CR_OCP_DEBUG_CONFIG, EUR_CR_OCP_DEBUG_CONFIG_THALIA_INT_BYPASS_MASK); +	} +#endif +	return eError; +} + +#else /* defined(SGX_OCP_REGS_ENABLED) */ + +static INLINE PVRSRV_ERROR EnableSGXClocksWrap(SYS_DATA *psSysData) +{ +	return EnableSGXClocks(psSysData); +} + +#endif /* defined(SGX_OCP_REGS_ENABLED) */ + +static INLINE PVRSRV_ERROR EnableSystemClocksWrap(SYS_DATA *psSysData) +{ +	PVRSRV_ERROR eError = EnableSystemClocks(psSysData); + +#if !defined(SUPPORT_ACTIVE_POWER_MANAGEMENT) +	if(eError == PVRSRV_OK) +	{ +		/* +		 * The SGX Clocks are enabled separately if active power +		 * management is enabled. +		 */ +		eError = EnableSGXClocksWrap(psSysData); +		if (eError != PVRSRV_OK) +		{ +			DisableSystemClocks(psSysData); +		} +	} +#endif + +	return eError; +} + +/*! +****************************************************************************** + + @Function	SysLocateDevices + + @Description	Specifies devices in the systems memory map + + @Input		psSysData - sys data + + @Return	PVRSRV_ERROR + +******************************************************************************/ +static PVRSRV_ERROR SysLocateDevices(SYS_DATA *psSysData) +{ +#if defined(NO_HARDWARE) +	PVRSRV_ERROR eError; +	IMG_CPU_PHYADDR sCpuPAddr; +#else +#if defined(PVR_LINUX_DYNAMIC_SGX_RESOURCE_INFO) +	struct resource *dev_res; +	int dev_irq; +#endif +#endif + +	PVR_UNREFERENCED_PARAMETER(psSysData); + +	/* SGX Device: */ +	gsSGXDeviceMap.ui32Flags = 0x0; +	 +#if defined(NO_HARDWARE) +	/*  +	 * For no hardware, allocate some contiguous memory for the +	 * register block. +	 */ + +	/* Registers */ +	gsSGXDeviceMap.ui32RegsSize = SYS_OMAP3630_SGX_REGS_SIZE; + +	eError = OSBaseAllocContigMemory(gsSGXDeviceMap.ui32RegsSize, +									 &gsSGXRegsCPUVAddr, +									 &sCpuPAddr); +	if(eError != PVRSRV_OK) +	{ +		return eError; +	} +	gsSGXDeviceMap.sRegsCpuPBase = sCpuPAddr; +	gsSGXDeviceMap.sRegsSysPBase = SysCpuPAddrToSysPAddr(gsSGXDeviceMap.sRegsCpuPBase); +#if defined(__linux__) +	/* Indicate the registers are already mapped */ +	gsSGXDeviceMap.pvRegsCpuVBase = gsSGXRegsCPUVAddr; +#else +	/* +	 * FIXME: Could we just use the virtual address returned by +	 * OSBaseAllocContigMemory? +	 */ +	gsSGXDeviceMap.pvRegsCpuVBase = IMG_NULL; +#endif + +	OSMemSet(gsSGXRegsCPUVAddr, 0, gsSGXDeviceMap.ui32RegsSize); + +	/* +		device interrupt IRQ +		Note: no interrupts available on no hardware system +	*/ +	gsSGXDeviceMap.ui32IRQ = 0; + +#else /* defined(NO_HARDWARE) */ +#if defined(PVR_LINUX_DYNAMIC_SGX_RESOURCE_INFO) +	/* get the resource and IRQ through platform resource API */ +	dev_res = platform_get_resource(gpsPVRLDMDev, IORESOURCE_MEM, 0); +	if (dev_res == NULL) +	{ +		PVR_DPF((PVR_DBG_ERROR, "%s: platform_get_resource failed", __FUNCTION__)); +		return PVRSRV_ERROR_INVALID_DEVICE; +	} + +	dev_irq = platform_get_irq(gpsPVRLDMDev, 0); +	if (dev_irq < 0) +	{ +		PVR_DPF((PVR_DBG_ERROR, "%s: platform_get_irq failed (%d)", __FUNCTION__, -dev_irq)); +		return PVRSRV_ERROR_INVALID_DEVICE; +	} +	 +	gsSGXDeviceMap.sRegsSysPBase.uiAddr = dev_res->start; +	gsSGXDeviceMap.sRegsCpuPBase = +		SysSysPAddrToCpuPAddr(gsSGXDeviceMap.sRegsSysPBase); +	PVR_TRACE(("SGX register base: 0x%lx", (unsigned long)gsSGXDeviceMap.sRegsCpuPBase.uiAddr)); + +#if defined(SGX544) && defined(SGX_FEATURE_MP) +	/* Workaround: Due to the change in the HWMOD, the driver is only detecting the +	   size of the first memory section. For the moment, set the size with a macro +	   until a better solution found						*/ +	gsSGXDeviceMap.ui32RegsSize = SYS_OMAP3630_SGX_REGS_SIZE; +#else +	gsSGXDeviceMap.ui32RegsSize = (unsigned int)(dev_res->end - dev_res->start); +#endif + +	PVR_TRACE(("SGX register size: %d",gsSGXDeviceMap.ui32RegsSize)); + +	gsSGXDeviceMap.ui32IRQ = dev_irq; +	PVR_TRACE(("SGX IRQ: %d", gsSGXDeviceMap.ui32IRQ)); +#else	/* defined(PVR_LINUX_DYNAMIC_SGX_RESOURCE_INFO) */ +	gsSGXDeviceMap.sRegsSysPBase.uiAddr = SYS_OMAP3630_SGX_REGS_SYS_PHYS_BASE; +	gsSGXDeviceMap.sRegsCpuPBase = SysSysPAddrToCpuPAddr(gsSGXDeviceMap.sRegsSysPBase); +	gsSGXDeviceMap.ui32RegsSize = SYS_OMAP3630_SGX_REGS_SIZE; + +	gsSGXDeviceMap.ui32IRQ = SYS_OMAP3630_SGX_IRQ; + +#endif	/* defined(PVR_LINUX_DYNAMIC_SGX_RESOURCE_INFO) */ +#if defined(SGX_OCP_REGS_ENABLED) +	gsSGXRegsCPUVAddr = OSMapPhysToLin(gsSGXDeviceMap.sRegsCpuPBase, +	gsSGXDeviceMap.ui32RegsSize, +											 PVRSRV_HAP_UNCACHED|PVRSRV_HAP_KERNEL_ONLY, +											 IMG_NULL); + +	if (gsSGXRegsCPUVAddr == IMG_NULL) +	{ +		PVR_DPF((PVR_DBG_ERROR,"SysLocateDevices: Failed to map SGX registers")); +		return PVRSRV_ERROR_BAD_MAPPING; +	} + +	/* Indicate the registers are already mapped */ +	gsSGXDeviceMap.pvRegsCpuVBase = gsSGXRegsCPUVAddr; +	gpvOCPRegsLinAddr = gsSGXRegsCPUVAddr; +#endif +#endif /* defined(NO_HARDWARE) */ + +#if defined(PDUMP) +	{ +		/* initialise memory region name for pdumping */ +		static IMG_CHAR pszPDumpDevName[] = "SGXMEM"; +		gsSGXDeviceMap.pszPDumpDevName = pszPDumpDevName; +	} +#endif + +	/* add other devices here: */ + + +	return PVRSRV_OK; +} + + +/*! +****************************************************************************** + + @Function	SysCreateVersionString + + @Description Read the version string  + + @Return   IMG_CHAR *  : Version string + +******************************************************************************/ +static IMG_CHAR *SysCreateVersionString(void) +{ +	static IMG_CHAR aszVersionString[100]; +	SYS_DATA	*psSysData; +	IMG_UINT32	ui32SGXRevision; +	IMG_INT32	i32Count; +#if !defined(NO_HARDWARE) +	IMG_VOID	*pvRegsLinAddr; + +	pvRegsLinAddr = OSMapPhysToLin(gsSGXDeviceMap.sRegsCpuPBase, +								   gsSGXDeviceMap.ui32RegsSize, +								   PVRSRV_HAP_UNCACHED|PVRSRV_HAP_KERNEL_ONLY, +								   IMG_NULL); +	if(!pvRegsLinAddr) +	{ +		return IMG_NULL; +	} + +#if defined(SGX544) && defined(SGX_FEATURE_MP) +	ui32SGXRevision = OMAP5430_CORE_REV; +#else +	ui32SGXRevision = OSReadHWReg((IMG_PVOID)((IMG_PBYTE)pvRegsLinAddr), +			EUR_CR_CORE_REVISION); +#endif + +#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_OMAP3630_SGX_REGS_SIZE, +					 PVRSRV_HAP_UNCACHED|PVRSRV_HAP_KERNEL_ONLY, +					 IMG_NULL); +#endif + +	if(i32Count == -1) +	{ +		return IMG_NULL; +	} + +	return aszVersionString; +} + + +/*! +****************************************************************************** + + @Function	SysInitialise +  + @Description Initialises kernel services at 'driver load' time +  + @Return   PVRSRV_ERROR  :  + +******************************************************************************/ +PVRSRV_ERROR SysInitialise(IMG_VOID) +{ +	IMG_UINT32			i; +	PVRSRV_ERROR 		eError; +	PVRSRV_DEVICE_NODE	*psDeviceNode; +#if !defined(PVR_NO_OMAP_TIMER) +	IMG_CPU_PHYADDR		TimerRegPhysBase; +#endif +#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; + +	/* init device ID's */ +	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; +	} + +#if !defined(SGX_DYNAMIC_TIMING_INFO) +	/* Set up timing information*/ +	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 /* SUPPORT_ACTIVE_POWER_MANAGEMENT */ +	psTimingInfo->ui32ActivePowManLatencyms = SYS_SGX_ACTIVE_POWER_LATENCY_MS;  +	psTimingInfo->ui32uKernelFreq = SYS_SGX_PDS_TIMER_FREQ;  +#endif + +	/* +		Setup the Source Clock Divider value +	*/ +	gpsSysSpecificData->ui32SrcClockDiv = 3; + +	/* +		Locate the devices within the system, specifying  +		the physical addresses of each devices components  +		(regs, mem, ports etc.) +	*/ +	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); + +	eError = SysPMRuntimeRegister(gpsSysSpecificData); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR,"SysInitialise: Failed to register with OSPM!")); +		(IMG_VOID)SysDeinitialise(gpsSysData); +		gpsSysData = IMG_NULL; +		return eError; +	} +	SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_PM_RUNTIME); + +	eError = SysDvfsInitialize(gpsSysSpecificData); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR,"SysInitialise: Failed to initialize DVFS")); +		(IMG_VOID)SysDeinitialise(gpsSysData); +		gpsSysData = IMG_NULL; +		return eError; +	} +	SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, SYS_SPECIFIC_DATA_DVFS_INIT); + +	/* +		Register devices with the system +		This also sets up their memory maps/heaps +	*/ +	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); + +	/* +		Once all devices are registered, specify the backing store +		and, if required, customise the memory heap config +	*/	 +	psDeviceNode = gpsSysData->psDeviceNodeList; +	while(psDeviceNode) +	{ +		/* perform any OEM SOC address space customisations here */ +		switch(psDeviceNode->sDevId.eDeviceType) +		{ +			case PVRSRV_DEVICE_TYPE_SGX: +			{ +				DEVICE_MEMORY_INFO *psDevMemoryInfo; +				DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap; + +				/*  +					specify the backing store to use for the devices MMU PT/PDs +					- the PT/PDs are always UMA in this system +				*/ +				psDeviceNode->psLocalDevMemArena = IMG_NULL; + +				/* useful pointers */ +				psDevMemoryInfo = &psDeviceNode->sDevMemoryInfo; +				psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap; + +				/* specify the backing store for all SGX heaps */ +				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; +		} + +		/* advance to next device */ +		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	/* SUPPORT_ACTIVE_POWER_MANAGEMENT */ + +	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) +	/* SGX defaults to D3 power state */ +	DisableSGXClocks(gpsSysData); +#endif	/* SUPPORT_ACTIVE_POWER_MANAGEMENT */ + +#if !defined(PVR_NO_OMAP_TIMER) +#if defined(PVR_OMAP_TIMER_BASE_IN_SYS_SPEC_DATA) +	TimerRegPhysBase = gsSysSpecificData.sTimerRegPhysBase; +#else +	TimerRegPhysBase.uiAddr = SYS_OMAP3630_GP11TIMER_REGS_SYS_PHYS_BASE; +#endif +	gpsSysData->pvSOCTimerRegisterKM = IMG_NULL; +	gpsSysData->hSOCTimerRegisterOSMemHandle = 0; +	if (TimerRegPhysBase.uiAddr != 0) +	{ +		OSReservePhys(TimerRegPhysBase, +				  4, +				  PVRSRV_HAP_MULTI_PROCESS|PVRSRV_HAP_UNCACHED, +				  IMG_NULL, +				  (IMG_VOID **)&gpsSysData->pvSOCTimerRegisterKM, +				  &gpsSysData->hSOCTimerRegisterOSMemHandle); +	} +#endif /* !defined(PVR_NO_OMAP_TIMER) */ + + +	return PVRSRV_OK; +} + +#if defined(CONFIG_OMAPLFB) +int OMAPLFBRegisterPVRDriver(void * pfnFuncTable); +#endif + +/*! +****************************************************************************** + + @Function	SysFinalise +  + @Description Final part of initialisation at 'driver load' time +  + @Return   PVRSRV_ERROR  :  + +******************************************************************************/ +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,"SysFinalise: Failed to Enable SGX clocks (%d)", eError)); +		return eError; +	} +#endif	/* SUPPORT_ACTIVE_POWER_MANAGEMENT */ + +	eError = OSInstallMISR(gpsSysData); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR,"SysFinalise: Failed to install MISR")); +		return eError; +	} +	SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_MISR); + +#if defined(SYS_USING_INTERRUPTS) +	/* install a Device ISR */ +	eError = OSInstallDeviceLISR(gpsSysData, gsSGXDeviceMap.ui32IRQ, "SGX ISR", gpsSGXDevNode); +	if (eError != PVRSRV_OK) +	{ +		PVR_DPF((PVR_DBG_ERROR,"SysFinalise: Failed to install ISR")); +		return eError; +	} +	SYS_SPECIFIC_DATA_SET(&gsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_LISR); +#if !defined(SUPPORT_ACTIVE_POWER_MANAGEMENT) +	SysEnableSGXInterrupts(gpsSysData); +#endif +#endif /* defined(SYS_USING_INTERRUPTS) */ +#if defined(__linux__) +	/* Create a human readable version string for this system */ +	gpsSysData->pszVersionString = SysCreateVersionString(); +	if (!gpsSysData->pszVersionString) +	{ +		PVR_DPF((PVR_DBG_ERROR,"SysFinalise: Failed to create a system version string")); +	} +	else +	{ +		PVR_TRACE(("SysFinalise: Version string: %s", gpsSysData->pszVersionString)); +	} +#endif + +#if defined(SUPPORT_ACTIVE_POWER_MANAGEMENT) +	/* SGX defaults to D3 power state */ +	DisableSGXClocks(gpsSysData); +#endif	/* SUPPORT_ACTIVE_POWER_MANAGEMENT */ + +#if defined(CONFIG_OMAPLFB) +	if (OMAPLFBRegisterPVRDriver((void *)&PVRGetDisplayClassJTable) != 0) +	{ +		PVR_DPF((PVR_DBG_ERROR,"SysFinalise: Failed to register PVR driver with omaplfb")); +		return PVRSRV_ERROR_INIT_FAILURE; +	} +#endif + +	gpsSysSpecificData->bSGXInitComplete = IMG_TRUE; + +	return eError; +} + + +/*! +****************************************************************************** + + @Function	SysDeinitialise + + @Description	De-initialises kernel services at 'driver unload' time + + @Return	PVRSRV_ERROR + +******************************************************************************/ +PVRSRV_ERROR SysDeinitialise (SYS_DATA *psSysData) +{ +	PVRSRV_ERROR eError; + +	PVR_UNREFERENCED_PARAMETER(psSysData); + +	if(gpsSysData->pvSOCTimerRegisterKM) +	{ +		OSUnReservePhys(gpsSysData->pvSOCTimerRegisterKM, +						4, +						PVRSRV_HAP_MULTI_PROCESS|PVRSRV_HAP_UNCACHED, +						gpsSysData->hSOCTimerRegisterOSMemHandle); +	} + + +#if defined(SYS_USING_INTERRUPTS) +	if (SYS_SPECIFIC_DATA_TEST(gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_LISR)) +	{ +		eError = OSUninstallDeviceLISR(gpsSysData); +		if (eError != PVRSRV_OK) +		{ +			PVR_DPF((PVR_DBG_ERROR,"SysDeinitialise: OSUninstallDeviceLISR failed")); +			return eError; +		} +	} +#endif + +	if (SYS_SPECIFIC_DATA_TEST(gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_MISR)) +	{ +		eError = OSUninstallMISR(gpsSysData); +		if (eError != PVRSRV_OK) +		{ +			PVR_DPF((PVR_DBG_ERROR,"SysDeinitialise: OSUninstallMISR failed")); +			return eError; +		} +	} + +	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)); +		/* Reenable SGX clocks whilst SGX is being deinitialised. */ +		eError = EnableSGXClocksWrap(gpsSysData); +		if (eError != PVRSRV_OK) +		{ +			PVR_DPF((PVR_DBG_ERROR,"SysDeinitialise: EnableSGXClocks failed")); +			return eError; +		} +#endif	/* SUPPORT_ACTIVE_POWER_MANAGEMENT */ + +		/* Deinitialise SGX */ +		eError = PVRSRVDeinitialiseDevice (gui32SGXDeviceID); +		if (eError != PVRSRV_OK) +		{ +			PVR_DPF((PVR_DBG_ERROR,"SysDeinitialise: failed to de-init the device")); +			return eError; +		} +	} + +	if (SYS_SPECIFIC_DATA_TEST(gpsSysSpecificData, SYS_SPECIFIC_DATA_DVFS_INIT)) +	{ +		eError = SysDvfsDeinitialize(gpsSysSpecificData); +		if (eError != PVRSRV_OK) +		{ +			PVR_DPF((PVR_DBG_ERROR,"SysDeinitialise: Failed to de-init DVFS")); +			gpsSysData = IMG_NULL; +			return eError; +		} +	} + +	if (SYS_SPECIFIC_DATA_TEST(gpsSysSpecificData, SYS_SPECIFIC_DATA_ENABLE_PM_RUNTIME)) +	{ +		eError = SysPMRuntimeUnregister(gpsSysSpecificData); +		if (eError != PVRSRV_OK) +		{ +			PVR_DPF((PVR_DBG_ERROR,"SysDeinitialise: Failed to unregister with OSPM!")); +			gpsSysData = IMG_NULL; +			return eError; +		} +	} + +	/* +		Disable system clocks - must happen after last access to hardware. +	 */ +	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; +		} +	} + +	SysDeinitialiseCommon(gpsSysData); + +#if defined(NO_HARDWARE) || defined(SGX_OCP_REGS_ENABLED) +	if(gsSGXRegsCPUVAddr != IMG_NULL) +	{ +#if defined(NO_HARDWARE) +		/* Free hardware resources. */ +		OSBaseFreeContigMemory(SYS_OMAP3630_SGX_REGS_SIZE, gsSGXRegsCPUVAddr, gsSGXDeviceMap.sRegsCpuPBase); +#else +#if defined(SGX_OCP_REGS_ENABLED) +		OSUnMapPhysToLin(gsSGXRegsCPUVAddr, +		gsSGXDeviceMap.ui32RegsSize, +												 PVRSRV_HAP_UNCACHED|PVRSRV_HAP_KERNEL_ONLY, +												 IMG_NULL); + +		gpvOCPRegsLinAddr = IMG_NULL; +#endif +#endif	/* defined(NO_HARDWARE) */ +		gsSGXRegsCPUVAddr = IMG_NULL; +		gsSGXDeviceMap.pvRegsCpuVBase = gsSGXRegsCPUVAddr; +	} +#endif	/* defined(NO_HARDWARE) || defined(SGX_OCP_REGS_ENABLED) */ + +	 +	gpsSysSpecificData->ui32SysSpecificData = 0; +	gpsSysSpecificData->bSGXInitComplete = IMG_FALSE; + +	gpsSysData = IMG_NULL; + +	return PVRSRV_OK; +} + + +/*! +****************************************************************************** + + @Function		SysGetDeviceMemoryMap + + @Description	returns a device address map for the specified device + + @Input			eDeviceType - device type + @Input			ppvDeviceMap - void ptr to receive device specific info. + + @Return		PVRSRV_ERROR + +******************************************************************************/ +PVRSRV_ERROR SysGetDeviceMemoryMap(PVRSRV_DEVICE_TYPE	eDeviceType, +								   IMG_VOID				**ppvDeviceMap) +{ + +	switch(eDeviceType) +	{ +		case PVRSRV_DEVICE_TYPE_SGX: +		{ +			/* just return a pointer to the structure */ +			*ppvDeviceMap = (IMG_VOID*)&gsSGXDeviceMap; + +			break; +		} +		default: +		{ +			PVR_DPF((PVR_DBG_ERROR,"SysGetDeviceMemoryMap: unsupported device type")); +		} +	} +	return PVRSRV_OK; +} + + +/*! +****************************************************************************** + @Function        SysCpuPAddrToDevPAddr + + @Description     Compute a device physical address from a cpu physical +                  address. Relevant when + + @Input           cpu_paddr - cpu physical address. + @Input           eDeviceType - device type required if DevPAddr +                                address spaces vary across devices +                                in the same system + @Return         device physical address. + +******************************************************************************/ +IMG_DEV_PHYADDR SysCpuPAddrToDevPAddr(PVRSRV_DEVICE_TYPE	eDeviceType, +									  IMG_CPU_PHYADDR		CpuPAddr) +{ +	IMG_DEV_PHYADDR DevPAddr; + +	PVR_UNREFERENCED_PARAMETER(eDeviceType); + +	/* Note: for UMA system we assume DevP == CpuP */ +	DevPAddr.uiAddr = CpuPAddr.uiAddr; +	 +	return DevPAddr; +} + +/*! +****************************************************************************** + @Function        SysSysPAddrToCpuPAddr + + @Description     Compute a cpu physical address from a system physical +                  address. + + @Input           sys_paddr - system physical address. + @Return          cpu physical address. + +******************************************************************************/ +IMG_CPU_PHYADDR SysSysPAddrToCpuPAddr (IMG_SYS_PHYADDR sys_paddr) +{ +	IMG_CPU_PHYADDR cpu_paddr; + +	/* This would only be an inequality if the CPU's MMU did not point to +	   sys address 0, ie. multi CPU system */ +	cpu_paddr.uiAddr = sys_paddr.uiAddr; +	return cpu_paddr; +} + +/*! +****************************************************************************** + @Function        SysCpuPAddrToSysPAddr + + @Description     Compute a system physical address from a cpu physical +	            address. + + @Input           cpu_paddr - cpu physical address. + @Return          device physical address. + +******************************************************************************/ +IMG_SYS_PHYADDR SysCpuPAddrToSysPAddr (IMG_CPU_PHYADDR cpu_paddr) +{ +	IMG_SYS_PHYADDR sys_paddr; + +	/* This would only be an inequality if the CPU's MMU did not point to +	   sys address 0, ie. multi CPU system */ +	sys_paddr.uiAddr = cpu_paddr.uiAddr; +	return sys_paddr; +} + + +/*! +****************************************************************************** + @Function        SysSysPAddrToDevPAddr + + @Description     Compute a device physical address from a system physical +	            address. + + @Input           SysPAddr - system physical address. + @Input           eDeviceType - device type required if DevPAddr  +				address spaces vary across devices  +				in the same system + + @Return        Device physical address. + +******************************************************************************/ +IMG_DEV_PHYADDR SysSysPAddrToDevPAddr(PVRSRV_DEVICE_TYPE eDeviceType, IMG_SYS_PHYADDR SysPAddr) +{ +	IMG_DEV_PHYADDR DevPAddr; + +	PVR_UNREFERENCED_PARAMETER(eDeviceType); + +	/* Note: for UMA system we assume DevP == CpuP */ +	DevPAddr.uiAddr = SysPAddr.uiAddr; + +	return DevPAddr; +} + + +/*! +****************************************************************************** + @Function        SysDevPAddrToSysPAddr + + @Description     Compute a device physical address from a system physical +	            address. + + @Input           DevPAddr - device physical address. + @Input           eDeviceType - device type required if DevPAddr  +		  address spaces vary across devices  +		  in the same system + + @Return        System physical address. + +******************************************************************************/ +IMG_SYS_PHYADDR SysDevPAddrToSysPAddr(PVRSRV_DEVICE_TYPE eDeviceType, IMG_DEV_PHYADDR DevPAddr) +{ +	IMG_SYS_PHYADDR SysPAddr; + +	PVR_UNREFERENCED_PARAMETER(eDeviceType); + +	/* Note: for UMA system we assume DevP == SysP */ +	SysPAddr.uiAddr = DevPAddr.uiAddr; + +	return SysPAddr; +} + + +/***************************************************************************** + @Function        SysRegisterExternalDevice + + @Description     Called when a 3rd party device registers with services + + @Input           psDeviceNode - the new device node. + + @Return        IMG_VOID +*****************************************************************************/ +IMG_VOID SysRegisterExternalDevice(PVRSRV_DEVICE_NODE *psDeviceNode) +{ +	PVR_UNREFERENCED_PARAMETER(psDeviceNode); +} + + +/***************************************************************************** + @Function        SysRemoveExternalDevice + + @Description     Called when a 3rd party device unregisters from services + + @Input           psDeviceNode - the device node being removed. + + @Return        IMG_VOID +*****************************************************************************/ +IMG_VOID SysRemoveExternalDevice(PVRSRV_DEVICE_NODE *psDeviceNode) +{ +	PVR_UNREFERENCED_PARAMETER(psDeviceNode); +} + +/*! +****************************************************************************** + @Function        SysGetInterruptSource + + @Description     Returns System specific information about the device(s) that +				generated the interrupt in the system + + @Input           psSysData + @Input           psDeviceNode + + @Return        System specific information indicating which device(s)  +				generated the interrupt + +******************************************************************************/ +IMG_UINT32 SysGetInterruptSource(SYS_DATA			*psSysData, +								 PVRSRV_DEVICE_NODE	*psDeviceNode) +{ +	PVR_UNREFERENCED_PARAMETER(psSysData); +#if defined(NO_HARDWARE) +	/* no interrupts in no_hw system just return all bits */ +	return 0xFFFFFFFF; +#else +	/* Not a shared irq, so we know this is an interrupt for this device */ +	return psDeviceNode->ui32SOCInterruptBit; +#endif +} + + +/*! +****************************************************************************** + @Function        SysClearInterrupts + + @Description     Clears specified system interrupts + + @Input           psSysData + @Input           ui32ClearBits + + @Return        IMG_VOID + +******************************************************************************/ +IMG_VOID SysClearInterrupts(SYS_DATA* psSysData, IMG_UINT32 ui32ClearBits) +{ +	PVR_UNREFERENCED_PARAMETER(ui32ClearBits); +	PVR_UNREFERENCED_PARAMETER(psSysData); +#if !defined(NO_HARDWARE) +#if defined(SGX_OCP_NO_INT_BYPASS) +	OSWriteHWReg(gpvOCPRegsLinAddr, EUR_CR_OCP_IRQSTATUS_2, 0x1); +#endif +	/* Flush posted writes */ +	OSReadHWReg(((PVRSRV_SGXDEV_INFO *)gpsSGXDevNode->pvDevice)->pvRegsBaseKM, EUR_CR_EVENT_HOST_CLEAR); +#endif	/* defined(NO_HARDWARE) */ +} + +#if defined(SGX_OCP_NO_INT_BYPASS) +/*! +****************************************************************************** + @Function        SysEnableSGXInterrupts + + @Description     Enables SGX interrupts + + @Input           psSysData + + @Return        IMG_VOID + +******************************************************************************/ +IMG_VOID SysEnableSGXInterrupts(SYS_DATA *psSysData) +{ +	SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData; +	if (SYS_SPECIFIC_DATA_TEST(psSysSpecData, SYS_SPECIFIC_DATA_ENABLE_LISR) && !SYS_SPECIFIC_DATA_TEST(psSysSpecData, SYS_SPECIFIC_DATA_IRQ_ENABLED)) +	{ +		OSWriteHWReg(gpvOCPRegsLinAddr, EUR_CR_OCP_IRQSTATUS_2, 0x1); +		OSWriteHWReg(gpvOCPRegsLinAddr, EUR_CR_OCP_IRQENABLE_SET_2, 0x1); +		SYS_SPECIFIC_DATA_SET(psSysSpecData, SYS_SPECIFIC_DATA_IRQ_ENABLED); +	} +} + +/*! +****************************************************************************** + @Function        SysDisableSGXInterrupts + + @Description     Disables SGX interrupts + + @Input           psSysData + + @Return        IMG_VOID + +******************************************************************************/ +IMG_VOID SysDisableSGXInterrupts(SYS_DATA *psSysData) +{ +	SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData; + +	if (SYS_SPECIFIC_DATA_TEST(psSysSpecData, SYS_SPECIFIC_DATA_IRQ_ENABLED)) +	{ +		OSWriteHWReg(gpvOCPRegsLinAddr, EUR_CR_OCP_IRQENABLE_CLR_2, 0x1); +		SYS_SPECIFIC_DATA_CLEAR(psSysSpecData, SYS_SPECIFIC_DATA_IRQ_ENABLED); +	} +} +#endif	/* defined(SGX_OCP_NO_INT_BYPASS) */ + +/*! +****************************************************************************** + + @Function	SysSystemPrePowerState + + @Description	Perform system-level processing required before a power transition + + @Input		eNewPowerState : + + @Return	PVRSRV_ERROR + +******************************************************************************/ +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; +} + + +/*! +****************************************************************************** + + @Function	SysSystemPostPowerState + + @Description	Perform system-level processing required after a power transition + + @Input		eNewPowerState : + + @Return	PVRSRV_ERROR + +******************************************************************************/ +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; +} + + +/*! +****************************************************************************** + + @Function	SysDevicePrePowerState + + @Description	Perform system level processing required before a device power + 				transition + + @Input		ui32DeviceIndex : + @Input		eNewPowerState : + @Input		eCurrentPowerState : + + @Return	PVRSRV_ERROR + +******************************************************************************/ +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	/* SUPPORT_ACTIVE_POWER_MANAGEMENT */ +	PVR_UNREFERENCED_PARAMETER(eNewPowerState ); +#endif /* SUPPORT_ACTIVE_POWER_MANAGEMENT */ +	return PVRSRV_OK; +} + + +/*! +****************************************************************************** + + @Function	SysDevicePostPowerState + + @Description	Perform system level processing required after a device power + 				transition + + @Input		ui32DeviceIndex : + @Input		eNewPowerState : + @Input		eCurrentPowerState : + + @Return	PVRSRV_ERROR + +******************************************************************************/ +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	/* SUPPORT_ACTIVE_POWER_MANAGEMENT */ +	PVR_UNREFERENCED_PARAMETER(eCurrentPowerState); +#endif	/* SUPPORT_ACTIVE_POWER_MANAGEMENT */ + +	return eError; +} + +IMG_VOID SysLockSystemSuspend(IMG_VOID) +{ +#if defined(CONFIG_HAS_WAKELOCK) +	wake_lock(&gpsSysSpecificData->wake_lock); +#endif +} + +IMG_VOID SysUnlockSystemSuspend(IMG_VOID) +{ +#if defined(CONFIG_HAS_WAKELOCK) +	wake_unlock(&gpsSysSpecificData->wake_lock); +#endif +} + +/***************************************************************************** + @Function        SysOEMFunction + + @Description     marshalling function for custom OEM functions + + @Input           ui32ID  - function ID + @Input           pvIn - in data + @Output          pvOut - out data + + @Return        PVRSRV_ERROR +*****************************************************************************/ +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; +} +/****************************************************************************** + End of file (sysconfig.c) +******************************************************************************/ diff --git a/drivers/gpu/pvr/services4/system/omap3630/sysconfig.h b/drivers/gpu/pvr/services4/system/omap3630/sysconfig.h new file mode 100644 index 00000000000..16b40ad24ec --- /dev/null +++ b/drivers/gpu/pvr/services4/system/omap3630/sysconfig.h @@ -0,0 +1,110 @@ +/*************************************************************************/ /*! +@Title          System Description Header +@Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description    This header provides system-specific declarations and macros +@License        Dual MIT/GPLv2 + +The contents of this file are subject to the MIT license as set out below. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Alternatively, the contents of this file may be used under the terms of +the GNU General Public License Version 2 ("GPL") in which case the provisions +of GPL are applicable instead of those above. + +If you wish to allow use of your version of this file only under the terms of +GPL, and not to allow others to use your version of this file under the terms +of the MIT license, indicate your decision by deleting the provisions above +and replace them with the notice and other provisions required by GPL as set +out in the file called "GPL-COPYING" included in this distribution. If you do +not delete the provisions above, a recipient may use your version of this file +under the terms of either the MIT license or GPL. + +This License is also included in this distribution in the file called +"MIT-COPYING". + +EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS +PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ /**************************************************************************/ + +#if !defined(__SOCCONFIG_H__) +#define __SOCCONFIG_H__ + +#define VS_PRODUCT_NAME	"OMAP3630" + +#if defined(SGX540) && (SGX_CORE_REV == 120) +#define SYS_SGX_CLOCK_SPEED		307200000 +#else +#define SYS_SGX_CLOCK_SPEED		200000000 +#endif + +#define SYS_SGX_HWRECOVERY_TIMEOUT_FREQ		(100)	// 10ms (100hz) +#define SYS_SGX_PDS_TIMER_FREQ				(1000)	// 1ms (1000hz) + +/* Allow the AP latency to be overridden in the build config */ +#if !defined(SYS_SGX_ACTIVE_POWER_LATENCY_MS) +#define SYS_SGX_ACTIVE_POWER_LATENCY_MS		(2) +#endif + + +#define SYS_OMAP3630_SGX_REGS_SYS_PHYS_BASE  0x50000000 +#define SYS_OMAP3630_SGX_REGS_SIZE           0x10000 + +#define SYS_OMAP3630_SGX_IRQ				 21 + +#define SYS_OMAP3630_DSS_REGS_SYS_PHYS_BASE  0x58000000 +#define SYS_OMAP3630_DSS_REGS_SIZE           0x7000 + +#define SYS_OMAP3630_DSS_HDMI_INTERRUPT_STATUS_REG 0x6028 +#define SYS_OMAP3630_DSS_HDMI_INTERRUPT_ENABLE_REG 0x602c + +#define SYS_OMAP3630_DSS_HDMI_INTERRUPT_VSYNC_ENABLE_MASK 0x10000 +#define SYS_OMAP3630_DSS_HDMI_INTERRUPT_VSYNC_STATUS_MASK 0x10000 + +#define SYS_OMAP3630_DSS_LCD_INTERRUPT_STATUS_REG 0x1018 +#define SYS_OMAP3630_DSS_LCD_INTERRUPT_ENABLE_REG 0x101c + +#define SYS_OMAP3630_DSS_LCD_INTERRUPT_VSYNC_ENABLE_MASK 0x40002 +#define SYS_OMAP3630_DSS_LCD_INTERRUPT_VSYNC_STATUS_MASK 0x40002 + + +#define SYS_OMAP3630_GP11TIMER_ENABLE_SYS_PHYS_BASE	0x48088024 +#define SYS_OMAP3630_GP11TIMER_REGS_SYS_PHYS_BASE	0x48088028 +#define SYS_OMAP3630_GP11TIMER_TSICR_SYS_PHYS_BASE	0x48088040 + +/* Interrupt bits */ +#define DEVICE_SGX_INTERRUPT		(1<<0) +#define DEVICE_MSVDX_INTERRUPT		(1<<1) +#define DEVICE_DISP_INTERRUPT		(1<<2) + +#if defined(__linux__) +/* + * Recent OMAP4 kernels register SGX as platform device "omap_gpu". + * This device must be used with the Linux power management calls + * in sysutils_linux.c, in order for SGX to be powered on. + */ +#if defined(PVR_LDM_PLATFORM_PRE_REGISTERED_DEV) +#define	SYS_SGX_DEV_NAME	PVR_LDM_PLATFORM_PRE_REGISTERED_DEV +#else +#define	SYS_SGX_DEV_NAME	"omap_gpu" +#endif	/* defined(PVR_LDM_PLATFORM_PRE_REGISTERED_DEV) */ +#endif	/* defined(__linux__) */ + +/***************************************************************************** + * system specific data structures + *****************************************************************************/ +  +#endif	/* __SYSCONFIG_H__ */ diff --git a/drivers/gpu/pvr/services4/system/omap3630/sysinfo.h b/drivers/gpu/pvr/services4/system/omap3630/sysinfo.h new file mode 100644 index 00000000000..70ae1481b70 --- /dev/null +++ b/drivers/gpu/pvr/services4/system/omap3630/sysinfo.h @@ -0,0 +1,64 @@ +/*************************************************************************/ /*! +@Title          System Description Header +@Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description    This header provides system-specific declarations and macros +@License        Dual MIT/GPLv2 + +The contents of this file are subject to the MIT license as set out below. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Alternatively, the contents of this file may be used under the terms of +the GNU General Public License Version 2 ("GPL") in which case the provisions +of GPL are applicable instead of those above. + +If you wish to allow use of your version of this file only under the terms of +GPL, and not to allow others to use your version of this file under the terms +of the MIT license, indicate your decision by deleting the provisions above +and replace them with the notice and other provisions required by GPL as set +out in the file called "GPL-COPYING" included in this distribution. If you do +not delete the provisions above, a recipient may use your version of this file +under the terms of either the MIT license or GPL. + +This License is also included in this distribution in the file called +"MIT-COPYING". + +EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS +PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ /**************************************************************************/ + +#if !defined(__SYSINFO_H__) +#define __SYSINFO_H__ + +/*!< System specific poll/timeout details */ +#if defined(PVR_LINUX_USING_WORKQUEUES) +/* + * The workqueue based 3rd party display driver may be blocked for up + * to 500ms waiting for a vsync when the screen goes blank, so we + * need to wait longer for the hardware if a flush of the swap chain is + * required. + */ +#define MAX_HW_TIME_US				(1000000) +#define WAIT_TRY_COUNT				(20000) +#else +#define MAX_HW_TIME_US				(500000) +#define WAIT_TRY_COUNT				(10000) +#endif + + +#define SYS_DEVICE_COUNT 15 /* SGX, DISPLAYCLASS (external), BUFFERCLASS (external) */ + +#endif	/* __SYSINFO_H__ */ diff --git a/drivers/gpu/pvr/services4/system/omap3630/syslocal.h b/drivers/gpu/pvr/services4/system/omap3630/syslocal.h new file mode 100644 index 00000000000..91aef99ef64 --- /dev/null +++ b/drivers/gpu/pvr/services4/system/omap3630/syslocal.h @@ -0,0 +1,267 @@ +/*************************************************************************/ /*! +@Title          Local system definitions +@Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description    This header provides local system declarations and macros +@License        Dual MIT/GPLv2 + +The contents of this file are subject to the MIT license as set out below. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Alternatively, the contents of this file may be used under the terms of +the GNU General Public License Version 2 ("GPL") in which case the provisions +of GPL are applicable instead of those above. + +If you wish to allow use of your version of this file only under the terms of +GPL, and not to allow others to use your version of this file under the terms +of the MIT license, indicate your decision by deleting the provisions above +and replace them with the notice and other provisions required by GPL as set +out in the file called "GPL-COPYING" included in this distribution. If you do +not delete the provisions above, a recipient may use your version of this file +under the terms of either the MIT license or GPL. + +This License is also included in this distribution in the file called +"MIT-COPYING". + +EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS +PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ /**************************************************************************/ + +#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 /* (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)) */ +#include <asm/semaphore.h> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)) +#include <asm/arch/resource.h> +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)) */ +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)) */ + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) +#if !defined(LDM_PLATFORM) +#error "LDM_PLATFORM must be set" +#endif +#define	PVR_LINUX_DYNAMIC_SGX_RESOURCE_INFO +#include <linux/platform_device.h> +#endif + +#if ((defined(DEBUG) || defined(TIMING)) && \ +    (LINUX_VERSION_CODE == KERNEL_VERSION(2,6,34))) && \ +    !defined(PVR_NO_OMAP_TIMER) +/* + * We need to explicitly enable the GPTIMER11 clocks, or we'll get an + * abort when we try to access the timer registers. + */ +#define	PVR_OMAP4_TIMING_PRCM +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)) +#include <plat/gpu.h> +#endif +#if !defined(PVR_NO_OMAP_TIMER) +#define	PVR_OMAP_USE_DM_TIMER_API +#include <plat/dmtimer.h> +#endif +#endif + +#if defined(CONFIG_HAS_WAKELOCK) +#include <linux/wakelock.h> +#endif + +#if !defined(PVR_NO_OMAP_TIMER) +#define PVR_OMAP_TIMER_BASE_IN_SYS_SPEC_DATA +#endif +#endif /* defined(__linux__) */ + +#if !defined(NO_HARDWARE) && \ +     defined(SYS_USING_INTERRUPTS) +#define SGX_OCP_REGS_ENABLED +#endif + +#if defined(__linux__) +#if defined(SGX_OCP_REGS_ENABLED) +#define SGX_OCP_NO_INT_BYPASS +#endif +#endif + +#if defined (__cplusplus) +extern "C" { +#endif + +/***************************************************************************** + * system specific data structures + *****************************************************************************/ +  +/***************************************************************************** + * system specific function prototypes + *****************************************************************************/ +  +IMG_VOID DisableSystemClocks(SYS_DATA *psSysData); +PVRSRV_ERROR EnableSystemClocks(SYS_DATA *psSysData); + +IMG_VOID DisableSGXClocks(SYS_DATA *psSysData); +PVRSRV_ERROR EnableSGXClocks(SYS_DATA *psSysData); + +/* + * Various flags to indicate what has been initialised, and what + * has been temporarily deinitialised for power management purposes. + */ +#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_ENABLE_OCPREGS	0x00000800 +#define SYS_SPECIFIC_DATA_ENABLE_PM_RUNTIME	0x00001000 +#define SYS_SPECIFIC_DATA_IRQ_ENABLED		0x00002000 +#define SYS_SPECIFIC_DATA_DVFS_INIT			0x00004000 + +#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(PVR_OMAP_TIMER_BASE_IN_SYS_SPEC_DATA) +	IMG_CPU_PHYADDR	sTimerRegPhysBase; +#endif +#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 +#if defined(DEBUG) || defined(TIMING) +	struct clk	*psGPT11_FCK; +	struct clk	*psGPT11_ICK; +#endif +#if defined(PVR_OMAP_USE_DM_TIMER_API) +	struct omap_dm_timer *psGPTimer; +#endif +#if defined(CONFIG_HAS_WAKELOCK) +	struct wake_lock wake_lock; +#endif /* CONFIG_HAS_WAKELOCK */ +#endif	/* defined(__linux__) */ +} SYS_SPECIFIC_DATA; + +extern SYS_SPECIFIC_DATA *gpsSysSpecificData; + +#if defined(SGX_OCP_REGS_ENABLED) && defined(SGX_OCP_NO_INT_BYPASS) +IMG_VOID SysEnableSGXInterrupts(SYS_DATA* psSysData); +IMG_VOID SysDisableSGXInterrupts(SYS_DATA* psSysData); +#else +#define	SysEnableSGXInterrupts(psSysData) +#define SysDisableSGXInterrupts(psSysData) +#endif + +#if defined(SYS_CUSTOM_POWERLOCK_WRAP) +IMG_BOOL WrapSystemPowerChange(SYS_SPECIFIC_DATA *psSysSpecData); +IMG_VOID UnwrapSystemPowerChange(SYS_SPECIFIC_DATA *psSysSpecData); +#endif + +#if defined(__linux__) + +PVRSRV_ERROR SysPMRuntimeRegister(SYS_SPECIFIC_DATA *psSysSpecificData); +PVRSRV_ERROR SysPMRuntimeUnregister(SYS_SPECIFIC_DATA *psSysSpecificData); + +PVRSRV_ERROR SysDvfsInitialize(SYS_SPECIFIC_DATA *psSysSpecificData); +PVRSRV_ERROR SysDvfsDeinitialize(SYS_SPECIFIC_DATA *psSysSpecificData); +int pvr_access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); + +#else /* defined(__linux__) */ + +#ifdef INLINE_IS_PRAGMA +#pragma inline(SysPMRuntimeRegister) +#endif +static INLINE PVRSRV_ERROR SysPMRuntimeRegister(void) +{ +	return PVRSRV_OK; +} + +#ifdef INLINE_IS_PRAGMA +#pragma inline(SysPMRuntimeUnregister) +#endif +static INLINE PVRSRV_ERROR SysPMRuntimeUnregister(void) +{ +	return PVRSRV_OK; +} + +#ifdef INLINE_IS_PRAGMA +#pragma inline(SysDvfsInitialize) +#endif +static INLINE PVRSRV_ERROR SysDvfsInitialize(void) +{ +	return PVRSRV_OK; +} + +#ifdef INLINE_IS_PRAGMA +#pragma inline(SysDvfsDeinitialize) +#endif +static INLINE PVRSRV_ERROR SysDvfsDeinitialize(void) +{ +	return PVRSRV_OK; +} + +#define pvr_access_process_vm(tsk, addr, buf, len, write) -1 + +#endif /* defined(__linux__) */ + +#if defined(__cplusplus) +} +#endif + +#endif	/* __SYSLOCAL_H__ */ + + diff --git a/drivers/gpu/pvr/services4/system/omap3630/sysutils.c b/drivers/gpu/pvr/services4/system/omap3630/sysutils.c new file mode 100644 index 00000000000..20baad2a7d5 --- /dev/null +++ b/drivers/gpu/pvr/services4/system/omap3630/sysutils.c @@ -0,0 +1,59 @@ +/*************************************************************************/ /*! +@Title          Shared (User/kernel) and System dependent utilities +@Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description    Provides system-specific functions +@License        Dual MIT/GPLv2 + +The contents of this file are subject to the MIT license as set out below. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Alternatively, the contents of this file may be used under the terms of +the GNU General Public License Version 2 ("GPL") in which case the provisions +of GPL are applicable instead of those above. + +If you wish to allow use of your version of this file only under the terms of +GPL, and not to allow others to use your version of this file under the terms +of the MIT license, indicate your decision by deleting the provisions above +and replace them with the notice and other provisions required by GPL as set +out in the file called "GPL-COPYING" included in this distribution. If you do +not delete the provisions above, a recipient may use your version of this file +under the terms of either the MIT license or GPL. + +This License is also included in this distribution in the file called +"MIT-COPYING". + +EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS +PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ /**************************************************************************/ + +/* Pull in the correct system dependent sysutils source */ + +#if defined(__linux__) +#include "sysutils_linux.c" +#if defined(SYS_OMAP4_HAS_DVFS_FRAMEWORK) +#include "sgxfreq.c" +#include "sgxfreq_onoff.c" +#include "sgxfreq_activeidle.c" +#include "sgxfreq_on3demand.c" +#include "sgxfreq_userspace.c" +#if defined(CONFIG_THERMAL_FRAMEWORK) +#include "sgxfreq_cool.c" +#endif +#endif +#endif + + diff --git a/drivers/gpu/pvr/services4/system/omap3630/sysutils_linux.c b/drivers/gpu/pvr/services4/system/omap3630/sysutils_linux.c new file mode 100644 index 00000000000..14719223388 --- /dev/null +++ b/drivers/gpu/pvr/services4/system/omap3630/sysutils_linux.c @@ -0,0 +1,747 @@ +/*************************************************************************/ /*! +@Title          System dependent utilities +@Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description    Provides system-specific functions +@License        Dual MIT/GPLv2 + +The contents of this file are subject to the MIT license as set out below. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Alternatively, the contents of this file may be used under the terms of +the GNU General Public License Version 2 ("GPL") in which case the provisions +of GPL are applicable instead of those above. + +If you wish to allow use of your version of this file only under the terms of +GPL, and not to allow others to use your version of this file under the terms +of the MIT license, indicate your decision by deleting the provisions above +and replace them with the notice and other provisions required by GPL as set +out in the file called "GPL-COPYING" included in this distribution. If you do +not delete the provisions above, a recipient may use your version of this file +under the terms of either the MIT license or GPL. + +This License is also included in this distribution in the file called +"MIT-COPYING". + +EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS +PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ /**************************************************************************/ +#include <linux/version.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/hardirq.h> +#include <linux/mutex.h> +#include <linux/slab.h> + +#include "sgxdefs.h" +#include "services_headers.h" +#include "sysinfo.h" +#include "sgxapi_km.h" +#include "sysconfig.h" +#include "sgxinfokm.h" +#include "syslocal.h" + +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +#if defined(SYS_OMAP4_HAS_DVFS_FRAMEWORK) +#include "sgxfreq.h" +#endif + +#if defined(SUPPORT_DRI_DRM_PLUGIN) +#include <drm/drmP.h> +#include <drm/drm.h> + +#include <linux/omap_gpu.h> + +#include "pvr_drm.h" +#endif + +#if defined(CONFIG_OMAP4_DPLL_CASCADING) +#include <mach/omap4-common.h> +#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 + +#if defined(LDM_PLATFORM) && !defined(PVR_DRI_DRM_NOT_PCI) +extern struct platform_device *gpsPVRLDMDev; +#endif + +static PVRSRV_ERROR PowerLockWrap(SYS_SPECIFIC_DATA *psSysSpecData, IMG_BOOL bTryLock) +{ +	if (!in_interrupt()) +	{ +		if (bTryLock) +		{ +			int locked = mutex_trylock(&psSysSpecData->sPowerLock); +			if (locked == 0) +			{ +				return PVRSRV_ERROR_RETRY; +			} +		} +		else +		{ +			mutex_lock(&psSysSpecData->sPowerLock); +		} +	} + +	return PVRSRV_OK; +} + +static IMG_VOID PowerLockUnwrap(SYS_SPECIFIC_DATA *psSysSpecData) +{ +	if (!in_interrupt()) +	{ +		mutex_unlock(&psSysSpecData->sPowerLock); +	} +} + +PVRSRV_ERROR SysPowerLockWrap(IMG_BOOL bTryLock) +{ +	SYS_DATA	*psSysData; + +	SysAcquireData(&psSysData); + +	return PowerLockWrap(psSysData->pvSysSpecificData, bTryLock); +} + +IMG_VOID SysPowerLockUnwrap(IMG_VOID) +{ +	SYS_DATA	*psSysData; + +	SysAcquireData(&psSysData); + +	PowerLockUnwrap(psSysData->pvSysSpecificData); +} + +/* + * This function should be called to unwrap the Services power lock, prior + * to calling any function that might sleep. + * This function shouldn't be called prior to calling EnableSystemClocks + * or DisableSystemClocks, as those functions perform their own power lock + * unwrapping. + * If the function returns IMG_TRUE, UnwrapSystemPowerChange must be + * called to rewrap the power lock, prior to returning to Services. + */ +IMG_BOOL WrapSystemPowerChange(SYS_SPECIFIC_DATA *psSysSpecData) +{ +	return IMG_TRUE; +} + +IMG_VOID UnwrapSystemPowerChange(SYS_SPECIFIC_DATA *psSysSpecData) +{ +} + +/* + * Return SGX timining information to caller. + */ +IMG_VOID SysGetSGXTimingInformation(SGX_TIMING_INFORMATION *psTimingInfo) +{ +#if !defined(NO_HARDWARE) +	PVR_ASSERT(atomic_read(&gpsSysSpecificData->sSGXClocksEnabled) != 0); +#endif +#if defined(SYS_OMAP4_HAS_DVFS_FRAMEWORK) +	/* +	 * The core SGX driver and ukernel code expects SGX frequency +	 * changes to occur only just prior to SGX initialization. We +	 * don't wish to constrain the DVFS implementation as such. So +	 * we let these components believe that frequency setting is +	 * always at maximum. This produces safe values for derived +	 * parameters such as APM and HWR timeouts. +	 */ +	psTimingInfo->ui32CoreClockSpeed = (IMG_UINT32)sgxfreq_get_freq_max(); +#else /* defined(SYS_OMAP4_HAS_DVFS_FRAMEWORK) */ +	psTimingInfo->ui32CoreClockSpeed = SYS_SGX_CLOCK_SPEED; +#endif +	psTimingInfo->ui32HWRecoveryFreq = SYS_SGX_HWRECOVERY_TIMEOUT_FREQ; +	psTimingInfo->ui32uKernelFreq = SYS_SGX_PDS_TIMER_FREQ; +#if defined(SUPPORT_ACTIVE_POWER_MANAGEMENT) +	psTimingInfo->bEnableActivePM = IMG_TRUE; +#else +	psTimingInfo->bEnableActivePM = IMG_FALSE; +#endif /* SUPPORT_ACTIVE_POWER_MANAGEMENT */ +	psTimingInfo->ui32ActivePowManLatencyms = SYS_SGX_ACTIVE_POWER_LATENCY_MS; +} + +/*! +****************************************************************************** + + @Function  EnableSGXClocks + + @Description Enable SGX clocks + + @Return   PVRSRV_ERROR + +******************************************************************************/ +PVRSRV_ERROR EnableSGXClocks(SYS_DATA *psSysData) +{ +#if !defined(NO_HARDWARE) +	SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData; + +	/* SGX clocks already enabled? */ +	if (atomic_read(&psSysSpecData->sSGXClocksEnabled) != 0) +	{ +		return PVRSRV_OK; +	} + +	PVR_DPF((PVR_DBG_MESSAGE, "EnableSGXClocks: Enabling SGX Clocks")); + +#if defined(LDM_PLATFORM) && !defined(PVR_DRI_DRM_NOT_PCI) +	{ +		int res; + +#if defined(CONFIG_OMAP4_DPLL_CASCADING) +		if (omap4_dpll_cascading_blocker_hold(&gpsPVRLDMDev->dev)) +		{ +			PVR_DPF((PVR_DBG_WARNING, "EnableSGXClocks: " +				"omap4_dpll_cascading_blocker_hold failed")); +		} +#endif +		/* +		 * pm_runtime_get_sync returns 1 after the module has +		 * been reloaded. +		 */ +		res = pm_runtime_get_sync(&gpsPVRLDMDev->dev); +		if (res < 0) +		{ +			PVR_DPF((PVR_DBG_ERROR, "EnableSGXClocks: pm_runtime_get_sync failed (%d)", -res)); +			return PVRSRV_ERROR_UNABLE_TO_ENABLE_CLOCK; +		} +	} +#if defined(SYS_OMAP4_HAS_DVFS_FRAMEWORK) +	sgxfreq_notif_sgx_clk_on(); +#endif /* defined(SYS_OMAP4_HAS_DVFS_FRAMEWORK) */ +#endif /* defined(LDM_PLATFORM) && !defined(PVR_DRI_DRM_NOT_PCI) */ + +	SysEnableSGXInterrupts(psSysData); + +	/* Indicate that the SGX clocks are enabled */ +	atomic_set(&psSysSpecData->sSGXClocksEnabled, 1); + +#else	/* !defined(NO_HARDWARE) */ +	PVR_UNREFERENCED_PARAMETER(psSysData); +#endif	/* !defined(NO_HARDWARE) */ +	return PVRSRV_OK; +} + + +/*! +****************************************************************************** + + @Function  DisableSGXClocks + + @Description Disable SGX clocks. + + @Return   none + +******************************************************************************/ +IMG_VOID DisableSGXClocks(SYS_DATA *psSysData) +{ +#if !defined(NO_HARDWARE) +	SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData; + +	/* SGX clocks already disabled? */ +	if (atomic_read(&psSysSpecData->sSGXClocksEnabled) == 0) +	{ +		return; +	} + +	PVR_DPF((PVR_DBG_MESSAGE, "DisableSGXClocks: Disabling SGX Clocks")); + +	SysDisableSGXInterrupts(psSysData); + +#if defined(LDM_PLATFORM) && !defined(PVR_DRI_DRM_NOT_PCI) +	{ +		int res = pm_runtime_put_sync(&gpsPVRLDMDev->dev); +		if (res < 0) +		{ +			PVR_DPF((PVR_DBG_ERROR, "DisableSGXClocks: pm_runtime_put_sync failed (%d)", -res)); +		} +#if defined(CONFIG_OMAP4_DPLL_CASCADING) +		if (omap4_dpll_cascading_blocker_release(&gpsPVRLDMDev->dev)) +		{ +			PVR_DPF((PVR_DBG_WARNING, "DisableSGXClocks: " +				"omap4_dpll_cascading_blocker_release failed")); +		} +#endif +	} +#if defined(SYS_OMAP4_HAS_DVFS_FRAMEWORK) +	sgxfreq_notif_sgx_clk_off(); +#endif /* defined(SYS_OMAP4_HAS_DVFS_FRAMEWORK) */ +#endif /* defined(LDM_PLATFORM) && !defined(PVR_DRI_DRM_NOT_PCI) */ + +	/* Indicate that the SGX clocks are disabled */ +	atomic_set(&psSysSpecData->sSGXClocksEnabled, 0); + +#else	/* !defined(NO_HARDWARE) */ +	PVR_UNREFERENCED_PARAMETER(psSysData); +#endif	/* !defined(NO_HARDWARE) */ +} + +#if (defined(DEBUG) || defined(TIMING)) && !defined(PVR_NO_OMAP_TIMER) +#if defined(PVR_OMAP_USE_DM_TIMER_API) +#define	GPTIMER_TO_USE 11 +/*! +****************************************************************************** + + @Function  AcquireGPTimer + + @Description Acquire a GP timer + + @Return   PVRSRV_ERROR + +******************************************************************************/ +static PVRSRV_ERROR AcquireGPTimer(SYS_SPECIFIC_DATA *psSysSpecData) +{ +	PVR_ASSERT(psSysSpecData->psGPTimer == NULL); + +	/* +	 * This code could try requesting registers 9, 10, and 11, +	 * stopping at the first succesful request.  We'll stick with +	 * 11 for now, as it avoids having to hard code yet more +	 * physical addresses into the code. +	 */ +	psSysSpecData->psGPTimer = omap_dm_timer_request_specific(GPTIMER_TO_USE); +	if (psSysSpecData->psGPTimer == NULL) +	{ +	 +		PVR_DPF((PVR_DBG_WARNING, "%s: omap_dm_timer_request_specific failed", __FUNCTION__)); +		return PVRSRV_ERROR_CLOCK_REQUEST_FAILED; +	} + +	/* Set timer source to system clock */ +	omap_dm_timer_set_source(psSysSpecData->psGPTimer, OMAP_TIMER_SRC_SYS_CLK); +	omap_dm_timer_enable(psSysSpecData->psGPTimer); + +	/* Set autoreload, and start value of 0 */ +	omap_dm_timer_set_load_start(psSysSpecData->psGPTimer, 1, 0); + +	omap_dm_timer_start(psSysSpecData->psGPTimer); + +	/* +	 * The DM timer API doesn't have a mechansim for obtaining the +	 * physical address of the counter register. +	 */ +	psSysSpecData->sTimerRegPhysBase.uiAddr = SYS_OMAP3630_GP11TIMER_REGS_SYS_PHYS_BASE; + +	return PVRSRV_OK; +} + +/*! +****************************************************************************** + + @Function  ReleaseGPTimer + + @Description Release a GP timer + + @Return   PVRSRV_ERROR + +******************************************************************************/ +static void ReleaseGPTimer(SYS_SPECIFIC_DATA *psSysSpecData) +{ +	if (psSysSpecData->psGPTimer != NULL) +	{ +		/* Always returns 0 */	 +		(void) omap_dm_timer_stop(psSysSpecData->psGPTimer); + +		omap_dm_timer_disable(psSysSpecData->psGPTimer); + +		omap_dm_timer_free(psSysSpecData->psGPTimer); + +		psSysSpecData->sTimerRegPhysBase.uiAddr = 0; + +		psSysSpecData->psGPTimer = NULL; +	} + +} +#else	/* PVR_OMAP_USE_DM_TIMER_API */ +/*! +****************************************************************************** + + @Function  AcquireGPTimer + + @Description Acquire a GP timer + + @Return   PVRSRV_ERROR + +******************************************************************************/ +static PVRSRV_ERROR AcquireGPTimer(SYS_SPECIFIC_DATA *psSysSpecData) +{ +#if defined(PVR_OMAP4_TIMING_PRCM) +	struct clk *psCLK; +	IMG_INT res; +	struct clk *sys_ck; +	IMG_INT rate; +#endif +	PVRSRV_ERROR eError; + +	IMG_CPU_PHYADDR sTimerRegPhysBase; +	IMG_HANDLE hTimerEnable; +	IMG_UINT32 *pui32TimerEnable; + +	PVR_ASSERT(psSysSpecData->sTimerRegPhysBase.uiAddr == 0); + +#if defined(PVR_OMAP4_TIMING_PRCM) +	/* assert our dependence on the GPTIMER11 module */ +	psCLK = clk_get(NULL, "gpt11_fck"); +	if (IS_ERR(psCLK)) +	{ +		PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get GPTIMER11 functional clock")); +		goto ExitError; +	} +	psSysSpecData->psGPT11_FCK = psCLK; + +	psCLK = clk_get(NULL, "gpt11_ick"); +	if (IS_ERR(psCLK)) +	{ +		PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get GPTIMER11 interface clock")); +		goto ExitError; +	} +	psSysSpecData->psGPT11_ICK = psCLK; + +	sys_ck = clk_get(NULL, "sys_clkin_ck"); +	if (IS_ERR(sys_ck)) +	{ +		PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get System clock")); +		goto ExitError; +	} + +	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 ExitError; +		} +	} + +	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 ExitError; +	} + +	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; +	} +#endif	/* defined(PVR_OMAP4_TIMING_PRCM) */ + +	/* Set the timer to non-posted mode */ +	sTimerRegPhysBase.uiAddr = SYS_OMAP3630_GP11TIMER_TSICR_SYS_PHYS_BASE; +	pui32TimerEnable = OSMapPhysToLin(sTimerRegPhysBase, +                  4, +                  PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED, +                  &hTimerEnable); + +	if (pui32TimerEnable == IMG_NULL) +	{ +		PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: OSMapPhysToLin failed")); +		goto ExitDisableGPT11ICK; +	} + +	if(!(*pui32TimerEnable & 4)) +	{ +		PVR_TRACE(("Setting GPTIMER11 mode to posted (currently is non-posted)")); + +		/* Set posted mode */ +		*pui32TimerEnable |= 4; +	} + +	OSUnMapPhysToLin(pui32TimerEnable, +		    4, +		    PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED, +		    hTimerEnable); + +	/* Enable the timer */ +	sTimerRegPhysBase.uiAddr = SYS_OMAP3630_GP11TIMER_ENABLE_SYS_PHYS_BASE; +	pui32TimerEnable = OSMapPhysToLin(sTimerRegPhysBase, +                  4, +                  PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED, +                  &hTimerEnable); + +	if (pui32TimerEnable == IMG_NULL) +	{ +		PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: OSMapPhysToLin failed")); +		goto ExitDisableGPT11ICK; +	} + +	/* Enable and set autoreload on overflow */ +	*pui32TimerEnable = 3; + +	OSUnMapPhysToLin(pui32TimerEnable, +		    4, +		    PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED, +		    hTimerEnable); + +	psSysSpecData->sTimerRegPhysBase = sTimerRegPhysBase; + +	eError = PVRSRV_OK; + +	goto Exit; + +ExitDisableGPT11ICK: +#if defined(PVR_OMAP4_TIMING_PRCM) +	clk_disable(psSysSpecData->psGPT11_ICK); +ExitDisableGPT11FCK: +	clk_disable(psSysSpecData->psGPT11_FCK); +ExitError: +#endif	/* defined(PVR_OMAP4_TIMING_PRCM) */ +	eError = PVRSRV_ERROR_CLOCK_REQUEST_FAILED; +Exit: +	return eError; +} + +/*! +****************************************************************************** + + @Function  ReleaseGPTimer + + @Description Release a GP timer + + @Return   PVRSRV_ERROR + +******************************************************************************/ +static void ReleaseGPTimer(SYS_SPECIFIC_DATA *psSysSpecData) +{ +	IMG_HANDLE hTimerDisable; +	IMG_UINT32 *pui32TimerDisable; + +	if (psSysSpecData->sTimerRegPhysBase.uiAddr == 0) +	{ +		return; +	} + +	/* Disable the timer */ +	pui32TimerDisable = OSMapPhysToLin(psSysSpecData->sTimerRegPhysBase, +				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); +	} + +	psSysSpecData->sTimerRegPhysBase.uiAddr = 0; + +#if defined(PVR_OMAP4_TIMING_PRCM) +	clk_disable(psSysSpecData->psGPT11_ICK); + +	clk_disable(psSysSpecData->psGPT11_FCK); +#endif	/* defined(PVR_OMAP4_TIMING_PRCM) */ +} +#endif	/* PVR_OMAP_USE_DM_TIMER_API */ +#else	/* (DEBUG || TIMING) && !PVR_NO_OMAP_TIMER */ +static PVRSRV_ERROR AcquireGPTimer(SYS_SPECIFIC_DATA *psSysSpecData) +{ +	PVR_UNREFERENCED_PARAMETER(psSysSpecData); + +	return PVRSRV_OK; +} +static void ReleaseGPTimer(SYS_SPECIFIC_DATA *psSysSpecData) +{ +	PVR_UNREFERENCED_PARAMETER(psSysSpecData); +} +#endif /* (DEBUG || TIMING) && !PVR_NO_OMAP_TIMER */ + +/*! +****************************************************************************** + + @Function  EnableSystemClocks + + @Description Setup up the clocks for the graphics device to work. + + @Return   PVRSRV_ERROR + +******************************************************************************/ +PVRSRV_ERROR EnableSystemClocks(SYS_DATA *psSysData) +{ +	SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData; + +	PVR_TRACE(("EnableSystemClocks: Enabling System Clocks")); + +	if (!psSysSpecData->bSysClocksOneTimeInit) +	{ +		mutex_init(&psSysSpecData->sPowerLock); + +		atomic_set(&psSysSpecData->sSGXClocksEnabled, 0); + +		psSysSpecData->bSysClocksOneTimeInit = IMG_TRUE; +	} + +	return AcquireGPTimer(psSysSpecData); +} + +/*! +****************************************************************************** + + @Function  DisableSystemClocks + + @Description Disable the graphics clocks. + + @Return  none + +******************************************************************************/ +IMG_VOID DisableSystemClocks(SYS_DATA *psSysData) +{ +	SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData; + +	PVR_TRACE(("DisableSystemClocks: Disabling System Clocks")); + +	/* +	 * Always disable the SGX clocks when the system clocks are disabled. +	 * This saves having to make an explicit call to DisableSGXClocks if +	 * active power management is enabled. +	 */ +	DisableSGXClocks(psSysData); + +	ReleaseGPTimer(psSysSpecData); +} + +PVRSRV_ERROR SysPMRuntimeRegister(SYS_SPECIFIC_DATA *psSysSpecificData) +{ +#if defined(LDM_PLATFORM) && !defined(PVR_DRI_DRM_NOT_PCI) +	pm_runtime_enable(&gpsPVRLDMDev->dev); +#endif +#if defined(CONFIG_HAS_WAKELOCK) +	wake_lock_init(&psSysSpecificData->wake_lock, WAKE_LOCK_SUSPEND, "pvrsrvkm"); +#endif +	return PVRSRV_OK; +} + +PVRSRV_ERROR SysPMRuntimeUnregister(SYS_SPECIFIC_DATA *psSysSpecificData) +{ +#if defined(LDM_PLATFORM) && !defined(PVR_DRI_DRM_NOT_PCI) +	pm_runtime_disable(&gpsPVRLDMDev->dev); +#endif +#if defined(CONFIG_HAS_WAKELOCK) +	wake_lock_destroy(&psSysSpecificData->wake_lock); +#endif +	return PVRSRV_OK; +} + +PVRSRV_ERROR SysDvfsInitialize(SYS_SPECIFIC_DATA *psSysSpecificData) +{ +	PVR_UNREFERENCED_PARAMETER(psSysSpecificData); +#if defined(SYS_OMAP4_HAS_DVFS_FRAMEWORK) +	if (sgxfreq_init(&gpsPVRLDMDev->dev)) +		return PVRSRV_ERROR_NOT_SUPPORTED; +#endif /* defined(SYS_OMAP4_HAS_DVFS_FRAMEWORK) */ + +	return PVRSRV_OK; +} + +PVRSRV_ERROR SysDvfsDeinitialize(SYS_SPECIFIC_DATA *psSysSpecificData) +{ +	PVR_UNREFERENCED_PARAMETER(psSysSpecificData); +#if defined(SYS_OMAP4_HAS_DVFS_FRAMEWORK) +	if (sgxfreq_deinit()) +		return PVRSRV_ERROR_NOT_SUPPORTED; +#endif /* defined(SYS_OMAP4_HAS_DVFS_FRAMEWORK) */ + +	return PVRSRV_OK; +} + +#if defined(SUPPORT_DRI_DRM_PLUGIN) +static struct omap_gpu_plugin sOMAPGPUPlugin; + +#define	SYS_DRM_SET_PLUGIN_FIELD(d, s, f) (d)->f = (s)->f +int +SysDRMRegisterPlugin(PVRSRV_DRM_PLUGIN *psDRMPlugin) +{ +	int iRes; + +	SYS_DRM_SET_PLUGIN_FIELD(&sOMAPGPUPlugin, psDRMPlugin, name); +	SYS_DRM_SET_PLUGIN_FIELD(&sOMAPGPUPlugin, psDRMPlugin, open); +	SYS_DRM_SET_PLUGIN_FIELD(&sOMAPGPUPlugin, psDRMPlugin, load); +	SYS_DRM_SET_PLUGIN_FIELD(&sOMAPGPUPlugin, psDRMPlugin, unload); +	SYS_DRM_SET_PLUGIN_FIELD(&sOMAPGPUPlugin, psDRMPlugin, release); +	SYS_DRM_SET_PLUGIN_FIELD(&sOMAPGPUPlugin, psDRMPlugin, mmap); +	SYS_DRM_SET_PLUGIN_FIELD(&sOMAPGPUPlugin, psDRMPlugin, ioctls); +	SYS_DRM_SET_PLUGIN_FIELD(&sOMAPGPUPlugin, psDRMPlugin, num_ioctls); +	SYS_DRM_SET_PLUGIN_FIELD(&sOMAPGPUPlugin, psDRMPlugin, ioctl_start); + +	iRes = omap_gpu_register_plugin(&sOMAPGPUPlugin); +	if (iRes != 0) +	{ +		PVR_DPF((PVR_DBG_ERROR, "%s: omap_gpu_register_plugin failed (%d)", __FUNCTION__, iRes)); +	} + +	return iRes; +} + +void +SysDRMUnregisterPlugin(PVRSRV_DRM_PLUGIN *psDRMPlugin) +{ +	int iRes = omap_gpu_unregister_plugin(&sOMAPGPUPlugin); +	if (iRes != 0) +	{ +		PVR_DPF((PVR_DBG_ERROR, "%s: omap_gpu_unregister_plugin failed (%d)", __FUNCTION__, iRes)); +	} +} +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)) +int pvr_access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) +{ +	struct gpu_platform_data *pdata; +	pdata = (struct gpu_platform_data *)gpsPVRLDMDev->dev.platform_data; +	if(!pdata || !pdata->access_process_vm) +		return -1; +	return pdata->access_process_vm(tsk, addr, buf, len, write); +} +#endif + +IMG_VOID SysSGXIdleEntered(IMG_VOID) +{ +#if defined(SYS_OMAP4_HAS_DVFS_FRAMEWORK) +	sgxfreq_notif_sgx_idle(); +#endif +} + +IMG_VOID SysSGXCommandPending(IMG_BOOL bSGXIdle) +{ +#if defined(SYS_OMAP4_HAS_DVFS_FRAMEWORK) +		sgxfreq_notif_sgx_active(); +#else +	PVR_UNREFERENCED_PARAMETER(bSGXIdle); +#endif +} diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 0669dac2301..0838d4402dc 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -23,6 +23,8 @@ source "drivers/gpu/drm/Kconfig"  source "drivers/gpu/host1x/Kconfig" +source "drivers/gpu/pvr/Kconfig" +  config VGASTATE         tristate         default n |