]>
Commit | Line | Data |
---|---|---|
8747ec2e VS |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | ||
3 | /* | |
4 | * The OCOTP driver for Sunplus SP7021 | |
5 | * | |
6 | * Copyright (C) 2019 Sunplus Technology Inc., All rights reserved. | |
7 | */ | |
8 | ||
9 | #include <linux/bitfield.h> | |
10 | #include <linux/clk.h> | |
11 | #include <linux/delay.h> | |
12 | #include <linux/device.h> | |
13 | #include <linux/io.h> | |
14 | #include <linux/iopoll.h> | |
15 | #include <linux/module.h> | |
9bf75da0 | 16 | #include <linux/mod_devicetable.h> |
8747ec2e | 17 | #include <linux/nvmem-provider.h> |
8747ec2e VS |
18 | #include <linux/platform_device.h> |
19 | ||
20 | /* | |
21 | * OTP memory | |
22 | * Each bank contains 4 words (32 bits). | |
23 | * Bank 0 starts at offset 0 from the base. | |
24 | */ | |
25 | ||
26 | #define OTP_WORDS_PER_BANK 4 | |
27 | #define OTP_WORD_SIZE sizeof(u32) | |
28 | #define OTP_BIT_ADDR_OF_BANK (8 * OTP_WORD_SIZE * OTP_WORDS_PER_BANK) | |
29 | #define QAC628_OTP_NUM_BANKS 8 | |
30 | #define QAC628_OTP_SIZE (QAC628_OTP_NUM_BANKS * OTP_WORDS_PER_BANK * OTP_WORD_SIZE) | |
31 | #define OTP_READ_TIMEOUT_US 200000 | |
32 | ||
33 | /* HB_GPIO */ | |
34 | #define ADDRESS_8_DATA 0x20 | |
35 | ||
36 | /* OTP_RX */ | |
37 | #define OTP_CONTROL_2 0x48 | |
38 | #define OTP_RD_PERIOD GENMASK(15, 8) | |
39 | #define OTP_RD_PERIOD_MASK ~GENMASK(15, 8) | |
40 | #define CPU_CLOCK FIELD_PREP(OTP_RD_PERIOD, 30) | |
41 | #define SEL_BAK_KEY2 BIT(5) | |
42 | #define SEL_BAK_KEY2_MASK ~BIT(5) | |
43 | #define SW_TRIM_EN BIT(4) | |
44 | #define SW_TRIM_EN_MASK ~BIT(4) | |
45 | #define SEL_BAK_KEY BIT(3) | |
46 | #define SEL_BAK_KEY_MASK ~BIT(3) | |
47 | #define OTP_READ BIT(2) | |
48 | #define OTP_LOAD_SECURE_DATA BIT(1) | |
49 | #define OTP_LOAD_SECURE_DATA_MASK ~BIT(1) | |
50 | #define OTP_DO_CRC BIT(0) | |
51 | #define OTP_DO_CRC_MASK ~BIT(0) | |
52 | #define OTP_STATUS 0x4c | |
53 | #define OTP_READ_DONE BIT(4) | |
54 | #define OTP_READ_DONE_MASK ~BIT(4) | |
55 | #define OTP_LOAD_SECURE_DONE_MASK ~BIT(2) | |
56 | #define OTP_READ_ADDRESS 0x50 | |
57 | ||
58 | enum base_type { | |
59 | HB_GPIO, | |
60 | OTPRX, | |
61 | BASEMAX, | |
62 | }; | |
63 | ||
64 | struct sp_ocotp_priv { | |
65 | struct device *dev; | |
66 | void __iomem *base[BASEMAX]; | |
67 | struct clk *clk; | |
68 | }; | |
69 | ||
70 | struct sp_ocotp_data { | |
71 | int size; | |
72 | }; | |
73 | ||
1066f815 | 74 | static const struct sp_ocotp_data sp_otp_v0 = { |
8747ec2e VS |
75 | .size = QAC628_OTP_SIZE, |
76 | }; | |
77 | ||
78 | static int sp_otp_read_real(struct sp_ocotp_priv *otp, int addr, char *value) | |
79 | { | |
80 | unsigned int addr_data; | |
81 | unsigned int byte_shift; | |
82 | unsigned int status; | |
83 | int ret; | |
84 | ||
85 | addr_data = addr % (OTP_WORD_SIZE * OTP_WORDS_PER_BANK); | |
86 | addr_data = addr_data / OTP_WORD_SIZE; | |
87 | ||
88 | byte_shift = addr % (OTP_WORD_SIZE * OTP_WORDS_PER_BANK); | |
89 | byte_shift = byte_shift % OTP_WORD_SIZE; | |
90 | ||
91 | addr = addr / (OTP_WORD_SIZE * OTP_WORDS_PER_BANK); | |
92 | addr = addr * OTP_BIT_ADDR_OF_BANK; | |
93 | ||
94 | writel(readl(otp->base[OTPRX] + OTP_STATUS) & OTP_READ_DONE_MASK & | |
95 | OTP_LOAD_SECURE_DONE_MASK, otp->base[OTPRX] + OTP_STATUS); | |
96 | writel(addr, otp->base[OTPRX] + OTP_READ_ADDRESS); | |
97 | writel(readl(otp->base[OTPRX] + OTP_CONTROL_2) | OTP_READ, | |
98 | otp->base[OTPRX] + OTP_CONTROL_2); | |
99 | writel(readl(otp->base[OTPRX] + OTP_CONTROL_2) & SEL_BAK_KEY2_MASK & SW_TRIM_EN_MASK | |
100 | & SEL_BAK_KEY_MASK & OTP_LOAD_SECURE_DATA_MASK & OTP_DO_CRC_MASK, | |
101 | otp->base[OTPRX] + OTP_CONTROL_2); | |
102 | writel((readl(otp->base[OTPRX] + OTP_CONTROL_2) & OTP_RD_PERIOD_MASK) | CPU_CLOCK, | |
103 | otp->base[OTPRX] + OTP_CONTROL_2); | |
104 | ||
105 | ret = readl_poll_timeout(otp->base[OTPRX] + OTP_STATUS, status, | |
106 | status & OTP_READ_DONE, 10, OTP_READ_TIMEOUT_US); | |
107 | ||
108 | if (ret < 0) | |
109 | return ret; | |
110 | ||
111 | *value = (readl(otp->base[HB_GPIO] + ADDRESS_8_DATA + addr_data * OTP_WORD_SIZE) | |
112 | >> (8 * byte_shift)) & 0xff; | |
113 | ||
114 | return ret; | |
115 | } | |
116 | ||
117 | static int sp_ocotp_read(void *priv, unsigned int offset, void *value, size_t bytes) | |
118 | { | |
119 | struct sp_ocotp_priv *otp = priv; | |
120 | unsigned int addr; | |
121 | char *buf = value; | |
122 | char val[4]; | |
123 | int ret; | |
124 | ||
125 | ret = clk_enable(otp->clk); | |
126 | if (ret) | |
127 | return ret; | |
128 | ||
129 | *buf = 0; | |
130 | for (addr = offset; addr < (offset + bytes); addr++) { | |
131 | ret = sp_otp_read_real(otp, addr, val); | |
132 | if (ret < 0) { | |
133 | dev_err(otp->dev, "OTP read fail:%d at %d", ret, addr); | |
134 | goto disable_clk; | |
135 | } | |
136 | ||
137 | *buf++ = *val; | |
138 | } | |
139 | ||
140 | disable_clk: | |
141 | clk_disable(otp->clk); | |
142 | ||
143 | return ret; | |
144 | } | |
145 | ||
146 | static struct nvmem_config sp_ocotp_nvmem_config = { | |
147 | .name = "sp-ocotp", | |
2cc3b37f | 148 | .add_legacy_fixed_of_cells = true, |
8747ec2e VS |
149 | .read_only = true, |
150 | .word_size = 1, | |
151 | .size = QAC628_OTP_SIZE, | |
152 | .stride = 1, | |
153 | .reg_read = sp_ocotp_read, | |
154 | .owner = THIS_MODULE, | |
155 | }; | |
156 | ||
157 | static int sp_ocotp_probe(struct platform_device *pdev) | |
158 | { | |
159 | struct device *dev = &pdev->dev; | |
160 | struct nvmem_device *nvmem; | |
161 | struct sp_ocotp_priv *otp; | |
162 | struct resource *res; | |
163 | int ret; | |
164 | ||
165 | otp = devm_kzalloc(dev, sizeof(*otp), GFP_KERNEL); | |
166 | if (!otp) | |
167 | return -ENOMEM; | |
168 | ||
169 | otp->dev = dev; | |
170 | ||
171 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hb_gpio"); | |
172 | otp->base[HB_GPIO] = devm_ioremap_resource(dev, res); | |
173 | if (IS_ERR(otp->base[HB_GPIO])) | |
174 | return PTR_ERR(otp->base[HB_GPIO]); | |
175 | ||
176 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otprx"); | |
177 | otp->base[OTPRX] = devm_ioremap_resource(dev, res); | |
178 | if (IS_ERR(otp->base[OTPRX])) | |
179 | return PTR_ERR(otp->base[OTPRX]); | |
180 | ||
181 | otp->clk = devm_clk_get(&pdev->dev, NULL); | |
182 | if (IS_ERR(otp->clk)) | |
183 | return dev_err_probe(&pdev->dev, PTR_ERR(otp->clk), | |
184 | "devm_clk_get fail\n"); | |
185 | ||
186 | ret = clk_prepare(otp->clk); | |
187 | if (ret < 0) { | |
188 | dev_err(dev, "failed to prepare clk: %d\n", ret); | |
189 | return ret; | |
190 | } | |
191 | ||
192 | sp_ocotp_nvmem_config.priv = otp; | |
193 | sp_ocotp_nvmem_config.dev = dev; | |
194 | ||
195 | nvmem = devm_nvmem_register(dev, &sp_ocotp_nvmem_config); | |
095bb8ba YY |
196 | if (IS_ERR(nvmem)) { |
197 | ret = dev_err_probe(&pdev->dev, PTR_ERR(nvmem), | |
8747ec2e | 198 | "register nvmem device fail\n"); |
095bb8ba YY |
199 | goto err; |
200 | } | |
8747ec2e VS |
201 | |
202 | platform_set_drvdata(pdev, nvmem); | |
203 | ||
204 | dev_dbg(dev, "banks:%d x wpb:%d x wsize:%d = %d", | |
205 | (int)QAC628_OTP_NUM_BANKS, (int)OTP_WORDS_PER_BANK, | |
206 | (int)OTP_WORD_SIZE, (int)QAC628_OTP_SIZE); | |
207 | ||
8747ec2e | 208 | return 0; |
095bb8ba YY |
209 | err: |
210 | clk_unprepare(otp->clk); | |
211 | return ret; | |
8747ec2e VS |
212 | } |
213 | ||
214 | static const struct of_device_id sp_ocotp_dt_ids[] = { | |
215 | { .compatible = "sunplus,sp7021-ocotp", .data = &sp_otp_v0 }, | |
216 | { } | |
217 | }; | |
218 | MODULE_DEVICE_TABLE(of, sp_ocotp_dt_ids); | |
219 | ||
220 | static struct platform_driver sp_otp_driver = { | |
221 | .probe = sp_ocotp_probe, | |
222 | .driver = { | |
223 | .name = "sunplus,sp7021-ocotp", | |
224 | .of_match_table = sp_ocotp_dt_ids, | |
225 | } | |
226 | }; | |
227 | module_platform_driver(sp_otp_driver); | |
228 | ||
229 | MODULE_AUTHOR("Vincent Shih <[email protected]>"); | |
230 | MODULE_DESCRIPTION("Sunplus On-Chip OTP driver"); | |
231 | MODULE_LICENSE("GPL"); | |
232 |