1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * JZ4780 EFUSE driver 4 * 5 * Copyright (c) 2014 Imagination Technologies 6 * Author: Alex Smith <alex.smith@imgtec.com> 7 */ 8 9 #include <common.h> 10 #include <asm/io.h> 11 #include <asm/unaligned.h> 12 #include <errno.h> 13 #include <mach/jz4780.h> 14 #include <wait_bit.h> 15 16 #define EFUSE_EFUCTRL 0xd0 17 #define EFUSE_EFUCFG 0xd4 18 #define EFUSE_EFUSTATE 0xd8 19 #define EFUSE_EFUDATA(n) (0xdc + ((n) * 4)) 20 21 #define EFUSE_EFUCTRL_RD_EN BIT(0) 22 #define EFUSE_EFUCTRL_LEN_BIT 16 23 #define EFUSE_EFUCTRL_LEN_MASK 0x1f 24 #define EFUSE_EFUCTRL_ADDR_BIT 21 25 #define EFUSE_EFUCTRL_ADDR_MASK 0x1ff 26 #define EFUSE_EFUCTRL_CS BIT(30) 27 28 #define EFUSE_EFUCFG_RD_STROBE_BIT 16 29 #define EFUSE_EFUCFG_RD_STROBE_MASK 0xf 30 #define EFUSE_EFUCFG_RD_ADJ_BIT 20 31 #define EFUSE_EFUCFG_RD_ADJ_MASK 0xf 32 33 #define EFUSE_EFUSTATE_RD_DONE BIT(0) 34 35 static void jz4780_efuse_read_chunk(size_t addr, size_t count, u8 *buf) 36 { 37 void __iomem *regs = (void __iomem *)NEMC_BASE; 38 size_t i; 39 u32 val; 40 int ret; 41 42 val = EFUSE_EFUCTRL_RD_EN | 43 ((count - 1) << EFUSE_EFUCTRL_LEN_BIT) | 44 (addr << EFUSE_EFUCTRL_ADDR_BIT) | 45 ((addr > 0x200) ? EFUSE_EFUCTRL_CS : 0); 46 writel(val, regs + EFUSE_EFUCTRL); 47 48 ret = wait_for_bit_le32(regs + EFUSE_EFUSTATE, 49 EFUSE_EFUSTATE_RD_DONE, true, 10000, false); 50 if (ret) 51 return; 52 53 if ((count % 4) == 0) { 54 for (i = 0; i < count / 4; i++) { 55 val = readl(regs + EFUSE_EFUDATA(i)); 56 put_unaligned(val, (u32 *)(buf + (i * 4))); 57 } 58 } else { 59 val = readl(regs + EFUSE_EFUDATA(0)); 60 if (count > 2) 61 buf[2] = (val >> 16) & 0xff; 62 if (count > 1) 63 buf[1] = (val >> 8) & 0xff; 64 buf[0] = val & 0xff; 65 } 66 } 67 68 static inline int jz4780_efuse_chunk_size(size_t count) 69 { 70 if (count >= 32) 71 return 32; 72 else if ((count / 4) > 0) 73 return (count / 4) * 4; 74 else 75 return count % 4; 76 } 77 78 void jz4780_efuse_read(size_t addr, size_t count, u8 *buf) 79 { 80 size_t chunk; 81 82 while (count > 0) { 83 chunk = jz4780_efuse_chunk_size(count); 84 jz4780_efuse_read_chunk(addr, chunk, buf); 85 addr += chunk; 86 buf += chunk; 87 count -= chunk; 88 } 89 } 90 91 void jz4780_efuse_init(u32 ahb2_rate) 92 { 93 void __iomem *regs = (void __iomem *)NEMC_BASE; 94 u32 rd_adj, rd_strobe, tmp; 95 96 rd_adj = (((6500 * (ahb2_rate / 1000000)) / 1000000) + 0xf) / 2; 97 tmp = (((35000 * (ahb2_rate / 1000000)) / 1000000) - 4) - rd_adj; 98 rd_strobe = ((tmp + 0xf) / 2 < 7) ? 7 : (tmp + 0xf) / 2; 99 100 tmp = (rd_adj << EFUSE_EFUCFG_RD_ADJ_BIT) | 101 (rd_strobe << EFUSE_EFUCFG_RD_STROBE_BIT); 102 writel(tmp, regs + EFUSE_EFUCFG); 103 } 104