diff options
author | James Wylder <james.wylder@motorola.com> | 2011-03-01 09:25:06 -0600 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2011-03-03 18:54:12 -0800 |
commit | 1bc517b59d5cc44e10f173ea96d9686053ab0bcd (patch) | |
tree | c019bcad5ad17cc4512333fd0add005fa046c3d0 /arch | |
parent | 8e15ee8536752c0ae321c80ee4d156c14cbb4d92 (diff) |
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 <james.wylder@motorola.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-tegra/tegra2_emc.c | 85 | ||||
-rw-r--r-- | 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); |