2 * arch/arm/mach-tegra/fuse.c
4 * Copyright (C) 2010 Google, Inc.
7 * Colin Cross <ccross@android.com>
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
20 #include <linux/kernel.h>
22 #include <linux/dma-mapping.h>
23 #include <linux/spinlock.h>
24 #include <linux/completion.h>
25 #include <linux/sched.h>
26 #include <linux/mutex.h>
29 #include <mach/iomap.h>
33 #define FUSE_UID_LOW 0x108
34 #define FUSE_UID_HIGH 0x10c
35 #define FUSE_SKU_INFO 0x110
36 #define FUSE_SPARE_BIT 0x200
38 static DEFINE_MUTEX(tegra_fuse_dma_lock);
40 #ifdef CONFIG_TEGRA_SYSTEM_DMA
41 static struct tegra_dma_channel *tegra_fuse_dma;
42 static u32 *tegra_fuse_bb;
43 static dma_addr_t tegra_fuse_bb_phys;
44 static DECLARE_COMPLETION(tegra_fuse_wait);
46 static void fuse_dma_complete(struct tegra_dma_req *req)
48 complete(&tegra_fuse_wait);
51 static inline u32 fuse_readl(unsigned long offset)
53 struct tegra_dma_req req;
57 return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
59 mutex_lock(&tegra_fuse_dma_lock);
60 req.complete = fuse_dma_complete;
62 req.dest_addr = tegra_fuse_bb_phys;
63 req.dest_bus_width = 32;
65 req.source_addr = TEGRA_FUSE_BASE + offset;
66 req.source_bus_width = 32;
71 INIT_COMPLETION(tegra_fuse_wait);
73 tegra_dma_enqueue_req(tegra_fuse_dma, &req);
75 ret = wait_for_completion_timeout(&tegra_fuse_wait,
76 msecs_to_jiffies(50));
78 if (WARN(ret == 0, "fuse read dma timed out"))
79 *(u32 *)tegra_fuse_bb = 0;
81 mutex_unlock(&tegra_fuse_dma_lock);
82 return *((u32 *)tegra_fuse_bb);
85 static inline void fuse_writel(u32 value, unsigned long offset)
87 struct tegra_dma_req req;
90 if (!tegra_fuse_dma) {
91 writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
95 mutex_lock(&tegra_fuse_dma_lock);
96 *((u32 *)tegra_fuse_bb) = value;
97 req.complete = fuse_dma_complete;
99 req.dest_addr = TEGRA_FUSE_BASE + offset;
101 req.dest_bus_width = 32;
102 req.source_addr = tegra_fuse_bb_phys;
103 req.source_bus_width = 32;
108 INIT_COMPLETION(tegra_fuse_wait);
110 tegra_dma_enqueue_req(tegra_fuse_dma, &req);
112 ret = wait_for_completion_timeout(&tegra_fuse_wait,
113 msecs_to_jiffies(50));
115 mutex_unlock(&tegra_fuse_dma_lock);
118 static inline u32 fuse_readl(unsigned long offset)
120 return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
123 static inline void fuse_writel(u32 value, unsigned long offset)
125 writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
129 u32 tegra_fuse_readl(unsigned long offset)
131 return fuse_readl(offset);
134 void tegra_fuse_writel(u32 value, unsigned long offset)
136 fuse_writel(value, offset);
139 void tegra_init_fuse(void)
141 u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
143 writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
145 pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n",
146 tegra_sku_id(), tegra_cpu_process_id(),
147 tegra_core_process_id());
150 void tegra_init_fuse_dma(void)
152 #ifdef CONFIG_TEGRA_SYSTEM_DMA
153 tegra_fuse_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
155 if (!tegra_fuse_dma) {
156 pr_err("%s: can not allocate dma channel\n", __func__);
160 tegra_fuse_bb = dma_alloc_coherent(NULL, sizeof(u32),
161 &tegra_fuse_bb_phys, GFP_KERNEL);
162 if (!tegra_fuse_bb) {
163 pr_err("%s: can not allocate bounce buffer\n", __func__);
164 tegra_dma_free_channel(tegra_fuse_dma);
165 tegra_fuse_dma = NULL;
171 unsigned long long tegra_chip_uid(void)
173 unsigned long long lo, hi;
175 lo = fuse_readl(FUSE_UID_LOW);
176 hi = fuse_readl(FUSE_UID_HIGH);
177 return (hi << 32ull) | lo;
180 int tegra_sku_id(void)
183 u32 reg = fuse_readl(FUSE_SKU_INFO);
188 int tegra_cpu_process_id(void)
191 u32 reg = fuse_readl(FUSE_SPARE_BIT);
192 cpu_process_id = (reg >> 6) & 3;
193 return cpu_process_id;
196 int tegra_core_process_id(void)
199 u32 reg = fuse_readl(FUSE_SPARE_BIT);
200 core_process_id = (reg >> 12) & 3;
201 return core_process_id;