aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Zhu <r65037@freescale.com>2014-04-15 02:23:42 -0400
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:58:21 -0400
commitd9bc7e358e1494e29da5acc4c33c1144cdbd31f2 (patch)
tree1d665ea6cc1f5d992c769078fff5422be2227ba8
parent81b4f7898ff6f212d016f0ad8877a15160c7f0e1 (diff)
ENGR00308060-2 mcc: implementation mcc on imx6sx
- inherited mcc ver 001.002 from vibryd mqx release. - use mu general int4 as the cpu2cpu int (num is 122 at a9 side). - add linux wait_event/wake_up mechanism on the buffer management of share memory - replace wait_event_interruptible### by wait_event###, so the sleep task wouldn't be waken up by reboot or CTRL+C signals. - use the offset address to do the MQX_TO_VIRT and VIRT_TO_MQX exchanges. - regmap_bits_updat can't write 1 to clear the bit-set asr, use regmap_read/write - fix mu irq clear hang issue only do the regmap once in the isr register func, and replace the multi-regmap operations in the kinds of mx6sx mcc related apis by one global imx_mu_reg. Signed-off-by: Richard Zhu <r65037@freescale.com>
-rw-r--r--arch/arm/mach-imx/Kconfig5
-rw-r--r--arch/arm/mach-imx/Makefile1
-rw-r--r--arch/arm/mach-imx/mcc_imx6sx.c148
-rw-r--r--arch/arm/mach-imx/mcc_linux.c281
-rw-r--r--include/linux/mcc_imx6sx.h43
-rw-r--r--include/linux/mcc_linux.h53
6 files changed, 531 insertions, 0 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 7875adb8c7f4..65d5476679c6 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -81,6 +81,10 @@ config HAVE_IMX_MMDC
81config HAVE_IMX_SRC 81config HAVE_IMX_SRC
82 def_bool y if SMP 82 def_bool y if SMP
83 83
84config HAVE_IMX_MCC
85 select IMX_SEMA4
86 bool
87
84config IMX_HAVE_IOMUX_V1 88config IMX_HAVE_IOMUX_V1
85 bool 89 bool
86 90
@@ -860,6 +864,7 @@ config SOC_IMX6SX
860 select HAVE_IMX_SRC 864 select HAVE_IMX_SRC
861 select MIGHT_HAVE_PCI 865 select MIGHT_HAVE_PCI
862 select PCI_DOMAINS if PCI 866 select PCI_DOMAINS if PCI
867 select HAVE_IMX_MCC
863 select PINCTRL 868 select PINCTRL
864 select PINCTRL_IMX6SX 869 select PINCTRL_IMX6SX
865 select PL310_ERRATA_588369 if CACHE_PL310 870 select PL310_ERRATA_588369 if CACHE_PL310
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index d56ea8b34182..ed67b70a7a24 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -96,6 +96,7 @@ obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o
96obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o 96obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
97obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o 97obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
98obj-$(CONFIG_HAVE_IMX_SRC) += src.o 98obj-$(CONFIG_HAVE_IMX_SRC) += src.o
99obj-$(CONFIG_HAVE_IMX_MCC) += mcc_api.o mcc_common.o mcc_linux.o mcc_imx6sx.o
99AFLAGS_headsmp.o :=-Wa,-march=armv7-a 100AFLAGS_headsmp.o :=-Wa,-march=armv7-a
100obj-$(CONFIG_SMP) += headsmp.o platsmp.o 101obj-$(CONFIG_SMP) += headsmp.o platsmp.o
101obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o 102obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
diff --git a/arch/arm/mach-imx/mcc_imx6sx.c b/arch/arm/mach-imx/mcc_imx6sx.c
new file mode 100644
index 000000000000..4e22ffc6f6f4
--- /dev/null
+++ b/arch/arm/mach-imx/mcc_imx6sx.c
@@ -0,0 +1,148 @@
1/*
2 * Copyright (C) 2014 Freescale Semiconductor, Inc.
3 * Freescale IMX Linux-specific MCC implementation.
4 * iMX6sx-specific MCC library functions.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/delay.h>
20#include <linux/err.h>
21#include <linux/io.h>
22#include <linux/regmap.h>
23#include <linux/mcc_imx6sx.h>
24#include <linux/mcc_linux.h>
25
26/*!
27 * \brief This function returns the core number
28 *
29 * \return int
30 */
31unsigned int _psp_core_num(void)
32{
33 return 0;
34}
35
36/*
37 * This field contains CPU-to-CPU interrupt vector numbers
38 * for all device cores.
39 */
40static const unsigned int mcc_cpu_to_cpu_vectors[] = {INT_CPU_TO_CPU_MU_A2M,
41 INT_CPU_TO_CPU_MU_M2A};
42
43/*!
44 * \brief This function gets the CPU-to-CPU vector num for the particular core.
45 *
46 * Platform-specific inter-CPU vector numbers for each core are defined in the
47 * mcc_cpu_to_cpu_vectors[] field.
48 *
49 * \param[in] core Core number.
50 *
51 * \return vector number for the particular core
52 * \return MCC_VECTOR_NUMBER_INVALID (vector number for the particular core
53 * number not found)
54 */
55unsigned int mcc_get_cpu_to_cpu_vector(unsigned int core)
56{
57 u32 val;
58
59 val = sizeof(mcc_cpu_to_cpu_vectors)/sizeof(mcc_cpu_to_cpu_vectors[0]);
60 if (core < val)
61 return mcc_cpu_to_cpu_vectors[core];
62
63 return MCC_VECTOR_NUMBER_INVALID;
64}
65
66/*!
67 * \brief This function clears the CPU-to-CPU int flag for the particular core.
68 *
69 * Implementation is platform-specific.
70 *
71 * \param[in] core Core number.
72 */
73void mcc_clear_cpu_to_cpu_interrupt(unsigned int core)
74{
75 u32 val;
76
77 regmap_read(imx_mu_reg, MU_ASR, &val);
78 /* write 1 to BIT31 to clear the bit31(GIP3) of MU_ASR */
79 val = val | (1 << 31);
80 regmap_write(imx_mu_reg, MU_ASR, val);
81}
82
83/*!
84 * \brief This function triggers the CPU-to-CPU interrupt.
85 *
86 * Platform-specific software triggering the inter-CPU interrupts.
87 */
88void mcc_triger_cpu_to_cpu_interrupt(void)
89{
90 int i = 0;
91 u32 val;
92
93 regmap_read(imx_mu_reg, MU_ACR, &val);
94
95 if ((val & BIT(19)) != 0) {
96 do {
97 regmap_read(imx_mu_reg, MU_ACR, &val);
98 msleep(1);
99 } while (((val & BIT(19)) > 0) && (i++ < 100));
100 }
101
102 if ((val & BIT(19)) == 0)
103 /* Enable the bit19(GIR3) of MU_ACR */
104 regmap_update_bits(imx_mu_reg, MU_ACR, BIT(19), BIT(19));
105 else
106 pr_info("mcc int still be triggered after %d ms polling!\n", i);
107}
108
109/*!
110 * \brief This function disable the CPU-to-CPU interrupt.
111 *
112 * Platform-specific software disable the inter-CPU interrupts.
113 */
114int imx_mcc_bsp_int_disable(unsigned int vector_number)
115{
116 u32 val;
117
118 if (vector_number == INT_CPU_TO_CPU_MU_A2M) {
119 /* Disable the bit31(GIE3) of MU_ACR */
120 regmap_update_bits(imx_mu_reg, MU_ACR, BIT(31), 0);
121 /* flush */
122 regmap_read(imx_mu_reg, MU_ACR, &val);
123 } else
124 pr_err("ERR:wrong vector number in mcc.\n");
125
126 return 0;
127}
128
129/*!
130 * \brief This function enable the CPU-to-CPU interrupt.
131 *
132 * Platform-specific software enable the inter-CPU interrupts.
133 */
134int imx_mcc_bsp_int_enable(unsigned int vector_number)
135{
136 u32 val;
137
138 if (vector_number == INT_CPU_TO_CPU_MU_A2M) {
139 /* Enable the bit31(GIE3) of MU_ACR */
140 regmap_update_bits(imx_mu_reg, MU_ACR, BIT(31), BIT(31));
141 /* flush */
142 regmap_read(imx_mu_reg, MU_ACR, &val);
143 return 0;
144 } else {
145 pr_err("ERR:wrong vector number in mcc.\n");
146 return -EINVAL;
147 }
148}
diff --git a/arch/arm/mach-imx/mcc_linux.c b/arch/arm/mach-imx/mcc_linux.c
new file mode 100644
index 000000000000..551cc12ed4a5
--- /dev/null
+++ b/arch/arm/mach-imx/mcc_linux.c
@@ -0,0 +1,281 @@
1/*
2 * Copyright (C) 2014 Freescale Semiconductor, Inc.
3 * Freescale IMX Linux-specific MCC implementation.
4 * Linux-specific MCC library functions
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/delay.h>
20#include <linux/interrupt.h>
21#include <linux/mfd/syscon.h>
22#include <linux/regmap.h>
23#include <linux/sched.h>
24#include <linux/wait.h>
25#include <linux/imx_sema4.h>
26#include "mcc_config.h"
27#include <linux/mcc_common.h>
28#include <linux/mcc_api.h>
29#include <linux/mcc_imx6sx.h>
30#include <linux/mcc_linux.h>
31
32/* Global variables */
33struct regmap *imx_mu_reg;
34unsigned long mcc_shm_offset;
35static struct imx_sema4_mutex *shm_ptr;
36static unsigned int cpu_to_cpu_isr_vector = MCC_VECTOR_NUMBER_INVALID;
37
38unsigned int imx_mcc_buffer_freed = 0, imx_mcc_buffer_queued = 0;
39DECLARE_WAIT_QUEUE_HEAD(buffer_freed_wait_queue); /* Used for blocking send */
40DECLARE_WAIT_QUEUE_HEAD(buffer_queued_wait_queue); /* Used for blocking recv */
41
42/*!
43 * \brief This function is the CPU-to-CPU interrupt handler.
44 *
45 * Each core can interrupt the other. There are two logical signals:
46 * \n - Receive data available for (Node,Port) - signaled when a buffer
47 * is queued to a Receive Data Queue.
48 * \n - Buffer available - signaled when a buffer is queued to the Free
49 * Buffer Queue.
50 * \n It is possible that several signals can occur while one interrupt
51 * is being processed.
52 * Therefore, a Receive Signal Queue of received signals is also required
53 * - one for each core.
54 * The interrupting core queues to the tail and the interrupted core pulls
55 * from the head.
56 * For a circular file, no semaphore is required since only the sender
57 * modifies the tail and only the receiver modifies the head.
58 *
59 * \param[in] param Pointer to data being passed to the ISR.
60 */
61static irqreturn_t mcc_cpu_to_cpu_isr(int irq, void *param)
62{
63 MCC_SIGNAL serviced_signal;
64
65 /*
66 * Try to lock the core mutex. If successfully locked, perform
67 * mcc_dequeue_signal(), release the gate and finally clear the
68 * interrupt flag. If trylock fails (HW semaphore already locked
69 * by another core), do not clear the interrupt flag – this
70 * way the CPU-to-CPU isr is re-issued again until the HW semaphore
71 * is locked. Higher priority ISRs will be serviced while issued at
72 * the time we are waiting for the unlocked gate. To prevent trylog
73 * failure due to core mutex currently locked by our own core(a task),
74 * the cpu-to-cpu isr is temporarily disabled when mcc_get_semaphore()
75 * is called and re-enabled again when mcc_release_semaphore()
76 * is issued.
77 */
78 if (SEMA4_A9_LOCK == imx_sema4_mutex_trylock(shm_ptr)) {
79 while (MCC_SUCCESS == mcc_dequeue_signal(MCC_CORE_NUMBER,
80 &serviced_signal)) {
81 if ((serviced_signal.type == BUFFER_QUEUED) &&
82 (serviced_signal.destination.core == MCC_CORE_NUMBER)) {
83 /*
84 * Unblock receiver, in case of asynchronous
85 * communication
86 */
87 imx_mcc_buffer_queued = 1;
88 wake_up(&buffer_queued_wait_queue);
89 } else if (serviced_signal.type == BUFFER_FREED) {
90 /* Unblock sender, in case of asynchronous
91 * communication
92 */
93 imx_mcc_buffer_freed = 1;
94 wake_up(&buffer_freed_wait_queue);
95 }
96 }
97
98 /* Clear the interrupt flag */
99 mcc_clear_cpu_to_cpu_interrupt(MCC_CORE_NUMBER);
100
101 /* Unlocks the core mutex */
102 imx_sema4_mutex_unlock(shm_ptr);
103 }
104
105 return IRQ_HANDLED;
106}
107
108/*!
109 * \brief This function initializes the hw semaphore (SEMA4).
110 *
111 * Calls core-mutex driver to create a core mutex.
112 *
113 * \param[in] sem_num SEMA4 gate number.
114 */
115int mcc_init_semaphore(unsigned int sem_num)
116{
117 /* Create a core mutex */
118 shm_ptr = imx_sema4_mutex_create(0, sem_num);
119
120 if (NULL == shm_ptr)
121 return MCC_ERR_SEMAPHORE;
122 else
123 return MCC_SUCCESS;
124}
125
126/*!
127 * \brief This function de-initializes the hw semaphore (SEMA4).
128 *
129 * Calls core-mutex driver to destroy a core mutex.
130 *
131 * \param[in] sem_num SEMA4 gate number.
132 */
133int mcc_deinit_semaphore(unsigned int sem_num)
134{
135 /* Destroy the core mutex */
136 if (0 == imx_sema4_mutex_destroy(shm_ptr))
137 return MCC_SUCCESS;
138 else
139 return MCC_ERR_SEMAPHORE;
140}
141
142/*!
143 * \brief This function locks the specified core mutex.
144 *
145 * Calls core-mutex driver to lock the core mutex.
146 *
147 */
148int mcc_get_semaphore(void)
149{
150 if (imx_mcc_bsp_int_disable(cpu_to_cpu_isr_vector)) {
151 pr_err("ERR:failed to disable mcc int.\n");
152 return MCC_ERR_SEMAPHORE;
153 }
154
155 if (0 == imx_sema4_mutex_lock(shm_ptr)) {
156 return MCC_SUCCESS;
157 } else {
158 if (imx_mcc_bsp_int_enable(cpu_to_cpu_isr_vector)) {
159 pr_err("ERR:failed to enable mcc int.\n");
160 return MCC_ERR_INT;
161 }
162 return MCC_ERR_SEMAPHORE;
163 }
164}
165
166/*!
167 * \brief This function unlocks the specified core mutex.
168 *
169 * Calls core-mutex driver to unlock the core mutex.
170 *
171 */
172int mcc_release_semaphore(void)
173{
174 if (0 == imx_sema4_mutex_unlock(shm_ptr)) {
175 /*
176 * Enable the cpu-to-cpu isr just in case imx_semae_mutex_unlock
177 * function has not woke up another task waiting for the core
178 * mutex.
179 */
180 if (shm_ptr->gate_val != (MCC_CORE_NUMBER + 1))
181 imx_mcc_bsp_int_enable(cpu_to_cpu_isr_vector);
182 return MCC_SUCCESS;
183 }
184
185 return MCC_ERR_SEMAPHORE;
186}
187
188/*!
189 * \brief This function registers the CPU-to-CPU interrupt.
190 *
191 * Calls interrupt component functions to install and enable the
192 * CPU-to-CPU interrupt.
193 *
194 */
195int mcc_register_cpu_to_cpu_isr(void)
196{
197 int ret;
198 unsigned int vector_number;
199
200 vector_number = mcc_get_cpu_to_cpu_vector(MCC_CORE_NUMBER);
201
202 if (vector_number != MCC_VECTOR_NUMBER_INVALID) {
203 imx_mu_reg =
204 syscon_regmap_lookup_by_compatible("fsl,imx6sx-mu");
205 if (IS_ERR(imx_mu_reg))
206 pr_err("ERR:unable to find imx mu registers\n");
207
208 ret = request_irq(vector_number, mcc_cpu_to_cpu_isr,
209 0, "imx-linux-mcc", NULL);
210 if (ret) {
211 pr_err("%s: register interrupt %d failed, rc %d\n",
212 __func__, vector_number, ret);
213 return MCC_ERR_INT;
214 }
215 /* Make sure the INT is cleared */
216 mcc_clear_cpu_to_cpu_interrupt(MCC_CORE_NUMBER);
217
218 /* Enable INT */
219 ret = imx_mcc_bsp_int_enable(vector_number);
220 if (ret < 0) {
221 pr_err("ERR:failed to enable mcc int.\n");
222 return MCC_ERR_INT;
223 }
224
225 cpu_to_cpu_isr_vector = vector_number;
226 return MCC_SUCCESS;
227 } else {
228 return MCC_ERR_INT;
229 }
230}
231
232/*!
233 * \brief This function triggers an interrupt to other core(s).
234 *
235 */
236int mcc_generate_cpu_to_cpu_interrupt(void)
237{
238 /*
239 * Assert directed CPU interrupts for all processors except
240 * the requesting core
241 */
242 mcc_triger_cpu_to_cpu_interrupt();
243
244 return MCC_SUCCESS;
245}
246
247/*!
248 * \brief This function copies data.
249 *
250 * Copies the number of single-addressable units from the source address
251 * to destination address.
252 *
253 * \param[in] src Source address.
254 * \param[in] dest Destination address.
255 * \param[in] size Number of single-addressable units to copy.
256 */
257void mcc_memcpy(void *src, void *dest, unsigned int size)
258{
259 memcpy(dest, src, size);
260}
261
262void _mem_zero(void *ptr, unsigned int size)
263{
264 memset(ptr, 0, size);
265}
266
267void *virt_to_mqx(void *x)
268{
269 if (null == x)
270 return NULL;
271 else
272 return (void *)((unsigned long) (x) - mcc_shm_offset);
273}
274
275void *mqx_to_virt(void *x)
276{
277 if (null == x)
278 return NULL;
279 else
280 return (void *)((unsigned long) (x) + mcc_shm_offset);
281}
diff --git a/include/linux/mcc_imx6sx.h b/include/linux/mcc_imx6sx.h
new file mode 100644
index 000000000000..86a6de7da31d
--- /dev/null
+++ b/include/linux/mcc_imx6sx.h
@@ -0,0 +1,43 @@
1/*
2 * Copyright (C) 2014 Freescale Semiconductor, Inc.
3 * Freescale IMX Linux-specific MCC implementation.
4 * Prototypes for iMX6sx-specific MCC library functions.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Define the phiscal memory address on A9 and shared M4,
21 * This definition should be aligned on both A9 and M4
22 */
23#define MCC_VECTOR_NUMBER_INVALID (0)
24
25enum {
26 /* FIXME */
27 INT_CPU_TO_CPU_MU_A2M = 122,
28 INT_CPU_TO_CPU_MU_M2A = 90,
29
30 MU_ASR = 0x20,
31 MU_ACR = 0x24,
32};
33
34extern struct regmap *imx_mu_reg;
35
36/* Return core num. A9 0, M4 1 */
37unsigned int _psp_core_num(void);
38
39unsigned int mcc_get_cpu_to_cpu_vector(unsigned int);
40void mcc_clear_cpu_to_cpu_interrupt(unsigned int);
41void mcc_triger_cpu_to_cpu_interrupt(void);
42int imx_mcc_bsp_int_disable(unsigned int vector_number);
43int imx_mcc_bsp_int_enable(unsigned int vector_number);
diff --git a/include/linux/mcc_linux.h b/include/linux/mcc_linux.h
new file mode 100644
index 000000000000..f8591de63e74
--- /dev/null
+++ b/include/linux/mcc_linux.h
@@ -0,0 +1,53 @@
1/*
2 * Copyright (C) 2014 Freescale Semiconductor, Inc.
3 * Freescale IMX Linux-specific MCC implementation.
4 * Prototypes for Linunx-specific MCC library functions
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef __MCC_LINUX__
20#define __MCC_LINUX__
21
22/* Define the kinds of cache macros */
23#define MCC_DCACHE_ENABLE(n)
24#define MCC_DCACHE_DISABLE()
25#define MCC_DCACHE_FLUSH()
26#define MCC_DCACHE_FLUSH_LINE(p)
27#define MCC_DCACHE_FLUSH_MLINES(p, m)
28#define MCC_DCACHE_INVALIDATE()
29#define MCC_DCACHE_INVALIDATE_LINE(p)
30#define MCC_DCACHE_INVALIDATE_MLINES(p, m)
31
32#define _mem_size unsigned int
33
34void * virt_to_mqx(void *);
35void * mqx_to_virt(void *);
36#define VIRT_TO_MQX(x) virt_to_mqx(x)
37#define MQX_TO_VIRT(x) mqx_to_virt(x)
38
39/* Semaphore-related functions */
40int mcc_init_semaphore(unsigned int);
41int mcc_deinit_semaphore(unsigned int);
42int mcc_get_semaphore(void);
43int mcc_release_semaphore(void);
44
45/* CPU-to-CPU interrupt-related functions */
46int mcc_register_cpu_to_cpu_isr(void);
47int mcc_generate_cpu_to_cpu_interrupt(void);
48
49/* Memory management-related functions */
50void mcc_memcpy(void *, void *, unsigned int);
51void _mem_zero(void *, unsigned int);
52
53#endif /* __MCC_LINUX__ */