"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";
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
# 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
--- /dev/null
+/*
+ * 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>");
#ifndef __EFUSE_H
#define __EFUSE_H
+/* #define EFUSE_DEBUG */
/*#define EFUSE_READ_ONLY 1*/
/* #define EFUSE_NONE_ID 0 */
#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
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 {
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);
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;
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+
+
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