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_MBOX_CMD_OFF 0x4 16 17 /* Tx Registers */ 18 #define APSS_CPUCP_TX_MBOX_CMD(i) (0x100 + ((i) * 8)) 19 20 /* Rx Registers */ 21 #define APSS_CPUCP_RX_MBOX_CMD(i) (0x100 + ((i) * 8)) 22 #define APSS_CPUCP_RX_MBOX_MAP 0x4000 23 #define APSS_CPUCP_RX_MBOX_STAT 0x4400 24 #define APSS_CPUCP_RX_MBOX_CLEAR 0x4800 25 #define APSS_CPUCP_RX_MBOX_EN 0x4c00 26 #define APSS_CPUCP_RX_MBOX_CMD_MASK GENMASK_ULL(63, 0) 27 28 /** 29 * struct qcom_cpucp_mbox_data - Per-hardware mailbox configuration data 30 * @num_chans: Number of IPC channels supported by this hardware 31 */ 32 struct qcom_cpucp_mbox_data { 33 int num_chans; 34 }; 35 36 /** 37 * struct qcom_cpucp_mbox - Holder for the mailbox driver 38 * @chans: The mailbox channel 39 * @mbox: The mailbox controller 40 * @tx_base: Base address of the CPUCP tx registers 41 * @rx_base: Base address of the CPUCP rx registers 42 */ 43 struct qcom_cpucp_mbox { 44 struct mbox_chan *chans; 45 struct mbox_controller mbox; 46 void __iomem *tx_base; 47 void __iomem *rx_base; 48 }; 49 50 static inline int channel_number(struct mbox_chan *chan) 51 { 52 return chan - chan->mbox->chans; 53 } 54 55 static irqreturn_t qcom_cpucp_mbox_irq_fn(int irq, void *data) 56 { 57 struct qcom_cpucp_mbox *cpucp = data; 58 u64 status; 59 int i; 60 61 status = readq(cpucp->rx_base + APSS_CPUCP_RX_MBOX_STAT); 62 63 for_each_set_bit(i, (unsigned long *)&status, cpucp->mbox.num_chans) { 64 u32 val = readl(cpucp->rx_base + APSS_CPUCP_RX_MBOX_CMD(i) + APSS_CPUCP_MBOX_CMD_OFF); 65 struct mbox_chan *chan = &cpucp->chans[i]; 66 unsigned long flags; 67 68 /* Provide mutual exclusion with changes to chan->cl */ 69 spin_lock_irqsave(&chan->lock, flags); 70 if (chan->cl) 71 mbox_chan_received_data(chan, &val); 72 writeq(BIT(i), cpucp->rx_base + APSS_CPUCP_RX_MBOX_CLEAR); 73 spin_unlock_irqrestore(&chan->lock, flags); 74 } 75 76 return IRQ_HANDLED; 77 } 78 79 static int qcom_cpucp_mbox_startup(struct mbox_chan *chan) 80 { 81 struct qcom_cpucp_mbox *cpucp = container_of(chan->mbox, struct qcom_cpucp_mbox, mbox); 82 unsigned long chan_id = channel_number(chan); 83 u64 val; 84 85 val = readq(cpucp->rx_base + APSS_CPUCP_RX_MBOX_EN); 86 val |= BIT(chan_id); 87 writeq(val, cpucp->rx_base + APSS_CPUCP_RX_MBOX_EN); 88 89 return 0; 90 } 91 92 static void qcom_cpucp_mbox_shutdown(struct mbox_chan *chan) 93 { 94 struct qcom_cpucp_mbox *cpucp = container_of(chan->mbox, struct qcom_cpucp_mbox, mbox); 95 unsigned long chan_id = channel_number(chan); 96 u64 val; 97 98 val = readq(cpucp->rx_base + APSS_CPUCP_RX_MBOX_EN); 99 val &= ~BIT(chan_id); 100 writeq(val, cpucp->rx_base + APSS_CPUCP_RX_MBOX_EN); 101 } 102 103 static int qcom_cpucp_mbox_send_data(struct mbox_chan *chan, void *data) 104 { 105 struct qcom_cpucp_mbox *cpucp = container_of(chan->mbox, struct qcom_cpucp_mbox, mbox); 106 unsigned long chan_id = channel_number(chan); 107 u32 *val = data; 108 109 writel(*val, cpucp->tx_base + APSS_CPUCP_TX_MBOX_CMD(chan_id) + APSS_CPUCP_MBOX_CMD_OFF); 110 111 return 0; 112 } 113 114 static const struct mbox_chan_ops qcom_cpucp_mbox_chan_ops = { 115 .startup = qcom_cpucp_mbox_startup, 116 .send_data = qcom_cpucp_mbox_send_data, 117 .shutdown = qcom_cpucp_mbox_shutdown 118 }; 119 120 static int qcom_cpucp_mbox_probe(struct platform_device *pdev) 121 { 122 const struct qcom_cpucp_mbox_data *data; 123 struct device *dev = &pdev->dev; 124 struct qcom_cpucp_mbox *cpucp; 125 struct mbox_controller *mbox; 126 int irq, ret; 127 128 data = of_device_get_match_data(dev); 129 if (!data) 130 return dev_err_probe(dev, -EINVAL, "No match data found\n"); 131 132 cpucp = devm_kzalloc(dev, sizeof(*cpucp), GFP_KERNEL); 133 if (!cpucp) 134 return -ENOMEM; 135 136 cpucp->chans = devm_kcalloc(dev, data->num_chans, sizeof(*cpucp->chans), GFP_KERNEL); 137 if (!cpucp->chans) 138 return -ENOMEM; 139 140 cpucp->rx_base = devm_of_iomap(dev, dev->of_node, 0, NULL); 141 if (IS_ERR(cpucp->rx_base)) 142 return PTR_ERR(cpucp->rx_base); 143 144 cpucp->tx_base = devm_of_iomap(dev, dev->of_node, 1, NULL); 145 if (IS_ERR(cpucp->tx_base)) 146 return PTR_ERR(cpucp->tx_base); 147 148 writeq(0, cpucp->rx_base + APSS_CPUCP_RX_MBOX_EN); 149 writeq(0, cpucp->rx_base + APSS_CPUCP_RX_MBOX_CLEAR); 150 writeq(0, cpucp->rx_base + APSS_CPUCP_RX_MBOX_MAP); 151 152 irq = platform_get_irq(pdev, 0); 153 if (irq < 0) 154 return irq; 155 156 ret = devm_request_irq(dev, irq, qcom_cpucp_mbox_irq_fn, 157 IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND, "apss_cpucp_mbox", cpucp); 158 if (ret < 0) 159 return dev_err_probe(dev, ret, "Failed to register irq: %d\n", irq); 160 161 writeq(APSS_CPUCP_RX_MBOX_CMD_MASK, cpucp->rx_base + APSS_CPUCP_RX_MBOX_MAP); 162 163 mbox = &cpucp->mbox; 164 mbox->dev = dev; 165 mbox->num_chans = data->num_chans; 166 mbox->chans = cpucp->chans; 167 mbox->ops = &qcom_cpucp_mbox_chan_ops; 168 169 ret = devm_mbox_controller_register(dev, mbox); 170 if (ret) 171 return dev_err_probe(dev, ret, "Failed to create mailbox\n"); 172 173 return 0; 174 } 175 176 static const struct qcom_cpucp_mbox_data qcom_x1e80100_mbox_data = { 177 .num_chans = 3, 178 }; 179 180 static const struct qcom_cpucp_mbox_data qcom_nord_mbox_data = { 181 .num_chans = 16, 182 }; 183 184 static const struct of_device_id qcom_cpucp_mbox_of_match[] = { 185 { .compatible = "qcom,nord-cpucp-mbox", .data = &qcom_nord_mbox_data }, 186 { .compatible = "qcom,x1e80100-cpucp-mbox", .data = &qcom_x1e80100_mbox_data }, 187 {} 188 }; 189 MODULE_DEVICE_TABLE(of, qcom_cpucp_mbox_of_match); 190 191 static struct platform_driver qcom_cpucp_mbox_driver = { 192 .probe = qcom_cpucp_mbox_probe, 193 .driver = { 194 .name = "qcom_cpucp_mbox", 195 .of_match_table = qcom_cpucp_mbox_of_match, 196 }, 197 }; 198 199 static int __init qcom_cpucp_mbox_init(void) 200 { 201 return platform_driver_register(&qcom_cpucp_mbox_driver); 202 } 203 core_initcall(qcom_cpucp_mbox_init); 204 205 static void __exit qcom_cpucp_mbox_exit(void) 206 { 207 platform_driver_unregister(&qcom_cpucp_mbox_driver); 208 } 209 module_exit(qcom_cpucp_mbox_exit); 210 211 MODULE_DESCRIPTION("QTI CPUCP MBOX Driver"); 212 MODULE_LICENSE("GPL"); 213