summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2010-09-11 21:20:57 -0700
committerVarun Colbert <vcolbert@nvidia.com>2010-10-12 22:36:09 -0700
commitbd56f15ff5f6cde67a23ee7b2acfa46c267d21f8 (patch)
tree192d487a4e313d0916937eb1e5675cddbf7ad278
parentd15bba7c21d6cbe34ec44394d3b87e7a34d6469a (diff)
[ARM/tegra] RM: Restarted EMC digital dll.
Restarted EMC digital dll after EMC clock change. Bug 722440 Change-Id: Id8b0ea4381302eb9dec85757840587d782a7a793 Reviewed-on: http://git-master/r/8259 Tested-by: Aleksandr Frid <afrid@nvidia.com> Reviewed-by: Hoang Pham <hopham@nvidia.com> Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_clock_config.c46
1 files changed, 43 insertions, 3 deletions
diff --git a/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_clock_config.c b/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_clock_config.c
index 740c5527c7d8..ca9bce2f9270 100644
--- a/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_clock_config.c
+++ b/arch/arm/mach-tegra/nvrm/core/ap20/ap20rm_clock_config.c
@@ -520,6 +520,9 @@ static void Ap20EmcConfigInit(NvRmDeviceHandle hRmDevice)
}
}
+// EMC module virtual base address to speed up timing update
+static void* s_pEmcBaseReg = NULL;
+
static void
Ap20EmcTimingSet(
NvRmDeviceHandle hRmDevice,
@@ -527,9 +530,6 @@ Ap20EmcTimingSet(
{
NvU32 i, a, d;
- // EMC module virtual base address to speed up timing update
- static void* s_pEmcBaseReg = NULL;
-
if (s_pEmcBaseReg == NULL)
{
NvRmModuleTable *tbl = NvRmPrivGetModuleTable(hRmDevice);
@@ -547,6 +547,43 @@ Ap20EmcTimingSet(
a = (((NvU32)(s_pEmcBaseReg)) + s_Ap20EmcConfig.pEmcTimingReg[i]);
NV_WRITE32(a, d);
}
+
+ // Clear clock change interrupt status (write 1 to clear)
+ a = (((NvU32)(s_pEmcBaseReg)) + EMC_INTSTATUS_0);
+ d = NV_DRF_NUM(EMC, INTSTATUS, CLKCHANGE_COMPLETE_INT, 1);
+ NV_WRITE32(a, d);
+
+ d = NV_READ32(a); // make sure writes are completed
+}
+
+static void
+Ap20EmcTimingSetFinish(
+ NvRmDeviceHandle hRmDevice,
+ const NvRmAp20EmcTimingConfig* pEmcConfig)
+{
+ NvU32 a, d;
+ NV_ASSERT(s_pEmcBaseReg);
+
+ // After EMC clock change is completed, digital DLL should be restarted
+ // (provided it is enabled for current EMC frequency)
+ if (!NV_DRF_VAL(EMC, CFG_DIG_DLL, CFG_DLL_EN, pEmcConfig->EmcDigDll))
+ return;
+
+ a = (((NvU32)(s_pEmcBaseReg)) + EMC_INTSTATUS_0);
+ for (;;)
+ {
+ d = NV_DRF_VAL(EMC, INTSTATUS, CLKCHANGE_COMPLETE_INT, NV_READ32(a));
+ if (d)
+ break;
+ }
+
+ a = (((NvU32)(s_pEmcBaseReg)) + EMC_CFG_DIG_DLL_0);
+ NV_WRITE32(a, pEmcConfig->EmcDigDll);
+ d = NV_READ32(a); // make sure writes are completed
+
+ a = (((NvU32)(s_pEmcBaseReg)) + EMC_TIMING_CONTROL_0);
+ d = NV_DRF_NUM(EMC, TIMING_CONTROL, TIMING_UPDATE, 1);
+ NV_WRITE32(a, d);
d = NV_READ32(a); // make sure writes are completed
}
@@ -615,6 +652,7 @@ Ap20EmcSwitchToUndividedPllM0(
NV_REGW(hRmDevice, NvRmPrivModuleID_ClockAndReset, 0,
CLK_RST_CONTROLLER_CLK_SOURCE_EMC_0, reg);
NvOsWaitUS(NVRM_CLOCK_CHANGE_DELAY);
+ Ap20EmcTimingSetFinish(hRmDevice, pEmcConfig);
// Now set new divider value. Note that PLLM_UD bit is already set, so
// the actual EMC frequency is not changed. Hence, no need to update EMC
@@ -657,6 +695,7 @@ Ap20EmcSwitchFromUndividedPllM0(
NV_REGW(hRmDevice, NvRmPrivModuleID_ClockAndReset, 0,
CLK_RST_CONTROLLER_CLK_SOURCE_EMC_0, reg);
NvOsWaitUS(NVRM_CLOCK_CHANGE_DELAY);
+ Ap20EmcTimingSetFinish(hRmDevice, pEmcConfig);
// Update EMC state
s_Ap20EmcConfig.UdPllM0 = NV_FALSE;
@@ -696,6 +735,7 @@ Ap20EmcSwitchDividedSources(
NV_REGW(hRmDevice, NvRmPrivModuleID_ClockAndReset, 0,
CLK_RST_CONTROLLER_CLK_SOURCE_EMC_0, reg);
NvOsWaitUS(NVRM_CLOCK_CHANGE_DELAY);
+ Ap20EmcTimingSetFinish(hRmDevice, pEmcConfig);
// Update EMC state (undivided path status not changed)
NV_ASSERT(!s_Ap20EmcConfig.UdPllM0);