Merge tag 'efi-2020-07-rc6' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi
[oweals/u-boot.git] / drivers / misc / jz4780_efuse.c
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 <linux/bitops.h>
14 #include <mach/jz4780.h>
15 #include <wait_bit.h>
16
17 #define EFUSE_EFUCTRL                   0xd0
18 #define EFUSE_EFUCFG                    0xd4
19 #define EFUSE_EFUSTATE                  0xd8
20 #define EFUSE_EFUDATA(n)                (0xdc + ((n) * 4))
21
22 #define EFUSE_EFUCTRL_RD_EN             BIT(0)
23 #define EFUSE_EFUCTRL_LEN_BIT           16
24 #define EFUSE_EFUCTRL_LEN_MASK          0x1f
25 #define EFUSE_EFUCTRL_ADDR_BIT          21
26 #define EFUSE_EFUCTRL_ADDR_MASK         0x1ff
27 #define EFUSE_EFUCTRL_CS                BIT(30)
28
29 #define EFUSE_EFUCFG_RD_STROBE_BIT      16
30 #define EFUSE_EFUCFG_RD_STROBE_MASK     0xf
31 #define EFUSE_EFUCFG_RD_ADJ_BIT         20
32 #define EFUSE_EFUCFG_RD_ADJ_MASK        0xf
33
34 #define EFUSE_EFUSTATE_RD_DONE          BIT(0)
35
36 static void jz4780_efuse_read_chunk(size_t addr, size_t count, u8 *buf)
37 {
38         void __iomem *regs = (void __iomem *)NEMC_BASE;
39         size_t i;
40         u32 val;
41         int ret;
42
43         val = EFUSE_EFUCTRL_RD_EN |
44                 ((count - 1) << EFUSE_EFUCTRL_LEN_BIT) |
45                 (addr << EFUSE_EFUCTRL_ADDR_BIT) |
46                 ((addr > 0x200) ? EFUSE_EFUCTRL_CS : 0);
47         writel(val, regs + EFUSE_EFUCTRL);
48
49         ret = wait_for_bit_le32(regs + EFUSE_EFUSTATE,
50                                 EFUSE_EFUSTATE_RD_DONE, true, 10000, false);
51         if (ret)
52                 return;
53
54         if ((count % 4) == 0) {
55                 for (i = 0; i < count / 4; i++) {
56                         val = readl(regs + EFUSE_EFUDATA(i));
57                         put_unaligned(val, (u32 *)(buf + (i * 4)));
58                 }
59         } else {
60                 val = readl(regs + EFUSE_EFUDATA(0));
61                 if (count > 2)
62                         buf[2] = (val >> 16) & 0xff;
63                 if (count > 1)
64                         buf[1] = (val >> 8) & 0xff;
65                 buf[0] = val & 0xff;
66         }
67 }
68
69 static inline int jz4780_efuse_chunk_size(size_t count)
70 {
71         if (count >= 32)
72                 return 32;
73         else if ((count / 4) > 0)
74                 return (count / 4) * 4;
75         else
76                 return count % 4;
77 }
78
79 void jz4780_efuse_read(size_t addr, size_t count, u8 *buf)
80 {
81         size_t chunk;
82
83         while (count > 0) {
84                 chunk = jz4780_efuse_chunk_size(count);
85                 jz4780_efuse_read_chunk(addr, chunk, buf);
86                 addr += chunk;
87                 buf += chunk;
88                 count -= chunk;
89         }
90 }
91
92 void jz4780_efuse_init(u32 ahb2_rate)
93 {
94         void __iomem *regs = (void __iomem *)NEMC_BASE;
95         u32 rd_adj, rd_strobe, tmp;
96
97         rd_adj = (((6500 * (ahb2_rate / 1000000)) / 1000000) + 0xf) / 2;
98         tmp = (((35000 * (ahb2_rate / 1000000)) / 1000000) - 4) - rd_adj;
99         rd_strobe = ((tmp + 0xf) / 2 < 7) ? 7 : (tmp + 0xf) / 2;
100
101         tmp = (rd_adj << EFUSE_EFUCFG_RD_ADJ_BIT) |
102               (rd_strobe << EFUSE_EFUCFG_RD_STROBE_BIT);
103         writel(tmp, regs + EFUSE_EFUCFG);
104 }