aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabien Dessenne <fabien.dessenne@st.com>2018-05-31 04:27:25 -0400
committerJassi Brar <jaswinder.singh@linaro.org>2018-06-06 12:51:59 -0400
commitffbded7dee975632f5ca56e565e68e84457f9213 (patch)
tree879cde90d922f119b89d497529af088b162ac37e
parent8f51bb7caeb3731f3fff39109a45ed2c484dd30a (diff)
mailbox: add STMicroelectronics STM32 IPCC driver
The STMicroelectronics STM32 Inter-Processor Communication Controller (IPCC) is used for communicating data between two processors. It provides a non blocking signaling mechanism to post and retrieve communication data in an atomic way. Signed-off-by: Fabien Dessenne <fabien.dessenne@st.com> Signed-off-by: Ludovic Barre <ludovic.barre@st.com> Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
-rw-r--r--drivers/mailbox/Kconfig8
-rw-r--r--drivers/mailbox/Makefile2
-rw-r--r--drivers/mailbox/stm32-ipcc.c402
3 files changed, 412 insertions, 0 deletions
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 725dce5ba62d..fb3f250e587b 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -177,4 +177,12 @@ config BCM_FLEXRM_MBOX
177 Mailbox implementation of the Broadcom FlexRM ring manager, 177 Mailbox implementation of the Broadcom FlexRM ring manager,
178 which provides access to various offload engines on Broadcom 178 which provides access to various offload engines on Broadcom
179 SoCs. Say Y here if you want to use the Broadcom FlexRM. 179 SoCs. Say Y here if you want to use the Broadcom FlexRM.
180
181config STM32_IPCC
182 tristate "STM32 IPCC Mailbox"
183 depends on MACH_STM32MP157
184 help
185 Mailbox implementation for STMicroelectonics STM32 family chips
186 with hardware for Inter-Processor Communication Controller (IPCC)
187 between processors. Say Y here if you want to have this support.
180endif 188endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index cc23c3a43fcd..4d501bea7863 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -38,3 +38,5 @@ obj-$(CONFIG_BCM_FLEXRM_MBOX) += bcm-flexrm-mailbox.o
38obj-$(CONFIG_QCOM_APCS_IPC) += qcom-apcs-ipc-mailbox.o 38obj-$(CONFIG_QCOM_APCS_IPC) += qcom-apcs-ipc-mailbox.o
39 39
40obj-$(CONFIG_TEGRA_HSP_MBOX) += tegra-hsp.o 40obj-$(CONFIG_TEGRA_HSP_MBOX) += tegra-hsp.o
41
42obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o
diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c
new file mode 100644
index 000000000000..533b0da5235d
--- /dev/null
+++ b/drivers/mailbox/stm32-ipcc.c
@@ -0,0 +1,402 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
4 * Authors: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
5 * Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
6 */
7
8#include <linux/bitfield.h>
9#include <linux/clk.h>
10#include <linux/interrupt.h>
11#include <linux/mailbox_controller.h>
12#include <linux/module.h>
13#include <linux/of_irq.h>
14#include <linux/platform_device.h>
15#include <linux/pm_wakeirq.h>
16
17#define IPCC_XCR 0x000
18#define XCR_RXOIE BIT(0)
19#define XCR_TXOIE BIT(16)
20
21#define IPCC_XMR 0x004
22#define IPCC_XSCR 0x008
23#define IPCC_XTOYSR 0x00c
24
25#define IPCC_PROC_OFFST 0x010
26
27#define IPCC_HWCFGR 0x3f0
28#define IPCFGR_CHAN_MASK GENMASK(7, 0)
29
30#define IPCC_VER 0x3f4
31#define VER_MINREV_MASK GENMASK(3, 0)
32#define VER_MAJREV_MASK GENMASK(7, 4)
33
34#define RX_BIT_MASK GENMASK(15, 0)
35#define RX_BIT_CHAN(chan) BIT(chan)
36#define TX_BIT_SHIFT 16
37#define TX_BIT_MASK GENMASK(31, 16)
38#define TX_BIT_CHAN(chan) BIT(TX_BIT_SHIFT + (chan))
39
40#define STM32_MAX_PROCS 2
41
42enum {
43 IPCC_IRQ_RX,
44 IPCC_IRQ_TX,
45 IPCC_IRQ_NUM,
46};
47
48struct stm32_ipcc {
49 struct mbox_controller controller;
50 void __iomem *reg_base;
51 void __iomem *reg_proc;
52 struct clk *clk;
53 int irqs[IPCC_IRQ_NUM];
54 int wkp;
55 u32 proc_id;
56 u32 n_chans;
57 u32 xcr;
58 u32 xmr;
59};
60
61static inline void stm32_ipcc_set_bits(void __iomem *reg, u32 mask)
62{
63 writel_relaxed(readl_relaxed(reg) | mask, reg);
64}
65
66static inline void stm32_ipcc_clr_bits(void __iomem *reg, u32 mask)
67{
68 writel_relaxed(readl_relaxed(reg) & ~mask, reg);
69}
70
71static irqreturn_t stm32_ipcc_rx_irq(int irq, void *data)
72{
73 struct stm32_ipcc *ipcc = data;
74 struct device *dev = ipcc->controller.dev;
75 u32 status, mr, tosr, chan;
76 irqreturn_t ret = IRQ_NONE;
77 int proc_offset;
78
79 /* read 'channel occupied' status from other proc */
80 proc_offset = ipcc->proc_id ? -IPCC_PROC_OFFST : IPCC_PROC_OFFST;
81 tosr = readl_relaxed(ipcc->reg_proc + proc_offset + IPCC_XTOYSR);
82 mr = readl_relaxed(ipcc->reg_proc + IPCC_XMR);
83
84 /* search for unmasked 'channel occupied' */
85 status = tosr & FIELD_GET(RX_BIT_MASK, ~mr);
86
87 for (chan = 0; chan < ipcc->n_chans; chan++) {
88 if (!(status & (1 << chan)))
89 continue;
90
91 dev_dbg(dev, "%s: chan:%d rx\n", __func__, chan);
92
93 mbox_chan_received_data(&ipcc->controller.chans[chan], NULL);
94
95 stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XSCR,
96 RX_BIT_CHAN(chan));
97
98 ret = IRQ_HANDLED;
99 }
100
101 return ret;
102}
103
104static irqreturn_t stm32_ipcc_tx_irq(int irq, void *data)
105{
106 struct stm32_ipcc *ipcc = data;
107 struct device *dev = ipcc->controller.dev;
108 u32 status, mr, tosr, chan;
109 irqreturn_t ret = IRQ_NONE;
110
111 tosr = readl_relaxed(ipcc->reg_proc + IPCC_XTOYSR);
112 mr = readl_relaxed(ipcc->reg_proc + IPCC_XMR);
113
114 /* search for unmasked 'channel free' */
115 status = ~tosr & FIELD_GET(TX_BIT_MASK, ~mr);
116
117 for (chan = 0; chan < ipcc->n_chans ; chan++) {
118 if (!(status & (1 << chan)))
119 continue;
120
121 dev_dbg(dev, "%s: chan:%d tx\n", __func__, chan);
122
123 /* mask 'tx channel free' interrupt */
124 stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XMR,
125 TX_BIT_CHAN(chan));
126
127 mbox_chan_txdone(&ipcc->controller.chans[chan], 0);
128
129 ret = IRQ_HANDLED;
130 }
131
132 return ret;
133}
134
135static int stm32_ipcc_send_data(struct mbox_chan *link, void *data)
136{
137 unsigned int chan = (unsigned int)link->con_priv;
138 struct stm32_ipcc *ipcc = container_of(link->mbox, struct stm32_ipcc,
139 controller);
140
141 dev_dbg(ipcc->controller.dev, "%s: chan:%d\n", __func__, chan);
142
143 /* set channel n occupied */
144 stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XSCR, TX_BIT_CHAN(chan));
145
146 /* unmask 'tx channel free' interrupt */
147 stm32_ipcc_clr_bits(ipcc->reg_proc + IPCC_XMR, TX_BIT_CHAN(chan));
148
149 return 0;
150}
151
152static int stm32_ipcc_startup(struct mbox_chan *link)
153{
154 unsigned int chan = (unsigned int)link->con_priv;
155 struct stm32_ipcc *ipcc = container_of(link->mbox, struct stm32_ipcc,
156 controller);
157 int ret;
158
159 ret = clk_prepare_enable(ipcc->clk);
160 if (ret) {
161 dev_err(ipcc->controller.dev, "can not enable the clock\n");
162 return ret;
163 }
164
165 /* unmask 'rx channel occupied' interrupt */
166 stm32_ipcc_clr_bits(ipcc->reg_proc + IPCC_XMR, RX_BIT_CHAN(chan));
167
168 return 0;
169}
170
171static void stm32_ipcc_shutdown(struct mbox_chan *link)
172{
173 unsigned int chan = (unsigned int)link->con_priv;
174 struct stm32_ipcc *ipcc = container_of(link->mbox, struct stm32_ipcc,
175 controller);
176
177 /* mask rx/tx interrupt */
178 stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XMR,
179 RX_BIT_CHAN(chan) | TX_BIT_CHAN(chan));
180
181 clk_disable_unprepare(ipcc->clk);
182}