xref: /openbmc/linux/drivers/mailbox/tegra-hsp.c (revision 4f6cce39)
1 /*
2  * Copyright (c) 2016, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  */
13 
14 #include <linux/interrupt.h>
15 #include <linux/io.h>
16 #include <linux/mailbox_controller.h>
17 #include <linux/of.h>
18 #include <linux/of_device.h>
19 #include <linux/platform_device.h>
20 #include <linux/slab.h>
21 
22 #include <dt-bindings/mailbox/tegra186-hsp.h>
23 
24 #define HSP_INT_DIMENSIONING	0x380
25 #define HSP_nSM_SHIFT		0
26 #define HSP_nSS_SHIFT		4
27 #define HSP_nAS_SHIFT		8
28 #define HSP_nDB_SHIFT		12
29 #define HSP_nSI_SHIFT		16
30 #define HSP_nINT_MASK		0xf
31 
32 #define HSP_DB_TRIGGER	0x0
33 #define HSP_DB_ENABLE	0x4
34 #define HSP_DB_RAW	0x8
35 #define HSP_DB_PENDING	0xc
36 
37 #define HSP_DB_CCPLEX		1
38 #define HSP_DB_BPMP		3
39 #define HSP_DB_MAX		7
40 
41 struct tegra_hsp_channel;
42 struct tegra_hsp;
43 
44 struct tegra_hsp_channel {
45 	struct tegra_hsp *hsp;
46 	struct mbox_chan *chan;
47 	void __iomem *regs;
48 };
49 
50 struct tegra_hsp_doorbell {
51 	struct tegra_hsp_channel channel;
52 	struct list_head list;
53 	const char *name;
54 	unsigned int master;
55 	unsigned int index;
56 };
57 
58 struct tegra_hsp_db_map {
59 	const char *name;
60 	unsigned int master;
61 	unsigned int index;
62 };
63 
64 struct tegra_hsp_soc {
65 	const struct tegra_hsp_db_map *map;
66 };
67 
68 struct tegra_hsp {
69 	const struct tegra_hsp_soc *soc;
70 	struct mbox_controller mbox;
71 	void __iomem *regs;
72 	unsigned int irq;
73 	unsigned int num_sm;
74 	unsigned int num_as;
75 	unsigned int num_ss;
76 	unsigned int num_db;
77 	unsigned int num_si;
78 	spinlock_t lock;
79 
80 	struct list_head doorbells;
81 };
82 
83 static inline struct tegra_hsp *
84 to_tegra_hsp(struct mbox_controller *mbox)
85 {
86 	return container_of(mbox, struct tegra_hsp, mbox);
87 }
88 
89 static inline u32 tegra_hsp_readl(struct tegra_hsp *hsp, unsigned int offset)
90 {
91 	return readl(hsp->regs + offset);
92 }
93 
94 static inline void tegra_hsp_writel(struct tegra_hsp *hsp, u32 value,
95 				    unsigned int offset)
96 {
97 	writel(value, hsp->regs + offset);
98 }
99 
100 static inline u32 tegra_hsp_channel_readl(struct tegra_hsp_channel *channel,
101 					  unsigned int offset)
102 {
103 	return readl(channel->regs + offset);
104 }
105 
106 static inline void tegra_hsp_channel_writel(struct tegra_hsp_channel *channel,
107 					    u32 value, unsigned int offset)
108 {
109 	writel(value, channel->regs + offset);
110 }
111 
112 static bool tegra_hsp_doorbell_can_ring(struct tegra_hsp_doorbell *db)
113 {
114 	u32 value;
115 
116 	value = tegra_hsp_channel_readl(&db->channel, HSP_DB_ENABLE);
117 
118 	return (value & BIT(TEGRA_HSP_DB_MASTER_CCPLEX)) != 0;
119 }
120 
121 static struct tegra_hsp_doorbell *
122 __tegra_hsp_doorbell_get(struct tegra_hsp *hsp, unsigned int master)
123 {
124 	struct tegra_hsp_doorbell *entry;
125 
126 	list_for_each_entry(entry, &hsp->doorbells, list)
127 		if (entry->master == master)
128 			return entry;
129 
130 	return NULL;
131 }
132 
133 static struct tegra_hsp_doorbell *
134 tegra_hsp_doorbell_get(struct tegra_hsp *hsp, unsigned int master)
135 {
136 	struct tegra_hsp_doorbell *db;
137 	unsigned long flags;
138 
139 	spin_lock_irqsave(&hsp->lock, flags);
140 	db = __tegra_hsp_doorbell_get(hsp, master);
141 	spin_unlock_irqrestore(&hsp->lock, flags);
142 
143 	return db;
144 }
145 
146 static irqreturn_t tegra_hsp_doorbell_irq(int irq, void *data)
147 {
148 	struct tegra_hsp *hsp = data;
149 	struct tegra_hsp_doorbell *db;
150 	unsigned long master, value;
151 
152 	db = tegra_hsp_doorbell_get(hsp, TEGRA_HSP_DB_MASTER_CCPLEX);
153 	if (!db)
154 		return IRQ_NONE;
155 
156 	value = tegra_hsp_channel_readl(&db->channel, HSP_DB_PENDING);
157 	tegra_hsp_channel_writel(&db->channel, value, HSP_DB_PENDING);
158 
159 	spin_lock(&hsp->lock);
160 
161 	for_each_set_bit(master, &value, hsp->mbox.num_chans) {
162 		struct tegra_hsp_doorbell *db;
163 
164 		db = __tegra_hsp_doorbell_get(hsp, master);
165 		/*
166 		 * Depending on the bootloader chain, the CCPLEX doorbell will
167 		 * have some doorbells enabled, which means that requesting an
168 		 * interrupt will immediately fire.
169 		 *
170 		 * In that case, db->channel.chan will still be NULL here and
171 		 * cause a crash if not properly guarded.
172 		 *
173 		 * It remains to be seen if ignoring the doorbell in that case
174 		 * is the correct solution.
175 		 */
176 		if (db && db->channel.chan)
177 			mbox_chan_received_data(db->channel.chan, NULL);
178 	}
179 
180 	spin_unlock(&hsp->lock);
181 
182 	return IRQ_HANDLED;
183 }
184 
185 static struct tegra_hsp_channel *
186 tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
187 			  unsigned int master, unsigned int index)
188 {
189 	struct tegra_hsp_doorbell *db;
190 	unsigned int offset;
191 	unsigned long flags;
192 
193 	db = kzalloc(sizeof(*db), GFP_KERNEL);
194 	if (!db)
195 		return ERR_PTR(-ENOMEM);
196 
197 	offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) << 16;
198 	offset += index * 0x100;
199 
200 	db->channel.regs = hsp->regs + offset;
201 	db->channel.hsp = hsp;
202 
203 	db->name = kstrdup_const(name, GFP_KERNEL);
204 	db->master = master;
205 	db->index = index;
206 
207 	spin_lock_irqsave(&hsp->lock, flags);
208 	list_add_tail(&db->list, &hsp->doorbells);
209 	spin_unlock_irqrestore(&hsp->lock, flags);
210 
211 	return &db->channel;
212 }
213 
214 static void __tegra_hsp_doorbell_destroy(struct tegra_hsp_doorbell *db)
215 {
216 	list_del(&db->list);
217 	kfree_const(db->name);
218 	kfree(db);
219 }
220 
221 static int tegra_hsp_doorbell_send_data(struct mbox_chan *chan, void *data)
222 {
223 	struct tegra_hsp_doorbell *db = chan->con_priv;
224 
225 	tegra_hsp_channel_writel(&db->channel, 1, HSP_DB_TRIGGER);
226 
227 	return 0;
228 }
229 
230 static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
231 {
232 	struct tegra_hsp_doorbell *db = chan->con_priv;
233 	struct tegra_hsp *hsp = db->channel.hsp;
234 	struct tegra_hsp_doorbell *ccplex;
235 	unsigned long flags;
236 	u32 value;
237 
238 	if (db->master >= hsp->mbox.num_chans) {
239 		dev_err(hsp->mbox.dev,
240 			"invalid master ID %u for HSP channel\n",
241 			db->master);
242 		return -EINVAL;
243 	}
244 
245 	ccplex = tegra_hsp_doorbell_get(hsp, TEGRA_HSP_DB_MASTER_CCPLEX);
246 	if (!ccplex)
247 		return -ENODEV;
248 
249 	if (!tegra_hsp_doorbell_can_ring(db))
250 		return -ENODEV;
251 
252 	spin_lock_irqsave(&hsp->lock, flags);
253 
254 	value = tegra_hsp_channel_readl(&ccplex->channel, HSP_DB_ENABLE);
255 	value |= BIT(db->master);
256 	tegra_hsp_channel_writel(&ccplex->channel, value, HSP_DB_ENABLE);
257 
258 	spin_unlock_irqrestore(&hsp->lock, flags);
259 
260 	return 0;
261 }
262 
263 static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
264 {
265 	struct tegra_hsp_doorbell *db = chan->con_priv;
266 	struct tegra_hsp *hsp = db->channel.hsp;
267 	struct tegra_hsp_doorbell *ccplex;
268 	unsigned long flags;
269 	u32 value;
270 
271 	ccplex = tegra_hsp_doorbell_get(hsp, TEGRA_HSP_DB_MASTER_CCPLEX);
272 	if (!ccplex)
273 		return;
274 
275 	spin_lock_irqsave(&hsp->lock, flags);
276 
277 	value = tegra_hsp_channel_readl(&ccplex->channel, HSP_DB_ENABLE);
278 	value &= ~BIT(db->master);
279 	tegra_hsp_channel_writel(&ccplex->channel, value, HSP_DB_ENABLE);
280 
281 	spin_unlock_irqrestore(&hsp->lock, flags);
282 }
283 
284 static const struct mbox_chan_ops tegra_hsp_doorbell_ops = {
285 	.send_data = tegra_hsp_doorbell_send_data,
286 	.startup = tegra_hsp_doorbell_startup,
287 	.shutdown = tegra_hsp_doorbell_shutdown,
288 };
289 
290 static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
291 					    const struct of_phandle_args *args)
292 {
293 	struct tegra_hsp_channel *channel = ERR_PTR(-ENODEV);
294 	struct tegra_hsp *hsp = to_tegra_hsp(mbox);
295 	unsigned int type = args->args[0];
296 	unsigned int master = args->args[1];
297 	struct tegra_hsp_doorbell *db;
298 	struct mbox_chan *chan;
299 	unsigned long flags;
300 	unsigned int i;
301 
302 	switch (type) {
303 	case TEGRA_HSP_MBOX_TYPE_DB:
304 		db = tegra_hsp_doorbell_get(hsp, master);
305 		if (db)
306 			channel = &db->channel;
307 
308 		break;
309 
310 	default:
311 		break;
312 	}
313 
314 	if (IS_ERR(channel))
315 		return ERR_CAST(channel);
316 
317 	spin_lock_irqsave(&hsp->lock, flags);
318 
319 	for (i = 0; i < hsp->mbox.num_chans; i++) {
320 		chan = &hsp->mbox.chans[i];
321 		if (!chan->con_priv) {
322 			chan->con_priv = channel;
323 			channel->chan = chan;
324 			break;
325 		}
326 
327 		chan = NULL;
328 	}
329 
330 	spin_unlock_irqrestore(&hsp->lock, flags);
331 
332 	return chan ?: ERR_PTR(-EBUSY);
333 }
334 
335 static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp)
336 {
337 	struct tegra_hsp_doorbell *db, *tmp;
338 	unsigned long flags;
339 
340 	spin_lock_irqsave(&hsp->lock, flags);
341 
342 	list_for_each_entry_safe(db, tmp, &hsp->doorbells, list)
343 		__tegra_hsp_doorbell_destroy(db);
344 
345 	spin_unlock_irqrestore(&hsp->lock, flags);
346 }
347 
348 static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp)
349 {
350 	const struct tegra_hsp_db_map *map = hsp->soc->map;
351 	struct tegra_hsp_channel *channel;
352 
353 	while (map->name) {
354 		channel = tegra_hsp_doorbell_create(hsp, map->name,
355 						    map->master, map->index);
356 		if (IS_ERR(channel)) {
357 			tegra_hsp_remove_doorbells(hsp);
358 			return PTR_ERR(channel);
359 		}
360 
361 		map++;
362 	}
363 
364 	return 0;
365 }
366 
367 static int tegra_hsp_probe(struct platform_device *pdev)
368 {
369 	struct tegra_hsp *hsp;
370 	struct resource *res;
371 	u32 value;
372 	int err;
373 
374 	hsp = devm_kzalloc(&pdev->dev, sizeof(*hsp), GFP_KERNEL);
375 	if (!hsp)
376 		return -ENOMEM;
377 
378 	hsp->soc = of_device_get_match_data(&pdev->dev);
379 	INIT_LIST_HEAD(&hsp->doorbells);
380 	spin_lock_init(&hsp->lock);
381 
382 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
383 	hsp->regs = devm_ioremap_resource(&pdev->dev, res);
384 	if (IS_ERR(hsp->regs))
385 		return PTR_ERR(hsp->regs);
386 
387 	value = tegra_hsp_readl(hsp, HSP_INT_DIMENSIONING);
388 	hsp->num_sm = (value >> HSP_nSM_SHIFT) & HSP_nINT_MASK;
389 	hsp->num_ss = (value >> HSP_nSS_SHIFT) & HSP_nINT_MASK;
390 	hsp->num_as = (value >> HSP_nAS_SHIFT) & HSP_nINT_MASK;
391 	hsp->num_db = (value >> HSP_nDB_SHIFT) & HSP_nINT_MASK;
392 	hsp->num_si = (value >> HSP_nSI_SHIFT) & HSP_nINT_MASK;
393 
394 	err = platform_get_irq_byname(pdev, "doorbell");
395 	if (err < 0) {
396 		dev_err(&pdev->dev, "failed to get doorbell IRQ: %d\n", err);
397 		return err;
398 	}
399 
400 	hsp->irq = err;
401 
402 	hsp->mbox.of_xlate = of_tegra_hsp_xlate;
403 	hsp->mbox.num_chans = 32;
404 	hsp->mbox.dev = &pdev->dev;
405 	hsp->mbox.txdone_irq = false;
406 	hsp->mbox.txdone_poll = false;
407 	hsp->mbox.ops = &tegra_hsp_doorbell_ops;
408 
409 	hsp->mbox.chans = devm_kcalloc(&pdev->dev, hsp->mbox.num_chans,
410 					sizeof(*hsp->mbox.chans),
411 					GFP_KERNEL);
412 	if (!hsp->mbox.chans)
413 		return -ENOMEM;
414 
415 	err = tegra_hsp_add_doorbells(hsp);
416 	if (err < 0) {
417 		dev_err(&pdev->dev, "failed to add doorbells: %d\n", err);
418 		return err;
419 	}
420 
421 	platform_set_drvdata(pdev, hsp);
422 
423 	err = mbox_controller_register(&hsp->mbox);
424 	if (err) {
425 		dev_err(&pdev->dev, "failed to register mailbox: %d\n", err);
426 		tegra_hsp_remove_doorbells(hsp);
427 		return err;
428 	}
429 
430 	err = devm_request_irq(&pdev->dev, hsp->irq, tegra_hsp_doorbell_irq,
431 			       IRQF_NO_SUSPEND, dev_name(&pdev->dev), hsp);
432 	if (err < 0) {
433 		dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n",
434 			hsp->irq, err);
435 		return err;
436 	}
437 
438 	return 0;
439 }
440 
441 static int tegra_hsp_remove(struct platform_device *pdev)
442 {
443 	struct tegra_hsp *hsp = platform_get_drvdata(pdev);
444 
445 	mbox_controller_unregister(&hsp->mbox);
446 	tegra_hsp_remove_doorbells(hsp);
447 
448 	return 0;
449 }
450 
451 static const struct tegra_hsp_db_map tegra186_hsp_db_map[] = {
452 	{ "ccplex", TEGRA_HSP_DB_MASTER_CCPLEX, HSP_DB_CCPLEX, },
453 	{ "bpmp",   TEGRA_HSP_DB_MASTER_BPMP,   HSP_DB_BPMP,   },
454 	{ /* sentinel */ }
455 };
456 
457 static const struct tegra_hsp_soc tegra186_hsp_soc = {
458 	.map = tegra186_hsp_db_map,
459 };
460 
461 static const struct of_device_id tegra_hsp_match[] = {
462 	{ .compatible = "nvidia,tegra186-hsp", .data = &tegra186_hsp_soc },
463 	{ }
464 };
465 
466 static struct platform_driver tegra_hsp_driver = {
467 	.driver = {
468 		.name = "tegra-hsp",
469 		.of_match_table = tegra_hsp_match,
470 	},
471 	.probe = tegra_hsp_probe,
472 	.remove = tegra_hsp_remove,
473 };
474 
475 static int __init tegra_hsp_init(void)
476 {
477 	return platform_driver_register(&tegra_hsp_driver);
478 }
479 core_initcall(tegra_hsp_init);
480