xref: /openbmc/u-boot/arch/arm/mach-mvebu/efuse.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2a1b6b0a9SMario Six /*
3a1b6b0a9SMario Six  * Copyright (C) 2015-2016 Reinhard Pfau <reinhard.pfau@gdsys.cc>
4a1b6b0a9SMario Six  */
5a1b6b0a9SMario Six 
6a1b6b0a9SMario Six #include <config.h>
7a1b6b0a9SMario Six #include <common.h>
8a1b6b0a9SMario Six #include <errno.h>
9a1b6b0a9SMario Six #include <asm/io.h>
10a1b6b0a9SMario Six #include <asm/arch/cpu.h>
11a1b6b0a9SMario Six #include <asm/arch/efuse.h>
12a1b6b0a9SMario Six #include <asm/arch/soc.h>
13a1b6b0a9SMario Six #include <linux/mbus.h>
14a1b6b0a9SMario Six 
15a1b6b0a9SMario Six #if defined(CONFIG_MVEBU_EFUSE_FAKE)
16a1b6b0a9SMario Six #define DRY_RUN
17a1b6b0a9SMario Six #else
18a1b6b0a9SMario Six #undef DRY_RUN
19a1b6b0a9SMario Six #endif
20a1b6b0a9SMario Six 
21a1b6b0a9SMario Six #define MBUS_EFUSE_BASE 0xF6000000
22a1b6b0a9SMario Six #define MBUS_EFUSE_SIZE BIT(20)
23a1b6b0a9SMario Six 
24a1b6b0a9SMario Six #define MVEBU_EFUSE_CONTROL (MVEBU_REGISTER(0xE4008))
25a1b6b0a9SMario Six 
26a1b6b0a9SMario Six enum {
27a1b6b0a9SMario Six 	MVEBU_EFUSE_CTRL_PROGRAM_ENABLE = (1 << 31),
28a1b6b0a9SMario Six };
29a1b6b0a9SMario Six 
30a1b6b0a9SMario Six struct mvebu_hd_efuse {
31a1b6b0a9SMario Six 	u32 bits_31_0;
32a1b6b0a9SMario Six 	u32 bits_63_32;
33a1b6b0a9SMario Six 	u32 bit64;
34a1b6b0a9SMario Six 	u32 reserved0;
35a1b6b0a9SMario Six };
36a1b6b0a9SMario Six 
37a1b6b0a9SMario Six #ifndef DRY_RUN
38a1b6b0a9SMario Six static struct mvebu_hd_efuse *efuses =
39a1b6b0a9SMario Six 	(struct mvebu_hd_efuse *)(MBUS_EFUSE_BASE + 0xF9000);
40a1b6b0a9SMario Six #else
41a1b6b0a9SMario Six static struct mvebu_hd_efuse efuses[EFUSE_LINE_MAX + 1];
42a1b6b0a9SMario Six #endif
43a1b6b0a9SMario Six 
44a1b6b0a9SMario Six static int efuse_initialised;
45a1b6b0a9SMario Six 
get_efuse_line(int nr)46a1b6b0a9SMario Six static struct mvebu_hd_efuse *get_efuse_line(int nr)
47a1b6b0a9SMario Six {
48a1b6b0a9SMario Six 	if (nr < 0 || nr > 63 || !efuse_initialised)
49a1b6b0a9SMario Six 		return NULL;
50a1b6b0a9SMario Six 
51a1b6b0a9SMario Six 	return efuses + nr;
52a1b6b0a9SMario Six }
53a1b6b0a9SMario Six 
enable_efuse_program(void)54a1b6b0a9SMario Six static void enable_efuse_program(void)
55a1b6b0a9SMario Six {
56a1b6b0a9SMario Six #ifndef DRY_RUN
57a1b6b0a9SMario Six 	setbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_CTRL_PROGRAM_ENABLE);
58a1b6b0a9SMario Six #endif
59a1b6b0a9SMario Six }
60a1b6b0a9SMario Six 
disable_efuse_program(void)61a1b6b0a9SMario Six static void disable_efuse_program(void)
62a1b6b0a9SMario Six {
63a1b6b0a9SMario Six #ifndef DRY_RUN
64a1b6b0a9SMario Six 	clrbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_CTRL_PROGRAM_ENABLE);
65a1b6b0a9SMario Six #endif
66a1b6b0a9SMario Six }
67a1b6b0a9SMario Six 
do_prog_efuse(struct mvebu_hd_efuse * efuse,struct efuse_val * new_val,u32 mask0,u32 mask1)68a1b6b0a9SMario Six static int do_prog_efuse(struct mvebu_hd_efuse *efuse,
69a1b6b0a9SMario Six 			 struct efuse_val *new_val, u32 mask0, u32 mask1)
70a1b6b0a9SMario Six {
71a1b6b0a9SMario Six 	struct efuse_val val;
72a1b6b0a9SMario Six 
73a1b6b0a9SMario Six 	val.dwords.d[0] = readl(&efuse->bits_31_0);
74a1b6b0a9SMario Six 	val.dwords.d[1] = readl(&efuse->bits_63_32);
75a1b6b0a9SMario Six 	val.lock = readl(&efuse->bit64);
76a1b6b0a9SMario Six 
77a1b6b0a9SMario Six 	if (val.lock & 1)
78a1b6b0a9SMario Six 		return -EPERM;
79a1b6b0a9SMario Six 
80a1b6b0a9SMario Six 	val.dwords.d[0] |= (new_val->dwords.d[0] & mask0);
81a1b6b0a9SMario Six 	val.dwords.d[1] |= (new_val->dwords.d[1] & mask1);
82a1b6b0a9SMario Six 	val.lock |= new_val->lock;
83a1b6b0a9SMario Six 
84a1b6b0a9SMario Six 	writel(val.dwords.d[0], &efuse->bits_31_0);
85a1b6b0a9SMario Six 	mdelay(1);
86a1b6b0a9SMario Six 	writel(val.dwords.d[1], &efuse->bits_63_32);
87a1b6b0a9SMario Six 	mdelay(1);
88a1b6b0a9SMario Six 	writel(val.lock, &efuse->bit64);
89a1b6b0a9SMario Six 	mdelay(5);
90a1b6b0a9SMario Six 
91a1b6b0a9SMario Six 	return 0;
92a1b6b0a9SMario Six }
93a1b6b0a9SMario Six 
prog_efuse(int nr,struct efuse_val * new_val,u32 mask0,u32 mask1)94a1b6b0a9SMario Six static int prog_efuse(int nr, struct efuse_val *new_val, u32 mask0, u32 mask1)
95a1b6b0a9SMario Six {
96a1b6b0a9SMario Six 	struct mvebu_hd_efuse *efuse;
97a1b6b0a9SMario Six 	int res = 0;
98a1b6b0a9SMario Six 
99a1b6b0a9SMario Six 	res = mvebu_efuse_init_hw();
100a1b6b0a9SMario Six 	if (res)
101a1b6b0a9SMario Six 		return res;
102a1b6b0a9SMario Six 
103a1b6b0a9SMario Six 	efuse = get_efuse_line(nr);
104a1b6b0a9SMario Six 	if (!efuse)
105a1b6b0a9SMario Six 		return -ENODEV;
106a1b6b0a9SMario Six 
107a1b6b0a9SMario Six 	if (!new_val)
108a1b6b0a9SMario Six 		return -EINVAL;
109a1b6b0a9SMario Six 
110a1b6b0a9SMario Six 	/* only write a fuse line with lock bit */
111a1b6b0a9SMario Six 	if (!new_val->lock)
112a1b6b0a9SMario Six 		return -EINVAL;
113a1b6b0a9SMario Six 
114a1b6b0a9SMario Six 	/* according to specs ECC protection bits must be 0 on write */
115a1b6b0a9SMario Six 	if (new_val->bytes.d[7] & 0xFE)
116a1b6b0a9SMario Six 		return -EINVAL;
117a1b6b0a9SMario Six 
118a1b6b0a9SMario Six 	if (!new_val->dwords.d[0] && !new_val->dwords.d[1] && (mask0 | mask1))
119a1b6b0a9SMario Six 		return 0;
120a1b6b0a9SMario Six 
121a1b6b0a9SMario Six 	enable_efuse_program();
122a1b6b0a9SMario Six 
123a1b6b0a9SMario Six 	res = do_prog_efuse(efuse, new_val, mask0, mask1);
124a1b6b0a9SMario Six 
125a1b6b0a9SMario Six 	disable_efuse_program();
126a1b6b0a9SMario Six 
127a1b6b0a9SMario Six 	return res;
128a1b6b0a9SMario Six }
129a1b6b0a9SMario Six 
mvebu_efuse_init_hw(void)130a1b6b0a9SMario Six int mvebu_efuse_init_hw(void)
131a1b6b0a9SMario Six {
132a1b6b0a9SMario Six 	int ret;
133a1b6b0a9SMario Six 
134a1b6b0a9SMario Six 	if (efuse_initialised)
135a1b6b0a9SMario Six 		return 0;
136a1b6b0a9SMario Six 
137a1b6b0a9SMario Six 	ret = mvebu_mbus_add_window_by_id(
138a1b6b0a9SMario Six 		CPU_TARGET_SATA23_DFX, 0xA, MBUS_EFUSE_BASE, MBUS_EFUSE_SIZE);
139a1b6b0a9SMario Six 
140a1b6b0a9SMario Six 	if (ret)
141a1b6b0a9SMario Six 		return ret;
142a1b6b0a9SMario Six 
143a1b6b0a9SMario Six 	efuse_initialised = 1;
144a1b6b0a9SMario Six 
145a1b6b0a9SMario Six 	return 0;
146a1b6b0a9SMario Six }
147a1b6b0a9SMario Six 
mvebu_read_efuse(int nr,struct efuse_val * val)148a1b6b0a9SMario Six int mvebu_read_efuse(int nr, struct efuse_val *val)
149a1b6b0a9SMario Six {
150a1b6b0a9SMario Six 	struct mvebu_hd_efuse *efuse;
151a1b6b0a9SMario Six 	int res;
152a1b6b0a9SMario Six 
153a1b6b0a9SMario Six 	res = mvebu_efuse_init_hw();
154a1b6b0a9SMario Six 	if (res)
155a1b6b0a9SMario Six 		return res;
156a1b6b0a9SMario Six 
157a1b6b0a9SMario Six 	efuse = get_efuse_line(nr);
158a1b6b0a9SMario Six 	if (!efuse)
159a1b6b0a9SMario Six 		return -ENODEV;
160a1b6b0a9SMario Six 
161a1b6b0a9SMario Six 	if (!val)
162a1b6b0a9SMario Six 		return -EINVAL;
163a1b6b0a9SMario Six 
164a1b6b0a9SMario Six 	val->dwords.d[0] = readl(&efuse->bits_31_0);
165a1b6b0a9SMario Six 	val->dwords.d[1] = readl(&efuse->bits_63_32);
166a1b6b0a9SMario Six 	val->lock = readl(&efuse->bit64);
167a1b6b0a9SMario Six 	return 0;
168a1b6b0a9SMario Six }
169a1b6b0a9SMario Six 
mvebu_write_efuse(int nr,struct efuse_val * val)170a1b6b0a9SMario Six int mvebu_write_efuse(int nr, struct efuse_val *val)
171a1b6b0a9SMario Six {
172a1b6b0a9SMario Six 	return prog_efuse(nr, val, ~0, ~0);
173a1b6b0a9SMario Six }
174a1b6b0a9SMario Six 
mvebu_lock_efuse(int nr)175a1b6b0a9SMario Six int mvebu_lock_efuse(int nr)
176a1b6b0a9SMario Six {
177a1b6b0a9SMario Six 	struct efuse_val val = {
178a1b6b0a9SMario Six 		.lock = 1,
179a1b6b0a9SMario Six 	};
180a1b6b0a9SMario Six 
181a1b6b0a9SMario Six 	return prog_efuse(nr, &val, 0, 0);
182a1b6b0a9SMario Six }
183a1b6b0a9SMario Six 
184a1b6b0a9SMario Six /*
185a1b6b0a9SMario Six  * wrapper funcs providing the fuse API
186a1b6b0a9SMario Six  *
187a1b6b0a9SMario Six  * we use the following mapping:
188a1b6b0a9SMario Six  *   "bank" ->	eFuse line
189a1b6b0a9SMario Six  *   "word" ->	0: bits 0-31
190a1b6b0a9SMario Six  *		1: bits 32-63
191a1b6b0a9SMario Six  *		2: bit 64 (lock)
192a1b6b0a9SMario Six  */
193a1b6b0a9SMario Six 
194a1b6b0a9SMario Six static struct efuse_val prog_val;
195a1b6b0a9SMario Six static int valid_prog_words;
196a1b6b0a9SMario Six 
fuse_read(u32 bank,u32 word,u32 * val)197a1b6b0a9SMario Six int fuse_read(u32 bank, u32 word, u32 *val)
198a1b6b0a9SMario Six {
199a1b6b0a9SMario Six 	struct efuse_val fuse_line;
200a1b6b0a9SMario Six 	int res;
201a1b6b0a9SMario Six 
202a1b6b0a9SMario Six 	if (bank < EFUSE_LINE_MIN || bank > EFUSE_LINE_MAX || word > 2)
203a1b6b0a9SMario Six 		return -EINVAL;
204a1b6b0a9SMario Six 
205a1b6b0a9SMario Six 	res = mvebu_read_efuse(bank, &fuse_line);
206a1b6b0a9SMario Six 	if (res)
207a1b6b0a9SMario Six 		return res;
208a1b6b0a9SMario Six 
209a1b6b0a9SMario Six 	if (word < 2)
210a1b6b0a9SMario Six 		*val = fuse_line.dwords.d[word];
211a1b6b0a9SMario Six 	else
212a1b6b0a9SMario Six 		*val = fuse_line.lock;
213a1b6b0a9SMario Six 
214a1b6b0a9SMario Six 	return res;
215a1b6b0a9SMario Six }
216a1b6b0a9SMario Six 
fuse_sense(u32 bank,u32 word,u32 * val)217a1b6b0a9SMario Six int fuse_sense(u32 bank, u32 word, u32 *val)
218a1b6b0a9SMario Six {
219a1b6b0a9SMario Six 	/* not supported */
220a1b6b0a9SMario Six 	return -ENOSYS;
221a1b6b0a9SMario Six }
222a1b6b0a9SMario Six 
fuse_prog(u32 bank,u32 word,u32 val)223a1b6b0a9SMario Six int fuse_prog(u32 bank, u32 word, u32 val)
224a1b6b0a9SMario Six {
225a1b6b0a9SMario Six 	int res = 0;
226a1b6b0a9SMario Six 
227a1b6b0a9SMario Six 	/*
228a1b6b0a9SMario Six 	 * NOTE: Fuse line should be written as whole.
229a1b6b0a9SMario Six 	 * So how can we do that with this API?
230a1b6b0a9SMario Six 	 * For now: remember values for word == 0 and word == 1 and write the
231a1b6b0a9SMario Six 	 * whole line when word == 2.
232a1b6b0a9SMario Six 	 * This implies that we always require all 3 fuse prog cmds (one for
233a1b6b0a9SMario Six 	 * for each word) to write a single fuse line.
234a1b6b0a9SMario Six 	 * Exception is a single write to word 2 which will lock the fuse line.
235a1b6b0a9SMario Six 	 *
236a1b6b0a9SMario Six 	 * Hope that will be OK.
237a1b6b0a9SMario Six 	 */
238a1b6b0a9SMario Six 
239a1b6b0a9SMario Six 	if (bank < EFUSE_LINE_MIN || bank > EFUSE_LINE_MAX || word > 2)
240a1b6b0a9SMario Six 		return -EINVAL;
241a1b6b0a9SMario Six 
242a1b6b0a9SMario Six 	if (word < 2) {
243a1b6b0a9SMario Six 		prog_val.dwords.d[word] = val;
244a1b6b0a9SMario Six 		valid_prog_words |= (1 << word);
245a1b6b0a9SMario Six 	} else if ((valid_prog_words & 3) == 0 && val) {
246a1b6b0a9SMario Six 		res = mvebu_lock_efuse(bank);
247a1b6b0a9SMario Six 		valid_prog_words = 0;
248a1b6b0a9SMario Six 	} else if ((valid_prog_words & 3) != 3 || !val) {
249a1b6b0a9SMario Six 		res = -EINVAL;
250a1b6b0a9SMario Six 	} else {
251a1b6b0a9SMario Six 		prog_val.lock = val != 0;
252a1b6b0a9SMario Six 		res = mvebu_write_efuse(bank, &prog_val);
253a1b6b0a9SMario Six 		valid_prog_words = 0;
254a1b6b0a9SMario Six 	}
255a1b6b0a9SMario Six 
256a1b6b0a9SMario Six 	return res;
257a1b6b0a9SMario Six }
258a1b6b0a9SMario Six 
fuse_override(u32 bank,u32 word,u32 val)259a1b6b0a9SMario Six int fuse_override(u32 bank, u32 word, u32 val)
260a1b6b0a9SMario Six {
261a1b6b0a9SMario Six 	/* not supported */
262a1b6b0a9SMario Six 	return -ENOSYS;
263a1b6b0a9SMario Six }
264