summaryrefslogtreecommitdiff
path: root/drivers/misc/imx_ele/fuse.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/imx_ele/fuse.c')
-rw-r--r--drivers/misc/imx_ele/fuse.c111
1 files changed, 82 insertions, 29 deletions
diff --git a/drivers/misc/imx_ele/fuse.c b/drivers/misc/imx_ele/fuse.c
index d12539c8aac..c1e7434dbf3 100644
--- a/drivers/misc/imx_ele/fuse.c
+++ b/drivers/misc/imx_ele/fuse.c
@@ -11,10 +11,10 @@
#include <env.h>
#include <asm/mach-imx/ele_api.h>
#include <asm/global_data.h>
+#include <env.h>
DECLARE_GLOBAL_DATA_PTR;
-#define FUSE_BANKS 64
#define WORDS_PER_BANKS 8
struct fsb_map_entry {
@@ -32,6 +32,7 @@ struct ele_map_entry {
#if defined(CONFIG_IMX8ULP)
#define FSB_OTP_SHADOW 0x800
+#define IS_FSB_ALLOWED (true)
struct fsb_map_entry fsb_mapping_table[] = {
{ 3, 8 },
@@ -84,6 +85,8 @@ struct ele_map_entry ele_api_mapping_table[] = {
};
#elif defined(CONFIG_ARCH_IMX9)
#define FSB_OTP_SHADOW 0x8000
+#define IS_FSB_ALLOWED (!IS_ENABLED(CONFIG_SCMI_FIRMWARE) && \
+ !(readl(BLK_CTRL_NS_ANOMIX_BASE_ADDR + 0x28) & BIT(0)))
struct fsb_map_entry fsb_mapping_table[] = {
{ 0, 8 },
@@ -138,8 +141,7 @@ static s32 map_fsb_fuse_index(u32 bank, u32 word, bool *redundancy)
/* map the fuse from ocotp fuse map to FSB*/
for (i = 0; i < size; i++) {
if (fsb_mapping_table[i].fuse_bank != -1 &&
- fsb_mapping_table[i].fuse_bank == bank &&
- fsb_mapping_table[i].fuse_words > word) {
+ fsb_mapping_table[i].fuse_bank == bank) {
break;
}
@@ -150,8 +152,13 @@ static s32 map_fsb_fuse_index(u32 bank, u32 word, bool *redundancy)
return -1; /* Failed to find */
if (fsb_mapping_table[i].redundancy) {
+ if ((fsb_mapping_table[i].fuse_words << 1) <= word)
+ return -2; /* Not valid word */
+
*redundancy = true;
return (word >> 1) + word_pos;
+ } else if (fsb_mapping_table[i].fuse_words <= word) {
+ return -2; /* Not valid word */
}
*redundancy = false;
@@ -187,24 +194,14 @@ static s32 map_ele_fuse_index(u32 bank, u32 word)
int fuse_sense(u32 bank, u32 word, u32 *val)
{
s32 word_index;
- bool redundancy;
- if (bank >= FUSE_BANKS || word >= WORDS_PER_BANKS || !val)
+ if (word >= WORDS_PER_BANKS || !val)
return -EINVAL;
- word_index = map_fsb_fuse_index(bank, word, &redundancy);
- if (word_index >= 0) {
- *val = readl((ulong)FSB_BASE_ADDR + FSB_OTP_SHADOW + (word_index << 2));
- if (redundancy)
- *val = (*val >> ((word % 2) * 16)) & 0xFFFF;
-
- return 0;
- }
-
word_index = map_ele_fuse_index(bank, word);
if (word_index >= 0) {
u32 data[4];
- u32 res, size = 4;
+ u32 res = 0, size = 4;
int ret;
/* Only UID return 4 words */
@@ -236,28 +233,29 @@ int fuse_sense(u32 bank, u32 word, u32 *val)
return -ENOENT;
}
+
#elif defined(CONFIG_ARCH_IMX9)
int fuse_sense(u32 bank, u32 word, u32 *val)
{
s32 word_index;
bool redundancy;
- if (bank >= FUSE_BANKS || word >= WORDS_PER_BANKS || !val)
+ if (word >= WORDS_PER_BANKS || !val)
return -EINVAL;
- word_index = map_fsb_fuse_index(bank, word, &redundancy);
- if (word_index >= 0) {
- *val = readl((ulong)FSB_BASE_ADDR + FSB_OTP_SHADOW + (word_index << 2));
- if (redundancy)
- *val = (*val >> ((word % 2) * 16)) & 0xFFFF;
+ if (!IS_ENABLED(CONFIG_SCMI_FIRMWARE)) {
+ word_index = map_fsb_fuse_index(bank, word, &redundancy);
- return 0;
+ /* ELE read common fuse API supports all FSB fuse. */
+ if (word_index < 0)
+ word_index = map_ele_fuse_index(bank, word);
+ } else {
+ word_index = bank * 8 + word;
}
- word_index = map_ele_fuse_index(bank, word);
if (word_index >= 0) {
u32 data;
- u32 res, size = 1;
+ u32 res = 0, size = 1;
int ret;
ret = ele_read_common_fuse(word_index, &data, size, &res);
@@ -275,18 +273,62 @@ int fuse_sense(u32 bank, u32 word, u32 *val)
}
#endif
-int fuse_read(u32 bank, u32 word, u32 *val)
+static int fuse_read_default(u32 bank, u32 word, u32 *val)
{
+ s32 word_index;
+ bool redundancy;
+
+ if (IS_FSB_ALLOWED) {
+ word_index = map_fsb_fuse_index(bank, word, &redundancy);
+ if (word_index >= 0) {
+ *val = readl((ulong)FSB_BASE_ADDR + FSB_OTP_SHADOW + (word_index << 2));
+ if (redundancy)
+ *val = (*val >> ((word % 2) * 16)) & 0xFFFF;
+
+ return 0;
+ }
+ }
+
return fuse_sense(bank, word, val);
}
+static int fuse_read_ele_shd(u32 bank, u32 word, u32 *val)
+{
+ u32 res = 0;
+ int ret;
+ struct udevice *dev = gd->arch.ele_dev;
+
+ if (!dev)
+ return -ENODEV;
+
+ ret = ele_read_shadow_fuse((bank * 8 + word), val, &res);
+ if (ret) {
+ printf("ele read shadow fuse failed %d, 0x%x\n", ret, res);
+ return ret;
+ }
+
+ return 0;
+}
+
+int fuse_read(u32 bank, u32 word, u32 *val)
+{
+ if (word >= WORDS_PER_BANKS || !val)
+ return -EINVAL;
+
+ if (!IS_ENABLED(CONFIG_SPL_BUILD) &&
+ env_get_yesno("enable_ele_shd") == 1)
+ return fuse_read_ele_shd(bank, word, val);
+ else
+ return fuse_read_default(bank, word, val);
+}
+
int fuse_prog(u32 bank, u32 word, u32 val)
{
- u32 res;
+ u32 res = 0;
int ret;
bool lock = false;
- if (bank >= FUSE_BANKS || word >= WORDS_PER_BANKS || !val)
+ if (word >= WORDS_PER_BANKS || !val)
return -EINVAL;
/* Lock 8ULP ECC fuse word, so second programming will return failure.
@@ -314,6 +356,17 @@ int fuse_prog(u32 bank, u32 word, u32 val)
int fuse_override(u32 bank, u32 word, u32 val)
{
- printf("Override fuse to i.MX8ULP in u-boot is forbidden\n");
- return -EPERM;
+ u32 res = 0;
+ int ret;
+
+ if (word >= WORDS_PER_BANKS || !val)
+ return -EINVAL;
+
+ ret = ele_write_shadow_fuse((bank * 8 + word), val, &res);
+ if (ret) {
+ printf("ahab write shadow fuse failed %d, 0x%x\n", ret, res);
+ return ret;
+ }
+
+ return 0;
}