From 1f90a35f3bc651203c9ff1a2fef7f1b14c76e1a1 Mon Sep 17 00:00:00 2001 From: Jon Mayo Date: Wed, 5 Jan 2011 11:18:46 -0800 Subject: [PATCH] [ARM] tegra: kfuse driver factory programmed encrypted key fuses held in kfuse module. use APB DMA for accessing kfuse registers, reading directly can hang if any other DMA is active. Change-Id: I85e44cc169607bc22116075e28938014aa299d75 Reviewed-by: Jon Mayo Tested-by: Jon Mayo Reviewed-by: Yu-Huan Hsu Signed-off-by: Jon Mayo --- arch/arm/mach-tegra/Makefile | 1 + arch/arm/mach-tegra/include/mach/kfuse.h | 20 ++++++ arch/arm/mach-tegra/kfuse.c | 88 ++++++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 arch/arm/mach-tegra/include/mach/kfuse.h create mode 100644 arch/arm/mach-tegra/kfuse.c diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 2223fee1aa92..985c4e1e4ef1 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -11,6 +11,7 @@ obj-y += delay.o obj-y += powergate.o obj-y += suspend.o obj-y += fuse.o +obj-y += kfuse.o obj-y += tegra_i2s_audio.o obj-y += tegra_spdif_audio.o obj-y += mc.o diff --git a/arch/arm/mach-tegra/include/mach/kfuse.h b/arch/arm/mach-tegra/include/mach/kfuse.h new file mode 100644 index 000000000000..cfe85cc86ff2 --- /dev/null +++ b/arch/arm/mach-tegra/include/mach/kfuse.h @@ -0,0 +1,20 @@ +/* + * arch/arm/mach-tegra/kfuse.h + * + * Copyright (C) 2010-2011 NVIDIA Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* there are 144 32-bit values in total */ +#define KFUSE_DATA_SZ (144 * 4) + +int tegra_kfuse_read(void *dest, size_t len); diff --git a/arch/arm/mach-tegra/kfuse.c b/arch/arm/mach-tegra/kfuse.c new file mode 100644 index 000000000000..f5de828bb508 --- /dev/null +++ b/arch/arm/mach-tegra/kfuse.c @@ -0,0 +1,88 @@ +/* + * arch/arm/mach-tegra/kfuse.c + * + * Copyright (C) 2010-2011 NVIDIA Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* The kfuse block stores downstream and upstream HDCP keys for use by HDMI + * module. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "apbio.h" + +/* register definition */ +#define KFUSE_STATE 0x80 +#define KFUSE_STATE_DONE (1u << 16) +#define KFUSE_STATE_CRCPASS (1u << 17) +#define KFUSE_KEYADDR 0x88 +#define KFUSE_KEYADDR_AUTOINC (1u << 16) +#define KFUSE_KEYS 0x8c + +static inline u32 tegra_kfuse_readl(unsigned long offset) +{ + return tegra_apb_readl(TEGRA_KFUSE_BASE + offset); +} + +static inline void tegra_kfuse_writel(u32 value, unsigned long offset) +{ + tegra_apb_writel(value, TEGRA_KFUSE_BASE + offset); +} + +static int wait_for_done(void) +{ + u32 reg; + int retries = 50; + do { + reg = tegra_kfuse_readl(KFUSE_STATE); + if (reg & KFUSE_STATE_DONE); + return 0; + msleep(10); + } while(--retries); + return -ETIMEDOUT; +} + +/* read up to KFUSE_DATA_SZ bytes into dest. + * always starts at the first kfuse. + */ +int tegra_kfuse_read(void *dest, size_t len) +{ + u32 v; + unsigned cnt; + + if (len > KFUSE_DATA_SZ) + return -EINVAL; + + tegra_kfuse_writel(KFUSE_KEYADDR_AUTOINC, KFUSE_KEYADDR); + wait_for_done(); + + if ((tegra_kfuse_readl(KFUSE_STATE) & KFUSE_STATE_CRCPASS) == 0) { + pr_err("kfuse: crc failed\n"); + return -EIO; + } + + for (cnt = 0; cnt < len; cnt += 4) { + v = tegra_kfuse_readl(KFUSE_KEYS); + memcpy(dest + cnt, &v, sizeof v); + } + + return 0; +} -- 2.34.1