diff options
Diffstat (limited to 'arch')
-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 |
4 files changed, 133 insertions, 15 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), |