blob: 03778f17ea499de9ed8025d3be229ccf2e9b42d2 [file] [log] [blame]
Pali Rohár10154b82022-02-23 14:15:45 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) 2017 Marvell International Ltd.
4 * (C) 2021 Pali Rohár <pali@kernel.org>
5 */
6
7#include <config.h>
8#include <common.h>
9#include <asm/io.h>
10#include <linux/delay.h>
11#include <mach/soc.h>
12
13#define OTP_NB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x12600))
14#define OTP_SB_REG_BASE ((void __iomem *)MVEBU_REGISTER(0x1A200))
15
16#define OTP_CONTROL_OFF 0x00
17#define OTP_MODE_BIT BIT(15)
18#define OTP_RPTR_RST_BIT BIT(14)
19#define OTP_POR_B_BIT BIT(13)
20#define OTP_PRDT_BIT BIT(3)
21#define OTP_READ_PORT_OFF 0x04
22#define OTP_READ_POINTER_OFF 0x08
23#define OTP_PTR_INC_BIT BIT(8)
24
25static void otp_read_parallel(void __iomem *base, u32 *data, u32 count)
26{
27 u32 regval;
28
29 /* 1. Clear OTP_MODE_NB to parallel mode */
30 regval = readl(base + OTP_CONTROL_OFF);
31 regval &= ~OTP_MODE_BIT;
32 writel(regval, base + OTP_CONTROL_OFF);
33
34 /* 2. Set OTP_POR_B_NB enter normal operation */
35 regval = readl(base + OTP_CONTROL_OFF);
36 regval |= OTP_POR_B_BIT;
37 writel(regval, base + OTP_CONTROL_OFF);
38
39 /* 3. Set OTP_PTR_INC_NB to auto-increment pointer after each read */
40 regval = readl(base + OTP_READ_POINTER_OFF);
41 regval |= OTP_PTR_INC_BIT;
42 writel(regval, base + OTP_READ_POINTER_OFF);
43
44 /* 4. Set OTP_RPTR_RST_NB, then clear the same field */
45 regval = readl(base + OTP_CONTROL_OFF);
46 regval |= OTP_RPTR_RST_BIT;
47 writel(regval, base + OTP_CONTROL_OFF);
48
49 regval = readl(base + OTP_CONTROL_OFF);
50 regval &= ~OTP_RPTR_RST_BIT;
51 writel(regval, base + OTP_CONTROL_OFF);
52
53 /* 5. Toggle OTP_PRDT_NB
54 * a. Set OTP_PRDT_NB to 1.
55 * b. Clear OTP_PRDT_NB to 0.
56 * c. Wait for a minimum of 100 ns.
57 * d. Set OTP_PRDT_NB to 1
58 */
59 regval = readl(base + OTP_CONTROL_OFF);
60 regval |= OTP_PRDT_BIT;
61 writel(regval, base + OTP_CONTROL_OFF);
62
63 regval = readl(base + OTP_CONTROL_OFF);
64 regval &= ~OTP_PRDT_BIT;
65 writel(regval, base + OTP_CONTROL_OFF);
66
67 ndelay(100);
68
69 regval = readl(base + OTP_CONTROL_OFF);
70 regval |= OTP_PRDT_BIT;
71 writel(regval, base + OTP_CONTROL_OFF);
72
73 while (count-- > 0) {
74 /* 6. Read the content of OTP 32-bits at a time */
75 ndelay(100000);
76 *(data++) = readl(base + OTP_READ_PORT_OFF);
77 }
78}
79
80/*
81 * Banks 0-43 are used for accessing Security OTP (44 rows with 67 bits via 44 banks and words 0-2)
82 * Bank 44 is used for accessing North Bridge OTP (69 bits via words 0-2)
83 * Bank 45 is used for accessing South Bridge OTP (97 bits via words 0-3)
84 */
85
86#define RWTM_ROWS 44
87#define RWTM_MAX_BANK (RWTM_ROWS - 1)
88#define RWTM_ROW_WORDS 3
89#define OTP_NB_BANK RWTM_ROWS
90#define OTP_NB_WORDS 3
91#define OTP_SB_BANK (RWTM_ROWS + 1)
92#define OTP_SB_WORDS 4
93
94int fuse_read(u32 bank, u32 word, u32 *val)
95{
96 if (bank <= RWTM_MAX_BANK) {
97 if (word >= RWTM_ROW_WORDS)
98 return -EINVAL;
99 /* TODO: not implemented yet */
100 return -ENOSYS;
101 } else if (bank == OTP_NB_BANK) {
102 u32 data[OTP_NB_WORDS];
103 if (word >= OTP_NB_WORDS)
104 return -EINVAL;
105 otp_read_parallel(OTP_NB_REG_BASE, data, OTP_NB_WORDS);
106 *val = data[word];
107 return 0;
108 } else if (bank == OTP_SB_BANK) {
109 u32 data[OTP_SB_WORDS];
110 if (word >= OTP_SB_WORDS)
111 return -EINVAL;
112 otp_read_parallel(OTP_SB_REG_BASE, data, OTP_SB_WORDS);
113 *val = data[word];
114 return 0;
115 } else {
116 return -EINVAL;
117 }
118}
119
120int fuse_prog(u32 bank, u32 word, u32 val)
121{
122 /* TODO: not implemented yet */
123 return -ENOSYS;
124}
125
126int fuse_sense(u32 bank, u32 word, u32 *val)
127{
128 /* not supported */
129 return -ENOSYS;
130}
131
132int fuse_override(u32 bank, u32 word, u32 val)
133{
134 /* not supported */
135 return -ENOSYS;
136}