1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2022 MediaTek Corporation. All rights reserved. 4 * Author: Allen-KH Cheng <allen-kh.cheng@mediatek.com> 5 */ 6 7 #include <linux/interrupt.h> 8 #include <linux/io.h> 9 #include <linux/iopoll.h> 10 #include <linux/kernel.h> 11 #include <linux/mailbox_controller.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/platform_device.h> 15 #include <linux/slab.h> 16 17 struct mtk_adsp_mbox_priv { 18 struct device *dev; 19 struct mbox_controller mbox; 20 void __iomem *va_mboxreg; 21 const struct mtk_adsp_mbox_cfg *cfg; 22 int irq; 23 }; 24 25 struct mtk_adsp_mbox_cfg { 26 u32 set_in; 27 u32 set_out; 28 u32 clr_in; 29 u32 clr_out; 30 }; 31 32 static inline struct mtk_adsp_mbox_priv *get_mtk_adsp_mbox_priv(struct mbox_controller *mbox) 33 { 34 return container_of(mbox, struct mtk_adsp_mbox_priv, mbox); 35 } 36 37 static irqreturn_t mtk_adsp_mbox_irq(int irq, void *data) 38 { 39 struct mbox_chan *chan = data; 40 struct mtk_adsp_mbox_priv *priv = get_mtk_adsp_mbox_priv(chan->mbox); 41 u32 op = readl(priv->va_mboxreg + priv->cfg->set_out); 42 43 writel(op, priv->va_mboxreg + priv->cfg->clr_out); 44 45 return IRQ_WAKE_THREAD; 46 } 47 48 static irqreturn_t mtk_adsp_mbox_isr(int irq, void *data) 49 { 50 struct mbox_chan *chan = data; 51 52 mbox_chan_received_data(chan, NULL); 53 54 return IRQ_HANDLED; 55 } 56 57 static struct mbox_chan *mtk_adsp_mbox_xlate(struct mbox_controller *mbox, 58 const struct of_phandle_args *sp) 59 { 60 return mbox->chans; 61 } 62 63 static int mtk_adsp_mbox_startup(struct mbox_chan *chan) 64 { 65 struct mtk_adsp_mbox_priv *priv = get_mtk_adsp_mbox_priv(chan->mbox); 66 67 /* Clear ADSP mbox command */ 68 writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_in); 69 writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_out); 70 71 enable_irq(priv->irq); 72 73 return 0; 74 } 75 76 static void mtk_adsp_mbox_shutdown(struct mbox_chan *chan) 77 { 78 struct mtk_adsp_mbox_priv *priv = get_mtk_adsp_mbox_priv(chan->mbox); 79 80 disable_irq(priv->irq); 81 82 /* Clear ADSP mbox command */ 83 writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_in); 84 writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_out); 85 } 86 87 static int mtk_adsp_mbox_send_data(struct mbox_chan *chan, void *data) 88 { 89 struct mtk_adsp_mbox_priv *priv = get_mtk_adsp_mbox_priv(chan->mbox); 90 u32 *msg = data; 91 92 writel(*msg, priv->va_mboxreg + priv->cfg->set_in); 93 94 return 0; 95 } 96 97 static bool mtk_adsp_mbox_last_tx_done(struct mbox_chan *chan) 98 { 99 struct mtk_adsp_mbox_priv *priv = get_mtk_adsp_mbox_priv(chan->mbox); 100 101 return readl(priv->va_mboxreg + priv->cfg->set_in) == 0; 102 } 103 104 static const struct mbox_chan_ops mtk_adsp_mbox_chan_ops = { 105 .send_data = mtk_adsp_mbox_send_data, 106 .startup = mtk_adsp_mbox_startup, 107 .shutdown = mtk_adsp_mbox_shutdown, 108 .last_tx_done = mtk_adsp_mbox_last_tx_done, 109 }; 110 111 static int mtk_adsp_mbox_probe(struct platform_device *pdev) 112 { 113 struct device *dev = &pdev->dev; 114 struct mtk_adsp_mbox_priv *priv; 115 const struct mtk_adsp_mbox_cfg *cfg; 116 struct mbox_controller *mbox; 117 int ret, irq; 118 119 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 120 if (!priv) 121 return -ENOMEM; 122 123 mbox = &priv->mbox; 124 mbox->dev = dev; 125 mbox->ops = &mtk_adsp_mbox_chan_ops; 126 mbox->txdone_irq = false; 127 mbox->txdone_poll = true; 128 mbox->of_xlate = mtk_adsp_mbox_xlate; 129 mbox->num_chans = 1; 130 mbox->chans = devm_kzalloc(dev, sizeof(*mbox->chans), GFP_KERNEL); 131 if (!mbox->chans) 132 return -ENOMEM; 133 134 priv->va_mboxreg = devm_platform_ioremap_resource(pdev, 0); 135 if (IS_ERR(priv->va_mboxreg)) 136 return PTR_ERR(priv->va_mboxreg); 137 138 cfg = of_device_get_match_data(dev); 139 if (!cfg) 140 return -EINVAL; 141 priv->cfg = cfg; 142 143 irq = platform_get_irq(pdev, 0); 144 if (irq < 0) 145 return irq; 146 147 priv->irq = irq; 148 ret = devm_request_threaded_irq(dev, irq, mtk_adsp_mbox_irq, 149 mtk_adsp_mbox_isr, 150 IRQF_TRIGGER_NONE | IRQF_NO_AUTOEN, 151 dev_name(dev), mbox->chans); 152 if (ret < 0) 153 return ret; 154 155 platform_set_drvdata(pdev, priv); 156 157 return devm_mbox_controller_register(dev, &priv->mbox); 158 } 159 160 static const struct mtk_adsp_mbox_cfg mt8186_adsp_mbox_cfg = { 161 .set_in = 0x00, 162 .set_out = 0x04, 163 .clr_in = 0x08, 164 .clr_out = 0x0C, 165 }; 166 167 static const struct mtk_adsp_mbox_cfg mt8195_adsp_mbox_cfg = { 168 .set_in = 0x00, 169 .set_out = 0x1c, 170 .clr_in = 0x04, 171 .clr_out = 0x20, 172 }; 173 174 static const struct of_device_id mtk_adsp_mbox_of_match[] = { 175 { .compatible = "mediatek,mt8186-adsp-mbox", .data = &mt8186_adsp_mbox_cfg }, 176 { .compatible = "mediatek,mt8195-adsp-mbox", .data = &mt8195_adsp_mbox_cfg }, 177 {}, 178 }; 179 MODULE_DEVICE_TABLE(of, mtk_adsp_mbox_of_match); 180 181 static struct platform_driver mtk_adsp_mbox_driver = { 182 .probe = mtk_adsp_mbox_probe, 183 .driver = { 184 .name = "mtk_adsp_mbox", 185 .of_match_table = mtk_adsp_mbox_of_match, 186 }, 187 }; 188 module_platform_driver(mtk_adsp_mbox_driver); 189 190 MODULE_AUTHOR("Allen-KH Cheng <Allen-KH.Cheng@mediatek.com>"); 191 MODULE_DESCRIPTION("MTK ADSP Mailbox Controller"); 192 MODULE_LICENSE("GPL v2"); 193