temp revert rk change
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-tegra / apbio.c
1 /*
2  * arch/arm/mach-tegra/apbio.c
3  *
4  * Copyright (C) 2010 NVIDIA Corporation.
5  * Copyright (C) 2010 Google, Inc.
6  *
7  * This software is licensed under the terms of the GNU General Public
8  * License version 2, as published by the Free Software Foundation, and
9  * may be copied, distributed, and modified under those terms.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17
18 #include <linux/kernel.h>
19 #include <linux/io.h>
20 #include <linux/dma-mapping.h>
21 #include <linux/spinlock.h>
22 #include <linux/completion.h>
23 #include <linux/sched.h>
24 #include <linux/mutex.h>
25
26 #include <mach/dma.h>
27 #include <mach/iomap.h>
28
29 #include "apbio.h"
30
31 static DEFINE_MUTEX(tegra_apb_dma_lock);
32
33 #ifdef CONFIG_TEGRA_SYSTEM_DMA
34 static struct tegra_dma_channel *tegra_apb_dma;
35 static u32 *tegra_apb_bb;
36 static dma_addr_t tegra_apb_bb_phys;
37 static DECLARE_COMPLETION(tegra_apb_wait);
38
39 static void apb_dma_complete(struct tegra_dma_req *req)
40 {
41         complete(&tegra_apb_wait);
42 }
43
44 static inline u32 apb_readl(unsigned long offset)
45 {
46         struct tegra_dma_req req;
47         int ret;
48
49         if (!tegra_apb_dma)
50                 return readl(IO_TO_VIRT(offset));
51
52         mutex_lock(&tegra_apb_dma_lock);
53         req.complete = apb_dma_complete;
54         req.to_memory = 1;
55         req.dest_addr = tegra_apb_bb_phys;
56         req.dest_bus_width = 32;
57         req.dest_wrap = 1;
58         req.source_addr = offset;
59         req.source_bus_width = 32;
60         req.source_wrap = 4;
61         req.req_sel = 0;
62         req.size = 4;
63
64         INIT_COMPLETION(tegra_apb_wait);
65
66         tegra_dma_enqueue_req(tegra_apb_dma, &req);
67
68         ret = wait_for_completion_timeout(&tegra_apb_wait,
69                 msecs_to_jiffies(50));
70
71         if (WARN(ret == 0, "apb read dma timed out"))
72                 *(u32 *)tegra_apb_bb = 0;
73
74         mutex_unlock(&tegra_apb_dma_lock);
75         return *((u32 *)tegra_apb_bb);
76 }
77
78 static inline void apb_writel(u32 value, unsigned long offset)
79 {
80         struct tegra_dma_req req;
81         int ret;
82
83         if (!tegra_apb_dma) {
84                 writel(value, IO_TO_VIRT(offset));
85                 return;
86         }
87
88         mutex_lock(&tegra_apb_dma_lock);
89         *((u32 *)tegra_apb_bb) = value;
90         req.complete = apb_dma_complete;
91         req.to_memory = 0;
92         req.dest_addr = offset;
93         req.dest_wrap = 4;
94         req.dest_bus_width = 32;
95         req.source_addr = tegra_apb_bb_phys;
96         req.source_bus_width = 32;
97         req.source_wrap = 1;
98         req.req_sel = 0;
99         req.size = 4;
100
101         INIT_COMPLETION(tegra_apb_wait);
102
103         tegra_dma_enqueue_req(tegra_apb_dma, &req);
104
105         ret = wait_for_completion_timeout(&tegra_apb_wait,
106                 msecs_to_jiffies(50));
107
108         mutex_unlock(&tegra_apb_dma_lock);
109 }
110 #else
111 static inline u32 apb_readl(unsigned long offset)
112 {
113         return readl(IO_TO_VIRT(offset));
114 }
115
116 static inline void apb_writel(u32 value, unsigned long offset)
117 {
118         writel(value, IO_TO_VIRT(offset));
119 }
120 #endif
121
122 u32 tegra_apb_readl(unsigned long offset)
123 {
124         return apb_readl(offset);
125 }
126
127 void tegra_apb_writel(u32 value, unsigned long offset)
128 {
129         apb_writel(value, offset);
130 }
131
132 void tegra_init_apb_dma(void)
133 {
134 #ifdef CONFIG_TEGRA_SYSTEM_DMA
135         tegra_apb_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
136                 TEGRA_DMA_SHARED);
137         if (!tegra_apb_dma) {
138                 pr_err("%s: can not allocate dma channel\n", __func__);
139                 return;
140         }
141
142         tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32),
143                 &tegra_apb_bb_phys, GFP_KERNEL);
144         if (!tegra_apb_bb) {
145                 pr_err("%s: can not allocate bounce buffer\n", __func__);
146                 tegra_dma_free_channel(tegra_apb_dma);
147                 tegra_apb_dma = NULL;
148                 return;
149         }
150 #endif
151 }