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 struct mbox_client *cl; 67 unsigned long flags; 68 69 /* 70 * Provide mutual exclusion with changes to chan->cl. 71 * Save cl locally and clear the HW interrupt inside the lock, 72 * then invoke mbox_chan_received_data() outside the lock to 73 * avoid a PREEMPT_RT self-deadlock: mbox_chan_received_data() 74 * can call back into mbox_send_message() via scmi_rx_callback() 75 * -> mailbox_clear_channel(), which re-acquires chan->lock 76 * (converted to an rt_spinlock under PREEMPT_RT). 77 */ 78 spin_lock_irqsave(&chan->lock, flags); 79 cl = chan->cl; 80 writeq(BIT(i), cpucp->rx_base + APSS_CPUCP_RX_MBOX_CLEAR); 81 spin_unlock_irqrestore(&chan->lock, flags); 82 83 if (cl) 84 mbox_chan_received_data(chan, &val); 85 } 86 87 return IRQ_HANDLED; 88 } 89 90 static int qcom_cpucp_mbox_startup(struct mbox_chan *chan) 91 { 92 struct qcom_cpucp_mbox *cpucp = container_of(chan->mbox, struct qcom_cpucp_mbox, mbox); 93 unsigned long chan_id = channel_number(chan); 94 u64 val; 95 96 val = readq(cpucp->rx_base + APSS_CPUCP_RX_MBOX_EN); 97 val |= BIT(chan_id); 98 writeq(val, cpucp->rx_base + APSS_CPUCP_RX_MBOX_EN); 99 100 return 0; 101 } 102 103 static void qcom_cpucp_mbox_shutdown(struct mbox_chan *chan) 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 u64 val; 108 109 val = readq(cpucp->rx_base + APSS_CPUCP_RX_MBOX_EN); 110 val &= ~BIT(chan_id); 111 writeq(val, cpucp->rx_base + APSS_CPUCP_RX_MBOX_EN); 112 } 113 114 static int qcom_cpucp_mbox_send_data(struct mbox_chan *chan, void *data) 115 { 116 struct qcom_cpucp_mbox *cpucp = container_of(chan->mbox, struct qcom_cpucp_mbox, mbox); 117 unsigned long chan_id = channel_number(chan); 118 u32 *val = data; 119 120 /* 121 * mailbox_clear_channel() calls mbox_send_message() with NULL data to 122 * signal the remote side that the channel has been cleared. Nothing 123 * needs to be written to the TX register in that case, so just return. 124 */ 125 if (!val) 126 return 0; 127 128 writel(*val, cpucp->tx_base + APSS_CPUCP_TX_MBOX_CMD(chan_id) + APSS_CPUCP_MBOX_CMD_OFF); 129 130 return 0; 131 } 132 133 static const struct mbox_chan_ops qcom_cpucp_mbox_chan_ops = { 134 .startup = qcom_cpucp_mbox_startup, 135 .send_data = qcom_cpucp_mbox_send_data, 136 .shutdown = qcom_cpucp_mbox_shutdown 137 }; 138 139 static int qcom_cpucp_mbox_probe(struct platform_device *pdev) 140 { 141 const struct qcom_cpucp_mbox_data *data; 142 struct device *dev = &pdev->dev; 143 struct qcom_cpucp_mbox *cpucp; 144 struct mbox_controller *mbox; 145 int irq, ret; 146 147 data = of_device_get_match_data(dev); 148 if (!data) 149 return dev_err_probe(dev, -EINVAL, "No match data found\n"); 150 151 cpucp = devm_kzalloc(dev, sizeof(*cpucp), GFP_KERNEL); 152 if (!cpucp) 153 return -ENOMEM; 154 155 cpucp->chans = devm_kcalloc(dev, data->num_chans, sizeof(*cpucp->chans), GFP_KERNEL); 156 if (!cpucp->chans) 157 return -ENOMEM; 158 159 cpucp->rx_base = devm_of_iomap(dev, dev->of_node, 0, NULL); 160 if (IS_ERR(cpucp->rx_base)) 161 return PTR_ERR(cpucp->rx_base); 162 163 cpucp->tx_base = devm_of_iomap(dev, dev->of_node, 1, NULL); 164 if (IS_ERR(cpucp->tx_base)) 165 return PTR_ERR(cpucp->tx_base); 166 167 writeq(0, cpucp->rx_base + APSS_CPUCP_RX_MBOX_EN); 168 writeq(0, cpucp->rx_base + APSS_CPUCP_RX_MBOX_CLEAR); 169 writeq(0, cpucp->rx_base + APSS_CPUCP_RX_MBOX_MAP); 170 171 irq = platform_get_irq(pdev, 0); 172 if (irq < 0) 173 return irq; 174 175 ret = devm_request_irq(dev, irq, qcom_cpucp_mbox_irq_fn, 176 IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND, "apss_cpucp_mbox", cpucp); 177 if (ret < 0) 178 return ret; 179 180 writeq(APSS_CPUCP_RX_MBOX_CMD_MASK, cpucp->rx_base + APSS_CPUCP_RX_MBOX_MAP); 181 182 mbox = &cpucp->mbox; 183 mbox->dev = dev; 184 mbox->num_chans = data->num_chans; 185 mbox->chans = cpucp->chans; 186 mbox->ops = &qcom_cpucp_mbox_chan_ops; 187 188 ret = devm_mbox_controller_register(dev, mbox); 189 if (ret) 190 return dev_err_probe(dev, ret, "Failed to create mailbox\n"); 191 192 return 0; 193 } 194 195 static const struct qcom_cpucp_mbox_data qcom_x1e80100_mbox_data = { 196 .num_chans = 3, 197 }; 198 199 static const struct qcom_cpucp_mbox_data qcom_nord_mbox_data = { 200 .num_chans = 16, 201 }; 202 203 static const struct of_device_id qcom_cpucp_mbox_of_match[] = { 204 { .compatible = "qcom,nord-cpucp-mbox", .data = &qcom_nord_mbox_data }, 205 { .compatible = "qcom,x1e80100-cpucp-mbox", .data = &qcom_x1e80100_mbox_data }, 206 {} 207 }; 208 MODULE_DEVICE_TABLE(of, qcom_cpucp_mbox_of_match); 209 210 static struct platform_driver qcom_cpucp_mbox_driver = { 211 .probe = qcom_cpucp_mbox_probe, 212 .driver = { 213 .name = "qcom_cpucp_mbox", 214 .of_match_table = qcom_cpucp_mbox_of_match, 215 }, 216 }; 217 218 static int __init qcom_cpucp_mbox_init(void) 219 { 220 return platform_driver_register(&qcom_cpucp_mbox_driver); 221 } 222 core_initcall(qcom_cpucp_mbox_init); 223 224 static void __exit qcom_cpucp_mbox_exit(void) 225 { 226 platform_driver_unregister(&qcom_cpucp_mbox_driver); 227 } 228 module_exit(qcom_cpucp_mbox_exit); 229 230 MODULE_DESCRIPTION("QTI CPUCP MBOX Driver"); 231 MODULE_LICENSE("GPL"); 232