diff options
author | byan <byan@nvidia.com> | 2010-11-09 12:37:37 -0800 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2010-11-29 11:24:59 -0800 |
commit | 1ce2f5538e754957fe2f888fbcbccba41c5a6fd6 (patch) | |
tree | e3984c77f8d029da54fe03bd45d9960976834375 /arch/arm/mach-tegra | |
parent | 05074ac6ce18a61467ad6d5dd5e53d56725c8d58 (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.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/nvrm_pinmux.h | 9 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvrm/dispatch/nvrm_pinmux_dispatch.c | 51 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvrm_user.c | 92 |
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); |