diff options
author | Jay Bhukhanwala <jbhukhanwala@nvidia.com> | 2013-08-21 12:52:28 -0700 |
---|---|---|
committer | Graziano Misuraca <gmisuraca@nvidia.com> | 2013-10-23 13:05:25 -0700 |
commit | ea0661d9dbe19e9e4b5c6d425766e44e987d16c7 (patch) | |
tree | e48d27c5446d8a3136e88582505465b6dbdb2db6 | |
parent | b93cf600fb36f90dc477c2b2138617d546b13e28 (diff) |
ARM: Tegra12: Ardbeg: NCT: Load EMC tables
Adds functionality to load the EMC table from the NCT
partition. If no memory table is in NCT or the NCT
partition doesn't exist, fall back to the built-in table.
Bug 1300925
Change-Id: I09c13443600c987884f67520ca72a7702e052837
Signed-off-by: Jay Bhukhanwala <jbhukhanwala@nvidia.com>
Signed-off-by: Ray Poudrier <rapoudrier@nvidia.com>
Signed-off-by: Graziano Misuraca <gmisuraca@nvidia.com>
Reviewed-on: http://git-master/r/289290
GVS: Gerrit_Virtual_Submit
Reviewed-by: Thomas Cherry <tcherry@nvidia.com>
-rw-r--r-- | arch/arm/mach-tegra/board-ardbeg-memory.c | 47 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/nct.h | 12 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra12_emc.c | 84 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra12_emc.h | 5 | ||||
-rw-r--r-- | include/linux/platform_data/tegra_emc.h | 10 |
5 files changed, 139 insertions, 19 deletions
diff --git a/arch/arm/mach-tegra/board-ardbeg-memory.c b/arch/arm/mach-tegra/board-ardbeg-memory.c index 36a49627cdac..e6d2ce0dfd74 100644 --- a/arch/arm/mach-tegra/board-ardbeg-memory.c +++ b/arch/arm/mach-tegra/board-ardbeg-memory.c @@ -5432,11 +5432,16 @@ static struct tegra12_emc_table ardbeg_lpddr3_emc_table[] = { }, }; +#ifdef CONFIG_TEGRA_USE_NCT +static struct tegra12_emc_pdata board_emc_pdata; +#endif + static struct tegra12_emc_pdata ardbeg_emc_pdata = { .description = "ardbeg_emc_tables", .tables = ardbeg_emc_table, .num_tables = ARRAY_SIZE(ardbeg_emc_table), }; + static struct tegra12_emc_pdata ardbeg_lpddr3_emc_pdata = { .description = "ardbeg_emc_tables", .tables = ardbeg_lpddr3_emc_table, @@ -5450,22 +5455,36 @@ int __init ardbeg_emc_init(void) { struct board_info bi; - tegra_get_board_info(&bi); + /* + * If the EMC table is successfully read from the NCT partition, + * we do not need to check for board ids and blindly load the one + * flashed on the NCT partition. + */ + #ifdef CONFIG_TEGRA_USE_NCT + if (!tegra12_nct_emc_table_init(&board_emc_pdata)) { + tegra_emc_device.dev.platform_data = &board_emc_pdata; + pr_info("Loading EMC table read from NCT partition.\n"); + } else { + #endif + tegra_get_board_info(&bi); - - switch (bi.board_id) { - case BOARD_E1780: - pr_info("Loading Ardbeg EMC tables.\n"); - tegra_emc_device.dev.platform_data = &ardbeg_emc_pdata; - break; - case BOARD_E1792: - pr_info("Loading Ardbeg EMC tables.\n"); - tegra_emc_device.dev.platform_data = &ardbeg_lpddr3_emc_pdata; - break; - default: - WARN(1, "Invalid board ID: %u\n", bi.board_id); - return -EINVAL; + switch (bi.board_id) { + case BOARD_E1780: + pr_info("Loading Ardbeg EMC tables.\n"); + tegra_emc_device.dev.platform_data = &ardbeg_emc_pdata; + break; + case BOARD_E1792: + pr_info("Loading Ardbeg EMC tables.\n"); + tegra_emc_device.dev.platform_data = &ardbeg_lpddr3_emc_pdata; + break; + default: + WARN(1, "Invalid board ID: %u\n", bi.board_id); + return -EINVAL; + } + #ifdef CONFIG_TEGRA_USE_NCT } + #endif + platform_device_register(&tegra_emc_device); tegra12_emc_init(); return 0; diff --git a/arch/arm/mach-tegra/include/mach/nct.h b/arch/arm/mach-tegra/include/mach/nct.h index dc4a8a91e3bb..2cee12a5f23b 100644 --- a/arch/arm/mach-tegra/include/mach/nct.h +++ b/arch/arm/mach-tegra/include/mach/nct.h @@ -21,6 +21,8 @@ #ifndef __MACH_TEGRA_NCT_H #define __MACH_TEGRA_NCT_H +#include <linux/platform_data/tegra_emc.h> + #define NCT_MAGIC_ID 0x7443566E /* "nVCt" */ #define NCT_FORMAT_VERSION 0x00010000 /* 0xMMMMNNNN (VMMMM.NNNN) */ @@ -51,7 +53,9 @@ enum nct_id_type { NCT_ID_CHARGER_ID, NCT_ID_TOUCH_ID, NCT_ID_FUELGAUGE_ID, - NCT_ID_END = NCT_ID_FUELGAUGE_ID, + NCT_ID_MEMTABLE, + NCT_ID_MEMTABLE_END = NCT_ID_MEMTABLE + TEGRA_EMC_MAX_FREQS - 1, + NCT_ID_END = NCT_ID_MEMTABLE_END, NCT_ID_DISABLED = 0xEEEE, NCT_ID_MAX = 0xFFFF }; @@ -92,6 +96,11 @@ struct nct_board_info_type { u16 minor_revision; }; +union nct_tegra_emc_table_type { + struct tegra12_emc_table tegra12_emc_table; +} __packed; + + union nct_item_type { struct nct_serial_number_type serial_number; struct nct_wifi_mac_addr_type wifi_mac_addr; @@ -110,6 +119,7 @@ union nct_item_type { struct nct_lbh_id_type charger_id; struct nct_lbh_id_type touch_id; u8 fuelgauge_id[MAX_NCT_DATA_SIZE]; + union nct_tegra_emc_table_type tegra_emc_table; u8 u8[MAX_NCT_DATA_SIZE]; u16 u16[MAX_NCT_DATA_SIZE/2]; u32 u32[MAX_NCT_DATA_SIZE/4]; diff --git a/arch/arm/mach-tegra/tegra12_emc.c b/arch/arm/mach-tegra/tegra12_emc.c index 36471c91fe56..6286d6af18a6 100644 --- a/arch/arm/mach-tegra/tegra12_emc.c +++ b/arch/arm/mach-tegra/tegra12_emc.c @@ -30,6 +30,8 @@ #include <linux/seq_file.h> #include <linux/hrtimer.h> #include <linux/pasr.h> +#include <linux/slab.h> +#include <mach/nct.h> #include <asm/cputime.h> @@ -1479,6 +1481,88 @@ int tegra_emc_get_dram_temperature(void) return mr4; } +#ifdef CONFIG_TEGRA_USE_NCT +int tegra12_nct_emc_table_init(struct tegra12_emc_pdata *nct_emc_pdata) +{ + union nct_item_type *entry = NULL; + struct tegra12_emc_table *mem_table_ptr; + u8 *src, *dest; + unsigned int i, non_zero_freqs; + int ret = 0; + + /* Allocating memory for holding a single NCT entry */ + entry = kmalloc(sizeof(union nct_item_type), GFP_KERNEL); + if (!entry) { + pr_err("%s: failed to allocate buffer for single entry. ", + __func__); + ret = -ENOMEM; + goto done; + } + src = (u8 *)entry; + + /* Counting the actual number of frequencies present in the table */ + non_zero_freqs = 0; + for (i = 0; i < TEGRA_EMC_MAX_FREQS; i++) { + if (!tegra_nct_read_item(NCT_ID_MEMTABLE + i, entry)) { + if (entry->tegra_emc_table.tegra12_emc_table.rate > 0) { + non_zero_freqs++; + pr_info("%s: Found NCT item for freq %lu.\n", + __func__, + entry->tegra_emc_table.tegra12_emc_table.rate); + } else + break; + } else { + pr_err("%s: NCT: Could not read item for %dth freq.\n", + __func__, i); + ret = -EIO; + goto free_entry; + } + } + + /* Allocating memory for the DVFS table */ + mem_table_ptr = kmalloc(sizeof(struct tegra12_emc_table) * + non_zero_freqs, GFP_KERNEL); + if (!mem_table_ptr) { + pr_err("%s: Memory allocation for emc table failed.", + __func__); + ret = -ENOMEM; + goto free_entry; + } + + /* Copy paste the emc table from NCT partition */ + for (i = 0; i < non_zero_freqs; i++) { + /* + * We reset the whole buffer, to emulate the property + * of a static variable being initialized to zero + */ + memset(entry, 0, sizeof(*entry)); + ret = tegra_nct_read_item(NCT_ID_MEMTABLE + i, entry); + if (!ret) { + dest = (u8 *)mem_table_ptr + (i * sizeof(struct + tegra12_emc_table)); + memcpy(dest, src, sizeof(struct tegra12_emc_table)); + } else { + pr_err("%s: Could not copy item for %dth freq.\n", + __func__, i); + goto free_mem_table_ptr; + } + } + + /* Setting appropriate pointers */ + nct_emc_pdata->tables = mem_table_ptr; + nct_emc_pdata->num_tables = non_zero_freqs; + + goto free_entry; + +free_mem_table_ptr: + kfree(mem_table_ptr); +free_entry: + kfree(entry); +done: + return ret; +} +#endif + #ifdef CONFIG_DEBUG_FS static struct dentry *emc_debugfs_root; diff --git a/arch/arm/mach-tegra/tegra12_emc.h b/arch/arm/mach-tegra/tegra12_emc.h index 2e0b3640d5c0..bb2d4ac64568 100644 --- a/arch/arm/mach-tegra/tegra12_emc.h +++ b/arch/arm/mach-tegra/tegra12_emc.h @@ -23,9 +23,14 @@ #define _MACH_TEGRA_TEGRA12_EMC_H #include "tegra_emc.h" +#include <linux/platform_data/tegra_emc.h> int tegra12_emc_init(void); +#ifdef CONFIG_TEGRA_USE_NCT +extern int tegra12_nct_emc_table_init(struct tegra12_emc_pdata *nct_emc_pdata); +#endif + enum { DRAM_DEV_SEL_ALL = 0, DRAM_DEV_SEL_0 = (2 << 30), diff --git a/include/linux/platform_data/tegra_emc.h b/include/linux/platform_data/tegra_emc.h index 302d83a94e4b..b69e4ae127e8 100644 --- a/include/linux/platform_data/tegra_emc.h +++ b/include/linux/platform_data/tegra_emc.h @@ -23,6 +23,7 @@ #define TEGRA14_MAX_TABLE_ID_LEN 16 #define TEGRA12_MAX_TABLE_ID_LEN 60 +#define TEGRA_EMC_MAX_FREQS 20 #define TEGRA_EMC_NUM_REGS 46 #define TEGRA30_EMC_NUM_REGS 110 @@ -147,8 +148,9 @@ struct tegra14_emc_pdata { struct tegra14_emc_table *tables_derated; }; -#define TEGRA12_EMC_MAX_NUM_REGS 200 -#define TEGRA12_EMC_MAX_UP_DOWN_REGS 40 +#define TEGRA12_EMC_MAX_NUM_REGS 200 +#define TEGRA12_EMC_MAX_NUM_BURST_REGS 175 +#define TEGRA12_EMC_MAX_UP_DOWN_REGS 40 struct tegra12_emc_table { u8 rev; @@ -156,14 +158,14 @@ struct tegra12_emc_table { unsigned long rate; int emc_min_mv; int gk20a_min_mv; - const char *src_name; + char src_name[16]; u32 src_sel_reg; int burst_regs_num; int burst_up_down_regs_num; /* unconditionally updated in one burst shot */ - u32 burst_regs[TEGRA12_EMC_MAX_NUM_REGS]; + u32 burst_regs[TEGRA12_EMC_MAX_NUM_BURST_REGS]; /* one burst shot, but update time depends on rate change direction */ u32 burst_up_down_regs[TEGRA12_EMC_MAX_UP_DOWN_REGS]; |