185 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2016 BayLibre SAS.4 * Author: Neil Armstrong <narmstrong@baylibre.com>5 * Synchronised with arm_mhu.c from :6 * Copyright (C) 2013-2015 Fujitsu Semiconductor Ltd.7 * Copyright (C) 2015 Linaro Ltd.8 * Author: Jassi Brar <jaswinder.singh@linaro.org>9 */10 11#include <linux/interrupt.h>12#include <linux/spinlock.h>13#include <linux/mutex.h>14#include <linux/delay.h>15#include <linux/slab.h>16#include <linux/err.h>17#include <linux/io.h>18#include <linux/mod_devicetable.h>19#include <linux/module.h>20#include <linux/platform_device.h>21#include <linux/mailbox_controller.h>22 23#define INTR_SET_OFS 0x024#define INTR_STAT_OFS 0x425#define INTR_CLR_OFS 0x826 27#define MHU_SEC_OFFSET 0x028#define MHU_LP_OFFSET 0xc29#define MHU_HP_OFFSET 0x1830#define TX_REG_OFFSET 0x2431 32#define MHU_CHANS 333 34struct platform_mhu_link {35 int irq;36 void __iomem *tx_reg;37 void __iomem *rx_reg;38};39 40struct platform_mhu {41 void __iomem *base;42 struct platform_mhu_link mlink[MHU_CHANS];43 struct mbox_chan chan[MHU_CHANS];44 struct mbox_controller mbox;45};46 47static irqreturn_t platform_mhu_rx_interrupt(int irq, void *p)48{49 struct mbox_chan *chan = p;50 struct platform_mhu_link *mlink = chan->con_priv;51 u32 val;52 53 val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS);54 if (!val)55 return IRQ_NONE;56 57 mbox_chan_received_data(chan, (void *)&val);58 59 writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS);60 61 return IRQ_HANDLED;62}63 64static bool platform_mhu_last_tx_done(struct mbox_chan *chan)65{66 struct platform_mhu_link *mlink = chan->con_priv;67 u32 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);68 69 return (val == 0);70}71 72static int platform_mhu_send_data(struct mbox_chan *chan, void *data)73{74 struct platform_mhu_link *mlink = chan->con_priv;75 u32 *arg = data;76 77 writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS);78 79 return 0;80}81 82static int platform_mhu_startup(struct mbox_chan *chan)83{84 struct platform_mhu_link *mlink = chan->con_priv;85 u32 val;86 int ret;87 88 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);89 writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS);90 91 ret = request_irq(mlink->irq, platform_mhu_rx_interrupt,92 IRQF_SHARED, "platform_mhu_link", chan);93 if (ret) {94 dev_err(chan->mbox->dev,95 "Unable to acquire IRQ %d\n", mlink->irq);96 return ret;97 }98 99 return 0;100}101 102static void platform_mhu_shutdown(struct mbox_chan *chan)103{104 struct platform_mhu_link *mlink = chan->con_priv;105 106 free_irq(mlink->irq, chan);107}108 109static const struct mbox_chan_ops platform_mhu_ops = {110 .send_data = platform_mhu_send_data,111 .startup = platform_mhu_startup,112 .shutdown = platform_mhu_shutdown,113 .last_tx_done = platform_mhu_last_tx_done,114};115 116static int platform_mhu_probe(struct platform_device *pdev)117{118 int i, err;119 struct platform_mhu *mhu;120 struct device *dev = &pdev->dev;121 int platform_mhu_reg[MHU_CHANS] = {122 MHU_SEC_OFFSET, MHU_LP_OFFSET, MHU_HP_OFFSET123 };124 125 /* Allocate memory for device */126 mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL);127 if (!mhu)128 return -ENOMEM;129 130 mhu->base = devm_platform_ioremap_resource(pdev, 0);131 if (IS_ERR(mhu->base)) {132 dev_err(dev, "ioremap failed\n");133 return PTR_ERR(mhu->base);134 }135 136 for (i = 0; i < MHU_CHANS; i++) {137 mhu->chan[i].con_priv = &mhu->mlink[i];138 mhu->mlink[i].irq = platform_get_irq(pdev, i);139 if (mhu->mlink[i].irq < 0)140 return mhu->mlink[i].irq;141 mhu->mlink[i].rx_reg = mhu->base + platform_mhu_reg[i];142 mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET;143 }144 145 mhu->mbox.dev = dev;146 mhu->mbox.chans = &mhu->chan[0];147 mhu->mbox.num_chans = MHU_CHANS;148 mhu->mbox.ops = &platform_mhu_ops;149 mhu->mbox.txdone_irq = false;150 mhu->mbox.txdone_poll = true;151 mhu->mbox.txpoll_period = 1;152 153 platform_set_drvdata(pdev, mhu);154 155 err = devm_mbox_controller_register(dev, &mhu->mbox);156 if (err) {157 dev_err(dev, "Failed to register mailboxes %d\n", err);158 return err;159 }160 161 dev_info(dev, "Platform MHU Mailbox registered\n");162 return 0;163}164 165static const struct of_device_id platform_mhu_dt_ids[] = {166 { .compatible = "amlogic,meson-gxbb-mhu", },167 { /* sentinel */ },168};169MODULE_DEVICE_TABLE(of, platform_mhu_dt_ids);170 171static struct platform_driver platform_mhu_driver = {172 .probe = platform_mhu_probe,173 .driver = {174 .name = "platform-mhu",175 .of_match_table = platform_mhu_dt_ids,176 },177};178 179module_platform_driver(platform_mhu_driver);180 181MODULE_LICENSE("GPL v2");182MODULE_ALIAS("platform:platform-mhu");183MODULE_DESCRIPTION("Platform MHU Driver");184MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");185