efuse: support m8baby
authorYun Cai <yun.cai@amlogic.com>
Mon, 10 Apr 2017 01:55:44 +0000 (09:55 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Fri, 14 Apr 2017 09:11:09 +0000 (02:11 -0700)
PD#141217: initialize m8baby efuse

Change-Id: I1b88e61f952ea0431a635238770a80e221868b64
Signed-off-by: Yun Cai <yun.cai@amlogic.com>
arch/arm/boot/dts/amlogic/meson8b.dtsi
arch/arm/configs/meson32_defconfig
drivers/amlogic/efuse/Makefile
drivers/amlogic/efuse/efuse.c [new file with mode: 0644]
drivers/amlogic/efuse/efuse.h
drivers/amlogic/efuse/efuse64.c
drivers/amlogic/efuse/efuse_hw.c [new file with mode: 0644]
drivers/amlogic/efuse/efuse_regs.h [new file with mode: 0644]
drivers/amlogic/efuse/efuse_version.c [new file with mode: 0644]
include/linux/amlogic/efuse.h

index e205d43..78bcfeb 100644 (file)
@@ -591,6 +591,13 @@ dwc2_b {
                                                "usb0_to_ddr",
                                                "usb0";
        };
+       efuse: efuse{
+               compatible = "amlogic, efuse";
+               reg = <0xda000000 0x14>;
+               clocks = <&clkc CLKID_EFUSE>;
+               clock-names = "efuse_clk";
+               status = "okay";
+       };
 
        aml_tdes {
                compatible = "amlogic,des,tdes";
index 54ac361..f92b68d 100644 (file)
@@ -60,6 +60,7 @@ CONFIG_AMLOGIC_CLK=y
 CONFIG_AMLOGIC_M8B_CLK=y
 CONFIG_AMLOGIC_CRYPTO=y
 CONFIG_AMLOGIC_CRYPTO_BLKMV=y
+CONFIG_AMLOGIC_EFUSE=y
 CONFIG_AMLOGIC_CPU_HOTPLUG=y
 CONFIG_AMLOGIC_PWM=y
 CONFIG_AMLOGIC_INPUT=y
index 8205cf1..05b5b7b 100644 (file)
@@ -2,4 +2,8 @@
 # Makefile for eFuse.
 #
 
+ifneq ($(CONFIG_ARM64),y)
+obj-$(CONFIG_AMLOGIC_EFUSE) += efuse_version.o efuse_hw.o efuse.o
+else
 obj-$(CONFIG_AMLOGIC_EFUSE) += efuse_hw64.o efuse64.o
+endif
\ No newline at end of file
diff --git a/drivers/amlogic/efuse/efuse.c b/drivers/amlogic/efuse/efuse.c
new file mode 100644 (file)
index 0000000..35109c6
--- /dev/null
@@ -0,0 +1,554 @@
+/*
+ * drivers/amlogic/efuse/efuse.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/cdev.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/amlogic/secmon.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include "efuse.h"
+#include "efuse_regs.h"
+
+#define EFUSE_MODULE_NAME   "efuse"
+#define EFUSE_DRIVER_NAME      "efuse"
+#define EFUSE_DEVICE_NAME   "efuse"
+#define EFUSE_CLASS_NAME    "efuse"
+#define EFUSE_IS_OPEN           (0x01)
+
+struct efuse_dev_t {
+       struct cdev cdev;
+       unsigned int flags;
+};
+
+static struct efuse_dev_t *efuse_devp;
+/* static struct class *efuse_clsp; */
+static dev_t efuse_devno;
+void __iomem *efuse_base;
+struct clk *efuse_clk;
+
+static int efuse_open(struct inode *inode, struct file *file)
+{
+       int ret = 0;
+       struct efuse_dev_t *devp;
+
+       devp = container_of(inode->i_cdev, struct efuse_dev_t, cdev);
+       file->private_data = devp;
+
+       return ret;
+}
+
+static int efuse_release(struct inode *inode, struct file *file)
+{
+       int ret = 0;
+       struct efuse_dev_t *devp;
+       unsigned long efuse_status = 0;
+
+       devp = file->private_data;
+       efuse_status &= ~EFUSE_IS_OPEN;
+       return ret;
+}
+
+loff_t efuse_llseek(struct file *filp, loff_t off, int whence)
+{
+       loff_t newpos;
+
+       switch (whence) {
+       case 0: /* SEEK_SET */
+               newpos = off;
+               break;
+
+       case 1: /* SEEK_CUR */
+               newpos = filp->f_pos + off;
+               break;
+
+       case 2: /* SEEK_END */
+               newpos = EFUSE_BYTES + off;
+               break;
+
+       default: /* can't happen */
+               return -EINVAL;
+       }
+
+       if (newpos < 0)
+               return -EINVAL;
+       filp->f_pos = newpos;
+               return newpos;
+}
+
+static long efuse_unlocked_ioctl(struct file *file, unsigned int cmd,
+       unsigned long arg)
+{
+       struct efuseinfo_item_t *info;
+
+       switch (cmd) {
+       case EFUSE_INFO_GET:
+               info = (struct efuseinfo_item_t *)arg;
+               if (efuse_getinfo_byTitle(info->title, info) < 0)
+                       return  -EFAULT;
+               break;
+
+       default:
+               return -ENOTTY;
+       }
+       return 0;
+}
+
+static ssize_t efuse_read(struct file *file, char __user *buf,
+       size_t count, loff_t *ppos)
+{
+       int ret;
+       int local_count = 0;
+       unsigned char *local_buf = kcalloc(count, sizeof(char), GFP_KERNEL);
+
+       if (!local_buf) {
+               /* pr_info("memory not enough\n"); */
+               return -ENOMEM;
+       }
+
+       local_count = efuse_read_item(local_buf, count, ppos);
+       if (local_count < 0) {
+               ret =  -EFAULT;
+               goto error_exit;
+       }
+
+       if (copy_to_user((void *)buf, (void *)local_buf, local_count)) {
+               ret =  -EFAULT;
+               goto error_exit;
+       }
+       ret = local_count;
+
+error_exit:
+       /*if (local_buf)*/
+               kfree(local_buf);
+       return ret;
+}
+
+static ssize_t efuse_write(struct file *file,
+       const char __user *buf, size_t count, loff_t *ppos)
+{
+       unsigned int  pos = (unsigned int)*ppos;
+       int ret, size;
+       unsigned char *contents = NULL;
+
+       if (pos >= EFUSE_BYTES)
+               return 0;       /* Past EOF */
+       if (count > EFUSE_BYTES - pos)
+               count = EFUSE_BYTES - pos;
+       if (count > EFUSE_BYTES)
+               return -EFAULT;
+
+       ret = check_if_efused(pos, count);
+       if (ret) {
+               pr_info("check if has been efused failed\n");
+               if (ret == 1)
+                       return -EROFS;
+               else if (ret < 0)
+                       return ret;
+       }
+
+       contents = kzalloc(sizeof(unsigned char)*EFUSE_BYTES, GFP_KERNEL);
+       if (!contents) {
+               /* pr_info("memory not enough\n"); */
+               return -ENOMEM;
+       }
+       size = sizeof(contents);
+       memset(contents, 0, size);
+       if (copy_from_user(contents, buf, count)) {
+               /*if (contents)*/
+               kfree(contents);
+               return -EFAULT;
+       }
+
+       if (efuse_write_item(contents, count, ppos) < 0) {
+               kfree(contents);
+               return -EFAULT;
+       }
+
+       kfree(contents);
+       return count;
+}
+
+static const struct file_operations efuse_fops = {
+       .owner      = THIS_MODULE,
+       .llseek     = efuse_llseek,
+       .open       = efuse_open,
+       .release    = efuse_release,
+       .read       = efuse_read,
+       .write      = efuse_write,
+       .unlocked_ioctl      = efuse_unlocked_ioctl,
+};
+
+/* Sysfs Files */
+ssize_t efuse_attr_store(char *name, const char *buf, size_t count)
+{
+#ifndef EFUSE_READ_ONLY
+       char *local_buf;
+       ssize_t ret;
+       int i;
+       const unsigned char *s;
+       struct efuseinfo_item_t info;
+       unsigned int uint_val;
+
+       if (efuse_getinfo_byTitle(name, &info) < 0) {
+               pr_err("%s is not found\n", name);
+               return -EFAULT;
+       }
+
+       if (count < info.data_len) {
+               pr_info("%s:item: %s: size: %d too few arguments to store\n",
+                       __func__, name, info.data_len);
+               count = info.data_len + 1;
+       }
+       if (check_if_efused(info.offset, info.data_len)) {
+
+               pr_err("%s error!data_verify failed!\n", __func__);
+               return -1;
+       }
+
+       local_buf = kzalloc(sizeof(char)*(count), GFP_KERNEL);
+
+       memcpy(local_buf, buf, (strlen(buf) < info.data_len)
+               ? strlen(buf):count);
+
+       s = local_buf;
+
+       strim(local_buf);
+
+       /* only support separated with whitespace or colon
+        * eg. A1:B2:C3 or D4 E5 F6 in hexadecimal
+        */
+       if ((strstr(s, ":") != NULL) || (strstr(s, " ") != NULL)) {
+               for (i = 0; i < info.data_len; i++) {
+                       while ((!strncmp(s, ":", 1)) ||
+                               !strncmp(s, " ", 1))
+                       s++;
+                       if (!*s) {
+                               local_buf[i] = 0;
+                               continue;
+                       }
+                               ret = sscanf(s, "%x", &uint_val);
+                               if (ret < 0) {
+                                       pr_err("ERROR: efuse get user data fail!\n");
+                                       goto error_exit;
+                               } else {
+                                       local_buf[i] = uint_val;
+                                       s += 2;
+                               }
+
+                               pr_debug("local_buf[%d]: 0x%x\n",
+                                       i, local_buf[i]);
+                       }
+       } else {/* only support separated with whitespace */
+               for (i = 0; i < info.data_len; i++) {
+                       uint_val = 0;
+                       if (!*s) {
+                               local_buf[i] = 0;
+                               continue;
+                       }
+                       ret = sscanf(s, "%x", &uint_val);
+
+                       if (ret < 0) {
+                               pr_err("ERROR: efuse get user data fail!\n");
+                               goto error_exit;
+                       } else {
+                               local_buf[i] = uint_val;
+                               s += 2;
+                       }
+                       pr_debug("local_buf[%d]: 0x%x\n",
+                               i, local_buf[i]);
+                       }
+       }
+
+       ret = efuse_write_item(local_buf, info.data_len,
+               (loff_t *)&(info.offset));
+       if (ret == -1) {
+               pr_err("ERROR: efuse write user data fail!\n");
+               goto error_exit;
+       }
+       if (ret != info.data_len)
+               pr_err("ERROR: write %zd byte(s) not %d byte(s) data\n",
+                       ret, info.data_len);
+       pr_info("efuse write %zd data OK\n", ret);
+
+error_exit:
+       kfree(local_buf);
+       return ret;
+#else
+       pr_err("no permission to write!!\n");
+       return -1;
+#endif
+}
+
+ssize_t efuse_attr_show(char *name, char *buf)
+{
+       char *local_buf;
+       ssize_t ret;
+       int i;
+       struct efuseinfo_item_t info;
+
+       if (efuse_getinfo_byTitle(name, &info) < 0) {
+               pr_err("%s is not found\n", name);
+               return -EFAULT;
+       }
+
+       local_buf = kzalloc(sizeof(char)*(info.data_len), GFP_KERNEL);
+       memset(local_buf, 0, info.data_len);
+
+       ret = efuse_read_item(local_buf, info.data_len,
+               (loff_t *)&(info.offset));
+       if (ret == -1) {
+               pr_err("ERROR: efuse read user data fail!\n");
+               goto error_exit;
+       }
+       if (ret != info.data_len)
+               pr_err("ERROR: read %zd byte(s) not %d byte(s) data\n",
+                       ret, info.data_len);
+
+       for (i = 0; i < info.data_len; i++)
+               buf[i] = local_buf[i];
+
+error_exit:
+       kfree(local_buf);
+       return ret;
+}
+
+#define  DEFINE_EFUE_SHOW_ATTR(name)   \
+       static ssize_t show_##name(struct class *cla, \
+                                         struct class_attribute *attr, \
+                                               char *buf)      \
+       {       \
+               ssize_t ret;    \
+               int i = 0; \
+               \
+               ret = efuse_attr_show(#name, buf); \
+               if (ret > 0) {\
+               pr_info("efuse read data\n"); \
+               for (; i < ret; i++) \
+                       pr_info("%02x%s", buf[i], ((i+1)%16 == 0)?"\n":":"); \
+               pr_info("\n"); \
+               } \
+               return ret; \
+       }
+
+DEFINE_EFUE_SHOW_ATTR(version)
+DEFINE_EFUE_SHOW_ATTR(mac)
+DEFINE_EFUE_SHOW_ATTR(mac_bt)
+DEFINE_EFUE_SHOW_ATTR(mac_wifi)
+DEFINE_EFUE_SHOW_ATTR(usid)
+
+#define  DEFINE_EFUE_STORE_ATTR(name)  \
+       static ssize_t store_##name(struct class *cla, \
+                                         struct class_attribute *attr, \
+                                               const char *buf,        \
+                                               size_t count)   \
+       {       \
+               ssize_t ret;    \
+               \
+               ret = efuse_attr_store(#name, buf, count); \
+               return ret; \
+       }
+#ifdef CONFIG_AMLOGIC_EFUSE_WRITE_VERSION_PERMIT
+DEFINE_EFUE_STORE_ATTR(version)
+#endif
+//DEFINE_EFUE_STORE_ATTR(mac)
+//DEFINE_EFUE_STORE_ATTR(mac_bt)
+//DEFINE_EFUE_STORE_ATTR(mac_wifi)
+DEFINE_EFUE_STORE_ATTR(usid)
+
+static struct class_attribute efuse_class_attrs[] = {
+#ifdef CONFIG_AMLOGIC_EFUSE_WRITE_VERSION_PERMIT
+       __ATTR(version, 0700, show_version, store_version),
+#else
+       __ATTR(version, 0500, show_version, NULL),
+#endif
+       __ATTR(mac, 0500, show_mac, NULL),
+       __ATTR(mac_bt, 0500, show_mac_bt, NULL),
+       __ATTR(mac_wifi, 0500, show_mac_wifi, NULL),
+       __ATTR(usid, 0700, show_usid, store_usid),
+       __ATTR_NULL
+
+};
+
+static struct class efuse_class = {
+       .name = EFUSE_CLASS_NAME,
+       .class_attrs = efuse_class_attrs,
+};
+
+static int efuse_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct device *devp;
+       struct device_node *np = pdev->dev.of_node;
+
+       ret = alloc_chrdev_region(&efuse_devno, 0, 1, EFUSE_DEVICE_NAME);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "efuse: failed to allocate major number\n");
+               ret = -ENODEV;
+               goto out;
+       }
+
+       ret = class_register(&efuse_class);
+       if (ret)
+               goto error1;
+
+       efuse_devp = kmalloc(sizeof(struct efuse_dev_t), GFP_KERNEL);
+       if (!efuse_devp) {
+               /* dev_err(&pdev->dev, "efuse: failed to allocate memory\n"); */
+               ret = -ENOMEM;
+               goto error2;
+       }
+
+       efuse_base = of_iomap(pdev->dev.of_node, 0);
+       if (!efuse_base) {
+               pr_err("%s: Unable to map efuse base\n", __func__);
+               ret = -ENXIO;
+               goto error3;
+       }
+       /* connect the file operations with cdev */
+       cdev_init(&efuse_devp->cdev, &efuse_fops);
+       efuse_devp->cdev.owner = THIS_MODULE;
+       /* connect the major/minor number to the cdev */
+       ret = cdev_add(&efuse_devp->cdev, efuse_devno, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "efuse: failed to add device\n");
+               goto error4;
+       }
+
+       devp = device_create(&efuse_class, NULL, efuse_devno, NULL, "efuse");
+       if (IS_ERR(devp)) {
+               dev_err(&pdev->dev, "efuse: failed to create device node\n");
+               ret = PTR_ERR(devp);
+               goto error5;
+       }
+       dev_dbg(&pdev->dev, "device %s created\n", EFUSE_DEVICE_NAME);
+
+       if (pdev->dev.of_node) {
+               of_node_get(np);
+#if 0
+               ret = of_property_read_u32(np, "plat-pos", &pos);
+               if (ret) {
+                       dev_err(&pdev->dev, "please config plat-pos item\n");
+                       return -1;
+               }
+               ret = of_property_read_u32(np, "plat-count", &count);
+               if (ret) {
+                       dev_err(&pdev->dev, "please config plat-count item\n");
+                       return -1;
+               }
+               ret = of_property_read_u32(np, "usid-min", &usid_min);
+               if (ret) {
+                       dev_err(&pdev->dev, "please config usid-min item\n");
+                       return -1;
+               }
+               ret = of_property_read_u32(np, "usid-max", &usid_max);
+               if (ret) {
+                       dev_err(&pdev->dev, "please config usid-max item\n");
+                       return -1;
+               }
+#endif
+               /* todo reserved for user id <usid-min ~ usid max> */
+       }
+       /* open clk gate HHI_GCLK_MPEG0 bit62*/
+       efuse_clk = devm_clk_get(&pdev->dev, "efuse_clk");
+       if (IS_ERR(efuse_clk))
+               dev_err(&pdev->dev, " open efuse clk gate error!!\n");
+       else{
+               ret = clk_prepare_enable(efuse_clk);
+               if (ret)
+                       dev_err(&pdev->dev, "enable efuse clk gate error!!\n");
+       }
+
+       dev_info(&pdev->dev, "probe ok!\n");
+       return 0;
+
+error5:
+       cdev_del(&efuse_devp->cdev);
+error4:
+       kfree(efuse_devp);
+error3:
+       iounmap(efuse_base);
+error2:
+       /* class_destroy(efuse_clsp); */
+       class_unregister(&efuse_class);
+error1:
+       unregister_chrdev_region(efuse_devno, 1);
+out:
+       return ret;
+}
+
+static int efuse_remove(struct platform_device *pdev)
+{
+       unregister_chrdev_region(efuse_devno, 1);
+       /* device_destroy(efuse_clsp, efuse_devno); */
+       device_destroy(&efuse_class, efuse_devno);
+       cdev_del(&efuse_devp->cdev);
+       kfree(efuse_devp);
+       iounmap(efuse_base);
+       /* class_destroy(efuse_clsp); */
+       class_unregister(&efuse_class);
+       return 0;
+}
+
+static const struct of_device_id amlogic_efuse_dt_match[] = {
+       {       .compatible = "amlogic, efuse",
+       },
+       {},
+};
+
+static struct platform_driver efuse_driver = {
+       .probe = efuse_probe,
+       .remove = efuse_remove,
+       .driver = {
+               .name = EFUSE_DEVICE_NAME,
+               .of_match_table = amlogic_efuse_dt_match,
+       .owner = THIS_MODULE,
+       },
+};
+
+static int __init efuse_init(void)
+{
+       int ret = -1;
+
+       ret = platform_driver_register(&efuse_driver);
+       if (ret != 0) {
+               pr_err("failed to register efuse driver, error %d\n", ret);
+               return -ENODEV;
+       }
+
+       return ret;
+}
+
+static void __exit efuse_exit(void)
+{
+       platform_driver_unregister(&efuse_driver);
+}
+
+module_init(efuse_init);
+module_exit(efuse_exit);
+
+MODULE_DESCRIPTION("AMLOGIC eFuse driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yun Cai <yun.cai@amlogic.com>");
index cde6466..acd5378 100644 (file)
@@ -18,6 +18,7 @@
 #ifndef __EFUSE_H
 #define __EFUSE_H
 
