summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-tegra/board-ardbeg-memory.c47
-rw-r--r--arch/arm/mach-tegra/include/mach/nct.h12
-rw-r--r--arch/arm/mach-tegra/tegra12_emc.c84
-rw-r--r--arch/arm/mach-tegra/tegra12_emc.h5
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),