1 /* 2 * eFuse driver for Rockchip devices 3 * 4 * Copyright 2017, Theobroma Systems Design und Consulting GmbH 5 * Written by Philipp Tomsich <philipp.tomsich@theobroma-systems.com> 6 * 7 * SPDX-License-Identifier: GPL-2.0+ 8 */ 9 10 #include <common.h> 11 #include <asm/io.h> 12 #include <command.h> 13 #include <display_options.h> 14 #include <dm.h> 15 #include <linux/bitops.h> 16 #include <linux/delay.h> 17 #include <misc.h> 18 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) 30 31 #define RK3288_A_SHIFT 6 32 #define RK3288_A_MASK 0x3ff 33 #define RK3288_NFUSES 32 34 #define RK3288_BYTES_PER_FUSE 1 35 #define RK3288_PGENB BIT(3) 36 #define RK3288_LOAD BIT(2) 37 #define RK3288_STROBE BIT(1) 38 #define RK3288_CSB BIT(0) 39 40 #define RK3328_INT_STATUS 0x0018 41 #define RK3328_DOUT 0x0020 42 #define RK3328_AUTO_CTRL 0x0024 43 #define RK3328_INT_FINISH BIT(0) 44 #define RK3328_AUTO_ENB BIT(0) 45 #define RK3328_AUTO_RD BIT(1) 46 47 typedef int (*EFUSE_READ)(struct udevice *dev, int offset, void *buf, int size); 48 49 struct rockchip_efuse_regs { 50 u32 ctrl; /* 0x00 efuse control register */ 51 u32 dout; /* 0x04 efuse data out register */ 52 u32 rf; /* 0x08 efuse redundancy bit used register */ 53 u32 _rsvd0; 54 u32 jtag_pass; /* 0x10 JTAG password */ 55 u32 strobe_finish_ctrl; 56 /* 0x14 efuse strobe finish control register */ 57 u32 int_status;/* 0x18 */ 58 u32 reserved; /* 0x1c */ 59 u32 dout2; /* 0x20 */ 60 u32 auto_ctrl; /* 0x24 */ 61 }; 62 63 struct rockchip_efuse_platdata { 64 void __iomem *base; 65 struct clk *clk; 66 }; 67 68 #if defined(DEBUG) 69 static int dump_efuses(cmd_tbl_t *cmdtp, int flag, 70 int argc, char * const argv[]) 71 { 72 /* 73 * N.B.: This function is tailored towards the RK3399 and assumes that 74 * there's always 32 fuses x 32 bits (i.e. 128 bytes of data) to 75 * be read. 76 */ 77 78 struct udevice *dev; 79 u8 fuses[128] = {0}; 80 int ret; 81 82 /* retrieve the device */ 83 ret = uclass_get_device_by_driver(UCLASS_MISC, 84 DM_GET_DRIVER(rockchip_efuse), &dev); 85 if (ret) { 86 printf("%s: no misc-device found\n", __func__); 87 return 0; 88 } 89 90 ret = misc_read(dev, 0, &fuses, sizeof(fuses)); 91 if (ret) { 92 printf("%s: misc_read failed\n", __func__); 93 return 0; 94 } 95 96 printf("efuse-contents:\n"); 97 print_buffer(0, fuses, 1, 128, 16); 98 99 return 0; 100 } 101 102 U_BOOT_CMD( 103 rockchip_dump_efuses, 1, 1, dump_efuses, 104 "Dump the content of the efuses", 105 "" 106 ); 107 #endif 108 109 static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset, 110 void *buf, int size) 111 { 112 struct rockchip_efuse_platdata *plat = dev_get_platdata(dev); 113 struct rockchip_efuse_regs *efuse = 114 (struct rockchip_efuse_regs *)plat->base; 115 116 unsigned int addr_start, addr_end, addr_offset; 117 u32 out_value; 118 u8 bytes[RK3399_NFUSES * RK3399_BYTES_PER_FUSE]; 119 int i = 0; 120 u32 addr; 121 122 addr_start = offset / RK3399_BYTES_PER_FUSE; 123 addr_offset = offset % RK3399_BYTES_PER_FUSE; 124 addr_end = DIV_ROUND_UP(offset + size, RK3399_BYTES_PER_FUSE); 125 126 /* cap to the size of the efuse block */ 127 if (addr_end > RK3399_NFUSES) 128 addr_end = RK3399_NFUSES; 129 130 writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB, 131 &efuse->ctrl); 132 udelay(1); 133 for (addr = addr_start; addr < addr_end; addr++) { 134 setbits_le32(&efuse->ctrl, 135 RK3399_STROBE | (addr << RK3399_A_SHIFT)); 136 udelay(1); 137 out_value = readl(&efuse->dout); 138 clrbits_le32(&efuse->ctrl, RK3399_STROBE); 139 udelay(1); 140 141 memcpy(&bytes[i], &out_value, RK3399_BYTES_PER_FUSE); 142 i += RK3399_BYTES_PER_FUSE; 143 } 144 145 /* Switch to standby mode */ 146 writel(RK3399_PD | RK3399_CSB, &efuse->ctrl); 147 148 memcpy(buf, bytes + addr_offset, size); 149 150 return 0; 151 } 152 153 static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset, 154 void *buf, int size) 155 { 156 struct rockchip_efuse_platdata *plat = dev_get_platdata(dev); 157 struct rockchip_efuse_regs *efuse = 158 (struct rockchip_efuse_regs *)plat->base; 159 u8 *buffer = buf; 160 int max_size = RK3288_NFUSES * RK3288_BYTES_PER_FUSE; 161 162 if (size > (max_size - offset)) 163 size = max_size - offset; 164 165 /* Switch to read mode */ 166 writel(RK3288_LOAD | RK3288_PGENB, &efuse->ctrl); 167 udelay(1); 168 169 while (size--) { 170 writel(readl(&efuse->ctrl) & 171 (~(RK3288_A_MASK << RK3288_A_SHIFT)), 172 &efuse->ctrl); 173 /* set addr */ 174 writel(readl(&efuse->ctrl) | 175 ((offset++ & RK3288_A_MASK) << RK3288_A_SHIFT), 176 &efuse->ctrl); 177 udelay(1); 178 /* strobe low to high */ 179 writel(readl(&efuse->ctrl) | 180 RK3288_STROBE, &efuse->ctrl); 181 ndelay(60); 182 /* read data */ 183 *buffer++ = readl(&efuse->dout); 184 /* reset strobe to low */ 185 writel(readl(&efuse->ctrl) & 186 (~RK3288_STROBE), &efuse->ctrl); 187 udelay(1); 188 } 189 190 /* Switch to standby mode */ 191 writel(RK3288_PGENB | RK3288_CSB, &efuse->ctrl); 192 193 return 0; 194 } 195 196 static int rockchip_rk3328_efuse_read(struct udevice *dev, int offset, 197 void *buf, int size) 198 { 199 struct rockchip_efuse_platdata *plat = dev_get_platdata(dev); 200 struct rockchip_efuse_regs *efuse = 201 (struct rockchip_efuse_regs *)plat->base; 202 unsigned int addr_start, addr_end, addr_offset, addr_len; 203 u32 out_value, status; 204 u8 *buffer; 205 int ret = 0, i = 0, j = 0; 206 207 /* Max non-secure Byte */ 208 if (size > 32) 209 size = 32; 210 211 /* 128 Byte efuse, 96 Byte for secure, 32 Byte for non-secure */ 212 offset += 96; 213 addr_start = rounddown(offset, RK3399_BYTES_PER_FUSE) / 214 RK3399_BYTES_PER_FUSE; 215 addr_end = roundup(offset + size, RK3399_BYTES_PER_FUSE) / 216 RK3399_BYTES_PER_FUSE; 217 addr_offset = offset % RK3399_BYTES_PER_FUSE; 218 addr_len = addr_end - addr_start; 219 220 buffer = calloc(1, sizeof(*buffer) * addr_len * RK3399_BYTES_PER_FUSE); 221 if (!buffer) 222 return -ENOMEM; 223 224 for (j = 0; j < addr_len; j++) { 225 writel(RK3328_AUTO_RD | RK3328_AUTO_ENB | 226 ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT), 227 &efuse->auto_ctrl); 228 udelay(5); 229 status = readl(&efuse->int_status); 230 if (!(status & RK3328_INT_FINISH)) { 231 ret = -EIO; 232 goto err; 233 } 234 out_value = readl(&efuse->dout2); 235 writel(RK3328_INT_FINISH, &efuse->int_status); 236 237 memcpy(&buffer[i], &out_value, RK3399_BYTES_PER_FUSE); 238 i += RK3399_BYTES_PER_FUSE; 239 } 240 memcpy(buf, buffer + addr_offset, size); 241 err: 242 free(buffer); 243 244 return ret; 245 } 246 247 static int rockchip_efuse_read(struct udevice *dev, int offset, 248 void *buf, int size) 249 { 250 EFUSE_READ efuse_read = NULL; 251 252 efuse_read = (EFUSE_READ)dev_get_driver_data(dev); 253 if (!efuse_read) 254 return -ENOSYS; 255 256 return (*efuse_read)(dev, offset, buf, size); 257 } 258 259 static const struct misc_ops rockchip_efuse_ops = { 260 .read = rockchip_efuse_read, 261 }; 262 263 static int rockchip_efuse_ofdata_to_platdata(struct udevice *dev) 264 { 265 struct rockchip_efuse_platdata *plat = dev_get_platdata(dev); 266 267 plat->base = dev_read_addr_ptr(dev); 268 return 0; 269 } 270 271 static const struct udevice_id rockchip_efuse_ids[] = { 272 { 273 .compatible = "rockchip,rockchip-efuse", 274 .data = (ulong)&rockchip_rk3288_efuse_read, 275 }, 276 { 277 .compatible = "rockchip,rk3066a-efuse", 278 .data = (ulong)&rockchip_rk3288_efuse_read, 279 }, 280 { 281 .compatible = "rockchip,rk3188-efuse", 282 .data = (ulong)&rockchip_rk3288_efuse_read, 283 }, 284 { 285 .compatible = "rockchip,rk322x-efuse", 286 .data = (ulong)&rockchip_rk3288_efuse_read, 287 }, 288 { 289 .compatible = "rockchip,rk3328-efuse", 290 .data = (ulong)&rockchip_rk3328_efuse_read, 291 }, 292 { 293 .compatible = "rockchip,rk3399-efuse", 294 .data = (ulong)&rockchip_rk3399_efuse_read, 295 }, 296 {} 297 }; 298 299 U_BOOT_DRIVER(rockchip_efuse) = { 300 .name = "rockchip_efuse", 301 .id = UCLASS_MISC, 302 .of_match = rockchip_efuse_ids, 303 .ofdata_to_platdata = rockchip_efuse_ofdata_to_platdata, 304 .platdata_auto_alloc_size = sizeof(struct rockchip_efuse_platdata), 305 .ops = &rockchip_efuse_ops, 306 }; 307