Skip to content

Commit 0e2a9a0

Browse files
Sibi SankarJassi Brar
authored andcommitted
mailbox: Add support for QTI CPUCP mailbox controller
Add support for CPUSS Control Processor (CPUCP) mailbox controller, this driver enables communication between AP and CPUCP by acting as a doorbell between them. Reviewed-by: Dmitry Baryshkov <[email protected]> Signed-off-by: Sibi Sankar <[email protected]> Reviewed-by: Bjorn Andersson <[email protected]> Reviewed-by: Konrad Dybcio <[email protected]> Signed-off-by: Jassi Brar <[email protected]>
1 parent 6e7c4cc commit 0e2a9a0

File tree

4 files changed

+204
-0
lines changed

4 files changed

+204
-0
lines changed

MAINTAINERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18461,6 +18461,13 @@ S: Maintained
1846118461
F: Documentation/devicetree/bindings/power/avs/qcom,cpr.yaml
1846218462
F: drivers/pmdomain/qcom/cpr.c
1846318463

18464+
QUALCOMM CPUCP MAILBOX DRIVER
18465+
M: Sibi Sankar <[email protected]>
18466+
18467+
S: Supported
18468+
F: Documentation/devicetree/bindings/mailbox/qcom,cpucp-mbox.yaml
18469+
F: drivers/mailbox/qcom-cpucp-mbox.c
18470+
1846418471
QUALCOMM CPUFREQ DRIVER MSM8996/APQ8096
1846518472
M: Ilia Lin <[email protected]>
1846618473

drivers/mailbox/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,14 @@ config SPRD_MBOX
276276
to send message between application processors and MCU. Say Y here if
277277
you want to build the Spreatrum mailbox controller driver.
278278

279+
config QCOM_CPUCP_MBOX
280+
tristate "Qualcomm Technologies, Inc. CPUCP mailbox driver"
281+
depends on ARCH_QCOM || (COMPILE_TEST && 64BIT)
282+
help
283+
Qualcomm Technologies, Inc. CPUSS Control Processor (CPUCP) mailbox
284+
controller driver enables communication between AP and CPUCP. Say
285+
Y here if you want to build this driver.
286+
279287
config QCOM_IPCC
280288
tristate "Qualcomm Technologies, Inc. IPCC driver"
281289
depends on ARCH_QCOM || COMPILE_TEST

drivers/mailbox/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,6 @@ obj-$(CONFIG_SUN6I_MSGBOX) += sun6i-msgbox.o
6161

6262
obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o
6363

64+
obj-$(CONFIG_QCOM_CPUCP_MBOX) += qcom-cpucp-mbox.o
65+
6466
obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o

