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 31*b4fa32f0SFrancis Fan #define RK3288_A_SHIFT 6 32*b4fa32f0SFrancis Fan #define RK3288_A_MASK 0x3ff 33*b4fa32f0SFrancis Fan #define RK3288_NFUSES 32 34*b4fa32f0SFrancis Fan #define RK3288_BYTES_PER_FUSE 1 35*b4fa32f0SFrancis Fan #define RK3288_PGENB BIT(3) 36*b4fa32f0SFrancis Fan #define RK3288_LOAD BIT(2) 37*b4fa32f0SFrancis Fan #define RK3288_STROBE BIT(1) 38*b4fa32f0SFrancis Fan #define RK3288_CSB BIT(0) 39*b4fa32f0SFrancis Fan 40*b4fa32f0SFrancis Fan typedef int (*EFUSE_READ)(struct udevice *dev, int offset, void *buf, int size); 41*b4fa32f0SFrancis 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; 68*b4fa32f0SFrancis 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( 92*b4fa32f0SFrancis 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 142*b4fa32f0SFrancis Fan static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset, 143*b4fa32f0SFrancis Fan void *buf, int size) 144*b4fa32f0SFrancis Fan { 145*b4fa32f0SFrancis Fan struct rockchip_efuse_platdata *plat = dev_get_platdata(dev); 146*b4fa32f0SFrancis Fan struct rockchip_efuse_regs *efuse = 147*b4fa32f0SFrancis Fan (struct rockchip_efuse_regs *)plat->base; 148*b4fa32f0SFrancis Fan u8 *buffer = buf; 149*b4fa32f0SFrancis Fan int max_size = RK3288_NFUSES * RK3288_BYTES_PER_FUSE; 150*b4fa32f0SFrancis Fan 151*b4fa32f0SFrancis Fan if (size > (max_size - offset)) 152*b4fa32f0SFrancis Fan size = max_size - offset; 153*b4fa32f0SFrancis Fan 154*b4fa32f0SFrancis Fan /* Switch to read mode */ 155*b4fa32f0SFrancis Fan writel(RK3288_LOAD | RK3288_PGENB, &efuse->ctrl); 156*b4fa32f0SFrancis Fan udelay(1); 157*b4fa32f0SFrancis Fan 158*b4fa32f0SFrancis Fan while (size--) { 159*b4fa32f0SFrancis Fan writel(readl(&efuse->ctrl) & 160*b4fa32f0SFrancis Fan (~(RK3288_A_MASK << RK3288_A_SHIFT)), 161*b4fa32f0SFrancis Fan &efuse->ctrl); 162*b4fa32f0SFrancis Fan /* set addr */ 163*b4fa32f0SFrancis Fan writel(readl(&efuse->ctrl) | 164*b4fa32f0SFrancis Fan ((offset++ & RK3288_A_MASK) << RK3288_A_SHIFT), 165*b4fa32f0SFrancis Fan &efuse->ctrl); 166*b4fa32f0SFrancis Fan udelay(1); 167*b4fa32f0SFrancis Fan /* strobe low to high */ 168*b4fa32f0SFrancis Fan writel(readl(&efuse->ctrl) | 169*b4fa32f0SFrancis Fan RK3288_STROBE, &efuse->ctrl); 170*b4fa32f0SFrancis Fan ndelay(60); 171*b4fa32f0SFrancis Fan /* read data */ 172*b4fa32f0SFrancis Fan *buffer++ = readl(&efuse->dout); 173*b4fa32f0SFrancis Fan /* reset strobe to low */ 174*b4fa32f0SFrancis Fan writel(readl(&efuse->ctrl) & 175*b4fa32f0SFrancis Fan (~RK3288_STROBE), &efuse->ctrl); 176*b4fa32f0SFrancis Fan udelay(1); 177*b4fa32f0SFrancis Fan } 178*b4fa32f0SFrancis Fan 179*b4fa32f0SFrancis Fan /* Switch to standby mode */ 180*b4fa32f0SFrancis Fan writel(RK3288_PGENB | RK3288_CSB, &efuse->ctrl); 181*b4fa32f0SFrancis Fan 182*b4fa32f0SFrancis Fan return 0; 183*b4fa32f0SFrancis Fan } 184*b4fa32f0SFrancis Fan 18549cd8e85SPhilipp Tomsich static int rockchip_efuse_read(struct udevice *dev, int offset, 18649cd8e85SPhilipp Tomsich void *buf, int size) 18749cd8e85SPhilipp Tomsich { 188*b4fa32f0SFrancis Fan EFUSE_READ efuse_read = NULL; 189*b4fa32f0SFrancis Fan 190*b4fa32f0SFrancis Fan efuse_read = (EFUSE_READ)dev_get_driver_data(dev); 191*b4fa32f0SFrancis Fan if (!efuse_read) 192*b4fa32f0SFrancis Fan return -ENOSYS; 193*b4fa32f0SFrancis Fan 194*b4fa32f0SFrancis 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[] = { 210*b4fa32f0SFrancis Fan { 211*b4fa32f0SFrancis Fan .compatible = "rockchip,rockchip-efuse", 212*b4fa32f0SFrancis Fan .data = (void *)&rockchip_rk3288_efuse_read, 213*b4fa32f0SFrancis Fan }, 214*b4fa32f0SFrancis Fan { 215*b4fa32f0SFrancis Fan .compatible = "rockchip,rk3066a-efuse", 216*b4fa32f0SFrancis Fan .data = (void *)&rockchip_rk3288_efuse_read, 217*b4fa32f0SFrancis Fan }, 218*b4fa32f0SFrancis Fan { 219*b4fa32f0SFrancis Fan .compatible = "rockchip,rk3188-efuse", 220*b4fa32f0SFrancis Fan .data = (void *)&rockchip_rk3288_efuse_read, 221*b4fa32f0SFrancis Fan }, 222*b4fa32f0SFrancis Fan { 223*b4fa32f0SFrancis Fan .compatible = "rockchip,rk322x-efuse", 224*b4fa32f0SFrancis Fan .data = (void *)&rockchip_rk3288_efuse_read, 225*b4fa32f0SFrancis Fan }, 226*b4fa32f0SFrancis Fan { 227*b4fa32f0SFrancis Fan .compatible = "rockchip,rk3399-efuse", 228*b4fa32f0SFrancis Fan .data = (ulong)&rockchip_rk3399_efuse_read, 229*b4fa32f0SFrancis 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