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 1949cd8e85SPhilipp Tomsich #define RK3399_A_SHIFT 16 2049cd8e85SPhilipp Tomsich #define RK3399_A_MASK 0x3ff 2149cd8e85SPhilipp Tomsich #define RK3399_NFUSES 32 2249cd8e85SPhilipp Tomsich #define RK3399_BYTES_PER_FUSE 4 2349cd8e85SPhilipp Tomsich #define RK3399_STROBSFTSEL BIT(9) 2449cd8e85SPhilipp Tomsich #define RK3399_RSB BIT(7) 2549cd8e85SPhilipp Tomsich #define RK3399_PD BIT(5) 2649cd8e85SPhilipp Tomsich #define RK3399_PGENB BIT(3) 2749cd8e85SPhilipp Tomsich #define RK3399_LOAD BIT(2) 2849cd8e85SPhilipp Tomsich #define RK3399_STROBE BIT(1) 2949cd8e85SPhilipp Tomsich #define RK3399_CSB BIT(0) 3049cd8e85SPhilipp Tomsich 31b4fa32f0SFrancis Fan #define RK3288_A_SHIFT 6 32b4fa32f0SFrancis Fan #define RK3288_A_MASK 0x3ff 33b4fa32f0SFrancis Fan #define RK3288_NFUSES 32 34b4fa32f0SFrancis Fan #define RK3288_BYTES_PER_FUSE 1 35b4fa32f0SFrancis Fan #define RK3288_PGENB BIT(3) 36b4fa32f0SFrancis Fan #define RK3288_LOAD BIT(2) 37b4fa32f0SFrancis Fan #define RK3288_STROBE BIT(1) 38b4fa32f0SFrancis Fan #define RK3288_CSB BIT(0) 39b4fa32f0SFrancis Fan 40b4fa32f0SFrancis Fan typedef int (*EFUSE_READ)(struct udevice *dev, int offset, void *buf, int size); 41b4fa32f0SFrancis Fan 4249cd8e85SPhilipp Tomsich struct rockchip_efuse_regs { 4349cd8e85SPhilipp Tomsich u32 ctrl; /* 0x00 efuse control register */ 4449cd8e85SPhilipp Tomsich u32 dout; /* 0x04 efuse data out register */ 4549cd8e85SPhilipp Tomsich u32 rf; /* 0x08 efuse redundancy bit used register */ 4649cd8e85SPhilipp Tomsich u32 _rsvd0; 4749cd8e85SPhilipp Tomsich u32 jtag_pass; /* 0x10 JTAG password */ 4849cd8e85SPhilipp Tomsich u32 strobe_finish_ctrl; 4949cd8e85SPhilipp Tomsich /* 0x14 efuse strobe finish control register */ 5049cd8e85SPhilipp Tomsich }; 5149cd8e85SPhilipp Tomsich 5249cd8e85SPhilipp Tomsich struct rockchip_efuse_platdata { 5349cd8e85SPhilipp Tomsich void __iomem *base; 5449cd8e85SPhilipp Tomsich struct clk *clk; 5549cd8e85SPhilipp Tomsich }; 5649cd8e85SPhilipp Tomsich 5749cd8e85SPhilipp Tomsich #if defined(DEBUG) 5849cd8e85SPhilipp Tomsich static int dump_efuses(cmd_tbl_t *cmdtp, int flag, 5949cd8e85SPhilipp Tomsich int argc, char * const argv[]) 6049cd8e85SPhilipp Tomsich { 6149cd8e85SPhilipp Tomsich /* 6249cd8e85SPhilipp Tomsich * N.B.: This function is tailored towards the RK3399 and assumes that 6349cd8e85SPhilipp Tomsich * there's always 32 fuses x 32 bits (i.e. 128 bytes of data) to 6449cd8e85SPhilipp Tomsich * be read. 6549cd8e85SPhilipp Tomsich */ 6649cd8e85SPhilipp Tomsich 6749cd8e85SPhilipp Tomsich struct udevice *dev; 68b4fa32f0SFrancis Fan u8 fuses[128] = {0}; 6949cd8e85SPhilipp Tomsich int ret; 7049cd8e85SPhilipp Tomsich 7149cd8e85SPhilipp Tomsich /* retrieve the device */ 7249cd8e85SPhilipp Tomsich ret = uclass_get_device_by_driver(UCLASS_MISC, 7349cd8e85SPhilipp Tomsich DM_GET_DRIVER(rockchip_efuse), &dev); 7449cd8e85SPhilipp Tomsich if (ret) { 7549cd8e85SPhilipp Tomsich printf("%s: no misc-device found\n", __func__); 7649cd8e85SPhilipp Tomsich return 0; 7749cd8e85SPhilipp Tomsich } 7849cd8e85SPhilipp Tomsich 7949cd8e85SPhilipp Tomsich ret = misc_read(dev, 0, &fuses, sizeof(fuses)); 8049cd8e85SPhilipp Tomsich if (ret) { 8149cd8e85SPhilipp Tomsich printf("%s: misc_read failed\n", __func__); 8249cd8e85SPhilipp Tomsich return 0; 8349cd8e85SPhilipp Tomsich } 8449cd8e85SPhilipp Tomsich 8549cd8e85SPhilipp Tomsich printf("efuse-contents:\n"); 8649cd8e85SPhilipp Tomsich print_buffer(0, fuses, 1, 128, 16); 8749cd8e85SPhilipp Tomsich 8849cd8e85SPhilipp Tomsich return 0; 8949cd8e85SPhilipp Tomsich } 9049cd8e85SPhilipp Tomsich 9149cd8e85SPhilipp Tomsich U_BOOT_CMD( 92b4fa32f0SFrancis Fan rockchip_dump_efuses, 1, 1, dump_efuses, 9349cd8e85SPhilipp Tomsich "Dump the content of the efuses", 9449cd8e85SPhilipp Tomsich "" 9549cd8e85SPhilipp Tomsich ); 9649cd8e85SPhilipp Tomsich #endif 9749cd8e85SPhilipp Tomsich 9849cd8e85SPhilipp Tomsich static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset, 9949cd8e85SPhilipp Tomsich void *buf, int size) 10049cd8e85SPhilipp Tomsich { 10149cd8e85SPhilipp Tomsich struct rockchip_efuse_platdata *plat = dev_get_platdata(dev); 10249cd8e85SPhilipp Tomsich struct rockchip_efuse_regs *efuse = 10349cd8e85SPhilipp Tomsich (struct rockchip_efuse_regs *)plat->base; 10449cd8e85SPhilipp Tomsich 10549cd8e85SPhilipp Tomsich unsigned int addr_start, addr_end, addr_offset; 10649cd8e85SPhilipp Tomsich u32 out_value; 10749cd8e85SPhilipp Tomsich u8 bytes[RK3399_NFUSES * RK3399_BYTES_PER_FUSE]; 10849cd8e85SPhilipp Tomsich int i = 0; 10949cd8e85SPhilipp Tomsich u32 addr; 11049cd8e85SPhilipp Tomsich 11149cd8e85SPhilipp Tomsich addr_start = offset / RK3399_BYTES_PER_FUSE; 11249cd8e85SPhilipp Tomsich addr_offset = offset % RK3399_BYTES_PER_FUSE; 11349cd8e85SPhilipp Tomsich addr_end = DIV_ROUND_UP(offset + size, RK3399_BYTES_PER_FUSE); 11449cd8e85SPhilipp Tomsich 11549cd8e85SPhilipp Tomsich /* cap to the size of the efuse block */ 11649cd8e85SPhilipp Tomsich if (addr_end > RK3399_NFUSES) 11749cd8e85SPhilipp Tomsich addr_end = RK3399_NFUSES; 11849cd8e85SPhilipp Tomsich 11949cd8e85SPhilipp Tomsich writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB, 12049cd8e85SPhilipp Tomsich &efuse->ctrl); 12149cd8e85SPhilipp Tomsich udelay(1); 12249cd8e85SPhilipp Tomsich for (addr = addr_start; addr < addr_end; addr++) { 12349cd8e85SPhilipp Tomsich setbits_le32(&efuse->ctrl, 12449cd8e85SPhilipp Tomsich RK3399_STROBE | (addr << RK3399_A_SHIFT)); 12549cd8e85SPhilipp Tomsich udelay(1); 12649cd8e85SPhilipp Tomsich out_value = readl(&efuse->dout); 12749cd8e85SPhilipp Tomsich clrbits_le32(&efuse->ctrl, RK3399_STROBE); 12849cd8e85SPhilipp Tomsich udelay(1); 12949cd8e85SPhilipp Tomsich 13049cd8e85SPhilipp Tomsich memcpy(&bytes[i], &out_value, RK3399_BYTES_PER_FUSE); 13149cd8e85SPhilipp Tomsich i += RK3399_BYTES_PER_FUSE; 13249cd8e85SPhilipp Tomsich } 13349cd8e85SPhilipp Tomsich 13449cd8e85SPhilipp Tomsich /* Switch to standby mode */ 13549cd8e85SPhilipp Tomsich writel(RK3399_PD | RK3399_CSB, &efuse->ctrl); 13649cd8e85SPhilipp Tomsich 13749cd8e85SPhilipp Tomsich memcpy(buf, bytes + addr_offset, size); 13849cd8e85SPhilipp Tomsich 13949cd8e85SPhilipp Tomsich return 0; 14049cd8e85SPhilipp Tomsich } 14149cd8e85SPhilipp Tomsich 142b4fa32f0SFrancis Fan static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset, 143b4fa32f0SFrancis Fan void *buf, int size) 144b4fa32f0SFrancis Fan { 145b4fa32f0SFrancis Fan struct rockchip_efuse_platdata *plat = dev_get_platdata(dev); 146b4fa32f0SFrancis Fan struct rockchip_efuse_regs *efuse = 147b4fa32f0SFrancis Fan (struct rockchip_efuse_regs *)plat->base; 148b4fa32f0SFrancis Fan u8 *buffer = buf; 149b4fa32f0SFrancis Fan int max_size = RK3288_NFUSES * RK3288_BYTES_PER_FUSE; 150b4fa32f0SFrancis Fan 151b4fa32f0SFrancis Fan if (size > (max_size - offset)) 152b4fa32f0SFrancis Fan size = max_size - offset; 153b4fa32f0SFrancis Fan 154b4fa32f0SFrancis Fan /* Switch to read mode */ 155b4fa32f0SFrancis Fan writel(RK3288_LOAD | RK3288_PGENB, &efuse->ctrl); 156b4fa32f0SFrancis Fan udelay(1); 157b4fa32f0SFrancis Fan 158b4fa32f0SFrancis Fan while (size--) { 159b4fa32f0SFrancis Fan writel(readl(&efuse->ctrl) & 160b4fa32f0SFrancis Fan (~(RK3288_A_MASK << RK3288_A_SHIFT)), 161b4fa32f0SFrancis Fan &efuse->ctrl); 162b4fa32f0SFrancis Fan /* set addr */ 163b4fa32f0SFrancis Fan writel(readl(&efuse->ctrl) | 164b4fa32f0SFrancis Fan ((offset++ & RK3288_A_MASK) << RK3288_A_SHIFT), 165b4fa32f0SFrancis Fan &efuse->ctrl); 166b4fa32f0SFrancis Fan udelay(1); 167b4fa32f0SFrancis Fan /* strobe low to high */ 168b4fa32f0SFrancis Fan writel(readl(&efuse->ctrl) | 169b4fa32f0SFrancis Fan RK3288_STROBE, &efuse->ctrl); 170b4fa32f0SFrancis Fan ndelay(60); 171b4fa32f0SFrancis Fan /* read data */ 172b4fa32f0SFrancis Fan *buffer++ = readl(&efuse->dout); 173b4fa32f0SFrancis Fan /* reset strobe to low */ 174b4fa32f0SFrancis Fan writel(readl(&efuse->ctrl) & 175b4fa32f0SFrancis Fan (~RK3288_STROBE), &efuse->ctrl); 176b4fa32f0SFrancis Fan udelay(1); 177b4fa32f0SFrancis Fan } 178b4fa32f0SFrancis Fan 179b4fa32f0SFrancis Fan /* Switch to standby mode */ 180b4fa32f0SFrancis Fan writel(RK3288_PGENB | RK3288_CSB, &efuse->ctrl); 181b4fa32f0SFrancis Fan 182b4fa32f0SFrancis Fan return 0; 183b4fa32f0SFrancis Fan } 184b4fa32f0SFrancis Fan 18549cd8e85SPhilipp Tomsich static int rockchip_efuse_read(struct udevice *dev, int offset, 18649cd8e85SPhilipp Tomsich void *buf, int size) 18749cd8e85SPhilipp Tomsich { 188b4fa32f0SFrancis Fan EFUSE_READ efuse_read = NULL; 189b4fa32f0SFrancis Fan 190b4fa32f0SFrancis Fan efuse_read = (EFUSE_READ)dev_get_driver_data(dev); 191b4fa32f0SFrancis Fan if (!efuse_read) 192b4fa32f0SFrancis Fan return -ENOSYS; 193b4fa32f0SFrancis Fan 194b4fa32f0SFrancis Fan return (*efuse_read)(dev, offset, buf, size); 19549cd8e85SPhilipp Tomsich } 19649cd8e85SPhilipp Tomsich 19749cd8e85SPhilipp Tomsich static const struct misc_ops rockchip_efuse_ops = { 19849cd8e85SPhilipp Tomsich .read = rockchip_efuse_read, 19949cd8e85SPhilipp Tomsich }; 20049cd8e85SPhilipp Tomsich 20149cd8e85SPhilipp Tomsich static int rockchip_efuse_ofdata_to_platdata(struct udevice *dev) 20249cd8e85SPhilipp Tomsich { 20349cd8e85SPhilipp Tomsich struct rockchip_efuse_platdata *plat = dev_get_platdata(dev); 20449cd8e85SPhilipp Tomsich 205928979cbSPhilipp Tomsich plat->base = (void *)dev_read_addr(dev); 20649cd8e85SPhilipp Tomsich return 0; 20749cd8e85SPhilipp Tomsich } 20849cd8e85SPhilipp Tomsich 20949cd8e85SPhilipp Tomsich static const struct udevice_id rockchip_efuse_ids[] = { 210b4fa32f0SFrancis Fan { 211b4fa32f0SFrancis Fan .compatible = "rockchip,rockchip-efuse", 212*e9cfb932SCody Xie .data = (ulong)&rockchip_rk3288_efuse_read, 213b4fa32f0SFrancis Fan }, 214b4fa32f0SFrancis Fan { 215b4fa32f0SFrancis Fan .compatible = "rockchip,rk3066a-efuse", 216*e9cfb932SCody Xie .data = (ulong)&rockchip_rk3288_efuse_read, 217b4fa32f0SFrancis Fan }, 218b4fa32f0SFrancis Fan { 219b4fa32f0SFrancis Fan .compatible = "rockchip,rk3188-efuse", 220*e9cfb932SCody Xie .data = (ulong)&rockchip_rk3288_efuse_read, 221b4fa32f0SFrancis Fan }, 222b4fa32f0SFrancis Fan { 223b4fa32f0SFrancis Fan .compatible = "rockchip,rk322x-efuse", 224*e9cfb932SCody Xie .data = (ulong)&rockchip_rk3288_efuse_read, 225b4fa32f0SFrancis Fan }, 226b4fa32f0SFrancis Fan { 227b4fa32f0SFrancis Fan .compatible = "rockchip,rk3399-efuse", 228b4fa32f0SFrancis Fan .data = (ulong)&rockchip_rk3399_efuse_read, 229b4fa32f0SFrancis Fan }, 23049cd8e85SPhilipp Tomsich {} 23149cd8e85SPhilipp Tomsich }; 23249cd8e85SPhilipp Tomsich 23349cd8e85SPhilipp Tomsich U_BOOT_DRIVER(rockchip_efuse) = { 23449cd8e85SPhilipp Tomsich .name = "rockchip_efuse", 23549cd8e85SPhilipp Tomsich .id = UCLASS_MISC, 23649cd8e85SPhilipp Tomsich .of_match = rockchip_efuse_ids, 23749cd8e85SPhilipp Tomsich .ofdata_to_platdata = rockchip_efuse_ofdata_to_platdata, 23849cd8e85SPhilipp Tomsich .platdata_auto_alloc_size = sizeof(struct rockchip_efuse_platdata), 23949cd8e85SPhilipp Tomsich .ops = &rockchip_efuse_ops, 24049cd8e85SPhilipp Tomsich }; 241