summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra11_emc.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2012-08-29 23:39:48 -0700
committerSimone Willett <swillett@nvidia.com>2012-10-22 13:54:37 -0700
commit4961bce1cf1ad0fe6e71234e84d843dbfa1331ef (patch)
tree8972531e3b047094517aee072d1afdae219b16e2 /arch/arm/mach-tegra/tegra11_emc.c
parentd96f279f09c214a6196625f14b880c4e4c863311 (diff)
ARM: tegra11: power: Read LPDDR2/3 temperature
Change-Id: I52ab569c3568f7e47c5d4a5ce6f151fa51bbad08 Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/132380 Signed-off-by: Bharat Nihalani <bnihalani@nvidia.com> Reviewed-on: http://git-master/r/146244 Reviewed-by: Automatic_Commit_Validation_User
Diffstat (limited to 'arch/arm/mach-tegra/tegra11_emc.c')
-rw-r--r--arch/arm/mach-tegra/tegra11_emc.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/tegra11_emc.c b/arch/arm/mach-tegra/tegra11_emc.c
index 1f3f4946b483..30db73b89c76 100644
--- a/arch/arm/mach-tegra/tegra11_emc.c
+++ b/arch/arm/mach-tegra/tegra11_emc.c
@@ -254,6 +254,7 @@ static const struct tegra11_emc_table *emc_timing;
static ktime_t clkchange_time;
static int clkchange_delay = 100;
+static const u32 *dram_to_soc_bit_map;
static const struct tegra11_emc_table *tegra_emc_table;
static int tegra_emc_table_size;
@@ -1066,6 +1067,72 @@ int tegra_emc_get_dram_type(void)
return dram_type;
}
+static u32 soc_to_dram_bit_swap(u32 soc_val, u32 dram_mask, u32 dram_shift)
+{
+ int bit;
+ u32 dram_val = 0;
+
+ /* tegra clocks definitions use shifted mask always */
+ if (!dram_to_soc_bit_map)
+ return soc_val & dram_mask;
+
+ for (bit = dram_shift; bit < 32; bit++) {
+ u32 dram_bit_mask = 0x1 << bit;
+ u32 soc_bit_mask = dram_to_soc_bit_map[bit];
+
+ if (!(dram_bit_mask & dram_mask))
+ break;
+
+ if (soc_bit_mask & soc_val)
+ dram_val |= dram_bit_mask;
+ }
+
+ return dram_val;
+}
+
+static int emc_read_mrr(int dev, int addr)
+{
+ int ret;
+ u32 val;
+
+ if (dram_type != DRAM_TYPE_LPDDR2)
+ return -ENODEV;
+
+ ret = wait_for_update(EMC_STATUS, EMC_STATUS_MRR_DIVLD, false);
+ if (ret)
+ return ret;
+
+ val = dev ? DRAM_DEV_SEL_1 : DRAM_DEV_SEL_0;
+ val |= (addr << EMC_MRR_MA_SHIFT) & EMC_MRR_MA_MASK;
+ emc_writel(val, EMC_MRR);
+
+ ret = wait_for_update(EMC_STATUS, EMC_STATUS_MRR_DIVLD, true);
+ if (ret)
+ return ret;
+
+ val = emc_readl(EMC_MRR) & EMC_MRR_DATA_MASK;
+ return val;
+}
+
+int tegra_emc_get_dram_temperature(void)
+{
+ int mr4;
+ unsigned long flags;
+
+ spin_lock_irqsave(&emc_access_lock, flags);
+
+ mr4 = emc_read_mrr(0, 4);
+ if (IS_ERR_VALUE(mr4)) {
+ spin_unlock_irqrestore(&emc_access_lock, flags);
+ return mr4;
+ }
+ spin_unlock_irqrestore(&emc_access_lock, flags);
+
+ mr4 = soc_to_dram_bit_swap(
+ mr4, LPDDR2_MR4_TEMP_MASK, LPDDR2_MR4_TEMP_SHIFT);
+ return mr4;
+}
+
#ifdef CONFIG_DEBUG_FS
static struct dentry *emc_debugfs_root;
@@ -1104,6 +1171,14 @@ static const struct file_operations emc_stats_fops = {
.release = single_release,
};
+static int dram_temperature_get(void *data, u64 *val)
+{
+ *val = tegra_emc_get_dram_temperature();
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(dram_temperature_fops, dram_temperature_get,
+ NULL, "%lld\n");
+
static int efficiency_get(void *data, u64 *val)
{
*val = tegra_emc_bw_efficiency;
@@ -1137,6 +1212,10 @@ static int __init tegra_emc_debug_init(void)
emc_debugfs_root, (u32 *)&clkchange_delay))
goto err_out;
+ if (!debugfs_create_file("dram_temperature", S_IRUGO, emc_debugfs_root,
+ NULL, &dram_temperature_fops))
+ goto err_out;
+
if (!debugfs_create_file("efficiency", S_IRUGO | S_IWUSR,
emc_debugfs_root, NULL, &efficiency_fops))
goto err_out;