blob: b81f73f283f4c5fb7f3325aaa4b7ed5a9a0df65d [file] [log] [blame]
Peng Fan90c98a52019-04-12 07:54:54 +00001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2019 NXP
4 */
5
6#include <common.h>
7#include <console.h>
8#include <errno.h>
9#include <fuse.h>
Peng Fan99ac6c72023-04-28 12:08:09 +080010#include <firmware/imx/sci/sci.h>
Peng Fan90c98a52019-04-12 07:54:54 +000011#include <asm/arch/sys_proto.h>
Simon Glass401d1c42020-10-30 21:38:53 -060012#include <asm/global_data.h>
Peng Fanc2eaa6e2020-05-11 15:16:07 +080013#include <linux/arm-smccc.h>
Peng Fan90c98a52019-04-12 07:54:54 +000014
15DECLARE_GLOBAL_DATA_PTR;
16
17#define FSL_ECC_WORD_START_1 0x10
18#define FSL_ECC_WORD_END_1 0x10F
19
Ye Lie5e95ec2020-05-03 22:31:46 +080020#ifdef CONFIG_IMX8QM
21#define FSL_ECC_WORD_START_2 0x1A0
22#define FSL_ECC_WORD_END_2 0x1FF
23#elif defined(CONFIG_IMX8QXP)
Peng Fan90c98a52019-04-12 07:54:54 +000024#define FSL_ECC_WORD_START_2 0x220
25#define FSL_ECC_WORD_END_2 0x31F
Ye Lie5e95ec2020-05-03 22:31:46 +080026#endif
Peng Fan90c98a52019-04-12 07:54:54 +000027
28#define FSL_QXP_FUSE_GAP_START 0x110
29#define FSL_QXP_FUSE_GAP_END 0x21F
Peng Fan90c98a52019-04-12 07:54:54 +000030
31#define FSL_SIP_OTP_READ 0xc200000A
32#define FSL_SIP_OTP_WRITE 0xc200000B
33
34int fuse_read(u32 bank, u32 word, u32 *val)
35{
36 return fuse_sense(bank, word, val);
37}
38
39int fuse_sense(u32 bank, u32 word, u32 *val)
40{
Peng Fanc2eaa6e2020-05-11 15:16:07 +080041 struct arm_smccc_res res;
Peng Fan90c98a52019-04-12 07:54:54 +000042
43 if (bank != 0) {
44 printf("Invalid bank argument, ONLY bank 0 is supported\n");
45 return -EINVAL;
46 }
47
Peng Fanc2eaa6e2020-05-11 15:16:07 +080048 arm_smccc_smc(FSL_SIP_OTP_READ, (unsigned long)word, 0, 0,
49 0, 0, 0, 0, &res);
50 *val = (u32)res.a1;
Peng Fan90c98a52019-04-12 07:54:54 +000051
Peng Fanc2eaa6e2020-05-11 15:16:07 +080052 return res.a0;
Peng Fan90c98a52019-04-12 07:54:54 +000053}
54
55int fuse_prog(u32 bank, u32 word, u32 val)
56{
Peng Fanc2eaa6e2020-05-11 15:16:07 +080057 struct arm_smccc_res res;
58
Peng Fan90c98a52019-04-12 07:54:54 +000059 if (bank != 0) {
60 printf("Invalid bank argument, ONLY bank 0 is supported\n");
61 return -EINVAL;
62 }
63
64 if (IS_ENABLED(CONFIG_IMX8QXP)) {
65 if (word >= FSL_QXP_FUSE_GAP_START &&
66 word <= FSL_QXP_FUSE_GAP_END) {
67 printf("Invalid word argument for this SoC\n");
68 return -EINVAL;
69 }
70 }
71
72 if ((word >= FSL_ECC_WORD_START_1 && word <= FSL_ECC_WORD_END_1) ||
73 (word >= FSL_ECC_WORD_START_2 && word <= FSL_ECC_WORD_END_2)) {
74 puts("Warning: Words in this index range have ECC protection\n"
75 "and can only be programmed once per word. Individual bit\n"
76 "operations will be rejected after the first one.\n"
77 "\n\n Really program this word? <y/N>\n");
78
79 if (!confirm_yesno()) {
80 puts("Word programming aborted\n");
81 return -EPERM;
82 }
83 }
84
Peng Fanc2eaa6e2020-05-11 15:16:07 +080085 arm_smccc_smc(FSL_SIP_OTP_WRITE, (unsigned long)word,
86 (unsigned long)val, 0, 0, 0, 0, 0, &res);
87
88 return res.a0;
Peng Fan90c98a52019-04-12 07:54:54 +000089}
90
91int fuse_override(u32 bank, u32 word, u32 val)
92{
93 printf("Override fuse to i.MX8 in u-boot is forbidden\n");
94 return -EPERM;
95}