| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright 2020 NXP
- */
- #include <common.h>
- #include <console.h>
- #include <errno.h>
- #include <fuse.h>
- #include <asm/arch/sys_proto.h>
- #include <asm/arch/imx-regs.h>
- #include <env.h>
- #include <asm/mach-imx/ele_api.h>
- #include <asm/global_data.h>
- DECLARE_GLOBAL_DATA_PTR;
- #define FUSE_BANKS 64
- #define WORDS_PER_BANKS 8
- struct fsb_map_entry {
- s32 fuse_bank;
- u32 fuse_words;
- bool redundancy;
- };
- struct ele_map_entry {
- s32 fuse_bank;
- u32 fuse_words;
- u32 fuse_offset;
- u32 ele_index;
- };
- #if defined(CONFIG_IMX8ULP)
- #define FSB_OTP_SHADOW 0x800
- struct fsb_map_entry fsb_mapping_table[] = {
- { 3, 8 },
- { 4, 8 },
- { -1, 48 }, /* Reserve 48 words */
- { 5, 8 },
- { 6, 8 },
- { 8, 4, true },
- { 24, 4, true },
- { 26, 4, true },
- { 27, 4, true },
- { 28, 8 },
- { 29, 8 },
- { 30, 8 },
- { 31, 8 },
- { 37, 8 },
- { 38, 8 },
- { 39, 8 },
- { 40, 8 },
- { 41, 8 },
- { 42, 8 },
- { 43, 8 },
- { 44, 8 },
- { 45, 8 },
- { 46, 8 },
- };
- /* None ECC banks such like Redundancy or Bit protect */
- u32 nonecc_fuse_banks[] = {
- 0, 1, 8, 12, 16, 22, 24, 25, 26, 27, 36, 41, 51, 56
- };
- struct ele_map_entry ele_api_mapping_table[] = {
- { 1, 8 }, /* LOCK */
- { 2, 8 }, /* ECID */
- { 7, 4, 0, 1 }, /* OTP_UNIQ_ID */
- { 15, 8 }, /* OEM SRK HASH */
- { 23, 1, 4, 2 }, /* OTFAD */
- { 25, 8 }, /* Test config2 */
- { 26, 8 }, /* PMU */
- { 27, 8 }, /* Test flow/USB */
- { 32, 8 }, /* GP1 */
- { 33, 8 }, /* GP2 */
- { 34, 8 }, /* GP3 */
- { 35, 8 }, /* GP4 */
- { 36, 8 }, /* GP5 */
- { 49, 8 }, /* GP8 */
- { 50, 8 }, /* GP9 */
- { 51, 8 }, /* GP10 */
- };
- #elif defined(CONFIG_ARCH_IMX9)
- #define FSB_OTP_SHADOW 0x8000
- struct fsb_map_entry fsb_mapping_table[] = {
- { 0, 8 },
- { 1, 8 },
- { 2, 8 },
- { 3, 8 },
- { 4, 8 },
- { 5, 8 },
- { 6, 4 },
- { -1, 260 },
- { 39, 8 },
- { 40, 8 },
- { 41, 8 },
- { 42, 8 },
- { 43, 8 },
- { 44, 8 },
- { 45, 8 },
- { 46, 8 },
- { 47, 8 },
- { 48, 8 },
- { 49, 8 },
- { 50, 8 },
- { 51, 8 },
- { 52, 8 },
- { 53, 8 },
- { 54, 8 },
- { 55, 8 },
- { 56, 8 },
- { 57, 8 },
- { 58, 8 },
- { 59, 8 },
- { 60, 8 },
- { 61, 8 },
- { 62, 8 },
- { 63, 8 },
- };
- struct ele_map_entry ele_api_mapping_table[] = {
- { 7, 1, 7, 63 },
- { 16, 8, },
- { 17, 8, },
- { 22, 1, 6 },
- { 23, 1, 4 },
- };
- #endif
- static s32 map_fsb_fuse_index(u32 bank, u32 word, bool *redundancy)
- {
- s32 size = ARRAY_SIZE(fsb_mapping_table);
- s32 i, word_pos = 0;
- /* 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) {
- break;
- }
- word_pos += fsb_mapping_table[i].fuse_words;
- }
- if (i == size)
- return -1; /* Failed to find */
- if (fsb_mapping_table[i].redundancy) {
- *redundancy = true;
- return (word >> 1) + word_pos;
- }
- *redundancy = false;
- return word + word_pos;
- }
- static s32 map_ele_fuse_index(u32 bank, u32 word)
- {
- s32 size = ARRAY_SIZE(ele_api_mapping_table);
- s32 i;
- /* map the fuse from ocotp fuse map to FSB*/
- for (i = 0; i < size; i++) {
- if (ele_api_mapping_table[i].fuse_bank != -1 &&
- ele_api_mapping_table[i].fuse_bank == bank) {
- if (word >= ele_api_mapping_table[i].fuse_offset &&
- word < (ele_api_mapping_table[i].fuse_offset +
- ele_api_mapping_table[i].fuse_words))
- break;
- }
- }
- if (i == size)
- return -1; /* Failed to find */
- if (ele_api_mapping_table[i].ele_index != 0)
- return ele_api_mapping_table[i].ele_index;
- return ele_api_mapping_table[i].fuse_bank * 8 + word;
- }
- #if defined(CONFIG_IMX8ULP)
- int fuse_sense(u32 bank, u32 word, u32 *val)
- {
- s32 word_index;
- bool redundancy;
- if (bank >= FUSE_BANKS || 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;
- int ret;
- /* Only UID return 4 words */
- if (word_index != 1)
- size = 1;
- ret = ele_read_common_fuse(word_index, data, size, &res);
- if (ret) {
- printf("ahab read fuse failed %d, 0x%x\n", ret, res);
- return ret;
- }
- if (word_index == 1) {
- *val = data[word]; /* UID */
- } else if (word_index == 2) {
- /*
- * OTFAD 3 bits as follow:
- * bit 0: OTFAD_ENABLE
- * bit 1: OTFAD_DISABLE_OVERRIDE
- * bit 2: KEY_BLOB_EN
- */
- *val = data[0] << 3;
- } else {
- *val = data[0];
- }
- return 0;
- }
- 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)
- 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;
- u32 res, size = 1;
- int ret;
- ret = ele_read_common_fuse(word_index, &data, size, &res);
- if (ret) {
- printf("ahab read fuse failed %d, 0x%x\n", ret, res);
- return ret;
- }
- *val = data;
- return 0;
- }
- return -ENOENT;
- }
- #endif
- int fuse_read(u32 bank, u32 word, u32 *val)
- {
- return fuse_sense(bank, word, val);
- }
- int fuse_prog(u32 bank, u32 word, u32 val)
- {
- u32 res;
- int ret;
- bool lock = false;
- if (bank >= FUSE_BANKS || word >= WORDS_PER_BANKS || !val)
- return -EINVAL;
- /* Lock 8ULP ECC fuse word, so second programming will return failure.
- * iMX9 OTP can protect ECC fuse, so not need it
- */
- #if defined(CONFIG_IMX8ULP)
- u32 i;
- for (i = 0; i < ARRAY_SIZE(nonecc_fuse_banks); i++) {
- if (nonecc_fuse_banks[i] == bank)
- break;
- }
- if (i == ARRAY_SIZE(nonecc_fuse_banks))
- lock = true;
- #endif
- ret = ele_write_fuse((bank * 8 + word), val, lock, &res);
- if (ret) {
- printf("ahab write fuse failed %d, 0x%x\n", ret, res);
- return ret;
- }
- return 0;
- }
- int fuse_override(u32 bank, u32 word, u32 val)
- {
- printf("Override fuse to i.MX8ULP in u-boot is forbidden\n");
- return -EPERM;
- }
|