2 * eFuse driver for Rockchip devices
4 * Copyright 2017, Theobroma Systems Design und Consulting GmbH
5 * Written by Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
7 * SPDX-License-Identifier: GPL-2.0+
13 #include <display_options.h>
15 #include <linux/bitops.h>
16 #include <linux/delay.h>
19 #define RK3399_A_SHIFT 16
20 #define RK3399_A_MASK 0x3ff
21 #define RK3399_NFUSES 32
22 #define RK3399_BYTES_PER_FUSE 4
23 #define RK3399_STROBSFTSEL BIT(9)
24 #define RK3399_RSB BIT(7)
25 #define RK3399_PD BIT(5)
26 #define RK3399_PGENB BIT(3)
27 #define RK3399_LOAD BIT(2)
28 #define RK3399_STROBE BIT(1)
29 #define RK3399_CSB BIT(0)
31 struct rockchip_efuse_regs
{
32 u32 ctrl
; /* 0x00 efuse control register */
33 u32 dout
; /* 0x04 efuse data out register */
34 u32 rf
; /* 0x08 efuse redundancy bit used register */
36 u32 jtag_pass
; /* 0x10 JTAG password */
37 u32 strobe_finish_ctrl
;
38 /* 0x14 efuse strobe finish control register */
41 struct rockchip_efuse_platdata
{
47 static int dump_efuses(cmd_tbl_t
*cmdtp
, int flag
,
48 int argc
, char * const argv
[])
51 * N.B.: This function is tailored towards the RK3399 and assumes that
52 * there's always 32 fuses x 32 bits (i.e. 128 bytes of data) to
60 /* retrieve the device */
61 ret
= uclass_get_device_by_driver(UCLASS_MISC
,
62 DM_GET_DRIVER(rockchip_efuse
), &dev
);
64 printf("%s: no misc-device found\n", __func__
);
68 ret
= misc_read(dev
, 0, &fuses
, sizeof(fuses
));
70 printf("%s: misc_read failed\n", __func__
);
74 printf("efuse-contents:\n");
75 print_buffer(0, fuses
, 1, 128, 16);
81 rk3399_dump_efuses
, 1, 1, dump_efuses
,
82 "Dump the content of the efuses",
87 static int rockchip_rk3399_efuse_read(struct udevice
*dev
, int offset
,
90 struct rockchip_efuse_platdata
*plat
= dev_get_platdata(dev
);
91 struct rockchip_efuse_regs
*efuse
=
92 (struct rockchip_efuse_regs
*)plat
->base
;
94 unsigned int addr_start
, addr_end
, addr_offset
;
96 u8 bytes
[RK3399_NFUSES
* RK3399_BYTES_PER_FUSE
];
100 addr_start
= offset
/ RK3399_BYTES_PER_FUSE
;
101 addr_offset
= offset
% RK3399_BYTES_PER_FUSE
;
102 addr_end
= DIV_ROUND_UP(offset
+ size
, RK3399_BYTES_PER_FUSE
);
104 /* cap to the size of the efuse block */
105 if (addr_end
> RK3399_NFUSES
)
106 addr_end
= RK3399_NFUSES
;
108 writel(RK3399_LOAD
| RK3399_PGENB
| RK3399_STROBSFTSEL
| RK3399_RSB
,
111 for (addr
= addr_start
; addr
< addr_end
; addr
++) {
112 setbits_le32(&efuse
->ctrl
,
113 RK3399_STROBE
| (addr
<< RK3399_A_SHIFT
));
115 out_value
= readl(&efuse
->dout
);
116 clrbits_le32(&efuse
->ctrl
, RK3399_STROBE
);
119 memcpy(&bytes
[i
], &out_value
, RK3399_BYTES_PER_FUSE
);
120 i
+= RK3399_BYTES_PER_FUSE
;
123 /* Switch to standby mode */
124 writel(RK3399_PD
| RK3399_CSB
, &efuse
->ctrl
);
126 memcpy(buf
, bytes
+ addr_offset
, size
);
131 static int rockchip_efuse_read(struct udevice
*dev
, int offset
,
134 return rockchip_rk3399_efuse_read(dev
, offset
, buf
, size
);
137 static const struct misc_ops rockchip_efuse_ops
= {
138 .read
= rockchip_efuse_read
,
141 static int rockchip_efuse_ofdata_to_platdata(struct udevice
*dev
)
143 struct rockchip_efuse_platdata
*plat
= dev_get_platdata(dev
);
145 plat
->base
= dev_read_addr_ptr(dev
);
149 static const struct udevice_id rockchip_efuse_ids
[] = {
150 { .compatible
= "rockchip,rk3399-efuse" },
154 U_BOOT_DRIVER(rockchip_efuse
) = {
155 .name
= "rockchip_efuse",
157 .of_match
= rockchip_efuse_ids
,
158 .ofdata_to_platdata
= rockchip_efuse_ofdata_to_platdata
,
159 .platdata_auto_alloc_size
= sizeof(struct rockchip_efuse_platdata
),
160 .ops
= &rockchip_efuse_ops
,