1 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2
3 /* Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd */
4
5 #include <linux/fs.h>
6 #include <linux/kthread.h>
7 #include <linux/miscdevice.h>
8 #include <linux/module.h>
9 #include <linux/platform_device.h>
10 #include <linux/slab.h>
11 #include <linux/soc/rockchip/rk_vendor_storage.h>
12 #include <linux/uaccess.h>
13 #include <misc/rkflash_vendor_storage.h>
14
15 #include "flash_vendor_storage.h"
16
17 #define FLASH_VENDOR_TEST 0
18 #define DRM_DEBUG 1
19
20 #if DRM_DEBUG
21 #define DLOG(fmt, args...) pr_info(fmt, ##args)
22 #else
23 #define DLOG(x...)
24 #endif
25
26 struct vendor_item {
27 u16 id;
28 u16 offset;
29 u16 size;
30 u16 flag;
31 };
32
33 #define FLASH_VENDOR_PART_START 8
34 #define FLASH_VENDOR_PART_SIZE 8
35 #define FLASH_VENDOR_PART_NUM 4
36 #define FLASH_VENDOR_TAG 0x524B5644
37
38 struct tag_vendor_info {
39 u32 tag;
40 u32 version;
41 u16 next_index;
42 u16 item_num;
43 u16 free_offset;
44 u16 free_size;
45 struct vendor_item item[62]; /* 62 * 8 */
46 u8 data[FLASH_VENDOR_PART_SIZE * 512 - 512 - 8];
47 u32 hash;
48 u32 version2;
49 };
50
51 static int (*_flash_read)(u32 sec, u32 n_sec, void *p_data);
52 static int (*_flash_write)(u32 sec, u32 n_sec, void *p_data);
53 static struct tag_vendor_info *g_vendor;
54
flash_vendor_dev_ops_register(int (* read)(u32 sec,u32 n_sec,void * p_data),int (* write)(u32 sec,u32 n_sec,void * p_data))55 int flash_vendor_dev_ops_register(int (*read)(u32 sec,
56 u32 n_sec,
57 void *p_data),
58 int (*write)(u32 sec,
59 u32 n_sec,
60 void *p_data))
61 {
62 if (!_flash_read) {
63 _flash_read = read;
64 _flash_write = write;
65 return 0;
66 }
67 return -1;
68 }
69
flash_vendor_init(void)70 static u32 flash_vendor_init(void)
71 {
72 u32 i, max_ver, max_index;
73
74 if (!_flash_read)
75 return -EPERM;
76
77 g_vendor = kmalloc(sizeof(*g_vendor), GFP_KERNEL | GFP_DMA);
78 if (!g_vendor)
79 return 0;
80
81 max_ver = 0;
82 max_index = 0;
83 for (i = 0; i < FLASH_VENDOR_PART_NUM; i++) {
84 _flash_read(FLASH_VENDOR_PART_START +
85 FLASH_VENDOR_PART_SIZE * i,
86 FLASH_VENDOR_PART_SIZE,
87 g_vendor);
88 if (g_vendor->tag == FLASH_VENDOR_TAG &&
89 g_vendor->version == g_vendor->version2) {
90 if (max_ver < g_vendor->version) {
91 max_index = i;
92 max_ver = g_vendor->version;
93 }
94 }
95 }
96 /* DLOG("max_ver = %d\n",max_ver); */
97 if (max_ver) {
98 _flash_read(FLASH_VENDOR_PART_START +
99 FLASH_VENDOR_PART_SIZE * max_index,
100 FLASH_VENDOR_PART_SIZE,
101 g_vendor);
102 } else {
103 memset(g_vendor, 0, sizeof(*g_vendor));
104 g_vendor->version = 1;
105 g_vendor->tag = FLASH_VENDOR_TAG;
106 g_vendor->version2 = g_vendor->version;
107 g_vendor->free_offset = 0;
108 g_vendor->free_size = sizeof(g_vendor->data);
109 }
110 /* rknand_print_hex("vendor:", g_vendor, 4, 1024); */
111
112 return 0;
113 }
114
flash_vendor_read(u32 id,void * pbuf,u32 size)115 static int flash_vendor_read(u32 id, void *pbuf, u32 size)
116 {
117 u32 i;
118
119 if (!g_vendor)
120 return -1;
121
122 for (i = 0; i < g_vendor->item_num; i++) {
123 if (g_vendor->item[i].id == id) {
124 if (size > g_vendor->item[i].size)
125 size = g_vendor->item[i].size;
126 memcpy(pbuf,
127 &g_vendor->data[g_vendor->item[i].offset],
128 size);
129 return size;
130 }
131 }
132 return (-1);
133 }
134
flash_vendor_write(u32 id,void * pbuf,u32 size)135 static int flash_vendor_write(u32 id, void *pbuf, u32 size)
136 {
137 u32 i, j, next_index, align_size, alloc_size, item_num;
138 u32 offset, next_size;
139 u8 *p_data;
140 struct vendor_item *item;
141 struct vendor_item *next_item;
142
143 if (!g_vendor)
144 return -1;
145
146 p_data = g_vendor->data;
147 item_num = g_vendor->item_num;
148 align_size = ALIGN(size, 0x40); /* align to 64 bytes*/
149 next_index = g_vendor->next_index;
150 for (i = 0; i < item_num; i++) {
151 item = &g_vendor->item[i];
152 if (item->id == id) {
153 alloc_size = ALIGN(item->size, 0x40);
154 if (size > alloc_size) {
155 if (g_vendor->free_size < align_size)
156 return -1;
157 offset = item->offset;
158 for (j = i; j < item_num - 1; j++) {
159 item = &g_vendor->item[j];
160 next_item = &g_vendor->item[j + 1];
161 item->id = next_item->id;
162 item->size = next_item->size;
163 item->offset = offset;
164 next_size = ALIGN(next_item->size,
165 0x40);
166 memcpy(&p_data[offset],
167 &p_data[next_item->offset],
168 next_size);
169 offset += next_size;
170 }
171 item = &g_vendor->item[j];
172 item->id = id;
173 item->offset = offset;
174 item->size = size;
175 memcpy(&p_data[item->offset], pbuf, size);
176 g_vendor->free_offset = offset + align_size;
177 g_vendor->free_size -= (align_size -
178 alloc_size);
179 } else {
180 memcpy(&p_data[item->offset],
181 pbuf,
182 size);
183 g_vendor->item[i].size = size;
184 }
185 g_vendor->version++;
186 g_vendor->version2 = g_vendor->version;
187 g_vendor->next_index++;
188 if (g_vendor->next_index >= FLASH_VENDOR_PART_NUM)
189 g_vendor->next_index = 0;
190 _flash_write(FLASH_VENDOR_PART_START +
191 FLASH_VENDOR_PART_SIZE * next_index,
192 FLASH_VENDOR_PART_SIZE,
193 g_vendor);
194 return 0;
195 }
196 }
197
198 if (g_vendor->free_size >= align_size) {
199 item = &g_vendor->item[g_vendor->item_num];
200 item->id = id;
201 item->offset = g_vendor->free_offset;
202 item->size = align_size;
203 item->size = size;
204 g_vendor->free_offset += align_size;
205 g_vendor->free_size -= align_size;
206 memcpy(&g_vendor->data[item->offset], pbuf, size);
207 g_vendor->item_num++;
208 g_vendor->version++;
209 g_vendor->next_index++;
210 g_vendor->version2 = g_vendor->version;
211 if (g_vendor->next_index >= FLASH_VENDOR_PART_NUM)
212 g_vendor->next_index = 0;
213 _flash_write(FLASH_VENDOR_PART_START +
214 FLASH_VENDOR_PART_SIZE * next_index,
215 FLASH_VENDOR_PART_SIZE,
216 g_vendor);
217 return 0;
218 }
219
220 return(-1);
221 }
222
223 #if (FLASH_VENDOR_TEST)
print_hex(char * s,void * buf,int width,int len)224 static void print_hex(char *s, void *buf, int width, int len)
225 {
226 print_hex_dump(KERN_WARNING, s, DUMP_PREFIX_OFFSET,
227 16, width, buf, len * width, 0);
228 }
229
flash_vendor_test(void)230 static void flash_vendor_test(void)
231 {
232 u32 i;
233 u8 test_buf[512];
234
235 memset(test_buf, 0, 512);
236 for (i = 0; i < 62; i++) {
237 memset(test_buf, i, i + 1);
238 flash_vendor_write(i, test_buf, i + 1);
239 }
240 memset(test_buf, 0, 512);
241 for (i = 0; i < 62; i++) {
242 flash_vendor_read(i, test_buf, i + 1);
243 DLOG("id = %d ,size = %d\n", i, i + 1);
244 print_hex("data:", test_buf, 1, i + 1);
245 }
246 flash_vendor_init();
247 memset(test_buf, 0, 512);
248 for (i = 0; i < 62; i++) {
249 flash_vendor_read(i, test_buf, i + 1);
250 DLOG("id = %d ,size = %d\n", i, i + 1);
251 print_hex("data:", test_buf, 1, i + 1);
252 }
253 while (1)
254 ;
255 }
256 #endif
257
vendor_storage_ioctl(struct file * file,unsigned int cmd,unsigned long arg)258 static long vendor_storage_ioctl(struct file *file,
259 unsigned int cmd,
260 unsigned long arg)
261 {
262 long ret = -EINVAL;
263 int size;
264 u32 *temp_buf;
265 struct RK_VENDOR_REQ *req;
266
267 req = kmalloc(sizeof(*req), GFP_KERNEL);
268 if (!req)
269 return ret;
270
271 temp_buf = (u32 *)req;
272
273 switch (cmd) {
274 case VENDOR_READ_IO:
275 {
276 if (copy_from_user(temp_buf,
277 (void __user *)arg,
278 sizeof(*req))) {
279 DLOG("copy_from_user error\n");
280 ret = -EFAULT;
281 break;
282 }
283 if (req->tag == VENDOR_REQ_TAG) {
284 size = flash_vendor_read(req->id,
285 req->data,
286 req->len);
287 if (size > 0) {
288 req->len = size;
289 ret = 0;
290 if (copy_to_user((void __user *)arg,
291 temp_buf,
292 sizeof(*req)))
293 ret = -EFAULT;
294 }
295 }
296 } break;
297 case VENDOR_WRITE_IO:
298 {
299 if (copy_from_user(temp_buf,
300 (void __user *)arg,
301 sizeof(struct RK_VENDOR_REQ))) {
302 DLOG("copy_from_user error\n");
303 ret = -EFAULT;
304 break;
305 }
306 if (req->tag == VENDOR_REQ_TAG)
307 ret = flash_vendor_write(req->id,
308 req->data,
309 req->len);
310 } break;
311 default:
312 return -EINVAL;
313 }
314 kfree(temp_buf);
315 DLOG("flash_vendor_ioctl cmd=%x ret = %lx\n", cmd, ret);
316 return ret;
317 }
318
319 static const struct file_operations vendor_storage_fops = {
320 .compat_ioctl = vendor_storage_ioctl,
321 .unlocked_ioctl = vendor_storage_ioctl,
322 };
323
324 static struct miscdevice vender_storage_dev = {
325 .minor = MISC_DYNAMIC_MINOR,
326 .name = "vendor_storage",
327 .fops = &vendor_storage_fops,
328 };
329
vendor_init_thread(void * arg)330 static int vendor_init_thread(void *arg)
331 {
332 int ret;
333
334 pr_info("flash %s!\n", __func__);
335 ret = flash_vendor_init();
336 if (!ret) {
337 ret = misc_register(&vender_storage_dev);
338 #ifdef CONFIG_ROCKCHIP_VENDOR_STORAGE
339 rk_vendor_register(flash_vendor_read, flash_vendor_write);
340 #endif
341 }
342 pr_info("flash vendor storage:20170308 ret = %d\n", ret);
343 return ret;
344 }
345
vendor_storage_init(void)346 static int __init vendor_storage_init(void)
347 {
348 kthread_run(vendor_init_thread, (void *)NULL, "vendor_storage_init");
349 return 0;
350 }
351
vendor_storage_deinit(void)352 static __exit void vendor_storage_deinit(void)
353 {
354 if (g_vendor) {
355 misc_deregister(&vender_storage_dev);
356 kfree(g_vendor);
357 g_vendor = NULL;
358 }
359 }
360
361 device_initcall_sync(vendor_storage_init);
362 module_exit(vendor_storage_deinit);
363 MODULE_LICENSE("GPL");
364