aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Zhu <r65037@freescale.com>2014-04-11 03:11:14 -0400
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:58:21 -0400
commit39e6a62bc0f89d34c7b62294aef343eac38ce982 (patch)
tree3f407d7b81ef9ef1787bddc6bca719601a63aa69
parentd9bc7e358e1494e29da5acc4c33c1144cdbd31f2 (diff)
ENGR00308060-3 mcc: add sema4 driver required by mcc
- add linux sema4 driver, that mandatory required by mcc. - use volatile types in sema4 structure - align the port definiton a9 is 1, m4 is 2. Signed-off-by: Richard Zhu <r65037@freescale.com>
-rw-r--r--drivers/char/Kconfig2
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/imx_mcc/Kconfig9
-rw-r--r--drivers/char/imx_mcc/Makefile5
-rw-r--r--drivers/char/imx_mcc/imx_sema4.c416
-rw-r--r--include/linux/imx_sema4.h71
6 files changed, 504 insertions, 0 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 09b813479de5..39b6a58e8237 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -627,5 +627,7 @@ config MXS_VIIM
627 Support for access to MXS Virtual IIM device, most people should say N here. 627 Support for access to MXS Virtual IIM device, most people should say N here.
628 628
629source "drivers/char/xillybus/Kconfig" 629source "drivers/char/xillybus/Kconfig"
630
631source "drivers/char/imx_mcc/Kconfig"
630endmenu 632endmenu
631 633
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index e27e9fb1bfd7..5a4efdacc5e2 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -65,3 +65,4 @@ js-rtc-y = rtc.o
65 65
66obj-$(CONFIG_TILE_SROM) += tile-srom.o 66obj-$(CONFIG_TILE_SROM) += tile-srom.o
67obj-$(CONFIG_XILLYBUS) += xillybus/ 67obj-$(CONFIG_XILLYBUS) += xillybus/
68obj-$(CONFIG_HAVE_IMX_MCC) += imx_mcc/
diff --git a/drivers/char/imx_mcc/Kconfig b/drivers/char/imx_mcc/Kconfig
new file mode 100644
index 000000000000..1f892f8daccb
--- /dev/null
+++ b/drivers/char/imx_mcc/Kconfig
@@ -0,0 +1,9 @@
1#
2# imx mcc
3#
4
5config IMX_SEMA4
6 bool "IMX SEMA4 driver"
7 depends on SOC_IMX6SX
8 help
9 Support for IMX SEMA4 driver, most people should say N here.
diff --git a/drivers/char/imx_mcc/Makefile b/drivers/char/imx_mcc/Makefile
new file mode 100644
index 000000000000..4e7a91691b39
--- /dev/null
+++ b/drivers/char/imx_mcc/Makefile
@@ -0,0 +1,5 @@
1#
2# Makefile for imx mcc
3#
4#
5obj-$(CONFIG_IMX_SEMA4) += imx_sema4.o
diff --git a/drivers/char/imx_mcc/imx_sema4.c b/drivers/char/imx_mcc/imx_sema4.c
new file mode 100644
index 000000000000..12d68a86dfe3
--- /dev/null
+++ b/drivers/char/imx_mcc/imx_sema4.c
@@ -0,0 +1,416 @@
1/*
2 * Copyright (C) 2014 Freescale Semiconductor, Inc.
3 */
4
5/*
6 * The code contained herein is licensed under the GNU General Public
7 * License. You may obtain a copy of the GNU General Public License
8 * Version 2 or later at the following locations:
9 *
10 * http://www.opensource.org/licenses/gpl-license.html
11 * http://www.gnu.org/copyleft/gpl.html
12 */
13
14#include <linux/platform_device.h>
15#include <linux/interrupt.h>
16#include <linux/io.h>
17#include <linux/err.h>
18#include <linux/module.h>
19#include <linux/of.h>
20#include <linux/wait.h>
21#include <linux/sched.h>
22#include <linux/slab.h>
23#include <linux/imx_sema4.h>
24
25static struct imx_sema4_mutex_device *imx6_sema4;
26
27/*!
28 * \brief mutex create function.
29 *
30 * This function allocates imx_sema4_mutex structure and returns a handle
31 * to it. The mutex to be created is identified by SEMA4 device number and mutex
32 * (gate) number. The handle is used to reference the created mutex in calls to
33 * other imx_sema4_mutex API functions. This function is to be called only
34 * once for each mutex.
35 *
36 * \param[in] dev_num SEMA4 device (module) number.
37 * \param[in] mutex_num Mutex (gate) number.
38 *
39 * \return NULL (Failure.)
40 * \return imx_sema4_mutex (Success.)
41 */
42struct imx_sema4_mutex *
43imx_sema4_mutex_create(u32 dev_num, u32 mutex_num)
44{
45 struct imx_sema4_mutex *mutex_ptr = NULL;
46
47 if ((mutex_num > SEMA4_NUM_GATES) || dev_num >= SEMA4_NUM_DEVICES)
48 goto out;
49
50 if (imx6_sema4->cpine_val & (1 < mutex_num)) {
51 pr_err("Error: requiring a allocated sema4.\n");
52 pr_err("mutex_num %d cpine_val 0x%08x.\n",
53 mutex_num, imx6_sema4->cpine_val);
54 }
55 mutex_ptr = kzalloc(sizeof(*mutex_ptr), GFP_KERNEL);
56 if (!mutex_ptr)
57 goto out;
58 imx6_sema4->mutex_ptr[mutex_num] = mutex_ptr;
59 imx6_sema4->alloced |= 1 < mutex_num;
60 imx6_sema4->cpine_val |= idx_sema4[mutex_num];
61 writew(imx6_sema4->cpine_val, imx6_sema4->ioaddr + SEMA4_CP0INE);
62
63 mutex_ptr->valid = CORE_MUTEX_VALID;
64 mutex_ptr->gate_num = mutex_num;
65 init_waitqueue_head(&mutex_ptr->wait_q);
66
67out:
68 return mutex_ptr;
69}
70EXPORT_SYMBOL(imx_sema4_mutex_create);
71
72/*!
73 * \brief mutex destroy function.
74 *
75 * This function destroys a mutex.
76 *
77 * \param[in] mutex_ptr Pointer to mutex structure.
78 *
79 * \return MQX_COMPONENT_DOES_NOT_EXIST (mutex component not installed.)
80 * \return MQX_INVALID_PARAMETER (Wrong input parameter.)
81 * \return COREMUTEX_OK (Success.)
82 *
83 */
84int imx_sema4_mutex_destroy(struct imx_sema4_mutex *mutex_ptr)
85{
86 u32 mutex_num;
87
88 if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID))
89 return -EINVAL;
90
91 mutex_num = mutex_ptr->gate_num;
92 if ((imx6_sema4->cpine_val & idx_sema4[mutex_num]) == 0) {
93 pr_err("Error: trying to destory a un-allocated sema4.\n");
94 pr_err("mutex_num %d cpine_val 0x%08x.\n",
95 mutex_num, imx6_sema4->cpine_val);
96 }
97 imx6_sema4->mutex_ptr[mutex_num] = NULL;
98 imx6_sema4->alloced &= ~(1 << mutex_num);
99 imx6_sema4->cpine_val &= ~(idx_sema4[mutex_num]);
100 writew(imx6_sema4->cpine_val, imx6_sema4->ioaddr + SEMA4_CP0INE);
101
102 kfree(mutex_ptr);
103
104 return 0;
105}
106EXPORT_SYMBOL(imx_sema4_mutex_destroy);
107
108/*!
109 * \brief Lock the mutex, shouldn't be interruted by INT.
110 *
111 * This function attempts to lock a mutex. If the mutex is already locked
112 * by another task the function return -EBUSY, and tell invoker wait until
113 * it is possible to lock the mutex.
114 *
115 * \param[in] mutex_ptr Pointer to mutex structure.
116 *
117 * \return MQX_INVALID_POINTER (Wrong pointer to the mutex structure provided.)
118 * \return COREMUTEX_OK (mutex successfully locked.)
119 *
120 * \see imx_sema4_mutex_unlock
121 */
122int _imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr)
123{
124 int ret = 0, i = mutex_ptr->gate_num;
125
126 if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID))
127 return -EINVAL;
128
129 mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
130 mutex_ptr->gate_val &= SEMA4_GATE_MASK;
131 /* Check to see if this core already own it */
132 if (mutex_ptr->gate_val == SEMA4_A9_LOCK) {
133 /* return -EBUSY, invoker should be in sleep, and re-lock ag */
134 pr_err("%s -> %s %d already locked, wait! num %d val %d.\n",
135 __FILE__, __func__, __LINE__,
136 i, mutex_ptr->gate_val);
137 ret = -EBUSY;
138 goto out;
139 } else {
140 /* try to lock the mutex */
141 mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
142 mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
143 mutex_ptr->gate_val |= SEMA4_A9_LOCK;
144 writeb(mutex_ptr->gate_val, imx6_sema4->ioaddr + i);
145 mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
146 mutex_ptr->gate_val &= SEMA4_GATE_MASK;
147 /* double check the mutex is locked, otherwise, return -EBUSY */
148 if (mutex_ptr->gate_val != SEMA4_A9_LOCK) {
149 pr_debug("wait-locked num %d val %d.\n",
150 i, mutex_ptr->gate_val);
151 ret = -EBUSY;
152 }
153 }
154out:
155 return ret;
156}
157
158/* !
159 * \brief Try to lock the core mutex.
160 *
161 * This function attempts to lock a mutex. If the mutex is successfully locked
162 * for the calling task, SEMA4_A9_LOCK is returned. If the mutex is already
163 * locked by another task, the function does not block but rather returns
164 * negative immediately.
165 *
166 * \param[in] mutex_ptr Pointer to core_mutex structure.
167 *
168 * \return SEMA4_A9_LOCK (mutex successfully locked.)
169 * \return negative (mutex not locked.)
170 *
171 */
172int imx_sema4_mutex_trylock(struct imx_sema4_mutex *mutex_ptr)
173{
174 int ret = 0;
175
176 ret = _imx_sema4_mutex_lock(mutex_ptr);
177 if (ret == 0)
178 return SEMA4_A9_LOCK;
179 else
180 return ret;
181}
182EXPORT_SYMBOL(imx_sema4_mutex_trylock);
183
184/*!
185 * \brief Invoke _imx_sema4_mutex_lock to lock the mutex.
186 *
187 * This function attempts to lock a mutex. If the mutex is already locked
188 * by another task the function, sleep itself and schedule out.
189 * Wait until it is possible to lock the mutex.
190 *
191 * Invoker should add its own wait queue into the wait queue header of the
192 * required semaphore, set TASK_INTERRUPTIBLE and sleep on itself by
193 * schedule() when the lock is failed. Re-try to lock the semaphore when
194 * it is woke up by the sema4 isr.
195 *
196 * \param[in] mutex_ptr Pointer to mutex structure.
197 *
198 * \return SEMA4_A9_LOCK (mutex successfully locked.)
199 *
200 * \see imx_sema4_mutex_unlock
201 */
202int imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr)
203{
204 int ret = 0;
205 unsigned long flags;
206 unsigned long timeout_j; /* jiffies */
207
208 spin_lock_irqsave(&imx6_sema4->lock, flags);
209 ret = _imx_sema4_mutex_lock(mutex_ptr);
210 spin_unlock_irqrestore(&imx6_sema4->lock, flags);
211 while (-EBUSY == ret) {
212 if (MCC_SHMEM_SEMAPHORE_NUMBER == mutex_ptr->gate_num) {
213 timeout_j = msecs_to_jiffies(1000);
214 wait_event_timeout(mutex_ptr->wait_q,
215 mutex_ptr->gate_val == 0, timeout_j);
216 pr_debug("wake up val %d.\n", mutex_ptr->gate_val);
217 }
218 spin_lock_irqsave(&imx6_sema4->lock, flags);
219 ret = _imx_sema4_mutex_lock(mutex_ptr);
220 spin_unlock_irqrestore(&imx6_sema4->lock, flags);
221 if (ret == 0)
222 break;
223 }
224
225 return ret;
226}
227EXPORT_SYMBOL(imx_sema4_mutex_lock);
228
229/*!
230 * \brief Unlock the mutex.
231 *
232 * This function unlocks the specified mutex.
233 *
234 * \param[in] mutex_ptr Pointer to mutex structure.
235 *
236 * \return -EINVAL (Wrong pointer to the mutex structure provided.)
237 * \return -EINVAL (This mutex has not been locked by this core.)
238 * \return 0 (mutex successfully unlocked.)
239 *
240 * \see imx_sema4_mutex_lock
241 */
242int imx_sema4_mutex_unlock(struct imx_sema4_mutex *mutex_ptr)
243{
244 int ret = 0, i = mutex_ptr->gate_num;
245
246 if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID))
247 return -EINVAL;
248
249 mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
250 mutex_ptr->gate_val &= SEMA4_GATE_MASK;
251 /* make sure it is locked by this core */
252 if (mutex_ptr->gate_val != SEMA4_A9_LOCK) {
253 pr_err("%d Trying to unlock an unlock mutex.\n", __LINE__);
254 ret = -EINVAL;
255 goto out;
256 }
257 /* unlock it */
258 mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
259 mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
260 writeb(mutex_ptr->gate_val | SEMA4_UNLOCK, imx6_sema4->ioaddr + i);
261 mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
262 mutex_ptr->gate_val &= SEMA4_GATE_MASK;
263 /* make sure it is locked by this core */
264 if (mutex_ptr->gate_val != SEMA4_UNLOCK)
265 pr_err("%d ERROR, failed to unlock the mutex.\n", __LINE__);
266
267out:
268 return ret;
269}
270EXPORT_SYMBOL(imx_sema4_mutex_unlock);
271
272/*
273 * isr used by SEMA4, wake up the sleep tasks if there are the tasks waiting
274 * for locking semaphore.
275 * FIXME the bits order of the gatn, cpnie, cpnntf are not exact identified yet!
276 */
277static irqreturn_t imx_sema4_isr(int irq, void *dev_id)
278{
279 int i;
280 struct imx_sema4_mutex *mutex_ptr;
281 u32 mask;
282 struct imx_sema4_mutex_device *imx6_sema4 = dev_id;
283
284 imx6_sema4->cpntf_val = readw(imx6_sema4->ioaddr + SEMA4_CP0NTF);
285 for (i = 0; i < SEMA4_NUM_GATES; i++) {
286 mask = idx_sema4[i];
287 if ((imx6_sema4->cpntf_val) & mask) {
288 mutex_ptr = imx6_sema4->mutex_ptr[i];
289 /*
290 * An interrupt is pending on this mutex, the only way
291 * to clear it is to lock it (either by this core or
292 * another).
293 */
294 mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
295 mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
296 mutex_ptr->gate_val |= SEMA4_A9_LOCK;
297 writeb(mutex_ptr->gate_val, imx6_sema4->ioaddr + i);
298 mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
299 mutex_ptr->gate_val &= SEMA4_GATE_MASK;
300 if (mutex_ptr->gate_val == SEMA4_A9_LOCK) {
301 /*
302 * wake up the wait queue, whatever there
303 * are wait task or not.
304 * NOTE: check gate is locted or not in
305 * sema4_lock func by wait task.
306 */
307 mutex_ptr->gate_val =
308 readb(imx6_sema4->ioaddr + i);
309 mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
310 mutex_ptr->gate_val |= SEMA4_UNLOCK;
311
312 writeb(mutex_ptr->gate_val,
313 imx6_sema4->ioaddr + i);
314 wake_up(&mutex_ptr->wait_q);
315 } else {
316 pr_err("can't lock gate%d re-do it! %s->%s\n",
317 i, __FILE__, __func__);
318 }
319 }
320 }
321
322 return IRQ_HANDLED;
323}
324
325static const struct of_device_id imx_sema4_dt_ids[] = {
326 { .compatible = "fsl,imx6sx-sema4", },
327 { /* sentinel */ }
328};
329MODULE_DEVICE_TABLE(of, imx_sema4_dt_ids);
330
331static int imx_sema4_probe(struct platform_device *pdev)
332{
333 struct resource *res;
334 int ret;
335
336 imx6_sema4 = devm_kzalloc(&pdev->dev, sizeof(*imx6_sema4), GFP_KERNEL);
337 if (!imx6_sema4)
338 return -ENOMEM;
339
340 imx6_sema4->dev = &pdev->dev;
341 imx6_sema4->cpine_val = 0;
342
343 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
344 if (IS_ERR(res)) {
345 dev_err(&pdev->dev, "unable to get imx sema4 resource 0\n");
346 ret = -ENODEV;
347 goto err;
348 }
349
350 imx6_sema4->ioaddr = devm_ioremap_resource(&pdev->dev, res);
351 if (IS_ERR(imx6_sema4->ioaddr)) {
352 ret = PTR_ERR(imx6_sema4->ioaddr);
353 goto err;
354 }
355
356 imx6_sema4->irq = platform_get_irq(pdev, 0);
357 if (!imx6_sema4->irq) {
358 dev_err(&pdev->dev, "failed to get irq\n");
359 ret = -ENODEV;
360 goto err;
361 }
362
363 ret = devm_request_irq(&pdev->dev, imx6_sema4->irq, imx_sema4_isr,
364 IRQF_SHARED, "imx6sx-sema4", imx6_sema4);
365 if (ret) {
366 dev_err(&pdev->dev, "failed to request imx sema4 irq\n");
367 ret = -ENODEV;
368 goto err;
369 }
370
371 platform_set_drvdata(pdev, imx6_sema4);
372
373err:
374 return ret;
375}
376
377static int imx_sema4_remove(struct platform_device *pdev)
378{
379 return 0;
380}
381
382static struct platform_driver imx_sema4_driver = {
383 .driver = {
384 .owner = THIS_MODULE,
385 .name = "imx-sema4",
386 .of_match_table = imx_sema4_dt_ids,
387 },
388 .probe = imx_sema4_probe,
389 .remove = imx_sema4_remove,
390};
391
392static int __init imx_sema4_init(void)
393{
394 int ret;
395
396 ret = platform_driver_register(&imx_sema4_driver);
397 if (ret)
398 pr_err("Unable to initialize sema4 driver\n");
399 else
400 pr_info("imx sema4 driver is registered.\n");
401
402 return ret;
403}
404
405static void __exit imx_sema4_exit(void)
406{
407 pr_info("imx sema4 driver is unregistered.\n");
408 platform_driver_unregister(&imx_sema4_driver);
409}
410
411module_exit(imx_sema4_exit);
412module_init(imx_sema4_init);
413
414MODULE_AUTHOR("Freescale Semiconductor, Inc.");
415MODULE_DESCRIPTION("IMX SEMA4 driver");
416MODULE_LICENSE("GPL");
diff --git a/include/linux/imx_sema4.h b/include/linux/imx_sema4.h
new file mode 100644
index 000000000000..51a25e1b51bc
--- /dev/null
+++ b/include/linux/imx_sema4.h
@@ -0,0 +1,71 @@
1/*
2 * Copyright (C) 2014 Freescale Semiconductor, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef __LINUX_IMX_SEMA4_H__
10#define __LINUX_IMX_SEMA4_H__
11
12/* semaphore number */
13#define MCC_SHMEM_SEMAPHORE_NUMBER (1)
14#define MCC_PRINTF_SEMAPHORE_NUMBER (2)
15#define MCC_I2C_SEMAPHORE_NUMBER (3)
16#define MCC_RESERVED1_SEMAPHORE_NUMBER (4)
17#define MCC_RESERVED2_SEMAPHORE_NUMBER (5)
18
19#define SEMA4_NUM_DEVICES 1
20#define SEMA4_NUM_GATES 16
21
22#define SEMA4_UNLOCK 0x00
23#define SEMA4_A9_LOCK 0x01
24#define SEMA4_GATE_MASK 0x03
25
26#define CORE_MUTEX_VALID (('c'<<24)|('m'<<24)|('t'<<24)|'x')
27
28/*
29 * The enumerates
30 */
31enum {
32 /* sema4 registers offset */
33 SEMA4_CP0INE = 0x40,
34 SEMA4_CP1INE = 0x48,
35 SEMA4_CP0NTF = 0x80,
36 SEMA4_CP1NTF = 0x88,
37};
38
39static const unsigned int idx_sema4[16] = {
40 1 << 7, 1 << 6, 1 << 5, 1 << 4,
41 1 << 3, 1 << 2, 1 << 1, 1 << 0,
42 1 << 15, 1 << 14, 1 << 13, 1 << 12,
43 1 << 11, 1 << 10, 1 << 9, 1 << 8,
44};
45
46struct imx_sema4_mutex {
47 u32 valid;
48 u32 gate_num;
49 unsigned char gate_val;
50 wait_queue_head_t wait_q;
51};
52
53struct imx_sema4_mutex_device {
54 struct device *dev;
55 u16 cpntf_val;
56 u16 cpine_val;
57 void __iomem *ioaddr; /* Mapped address */
58 spinlock_t lock; /* Mutex */
59 int irq;
60
61 u16 alloced;
62 struct imx_sema4_mutex *mutex_ptr[16];
63};
64
65struct imx_sema4_mutex *
66 imx_sema4_mutex_create(u32 dev_num, u32 mutex_num);
67int imx_sema4_mutex_destroy(struct imx_sema4_mutex *mutex_ptr);
68int imx_sema4_mutex_trylock(struct imx_sema4_mutex *mutex_ptr);
69int imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr);
70int imx_sema4_mutex_unlock(struct imx_sema4_mutex *mutex_ptr);
71#endif /* __LINUX_IMX_SEMA4_H__ */