aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/kfuse.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/kfuse.c')
-rw-r--r--arch/arm/mach-tegra/kfuse.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/kfuse.c b/arch/arm/mach-tegra/kfuse.c
new file mode 100644
index 00000000000..9e4b482e469
--- /dev/null
+++ b/arch/arm/mach-tegra/kfuse.c
@@ -0,0 +1,114 @@
1/*
2 * arch/arm/mach-tegra/kfuse.c
3 *
4 * Copyright (C) 2010-2011 NVIDIA Corporation.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17/* The kfuse block stores downstream and upstream HDCP keys for use by HDMI
18 * module.
19 */
20
21#include <linux/kernel.h>
22#include <linux/io.h>
23#include <linux/err.h>
24#include <linux/string.h>
25#include <linux/delay.h>
26#include <linux/clk.h>
27
28#include <mach/iomap.h>
29#include <mach/kfuse.h>
30
31#include "clock.h"
32#include "apbio.h"
33
34static struct clk *kfuse_clk = NULL;
35
36/* register definition */
37#define KFUSE_STATE 0x80
38#define KFUSE_STATE_DONE (1u << 16)
39#define KFUSE_STATE_CRCPASS (1u << 17)
40#define KFUSE_KEYADDR 0x88
41#define KFUSE_KEYADDR_AUTOINC (1u << 16)
42#define KFUSE_KEYS 0x8c
43
44static inline u32 tegra_kfuse_readl(unsigned long offset)
45{
46 return tegra_apb_readl(TEGRA_KFUSE_BASE + offset);
47}
48
49static inline void tegra_kfuse_writel(u32 value, unsigned long offset)
50{
51 tegra_apb_writel(value, TEGRA_KFUSE_BASE + offset);
52}
53
54static int wait_for_done(void)
55{
56 u32 reg;
57 int retries = 50;
58 do {
59 reg = tegra_kfuse_readl(KFUSE_STATE);
60 if (reg & KFUSE_STATE_DONE)
61 return 0;
62 msleep(10);
63 } while(--retries);
64 return -ETIMEDOUT;
65}
66
67/* read up to KFUSE_DATA_SZ bytes into dest.
68 * always starts at the first kfuse.
69 */
70int tegra_kfuse_read(void *dest, size_t len)
71{
72 int err;
73 u32 v;
74 unsigned cnt;
75
76 if (len > KFUSE_DATA_SZ)
77 return -EINVAL;
78
79 if (kfuse_clk == NULL) {
80 kfuse_clk = tegra_get_clock_by_name("kfuse");
81 if (IS_ERR_OR_NULL(kfuse_clk)) {
82 pr_err("kfuse: can't get kfuse clock\n");
83 return -EINVAL;
84 }
85 }
86
87 err = clk_enable(kfuse_clk);
88 if (err)
89 return err;
90
91 tegra_kfuse_writel(KFUSE_KEYADDR_AUTOINC, KFUSE_KEYADDR);
92
93 err = wait_for_done();
94 if (err) {
95 pr_err("kfuse: read timeout\n");
96 clk_disable(kfuse_clk);
97 return err;
98 }
99
100 if ((tegra_kfuse_readl(KFUSE_STATE) & KFUSE_STATE_CRCPASS) == 0) {
101 pr_err("kfuse: crc failed\n");
102 clk_disable(kfuse_clk);
103 return -EIO;
104 }
105
106 for (cnt = 0; cnt < len; cnt += 4) {
107 v = tegra_kfuse_readl(KFUSE_KEYS);
108 memcpy(dest + cnt, &v, sizeof v);
109 }
110
111 clk_disable(kfuse_clk);
112
113 return 0;
114}