From 1bc517b59d5cc44e10f173ea96d9686053ab0bcd Mon Sep 17 00:00:00 2001 From: James Wylder Date: Tue, 1 Mar 2011 09:25:06 -0600 Subject: [PATCH] ARM: tegra: add generic memory vendor matching Update tegra_init_emc to provide generic memory vendor matching. Read values from EMC_MRR_0, to uniquely identify memory types and compare them to table of memory passed in. Change-Id: Ie116fa6f497076149c87ff6c0ae0621309bac65f Signed-off-by: James Wylder --- arch/arm/mach-tegra/tegra2_emc.c | 85 ++++++++++++++++++++++++++++++-- arch/arm/mach-tegra/tegra2_emc.h | 13 ++++- 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c index bd4fa27b2086..47ba71672b86 100644 --- a/arch/arm/mach-tegra/tegra2_emc.c +++ b/arch/arm/mach-tegra/tegra2_emc.c @@ -25,6 +25,11 @@ #include "tegra2_emc.h" +#define TEGRA_MRR_DIVLD (1<<20) +#define TEGRA_EMC_STATUS 0x02b4 +#define TEGRA_EMC_MRR 0x00ec +static DEFINE_MUTEX(tegra_emc_mrr_lock); + #ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE static bool emc_enable = true; #else @@ -46,6 +51,35 @@ static inline u32 emc_readl(unsigned long addr) return readl(emc + addr); } +/* read LPDDR2 memory modes */ +static int tegra_emc_read_mrr(unsigned long addr) +{ + u32 value; + int count = 100; + + mutex_lock(&tegra_emc_mrr_lock); + do { + emc_readl(TEGRA_EMC_MRR); + } while (--count && (emc_readl(TEGRA_EMC_STATUS) & TEGRA_MRR_DIVLD)); + if (count == 0) { + pr_err("%s: Failed to read memory type\n", __func__); + BUG(); + } + value = (1 << 30) | (addr << 16); + emc_writel(value, TEGRA_EMC_MRR); + + count = 100; + while (--count && !(emc_readl(TEGRA_EMC_STATUS) & TEGRA_MRR_DIVLD)); + if (count == 0) { + pr_err("%s: Failed to read memory type\n", __func__); + BUG(); + } + value = emc_readl(TEGRA_EMC_MRR) & 0xFFFF; + mutex_unlock(&tegra_emc_mrr_lock); + + return value; +} + static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { 0x2c, /* RC */ 0x30, /* RFC */ @@ -165,8 +199,53 @@ int tegra_emc_set_rate(unsigned long rate) return 0; } -void tegra_init_emc(const struct tegra_emc_table *table, int table_size) +void tegra_init_emc(const struct tegra_emc_chip *chips, int chips_size) { - tegra_emc_table = table; - tegra_emc_table_size = table_size; + int i; + int vid; + int rev_id1; + int rev_id2; + int pid; + int chip_matched = -1; + + vid = tegra_emc_read_mrr(5); + rev_id1 = tegra_emc_read_mrr(6); + rev_id2 = tegra_emc_read_mrr(7); + pid = tegra_emc_read_mrr(8); + + for (i = 0; i < chips_size; i++) { + if (chips[i].mem_manufacturer_id >= 0) { + if (chips[i].mem_manufacturer_id != vid) + continue; + } + if (chips[i].mem_revision_id1 >= 0) { + if (chips[i].mem_revision_id1 != rev_id1) + continue; + } + if (chips[i].mem_revision_id2 >= 0) { + if (chips[i].mem_revision_id2 != rev_id2) + continue; + } + if (chips[i].mem_pid >= 0) { + if (chips[i].mem_pid != pid) + continue; + } + + chip_matched = i; + break; + } + + if (chip_matched >= 0) { + pr_info("%s: %s memory found\n", __func__, + chips[chip_matched].description); + tegra_emc_table = chips[chip_matched].table; + tegra_emc_table_size = chips[chip_matched].table_size; + } else { + pr_err("%s: Memory not recognized, memory scaling disabled\n", + __func__); + pr_info("%s: Memory vid = 0x%04x", __func__, vid); + pr_info("%s: Memory rev_id1 = 0x%04x", __func__, rev_id1); + pr_info("%s: Memory rev_id2 = 0x%04x", __func__, rev_id2); + pr_info("%s: Memory pid = 0x%04x", __func__, pid); + } } diff --git a/arch/arm/mach-tegra/tegra2_emc.h b/arch/arm/mach-tegra/tegra2_emc.h index 3515e57fd0d9..4f060f7355d6 100644 --- a/arch/arm/mach-tegra/tegra2_emc.h +++ b/arch/arm/mach-tegra/tegra2_emc.h @@ -22,6 +22,17 @@ struct tegra_emc_table { u32 regs[TEGRA_EMC_NUM_REGS]; }; +struct tegra_emc_chip { + const char *description; + int mem_manufacturer_id; /* LPDDR2 MR5 or -1 to ignore */ + int mem_revision_id1; /* LPDDR2 MR6 or -1 to ignore */ + int mem_revision_id2; /* LPDDR2 MR7 or -1 to ignore */ + int mem_pid; /* LPDDR2 MR8 or -1 to ignore */ + + const struct tegra_emc_table *table; + int table_size; +}; + int tegra_emc_set_rate(unsigned long rate); long tegra_emc_round_rate(unsigned long rate); -void tegra_init_emc(const struct tegra_emc_table *table, int table_size); +void tegra_init_emc(const struct tegra_emc_chip *chips, int chips_size); -- 2.34.1