• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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