149cd8e85SPhilipp Tomsich /* 249cd8e85SPhilipp Tomsich * eFuse driver for Rockchip devices 349cd8e85SPhilipp Tomsich * 449cd8e85SPhilipp Tomsich * Copyright 2017, Theobroma Systems Design und Consulting GmbH 549cd8e85SPhilipp Tomsich * Written by Philipp Tomsich <philipp.tomsich@theobroma-systems.com> 649cd8e85SPhilipp Tomsich * 749cd8e85SPhilipp Tomsich * SPDX-License-Identifier: GPL-2.0+ 849cd8e85SPhilipp Tomsich */ 949cd8e85SPhilipp Tomsich 1049cd8e85SPhilipp Tomsich #include <common.h> 1149cd8e85SPhilipp Tomsich #include <asm/io.h> 1249cd8e85SPhilipp Tomsich #include <command.h> 1349cd8e85SPhilipp Tomsich #include <display_options.h> 1449cd8e85SPhilipp Tomsich #include <dm.h> 1549cd8e85SPhilipp Tomsich #include <linux/bitops.h> 1649cd8e85SPhilipp Tomsich #include <linux/delay.h> 1749cd8e85SPhilipp Tomsich #include <misc.h> 1849cd8e85SPhilipp Tomsich 19*b13cc84cSFinley Xiao #define T_CSB_P_S 0 20*b13cc84cSFinley Xiao #define T_PGENB_P_S 0 21*b13cc84cSFinley Xiao #define T_LOAD_P_S 0 22*b13cc84cSFinley Xiao #define T_ADDR_P_S 0 23*b13cc84cSFinley Xiao #define T_STROBE_P_S (0 + 110) /* 1.1us */ 24*b13cc84cSFinley Xiao #define T_CSB_P_L (0 + 110 + 1000 + 20) /* 200ns */ 25*b13cc84cSFinley Xiao #define T_PGENB_P_L (0 + 110 + 1000 + 20) 26*b13cc84cSFinley Xiao #define T_LOAD_P_L (0 + 110 + 1000 + 20) 27*b13cc84cSFinley Xiao #define T_ADDR_P_L (0 + 110 + 1000 + 20) 28*b13cc84cSFinley Xiao #define T_STROBE_P_L (0 + 110 + 1000) /* 10us */ 29*b13cc84cSFinley Xiao #define T_CSB_R_S 0 30*b13cc84cSFinley Xiao #define T_PGENB_R_S 0 31*b13cc84cSFinley Xiao #define T_LOAD_R_S 0 32*b13cc84cSFinley Xiao #define T_ADDR_R_S 2 33*b13cc84cSFinley Xiao #define T_STROBE_R_S (2 + 3) 34*b13cc84cSFinley Xiao #define T_CSB_R_L (2 + 3 + 3 + 3) 35*b13cc84cSFinley Xiao #define T_PGENB_R_L (2 + 3 + 3 + 3) 36*b13cc84cSFinley Xiao #define T_LOAD_R_L (2 + 3 + 3 + 3) 37*b13cc84cSFinley Xiao #define T_ADDR_R_L (2 + 3 + 3 + 2) 38*b13cc84cSFinley Xiao #define T_STROBE_R_L (2 + 3 + 3) 39*b13cc84cSFinley Xiao 40*b13cc84cSFinley Xiao #define T_CSB_P 0x28 41*b13cc84cSFinley Xiao #define T_PGENB_P 0x2c 42*b13cc84cSFinley Xiao #define T_LOAD_P 0x30 43*b13cc84cSFinley Xiao #define T_ADDR_P 0x34 44*b13cc84cSFinley Xiao #define T_STROBE_P 0x38 45*b13cc84cSFinley Xiao #define T_CSB_R 0x3c 46*b13cc84cSFinley Xiao #define T_PGENB_R 0x40 47*b13cc84cSFinley Xiao #define T_LOAD_R 0x44 48*b13cc84cSFinley Xiao #define T_ADDR_R 0x48 49*b13cc84cSFinley Xiao #define T_STROBE_R 0x4c 50*b13cc84cSFinley Xiao 51*b13cc84cSFinley Xiao #define RK1808_USER_MODE BIT(0) 52*b13cc84cSFinley Xiao #define RK1808_INT_FINISH BIT(0) 53*b13cc84cSFinley Xiao #define RK1808_AUTO_ENB BIT(0) 54*b13cc84cSFinley Xiao #define RK1808_AUTO_RD BIT(1) 55*b13cc84cSFinley Xiao #define RK1808_A_SHIFT 16 56*b13cc84cSFinley Xiao #define RK1808_A_MASK 0x3ff 57*b13cc84cSFinley Xiao #define RK1808_NBYTES 4 58*b13cc84cSFinley Xiao 5949cd8e85SPhilipp Tomsich #define RK3399_A_SHIFT 16 6049cd8e85SPhilipp Tomsich #define RK3399_A_MASK 0x3ff 6149cd8e85SPhilipp Tomsich #define RK3399_NFUSES 32 6249cd8e85SPhilipp Tomsich #define RK3399_BYTES_PER_FUSE 4 6349cd8e85SPhilipp Tomsich #define RK3399_STROBSFTSEL BIT(9) 6449cd8e85SPhilipp Tomsich #define RK3399_RSB BIT(7) 6549cd8e85SPhilipp Tomsich #define RK3399_PD BIT(5) 6649cd8e85SPhilipp Tomsich #define RK3399_PGENB BIT(3) 6749cd8e85SPhilipp Tomsich #define RK3399_LOAD BIT(2) 6849cd8e85SPhilipp Tomsich #define RK3399_STROBE BIT(1) 6949cd8e85SPhilipp Tomsich #define RK3399_CSB BIT(0) 7049cd8e85SPhilipp Tomsich 71b4fa32f0SFrancis Fan #define RK3288_A_SHIFT 6 72b4fa32f0SFrancis Fan #define RK3288_A_MASK 0x3ff 73b4fa32f0SFrancis Fan #define RK3288_NFUSES 32 74b4fa32f0SFrancis Fan #define RK3288_BYTES_PER_FUSE 1 75b4fa32f0SFrancis Fan #define RK3288_PGENB BIT(3) 76b4fa32f0SFrancis Fan #define RK3288_LOAD BIT(2) 77b4fa32f0SFrancis Fan #define RK3288_STROBE BIT(1) 78b4fa32f0SFrancis Fan #define RK3288_CSB BIT(0) 79b4fa32f0SFrancis Fan 8059a83996SJoseph Chen #define RK3328_INT_STATUS 0x0018 8159a83996SJoseph Chen #define RK3328_DOUT 0x0020 8259a83996SJoseph Chen #define RK3328_AUTO_CTRL 0x0024 8359a83996SJoseph Chen #define RK3328_INT_FINISH BIT(0) 8459a83996SJoseph Chen #define RK3328_AUTO_ENB BIT(0) 8559a83996SJoseph Chen #define RK3328_AUTO_RD BIT(1) 8659a83996SJoseph Chen 87b4fa32f0SFrancis Fan typedef int (*EFUSE_READ)(struct udevice *dev, int offset, void *buf, int size); 88b4fa32f0SFrancis Fan 8949cd8e85SPhilipp Tomsich struct rockchip_efuse_regs { 9049cd8e85SPhilipp Tomsich u32 ctrl; /* 0x00 efuse control register */ 9149cd8e85SPhilipp Tomsich u32 dout; /* 0x04 efuse data out register */ 9249cd8e85SPhilipp Tomsich u32 rf; /* 0x08 efuse redundancy bit used register */ 9349cd8e85SPhilipp Tomsich u32 _rsvd0; 9449cd8e85SPhilipp Tomsich u32 jtag_pass; /* 0x10 JTAG password */ 9549cd8e85SPhilipp Tomsich u32 strobe_finish_ctrl; 9649cd8e85SPhilipp Tomsich /* 0x14 efuse strobe finish control register */ 9759a83996SJoseph Chen u32 int_status;/* 0x18 */ 9859a83996SJoseph Chen u32 reserved; /* 0x1c */ 9959a83996SJoseph Chen u32 dout2; /* 0x20 */ 10059a83996SJoseph Chen u32 auto_ctrl; /* 0x24 */ 10149cd8e85SPhilipp Tomsich }; 10249cd8e85SPhilipp Tomsich 10349cd8e85SPhilipp Tomsich struct rockchip_efuse_platdata { 10449cd8e85SPhilipp Tomsich void __iomem *base; 10549cd8e85SPhilipp Tomsich struct clk *clk; 10649cd8e85SPhilipp Tomsich }; 10749cd8e85SPhilipp Tomsich 10849cd8e85SPhilipp Tomsich #if defined(DEBUG) 10949cd8e85SPhilipp Tomsich static int dump_efuses(cmd_tbl_t *cmdtp, int flag, 11049cd8e85SPhilipp Tomsich int argc, char * const argv[]) 11149cd8e85SPhilipp Tomsich { 11249cd8e85SPhilipp Tomsich /* 11349cd8e85SPhilipp Tomsich * N.B.: This function is tailored towards the RK3399 and assumes that 11449cd8e85SPhilipp Tomsich * there's always 32 fuses x 32 bits (i.e. 128 bytes of data) to 11549cd8e85SPhilipp Tomsich * be read. 11649cd8e85SPhilipp Tomsich */ 11749cd8e85SPhilipp Tomsich 11849cd8e85SPhilipp Tomsich struct udevice *dev; 119b4fa32f0SFrancis Fan u8 fuses[128] = {0}; 12049cd8e85SPhilipp Tomsich int ret; 12149cd8e85SPhilipp Tomsich 12249cd8e85SPhilipp Tomsich /* retrieve the device */ 12349cd8e85SPhilipp Tomsich ret = uclass_get_device_by_driver(UCLASS_MISC, 12449cd8e85SPhilipp Tomsich DM_GET_DRIVER(rockchip_efuse), &dev); 12549cd8e85SPhilipp Tomsich if (ret) { 12649cd8e85SPhilipp Tomsich printf("%s: no misc-device found\n", __func__); 12749cd8e85SPhilipp Tomsich return 0; 12849cd8e85SPhilipp Tomsich } 12949cd8e85SPhilipp Tomsich 13049cd8e85SPhilipp Tomsich ret = misc_read(dev, 0, &fuses, sizeof(fuses)); 13149cd8e85SPhilipp Tomsich if (ret) { 13249cd8e85SPhilipp Tomsich printf("%s: misc_read failed\n", __func__); 13349cd8e85SPhilipp Tomsich return 0; 13449cd8e85SPhilipp Tomsich } 13549cd8e85SPhilipp Tomsich 13649cd8e85SPhilipp Tomsich printf("efuse-contents:\n"); 13749cd8e85SPhilipp Tomsich print_buffer(0, fuses, 1, 128, 16); 13849cd8e85SPhilipp Tomsich 13949cd8e85SPhilipp Tomsich return 0; 14049cd8e85SPhilipp Tomsich } 14149cd8e85SPhilipp Tomsich 14249cd8e85SPhilipp Tomsich U_BOOT_CMD( 143b4fa32f0SFrancis Fan rockchip_dump_efuses, 1, 1, dump_efuses, 14449cd8e85SPhilipp Tomsich "Dump the content of the efuses", 14549cd8e85SPhilipp Tomsich "" 14649cd8e85SPhilipp Tomsich ); 14749cd8e85SPhilipp Tomsich #endif 14849cd8e85SPhilipp Tomsich 149*b13cc84cSFinley Xiao static void rk1808_efuse_timing_init(void __iomem *base) 150*b13cc84cSFinley Xiao { 151*b13cc84cSFinley Xiao static bool init; 152*b13cc84cSFinley Xiao 153*b13cc84cSFinley Xiao if (init) 154*b13cc84cSFinley Xiao return; 155*b13cc84cSFinley Xiao 156*b13cc84cSFinley Xiao /* enable auto mode */ 157*b13cc84cSFinley Xiao writel(readl(base) & (~RK1808_USER_MODE), base); 158*b13cc84cSFinley Xiao 159*b13cc84cSFinley Xiao /* setup efuse timing */ 160*b13cc84cSFinley Xiao writel((T_CSB_P_S << 16) | T_CSB_P_L, base + T_CSB_P); 161*b13cc84cSFinley Xiao writel((T_PGENB_P_S << 16) | T_PGENB_P_L, base + T_PGENB_P); 162*b13cc84cSFinley Xiao writel((T_LOAD_P_S << 16) | T_LOAD_P_L, base + T_LOAD_P); 163*b13cc84cSFinley Xiao writel((T_ADDR_P_S << 16) | T_ADDR_P_L, base + T_ADDR_P); 164*b13cc84cSFinley Xiao writel((T_STROBE_P_S << 16) | T_STROBE_P_L, base + T_STROBE_P); 165*b13cc84cSFinley Xiao writel((T_CSB_R_S << 16) | T_CSB_R_L, base + T_CSB_R); 166*b13cc84cSFinley Xiao writel((T_PGENB_R_S << 16) | T_PGENB_R_L, base + T_PGENB_R); 167*b13cc84cSFinley Xiao writel((T_LOAD_R_S << 16) | T_LOAD_R_L, base + T_LOAD_R); 168*b13cc84cSFinley Xiao writel((T_ADDR_R_S << 16) | T_ADDR_R_L, base + T_ADDR_R); 169*b13cc84cSFinley Xiao writel((T_STROBE_R_S << 16) | T_STROBE_R_L, base + T_STROBE_R); 170*b13cc84cSFinley Xiao 171*b13cc84cSFinley Xiao init = true; 172*b13cc84cSFinley Xiao } 173*b13cc84cSFinley Xiao 174*b13cc84cSFinley Xiao static int rockchip_rk1808_efuse_read(struct udevice *dev, int offset, 175*b13cc84cSFinley Xiao void *buf, int size) 176*b13cc84cSFinley Xiao { 177*b13cc84cSFinley Xiao struct rockchip_efuse_platdata *plat = dev_get_platdata(dev); 178*b13cc84cSFinley Xiao struct rockchip_efuse_regs *efuse = 179*b13cc84cSFinley Xiao (struct rockchip_efuse_regs *)plat->base; 180*b13cc84cSFinley Xiao unsigned int addr_start, addr_end, addr_offset, addr_len; 181*b13cc84cSFinley Xiao u32 out_value, status; 182*b13cc84cSFinley Xiao u8 *buffer; 183*b13cc84cSFinley Xiao int ret = 0, i = 0; 184*b13cc84cSFinley Xiao 185*b13cc84cSFinley Xiao rk1808_efuse_timing_init(plat->base); 186*b13cc84cSFinley Xiao 187*b13cc84cSFinley Xiao addr_start = rounddown(offset, RK1808_NBYTES) / RK1808_NBYTES; 188*b13cc84cSFinley Xiao addr_end = roundup(offset + size, RK1808_NBYTES) / RK1808_NBYTES; 189*b13cc84cSFinley Xiao addr_offset = offset % RK1808_NBYTES; 190*b13cc84cSFinley Xiao addr_len = addr_end - addr_start; 191*b13cc84cSFinley Xiao 192*b13cc84cSFinley Xiao buffer = calloc(1, sizeof(*buffer) * addr_len * RK1808_NBYTES); 193*b13cc84cSFinley Xiao if (!buffer) 194*b13cc84cSFinley Xiao return -ENOMEM; 195*b13cc84cSFinley Xiao 196*b13cc84cSFinley Xiao while (addr_len--) { 197*b13cc84cSFinley Xiao writel(RK1808_AUTO_RD | RK1808_AUTO_ENB | 198*b13cc84cSFinley Xiao ((addr_start++ & RK1808_A_MASK) << RK1808_A_SHIFT), 199*b13cc84cSFinley Xiao &efuse->auto_ctrl); 200*b13cc84cSFinley Xiao udelay(2); 201*b13cc84cSFinley Xiao status = readl(&efuse->int_status); 202*b13cc84cSFinley Xiao if (!(status & RK1808_INT_FINISH)) { 203*b13cc84cSFinley Xiao ret = -EIO; 204*b13cc84cSFinley Xiao goto err; 205*b13cc84cSFinley Xiao } 206*b13cc84cSFinley Xiao out_value = readl(&efuse->dout2); 207*b13cc84cSFinley Xiao writel(RK1808_INT_FINISH, &efuse->int_status); 208*b13cc84cSFinley Xiao 209*b13cc84cSFinley Xiao memcpy(&buffer[i], &out_value, RK1808_NBYTES); 210*b13cc84cSFinley Xiao i += RK1808_NBYTES; 211*b13cc84cSFinley Xiao } 212*b13cc84cSFinley Xiao memcpy(buf, buffer + addr_offset, size); 213*b13cc84cSFinley Xiao err: 214*b13cc84cSFinley Xiao kfree(buffer); 215*b13cc84cSFinley Xiao 216*b13cc84cSFinley Xiao return ret; 217*b13cc84cSFinley Xiao } 218*b13cc84cSFinley Xiao 21949cd8e85SPhilipp Tomsich static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset, 22049cd8e85SPhilipp Tomsich void *buf, int size) 22149cd8e85SPhilipp Tomsich { 22249cd8e85SPhilipp Tomsich struct rockchip_efuse_platdata *plat = dev_get_platdata(dev); 22349cd8e85SPhilipp Tomsich struct rockchip_efuse_regs *efuse = 22449cd8e85SPhilipp Tomsich (struct rockchip_efuse_regs *)plat->base; 22549cd8e85SPhilipp Tomsich 22649cd8e85SPhilipp Tomsich unsigned int addr_start, addr_end, addr_offset; 22749cd8e85SPhilipp Tomsich u32 out_value; 22849cd8e85SPhilipp Tomsich u8 bytes[RK3399_NFUSES * RK3399_BYTES_PER_FUSE]; 22949cd8e85SPhilipp Tomsich int i = 0; 23049cd8e85SPhilipp Tomsich u32 addr; 23149cd8e85SPhilipp Tomsich 23249cd8e85SPhilipp Tomsich addr_start = offset / RK3399_BYTES_PER_FUSE; 23349cd8e85SPhilipp Tomsich addr_offset = offset % RK3399_BYTES_PER_FUSE; 23449cd8e85SPhilipp Tomsich addr_end = DIV_ROUND_UP(offset + size, RK3399_BYTES_PER_FUSE); 23549cd8e85SPhilipp Tomsich 23649cd8e85SPhilipp Tomsich /* cap to the size of the efuse block */ 23749cd8e85SPhilipp Tomsich if (addr_end > RK3399_NFUSES) 23849cd8e85SPhilipp Tomsich addr_end = RK3399_NFUSES; 23949cd8e85SPhilipp Tomsich 24049cd8e85SPhilipp Tomsich writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB, 24149cd8e85SPhilipp Tomsich &efuse->ctrl); 24249cd8e85SPhilipp Tomsich udelay(1); 24349cd8e85SPhilipp Tomsich for (addr = addr_start; addr < addr_end; addr++) { 24449cd8e85SPhilipp Tomsich setbits_le32(&efuse->ctrl, 24549cd8e85SPhilipp Tomsich RK3399_STROBE | (addr << RK3399_A_SHIFT)); 24649cd8e85SPhilipp Tomsich udelay(1); 24749cd8e85SPhilipp Tomsich out_value = readl(&efuse->dout); 24849cd8e85SPhilipp Tomsich clrbits_le32(&efuse->ctrl, RK3399_STROBE); 24949cd8e85SPhilipp Tomsich udelay(1); 25049cd8e85SPhilipp Tomsich 25149cd8e85SPhilipp Tomsich memcpy(&bytes[i], &out_value, RK3399_BYTES_PER_FUSE); 25249cd8e85SPhilipp Tomsich i += RK3399_BYTES_PER_FUSE; 25349cd8e85SPhilipp Tomsich } 25449cd8e85SPhilipp Tomsich 25549cd8e85SPhilipp Tomsich /* Switch to standby mode */ 25649cd8e85SPhilipp Tomsich writel(RK3399_PD | RK3399_CSB, &efuse->ctrl); 25749cd8e85SPhilipp Tomsich 25849cd8e85SPhilipp Tomsich memcpy(buf, bytes + addr_offset, size); 25949cd8e85SPhilipp Tomsich 26049cd8e85SPhilipp Tomsich return 0; 26149cd8e85SPhilipp Tomsich } 26249cd8e85SPhilipp Tomsich 263b4fa32f0SFrancis Fan static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset, 264b4fa32f0SFrancis Fan void *buf, int size) 265b4fa32f0SFrancis Fan { 266b4fa32f0SFrancis Fan struct rockchip_efuse_platdata *plat = dev_get_platdata(dev); 267b4fa32f0SFrancis Fan struct rockchip_efuse_regs *efuse = 268b4fa32f0SFrancis Fan (struct rockchip_efuse_regs *)plat->base; 269b4fa32f0SFrancis Fan u8 *buffer = buf; 270b4fa32f0SFrancis Fan int max_size = RK3288_NFUSES * RK3288_BYTES_PER_FUSE; 271b4fa32f0SFrancis Fan 272b4fa32f0SFrancis Fan if (size > (max_size - offset)) 273b4fa32f0SFrancis Fan size = max_size - offset; 274b4fa32f0SFrancis Fan 275b4fa32f0SFrancis Fan /* Switch to read mode */ 276b4fa32f0SFrancis Fan writel(RK3288_LOAD | RK3288_PGENB, &efuse->ctrl); 277b4fa32f0SFrancis Fan udelay(1); 278b4fa32f0SFrancis Fan 279b4fa32f0SFrancis Fan while (size--) { 280b4fa32f0SFrancis Fan writel(readl(&efuse->ctrl) & 281b4fa32f0SFrancis Fan (~(RK3288_A_MASK << RK3288_A_SHIFT)), 282b4fa32f0SFrancis Fan &efuse->ctrl); 283b4fa32f0SFrancis Fan /* set addr */ 284b4fa32f0SFrancis Fan writel(readl(&efuse->ctrl) | 285b4fa32f0SFrancis Fan ((offset++ & RK3288_A_MASK) << RK3288_A_SHIFT), 286b4fa32f0SFrancis Fan &efuse->ctrl); 287b4fa32f0SFrancis Fan udelay(1); 288b4fa32f0SFrancis Fan /* strobe low to high */ 289b4fa32f0SFrancis Fan writel(readl(&efuse->ctrl) | 290b4fa32f0SFrancis Fan RK3288_STROBE, &efuse->ctrl); 291b4fa32f0SFrancis Fan ndelay(60); 292b4fa32f0SFrancis Fan /* read data */ 293b4fa32f0SFrancis Fan *buffer++ = readl(&efuse->dout); 294b4fa32f0SFrancis Fan /* reset strobe to low */ 295b4fa32f0SFrancis Fan writel(readl(&efuse->ctrl) & 296b4fa32f0SFrancis Fan (~RK3288_STROBE), &efuse->ctrl); 297b4fa32f0SFrancis Fan udelay(1); 298b4fa32f0SFrancis Fan } 299b4fa32f0SFrancis Fan 300b4fa32f0SFrancis Fan /* Switch to standby mode */ 301b4fa32f0SFrancis Fan writel(RK3288_PGENB | RK3288_CSB, &efuse->ctrl); 302b4fa32f0SFrancis Fan 303b4fa32f0SFrancis Fan return 0; 304b4fa32f0SFrancis Fan } 305b4fa32f0SFrancis Fan 30659a83996SJoseph Chen static int rockchip_rk3328_efuse_read(struct udevice *dev, int offset, 30759a83996SJoseph Chen void *buf, int size) 30859a83996SJoseph Chen { 30959a83996SJoseph Chen struct rockchip_efuse_platdata *plat = dev_get_platdata(dev); 31059a83996SJoseph Chen struct rockchip_efuse_regs *efuse = 31159a83996SJoseph Chen (struct rockchip_efuse_regs *)plat->base; 31259a83996SJoseph Chen unsigned int addr_start, addr_end, addr_offset, addr_len; 31359a83996SJoseph Chen u32 out_value, status; 31459a83996SJoseph Chen u8 *buffer; 31559a83996SJoseph Chen int ret = 0, i = 0, j = 0; 31659a83996SJoseph Chen 31759a83996SJoseph Chen /* Max non-secure Byte */ 31859a83996SJoseph Chen if (size > 32) 31959a83996SJoseph Chen size = 32; 32059a83996SJoseph Chen 32159a83996SJoseph Chen /* 128 Byte efuse, 96 Byte for secure, 32 Byte for non-secure */ 32259a83996SJoseph Chen offset += 96; 32359a83996SJoseph Chen addr_start = rounddown(offset, RK3399_BYTES_PER_FUSE) / 32459a83996SJoseph Chen RK3399_BYTES_PER_FUSE; 32559a83996SJoseph Chen addr_end = roundup(offset + size, RK3399_BYTES_PER_FUSE) / 32659a83996SJoseph Chen RK3399_BYTES_PER_FUSE; 32759a83996SJoseph Chen addr_offset = offset % RK3399_BYTES_PER_FUSE; 32859a83996SJoseph Chen addr_len = addr_end - addr_start; 32959a83996SJoseph Chen 33059a83996SJoseph Chen buffer = calloc(1, sizeof(*buffer) * addr_len * RK3399_BYTES_PER_FUSE); 33159a83996SJoseph Chen if (!buffer) 33259a83996SJoseph Chen return -ENOMEM; 33359a83996SJoseph Chen 33459a83996SJoseph Chen for (j = 0; j < addr_len; j++) { 33559a83996SJoseph Chen writel(RK3328_AUTO_RD | RK3328_AUTO_ENB | 33659a83996SJoseph Chen ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT), 33759a83996SJoseph Chen &efuse->auto_ctrl); 33859a83996SJoseph Chen udelay(5); 33959a83996SJoseph Chen status = readl(&efuse->int_status); 34059a83996SJoseph Chen if (!(status & RK3328_INT_FINISH)) { 34159a83996SJoseph Chen ret = -EIO; 34259a83996SJoseph Chen goto err; 34359a83996SJoseph Chen } 34459a83996SJoseph Chen out_value = readl(&efuse->dout2); 34559a83996SJoseph Chen writel(RK3328_INT_FINISH, &efuse->int_status); 34659a83996SJoseph Chen 34759a83996SJoseph Chen memcpy(&buffer[i], &out_value, RK3399_BYTES_PER_FUSE); 34859a83996SJoseph Chen i += RK3399_BYTES_PER_FUSE; 34959a83996SJoseph Chen } 35059a83996SJoseph Chen memcpy(buf, buffer + addr_offset, size); 35159a83996SJoseph Chen err: 35259a83996SJoseph Chen free(buffer); 35359a83996SJoseph Chen 35459a83996SJoseph Chen return ret; 35559a83996SJoseph Chen } 35659a83996SJoseph Chen 35749cd8e85SPhilipp Tomsich static int rockchip_efuse_read(struct udevice *dev, int offset, 35849cd8e85SPhilipp Tomsich void *buf, int size) 35949cd8e85SPhilipp Tomsich { 360b4fa32f0SFrancis Fan EFUSE_READ efuse_read = NULL; 361b4fa32f0SFrancis Fan 362b4fa32f0SFrancis Fan efuse_read = (EFUSE_READ)dev_get_driver_data(dev); 363b4fa32f0SFrancis Fan if (!efuse_read) 364b4fa32f0SFrancis Fan return -ENOSYS; 365b4fa32f0SFrancis Fan 366b4fa32f0SFrancis Fan return (*efuse_read)(dev, offset, buf, size); 36749cd8e85SPhilipp Tomsich } 36849cd8e85SPhilipp Tomsich 36949cd8e85SPhilipp Tomsich static const struct misc_ops rockchip_efuse_ops = { 37049cd8e85SPhilipp Tomsich .read = rockchip_efuse_read, 37149cd8e85SPhilipp Tomsich }; 37249cd8e85SPhilipp Tomsich 37349cd8e85SPhilipp Tomsich static int rockchip_efuse_ofdata_to_platdata(struct udevice *dev) 37449cd8e85SPhilipp Tomsich { 37549cd8e85SPhilipp Tomsich struct rockchip_efuse_platdata *plat = dev_get_platdata(dev); 37649cd8e85SPhilipp Tomsich 37763a453e6SPhilipp Tomsich plat->base = dev_read_addr_ptr(dev); 37849cd8e85SPhilipp Tomsich return 0; 37949cd8e85SPhilipp Tomsich } 38049cd8e85SPhilipp Tomsich 38149cd8e85SPhilipp Tomsich static const struct udevice_id rockchip_efuse_ids[] = { 382b4fa32f0SFrancis Fan { 383*b13cc84cSFinley Xiao .compatible = "rockchip,rk1808-efuse", 384*b13cc84cSFinley Xiao .data = (ulong)&rockchip_rk1808_efuse_read, 385*b13cc84cSFinley Xiao }, 386*b13cc84cSFinley Xiao { 387b4fa32f0SFrancis Fan .compatible = "rockchip,rockchip-efuse", 388e9cfb932SCody Xie .data = (ulong)&rockchip_rk3288_efuse_read, 389b4fa32f0SFrancis Fan }, 390b4fa32f0SFrancis Fan { 391b4fa32f0SFrancis Fan .compatible = "rockchip,rk3066a-efuse", 392e9cfb932SCody Xie .data = (ulong)&rockchip_rk3288_efuse_read, 393b4fa32f0SFrancis Fan }, 394b4fa32f0SFrancis Fan { 395b4fa32f0SFrancis Fan .compatible = "rockchip,rk3188-efuse", 396e9cfb932SCody Xie .data = (ulong)&rockchip_rk3288_efuse_read, 397b4fa32f0SFrancis Fan }, 398b4fa32f0SFrancis Fan { 399b4fa32f0SFrancis Fan .compatible = "rockchip,rk322x-efuse", 400e9cfb932SCody Xie .data = (ulong)&rockchip_rk3288_efuse_read, 401b4fa32f0SFrancis Fan }, 402b4fa32f0SFrancis Fan { 40359a83996SJoseph Chen .compatible = "rockchip,rk3328-efuse", 40459a83996SJoseph Chen .data = (ulong)&rockchip_rk3328_efuse_read, 40559a83996SJoseph Chen }, 40659a83996SJoseph Chen { 407b4fa32f0SFrancis Fan .compatible = "rockchip,rk3399-efuse", 408b4fa32f0SFrancis Fan .data = (ulong)&rockchip_rk3399_efuse_read, 409b4fa32f0SFrancis Fan }, 41049cd8e85SPhilipp Tomsich {} 41149cd8e85SPhilipp Tomsich }; 41249cd8e85SPhilipp Tomsich 41349cd8e85SPhilipp Tomsich U_BOOT_DRIVER(rockchip_efuse) = { 41449cd8e85SPhilipp Tomsich .name = "rockchip_efuse", 41549cd8e85SPhilipp Tomsich .id = UCLASS_MISC, 41649cd8e85SPhilipp Tomsich .of_match = rockchip_efuse_ids, 41749cd8e85SPhilipp Tomsich .ofdata_to_platdata = rockchip_efuse_ofdata_to_platdata, 41849cd8e85SPhilipp Tomsich .platdata_auto_alloc_size = sizeof(struct rockchip_efuse_platdata), 41949cd8e85SPhilipp Tomsich .ops = &rockchip_efuse_ops, 42049cd8e85SPhilipp Tomsich }; 421