aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-mvebu/efuse.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-mvebu/efuse.c')
-rw-r--r--arch/arm/mach-mvebu/efuse.c83
1 files changed, 81 insertions, 2 deletions
diff --git a/arch/arm/mach-mvebu/efuse.c b/arch/arm/mach-mvebu/efuse.c
index 80318c339e..be5dc0e07d 100644
--- a/arch/arm/mach-mvebu/efuse.c
+++ b/arch/arm/mach-mvebu/efuse.c
@@ -10,6 +10,7 @@
#include <asm/arch/cpu.h>
#include <asm/arch/efuse.h>
#include <asm/arch/soc.h>
+#include <asm/gpio.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/mbus.h>
@@ -56,17 +57,48 @@ static struct mvebu_hd_efuse *get_efuse_line(int nr)
return efuses + nr;
}
-static void enable_efuse_program(void)
+#ifndef DRY_RUN
+static int vhv_gpio;
+#endif
+
+static int enable_efuse_program(void)
{
#ifndef DRY_RUN
+ if (CONFIG_MVEBU_EFUSE_VHV_GPIO[0]) {
+ if (gpio_lookup_name(CONFIG_MVEBU_EFUSE_VHV_GPIO, NULL, NULL, &vhv_gpio)) {
+ printf("Error: VHV gpio lookup failed\n");
+ return -EOPNOTSUPP;
+ }
+ if (gpio_request(vhv_gpio, CONFIG_MVEBU_EFUSE_VHV_GPIO)) {
+ printf("Error: VHV gpio request failed\n");
+ return -EOPNOTSUPP;
+ }
+ if (gpio_direction_output(vhv_gpio,
+ IS_ENABLED(CONFIG_MVEBU_EFUSE_VHV_GPIO_ACTIVE_LOW) ? 0 : 1)) {
+ printf("Error: VHV gpio enable failed\n");
+ return -EINVAL;
+ }
+ mdelay(5); /* Wait for the VHV power to stabilize */
+ }
+
setbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_CTRL_PROGRAM_ENABLE);
#endif
+
+ return 0;
}
static void disable_efuse_program(void)
{
#ifndef DRY_RUN
clrbits_le32(MVEBU_EFUSE_CONTROL, MVEBU_EFUSE_CTRL_PROGRAM_ENABLE);
+
+ if (CONFIG_MVEBU_EFUSE_VHV_GPIO[0]) {
+ if (gpio_direction_output(vhv_gpio,
+ IS_ENABLED(CONFIG_MVEBU_EFUSE_VHV_GPIO_ACTIVE_LOW) ? 1 : 0))
+ printf("Error: VHV gpio disable failed\n");
+ gpio_free(vhv_gpio);
+ vhv_gpio = 0;
+ }
#endif
}
@@ -123,7 +155,9 @@ static int prog_efuse(int nr, struct efuse_val *new_val, u32 mask0, u32 mask1)
if (!new_val->dwords.d[0] && !new_val->dwords.d[1] && (mask0 | mask1))
return 0;
- enable_efuse_program();
+ res = enable_efuse_program();
+ if (res)
+ return res;
res = do_prog_efuse(efuse, new_val, mask0, mask1);
@@ -132,6 +166,48 @@ static int prog_efuse(int nr, struct efuse_val *new_val, u32 mask0, u32 mask1)
return res;
}
+int mvebu_prog_ld_efuse(int ld1, u32 word, u32 val)
+{
+ int i, res;
+ u32 line[EFUSE_LD_WORDS];
+
+ res = mvebu_efuse_init_hw();
+ if (res)
+ return res;
+
+ mvebu_read_ld_efuse(ld1, line);
+
+ /* check if lock bit is already programmed */
+ if (line[EFUSE_LD_WORDS - 1])
+ return -EPERM;
+
+ /* check if word is valid */
+ if (word >= EFUSE_LD_WORDS)
+ return -EINVAL;
+
+ /* check if there is some bit for programming */
+ if (val == (line[word] & val))
+ return 0;
+
+ res = enable_efuse_program();
+ if (res)
+ return res;
+
+ mvebu_read_ld_efuse(ld1, line);
+ line[word] |= val;
+
+ for (i = 0; i < EFUSE_LD_WORDS; i++) {
+ writel(line[i], ld_efuses + i);
+ mdelay(1);
+ }
+
+ mdelay(5);
+
+ disable_efuse_program();
+
+ return 0;
+}
+
int mvebu_efuse_init_hw(void)
{
int ret;
@@ -254,6 +330,9 @@ int fuse_prog(u32 bank, u32 word, u32 val)
{
int res = 0;
+ if (bank == EFUSE_LD0_LINE || bank == EFUSE_LD1_LINE)
+ return mvebu_prog_ld_efuse(bank == EFUSE_LD1_LINE, word, val);
+
/*
* NOTE: Fuse line should be written as whole.
* So how can we do that with this API?