1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2015-2016 Reinhard Pfau <reinhard.pfau@gdsys.cc>
10 #include <asm/arch/cpu.h>
11 #include <asm/arch/efuse.h>
12 #include <asm/arch/soc.h>
13 #include <linux/mbus.h>
15 #if defined(CONFIG_MVEBU_EFUSE_FAKE)
21 #define MBUS_EFUSE_BASE 0xF6000000
22 #define MBUS_EFUSE_SIZE BIT(20)
24 #define MVEBU_EFUSE_CONTROL (MVEBU_REGISTER(0xE4008))
27 MVEBU_EFUSE_CTRL_PROGRAM_ENABLE
= (1 << 31),
30 struct mvebu_hd_efuse
{
38 static struct mvebu_hd_efuse
*efuses
=
39 (struct mvebu_hd_efuse
*)(MBUS_EFUSE_BASE
+ 0xF9000);
41 static struct mvebu_hd_efuse efuses
[EFUSE_LINE_MAX
+ 1];
44 static int efuse_initialised
;
46 static struct mvebu_hd_efuse
*get_efuse_line(int nr
)
48 if (nr
< 0 || nr
> 63 || !efuse_initialised
)
54 static void enable_efuse_program(void)
57 setbits_le32(MVEBU_EFUSE_CONTROL
, MVEBU_EFUSE_CTRL_PROGRAM_ENABLE
);
61 static void disable_efuse_program(void)
64 clrbits_le32(MVEBU_EFUSE_CONTROL
, MVEBU_EFUSE_CTRL_PROGRAM_ENABLE
);
68 static int do_prog_efuse(struct mvebu_hd_efuse
*efuse
,
69 struct efuse_val
*new_val
, u32 mask0
, u32 mask1
)
73 val
.dwords
.d
[0] = readl(&efuse
->bits_31_0
);
74 val
.dwords
.d
[1] = readl(&efuse
->bits_63_32
);
75 val
.lock
= readl(&efuse
->bit64
);
80 val
.dwords
.d
[0] |= (new_val
->dwords
.d
[0] & mask0
);
81 val
.dwords
.d
[1] |= (new_val
->dwords
.d
[1] & mask1
);
82 val
.lock
|= new_val
->lock
;
84 writel(val
.dwords
.d
[0], &efuse
->bits_31_0
);
86 writel(val
.dwords
.d
[1], &efuse
->bits_63_32
);
88 writel(val
.lock
, &efuse
->bit64
);
94 static int prog_efuse(int nr
, struct efuse_val
*new_val
, u32 mask0
, u32 mask1
)
96 struct mvebu_hd_efuse
*efuse
;
99 res
= mvebu_efuse_init_hw();
103 efuse
= get_efuse_line(nr
);
110 /* only write a fuse line with lock bit */
114 /* according to specs ECC protection bits must be 0 on write */
115 if (new_val
->bytes
.d
[7] & 0xFE)
118 if (!new_val
->dwords
.d
[0] && !new_val
->dwords
.d
[1] && (mask0
| mask1
))
121 enable_efuse_program();
123 res
= do_prog_efuse(efuse
, new_val
, mask0
, mask1
);
125 disable_efuse_program();
130 int mvebu_efuse_init_hw(void)
134 if (efuse_initialised
)
137 ret
= mvebu_mbus_add_window_by_id(
138 CPU_TARGET_SATA23_DFX
, 0xA, MBUS_EFUSE_BASE
, MBUS_EFUSE_SIZE
);
143 efuse_initialised
= 1;
148 int mvebu_read_efuse(int nr
, struct efuse_val
*val
)
150 struct mvebu_hd_efuse
*efuse
;
153 res
= mvebu_efuse_init_hw();
157 efuse
= get_efuse_line(nr
);
164 val
->dwords
.d
[0] = readl(&efuse
->bits_31_0
);
165 val
->dwords
.d
[1] = readl(&efuse
->bits_63_32
);
166 val
->lock
= readl(&efuse
->bit64
);
170 int mvebu_write_efuse(int nr
, struct efuse_val
*val
)
172 return prog_efuse(nr
, val
, ~0, ~0);
175 int mvebu_lock_efuse(int nr
)
177 struct efuse_val val
= {
181 return prog_efuse(nr
, &val
, 0, 0);
185 * wrapper funcs providing the fuse API
187 * we use the following mapping:
188 * "bank" -> eFuse line
189 * "word" -> 0: bits 0-31
194 static struct efuse_val prog_val
;
195 static int valid_prog_words
;
197 int fuse_read(u32 bank
, u32 word
, u32
*val
)
199 struct efuse_val fuse_line
;
202 if (bank
< EFUSE_LINE_MIN
|| bank
> EFUSE_LINE_MAX
|| word
> 2)
205 res
= mvebu_read_efuse(bank
, &fuse_line
);
210 *val
= fuse_line
.dwords
.d
[word
];
212 *val
= fuse_line
.lock
;
217 int fuse_sense(u32 bank
, u32 word
, u32
*val
)
223 int fuse_prog(u32 bank
, u32 word
, u32 val
)
228 * NOTE: Fuse line should be written as whole.
229 * So how can we do that with this API?
230 * For now: remember values for word == 0 and word == 1 and write the
231 * whole line when word == 2.
232 * This implies that we always require all 3 fuse prog cmds (one for
233 * for each word) to write a single fuse line.
234 * Exception is a single write to word 2 which will lock the fuse line.
236 * Hope that will be OK.
239 if (bank
< EFUSE_LINE_MIN
|| bank
> EFUSE_LINE_MAX
|| word
> 2)
243 prog_val
.dwords
.d
[word
] = val
;
244 valid_prog_words
|= (1 << word
);
245 } else if ((valid_prog_words
& 3) == 0 && val
) {
246 res
= mvebu_lock_efuse(bank
);
247 valid_prog_words
= 0;
248 } else if ((valid_prog_words
& 3) != 3 || !val
) {
251 prog_val
.lock
= val
!= 0;
252 res
= mvebu_write_efuse(bank
, &prog_val
);
253 valid_prog_words
= 0;
259 int fuse_override(u32 bank
, u32 word
, u32 val
)