summaryrefslogtreecommitdiff
path: root/arch/arm/mach-imx/imx8/fuse.c
blob: 4603b91a4126a17b837280237188825ded91daa7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*
 * Copyright 2017 NXP
 *
 * SPDX-License-Identifier:	GPL-2.0+
 *
 */

#include <common.h>
#include <errno.h>
#include <asm/io.h>
#include <console.h>
#include <fuse.h>
#include <asm/mach-imx/sci/sci.h>
#include <asm/arch/sys_proto.h>

DECLARE_GLOBAL_DATA_PTR;


#define FSL_ECC_WORD_START_1	 0x10
#define FSL_ECC_WORD_END_1	 0x10F

#ifdef CONFIG_IMX8QM
#define FSL_ECC_WORD_START_2	 0x1A0
#define FSL_ECC_WORD_END_2	 0x1FF
#endif

#ifdef CONFIG_IMX8QXP
#define FSL_ECC_WORD_START_2	 0x220
#define FSL_ECC_WORD_END_2	 0x31F

#define FSL_QXP_FUSE_GAP_START	 0x110
#define FSL_QXP_FUSE_GAP_END	 0x21F
#endif

#define FSL_SIP_OTP_READ             0xc200000A
#define FSL_SIP_OTP_WRITE            0xc200000B

int fuse_read(u32 bank, u32 word, u32 *val)
{
	return fuse_sense(bank, word, val);
}

int fuse_sense(u32 bank, u32 word, u32 *val)
{
	if (bank != 0) {
		printf("Invalid bank argument, ONLY bank 0 is supported\n");
		return -EINVAL;
	}
#if defined(CONFIG_SMC_FUSE)
	unsigned long ret = 0, value = 0;
	ret = call_imx_sip_ret2(FSL_SIP_OTP_READ, (unsigned long)word,
		&value, 0, 0);
	*val = (u32)value;
	return ret;
#else
	sc_err_t err;
	sc_ipc_t ipc;

	ipc = gd->arch.ipc_channel_handle;

	err = sc_misc_otp_fuse_read(ipc, word, val);
	if (err != SC_ERR_NONE) {
		printf("fuse read error: %d\n", err);
		return -EIO;
	}

	return 0;
#endif
}

int fuse_prog(u32 bank, u32 word, u32 val)
{
	if (bank != 0) {
		printf("Invalid bank argument, ONLY bank 0 is supported\n");
		return -EINVAL;
	}
#ifdef CONFIG_IMX8QXP
	if ((word >= FSL_QXP_FUSE_GAP_START) && (word <= FSL_QXP_FUSE_GAP_END)) {
		printf("Invalid word argument for this SoC\n");
		return -EINVAL;
	}
#endif

    if (((word >= FSL_ECC_WORD_START_1) && (word <= FSL_ECC_WORD_END_1)) ||
		((word >= FSL_ECC_WORD_START_2) && (word <= FSL_ECC_WORD_END_2)))
             puts("Warning: Words in this index range have ECC protection and\n"
                  "can only be programmed once per word. Individual bit operations will\n"
                  "be rejected after the first one. \n");

#if defined(CONFIG_SMC_FUSE)
	return call_imx_sip(FSL_SIP_OTP_WRITE, (unsigned long)word,\
		(unsigned long)val, 0, 0);
#else
	printf("Program fuse to i.MX8 in u-boot is forbidden\n");
	return -EPERM;
#endif
}

int fuse_override(u32 bank, u32 word, u32 val)
{
	printf("Override fuse to i.MX8 in u-boot is forbidden\n");
	return -EPERM;
}