blob: be181229370e93094cbf01524a153dff23fd298c [file] [log] [blame]
Peng Fan0fe6f162019-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>
10#include <asm/arch/sci/sci.h>
11#include <asm/arch/sys_proto.h>
Peng Fanb0b44412020-05-11 15:16:07 +080012#include <linux/arm-smccc.h>
Peng Fan0fe6f162019-04-12 07:54:54 +000013
14DECLARE_GLOBAL_DATA_PTR;
15
16#define FSL_ECC_WORD_START_1 0x10
17#define FSL_ECC_WORD_END_1 0x10F
18
Ye Li390f4602020-05-03 22:31:46 +080019#ifdef CONFIG_IMX8QM
20#define FSL_ECC_WORD_START_2 0x1A0
21#define FSL_ECC_WORD_END_2 0x1FF
22#elif defined(CONFIG_IMX8QXP)
Peng Fan0fe6f162019-04-12 07:54:54 +000023#define FSL_ECC_WORD_START_2 0x220
24#define FSL_ECC_WORD_END_2 0x31F
Ye Li390f4602020-05-03 22:31:46 +080025#endif
Peng Fan0fe6f162019-04-12 07:54:54 +000026
27#define FSL_QXP_FUSE_GAP_START 0x110
28#define FSL_QXP_FUSE_GAP_END 0x21F
Peng Fan0fe6f162019-04-12 07:54:54 +000029
30#define FSL_SIP_OTP_READ 0xc200000A
31#define FSL_SIP_OTP_WRITE 0xc200000B
32
33int fuse_read(u32 bank, u32 word, u32 *val)
34{
35 return fuse_sense(bank, word, val);
36}
37
38int fuse_sense(u32 bank, u32 word, u32 *val)
39{
Peng Fanb0b44412020-05-11 15:16:07 +080040 struct arm_smccc_res res;
Peng Fan0fe6f162019-04-12 07:54:54 +000041
42 if (bank != 0) {
43 printf("Invalid bank argument, ONLY bank 0 is supported\n");
44 return -EINVAL;
45 }
46
Peng Fanb0b44412020-05-11 15:16:07 +080047 arm_smccc_smc(FSL_SIP_OTP_READ, (unsigned long)word, 0, 0,
48 0, 0, 0, 0, &res);
49 *val = (u32)res.a1;
Peng Fan0fe6f162019-04-12 07:54:54 +000050
Peng Fanb0b44412020-05-11 15:16:07 +080051 return res.a0;
Peng Fan0fe6f162019-04-12 07:54:54 +000052}
53
54int fuse_prog(u32 bank, u32 word, u32 val)
55{
Peng Fanb0b44412020-05-11 15:16:07 +080056 struct arm_smccc_res res;
57
Peng Fan0fe6f162019-04-12 07:54:54 +000058 if (bank != 0) {
59 printf("Invalid bank argument, ONLY bank 0 is supported\n");
60 return -EINVAL;
61 }
62
63 if (IS_ENABLED(CONFIG_IMX8QXP)) {
64 if (word >= FSL_QXP_FUSE_GAP_START &&
65 word <= FSL_QXP_FUSE_GAP_END) {
66 printf("Invalid word argument for this SoC\n");
67 return -EINVAL;
68 }
69 }
70
71 if ((word >= FSL_ECC_WORD_START_1 && word <= FSL_ECC_WORD_END_1) ||
72 (word >= FSL_ECC_WORD_START_2 && word <= FSL_ECC_WORD_END_2)) {
73 puts("Warning: Words in this index range have ECC protection\n"
74 "and can only be programmed once per word. Individual bit\n"
75 "operations will be rejected after the first one.\n"
76 "\n\n Really program this word? <y/N>\n");
77
78 if (!confirm_yesno()) {
79 puts("Word programming aborted\n");
80 return -EPERM;
81 }
82 }
83
Peng Fanb0b44412020-05-11 15:16:07 +080084 arm_smccc_smc(FSL_SIP_OTP_WRITE, (unsigned long)word,
85 (unsigned long)val, 0, 0, 0, 0, 0, &res);
86
87 return res.a0;
Peng Fan0fe6f162019-04-12 07:54:54 +000088}
89
90int fuse_override(u32 bank, u32 word, u32 val)
91{
92 printf("Override fuse to i.MX8 in u-boot is forbidden\n");
93 return -EPERM;
94}