ARM: tegra12: set CPU rate to 2.2GHz for sku 0x87
[linux-3.10.git] / arch / arm / mach-tegra / arb_sema.c
1 /*
2  * Copyright (C) 2010, NVIDIA Corporation
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  */
14
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/slab.h>
18 #include <linux/interrupt.h>
19 #include <linux/irq.h>
20 #include <linux/io.h>
21 #include <linux/mutex.h>
22 #include <linux/err.h>
23 #include <linux/delay.h>
24 #include <linux/completion.h>
25
26 #include <mach/arb_sema.h>
27 #include <mach/irqs.h>
28
29 #include "iomap.h"
30
31 #define TEGRA_RPC_MAX_SEM 32
32
33 /* arb_gnt ictrl */
34 #define ARB_CPU_INT_EN          0x4
35
36 /* arb_sema */
37 #define ARB_GRANT_STATUS        0x0
38 #define ARB_GRANT_REQUEST       0x4
39 #define ARB_GRANT_RELEASE       0x8
40 #define ARB_GRANT_PENDING       0xC
41
42 struct tegra_arb_dev {
43         void __iomem    *sema_base;
44         void __iomem    *gnt_base;
45         spinlock_t lock;
46         struct completion arb_gnt_complete[TEGRA_RPC_MAX_SEM];
47         struct mutex mutexes[TEGRA_RPC_MAX_SEM];
48         int irq;
49         int status;
50         bool suspended;
51 };
52
53 static struct tegra_arb_dev *arb;
54
55 static inline u32 arb_sema_read(u32 offset)
56 {
57         return readl(arb->sema_base + offset);
58 }
59
60 static inline void arb_sema_write(u32 value, u32 offset)
61 {
62         writel(value, arb->sema_base + offset);
63 }
64
65 static inline u32 arb_gnt_read(u32 offset)
66 {
67         return readl(arb->gnt_base + offset);
68 }
69
70 static inline void arb_gnt_write(u32 value, u32 offset)
71 {
72         writel(value, arb->gnt_base + offset);
73 }
74
75 static void request_arb_sem(enum tegra_arb_module lock)
76 {
77         unsigned long flags;
78         u32 value;
79
80         spin_lock_irqsave(&arb->lock, flags);
81
82         arb_sema_write(1 << lock, ARB_GRANT_REQUEST);
83         value = arb_gnt_read(ARB_CPU_INT_EN);
84         value |= (1 << lock);
85         arb_gnt_write(value, ARB_CPU_INT_EN);
86
87         spin_unlock_irqrestore(&arb->lock, flags);
88 }
89
90 static void cancel_arb_sem(enum tegra_arb_module lock)
91 {
92         unsigned long flags;
93         u32 value;
94
95         spin_lock_irqsave(&arb->lock, flags);
96
97         arb_sema_write(1 << lock, ARB_GRANT_RELEASE);
98         value = arb_gnt_read(ARB_CPU_INT_EN);
99         value &= ~(1 << lock);
100         arb_gnt_write(value, ARB_CPU_INT_EN);
101
102         spin_unlock_irqrestore(&arb->lock, flags);
103 }
104
105 int tegra_arb_mutex_lock_timeout(enum tegra_arb_module lock, int msecs)
106 {
107         int ret;
108
109         if (!arb)
110                 return -ENODEV;
111
112         if (arb->suspended) {
113                 pr_err("device in suspend\n");
114                 return -ETIMEDOUT;
115         }
116
117         mutex_lock(&arb->mutexes[lock]);
118         INIT_COMPLETION(arb->arb_gnt_complete[lock]);
119         request_arb_sem(lock);
120         ret = wait_for_completion_timeout(&arb->arb_gnt_complete[lock], msecs_to_jiffies(msecs));
121         if (ret == 0) {
122                 pr_err("timed out. pending:0x%x\n", arb_sema_read(ARB_GRANT_PENDING));
123                 cancel_arb_sem(lock);
124                 mutex_unlock(&arb->mutexes[lock]);
125                 return -ETIMEDOUT;
126         }
127
128         return 0;
129 }
130 EXPORT_SYMBOL(tegra_arb_mutex_lock_timeout);
131
132 int tegra_arb_mutex_unlock(enum tegra_arb_module lock)
133 {
134         if (!arb)
135                 return -ENODEV;
136
137         if (arb->suspended) {
138                 pr_err("device in suspend\n");
139                 return -ETIMEDOUT;
140         }
141
142         cancel_arb_sem(lock);
143         mutex_unlock(&arb->mutexes[lock]);
144         return 0;
145 }
146 EXPORT_SYMBOL(tegra_arb_mutex_unlock);
147
148 static irqreturn_t arb_gnt_isr(int irq, void *dev_id)
149 {
150         struct tegra_arb_dev *dev = dev_id;
151         unsigned long status;
152         u32 cpu_int_en;
153         unsigned int bit;
154         unsigned long flags;
155
156         spin_lock_irqsave(&arb->lock, flags);
157
158         status = arb_sema_read(ARB_GRANT_STATUS);
159         pr_debug("%s: 0x%lx\n", __func__, status);
160
161         /* disable the arb semaphores which were signalled */
162         cpu_int_en = arb_gnt_read(ARB_CPU_INT_EN);
163         arb_gnt_write((cpu_int_en & ~(status & cpu_int_en)),
164                 ARB_CPU_INT_EN);
165
166         status &= cpu_int_en;
167         for_each_set_bit(bit, &status, BITS_PER_LONG)
168                 complete(&dev->arb_gnt_complete[bit]);
169
170         spin_unlock_irqrestore(&arb->lock, flags);
171         return IRQ_HANDLED;
172 }
173
174 int tegra_arb_suspend(void)
175 {
176         unsigned long status = arb_sema_read(ARB_GRANT_STATUS);
177
178         if (WARN_ON(status != 0)) {
179                 pr_err("%s: suspending while holding arbitration "
180                        "semaphore: %08lx\n", __func__, status);
181         }
182         arb->suspended = true;
183
184         return status ? -EBUSY : 0;
185 }
186
187 int tegra_arb_resume(void)
188 {
189         arb->suspended = false;
190         return 0;
191 }
192
193 static int __init tegra_arb_init(void)
194 {
195         struct tegra_arb_dev *dev = NULL;
196         int err, i;
197
198         dev = kzalloc(sizeof(struct tegra_arb_dev), GFP_KERNEL);
199         if (dev == NULL) {
200                 pr_err("%s: unable to alloc data struct.\n", __func__);
201                 return -ENOMEM;
202         }
203
204         for (i = 0; i < TEGRA_RPC_MAX_SEM; i++) {
205                 mutex_init(&dev->mutexes[i]);
206                 init_completion(&dev->arb_gnt_complete[i]);
207         }
208
209         dev->sema_base = IO_ADDRESS(TEGRA_ARB_SEMA_BASE);
210         if (!dev->sema_base) {
211                 pr_err("%s: can't get arb sema_base\n", __func__);
212                 err = -ENOMEM;
213                 goto out;
214         }
215
216         dev->gnt_base = IO_ADDRESS(TEGRA_ARBGNT_ICTLR_BASE);
217         if (!dev->gnt_base) {
218                 pr_err("%s: can't ioremap gnt_base\n", __func__);
219                 err = -ENOMEM;
220                 goto out;
221         }
222
223         dev->irq = INT_GNT_1;
224         err = request_irq(dev->irq, arb_gnt_isr, 0, "rpc-arbsema", dev);
225         if (err) {
226                 pr_err("%s: request_irq(%d) failed(%d)\n", __func__,
227                         dev->irq, err);
228                 goto out;
229         }
230
231         spin_lock_init(&dev->lock);
232         arb = dev;
233
234         pr_info("%s: initialized\n", __func__);
235         return 0;
236
237 out:
238         kfree(dev);
239         pr_err("%s: initialization failed.\n", __func__);
240         return err;
241 }
242 subsys_initcall(tegra_arb_init);
243
244 MODULE_LICENSE("GPLv2");