diff options
author | Alex Frid <afrid@nvidia.com> | 2012-08-29 23:39:48 -0700 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-10-22 13:54:37 -0700 |
commit | 4961bce1cf1ad0fe6e71234e84d843dbfa1331ef (patch) | |
tree | 8972531e3b047094517aee072d1afdae219b16e2 /arch/arm/mach-tegra/tegra11_emc.c | |
parent | d96f279f09c214a6196625f14b880c4e4c863311 (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.c | 79 |
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; |