rockchip: kernel add efuse support
author陈亮 <cl@rock-chips.com>
Mon, 28 Jul 2014 11:51:31 +0000 (04:51 -0700)
committer陈亮 <cl@rock-chips.com>
Mon, 28 Jul 2014 11:51:31 +0000 (04:51 -0700)
Signed-off-by: 陈亮 <cl@rock-chips.com>
arch/arm/mach-rockchip/Makefile
arch/arm/mach-rockchip/efuse.c [new file with mode: 0644]
arch/arm/mach-rockchip/efuse.h [new file with mode: 0644]

index 367a0aea6d76c6afe71934707c13f244bac5bf9a..6ac8c76fc4e70c46c1c15cbe4d3c4119303fc3d1 100755 (executable)
@@ -3,6 +3,7 @@ obj-y += cpu.o
 obj-y += rk3188.o
 obj-y += rk3288.o
 obj-y += ddr_freq.o
+obj-y += efuse.o
 obj-y += rk_system_status.o
 obj-$(CONFIG_PM) += rockchip_pm.o sleep.o
 obj-$(CONFIG_RK_FPGA) += fpga.o
diff --git a/arch/arm/mach-rockchip/efuse.c b/arch/arm/mach-rockchip/efuse.c
new file mode 100644 (file)
index 0000000..89d3d6c
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2013 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/rockchip/iomap.h>
+#include <linux/kobject.h>
+#include "efuse.h"
+
+#define efuse_readl(offset) readl_relaxed(RK_EFUSE_VIRT + offset)
+#define efuse_writel(val, offset) writel_relaxed(val, RK_EFUSE_VIRT + offset)
+
+static u8 efuse_buf[32 + 1] = {0, 0};
+
+static int efuse_readregs(u32 addr, u32 length, u8 *buf)
+{
+#ifndef efuse_readl
+       return 0;
+#else
+       unsigned long flags;
+       static DEFINE_SPINLOCK(efuse_lock);
+       int ret = length;
+
+       if (!length)
+               return 0;
+
+       spin_lock_irqsave(&efuse_lock, flags);
+
+       efuse_writel(EFUSE_CSB, REG_EFUSE_CTRL);
+       efuse_writel(EFUSE_LOAD | EFUSE_PGENB, REG_EFUSE_CTRL);
+       udelay(2);
+       do {
+               efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
+                       (~(EFUSE_A_MASK << EFUSE_A_SHIFT)), REG_EFUSE_CTRL);
+               efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
+                       ((addr & EFUSE_A_MASK) << EFUSE_A_SHIFT),
+                       REG_EFUSE_CTRL);
+               udelay(2);
+               efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
+                               EFUSE_STROBE, REG_EFUSE_CTRL);
+               udelay(2);
+               *buf = efuse_readl(REG_EFUSE_DOUT);
+               efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
+                               (~EFUSE_STROBE), REG_EFUSE_CTRL);
+               udelay(2);
+               buf++;
+               addr++;
+       } while (--length);
+       udelay(2);
+       efuse_writel(efuse_readl(REG_EFUSE_CTRL) | EFUSE_CSB, REG_EFUSE_CTRL);
+       udelay(1);
+
+       spin_unlock_irqrestore(&efuse_lock, flags);
+       return ret;
+#endif
+}
+
+/*
+static int efuse_writeregs(u32 addr, u32 length, u8 *buf)
+{
+       u32 j=0;
+       unsigned long flags;
+       static DEFINE_SPINLOCK(efuse_lock);
+       spin_lock_irqsave(&efuse_lock, flags);
+
+       efuse_writel(EFUSE_CSB|EFUSE_LOAD|EFUSE_PGENB,REG_EFUSE_CTRL);
+       udelay(10);
+       efuse_writel((~EFUSE_PGENB)&(efuse_readl(REG_EFUSE_CTRL)),
+               REG_EFUSE_CTRL);
+       udelay(10);
+       efuse_writel((~(EFUSE_LOAD | EFUSE_CSB))&(efuse_readl(REG_EFUSE_CTRL)),
+               REG_EFUSE_CTRL);
+       udelay(1);
+
+       do {
+               for(j=0; j<8; j++){
+                       if(*buf & (1<<j)){
+                               efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
+                                       (~(EFUSE_A_MASK << EFUSE_A_SHIFT)),
+                                       REG_EFUSE_CTRL);
+                               efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
+                                       (((addr + (j<<5))&EFUSE_A_MASK) << EFUSE_A_SHIFT),
+                                       REG_EFUSE_CTRL);
+                               udelay(1);
+                               efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
+                               EFUSE_STROBE, REG_EFUSE_CTRL);
+                               udelay(10);
+                               efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
+                               (~EFUSE_STROBE), REG_EFUSE_CTRL);
+                               udelay(1);
+                       }
+               }
+               buf++;
+               addr++;
+       } while (--length);
+
+       udelay(1);
+       efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
+               EFUSE_CSB | EFUSE_LOAD, REG_EFUSE_CTRL);
+       udelay(1);
+       efuse_writel(efuse_readl(REG_EFUSE_CTRL)|EFUSE_PGENB, REG_EFUSE_CTRL);
+       udelay(1);
+
+       spin_unlock_irqrestore(&efuse_lock, flags);
+       return 0;
+}
+*/
+
+int rockchip_efuse_version(void)
+{
+       int ret = efuse_buf[4] & (~(0x1 << 3));
+       return ret;
+}
+
+int rockchip_get_leakage(int ch)
+{
+       if ((ch < 0) || (ch > 2))
+               return 0;
+
+       return efuse_buf[23+ch];
+}
+
+static int efuse_init(void)
+{
+       efuse_readregs(0, 32, efuse_buf);
+
+       return 0;
+}
+
+core_initcall(efuse_init);
diff --git a/arch/arm/mach-rockchip/efuse.h b/arch/arm/mach-rockchip/efuse.h
new file mode 100644 (file)
index 0000000..77b26fb
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _EFUSE_H_
+#define _EFUSE_H_
+
+#include <asm/types.h>
+
+/* eFuse controller register */
+#define EFUSE_A_SHIFT          (6)
+#define EFUSE_A_MASK           (0x3FF)
+//#define EFUSE_PD             (1 << 5)
+//#define EFUSE_PS             (1 << 4)
+#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_CTRL         (0x0000)
+#define REG_EFUSE_DOUT         (0x0004)
+
+#define ARM_LEAKAGE_CH 0
+#define GPU_LEAKAGE_CH 1
+#define LOG_LEAKAGE_CH 2
+
+int rockchip_efuse_version(void);
+int rockchip_get_leakage(int ch);
+#endif