summaryrefslogtreecommitdiff
path: root/arch/arm/mach-imx/imx8/fuse.c
blob: 104833ca70421d220e2381ed47bcca8a0242c4f3 (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
104
105
106
107
108
109
110
111
/*
 * 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"
                  "\n\n Really program this word? <y/N> \n");

             if(!confirm_yesno()) {
                 puts("Word programming aborted\n");
                 return -EPERM;
             }
       }

#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;
}