firmware/br-ext-chip-allwinner/board/v83x/kernel/patches/00000-drivers_soc_sunxi_sun...

837 lines
20 KiB
Diff

diff -drupN a/drivers/soc/sunxi/sunxi-sid.c b/drivers/soc/sunxi/sunxi-sid.c
--- a/drivers/soc/sunxi/sunxi-sid.c 1970-01-01 03:00:00.000000000 +0300
+++ b/drivers/soc/sunxi/sunxi-sid.c 2022-06-12 05:28:14.000000000 +0300
@@ -0,0 +1,832 @@
+/*
+ * drivers/soc/sunxi-sid.c
+ *
+ * Copyright(c) 2014-2016 Allwinnertech Co., Ltd.
+ * http://www.allwinnertech.com
+ *
+ * Author: sunny <sunny@allwinnertech.com>
+ * Author: superm <superm@allwinnertech.com>
+ * Author: Matteo <duanmintao@allwinnertech.com>
+ *
+ * Allwinner sunxi soc chip version and chip id manager.
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/err.h>
+#include <linux/sunxi-smc.h>
+
+#include <linux/sunxi-sid.h>
+#include "sunxi-sid-efuse.h"
+
+#define SID_DBG(fmt, arg...) pr_debug("%s()%d - "fmt, __func__, __LINE__, ##arg)
+#define SID_WARN(fmt, arg...) pr_warn("%s()%d - "fmt, __func__, __LINE__, ##arg)
+#define SID_ERR(fmt, arg...) pr_err("%s()%d - "fmt, __func__, __LINE__, ##arg)
+
+#if defined(CONFIG_ARCH_SUN50I) || defined(CONFIG_ARCH_SUN8IW6)
+#define SUNXI_SECURITY_SUPPORT 1
+#endif
+
+#define SUNXI_VER_MAX_NUM 8
+struct soc_ver_map {
+ u32 id;
+ u32 rev[SUNXI_VER_MAX_NUM];
+};
+
+#define SUNXI_SOC_ID_INDEX 1
+#define SUNXI_SECURITY_ENABLE_INDEX 2
+struct soc_ver_reg {
+ s8 compatile[48];
+ u32 offset;
+ u32 mask;
+ u32 shift;
+};
+
+#if defined(CONFIG_ARCH_SUN8IW6)
+
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN8IW6P1_REV_A, SUN8IW6P1_REV_B} },
+ {1, {SUN8IW6P1_REV_A, SUN8IW6P1_REV_B} },
+ {0xFF, {0} },
+};
+
+static struct soc_ver_reg soc_ver_regs[] = {
+ {"allwinner,sram_ctrl", 0x24, 0xFF, 0},
+ {"", 0, 0, 0},
+ {EFUSE_CHIPID_BASE, 0xF4, 1, 11},
+};
+
+#elif defined(CONFIG_ARCH_SUN8IW7)
+#define SID_REG_READ
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN8IW7P1_REV_A, SUN8IW7P1_REV_B} },
+ {1, {SUN8IW7P2_REV_A, SUN8IW7P2_REV_B} },
+ {0xFF, {0} },
+ };
+
+static struct soc_ver_reg soc_ver_regs[] = {
+ {"allwinner,sram_ctrl", 0xf0, 0x1, 0},
+ {"", 0, 0, 0},
+ {"", 0, 0, 0},
+};
+#elif defined(CONFIG_ARCH_SUN8IW11)
+
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN8IW11P1_REV_A, SUN8IW11P1_REV_A} },
+ {1, {SUN8IW11P2_REV_A, SUN8IW11P2_REV_A} },
+ {3, {SUN8IW11P3_REV_A, SUN8IW11P3_REV_A} },
+ {5, {SUN8IW11P4_REV_A, SUN8IW11P4_REV_A} },
+ {0xFF, {0} },
+ };
+
+static struct soc_ver_reg soc_ver_regs[] = {
+ {EFUSE_SID_BASE, 0x88, 1, 0},
+ {"", 0, 0, 0},
+ {"", 0, 0, 0},
+};
+#elif defined(CONFIG_ARCH_SUN8IW12)
+
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN8IW12P1_REV_A, 0} },
+ {0xFF, {0} },
+ };
+static struct soc_ver_reg soc_ver_regs[] = {
+ {"allwinner,sram_ctrl", 0x24, 0x7, 0},
+ {EFUSE_SID_BASE, 0x100, 0xF, 0},
+ {"", 0, 0, 0},
+};
+#elif defined(CONFIG_ARCH_SUN8IW15)
+
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN8IW15P1_REV_A, 0} },
+ {0xFF, {0} },
+ };
+static struct soc_ver_reg soc_ver_regs[] = {
+ {"allwinner,sram_ctrl", 0x24, 0x7, 0},
+ {EFUSE_SID_BASE, 0x100, 0xF, 0},
+ {EFUSE_SID_BASE, 0xA0, 0x1, 0},
+};
+#elif defined(CONFIG_ARCH_SUN8IW16)
+
+#define SUNXI_SOC_ID_IN_SID
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN8IW16P1_REV_A, SUN8IW16P1_REV_B} },
+ {0xFF, {0} },
+ };
+static struct soc_ver_reg soc_ver_regs[] = {
+ {"allwinner,sram_ctrl", 0x24, 0x7, 0},
+ {EFUSE_SID_BASE, 0x100, 0xF, 0},
+ {"", 0x0, 0x0, 0},
+};
+
+#elif defined(CONFIG_ARCH_SUN8IW19)
+
+#define SUNXI_SOC_ID_IN_SID
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN8IW19P1_REV_A, 0} },
+ {0xFF, {0} },
+ };
+static struct soc_ver_reg soc_ver_regs[] = {
+ {"allwinner,sram_ctrl", 0x24, 0x7, 0},
+ {EFUSE_SID_BASE, 0x100, 0xF, 0},
+};
+
+#elif defined(CONFIG_ARCH_SUN8IW17)
+
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN8IW17P1_REV_A} },
+ {0xFF, {0} },
+};
+#elif defined(CONFIG_ARCH_SUN8IW18)
+
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN8IW18P1_REV_A} },
+ {0xFF, {0} },
+};
+
+static struct soc_ver_reg soc_ver_regs[] = {
+ {"allwinner,sram_ctrl", 0x24, 0x7, 0},
+ {EFUSE_SID_BASE, 0x100, 0x7, 0},
+ {EFUSE_SID_BASE, 0xA0, 0xf, 0},
+};
+#elif defined(CONFIG_ARCH_SUN8IW5)
+
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN8IW5P1_REV_A} },
+ {1, {SUN8IW5P1_REV_B} },
+ {0xFF, {0} },
+};
+
+#elif defined(CONFIG_ARCH_SUN50IW1)
+
+#define SUNXI_GET_CHIPID_BY_SMC
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN50IW1P1_REV_A} },
+ {0xFF, {0} },
+};
+
+#elif defined(CONFIG_ARCH_SUN50IW2)
+
+#define SUNXI_GET_CHIPID_BY_SMC
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN50IW2P1_REV_A} },
+ {0xFF, {0} },
+};
+
+#elif defined(CONFIG_ARCH_SUN50IW3)
+
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN50IW3P1_REV_A} },
+ {0xFF, {0} },
+};
+
+#elif defined(CONFIG_ARCH_SUN50IW6)
+
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN50IW6P1_REV_A} },
+ {0xFF, {0} },
+};
+
+#elif defined(CONFIG_ARCH_SUN50IW9)
+
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN50IW9P1_REV_A, 0} },
+ {0xFF, {0} },
+ };
+static struct soc_ver_reg soc_ver_regs[] = {
+ {"allwinner,sram_ctrl", 0x24, 0x7, 0},
+ {EFUSE_SID_BASE, 0x100, 0x7, 0},
+ {EFUSE_SID_BASE, 0xA0, 0xF, 0},
+};
+
+#elif defined(CONFIG_ARCH_SUN50IW10)
+
+static struct soc_ver_map soc_ver[] = {
+ {0, {SUN50IW10P1_REV_A, 0} },
+ {0xFF, {0} },
+};
+static struct soc_ver_reg soc_ver_regs[] = {
+ {"allwinner,sram_ctrl", 0x24, 0x7, 0},
+ {"", 0, 0, 0},
+ {EFUSE_SID_BASE, 0xA0, 0x1, 0},
+};
+
+#else
+
+static struct soc_ver_map soc_ver[] = {
+ {0xFF, {0} },
+};
+static struct soc_ver_reg soc_ver_regs[] = {
+ {"", 0, 0, 0},
+ {"", 0, 0, 0},
+ {"", 0, 0, 0},
+};
+
+#endif
+
+#if defined(CONFIG_ARCH_SUN50IW1)
+static struct soc_ver_reg soc_ver_regs[] = {
+ {"allwinner,sram_ctrl", 0x24, 0xFF, 0},
+ {"", 0, 0, 0},
+ {EFUSE_CHIPID_BASE, 0xF4, 1, 11},
+};
+#elif defined(CONFIG_ARCH_SUN50IW2)
+static struct soc_ver_reg soc_ver_regs[] = {
+ {"allwinner,sram_ctrl", 0x24, 0xFF, 0},
+ {"", 0, 0, 0},
+ {EFUSE_SID_BASE, 0xA0, 0x1, 0},
+};
+#elif defined(CONFIG_ARCH_SUN50IW3) || defined(CONFIG_ARCH_SUN50IW6)
+static struct soc_ver_reg soc_ver_regs[] = {
+ {"allwinner,sram_ctrl", 0x24, 0x7, 0},
+ {EFUSE_SID_BASE, 0x100, 0xF, 0},
+ {EFUSE_SID_BASE, 0xA0, 0x1, 0},
+};
+#define SUNXI_SOC_ID_IN_SID
+#elif defined(CONFIG_ARCH_SUN8IW17)
+
+static struct soc_ver_reg soc_ver_regs[] = {
+ {"allwinner,sram_ctrl", 0x24, 0x7, 0},
+ {EFUSE_SID_BASE, 0x100, 0x7, 0},
+ {EFUSE_SID_BASE, 0xA0, 0x1, 0},
+};
+#define SUNXI_SOC_ID_IN_SID
+
+#endif
+
+static struct soc_ver_reg soc_bin_regs[] = {
+#if defined(CONFIG_ARCH_SUN8IW11)
+ {EFUSE_CHIPID_BASE, 0x4, 0x7, 22},/* soc bin bit22~24 */
+#elif defined(CONFIG_ARCH_SUN50IW6)
+ {EFUSE_CHIPID_BASE, 0x1c, 0x7, 5},
+#else
+ {EFUSE_CHIPID_BASE, 0x0, 0x3ff, 0},/* soc bin bit0~9 */
+#endif
+};
+
+/* bin0 has higher voltage */
+#if defined(CONFIG_ARCH_SUN50IW6)
+#define SPEED_BIN0 (0b110)
+#define SPEED_BIN1 (0b001)
+#define SPEED_BIN2 (0b010)
+#define SPEED_BIN3 (0b011)
+#else
+#define SPEED_BIN0 (0b001)
+#define SPEED_BIN1 (0b011)
+#define SPEED_BIN2 (0b111)
+#endif
+
+static unsigned int sunxi_soc_chipid[4];
+static unsigned int sunxi_soc_ftzone[4];
+static unsigned int sunxi_serial[4];
+static int sunxi_soc_secure;
+static unsigned int sunxi_soc_bin;
+static unsigned int sunxi_soc_ver;
+static unsigned int sunxi_soc_rotpk_status;
+
+static s32 sid_get_vir_base(struct device_node **pnode, void __iomem **base,
+ s8 *compatible)
+{
+ *pnode = of_find_compatible_node(NULL, NULL, compatible);
+ if (IS_ERR_OR_NULL(*pnode)) {
+ SID_ERR("Failed to find \"%s\" in dts.\n", compatible);
+ return -ENXIO;
+ }
+
+ *base = of_iomap(*pnode, 0); /* reg[0] must be accessible. */
+ if (*base == NULL) {
+ SID_ERR("Unable to remap IO\n");
+ return -ENXIO;
+ }
+ SID_DBG("Base addr of \"%s\" is %p\n", compatible, *base);
+ return 0;
+}
+
+static s32 sid_get_phy_base(struct device_node **pnode, phys_addr_t **base,
+ s8 *compatible)
+{
+ struct resource res = {0};
+
+ *pnode = of_find_compatible_node(NULL, NULL, compatible);
+ if (IS_ERR_OR_NULL(*pnode)) {
+ SID_ERR("Failed to find \"%s\" in dts.\n", compatible);
+ return -ENXIO;
+ }
+
+ if (of_address_to_resource(*pnode, 0, &res)) {
+ SID_ERR("Failed to get \"%s\" base address\n", compatible);
+ return -ENXIO;
+ }
+ *base = (phys_addr_t *)res.start;
+ SID_DBG("Base addr of \"%s\" is %p\n", compatible, (void *)*base);
+ return 0;
+}
+
+static s32 sid_get_base(struct device_node **pnode,
+ void __iomem **base, s8 *compatible, u32 sec)
+{
+ if (sec == 1)
+ return sid_get_phy_base(pnode,
+ (phys_addr_t **)base, compatible);
+ else
+ return sid_get_vir_base(pnode, base, compatible);
+}
+
+static void sid_put_base(struct device_node *pnode, void __iomem *base, u32 sec)
+{
+ SID_DBG("base = %p, Sec = %d\n", base, sec);
+ if ((sec == 0) && (base != NULL))
+ iounmap(base);
+ if (pnode)
+ of_node_put(pnode);
+}
+
+static u32 sid_readl(void __iomem *base, u32 sec)
+{
+ if (sec == 0)
+ return readl(base);
+ else
+ return sunxi_smc_readl((phys_addr_t)base);
+}
+
+#ifdef SID_REG_READ
+#define unmap_io_addr(x) ((phys_addr_t)(x - 0xf0000000))
+static u32 __sid_reg_read_key(uint key_index)
+{
+ u32 reg_val;
+ void __iomem *base = NULL;
+ phys_addr_t phys_base;
+ struct device_node *node = NULL;
+
+ if (sid_get_base(&node, &base, EFUSE_SID_BASE, 0))
+ return 0;
+
+ phys_base = unmap_io_addr(base);
+ reg_val = sunxi_smc_readl(phys_base + SID_PRCTL);
+ reg_val &= ~((0x1ff << 16)|0x3);
+ reg_val |= key_index << 16;
+ sunxi_smc_writel(reg_val, phys_base + SID_PRCTL);
+ reg_val &= ~((0xff << 8)|0x3);
+ reg_val |= (SID_OP_LOCK << 8) | 0x2;
+ sunxi_smc_writel(reg_val, phys_base + SID_PRCTL);
+ while (sunxi_smc_readl(phys_base + SID_PRCTL) & 0x2)
+ ;
+ reg_val &= ~((0x1ff << 16)|(0xff << 8)|0x3);
+ sunxi_smc_writel(reg_val, phys_base + SID_PRCTL);
+ reg_val = sunxi_smc_readl(phys_base + SID_RDKEY);
+
+ return reg_val;
+}
+#endif
+
+static u32 sid_rd_bits(s8 *name, u32 offset, u32 shift, u32 mask, u32 sec)
+{
+ u32 value = 0;
+ void __iomem *baseaddr = NULL;
+ struct device_node *dev_node = NULL;
+
+#ifdef SID_REG_READ
+ return __sid_reg_read_key(offset);
+#endif
+
+ if (sid_get_base(&dev_node, &baseaddr, name, sec))
+ return 0;
+
+ value = sid_readl(baseaddr + offset, sec);
+
+ value = (value >> shift) & mask;
+ SID_DBG("Read \"%s\" + %#x, shift %#x, mask %#x, return %#x, Sec %d\n",
+ name, offset, shift, mask, value, sec);
+
+ sid_put_base(dev_node, baseaddr, sec);
+ return value;
+}
+
+void sid_rd_ver_reg(u32 id)
+{
+ s32 i = 0;
+ u32 ver = 0;
+ struct soc_ver_reg *reg = &soc_ver_regs[0];
+
+ ver = sid_rd_bits(reg->compatile, reg->offset,
+ reg->shift, reg->mask, 0);
+ WARN_ON(ver >= SUNXI_VER_MAX_NUM/2);
+
+ sunxi_soc_ver = soc_ver[0].rev[ver];
+ for (i = 0; soc_ver[i].id != 0xFF; i++)
+ if (id == soc_ver[i].id) {
+ sunxi_soc_ver = soc_ver[i].rev[ver];
+ break;
+ }
+
+ SID_DBG("%d-%d: soc_ver %#x\n", i, ver, sunxi_soc_ver);
+}
+
+#ifdef SUNXI_SOC_ID_IN_SID
+
+static s32 sid_rd_soc_ver_from_sid(void)
+{
+ u32 id = 0;
+ struct soc_ver_reg *reg = &soc_ver_regs[SUNXI_SOC_ID_INDEX];
+
+ id = sid_rd_bits(reg->compatile, reg->offset, reg->shift, reg->mask, 0);
+ sid_rd_ver_reg(id);
+
+ return 0;
+}
+
+#else
+
+/*
+ * SMP_init maybe call this function, while CCU module wasn't inited.
+ * So we have to read/write the CCU register directly.
+ */
+static s32 sid_rd_soc_ver_from_ce(void)
+{
+ s32 ret = 0;
+ u32 id = 0;
+ void __iomem *ccu_base = NULL;
+ struct device_node *ccu_node = NULL;
+ u32 bus_clk_reg, bus_rst_reg, ce_clk_reg;
+
+ ret = sid_get_base(&ccu_node, &ccu_base, "allwinner,clk-init", 0);
+ if (ret)
+ goto sid_ce_init_failed;
+
+ /* backup ce clock */
+ bus_clk_reg = readl(ccu_base + 0x060);
+ bus_rst_reg = readl(ccu_base + 0x2c0);
+ ce_clk_reg = readl(ccu_base + 0x09c);
+
+ if ((bus_clk_reg&(1<<5)) && (bus_rst_reg&(1<<5))
+ && (ce_clk_reg&(1<<31))) {
+ SID_DBG("The CE module is already enable.\n");
+ } else {
+ /* enable ce clock */
+ writel(bus_clk_reg | (1<<5), ccu_base + 0x060);
+ writel(bus_rst_reg | (1<<5), ccu_base + 0x2c0);
+ writel(ce_clk_reg | (1<<31), ccu_base + 0x09c);
+ }
+
+#if defined(CONFIG_ARCH_SUN8IW6)
+ id = sid_rd_bits("allwinner,sunxi-ce", 0, 20, 7, 0);
+#else
+ id = sid_rd_bits("allwinner,sunxi-ce", 4, 0, 7, 0);
+#endif
+
+ /* restore ce clock */
+ writel(bus_clk_reg, ccu_base + 0x060);
+ writel(bus_rst_reg, ccu_base + 0x2c0);
+ writel(ce_clk_reg, ccu_base + 0x09c);
+
+ sid_rd_ver_reg(id);
+
+sid_ce_init_failed:
+ sid_put_base(ccu_node, ccu_base, 0);
+ return ret;
+}
+
+#endif
+
+static void sid_soc_ver_init(void)
+{
+ static s32 init_flag;
+
+ if (init_flag == 1) {
+ SID_DBG("It's already inited.\n");
+ return;
+ }
+
+#ifdef SUNXI_SOC_ID_IN_SID
+ sid_rd_soc_ver_from_sid();
+#else
+ sid_rd_soc_ver_from_ce();
+#endif
+
+ SID_DBG("The SoC version: %#x\n", sunxi_soc_ver);
+ init_flag = 1;
+}
+
+static void sid_chipid_init(void)
+{
+ u32 type = 0;
+ static s32 init_flag;
+ struct soc_ver_reg *reg;
+
+ if (init_flag == 1) {
+ SID_DBG("It's already inited.\n");
+ return;
+ }
+
+ sunxi_soc_chipid[0] = sid_rd_bits(EFUSE_CHIPID_BASE, 0,
+ 0, 0xFFFFFFFF, sunxi_soc_is_secure());
+ sunxi_soc_chipid[1] = sid_rd_bits(EFUSE_CHIPID_BASE, 4,
+ 0, 0xFFFFFFFF, sunxi_soc_is_secure());
+ sunxi_soc_chipid[2] = sid_rd_bits(EFUSE_CHIPID_BASE, 8,
+ 0, 0xFFFFFFFF, sunxi_soc_is_secure());
+ sunxi_soc_chipid[3] = sid_rd_bits(EFUSE_CHIPID_BASE, 12,
+ 0, 0xFFFFFFFF, sunxi_soc_is_secure());
+ sunxi_serial[0] = sunxi_soc_chipid[3];
+ sunxi_serial[1] = sunxi_soc_chipid[2];
+ sunxi_serial[2] = (sunxi_soc_chipid[1] >> 16) & 0x0FFFF;
+
+ reg = &soc_bin_regs[0];
+
+ type = sid_rd_bits(reg->compatile, reg->offset, reg->shift,
+ reg->mask, sunxi_soc_is_secure());
+
+ switch (type) {
+ case SPEED_BIN0:
+ sunxi_soc_bin = 1;
+ break;
+ case SPEED_BIN1:
+ sunxi_soc_bin = 2;
+ break;
+ case SPEED_BIN2:
+ sunxi_soc_bin = 3;
+ break;
+#if defined(CONFIG_ARCH_SUN50IW6)
+ case SPEED_BIN3:
+ sunxi_soc_bin = 4;
+ break;
+#endif
+ default:
+ break;
+ }
+ SID_DBG("soc bin: %d\n", sunxi_soc_bin);
+
+ init_flag = 1;
+}
+
+void sid_ft_zone_init(void)
+{
+ static s32 init_flag;
+
+ if (init_flag == 1) {
+ SID_DBG("It's already inited.\n");
+ return;
+ }
+
+ sunxi_soc_ftzone[0] = sid_rd_bits(EFUSE_CHIPID_BASE, 0x20,
+ 0, 0xFFFFFFFF, sunxi_soc_is_secure());
+ sunxi_soc_ftzone[1] = sid_rd_bits(EFUSE_CHIPID_BASE, 0x24,
+ 0, 0xFFFFFFFF, sunxi_soc_is_secure());
+ sunxi_soc_ftzone[2] = sid_rd_bits(EFUSE_CHIPID_BASE, 0x28,
+ 0, 0xFFFFFFFF, sunxi_soc_is_secure());
+ sunxi_soc_ftzone[3] = sid_rd_bits(EFUSE_CHIPID_BASE, 0x2c,
+ 0, 0xFFFFFFFF, sunxi_soc_is_secure());
+
+ init_flag = 1;
+
+}
+
+void sid_rd_soc_secure_status(void)
+{
+#if defined(CONFIG_TEE) && \
+ (defined(CONFIG_ARCH_SUN8IW7) || defined(CONFIG_ARCH_SUN8IW6))
+ sunxi_soc_secure = 1;
+#else
+ static s32 init_flag;
+ void __iomem *base = NULL;
+ struct device_node *node = NULL;
+ struct soc_ver_reg *reg = &soc_ver_regs[SUNXI_SECURITY_ENABLE_INDEX];
+
+ if (init_flag == 1) {
+ SID_DBG("It's already inited.\n");
+ return;
+ }
+
+ if (sid_get_base(&node, &base, reg->compatile, 1))
+ return;
+
+ sunxi_soc_secure = ((sunxi_smc_readl((phys_addr_t)(base + reg->offset)))
+ >> reg->shift) & reg->mask;
+
+ sid_put_base(node, base, 1);
+ init_flag = 1;
+#endif
+}
+
+void sid_rotpk_status_init(void)
+{
+ static s32 init_flag;
+
+ if (init_flag == 1) {
+ SID_DBG("It's already inited.\n");
+ return;
+ }
+
+ sunxi_soc_rotpk_status = sid_rd_bits(EFUSE_SID_BASE, 0x140,
+ 0, 0xFFFFFFFF, sunxi_soc_is_secure());
+
+ init_flag = 1;
+
+}
+
+s32 sunxi_get_platform(s8 *buf, s32 size)
+{
+ return snprintf(buf, size, "%s", CONFIG_SUNXI_SOC_NAME);
+}
+EXPORT_SYMBOL(sunxi_get_platform);
+
+/**
+ * soc chipid:
+ */
+int sunxi_get_soc_chipid(u8 *chipid)
+{
+ sid_chipid_init();
+ memcpy(chipid, sunxi_soc_chipid, 16);
+ return 0;
+}
+EXPORT_SYMBOL(sunxi_get_soc_chipid);
+
+/**
+ * soc chipid serial:
+ */
+int sunxi_get_serial(u8 *serial)
+{
+ sid_chipid_init();
+ memcpy(serial, sunxi_serial, 16);
+ return 0;
+}
+EXPORT_SYMBOL(sunxi_get_serial);
+
+/**
+ * soc chipid str:
+ */
+int sunxi_get_soc_chipid_str(char *serial)
+{
+ size_t size;
+
+ sid_chipid_init();
+ size = sprintf(serial, "%08x", sunxi_soc_chipid[0] & 0xffff);
+ return size;
+}
+EXPORT_SYMBOL(sunxi_get_soc_chipid_str);
+
+/**
+ * soc ft zone str:
+ */
+int sunxi_get_soc_ft_zone_str(char *serial)
+{
+ size_t size;
+
+ sid_ft_zone_init();
+ size = sprintf(serial, "%08x", (sunxi_soc_ftzone[0] & 0xff000000) >> 24);
+ return size;
+}
+EXPORT_SYMBOL(sunxi_get_soc_ft_zone_str);
+
+/**
+ * soc rotpk status str:
+ */
+int sunxi_get_soc_rotpk_status_str(char *status)
+{
+ size_t size;
+
+ sid_rotpk_status_init();
+ size = sprintf(status, "%d", (sunxi_soc_rotpk_status & 0x3) >> 1);
+ return size;
+}
+EXPORT_SYMBOL(sunxi_get_soc_rotpk_status_str);
+
+/**
+ * soc chipid:
+ */
+int sunxi_soc_is_secure(void)
+{
+ sid_rd_soc_secure_status();
+ return sunxi_soc_secure;
+}
+EXPORT_SYMBOL(sunxi_soc_is_secure);
+
+/**
+ * get sunxi soc bin
+ *
+ * return: the bin of sunxi soc, like that:
+ * 0 : fail
+ * 1 : slow
+ * 2 : normal
+ * 3 : fast
+ */
+unsigned int sunxi_get_soc_bin(void)
+{
+ sid_chipid_init();
+ return sunxi_soc_bin;
+}
+EXPORT_SYMBOL(sunxi_get_soc_bin);
+
+unsigned int sunxi_get_soc_ver(void)
+{
+ sid_soc_ver_init();
+ return sunxi_soc_ver;
+}
+EXPORT_SYMBOL(sunxi_get_soc_ver);
+
+/* Return 0, unreadable; 1, readable. */
+int sid_efuse_key_is_readable(struct efuse_key_map *key_map)
+{
+#ifndef EFUSE_HAS_NO_RW_PROTECT
+ u32 value = 0;
+#endif
+
+#ifndef EFUSE_IS_PUBLIC
+ if (key_map->public == 1)
+ return 1;
+
+ if (sunxi_soc_is_secure())
+ return 0;
+#endif
+
+#ifndef EFUSE_HAS_NO_RW_PROTECT
+ if (key_map->read_flag_shift < 0)
+ return 1;
+
+ /* TODO: Check the protection of wr/rd_protect register. */
+ value = sid_rd_bits(EFUSE_CHIPID_BASE, key_map_rd_pro.offset,
+ 0, 0xFFFFFFFF, sunxi_soc_is_secure());
+ if ((value >> key_map->read_flag_shift) & 1) {
+ SID_ERR("The key %s is unreadable!\n", key_map->name);
+ return 0;
+ }
+
+ value = sid_rd_bits(EFUSE_CHIPID_BASE, key_map_wr_pro.offset,
+ 0, 0xFFFFFFFF, sunxi_soc_is_secure());
+ if (((value >> key_map->burn_flag_shift) & 1) == 0)
+ SID_WARN("The key %s write protect bit not burned!\n",
+ key_map->name);
+#endif
+ return 1;
+}
+
+void sid_efuse_key_rd(struct efuse_key_map *key_map, void *buf, u32 n)
+{
+ u32 i;
+ u32 value = 0;
+ u32 key_size = 0;
+ u32 remainder = n;
+ u32 *dst = (u32 *)buf;
+
+ key_size = key_map->size / 8;
+ WARN_ON(key_size & 3);
+ if (remainder > key_size)
+ remainder = key_size;
+
+ SID_DBG("Read the key %s, len: %d\n", key_map->name, remainder);
+ for (i = 0; i < key_size/4; i++) {
+ value = sid_rd_bits(EFUSE_CHIPID_BASE, key_map->offset + i*4,
+ 0, 0xFFFFFFFF, sunxi_soc_is_secure());
+ pr_debug("0x%04x: 0x%08x\n", key_map->offset + i*4, value);
+ if (remainder <= 4) {
+ memcpy(&dst[i], &value, remainder);
+ break;
+ }
+ dst[i] = value;
+ remainder -= 4;
+ }
+ pr_debug("\n");
+}
+
+/* n - the size of read_buf, in bytes */
+s32 sunxi_efuse_readn(void *key_name, void *buf, u32 n)
+{
+ struct efuse_key_map *key_map = key_maps;
+
+ if ((key_name == NULL) || (*(s8 *)key_name == 0)
+ || (n == 0) || (buf == NULL)) {
+ SID_ERR("Invalid parameter. name: %p, read_buf: %p, size: %d\n",
+ key_name, buf, n);
+ return -EINVAL;
+ }
+ WARN_ON(n < 4);
+
+ /* Confirm the readable attribute. */
+ for (; key_map->name[0] != 0; key_map++) {
+ if (strncmp(key_name, key_map->name,
+ strlen(key_map->name)))
+ continue;
+
+ SID_DBG("Read key: %s, offset: %#x\n",
+ key_map->name, key_map->offset);
+ if (sid_efuse_key_is_readable(key_map))
+ break;
+
+ return -EACCES;
+ }
+
+ if (key_map->name[0] == 0) {
+ SID_ERR("The key %s is unavailable.\n", (s8 *)key_name);
+ return -1;
+ }
+
+ sid_efuse_key_rd(key_map, buf, n);
+ return 0;
+}
+EXPORT_SYMBOL(sunxi_efuse_readn);
+