+/* #define EFUSE_DEBUG */
 /*#define EFUSE_READ_ONLY                      1*/
 
 /* #define EFUSE_NONE_ID                       0 */
@@ -39,7 +40,7 @@
 
 #define EFUSE_BYTES            512  /* (EFUSE_BITS/8) */
 
-#define EFUSE_INFO_GET                         _IO('f', 0x40)
+#define EFUSE_INFO_GET                 _IO('f', 0x40)
 
 #define EFUSE_HAL_API_READ     0
 #define EFUSE_HAL_API_WRITE 1
@@ -59,10 +60,7 @@ struct efuseinfo_item_t {
        char title[40];
        unsigned int id;
        loff_t offset;    /* write offset */
-       unsigned int enc_len;
        unsigned int data_len;
-       int bch_en;
-       int bch_reverse;
 };
 
 struct efuseinfo_t {
@@ -88,10 +86,12 @@ struct efuse_hal_api_arg {
 
 extern struct efuseinfo_t efuseinfo[];
 #ifndef CONFIG_ARM64
-int efuse_getinfo_byID(unsigned int id, struct efuseinfo_item_t *info);
+int efuse_getinfo_byTitle(unsigned char *name, struct efuseinfo_item_t *info);
 int check_if_efused(loff_t pos, size_t count);
 int efuse_read_item(char *buf, size_t count, loff_t *ppos);
 int efuse_write_item(char *buf, size_t count, loff_t *ppos);
+extern int efuse_active_version;
+extern struct clk *efuse_clk;
 #else
 
 ssize_t efuse_get_max(void);
index 5cf6eb1..1b8cd90 100644 (file)
@@ -309,7 +309,7 @@ ssize_t efuse_user_attr_store(char *name, const char *buf, size_t count)
        if (strstr(s, c) != NULL) {
                for (i = 0; i < info.size; i++) {
                        uint_val = 0;
-                       ret = kstrtouint(s, 0, &uint_val);
+                       ret = sscanf(s, "%x", &uint_val);
                        if (ret < 0) {
                                pr_err("ERROR: efuse get user data fail!\n");
                                goto error_exit;
diff --git a/drivers/amlogic/efuse/efuse_hw.c b/drivers/amlogic/efuse/efuse_hw.c
new file mode 100644 (file)
index 0000000..6e5884b
--- /dev/null
@@ -0,0 +1,786 @@
+/*
+ * drivers/amlogic/efuse/efuse_hw.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/cdev.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/iomap.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#ifndef CONFIG_ARM64
+#include <asm/opcodes-sec.h>
+#endif
+#include <linux/amlogic/efuse.h>
+#include "efuse_regs.h"
+#include "efuse.h"
+int efuse_active_version = -1;
+
+#ifdef EFUSE_DEBUG
+
+static unsigned long efuse_test_buf_32[EFUSE_DWORDS] = {0};
+static unsigned char *efuse_test_buf_8 = (unsigned char *)efuse_test_buf_32;
+
+static void __efuse_write_byte_debug(unsigned long addr, unsigned char data)
+{
+       efuse_test_buf_8[addr] = data;
+}
+
+static void __efuse_read_dword_debug(unsigned long addr, unsigned long *data)
+{
+       *data = efuse_test_buf_32[addr >> 2];
+}
+#endif
+
+/* to do meson_efuse_fn_smc */
+
+int meson_trustzone_efuse(struct efuse_hal_api_arg *arg)
+{
+       int ret;
+
+       if (!arg)
+               return -1;
+
+       set_cpus_allowed_ptr(current, cpumask_of(0));
+       //ret = meson_efuse_fn_smc(arg);
+       set_cpus_allowed_ptr(current, cpu_all_mask);
+       return ret;
+}
+
+#ifndef CONFIG_MESON_TRUSTZONE
+#ifndef EFUSE_DEBUG
+static void __efuse_write_byte(unsigned long addr, unsigned long data)
+{
+       unsigned long auto_wr_is_enabled = 0;
+       /* cpu after M8 */
+       unsigned int byte_sel;
+
+       clk_prepare_enable(efuse_clk);
+       //set efuse PD=0
+       aml_set_reg32_bits(P_EFUSE_CNTL1, 0, 27, 1);
+
+       if (readl((void *) P_EFUSE_CNTL1) & (1 << CNTL1_AUTO_WR_ENABLE_BIT)) {
+               auto_wr_is_enabled = 1;
+       } else {
+               /* temporarily enable Write mode */
+               aml_set_reg32_bits(P_EFUSE_CNTL1, CNTL1_AUTO_WR_ENABLE_ON,
+               CNTL1_AUTO_WR_ENABLE_BIT, CNTL1_AUTO_WR_ENABLE_SIZE);
+       }
+
+  /* cpu after M8 */
+       byte_sel = addr % 4;
+       addr = addr / 4;
+
+       /* write the address */
+       aml_set_reg32_bits(P_EFUSE_CNTL1, addr,
+                       CNTL1_BYTE_ADDR_BIT, CNTL1_BYTE_ADDR_SIZE);
+
+       //auto write byte select (0-3), for m8
+       aml_set_reg32_bits(P_EFUSE_CNTL3, byte_sel,
+       CNTL1_AUTO_WR_START_BIT, 2);
+
+       /* set starting byte address */
+       aml_set_reg32_bits(P_EFUSE_CNTL1, CNTL1_BYTE_ADDR_SET_ON,
+                       CNTL1_BYTE_ADDR_SET_BIT, CNTL1_BYTE_ADDR_SET_SIZE);
+       aml_set_reg32_bits(P_EFUSE_CNTL1, CNTL1_BYTE_ADDR_SET_OFF,
+                       CNTL1_BYTE_ADDR_SET_BIT, CNTL1_BYTE_ADDR_SET_SIZE);
+
+       /* write the byte */
+       aml_set_reg32_bits(P_EFUSE_CNTL1, data,
+                       CNTL1_BYTE_WR_DATA_BIT, CNTL1_BYTE_WR_DATA_SIZE);
+       /* start the write process */
+       aml_set_reg32_bits(P_EFUSE_CNTL1, CNTL1_AUTO_WR_START_ON,
+                       CNTL1_AUTO_WR_START_BIT, CNTL1_AUTO_WR_START_SIZE);
+       aml_set_reg32_bits(P_EFUSE_CNTL1, CNTL1_AUTO_WR_START_OFF,
+                       CNTL1_AUTO_WR_START_BIT, CNTL1_AUTO_WR_START_SIZE);
+       /* dummy read */
+       readl((void *) P_EFUSE_CNTL1);
+
+       while (readl((void *)P_EFUSE_CNTL1) & (1 << CNTL1_AUTO_WR_BUSY_BIT))
+               udelay(1);
+
+       /* if auto write wasn't enabled and we enabled it,
+        * then disable it upon exit
+        */
+       if (auto_wr_is_enabled == 0) {
+               aml_set_reg32_bits(P_EFUSE_CNTL1, CNTL1_AUTO_WR_ENABLE_OFF,
+           CNTL1_AUTO_WR_ENABLE_BIT, CNTL1_AUTO_WR_ENABLE_SIZE);
+       }
+
+       //set efuse PD=1
+       aml_set_reg32_bits(P_EFUSE_CNTL1, 1, 27, 1);
+       clk_disable_unprepare(efuse_clk);
+
+       pr_debug("__efuse_write_byte: addr=0x%lx, data=0x%lx\n", addr, data);
+}
+
+static void __efuse_read_dword(unsigned long addr, unsigned long *data)
+{
+       //unsigned long auto_rd_is_enabled = 0;
+
+
+       //if( aml_read_reg32(EFUSE_CNTL1) & ( 1 << CNTL1_AUTO_RD_ENABLE_BIT ) ){
+       //      auto_rd_is_enabled = 1;
+       //} else {
+               /* temporarily enable Read mode */
+       //aml_set_reg32_bits( P_EFUSE_CNTL1, CNTL1_AUTO_RD_ENABLE_ON,
+       //      CNTL1_AUTO_RD_ENABLE_BIT, CNTL1_AUTO_RD_ENABLE_SIZE );
+       //}
+
+       //set efuse PD=0
+       aml_set_reg32_bits(P_EFUSE_CNTL1, 0, 27, 1);
+
+       /* cpu after M8 */
+       addr = addr / 4;        //each address have 4 bytes in m8
+
+       /* write the address */
+       aml_set_reg32_bits(P_EFUSE_CNTL1, addr,
+                       CNTL1_BYTE_ADDR_BIT,  CNTL1_BYTE_ADDR_SIZE);
+       /* set starting byte address */
+       aml_set_reg32_bits(P_EFUSE_CNTL1, CNTL1_BYTE_ADDR_SET_ON,
+                       CNTL1_BYTE_ADDR_SET_BIT, CNTL1_BYTE_ADDR_SET_SIZE);
+       aml_set_reg32_bits(P_EFUSE_CNTL1, CNTL1_BYTE_ADDR_SET_OFF,
+                       CNTL1_BYTE_ADDR_SET_BIT, CNTL1_BYTE_ADDR_SET_SIZE);
+
+       /* start the read process */
+       aml_set_reg32_bits(P_EFUSE_CNTL1, CNTL1_AUTO_WR_START_ON,
+                       CNTL1_AUTO_RD_START_BIT, CNTL1_AUTO_RD_START_SIZE);
+       aml_set_reg32_bits(P_EFUSE_CNTL1, CNTL1_AUTO_WR_START_OFF,
+                       CNTL1_AUTO_RD_START_BIT, CNTL1_AUTO_RD_START_SIZE);
+       /* dummy read */
+       readl((void *)P_EFUSE_CNTL1);
+
+       while (readl((void *)P_EFUSE_CNTL1) & (1 << CNTL1_AUTO_RD_BUSY_BIT))
+               udelay(1);
+
+       /* read the 32-bits value */
+       (*data) = readl((void *)P_EFUSE_CNTL2);
+
+       //set efuse PD=1
+       aml_set_reg32_bits(P_EFUSE_CNTL1, 1, 27, 1);
+       /* if auto read wasn't enabled and we enabled it,
+        * then disable it upon exit
+        */
+       //if ( auto_rd_is_enabled == 0 ){
+               //aml_set_reg32_bits( P_EFUSE_CNTL1, CNTL1_AUTO_RD_ENABLE_OFF,
+               //      CNTL1_AUTO_RD_ENABLE_BIT, CNTL1_AUTO_RD_ENABLE_SIZE );
+       //}
+
+       pr_debug("__efuse_read_dword: addr=%ld, data=0x%lx\n", addr, *data);
+}
+#endif
+#endif
+static ssize_t __efuse_read(char *buf, size_t count, loff_t *ppos)
+{
+       unsigned long *contents = kzalloc(sizeof(unsigned long)*EFUSE_DWORDS,
+               GFP_KERNEL);
+       unsigned int pos = *ppos;
+#ifndef CONFIG_MESON_TRUSTZONE
+       unsigned long *pdw;
+       char *tmp_p;
+       /*pos may not align to 4*/
+       unsigned int dwsize = (count + 3 +  pos%4) >> 2;
+#else
+       struct efuse_hal_api_arg arg;
+       unsigned long retcnt;
+       int ret;
+#endif
+       if (!contents) {
+               pr_info("memory not enough\n");
+               return -ENOMEM;
+       }
+
+       if (pos >= EFUSE_BYTES)
+               return 0;
+
+       if (count > EFUSE_BYTES - pos)
+               count = EFUSE_BYTES - pos;
+       if (count > EFUSE_BYTES)
+               return -EFAULT;
+
+#ifndef CONFIG_MESON_TRUSTZONE
+       clk_prepare_enable(efuse_clk);
+       aml_set_reg32_bits(P_EFUSE_CNTL1, CNTL1_AUTO_RD_ENABLE_ON,
+               CNTL1_AUTO_RD_ENABLE_BIT, CNTL1_AUTO_RD_ENABLE_SIZE);
+
+       for (pdw = contents + pos/4;
+               dwsize-- > 0 && pos < EFUSE_BYTES;
+               pos += 4, ++pdw) {
+               #ifdef EFUSE_DEBUG
+               __efuse_read_dword_debug(pos, pdw);
+               #else
+               /* if pos does not align to 4,  __efuse_read_dword
+                * read from next dword, so, discount this un-aligned
+                * partition
+                */
+               __efuse_read_dword((pos - pos%4), pdw);
+               #endif
+       }
+
+       aml_set_reg32_bits(P_EFUSE_CNTL1, CNTL1_AUTO_RD_ENABLE_OFF,
+                       CNTL1_AUTO_RD_ENABLE_BIT, CNTL1_AUTO_RD_ENABLE_SIZE);
+
+       clk_disable_unprepare(efuse_clk);
+       tmp_p = (char *)contents;
+       tmp_p += *ppos;
+
+       memcpy(buf, tmp_p, count);
+
+       *ppos += count;
+#else
+       arg.cmd = EFUSE_HAL_API_READ;
+       arg.offset = pos;
+       arg.size = count;
+       arg.buffer = (unsigned long)contents;
+       arg.retcnt = (unsigned long)(&retcnt);
+       ret = meson_trustzone_efuse(&arg);
+
+       if (ret == 0) {
+               count = retcnt;
+               *ppos += retcnt;
+               memcpy(buf, contents, retcnt);
+       } else
+               count = 0;
+#endif /* CONFIG_MESON_TRUSTZONE */
+
+       /*if (contents)*/
+               kfree(contents);
+       return count;
+}
+
+static ssize_t __efuse_write(const char *buf, size_t count, loff_t *ppos)
+{
+       unsigned int pos = *ppos;
+#ifndef CONFIG_MESON_TRUSTZONE
+       unsigned char *pc;
+#else
+       struct efuse_hal_api_arg arg;
+       unsigned int retcnt;
+       int ret;
+#endif
+
+       if (pos >= EFUSE_BYTES)
+               return 0;       /* Past EOF */
+       if (count > EFUSE_BYTES - pos)
+               count = EFUSE_BYTES - pos;
+       if (count > EFUSE_BYTES)
+               return -EFAULT;
+
+#ifndef CONFIG_MESON_TRUSTZONE
+       for (pc = (char *)buf; count--; ++pos, ++pc)
+       #ifdef EFUSE_DEBUG
+               __efuse_write_byte_debug(pos, *pc);
+       #else
+               __efuse_write_byte(pos, *pc);
+       #endif
+
+       *ppos = pos;
+       return (const char *)pc - buf;
+#else
+       arg.cmd = EFUSE_HAL_API_WRITE;
+       arg.offset = pos;
+       arg.size = count;
+       arg.buffer = (unsigned long)buf;
+       arg.retcnt = (unsigned long)(&retcnt);
+       ret = meson_trustzone_efuse(&arg);
+       if (ret == 0) {
+               *ppos = pos+retcnt;
+               return retcnt;
+       } else
+               return 0;
+#endif
+}
+
+ssize_t aml__efuse_read(char *buf, size_t count, loff_t *ppos)
+{
+       return __efuse_read(buf, count, ppos);
+}
+ssize_t aml__efuse_write(const char *buf, size_t count, loff_t *ppos)
+{
+       return __efuse_write(buf, count, ppos);
+}
+
+/* ================================================ */
+
+/* #define SOC_CHIP_TYPE_TEST */
+#ifdef SOC_CHIP_TYPE_TEST
+static char *soc_chip[] = {
+       {"efuse soc chip m8baby"},
+       {"efuse soc chip unknown"},
+};
+#endif
+
+struct efuse_chip_identify_t {
+       unsigned int chiphw_mver;
+       unsigned int chiphw_subver;
+       unsigned int chiphw_thirdver;
+       enum efuse_socchip_type_e type;
+};
+static const struct efuse_chip_identify_t efuse_chip_hw_info[] = {
+       {
+               .chiphw_mver = 27,
+               .chiphw_subver = 0,
+               .chiphw_thirdver = 0,
+               .type = EFUSE_SOC_CHIP_M8BABY
+       },
+};
+#define EFUSE_CHIP_HW_INFO_NUM  (sizeof(efuse_chip_hw_info)/ \
+       sizeof(efuse_chip_hw_info[0]))
+
+
+enum efuse_socchip_type_e efuse_get_socchip_type(void)
+{
+       enum efuse_socchip_type_e type;
+       unsigned int regval;
+       int i;
+       struct efuse_chip_identify_t *pinfo =
+               (struct efuse_chip_identify_t *)&efuse_chip_hw_info[0];
+       type = EFUSE_SOC_CHIP_UNKNOWN;
+               regval = aml_read_cbus(ASSIST_HW_REV);
+               /* pr_info("chip ASSIST_HW_REV reg:%d\n",regval); */
+               for (i = 0; i < EFUSE_CHIP_HW_INFO_NUM; i++) {
+                       if (pinfo->chiphw_mver == regval) {
+                               type = pinfo->type;
+                               break;
+                       }
+                       pinfo++;
+               }
+
+#ifdef SOC_CHIP_TYPE_TEST
+       pr_info("%s\n", soc_chip[type]);
+#endif
+       return type;
+}
+
+static int efuse_checkversion(char *buf)
+{
+       enum efuse_socchip_type_e soc_type;
+       int i;
+       int ver = buf[0];
+
+       for (i = 0; i < efuseinfo_num; i++) {
+               if (efuseinfo[i].version == ver) {
+                       soc_type = efuse_get_socchip_type();
+                       switch (soc_type) {
+                       case EFUSE_SOC_CHIP_M8BABY:
+                               if (ver != M8_EFUSE_VERSION_SERIALNUM_V1)
+                                       ver = -1;
+                               break;
+                       case EFUSE_SOC_CHIP_UNKNOWN:
+                       default:
+                               pr_info("%s:%d soc is unknown\n",
+                                       __func__, __LINE__);
+                               ver = -1;
+                               break;
+                       }
+                       return ver;
+               }
+       }
+
+       return -1;
+}
+
+
+static int efuse_set_versioninfo(struct efuseinfo_item_t *info)
+{
+       int ret =  -1;
+       enum efuse_socchip_type_e soc_type;
+
+       strcpy(info->title, "version");
+       info->id = EFUSE_VERSION_ID;
+       soc_type = efuse_get_socchip_type();
+       switch (soc_type) {
+       case EFUSE_SOC_CHIP_M8BABY:
+               info->offset = M8_EFUSE_VERSION_OFFSET; /* 509 */
+               info->data_len = M8_EFUSE_VERSION_DATA_LEN;
+               ret = 0;
+               break;
+       case EFUSE_SOC_CHIP_UNKNOWN:
+       default:
+               pr_info("%s:%d chip is unknown, use default M8 chip\n",
+                        __func__, __LINE__);
+               info->offset = M8_EFUSE_VERSION_OFFSET; /* 509 */
+               info->data_len = M8_EFUSE_VERSION_DATA_LEN;
+               ret = 0;
+               break;
+               break;
+       }
+
+       return ret;
+}
+
+
+static int efuse_readversion(void)
+{
+       char ver_buf[4], buf[4];
+       struct efuseinfo_item_t info;
+       int ret;
+
+       if (efuse_active_version != -1)
+               return efuse_active_version;
+
+       ret = efuse_set_versioninfo(&info);
+       if (ret < 0)
+               return ret;
+
+       memset(ver_buf, 0, sizeof(ver_buf));
+       memset(buf, 0, sizeof(buf));
+       __efuse_read(buf, info.data_len, &info.offset);
+       memcpy(ver_buf, buf, sizeof(buf));
+       ret = efuse_checkversion(ver_buf);   /* m3,m6,m8 */
+       if ((ret > 0) && (ver_buf[0] != 0)) {
+               efuse_active_version = ver_buf[0];
+               return ver_buf[0];  /* version right */
+       } else
+               return -1; /* version err */
+}
+
+static int efuse_getinfo_byPOS(unsigned int pos, struct efuseinfo_item_t *info)
+{
+       int ver;
+       int i;
+       struct efuseinfo_t *vx = NULL;
+       struct efuseinfo_item_t *item = NULL;
+       int size;
+       int ret = -1;
+       enum efuse_socchip_type_e soc_type;
+
+       unsigned int versionPOS;
+
+       soc_type = efuse_get_socchip_type();
+       switch (soc_type) {
+       case EFUSE_SOC_CHIP_M8BABY:
+               versionPOS = M8_EFUSE_VERSION_OFFSET; /* 509 */
+               break;
+
+       case EFUSE_SOC_CHIP_UNKNOWN:
+       default:
+               pr_info("%s:%d chip is unknown\n", __func__, __LINE__);
+               return -1;
+               /* break; */
+       }
+
+       if (pos == versionPOS) {
+               ret = efuse_set_versioninfo(info);
+               return ret;
+       }
+
+       ver = efuse_readversion();
+               if (ver < 0) {
+                       pr_info("efuse version is not selected.\n");
+                       return -1;
+               }
+
+               for (i = 0; i < efuseinfo_num; i++) {
+                       if (efuseinfo[i].version == ver) {
+                               vx = &(efuseinfo[i]);
+                               break;
+                       }
+               }
+               if (!vx) {
+                       pr_info("efuse version %d is not supported.\n", ver);
+                       return -1;
+               }
+
+               item = vx->efuseinfo_version;
+               size = vx->size;
+               ret = -1;
+               for (i = 0; i < size; i++, item++) {
+                       if (pos == item->offset) {
+                               strcpy(info->title, item->title);
+                               info->offset = item->offset;
+                               info->id = item->id;
+                               info->data_len = item->data_len;
+                                       /* /what's up ? typo error? */
+                               ret = 0;
+                               break;
+                       }
+               }
+
+               if (ret < 0)
+                       pr_info("POS:%d is not found.\n", pos);
+
+               return ret;
+}
+
+/* ================================================ */
+/* public interface */
+/* ================================================ */
+
+int efuse_getinfo_byTitle(unsigned char *title, struct efuseinfo_item_t *info)
+{
+       int ver;
+       int i;
+       struct efuseinfo_t *vx = NULL;
+       struct efuseinfo_item_t *item = NULL;
+       int size;
+       int ret = -1;
+
+       if (!strcmp(title, "version")) {
+               ret = efuse_set_versioninfo(info);
+               return ret;
+       }
+
+       ver = efuse_readversion();
+       if (ver < 0) {
+               pr_info("efuse version is not selected.\n");
+               return -1;
+       }
+
+       for (i = 0; i < efuseinfo_num; i++) {
+               if (efuseinfo[i].version == ver) {
+                       vx = &(efuseinfo[i]);
+                       break;
+               }
+       }
+       if (!vx) {
+               pr_info("efuse version %d is not supported.\n", ver);
+               return -1;
+       }
+
+               item = vx->efuseinfo_version;
+               size = vx->size;
+               ret = -1;
+               for (i = 0; i < size; i++, item++) {
+                       if (!strcmp(title, item->title)) {
+                               info->id = item->id;
+                               strcpy(info->title, item->title);
+                               info->offset = item->offset;
+                               info->id = item->id;
+                               info->data_len = item->data_len;
+                               ret = 0;
+                               break;
+                       }
+               }
+
+               if (ret < 0)
+                       pr_info("title: %s is not found.\n", title);
+
+               return ret;
+}
+
+
+int check_if_efused(loff_t pos, size_t count)
+{
+       loff_t local_pos = pos;
+       int i;
+       unsigned char *buf = NULL;
+       struct efuseinfo_item_t info;
+
+       if (efuse_getinfo_byPOS(pos, &info) < 0) {
+               pr_info("not found the position:%lld.\n", pos);
+               return -1;
+       }
+       if (count > info.data_len) {
+               pr_info("data length: %zd is out of EFUSE layout!\n", count);
+               return -1;
+       }
+       if (count == 0) {
+               pr_info("data length: 0 is error!\n");
+               return -1;
+       }
+
+       buf = kcalloc(info.data_len, sizeof(char), GFP_KERNEL);
+       if (buf) {
+               if (__efuse_read(buf, info.data_len, &local_pos)
+                       == info.data_len) {
+                       for (i = 0; i < info.data_len; i++) {
+                               if (buf[i]) {
+                                       pr_info("pos %zd value is %d",
+                                               (size_t)(pos + i), buf[i]);
+                                       return 1;
+                               }
+                       }
+               }
+       } else {
+               pr_info("no memory\n");
+               return -ENOMEM;
+       }
+
+       kfree(buf);
+       buf = NULL;
+       return 0;
+}
+
+int efuse_read_item(char *buf, size_t count, loff_t *ppos)
+{
+       char *data_buf = NULL;
+       char *pdata = NULL;
+
+       unsigned int pos = (unsigned int)*ppos;
+       struct efuseinfo_item_t info;
+
+       if (efuse_getinfo_byPOS(pos, &info) < 0) {
+               pr_info("not found the position:%d.\n", pos);
+               return -1;
+       }
+
+       if (count > info.data_len) {
+               pr_info("data length: %zd is out of EFUSE layout!\n", count);
+               return -1;
+       }
+       if (count == 0) {
+               pr_info("data length: 0 is error!\n");
+               return -1;
+       }
+
+       data_buf = kzalloc(sizeof(char)*EFUSE_BYTES, GFP_KERNEL);
+       if (!data_buf) {
+               /* pr_info("memory not enough\n");*/
+               return -ENOMEM;
+       }
+
+       pdata = data_buf;
+       __efuse_read(pdata, info.data_len, ppos);
+
+       memcpy(buf, data_buf, count);
+
+       /*if (data_buf)*/
+               kfree(data_buf);
+       return count;
+}
+
+int efuse_write_item(char *buf, size_t count, loff_t *ppos)
+{
+
+       char *data_buf = NULL;
+       char *pdata = NULL;
+       unsigned int data_len;
+
+       unsigned int pos = (unsigned int)*ppos;
+       struct efuseinfo_item_t info;
+
+       if (efuse_getinfo_byPOS(pos, &info) < 0) {
+               pr_info("not found the position:%d.\n", pos);
+               return -1;
+       }
+#ifndef CONFIG_AMLOGIC_EFUSE_WRITE_VERSION_PERMIT
+       if (strcmp(info.title, "version") == 0) {
+               pr_info("prohibit write version in kernel\n");
+               return 0;
+       }
+#endif
+
+       if (count > info.data_len) {
+               pr_info("data length: %zd is out of EFUSE layout!\n", count);
+               return -1;
+       }
+       if (count == 0) {
+               pr_info("data length: 0 is error!\n");
+               return -1;
+       }
+
+       data_buf = kzalloc(sizeof(char)*EFUSE_BYTES, GFP_KERNEL);
+       if (!data_buf) {
+               /* pr_info("memory not enough\n");*/
+               return -ENOMEM;
+       }
+
+       memcpy(data_buf, buf, count);
+
+       pdata = data_buf;
+
+       data_len = info.data_len;
+
+       __efuse_write(data_buf, data_len, ppos);
+
+       kfree(data_buf);
+
+       return data_len;
+}
+
+/* function: efuse_read_intlItem
+ * intl_item: item name,name is [temperature,cvbs_trimming,temper_cvbs]
+ *            [temperature: 2byte]
+ *            [cvbs_trimming: 2byte]
+ *            [temper_cvbs: 4byte]
+ * buf:  output para
+ * size: buf size
+ * return: <0 fail, >=0 ok
+ */
+int efuse_read_intlItem(char *intl_item, char *buf, int size)
+{
+       enum efuse_socchip_type_e soc_type;
+       loff_t pos;
+       int len;
+       int ret =  -1;
+
+       soc_type = efuse_get_socchip_type();
+       switch (soc_type) {
+       case EFUSE_SOC_CHIP_M8BABY:
+               if (strcasecmp(intl_item, "temperature") == 0) {
+                       pos = 502;
+                       len = 2;
+                       if (size <= 0) {
+                               pr_err("%s input size:%d is error\n",
+                               intl_item, size);
+                               return -1;
+                       }
+                       if (len > size)
+                               len = size;
+
+                       ret = __efuse_read(buf, len, &pos);
+                       return ret;
+               }
+               if (strcasecmp(intl_item, "cvbs_trimming") == 0) {
+     /* cvbs note:
+      * cvbs has 2 bytes, position is 504 and 505,
+      * 504 is low byte,505 is high byte
+      * p504[bit2~0] is cvbs trimming CDAC_GSW<2:0>
+      * p505[bit7-6] : 10--wrote cvbs,
+      * 00-- not wrote cvbs
+      */
+                       pos = 504;
+                       len = 2;
+                       if (size <= 0) {
+                               pr_err("%s input size:%d is error\n",
+                                       intl_item, size);
+                               return -1;
+                       }
+                       if (len > size) {
+                               len = size;
+                               ret = __efuse_read(buf, len, &pos);
+                               return ret;
+                       }
+               }
+                       if (strcasecmp(intl_item, "temper_cvbs") == 0) {
+                               pos = 502;
+                               len = 4;
+                               if (size <= 0) {
+                                       pr_err("%s input size:%d is error\n",
+                                               intl_item, size);
+                                       return -1;
+                               }
+                               if (len > size)
+                                       len = size;
+                               ret = __efuse_read(buf, len, &pos);
+                               return ret;
+                       }
+                       break;
+       case EFUSE_SOC_CHIP_UNKNOWN:
+       default:
+               pr_err("%s:%d chip is unknown\n", __func__, __LINE__);
+               //return -1;
+               break;
+       }
+       return ret;
+}
diff --git a/drivers/amlogic/efuse/efuse_regs.h b/drivers/amlogic/efuse/efuse_regs.h
new file mode 100644 (file)
index 0000000..12e3ba6
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * drivers/amlogic/efuse/efuse_regs.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __EFUSE_REG_H
+#define __EFUSE_REG_H
+
+#include <linux/io.h>
+
+#define        M8_EFUSE_VERSION_OFFSET                 509
+#define        M8_EFUSE_VERSION_DATA_LEN               1
+#define M8_EFUSE_VERSION_SERIALNUM_V1  20
+
+enum efuse_socchip_type_e {
+       EFUSE_SOC_CHIP_M8BABY = 1,
+       EFUSE_SOC_CHIP_UNKNOWN,
+};
+
+extern void __iomem *efuse_base;
+
+#define P_EFUSE_CNTL0 (unsigned int)(efuse_base + 0x4*0)
+#define P_EFUSE_CNTL1 (unsigned int)(efuse_base + 0x4*1)
+#define P_EFUSE_CNTL2 (unsigned int)(efuse_base + 0x4*2)
+#define P_EFUSE_CNTL3 (unsigned int)(efuse_base + 0x4*3)
+#define P_EFUSE_CNTL4 (unsigned int)(efuse_base + 0x4*4)
+
+/* efuse register define*/
+/* EFUSE_CNTL0 */
+
+/*
+ * EFUSE_CNTL1
+ * bit[31-27]
+ * bit[26]     AUTO_RD_BUSY
+ * bit[25]     AUTO_RD_START
+ * bit[24]     AUTO_RD_ENABLE
+ * bit[23-16]  BYTE_WR_DATA
+ * bit[15]
+ * bit[14]     AUTO_WR_BUSY
+ * bit[13]     AUTO_WR_START
+ * bit[12]     AUTO_WR_ENABLE
+ * bit[11]     BYTE_ADDR_SET
+ * bit[10]
+ * bit[9-0]    BYTE_ADDR
+ */
+#define CNTL1_PD_ENABLE_BIT                                    27
+#define CNTL1_PD_ENABLE_SIZE                                   1
+#define CNTL1_PD_ENABLE_ON                                     1
+#define CNTL1_PD_ENABLE_OFF                            0
+
+#define CNTL1_AUTO_RD_BUSY_BIT              26
+#define CNTL1_AUTO_RD_BUSY_SIZE             1
+
+#define CNTL1_AUTO_RD_START_BIT             25
+#define CNTL1_AUTO_RD_START_SIZE            1
+
+#define CNTL1_AUTO_RD_ENABLE_BIT            24
+#define CNTL1_AUTO_RD_ENABLE_SIZE           1
+#define CNTL1_AUTO_RD_ENABLE_ON             1
+#define CNTL1_AUTO_RD_ENABLE_OFF            0
+
+#define CNTL1_BYTE_WR_DATA_BIT              16
+#define CNTL1_BYTE_WR_DATA_SIZE             8
+
+#define CNTL1_AUTO_WR_BUSY_BIT              14
+#define CNTL1_AUTO_WR_BUSY_SIZE             1
+
+#define CNTL1_AUTO_WR_START_BIT             13
+#define CNTL1_AUTO_WR_START_SIZE            1
+#define CNTL1_AUTO_WR_START_ON              1
+#define CNTL1_AUTO_WR_START_OFF             0
+
+#define CNTL1_AUTO_WR_ENABLE_BIT            12
+#define CNTL1_AUTO_WR_ENABLE_SIZE           1
+#define CNTL1_AUTO_WR_ENABLE_ON             1
+#define CNTL1_AUTO_WR_ENABLE_OFF            0
+
+#define CNTL1_BYTE_ADDR_SET_BIT             11
+#define CNTL1_BYTE_ADDR_SET_SIZE            1
+#define CNTL1_BYTE_ADDR_SET_ON              1
+#define CNTL1_BYTE_ADDR_SET_OFF             0
+
+#define CNTL1_BYTE_ADDR_BIT                 0
+#define CNTL1_BYTE_ADDR_SIZE                10
+
+/* EFUSE_CNTL2 */
+
+/* EFUSE_CNTL3 */
+
+/*
+ * EFUSE_CNTL4
+ *
+ * bit[31-24]
+ * bit[23-16]  RD_CLOCK_HIGH
+ * bit[15-11]
+ * bit[10]     Encrypt enable
+ * bit[9]      Encrypt reset
+ * bit[8]      XOR_ROTATE
+ * bit[7-0]    XOR
+ */
+#define CNTL4_ENCRYPT_ENABLE_BIT            10
+#define CNTL4_ENCRYPT_ENABLE_SIZE           1
+#define CNTL4_ENCRYPT_ENABLE_ON             1
+#define CNTL4_ENCRYPT_ENABLE_OFF            0
+
+#define CNTL4_ENCRYPT_RESET_BIT             9
+#define CNTL4_ENCRYPT_RESET_SIZE            1
+#define CNTL4_ENCRYPT_RESET_ON              1
+#define CNTL4_ENCRYPT_RESET_OFF             0
+
+#define CNTL4_XOR_ROTATE_BIT                8
+#define CNTL4_XOR_ROTATE_SIZE               1
+
+#define CNTL4_XOR_BIT                       0
+#define CNTL4_XOR_SIZE                      8
+
+static inline void aml_set_reg32_bits(uint32_t _reg, const uint32_t _value,
+       const uint32_t _start, const uint32_t   _len)
+{
+       writel(((readl((void *)_reg)
+               & ~(((1L << (_len))-1) << (_start)))
+               | ((unsigned int)((_value)&((1L<<(_len))-1)) << (_start))),
+               (void *)_reg);
+}
+#endif
diff --git a/drivers/amlogic/efuse/efuse_version.c b/drivers/amlogic/efuse/efuse_version.c
new file mode 100644 (file)
index 0000000..2571ab1
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * drivers/amlogic/efuse/efuse_version.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/types.h>
+/* #include <mach/am_regs.h> */
+#include "efuse_regs.h"
+#include "efuse.h"
+/* #include <linux/amlogic/efuse-amlogic.h> */
+
+
+/**
+ * efuse version 0.1 (for M3 )
+ * M3 efuse: read all free efuse data maybe fail on addr 0 and addr 0x40
+ * so M3 EFUSE layout avoid using 0 and 0x40
+title    offset datasize checksize totalsize
+reserved  0       0        0        4
+usid      4       33       2        35
+mac_wifi  39      6        1        7
+mac_bt    46      6        1        7
+mac       53      6        1        7
+licence   60      3        1        4
+reserved  64      0        0        4
+hdcp      68      300      10       310
+reserved  378     0        0        2
+version   380     3        1        4 (version+machid, version=1)
+*/
+
+/* m8 efuse layout according to haixiang.bao allocation */
+static struct efuseinfo_item_t efuseinfo_M8_serialNum_v1[] = {
+       {
+               .title = "licence",
+               .id = EFUSE_LICENCE_ID,
+               .offset = 0,
+               .data_len = 4,
+       },
+       {
+               .title = "nandextcmd",
+               .id = EFUSE_NANDEXTCMD_ID,
+               .offset = 4,
+               .data_len = 16,
+       },
+       {
+               .title = "mac",  /* for the main network interface */
+               .id = EFUSE_MAC_ID,
+               .offset = 436,
+               .data_len = 6,
+       },
+       {
+               /* for the second network interface or bt */
+               .title = "mac_bt",
+               .id = EFUSE_MAC_BT_ID,
+               .offset = 442,
+               .data_len = 6,
+       },
+       {
+               /* for the second network interface or bt */
+               .title = "mac_wifi",
+               .id = EFUSE_MAC_WIFI_ID,
+               .offset = 448,
+               .data_len = 6,
+       },
+       {
+               .title = "usid",
+               .id = EFUSE_USID_ID,
+               .offset = 454,
+               .data_len = 48,
+       },
+       {
+               .title = "version",
+               .id = EFUSE_VERSION_ID,
+               .offset = M8_EFUSE_VERSION_OFFSET, /* 509 */
+               .data_len = M8_EFUSE_VERSION_DATA_LEN,
+       },
+};
+
+
+struct efuseinfo_t efuseinfo[] = {
+       {
+               .efuseinfo_version = efuseinfo_M8_serialNum_v1,
+               .size = sizeof(efuseinfo_M8_serialNum_v1)/
+                                               sizeof(struct efuseinfo_item_t),
+               .version = M8_EFUSE_VERSION_SERIALNUM_V1,
+       },
+};
+
+int efuseinfo_num = sizeof(efuseinfo)/sizeof(struct efuseinfo_t);
+
+
index 0a2c779..11f20be 100644 (file)
@@ -30,5 +30,7 @@ extern int efusekeynum;
 int efuse_getinfo(char *item, struct efusekey_info *info);
 ssize_t efuse_user_attr_show(char *name, char *buf);
 ssize_t efuse_user_attr_store(char *name, const char *buf, size_t count);
+#else
+int efuse_read_intlItem(char *intl_item, char *buf, int size);
 #endif
 #endif