drivers/mailbox/qcom-cpucp-mbox.c

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
4+
*/
5+
6+
#include <linux/bitops.h>
7+
#include <linux/interrupt.h>
8+
#include <linux/io.h>
9+
#include <linux/irq.h>
10+
#include <linux/irqdomain.h>
11+
#include <linux/mailbox_controller.h>
12+
#include <linux/module.h>
13+
#include <linux/platform_device.h>
14+
15+
#define APSS_CPUCP_IPC_CHAN_SUPPORTED 3
16+
#define APSS_CPUCP_MBOX_CMD_OFF 0x4
17+
18+
/* Tx Registers */
19+
#define APSS_CPUCP_TX_MBOX_CMD(i) (0x100 + ((i) * 8))
20+
21+
/* Rx Registers */
22+
#define APSS_CPUCP_RX_MBOX_CMD(i) (0x100 + ((i) * 8))
23+
#define APSS_CPUCP_RX_MBOX_MAP 0x4000
24+
#define APSS_CPUCP_RX_MBOX_STAT 0x4400
25+
#define APSS_CPUCP_RX_MBOX_CLEAR 0x4800
26+
#define APSS_CPUCP_RX_MBOX_EN 0x4c00
27+
#define APSS_CPUCP_RX_MBOX_CMD_MASK GENMASK_ULL(63, 0)
28+
29+
/**
30+
* struct qcom_cpucp_mbox - Holder for the mailbox driver
31+
* @chans: The mailbox channel
32+
* @mbox: The mailbox controller
33+
* @tx_base: Base address of the CPUCP tx registers
34+
* @rx_base: Base address of the CPUCP rx registers
35+
*/
36+
struct qcom_cpucp_mbox {
37+
struct mbox_chan chans[APSS_CPUCP_IPC_CHAN_SUPPORTED];
38+
struct mbox_controller mbox;
39+
void __iomem *tx_base;
40+
void __iomem *rx_base;
41+
};
42+
43+
static inline int channel_number(struct mbox_chan *chan)
44+
{
45+
return chan - chan->mbox->chans;
46+
}
47+
48+
static irqreturn_t qcom_cpucp_mbox_irq_fn(int irq, void *data)
49+
{
50+
struct qcom_cpucp_mbox *cpucp = data;
51+
u64 status;
52+
int i;
53+
54+
status = readq(cpucp->rx_base + APSS_CPUCP_RX_MBOX_STAT);
55+
56+
for_each_set_bit(i, (unsigned long *)&status, APSS_CPUCP_IPC_CHAN_SUPPORTED) {
57+
u32 val = readl(cpucp->rx_base + APSS_CPUCP_RX_MBOX_CMD(i) + APSS_CPUCP_MBOX_CMD_OFF);
58+
struct mbox_chan *chan = &cpucp->chans[i];
59+
unsigned long flags;
60+
61+
/* Provide mutual exclusion with changes to chan->cl */
62+
spin_lock_irqsave(&chan->lock, flags);
63+
if (chan->cl)
64+
mbox_chan_received_data(chan, &val);
65+
writeq(BIT(i), cpucp->rx_base + APSS_CPUCP_RX_MBOX_CLEAR);
66+
spin_unlock_irqrestore(&chan->lock, flags);
67+
}
68+
69+
return IRQ_HANDLED;
70+
}
71+
72+
static int qcom_cpucp_mbox_startup(struct mbox_chan *chan)
73+
{
74+
struct qcom_cpucp_mbox *cpucp = container_of(chan->mbox, struct qcom_cpucp_mbox, mbox);
75+
unsigned long chan_id = channel_number(chan);
76+
u64 val;
77+
78+
val = readq(cpucp->rx_base + APSS_CPUCP_RX_MBOX_EN);
79+
val |= BIT(chan_id);
80+
writeq(val, cpucp->rx_base + APSS_CPUCP_RX_MBOX_EN);
81+
82+
return 0;
83+
}
84+
85+
static void qcom_cpucp_mbox_shutdown(struct mbox_chan *chan)
86+
{
87+
struct qcom_cpucp_mbox *cpucp = container_of(chan->mbox, struct qcom_cpucp_mbox, mbox);
88+
unsigned long chan_id = channel_number(chan);
89+
u64 val;
90+
91+
val = readq(cpucp->rx_base + APSS_CPUCP_RX_MBOX_EN);
92+
val &= ~BIT(chan_id);
93+
writeq(val, cpucp->rx_base + APSS_CPUCP_RX_MBOX_EN);
94+
}
95+
96+
static int qcom_cpucp_mbox_send_data(struct mbox_chan *chan, void *data)
97+
{
98+
struct qcom_cpucp_mbox *cpucp = container_of(chan->mbox, struct qcom_cpucp_mbox, mbox);
99+
unsigned long chan_id = channel_number(chan);
100+
u32 *val = data;
101+
102+
writel(*val, cpucp->tx_base + APSS_CPUCP_TX_MBOX_CMD(chan_id) + APSS_CPUCP_MBOX_CMD_OFF);
103+
104+
return 0;
105+
}
106+
107+
static const struct mbox_chan_ops qcom_cpucp_mbox_chan_ops = {
108+
.startup = qcom_cpucp_mbox_startup,
109+
.send_data = qcom_cpucp_mbox_send_data,
110+
.shutdown = qcom_cpucp_mbox_shutdown
111+
};
112+
113+
static int qcom_cpucp_mbox_probe(struct platform_device *pdev)
114+
{
115+
struct device *dev = &pdev->dev;
116+
struct qcom_cpucp_mbox *cpucp;
117+
struct mbox_controller *mbox;
118+
int irq, ret;
119+
120+
cpucp = devm_kzalloc(dev, sizeof(*cpucp), GFP_KERNEL);
121+
if (!cpucp)
122+
return -ENOMEM;
123+
124+
cpucp->rx_base = devm_of_iomap(dev, dev->of_node, 0, NULL);
125+
if (IS_ERR(cpucp->rx_base))
126+
return PTR_ERR(cpucp->rx_base);
127+
128+
cpucp->tx_base = devm_of_iomap(dev, dev->of_node, 1, NULL);
129+
if (IS_ERR(cpucp->tx_base))
130+
return PTR_ERR(cpucp->tx_base);
131+
132+
writeq(0, cpucp->rx_base + APSS_CPUCP_RX_MBOX_EN);
133+
writeq(0, cpucp->rx_base + APSS_CPUCP_RX_MBOX_CLEAR);
134+
writeq(0, cpucp->rx_base + APSS_CPUCP_RX_MBOX_MAP);
135+
136+
irq = platform_get_irq(pdev, 0);
137+
if (irq < 0)
138+
return irq;
139+
140+
ret = devm_request_irq(dev, irq, qcom_cpucp_mbox_irq_fn,
141+
IRQF_TRIGGER_HIGH, "apss_cpucp_mbox", cpucp);
142+
if (ret < 0)
143+
return dev_err_probe(dev, ret, "Failed to register irq: %d\n", irq);
144+
145+
writeq(APSS_CPUCP_RX_MBOX_CMD_MASK, cpucp->rx_base + APSS_CPUCP_RX_MBOX_MAP);
146+
147+
mbox = &cpucp->mbox;
148+
mbox->dev = dev;
149+
mbox->num_chans = APSS_CPUCP_IPC_CHAN_SUPPORTED;
150+
mbox->chans = cpucp->chans;
151+
mbox->ops = &qcom_cpucp_mbox_chan_ops;
152+
153+
ret = devm_mbox_controller_register(dev, mbox);
154+
if (ret)
155+
return dev_err_probe(dev, ret, "Failed to create mailbox\n");
156+
157+
return 0;
158+
}
159+
160+
static const struct of_device_id qcom_cpucp_mbox_of_match[] = {
161+
{ .compatible = "qcom,x1e80100-cpucp-mbox" },
162+
{}
163+
};
164+
MODULE_DEVICE_TABLE(of, qcom_cpucp_mbox_of_match);
165+
166+
static struct platform_driver qcom_cpucp_mbox_driver = {
167+
.probe = qcom_cpucp_mbox_probe,
168+
.driver = {
169+
.name = "qcom_cpucp_mbox",
170+
.of_match_table = qcom_cpucp_mbox_of_match,
171+
},
172+
};
173+
174+
static int __init qcom_cpucp_mbox_init(void)
175+
{
176+
return platform_driver_register(&qcom_cpucp_mbox_driver);
177+
}
178+
core_initcall(qcom_cpucp_mbox_init);
179+
180+
static void __exit qcom_cpucp_mbox_exit(void)
181+
{
182+
platform_driver_unregister(&qcom_cpucp_mbox_driver);
183+
}
184+
module_exit(qcom_cpucp_mbox_exit);
185+
186+
MODULE_DESCRIPTION("QTI CPUCP MBOX Driver");
187+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)