summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
authorbyan <byan@nvidia.com>2010-11-09 12:37:37 -0800
committerVarun Colbert <vcolbert@nvidia.com>2010-11-29 11:24:59 -0800
commit1ce2f5538e754957fe2f888fbcbccba41c5a6fd6 (patch)
treee3984c77f8d029da54fe03bd45d9960976834375 /arch/arm/mach-tegra
parent05074ac6ce18a61467ad6d5dd5e53d56725c8d58 (diff)
[Tegra NvRm]: Tristate MCLK if mediaserver crash
for bug 728160 Tristate MCLK if mediaserver crash to save power. This is done by ref-tracking pinmux for MCLK. The change actually also tracks the other 2 external clock sources, so all external clocks are tracked and cleaned up upon user space application crash. Change-Id: Ie2bc40f680586c01a916abbe51c91a7eb2d1cb13 Reviewed-on: http://git-master/r/10451 Reviewed-on: http://git-master/r/11451 Reviewed-by: Bo Yan <byan@nvidia.com> Tested-by: Bo Yan <byan@nvidia.com> Reviewed-by: Venkata (Muni) Anda <vanda@nvidia.com> Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com> Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/include/nvreftrack.h3
-rw-r--r--arch/arm/mach-tegra/include/nvrm_pinmux.h9
-rw-r--r--arch/arm/mach-tegra/nvrm/dispatch/nvrm_pinmux_dispatch.c51
-rw-r--r--arch/arm/mach-tegra/nvrm_user.c92
4 files changed, 119 insertions, 36 deletions
diff --git a/arch/arm/mach-tegra/include/nvreftrack.h b/arch/arm/mach-tegra/include/nvreftrack.h
index ceecaab0a523..01bd4e4be48a 100644
--- a/arch/arm/mach-tegra/include/nvreftrack.h
+++ b/arch/arm/mach-tegra/include/nvreftrack.h
@@ -98,9 +98,10 @@
typedef enum
{
NvRtObjType_NvRm_NvRmMemHandle = 0,
- NvRtObjType_NvRm_NvRmDmaHandle,
NvRtObjType_NvRm_NvRmI2cHandle,
NvRtObjType_NvRm_GpioHandle,
+ NvRtObjType_NvRm_NvRmDmaHandle,
+ NvRtObjType_NvRm_PinmuxClkHandle,
NvRtObjType_NvRm_Num,
NvRtObjType_NvRm_ForceWord = 0x7FFFFFFF
} NvRtObjType_NvRm;
diff --git a/arch/arm/mach-tegra/include/nvrm_pinmux.h b/arch/arm/mach-tegra/include/nvrm_pinmux.h
index bafe6a2655b4..2a92b9361563 100644
--- a/arch/arm/mach-tegra/include/nvrm_pinmux.h
+++ b/arch/arm/mach-tegra/include/nvrm_pinmux.h
@@ -114,6 +114,15 @@ extern "C"
NvU32 Config,
NvBool EnableTristate );
+/* maximum number of external clocks */
+#define NVRM_EXT_CLK_CNT 3
+
+typedef struct NvRmExternalClockObjRec
+{
+ NvU32 Instance;
+ NvU32 Config;
+} NvRmExternalClockObj;
+
typedef struct NvRmModuleSdmmcInterfaceCapsRec
{
diff --git a/arch/arm/mach-tegra/nvrm/dispatch/nvrm_pinmux_dispatch.c b/arch/arm/mach-tegra/nvrm/dispatch/nvrm_pinmux_dispatch.c
index 4064ca6e0029..52fb18c71065 100644
--- a/arch/arm/mach-tegra/nvrm/dispatch/nvrm_pinmux_dispatch.c
+++ b/arch/arm/mach-tegra/nvrm/dispatch/nvrm_pinmux_dispatch.c
@@ -32,6 +32,7 @@
#define NV_IDL_IS_DISPATCH
+#include <linux/kernel.h>
#include "nvcommon.h"
#include "nvos.h"
#include "nvassert.h"
@@ -237,6 +238,56 @@ static NvError NvRmExternalClockConfig_dispatch_( void *InBuffer, NvU32 InSize,
p_out->ret_ = NvRmExternalClockConfig( p_in->hDevice, p_in->IoModule, p_in->Instance, p_in->Config, p_in->EnableTristate );
+ printk(KERN_INFO "ioModule=%d, instance=%d, config=%d, enable=%d\n",
+ p_in->IoModule, p_in->Instance, p_in->Config, p_in->EnableTristate);
+
+ if ((p_out->ret_ > 0)
+ && (p_in->IoModule == NvOdmIoModule_ExternalClock))
+ {
+ NvRtObjRefHandle ref_pClk;
+ static NvRmExternalClockObj objs[NVRM_EXT_CLK_CNT] =
+ {
+ {NVRM_EXT_CLK_CNT,0},
+ {NVRM_EXT_CLK_CNT,0},
+ {NVRM_EXT_CLK_CNT,0}
+ };
+ if (p_in->EnableTristate == NV_FALSE)
+ {
+ if (objs[p_in->Instance].Instance == p_in->Instance)
+ {
+ /* If the instance number matches, this has already been
+ * added to reftrack, so we just update value "Config"
+ */
+ objs[p_in->Instance].Config = p_in->Config;
+ }
+ else
+ {
+ /* If the instance number doesn't match, there is only one
+ * possibility: the objs[p_in->Instance] is NVRM_EXT_CLK_CNT.
+ * In this case, we need to add a new ref tracking obj.
+ */
+ if (NvSuccess == (err_ = NvRtAllocObjRef(Ctx, &ref_pClk)))
+ {
+ objs[p_in->Instance].Instance = p_in->Instance;
+ objs[p_in->Instance].Config = p_in->Config;
+ NvRtStoreObjRef(Ctx,
+ ref_pClk,
+ NvRtObjType_NvRm_PinmuxClkHandle,
+ &objs[p_in->Instance]);
+ }
+ }
+ }
+ else
+ {
+ /* When tristating clock pins, we blindly remove it from nvreftrack
+ * obj store
+ */
+ NvRtFreeObjRef(Ctx,
+ NvRtObjType_NvRm_PinmuxClkHandle,
+ &objs[p_in->Instance]);
+ objs[p_in->Instance].Instance = NVRM_EXT_CLK_CNT;
+ }
+ }
return err_;
}
diff --git a/arch/arm/mach-tegra/nvrm_user.c b/arch/arm/mach-tegra/nvrm_user.c
index ec21afd71a91..db46298bd82d 100644
--- a/arch/arm/mach-tegra/nvrm_user.c
+++ b/arch/arm/mach-tegra/nvrm_user.c
@@ -120,47 +120,69 @@ static void client_detach(NvRtClientHandle client)
dctx.Rt = s_RtHandle;
dctx.Client = client;
dctx.PackageIdx = 0;
+
for (;;)
{
- NvBool found = NV_FALSE;
- if ((ptr = NvRtFreeObjRef(&dctx,
- NvRtObjType_NvRm_GpioHandle,
- NULL)) != NULL)
- {
- printk(KERN_INFO "close gpio handle in case something is wrong, GPIO handle: 0x%x\n", (NvU32)ptr);
- NvRmGpioReleasePinHandles((NvRmGpioHandle)s_hRmGlobal, (NvRmGpioPinHandle *)&ptr, 1);
- found = NV_TRUE;
- }
+ ptr = NvRtFreeObjRef(&dctx,
+ NvRtObjType_NvRm_GpioHandle,
+ NULL);
+ if (!ptr) break;
+ NVRT_LEAK("NvRm", "GpioHandle", (NvU32)ptr);
+ NvRmGpioReleasePinHandles((NvRmGpioHandle)s_hRmGlobal, (NvRmGpioPinHandle *)&ptr, 1);
+ }
- if ((ptr = NvRtFreeObjRef(&dctx,
- NvRtObjType_NvRm_NvRmMemHandle,
- NULL)) != NULL)
- {
- NVRT_LEAK("NvRm", "NvRmMemHandle", ptr);
- NvRmMemHandleFree(ptr);
- found = NV_TRUE;
- }
- if ((ptr = NvRtFreeObjRef(&dctx,
- NvRtObjType_NvRm_NvRmI2cHandle,
- NULL)) != NULL)
- {
- printk(KERN_INFO "close i2c in client_detach\n");
- NvRmI2cClose((NvRmI2cHandle)ptr);
- found = NV_TRUE;
- }
+ for (;;)
+ {
+ ptr = NvRtFreeObjRef(&dctx,
+ NvRtObjType_NvRm_NvRmMemHandle,
+ NULL);
+ if (!ptr) break;
+ NVRT_LEAK("NvRm", "NvRmMemHandle", (NvU32)ptr);
+ NvRmMemHandleFree(ptr);
+ }
- if ((ptr = NvRtFreeObjRef(&dctx,
- NvRtObjType_NvRm_NvRmDmaHandle,
- NULL)) != NULL)
- {
- NVRT_LEAK("NvRm", "NvRmDmaHandle", ptr);
- NvRmDmaFree(ptr);
- found = NV_TRUE;
- }
+ for(;;)
+ {
+ ptr = NvRtFreeObjRef(&dctx,
+ NvRtObjType_NvRm_NvRmI2cHandle,
+ NULL);
+ if (!ptr) break;
+ NVRT_LEAK("NvRm", "NvRmI2cHandle", (NvU32)ptr);
+ NvRmI2cClose((NvRmI2cHandle)ptr);
+ }
- if (found == NV_FALSE)
- break;
+ for(;;)
+ {
+ ptr = NvRtFreeObjRef(&dctx,
+ NvRtObjType_NvRm_NvRmDmaHandle,
+ NULL);
+ if(!ptr) break;
+ NVRT_LEAK("NvRm", "NvRmDmaHandle", (NvU32)ptr);
+ NvRmDmaFree(ptr);
+ }
+
+ for(;;)
+ {
+ NvRmExternalClockObj *obj = NULL;
+ ptr = NvRtFreeObjRef(&dctx,
+ NvRtObjType_NvRm_PinmuxClkHandle,
+ NULL);
+ if(!ptr) break;
+ NVRT_LEAK("NvRm", "PinmuxClkHandle", (NvU32)ptr);
+
+ obj = (NvRmExternalClockObj *)ptr;
+ NvRmExternalClockConfig(g_NvRmHandle,
+ NvOdmIoModule_ExternalClock,
+ obj->Instance,
+ obj->Config,
+ NV_TRUE);
+ /*
+ * this "obj" is a static struct in nvrm_pinmux_dispatch.c
+ * reset Instance number so it can be reused for next clock
+ * config
+ */
+ obj->Instance = NVRM_EXT_CLK_CNT;
}
NvRtUnregisterClient(s_RtHandle, client);