From 03343c2a0b2ed8b85a6dce567bbe515d69f75697 Mon Sep 17 00:00:00 2001
From: Paolo Sabatino <paolo.sabatino@gmail.com>
Date: Thu, 18 Nov 2021 17:33:59 +0000
Subject: [PATCH] rk3328: add efuse initialization in ATF

---
 plat/rockchip/rk3328/drivers/efuse/efuse.c | 397 +++++++++++++++++++++
 plat/rockchip/rk3328/drivers/efuse/efuse.h | 142 ++++++++
 plat/rockchip/rk3328/drivers/soc/soc.c     |   6 +
 plat/rockchip/rk3328/platform.mk           |   4 +-
 4 files changed, 548 insertions(+), 1 deletion(-)
 create mode 100644 plat/rockchip/rk3328/drivers/efuse/efuse.c
 create mode 100644 plat/rockchip/rk3328/drivers/efuse/efuse.h

diff --git a/plat/rockchip/rk3328/drivers/efuse/efuse.c b/plat/rockchip/rk3328/drivers/efuse/efuse.c
new file mode 100644
index 0000000..05bbcf4
--- /dev/null
+++ b/plat/rockchip/rk3328/drivers/efuse/efuse.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2016, Fuzhou Rockchip Electronics Co., Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+#include <efuse.h>
+#include <string.h>
+
+#define EFUSE_AUTO_MODE		1 // RK3328 wants auto mode on
+
+#define read32(reg)			mmio_read_32(reg)
+#define write32(v, reg)			mmio_write_32(reg, v)
+#define efuse8_read(offset)		mmio_read_32(EFUSE8_BASE + offset)
+#define efuse8_write(v, offset)		mmio_write_32(EFUSE8_BASE + offset, v)
+#define efuse32_read(offset)		mmio_read_32(EFUSE32_BASE + offset)
+#define efuse32_write(v, offset)	mmio_write_32(EFUSE32_BASE + offset, v)
+
+/* global buf to store efuse data */
+static uint32_t efuse32_buf[32] = {0};
+
+enum clk_type {
+	CLK = 0,
+	PCLK,
+};
+
+int enable_efuse_clk()
+{
+
+	uint32_t reg = 0;
+
+	reg = read32(CRU_BASE + CRU_CLKGATE_CON2);
+	/* enable efuse work clk */
+	if (reg & EFUSE_SRC_CLK_EN)
+		write32(EFUSE_SRC_CLK_EN << CRU_WRITE_MASK,
+			CRU_BASE + CRU_CLKGATE_CON2);
+
+	reg = read32(CRU_BASE + CRU_CLKGATE_CON15);
+	/* enable efuse APB clk */
+	if (reg & EFUSE_1024_PCLK_EN)
+		write32(EFUSE_1024_PCLK_EN << CRU_WRITE_MASK,
+			CRU_BASE + CRU_CLKGATE_CON15);
+
+	return reg;
+
+}
+
+/*
+static uint32_t enable_efuse_clk(int clk)
+{
+	uint32_t reg = 0;
+
+	switch (clk) {
+	case CLK:
+		reg = read32(CRU_BASE + CRU_CLKGATE_CON2);
+		// enable efuse work clk
+		if (reg & EFUSE_SRC_CLK_EN)
+			write32(EFUSE_SRC_CLK_EN << CRU_WRITE_MASK,
+				CRU_BASE + CRU_CLKGATE_CON2);
+		break;
+	case PCLK:
+		reg = read32(CRU_BASE + CRU_CLKGATE_CON15);
+		// enable efuse APB clk 
+		if (reg & EFUSE_1024_PCLK_EN)
+			write32(EFUSE_1024_PCLK_EN << CRU_WRITE_MASK,
+				CRU_BASE + CRU_CLKGATE_CON15);
+		break;
+	default:
+		break;
+	}
+
+	return reg;
+}
+*/
+
+static void restore_efuse_clk(int clk, uint32_t reg)
+{
+	switch (clk) {
+	case CLK:
+		/* disable efuse work clk */
+		if (reg & EFUSE_SRC_CLK_EN)
+			write32(reg | (EFUSE_SRC_CLK_EN << CRU_WRITE_MASK),
+				CRU_BASE + CRU_CLKGATE_CON2);
+		break;
+	case PCLK:
+		/* disable efuse APB clk */
+		if (reg & EFUSE_1024_PCLK_EN)
+			write32(reg | (EFUSE_1024_PCLK_EN << CRU_WRITE_MASK),
+				CRU_BASE + CRU_CLKGATE_CON15);
+		break;
+	default:
+		return;
+	}
+}
+
+/* user mode and auto mode */
+int rk_efuse32_readregs(uint32_t addr, uint32_t length, uint32_t *buf)
+{
+	uint32_t reg0 = 0;
+	uint32_t reg1 = 0;
+
+	uint32_t efuse_base = 0;
+
+	if (addr > 31)
+		return -1;
+	if (length < 1 || length > 32)
+		return -1;
+	if (!buf)
+		return -1;
+
+	if (addr < 24) {
+		if (addr + length < 25)
+			efuse_base = EFUSE32_BASE;
+		else
+			return -1;
+	}
+	if (addr > 23) {
+		if (addr + length < 33)
+			efuse_base = EFUSE8_BASE;
+		else
+			return -1;
+	}
+
+	//reg0 = enable_efuse_clk(CLK);
+	//reg1 = enable_efuse_clk(PCLK);
+
+#if EFUSE_AUTO_MODE
+	do {
+		write32(EFUSE_AUTO_RD | EFUSE_AUTO_ENABLE |
+			((addr & EFUSE_A_MASK) << EFUSE_A_SHIFT),
+			efuse_base + REG_EFUSE_AUTO_CTRL);
+		udelay(2);
+		while (1) {
+			if (read32(efuse_base + REG_EFUSE_INT_STATUS) & 0x01)
+				break;
+		}
+		*buf = read32(efuse_base + REG_EFUSE_DOUT);
+		write32(read32(efuse_base + REG_EFUSE_AUTO_CTRL) &
+			(~EFUSE_AUTO_ENABLE), efuse_base + REG_EFUSE_AUTO_CTRL);
+		write32(0x07, efuse_base + REG_EFUSE_INT_STATUS);
+		buf++;
+		addr++;
+
+	} while (--length);
+#else
+	/* enable read in user mode */
+	write32((read32(efuse_base + REG_EFUSE_MOD) | EFUSE_RD_ENB_USER) &
+		(~EFUSE_PG_ENB_USER), efuse_base + REG_EFUSE_MOD);
+	write32(EFUSE_CSB, efuse_base + REG_EFUSE_CTRL);
+	write32(EFUSE_LOAD | EFUSE_PGENB, efuse_base + REG_EFUSE_CTRL);
+	udelay(2);
+	do {
+		write32(read32(efuse_base + REG_EFUSE_CTRL) &
+			(~(EFUSE_A_MASK << EFUSE_A_SHIFT)),
+			efuse_base + REG_EFUSE_CTRL);
+		write32(read32(efuse_base + REG_EFUSE_CTRL) |
+			((addr & EFUSE_A_MASK) << EFUSE_A_SHIFT),
+			efuse_base + REG_EFUSE_CTRL);
+
+		udelay(2);
+		write32(read32(efuse_base + REG_EFUSE_CTRL) |
+			EFUSE_STROBE, efuse_base + REG_EFUSE_CTRL);
+		udelay(2);
+		*buf = read32(efuse_base + REG_EFUSE_DOUT);
+		write32(read32(efuse_base + REG_EFUSE_CTRL) &
+			(~EFUSE_STROBE), efuse_base + REG_EFUSE_CTRL);
+		udelay(2);
+		buf++;
+		addr++;
+	} while (--length);
+	udelay(2);
+	write32(read32(efuse_base + REG_EFUSE_CTRL) | EFUSE_CSB,
+		efuse_base + REG_EFUSE_CTRL);
+	udelay(1);
+#endif /* EFUSE_AUTO_MODE */
+
+	restore_efuse_clk(CLK, reg0);
+	restore_efuse_clk(PCLK, reg1);
+
+	return 0;
+}
+
+/*user mode and auto mode*/
+int rk_efuse32_write(uint32_t addr, uint32_t val)
+{
+	uint32_t reg0 = 0, reg1 = 0, efuse_base = 0;
+
+	if (addr > 31)
+		return -1;
+
+	if (addr < 24)
+		efuse_base = EFUSE32_BASE;
+	if (addr > 23 && addr < 32)
+		efuse_base = EFUSE8_BASE;
+
+	//reg0 = enable_efuse_clk(CLK);
+	//reg1 = enable_efuse_clk(PCLK);
+
+#if EFUSE_AUTO_MODE
+	while (val) {
+		if (val & 0x01) {
+			write32((EFUSE_AUTO_ENABLE |
+				((addr & EFUSE_A_MASK) << EFUSE_A_SHIFT))
+				& (~EFUSE_AUTO_RD),
+				efuse_base + REG_EFUSE_AUTO_CTRL);
+			udelay(2);
+			while (1) {
+				if (read32(efuse_base + REG_EFUSE_INT_STATUS) &
+					   0x01)
+					break;
+			}
+			write32(read32(efuse_base + REG_EFUSE_AUTO_CTRL) &
+				(~EFUSE_AUTO_ENABLE),
+				efuse_base + REG_EFUSE_AUTO_CTRL);
+			write32(0x07, efuse_base + REG_EFUSE_INT_STATUS);
+			udelay(2);
+		}
+		addr += 32;
+		val = val >> 1;
+		udelay(2);
+	}
+#else
+	/* enable program in user mode */
+	write32((read32(efuse_base + REG_EFUSE_MOD) | EFUSE_PG_ENB_USER) &
+		(~EFUSE_RD_ENB_USER), efuse_base + REG_EFUSE_MOD);
+	write32(EFUSE_CSB | EFUSE_LOAD | EFUSE_PGENB,
+		efuse_base + REG_EFUSE_CTRL);
+	write32(read32(efuse_base + REG_EFUSE_CTRL) & (~EFUSE_CSB),
+		efuse_base + REG_EFUSE_CTRL);
+	write32(read32(efuse_base + REG_EFUSE_CTRL) & (~EFUSE_PGENB) &
+		(~EFUSE_LOAD), efuse_base + REG_EFUSE_CTRL);
+	udelay(2);
+
+	while (val) {
+		if (val & 0x01) {
+			write32(read32(efuse_base + REG_EFUSE_CTRL) &
+				(~(EFUSE_A_MASK << EFUSE_A_SHIFT)),
+				efuse_base + REG_EFUSE_CTRL);
+			write32(read32(efuse_base + REG_EFUSE_CTRL) |
+				((addr & EFUSE_A_MASK) << EFUSE_A_SHIFT),
+				efuse_base + REG_EFUSE_CTRL);
+			udelay(2);
+			write32(read32(efuse_base + REG_EFUSE_CTRL) |
+				EFUSE_STROBE, efuse_base + REG_EFUSE_CTRL);
+			udelay(10);
+			write32(read32(efuse_base + REG_EFUSE_CTRL) &
+				(~EFUSE_STROBE),
+				efuse_base + REG_EFUSE_CTRL);
+			udelay(2);
+		}
+		addr += 32;
+		val = val >> 1;
+	}
+
+	udelay(2);
+	write32(read32(efuse_base + REG_EFUSE_CTRL) | EFUSE_LOAD |
+		EFUSE_PGENB, efuse_base + REG_EFUSE_CTRL);
+	write32(read32(efuse_base + REG_EFUSE_CTRL) | EFUSE_CSB,
+		efuse_base + REG_EFUSE_CTRL);
+	udelay(1);
+#endif /* EFUSE_AUTO_MODE */
+
+	restore_efuse_clk(CLK, reg0);
+	restore_efuse_clk(PCLK, reg1);
+
+	return 0;
+}
+
+int rk_efuse32_read(uint32_t addr, uint32_t length, uint32_t *buf)
+{
+	if (!buf)
+		return -1;
+
+	if (addr > 23) {
+		if (length < 1 || length + addr > 32)
+			return -1;
+
+		memcpy(buf, efuse32_buf + addr, length * sizeof(uint32_t));
+	} else if (addr < 24) {
+		if (length < 1 || length + addr > 24)
+			return -1;
+
+		memcpy(buf, efuse32_buf + addr, length * sizeof(uint32_t));
+	}
+
+	return 0;
+}
+
+void mode_init(int sec)
+{
+	int reg;
+	uint32_t efuse_base = 0;
+
+	if (sec == 1)
+		efuse_base = EFUSE32_BASE;/*secure efuse addr*/
+	if (sec == 0)
+		efuse_base = EFUSE8_BASE;/*un_secure efsue addr*/
+
+#if EFUSE_AUTO_MODE
+	/* enable auto mode */
+	reg = read32(efuse_base + REG_EFUSE_MOD);
+	write32(reg & (~EFUSE_USER_MODE), efuse_base + REG_EFUSE_MOD);
+
+	/* enable finish & auto_s_access_ns_err & auto_ns_access_s_err int */
+	write32(0x07, efuse_base + REG_EFUSE_INT_CON);
+	write32((T_CSB_P_S << 16) | T_CSB_P_L,
+		efuse_base + REG_EFUSE_T_CSB_P);
+	write32((T_PGENB_P_S << 16) | T_PGENB_P_L,
+		efuse_base + REG_EFUSE_T_PGENB_P);
+	write32((T_LOAD_P_S << 16) | T_LOAD_P_L,
+		efuse_base + REG_EFUSE_T_LOAD_P);
+	write32((T_ADDR_P_S << 16) | T_ADDR_P_L,
+		efuse_base + REG_EFUSE_T_ADDR_P);
+	write32((T_STROBE_P_S << 16) | T_STROBE_P_L,
+		efuse_base + REG_EFUSE_T_STROBE_P);
+	write32((T_CSB_R_S << 16) | T_CSB_R_L,
+		efuse_base + REG_EFUSE_T_CSB_R);
+	write32((T_PGENB_R_S << 16) | T_PGENB_R_L,
+		efuse_base + REG_EFUSE_T_PGENB_R);
+	write32((T_LOAD_R_S << 16) | T_LOAD_R_L,
+		efuse_base + REG_EFUSE_T_LOAD_R);
+	write32((T_ADDR_R_S << 16) | T_ADDR_R_L,
+		efuse_base + REG_EFUSE_T_ADDR_R);
+	write32((T_STROBE_R_S << 16) | T_STROBE_R_L,
+		efuse_base + REG_EFUSE_T_STROBE_R);
+#else
+	reg = read32(efuse_base + REG_EFUSE_MOD);
+	write32(reg | EFUSE_USER_MODE, efuse_base + REG_EFUSE_MOD);
+#endif /* EFUSE_AUTO_MODE */
+}
+
+void rk_efuse_prog_en(int n)
+{
+	if (n == 1) {
+		write32(read32(GPIO2_BASE) & (~(0X1 << 3)), GPIO2_BASE);
+		write32((efuse_pwren | efuse_pwren << 16) |
+			((0) << 7 | efuse_pwren << 16 << 1),
+			GRF_BASE + GRF_GPIO2A_IOMUX);
+		/*efuse program enable*/
+		write32((1 << 7) | (1 << 7 << 16), SGRF_BASE +
+			EFUSE_SGRF_SOC_CON5);
+	} else {
+		write32((0 << 7) | (1 << 7 << 16),
+			SGRF_BASE + EFUSE_SGRF_SOC_CON5);
+		write32(0 << 6 | efuse_pwren << 16 |
+			((0) << 7 | efuse_pwren << 16 << 1),
+			GRF_BASE + GRF_GPIO2A_IOMUX);
+		write32(read32(GPIO2_BASE) | (0X1 << 3), GPIO2_BASE);
+	}
+}
+
+int rk_efuse_init(void)
+{
+	mode_init(1);
+	mode_init(0);
+
+	if (rk_efuse32_readregs(RK322XH_S_EFUSE_START,
+				RK322XH_S_EFUSE_WORDS,
+				efuse32_buf)) {
+		ERROR("read S-efuse failed!!!!\n");
+		return -1;
+	}
+
+	if (rk_efuse32_readregs(RK322XH_NS_EFUSE_START,
+				RK322XH_NS_EFUSE_WORDS,
+				efuse32_buf + RK322XH_NS_EFUSE_START)) {
+		ERROR("read NS-efuse failed!!!!\n");
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/plat/rockchip/rk3328/drivers/efuse/efuse.h b/plat/rockchip/rk3328/drivers/efuse/efuse.h
new file mode 100644
index 0000000..22275c2
--- /dev/null
+++ b/plat/rockchip/rk3328/drivers/efuse/efuse.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2016, Fuzhou Rockchip Electronics Co., Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef EFUSE_H
+#define EFUSE_H
+
+#include <platform_def.h>
+
+/* CRU controller register */
+#define CRU_WRITE_MASK		(16)
+
+#define GRF_GPIO2A_IOMUX	(0x0020)
+#define EFUSE_SGRF_SOC_CON5	(0X0014)
+
+#define CRU_CLKGATE_CON2	(0x0208)
+#define CRU_CLKGATE_CON15	(0x023C)
+#define EFUSE_SRC_CLK_EN	(1 << 13)
+#define EFUSE_1024_PCLK_EN	(1 << 9)
+
+#define RK322XH_S_EFUSE_START	0
+#define RK322XH_S_EFUSE_WORDS	24
+#define RK322XH_NS_EFUSE_START	(RK322XH_S_EFUSE_START + RK322XH_S_EFUSE_WORDS)
+#define RK322XH_NS_EFUSE_WORDS	8
+
+/* SGRF controller register */
+#define SGRF_WRITE_MASK		(16)
+
+/* eFuse controller register */
+#define CRU_CLKSEL_CON5		(0x0114)
+#define REG_EFUSE_MOD		(0x0000)
+#define efuse_pwren		(1 << 6)
+#define EFUSE_RD_ENB_USER	(1 << 6)
+#define EFUSE_PG_ENB_USER	(1 << 5)
+#define EFUSE_STROBE_POL	(1 << 4)
+#define EFUSE_LOAD_POL		(1 << 3)
+#define EFUSE_PGENB_POL		(1 << 2)
+#define EFUSE_CSB_POL		(1 << 1)
+/* 0:auto mode; 1:user mode */
+#define EFUSE_USER_MODE		(1 << 0)
+
+#define REG_EFUSE_RD_MASK_S	(0x0004)
+#define REG_EFUSE_PG_MASK_S	(0x0008)
+
+#define REG_EFUSE_RD_MASK_NS	(0x000C)
+#define REG_EFUSE_PG_MASK_NS	(0x0010)
+
+#define REG_EFUSE_INT_CON	(0x0014)
+#define REG_EFUSE_INT_STATUS	(0x0018)
+#define REG_EFUSE_USER_CTRL	(0x001C)
+#define EFUSE_A_SHIFT		(16)
+#define EFUSE_A_MASK		(0x3FF)
+#define EFUSE_PGENB		(1 << 3) /* active low */
+#define EFUSE_LOAD		(1 << 2)
+#define EFUSE_STROBE		(1 << 1)
+#define EFUSE_CSB		(1 << 0) /* active low */
+#define REG_EFUSE_DOUT		(0x0020)
+#define REG_EFUSE_AUTO_CTRL	(0x0024)
+/* 0:programming mode; 1:read mode */
+#define EFUSE_AUTO_RD		(1 << 1)
+#define EFUSE_AUTO_ENABLE	(1 << 0)
+
+#define EFUSE_PG_ENB_MODE	(0 << 1)
+
+#define REG_EFUSE_T_CSB_P	(0x0028)
+#define REG_EFUSE_T_PGENB_P	(0x002C)
+#define REG_EFUSE_T_LOAD_P	(0x0030)
+#define REG_EFUSE_T_ADDR_P	(0x0034)
+#define REG_EFUSE_T_STROBE_P	(0x0038)
+#define REG_EFUSE_T_CSB_R	(0x003C)
+#define REG_EFUSE_T_PGENB_R	(0x0040)
+#define REG_EFUSE_T_LOAD_R	(0x0044)
+#define REG_EFUSE_T_ADDR_R	(0x0048)
+#define REG_EFUSE_T_STROBE_R	(0x004C)
+#define REG_EFUSE_REVISION	(0x0050)
+#define REG_EFUSE_CTRL		REG_EFUSE_USER_CTRL
+
+#define T_CSB_P_S		1
+#define T_PGENB_P_S		1
+#define T_LOAD_P_S		1
+#define T_ADDR_P_S		1
+#define T_STROBE_P_S		2
+#define T_CSB_P_L		241
+#define T_PGENB_P_L		241
+#define T_LOAD_P_L		241
+#define T_ADDR_P_L		241
+#define T_STROBE_P_L		240
+#define T_CSB_R_S		1
+#define T_PGENB_R_S		1
+#define T_LOAD_R_S		1
+#define T_ADDR_R_S		1
+#define T_STROBE_R_S		2
+#define T_CSB_R_L		4
+#define T_PGENB_R_L		4
+#define T_LOAD_R_L		4
+#define T_ADDR_R_L		4
+#define T_STROBE_R_L		3
+
+/*
+ * readregs function is real-time read, from the efuse hardware.
+ * read function is not real-time read, read the value stored in
+ * memory when machine starting up.
+ */
+int rk_efuse8_readregs(uint32_t addr, uint32_t length, uint8_t *buf);
+int rk_efuse8_write(uint32_t addr, uint8_t val);
+
+int rk_efuse32_readregs(uint32_t addr, uint32_t length, uint32_t *buf);
+int rk_efuse32_write(uint32_t addr, uint32_t val);
+int rk_efuse32_read(uint32_t addr, uint32_t length, uint32_t *buf);
+
+int enable_efuse_clk();
+
+void mode_init(int sec);
+void rk_efuse_prog_en(int n);
+
+int rk_efuse_init(void);
+
+#endif /* RK_EFUSE_H */
+
diff --git a/plat/rockchip/rk3328/drivers/soc/soc.c b/plat/rockchip/rk3328/drivers/soc/soc.c
index 306308f..48a001c 100644
--- a/plat/rockchip/rk3328/drivers/soc/soc.c
+++ b/plat/rockchip/rk3328/drivers/soc/soc.c
@@ -16,6 +16,7 @@
 #include <plat_private.h>
 #include <rk3328_def.h>
 #include <soc.h>
+#include <efuse.h>
 
 /* Table of regions to map using the MMU. */
 const mmap_region_t plat_rk_mmap[] = {
@@ -153,6 +154,11 @@ void plat_rockchip_soc_init(void)
 	secure_timer_init();
 	sgrf_init();
 
+	mode_init(1);
+	mode_init(0);
+
+	enable_efuse_clk();
+
 	NOTICE("BL31:Rockchip release version: v%d.%d\n",
 	       MAJOR_VERSION, MINOR_VERSION);
 }
diff --git a/plat/rockchip/rk3328/platform.mk b/plat/rockchip/rk3328/platform.mk
index 5b4766d..4ff5a7a 100644
--- a/plat/rockchip/rk3328/platform.mk
+++ b/plat/rockchip/rk3328/platform.mk
@@ -22,6 +22,7 @@ PLAT_INCLUDES		:=	-Idrivers/arm/gic/common/			\
 				-I${RK_PLAT_SOC}/				\
 				-I${RK_PLAT_SOC}/drivers/pmu/			\
 				-I${RK_PLAT_SOC}/drivers/soc/			\
+				-I${RK_PLAT_SOC}/drivers/efuse/			\
 				-I${RK_PLAT_SOC}/include/
 
 RK_GIC_SOURCES		:=	${GICV2_SOURCES}				\
@@ -54,7 +55,8 @@ BL31_SOURCES		+=	${RK_GIC_SOURCES}				\
 				${RK_PLAT_COMMON}/plat_topology.c		\
 				${RK_PLAT_COMMON}/aarch64/platform_common.c	\
 				${RK_PLAT_SOC}/drivers/pmu/pmu.c		\
-				${RK_PLAT_SOC}/drivers/soc/soc.c
+				${RK_PLAT_SOC}/drivers/soc/soc.c		\
+				${RK_PLAT_SOC}/drivers/efuse/efuse.c
 
 ifdef PLAT_RK_SECURE_DDR_MINILOADER
 BL31_SOURCES		+=	${RK_PLAT_COMMON}/drivers/parameter/ddr_parameter.c
-- 
2.30.2

