[ARM] tegra: nvrm: add basic implementation of clock controls

add support for enabling, disabling and configuring the ISP, VI and
CSI clocks from user-space through the RM APIs

Change-Id: I652af05d5406928721ac62371b85cb3e2cbb3f6b
Signed-off-by: Gary King <gking@nvidia.com>
This commit is contained in:
Gary King 2010-07-21 15:08:57 -07:00 committed by Colin Cross
parent 11d90deeb8
commit e562176306
6 changed files with 217 additions and 1690 deletions

View File

@ -12,4 +12,5 @@ ccflags-y += -Iarch/arm/mach-tegra/nv/nvrm/core
obj-y += nvrm_rmctrace.o
obj-y += nvrm_transport.o
obj-y += nvrm_module_stub.o
obj-y += nvrm_module_stub.o
obj-y += nvrm_power.o

View File

@ -12,11 +12,14 @@
*/
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <mach/iomap.h>
#include "nvcommon.h"
#include "nvrm_module.h"
#include "../../../../clock.h"
NvError NvRmModuleGetCapabilities( NvRmDeviceHandle hDeviceHandle,
NvRmModuleID Module, NvRmModuleCapability * pCaps, NvU32 NumCaps,
@ -160,18 +163,37 @@ void NvRmModuleGetBaseAddress( NvRmDeviceHandle hRmDeviceHandle, NvRmModuleID Mo
printk("%s module %d 0x%08x x %dK\n", __func__, Module, *pBaseAddress, *pSize / 1024);
}
#define is_avp(_mod) (NVRM_MODULE_ID_MODULE(_mod)==NvRmModuleID_Avp)
#define is_csi(_mod) (NVRM_MODULE_ID_MODULE(_mod)==NvRmModuleID_Csi)
#define is_isp(_mod) (NVRM_MODULE_ID_MODULE(_mod)==NvRmModuleID_Isp)
#define is_vi(_mod) (NVRM_MODULE_ID_MODULE(_mod)==NvRmModuleID_Vi)
void NvRmModuleReset(NvRmDeviceHandle hRmDevice, NvRmModuleID Module)
{
struct clk *clk = NULL;
void __iomem *clk_rst = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
if (NVRM_MODULE_ID_MODULE(Module) != NvRmModuleID_Avp ||
NVRM_MODULE_ID_INSTANCE(Module) != 0) {
if (is_avp(Module)) {
writel(1<<1, clk_rst + 0x300);
udelay(10);
writel(1<<1, clk_rst + 0x304);
} else if (is_csi(Module))
clk = clk_get_sys("csi", NULL);
else if (is_vi(Module))
clk = clk_get_sys("vi", NULL);
else if (is_isp(Module))
clk = clk_get_sys("isp", NULL);
else {
printk("%s MOD[%lu] INST[%lu] not implemented\n", __func__,
NVRM_MODULE_ID_MODULE(Module),
NVRM_MODULE_ID_INSTANCE(Module));
return;
}
writel(1<<1, clk_rst + 0x300);
udelay(10);
writel(1<<1, clk_rst + 0x304);
if (clk) {
tegra2_periph_reset_assert(clk);
udelay(10);
tegra2_periph_reset_deassert(clk);
clk_put(clk);
}
}

View File

@ -0,0 +1,185 @@
/*
* Copyright (c) 2010 NVIDIA Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NVIDIA Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <mach/iomap.h>
#include "nvcommon.h"
#include "nvrm_power.h"
#include "../../../../clock.h"
#define is_vi(module) (NVRM_MODULE_ID_MODULE(module)==NvRmModuleID_Vi)
#define is_csi(module) (NVRM_MODULE_ID_MODULE(module)==NvRmModuleID_Csi)
#define is_isp(module) (NVRM_MODULE_ID_MODULE(module)==NvRmModuleID_Isp)
#define CLK_VI_CORE_EXTERNAL (1<<24)
#define CLK_VI_PAD_INTERNAL (1<<25)
NvError NvRmPowerModuleClockConfig(
NvRmDeviceHandle hRmDeviceHandle,
NvRmModuleID ModuleId,
NvU32 ClientId,
NvRmFreqKHz MinFreq,
NvRmFreqKHz MaxFreq,
const NvRmFreqKHz *PrefFreqList,
NvU32 PrefFreqListCount,
NvRmFreqKHz *CurrentFreq,
NvU32 flags)
{
struct clk *clk = NULL;
const char *name;
unsigned long rate;
int ret;
if (CurrentFreq)
*CurrentFreq = 0;
if (!is_vi(ModuleId))
return NvSuccess;
if (flags & NvRmClockConfig_SubConfig)
name = "vi_sensor";
else
name = "vi";
clk = clk_get_sys(name, NULL);
if (IS_ERR_OR_NULL(clk)) {
pr_err("%s: failed to get struct clk %s\n", __func__, name);
return NvSuccess;
}
if (PrefFreqListCount)
rate = *PrefFreqList * 1000;
else if (MaxFreq != NvRmFreqUnspecified)
rate = MaxFreq * 1000;
else if (MinFreq != NvRmFreqUnspecified)
rate = MinFreq * 1000;
else
rate = INT_MAX;
ret = clk_set_rate(clk, rate);
if (ret) {
pr_err("%s: err %d setting %s to %luHz\n", __func__, ret, name, rate);
clk_put(clk);
return NvError_BadParameter;
}
rate = clk_get_rate(clk);
if (CurrentFreq)
*CurrentFreq = (rate+500) / 1000;
if (!(flags & NvRmClockConfig_SubConfig)) {
void __iomem *car = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
u32 val;
if ((flags & NvRmClockConfig_InternalClockForPads) &&
(flags & NvRmClockConfig_ExternalClockForCore)) {
pr_err("%s: invalid VI flag combination: %08x\n", __func__, flags);
clk_put(clk);
return NvError_BadParameter;
}
val = readl(car + clk->reg);
val &= ~(CLK_VI_CORE_EXTERNAL | CLK_VI_PAD_INTERNAL);
if (flags & NvRmClockConfig_InternalClockForPads)
val |= CLK_VI_PAD_INTERNAL;
else if (flags & NvRmClockConfig_ExternalClockForCore)
val |= CLK_VI_CORE_EXTERNAL;
writel(val, car + clk->reg);
}
clk_put(clk);
return NvSuccess;
}
NvError NvRmPowerModuleClockControl(
NvRmDeviceHandle hRmDeviceHandle,
NvRmModuleID ModuleId,
NvU32 ClientId,
NvBool Enable)
{
const char *vi_names[] = { "vi", "vi_sensor", "csus", NULL };
const char *csi_names[] = { "csi", NULL };
const char *isp_names[] = { "isp", NULL };
const char **names = NULL;
if (is_vi(ModuleId))
names = vi_names;
else if (is_csi(ModuleId))
names = csi_names;
else if (is_isp(ModuleId))
names = isp_names;
if (!names) {
pr_err("%s: MOD[%lu] INST[%lu] not supported\n", __func__,
NVRM_MODULE_ID_MODULE(ModuleId),
NVRM_MODULE_ID_INSTANCE(ModuleId));
return NvSuccess;
}
for ( ; *names ; names++) {
struct clk *clk = clk_get_sys(*names, NULL);
if (IS_ERR_OR_NULL(clk)) {
pr_err("%s: unable to get struct clk for %s\n", __func__, *names);
continue;
}
if (Enable)
clk_enable(clk);
else
clk_disable(clk);
}
return NvSuccess;
}
NvError NvRmPowerVoltageControl(
NvRmDeviceHandle hRmDeviceHandle,
NvRmModuleID ModuleId,
NvU32 ClientId,
NvRmMilliVolts MinVolts,
NvRmMilliVolts MaxVolts,
const NvRmMilliVolts * PrefVoltageList,
NvU32 PrefVoltageListCount,
NvRmMilliVolts * CurrentVolts)
{
return NvSuccess;
}

View File

@ -21,7 +21,7 @@ obj-y += NvRm_Dispatch.o
#obj-y += nvrm_memmgr_dispatch.o
obj-y += nvrm_module_dispatch.o
#obj-y += nvrm_pinmux_dispatch.o
#obj-y += nvrm_power_dispatch.o
obj-y += nvrm_power_dispatch.o
#obj-y += nvrm_spi_dispatch.o
#obj-y += nvrm_pmu_dispatch.o
#obj-y += nvrm_keylist_dispatch.o

View File

@ -162,12 +162,6 @@ NvError nvrm_dma_Dispatch( NvU32 function, void *InBuffer, NvU32 InSize, void *O
return NvSuccess;
}
NvError nvrm_power_Dispatch( NvU32 function, void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
{
printk("NVRM: %s %d\n", __func__, function);
return NvSuccess;
}
NvError nvrm_gpio_Dispatch( NvU32 function, void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx )
{
printk("NVRM: %s %d\n", __func__, function);

File diff suppressed because it is too large Load Diff