diff options
Diffstat (limited to 'pvr-source/services4/system')
-rw-r--r-- | pvr-source/services4/system/include/syscommon.h | 397 | ||||
-rw-r--r-- | pvr-source/services4/system/omap4/oemfuncs.h | 80 | ||||
-rw-r--r-- | pvr-source/services4/system/omap4/sgxfreq.c | 590 | ||||
-rw-r--r-- | pvr-source/services4/system/omap4/sgxfreq.h | 97 | ||||
-rw-r--r-- | pvr-source/services4/system/omap4/sgxfreq_activeidle.c | 181 | ||||
-rw-r--r-- | pvr-source/services4/system/omap4/sgxfreq_cool.c | 104 | ||||
-rw-r--r-- | pvr-source/services4/system/omap4/sgxfreq_on3demand.c | 324 | ||||
-rw-r--r-- | pvr-source/services4/system/omap4/sgxfreq_onoff.c | 180 | ||||
-rw-r--r-- | pvr-source/services4/system/omap4/sgxfreq_userspace.c | 180 | ||||
-rw-r--r-- | pvr-source/services4/system/omap4/sysconfig.c | 1329 | ||||
-rw-r--r-- | pvr-source/services4/system/omap4/sysconfig.h | 110 | ||||
-rw-r--r-- | pvr-source/services4/system/omap4/sysinfo.h | 64 | ||||
-rw-r--r-- | pvr-source/services4/system/omap4/syslocal.h | 265 | ||||
-rw-r--r-- | pvr-source/services4/system/omap4/sysutils.c | 59 | ||||
-rw-r--r-- | pvr-source/services4/system/omap4/sysutils_linux.c | 745 |
15 files changed, 4705 insertions, 0 deletions
diff --git a/pvr-source/services4/system/include/syscommon.h b/pvr-source/services4/system/include/syscommon.h new file mode 100644 index 0000000..4fd3512 --- /dev/null +++ b/pvr-source/services4/system/include/syscommon.h @@ -0,0 +1,397 @@ +/*************************************************************************/ /*! +@Title Common System APIs and structures +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@Description This header provides common system-specific declarations and macros + that are supported by all system's +@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. +*/ /**************************************************************************/ + +#ifndef _SYSCOMMON_H +#define _SYSCOMMON_H + +#include "sysconfig.h" /* System specific system defines */ +#include "sysinfo.h" /* globally accessible system info */ +#include "servicesint.h" +#include "queue.h" +#include "power.h" +#include "resman.h" +#include "ra.h" +#include "device.h" +#include "buffer_manager.h" +#include "pvr_debug.h" +#include "services.h" + +#if defined(NO_HARDWARE) && defined(__linux__) && defined(__KERNEL__) +#include <asm/io.h> +#endif + +#if defined (__cplusplus) +extern "C" { +#endif + +/*! + **************************************************************************** + device id management structure + ****************************************************************************/ +typedef struct _SYS_DEVICE_ID_TAG +{ + IMG_UINT32 uiID; + IMG_BOOL bInUse; + +} SYS_DEVICE_ID; + + +/* + the max number of independent local backing stores services supports + (grow this number if ever required) +*/ +#define SYS_MAX_LOCAL_DEVMEM_ARENAS 4 + +typedef IMG_HANDLE (*PFN_HTIMER_CREATE) (IMG_VOID); +typedef IMG_UINT32 (*PFN_HTIMER_GETUS) (IMG_HANDLE); +typedef IMG_VOID (*PFN_HTIMER_DESTROY) (IMG_HANDLE); +/*! + **************************************************************************** + Top level system data structure + ****************************************************************************/ +typedef struct _SYS_DATA_TAG_ +{ + IMG_UINT32 ui32NumDevices; /*!< number of devices in system */ + SYS_DEVICE_ID sDeviceID[SYS_DEVICE_COUNT]; + PVRSRV_DEVICE_NODE *psDeviceNodeList; /*!< list of private device info structures */ + PVRSRV_POWER_DEV *psPowerDeviceList; /*!< list of devices registered with the power manager */ + PVRSRV_RESOURCE sPowerStateChangeResource; /*!< lock for power state transitions */ + PVRSRV_SYS_POWER_STATE eCurrentPowerState; /*!< current Kernel services power state */ + PVRSRV_SYS_POWER_STATE eFailedPowerState; /*!< Kernel services power state (Failed to transition to) */ + IMG_UINT32 ui32CurrentOSPowerState; /*!< current OS specific power state */ + PVRSRV_QUEUE_INFO *psQueueList; /*!< list of all command queues in the system */ + PVRSRV_KERNEL_SYNC_INFO *psSharedSyncInfoList; /*!< list of cross process syncinfos */ + IMG_PVOID pvEnvSpecificData; /*!< Environment specific data */ + IMG_PVOID pvSysSpecificData; /*!< Unique to system, accessible at system layer only */ + PVRSRV_RESOURCE sQProcessResource; /*!< Command Q processing access lock */ + IMG_VOID *pvSOCRegsBase; /*!< SOC registers base linear address */ + IMG_HANDLE hSOCTimerRegisterOSMemHandle; /*!< SOC Timer register (if present) */ + IMG_UINT32 *pvSOCTimerRegisterKM; /*!< SOC Timer register (if present) */ + IMG_VOID *pvSOCClockGateRegsBase; /*!< SOC Clock gating registers (if present) */ + IMG_UINT32 ui32SOCClockGateRegsSize; + + struct _DEVICE_COMMAND_DATA_ *apsDeviceCommandData[SYS_DEVICE_COUNT]; + /*!< command complete data and callback function store for every command for every device */ + + RA_ARENA *apsLocalDevMemArena[SYS_MAX_LOCAL_DEVMEM_ARENAS]; /*!< RA Arenas for local device memory heap management */ + + IMG_CHAR *pszVersionString; /*!< Human readable string showing relevent system version info */ +#if defined (SUPPORT_SID_INTERFACE) + PVRSRV_EVENTOBJECT_KM *psGlobalEventObject; /*!< OS Global Event Object */ +#else + PVRSRV_EVENTOBJECT *psGlobalEventObject; /*!< OS Global Event Object */ +#endif + + PVRSRV_MISC_INFO_CPUCACHEOP_TYPE ePendingCacheOpType; /*!< Deferred CPU cache op control */ + + PFN_HTIMER_CREATE pfnHighResTimerCreate; + PFN_HTIMER_GETUS pfnHighResTimerGetus; + PFN_HTIMER_DESTROY pfnHighResTimerDestroy; +} SYS_DATA; + + +/**************************************************************************** + * common function prototypes + ****************************************************************************/ + +#if defined (CUSTOM_DISPLAY_SEGMENT) +PVRSRV_ERROR SysGetDisplaySegmentAddress (IMG_VOID *pvDevInfo, IMG_VOID *pvPhysicalAddress, IMG_UINT32 *pui32Length); +#endif + +PVRSRV_ERROR SysInitialise(IMG_VOID); +PVRSRV_ERROR SysFinalise(IMG_VOID); + +PVRSRV_ERROR SysDeinitialise(SYS_DATA *psSysData); +PVRSRV_ERROR SysGetDeviceMemoryMap(PVRSRV_DEVICE_TYPE eDeviceType, + IMG_VOID **ppvDeviceMap); + +IMG_VOID SysRegisterExternalDevice(PVRSRV_DEVICE_NODE *psDeviceNode); +IMG_VOID SysRemoveExternalDevice(PVRSRV_DEVICE_NODE *psDeviceNode); + +IMG_UINT32 SysGetInterruptSource(SYS_DATA *psSysData, + PVRSRV_DEVICE_NODE *psDeviceNode); + +IMG_VOID SysClearInterrupts(SYS_DATA* psSysData, IMG_UINT32 ui32ClearBits); + +PVRSRV_ERROR SysResetDevice(IMG_UINT32 ui32DeviceIndex); + +PVRSRV_ERROR SysSystemPrePowerState(PVRSRV_SYS_POWER_STATE eNewPowerState); +PVRSRV_ERROR SysSystemPostPowerState(PVRSRV_SYS_POWER_STATE eNewPowerState); +PVRSRV_ERROR SysDevicePrePowerState(IMG_UINT32 ui32DeviceIndex, + PVRSRV_DEV_POWER_STATE eNewPowerState, + PVRSRV_DEV_POWER_STATE eCurrentPowerState); +PVRSRV_ERROR SysDevicePostPowerState(IMG_UINT32 ui32DeviceIndex, + PVRSRV_DEV_POWER_STATE eNewPowerState, + PVRSRV_DEV_POWER_STATE eCurrentPowerState); + +IMG_VOID SysSGXIdleEntered(IMG_VOID); +IMG_VOID SysSGXCommandPending(IMG_BOOL bSGXIdle); + +#if defined(SYS_CUSTOM_POWERLOCK_WRAP) +PVRSRV_ERROR SysPowerLockWrap(IMG_BOOL bTryLock); +IMG_VOID SysPowerLockUnwrap(IMG_VOID); +#endif + +IMG_VOID SysLockSystemSuspend(IMG_VOID); +IMG_VOID SysUnlockSystemSuspend(IMG_VOID); + +PVRSRV_ERROR SysOEMFunction ( IMG_UINT32 ui32ID, + IMG_VOID *pvIn, + IMG_UINT32 ulInSize, + IMG_VOID *pvOut, + IMG_UINT32 ulOutSize); + + +IMG_DEV_PHYADDR SysCpuPAddrToDevPAddr (PVRSRV_DEVICE_TYPE eDeviceType, IMG_CPU_PHYADDR cpu_paddr); +IMG_DEV_PHYADDR SysSysPAddrToDevPAddr (PVRSRV_DEVICE_TYPE eDeviceType, IMG_SYS_PHYADDR SysPAddr); +IMG_SYS_PHYADDR SysDevPAddrToSysPAddr (PVRSRV_DEVICE_TYPE eDeviceType, IMG_DEV_PHYADDR SysPAddr); +IMG_CPU_PHYADDR SysSysPAddrToCpuPAddr (IMG_SYS_PHYADDR SysPAddr); +IMG_SYS_PHYADDR SysCpuPAddrToSysPAddr (IMG_CPU_PHYADDR cpu_paddr); +#if defined(PVR_LMA) +IMG_BOOL SysVerifyCpuPAddrToDevPAddr (PVRSRV_DEVICE_TYPE eDeviceType, IMG_CPU_PHYADDR CpuPAddr); +IMG_BOOL SysVerifySysPAddrToDevPAddr (PVRSRV_DEVICE_TYPE eDeviceType, IMG_SYS_PHYADDR SysPAddr); +#endif + +extern SYS_DATA* gpsSysData; + + +#if !defined(USE_CODE) + +/*! +****************************************************************************** + + @Function SysAcquireData + + @Description returns reference to to sysdata + creating one on first call + + @Input ppsSysData - pointer to copy reference into + + @Return ppsSysData updated + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(SysAcquireData) +#endif +static INLINE IMG_VOID SysAcquireData(SYS_DATA **ppsSysData) +{ + /* Copy pointer back system information pointer */ + *ppsSysData = gpsSysData; + + /* + Verify we've not been called before being initialised. Instinctively + we should do this check first, but in the failing case we'll just write + null back and the compiler won't warn about an uninitialised varible. + */ + PVR_ASSERT (gpsSysData != IMG_NULL); +} + + +/*! +****************************************************************************** + + @Function SysAcquireDataNoCheck + + @Description returns reference to to sysdata + creating one on first call + + @Input none + + @Return psSysData - pointer to copy reference into + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(SysAcquireDataNoCheck) +#endif +static INLINE SYS_DATA * SysAcquireDataNoCheck(IMG_VOID) +{ + /* return pointer back system information pointer */ + return gpsSysData; +} + + +/*! +****************************************************************************** + + @Function SysInitialiseCommon + + @Description Performs system initialisation common to all systems + + @Input psSysData - pointer to system data + + @Return PVRSRV_ERROR : + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(SysInitialiseCommon) +#endif +static INLINE PVRSRV_ERROR SysInitialiseCommon(SYS_DATA *psSysData) +{ + PVRSRV_ERROR eError; + + /* Initialise Services */ + eError = PVRSRVInit(psSysData); + + return eError; +} + +/*! +****************************************************************************** + + @Function SysDeinitialiseCommon + + @Description Performs system deinitialisation common to all systems + + @Input psSysData - pointer to system data + + @Return PVRSRV_ERROR : + +******************************************************************************/ +#ifdef INLINE_IS_PRAGMA +#pragma inline(SysDeinitialiseCommon) +#endif +static INLINE IMG_VOID SysDeinitialiseCommon(SYS_DATA *psSysData) +{ + /* De-initialise Services */ + PVRSRVDeInit(psSysData); + + OSDestroyResource(&psSysData->sPowerStateChangeResource); +} +#endif /* !defined(USE_CODE) */ + + +/* + * SysReadHWReg and SysWriteHWReg differ from OSReadHWReg and OSWriteHWReg + * in that they are always intended for use with real hardware, even on + * NO_HARDWARE systems. + */ +#if !(defined(NO_HARDWARE) && defined(__linux__) && defined(__KERNEL__)) +#define SysReadHWReg(p, o) OSReadHWReg(p, o) +#define SysWriteHWReg(p, o, v) OSWriteHWReg(p, o, v) +#else /* !(defined(NO_HARDWARE) && defined(__linux__)) */ +/*! +****************************************************************************** + + @Function SysReadHWReg + + @Description + + register read function + + @input pvLinRegBaseAddr : lin addr of register block base + + @input ui32Offset : + + @Return register value + +******************************************************************************/ +static inline IMG_UINT32 SysReadHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset) +{ + return (IMG_UINT32) readl(pvLinRegBaseAddr + ui32Offset); +} + +/*! +****************************************************************************** + + @Function SysWriteHWReg + + @Description + + register write function + + @input pvLinRegBaseAddr : lin addr of register block base + + @input ui32Offset : + + @input ui32Value : + + @Return none + +******************************************************************************/ +static inline IMG_VOID SysWriteHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset, IMG_UINT32 ui32Value) +{ + writel(ui32Value, pvLinRegBaseAddr + ui32Offset); +} +#endif /* !(defined(NO_HARDWARE) && defined(__linux__)) */ + +#if defined(__cplusplus) +} +#endif + +#ifdef INLINE_IS_PRAGMA +#pragma inline(SysHighResTimerCreate) +#endif +static INLINE IMG_HANDLE SysHighResTimerCreate(IMG_VOID) +{ + SYS_DATA *psSysData; + + SysAcquireData(&psSysData); + return psSysData->pfnHighResTimerCreate(); +} + +#ifdef INLINE_IS_PRAGMA +#pragma inline(SysHighResTimerGetus) +#endif +static INLINE IMG_UINT32 SysHighResTimerGetus(IMG_HANDLE hTimer) +{ + SYS_DATA *psSysData; + + SysAcquireData(&psSysData); + return psSysData->pfnHighResTimerGetus(hTimer); +} + +#ifdef INLINE_IS_PRAGMA +#pragma inline(SysHighResTimerDestroy) +#endif +static INLINE IMG_VOID SysHighResTimerDestroy(IMG_HANDLE hTimer) +{ + SYS_DATA *psSysData; + + SysAcquireData(&psSysData); + psSysData->pfnHighResTimerDestroy(hTimer); +} +#endif + +/***************************************************************************** + End of file (syscommon.h) +*****************************************************************************/ diff --git a/pvr-source/services4/system/omap4/oemfuncs.h b/pvr-source/services4/system/omap4/oemfuncs.h new file mode 100644 index 0000000..0902042 --- /dev/null +++ b/pvr-source/services4/system/omap4/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/pvr-source/services4/system/omap4/sgxfreq.c b/pvr-source/services4/system/omap4/sgxfreq.c new file mode 100644 index 0000000..7e8e8fd --- /dev/null +++ b/pvr-source/services4/system/omap4/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/pvr-source/services4/system/omap4/sgxfreq.h b/pvr-source/services4/system/omap4/sgxfreq.h new file mode 100644 index 0000000..ff6fc88 --- /dev/null +++ b/pvr-source/services4/system/omap4/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/pvr-source/services4/system/omap4/sgxfreq_activeidle.c b/pvr-source/services4/system/omap4/sgxfreq_activeidle.c new file mode 100644 index 0000000..45159d7 --- /dev/null +++ b/pvr-source/services4/system/omap4/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/pvr-source/services4/system/omap4/sgxfreq_cool.c b/pvr-source/services4/system/omap4/sgxfreq_cool.c new file mode 100644 index 0000000..9233def --- /dev/null +++ b/pvr-source/services4/system/omap4/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/pvr-source/services4/system/omap4/sgxfreq_on3demand.c b/pvr-source/services4/system/omap4/sgxfreq_on3demand.c new file mode 100644 index 0000000..c4e4bd9 --- /dev/null +++ b/pvr-source/services4/system/omap4/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/pvr-source/services4/system/omap4/sgxfreq_onoff.c b/pvr-source/services4/system/omap4/sgxfreq_onoff.c new file mode 100644 index 0000000..39dd3fc --- /dev/null +++ b/pvr-source/services4/system/omap4/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/pvr-source/services4/system/omap4/sgxfreq_userspace.c b/pvr-source/services4/system/omap4/sgxfreq_userspace.c new file mode 100644 index 0000000..5ff0dd0 --- /dev/null +++ b/pvr-source/services4/system/omap4/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/pvr-source/services4/system/omap4/sysconfig.c b/pvr-source/services4/system/omap4/sysconfig.c new file mode 100644 index 0000000..e9fd069 --- /dev/null +++ b/pvr-source/services4/system/omap4/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_OMAP4430_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_OMAP4430_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_OMAP4430_SGX_REGS_SYS_PHYS_BASE; + gsSGXDeviceMap.sRegsCpuPBase = SysSysPAddrToCpuPAddr(gsSGXDeviceMap.sRegsSysPBase); + gsSGXDeviceMap.ui32RegsSize = SYS_OMAP4430_SGX_REGS_SIZE; + + gsSGXDeviceMap.ui32IRQ = SYS_OMAP4430_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_OMAP4430_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_OMAP4430_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_OMAP4430_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/pvr-source/services4/system/omap4/sysconfig.h b/pvr-source/services4/system/omap4/sysconfig.h new file mode 100644 index 0000000..64f3187 --- /dev/null +++ b/pvr-source/services4/system/omap4/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 "OMAP4" + +#if defined(SGX540) && (SGX_CORE_REV == 120) +#define SYS_SGX_CLOCK_SPEED 307200000 +#else +#define SYS_SGX_CLOCK_SPEED 304742400 +#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_OMAP4430_SGX_REGS_SYS_PHYS_BASE 0x56000000 +#define SYS_OMAP4430_SGX_REGS_SIZE 0xFFFF + +#define SYS_OMAP4430_SGX_IRQ 53 /* OMAP4 IRQ's are offset by 32 */ + +#define SYS_OMAP4430_DSS_REGS_SYS_PHYS_BASE 0x58000000 +#define SYS_OMAP4430_DSS_REGS_SIZE 0x7000 + +#define SYS_OMAP4430_DSS_HDMI_INTERRUPT_STATUS_REG 0x6028 +#define SYS_OMAP4430_DSS_HDMI_INTERRUPT_ENABLE_REG 0x602c + +#define SYS_OMAP4430_DSS_HDMI_INTERRUPT_VSYNC_ENABLE_MASK 0x10000 +#define SYS_OMAP4430_DSS_HDMI_INTERRUPT_VSYNC_STATUS_MASK 0x10000 + +#define SYS_OMAP4430_DSS_LCD_INTERRUPT_STATUS_REG 0x1018 +#define SYS_OMAP4430_DSS_LCD_INTERRUPT_ENABLE_REG 0x101c + +#define SYS_OMAP4430_DSS_LCD_INTERRUPT_VSYNC_ENABLE_MASK 0x40002 +#define SYS_OMAP4430_DSS_LCD_INTERRUPT_VSYNC_STATUS_MASK 0x40002 + + +#define SYS_OMAP4430_GP11TIMER_ENABLE_SYS_PHYS_BASE 0x48088038 +#define SYS_OMAP4430_GP11TIMER_REGS_SYS_PHYS_BASE 0x4808803C +#define SYS_OMAP4430_GP11TIMER_TSICR_SYS_PHYS_BASE 0x48088054 + +/* 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/pvr-source/services4/system/omap4/sysinfo.h b/pvr-source/services4/system/omap4/sysinfo.h new file mode 100644 index 0000000..70ae148 --- /dev/null +++ b/pvr-source/services4/system/omap4/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/pvr-source/services4/system/omap4/syslocal.h b/pvr-source/services4/system/omap4/syslocal.h new file mode 100644 index 0000000..5fd36b3 --- /dev/null +++ b/pvr-source/services4/system/omap4/syslocal.h @@ -0,0 +1,265 @@ +/*************************************************************************/ /*! +@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)) +#include <plat/gpu.h> +#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/pvr-source/services4/system/omap4/sysutils.c b/pvr-source/services4/system/omap4/sysutils.c new file mode 100644 index 0000000..20baad2 --- /dev/null +++ b/pvr-source/services4/system/omap4/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/pvr-source/services4/system/omap4/sysutils_linux.c b/pvr-source/services4/system/omap4/sysutils_linux.c new file mode 100644 index 0000000..1bef2ee --- /dev/null +++ b/pvr-source/services4/system/omap4/sysutils_linux.c @@ -0,0 +1,745 @@ +/*************************************************************************/ /*! +@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_OMAP4430_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_OMAP4430_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_OMAP4430_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 + +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); +} + +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 +} |