2 * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or (at
7 * your option) any later version.
10 #include <linux/miscdevice.h>
11 #include <linux/platform_device.h>
13 #include <linux/file.h>
15 #include <linux/list.h>
16 #include <linux/debugfs.h>
17 #include <linux/mempolicy.h>
18 #include <linux/sched.h>
19 #include <linux/dma-mapping.h>
21 #include <linux/uaccess.h>
22 #include <linux/module.h>
23 #include <linux/soc/rockchip/rk_vendor_storage.h>
24 #include <linux/kthread.h>
25 #include <linux/delay.h>
27 #define EMMC_IDB_PART_OFFSET 64
28 #define EMMC_SYS_PART_OFFSET 8064
29 #define EMMC_BOOT_PART_SIZE 1024
30 #define EMMC_VENDOR_PART_START (1024 * 7)
31 #define EMMC_VENDOR_PART_SIZE 128
32 #define EMMC_VENDOR_PART_NUM 4
33 #define EMMC_VENDOR_TAG 0x524B5644
41 struct rk_vendor_req {
62 struct vendor_item item[126]; /* 126 * 8*/
63 u8 data[EMMC_VENDOR_PART_SIZE * 512 - 1024 - 8];
68 #define READ_SECTOR_IO _IOW('r', 0x04, unsigned int)
69 #define WRITE_SECTOR_IO _IOW('r', 0x05, unsigned int)
70 #define END_WRITE_SECTOR_IO _IOW('r', 0x52, unsigned int)
71 #define GET_FLASH_INFO_IO _IOW('r', 0x1A, unsigned int)
72 #define GET_BAD_BLOCK_IO _IOW('r', 0x03, unsigned int)
73 #define GET_LOCK_FLAG_IO _IOW('r', 0x53, unsigned int)
75 #define VENDOR_REQ_TAG 0x56524551
76 #define VENDOR_READ_IO _IOW('v', 0x01, unsigned int)
77 #define VENDOR_WRITE_IO _IOW('v', 0x02, unsigned int)
79 static u8 *g_idb_buffer;
80 static struct vendor_info *g_vendor;
82 extern int rk_emmc_transfer(u8 *buffer, unsigned addr, unsigned blksz,
85 static int emmc_vendor_ops(u8 *buffer, u32 addr, u32 n_sec, int write)
89 for (i = 0; i < n_sec; i++)
90 ret = rk_emmc_transfer(buffer + i * 512, addr + i, 512, write);
95 static int emmc_vendor_storage_init(void)
97 u32 i, max_ver, max_index;
100 g_vendor = kmalloc(sizeof(*g_vendor), GFP_KERNEL | GFP_DMA);
106 for (i = 0; i < EMMC_VENDOR_PART_NUM; i++) {
107 /* read first 512 bytes */
108 p_buf = (u8 *)g_vendor;
109 if (rk_emmc_transfer(p_buf, EMMC_VENDOR_PART_START +
110 EMMC_VENDOR_PART_SIZE * i, 512, 0))
112 /* read last 512 bytes */
113 p_buf += (EMMC_VENDOR_PART_SIZE - 1) * 512;
114 if (rk_emmc_transfer(p_buf, EMMC_VENDOR_PART_START +
115 EMMC_VENDOR_PART_SIZE * (i + 1) - 1,
119 if (g_vendor->tag == EMMC_VENDOR_TAG &&
120 g_vendor->version2 == g_vendor->version) {
121 if (max_ver < g_vendor->version) {
123 max_ver = g_vendor->version;
128 if (emmc_vendor_ops((u8 *)g_vendor, EMMC_VENDOR_PART_START +
129 EMMC_VENDOR_PART_SIZE * max_index,
130 EMMC_VENDOR_PART_SIZE, 0))
133 memset((void *)g_vendor, 0, sizeof(g_vendor));
134 g_vendor->version = 1;
135 g_vendor->tag = EMMC_VENDOR_TAG;
136 g_vendor->version2 = g_vendor->version;
137 g_vendor->free_offset = 0;
138 g_vendor->free_size = sizeof(g_vendor->data);
147 static int emmc_vendor_read(u32 id, void *pbuf, u32 size)
154 for (i = 0; i < g_vendor->item_num; i++) {
155 if (g_vendor->item[i].id == id) {
156 if (size > g_vendor->item[i].size)
157 size = g_vendor->item[i].size;
159 &g_vendor->data[g_vendor->item[i].offset],
167 static int emmc_vendor_write(u32 id, void *pbuf, u32 size)
169 u32 i, next_index, algin_size;
170 struct vendor_item *item;
175 algin_size = (size + 0x3F) & (~0x3F); /* algin to 32 bytes*/
176 next_index = g_vendor->next_index;
177 for (i = 0; i < g_vendor->item_num; i++) {
178 if (g_vendor->item[i].id == id) {
179 if (size > algin_size)
181 memcpy(&g_vendor->data[g_vendor->item[i].offset],
184 g_vendor->item[i].size = size;
186 g_vendor->version2 = g_vendor->version;
187 g_vendor->next_index++;
188 if (g_vendor->next_index >= EMMC_VENDOR_PART_NUM)
189 g_vendor->next_index = 0;
190 emmc_vendor_ops((u8 *)g_vendor, EMMC_VENDOR_PART_START +
191 EMMC_VENDOR_PART_SIZE * next_index,
192 EMMC_VENDOR_PART_SIZE, 1);
197 if (g_vendor->free_size >= algin_size) {
198 item = &g_vendor->item[g_vendor->item_num];
200 item->offset = g_vendor->free_offset;
202 g_vendor->free_offset += algin_size;
203 g_vendor->free_size -= algin_size;
204 memcpy(&g_vendor->data[item->offset], pbuf, size);
205 g_vendor->item_num++;
207 g_vendor->version2 = g_vendor->version;
208 g_vendor->next_index++;
209 if (g_vendor->next_index >= EMMC_VENDOR_PART_NUM)
210 g_vendor->next_index = 0;
211 emmc_vendor_ops((u8 *)g_vendor, EMMC_VENDOR_PART_START +
212 EMMC_VENDOR_PART_SIZE * next_index,
213 EMMC_VENDOR_PART_SIZE, 1);
219 static int id_blk_read_data(u32 index, u32 n_sec, u8 *buf)
224 if (index + n_sec >= 1024 * 5)
226 index = index + EMMC_IDB_PART_OFFSET;
227 for (i = 0; i < n_sec; i++) {
228 ret = rk_emmc_transfer(buf + i * 512, index + i, 512, 0);
235 static int id_blk_write_data(u32 index, u32 n_sec, u8 *buf)
240 if (index + n_sec >= 1024 * 5)
242 index = index + EMMC_IDB_PART_OFFSET;
243 for (i = 0; i < n_sec; i++) {
244 ret = rk_emmc_transfer(buf + i * 512, index + i, 512, 1);
251 static int emmc_write_idblock(u32 size, u8 *buf, u32 *id_blk_tbl)
254 u32 totle_write_count = 0;
255 u32 *p_raw_data = (u32 *)buf;
256 u32 *p_check_buf = kmalloc(EMMC_BOOT_PART_SIZE * 512, GFP_KERNEL);
261 totle_sec = (size + 511) >> 9;
265 for (i = 0; i < 5; i++) {
266 memset(p_check_buf, 0, 512);
267 id_blk_write_data(EMMC_BOOT_PART_SIZE * i, 1,
269 id_blk_write_data(EMMC_BOOT_PART_SIZE * i + 1,
270 totle_sec - 1, buf + 512);
271 id_blk_write_data(EMMC_BOOT_PART_SIZE * i, 1, buf);
272 id_blk_read_data(EMMC_BOOT_PART_SIZE * i, totle_sec,
274 for (j = 0; j < totle_sec * 128; j++) {
275 if (p_check_buf[j] != p_raw_data[j]) {
276 memset(p_check_buf, 0, 512);
277 id_blk_write_data(EMMC_BOOT_PART_SIZE * i, 1,
282 if (j >= totle_sec * 128)
286 if (totle_write_count)
291 static int vendor_storage_open(struct inode *inode, struct file *file)
296 static int vendor_storage_release(struct inode *inode, struct file *file)
301 static const u32 g_crc32_tbl[256] = {
302 0x00000000, 0x04c10db7, 0x09821b6e, 0x0d4316d9,
303 0x130436dc, 0x17c53b6b, 0x1a862db2, 0x1e472005,
304 0x26086db8, 0x22c9600f, 0x2f8a76d6, 0x2b4b7b61,
305 0x350c5b64, 0x31cd56d3, 0x3c8e400a, 0x384f4dbd,
306 0x4c10db70, 0x48d1d6c7, 0x4592c01e, 0x4153cda9,
307 0x5f14edac, 0x5bd5e01b, 0x5696f6c2, 0x5257fb75,
308 0x6a18b6c8, 0x6ed9bb7f, 0x639aada6, 0x675ba011,
309 0x791c8014, 0x7ddd8da3, 0x709e9b7a, 0x745f96cd,
310 0x9821b6e0, 0x9ce0bb57, 0x91a3ad8e, 0x9562a039,
311 0x8b25803c, 0x8fe48d8b, 0x82a79b52, 0x866696e5,
312 0xbe29db58, 0xbae8d6ef, 0xb7abc036, 0xb36acd81,
313 0xad2ded84, 0xa9ece033, 0xa4aff6ea, 0xa06efb5d,
314 0xd4316d90, 0xd0f06027, 0xddb376fe, 0xd9727b49,
315 0xc7355b4c, 0xc3f456fb, 0xceb74022, 0xca764d95,
316 0xf2390028, 0xf6f80d9f, 0xfbbb1b46, 0xff7a16f1,
317 0xe13d36f4, 0xe5fc3b43, 0xe8bf2d9a, 0xec7e202d,
318 0x34826077, 0x30436dc0, 0x3d007b19, 0x39c176ae,
319 0x278656ab, 0x23475b1c, 0x2e044dc5, 0x2ac54072,
320 0x128a0dcf, 0x164b0078, 0x1b0816a1, 0x1fc91b16,
321 0x018e3b13, 0x054f36a4, 0x080c207d, 0x0ccd2dca,
322 0x7892bb07, 0x7c53b6b0, 0x7110a069, 0x75d1adde,
323 0x6b968ddb, 0x6f57806c, 0x621496b5, 0x66d59b02,
324 0x5e9ad6bf, 0x5a5bdb08, 0x5718cdd1, 0x53d9c066,
325 0x4d9ee063, 0x495fedd4, 0x441cfb0d, 0x40ddf6ba,
326 0xaca3d697, 0xa862db20, 0xa521cdf9, 0xa1e0c04e,
327 0xbfa7e04b, 0xbb66edfc, 0xb625fb25, 0xb2e4f692,
328 0x8aabbb2f, 0x8e6ab698, 0x8329a041, 0x87e8adf6,
329 0x99af8df3, 0x9d6e8044, 0x902d969d, 0x94ec9b2a,
330 0xe0b30de7, 0xe4720050, 0xe9311689, 0xedf01b3e,
331 0xf3b73b3b, 0xf776368c, 0xfa352055, 0xfef42de2,
332 0xc6bb605f, 0xc27a6de8, 0xcf397b31, 0xcbf87686,
333 0xd5bf5683, 0xd17e5b34, 0xdc3d4ded, 0xd8fc405a,
334 0x6904c0ee, 0x6dc5cd59, 0x6086db80, 0x6447d637,
335 0x7a00f632, 0x7ec1fb85, 0x7382ed5c, 0x7743e0eb,
336 0x4f0cad56, 0x4bcda0e1, 0x468eb638, 0x424fbb8f,
337 0x5c089b8a, 0x58c9963d, 0x558a80e4, 0x514b8d53,
338 0x25141b9e, 0x21d51629, 0x2c9600f0, 0x28570d47,
339 0x36102d42, 0x32d120f5, 0x3f92362c, 0x3b533b9b,
340 0x031c7626, 0x07dd7b91, 0x0a9e6d48, 0x0e5f60ff,
341 0x101840fa, 0x14d94d4d, 0x199a5b94, 0x1d5b5623,
342 0xf125760e, 0xf5e47bb9, 0xf8a76d60, 0xfc6660d7,
343 0xe22140d2, 0xe6e04d65, 0xeba35bbc, 0xef62560b,
344 0xd72d1bb6, 0xd3ec1601, 0xdeaf00d8, 0xda6e0d6f,
345 0xc4292d6a, 0xc0e820dd, 0xcdab3604, 0xc96a3bb3,
346 0xbd35ad7e, 0xb9f4a0c9, 0xb4b7b610, 0xb076bba7,
347 0xae319ba2, 0xaaf09615, 0xa7b380cc, 0xa3728d7b,
348 0x9b3dc0c6, 0x9ffccd71, 0x92bfdba8, 0x967ed61f,
349 0x8839f61a, 0x8cf8fbad, 0x81bbed74, 0x857ae0c3,
350 0x5d86a099, 0x5947ad2e, 0x5404bbf7, 0x50c5b640,
351 0x4e829645, 0x4a439bf2, 0x47008d2b, 0x43c1809c,
352 0x7b8ecd21, 0x7f4fc096, 0x720cd64f, 0x76cddbf8,
353 0x688afbfd, 0x6c4bf64a, 0x6108e093, 0x65c9ed24,
354 0x11967be9, 0x1557765e, 0x18146087, 0x1cd56d30,
355 0x02924d35, 0x06534082, 0x0b10565b, 0x0fd15bec,
356 0x379e1651, 0x335f1be6, 0x3e1c0d3f, 0x3add0088,
357 0x249a208d, 0x205b2d3a, 0x2d183be3, 0x29d93654,
358 0xc5a71679, 0xc1661bce, 0xcc250d17, 0xc8e400a0,
359 0xd6a320a5, 0xd2622d12, 0xdf213bcb, 0xdbe0367c,
360 0xe3af7bc1, 0xe76e7676, 0xea2d60af, 0xeeec6d18,
361 0xf0ab4d1d, 0xf46a40aa, 0xf9295673, 0xfde85bc4,
362 0x89b7cd09, 0x8d76c0be, 0x8035d667, 0x84f4dbd0,
363 0x9ab3fbd5, 0x9e72f662, 0x9331e0bb, 0x97f0ed0c,
364 0xafbfa0b1, 0xab7ead06, 0xa63dbbdf, 0xa2fcb668,
365 0xbcbb966d, 0xb87a9bda, 0xb5398d03, 0xb1f880b4,
368 static u32 rk_crc_32(unsigned char *buf, u32 len)
373 for (i = 0; i < len; i++)
374 crc = (crc << 8) ^ g_crc32_tbl[(crc >> 24) ^ *buf++];
378 static long vendor_storage_ioctl(struct file *file, unsigned int cmd,
383 struct rk_sys_req *s_req;
384 struct rk_vendor_req *v_req;
387 page_buf = kmalloc(4096, GFP_KERNEL);
391 v_req = (struct rk_vendor_req *)page_buf;
392 s_req = (struct rk_sys_req *)page_buf;
397 if (copy_from_user(page_buf, (void __user *)arg, 8)) {
401 if (v_req->tag == VENDOR_REQ_TAG) {
402 size = emmc_vendor_read(v_req->id, v_req->data,
407 if (copy_to_user((void __user *)arg,
414 case VENDOR_WRITE_IO:
416 if (copy_from_user(page_buf, (void __user *)arg, 8)) {
420 if (v_req->tag == VENDOR_REQ_TAG && (v_req->len < 4096 - 8)) {
421 if (copy_from_user(page_buf, (void __user *)arg,
426 ret = emmc_vendor_write(v_req->id,
434 if (copy_from_user(page_buf, (void __user *)arg, 512)) {
441 id_blk_read_data(page_buf[0], size, (u8 *)page_buf);
442 if (copy_to_user((void __user *)arg, page_buf,
453 case WRITE_SECTOR_IO:
455 if (copy_from_user(page_buf, (void __user *)arg, 4096)) {
460 g_idb_buffer = kmalloc(4096 + EMMC_BOOT_PART_SIZE * 512,
467 if (page_buf[1] <= 4088 && page_buf[0] <=
468 (EMMC_BOOT_PART_SIZE * 512 - 4096)) {
469 memcpy(g_idb_buffer + page_buf[0], page_buf + 2,
478 case END_WRITE_SECTOR_IO:
480 if (copy_from_user(page_buf, (void __user *)arg, 28)) {
484 if (page_buf[0] <= (EMMC_BOOT_PART_SIZE * 512)) {
490 rk_crc_32(g_idb_buffer, page_buf[0])) {
494 ret = emmc_write_idblock(page_buf[0],
506 case GET_BAD_BLOCK_IO:
508 memset(page_buf, 0, 64);
509 if (copy_to_user((void __user *)arg, page_buf, 64)) {
516 case GET_LOCK_FLAG_IO:
519 if (copy_to_user((void __user *)arg, page_buf, 4)) {
526 case GET_FLASH_INFO_IO:
528 page_buf[0] = 0x00800000;
529 page_buf[1] = 0x00040400;
530 page_buf[2] = 0x00010028;
531 if (copy_to_user((void __user *)arg, page_buf, 11)) {
543 pr_info("ret = %lx\n", ret);
548 const struct file_operations vendor_storage_fops = {
549 .open = vendor_storage_open,
550 .compat_ioctl = vendor_storage_ioctl,
551 .unlocked_ioctl = vendor_storage_ioctl,
552 .release = vendor_storage_release,
555 static struct miscdevice vender_storage_dev = {
556 .minor = MISC_DYNAMIC_MINOR,
557 .name = "vendor_storage",
558 .fops = &vendor_storage_fops,
561 static int vendor_init_thread(void *arg)
565 /* sleep 500ms wait emmc initialize completed */
567 ret = emmc_vendor_storage_init();
569 ret = misc_register(&vender_storage_dev);
570 rk_vendor_register(emmc_vendor_read, emmc_vendor_write);
572 pr_info("vendor storage:20160801 ret = %d\n", ret);
576 static int __init vendor_storage_init(void)
579 kthread_run(vendor_init_thread, (void *)NULL, "vendor_storage_init");
583 static __exit void vendor_storage_deinit(void)
586 misc_deregister(&vender_storage_dev);
589 device_initcall_sync(vendor_storage_init);
590 module_exit(vendor_storage_deinit);