// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. */ #include "../include/phynand.h" #ifndef AML_NAND_UBOOT #include #include #define CONFIG_ENV_SIZE \ ((get_cpu_type() >= MESON_CPU_MAJOR_ID_M8) ? (64*1024U) : (0x8000U)) #define ENV_NAME "nand_env" static dev_t uboot_env_no; struct cdev uboot_env; struct device *uboot_dev = NULL; struct class *uboot_env_class = NULL; #endif /* AML_NAND_UBOOT */ struct amlnand_chip *aml_chip_env = NULL; int amlnf_env_save(u8 *buf, int len) { u8 *env_buf = NULL; struct nand_flash *flash = &aml_chip_env->flash; int ret = 0; aml_nand_msg("uboot env amlnf_env_save : ####"); if (aml_chip_env == NULL) { aml_nand_msg("uboot env not init yet!,%s", __func__); return -EFAULT; } if (len > CONFIG_ENV_SIZE) { aml_nand_msg("uboot env data len too much,%s", __func__); return -EFAULT; } env_buf = aml_nand_malloc(CONFIG_ENV_SIZE + flash->pagesize); if (env_buf == NULL) { aml_nand_msg("nand malloc for uboot env failed"); ret = -1; goto exit_err; } memset(env_buf, 0, CONFIG_ENV_SIZE); memcpy(env_buf, buf, len); ret = amlnand_save_info_by_name(aml_chip_env, (u8 *)&(aml_chip_env->uboot_env), env_buf, (u8 *)ENV_INFO_HEAD_MAGIC, CONFIG_ENV_SIZE); if (ret) { aml_nand_msg("nand uboot env error,%s", __func__); ret = -EFAULT; goto exit_err; } exit_err: if (env_buf) { /* kfree(env_buf); */ kfree(env_buf); env_buf = NULL; } return ret; } int amlnf_env_read(u8 *buf, int len) { u8 *env_buf = NULL; int ret = 0; //struct nand_flash *flash = &aml_chip_env->flash; aml_nand_msg("uboot env amlnf_env_read : ####"); if (len > CONFIG_ENV_SIZE) { aml_nand_msg("uboot env data len too much,%s", __func__); return -EFAULT; } if (aml_chip_env == NULL) { memset(buf, 0x0, len); aml_nand_msg("uboot env arg_valid = 0 invalid,%s", __func__); return 0; } if (aml_chip_env->uboot_env.arg_valid == 0) { memset(buf, 0x0, len); aml_nand_msg("uboot env arg_valid = 0 invalid,%s", __func__); return 0; } env_buf = aml_nand_malloc(CONFIG_ENV_SIZE); if (env_buf == NULL) { aml_nand_msg("nand malloc for uboot env failed"); ret = -1; goto exit_err; } memset(env_buf, 0, CONFIG_ENV_SIZE); ret = amlnand_read_info_by_name(aml_chip_env, (u8 *)&(aml_chip_env->uboot_env), (u8 *)env_buf, (u8 *)ENV_INFO_HEAD_MAGIC, CONFIG_ENV_SIZE); if (ret) { aml_nand_msg("nand uboot env error,%s", __func__); ret = -EFAULT; goto exit_err; } memcpy(buf, env_buf, len); exit_err: if (env_buf) { /* kfree(env_buf); */ kfree(env_buf); env_buf = NULL; } return ret; } int amlnf_env_erase(void) { int ret = 0; if (aml_chip_env == NULL) { aml_nand_msg("%s amlnf not ready yet!", __func__); return -1; } ret = amlnand_erase_info_by_name(aml_chip_env, (u8 *)&(aml_chip_env->uboot_env), (u8 *)ENV_INFO_HEAD_MAGIC); if (ret) { aml_nand_msg("%s erase key error", __func__); } else { aml_nand_msg("env erase success"); } return ret; } #ifndef AML_NAND_UBOOT ssize_t env_show(struct class *class, struct class_attribute *attr, char *buf) { aml_nand_dbg("env_show : #####"); return 0; } ssize_t env_store(struct class *class, struct class_attribute *attr, const char *buf, size_t count) { int ret = 0; u8 *env_ptr = NULL; aml_nand_dbg("env_store : #####"); env_ptr = kzalloc(CONFIG_ENV_SIZE, GFP_KERNEL); if (env_ptr == NULL) { aml_nand_msg("nand_env_read: nand env malloc buf failed "); return -ENOMEM; } ret = amlnf_env_read(env_ptr, CONFIG_ENV_SIZE); if (ret) { aml_nand_msg("nand_env_read: nand env read failed"); kfree(env_ptr); return -EFAULT; } ret = amlnf_env_save(env_ptr, CONFIG_ENV_SIZE); if (ret) { aml_nand_msg("nand_env_read: nand env read failed"); kfree(env_ptr); return -EFAULT; } aml_nand_dbg("env_store : OK #####"); return count; } static CLASS_ATTR(env, S_IWUSR | S_IRUGO, env_show, env_store); int uboot_env_open(struct inode *node, struct file *file) { return 0; } ssize_t uboot_env_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { u8 *env_ptr = NULL; struct nand_flash *flash = &aml_chip_env->flash; ssize_t read_size = 0; int ret = 0; if (*ppos == CONFIG_ENV_SIZE) return 0; if (*ppos >= CONFIG_ENV_SIZE) { aml_nand_msg("nand env: data access out of space!"); return -EFAULT; } /* env_ptr = kzalloc(CONFIG_ENV_SIZE, GFP_KERNEL); */ env_ptr = vmalloc(CONFIG_ENV_SIZE + flash->pagesize); if (env_ptr == NULL) { aml_nand_msg("nand_env_read: nand env malloc buf failed "); return -ENOMEM; } amlnand_get_device(aml_chip_env, CHIP_READING); ret = amlnf_env_read((u8 *)env_ptr, CONFIG_ENV_SIZE); if (ret) { aml_nand_msg("nand_env_read: nand env read failed:%d", ret); ret = -EFAULT; goto exit; } if ((*ppos + count) > CONFIG_ENV_SIZE) read_size = CONFIG_ENV_SIZE - *ppos; else read_size = count; ret = copy_to_user(buf, (env_ptr + *ppos), read_size); *ppos += read_size; exit: amlnand_release_device(aml_chip_env); /* kfree(env_ptr); */ vfree(env_ptr); return read_size; } ssize_t uboot_env_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { u8 *env_ptr = NULL; ssize_t write_size = 0; struct nand_flash *flash = &aml_chip_env->flash; int ret = 0; if (*ppos == CONFIG_ENV_SIZE) return 0; if (*ppos >= CONFIG_ENV_SIZE) { aml_nand_msg("nand env: data access out of space!"); return -EFAULT; } /* env_ptr = kzalloc(CONFIG_ENV_SIZE, GFP_KERNEL); */ env_ptr = vmalloc(CONFIG_ENV_SIZE + flash->pagesize); if (env_ptr == NULL) { aml_nand_msg("nand_env_read: nand env malloc buf failed "); return -ENOMEM; } amlnand_get_device(aml_chip_env, CHIP_WRITING); ret = amlnf_env_read((u8 *)env_ptr, CONFIG_ENV_SIZE); if (ret) { aml_nand_msg("nand_env_read: nand env read failed"); ret = -EFAULT; goto exit; } if ((*ppos + count) > CONFIG_ENV_SIZE) write_size = CONFIG_ENV_SIZE - *ppos; else write_size = count; ret = copy_from_user((env_ptr + *ppos), buf, write_size); ret = amlnf_env_save(env_ptr, CONFIG_ENV_SIZE); if (ret) { aml_nand_msg("nand_env_read: nand env read failed"); ret = -EFAULT; goto exit; } *ppos += write_size; exit: amlnand_release_device(aml_chip_env); /* kfree(env_ptr); */ vfree(env_ptr); return write_size; } long uboot_env_ioctl(struct file *file, u32 cmd, u32 args) { return 0; } static const struct file_operations uboot_env_ops = { .open = uboot_env_open, .read = uboot_env_read, .write = uboot_env_write, .unlocked_ioctl = uboot_env_ioctl, }; #endif /* AML_NAND_UBOOT */ int aml_ubootenv_init(struct amlnand_chip *aml_chip) { int ret = 0; u8 *env_buf = NULL; aml_chip_env = aml_chip; env_buf = aml_nand_malloc(CONFIG_ENV_SIZE); if (env_buf == NULL) { aml_nand_msg("nand malloc for secure_ptr failed"); ret = -1; goto exit_err; } memset(env_buf, 0x0, CONFIG_ENV_SIZE); ret = amlnand_info_init(aml_chip, (u8 *)&(aml_chip->uboot_env), env_buf, (u8 *)ENV_INFO_HEAD_MAGIC, CONFIG_ENV_SIZE); if (ret < 0) { aml_nand_msg("%s failed\n", __func__); ret = -1; goto exit_err; } /*if(aml_chip->uboot_env.arg_valid == 0){ memset(env_buf,0x0,CONFIG_ENV_SIZE); ret = amlnf_env_save(env_buf,CONFIG_ENV_SIZE); if (ret) { aml_nand_msg("amlnf_env_save: save env failed"); } }*/ #ifndef AML_NAND_UBOOT aml_nand_dbg("%s: register env chardev", __func__); ret = alloc_chrdev_region(&uboot_env_no, 0, 1, ENV_NAME); if (ret < 0) { aml_nand_msg("alloc uboot env dev_t no failed"); ret = -1; goto exit_err; } cdev_init(&uboot_env, &uboot_env_ops); uboot_env.owner = THIS_MODULE; ret = cdev_add(&uboot_env, uboot_env_no, 1); if (ret) { aml_nand_msg("uboot env dev add failed"); ret = -1; goto exit_err1; } uboot_env_class = class_create(THIS_MODULE, ENV_NAME); if (IS_ERR(uboot_env_class)) { aml_nand_msg("uboot env dev add failed"); ret = -1; goto exit_err2; } ret = class_create_file(uboot_env_class, &class_attr_env); if (ret) { aml_nand_msg("uboot env dev add failed"); ret = -1; goto exit_err2; } uboot_dev = device_create(uboot_env_class, NULL, uboot_env_no, NULL, ENV_NAME); if (IS_ERR(uboot_dev)) { aml_nand_msg("uboot env dev add failed"); ret = -1; goto exit_err3; } aml_nand_dbg("%s: register env chardev OK", __func__); kfree(env_buf); env_buf = NULL; return ret; exit_err3: class_remove_file(uboot_env_class, &class_attr_env); class_destroy(uboot_env_class); exit_err2: cdev_del(&uboot_env); exit_err1: unregister_chrdev_region(uboot_env_no, 1); #endif /* AML_NAND_UBOOT */ exit_err: if (env_buf) { kfree(env_buf); env_buf = NULL; } return ret; } /* update env if only it is still readable! */ int aml_nand_update_ubootenv(struct amlnand_chip *aml_chip, char *env_ptr) { int ret = 0; char malloc_flag = 0; char *env_buf = NULL; struct nand_flash *flash = &aml_chip->flash; if (env_buf == NULL) { env_buf = kzalloc(CONFIG_ENV_SIZE + flash->pagesize, GFP_KERNEL); malloc_flag = 1; if (env_buf == NULL) return -ENOMEM; memset(env_buf, 0, CONFIG_ENV_SIZE); ret = amlnand_read_info_by_name(aml_chip, (u8 *)&(aml_chip->uboot_env), (u8 *)env_buf, (u8 *)ENV_INFO_HEAD_MAGIC, CONFIG_ENV_SIZE); if (ret) { aml_nand_msg("read ubootenv error,%s\n", __func__); ret = -EFAULT; goto exit; } } else env_buf = env_ptr; ret = amlnand_save_info_by_name(aml_chip, (u8 *)&(aml_chip->uboot_env), (u8 *)env_buf, (u8 *)ENV_INFO_HEAD_MAGIC, CONFIG_ENV_SIZE); if (ret < 0) aml_nand_msg("aml_nand_update_secure : update secure failed"); exit: if (malloc_flag && (env_buf)) { kfree(env_buf); env_buf = NULL; } return 0; }