xref: /openbmc/u-boot/drivers/misc/jz4780_efuse.c (revision 7e40d0a3)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * JZ4780 EFUSE driver
4  *
5  * Copyright (c) 2014 Imagination Technologies
6  * Author: Alex Smith <alex.smith@imgtec.com>
7  */
8 
9 #include <common.h>
10 #include <asm/io.h>
11 #include <asm/unaligned.h>
12 #include <errno.h>
13 #include <mach/jz4780.h>
14 #include <wait_bit.h>
15 
16 #define EFUSE_EFUCTRL			0xd0
17 #define EFUSE_EFUCFG			0xd4
18 #define EFUSE_EFUSTATE			0xd8
19 #define EFUSE_EFUDATA(n)		(0xdc + ((n) * 4))
20 
21 #define EFUSE_EFUCTRL_RD_EN		BIT(0)
22 #define EFUSE_EFUCTRL_LEN_BIT		16
23 #define EFUSE_EFUCTRL_LEN_MASK		0x1f
24 #define EFUSE_EFUCTRL_ADDR_BIT		21
25 #define EFUSE_EFUCTRL_ADDR_MASK		0x1ff
26 #define EFUSE_EFUCTRL_CS		BIT(30)
27 
28 #define EFUSE_EFUCFG_RD_STROBE_BIT	16
29 #define EFUSE_EFUCFG_RD_STROBE_MASK	0xf
30 #define EFUSE_EFUCFG_RD_ADJ_BIT		20
31 #define EFUSE_EFUCFG_RD_ADJ_MASK	0xf
32 
33 #define EFUSE_EFUSTATE_RD_DONE		BIT(0)
34 
jz4780_efuse_read_chunk(size_t addr,size_t count,u8 * buf)35 static void jz4780_efuse_read_chunk(size_t addr, size_t count, u8 *buf)
36 {
37 	void __iomem *regs = (void __iomem *)NEMC_BASE;
38 	size_t i;
39 	u32 val;
40 	int ret;
41 
42 	val = EFUSE_EFUCTRL_RD_EN |
43 		((count - 1) << EFUSE_EFUCTRL_LEN_BIT) |
44 		(addr << EFUSE_EFUCTRL_ADDR_BIT) |
45 		((addr > 0x200) ? EFUSE_EFUCTRL_CS : 0);
46 	writel(val, regs + EFUSE_EFUCTRL);
47 
48 	ret = wait_for_bit_le32(regs + EFUSE_EFUSTATE,
49 				EFUSE_EFUSTATE_RD_DONE, true, 10000, false);
50 	if (ret)
51 		return;
52 
53 	if ((count % 4) == 0) {
54 		for (i = 0; i < count / 4; i++) {
55 			val = readl(regs + EFUSE_EFUDATA(i));
56 			put_unaligned(val, (u32 *)(buf + (i * 4)));
57 		}
58 	} else {
59 		val = readl(regs + EFUSE_EFUDATA(0));
60 		if (count > 2)
61 			buf[2] = (val >> 16) & 0xff;
62 		if (count > 1)
63 			buf[1] = (val >> 8) & 0xff;
64 		buf[0] = val & 0xff;
65 	}
66 }
67 
jz4780_efuse_chunk_size(size_t count)68 static inline int jz4780_efuse_chunk_size(size_t count)
69 {
70 	if (count >= 32)
71 		return 32;
72 	else if ((count / 4) > 0)
73 		return (count / 4) * 4;
74 	else
75 		return count % 4;
76 }
77 
jz4780_efuse_read(size_t addr,size_t count,u8 * buf)78 void jz4780_efuse_read(size_t addr, size_t count, u8 *buf)
79 {
80 	size_t chunk;
81 
82 	while (count > 0) {
83 		chunk = jz4780_efuse_chunk_size(count);
84 		jz4780_efuse_read_chunk(addr, chunk, buf);
85 		addr += chunk;
86 		buf += chunk;
87 		count -= chunk;
88 	}
89 }
90 
jz4780_efuse_init(u32 ahb2_rate)91 void jz4780_efuse_init(u32 ahb2_rate)
92 {
93 	void __iomem *regs = (void __iomem *)NEMC_BASE;
94 	u32 rd_adj, rd_strobe, tmp;
95 
96 	rd_adj = (((6500 * (ahb2_rate / 1000000)) / 1000000) + 0xf) / 2;
97 	tmp = (((35000 * (ahb2_rate / 1000000)) / 1000000) - 4) - rd_adj;
98 	rd_strobe = ((tmp + 0xf) / 2 < 7) ? 7 : (tmp + 0xf) / 2;
99 
100 	tmp = (rd_adj << EFUSE_EFUCFG_RD_ADJ_BIT) |
101 	      (rd_strobe << EFUSE_EFUCFG_RD_STROBE_BIT);
102 	writel(tmp, regs + EFUSE_EFUCFG);
103 }
104