Blame view
drivers/mailbox/arm_mhu.c
3.73 KB
8e8e69d67
|
1 |
// SPDX-License-Identifier: GPL-2.0-only |
ee23d66af
|
2 3 4 5 |
/* * Copyright (C) 2013-2015 Fujitsu Semiconductor Ltd. * Copyright (C) 2015 Linaro Ltd. * Author: Jassi Brar <jaswinder.singh@linaro.org> |
ee23d66af
|
6 |
*/ |
06c182c3b
|
7 8 |
#include <linux/amba/bus.h> #include <linux/device.h> |
ee23d66af
|
9 |
#include <linux/err.h> |
06c182c3b
|
10 |
#include <linux/interrupt.h> |
ee23d66af
|
11 |
#include <linux/io.h> |
ee23d66af
|
12 |
#include <linux/mailbox_controller.h> |
06c182c3b
|
13 |
#include <linux/module.h> |
ee23d66af
|
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
#define INTR_STAT_OFS 0x0 #define INTR_SET_OFS 0x8 #define INTR_CLR_OFS 0x10 #define MHU_LP_OFFSET 0x0 #define MHU_HP_OFFSET 0x20 #define MHU_SEC_OFFSET 0x200 #define TX_REG_OFFSET 0x100 #define MHU_CHANS 3 struct mhu_link { unsigned irq; void __iomem *tx_reg; void __iomem *rx_reg; }; struct arm_mhu { void __iomem *base; struct mhu_link mlink[MHU_CHANS]; struct mbox_chan chan[MHU_CHANS]; struct mbox_controller mbox; }; static irqreturn_t mhu_rx_interrupt(int irq, void *p) { struct mbox_chan *chan = p; struct mhu_link *mlink = chan->con_priv; u32 val; val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS); if (!val) return IRQ_NONE; mbox_chan_received_data(chan, (void *)&val); writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS); return IRQ_HANDLED; } static bool mhu_last_tx_done(struct mbox_chan *chan) { struct mhu_link *mlink = chan->con_priv; u32 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS); return (val == 0); } static int mhu_send_data(struct mbox_chan *chan, void *data) { struct mhu_link *mlink = chan->con_priv; u32 *arg = data; writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS); return 0; } static int mhu_startup(struct mbox_chan *chan) { struct mhu_link *mlink = chan->con_priv; u32 val; int ret; val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS); writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS); ret = request_irq(mlink->irq, mhu_rx_interrupt, IRQF_SHARED, "mhu_link", chan); if (ret) { dev_err(chan->mbox->dev, |
971bd8fa3
|
87 88 |
"Unable to acquire IRQ %d ", mlink->irq); |
ee23d66af
|
89 90 91 92 93 94 95 96 97 98 99 100 |
return ret; } return 0; } static void mhu_shutdown(struct mbox_chan *chan) { struct mhu_link *mlink = chan->con_priv; free_irq(mlink->irq, chan); } |
05ae79756
|
101 |
static const struct mbox_chan_ops mhu_ops = { |
ee23d66af
|
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
.send_data = mhu_send_data, .startup = mhu_startup, .shutdown = mhu_shutdown, .last_tx_done = mhu_last_tx_done, }; static int mhu_probe(struct amba_device *adev, const struct amba_id *id) { int i, err; struct arm_mhu *mhu; struct device *dev = &adev->dev; int mhu_reg[MHU_CHANS] = {MHU_LP_OFFSET, MHU_HP_OFFSET, MHU_SEC_OFFSET}; /* Allocate memory for device */ mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL); if (!mhu) return -ENOMEM; mhu->base = devm_ioremap_resource(dev, &adev->res); if (IS_ERR(mhu->base)) { dev_err(dev, "ioremap failed "); return PTR_ERR(mhu->base); } for (i = 0; i < MHU_CHANS; i++) { mhu->chan[i].con_priv = &mhu->mlink[i]; mhu->mlink[i].irq = adev->irq[i]; mhu->mlink[i].rx_reg = mhu->base + mhu_reg[i]; mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET; } mhu->mbox.dev = dev; mhu->mbox.chans = &mhu->chan[0]; mhu->mbox.num_chans = MHU_CHANS; mhu->mbox.ops = &mhu_ops; mhu->mbox.txdone_irq = false; mhu->mbox.txdone_poll = true; |
86e488ada
|
140 |
mhu->mbox.txpoll_period = 1; |
ee23d66af
|
141 142 |
amba_set_drvdata(adev, mhu); |
6aba2f4aa
|
143 |
err = devm_mbox_controller_register(dev, &mhu->mbox); |
ee23d66af
|
144 145 146 147 148 149 150 151 152 153 |
if (err) { dev_err(dev, "Failed to register mailboxes %d ", err); return err; } dev_info(dev, "ARM MHU Mailbox registered "); return 0; } |
ee23d66af
|
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
static struct amba_id mhu_ids[] = { { .id = 0x1bb098, .mask = 0xffffff, }, { 0, 0 }, }; MODULE_DEVICE_TABLE(amba, mhu_ids); static struct amba_driver arm_mhu_driver = { .drv = { .name = "mhu", }, .id_table = mhu_ids, .probe = mhu_probe, |
ee23d66af
|
169 170 171 172 173 174 |
}; module_amba_driver(arm_mhu_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("ARM MHU Driver"); MODULE_AUTHOR("Jassi Brar <jassisinghbrar@gmail.com>"); |