fcb6d05495fba8f8f536d93db64b0fd24a1f3c67
[linux-2.6.git] / arch / arm / mach-tegra / fuse.c
1 /*
2  * arch/arm/mach-tegra/fuse.c
3  *
4  * Copyright (C) 2010 Google, Inc.
5  *
6  * Author:
7  *      Colin Cross <ccross@android.com>
8  *
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.
12  *
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.
17  *
18  */
19
20 #include <linux/kernel.h>
21 #include <linux/io.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>
27
28 #include <mach/dma.h>
29 #include <mach/iomap.h>
30
31 #include "fuse.h"
32
33 #define FUSE_UID_LOW            0x108
34 #define FUSE_UID_HIGH           0x10c
35 #define FUSE_SKU_INFO           0x110
36 #define FUSE_SPARE_BIT          0x200
37
38 static DEFINE_MUTEX(tegra_fuse_dma_lock);
39
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);
45
46 static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
47         [TEGRA_REVISION_UNKNOWN] = "unknown",
48         [TEGRA_REVISION_A02] = "A02",
49         [TEGRA_REVISION_A03] = "A03",
50         [TEGRA_REVISION_A03p] = "A03 prime",
51 };
52
53 static void fuse_dma_complete(struct tegra_dma_req *req)
54 {
55         complete(&tegra_fuse_wait);
56 }
57
58 static inline u32 fuse_readl(unsigned long offset)
59 {
60         struct tegra_dma_req req;
61         int ret;
62
63         if (!tegra_fuse_dma)
64                 return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
65
66         mutex_lock(&tegra_fuse_dma_lock);
67         req.complete = fuse_dma_complete;
68         req.to_memory = 1;
69         req.dest_addr = tegra_fuse_bb_phys;
70         req.dest_bus_width = 32;
71         req.dest_wrap = 1;
72         req.source_addr = TEGRA_FUSE_BASE + offset;
73         req.source_bus_width = 32;
74         req.source_wrap = 4;
75         req.req_sel = 0;
76         req.size = 4;
77
78         INIT_COMPLETION(tegra_fuse_wait);
79
80         tegra_dma_enqueue_req(tegra_fuse_dma, &req);
81
82         ret = wait_for_completion_timeout(&tegra_fuse_wait,
83                 msecs_to_jiffies(50));
84
85         if (WARN(ret == 0, "fuse read dma timed out"))
86                 *(u32 *)tegra_fuse_bb = 0;
87
88         mutex_unlock(&tegra_fuse_dma_lock);
89         return *((u32 *)tegra_fuse_bb);
90 }
91
92 static inline void fuse_writel(u32 value, unsigned long offset)
93 {
94         struct tegra_dma_req req;
95         int ret;
96
97         if (!tegra_fuse_dma) {
98                 writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
99                 return;
100         }
101
102         mutex_lock(&tegra_fuse_dma_lock);
103         *((u32 *)tegra_fuse_bb) = value;
104         req.complete = fuse_dma_complete;
105         req.to_memory = 0;
106         req.dest_addr = TEGRA_FUSE_BASE + offset;
107         req.dest_wrap = 4;
108         req.dest_bus_width = 32;
109         req.source_addr = tegra_fuse_bb_phys;
110         req.source_bus_width = 32;
111         req.source_wrap = 1;
112         req.req_sel = 0;
113         req.size = 4;
114
115         INIT_COMPLETION(tegra_fuse_wait);
116
117         tegra_dma_enqueue_req(tegra_fuse_dma, &req);
118
119         ret = wait_for_completion_timeout(&tegra_fuse_wait,
120                 msecs_to_jiffies(50));
121
122         mutex_unlock(&tegra_fuse_dma_lock);
123 }
124 #else
125 static inline u32 fuse_readl(unsigned long offset)
126 {
127         return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
128 }
129
130 static inline void fuse_writel(u32 value, unsigned long offset)
131 {
132         writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
133 }
134 #endif
135
136 u32 tegra_fuse_readl(unsigned long offset)
137 {
138         return fuse_readl(offset);
139 }
140
141 void tegra_fuse_writel(u32 value, unsigned long offset)
142 {
143         fuse_writel(value, offset);
144 }
145
146 static inline bool get_spare_fuse(int bit)
147 {
148         return fuse_readl(FUSE_SPARE_BIT + bit * 4);
149 }
150
151 void tegra_init_fuse(void)
152 {
153         u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
154         reg |= 1 << 28;
155         writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
156
157         pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
158                 tegra_revision_name[tegra_get_revision()],
159                 tegra_sku_id(), tegra_cpu_process_id(),
160                 tegra_core_process_id());
161 }
162
163 void tegra_init_fuse_dma(void)
164 {
165 #ifdef CONFIG_TEGRA_SYSTEM_DMA
166         tegra_fuse_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
167                 TEGRA_DMA_SHARED);
168         if (!tegra_fuse_dma) {
169                 pr_err("%s: can not allocate dma channel\n", __func__);
170                 return;
171         }
172
173         tegra_fuse_bb = dma_alloc_coherent(NULL, sizeof(u32),
174                 &tegra_fuse_bb_phys, GFP_KERNEL);
175         if (!tegra_fuse_bb) {
176                 pr_err("%s: can not allocate bounce buffer\n", __func__);
177                 tegra_dma_free_channel(tegra_fuse_dma);
178                 tegra_fuse_dma = NULL;
179                 return;
180         }
181 #endif
182 }
183
184 unsigned long long tegra_chip_uid(void)
185 {
186         unsigned long long lo, hi;
187
188         lo = fuse_readl(FUSE_UID_LOW);
189         hi = fuse_readl(FUSE_UID_HIGH);
190         return (hi << 32ull) | lo;
191 }
192
193 int tegra_sku_id(void)
194 {
195         int sku_id;
196         u32 reg = fuse_readl(FUSE_SKU_INFO);
197         sku_id = reg & 0xFF;
198         return sku_id;
199 }
200
201 int tegra_cpu_process_id(void)
202 {
203         int cpu_process_id;
204         u32 reg = fuse_readl(FUSE_SPARE_BIT);
205         cpu_process_id = (reg >> 6) & 3;
206         return cpu_process_id;
207 }
208
209 int tegra_core_process_id(void)
210 {
211         int core_process_id;
212         u32 reg = fuse_readl(FUSE_SPARE_BIT);
213         core_process_id = (reg >> 12) & 3;
214         return core_process_id;
215 }
216
217 enum tegra_revision tegra_get_revision(void)
218 {
219         void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804;
220         u32 id = readl(chip_id);
221
222         switch ((id >> 16) & 0xf) {
223         case 2:
224                 return TEGRA_REVISION_A02;
225         case 3:
226                 if (get_spare_fuse(18) || get_spare_fuse(19))
227                         return TEGRA_REVISION_A03p;
228                 else
229                         return TEGRA_REVISION_A03;
230         default:
231                 return TEGRA_REVISION_UNKNOWN;
232         }
233 }