Blame view

drivers/mailbox/arm_mhu.c 3.73 KB
8e8e69d67   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
ee23d66af   Jassi Brar   mailbox: arm_mhu:...
2
3
4
5
  /*
   * Copyright (C) 2013-2015 Fujitsu Semiconductor Ltd.
   * Copyright (C) 2015 Linaro Ltd.
   * Author: Jassi Brar <jaswinder.singh@linaro.org>
ee23d66af   Jassi Brar   mailbox: arm_mhu:...
6
   */
06c182c3b   Sudeep Holla   mailbox: arm_mhu:...
7
8
  #include <linux/amba/bus.h>
  #include <linux/device.h>
ee23d66af   Jassi Brar   mailbox: arm_mhu:...
9
  #include <linux/err.h>
06c182c3b   Sudeep Holla   mailbox: arm_mhu:...
10
  #include <linux/interrupt.h>
ee23d66af   Jassi Brar   mailbox: arm_mhu:...
11
  #include <linux/io.h>
ee23d66af   Jassi Brar   mailbox: arm_mhu:...
12
  #include <linux/mailbox_controller.h>
06c182c3b   Sudeep Holla   mailbox: arm_mhu:...
13
  #include <linux/module.h>
ee23d66af   Jassi Brar   mailbox: arm_mhu:...
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   Masanari Iida   treewide: Fix typ...
87
88
  			"Unable to acquire IRQ %d
  ", mlink->irq);
ee23d66af   Jassi Brar   mailbox: arm_mhu:...
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   Andrew Bresticker   mailbox: Make mbo...
101
  static const struct mbox_chan_ops mhu_ops = {
ee23d66af   Jassi Brar   mailbox: arm_mhu:...
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   Sudeep Holla   mailbox: arm_mhu:...
140
  	mhu->mbox.txpoll_period = 1;
ee23d66af   Jassi Brar   mailbox: arm_mhu:...
141
142
  
  	amba_set_drvdata(adev, mhu);
6aba2f4aa   Thierry Reding   mailbox: arm-mhu:...
143
  	err = devm_mbox_controller_register(dev, &mhu->mbox);
ee23d66af   Jassi Brar   mailbox: arm_mhu:...
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   Jassi Brar   mailbox: arm_mhu:...
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   Jassi Brar   mailbox: arm_mhu:...
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>");