[ARM] tegra: spdif/i2s audio: fixes
[firefly-linux-kernel-4.4.55.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 void fuse_dma_complete(struct tegra_dma_req *req)
47 {
48         complete(&tegra_fuse_wait);
49 }
50
51 static inline u32 fuse_readl(unsigned long offset)
52 {
53         struct tegra_dma_req req;
54         int ret;
55
56         if (!tegra_fuse_dma)
57                 return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
58
59         mutex_lock(&tegra_fuse_dma_lock);
60         req.complete = fuse_dma_complete;
61         req.to_memory = 1;
62         req.dest_addr = tegra_fuse_bb_phys;
63         req.dest_bus_width = 32;
64         req.dest_wrap = 1;
65         req.source_addr = TEGRA_FUSE_BASE + offset;
66         req.source_bus_width = 32;
67         req.source_wrap = 4;
68         req.req_sel = 0;
69         req.size = 4;
70
71         INIT_COMPLETION(tegra_fuse_wait);
72
73         tegra_dma_enqueue_req(tegra_fuse_dma, &req);
74
75         ret = wait_for_completion_timeout(&tegra_fuse_wait,
76                 msecs_to_jiffies(50));
77
78         if (WARN(ret == 0, "fuse read dma timed out"))
79                 *(u32 *)tegra_fuse_bb = 0;
80
81         mutex_unlock(&tegra_fuse_dma_lock);
82         return *((u32 *)tegra_fuse_bb);
83 }
84
85 static inline void fuse_writel(u32 value, unsigned long offset)
86 {
87         struct tegra_dma_req req;
88         int ret;
89
90         if (!tegra_fuse_dma) {
91                 writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
92                 return;
93         }
94
95         mutex_lock(&tegra_fuse_dma_lock);
96         *((u32 *)tegra_fuse_bb) = value;
97         req.complete = fuse_dma_complete;
98         req.to_memory = 0;
99         req.dest_addr = TEGRA_FUSE_BASE + offset;
100         req.dest_wrap = 4;
101         req.dest_bus_width = 32;
102         req.source_addr = tegra_fuse_bb_phys;
103         req.source_bus_width = 32;
104         req.source_wrap = 1;
105         req.req_sel = 0;
106         req.size = 4;
107
108         INIT_COMPLETION(tegra_fuse_wait);
109
110         tegra_dma_enqueue_req(tegra_fuse_dma, &req);
111
112         ret = wait_for_completion_timeout(&tegra_fuse_wait,
113                 msecs_to_jiffies(50));
114
115         mutex_unlock(&tegra_fuse_dma_lock);
116 }
117 #else
118 static inline u32 fuse_readl(unsigned long offset)
119 {
120         return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
121 }
122
123 static inline void fuse_writel(u32 value, unsigned long offset)
124 {
125         writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
126 }
127 #endif
128
129 u32 tegra_fuse_readl(unsigned long offset)
130 {
131         return fuse_readl(offset);
132 }
133
134 void tegra_fuse_writel(u32 value, unsigned long offset)
135 {
136         fuse_writel(value, offset);
137 }
138
139 void tegra_init_fuse(void)
140 {
141         u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
142         reg |= 1 << 28;
143         writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
144
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());
148 }
149
150 void tegra_init_fuse_dma(void)
151 {
152 #ifdef CONFIG_TEGRA_SYSTEM_DMA
153         tegra_fuse_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
154                 TEGRA_DMA_SHARED);
155         if (!tegra_fuse_dma) {
156                 pr_err("%s: can not allocate dma channel\n", __func__);
157                 return;
158         }
159
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;
166                 return;
167         }
168 #endif
169 }
170
171 unsigned long long tegra_chip_uid(void)
172 {
173         unsigned long long lo, hi;
174
175         lo = fuse_readl(FUSE_UID_LOW);
176         hi = fuse_readl(FUSE_UID_HIGH);
177         return (hi << 32ull) | lo;
178 }
179
180 int tegra_sku_id(void)
181 {
182         int sku_id;
183         u32 reg = fuse_readl(FUSE_SKU_INFO);
184         sku_id = reg & 0xFF;
185         return sku_id;
186 }
187
188 int tegra_cpu_process_id(void)
189 {
190         int cpu_process_id;
191         u32 reg = fuse_readl(FUSE_SPARE_BIT);
192         cpu_process_id = (reg >> 6) & 3;
193         return cpu_process_id;
194 }
195
196 int tegra_core_process_id(void)
197 {
198         int core_process_id;
199         u32 reg = fuse_readl(FUSE_SPARE_BIT);
200         core_process_id = (reg >> 12) & 3;
201         return core_process_id;
202 }