From d66b1d9e6ac27f18a7e7bc247357efddbfbd567d Mon Sep 17 00:00:00 2001 From: Dingqiang Lin Date: Tue, 15 May 2018 21:53:23 +0800 Subject: [PATCH] soc: rockchip: add flash vendor storage support Change-Id: I0261e652161e6a20a4d988c4ddfd7f186ad2200e Signed-off-by: Dingqiang Lin --- drivers/soc/rockchip/Makefile | 1 + drivers/soc/rockchip/flash_vendor_storage.c | 320 ++++++++++++++++++++ drivers/soc/rockchip/flash_vendor_storage.h | 16 + include/uapi/misc/rkflash_vendor_storage.h | 19 ++ 4 files changed, 356 insertions(+) create mode 100644 drivers/soc/rockchip/flash_vendor_storage.c create mode 100644 drivers/soc/rockchip/flash_vendor_storage.h create mode 100644 include/uapi/misc/rkflash_vendor_storage.h diff --git a/drivers/soc/rockchip/Makefile b/drivers/soc/rockchip/Makefile index f7697e7b334d..d44bc88fdcd8 100644 --- a/drivers/soc/rockchip/Makefile +++ b/drivers/soc/rockchip/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_ROCKCHIP_GRF) += grf.o obj-$(CONFIG_ROCKCHIP_PM_DOMAINS) += pm_domains.o obj-$(CONFIG_FIQ_DEBUGGER) += rk_fiq_debugger.o obj-$(CONFIG_MMC_DW_ROCKCHIP) += sdmmc_vendor_storage.o +obj-$(CONFIG_RK_FLASH) += flash_vendor_storage.o obj-$(CONFIG_ROCKCHIP_PVTM) += rockchip_pvtm.o obj-$(CONFIG_ROCKCHIP_SUSPEND_MODE) += rockchip_pm_config.o obj-$(CONFIG_ROCK_CHIP_SOC_CAMERA) += rk_camera.o diff --git a/drivers/soc/rockchip/flash_vendor_storage.c b/drivers/soc/rockchip/flash_vendor_storage.c new file mode 100644 index 000000000000..9d6a5599119d --- /dev/null +++ b/drivers/soc/rockchip/flash_vendor_storage.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/* Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "flash_vendor_storage.h" + +#define FLASH_VENDOR_TEST 0 +#define DRM_DEBUG 1 + +#if DRM_DEBUG +#define DLOG(fmt, args...) pr_info(fmt, ##args) +#else +#define DLOG(x...) +#endif + +struct vendor_item { + u16 id; + u16 offset; + u16 size; + u16 flag; +}; + +#define FLASH_VENDOR_PART_START 8 +#define FLASH_VENDOR_PART_SIZE 8 +#define FLASH_VENDOR_PART_NUM 4 +#define FLASH_VENDOR_TAG 0x524B5644 + +struct tag_vendor_info { + u32 tag; + u32 version; + u16 next_index; + u16 item_num; + u16 free_offset; + u16 free_size; + struct vendor_item item[62]; /* 62 * 8 */ + u8 data[FLASH_VENDOR_PART_SIZE * 512 - 512 - 8]; + u32 hash; + u32 version2; +}; + +static int (*_flash_read)(u32 sec, u32 n_sec, void *p_data); +static int (*_flash_write)(u32 sec, u32 n_sec, void *p_data); +static struct tag_vendor_info *g_vendor; + +int 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)) +{ + if (!_flash_read) { + _flash_read = read; + _flash_write = write; + return 0; + } + return -1; +} + +static u32 flash_vendor_init(void) +{ + u32 i, max_ver, max_index; + + g_vendor = kmalloc(sizeof(*g_vendor), GFP_KERNEL | GFP_DMA); + if (!g_vendor) + return 0; + + max_ver = 0; + max_index = 0; + for (i = 0; i < FLASH_VENDOR_PART_NUM; i++) { + _flash_read(FLASH_VENDOR_PART_START + + FLASH_VENDOR_PART_SIZE * i, + FLASH_VENDOR_PART_SIZE, + g_vendor); + if (g_vendor->tag == FLASH_VENDOR_TAG && + g_vendor->version == g_vendor->version2) { + if (max_ver < g_vendor->version) { + max_index = i; + max_ver = g_vendor->version; + } + } + } + /* DLOG("max_ver = %d\n",max_ver); */ + if (max_ver) { + _flash_read(FLASH_VENDOR_PART_START + + FLASH_VENDOR_PART_SIZE * max_index, + FLASH_VENDOR_PART_SIZE, + g_vendor); + } else { + memset(g_vendor, 0, sizeof(*g_vendor)); + g_vendor->version = 1; + g_vendor->tag = FLASH_VENDOR_TAG; + g_vendor->version2 = g_vendor->version; + g_vendor->free_offset = 0; + g_vendor->free_size = sizeof(g_vendor->data); + } + /* rknand_print_hex("vendor:", g_vendor, 4, 1024); */ + + return 0; +} + +static int flash_vendor_read(u32 id, void *pbuf, u32 size) +{ + u32 i; + + if (!g_vendor) + return -1; + + for (i = 0; i < g_vendor->item_num; i++) { + if (g_vendor->item[i].id == id) { + if (size > g_vendor->item[i].size) + size = g_vendor->item[i].size; + memcpy(pbuf, + &g_vendor->data[g_vendor->item[i].offset], + size); + return size; + } + } + return (-1); +} + +static int flash_vendor_write(u32 id, void *pbuf, u32 size) +{ + u32 i, next_index, algin_size; + struct vendor_item *item; + + algin_size = (size + 0x3F) & (~0x3F); /* algin to 64 bytes */ + next_index = g_vendor->next_index; + for (i = 0; i < g_vendor->item_num; i++) { + if (g_vendor->item[i].id == id) { + if (size > algin_size) + return -1; + memcpy(&g_vendor->data[g_vendor->item[i].offset], + pbuf, + size); + g_vendor->item[i].size = size; + g_vendor->version++; + g_vendor->version2 = g_vendor->version; + g_vendor->next_index++; + if (g_vendor->next_index >= FLASH_VENDOR_PART_NUM) + g_vendor->next_index = 0; + _flash_write(FLASH_VENDOR_PART_START + + FLASH_VENDOR_PART_SIZE * next_index, + FLASH_VENDOR_PART_SIZE, + g_vendor); + return 0; + } + } + + if (g_vendor->free_size >= algin_size) { + item = &g_vendor->item[g_vendor->item_num]; + item->id = id; + item->offset = g_vendor->free_offset; + item->size = algin_size; + item->size = size; + g_vendor->free_offset += algin_size; + g_vendor->free_size -= algin_size; + memcpy(&g_vendor->data[item->offset], pbuf, size); + g_vendor->item_num++; + g_vendor->version++; + g_vendor->next_index++; + g_vendor->version2 = g_vendor->version; + if (g_vendor->next_index >= FLASH_VENDOR_PART_NUM) + g_vendor->next_index = 0; + _flash_write(FLASH_VENDOR_PART_START + + FLASH_VENDOR_PART_SIZE * next_index, + FLASH_VENDOR_PART_SIZE, + g_vendor); + return 0; + } + + return(-1); +} + +#if (FLASH_VENDOR_TEST) +static void print_hex(char *s, void *buf, int width, int len) +{ + print_hex_dump(KERN_WARNING, s, DUMP_PREFIX_OFFSET, + 16, width, buf, len * width, 0); +} + +static void flash_vendor_test(void) +{ + u32 i; + u8 test_buf[512]; + + memset(test_buf, 0, 512); + for (i = 0; i < 62; i++) { + memset(test_buf, i, i + 1); + flash_vendor_write(i, test_buf, i + 1); + } + memset(test_buf, 0, 512); + for (i = 0; i < 62; i++) { + flash_vendor_read(i, test_buf, i + 1); + DLOG("id = %d ,size = %d\n", i, i + 1); + print_hex("data:", test_buf, 1, i + 1); + } + flash_vendor_init(); + memset(test_buf, 0, 512); + for (i = 0; i < 62; i++) { + flash_vendor_read(i, test_buf, i + 1); + DLOG("id = %d ,size = %d\n", i, i + 1); + print_hex("data:", test_buf, 1, i + 1); + } + while (1) + ; +} +#endif + +static long vendor_storage_ioctl(struct file *file, + unsigned int cmd, + unsigned long arg) +{ + long ret = -EINVAL; + int size; + u32 *temp_buf; + struct RK_VENDOR_REQ *req; + + req = kmalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return ret; + + temp_buf = (u32 *)req; + + switch (cmd) { + case VENDOR_READ_IO: + { + if (copy_from_user(temp_buf, + (void __user *)arg, + sizeof(*req))) { + DLOG("copy_from_user error\n"); + ret = -EFAULT; + break; + } + if (req->tag == VENDOR_REQ_TAG) { + size = flash_vendor_read(req->id, + req->data, + req->len); + if (size > 0) { + req->len = size; + ret = 0; + if (copy_to_user((void __user *)arg, + temp_buf, + sizeof(*req))) + ret = -EFAULT; + } + } + } break; + case VENDOR_WRITE_IO: + { + if (copy_from_user(temp_buf, + (void __user *)arg, + sizeof(struct RK_VENDOR_REQ))) { + DLOG("copy_from_user error\n"); + ret = -EFAULT; + break; + } + if (req->tag == VENDOR_REQ_TAG) + ret = flash_vendor_write(req->id, + req->data, + req->len); + } break; + default: + return -EINVAL; + } + kfree(temp_buf); + DLOG("flash_vendor_ioctl cmd=%x ret = %lx\n", cmd, ret); + return ret; +} + +static const struct file_operations vendor_storage_fops = { + .compat_ioctl = vendor_storage_ioctl, + .unlocked_ioctl = vendor_storage_ioctl, +}; + +static struct miscdevice vender_storage_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "vendor_storage", + .fops = &vendor_storage_fops, +}; + +static int vendor_init_thread(void *arg) +{ + int ret; + + pr_info("flash %s!\n", __func__); + ret = flash_vendor_init(); + if (!ret) { + ret = misc_register(&vender_storage_dev); + #ifdef CONFIG_ROCKCHIP_VENDOR_STORAGE + rk_vendor_register(flash_vendor_read, flash_vendor_write); + #endif + } + pr_info("flash vendor storage:20170308 ret = %d\n", ret); + return ret; +} + +static int __init vendor_storage_init(void) +{ + kthread_run(vendor_init_thread, (void *)NULL, "vendor_storage_init"); + return 0; +} + +static __exit void vendor_storage_deinit(void) +{ + if (g_vendor) + misc_deregister(&vender_storage_dev); +} + +device_initcall_sync(vendor_storage_init); +module_exit(vendor_storage_deinit); diff --git a/drivers/soc/rockchip/flash_vendor_storage.h b/drivers/soc/rockchip/flash_vendor_storage.h new file mode 100644 index 000000000000..55ca52486de7 --- /dev/null +++ b/drivers/soc/rockchip/flash_vendor_storage.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ + +/* Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd */ + +#ifndef _FLASH_VENDOR_STORAGE +#define _FLASH_VENDOR_STORAGE + +int 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)); + +#endif + diff --git a/include/uapi/misc/rkflash_vendor_storage.h b/include/uapi/misc/rkflash_vendor_storage.h new file mode 100644 index 000000000000..fc36bedb45bf --- /dev/null +++ b/include/uapi/misc/rkflash_vendor_storage.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ + +/* Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd */ + +#ifndef _RKFLASH_VENDOR_STORAGE +#define _RKFLASH_VENDOR_STORAGE + +struct RK_VENDOR_REQ { + __u32 tag; + __u32 id; + __u32 len; + __u8 data[1024]; +}; + +#define VENDOR_REQ_TAG 0x56524551 +#define VENDOR_READ_IO _IOW('v', 0x01, __u32) +#define VENDOR_WRITE_IO _IOW('v', 0x02, __u32) + +#endif