1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2024 Sophgo Technology Inc. 4 * Copyright (C) 2024 Yuntao Dai <d1581209858@live.com> 5 * Copyright (C) 2025 Junhui Liu <junhui.liu@pigmoral.tech> 6 */ 7 8 #include <linux/bits.h> 9 #include <linux/device.h> 10 #include <linux/err.h> 11 #include <linux/interrupt.h> 12 #include <linux/io.h> 13 #include <linux/kfifo.h> 14 #include <linux/mailbox_client.h> 15 #include <linux/mailbox_controller.h> 16 #include <linux/module.h> 17 #include <linux/platform_device.h> 18 #include <linux/slab.h> 19 20 #define RECV_CPU 1 21 22 #define MAILBOX_MAX_CHAN 8 23 #define MAILBOX_MSG_LEN 8 24 25 #define MBOX_EN_REG(cpu) (cpu << 2) 26 #define MBOX_DONE_REG(cpu) ((cpu << 2) + 2) 27 #define MBOX_SET_CLR_REG(cpu) (0x10 + (cpu << 4)) 28 #define MBOX_SET_INT_REG(cpu) (0x18 + (cpu << 4)) 29 #define MBOX_SET_REG 0x60 30 31 #define MAILBOX_CONTEXT_OFFSET 0x0400 32 #define MAILBOX_CONTEXT_SIZE 0x0040 33 34 #define MBOX_CONTEXT_BASE_INDEX(base, index) \ 35 ((u64 __iomem *)(base + MAILBOX_CONTEXT_OFFSET) + index) 36 37 /** 38 * struct cv1800_mbox_chan_priv - cv1800 mailbox channel private data 39 * @idx: index of channel 40 * @cpu: send to which processor 41 */ 42 struct cv1800_mbox_chan_priv { 43 int idx; 44 int cpu; 45 }; 46 47 struct cv1800_mbox { 48 struct mbox_controller mbox; 49 struct cv1800_mbox_chan_priv priv[MAILBOX_MAX_CHAN]; 50 struct mbox_chan chans[MAILBOX_MAX_CHAN]; 51 u64 __iomem *content[MAILBOX_MAX_CHAN]; 52 void __iomem *mbox_base; 53 int recvid; 54 }; 55 56 static irqreturn_t cv1800_mbox_isr(int irq, void *dev_id) 57 { 58 struct cv1800_mbox *mbox = (struct cv1800_mbox *)dev_id; 59 size_t i; 60 u64 msg; 61 int ret = IRQ_NONE; 62 63 for (i = 0; i < MAILBOX_MAX_CHAN; i++) { 64 if (mbox->content[i] && mbox->chans[i].cl) { 65 memcpy_fromio(&msg, mbox->content[i], MAILBOX_MSG_LEN); 66 mbox->content[i] = NULL; 67 mbox_chan_received_data(&mbox->chans[i], (void *)&msg); 68 ret = IRQ_HANDLED; 69 } 70 } 71 72 return ret; 73 } 74 75 static irqreturn_t cv1800_mbox_irq(int irq, void *dev_id) 76 { 77 struct cv1800_mbox *mbox = (struct cv1800_mbox *)dev_id; 78 u8 set, valid; 79 size_t i; 80 int ret = IRQ_NONE; 81 82 set = readb(mbox->mbox_base + MBOX_SET_INT_REG(RECV_CPU)); 83 84 if (!set) 85 return ret; 86 87 for (i = 0; i < MAILBOX_MAX_CHAN; i++) { 88 valid = set & BIT(i); 89 if (valid) { 90 mbox->content[i] = 91 MBOX_CONTEXT_BASE_INDEX(mbox->mbox_base, i); 92 writeb(valid, mbox->mbox_base + 93 MBOX_SET_CLR_REG(RECV_CPU)); 94 writeb(~valid, mbox->mbox_base + MBOX_EN_REG(RECV_CPU)); 95 ret = IRQ_WAKE_THREAD; 96 } 97 } 98 99 return ret; 100 } 101 102 static int cv1800_mbox_send_data(struct mbox_chan *chan, void *data) 103 { 104 struct cv1800_mbox_chan_priv *priv = 105 (struct cv1800_mbox_chan_priv *)chan->con_priv; 106 struct cv1800_mbox *mbox = dev_get_drvdata(chan->mbox->dev); 107 int idx = priv->idx; 108 int cpu = priv->cpu; 109 u8 en, valid; 110 111 memcpy_toio(MBOX_CONTEXT_BASE_INDEX(mbox->mbox_base, idx), 112 data, MAILBOX_MSG_LEN); 113 114 valid = BIT(idx); 115 writeb(valid, mbox->mbox_base + MBOX_SET_CLR_REG(cpu)); 116 en = readb(mbox->mbox_base + MBOX_EN_REG(cpu)); 117 writeb(en | valid, mbox->mbox_base + MBOX_EN_REG(cpu)); 118 writeb(valid, mbox->mbox_base + MBOX_SET_REG); 119 120 return 0; 121 } 122 123 static bool cv1800_last_tx_done(struct mbox_chan *chan) 124 { 125 struct cv1800_mbox_chan_priv *priv = 126 (struct cv1800_mbox_chan_priv *)chan->con_priv; 127 struct cv1800_mbox *mbox = dev_get_drvdata(chan->mbox->dev); 128 u8 en; 129 130 en = readb(mbox->mbox_base + MBOX_EN_REG(priv->cpu)); 131 132 return !(en & BIT(priv->idx)); 133 } 134 135 static const struct mbox_chan_ops cv1800_mbox_chan_ops = { 136 .send_data = cv1800_mbox_send_data, 137 .last_tx_done = cv1800_last_tx_done, 138 }; 139 140 static struct mbox_chan *cv1800_mbox_xlate(struct mbox_controller *mbox, 141 const struct of_phandle_args *spec) 142 { 143 struct cv1800_mbox_chan_priv *priv; 144 145 int idx = spec->args[0]; 146 int cpu = spec->args[1]; 147 148 if (idx >= mbox->num_chans) 149 return ERR_PTR(-EINVAL); 150 151 priv = mbox->chans[idx].con_priv; 152 priv->cpu = cpu; 153 154 return &mbox->chans[idx]; 155 } 156 157 static const struct of_device_id cv1800_mbox_of_match[] = { 158 { .compatible = "sophgo,cv1800b-mailbox", }, 159 {}, 160 }; 161 MODULE_DEVICE_TABLE(of, cv1800_mbox_of_match); 162 163 static int cv1800_mbox_probe(struct platform_device *pdev) 164 { 165 struct device *dev = &pdev->dev; 166 struct cv1800_mbox *mb; 167 int irq, idx, err; 168 169 mb = devm_kzalloc(dev, sizeof(*mb), GFP_KERNEL); 170 if (!mb) 171 return -ENOMEM; 172 173 mb->mbox_base = devm_platform_ioremap_resource(pdev, 0); 174 if (IS_ERR(mb->mbox_base)) 175 return dev_err_probe(dev, PTR_ERR(mb->mbox_base), 176 "Failed to map resource\n"); 177 178 mb->mbox.dev = dev; 179 mb->mbox.chans = mb->chans; 180 mb->mbox.txdone_poll = true; 181 mb->mbox.ops = &cv1800_mbox_chan_ops; 182 mb->mbox.num_chans = MAILBOX_MAX_CHAN; 183 mb->mbox.of_xlate = cv1800_mbox_xlate; 184 185 irq = platform_get_irq(pdev, 0); 186 if (irq < 0) 187 return irq; 188 189 err = devm_request_threaded_irq(dev, irq, cv1800_mbox_irq, 190 cv1800_mbox_isr, IRQF_ONESHOT, 191 dev_name(&pdev->dev), mb); 192 if (err < 0) 193 return dev_err_probe(dev, err, "Failed to register irq\n"); 194 195 for (idx = 0; idx < MAILBOX_MAX_CHAN; idx++) { 196 mb->priv[idx].idx = idx; 197 mb->mbox.chans[idx].con_priv = &mb->priv[idx]; 198 } 199 200 platform_set_drvdata(pdev, mb); 201 202 err = devm_mbox_controller_register(dev, &mb->mbox); 203 if (err) 204 return dev_err_probe(dev, err, "Failed to register mailbox\n"); 205 206 return 0; 207 } 208 209 static struct platform_driver cv1800_mbox_driver = { 210 .driver = { 211 .name = "cv1800-mbox", 212 .of_match_table = cv1800_mbox_of_match, 213 }, 214 .probe = cv1800_mbox_probe, 215 }; 216 217 module_platform_driver(cv1800_mbox_driver); 218 219 MODULE_DESCRIPTION("cv1800 mailbox driver"); 220 MODULE_LICENSE("GPL"); 221