xref: /linux/drivers/soc/renesas/rcar-mfis.c (revision 637315cb400eed1dbe721954fea437a61a2d65b2)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Renesas R-Car MFIS (Multifunctional Interface) driver
4  *
5  * Copyright (C) Renesas Solutions Corp.
6  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
7  * Wolfram Sang <wsa+renesas@sang-engineering.com>
8  */
9 #include <dt-bindings/soc/renesas,r8a78000-mfis.h>
10 #include <linux/device.h>
11 #include <linux/interrupt.h>
12 #include <linux/io.h>
13 #include <linux/kernel.h>
14 #include <linux/mailbox_controller.h>
15 #include <linux/module.h>
16 #include <linux/of.h>
17 #include <linux/of_irq.h>
18 #include <linux/of_platform.h>
19 #include <linux/platform_device.h>
20 #include <linux/spinlock.h>
21 
22 #define MFISWPCNTR	0x0900
23 #define MFISWACNTR	0x0904
24 
25 #define MFIS_X5H_IICR(i) ((i) * 0x1000 + 0x00)
26 #define MFIS_X5H_EICR(i) ((i) * 0x1000 + 0x04)
27 
28 #define MFIS_UNPROTECT_KEY 0xACCE0000
29 
30 struct mfis_priv;
31 
32 struct mfis_reg {
33 	void __iomem *base;
34 	resource_size_t start;
35 	struct mfis_priv *priv;
36 };
37 
38 struct mfis_info {
39 	u32 unprotect_mask;
40 	unsigned int mb_num_channels;
41 	unsigned int mb_reg_comes_from_dt:1;
42 	unsigned int mb_tx_uses_eicr:1;
43 	unsigned int mb_channels_are_unidir:1;
44 	u32 (*mb_calc_reg)(u32 chan_num, bool tx_uses_eicr, bool is_only_rx);
45 };
46 
47 struct mfis_chan_priv {
48 	u32 reg;
49 	int irq;
50 };
51 
52 struct mfis_priv {
53 	spinlock_t unprotect_lock; /* guards access to the unprotection reg */
54 	struct device *dev;
55 	struct mfis_reg common_reg;
56 	struct mfis_reg mbox_reg;
57 	const struct mfis_info *info;
58 
59 	/* mailbox private data */
60 	struct mbox_controller mbox;
61 	struct mfis_chan_priv *chan_privs;
62 };
63 
64 static u32 mfis_read(struct mfis_reg *mreg, unsigned int reg)
65 {
66 	return ioread32(mreg->base + reg);
67 }
68 
69 static void mfis_write(struct mfis_reg *mreg, u32 reg, u32 val)
70 {
71 	struct mfis_priv *priv = mreg->priv;
72 	u32 unprotect_mask = priv->info->unprotect_mask;
73 	unsigned long flags;
74 	u32 unprotect_code;
75 
76 	/*
77 	 * [Gen4] key: 0xACCE0000, mask: 0x0000FFFF
78 	 * [Gen5] key: 0xACC00000, mask: 0x000FFFFF
79 	 */
80 	unprotect_code = (MFIS_UNPROTECT_KEY & ~unprotect_mask) |
81 			 ((mreg->start + reg) & unprotect_mask);
82 
83 	spin_lock_irqsave(&priv->unprotect_lock, flags);
84 	iowrite32(unprotect_code, priv->common_reg.base + MFISWACNTR);
85 	iowrite32(val, mreg->base + reg);
86 	spin_unlock_irqrestore(&priv->unprotect_lock, flags);
87 }
88 
89 /********************************************************
90  *			Mailbox				*
91  ********************************************************/
92 
93 #define mfis_mb_mbox_to_priv(_m) container_of((_m), struct mfis_priv, mbox)
94 
95 static irqreturn_t mfis_mb_iicr_interrupt(int irq, void *data)
96 {
97 	struct mbox_chan *chan = data;
98 	struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox);
99 	struct mfis_chan_priv *chan_priv = chan->con_priv;
100 
101 	mbox_chan_received_data(chan, NULL);
102 	/* Stop remote(!) doorbell */
103 	mfis_write(&priv->mbox_reg, chan_priv->reg, 0);
104 
105 	return IRQ_HANDLED;
106 }
107 
108 static int mfis_mb_startup(struct mbox_chan *chan)
109 {
110 	struct mfis_chan_priv *chan_priv = chan->con_priv;
111 
112 	if (!chan_priv->irq)
113 		return 0;
114 
115 	return request_irq(chan_priv->irq, mfis_mb_iicr_interrupt, 0,
116 			   dev_name(chan->mbox->dev), chan);
117 }
118 
119 static void mfis_mb_shutdown(struct mbox_chan *chan)
120 {
121 	struct mfis_chan_priv *chan_priv = chan->con_priv;
122 
123 	if (chan_priv->irq)
124 		free_irq(chan_priv->irq, chan);
125 }
126 
127 static int mfis_mb_iicr_send_data(struct mbox_chan *chan, void *data)
128 {
129 	struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox);
130 	struct mfis_chan_priv *chan_priv = chan->con_priv;
131 
132 	/* Our doorbell still active? */
133 	if (mfis_read(&priv->mbox_reg, chan_priv->reg) & BIT(0))
134 		return -EBUSY;
135 
136 	/* Start our doorbell */
137 	mfis_write(&priv->mbox_reg, chan_priv->reg, BIT(0));
138 
139 	return 0;
140 }
141 
142 static bool mfis_mb_iicr_last_tx_done(struct mbox_chan *chan)
143 {
144 	struct mfis_priv *priv = mfis_mb_mbox_to_priv(chan->mbox);
145 	struct mfis_chan_priv *chan_priv = chan->con_priv;
146 
147 	/* Our doorbell still active? */
148 	return !(mfis_read(&priv->mbox_reg, chan_priv->reg) & BIT(0));
149 }
150 
151 /* For MFIS variants using the IICR/EICR register pair */
152 static const struct mbox_chan_ops mfis_iicr_ops = {
153 	.startup = mfis_mb_startup,
154 	.shutdown = mfis_mb_shutdown,
155 	.send_data = mfis_mb_iicr_send_data,
156 	.last_tx_done = mfis_mb_iicr_last_tx_done,
157 };
158 
159 static u32 mfis_mb_r8a779g0_calc_reg(u32 chan_num, bool tx_uses_eicr, bool is_only_rx)
160 {
161 	unsigned int i, k;
162 	u32 reg;
163 
164 	i = chan_num & 3;
165 	k = chan_num >> 2;
166 
167 	if (is_only_rx) {
168 		if (k < 2)
169 			reg = 0x9404 + 0x1020 * k + 0x08 * i;
170 		else
171 			reg = 0xb504 + 0x08 * i;
172 	} else {
173 		if (k < 2)
174 			reg = 0x1400 + 0x1008 * i + 0x20 * k;
175 		else
176 			reg = 0x1500 + 0x1008 * i;
177 	}
178 
179 	return reg;
180 }
181 
182 static u32 mfis_mb_r8a78000_calc_reg(u32 chan_num, bool tx_uses_eicr, bool is_only_rx)
183 {
184 	return (tx_uses_eicr ^ is_only_rx) ? MFIS_X5H_EICR(chan_num) :
185 					     MFIS_X5H_IICR(chan_num);
186 }
187 
188 static struct mbox_chan *mfis_mb_of_xlate(struct mbox_controller *mbox,
189 					  const struct of_phandle_args *sp)
190 {
191 	struct mfis_priv *priv = mfis_mb_mbox_to_priv(mbox);
192 	struct mfis_chan_priv *chan_priv;
193 	bool tx_uses_eicr, is_only_rx;
194 	u32 chan_num, chan_flags;
195 	struct mbox_chan *chan;
196 
197 	if (sp->args_count != 2)
198 		return ERR_PTR(-EINVAL);
199 
200 	chan_num = sp->args[0];
201 	chan_flags = sp->args[1];
202 
203 	if (chan_num >= priv->info->mb_num_channels)
204 		return ERR_PTR(-EINVAL);
205 
206 	/* Channel layout is described in mfis_mb_probe() */
207 	if (priv->info->mb_channels_are_unidir) {
208 		is_only_rx = chan_flags & MFIS_CHANNEL_RX;
209 		chan = mbox->chans + 2 * chan_num + is_only_rx;
210 	} else {
211 		is_only_rx = false;
212 		chan = mbox->chans + chan_num;
213 	}
214 
215 	if (priv->info->mb_reg_comes_from_dt) {
216 		tx_uses_eicr = chan_flags & MFIS_CHANNEL_EICR;
217 		if (tx_uses_eicr)
218 			chan += mbox->num_chans / 2;
219 	} else {
220 		tx_uses_eicr = priv->info->mb_tx_uses_eicr;
221 	}
222 
223 	chan_priv = chan->con_priv;
224 	chan_priv->reg = priv->info->mb_calc_reg(chan_num, tx_uses_eicr, is_only_rx);
225 
226 	if (!priv->info->mb_channels_are_unidir || is_only_rx) {
227 		char irqname[8];
228 		char suffix = tx_uses_eicr ? 'i' : 'e';
229 
230 		/* "ch0i" or "ch0e" */
231 		scnprintf(irqname, sizeof(irqname), "ch%u%c", chan_num, suffix);
232 
233 		chan_priv->irq = of_irq_get_byname(mbox->dev->of_node, irqname);
234 		if (chan_priv->irq < 0)
235 			return ERR_PTR(chan_priv->irq);
236 		if (chan_priv->irq == 0)
237 			return ERR_PTR(-ENOENT);
238 	}
239 
240 	return chan;
241 }
242 
243 static int mfis_mb_probe(struct mfis_priv *priv)
244 {
245 	unsigned int num_chan = priv->info->mb_num_channels;
246 	struct device *dev = priv->dev;
247 	struct mbox_controller *mbox;
248 	struct mbox_chan *chan;
249 
250 	if (priv->info->mb_channels_are_unidir) {
251 		/* Channel layout: Ch0-TX, Ch0-RX, Ch1-TX... */
252 		num_chan *= 2;
253 	}
254 
255 	if (priv->info->mb_reg_comes_from_dt) {
256 		/* Channel layout: <n> IICR channels, <n> EICR channels */
257 		num_chan *= 2;
258 	}
259 
260 	chan  = devm_kcalloc(dev, num_chan, sizeof(*chan), GFP_KERNEL);
261 	if (!chan)
262 		return -ENOMEM;
263 
264 	priv->chan_privs = devm_kcalloc(dev, num_chan, sizeof(*priv->chan_privs),
265 					    GFP_KERNEL);
266 	if (!priv->chan_privs)
267 		return -ENOMEM;
268 
269 	mbox = &priv->mbox;
270 
271 	for (unsigned int i = 0; i < num_chan; i++)
272 		chan[i].con_priv = &priv->chan_privs[i];
273 
274 	mbox->chans = chan;
275 	mbox->num_chans = num_chan;
276 	mbox->txdone_poll = true;
277 	mbox->ops = &mfis_iicr_ops;
278 	mbox->dev = dev;
279 	mbox->of_xlate = mfis_mb_of_xlate;
280 
281 	return devm_mbox_controller_register(dev, mbox);
282 }
283 
284 /********************************************************
285  *			Common				*
286  ********************************************************/
287 static int mfis_reg_probe(struct platform_device *pdev, struct mfis_priv *priv,
288 			  struct mfis_reg *mreg, const char *name, bool required)
289 {
290 	struct resource *res;
291 	void __iomem *base;
292 
293 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
294 
295 	/* If there is no mailbox resource, registers are in the common space */
296 	if (!res && !required) {
297 		*mreg = priv->common_reg;
298 	} else {
299 		base = devm_ioremap_resource(&pdev->dev, res);
300 		if (IS_ERR(base))
301 			return PTR_ERR(base);
302 
303 		mreg->base = base;
304 		mreg->start = res->start;
305 		mreg->priv = priv;
306 	}
307 
308 	return 0;
309 }
310 
311 static int mfis_probe(struct platform_device *pdev)
312 {
313 	struct device *dev = &pdev->dev;
314 	struct mfis_priv *priv;
315 	int ret;
316 
317 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
318 	if (!priv)
319 		return -ENOMEM;
320 
321 	priv->dev = dev;
322 	priv->info = of_device_get_match_data(dev);
323 	if (!priv->info)
324 		return -ENOENT;
325 
326 	spin_lock_init(&priv->unprotect_lock);
327 
328 	ret = mfis_reg_probe(pdev, priv, &priv->common_reg, "common", true);
329 	if (ret)
330 		return ret;
331 
332 	ret = mfis_reg_probe(pdev, priv, &priv->mbox_reg, "mboxes", false);
333 	if (ret)
334 		return ret;
335 
336 	return mfis_mb_probe(priv);
337 }
338 
339 static const struct mfis_info mfis_info_r8a779g0 = {
340 	.unprotect_mask	= 0x0000ffff,
341 	.mb_num_channels = 12,
342 	.mb_channels_are_unidir = true,
343 	.mb_calc_reg = mfis_mb_r8a779g0_calc_reg,
344 };
345 
346 static const struct mfis_info mfis_info_r8a78000 = {
347 	.unprotect_mask	= 0x000fffff,
348 	.mb_num_channels = 64,
349 	.mb_reg_comes_from_dt = true,
350 	.mb_channels_are_unidir = true,
351 	.mb_calc_reg = mfis_mb_r8a78000_calc_reg,
352 };
353 
354 static const struct mfis_info mfis_info_r8a78000_scp = {
355 	.unprotect_mask	= 0x000fffff,
356 	.mb_num_channels = 32,
357 	.mb_tx_uses_eicr = true,
358 	.mb_channels_are_unidir = true,
359 	.mb_calc_reg = mfis_mb_r8a78000_calc_reg,
360 };
361 
362 static const struct of_device_id mfis_mfd_of_match[] = {
363 	{ .compatible = "renesas,r8a779g0-mfis", .data = &mfis_info_r8a779g0, },
364 	{ .compatible = "renesas,r8a779h0-mfis", .data = &mfis_info_r8a779g0, },
365 	{ .compatible = "renesas,r8a78000-mfis", .data = &mfis_info_r8a78000, },
366 	{ .compatible = "renesas,r8a78000-mfis-scp", .data = &mfis_info_r8a78000_scp, },
367 	{}
368 };
369 MODULE_DEVICE_TABLE(of, mfis_mfd_of_match);
370 
371 static struct platform_driver mfis_driver = {
372 	.driver = {
373 		.name = "rcar-mfis",
374 		.of_match_table = mfis_mfd_of_match,
375 		.suppress_bind_attrs = true,
376 	},
377 	.probe	= mfis_probe,
378 };
379 module_platform_driver(mfis_driver);
380 
381 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
382 MODULE_AUTHOR("Wolfram Sang <wsa+renesas@sang-engineering.com>");
383 MODULE_LICENSE("GPL");
384 MODULE_DESCRIPTION("Renesas R-Car MFIS driver");
385