efuse: support EFUSE pattern burning
authorZhongfu Luo <zhongfu.luo@amlogic.com>
Thu, 12 Jul 2018 06:50:48 +0000 (14:50 +0800)
committerZhongfu Luo <zhongfu.luo@amlogic.com>
Thu, 12 Jul 2018 06:55:06 +0000 (14:55 +0800)
PD#168568: G12A need to support EFUSE burning

1.add child node amlogic_set in efuse
2.node amlogic_set support EFUSE pattern burning

Change-Id: Ie20a8b61678e351cf32418879d4b40228e1d365f
Signed-off-by: Zhongfu Luo <zhongfu.luo@amlogic.com>
drivers/amlogic/efuse/efuse.h
drivers/amlogic/efuse/efuse64.c
drivers/amlogic/efuse/efuse_hw64.c
drivers/amlogic/secmon/secmon.c
include/linux/amlogic/secmon.h

index acd5378d283ab8e863459ae7109a55c1e790c4b2..4642dc38bfa8ed0de0ff05fc30b354f411f3ed66 100644 (file)
 #define EFUSE_HAL_API_WRITE 1
 #define EFUSE_HAL_API_USER_MAX 3
 
+#define AML_DATA_PROCESS            (0x820000FF)
+#define AML_D_P_W_EFUSE_AMLOGIC     (0x20)
+#define GXB_EFUSE_PATTERN_SIZE      (0x400)
+
 #define ASSIST_HW_REV 0x1f53
 
 extern int efuseinfo_num;
@@ -97,6 +101,7 @@ extern struct clk *efuse_clk;
 ssize_t efuse_get_max(void);
 ssize_t efuse_read_usr(char *buf, size_t count, loff_t *ppos);
 ssize_t efuse_write_usr(char *buf, size_t count, loff_t *ppos);
+unsigned long efuse_amlogic_set(char *buf, size_t count);
 
 #endif
 
index 175c99f270a5139149d5fbec7ebb1f543509c03b..de552e7ec680a99e719bb9a1ac0d82c7e664b0b4 100644 (file)
@@ -483,6 +483,43 @@ static ssize_t userdata_write(struct class *cla,
 }
 #endif
 
+static ssize_t amlogic_set_store(struct class *cla,
+       struct class_attribute *attr, const char *buf, size_t count)
+{
+       int i;
+       int ret;
+       char *op = NULL;
+
+       if (count != GXB_EFUSE_PATTERN_SIZE) {
+               pr_err("efuse: bad size, only support size %d!\n",
+                       GXB_EFUSE_PATTERN_SIZE);
+               return -EINVAL;
+       }
+
+       op = kzalloc((sizeof(char)*count), GFP_KERNEL);
+       if (!op) {
+               ret = -ENOMEM;
+               pr_err("efuse: failed to allocate memory!\n");
+               return ret;
+       }
+
+       memset(op, 0, count);
+       for (i = 0; i < count; i++)
+               op[i] = buf[i];
+
+       ret = efuse_amlogic_set(op, count);
+       kfree(op);
+
+       if (ret) {
+               pr_err("EFUSE pattern programming fail! ret: %d\n", ret);
+               return -EINVAL;
+       }
+
+       pr_info("EFUSE pattern programming success!\n");
+
+       return count;
+}
+
 static struct class_attribute efuse_class_attrs[] = {
 
        #ifndef EFUSE_READ_ONLY
@@ -502,6 +539,8 @@ static struct class_attribute efuse_class_attrs[] = {
 
        __ATTR(usid, 0700, show_usid, store_usid),
 
+       __ATTR_WO(amlogic_set),
+
        __ATTR_NULL
 
 };
index 0e93454bff32ca7eecba67e2f3afda1ea7680a10..6da11f4897553a13e1f3d274c5df44fbdfdf7eef 100644 (file)
@@ -31,6 +31,7 @@
 #endif
 #include <linux/amlogic/secmon.h>
 #include <linux/arm-smccc.h>
+#include <asm/cacheflush.h>
 
 static long meson_efuse_fn_smc(struct efuse_hal_api_arg *arg)
 {
@@ -83,6 +84,55 @@ int meson_trustzone_efuse(struct efuse_hal_api_arg *arg)
        return ret;
 }
 
+unsigned long efuse_aml_sec_boot_check(unsigned long nType,
+       unsigned long pBuffer,
+       unsigned long nLength,
+       unsigned long nOption)
+{
+       struct arm_smccc_res res;
+       long sharemem_phy_base;
+
+       sharemem_phy_base = get_secmon_phy_input_base();
+       if ((!sharemem_input_base) || (!sharemem_phy_base))
+               return -1;
+
+       sharemem_mutex_lock();
+
+       memcpy((void *)sharemem_input_base,
+               (const void *)pBuffer, nLength);
+
+       __flush_dcache_area(sharemem_input_base, nLength);
+
+       asm __volatile__("" : : : "memory");
+
+       do {
+               arm_smccc_smc((unsigned long)AML_DATA_PROCESS,
+                                       (unsigned long)nType,
+                                       (unsigned long)sharemem_phy_base,
+                                       (unsigned long)nLength,
+                                       (unsigned long)nOption,
+                                       0, 0, 0, &res);
+       } while (0);
+
+       sharemem_mutex_unlock();
+
+       return res.a0;
+}
+
+unsigned long efuse_amlogic_set(char *buf, size_t count)
+{
+       unsigned long ret;
+
+       set_cpus_allowed_ptr(current, cpumask_of(0));
+
+       ret = efuse_aml_sec_boot_check(AML_D_P_W_EFUSE_AMLOGIC,
+               (unsigned long)buf, (unsigned long)count, 0);
+
+       set_cpus_allowed_ptr(current, cpu_all_mask);
+
+       return ret;
+}
+
 ssize_t meson_trustzone_efuse_get_max(struct efuse_hal_api_arg *arg)
 {
        ssize_t ret;
index 99704a31fc0e1c5e75e6c32f0e3e6a25af91c1a5..c24a866d38c9d4d79b641d37e76826d97bceb40f 100644 (file)
@@ -148,3 +148,12 @@ void __iomem *get_secmon_sharemem_output_base(void)
 {
        return sharemem_out_base;
 }
+
+long get_secmon_phy_input_base(void)
+{
+       return phy_in_base;
+}
+long get_secmon_phy_output_base(void)
+{
+       return phy_out_base;
+}
index 21db071213e88a74b08d2646413ae3f17033c428..07bc94aef038069cc9015d74284d599c614ce1c0 100644 (file)
@@ -20,6 +20,9 @@
 
 void __iomem *get_secmon_sharemem_input_base(void);
 void __iomem *get_secmon_sharemem_output_base(void);
+long get_secmon_phy_input_base(void);
+long get_secmon_phy_output_base(void);
+
 void sharemem_mutex_lock(void);
 void sharemem_mutex_unlock(void);